From ff87a80531f8bf666f4caca336c392437b75441a Mon Sep 17 00:00:00 2001 From: "kelvin.yau" Date: Fri, 23 Oct 2026 17:48:26 +0800 Subject: [PATCH] Harden demo anonymize stock and workbench DN/label download. Ensure hero lots are available with enough qty, limit ST-012 to four PPs, and distinguish draft vs final DN while exposing DNLabels PDF download. --- scripts/anonymize_demo_copy.sql | 66 +++++++++++-------- .../service/DoWorkbenchMainService.kt | 23 +++++-- .../web/DoWorkbenchController.kt | 14 ++++ 3 files changed, 68 insertions(+), 35 deletions(-) diff --git a/scripts/anonymize_demo_copy.sql b/scripts/anonymize_demo_copy.sql index 5ff3a1c4..b6bfca81 100644 --- a/scripts/anonymize_demo_copy.sql +++ b/scripts/anonymize_demo_copy.sql @@ -8,10 +8,11 @@ -- in UTC+8. Lot expiry dates move forward by the same number of days -- as the newest delivery arrival day, so usable stock stays usable. -- settings DEMO.dateAnchor stores that day. Line prices become 1. --- Also tops up depleted MG1757 lots (PP2220 JO pick material) so demo --- 提料 is not blocked by zero olive-oil stock. --- Makes PP2236/PP2237 lot lines pickable (status available; move off Hold --- bin 2F-W202-01-00) so DO 執貨 with those FGs can suggest lots. +-- Tops up demo hero stock (MG1757, PP2236, PP2237): every lot line gets +-- >=20 available units, status=available, hold cleared, and Hold bin +-- 2F-W202-01-00 → 2F-W201-#J-01 so JO 提料 / DO 執貨 can use them. +-- Stocktake section ST-012 keeps only PP2220/PP2074/PP2126/PP2326; +-- other items in those bins are stocked out (net qty → 0). -- DO.floor.suppliers.2F / 4F keep production split; shop codes expand to -- all matching S{id} (do not copy the same CSV into both floors). -- Opening the backend does not move dates. On a later demo day, run @@ -507,52 +508,61 @@ BEGIN ) WHERE p.deleted = 0; - -- Demo hero PP2220: MG1757 (olive oil) is often fully issued on the - -- production copy. Restore usable qty on depleted lot lines so JO 提料 - -- can pick. inventory_lot_line AFTER UPDATE trigger syncs inventory. + -- Demo hero stock: MG1757 (PP2220 JO 提料) + PP2236/PP2237 (DO 執貨). + -- Production copy often leaves these depleted and/or status=unavailable + -- (and on Hold). Every lot line: >=20 net qty, status=available, + -- holdQty=0, Hold bin → 2F-W201-#J-01. Trigger syncs inventory. UPDATE inventory_lot_line ill JOIN inventory_lot l ON l.id = ill.inventoryLotId AND IFNULL(l.deleted, 0) = 0 JOIN items i ON i.id = l.itemId - AND i.code = 'MG1757' - AND IFNULL(i.deleted, 0) = 0 - SET ill.inQty = IFNULL(ill.outQty, 0) + 20, - ill.holdQty = 0 - WHERE IFNULL(ill.deleted, 0) = 0 - AND ( - IFNULL(ill.inQty, 0) - - IFNULL(ill.outQty, 0) - - IFNULL(ill.holdQty, 0) - ) <= 0; - - -- Demo DO 執貨: PP2236 / PP2237 often sit unavailable (and on Hold bin). - -- Mark remaining qty available and move Hold → 2F-W201-#J-01 when present. - UPDATE inventory_lot_line ill - JOIN inventory_lot l - ON l.id = ill.inventoryLotId AND IFNULL(l.deleted, 0) = 0 - JOIN items i - ON i.id = l.itemId - AND i.code IN ('PP2236', 'PP2237') + AND i.code IN ('MG1757', 'PP2236', 'PP2237') AND IFNULL(i.deleted, 0) = 0 LEFT JOIN warehouse w ON w.id = ill.warehouseId LEFT JOIN warehouse w_pick ON w_pick.code = '2F-W201-#J-01' AND IFNULL(w_pick.deleted, 0) = 0 - SET ill.status = 'available', + SET ill.inQty = IF( + ( + IFNULL(ill.inQty, 0) + - IFNULL(ill.outQty, 0) + - IFNULL(ill.holdQty, 0) + ) < 20, + IFNULL(ill.outQty, 0) + 20, + ill.inQty + ), ill.holdQty = 0, + ill.status = 'available', ill.warehouseId = IF( w.code = '2F-W202-01-00' AND w_pick.id IS NOT NULL, w_pick.id, ill.warehouseId ) + WHERE IFNULL(ill.deleted, 0) = 0; + + -- Demo stocktake ST-012 (2F 麵包餡): only keep PP2220 / PP2074 / PP2126 / + -- PP2326. Zero every other item in those bins so 盤點 shows a short list. + UPDATE inventory_lot_line ill + JOIN inventory_lot l + ON l.id = ill.inventoryLotId AND IFNULL(l.deleted, 0) = 0 + JOIN items i + ON i.id = l.itemId + AND IFNULL(i.deleted, 0) = 0 + AND i.code NOT IN ('PP2220', 'PP2074', 'PP2126', 'PP2326') + JOIN warehouse w + ON w.id = ill.warehouseId + AND IFNULL(w.deleted, 0) = 0 + AND w.stockTakeSection = 'ST-012' + SET ill.outQty = IFNULL(ill.inQty, 0), + ill.holdQty = 0 WHERE IFNULL(ill.deleted, 0) = 0 AND ( IFNULL(ill.inQty, 0) - IFNULL(ill.outQty, 0) - IFNULL(ill.holdQty, 0) - ) > 0; + ) <> 0; INSERT INTO settings (name, value, category, type) VALUES ('DEMO.anonymized.v1', '1', 'DEMO', 'string'); diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt index 2abc174f..b5861813 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt @@ -3132,12 +3132,21 @@ return MessageResponse( ) } - params["dnTitle"] = "送貨單" - params["colQty"] = "已提數量" - params["totalCartonTitle"] = "總箱數:" - params["deliveryNoteCodeTitle"] = "送貨單編號:" - params["deliveryNoteCode"] = ctx.header.deliveryNoteCode ?: "" - params["numOfCarton"] = request.numOfCarton.toString().takeUnless { it == "0" } ?: "" + if (request.isDraft) { + params["dnTitle"] = "送貨單(初稿)" + params["colQty"] = "所需數量" + params["totalCartonTitle"] = "" + params["deliveryNoteCodeTitle"] = "" + params["deliveryNoteCode"] = "" + params["numOfCarton"] = "" + } else { + params["dnTitle"] = "送貨單" + params["colQty"] = "已提數量" + params["totalCartonTitle"] = "總箱數:" + params["deliveryNoteCodeTitle"] = "送貨單編號:" + params["deliveryNoteCode"] = ctx.header.deliveryNoteCode ?: "" + params["numOfCarton"] = request.numOfCarton.toString().takeUnless { it == "0" } ?: "" + } params["shopName"] = deliveryOrderService.formatShopNameForDeliveryNote( ctx.header.shopName ?: deliveryNoteInfo[0].shopName ?: "", ) @@ -3210,7 +3219,7 @@ return MessageResponse( return params } - private fun exportDNLabelsWorkbench(request: ExportDNLabelsRequest): Map { + open fun exportDNLabelsWorkbench(request: ExportDNLabelsRequest): Map { val DNLABELS_PDF = "DeliveryNote/DeliveryNoteCartonLabelsPDF.jrxml" val resource = ClassPathResource(DNLABELS_PDF) if (!resource.exists()) { diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DoWorkbenchController.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DoWorkbenchController.kt index 9ffbd457..d62f5457 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DoWorkbenchController.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DoWorkbenchController.kt @@ -286,6 +286,20 @@ class DoWorkbenchController( out.write(JasperExportManager.exportReportToPdf(jasperPrint)) } + @PostMapping("/DNLabels") + fun downloadWorkbenchDNLabels( + @Valid @RequestBody request: ExportDNLabelsRequest, + response: HttpServletResponse, + ) { + response.characterEncoding = "utf-8" + response.contentType = "application/pdf" + val out: OutputStream = response.outputStream + val pdf = doWorkbenchMainService.exportDNLabelsWorkbench(request) + val jasperPrint = pdf["report"] as JasperPrint + response.addHeader("filename", "${pdf["filename"]}.pdf") + out.write(JasperExportManager.exportReportToPdf(jasperPrint)) + } + @GetMapping("/print-DNLabels") fun printWorkbenchDNLabels(@ModelAttribute request: PrintDNLabelsRequest) { doWorkbenchMainService.printDNLabelsWorkbench(request)