| @@ -517,8 +517,10 @@ open class ProductProcessService( | |||
| line.handler = user | |||
| line.startTime = LocalDateTime.now() | |||
| line.status = "InProgress" | |||
| val saved = productProcessLineRepository.save(line) | |||
| syncProductProcessStatusFromLines(saved.productProcess.id) | |||
| println(" Service: Line started, handlerId: ${saved.handler?.id}") | |||
| return saved | |||
| } | |||
| @@ -1163,6 +1165,7 @@ open class ProductProcessService( | |||
| } | |||
| productProcessLine.startTime = LocalDateTime.now() | |||
| productProcessLineRepository.save(productProcessLine) | |||
| syncProductProcessStatusFromLines(productProcessLine.productProcess?.id ?: 0L) | |||
| return MessageResponse( | |||
| id = null, | |||
| code = null, | |||
| @@ -1249,8 +1252,7 @@ open class ProductProcessService( | |||
| // productProcessLine.endTime = LocalDateTime.now() | |||
| productProcessLineRepository.save(productProcessLine) | |||
| println(" Service: ProductProcessLine Status Updated: ${productProcessLine.status}") | |||
| CompleteProductProcessStatusIfAllLinesCompleted(productProcessLine.productProcess?.id ?: 0) | |||
| syncProductProcessStatusFromLines(productProcessLine.productProcess?.id ?: 0L) | |||
| return MessageResponse( | |||
| id = productProcessLineId, | |||
| @@ -1285,10 +1287,8 @@ open class ProductProcessService( | |||
| // 更新状态为 "Pass" | |||
| updateProductProcessLineStatus(productProcessLineId, "Pass") | |||
| // 检查是否所有 lines 都完成(Completed 或 Pass) | |||
| // 注意:这里应该传入 productProcessId,而不是 productProcessLineId | |||
| val productProcessId = productProcessLine?.productProcess?.id ?: 0L | |||
| ifAllLinesCompletedOrPassed(productProcessId) | |||
| syncProductProcessStatusFromLines(productProcessId) | |||
| return MessageResponse( | |||
| id = productProcessLineId, | |||
| @@ -1940,24 +1940,68 @@ open class ProductProcessService( | |||
| ) | |||
| } | |||
| private fun normalizeLineStatus(status: String?): String = | |||
| status?.trim()?.lowercase()?.replace(" ", "") ?: "" | |||
| private fun isLineDone(status: String?): Boolean { | |||
| val n = normalizeLineStatus(status) | |||
| return n == "completed" || n == "pass" | |||
| } | |||
| private fun isLineActive(status: String?): Boolean { | |||
| val n = normalizeLineStatus(status) | |||
| return n == "inprogress" || n == "paused" | |||
| } | |||
| /** | |||
| * Align parent [ProductProcess.status] with all line states. | |||
| * - All Completed/Pass -> completed (via [ifAllLinesCompletedOrPassed]) | |||
| * - Any line started but not all done -> in_progress | |||
| * - Does not override STOPPED or CANCELLED on the parent. | |||
| */ | |||
| open fun syncProductProcessStatusFromLines(productProcessId: Long) { | |||
| if (productProcessId <= 0L) return | |||
| val productProcess = productProcessRepository.findById(productProcessId).orElse(null) ?: return | |||
| if (productProcess.status == ProductProcessStatus.STOPPED || | |||
| productProcess.status == ProductProcessStatus.CANCELLED | |||
| ) { | |||
| return | |||
| } | |||
| val lines = productProcessLineRepository.findByProductProcess_Id(productProcessId) | |||
| if (lines.isEmpty()) return | |||
| if (lines.all { isLineDone(it.status) }) { | |||
| ifAllLinesCompletedOrPassed(productProcessId) | |||
| return | |||
| } | |||
| val anyStarted = lines.any { line -> | |||
| isLineActive(line.status) || | |||
| isLineDone(line.status) || | |||
| line.startTime != null | |||
| } | |||
| if (anyStarted) { | |||
| if (productProcess.startTime == null) { | |||
| productProcess.startTime = | |||
| lines.mapNotNull { it.startTime }.minOrNull() ?: LocalDateTime.now() | |||
| } | |||
| if (productProcess.status != ProductProcessStatus.IN_PROGRESS) { | |||
| productProcess.status = ProductProcessStatus.IN_PROGRESS | |||
| } | |||
| productProcessRepository.save(productProcess) | |||
| } | |||
| } | |||
| open fun StartProductProcessLine(productProcessLineId: Long): MessageResponse { | |||
| updateProductProcessLineStartTime(productProcessLineId) | |||
| //updateProductProcessLineStatus(productProcessLineId, "InProgress") | |||
| val productProcessLine = productProcessLineRepository.findById(productProcessLineId).orElse(null) | |||
| val allproductProcessLines = | |||
| productProcessLineRepository.findByProductProcess_Id(productProcessLine.productProcess?.id ?: 0L) | |||
| if (allproductProcessLines.all { it.status == "Pending" }) { | |||
| updateProductProcessLineStatus(productProcessLineId, "InProgress") | |||
| updateProductProcessStartTime(productProcessLine.productProcess.id) | |||
| updateProductProcessStatus(productProcessLine.productProcess.id, ProductProcessStatus.IN_PROGRESS) | |||
| } else { | |||
| updateProductProcessLineStatus(productProcessLineId, "InProgress") | |||
| println(" Service: ProductProcess Lines are not Pending") | |||
| println(" Service: ProductProcess Lines: ${allproductProcessLines.map { it.status }}") | |||
| println(" Service: ProductProcess Line: ${productProcessLine.status}") | |||
| } | |||
| updateProductProcessLineStartTime(productProcessLineId) | |||
| updateProductProcessLineStatus(productProcessLineId, "InProgress") | |||
| val productProcessId = productProcessLine?.productProcess?.id ?: 0L | |||
| syncProductProcessStatusFromLines(productProcessId) | |||
| return MessageResponse( | |||
| id = productProcessLine.id, | |||
| id = productProcessLine?.id, | |||
| code = "200", | |||
| name = "ProductProcess StartTime Updated", | |||
| type = "success", | |||
| @@ -1976,47 +2020,7 @@ open class ProductProcessService( | |||
| productProcessLine.startTime = LocalDateTime.now() | |||
| productProcessLineRepository.save(productProcessLine) | |||
| } | |||
| if (allproductProcessLines.all { it.status == "Completed" || it.status == "Pass" }) { | |||
| updateProductProcessEndTime(productProcessId) | |||
| updateProductProcessStatus(productProcessId, ProductProcessStatus.COMPLETED) | |||
| val productProcess = productProcessRepository.findById(productProcessId).orElse(null) | |||
| val jobOrder = jobOrderRepository.findById(productProcess?.jobOrder?.id ?: 0L).orElse(null) | |||
| if (jobOrder != null) { | |||
| jobOrder.status = JobOrderStatus.STORING | |||
| jobOrderRepository.save(jobOrder) | |||
| val existingSil = jobOrder.id?.let { stockInLineRepository.findFirstByJobOrder_IdAndDeletedFalse(it) } | |||
| if (existingSil != null) { | |||
| stockInLineService.update( | |||
| SaveStockInLineRequest( | |||
| id = existingSil.id, | |||
| itemId = existingSil.item?.id ?: productProcess?.item?.id ?: 0L, | |||
| acceptedQty = jobOrder.reqQty ?: BigDecimal.ZERO, | |||
| acceptQty = jobOrder.reqQty ?: BigDecimal.ZERO, | |||
| productLotNo = jobOrder.code, | |||
| productionDate = LocalDate.now(), | |||
| jobOrderId = jobOrder.id, | |||
| expiryDate = null, | |||
| status = "pending", | |||
| receiptDate = null, | |||
| ) | |||
| ) | |||
| } else { | |||
| stockInLineService.create( | |||
| SaveStockInLineRequest( | |||
| itemId = productProcess?.item?.id ?: 0L, | |||
| acceptedQty = jobOrder?.reqQty ?: BigDecimal.ZERO, | |||
| productLotNo = jobOrder?.code, | |||
| productionDate = LocalDate.now(), | |||
| jobOrderId = jobOrder.id, | |||
| acceptQty = jobOrder?.reqQty ?: BigDecimal.ZERO, | |||
| expiryDate = null, | |||
| status = "pending", | |||
| ) | |||
| ) | |||
| } | |||
| } | |||
| } | |||
| syncProductProcessStatusFromLines(productProcessId) | |||
| return MessageResponse( | |||
| id = productProcessLine.id, | |||
| code = "200", | |||
| @@ -2144,6 +2148,7 @@ open class ProductProcessService( | |||
| productionProcessIssueRepository.save(productProcessLineIssue) | |||
| productProcessLine.status = "InProgress" | |||
| productProcessLineRepository.save(productProcessLine) | |||
| syncProductProcessStatusFromLines(productProcessLine.productProcess?.id ?: 0L) | |||
| return MessageResponse( | |||
| id = 0, | |||