|
|
|
@@ -28,7 +28,6 @@ import com.ffii.fpsms.modules.pickOrder.service.PickOrderService |
|
|
|
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrder |
|
|
|
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRepository |
|
|
|
import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus |
|
|
|
import java.time.LocalDate |
|
|
|
import java.math.BigDecimal |
|
|
|
import com.ffii.fpsms.modules.master.web.models.MessageResponse |
|
|
|
import java.time.LocalDateTime |
|
|
|
@@ -38,13 +37,19 @@ import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecordRepository |
|
|
|
import com.ffii.fpsms.modules.deliveryOrder.web.models.* // ✅ 导入 |
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository |
|
|
|
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus |
|
|
|
|
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.TruckRepository |
|
|
|
import java.time.LocalDate |
|
|
|
import java.time.format.DateTimeFormatter |
|
|
|
import com.ffii.core.support.JdbcDao |
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.Truck |
|
|
|
@Service |
|
|
|
class DoPickOrderService( |
|
|
|
private val doPickOrderRepository: DoPickOrderRepository, |
|
|
|
private val doPickOrderRecordRepository: DoPickOrderRecordRepository, |
|
|
|
private val userRepository: UserRepository, |
|
|
|
private val pickOrderRepository: PickOrderRepository, |
|
|
|
private val jdbcDao: JdbcDao, // ✅ 添加这行 |
|
|
|
private val truckRepository: TruckRepository |
|
|
|
|
|
|
|
) { |
|
|
|
fun findReleasedDoPickOrders(): List<DoPickOrder> { |
|
|
|
@@ -80,16 +85,17 @@ class DoPickOrderService( |
|
|
|
throw e |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fun save(record: DoPickOrder): DoPickOrder { |
|
|
|
return doPickOrderRepository.save(record) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fun findByStoreIdOrderByTruckDepartureTime(storeId: String): List<DoPickOrder> { |
|
|
|
return doPickOrderRepository.findByStoreIdAndTicketStatusOrderByTruckDepartureTimeAsc( |
|
|
|
storeId, DoPickOrderStatus.pending |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Add these missing methods |
|
|
|
fun assignByStore(request: AssignByStoreRequest): MessageResponse { |
|
|
|
// TODO: Implement store-based assignment logic |
|
|
|
@@ -103,7 +109,7 @@ class DoPickOrderService( |
|
|
|
entity = null |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fun releaseAssignedByStore(request: AssignByStoreRequest): MessageResponse { |
|
|
|
// TODO: Implement store-based release logic |
|
|
|
return MessageResponse( |
|
|
|
@@ -116,29 +122,30 @@ class DoPickOrderService( |
|
|
|
entity = null |
|
|
|
) |
|
|
|
} |
|
|
|
// ✅ Updated method to set ticketReleaseTime when assigning order to user |
|
|
|
fun updateHandledByForPickOrder(pickOrderId: Long, userId: Long): List<DoPickOrder> { |
|
|
|
val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) |
|
|
|
val user = userRepository.findById(userId).orElse(null) // ✅ 改用 orElse(null) |
|
|
|
val handlerName = user?.name ?: "Unknown" |
|
|
|
doPickOrders.forEach { |
|
|
|
it.handledBy = userId |
|
|
|
it.handlerName = handlerName |
|
|
|
it.ticketStatus = DoPickOrderStatus.released |
|
|
|
it.ticketReleaseTime = LocalDateTime.now() |
|
|
|
} |
|
|
|
return doPickOrderRepository.saveAll(doPickOrders) |
|
|
|
|
|
|
|
// ✅ Updated method to set ticketReleaseTime when assigning order to user |
|
|
|
fun updateHandledByForPickOrder(pickOrderId: Long, userId: Long): List<DoPickOrder> { |
|
|
|
val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) |
|
|
|
val user = userRepository.findById(userId).orElse(null) // ✅ 改用 orElse(null) |
|
|
|
val handlerName = user?.name ?: "Unknown" |
|
|
|
doPickOrders.forEach { |
|
|
|
it.handledBy = userId |
|
|
|
it.handlerName = handlerName |
|
|
|
it.ticketStatus = DoPickOrderStatus.released |
|
|
|
it.ticketReleaseTime = LocalDateTime.now() |
|
|
|
} |
|
|
|
|
|
|
|
fun completeDoPickOrdersForPickOrder(pickOrderId: Long): List<DoPickOrder> { |
|
|
|
val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) |
|
|
|
doPickOrders.forEach { |
|
|
|
it.ticketStatus = DoPickOrderStatus.completed |
|
|
|
it.ticketCompleteDateTime = LocalDateTime.now() // ✅ 设置完成时间 |
|
|
|
} |
|
|
|
return doPickOrderRepository.saveAll(doPickOrders) |
|
|
|
return doPickOrderRepository.saveAll(doPickOrders) |
|
|
|
} |
|
|
|
|
|
|
|
fun completeDoPickOrdersForPickOrder(pickOrderId: Long): List<DoPickOrder> { |
|
|
|
val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) |
|
|
|
doPickOrders.forEach { |
|
|
|
it.ticketStatus = DoPickOrderStatus.completed |
|
|
|
it.ticketCompleteDateTime = LocalDateTime.now() // ✅ 设置完成时间 |
|
|
|
} |
|
|
|
|
|
|
|
return doPickOrderRepository.saveAll(doPickOrders) |
|
|
|
} |
|
|
|
|
|
|
|
// ✅ New method to remove do_pick_order records when auto-assigning by store |
|
|
|
fun removeDoPickOrdersForPickOrder(pickOrderId: Long): Int { |
|
|
|
val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) |
|
|
|
@@ -153,13 +160,13 @@ class DoPickOrderService( |
|
|
|
fun saveRecord(record: DoPickOrderRecord): DoPickOrderRecord { |
|
|
|
return doPickOrderRecordRepository.save(record) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ✅ Add method to update DoPickOrderRecord status |
|
|
|
fun updateRecordHandledByForPickOrder(pickOrderId: Long, userId: Long): List<DoPickOrderRecord> { |
|
|
|
val doPickOrderRecords = doPickOrderRecordRepository.findByPickOrderId(pickOrderId) |
|
|
|
val user = userRepository.findById(userId).orElse(null) // ✅ 改用 orElse(null) |
|
|
|
val handlerName = user?.name ?: "Unknown" |
|
|
|
doPickOrderRecords.forEach { |
|
|
|
doPickOrderRecords.forEach { |
|
|
|
it.handledBy = userId |
|
|
|
it.handlerName = handlerName |
|
|
|
it.ticketStatus = DoPickOrderStatus.released |
|
|
|
@@ -167,43 +174,45 @@ class DoPickOrderService( |
|
|
|
} |
|
|
|
return doPickOrderRecordRepository.saveAll(doPickOrderRecords) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ✅ Add method to complete DoPickOrderRecord |
|
|
|
fun completeDoPickOrderRecordsForPickOrder(pickOrderId: Long): List<DoPickOrderRecord> { |
|
|
|
val doPickOrderRecords = doPickOrderRecordRepository.findByPickOrderId(pickOrderId) |
|
|
|
doPickOrderRecords.forEach { |
|
|
|
doPickOrderRecords.forEach { |
|
|
|
it.ticketStatus = DoPickOrderStatus.completed |
|
|
|
it.ticketCompleteDateTime = LocalDateTime.now() // ✅ 设置完成时间 |
|
|
|
} |
|
|
|
return doPickOrderRecordRepository.saveAll(doPickOrderRecords) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Add method to find do_pick_order records by pick order ID |
|
|
|
fun findByPickOrderId(pickOrderId: Long): List<DoPickOrder> { |
|
|
|
return doPickOrderRepository.findByPickOrderId(pickOrderId) |
|
|
|
} |
|
|
|
|
|
|
|
fun updateDoOrderIdForPickOrder(pickOrderId: Long, doOrderId: Long): List<DoPickOrder> { |
|
|
|
val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) |
|
|
|
doPickOrders.forEach { |
|
|
|
doPickOrders.forEach { |
|
|
|
it.doOrderId = doOrderId |
|
|
|
} |
|
|
|
return doPickOrderRepository.saveAll(doPickOrders) |
|
|
|
} |
|
|
|
|
|
|
|
fun getSummaryByStore(storeId: String, requiredDate: LocalDate?): StoreLaneSummary { |
|
|
|
// ✅ 使用传入的日期,如果没有传入则使用今天 |
|
|
|
val targetDate = requiredDate ?: LocalDate.now() |
|
|
|
|
|
|
|
|
|
|
|
println("🔍 DEBUG: Getting summary for store=$storeId, date=$targetDate") |
|
|
|
|
|
|
|
|
|
|
|
// ✅ 修改:按日期查询订单 |
|
|
|
val allRecords = doPickOrderRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( |
|
|
|
storeId, |
|
|
|
storeId, |
|
|
|
targetDate, |
|
|
|
listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
println("🔍 DEBUG: Found ${allRecords.size} records for date $targetDate") |
|
|
|
|
|
|
|
|
|
|
|
val grouped = allRecords.groupBy { it.truckDepartureTime to it.truckLanceCode } |
|
|
|
.mapValues { (_, list) -> |
|
|
|
LaneBtn( |
|
|
|
@@ -212,10 +221,10 @@ class DoPickOrderService( |
|
|
|
total = list.size // 总订单数(包括已分配和未分配) |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
val timeGroups = grouped.entries |
|
|
|
.groupBy { it.key.first } |
|
|
|
.mapValues { (_, entries) -> |
|
|
|
.mapValues { (_, entries) -> |
|
|
|
entries.map { it.value } |
|
|
|
.sortedByDescending { it.unassigned } |
|
|
|
.take(3) |
|
|
|
@@ -229,16 +238,17 @@ class DoPickOrderService( |
|
|
|
lanes = lanes |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return StoreLaneSummary(storeId = storeId, rows = timeGroups) |
|
|
|
} |
|
|
|
|
|
|
|
// ✅ 修复:把 assignByLane 移到类里面 |
|
|
|
fun assignByLane(request: AssignByLaneRequest): MessageResponse { |
|
|
|
val existingOrders = doPickOrderRepository.findByHandledByAndTicketStatusIn( |
|
|
|
request.userId, |
|
|
|
request.userId, |
|
|
|
listOf(DoPickOrderStatus.released, DoPickOrderStatus.pending) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
if (existingOrders.isNotEmpty()) { |
|
|
|
return MessageResponse( |
|
|
|
id = null, code = "USER_BUSY", name = null, type = null, |
|
|
|
@@ -246,19 +256,19 @@ class DoPickOrderService( |
|
|
|
errorPosition = null, entity = null |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
val candidates = doPickOrderRepository |
|
|
|
.findByStoreIdAndTicketStatusOrderByTruckDepartureTimeAsc( |
|
|
|
request.storeId, |
|
|
|
request.storeId, |
|
|
|
DoPickOrderStatus.pending |
|
|
|
) |
|
|
|
.filter { |
|
|
|
.filter { |
|
|
|
it.handledBy == null && |
|
|
|
it.truckLanceCode == request.truckLanceCode && |
|
|
|
(request.truckDepartureTime == null || |
|
|
|
it.truckDepartureTime?.toString() == request.truckDepartureTime) |
|
|
|
it.truckLanceCode == request.truckLanceCode && |
|
|
|
(request.truckDepartureTime == null || |
|
|
|
it.truckDepartureTime?.toString() == request.truckDepartureTime) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (candidates.isEmpty()) { |
|
|
|
return MessageResponse( |
|
|
|
id = null, code = "NO_ORDERS", name = null, type = null, |
|
|
|
@@ -266,22 +276,22 @@ class DoPickOrderService( |
|
|
|
errorPosition = null, entity = null |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
val firstOrder = candidates.first() |
|
|
|
val user = userRepository.findById(request.userId).orElse(null) |
|
|
|
val handlerName = user?.name ?: "Unknown" |
|
|
|
|
|
|
|
|
|
|
|
// ✅ 更新 do_pick_order - 保持原有的卡车信息 |
|
|
|
firstOrder.handledBy = request.userId |
|
|
|
firstOrder.handlerName = handlerName |
|
|
|
firstOrder.ticketStatus = DoPickOrderStatus.released |
|
|
|
firstOrder.ticketReleaseTime = LocalDateTime.now() |
|
|
|
|
|
|
|
|
|
|
|
// ✅ 重要:不要修改 truckDepartureTime 和 truckLanceCode |
|
|
|
// 这些信息应该保持用户选择的值 |
|
|
|
|
|
|
|
|
|
|
|
doPickOrderRepository.save(firstOrder) |
|
|
|
|
|
|
|
|
|
|
|
// ✅ 同步更新 pick_order 表 |
|
|
|
if (firstOrder.pickOrderId != null) { |
|
|
|
val pickOrder = pickOrderRepository.findById(firstOrder.pickOrderId!!).orElse(null) |
|
|
|
@@ -292,7 +302,7 @@ class DoPickOrderService( |
|
|
|
pickOrderRepository.save(pickOrder) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 同步更新 record |
|
|
|
val records = doPickOrderRecordRepository.findByPickOrderId(firstOrder.pickOrderId!!) |
|
|
|
records.forEach { |
|
|
|
@@ -302,7 +312,7 @@ class DoPickOrderService( |
|
|
|
it.ticketReleaseTime = LocalDateTime.now() |
|
|
|
} |
|
|
|
doPickOrderRecordRepository.saveAll(records) |
|
|
|
|
|
|
|
|
|
|
|
return MessageResponse( |
|
|
|
id = firstOrder.pickOrderId, |
|
|
|
code = "SUCCESS", |
|
|
|
@@ -316,7 +326,124 @@ class DoPickOrderService( |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
// 在 DoPickOrderService 类中添加这个方法 |
|
|
|
|
|
|
|
// 在 DoPickOrderService 类中添加这个方法 |
|
|
|
open fun determineStoreId(doOrderId: Long): String { |
|
|
|
val sql = """ |
|
|
|
SELECT |
|
|
|
dol.deliveryOrderId, |
|
|
|
w.store_id, |
|
|
|
SUM(ill.inQty - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) AS total_inventory |
|
|
|
FROM fpsmsdb.delivery_order_line dol |
|
|
|
LEFT JOIN fpsmsdb.inventory_lot il ON il.itemId = dol.itemId AND il.deleted = 0 |
|
|
|
LEFT JOIN fpsmsdb.inventory_lot_line ill ON ill.inventoryLotId = il.id AND ill.deleted = 0 |
|
|
|
LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId AND w.deleted = 0 |
|
|
|
WHERE dol.deleted = 0 AND dol.deliveryOrderId = :doOrderId |
|
|
|
GROUP BY dol.deliveryOrderId, w.store_id |
|
|
|
ORDER BY total_inventory DESC |
|
|
|
LIMIT 1 |
|
|
|
""".trimIndent() |
|
|
|
|
|
|
|
val results = jdbcDao.queryForList(sql, mapOf("doOrderId" to doOrderId)) |
|
|
|
return if (results.isNotEmpty()) { |
|
|
|
val storeId = results.first()["store_id"] as? String ?: "2F" |
|
|
|
when (storeId) { |
|
|
|
"2F" -> "2/F" |
|
|
|
"4F" -> "4/F" |
|
|
|
"3F" -> "3/F" |
|
|
|
else -> "2/F" |
|
|
|
} |
|
|
|
} else { |
|
|
|
"2/F" // 默认值 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} // ✅ 类结束 |
|
|
|
open fun selectTruck(shopId: Long?, storeId: String): Truck? { |
|
|
|
if (shopId == null) return null |
|
|
|
|
|
|
|
val storeIdInt = when (storeId) { |
|
|
|
"2/F" -> 2 |
|
|
|
"4/F" -> 4 |
|
|
|
"3/F" -> 3 |
|
|
|
else -> 2 |
|
|
|
} |
|
|
|
|
|
|
|
val trucks = truckRepository.findByShopIdAndDeletedFalse(shopId) |
|
|
|
return trucks.find { it.storeId == storeIdInt } ?: trucks.firstOrNull() |
|
|
|
} |
|
|
|
|
|
|
|
open fun finishDoPickOrder(doPickOrderId: Long): MessageResponse { |
|
|
|
val doPickOrder = doPickOrderRepository.findById(doPickOrderId).orElse(null) |
|
|
|
?: return MessageResponse( |
|
|
|
id = null, |
|
|
|
code = "NOT_FOUND", |
|
|
|
name = null, |
|
|
|
type = null, |
|
|
|
message = "DO Pick Order not found", |
|
|
|
errorPosition = null, |
|
|
|
entity = null |
|
|
|
) |
|
|
|
|
|
|
|
try { |
|
|
|
// 确定 store_id 和 truck |
|
|
|
val storeId = determineStoreId(doPickOrder.doOrderId ?: 0L) |
|
|
|
val truck = selectTruck(doPickOrder.shopId, storeId) |
|
|
|
|
|
|
|
// 生成 ticket 编号 |
|
|
|
val targetDate = doPickOrder.requiredDeliveryDate ?: LocalDate.now() |
|
|
|
val datePrefix = targetDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")) |
|
|
|
val ticketNumber = getNextTicketNumber(datePrefix, storeId) |
|
|
|
|
|
|
|
// 更新 do_pick_order |
|
|
|
doPickOrder.storeId = storeId |
|
|
|
doPickOrder.ticketNo = ticketNumber |
|
|
|
doPickOrder.truckId = truck?.id |
|
|
|
doPickOrder.truckDepartureTime = truck?.departureTime |
|
|
|
doPickOrder.truckLanceCode = truck?.truckLanceCode |
|
|
|
|
|
|
|
val updatedDoPickOrder = doPickOrderRepository.save(doPickOrder) |
|
|
|
|
|
|
|
// 创建 do_pick_order_record |
|
|
|
val doPickOrderRecord = DoPickOrderRecord( |
|
|
|
storeId = storeId, |
|
|
|
ticketNo = ticketNumber, |
|
|
|
ticketStatus = DoPickOrderStatus.pending, |
|
|
|
truckId = truck?.id, |
|
|
|
pickOrderId = doPickOrder.pickOrderId, |
|
|
|
truckDepartureTime = truck?.departureTime, |
|
|
|
shopId = doPickOrder.shopId, |
|
|
|
handledBy = null, |
|
|
|
doOrderId = doPickOrder.doOrderId, |
|
|
|
pickOrderCode = doPickOrder.pickOrderCode, |
|
|
|
deliveryOrderCode = doPickOrder.deliveryOrderCode, |
|
|
|
loadingSequence = doPickOrder.loadingSequence, |
|
|
|
truckLanceCode = truck?.truckLanceCode, |
|
|
|
shopCode = doPickOrder.shopCode, |
|
|
|
shopName = doPickOrder.shopName, |
|
|
|
requiredDeliveryDate = targetDate |
|
|
|
) |
|
|
|
|
|
|
|
doPickOrderRecordRepository.save(doPickOrderRecord) |
|
|
|
|
|
|
|
return MessageResponse( |
|
|
|
id = updatedDoPickOrder.id, |
|
|
|
code = "SUCCESS", |
|
|
|
name = null, |
|
|
|
type = null, |
|
|
|
message = "DO Pick Order finished successfully", |
|
|
|
errorPosition = null, |
|
|
|
entity = mapOf("ticketNo" to ticketNumber) |
|
|
|
) |
|
|
|
} catch (e: Exception) { |
|
|
|
return MessageResponse( |
|
|
|
id = null, |
|
|
|
code = "ERROR", |
|
|
|
name = null, |
|
|
|
type = null, |
|
|
|
message = "Error finishing DO Pick Order: ${e.message}", |
|
|
|
errorPosition = null, |
|
|
|
entity = null |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
}// ✅ 类结束 |