Explorar el Código

do PDF fix

production
CANCERYS\kw093 hace 3 semanas
padre
commit
46b5b9f8c8
Se han modificado 4 ficheros con 193 adiciones y 129 borrados
  1. +143
    -77
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt
  2. +30
    -51
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt
  3. +1
    -1
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt
  4. +19
    -0
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DoWorkbenchController.kt

+ 143
- 77
src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt Ver fichero

@@ -86,6 +86,9 @@ import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfoLite
import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfoLiteDto
import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderLineInfo
import com.ffii.fpsms.modules.master.entity.Items
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLine
import com.ffii.fpsms.modules.stock.entity.InventoryLotLine
import com.ffii.fpsms.modules.stock.entity.projection.StockOutLineInfo
import java.util.Locale
@@ -1242,18 +1245,18 @@ open class DeliveryOrderService(
val truckNo = doPickOrderRecord.truckLanceCode ?: ""
val selectedPickOrder = pickOrderRepository.findById(pickOrderId).orElse(null)
val allLines = deliveryNoteInfo.flatMap { info ->
info.deliveryOrderLines.map { line -> line }
}
val pickOrderIdByDoId = doPickOrderLineRecords.mapNotNull { rec ->
val doId = rec.doOrderId
val poId = rec.pickOrderId
if (doId != null && poId != null) doId to poId else null
}.toMap()

val exportLines = deliveryNoteExportLines(deliveryNoteInfo)

val pickOrderLines = pickOrderIds.flatMap { pid ->
pickOrderLineRepository.findAllByPickOrderId(pid)
}
val pickOrderLineIdsByItemId = pickOrderLines
.groupBy { it.item?.id }
.mapValues { (_, lines) -> lines.mapNotNull { it.id } }

val allPickOrderLineIds = pickOrderLines.mapNotNull { it.id }
val stockOutLinesByPickOrderLineId: Map<Long, List<StockOutLineInfo>> =
if (allPickOrderLineIds.isNotEmpty()) {
@@ -1269,7 +1272,7 @@ open class DeliveryOrderService(
?.replace(" ", "")
?: ""
val uniqueItemIdsForSort = allLines.mapNotNull { it.itemId }.distinct()
val uniqueItemIdsForSort = exportLines.mapNotNull { it.line.itemId }.distinct()
val itemsById = if (uniqueItemIdsForSort.isNotEmpty()) {
itemsRepository.findAllById(uniqueItemIdsForSort).associateBy { it.id!! }
} else {
@@ -1277,17 +1280,17 @@ open class DeliveryOrderService(
}
val sortedLines = when (doStoreFloorKey) {
"2F" -> allLines.sortedWith(
"2F" -> exportLines.sortedWith(
compareBy(
{ line -> itemsById[line.itemId]?.item_Order ?: Int.MAX_VALUE },
{ line -> line.itemNo },
{ row -> itemsById[row.line.itemId]?.item_Order ?: Int.MAX_VALUE },
{ row -> row.line.itemNo },
),
)
"4F" -> allLines.sortedBy { line ->
line.itemId?.let { getWarehouseOrderByItemId(it) } ?: Int.MAX_VALUE
"4F" -> exportLines.sortedBy { row ->
row.line.itemId?.let { getWarehouseOrderByItemId(it) } ?: Int.MAX_VALUE
}
else -> allLines.sortedBy { line ->
line.itemId?.let { getWarehouseOrderByItemId(it) } ?: Int.MAX_VALUE
else -> exportLines.sortedBy { row ->
row.line.itemId?.let { getWarehouseOrderByItemId(it) } ?: Int.MAX_VALUE
}
}
@@ -1300,61 +1303,19 @@ open class DeliveryOrderService(
emptyMap()
}
val itemsMap = itemsById
sortedLines.forEach { line ->
val field = mutableMapOf<String, Any>()
field["sequenceNumber"] = (fields.size + 1).toString()
field["itemNo"] = line.itemNo
field["itemName"] = line.itemName ?: ""
field["uom"] = line.uom ?: ""
val actualPickQty = if (line.itemId != null) {
val pickOrderLineIdsForItem = pickOrderLineIdsByItemId[line.itemId] ?: emptyList()
val totalQty = pickOrderLineIdsForItem.sumOf { polId ->
stockOutLinesByPickOrderLineId[polId].orEmpty().sumOf { it.qty }
}
totalQty.toString()
} else {
line.qty.toString()
}
field["qty"] = actualPickQty
field["shortName"] = line.uomShortDesc ?: ""
val route = line.itemId?.let { itemId ->
routeFromStockOutsForItem(
itemId,
pickOrderLineIdsByItemId,
stockOutLinesByPickOrderLineId,
illById,
).takeIf { it != "-" } ?: getWarehouseCodeByItemId(itemId)
} ?: "-"
field["route"] = route
val lotNo = line.itemId?.let { itemId ->
val pickOrderLineIdsForItem = pickOrderLineIdsByItemId[itemId] ?: emptyList()
val lotNumbers = pickOrderLineIdsForItem.flatMap { polId ->
stockOutLinesByPickOrderLineId[polId].orEmpty().mapNotNull { it.lotNo }
}.distinct().joinToString(", ")
lotNumbers.ifBlank { "沒有庫存" }
} ?: "沒有庫存"
field["lotNo"] = lotNo
val signOff = line.itemId?.let { itemId ->
val item = itemsMap[itemId]
if (item?.isEgg == true) {
"簽署: __________"
} else {
""
}
} ?: ""
field["signOff"] = signOff
fields.add(field)
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,
),
)
}
params["dnTitle"] = "送貨單"
@@ -1386,15 +1347,110 @@ open class DeliveryOrderService(
)
}
fun routeFromStockOutsForItem(
itemId: Long,
pickOrderLineIdsByItemId: Map<Long?, List<Long>>,
data class DeliveryNoteExportLine(
val deliveryOrderId: Long,
val line: DeliveryOrderLineInfo,
)

fun deliveryNoteExportLines(deliveryNoteInfo: List<DeliveryOrderInfo>): List<DeliveryNoteExportLine> =
deliveryNoteInfo.flatMap { info ->
info.deliveryOrderLines.map { line -> DeliveryNoteExportLine(info.id, line) }
}

fun resolvePickOrderLineIdForDeliveryNoteLine(
deliveryOrderId: Long,
itemId: Long?,
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
}

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>,
): MutableMap<String, Any> {
val field = mutableMapOf<String, Any>()
field["sequenceNumber"] = sequenceNumber.toString()
field["itemNo"] = line.itemNo
field["itemName"] = line.itemName ?: ""
field["uom"] = line.uom ?: ""
field["shortName"] = line.uomShortDesc ?: ""

val polId = resolvePickOrderLineIdForDeliveryNoteLine(
deliveryOrderId = deliveryOrderId,
itemId = line.itemId,
pickOrderIdByDoId = pickOrderIdByDoId,
pickOrderLines = pickOrderLines,
)
val polIdsForRow = listOfNotNull(polId)

field["qty"] = if (polId != null) {
sumActualPickQtyForPickOrderLineIds(polIdsForRow, stockOutLinesByPickOrderLineId)
} else {
line.qty.toString()
}

val itemId = line.itemId
field["route"] = when {
itemId != null && polId != null -> {
routeFromStockOutsForPickOrderLineIds(polIdsForRow, stockOutLinesByPickOrderLineId, illById)
.takeIf { it != "-" } ?: getWarehouseCodeByItemId(itemId) ?: "-"
}
itemId != null -> getWarehouseCodeByItemId(itemId) ?: "-"
else -> "-"
}

field["lotNo"] = if (itemId != null && polId != null) {
lotNumbersForPickOrderLineIds(polIdsForRow, stockOutLinesByPickOrderLineId).ifBlank { "沒有庫存" }
} else {
"沒有庫存"
}

field["signOff"] = if (itemId != null && itemsById[itemId]?.isEgg == true) {
"簽署: __________"
} else {
""
}

return field
}

fun sumActualPickQtyForPickOrderLineIds(
pickOrderLineIds: List<Long>,
stockOutLinesByPickOrderLineId: Map<Long, List<StockOutLineInfo>>,
): String {
if (pickOrderLineIds.isEmpty()) return "0"
return pickOrderLineIds.sumOf { polId ->
stockOutLinesByPickOrderLineId[polId].orEmpty().sumOf { it.qty }
}.toString()
}

fun lotNumbersForPickOrderLineIds(
pickOrderLineIds: List<Long>,
stockOutLinesByPickOrderLineId: Map<Long, List<StockOutLineInfo>>,
): String =
pickOrderLineIds.flatMap { polId ->
stockOutLinesByPickOrderLineId[polId].orEmpty().mapNotNull { it.lotNo }
}.distinct().joinToString(", ")

fun routeFromStockOutsForPickOrderLineIds(
pickOrderLineIds: List<Long>,
stockOutLinesByPickOrderLineId: Map<Long, List<StockOutLineInfo>>,
illById: Map<Long, InventoryLotLine>,
): String {
val polIds = pickOrderLineIdsByItemId[itemId] ?: return "-"
val codes = linkedSetOf<String>()
for (polId in polIds) {
for (polId in pickOrderLineIds) {
for (sol in stockOutLinesByPickOrderLineId[polId].orEmpty()) {
val illId = sol.inventoryLotLineId ?: continue
val ill = illById[illId] ?: continue
@@ -1403,6 +1459,16 @@ open class DeliveryOrderService(
}
return if (codes.isEmpty()) "-" else codes.joinToString(", ")
}

fun routeFromStockOutsForItem(
itemId: Long,
pickOrderLineIdsByItemId: Map<Long?, List<Long>>,
stockOutLinesByPickOrderLineId: Map<Long, List<StockOutLineInfo>>,
illById: Map<Long, InventoryLotLine>,
): String {
val polIds = pickOrderLineIdsByItemId[itemId] ?: return "-"
return routeFromStockOutsForPickOrderLineIds(polIds, stockOutLinesByPickOrderLineId, illById)
}
//Print Delivery Note
@Transactional
open fun printDeliveryNote(request: PrintDeliveryNoteRequest) {


+ 30
- 51
src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt Ver fichero

@@ -2638,6 +2638,7 @@ return MessageResponse(
val pickOrderIds: List<Long>,
val pickOrderCodes: List<String>,
val deliveryOrderIds: List<Long>,
val pickOrderIdByDoId: Map<Long, Long>,
)

private fun getWorkbenchPrintContext(deliveryOrderPickOrderId: Long): WorkbenchPrintContext {
@@ -2660,7 +2661,12 @@ return MessageResponse(

val pickOrderIds = rows.mapNotNull { (it["id"] as? Number)?.toLong() }.distinct()
val pickOrderCodes = rows.mapNotNull { it["code"]?.toString()?.takeIf { s -> s.isNotBlank() } }.distinct()
val deliveryOrderIds = rows.mapNotNull { (it["doId"] as? Number)?.toLong() }.distinct()
val pickOrderIdByDoId = rows.mapNotNull { row ->
val doId = (row["doId"] as? Number)?.toLong()
val poId = (row["id"] as? Number)?.toLong()
if (doId != null && poId != null) doId to poId else null
}.toMap()
val deliveryOrderIds = pickOrderIdByDoId.keys.distinct()
if (deliveryOrderIds.isEmpty()) {
throw IllegalStateException("DeliveryOrderPickOrder $deliveryOrderPickOrderId has no associated delivery orders")
}
@@ -2670,10 +2676,11 @@ return MessageResponse(
pickOrderIds = pickOrderIds,
pickOrderCodes = pickOrderCodes,
deliveryOrderIds = deliveryOrderIds,
pickOrderIdByDoId = pickOrderIdByDoId,
)
}

private fun exportDeliveryNoteWorkbench(request: ExportDeliveryNoteRequest): Map<String, Any> {
open fun exportDeliveryNoteWorkbench(request: ExportDeliveryNoteRequest): Map<String, Any> {
val DELIVERYNOTE_PDF = "DeliveryNote/DeliveryNotePDF.jrxml"
val resource = ClassPathResource(DELIVERYNOTE_PDF)
if (!resource.exists()) {
@@ -2693,13 +2700,11 @@ return MessageResponse(
throw NoSuchElementException("Delivery orders not found for IDs: ${ctx.deliveryOrderIds}")
}

val allLines = deliveryNoteInfo.flatMap { info -> info.deliveryOrderLines.map { it } }
val exportLines = deliveryOrderService.deliveryNoteExportLines(deliveryNoteInfo)

val pickOrderLines = ctx.pickOrderIds.flatMap { pid ->
pickOrderLineRepository.findAllByPickOrderId(pid)
}
val pickOrderLineIdsByItemId = pickOrderLines
.groupBy { it.item?.id }
.mapValues { (_, lines) -> lines.mapNotNull { it.id } }
val allPickOrderLineIds = pickOrderLines.mapNotNull { it.id }
val stockOutLinesByPickOrderLineId: Map<Long, List<StockOutLineInfo>> =
if (allPickOrderLineIds.isNotEmpty()) {
@@ -2714,21 +2719,21 @@ return MessageResponse(
?.replace("/", "")
?.replace(" ", "")
?: ""
val uniqueItemIdsForSort = allLines.mapNotNull { it.itemId }.distinct()
val uniqueItemIdsForSort = exportLines.mapNotNull { it.line.itemId }.distinct()
val itemsById = if (uniqueItemIdsForSort.isNotEmpty()) {
itemsRepository.findAllById(uniqueItemIdsForSort).associateBy { it.id!! }
} else {
emptyMap()
}
val sortedLines = when (doStoreFloorKey) {
"2F" -> allLines.sortedWith(
"2F" -> exportLines.sortedWith(
compareBy(
{ line -> itemsById[line.itemId]?.item_Order ?: Int.MAX_VALUE },
{ line -> line.itemNo },
{ row -> itemsById[row.line.itemId]?.item_Order ?: Int.MAX_VALUE },
{ row -> row.line.itemNo },
),
)
else -> allLines.sortedBy { line ->
line.itemId?.let { deliveryOrderService.getWarehouseOrderByItemId(it) } ?: Int.MAX_VALUE
else -> exportLines.sortedBy { row ->
row.line.itemId?.let { deliveryOrderService.getWarehouseOrderByItemId(it) } ?: Int.MAX_VALUE
}
}
val allIllIds = stockOutLinesByPickOrderLineId.values
@@ -2740,45 +2745,19 @@ return MessageResponse(
emptyMap()
}

sortedLines.forEach { line ->
val field = mutableMapOf<String, Any>()
field["sequenceNumber"] = (fields.size + 1).toString()
field["itemNo"] = line.itemNo
field["itemName"] = line.itemName ?: ""
field["uom"] = line.uom ?: ""
val actualPickQty = if (line.itemId != null) {
val pickOrderLineIdsForItem = pickOrderLineIdsByItemId[line.itemId] ?: emptyList()
val totalQty = pickOrderLineIdsForItem.sumOf { polId ->
stockOutLinesByPickOrderLineId[polId].orEmpty().sumOf { it.qty }
}
totalQty.toString()
} else {
line.qty.toString()
}
field["qty"] = actualPickQty
field["shortName"] = line.uomShortDesc ?: ""
val route = line.itemId?.let { itemId ->
deliveryOrderService.routeFromStockOutsForItem(
itemId,
pickOrderLineIdsByItemId,
stockOutLinesByPickOrderLineId,
illById,
).takeIf { it != "-" } ?: deliveryOrderService.getWarehouseCodeByItemId(itemId)
} ?: "-"
field["route"] = route
val lotNo = line.itemId?.let { itemId ->
val pickOrderLineIdsForItem = pickOrderLineIdsByItemId[itemId] ?: emptyList()
val lotNumbers = pickOrderLineIdsForItem.flatMap { polId ->
stockOutLinesByPickOrderLineId[polId].orEmpty().mapNotNull { it.lotNo }
}.distinct().joinToString(", ")
lotNumbers.ifBlank { "沒有庫存" }
} ?: "沒有庫存"
field["lotNo"] = lotNo
val signOff = line.itemId?.let { itemId ->
if (itemsById[itemId]?.isEgg == true) "簽署: __________" else ""
} ?: ""
field["signOff"] = signOff
fields.add(field)
sortedLines.forEach { row ->
fields.add(
deliveryOrderService.buildDeliveryNotePdfLineField(
deliveryOrderId = row.deliveryOrderId,
line = row.line,
sequenceNumber = fields.size + 1,
pickOrderIdByDoId = ctx.pickOrderIdByDoId,
pickOrderLines = pickOrderLines,
stockOutLinesByPickOrderLineId = stockOutLinesByPickOrderLineId,
illById = illById,
itemsById = itemsById,
),
)
}

params["dnTitle"] = "送貨單"


+ 1
- 1
src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt Ver fichero

@@ -94,7 +94,7 @@ class DeliveryOrderController(
}

/**
* DO 輕量搜 v2:車線關鍵字正規化(`車線-X`/`x`/`車線-` 前綴併入未指派)、
* DO 輕量搜 v2:車線關鍵字正規化(`車線-X`/`x`/`車線-` 前綴併入未指派)、
* 允許供應商條件下分批掃描,避免單次載入過大;請求體同 [searchDoLite]。
*/
@PostMapping("/search-do-lite-v2")


+ 19
- 0
src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DoWorkbenchController.kt Ver fichero

@@ -24,6 +24,11 @@ import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import java.time.format.DateTimeFormatter
import jakarta.servlet.http.HttpServletResponse
import jakarta.validation.Valid
import net.sf.jasperreports.engine.JasperExportManager
import net.sf.jasperreports.engine.JasperPrint
import java.io.OutputStream
@RestController
@RequestMapping("/doPickOrder/workbench")
class DoWorkbenchController(
@@ -237,6 +242,20 @@ class DoWorkbenchController(
doWorkbenchMainService.printDeliveryNoteWorkbench(request)
}

@PostMapping("/DN")
fun downloadWorkbenchDN(
@Valid @RequestBody request: ExportDeliveryNoteRequest,
response: HttpServletResponse,
) {
response.characterEncoding = "utf-8"
response.contentType = "application/pdf"
val out: OutputStream = response.outputStream
val pdf = doWorkbenchMainService.exportDeliveryNoteWorkbench(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)


Cargando…
Cancelar
Guardar