From 2c17ee7ab1a6962ad9887436d19c1d428e0ebaac Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Tue, 21 Apr 2026 23:02:24 +0800 Subject: [PATCH] update 4F handler name --- .../service/DoPickOrderQueryService.kt | 150 +++++++++--------- .../web/models/DoDetailResponse.kt | 16 +- 2 files changed, 89 insertions(+), 77 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt index 94a349a..a92e31a 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt @@ -9,6 +9,7 @@ import com.ffii.fpsms.modules.deliveryOrder.web.models.StoreLaneSummary import com.ffii.fpsms.modules.deliveryOrder.web.models.DoPickOrderSummaryItem import org.springframework.stereotype.Service import java.time.LocalDate +import java.time.LocalTime import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecordRepository import com.ffii.fpsms.modules.pickOrder.entity.TruckRepository @Service @@ -21,48 +22,40 @@ class DoPickOrderQueryService( fun getSummaryByStore(storeId: String, requiredDate: LocalDate?, releaseType: String): StoreLaneSummary { val targetDate = requiredDate ?: LocalDate.now() - //println(" DEBUG: Getting summary for store=$storeId, date=$targetDate, releaseType=$releaseType") - + val actualStoreId = when (storeId) { "2/F" -> "2/F" "4/F" -> "4/F" else -> storeId } - - // Query active do_pick_order records (pending, released, completed that haven't been moved yet) + + // Active: do_pick_order val activeRecords = doPickOrderRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( actualStoreId, targetDate, listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed) ) - - // 根据 releaseType 过滤 activeRecords + val filteredActiveRecordsByReleaseType = when (releaseType.lowercase()) { "batch" -> activeRecords.filter { it.releaseType == "batch" } "single" -> activeRecords.filter { it.releaseType == "single" } - else -> activeRecords // "all" 或其他值,不过滤 + else -> activeRecords } - - // Query completed records from do_pick_order_record table + + // Completed archive: do_pick_order_record val completedRecords = doPickOrderRecordRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( actualStoreId, targetDate, listOf(DoPickOrderStatus.completed) ) - - // 根据 releaseType 过滤 completedRecords + val filteredCompletedRecordsByReleaseType = when (releaseType.lowercase()) { "batch" -> completedRecords.filter { it.releaseType == "batch" } "single" -> completedRecords.filter { it.releaseType == "single" } - else -> completedRecords // "all" 或其他值,不过滤 + else -> completedRecords } - - //println(" DEBUG: Found ${activeRecords.size} active records for date $targetDate") - // println(" DEBUG: After releaseType filter: ${filteredActiveRecordsByReleaseType.size} active records") - //println(" DEBUG: Found ${completedRecords.size} completed records for date $targetDate") - //println(" DEBUG: After releaseType filter: ${filteredCompletedRecordsByReleaseType.size} completed records") - - // Filter active records (check for non-issue lines) + + // non-issue filter val filteredActiveRecords = filteredActiveRecordsByReleaseType.filter { doPickOrder -> val hasNonIssueLines = checkDoPickOrderHasNonIssueLines(doPickOrder.id!!) if (!hasNonIssueLines) { @@ -70,8 +63,7 @@ class DoPickOrderQueryService( } hasNonIssueLines } - - // For completed records, check if they have non-issue lines in the record table + val filteredCompletedRecords = filteredCompletedRecordsByReleaseType.filter { record -> val hasNonIssueLines = checkDoPickOrderRecordHasNonIssueLines(record.id!!) if (!hasNonIssueLines) { @@ -79,84 +71,100 @@ class DoPickOrderQueryService( } hasNonIssueLines } - - // Combine both lists - need to create a common interface or convert to a common type - // Since both have the same fields we need, we can create a wrapper or use a data class - val allRecords = filteredActiveRecords.map { + + // 合并为 summary item + // 你的要求是 handler 来源用 delivery_order_pick_order.handlerName + // 所以 active records 用 it.handlerName;completed records 这里给 null,避免混入 archive 来源 + val allRecords = filteredActiveRecords.map { DoPickOrderSummaryItem( truckDepartureTime = it.truckDepartureTime, truckLanceCode = it.truckLanceCode, - // 只對 4/F 顯示/分組 loadingSequence;2/F 維持舊邏輯避免同車線被拆成多序 loadingSequence = if (actualStoreId == "4/F") it.loadingSequence else null, - handledBy = it.handledBy + handledBy = it.handledBy, + handlerName = it.handlerName ) } + filteredCompletedRecords.map { DoPickOrderSummaryItem( truckDepartureTime = it.truckDepartureTime, truckLanceCode = it.truckLanceCode, loadingSequence = if (actualStoreId == "4/F") it.loadingSequence else null, - handledBy = it.handledBy + handledBy = it.handledBy, + handlerName = null ) } + val defaultTruckId = 5577L val defaultTruck = truckRepository.findById(defaultTruckId).orElse(null) val defaultTruckLaneCode = defaultTruck?.truckLanceCode ?: "" - //println(" DEBUG: After filtering, ${allRecords.size} records remain (${filteredActiveRecords.size} active + ${filteredCompletedRecords.size} completed)") - + val grouped = if (actualStoreId == "4/F") { allRecords.groupBy { Triple(it.truckDepartureTime, it.truckLanceCode, it.loadingSequence) } } else { - // 2/F:回到舊分組(truckDepartureTime + truckLanceCode) allRecords.groupBy { Pair(it.truckDepartureTime, it.truckLanceCode) } }.mapValues { (_, list) -> + val mergedHandlerNames = list + .mapNotNull { it.handlerName?.trim()?.takeIf { n -> n.isNotEmpty() } } + .distinct() + .sorted() + .joinToString(",") + LaneBtn( truckLanceCode = list.first().truckLanceCode ?: "", loadingSequence = if (actualStoreId == "4/F") list.first().loadingSequence else null, unassigned = list.count { it.handledBy == null }, - total = list.size + total = list.size, + handlerName = mergedHandlerNames.ifBlank { null } ) } - val filteredGrouped = grouped - .filter { (_, laneBtn) -> - laneBtn.truckLanceCode != defaultTruckLaneCode - } - val timeGroups = filteredGrouped.entries - .groupBy { (it.key as? Triple<*, *, *>)?.first as? java.time.LocalTime ?: (it.key as Pair<*, *>).first as java.time.LocalTime? } - .mapValues { (_, entries) -> - entries.map { it.value } - .filter { it.unassigned > 0 } // filter out lanes with no unassigned orders - .sortedWith( - compareByDescending { it.unassigned } - .thenBy { it.truckLanceCode } - .thenBy { it.loadingSequence ?: 999 } - ) - } - .filterValues { lanes -> lanes.isNotEmpty() } - .toSortedMap(compareBy { it }) - .entries.take(4) - .map { (time, lanes) -> - LaneRow( - truckDepartureTime = time?.toString() ?: "", - lanes = lanes - ) - } - val defaultTruckCandidates = doPickOrderRepository.findByRequiredDeliveryDateAndTicketStatusIn( - targetDate, - listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released) - ) - - // 只算:storeId = null 且 truckLanceCode = '車線-X' - val defaultTruckCount = defaultTruckCandidates.count { - it.storeId == null && it.truckLanceCode == "車線-X" - } - - // 9) 回傳 summary,附帶 defaultTruckCount - return StoreLaneSummary( - storeId = storeId, - rows = timeGroups, - defaultTruckCount = defaultTruckCount + + val filteredGrouped = grouped.filter { (_, laneBtn) -> + laneBtn.truckLanceCode != defaultTruckLaneCode + } + + val groupedByTime: Map>> = + filteredGrouped.entries.groupBy { entry: Map.Entry -> + when (val key = entry.key) { + is Triple<*, *, *> -> key.first as? LocalTime + is Pair<*, *> -> key.first as? LocalTime + else -> null + } + } + +val timeGroups = groupedByTime + .mapValues { (_, entries: List>) -> + entries.map { it.value } + .sortedWith( + compareByDescending { it.unassigned } + .thenBy { it.truckLanceCode } + .thenBy { it.loadingSequence ?: 999 } ) } + .filterValues { lanes -> lanes.isNotEmpty() } + .toSortedMap(compareBy { it }) + .entries + .take(4) + .map { (time, lanes) -> + LaneRow( + truckDepartureTime = time?.toString() ?: "", + lanes = lanes + ) + } + + val defaultTruckCandidates = doPickOrderRepository.findByRequiredDeliveryDateAndTicketStatusIn( + targetDate, + listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released) + ) + + val defaultTruckCount = defaultTruckCandidates.count { + it.storeId == null && it.truckLanceCode == "車線-X" + } + + return StoreLaneSummary( + storeId = storeId, + rows = timeGroups, + defaultTruckCount = defaultTruckCount + ) + } private fun checkDoPickOrderHasNonIssueLines(doPickOrderId: Long): Boolean { diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/DoDetailResponse.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/DoDetailResponse.kt index f52517d..768e3f1 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/DoDetailResponse.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/DoDetailResponse.kt @@ -47,7 +47,9 @@ data class LaneBtn( val truckLanceCode: String, val loadingSequence: Int? = null, val unassigned: Int, - val total: Int + val total: Int, + // 同一 truckLanceCode + loadingSequence 的 handler 去重后逗号拼接 + val handlerName: String? = null ) data class AssignByLaneRequest( val userId: Long, @@ -58,11 +60,13 @@ data class AssignByLaneRequest( val requiredDate: LocalDate? // 必填:车道编号 ) data class DoPickOrderSummaryItem( - val truckDepartureTime: java.time.LocalTime?, - val truckLanceCode: String?, - val loadingSequence: Int?, - val handledBy: Long? - ) + val truckDepartureTime: java.time.LocalTime?, + val truckLanceCode: String?, + val loadingSequence: Int?, + val handledBy: Long?, + // 来源:delivery_order_pick_order.handlerName + val handlerName: String? = null +) data class DoSearchRow( val id: Long, val code: String?,