Ver código fonte

update of pickorder api

master
CANCERYS\kw093 1 semana atrás
pai
commit
c91393b66f
5 arquivos alterados com 332 adições e 0 exclusões
  1. +2
    -0
      src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderRepository.kt
  2. +283
    -0
      src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt
  3. +17
    -0
      src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt
  4. +28
    -0
      src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/ConsoPickOrderResponse.kt
  5. +2
    -0
      src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLot.kt

+ 2
- 0
src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderRepository.kt Ver arquivo

@@ -61,4 +61,6 @@ interface PickOrderRepository : AbstractRepository<PickOrder, Long> {
fun findAllByConsoCode(consoCode: String): List<PickOrder>

fun findAllByConsoCodeAndStatus(consoCode: String, status: PickOrderStatus): List<PickOrder>

fun findAllByIdIn(id: List<Serializable>): List<PickOrder>
}

+ 283
- 0
src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt Ver arquivo

@@ -490,6 +490,289 @@ open class PickOrderService(
)
}

// TODO:
open fun getPickOrdersInfo(ids: List<Long>): 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<Map<String, Any>> {
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


+ 17
- 0
src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt Ver arquivo

@@ -92,6 +92,16 @@ class PickOrderController(
return pickOrderService.releaseConsoPickOrderInfo(consoCode);
}

// TODO:
@GetMapping("/detail/{ids}")
fun getPickOrdersInfo(@PathVariable ids: List<Long>): 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<Map<String, Any>> {
return pickOrderService.getPickOrderLineLotDetails(pickOrderLineId);
}


}

+ 28
- 0
src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/ConsoPickOrderResponse.kt Ver arquivo

@@ -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<CurrentInventoryItemInfo>
)

data class GetPickOrderInfoResponse(
// val consoCode: String,
val pickOrders: List<GetPickOrderInfo>,
val items: List<CurrentInventoryItemInfo>
)

// Components
data class ReleasePickOrderInfo(
val id: Long?,
@@ -21,6 +28,15 @@ data class ReleasePickOrderInfo(
val pickOrderLines: List<ReleasePickOrderLineInfo>
)

data class GetPickOrderInfo(
val id: Long?,
val code: String?,
val targetDate: LocalDateTime?,
val type: String?,
val status: String?,
val pickOrderLines: List<GetPickOrderLineInfo>
)

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<SuggestedPickLot>?,
)

// Final Response - Conso Pick Order Detail
data class ConsoPickOrderResponse(
val consoCode: String,


+ 2
- 0
src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLot.kt Ver arquivo

@@ -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<Long>() {
@JoinColumn(name = "itemId", nullable = false)
open var item: Items? = null

@JsonBackReference
@NotNull
@ManyToOne
@JoinColumn(name = "stockInLineId", nullable = false)


Carregando…
Cancelar
Salvar