Add documents to stock lots
This commit is contained in:
1 parent
e47990dfe0
commit
2bec934732
5 files changed
+294
-2
No files matched your search
@@ -20,6 +20,32 @@ try {
|
||||
json_response(405, ['ok' => false, 'error' => 'Method Not Allowed']);
|
||||
}
|
||||
|
||||
$contentType = (string) ($_SERVER['CONTENT_TYPE'] ?? '');
|
||||
if (str_starts_with($contentType, 'multipart/form-data')) {
|
||||
if (!auth_validate_csrf_token($_POST['csrfToken'] ?? null)) {
|
||||
json_response(403, ['ok' => false, 'error' => 'Invalid security token']);
|
||||
}
|
||||
if (($_POST['action'] ?? '') !== 'upload_document') {
|
||||
json_response(422, ['ok' => false, 'error' => 'Unsupported action']);
|
||||
}
|
||||
$file = $_FILES['document'] ?? null;
|
||||
if (!is_array($file)) {
|
||||
throw new InvalidArgumentException('Dokumentdatei fehlt');
|
||||
}
|
||||
$document = upload_stock_lot_document(
|
||||
$pdo,
|
||||
(int) ($_POST['lotId'] ?? 0),
|
||||
$file,
|
||||
(string) ($_POST['comment'] ?? ''),
|
||||
(string) ($currentUser['username'] ?? $currentUser['email'] ?? 'unknown')
|
||||
);
|
||||
json_response(201, ['ok' => true, 'document' => [
|
||||
'id' => (int) $document['id'],
|
||||
'original_filename' => (string) $document['original_filename'],
|
||||
'comment' => $document['comment'] === null ? '' : (string) $document['comment'],
|
||||
]]);
|
||||
}
|
||||
|
||||
$jsonInput = file_get_contents('php://input');
|
||||
if ($jsonInput === false || trim($jsonInput) === '') {
|
||||
json_response(400, ['ok' => false, 'error' => 'Empty payload']);
|
||||
@@ -77,6 +103,16 @@ try {
|
||||
json_response(200, ['ok' => true, 'productId' => $productId, 'availableQty' => get_lager_product_available_qty($pdo, $productId)]);
|
||||
}
|
||||
|
||||
if ($action === 'update_document_comment') {
|
||||
update_stock_lot_document_comment($pdo, (int) ($data['documentId'] ?? 0), (string) ($data['comment'] ?? ''));
|
||||
json_response(200, ['ok' => true]);
|
||||
}
|
||||
|
||||
if ($action === 'delete_document') {
|
||||
delete_stock_lot_document($pdo, (int) ($data['documentId'] ?? 0));
|
||||
json_response(200, ['ok' => true]);
|
||||
}
|
||||
|
||||
if ($action === 'prepare_lot') {
|
||||
$productId = (int) ($data['productId'] ?? 0);
|
||||
$lotNumber = trim((string) ($data['lotNumber'] ?? ''));
|
||||
|
||||
@@ -235,6 +235,32 @@ function get_lager_product_overview(PDO $pdo): array
|
||||
}
|
||||
unset($product);
|
||||
|
||||
$lotIds = [];
|
||||
foreach ($products as $product) {
|
||||
if (!empty($product['lot_id'])) {
|
||||
$lotIds[] = (int) $product['lot_id'];
|
||||
}
|
||||
foreach ($product['historical_lots'] as $lot) {
|
||||
$lotIds[] = (int) ($lot['lot_id'] ?? 0);
|
||||
}
|
||||
foreach ($product['open_lots'] as $lot) {
|
||||
$lotIds[] = (int) ($lot['lot_id'] ?? 0);
|
||||
}
|
||||
}
|
||||
$documentsByLot = get_stock_lot_documents_by_lot_ids($pdo, $lotIds);
|
||||
foreach ($products as &$product) {
|
||||
$product['documents'] = $documentsByLot[(int) ($product['lot_id'] ?? 0)] ?? [];
|
||||
foreach ($product['historical_lots'] as &$lot) {
|
||||
$lot['documents'] = $documentsByLot[(int) ($lot['lot_id'] ?? 0)] ?? [];
|
||||
}
|
||||
unset($lot);
|
||||
foreach ($product['open_lots'] as &$lot) {
|
||||
$lot['documents'] = $documentsByLot[(int) ($lot['lot_id'] ?? 0)] ?? [];
|
||||
}
|
||||
unset($lot);
|
||||
}
|
||||
unset($product);
|
||||
|
||||
return $products;
|
||||
}
|
||||
|
||||
@@ -251,6 +277,138 @@ function get_lager_product_available_qty(PDO $pdo, int $productId): float
|
||||
return (float) $stmt->fetchColumn();
|
||||
}
|
||||
|
||||
function get_stock_lot_documents_by_lot_ids(PDO $pdo, array $lotIds): array
|
||||
{
|
||||
$lotIds = array_values(array_unique(array_filter(array_map('intval', $lotIds), static fn (int $id): bool => $id > 0)));
|
||||
if ($lotIds === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($lotIds), '?'));
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT id, stock_lot_id, original_filename, mime_type, size_bytes, comment, uploaded_at
|
||||
FROM stock_lot_document
|
||||
WHERE stock_lot_id IN ({$placeholders})
|
||||
ORDER BY stock_lot_id, id"
|
||||
);
|
||||
$stmt->execute($lotIds);
|
||||
$documents = [];
|
||||
foreach ($stmt->fetchAll() as $row) {
|
||||
$documents[(int) $row['stock_lot_id']][] = [
|
||||
'id' => (int) $row['id'],
|
||||
'original_filename' => (string) $row['original_filename'],
|
||||
'mime_type' => (string) $row['mime_type'],
|
||||
'size_bytes' => (int) $row['size_bytes'],
|
||||
'comment' => $row['comment'] === null ? '' : (string) $row['comment'],
|
||||
'uploaded_at' => (string) $row['uploaded_at'],
|
||||
];
|
||||
}
|
||||
return $documents;
|
||||
}
|
||||
|
||||
function get_stock_lot_document(PDO $pdo, int $documentId): array
|
||||
{
|
||||
$stmt = $pdo->prepare(
|
||||
'SELECT id, stock_lot_id, original_filename, stored_filename, mime_type, size_bytes, comment
|
||||
FROM stock_lot_document WHERE id = :id'
|
||||
);
|
||||
$stmt->execute([':id' => $documentId]);
|
||||
$document = $stmt->fetch();
|
||||
if (!is_array($document)) {
|
||||
throw new RuntimeException('Dokument nicht gefunden');
|
||||
}
|
||||
return $document;
|
||||
}
|
||||
|
||||
function update_stock_lot_document_comment(PDO $pdo, int $documentId, string $comment): void
|
||||
{
|
||||
$document = get_stock_lot_document($pdo, $documentId);
|
||||
$statusStmt = $pdo->prepare('SELECT status FROM stock_lot WHERE id = :id');
|
||||
$statusStmt->execute([':id' => (int) $document['stock_lot_id']]);
|
||||
$status = $statusStmt->fetchColumn();
|
||||
if ($status !== 'current' && $status !== 'open') {
|
||||
throw new InvalidArgumentException('Dokumente vergangener Chargen können nicht bearbeitet werden');
|
||||
}
|
||||
$stmt = $pdo->prepare('UPDATE stock_lot_document SET comment = :comment WHERE id = :id');
|
||||
$stmt->execute([':comment' => trim($comment) === '' ? null : trim($comment), ':id' => $documentId]);
|
||||
if ($stmt->rowCount() !== 1) {
|
||||
throw new RuntimeException('Dokument nicht gefunden');
|
||||
}
|
||||
}
|
||||
|
||||
function delete_stock_lot_document(PDO $pdo, int $documentId): void
|
||||
{
|
||||
$document = get_stock_lot_document($pdo, $documentId);
|
||||
$statusStmt = $pdo->prepare('SELECT status FROM stock_lot WHERE id = :id');
|
||||
$statusStmt->execute([':id' => (int) $document['stock_lot_id']]);
|
||||
$status = $statusStmt->fetchColumn();
|
||||
if ($status !== 'current' && $status !== 'open') {
|
||||
throw new InvalidArgumentException('Dokumente vergangener Chargen können nicht gelöscht werden');
|
||||
}
|
||||
$stmt = $pdo->prepare('DELETE FROM stock_lot_document WHERE id = :id');
|
||||
$stmt->execute([':id' => $documentId]);
|
||||
$path = dirname(__DIR__, 3) . '/runtime/uploads/lager/' . basename((string) $document['stored_filename']);
|
||||
if (is_file($path) && !unlink($path)) {
|
||||
throw new RuntimeException('Dokumentdatei konnte nicht gelöscht werden');
|
||||
}
|
||||
}
|
||||
|
||||
function upload_stock_lot_document(PDO $pdo, int $lotId, array $file, string $comment, string $uploadedBy): array
|
||||
{
|
||||
if ($lotId <= 0 || !is_uploaded_file((string) ($file['tmp_name'] ?? ''))) {
|
||||
throw new InvalidArgumentException('Ungültige Dokumentdatei');
|
||||
}
|
||||
$error = (int) ($file['error'] ?? UPLOAD_ERR_NO_FILE);
|
||||
if ($error !== UPLOAD_ERR_OK) {
|
||||
throw new InvalidArgumentException('Dokument konnte nicht hochgeladen werden');
|
||||
}
|
||||
$size = (int) ($file['size'] ?? 0);
|
||||
if ($size <= 0 || $size > 52428800) {
|
||||
throw new InvalidArgumentException('Dokument darf maximal 50 MB groß sein');
|
||||
}
|
||||
$originalFilename = basename((string) ($file['name'] ?? ''));
|
||||
if ($originalFilename === '') {
|
||||
throw new InvalidArgumentException('Dateiname fehlt');
|
||||
}
|
||||
$lotStmt = $pdo->prepare("SELECT id FROM stock_lot WHERE id = :id AND status IN ('current', 'open')");
|
||||
$lotStmt->execute([':id' => $lotId]);
|
||||
if ($lotStmt->fetchColumn() === false) {
|
||||
throw new InvalidArgumentException('Charge nicht gefunden');
|
||||
}
|
||||
|
||||
$directory = dirname(__DIR__, 3) . '/runtime/uploads/lager';
|
||||
if (!is_dir($directory) && !mkdir($directory, 0770, true) && !is_dir($directory)) {
|
||||
throw new RuntimeException('Dokumentenverzeichnis konnte nicht erstellt werden');
|
||||
}
|
||||
$storedFilename = bin2hex(random_bytes(16));
|
||||
$targetPath = $directory . '/' . $storedFilename;
|
||||
if (!move_uploaded_file((string) $file['tmp_name'], $targetPath)) {
|
||||
throw new RuntimeException('Dokument konnte nicht gespeichert werden');
|
||||
}
|
||||
$mimeType = (new finfo(FILEINFO_MIME_TYPE))->file($targetPath) ?: 'application/octet-stream';
|
||||
try {
|
||||
$stmt = $pdo->prepare(
|
||||
'INSERT INTO stock_lot_document
|
||||
(stock_lot_id, original_filename, stored_filename, mime_type, size_bytes, comment, uploaded_by)
|
||||
VALUES (:lot_id, :original_filename, :stored_filename, :mime_type, :size_bytes, :comment, :uploaded_by)
|
||||
RETURNING id'
|
||||
);
|
||||
$stmt->execute([
|
||||
':lot_id' => $lotId,
|
||||
':original_filename' => $originalFilename,
|
||||
':stored_filename' => $storedFilename,
|
||||
':mime_type' => $mimeType,
|
||||
':size_bytes' => $size,
|
||||
':comment' => trim($comment) === '' ? null : trim($comment),
|
||||
':uploaded_by' => $uploadedBy,
|
||||
]);
|
||||
return get_stock_lot_document($pdo, (int) $stmt->fetchColumn());
|
||||
} catch (Throwable $error) {
|
||||
unlink($targetPath);
|
||||
throw $error;
|
||||
}
|
||||
}
|
||||
|
||||
function get_lager_product_forecast(PDO $pdo, int $productId): array
|
||||
{
|
||||
$stmt = $pdo->prepare(
|
||||
|
||||
Reference in new issue
Block a user