From a99979d3775dd54252b6b7e0747063d12e92bf4d Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Tue, 6 Oct 2026 11:10:06 +0800 Subject: [PATCH] dosearch not allow input withour date. if 4/F truck is not match that day count as truck X truck x tab have warn mesage --- .../service/DeliveryOrderService.kt | 151 ++++-------------- .../web/DeliveryOrderController.kt | 1 + .../web/models/ReleaseDoRequest.kt | 2 + 3 files changed, 38 insertions(+), 116 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt index cee583ca..ca55a0ce 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt @@ -350,9 +350,10 @@ open class DeliveryOrderService( truckLanceCode: String?, floor: String? = null, isExtra: Boolean? = null, + excludeUnassignedTruck: Boolean = false, ): RecordsRes { val mode = TruckLaneSearchSpec.parse(truckLanceCode) - if (mode is TruckLaneSearchSpec.Mode.NoFilter) { + if (mode is TruckLaneSearchSpec.Mode.NoFilter && !excludeUnassignedTruck) { return searchDoLiteByPage( code, shopName, @@ -371,7 +372,10 @@ open class DeliveryOrderService( val etaStart = estimatedArrivalDate val etaEnd = estimatedArrivalDate?.plusDays(1) - val lanePredicate: (String?) -> Boolean = { lane -> TruckLaneSearchSpec.matches(mode, lane) } + val lanePredicate: (String?) -> Boolean = { lane -> + TruckLaneSearchSpec.matches(mode, lane) && + (!excludeUnassignedTruck || !TruckLaneSearchSpec.isUnassignedResolvedLane(lane)) + } val matched = scanDoLiteSupplierFilteredWithLanePredicate( code = code?.ifBlank { null }, shopName = shopName?.ifBlank { null }, @@ -2231,62 +2235,16 @@ val inventoryLotLine = illId?.let { inventoryLotLineMap[it] } println(" - Preferred floor: $preferredFloor") val truck = deliveryOrder.shop?.id?.let { shopId -> - val trucks = truckRepository.findByShopIdAndDeletedFalse(shopId) - val preferredStoreId = when (preferredFloor) { - "2F" -> "2F" - "4F" -> "4F" - "3F" -> "3F" - else -> "2F" - } - - val matchedTrucks = trucks.filter { it.storeId == preferredStoreId } - - if (matchedTrucks.isEmpty()) { + val eta = deliveryOrder.estimatedArrivalDate?.toLocalDate() + if (preferredFloor == "4F" && eta == null) { null } else { - if (preferredStoreId == "4F" && matchedTrucks.size > 1) { - deliveryOrder.estimatedArrivalDate?.let { estimatedArrivalDate -> - val targetDate = estimatedArrivalDate.toLocalDate() - val dayOfWeek = targetDate.dayOfWeek - - val dayAbbr = when (dayOfWeek) { - java.time.DayOfWeek.MONDAY -> "Mon" - java.time.DayOfWeek.TUESDAY -> "Tue" - java.time.DayOfWeek.WEDNESDAY -> "Wed" - java.time.DayOfWeek.THURSDAY -> "Thu" - java.time.DayOfWeek.FRIDAY -> "Fri" - java.time.DayOfWeek.SATURDAY -> "Sat" - java.time.DayOfWeek.SUNDAY -> "Sun" - } - - println(" DEBUG: DO ${deliveryOrder.id} - Target date: $targetDate ($dayAbbr), Shop: $shopId") - println(" DEBUG: Found ${matchedTrucks.size} matched 4F trucks") - - val dayMatchedTrucks = matchedTrucks.filter { - it.truckLanceCode?.contains(dayAbbr, ignoreCase = true) == true - } - - println(" DEBUG: Found ${dayMatchedTrucks.size} trucks matching $dayAbbr") - dayMatchedTrucks.forEach { t -> - println(" - Truck ID=${t.id}, Code=${t.truckLanceCode}, Time=${t.departureTime}") - } - - if (dayMatchedTrucks.isNotEmpty()) { - val selected = dayMatchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } - println("✅ DEBUG: Selected truck matching $dayAbbr - ID=${selected?.id}, Code=${selected?.truckLanceCode}") - selected - } else { - println("⚠️ WARNING: No truck matching $dayAbbr, using first available truck") - matchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } - } - } ?: run { - matchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } - } - } else { - matchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } - } + resolveTruckForShopFloorAndDay( + shopId, + preferredFloor, + getDayOfWeekAbbr(eta ?: LocalDate.now()), + ) } - } val defaultTruckId = 5577L val effectiveTruck = truck ?: truckRepository.findById(defaultTruckId).orElse(null) @@ -2396,46 +2354,15 @@ val inventoryLotLine = illId?.let { inventoryLotLineMap[it] } val preferredFloor = preferredStoreFloorForSupplier(supplierCode, floorSuppliers2F, floorSuppliers4F) val truck = deliveryOrder.shop?.id?.let { shopId -> - val trucks = truckRepository.findByShopIdAndDeletedFalse(shopId) - val preferredStoreId = when (preferredFloor) { - "2F" -> "2F" - "4F" -> "4F" - "3F" -> "3F" - else -> "2F" - } - - val matchedTrucks = trucks.filter { it.storeId == preferredStoreId } - if (matchedTrucks.isEmpty()) { + val eta = deliveryOrder.estimatedArrivalDate?.toLocalDate() + if (preferredFloor == "4F" && eta == null) { null } else { - if (preferredStoreId == "4F" && matchedTrucks.size > 1) { - deliveryOrder.estimatedArrivalDate?.let { estimatedArrivalDate -> - val targetDate2 = estimatedArrivalDate.toLocalDate() - val dayAbbr = when (targetDate2.dayOfWeek) { - java.time.DayOfWeek.MONDAY -> "Mon" - java.time.DayOfWeek.TUESDAY -> "Tue" - java.time.DayOfWeek.WEDNESDAY -> "Wed" - java.time.DayOfWeek.THURSDAY -> "Thu" - java.time.DayOfWeek.FRIDAY -> "Fri" - java.time.DayOfWeek.SATURDAY -> "Sat" - java.time.DayOfWeek.SUNDAY -> "Sun" - } - - val dayMatchedTrucks = matchedTrucks.filter { - it.truckLanceCode?.contains(dayAbbr, ignoreCase = true) == true - } - - if (dayMatchedTrucks.isNotEmpty()) { - dayMatchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } - } else { - matchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } - } - } ?: run { - matchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } - } - } else { - matchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } - } + resolveTruckForShopFloorAndDay( + shopId, + preferredFloor, + getDayOfWeekAbbr(eta ?: LocalDate.now()), + ) } } @@ -2563,7 +2490,7 @@ val inventoryLotLine = illId?.let { inventoryLotLineMap[it] } /** * 依店鋪 + 揀貨樓層解析當日應顯示之車線。 * - **2F**(P07/P06D/P06Y):`TruckLanceCode` 多為 `車線-…` 且不含星期縮寫,不依 `LIKE '%Mon%'` 篩選;取該店該樓層未刪除車輛中出發時間最早者。 - * - **4F**(P06B):維持以星期縮寫篩選 [TruckRepository.findByShopIdAndStoreIdAndDayOfWeek];無命中時再退回同樓層最早出發。 + * - **4F**(P06B):只取車線代碼含當天星期的車。沒有對到當天車時回傳 null,搜尋顯示為車線-X,不退回其他日子的車。 */ private fun resolveTruckForShopFloorAndDay( shopId: Long, @@ -2575,13 +2502,16 @@ val inventoryLotLine = illId?.let { inventoryLotLineMap[it] } .filter { it.storeId == preferredFloor } .minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } } - val trucks = truckRepository.findByShopIdAndStoreIdAndDayOfWeek(shopId, preferredFloor, dayAbbr) - return if (trucks.isEmpty()) { + val dayMatched = truckRepository.findByShopIdAndStoreIdAndDayOfWeek(shopId, preferredFloor, dayAbbr) + if (preferredFloor == "4F") { + return dayMatched.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } + } + return if (dayMatched.isEmpty()) { truckRepository.findByShopIdAndDeletedFalse(shopId) .filter { it.storeId == preferredFloor } .minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } } else { - trucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } + dayMatched.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } } } @@ -2598,31 +2528,20 @@ val inventoryLotLine = illId?.let { inventoryLotLineMap[it] } open fun check4FTruckAvailabilityForDoList(doIds: List): Check4FTruckBatchResponse { val problems = mutableListOf() + val (floorSuppliers2F, floorSuppliers4F) = loadDoFloorSupplierLists() doIds.forEach { doId -> val deliveryOrder = deliveryOrderRepository.findByIdAndDeletedIsFalse(doId) ?: return@forEach val shopId = deliveryOrder.shop?.id ?: return@forEach val eta = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: return@forEach - // 1) Check if this DO is a 4F order (your “all items on 4F, no 2F” rule) - val sql = """ - SELECT - COUNT(DISTINCT CASE WHEN i.store_id = '4F' THEN dol.itemId END) AS count_4f, - COUNT(DISTINCT CASE WHEN i.store_id = '2F' THEN dol.itemId END) AS count_2f, - COUNT(DISTINCT dol.itemId) AS total_items - FROM fpsmsdb.delivery_order_line dol - INNER JOIN fpsmsdb.items i ON i.id = dol.itemId AND i.deleted = 0 - WHERE dol.deliveryOrderId = :doId AND dol.deleted = 0 - """.trimIndent() - - val res = jdbcDao.queryForList(sql, mapOf("doId" to doId)).firstOrNull() ?: return@forEach - val count4F = (res["count_4f"] as? Number)?.toInt() ?: 0 - val count2F = (res["count_2f"] as? Number)?.toInt() ?: 0 - val totalItems = (res["total_items"] as? Number)?.toInt() ?: 0 - - val is4FOrder = (totalItems > 0 && count4F == totalItems && count2F == 0) - if (!is4FOrder) { - // Not a 4F order → no problem, skip + // Same floor rule as release: supplier code (P06B → 4F), not item store_id. + val preferredFloor = preferredStoreFloorForSupplier( + deliveryOrder.supplier?.code, + floorSuppliers2F, + floorSuppliers4F, + ) + if (preferredFloor != "4F") { return@forEach } diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt index 5d11e4f1..c1a20208 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt @@ -113,6 +113,7 @@ class DeliveryOrderController( truckLanceCode = request.truckLanceCode, floor = request.floor, isExtra = request.isExtra, + excludeUnassignedTruck = request.excludeUnassignedTruck == true, ) } diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/ReleaseDoRequest.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/ReleaseDoRequest.kt index 5c827a8a..39204a31 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/ReleaseDoRequest.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/ReleaseDoRequest.kt @@ -36,4 +36,6 @@ data class SearchDeliveryOrderInfoRequest( val floor: String? = null, /** null:不篩 isExtra;true/false:只顯示加單或非加單 DO */ val isExtra: Boolean? = null, + /** true:排除推算車線為空白或「車線-X」的送貨單(2/F、4/F 分頁)。 */ + val excludeUnassignedTruck: Boolean? = null, )