From 7bb8d45483e690b7a473864eaf6c35968254ed7a Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Sun, 21 Dec 2025 22:35:39 +0800 Subject: [PATCH] update --- .../jobOrder/service/JoPickOrderService.kt | 106 +++++++++++------- .../jobOrder/web/JobOrderController.kt | 8 +- .../service/ProductProcessService.kt | 30 ++++- .../web/model/SaveProductProcessRequest.kt | 2 + .../stock/entity/StockInLineRepository.kt | 10 +- .../stock/service/StockInLineService.kt | 16 ++- 6 files changed, 118 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt index 581f8fe..46fbdcb 100644 --- a/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt @@ -12,7 +12,7 @@ import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import java.time.LocalDate + import com.ffii.fpsms.modules.stock.entity.enum.InventoryLotLineStatus import com.ffii.fpsms.modules.pickOrder.enums.PickOrderLineStatus import java.time.LocalDateTime @@ -48,6 +48,7 @@ import com.ffii.fpsms.modules.jobOrder.web.model.LotDetailResponse import com.ffii.fpsms.modules.stock.entity.enum.StockInLineStatus import com.ffii.fpsms.modules.stock.entity.StockInLineRepository +import java.time.LocalDate @Service open class JoPickOrderService( private val joPickOrderRepository: JoPickOrderRepository, @@ -1305,50 +1306,75 @@ open fun getCompletedJobOrderPickOrdersWithCompletedSecondScan(): List { - println("=== getJobOrderListForPrintQrCode ===") - return try { - val jobOrders = jobOrderRepository.findAllByStatusIn(listOf(JobOrderStatus.COMPLETED)) - // Get all stockInLines and filter for "received" status and BOM type "半成品" - val allStockInLines = stockInLineRepository.findAll() - val stockInLines = allStockInLines.filter { - it.jobOrder != null && - it.status == "received" && - it.deleted == false && - it.jobOrder?.bom?.description == "半成品" - } - val result = mutableListOf() - - for (stockInLine in stockInLines) { - val jobOrder = jobOrders.find { it.id == stockInLine.jobOrder?.id } - if (jobOrder != null && jobOrder.bom?.description == "半成品") { - // Check if this job order is already in the result (to avoid duplicates) - val existing = result.find { - it.stockInLineId == stockInLine.id - } +open fun getJobOrderListForPrintQrCode(date: LocalDate): List { + println("=== getJobOrderListForPrintQrCode ===") + println("Filtering by receiptDate: $date") + return try { + // 1. 根据 receiptDate 日期过滤 StockInLine(在数据库层面过滤) + val allStockInLines = stockInLineRepository.findByReceiptDateAndDeletedFalse(date) + println("📦 Found ${allStockInLines.size} StockInLines with receiptDate = $date") + println("📦 All StockInLines: ${allStockInLines.map { it.id }}, ${allStockInLines.map { it.jobOrder?.id }}") + println("📦 All StockInLines: ${allStockInLines.map { it.status }}, ${allStockInLines.map { it.jobOrder?.bom?.description }}") + + // 2. 进一步过滤:status = "received" 或 "completed",且 BOM type = "WIP" 或 "FG" + val stockInLines = allStockInLines.filter { + it.jobOrder != null && + it.status == "received" && // 只显示 QC 完成但尚未 putaway 的 + it.jobOrder?.bom?.description in listOf("WIP", "FG") + } + println("✅ After filtering: ${stockInLines.size} StockInLines") - if (existing == null) { - val response = JobOrderListForPrintQrCodeResponse( - id = stockInLine.id!!, - code = jobOrder.code ?: "JO-${jobOrder.id}", - name = jobOrder.bom?.name ?: "", - reqQty = jobOrder.reqQty ?: BigDecimal.ZERO, - stockInLineId = stockInLine.id!!, - stockInLineQty = stockInLine.acceptedQty?.toDouble() ?: 0.0, - stockInLineStatus = stockInLine.status ?: "received", - finihedTime = jobOrder.planEnd ?: jobOrder.modified ?: LocalDateTime.now() - ) - result.add(response) - } + // 3. 获取相关的 JobOrder IDs + val jobOrderIds = stockInLines.mapNotNull { it.jobOrder?.id }.distinct() + println("📋 JobOrder IDs to check: $jobOrderIds") + + // 4. 批量加载 JobOrders(只加载需要的,且状态为 COMPLETED) + val jobOrders = if (jobOrderIds.isNotEmpty()) { + jobOrderRepository.findAllById(jobOrderIds) + .filter { it.status == JobOrderStatus.COMPLETED } + } else { + emptyList() + } + println("✅ Completed JobOrders: ${jobOrders.map { "${it.id}(${it.status})" }}") + + // 5. 构建响应 + val result = mutableListOf() + + for (stockInLine in stockInLines) { + val jobOrder = jobOrders.find { it.id == stockInLine.jobOrder?.id } + if (jobOrder != null && jobOrder.bom?.description in listOf("WIP", "FG")) { + // Check if this job order is already in the result (to avoid duplicates) + val existing = result.find { + it.stockInLineId == stockInLine.id } + + if (existing == null) { + val response = JobOrderListForPrintQrCodeResponse( + id = stockInLine.id!!, + code = jobOrder.code ?: "JO-${jobOrder.id}", + name = jobOrder.bom?.name ?: "", + reqQty = jobOrder.reqQty ?: BigDecimal.ZERO, + stockInLineId = stockInLine.id!!, + stockInLineQty = stockInLine.acceptedQty?.toDouble() ?: 0.0, + stockInLineStatus = stockInLine.status ?: "received", + finihedTime = jobOrder.planEnd ?: jobOrder.modified ?: LocalDateTime.now() + ) + result.add(response) + println("✅ Added StockInLine ${stockInLine.id} (JobOrder ${jobOrder.id}, BOM: ${jobOrder.bom?.description})") + } + } else { + println("❌ StockInLine ${stockInLine.id}: JobOrder ${stockInLine.jobOrder?.id} not found or BOM type not WIP/FG") } - result - } catch (e: Exception) { - println("❌ Error in getJobOrderListForPrintQrCode: ${e.message}") - e.printStackTrace() - emptyList() } + + println("📊 Final result: ${result.size} items") + result + } catch (e: Exception) { + println("❌ Error in getJobOrderListForPrintQrCode: ${e.message}") + e.printStackTrace() + emptyList() } +} open fun getCompletedJobOrderPickOrderLotDetails(pickOrderId: Long): List> { println("=== getCompletedJobOrderPickOrderLotDetails ===") println("pickOrderId: $pickOrderId") diff --git a/src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt b/src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt index e519043..8f29c24 100644 --- a/src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt +++ b/src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt @@ -40,7 +40,7 @@ import com.ffii.fpsms.modules.jobOrder.web.model.UpdateJoPickOrderHandledByReque import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderInfo import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderInfoWithTypeName import com.ffii.fpsms.modules.jobOrder.web.model.ExportFGStockInLabelRequest - +import java.time.LocalDate @RestController @RequestMapping("/jo") @@ -231,9 +231,9 @@ fun recordSecondScanIssue( fun getCompletedJobOrderPickOrders(): List> { return joPickOrderService.getCompletedJobOrderPickOrders() } - @GetMapping("/joForPrintQrCode") - fun getJoForPrintQrCode(): List { - return joPickOrderService.getJobOrderListForPrintQrCode() + @GetMapping("/joForPrintQrCode/{date}") + fun getJoForPrintQrCode(@PathVariable date: String): List { + return joPickOrderService.getJobOrderListForPrintQrCode(LocalDate.parse(date)) } @GetMapping("/completed-job-order-pick-order-lot-details-completed-pick/{pickOrderId}") diff --git a/src/main/java/com/ffii/fpsms/modules/productProcess/service/ProductProcessService.kt b/src/main/java/com/ffii/fpsms/modules/productProcess/service/ProductProcessService.kt index 51830d6..1794b83 100644 --- a/src/main/java/com/ffii/fpsms/modules/productProcess/service/ProductProcessService.kt +++ b/src/main/java/com/ffii/fpsms/modules/productProcess/service/ProductProcessService.kt @@ -47,6 +47,7 @@ import java.time.ZoneOffset import com.ffii.fpsms.modules.jobOrder.entity.JoPickOrderRepository import com.ffii.fpsms.modules.jobOrder.enums.JoPickOrderStatus import com.ffii.fpsms.modules.master.entity.UomConversionRepository +import com.ffii.fpsms.modules.master.entity.ItemUomRespository @Service @Transactional open class ProductProcessService( @@ -71,6 +72,7 @@ open class ProductProcessService( private val pickOrderRepository: PickOrderRepository, private val joPickOrderRepository: JoPickOrderRepository, private val uomConversionRepository: UomConversionRepository, + private val itemUomRepository: ItemUomRespository, ) { open fun findAll(pageable: Pageable): Page { @@ -782,7 +784,7 @@ open class ProductProcessService( code = "400", name = "Equipment Validation Failed", type = "error", - message = "Input Equipment ID($equipmentId) and BOM Process Equipment ID(${bomProcessEquipment?.id}) not match", + message = "Input Equipment is not match with prcess", errorPosition = "equipmentId" ) } @@ -824,7 +826,7 @@ open class ProductProcessService( code = "400", name = "User Required", type = "error", - message = "Staff No is required when equipment is provided", + message = "Staff No is required", errorPosition = "staffNo" ) } @@ -839,7 +841,7 @@ open class ProductProcessService( code = "400", name = "Equipment Validation Failed", type = "error", - message = "Input Equipment ID(${equipmentDetail.equipmentTypeId}) and BOM Process Equipment ID(${bomProcessEquipment?.id}) not match", + message = "Input Equipment is not match with process", errorPosition = "equipmentId" ) } @@ -855,7 +857,22 @@ open class ProductProcessService( errorPosition = "staffNo" ) } - + if (user != null && productProcessLine.operator != null) { + val existingOperatorId = productProcessLine.operator?.id + val newOperatorId = user.id + + // 如果不是同一个用户,拒绝更新 + if (existingOperatorId != null && existingOperatorId != newOperatorId) { + return MessageResponse( + id = request.productProcessLineId, + code = "409", + name = "Conflict", + type = "error", + message = "This process line is already assigned to another operator", + errorPosition = "operator" + ) + } + } // ===== 通过校验,开始更新 ===== // 设备有(且已通过匹配校验) → 更新 equipment / equipmentDetailId @@ -1082,7 +1099,8 @@ open class ProductProcessService( val stockInLineId = stockInLine?.id val pickOrder = pickOrderRepository.findAllByJobOrder_Id(jobOrder?.id?:0L).firstOrNull() val joPickOrdersList = joPickOrderRepository.findByPickOrderId(pickOrder?.id?:0L) - + val itemUom = itemUomRepository.findByItemIdAndStockUnitIsTrueAndDeletedIsFalse(productProcesses.item?.id?:0L) + val bomUom = uomConversionRepository.findById(itemUom?.uom?.id?:0L).orElse(null) //val silHandlerId = stockInLine?.escalationLog?.firstOrNull { it.status == "pending" }?.handler?.id AllJoborderProductProcessInfoResponse( @@ -1100,10 +1118,12 @@ open class ProductProcessService( "pending" }, RequiredQty = jobOrder?.reqQty?.toInt() ?: 0, + Uom = bomUom?.udfShortDesc, date = productProcesses.date, bomId = productProcesses.bom?.id, assignedTo = pickOrder?.assignTo?.id, itemName = productProcesses.item?.name, + itemCode = productProcesses.item?.code, pickOrderId = pickOrder?.id, pickOrderStatus = pickOrder?.status?.value, jobOrderId = productProcesses.jobOrder?.id, diff --git a/src/main/java/com/ffii/fpsms/modules/productProcess/web/model/SaveProductProcessRequest.kt b/src/main/java/com/ffii/fpsms/modules/productProcess/web/model/SaveProductProcessRequest.kt index 9ef8e0c..26a1455 100644 --- a/src/main/java/com/ffii/fpsms/modules/productProcess/web/model/SaveProductProcessRequest.kt +++ b/src/main/java/com/ffii/fpsms/modules/productProcess/web/model/SaveProductProcessRequest.kt @@ -161,8 +161,10 @@ data class AllJoborderProductProcessInfoResponse( val date: LocalDate?, val bomId: Long?, val itemName: String?, + val itemCode: String?, val matchStatus: String?, val RequiredQty: Int?, + val Uom: String?, val jobOrderId: Long?, val jobOrderCode: String?, val assignedTo: Long?, diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt index f81d440..12ac003 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt @@ -6,7 +6,7 @@ import com.ffii.fpsms.modules.stock.entity.projection.StockInLineInfo import org.springframework.data.jpa.repository.Query import org.springframework.stereotype.Repository import java.util.Optional - +import java.time.LocalDate @Repository interface StockInLineRepository : AbstractRepository { fun findAllStockInLineInfoByStockInIdAndDeletedFalse(stockInId: Long): List @@ -23,4 +23,12 @@ interface StockInLineRepository : AbstractRepository { @Query("SELECT sil FROM StockInLine sil WHERE sil.item.id = :itemId AND sil.deleted = false") fun findAllByItemIdAndDeletedFalse(itemId: Long): List + + @Query(""" + SELECT sil FROM StockInLine sil + WHERE sil.receiptDate IS NOT NULL + AND DATE(sil.receiptDate) = :date + AND sil.deleted = false +""") +fun findByReceiptDateAndDeletedFalse(date: LocalDate): List } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt index 084b968..83335fa 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt @@ -421,10 +421,18 @@ open class StockInLineService( if (inventoryLotLines.sumOf { it.inQty ?: BigDecimal.ZERO } >= request.acceptQty?.times(ratio)) { stockInLine.apply { - this.status = if (request.acceptQty?.compareTo(request.acceptedQty) == 0) - StockInLineStatus.COMPLETE.status else StockInLineStatus.PARTIALLY_COMPLETE.status -// this.inventoryLotLine = savedInventoryLotLine - } + val isWipJobOrder = stockInLine.jobOrder?.bom?.description == "WIP" + this.status = if (isWipJobOrder) { + StockInLineStatus.COMPLETE.status + } else { + // For non-WIP, use original logic + if (request.acceptQty?.compareTo(request.acceptedQty) == 0) + StockInLineStatus.COMPLETE.status + else + StockInLineStatus.PARTIALLY_COMPLETE.status + } + // this.inventoryLotLine = savedInventoryLotLine + } // Update JO Status if (stockInLine.jobOrder != null) { //TODO Improve val jo = stockInLine.jobOrder