浏览代码

update

master
CANCERYS\kw093 3 个月前
父节点
当前提交
8db909945d
共有 4 个文件被更改,包括 280 次插入14 次删除
  1. +2
    -2
      src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt
  2. +262
    -10
      src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt
  3. +15
    -2
      src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt
  4. +1
    -0
      src/main/java/com/ffii/fpsms/modules/stock/entity/StockOutLIneRepository.kt

+ 2
- 2
src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt 查看文件

@@ -78,7 +78,7 @@ open class ItemsService(
pol.qty as requiredQty,
COALESCE(inv.availableQty, 0) as currentStock,
COALESCE(uc.udfudesc, 'N/A') as unit,
po.targetDate,
DATE_FORMAT(po.targetDate, '%Y-%m-%d') as targetDate,
po.status,
po.consoCode,
po.assignTo,
@@ -133,7 +133,7 @@ open class ItemsService(
val result = jdbcDao.queryForList(finalSql, args)
println("Query result size: ${result.size}")
result.forEach { row -> println("Result row: $row") }
return result
} catch (e: Exception) {
println("Error in getPickOrderItemsByPage: ${e.message}")


+ 262
- 10
src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt 查看文件

@@ -1041,19 +1041,41 @@ open class PickOrderService(
val inventoryLotLines = inventoryLotLineRepository.findAllByIdIn(
saveSuggestedPickLots.mapNotNull { it.suggestedLotLine?.id }
)
saveSuggestedPickLots.forEach { lot ->
if (lot.suggestedLotLine != null && lot.suggestedLotLine?.id != null && lot.suggestedLotLine!!.id!! > 0) {
val lineIndex = inventoryLotLines.indexOf(lot.suggestedLotLine)
if (lineIndex >= 0) {
inventoryLotLines[lineIndex].holdQty =
(inventoryLotLines[lineIndex].holdQty ?: zero).plus(lot.qty ?: zero)

logger.info("saveSuggestedPickLots: $saveSuggestedPickLots")
inventoryLotLineRepository.saveAll(inventoryLotLines)
var precreated = 0
saveSuggestedPickLots.forEach { lot ->
val polId = lot.pickOrderLine?.id
val illId = lot.suggestedLotLine?.id
if (polId != null && illId != null) {
try {
val existingLines = stockOutLIneRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse(polId, illId)
if (existingLines.isEmpty()) {
val pickOrderLine = pickOrderLineRepository.findById(polId).orElse(null)
val inventoryLotLine = inventoryLotLineRepository.findById(illId).orElse(null)
if (pickOrderLine != null && inventoryLotLine != null) {
val line = com.ffii.fpsms.modules.stock.entity.StockOutLine().apply {
this.stockOut = savedStockOut
this.pickOrderLine = pickOrderLine
this.inventoryLotLine = inventoryLotLine
this.item = pickOrderLine.item // ✅ Add the required item field
this.status = com.ffii.fpsms.modules.stock.web.model.StockOutLineStatus.PENDING.status
this.qty = 0.0
}
stockOutLIneRepository.save(line)
precreated++
} else {
logger.warn("Could not find pickOrderLine (id=$polId) or inventoryLotLine (id=$illId)")
}
}
inventoryLotLineRepository.saveAll(inventoryLotLines)
} catch (e: Exception) {
logger.warn("Failed to create stock out line for pickOrderLineId=$polId, inventoryLotLineId=$illId: ${e.message}")
}
}
}
logger.info("Precreated $precreated stock out lines for suggested lots on release.")
return MessageResponse(
id = null,
name = "Pick orders released successfully with inventory management",
@@ -2454,4 +2476,234 @@ open class PickOrderService(
return addressParts.joinToString(", ")
}

// Add this new method that doesn't auto-assign
open fun getAllPickOrderLotsWithDetailsWithoutAutoAssign(userId: Long): List<Map<String, Any>> {
println("=== Debug: getAllPickOrderLotsWithDetailsWithoutAutoAssign ===")
println("today: ${LocalDate.now()}")
println("userId filter: $userId")
// Get all pick order IDs assigned to the user (both RELEASED and PENDING with doId)
val user = userService.find(userId).orElse(null)
if (user == null) {
println("❌ User not found: $userId")
return emptyList()
}
// Get all pick orders assigned to user with PENDING or RELEASED status that have doId
val allAssignedPickOrders = pickOrderRepository.findAllByAssignToAndStatusIn(
user,
listOf(PickOrderStatus.PENDING, PickOrderStatus.RELEASED)
).filter { it.deliveryOrder != null } // Only pick orders with doId
val pickOrderIds = allAssignedPickOrders.map { it.id!! }
println(" Pick order IDs to fetch: $pickOrderIds")
if (pickOrderIds.isEmpty()) {
return emptyList()
}
// Use the same SQL query as the auto-assign version but without the auto-assignment
val pickOrderIdsStr = pickOrderIds.joinToString(",")
val sql = """
SELECT
-- Pick Order Information
po.id as pickOrderId,
po.code as pickOrderCode,
po.consoCode as pickOrderConsoCode,
DATE_FORMAT(po.targetDate, '%Y-%m-%d') as pickOrderTargetDate,
po.type as pickOrderType,
po.status as pickOrderStatus,
po.assignTo as pickOrderAssignTo,
-- Pick Order Line Information
pol.id as pickOrderLineId,
pol.qty as pickOrderLineRequiredQty,
pol.status as pickOrderLineStatus,
-- Item Information
i.id as itemId,
i.code as itemCode,
i.name as itemName,
uc.code as uomCode,
uc.udfudesc as uomDesc,
-- Lot Information (similar to lot-details endpoint)
ill.id as lotId,
il.lotNo,
DATE_FORMAT(il.expiryDate, '%Y-%m-%d') as expiryDate,
w.name as location,
COALESCE(uc.udfudesc, 'N/A') as stockUnit,
-- ✅ FIXED: Set quantities to NULL for rejected lots
CASE
WHEN sol.status = 'rejected' THEN NULL
ELSE (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0))
END as availableQty,
-- Required quantity for this lot
COALESCE(spl.qty, 0) as requiredQty,
-- Actual picked quantity
COALESCE(sol.qty, 0) as actualPickQty,
-- Suggested pick lot information
spl.id as suggestedPickLotId,
ill.status as lotStatus,
-- Stock out line information
sol.id as stockOutLineId,
sol.status as stockOutLineStatus,
COALESCE(sol.qty, 0) as stockOutLineQty,
-- Additional detailed fields from lot-details
COALESCE(ill.inQty, 0) as inQty,
COALESCE(ill.outQty, 0) as outQty,
COALESCE(ill.holdQty, 0) as holdQty,
COALESCE(spl.suggestedLotLineId, ill.id) as debugSuggestedLotLineId,
ill.inventoryLotId as debugInventoryLotId,
-- Calculate total picked quantity by ALL pick orders for this lot
COALESCE((
SELECT SUM(sol_all.qty)
FROM fpsmsdb.stock_out_line sol_all
WHERE sol_all.inventoryLotLineId = ill.id
AND sol_all.deleted = false
AND sol_all.status IN ('pending', 'checked', 'partially_completed', 'completed')
), 0) as totalPickedByAllPickOrders,
-- Calculate remaining available quantity correctly
(COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) as remainingAfterAllPickOrders,
-- Add detailed debug fields for lotAvailability calculation
ill.status as debug_ill_status,
(il.expiryDate IS NOT NULL AND il.expiryDate < CURDATE()) as debug_is_expired,
sol.status as debug_sol_status,
(COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) as debug_remaining_stock,
(COALESCE(spl.qty, 0) - COALESCE(sol.qty, 0)) as debug_required_after_picked,
-- Lot availability status (same logic as lot-details)
CASE
-- Check if lot is expired
WHEN (il.expiryDate IS NOT NULL AND il.expiryDate < CURDATE()) THEN 'expired'
-- Check if lot has rejected stock out line for this pick order
WHEN sol.status = 'rejected' THEN 'rejected'
-- Check if lot is unavailable due to insufficient stock
WHEN (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) <= 0 THEN 'insufficient_stock'
-- Check if lot status is unavailable
WHEN ill.status = 'unavailable' THEN 'status_unavailable'
-- Default to available
ELSE 'available'
END as lotAvailability,
-- Processing status
CASE
WHEN sol.status = 'completed' THEN 'completed'
WHEN sol.status = 'rejected' THEN 'rejected'
WHEN sol.status = 'created' THEN 'pending'
ELSE 'pending'
END as processingStatus
FROM fpsmsdb.pick_order po
JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id
JOIN fpsmsdb.items i ON i.id = pol.itemId
LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = pol.uomId
LEFT JOIN fpsmsdb.suggested_pick_lot spl ON pol.id = spl.pickOrderLineId
LEFT JOIN fpsmsdb.inventory_lot_line ill ON spl.suggestedLotLineId = ill.id
LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId
LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId
LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ill.id AND sol.deleted = false
WHERE po.deleted = false
AND po.id IN ($pickOrderIdsStr)
AND pol.deleted = false
AND po.status IN ('PENDING', 'RELEASED')
AND po.assignTo = :userId
AND ill.deleted = false
AND il.deleted = false
AND (spl.pickOrderLineId IS NOT NULL OR sol.pickOrderLineId IS NOT NULL)
ORDER BY
CASE WHEN sol.status = 'rejected' THEN 0 ELSE 1 END, -- Show rejected lots first
po.code ASC,
i.code ASC,
il.expiryDate ASC,
il.lotNo ASC
""".trimIndent()
println("🔍 Executing SQL for all pick order lots with details (no auto-assign): $sql")
println(" With parameters: userId = $userId, pickOrderIds = $pickOrderIdsStr")
val results = jdbcDao.queryForList(sql, mapOf("userId" to userId))
println("✅ Total result count: ${results.size}")
// Filter out lots with null availableQty (rejected lots)
val filteredResults = results.filter { row ->
val availableQty = row["availableQty"]
availableQty != null
}
println("✅ Filtered result count: ${filteredResults.size}")
// ✅ Add router information for each lot
val enrichedResults = filteredResults.map { row ->
val inventoryLotId = row["debugInventoryLotId"] as? Number
// Get router information for this inventory lot
val routerInfo = if (inventoryLotId != null) {
try {
val router = routerRepository.findFirstByInventoryLotIdAndDeletedFalse(inventoryLotId.toInt())
if (router != null) {
mapOf(
"routerIndex" to (router.index ?: 0),
"routerRoute" to (router.route ?: ""),
"routerArea" to (router.area ?: ""),
"routerItemCode" to (router.itemCode ?: 0),
"routerItemName" to (router.itemName ?: ""),
"routerUomId" to (router.uomId ?: 0),
"routerNoofCarton" to (router.noofCarton ?: 0)
)
} else {
mapOf(
"routerIndex" to 0,
"routerRoute" to "",
"routerArea" to "",
"routerItemCode" to 0,
"routerItemName" to "",
"routerUomId" to 0,
"routerNoofCarton" to 0
)
}
} catch (e: Exception) {
println("⚠️ Error getting router info for inventoryLotId $inventoryLotId: ${e.message}")
mapOf(
"routerIndex" to 0,
"routerRoute" to "",
"routerArea" to "",
"routerItemCode" to 0,
"routerItemName" to "",
"routerUomId" to 0,
"routerNoofCarton" to 0
)
}
} else {
mapOf(
"routerIndex" to 0,
"routerRoute" to "",
"routerArea" to "",
"routerItemCode" to 0,
"routerItemName" to "",
"routerUomId" to 0,
"routerNoofCarton" to 0
)
}
// Combine original row with router information
row.toMutableMap().apply {
putAll(routerInfo)
}
}
return enrichedResults
}
}

+ 15
- 2
src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt 查看文件

@@ -203,16 +203,18 @@ class PickOrderController(
return ResponseEntity.ok(response)



}

@GetMapping("/groups/latest")
fun getLatestGroupName(): MessageResponse {
return pickOrderService.getLatestGroupNameAndCreate()
}

@GetMapping("/groups/list")
fun getAllGroups(): List<PickOrderGroupInfo> {
return pickOrderService.allPickOrdersGroup()
}

@PostMapping("/groups/create")
fun createNewGroups(@Valid @RequestBody request: SavePickOrderGroupRequest): MessageResponse {
return pickOrderService.createNewGroups(request)
@@ -223,28 +225,39 @@ class PickOrderController(
fun getPickOrderDetailsOptimizedByUser(@PathVariable userId: Long): GetPickOrderInfoResponse {
return pickOrderService.getPickOrderDetailsOptimizedByUser(userId)
}

@PostMapping("/auto-assign-release/{userId}")
fun autoAssignAndReleasePickOrder(@PathVariable userId: Long): MessageResponse {
return pickOrderService.autoAssignAndReleasePickOrder(userId)
}

@GetMapping("/check-pick-completion/{userId}")
fun checkPickOrderCompletion(@PathVariable userId: Long): MessageResponse {
return pickOrderService.checkPickOrderCompletion(userId)
}

@PostMapping("/check-complete/{consoCode}")
fun checkAndCompletePickOrderByConsoCode(@PathVariable consoCode: String): MessageResponse {
return pickOrderService.checkAndCompletePickOrderByConsoCode(consoCode)
}

@GetMapping("/all-lots-with-details/{userId}")
fun getAllPickOrderLotsWithDetails(@PathVariable userId: Long): List<Map<String, Any?>> {
return pickOrderService.getAllPickOrderLotsWithDetailsWithAutoAssign(userId)
}

@GetMapping("/fg-pick-orders")
fun getFgPickOrders(): List<Map<String, Any?>> {
return pickOrderService.getFgPickOrders()
}

@GetMapping("/fg-pick-orders/{pickOrderId}")
fun getFgPickOrdersByPickOrderId(@PathVariable pickOrderId: Long): List<Map<String, Any?>> {
return pickOrderService.getFgPickOrdersByPickOrderId(pickOrderId)
}
}

@GetMapping("/all-lots-with-details-no-auto-assign/{userId}")
fun getAllPickOrderLotsWithDetailsWithoutAutoAssign(@PathVariable userId: Long): List<Map<String, Any>> {
return pickOrderService.getAllPickOrderLotsWithDetailsWithoutAutoAssign(userId)
}
}

+ 1
- 0
src/main/java/com/ffii/fpsms/modules/stock/entity/StockOutLIneRepository.kt 查看文件

@@ -20,4 +20,5 @@ interface StockOutLIneRepository: AbstractRepository<StockOutLine, Long> {
pickOrderLineId: Long,
inventoryLotLineId: Long
): List<StockOutLine>
fun existsByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse(pickOrderLineId: Long, inventoryLotLineId: Long): Boolean
}

正在加载...
取消
保存