From d640f3656d01be299c005dd444be8d902457f933 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mathias=20Gla=CC=88ser?=
Date: Tue, 8 Sep 2026 13:49:20 +0200
Subject: [PATCH] Revert "Add documents to stock lots"
This reverts commit 2bec9347325a796e1499789adf1aafc5e086f8b0.
---
db/migrations/0021_stock_lot_documents.sql | 18 ---
modules/erp/lager/api/lot.php | 36 -----
modules/erp/lager/service.php | 158 ---------------------
modules/shared/auth/ui/home.php | 54 +------
public/api/lager-document.php | 30 ----
5 files changed, 2 insertions(+), 294 deletions(-)
delete mode 100644 db/migrations/0021_stock_lot_documents.sql
delete mode 100644 public/api/lager-document.php
diff --git a/db/migrations/0021_stock_lot_documents.sql b/db/migrations/0021_stock_lot_documents.sql
deleted file mode 100644
index 5810b55..0000000
--- a/db/migrations/0021_stock_lot_documents.sql
+++ /dev/null
@@ -1,18 +0,0 @@
-BEGIN;
-
-CREATE TABLE stock_lot_document (
- id BIGSERIAL PRIMARY KEY,
- stock_lot_id BIGINT NOT NULL REFERENCES stock_lot(id) ON DELETE CASCADE,
- original_filename TEXT NOT NULL,
- stored_filename TEXT NOT NULL,
- mime_type TEXT NOT NULL,
- size_bytes BIGINT NOT NULL,
- comment TEXT,
- uploaded_by TEXT NOT NULL,
- uploaded_at TIMESTAMP NOT NULL DEFAULT NOW(),
- CONSTRAINT chk_stock_lot_document_size CHECK (size_bytes > 0 AND size_bytes <= 52428800)
-);
-
-CREATE INDEX idx_stock_lot_document_lot ON stock_lot_document(stock_lot_id, id);
-
-COMMIT;
diff --git a/modules/erp/lager/api/lot.php b/modules/erp/lager/api/lot.php
index 91da6e7..f699b6f 100644
--- a/modules/erp/lager/api/lot.php
+++ b/modules/erp/lager/api/lot.php
@@ -20,32 +20,6 @@ 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']);
@@ -103,16 +77,6 @@ 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'] ?? ''));
diff --git a/modules/erp/lager/service.php b/modules/erp/lager/service.php
index b728f47..17789a2 100644
--- a/modules/erp/lager/service.php
+++ b/modules/erp/lager/service.php
@@ -235,32 +235,6 @@ 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;
}
@@ -277,138 +251,6 @@ 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(
diff --git a/modules/shared/auth/ui/home.php b/modules/shared/auth/ui/home.php
index 243b943..3e9df45 100644
--- a/modules/shared/auth/ui/home.php
+++ b/modules/shared/auth/ui/home.php
@@ -254,7 +254,6 @@ function auth_render_lager_table(string $title, array $rows, array $columns, str
. ' data-lager-drawer-mfg-date="' . auth_escape_html((string) ($row['mfg_date'] ?? '')) . '"'
. ' data-lager-drawer-expiry-date="' . auth_escape_html((string) ($row['expiry_date'] ?? '')) . '"'
. ' data-lager-drawer-purchase-date="' . auth_escape_html((string) ($row['purchase_date'] ?? '')) . '"'
- . ' data-lager-drawer-documents="' . auth_escape_html((string) json_encode($row['documents'] ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)) . '"'
. ' data-lager-drawer-virtual-lot-number="' . auth_escape_html((string) ($row['virtual_lot_number'] ?? '')) . '"';
$openLot = $row['open_lots'][0] ?? [];
$detailData .= ' data-lager-open-lot-id="' . auth_escape_html((string) ($openLot['lot_id'] ?? '')) . '"'
@@ -298,39 +297,6 @@ function auth_format_lager_quantity(float $value): string
: number_format($value, 2, ',', '.');
}
-function auth_render_lager_documents(array $documents, bool $editable, string $scope): string
-{
- $html = '';
-}
-
function auth_render_lager_historical_lots(array $lagerProducts): string
{
$html = [];
@@ -352,7 +318,6 @@ function auth_render_lager_historical_lots(array $lagerProducts): string
. 'MHD: ' . auth_format_lager_date($lot['expiry_date'] ?? null) . '
'
. 'Hersteller: ' . auth_escape_html((string) ($lot['manufacturer_name'] ?? 'Nicht hinterlegt')) . '
'
. 'Hersteller-Chargennummer: ' . auth_escape_html((string) ($lot['manufacturer_lot_number'] ?? 'Nicht hinterlegt')) . '
'
- . auth_render_lager_documents($lot['documents'] ?? [], false, 'historical-' . (int) ($lot['lot_id'] ?? 0))
. '';
}
$html[] = '';
@@ -380,7 +345,6 @@ function auth_render_lager_open_lots(array $lagerProducts, string $manufacturerO
. 'Herstellungsdatum: ' . auth_format_lager_date($lot['mfg_date'] ?? null) . '
'
. 'MHD: ' . auth_format_lager_date($lot['expiry_date'] ?? null) . '
'
. 'Einkaufsdatum: ' . auth_format_lager_date($lot['purchase_date'] ?? null) . ''
- . auth_render_lager_documents($lot['documents'] ?? [], false, 'open-read-' . $lotId)
. ''
. 'Leere Felder speichern?
Die folgenden Felder werden leer gespeichert:
'
. 'Möchtest du diese offene Charge wirklich löschen?
Du kannst das nicht rückgängig machen. Bestätige durch Eingabe von DELETE.
';
@@ -445,7 +408,7 @@ function auth_render_lager_content(array $lagerProducts, array $lagerArtikel, ar
. '' . auth_render_lager_open_lots($lagerProducts, $manufacturerOptions) . '
'
. ''
. ''
- . 'Naurua-Chargennummer:
Aktueller Bestand:
Eingangsmenge:
Hersteller:
Hersteller-Chargennummer:
Herstellungsdatum:
MHD:
Einkaufsdatum:
' . auth_render_lager_documents([], false, 'current-read') . '
'
+ . 'Naurua-Chargennummer:
Aktueller Bestand:
Eingangsmenge:
Hersteller:
Hersteller-Chargennummer:
Herstellungsdatum:
MHD:
Einkaufsdatum:
'
. '