From e70712049619d03ef744ddceb3381bffbb7bd945 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Sun, 9 Aug 2026 22:11:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8C=85=E8=A3=9D=20Complete/Pass=20=E2=86=92?= =?UTF-8?q?=20=E5=90=8C=20JO=20=E5=85=B6=E4=BB=96=E5=8C=85=E8=A3=9D=20auto?= =?UTF-8?q?=20Pass=20QC=20ready=20=E6=94=B9=E6=88=90=E3=80=8C=E5=85=A8?= =?UTF-8?q?=E9=83=A8=20line=20done=E3=80=8D=EF=BC=88=E6=8B=BF=E6=8E=89?= =?UTF-8?q?=E3=80=8C=E4=BB=BB=E4=B8=80=E5=8C=85=E8=A3=9D=E5=8D=B3=E5=8F=AF?= =?UTF-8?q?=E3=80=8D=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ProductProcessService.kt | 71 ++++++++++++++++--- 1 file changed, 61 insertions(+), 10 deletions(-) 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 0a35199..51f0ac8 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 @@ -85,6 +85,10 @@ open class ProductProcessService( private val stockInLineRepository: StockInLineRepository, private val qcResultRepository: QcResultRepository, ) { + companion object { + private const val PACKAGING_PROCESS_NAME = "包裝" + private const val DRINK_PLANNED_LOOKBACK_DAYS = 30L + } open fun findAll(pageable: Pageable): Page { println(" Service: Finding all ProductProcess with page: ${pageable.pageNumber}, size: ${pageable.pageSize}") @@ -1246,6 +1250,7 @@ open class ProductProcessService( ) } + /** FP-MTMS Version Checklist | Functions Ref. No. 58 | v1.0.0 | 2026-08-09 */ open fun updateProductProcessLineStatus(productProcessLineId: Long, status: String): MessageResponse { println(" Service: Updating ProductProcessLine Status: $productProcessLineId") val productProcessLine = productProcessLineRepository.findById(productProcessLineId).orElse(null) @@ -1254,6 +1259,12 @@ open class ProductProcessService( // productProcessLine.endTime = LocalDateTime.now() productProcessLineRepository.save(productProcessLine) println(" Service: ProductProcessLine Status Updated: ${productProcessLine.status}") + + // One packaging Complete/Pass → auto-Pass remaining packaging lines on the same JO. + if (isLineDone(status) && isPackagingLine(productProcessLine)) { + autoPassSiblingPackagingLines(productProcessLineId) + } + syncProductProcessStatusFromLines(productProcessLine.productProcess?.id ?: 0L) return MessageResponse( @@ -1500,8 +1511,9 @@ open class ProductProcessService( } /** - * FP-MTMS Version Checklist | Functions Ref. No. 41 | v1.0.1 | 2026-08-06 + * FP-MTMS Version Checklist | Functions Ref. No. 41 | v1.0.2 | 2026-08-09 * QC 列表:按 jobOrder 粒度分页,qcReady 由该 jobOrder 下所有 productProcessLine 是否全部 Completed/Pass 决定。 + * (包裝 Complete/Pass 時會自動 Pass 同 JO 其餘包裝 line,因此不再需要「任一包裝即可」特例。) * * 注意:date/itemCode/jobOrderCode/bomIds 用来筛选“候选 jobOrder”,但 qcReady 判断会用该 jobOrder 下全部 productProcessLine。 */ @@ -1682,14 +1694,11 @@ open class ProductProcessService( } + // After packaging Complete/Pass auto-passes sibling 包裝 lines, qcReady is simply all lines done. val jobLines = linesByJobOrder[jobOrderId].orEmpty() - val packing = jobLines.filter { (it.name ?: "").trim() == "包裝" } - val nonPacking = jobLines.filter { (it.name ?: "").trim() != "包裝" } - - val nonPackingOk = nonPacking.isEmpty() || nonPacking.all { done(it.status) } - val packingOk = packing.isEmpty() || packing.any { done(it.status) } + val allLinesDone = jobLines.isNotEmpty() && jobLines.all { done(it.status) } - val ready = includedInList && stockInLine != null && nonPackingOk && packingOk + val ready = includedInList && stockInLine != null && allLinesDone JobOrderQcKey( jobOrderId = jobOrderId, @@ -2119,6 +2128,51 @@ open class ProductProcessService( return n == "inprogress" || n == "paused" } + /** FP-MTMS Version Checklist | Functions Ref. No. 58 | v1.0.0 | 2026-08-09 */ + private fun isPackagingLine(line: ProductProcessLine): Boolean = + (line.name ?: "").trim() == PACKAGING_PROCESS_NAME + + /** + * FP-MTMS Version Checklist | Functions Ref. No. 58 | v1.0.0 | 2026-08-09 + * When one 包裝 line is Completed/Pass, auto-Pass other unfinished 包裝 lines on the same job order, + * then sync each affected ProductProcess.status (Pass counts as done → COMPLETED). + */ + private fun autoPassSiblingPackagingLines(triggerLineId: Long) { + val trigger = productProcessLineRepository.findById(triggerLineId).orElse(null) ?: return + if (!isPackagingLine(trigger)) return + + val jobOrderId = trigger.productProcess?.jobOrder?.id ?: return + val processes = productProcessRepository.findByJobOrder_Id(jobOrderId) + .filter { it.deleted != true } + val processIds = processes.mapNotNull { it.id } + if (processIds.isEmpty()) return + + val allLines = productProcessLineRepository.findByProductProcess_IdIn(processIds) + val siblings = allLines.filter { line -> + line.id != null && + line.id != triggerLineId && + isPackagingLine(line) && + !isLineDone(line.status) + } + if (siblings.isEmpty()) return + + val now = LocalDateTime.now() + val affectedProcessIds = linkedSetOf() + for (line in siblings) { + if (line.startTime == null) { + line.startTime = now + } + line.endTime = now + line.status = "Pass" + productProcessLineRepository.save(line) + line.productProcess?.id?.let { affectedProcessIds.add(it) } + } + + for (processId in affectedProcessIds) { + syncProductProcessStatusFromLines(processId) + } + } + /** * Align parent [ProductProcess.status] with all line states. * - All Completed/Pass -> completed (via [ifAllLinesCompletedOrPassed]) @@ -2631,9 +2685,6 @@ open class ProductProcessService( } // ===== Drink Production Qty Dashboard ===== - private companion object { - const val DRINK_PLANNED_LOOKBACK_DAYS = 30L - } /** FP-MTMS Version Checklist | Functions Ref. No. 27 | v1.0.0 | 2026-07-20 */ open fun getDrinkProductionQty(