CANCERYS\kw093 17 timmar sedan
förälder
incheckning
75f704c8a9
10 ändrade filer med 251 tillägg och 49 borttagningar
  1. +1
    -1
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DeliveryOrderRepository.kt
  2. +4
    -2
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/models/DeliveryOrderInfo.kt
  3. +217
    -28
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt
  4. +16
    -14
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt
  5. +1
    -0
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/ReleaseDoRequest.kt
  6. +3
    -1
      src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt
  7. +2
    -1
      src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt
  8. +2
    -1
      src/main/java/com/ffii/fpsms/modules/jobOrder/web/model/SecondScanSubmitRequest.kt
  9. +4
    -0
      src/main/java/com/ffii/fpsms/modules/pickOrder/entity/TruckRepository.kt
  10. +1
    -1
      src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt

+ 1
- 1
src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DeliveryOrderRepository.kt Visa fil

@@ -102,7 +102,7 @@ fun searchDoLite(


@Query("""
select d from DeliveryOrder d
select distinct d from DeliveryOrder d
where d.deleted = false
and (:code is null or d.code like concat('%', :code, '%'))
and (:shopName is null or d.shop.name like concat('%', :shopName, '%'))


+ 4
- 2
src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/models/DeliveryOrderInfo.kt Visa fil

@@ -43,7 +43,8 @@ interface DeliveryOrderInfoLite {

@get:Value("#{target.supplier?.name}")
val supplierName: String?

@get:Value("#{target.supplier?.code}")
val supplierCode: String?
@get:Value("#{target.shop?.addr3}")
val shopAddress: String?
}
@@ -55,5 +56,6 @@ data class DeliveryOrderInfoLiteDto(
val status: String?,
val shopName: String?,
val supplierName: String?,
val shopAddress: String?
val shopAddress: String?,
val truckLanceCode: String?
)

+ 217
- 28
src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt Visa fil

@@ -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())
}
}





+ 16
- 14
src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt Visa fil

@@ -52,20 +52,22 @@ class DeliveryOrderController(
) {
@PostMapping("/search-do-lite")
fun searchDoLite(@RequestBody request: SearchDeliveryOrderInfoRequest): RecordsRes<DeliveryOrderInfoLiteDto> { // 改为 DeliveryOrderInfoLiteDto
println("DEBUG: searchDoLite - request: code=${request.code}, shopName=${request.shopName}, status=${request.status}")
println("DEBUG: searchDoLite - estimatedArrivalDate=${request.estimatedArrivalDate}")
println("DEBUG: searchDoLite - pagination: pageNum=${request.pageNum}, pageSize=${request.pageSize}")
return deliveryOrderService.searchDoLiteByPage(
code = request.code,
shopName = request.shopName,
status = request.status,
estimatedArrivalDate = request.estimatedArrivalDate,
pageNum = request.pageNum,
pageSize = request.pageSize
)
}
fun searchDoLite(@RequestBody request: SearchDeliveryOrderInfoRequest): RecordsRes<DeliveryOrderInfoLiteDto> {
println("DEBUG: searchDoLite - request: code=${request.code}, shopName=${request.shopName}, status=${request.status}")
println("DEBUG: searchDoLite - estimatedArrivalDate=${request.estimatedArrivalDate}")
println("DEBUG: searchDoLite - truckLanceCode=${request.truckLanceCode}") // 添加这行
println("DEBUG: searchDoLite - pagination: pageNum=${request.pageNum}, pageSize=${request.pageSize}")
return deliveryOrderService.searchDoLiteByPage(
code = request.code,
shopName = request.shopName,
status = request.status,
estimatedArrivalDate = request.estimatedArrivalDate,
pageNum = request.pageNum,
pageSize = request.pageSize,
truckLanceCode = request.truckLanceCode
)
}
@GetMapping("/list")
fun getDoList(): List<DeliveryOrderInfo> {
return deliveryOrderService.getDoList();


+ 1
- 0
src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/ReleaseDoRequest.kt Visa fil

@@ -28,4 +28,5 @@ data class SearchDeliveryOrderInfoRequest(
val estimatedArrivalDate: LocalDateTime?,
val pageSize: Int?,
val pageNum: Int?,
val truckLanceCode: String?
)

+ 3
- 1
src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt Visa fil

@@ -1024,7 +1024,9 @@ open fun submitSecondScanQty(request: SecondScanSubmitRequest): MessageResponse
// Set status to completed when submitting quantity
joPickOrderEntity.matchStatus = JoPickOrderStatus.completed
// 添加:如果 ticketCompleteTime 还没设置,现在设置(通常已经在拣货完成时设置了)
request.userId?.let { uid ->
joPickOrderEntity.matchBy = uid
}
if (joPickOrderEntity.ticketCompleteTime == null) {
joPickOrderEntity.ticketCompleteTime = LocalDateTime.now()
}


+ 2
- 1
src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt Visa fil

@@ -156,7 +156,8 @@ class JobOrderController(
itemId = itemId, // Use path variable
qty = (data["qty"] as Number).toDouble(),
isMissing = data["isMissing"] as? Boolean ?: false,
isBad = data["isBad"] as? Boolean ?: false
isBad = data["isBad"] as? Boolean ?: false,
userId = (data["userId"] as Number).toLong()
)
return joPickOrderService.submitSecondScanQty(request)
}


+ 2
- 1
src/main/java/com/ffii/fpsms/modules/jobOrder/web/model/SecondScanSubmitRequest.kt Visa fil

@@ -11,5 +11,6 @@ data class SecondScanSubmitRequest(
val qty: Double,
val isMissing: Boolean = false,
val isBad: Boolean = false,
val reason: String? = null
val reason: String? = null,
val userId: Long? = null
)

+ 4
- 0
src/main/java/com/ffii/fpsms/modules/pickOrder/entity/TruckRepository.kt Visa fil

@@ -143,4 +143,8 @@ fun findByShopIdAndStoreIdAndDayOfWeek(
"""
)
fun findAllUniqueShopNamesFromTrucks(): List<String>


@Query("SELECT t FROM Truck t WHERE t.truckLanceCode LIKE CONCAT('%', :truckLanceCode, '%') AND t.deleted = false")
fun findAllByTruckLanceCodeContainingAndDeletedFalse(@Param("truckLanceCode") truckLanceCode: String): List<Truck>
}

+ 1
- 1
src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt Visa fil

@@ -899,7 +899,7 @@ open fun saveApproverStockTakeRecord(
}
stockOutLineRepository.save(stockOutLine)
val newBalance = (inventory.onHandQty ?: BigDecimal.ZERO).toDouble()-(varianceQty).toDouble()
val newBalance = (inventory.onHandQty ?: BigDecimal.ZERO).toDouble()+(varianceQty).toDouble()
val stockLedger = StockLedger().apply {
this.inventory=inventory
this.itemId=inventoryLot.item?.id


Laddar…
Avbryt
Spara