瀏覽代碼

update job materail status dashboard

master
CANCERYS\kw093 15 小時之前
父節點
當前提交
b544cc8cd1
共有 4 個文件被更改,包括 127 次插入71 次删除
  1. +109
    -61
      src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt
  2. +3
    -3
      src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt
  3. +7
    -7
      src/main/java/com/ffii/fpsms/modules/report/service/ReportService.kt
  4. +8
    -0
      src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt

+ 109
- 61
src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt 查看文件

@@ -2274,90 +2274,138 @@ open fun deleteJoPickOrderJobOrderProductProcessPickOrder(jobOrderId: Long): Mes
errorPosition = null
)
}
open fun getMaterialPickStatus(): List<MaterialPickStatusItem> {
open fun getMaterialPickStatus(date: String?): List<MaterialPickStatusItem> {
// Parse date filter if provided
val filterDate = date?.let {
try {
LocalDate.parse(it)
} catch (e: Exception) {
null
}
}
// Get all joPickOrders
val joPickOrders = joPickOrderRepository.findAll()
return joPickOrders
// Filter by date if provided (filter by jobOrder.planStart date)
val filteredJoPickOrders = if (filterDate != null) {
joPickOrders.filter { joPickOrder ->
val jobOrder = joPickOrder.jobOrderId?.let {
jobOrderRepository.findById(it).orElse(null)
}
jobOrder?.planStart?.toLocalDate() == filterDate
}
} else {
joPickOrders
}
// Group by jobOrderId
val groupedByJobOrder = filteredJoPickOrders
.filter { joPickOrder ->
val jobOrder = joPickOrder.jobOrderId?.let {
jobOrderRepository.findById(it).orElse(null)
}
jobOrder?.status != JobOrderStatus.COMPLETED
}
.map { joPickOrder ->
// Get related entities for additional data
val jobOrder = joPickOrder.jobOrderId?.let {
jobOrderRepository.findById(it).orElse(null)
}
val item = joPickOrder.itemId?.let {
itemsRepository.findById(it).orElse(null)
}
val pickOrder = joPickOrder.pickOrderId?.let {
pickOrderRepository.findById(it).orElse(null)
.groupBy { it.jobOrderId }
// Map each job order group to a single MaterialPickStatusItem
return groupedByJobOrder.mapNotNull { (jobOrderId, joPickOrdersForJob) ->
if (jobOrderId == null) return@mapNotNull null
val jobOrder = jobOrderRepository.findById(jobOrderId).orElse(null)
?: return@mapNotNull null
// Get BOM item (finished good/semi-finished product), not BOM Material item
val bomItem = jobOrder.bom?.item
if (bomItem == null) return@mapNotNull null
// Get all pick orders for this job order
val pickOrderIds = joPickOrdersForJob.mapNotNull { it.pickOrderId }.distinct()
// Aggregate data from all pick orders for this job order
val allPickOrderLines = pickOrderIds.flatMap { poId ->
pickOrderLineRepository.findByPickOrderId(poId)
}
// Get stock out lines for this pick order and item to get start/end times
// First get all pick order lines for this pick order
val pickOrderLines = pickOrder?.let { po ->
pickOrderLineRepository.findByPickOrderId(po.id!!)
} ?: emptyList()
// Then get stock out lines for each pick order line that matches the item
val stockOutLines = pickOrderLines
.filter { it.item?.id == joPickOrder.itemId }
.flatMap { pol ->
stockOutLineRepository.findAllByPickOrderLineIdAndDeletedFalse(pol.id!!)
.mapNotNull { solInfo ->
// Convert StockOutLineInfo to StockOutLine entity to access startTime/endTime
// We need to fetch the actual entity
stockOutLineRepository.findById(solInfo.id).orElse(null)
}
}
// Get all stock out lines for all pick orders of this job order
val allStockOutLines = allPickOrderLines.flatMap { pol ->
stockOutLineRepository.findAllByPickOrderLineIdAndDeletedFalse(pol.id!!)
.mapNotNull { solInfo ->
stockOutLineRepository.findById(solInfo.id).orElse(null)
}
}
// Get earliest startTime and latest endTime from stock out lines
val pickStartTime = stockOutLines
// ✅ 修复:startTime = 第一个 item 开始提料的时间
// 只考虑已经开始的 items(status 不是 pending),取最早的 startTime
val pickStartTime = allStockOutLines
.filter { it.status != null && it.status != "pending" }
.mapNotNull { it.startTime }
.minOrNull()
val pickEndTime = stockOutLines
.mapNotNull { it.endTime }
.maxOrNull()
// Count total items to pick (number of distinct pick order lines)
val numberOfItemsToPick = allPickOrderLines.size
// ✅ 修复:检查所有 items 是否都已完成
// 计算已完成的 items 数量(每个 pickOrderLine 至少有一个 completed 的 stockOutLine)
val completedItemsCount = allPickOrderLines.count { pol ->
val stockOutLinesForPol = allStockOutLines.filter {
it.pickOrderLine?.id == pol.id
}
// 如果这个 pickOrderLine 有至少一个 completed 的 stockOutLine,则认为已完成
stockOutLinesForPol.any { it.status == "completed" }
}
// Count items to pick from pick order lines
val numberOfItemsToPick = pickOrder?.let { po ->
pickOrderLineRepository.findByPickOrderId(po.id!!).size
} ?: 0
// ✅ 修复:endTime = 最后一个 item 完成提料的时间
// 只有当所有 items 都完成时,才返回 endTime
val pickEndTime = if (completedItemsCount == numberOfItemsToPick && numberOfItemsToPick > 0) {
// 所有 items 都已完成,取最晚的 endTime
allStockOutLines
.filter { it.status == "completed" }
.mapNotNull { it.endTime }
.maxOrNull()
} else {
// 还有 items 未完成,返回 null
null
}
// Count items with issues from pick execution issues
val numberOfItemsWithIssue = joPickOrder.id?.let { joPickOrderId ->
pickExecutionIssueRepository.findByPickOrderIdAndDeletedFalse(joPickOrder.pickOrderId ?: 0L)
.filter { it.joPickOrderId == joPickOrderId }
.size
} ?: 0
// Count total items to pick (number of distinct pick order lines)
//val numberOfItemsToPick = allPickOrderLines.size
// Get job order quantity and UOM - access via bom
val jobOrderQty = jobOrder?.reqQty?.toDouble()
val uom = jobOrder?.bom?.uom?.code
// Count total items with issues from all pick orders
val numberOfItemsWithIssue = pickOrderIds.sumOf { poId ->
pickExecutionIssueRepository.findByPickOrderIdAndDeletedFalse(poId).size
}
// Get item name
val itemName = item?.name
// Get job order quantity and UOM
val jobOrderQty = jobOrder.reqQty?.toDouble()
val uom = jobOrder.bom?.uom?.code
// Determine pick status - prioritize pickOrder.status over matchStatus
// Determine pick status - check if all pick orders are completed
val pickOrders = pickOrderIds.mapNotNull { poId ->
pickOrderRepository.findById(poId).orElse(null)
}
val pickStatus = when {
pickOrder?.status != null -> pickOrder.status!!.value
joPickOrder.matchStatus != null -> joPickOrder.matchStatus!!.value
else -> null
pickOrders.isEmpty() -> null
pickOrders.all { it.status == com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus.COMPLETED } -> "completed"
pickOrders.any { it.status == com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus.RELEASED } -> "released"
else -> "pending"
}
// Use the first pick order code (or combine if multiple)
val pickOrderCode = pickOrderIds.firstOrNull()?.let { poId ->
pickOrderRepository.findById(poId).orElse(null)?.code
}
MaterialPickStatusItem(
id = joPickOrder.id ?: 0L,
pickOrderId = joPickOrder.pickOrderId,
pickOrderCode = joPickOrder.pickOrderCode,
jobOrderId = joPickOrder.jobOrderId,
jobOrderCode = joPickOrder.jobOrderCode,
itemId = joPickOrder.itemId,
itemCode = joPickOrder.itemCode,
itemName = itemName,
id = jobOrderId, // Use jobOrderId as id
pickOrderId = pickOrderIds.firstOrNull(), // First pick order ID
pickOrderCode = pickOrderCode,
jobOrderId = jobOrderId,
jobOrderCode = jobOrder.code,
itemId = bomItem.id, // BOM item ID (finished good/semi-finished)
itemCode = bomItem.code, // BOM item code
itemName = bomItem.name, // BOM item name (finished good/semi-finished)
jobOrderQty = jobOrderQty,
uom = uom,
pickStartTime = pickStartTime,


+ 3
- 3
src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt 查看文件

@@ -323,7 +323,7 @@ fun checkJobOrderCreated(@Valid @RequestBody request: CheckJobOrderCreatedReques
return jobOrderService.updateJoReqQty(request)
}
@GetMapping("/material-pick-status")
fun getMaterialPickStatus(): List<MaterialPickStatusItem> {
return joPickOrderService.getMaterialPickStatus()
}
fun getMaterialPickStatus(@RequestParam(required = false) date: String?): List<MaterialPickStatusItem> {
return joPickOrderService.getMaterialPickStatus(date)
}
}

+ 7
- 7
src/main/java/com/ffii/fpsms/modules/report/service/ReportService.kt 查看文件

@@ -329,7 +329,7 @@ return result
} else ""

val sql = """
SELECT
SELECT
IFNULL(DATE_FORMAT(
IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate),
'%Y-%m-%d'
@@ -340,10 +340,10 @@ return result
IFNULL(dpor.deliveryNoteCode, '') AS dnNo,
CAST(IFNULL(sp.id, 0) AS CHAR) AS customerId,
IFNULL(sp.name, '') AS customerName,
CAST(
SUM(IFNULL(sol.qty, 0)) OVER (PARTITION BY it.code) AS DECIMAL(14,2)
FORMAT(
ROUND(SUM(IFNULL(sol.qty, 0)) OVER (PARTITION BY it.code), 0), 0
) AS qtyNumeric,
CAST(ROUND(IFNULL(sol.qty, 0), 2) AS CHAR) AS qty,
FORMAT(ROUND(IFNULL(sol.qty, 0), 0), 0) AS qty,
'' AS truckNo,
'' AS driver,
IFNULL(do.code, '') AS deliveryOrderNo,
@@ -351,7 +351,7 @@ return result
IFNULL(po.code, '') AS stockReqNo,
IFNULL(il.lotNo, '') AS lotNo,
IFNULL(DATE_FORMAT(il.expiryDate, '%Y-%m-%d'), '') AS expiryDate,
CAST(ROUND(IFNULL(sol.qty, 0), 2) AS CHAR) AS stockOutQty,
FORMAT(ROUND(IFNULL(sol.qty, 0), 0), 0) AS stockOutQty,
COALESCE(
picker_user.name,
modified_user.name,
@@ -364,8 +364,8 @@ return result
) AS pickedBy,
GROUP_CONCAT(DISTINCT wh.code ORDER BY wh.code SEPARATOR ', ') AS storeLocation,
'' AS pickRemark,
CAST(
SUM(IFNULL(sol.qty, 0)) OVER (PARTITION BY it.code) AS CHAR
FORMAT(
ROUND(SUM(IFNULL(sol.qty, 0)) OVER (PARTITION BY it.code), 0), 0
) AS totalStockOutQty,
0 AS stockSubCategory
FROM do_pick_order_line_record dpolr


+ 8
- 0
src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt 查看文件

@@ -587,6 +587,10 @@ private fun getStockOutIdFromPickOrderLine(pickOrderLineId: Long): Long {
stockOutLine.startTime = LocalDateTime.now()
}
if (request.status == "completed") {
// ✅ 修复:如果 startTime 为 null,也设置它(处理直接完成的情况)
if (stockOutLine.startTime == null) {
stockOutLine.startTime = LocalDateTime.now()
}
stockOutLine.endTime = LocalDateTime.now()
}
// 2. 更新自身 status/qty
@@ -988,6 +992,10 @@ open fun updateStockOutLineStatusByQRCodeAndLotNo(request: UpdateStockOutLineSta
stockOutLine.startTime = LocalDateTime.now()
}
if (request.status == "completed") {
// ✅ 修复:如果 startTime 为 null,也设置它(处理直接完成的情况)
if (stockOutLine.startTime == null) {
stockOutLine.startTime = LocalDateTime.now()
}
stockOutLine.endTime = LocalDateTime.now()
}
val updateTime = System.currentTimeMillis() - updateStart


Loading…
取消
儲存