|
|
|
@@ -40,7 +40,7 @@ import com.ffii.fpsms.modules.master.service.PrinterService |
|
|
|
import java.time.format.DateTimeFormatter |
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.TruckRepository |
|
|
|
import java.time.LocalTime |
|
|
|
|
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.Truck |
|
|
|
import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository |
|
|
|
import com.ffii.fpsms.modules.stock.entity.StockOutRepository |
|
|
|
import com.ffii.fpsms.modules.stock.entity.StockOutLIneRepository |
|
|
|
@@ -113,47 +113,236 @@ open class DeliveryOrderService( |
|
|
|
private val itemsRepository: ItemsRepository |
|
|
|
) { |
|
|
|
open fun searchDoLiteByPage( |
|
|
|
code: String?, |
|
|
|
shopName: String?, |
|
|
|
status: String?, |
|
|
|
estimatedArrivalDate: LocalDateTime?, |
|
|
|
pageNum: Int?, |
|
|
|
pageSize: Int? |
|
|
|
): RecordsRes<DeliveryOrderInfoLiteDto> { |
|
|
|
|
|
|
|
val page = (pageNum ?: 1) - 1 // 如果你前端是 1-based;如果前端本来就是 0-based 就不要 -1 |
|
|
|
val size = pageSize ?: 10 |
|
|
|
val pageable = PageRequest.of(page.coerceAtLeast(0), size) |
|
|
|
|
|
|
|
val statusEnum = status?.let { s -> DeliveryOrderStatus.entries.find { it.value == s } } |
|
|
|
|
|
|
|
val etaStart = estimatedArrivalDate |
|
|
|
val etaEnd = estimatedArrivalDate?.plusDays(1) |
|
|
|
|
|
|
|
code: String?, |
|
|
|
shopName: String?, |
|
|
|
status: String?, |
|
|
|
estimatedArrivalDate: LocalDateTime?, |
|
|
|
pageNum: Int?, |
|
|
|
pageSize: Int?, |
|
|
|
truckLanceCode: String? |
|
|
|
): RecordsRes<DeliveryOrderInfoLiteDto> { |
|
|
|
|
|
|
|
val page = (pageNum ?: 1) - 1 |
|
|
|
val size = pageSize ?: 10 |
|
|
|
val statusEnum = status?.let { s -> DeliveryOrderStatus.entries.find { it.value == s } } |
|
|
|
|
|
|
|
val etaStart = estimatedArrivalDate |
|
|
|
val etaEnd = estimatedArrivalDate?.plusDays(1) |
|
|
|
|
|
|
|
val searchTruckLanceCode = truckLanceCode?.ifBlank { null }?.lowercase() |
|
|
|
|
|
|
|
if (searchTruckLanceCode != null) { |
|
|
|
println("DEBUG: Filtering by truckLanceCode: $searchTruckLanceCode") |
|
|
|
|
|
|
|
// ✅ 优化:先从 truck 表找到匹配的 truck,获取 Store_id 和 shopId |
|
|
|
val matchingTrucks = truckRepository.findAllByTruckLanceCodeContainingAndDeletedFalse(searchTruckLanceCode) |
|
|
|
println("DEBUG: Found ${matchingTrucks.size} matching trucks") |
|
|
|
|
|
|
|
// 收集所有匹配的 Store_id 和 shopId |
|
|
|
val matchingStoreIds = matchingTrucks.mapNotNull { it.storeId }.distinct() |
|
|
|
val matchingShopIds = matchingTrucks.mapNotNull { it.shop?.id }.distinct() |
|
|
|
|
|
|
|
println("DEBUG: Matching storeIds: $matchingStoreIds") |
|
|
|
println("DEBUG: Matching shopIds: ${matchingShopIds.size} shops") |
|
|
|
|
|
|
|
// 根据 Store_id 确定需要过滤的 supplier codes |
|
|
|
// Store_id = "2F" → supplier code != "P06B" |
|
|
|
// Store_id = "4F" → supplier code = "P06B" |
|
|
|
val supplierCodesToInclude = mutableSetOf<String?>() |
|
|
|
val supplierCodesToExclude = mutableSetOf<String?>() |
|
|
|
|
|
|
|
if (matchingStoreIds.contains("2F")) { |
|
|
|
supplierCodesToExclude.add("P06B") // 2F 排除 P06B |
|
|
|
} |
|
|
|
if (matchingStoreIds.contains("4F")) { |
|
|
|
supplierCodesToInclude.add("P06B") // 4F 只包含 P06B |
|
|
|
} |
|
|
|
|
|
|
|
// 查询符合条件的 DeliveryOrder(根据 supplier code 和 shopId 预过滤) |
|
|
|
// 注意:这里需要在 Repository 层面添加 supplier code 过滤 |
|
|
|
// 或者先查询所有,然后在代码层面过滤 |
|
|
|
|
|
|
|
val allResult = deliveryOrderRepository.searchDoLitePage( |
|
|
|
code = code?.ifBlank { null }, |
|
|
|
shopName = shopName?.ifBlank { null }, |
|
|
|
status = statusEnum, |
|
|
|
etaStart = etaStart, |
|
|
|
etaEnd = etaEnd, |
|
|
|
pageable = PageRequest.of(0, 100000) |
|
|
|
) |
|
|
|
|
|
|
|
println("DEBUG: Total records from DB before filtering: ${allResult.totalElements}") |
|
|
|
|
|
|
|
// ✅ 优化1: 批量查询所有 DeliveryOrder 实体 |
|
|
|
val deliveryOrderIds = allResult.content.mapNotNull { it.id } |
|
|
|
val deliveryOrdersMap = deliveryOrderRepository.findAllById(deliveryOrderIds) |
|
|
|
.associateBy { it.id } |
|
|
|
|
|
|
|
println("DEBUG: Loaded ${deliveryOrdersMap.size} delivery orders in batch") |
|
|
|
|
|
|
|
// ✅ 优化2: 预过滤 - 根据 supplier code 和 shopId 过滤 |
|
|
|
val preFilteredContent = allResult.content.filter { info -> |
|
|
|
val deliveryOrder = deliveryOrdersMap[info.id] |
|
|
|
val supplierCode = deliveryOrder?.supplier?.code |
|
|
|
|
|
|
|
// 检查 supplier code 是否匹配 |
|
|
|
val supplierMatches = when { |
|
|
|
supplierCodesToExclude.contains(supplierCode) -> false // 排除 |
|
|
|
supplierCodesToInclude.isNotEmpty() && !supplierCodesToInclude.contains(supplierCode) -> false // 只包含特定值 |
|
|
|
else -> true // 没有限制或匹配 |
|
|
|
} |
|
|
|
|
|
|
|
// 如果提供了 shopId 过滤,也检查 shopId |
|
|
|
val shopMatches = if (matchingShopIds.isNotEmpty()) { |
|
|
|
deliveryOrder?.shop?.id in matchingShopIds |
|
|
|
} else { |
|
|
|
true // 如果没有匹配的 shopId,不过滤 |
|
|
|
} |
|
|
|
|
|
|
|
supplierMatches && shopMatches |
|
|
|
} |
|
|
|
|
|
|
|
println("DEBUG: Pre-filtered records: ${preFilteredContent.size} (from ${allResult.content.size})") |
|
|
|
|
|
|
|
// ✅ 优化3: 收集所有需要查询的 shopId 和日期组合(只处理预过滤后的记录) |
|
|
|
val shopIdAndDatePairs = preFilteredContent.mapNotNull { info -> |
|
|
|
val deliveryOrder = deliveryOrdersMap[info.id] |
|
|
|
val shopId = deliveryOrder?.shop?.id |
|
|
|
val estimatedArrivalDate = info.estimatedArrivalDate |
|
|
|
if (shopId != null && estimatedArrivalDate != null) { |
|
|
|
val targetDate = estimatedArrivalDate.toLocalDate() |
|
|
|
val dayAbbr = getDayOfWeekAbbr(targetDate) |
|
|
|
val supplierCode = deliveryOrder.supplier?.code |
|
|
|
val preferredFloor = if (supplierCode == "P06B") "4F" else "2F" |
|
|
|
Triple(shopId, preferredFloor, dayAbbr) |
|
|
|
} else { |
|
|
|
null |
|
|
|
} |
|
|
|
}.distinct() |
|
|
|
|
|
|
|
println("DEBUG: Unique shopId/floor/day combinations: ${shopIdAndDatePairs.size}") |
|
|
|
|
|
|
|
// ✅ 优化4: 批量查询所有需要的 Truck |
|
|
|
val truckCache = mutableMapOf<Triple<Long, String, String>, Truck?>() |
|
|
|
shopIdAndDatePairs.forEach { (shopId, preferredFloor, dayAbbr) -> |
|
|
|
val trucks = truckRepository.findByShopIdAndStoreIdAndDayOfWeek(shopId, preferredFloor, dayAbbr) |
|
|
|
val matchedTruck = if (trucks.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) } |
|
|
|
} |
|
|
|
truckCache[Triple(shopId, preferredFloor, dayAbbr)] = matchedTruck |
|
|
|
} |
|
|
|
|
|
|
|
println("DEBUG: Cached ${truckCache.size} truck lookups") |
|
|
|
|
|
|
|
// 处理预过滤后的记录:计算 truckLanceCode 并过滤 |
|
|
|
val processedRecords = preFilteredContent.map { info -> |
|
|
|
val deliveryOrder = deliveryOrdersMap[info.id] |
|
|
|
val supplierCode = deliveryOrder?.supplier?.code |
|
|
|
val preferredFloor = if (supplierCode == "P06B") "4F" else "2F" |
|
|
|
val shop = deliveryOrder?.shop |
|
|
|
val shopId = shop?.id |
|
|
|
val estimatedArrivalDate = info.estimatedArrivalDate |
|
|
|
|
|
|
|
val calculatedTruckLanceCode = if (deliveryOrder != null && shopId != null && estimatedArrivalDate != null) { |
|
|
|
val targetDate = estimatedArrivalDate.toLocalDate() |
|
|
|
val dayAbbr = getDayOfWeekAbbr(targetDate) |
|
|
|
|
|
|
|
// 从缓存中获取 Truck |
|
|
|
val matchedTruck = truckCache[Triple(shopId, preferredFloor, dayAbbr)] |
|
|
|
matchedTruck?.truckLanceCode |
|
|
|
} else { |
|
|
|
null |
|
|
|
} |
|
|
|
|
|
|
|
DeliveryOrderInfoLiteDto( |
|
|
|
id = info.id, |
|
|
|
code = info.code, |
|
|
|
orderDate = info.orderDate, |
|
|
|
estimatedArrivalDate = info.estimatedArrivalDate, |
|
|
|
status = info.status, |
|
|
|
shopName = info.shopName, |
|
|
|
supplierName = info.supplierName, |
|
|
|
shopAddress = info.shopAddress, |
|
|
|
truckLanceCode = calculatedTruckLanceCode |
|
|
|
) |
|
|
|
}.filter { dto -> |
|
|
|
val dtoTruckLanceCode = dto.truckLanceCode?.lowercase() ?: "" |
|
|
|
dtoTruckLanceCode.contains(searchTruckLanceCode) |
|
|
|
} |
|
|
|
|
|
|
|
// 计算准确的总数(过滤后的总数) |
|
|
|
val totalCount = processedRecords.size |
|
|
|
println("DEBUG: Final filtered records count: $totalCount") |
|
|
|
|
|
|
|
// 对处理后的记录进行分页 |
|
|
|
val startIndex = page * size |
|
|
|
val endIndex = minOf(startIndex + size, processedRecords.size) |
|
|
|
|
|
|
|
val paginatedRecords = if (startIndex < processedRecords.size) { |
|
|
|
processedRecords.subList(startIndex, endIndex) |
|
|
|
} else { |
|
|
|
emptyList() |
|
|
|
} |
|
|
|
|
|
|
|
return RecordsRes(paginatedRecords, totalCount) |
|
|
|
} else { |
|
|
|
// 如果没有提供 truckLanceCode,使用分页查询 |
|
|
|
val result = deliveryOrderRepository.searchDoLitePage( |
|
|
|
code = code?.ifBlank { null }, |
|
|
|
shopName = shopName?.ifBlank { null }, |
|
|
|
status = statusEnum, |
|
|
|
etaStart = etaStart, |
|
|
|
etaEnd = etaEnd, |
|
|
|
pageable = pageable |
|
|
|
pageable = PageRequest.of(page.coerceAtLeast(0), size) |
|
|
|
) |
|
|
|
|
|
|
|
val records = result.content.map { |
|
|
|
// 处理当前页的记录 |
|
|
|
val records = result.content.map { info -> |
|
|
|
val deliveryOrder = deliveryOrderRepository.findByIdAndDeletedIsFalse(info.id) |
|
|
|
val supplierCode = deliveryOrder?.supplier?.code |
|
|
|
val preferredFloor = if (supplierCode == "P06B") "4F" else "2F" |
|
|
|
val shop = deliveryOrder?.shop |
|
|
|
val shopId = shop?.id |
|
|
|
val estimatedArrivalDate = info.estimatedArrivalDate |
|
|
|
|
|
|
|
val calculatedTruckLanceCode = if (deliveryOrder != null && shopId != null && estimatedArrivalDate != null) { |
|
|
|
val targetDate = estimatedArrivalDate.toLocalDate() |
|
|
|
val dayAbbr = getDayOfWeekAbbr(targetDate) |
|
|
|
val trucks = truckRepository.findByShopIdAndStoreIdAndDayOfWeek(shopId, preferredFloor, dayAbbr) |
|
|
|
|
|
|
|
val matchedTruck = if (trucks.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) } |
|
|
|
} |
|
|
|
|
|
|
|
matchedTruck?.truckLanceCode |
|
|
|
} else { |
|
|
|
null |
|
|
|
} |
|
|
|
|
|
|
|
DeliveryOrderInfoLiteDto( |
|
|
|
id = it.id, |
|
|
|
code = it.code, |
|
|
|
orderDate = it.orderDate, |
|
|
|
estimatedArrivalDate = it.estimatedArrivalDate, |
|
|
|
status = it.status, |
|
|
|
shopName = it.shopName, |
|
|
|
supplierName = it.supplierName, |
|
|
|
shopAddress = it.shopAddress |
|
|
|
id = info.id, |
|
|
|
code = info.code, |
|
|
|
orderDate = info.orderDate, |
|
|
|
estimatedArrivalDate = info.estimatedArrivalDate, |
|
|
|
status = info.status, |
|
|
|
shopName = info.shopName, |
|
|
|
supplierName = info.supplierName, |
|
|
|
shopAddress = info.shopAddress, |
|
|
|
truckLanceCode = calculatedTruckLanceCode |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
return RecordsRes(records, result.totalElements.toInt()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|