diff --git a/backend/src/db.js b/backend/src/db.js
index 202a012..56075bc 100644
--- a/backend/src/db.js
+++ b/backend/src/db.js
@@ -155,6 +155,8 @@ if (!cols.includes('bemerkung')) db.exec("ALTER TABLE calculations ADD COLUMN be
const ordCols = db.prepare("PRAGMA table_info(orders)").all().map(r => r.name);
if (!ordCols.includes('bezahlt')) db.exec("ALTER TABLE orders ADD COLUMN bezahlt INTEGER NOT NULL DEFAULT 0");
if (!ordCols.includes('bezahlt_am')) db.exec("ALTER TABLE orders ADD COLUMN bezahlt_am DATETIME");
+if (!ordCols.includes('abgeholt')) db.exec("ALTER TABLE orders ADD COLUMN abgeholt INTEGER NOT NULL DEFAULT 0");
+if (!ordCols.includes('abgeholt_am'))db.exec("ALTER TABLE orders ADD COLUMN abgeholt_am DATETIME");
// Migrationen order_items
// files migrations
diff --git a/backend/src/tools/bestellungen/routes.js b/backend/src/tools/bestellungen/routes.js
index 9c4ddb3..7f4e290 100644
--- a/backend/src/tools/bestellungen/routes.js
+++ b/backend/src/tools/bestellungen/routes.js
@@ -77,8 +77,16 @@ router.put('/:id', authenticate, (req, res) => {
bezahlt_am = req.body.bezahlt ? new Date().toISOString() : null;
}
- db.prepare('UPDATE orders SET name=?,bemerkung=?,status=?,custom_price=?,bezahlt=?,bezahlt_am=?,updated_at=CURRENT_TIMESTAMP WHERE id=? AND user_id=?')
- .run(name, bemerkung, status, custom_price, bezahlt, bezahlt_am, req.params.id, uid(req));
+ // Abgeholt-Status mit Datum
+ let abgeholt = ex.abgeholt;
+ let abgeholt_am = ex.abgeholt_am;
+ if (req.body.abgeholt !== undefined) {
+ abgeholt = req.body.abgeholt ? 1 : 0;
+ abgeholt_am = req.body.abgeholt ? new Date().toISOString() : null;
+ }
+
+ db.prepare('UPDATE orders SET name=?,bemerkung=?,status=?,custom_price=?,bezahlt=?,bezahlt_am=?,abgeholt=?,abgeholt_am=?,updated_at=CURRENT_TIMESTAMP WHERE id=? AND user_id=?')
+ .run(name, bemerkung, status, custom_price, bezahlt, bezahlt_am, abgeholt, abgeholt_am, req.params.id, uid(req));
res.json(loadOrder(req.params.id, uid(req)));
});
diff --git a/frontend/src/tools/bestellungen.jsx b/frontend/src/tools/bestellungen.jsx
index 8b3fe7e..e64c4be 100644
--- a/frontend/src/tools/bestellungen.jsx
+++ b/frontend/src/tools/bestellungen.jsx
@@ -128,6 +128,12 @@ function BestellungDetail({ id, toast, onBack }) {
api(`/tools/bestellungen/${id}`,{method:'PUT',body:{bezahlt:!order.bezahlt}})
.then(u=>{setOrder(u);toast(u.bezahlt?'Als bezahlt markiert':'Bezahlung aufgehoben');});
+ const toggleAbgeholt = () =>
+ api(`/tools/bestellungen/${id}`,{method:'PUT',body:{abgeholt:!order.abgeholt}})
+ .then(u=>{setOrder(u);toast(u.abgeholt?'Als abgeholt markiert':'Abholung aufgehoben');});
+
+ const isAbgeschlossen = order && !!order.bezahlt && !!order.abgeholt;
+
return (
@@ -178,6 +184,27 @@ function BestellungDetail({ id, toast, onBack }) {
π Bearbeitung gesperrt.
)}
+
+ {/* Abgeholt β nur bei fertig oder bezahlt anzeigen */}
+ {(order.status==='fertig' || !!order.bezahlt) && (
+
+
+ {!!order.abgeholt && order.abgeholt_am && (
+
+ am {new Date(order.abgeholt_am).toLocaleDateString('de-DE',{day:'2-digit',month:'2-digit',year:'numeric'})}
+
+ )}
+
+ )}
)}
@@ -598,6 +625,7 @@ export default function Bestellungen({ toast, mobile }) {
const [openId, setOpenId] = useState(null);
const [newMode, setNewMode] = useState(false);
const [archivItem, setArchivItem] = useState(null);
+ const [archivOpen, setArchivOpen] = useState(false);
const load = () => {
setLoading(true);
@@ -612,7 +640,11 @@ export default function Bestellungen({ toast, mobile }) {
};
const sq = search.trim().toLowerCase();
+ // Abgeschlossen = bezahlt UND abgeholt
+ const isAbgeschlossen = o => !!o.bezahlt && !!o.abgeholt;
+
const filtered = orders.filter(o => {
+ if (isAbgeschlossen(o)) return false; // nie in aktiver Liste
const ms = !sq || o.name.toLowerCase().includes(sq)
|| (o.items && o.items.some(i => i.calc_name.toLowerCase().includes(sq)));
const mf = filterStatus==='alle'
@@ -623,6 +655,9 @@ export default function Bestellungen({ toast, mobile }) {
return ms && mf;
});
+ const abgeschlossen = orders.filter(o => isAbgeschlossen(o)
+ && (!sq || o.name.toLowerCase().includes(sq)));
+
if (openId !== null || newMode) {
return (
);
})}
+
+ {/* ββ Archiv-Drawer βββββββββββββββββββββββββββββββββββββββββββββββββ */}
+ {abgeschlossen.length > 0 && (
+
+
+
+ {archivOpen && (
+
+ {abgeschlossen.map(order => {
+ const customSum = order.custom_price_sum || 0;
+ return (
+
+
+
+
+ π¦
+ π
+ {customSum > 0 && (
+
+ {customSum.toFixed(2)}β¬
+
+ )}
+
+
+
+
+
+
+
+ );
+ })}
+
+ )}
+
+ )}
);
}