From c91393b66fd9fbd8f032c70ac15c15367c0554b6 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Mon, 18 Aug 2025 14:44:58 +0800 Subject: [PATCH] update of pickorder api --- .../pickOrder/entity/PickOrderRepository.kt | 2 + .../pickOrder/service/PickOrderService.kt | 283 ++++++++++++++++++ .../pickOrder/web/PickOrderController.kt | 17 ++ .../web/models/ConsoPickOrderResponse.kt | 28 ++ .../modules/stock/entity/InventoryLot.kt | 2 + 5 files changed, 332 insertions(+) diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderRepository.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderRepository.kt index 3cf71ee..ead5172 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderRepository.kt @@ -61,4 +61,6 @@ interface PickOrderRepository : AbstractRepository { fun findAllByConsoCode(consoCode: String): List fun findAllByConsoCodeAndStatus(consoCode: String, status: PickOrderStatus): List + + fun findAllByIdIn(id: List): List } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt index 3471dc3..52d7f6a 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt @@ -490,6 +490,289 @@ open class PickOrderService( ) } + // TODO: + open fun getPickOrdersInfo(ids: List): GetPickOrderInfoResponse { + val today = LocalDate.now() + val zero = BigDecimal.ZERO + val one = BigDecimal.ONE + val pos = pickOrderRepository.findAllByIdIn(ids) + println(pos) + // Get Inventory Data + val requiredItems = pos + .flatMap { it.pickOrderLines } + .groupBy { it.item?.id } + .map { (key, value) -> + key to object : CurrentInventoryItemInfo { + override val id: Long? = value[0].item?.id + override val code: String? = value[0].item?.code + override val name: String? = value[0].item?.name + override val uomDesc: String? = value[0].uom?.udfudesc + override var availableQty: BigDecimal? = zero + override val requiredQty: BigDecimal = value.sumOf { it.qty ?: zero } + + } + } // itemId - requiredQty + + val itemIds = requiredItems.mapNotNull { it.first } +// val inventories = inventoryLotLineRepository.findCurrentInventoryByItems(itemIds) +// val inventories = inventoryService.allInventoriesByItemIds(itemIds) + val inventories = inventoryLotLineService + .allInventoryLotLinesByItemIdIn(itemIds) + .filter { it.status == InventoryLotLineStatus.AVAILABLE.value } + .filter { (it.inQty ?: zero).minus(it.outQty ?: zero).minus(it.holdQty ?: zero) > zero } + .filter { it.expiryDate.isAfter(today) || it.expiryDate.isEqual(today) } + .sortedBy { it.expiryDate } + .groupBy { it.item?.id } + + val suggestions = + suggestedPickLotService.suggestionForPickOrders(SuggestedPickLotForPoRequest(pickOrders = pos)) + // Pick Orders + val releasePickOrderInfos = pos + .map { po -> + val releasePickOrderLineInfos = po.pickOrderLines.map { pol -> +// if (pol.item?.id != null && pol.item!!.id!! > 0) { + val inventory = pol.item?.id?.let { inventories[it] } + val itemUom = pol.item?.id?.let { itemUomService.findSalesUnitByItemId(it) } +// val inventory = inventories.find { it.itemId == pol.item?.id } + + // Return + GetPickOrderLineInfo( + id = pol.id, + itemId = pol.item?.id, + itemCode = pol.item?.code, + itemName = pol.item?.name, +// availableQty = inventory?.availableQty, + availableQty = inventory?.sumOf { i -> (i.availableQty ?: zero) }, +// availableQty = inventory?.sumOf { i -> (i.availableQty ?: zero) * (itemUom?.ratioN ?: one) * (itemUom?.ratioD ?: one) }, + requiredQty = pol.qty, + uomCode = pol.uom?.code, + uomDesc = pol.uom?.udfudesc, + suggestedList = suggestions.suggestedList.filter { it.pickOrderLine?.id == pol.id } + ) +// } + } + + // Return + GetPickOrderInfo( + id = po.id, + code = po.code, + targetDate = po.targetDate, + type = po.type?.value, + status = po.status?.value, + pickOrderLines = releasePickOrderLineInfos + ) + } + + // Items + val currentInventoryInfos = requiredItems.map { item -> +// val inventory = inventories +// .find { it.itemId == item.first } + + val inventory = item.first?.let { inventories[it] } + val itemUom = item.first?.let { itemUomService.findSalesUnitByItemId(it) } + + item.second.let { +// it.availableQty = inventory?.availableQty + + it.availableQty = inventory?.sumOf { i -> i.availableQty ?: zero } +// it.availableQty = inventory?.sumOf { i -> (i.availableQty ?: zero) * (itemUom?.ratioN ?: one) * (itemUom?.ratioD ?: one) } + + // return + it + } + } + + return GetPickOrderInfoResponse( +// consoCode = consoCode, + pickOrders = releasePickOrderInfos, + items = currentInventoryInfos, + ) + } + + + open fun getAllPickOrdersInfo(): GetPickOrderInfoResponse { + // 使用现有的查询方法获取所有 Pick Orders,然后在内存中过滤 + val allPickOrders = pickOrderRepository.findAll() + val releasedPickOrderIds = allPickOrders + .filter { it.status == PickOrderStatus.RELEASED } + .map { it.id!! } + + println("All released pick order IDs: $releasedPickOrderIds") + + // 如果没有任何已发布的 Pick Orders,返回空结果 + if (releasedPickOrderIds.isEmpty()) { + return GetPickOrderInfoResponse( + pickOrders = emptyList(), + items = emptyList() + ) + } + + // 重用现有的 getPickOrdersInfo 方法 + return getPickOrdersInfo(releasedPickOrderIds) + } + + open fun getPickOrderLineLotDetails(pickOrderLineId: Long): List> { + val today = LocalDate.now() + + println("=== Debug: getPickOrderLineLotDetails ===") + println("pickOrderLineId: $pickOrderLineId") + println("today: $today") + + // 检查具体的数量字段值 + val quantityCheckSql = """ + SELECT + spl.id as suggestedPickLotId, + ill.id as lotLineId, + ill.inQty, + ill.outQty, + ill.holdQty, + COALESCE(ill.inQty, 0) as inQtyCoalesced, + COALESCE(ill.outQty, 0) as outQtyCoalesced, + COALESCE(ill.holdQty, 0) as holdQtyCoalesced, + (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) as availableQtyCalculated + FROM fpsmsdb.suggested_pick_lot spl + JOIN fpsmsdb.inventory_lot_line ill ON ill.id = spl.suggestedLotLineId + WHERE spl.pickOrderLineId = :pickOrderLineId + AND ill.status = 'available' + """.trimIndent() + + val quantityCheckResult = jdbcDao.queryForList(quantityCheckSql, mapOf("pickOrderLineId" to pickOrderLineId)) + println("Quantity check result:") + quantityCheckResult.forEach { row -> + println("Row: $row") + } + + // 检查日期条件 + val dateCheckSql = """ + SELECT + spl.id as suggestedPickLotId, + ill.id as lotLineId, + il.lotNo, + il.expiryDate, + :today as today, + il.expiryDate >= :today as isNotExpired, + il.expiryDate IS NULL as isNullExpiry + FROM fpsmsdb.suggested_pick_lot spl + JOIN fpsmsdb.inventory_lot_line ill ON ill.id = spl.suggestedLotLineId + JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId + WHERE spl.pickOrderLineId = :pickOrderLineId + AND ill.status = 'available' + AND (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) > 0 + """.trimIndent() + + val dateCheckResult = jdbcDao.queryForList(dateCheckSql, mapOf("pickOrderLineId" to pickOrderLineId, "today" to today)) + println("Date check result:") + dateCheckResult.forEach { row -> + println("Row: $row") + } + + // 检查 warehouse JOIN + val warehouseCheckSql = """ + SELECT + spl.id as suggestedPickLotId, + ill.id as lotLineId, + ill.warehouseId, + w.id as warehouseId, + w.name as warehouseName + FROM fpsmsdb.suggested_pick_lot spl + JOIN fpsmsdb.inventory_lot_line ill ON ill.id = spl.suggestedLotLineId + JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId + JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + WHERE spl.pickOrderLineId = :pickOrderLineId + AND ill.status = 'available' + AND (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) > 0 + AND (il.expiryDate IS NULL OR il.expiryDate >= :today) + """.trimIndent() + + val warehouseCheckResult = jdbcDao.queryForList(warehouseCheckSql, mapOf("pickOrderLineId" to pickOrderLineId, "today" to today)) + println("Warehouse check result count: ${warehouseCheckResult.size}") + warehouseCheckResult.forEach { row -> + println("Warehouse Row: $row") + } + + // 检查 uom_conversion JOIN - 使用 LEFT JOIN 并检查 stockItemUomId + val uomCheckSql = """ + SELECT + spl.id as suggestedPickLotId, + ill.id as lotLineId, + ill.stockItemUomId, + uc.id as uomId, + uc.code as uomCode + FROM fpsmsdb.suggested_pick_lot spl + JOIN fpsmsdb.inventory_lot_line ill ON ill.id = spl.suggestedLotLineId + JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId + JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = ill.stockItemUomId + WHERE spl.pickOrderLineId = :pickOrderLineId + AND ill.status = 'available' + AND (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) > 0 + AND (il.expiryDate IS NULL OR il.expiryDate >= :today) + """.trimIndent() + + val uomCheckResult = jdbcDao.queryForList(uomCheckSql, mapOf("pickOrderLineId" to pickOrderLineId, "today" to today)) + println("UOM check result count: ${uomCheckResult.size}") + uomCheckResult.forEach { row -> + println("UOM Row: $row") + } + + // 修改查询,通过 item_uom 表获取 UOM 信息 + val sql = """ + SELECT + ill.id as lotId, + il.lotNo, + il.expiryDate, + w.name as location, + COALESCE(uc.code, 'N/A') as stockUnit, + (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) as availableQty, + spl.qty as requiredQty, + COALESCE(sol.qty, 0) as actualPickQty, + spl.id as suggestedPickLotId, + ill.status as lotStatus, + CASE + WHEN ill.status != 'available' THEN 'status_unavailable' + WHEN (il.expiryDate IS NOT NULL AND il.expiryDate < :today) THEN 'expired' + WHEN (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) < spl.qty THEN 'insufficient_stock' + ELSE 'available' + END as lotAvailability + FROM fpsmsdb.suggested_pick_lot spl + JOIN fpsmsdb.inventory_lot_line ill ON ill.id = spl.suggestedLotLineId + JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId + JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + LEFT JOIN fpsmsdb.item_uom iu ON iu.id = ill.stockItemUomId + LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = iu.uomId + LEFT JOIN fpsmsdb.stock_out_line sol ON sol.inventoryLotLineId = ill.id + AND sol.pickOrderLineId = spl.pickOrderLineId + WHERE spl.pickOrderLineId = :pickOrderLineId + ORDER BY + CASE lotAvailability + WHEN 'available' THEN 1 + WHEN 'insufficient_stock' THEN 2 + WHEN 'expired' THEN 3 + WHEN 'status_unavailable' THEN 4 + END, + il.expiryDate ASC + """.trimIndent() + + val params = mapOf( + "pickOrderLineId" to pickOrderLineId, + "today" to today + ) + + val result = jdbcDao.queryForList(sql, params) + println("Final result count: ${result.size}") + result.forEach { row -> + println("Final Row: $row") + } + + return result + } + + + + + + + @Transactional(rollbackFor = [java.lang.Exception::class]) open fun releaseConsoPickOrderAction(request: ReleaseConsoPickOrderRequest): ReleasePickOrderInfoResponse { val zero = BigDecimal.ZERO diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt index ced346c..fd999d0 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt @@ -92,6 +92,16 @@ class PickOrderController( return pickOrderService.releaseConsoPickOrderInfo(consoCode); } + // TODO: + @GetMapping("/detail/{ids}") + fun getPickOrdersInfo(@PathVariable ids: List): GetPickOrderInfoResponse { + return pickOrderService.getPickOrdersInfo(ids); + } + + @GetMapping("/detail") + fun getAllPickOrdersInfo(): GetPickOrderInfoResponse { + return pickOrderService.getAllPickOrdersInfo(); + } @PostMapping("/releaseConso") fun releaseConsoPickOrderAction(@Valid @RequestBody request: ReleaseConsoPickOrderRequest): ReleasePickOrderInfoResponse { return pickOrderService.releaseConsoPickOrderAction(request) @@ -112,4 +122,11 @@ class PickOrderController( fun create(@Valid @RequestBody request: SavePickOrderRequest): MessageResponse { return pickOrderService.create(request) } + + @GetMapping("/lot-details/{pickOrderLineId}") + fun getPickOrderLineLotDetails(@PathVariable pickOrderLineId: Long): List> { + return pickOrderService.getPickOrderLineLotDetails(pickOrderLineId); + } + + } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/ConsoPickOrderResponse.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/ConsoPickOrderResponse.kt index b83dbe1..ac811c3 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/ConsoPickOrderResponse.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/ConsoPickOrderResponse.kt @@ -1,5 +1,6 @@ package com.ffii.fpsms.modules.pickOrder.web.models +import com.ffii.fpsms.modules.stock.entity.SuggestedPickLot import com.ffii.fpsms.modules.stock.entity.projection.CurrentInventoryItemInfo import java.math.BigDecimal import java.time.LocalDateTime @@ -11,6 +12,12 @@ data class ReleasePickOrderInfoResponse( val items: List ) +data class GetPickOrderInfoResponse( +// val consoCode: String, + val pickOrders: List, + val items: List +) + // Components data class ReleasePickOrderInfo( val id: Long?, @@ -21,6 +28,15 @@ data class ReleasePickOrderInfo( val pickOrderLines: List ) +data class GetPickOrderInfo( + val id: Long?, + val code: String?, + val targetDate: LocalDateTime?, + val type: String?, + val status: String?, + val pickOrderLines: List +) + data class ReleasePickOrderLineInfo( val id: Long?, val itemId: Long?, @@ -32,6 +48,18 @@ data class ReleasePickOrderLineInfo( val uomDesc: String?, ) +data class GetPickOrderLineInfo( + val id: Long?, + val itemId: Long?, + val itemCode: String?, + val itemName: String?, + val availableQty: BigDecimal?, + val requiredQty: BigDecimal?, + val uomCode: String?, + val uomDesc: String?, + val suggestedList: List?, +) + // Final Response - Conso Pick Order Detail data class ConsoPickOrderResponse( val consoCode: String, diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLot.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLot.kt index 5c16b1e..151f359 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLot.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLot.kt @@ -1,5 +1,6 @@ package com.ffii.fpsms.modules.stock.entity +import com.fasterxml.jackson.annotation.JsonBackReference import com.ffii.core.entity.BaseEntity import com.ffii.fpsms.modules.master.entity.Items import jakarta.persistence.* @@ -18,6 +19,7 @@ open class InventoryLot : BaseEntity() { @JoinColumn(name = "itemId", nullable = false) open var item: Items? = null + @JsonBackReference @NotNull @ManyToOne @JoinColumn(name = "stockInLineId", nullable = false)