Просмотр исходного кода

正式送貨單同一貨品有多筆提料行時,已提數量改按數量配對,避免都印成第一筆。

Co-authored-by: Cursor <[email protected]>
stockTakeUpdate
CANCERYS\kw093 1 неделю назад
Родитель
Сommit
1bae0e38a0
4 измененных файлов: 112 добавлений и 22 удалений
  1. +1
    -0
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/models/DeliveryOrderLineInfo.kt
  2. +100
    -20
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt
  3. +3
    -0
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReplenishmentService.kt
  4. +8
    -2
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt

+ 1
- 0
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


+ 100
- 20
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<DeliveryNoteExportLine>,
pickOrderIdByDoId: Map<Long, Long>,
pickOrderLines: List<PickOrderLine>,
): 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<Long> = emptySet(),
): Map<Pair<Long, Long>, 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<Long, Long>,
pickOrderLines: List<PickOrderLine>,
stockOutLinesByPickOrderLineId: Map<Long, List<StockOutLineInfo>>,
illById: Map<Long, InventoryLotLine>,
itemsById: Map<Long, Items>,
@@ -1689,6 +1724,7 @@ open class DeliveryOrderService(
headerTicketNo: String? = null,
headerIsMerge: Boolean = false,
replenishPdfIndex: DoReplenishmentService.ReplenishPdfIndex = DoReplenishmentService.ReplenishPdfIndex.EMPTY,
pickOrderLineIdByDeliveryLine: Map<Pair<Long, Long>, Long> = emptyMap(),
): MutableMap<String, Any> {
val field = mutableMapOf<String, Any>()
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<DeliveryNoteLineMatchKey>,
pickOrderIdByDoId: Map<Long, Long>,
pickLines: List<DeliveryNotePickLineCandidate>,
replenishmentPickOrderLineIds: Set<Long> = emptySet(),
): Map<Pair<Long, Long>, Long> {
val result = mutableMapOf<Pair<Long, Long>, 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
}
}

+ 3
- 0
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<Long> = pickOrderLineIds

companion object {
val EMPTY = ReplenishPdfIndex(emptySet(), emptySet())
}


+ 8
- 2
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<String, Any> {
val deliveryNote = deliveryNoteJasperTemplate
val fields = mutableListOf<MutableMap<String, Any>>()
@@ -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,
),
)
}


Загрузка…
Отмена
Сохранить