From 1bae0e38a038d1ec6a20b3883896e1cac17e2428 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Wed, 28 Oct 2026 18:01:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=AD=A3=E5=BC=8F=E9=80=81=E8=B2=A8=E5=96=AE?= =?UTF-8?q?=E5=90=8C=E4=B8=80=E8=B2=A8=E5=93=81=E6=9C=89=E5=A4=9A=E7=AD=86?= =?UTF-8?q?=E6=8F=90=E6=96=99=E8=A1=8C=E6=99=82=EF=BC=8C=E5=B7=B2=E6=8F=90?= =?UTF-8?q?=E6=95=B8=E9=87=8F=E6=94=B9=E6=8C=89=E6=95=B8=E9=87=8F=E9=85=8D?= =?UTF-8?q?=E5=B0=8D=EF=BC=8C=E9=81=BF=E5=85=8D=E9=83=BD=E5=8D=B0=E6=88=90?= =?UTF-8?q?=E7=AC=AC=E4=B8=80=E7=AD=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- .../entity/models/DeliveryOrderLineInfo.kt | 1 + .../service/DeliveryOrderService.kt | 120 +++++++++++++++--- .../service/DoReplenishmentService.kt | 3 + .../service/DoWorkbenchMainService.kt | 10 +- 4 files changed, 112 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/models/DeliveryOrderLineInfo.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/models/DeliveryOrderLineInfo.kt index 1fd8a3e1..98145832 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/models/DeliveryOrderLineInfo.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/models/DeliveryOrderLineInfo.kt @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Value import java.math.BigDecimal interface DeliveryOrderLineInfo { + val id: Long @get:Value("#{target.item?.name}") val itemName: String? val itemNo: String diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt index 73a0eb9d..dd4ccdf1 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt @@ -1383,6 +1383,7 @@ open class DeliveryOrderService( ) } + /** FP-MTMS Version Checklist | Functions Ref. No. 89 | v1.0.0 | 2026-10-28 */ private fun exportDeliveryNoteFromRecord( request: ExportDeliveryNoteRequest, deliveryNote: net.sf.jasperreports.engine.JasperReport, @@ -1476,15 +1477,19 @@ open class DeliveryOrderService( val deliveryOrderCodeById = deliveryOrders.associate { it.id!! to (it.code ?: "") } val isExtraByDoId = deliveryOrders.associate { it.id!! to it.isExtra } val replenishPdfIndex = doReplenishmentService.buildReplenishPdfIndex(deliveryOrderIds) - + val pickOrderLineIdByDeliveryLine = matchDeliveryNotePickOrderLines( + exportLines = exportLines, + pickOrderIdByDoId = pickOrderIdByDoId, + pickOrderLines = pickOrderLines, + replenishmentPickOrderLineIds = replenishPdfIndex.replenishmentPickOrderLineIds(), + ) + sortedLines.forEach { row -> fields.add( buildDeliveryNotePdfLineField( deliveryOrderId = row.deliveryOrderId, line = row.line, sequenceNumber = fields.size + 1, - pickOrderIdByDoId = pickOrderIdByDoId, - pickOrderLines = pickOrderLines, stockOutLinesByPickOrderLineId = stockOutLinesByPickOrderLineId, illById = illById, itemsById = itemsById, @@ -1493,6 +1498,7 @@ open class DeliveryOrderService( headerTicketNo = null, headerIsMerge = false, replenishPdfIndex = replenishPdfIndex, + pickOrderLineIdByDeliveryLine = pickOrderLineIdByDeliveryLine, ), ) } @@ -1553,17 +1559,47 @@ open class DeliveryOrderService( info.deliveryOrderLines.filter { it.deleted != true }.map { line -> DeliveryNoteExportLine(info.id, line) } } - fun resolvePickOrderLineIdForDeliveryNoteLine( - deliveryOrderId: Long, - itemId: Long?, + /** + * FP-MTMS Version Checklist | Functions Ref. No. 89 | v1.0.0 | 2026-10-28 + * Pair each delivery-order line with its own pick line. + * Same item on one pick order is matched by qty first (4↔4, 1↔1). + * Equal qty is paired in id order. Replenishment pick lines are left out; + * those rows still print from do_replenishment.pickOrderLineId. + */ + fun matchDeliveryNotePickOrderLines( + exportLines: List, pickOrderIdByDoId: Map, pickOrderLines: List, - ): Long? { - if (itemId == null) return null - val pickOrderId = pickOrderIdByDoId[deliveryOrderId] ?: return null - return pickOrderLines - .firstOrNull { pol -> pol.pickOrder?.id == pickOrderId && pol.item?.id == itemId } - ?.id + replenishmentPickOrderLineIds: Set = emptySet(), + ): Map, Long> { + val keys = exportLines.mapNotNull { row -> + val itemId = row.line.itemId ?: return@mapNotNull null + if (row.line.deleted == true) return@mapNotNull null + DeliveryNoteLineMatchKey( + deliveryOrderId = row.deliveryOrderId, + lineId = row.line.id, + itemId = itemId, + qty = row.line.qty, + ) + } + val candidates = pickOrderLines.mapNotNull { pol -> + val polId = pol.id ?: return@mapNotNull null + val pickOrderId = pol.pickOrder?.id ?: return@mapNotNull null + val itemId = pol.item?.id ?: return@mapNotNull null + val qty = pol.qty ?: return@mapNotNull null + DeliveryNotePickLineCandidate( + id = polId, + pickOrderId = pickOrderId, + itemId = itemId, + qty = qty, + ) + } + return DeliveryNotePickLineMatcher.match( + lines = keys, + pickOrderIdByDoId = pickOrderIdByDoId, + pickLines = candidates, + replenishmentPickOrderLineIds = replenishmentPickOrderLineIds, + ) } fun parseTicketTypeLetter(ticketNo: String?): String? { @@ -1675,12 +1711,11 @@ open class DeliveryOrderService( return field } + /** FP-MTMS Version Checklist | Functions Ref. No. 89 | v1.0.0 | 2026-10-28 */ fun buildDeliveryNotePdfLineField( deliveryOrderId: Long, line: DeliveryOrderLineInfo, sequenceNumber: Int, - pickOrderIdByDoId: Map, - pickOrderLines: List, stockOutLinesByPickOrderLineId: Map>, illById: Map, itemsById: Map, @@ -1689,6 +1724,7 @@ open class DeliveryOrderService( headerTicketNo: String? = null, headerIsMerge: Boolean = false, replenishPdfIndex: DoReplenishmentService.ReplenishPdfIndex = DoReplenishmentService.ReplenishPdfIndex.EMPTY, + pickOrderLineIdByDeliveryLine: Map, Long> = emptyMap(), ): MutableMap { val field = mutableMapOf() val isExtra = isExtraDeliveryTicket( @@ -1697,12 +1733,7 @@ open class DeliveryOrderService( headerIsMerge = headerIsMerge, ) - val polId = resolvePickOrderLineIdForDeliveryNoteLine( - deliveryOrderId = deliveryOrderId, - itemId = line.itemId, - pickOrderIdByDoId = pickOrderIdByDoId, - pickOrderLines = pickOrderLines, - ) + val polId = pickOrderLineIdByDeliveryLine[deliveryOrderId to line.id] val isReplenish = replenishPdfIndex.matches(deliveryOrderId, line.itemId, polId) field["sequenceNumber"] = formatSequenceNumber(sequenceNumber, isExtra, isReplenish) @@ -2806,3 +2837,52 @@ val inventoryLotLine = illId?.let { inventoryLotLineMap[it] } } } } + +internal data class DeliveryNoteLineMatchKey( + val deliveryOrderId: Long, + val lineId: Long, + val itemId: Long, + val qty: BigDecimal, +) + +internal data class DeliveryNotePickLineCandidate( + val id: Long, + val pickOrderId: Long, + val itemId: Long, + val qty: BigDecimal, +) + +internal object DeliveryNotePickLineMatcher { + /** FP-MTMS Version Checklist | Functions Ref. No. 89 | v1.0.0 | 2026-10-28 */ + fun match( + lines: List, + pickOrderIdByDoId: Map, + pickLines: List, + replenishmentPickOrderLineIds: Set = emptySet(), + ): Map, Long> { + val result = mutableMapOf, Long>() + val rowsByDoAndItem = lines.groupBy { it.deliveryOrderId to it.itemId } + for ((key, rows) in rowsByDoAndItem) { + val (deliveryOrderId, itemId) = key + val pickOrderId = pickOrderIdByDoId[deliveryOrderId] ?: continue + val available = pickLines + .filter { pol -> + pol.pickOrderId == pickOrderId && + pol.itemId == itemId && + pol.id !in replenishmentPickOrderLineIds + } + .sortedBy { it.id } + .toMutableList() + for (row in rows.sortedBy { it.lineId }) { + val qtyIndex = available.indexOfFirst { it.qty.compareTo(row.qty) == 0 } + val chosen = when { + qtyIndex >= 0 -> available.removeAt(qtyIndex) + available.isNotEmpty() -> available.removeAt(0) + else -> null + } ?: continue + result[row.deliveryOrderId to row.lineId] = chosen.id + } + } + return result + } +} diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReplenishmentService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReplenishmentService.kt index 81d0010a..50e8b0e2 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReplenishmentService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReplenishmentService.kt @@ -162,6 +162,9 @@ open class DoReplenishmentService( return deliveryOrderId to resolvedItemId in targetDoItemKeys } + /** FP-MTMS Version Checklist | Functions Ref. No. 89 | v1.0.0 | 2026-10-28 */ + fun replenishmentPickOrderLineIds(): Set = pickOrderLineIds + companion object { val EMPTY = ReplenishPdfIndex(emptySet(), emptySet()) } 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 50b2ec58..74d9e7f7 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 @@ -3057,6 +3057,7 @@ return MessageResponse( return deliveryOrderService.formatDoCodesPlain(codes) } + /** FP-MTMS Version Checklist | Functions Ref. No. 89 | v1.0.0 | 2026-10-28 */ open fun exportDeliveryNoteWorkbench(request: ExportDeliveryNoteRequest): Map { val deliveryNote = deliveryNoteJasperTemplate val fields = mutableListOf>() @@ -3108,6 +3109,12 @@ return MessageResponse( val headerIsMerge = ctx.header.ticketNo?.startsWith("TI-M-") == true val headerTicketNo = ctx.header.ticketNo val replenishPdfIndex = doReplenishmentService.buildReplenishPdfIndex(ctx.deliveryOrderIds) + val pickOrderLineIdByDeliveryLine = deliveryOrderService.matchDeliveryNotePickOrderLines( + exportLines = exportLines, + pickOrderIdByDoId = ctx.pickOrderIdByDoId, + pickOrderLines = pickOrderLines, + replenishmentPickOrderLineIds = replenishPdfIndex.replenishmentPickOrderLineIds(), + ) sortedLines.forEach { row -> fields.add( @@ -3115,8 +3122,6 @@ return MessageResponse( deliveryOrderId = row.deliveryOrderId, line = row.line, sequenceNumber = fields.size + 1, - pickOrderIdByDoId = ctx.pickOrderIdByDoId, - pickOrderLines = pickOrderLines, stockOutLinesByPickOrderLineId = stockOutLinesByPickOrderLineId, illById = illById, itemsById = itemsById, @@ -3125,6 +3130,7 @@ return MessageResponse( headerTicketNo = headerTicketNo, headerIsMerge = headerIsMerge, replenishPdfIndex = replenishPdfIndex, + pickOrderLineIdByDeliveryLine = pickOrderLineIdByDeliveryLine, ), ) }