From d841f4f8ce33f2022af43f741c3467bcf5a0c071 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Tue, 7 Oct 2025 17:11:31 +0800 Subject: [PATCH] update --- .../deliveryOrder/entity/DoPickOrder.kt | 46 +- .../deliveryOrder/entity/DoPickOrderRecord.kt | 42 +- .../service/DeliveryOrderService.kt | 205 +++--- .../service/DoPickOrderService.kt | 14 +- .../jobOrder/service/JoPickOrderService.kt | 41 +- .../fpsms/modules/pickOrder/entity/Router.kt | 18 +- .../modules/pickOrder/entity/RouterOrder.kt | 20 + .../pickOrder/entity/RouterOrderRepository.kt | 16 + .../pickOrder/entity/RouterRepository.kt | 10 +- .../fpsms/modules/pickOrder/entity/Truck.kt | 28 +- .../pickOrder/entity/TruckRepository.kt | 19 +- .../pickOrder/service/PickOrderService.kt | 644 ++++++++---------- .../pickOrder/web/PickOrderController.kt | 8 +- .../01_altertable_enson.sql | 27 + .../02_altertable_enson.sql | 68 ++ 15 files changed, 679 insertions(+), 527 deletions(-) create mode 100644 src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterOrder.kt create mode 100644 src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterOrderRepository.kt create mode 100644 src/main/resources/db/changelog/changes/202511005_01_enson/01_altertable_enson.sql create mode 100644 src/main/resources/db/changelog/changes/202511005_01_enson/02_altertable_enson.sql diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrder.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrder.kt index 470c0bf..7d6571d 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrder.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrder.kt @@ -3,6 +3,7 @@ package com.ffii.fpsms.modules.deliveryOrder.entity import jakarta.persistence.* import java.time.LocalDateTime import java.time.LocalTime +import java.time.LocalDate import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus import org.hibernate.annotations.CreationTimestamp import org.hibernate.annotations.UpdateTimestamp @@ -19,8 +20,10 @@ class DoPickOrder { @Column(name = "ticket_no", length = 50) var ticketNo: String? = null + @Column(name = "pick_order_id") var pickOrderId: Long? = null + @Enumerated(EnumType.STRING) @Column(name = "ticket_status") var ticketStatus: DoPickOrderStatus? = null @@ -30,21 +33,35 @@ class DoPickOrder { @Column(name = "truck_departure_time") var truckDepartureTime: LocalTime? = null - - @Column(name = "item_id") - var itemId: Long? = null - + @Column(name = "shop_id") var shopId: Long? = null + @Column(name = "do_order_id") var doOrderId: Long? = null - @Column(name = "shop_po_supplier_id") - var shopPoSupplierId: Long? = null @Column(name = "handled_by") var handledBy: Long? = null + @Column(name = "ticket_release_time") var ticketReleaseTime: LocalDateTime? = null + + // ✅ 新增字段声明 + @Column(name = "ticketCompleteDateTime") + var ticketCompleteDateTime: LocalDateTime? = null + + @Column(name = "TruckLanceCode", length = 50) + var truckLanceCode: String? = null + + @Column(name = "ShopCode", length = 50) + var shopCode: String? = null + + @Column(name = "ShopName", length = 255) + var shopName: String? = null + + @Column(name = "RequiredDeliveryDate") + var requiredDeliveryDate: LocalDate? = null + @CreationTimestamp @Column(name = "created") var created: LocalDateTime? = null @@ -64,9 +81,6 @@ class DoPickOrder { @Column(name = "deleted") var deleted: Boolean = false - - @Column(name = "hide", nullable = false) - var hide: Boolean = false // Default constructor for Hibernate constructor() @@ -81,10 +95,13 @@ class DoPickOrder { pickOrderId: Long? = null, doOrderId: Long? = null, ticketReleaseTime: LocalDateTime? = null, - itemId: Long? = null, shopId: Long? = null, - shopPoSupplierId: Long? = null, handledBy: Long? = null, + ticketCompleteDateTime: LocalDateTime? = null, + truckLanceCode: String? = null, + shopCode: String? = null, + shopName: String? = null, + requiredDeliveryDate: LocalDate? = null, createdBy: String? = null, modifiedBy: String? = null ) { @@ -96,10 +113,13 @@ class DoPickOrder { this.ticketStatus = ticketStatus this.truckId = truckId this.truckDepartureTime = truckDepartureTime - this.itemId = itemId this.shopId = shopId - this.shopPoSupplierId = shopPoSupplierId this.handledBy = handledBy + this.ticketCompleteDateTime = ticketCompleteDateTime + this.truckLanceCode = truckLanceCode + this.shopCode = shopCode + this.shopName = shopName + this.requiredDeliveryDate = requiredDeliveryDate this.createdBy = createdBy this.modifiedBy = modifiedBy } diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrderRecord.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrderRecord.kt index 211c6e7..78edfb4 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrderRecord.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrderRecord.kt @@ -6,6 +6,7 @@ import java.time.LocalTime import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus import org.hibernate.annotations.CreationTimestamp import org.hibernate.annotations.UpdateTimestamp +import java.time.LocalDate @Entity @Table(name = "do_pick_order_record") @@ -19,33 +20,48 @@ class DoPickOrderRecord { @Column(name = "ticket_no", length = 50) var ticketNo: String? = null + @Column(name = "pick_order_id") var pickOrderId: Long? = null + @Column(name = "do_order_id") var doOrderId: Long? = null + @Enumerated(EnumType.STRING) @Column(name = "ticket_status") var ticketStatus: DoPickOrderStatus? = null + @Column(name = "ticket_release_time") var ticketReleaseTime: LocalDateTime? = null + @Column(name = "truck_id") var truckId: Long? = null @Column(name = "truck_departure_time") var truckDepartureTime: LocalTime? = null - @Column(name = "item_id") - var itemId: Long? = null - @Column(name = "shop_id") var shopId: Long? = null - @Column(name = "shop_po_supplier_id") - var shopPoSupplierId: Long? = null - @Column(name = "handled_by") var handledBy: Long? = null + // ✅ 新增字段声明 + @Column(name = "ticketCompleteDateTime") + var ticketCompleteDateTime: LocalDateTime? = null + + @Column(name = "TruckLanceCode", length = 50) + var truckLanceCode: String? = null + + @Column(name = "ShopCode", length = 50) + var shopCode: String? = null + + @Column(name = "ShopName", length = 255) + var shopName: String? = null + + @Column(name = "RequiredDeliveryDate") + var requiredDeliveryDate: LocalDate? = null + @CreationTimestamp @Column(name = "created") var created: LocalDateTime? = null @@ -78,11 +94,14 @@ class DoPickOrderRecord { truckDepartureTime: LocalTime? = null, pickOrderId: Long? = null, doOrderId: Long? = null, - itemId: Long? = null, shopId: Long? = null, ticketReleaseTime: LocalDateTime? = null, - shopPoSupplierId: Long? = null, handledBy: Long? = null, + ticketCompleteDateTime: LocalDateTime? = null, + truckLanceCode: String? = null, + shopCode: String? = null, + shopName: String? = null, + requiredDeliveryDate: LocalDate? = null, createdBy: String? = null, modifiedBy: String? = null ) { @@ -94,10 +113,13 @@ class DoPickOrderRecord { this.ticketStatus = ticketStatus this.truckId = truckId this.truckDepartureTime = truckDepartureTime - this.itemId = itemId this.shopId = shopId - this.shopPoSupplierId = shopPoSupplierId this.handledBy = handledBy + this.ticketCompleteDateTime = ticketCompleteDateTime + this.truckLanceCode = truckLanceCode + this.shopCode = shopCode + this.shopName = shopName + this.requiredDeliveryDate = requiredDeliveryDate this.createdBy = createdBy this.modifiedBy = modifiedBy } 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 8861bea..3e0147f 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 @@ -469,101 +469,115 @@ open class DeliveryOrderService( } // ✅ CREATE do_pick_order_record entries - val targetDate = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now() - val datePrefix = targetDate.format(DateTimeFormatter.ofPattern("ddMMyy")) - - println("�� DEBUG: Target date: $targetDate, Date prefix: $datePrefix") - - val truck = deliveryOrder.shop?.id?.let { shopId -> - println("🔍 DEBUG: Looking for truck with shop ID: $shopId") - val trucks = truckRepository.findByShopIdAndDeletedFalse(shopId) - println("🔍 DEBUG: Found ${trucks.size} trucks for shop $shopId") - trucks.forEach { t -> - println("🔍 DEBUG: Truck ID: ${t.id}, DepartureTime: ${t.departureTime}") - } - val selectedTruck = trucks.minByOrNull { it.departureTime ?: LocalTime.MAX } - println("🔍 DEBUG: Selected truck: ID=${selectedTruck?.id}, DepartureTime=${selectedTruck?.departureTime}") - selectedTruck - } - - println("🔍 DEBUG: Processing ${deliveryOrder.deliveryOrderLines.size} delivery order lines") - - // ✅ Group lines by store ID to get unique ticket numbers per store - val linesByStore = deliveryOrder.deliveryOrderLines.groupBy { line -> - if (deliveryOrder.supplier?.code == "P06B") "4/F" else "2/F" - } - - linesByStore.forEach { (storeId, lines) -> - // ✅ Get ticket number for this specific store - val nextTicketNumber = doPickOrderService.getNextTicketNumber(datePrefix, storeId) - println("🔍 DEBUG: Next ticket number for store $storeId: $nextTicketNumber") - - lines.forEach { line -> - println("�� DEBUG: Processing line - Item ID: ${line.item?.id}, Store ID: $storeId") - - val doPickOrderRecord = DoPickOrderRecord( - storeId = storeId, - ticketNo = nextTicketNumber, - ticketStatus = DoPickOrderStatus.pending, - truckId = truck?.id, - pickOrderId = createdPickOrder.id, - truckDepartureTime = truck?.departureTime, - itemId = line.item?.id, - shopId = deliveryOrder.shop?.id, - shopPoSupplierId = deliveryOrder.shop?.id, - handledBy = null - ) - - println("�� DEBUG: Creating DoPickOrderRecord - Store: $storeId, Ticket: $nextTicketNumber, Truck: ${truck?.id}") - - val savedDoPickOrderRecord = doPickOrderRecordRepository.save(doPickOrderRecord) - println("🔍 DEBUG: Saved DoPickOrderRecord - ID: ${savedDoPickOrderRecord.id}") - } - - // ✅ Also create DoPickOrder records for this store - lines.forEach { line -> - println("�� DEBUG: Creating DoPickOrder - Store: $storeId, Ticket: $nextTicketNumber, Truck: ${truck?.id}") - - val doPickOrder = DoPickOrder( - storeId = storeId, - ticketNo = nextTicketNumber, - ticketStatus = DoPickOrderStatus.pending, - truckId = truck?.id, - doOrderId = deliveryOrder.id, - pickOrderId = createdPickOrder.id, - truckDepartureTime = truck?.departureTime, - itemId = line.item?.id, - shopId = deliveryOrder.shop?.id, - shopPoSupplierId = deliveryOrder.shop?.id, - handledBy = null, - ticketReleaseTime = null - ) - - val savedDoPickOrder = doPickOrderService.save(doPickOrder) - println("🔍 DEBUG: Saved DoPickOrder - ID: ${savedDoPickOrder.id}") - } - } - return MessageResponse( - id = deliveryOrder.id, - code = deliveryOrder.code, - name = deliveryOrder.shop?.name, - type = null, - message = null, - errorPosition = null, - entity = mapOf("status" to deliveryOrder.status?.value) - ) + // 第 471-555 行附近 - 修复创建逻辑 + +// ✅ CREATE do_pick_order_record entries +val targetDate = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now() +val datePrefix = targetDate.format(DateTimeFormatter.ofPattern("ddMMyy")) + +println("🔍 DEBUG: Target date: $targetDate, Date prefix: $datePrefix") +val truck = deliveryOrder.shop?.id?.let { shopId -> + println("🔍 DEBUG: Looking for truck with shop ID: $shopId") + val trucks = truckRepository.findByShopIdAndDeletedFalse(shopId) + println("🔍 DEBUG: Found ${trucks.size} trucks for shop $shopId") + trucks.forEach { t -> + println("🔍 DEBUG: Truck ID: ${t.id}, DepartureTime: ${t.departureTime}") + } + val selectedTruck = trucks.minByOrNull { it.departureTime ?: LocalTime.MAX } + println("🔍 DEBUG: Selected truck: ID=${selectedTruck?.id}, DepartureTime=${selectedTruck?.departureTime}") + selectedTruck +} + +// ✅ 根据 truck 的 Store_id 字段确定 storeId +val storeId = when (truck?.storeId) { + 4 -> "4/F" + 2 -> "2/F" + else -> "2/F" // 默认值 +} + +println("🔍 DEBUG: Determined store ID: $storeId") + +// ✅ Get ticket number for this store (只需要一次) +val nextTicketNumber = doPickOrderService.getNextTicketNumber(datePrefix, storeId) +println("🔍 DEBUG: Next ticket number for store $storeId: $nextTicketNumber") + +// ✅ 每个 pick order 只创建一条 DoPickOrderRecord +val doPickOrderRecord = DoPickOrderRecord( + storeId = storeId, + ticketNo = nextTicketNumber, + ticketStatus = DoPickOrderStatus.pending, + truckId = truck?.id, + pickOrderId = createdPickOrder.id, + truckDepartureTime = truck?.departureTime, + shopId = deliveryOrder.shop?.id, + handledBy = null, + // ✅ 填充新增字段 + truckLanceCode = truck?.truckLanceCode, + shopCode = deliveryOrder.shop?.code, + shopName = deliveryOrder.shop?.name, + requiredDeliveryDate = targetDate +) + +println("🔍 DEBUG: Creating DoPickOrderRecord - Store: $storeId, Ticket: $nextTicketNumber, Truck: ${truck?.id}") +val savedDoPickOrderRecord = doPickOrderRecordRepository.save(doPickOrderRecord) +println("🔍 DEBUG: Saved DoPickOrderRecord - ID: ${savedDoPickOrderRecord.id}") + +// ✅ 每个 pick order 只创建一条 DoPickOrder +val doPickOrder = DoPickOrder( + storeId = storeId, + ticketNo = nextTicketNumber, + ticketStatus = DoPickOrderStatus.pending, + truckId = truck?.id, + doOrderId = deliveryOrder.id, + pickOrderId = createdPickOrder.id, + truckDepartureTime = truck?.departureTime, + shopId = deliveryOrder.shop?.id, + handledBy = null, + ticketReleaseTime = null, + // ✅ 填充新增字段 + truckLanceCode = truck?.truckLanceCode, + shopCode = deliveryOrder.shop?.code, + shopName = deliveryOrder.shop?.name, + requiredDeliveryDate = targetDate +) + +println("🔍 DEBUG: Creating DoPickOrder - Store: $storeId, Ticket: $nextTicketNumber, Truck: ${truck?.id}") +val savedDoPickOrder = doPickOrderService.save(doPickOrder) +println("🔍 DEBUG: Saved DoPickOrder - ID: ${savedDoPickOrder.id}") + +return MessageResponse( + id = deliveryOrder.id, + code = deliveryOrder.code, + name = deliveryOrder.shop?.name, + type = null, + message = null, + errorPosition = null, + entity = mapOf("status" to deliveryOrder.status?.value) +) + +// ... existing code ... } open fun getRouteAndIndexByInventoryLotId(inventoryLotId: Int): List { return routerRepository.findByInventoryLotIdAndDeletedFalse(inventoryLotId) - .sortedBy { it.index } + .sortedWith(compareBy( + { it.routerOrder?.order ?: 999999 }, + { it.route ?: 999999 } + )) } open fun getRoutesByInventoryLotId(inventoryLotId: Int): List { return getRouteAndIndexByInventoryLotId(inventoryLotId) - .mapNotNull { it.route } + .mapNotNull { router -> + val routeArea = router.routerOrder?.routeArea ?: "" + val route = router.route?.toString() ?: "" + if (routeArea.isNotEmpty() || route.isNotEmpty()) { + "$routeArea$route" + } else { + null + } + } } - open fun getRouteByItemId(itemId: Long): String? { val inventoryLots = inventoryLotService.findByItemId(itemId) if (inventoryLots.isNotEmpty()){ @@ -575,16 +589,17 @@ open class DeliveryOrderService( return null } - open fun getRouterIndexByItemId(itemId: Long): Int? { - val inventoryLots = inventoryLotService.findByItemId(itemId) - if( inventoryLots.isNotEmpty()){ - val inventoryLotId = inventoryLots.first().id?.toInt() - return inventoryLotId?.let { lotId -> - getRouteAndIndexByInventoryLotId(lotId).firstOrNull()?.index - } + +open fun getRouterIndexByItemId(itemId: Long): Int? { + val inventoryLots = inventoryLotService.findByItemId(itemId) + if (inventoryLots.isNotEmpty()){ + val inventoryLotId = inventoryLots.first().id?.toInt() + return inventoryLotId?.let { lotId -> + getRouteAndIndexByInventoryLotId(lotId).firstOrNull()?.routerOrder?.order } - return null } + return null +} open fun getLotNumbersForPickOrderByItemId(itemId: Long, pickOrderId: Long): String { try { @@ -624,7 +639,7 @@ open class DeliveryOrderService( val deliveryOrderEntity = deliveryOrderRepository.findByIdAndDeletedIsFalse(request.deliveryOrderIds) val selectedTruckNo = deliveryOrderEntity?.shop?.id?.let { shopId -> val trucks = truckRepository.findByShopIdAndDeletedFalse(shopId) - trucks.firstOrNull()?.truckNo + trucks.firstOrNull()?.truckLanceCode } ?: "" val selectedPickOrder = pickOrderRepository.findById(request.pickOrderIds).orElse(null) diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt index 8d26611..ef2e050 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt @@ -109,13 +109,14 @@ class DoPickOrderService( return doPickOrderRepository.saveAll(doPickOrders) } - fun completeDoPickOrdersForPickOrder(pickOrderId: Long): List { - val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) - doPickOrders.forEach { - it.ticketStatus = DoPickOrderStatus.completed // ✅ Update status to "completed" + fun completeDoPickOrdersForPickOrder(pickOrderId: Long): List { + val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) + doPickOrders.forEach { + it.ticketStatus = DoPickOrderStatus.completed + it.ticketCompleteDateTime = LocalDateTime.now() // ✅ 设置完成时间 + } + return doPickOrderRepository.saveAll(doPickOrders) } - return doPickOrderRepository.saveAll(doPickOrders) - } // ✅ New method to remove do_pick_order records when auto-assigning by store fun removeDoPickOrdersForPickOrder(pickOrderId: Long): Int { @@ -151,6 +152,7 @@ class DoPickOrderService( val doPickOrderRecords = doPickOrderRecordRepository.findByPickOrderId(pickOrderId) doPickOrderRecords.forEach { it.ticketStatus = DoPickOrderStatus.completed + it.ticketCompleteDateTime = LocalDateTime.now() // ✅ 设置完成时间 } return doPickOrderRecordRepository.saveAll(doPickOrderRecords) } diff --git a/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt index 46f27ed..154fdb6 100644 --- a/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt @@ -221,9 +221,9 @@ open class JoPickOrderService( -- Router Information r.id as routerId, - r.index as routerIndex, - r.route as routerRoute, - r.area as routerArea, + ro.`order` as routerIndex, + CONCAT(COALESCE(ro.route_area, ''), COALESCE(r.route, '')) as routerRoute, + ro.route_area as routerArea, -- Set quantities to NULL for rejected lots CASE @@ -297,6 +297,7 @@ open class JoPickOrderService( LEFT JOIN fpsmsdb.router r ON r.inventoryLotId = ill.id AND r.deleted = false LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + LEFT JOIN fpsmsdb.router_order ro ON r.router_id = ro.id LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ill.id AND sol.deleted = false LEFT JOIN fpsmsdb.jo_pick_order jpo ON jpo.pick_order_id = po.id AND jpo.item_id = pol.itemId WHERE po.deleted = false @@ -309,7 +310,8 @@ open class JoPickOrderService( AND (spl.pickOrderLineId IS NOT NULL OR sol.pickOrderLineId IS NOT NULL) ORDER BY CASE WHEN sol.status = 'rejected' THEN 0 ELSE 1 END, - COALESCE(r.index, 0) ASC, + COALESCE(ro.`order`, 999999) ASC, + COALESCE(r.route, 999999) ASC, po.code ASC, i.code ASC, il.expiryDate ASC, @@ -497,10 +499,9 @@ open fun getCompletedJobOrderLotsHierarchical(userId: Long): Map { -- Router Information r.id as routerId, - r.index as routerIndex, - r.route as routerRoute, - r.area as routerArea, - + ro.`order` as routerIndex, + CONCAT(COALESCE(ro.route_area, ''), COALESCE(r.route, '')) as routerRoute, + ro.route_area as routerArea, -- Set quantities to NULL for rejected lots CASE WHEN sol.status = 'rejected' THEN NULL @@ -573,6 +574,7 @@ open fun getCompletedJobOrderLotsHierarchical(userId: Long): Map { LEFT JOIN fpsmsdb.router r ON r.inventoryLotId = ill.id AND r.deleted = false LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + LEFT JOIN fpsmsdb.router_order ro ON r.router_id = ro.id LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ill.id AND sol.deleted = false LEFT JOIN fpsmsdb.jo_pick_order jpo ON jpo.pick_order_id = po.id AND jpo.item_id = pol.itemId WHERE po.deleted = false @@ -586,7 +588,8 @@ open fun getCompletedJobOrderLotsHierarchical(userId: Long): Map { AND jpo.second_qr_scan_status = 'pending' OR jpo.second_qr_scan_status = 'scanned' ORDER BY CASE WHEN sol.status = 'rejected' THEN 0 ELSE 1 END, - COALESCE(r.index, 0) ASC, + COALESCE(ro.`order`, 999999) ASC, + COALESCE(r.route, 999999) ASC, po.code ASC, i.code ASC, il.expiryDate ASC, @@ -1158,9 +1161,9 @@ open fun getCompletedJobOrderPickOrderLotDetails(pickOrderId: Long): List() { - @Column(name = "`index`", nullable = false) - open var index: Int? = null - @Size(max = 50) @Column(name = "route") - open var route: String? = null - - @Size(max = 50) - @Column(name = "area") - open var area: String? = null + open var route: Int? = null @Column(name = "item_code") open var itemCode: Int? = null @@ -31,9 +24,12 @@ open class Router : BaseEntity() { @Column(name = "uomId") open var uomId: Int? = null - @Column(name = "NoofCarton") - open var noofCarton: Int? = null - @Column(name = "inventoryLotId") open var inventoryLotId: Int? = null + + @Column(name = "router_id") + open var routerId: Int? = null + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "router_id", insertable = false, updatable = false) + open var routerOrder: RouterOrder? = null } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterOrder.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterOrder.kt new file mode 100644 index 0000000..99954fc --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterOrder.kt @@ -0,0 +1,20 @@ +package com.ffii.fpsms.modules.pickOrder.entity + +import com.ffii.core.entity.BaseEntity +import jakarta.persistence.* +import jakarta.validation.constraints.NotNull +import jakarta.validation.constraints.Size +import java.math.BigDecimal + +@Entity +@Table(name = "router_order") +open class RouterOrder : BaseEntity() { + + @Size(max = 50) + @Column(name = "route_area") + open var routeArea: String? = null + + @Column(name = "`order`") + open var order: Int? = null + +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterOrderRepository.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterOrderRepository.kt new file mode 100644 index 0000000..77ac6c0 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterOrderRepository.kt @@ -0,0 +1,16 @@ +package com.ffii.fpsms.modules.pickOrder.entity + +import com.ffii.core.support.AbstractRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.query.Param +import org.springframework.stereotype.Repository + +@Repository +interface RouterOrderRepository : AbstractRepository { + + @Query("SELECT ro FROM RouterOrder ro WHERE ro.routeArea = :routeArea AND ro.deleted = false") + fun findByRouteAreaAndDeletedFalse(@Param("routeArea") routeArea: String): RouterOrder? + + @Query("SELECT ro FROM RouterOrder ro WHERE ro.deleted = false ORDER BY ro.order ASC") + fun findAllByDeletedFalseOrderByOrder(): List +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterRepository.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterRepository.kt index caeedc3..eb7adf6 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/RouterRepository.kt @@ -17,11 +17,9 @@ interface RouterRepository : AbstractRepository { @Query("SELECT r FROM Router r WHERE r.itemCode = :itemCode AND r.deleted = false") fun findByItemCodeAndDeletedFalse(@Param("itemCode") itemCode: Int): List - @Query("SELECT r FROM Router r WHERE r.`index` = :index AND r.deleted = false") - fun findByIndexAndDeletedFalse(@Param("index") index: Int): List - @Query("SELECT r FROM Router r WHERE r.route = :route AND r.deleted = false") - fun findByRouteAndDeletedFalse(@Param("route") route: String): List - - + fun findByRouteAndDeletedFalse(@Param("route") route: Int): List + + @Query("SELECT r FROM Router r WHERE r.routerId = :routerId AND r.deleted = false") + fun findByRouterIdAndDeletedFalse(@Param("routerId") routerId: Int): List } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/Truck.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/Truck.kt index 58a48a5..d303941 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/Truck.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/Truck.kt @@ -5,7 +5,6 @@ import com.ffii.fpsms.modules.master.entity.Shop import jakarta.persistence.* import jakarta.validation.constraints.NotNull import jakarta.validation.constraints.Size -import java.math.BigDecimal import java.time.LocalTime @Entity @@ -14,12 +13,8 @@ open class Truck : BaseEntity() { @Size(max = 50) @NotNull - @Column(name = "truckNo", nullable = false, unique = true) - open var truckNo: String? = null - - @Size(max = 100) - @Column(name = "truckName") - open var truckName: String? = null + @Column(name = "TruckLanceCode", nullable = false) + open var truckLanceCode: String? = null @Column(name = "DepartureTime") open var departureTime: LocalTime? = null @@ -27,11 +22,16 @@ open class Truck : BaseEntity() { @ManyToOne @JoinColumn(name = "shopId") open var shop: Shop? = null - - @Column(name = "capacity", precision = 10, scale = 2) - open var capacity: BigDecimal? = null - - @Size(max = 20) - @Column(name = "status") - open var status: String? = null + + @Column(name = "ShopName", length = 255) + open var shopName: String? = null + + @Column(name = "ShopCode", length = 50) + open var shopCode: String? = null + + @Column(name = "LoadingSequence") + open var loadingSequence: Int? = null + + @Column(name = "Store_id") + open var storeId: Int? = null } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/TruckRepository.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/TruckRepository.kt index 92aaa4e..3071714 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/TruckRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/TruckRepository.kt @@ -8,15 +8,20 @@ import org.springframework.stereotype.Repository @Repository interface TruckRepository : AbstractRepository { - @Query("SELECT t FROM Truck t WHERE t.shop.id = :shopId AND t.deleted = false") - fun findByShopIdAndDeletedFalse(@Param("shopId") shopId: Long): List + fun findByShopIdAndDeletedFalse(shopId: Long): List @Query("SELECT t FROM Truck t WHERE t.shop.id = :shopId AND t.deleted = false ORDER BY t.id ASC") - fun findFirstByShopIdAndDeletedFalse(@Param("shopId") shopId: Long): List // ✅ Change to List + fun findFirstByShopIdAndDeletedFalse(@Param("shopId") shopId: Long): List - @Query("SELECT t FROM Truck t WHERE t.truckNo = :truckNo AND t.deleted = false") - fun findByTruckNoAndDeletedFalse(@Param("truckNo") truckNo: String): Truck? + // ✅ 使用新的 TruckLanceCode 字段名 + @Query("SELECT t FROM Truck t WHERE t.truckLanceCode = :truckLanceCode AND t.deleted = false") + fun findByTruckLanceCodeAndDeletedFalse(@Param("truckLanceCode") truckLanceCode: String): Truck? - @Query("SELECT t FROM Truck t WHERE t.status = :status AND t.deleted = false") - fun findByStatusAndDeletedFalse(@Param("status") status: String): List + + // ✅ 按 ShopCode 查询 + @Query("SELECT t FROM Truck t WHERE t.shopCode = :shopCode AND t.deleted = false") + fun findByShopCodeAndDeletedFalse(@Param("shopCode") shopCode: String): List + + // ✅ 按 Store_id 查询 + fun findByStoreIdAndDeletedFalse(storeId: Int): List } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt index 15ad557..ffa09da 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt @@ -494,13 +494,6 @@ open class PickOrderService( ) } - // Actual Pick Lots -// val actualPickLots = pol.stockOutLines -// val finalActualPickLots = actualPickLots.map { -// ActualPickLotInConso( -// -// ) -// } // Return PickOrderLineInConso( @@ -2221,245 +2214,257 @@ open fun autoAssignAndReleasePickOrderByStoreAndTicket(storeId: String, ticketNo } } @Transactional(rollbackFor = [java.lang.Exception::class]) -open fun autoAssignAndReleasePickOrderByStore(userId: Long, storeId: String): MessageResponse { - try { - println("=== DEBUG: autoAssignAndReleasePickOrderByStore ===") - println("userId: $userId, storeId: $storeId") - - val zero = BigDecimal.ZERO - val releasedBy = SecurityUtils.getUser().getOrNull() - val user = userService.find(userId).orElse(null) - if (user == null) { - return MessageResponse(id = null, name = "User not found", code = "ERROR", type = "pickorder", - message = "User with ID $userId not found", errorPosition = null) - } - - val sql = """ - SELECT DISTINCT dpo.pick_order_id AS pickOrderId - FROM do_pick_order dpo - WHERE dpo.deleted = false - AND dpo.ticket_status = 'pending' - AND dpo.store_id = :storeId - AND dpo.pick_order_id IS NOT NULL - """.trimIndent() - val idRows = jdbcDao.queryForList(sql, mapOf("storeId" to storeId)) - val pickOrderIdsByStore = idRows.mapNotNull { row -> - when (val id = row["pickOrderId"]) { - is Number -> id.toLong() - is String -> id.toLongOrNull() - else -> null + open fun autoAssignAndReleasePickOrderByStore(userId: Long, storeId: String): MessageResponse { + try { + println("=== DEBUG: autoAssignAndReleasePickOrderByStore ===") + println("userId: $userId, storeId: $storeId") + + val zero = BigDecimal.ZERO + val releasedBy = SecurityUtils.getUser().getOrNull() + val user = userService.find(userId).orElse(null) + if (user == null) { + return MessageResponse(id = null, name = "User not found", code = "ERROR", type = "pickorder", + message = "User with ID $userId not found", errorPosition = null) } - }.toSet() - println("Candidate pickOrderIds by store $storeId: $pickOrderIdsByStore") - - if (pickOrderIdsByStore.isEmpty()) { - return MessageResponse(id = null, name = "No pick orders", code = "NO_ORDERS", type = "pickorder", - message = "No pending pick orders found for store $storeId", errorPosition = null) - } - - // Add this check after line 2142 (before finding availablePickOrders) - // ✅ Check if user already has pick orders in progress - val userExistingOrders = pickOrderRepository.findAllByAssignToAndStatusIn( - user, - listOf(PickOrderStatus.PENDING, PickOrderStatus.RELEASED) // Only active orders, not completed - ).filter { it.deliveryOrder != null } - - if (userExistingOrders.isNotEmpty()) { - println("🔍 DEBUG: User $userId already has ${userExistingOrders.size} pick orders in progress:") - userExistingOrders.forEach { po -> - println("�� DEBUG: Existing order ${po.id}: code=${po.code}, status=${po.status}") + + val sql = """ + SELECT DISTINCT dpo.pick_order_id AS pickOrderId + FROM do_pick_order dpo + WHERE dpo.deleted = false + AND dpo.ticket_status = 'pending' + AND dpo.store_id = :storeId + AND dpo.pick_order_id IS NOT NULL + """.trimIndent() + val idRows = jdbcDao.queryForList(sql, mapOf("storeId" to storeId)) + val pickOrderIdsByStore = idRows.mapNotNull { row -> + when (val id = row["pickOrderId"]) { + is Number -> id.toLong() + is String -> id.toLongOrNull() + else -> null + } + }.toSet() + println("Candidate pickOrderIds by store $storeId: $pickOrderIdsByStore") + + if (pickOrderIdsByStore.isEmpty()) { + return MessageResponse(id = null, name = "No pick orders", code = "NO_ORDERS", type = "pickorder", + message = "No pending pick orders found for store $storeId", errorPosition = null) } - return MessageResponse( - id = null, - name = "User already has pick orders", - code = "USER_BUSY", - type = "pickorder", - message = "User $userId already has ${userExistingOrders.size} pick orders in progress. Cannot assign new orders.", - errorPosition = null, - entity = mapOf( - "existingOrders" to userExistingOrders.map { mapOf( - "id" to it.id, - "code" to it.code, - "status" to it.status?.value - )} + + // ✅ Check if user already has pick orders in progress + val userExistingOrders = pickOrderRepository.findAllByAssignToAndStatusIn( + user, + listOf(PickOrderStatus.PENDING, PickOrderStatus.RELEASED) + ).filter { it.deliveryOrder != null } + + if (userExistingOrders.isNotEmpty()) { + println("🔍 DEBUG: User $userId already has ${userExistingOrders.size} pick orders in progress:") + userExistingOrders.forEach { po -> + println("🔍 DEBUG: Existing order ${po.id}: code=${po.code}, status=${po.status}") + } + return MessageResponse( + id = null, + name = "User already has pick orders", + code = "USER_BUSY", + type = "pickorder", + message = "User $userId already has ${userExistingOrders.size} pick orders in progress. Cannot assign new orders.", + errorPosition = null, + entity = mapOf( + "existingOrders" to userExistingOrders.map { mapOf( + "id" to it.id, + "code" to it.code, + "status" to it.status?.value + )} + ) ) - ) - } - - // Continue with existing logic... - val availablePickOrders = pickOrderRepository - .findAll() - .filter { it.id != null && pickOrderIdsByStore.contains(it.id!!) } - .filter { it.deliveryOrder != null } - .filter { it.assignTo == null } - .filter { it.status == PickOrderStatus.PENDING || it.status == PickOrderStatus.RELEASED } - .sortedBy { it.targetDate } - .take(1) - - if (availablePickOrders.isEmpty()) { - return MessageResponse(id = null, name = "No available pick orders", code = "NO_ORDERS", type = "pickorder", - message = "No unassigned pick orders available for store $storeId", errorPosition = null) - } - - val selected = availablePickOrders.first() - val currUser = SecurityUtils.getUser().orElseThrow() - - // If still PENDING, perform full release flow; if already RELEASED, skip creation duplication - if (selected.status == PickOrderStatus.PENDING) { - val newConsoCode = assignConsoCode() - - val stockOut = StockOut().apply { - this.type = "job" - this.consoPickOrderCode = newConsoCode - this.status = StockOutStatus.PENDING.status - this.handler = currUser.id } - val savedStockOut = stockOutRepository.saveAndFlush(stockOut) - - selected.apply { - this.releasedBy = releasedBy - status = PickOrderStatus.RELEASED - this.consoCode = newConsoCode + + val availablePickOrders = pickOrderRepository + .findAll() + .filter { it.id != null && pickOrderIdsByStore.contains(it.id!!) } + .filter { it.deliveryOrder != null } + .filter { it.assignTo == null } + .filter { it.status == PickOrderStatus.PENDING || it.status == PickOrderStatus.RELEASED } + .sortedBy { it.targetDate } + .take(1) + + if (availablePickOrders.isEmpty()) { + return MessageResponse(id = null, name = "No available pick orders", code = "NO_ORDERS", type = "pickorder", + message = "No unassigned pick orders available for store $storeId", errorPosition = null) } - - val suggestions = suggestedPickLotService.suggestionForPickOrders( - SuggestedPickLotForPoRequest(pickOrders = listOf(selected)) - ) - val saveSuggestedPickLots = suggestedPickLotService.saveAll(suggestions.suggestedList) - pickOrderRepository.saveAndFlush(selected) - - val inventoryLotLines = inventoryLotLineRepository.findAllByIdIn( - saveSuggestedPickLots.mapNotNull { it.suggestedLotLine?.id } - ) - saveSuggestedPickLots.forEach { lot -> - val lotLineId = lot.suggestedLotLine?.id - if (lotLineId != null) { - val idx = inventoryLotLines.indexOf(lot.suggestedLotLine) - if (idx >= 0) { - val currentHold = inventoryLotLines[idx].holdQty ?: zero - val addHold = lot.qty ?: zero - inventoryLotLines[idx].holdQty = currentHold.plus(addHold) + + val selected = availablePickOrders.first() + val currUser = SecurityUtils.getUser().orElseThrow() + + // If still PENDING, perform full release flow + if (selected.status == PickOrderStatus.PENDING) { + val newConsoCode = assignConsoCode() + + val stockOut = StockOut().apply { + this.type = "job" + this.consoPickOrderCode = newConsoCode + this.status = StockOutStatus.PENDING.status + this.handler = currUser.id + } + val savedStockOut = stockOutRepository.saveAndFlush(stockOut) + + selected.apply { + this.releasedBy = releasedBy + status = PickOrderStatus.RELEASED + this.consoCode = newConsoCode + } + + val suggestions = suggestedPickLotService.suggestionForPickOrders( + SuggestedPickLotForPoRequest(pickOrders = listOf(selected)) + ) + val saveSuggestedPickLots = suggestedPickLotService.saveAll(suggestions.suggestedList) + pickOrderRepository.saveAndFlush(selected) + + val inventoryLotLines = inventoryLotLineRepository.findAllByIdIn( + saveSuggestedPickLots.mapNotNull { it.suggestedLotLine?.id } + ) + saveSuggestedPickLots.forEach { lot -> + val lotLineId = lot.suggestedLotLine?.id + if (lotLineId != null) { + val idx = inventoryLotLines.indexOf(lot.suggestedLotLine) + if (idx >= 0) { + val currentHold = inventoryLotLines[idx].holdQty ?: zero + val addHold = lot.qty ?: zero + inventoryLotLines[idx].holdQty = currentHold.plus(addHold) + } } } - } - inventoryLotLineRepository.saveAll(inventoryLotLines) - - var precreated = 0 - saveSuggestedPickLots.forEach { lot -> - val polId = lot.pickOrderLine?.id - val illId = lot.suggestedLotLine?.id - if (polId != null && illId != null) { - val existing = stockOutLIneRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse(polId, illId) - if (existing.isEmpty()) { - val pol = pickOrderLineRepository.findById(polId).orElse(null) - val ill = inventoryLotLineRepository.findById(illId).orElse(null) - if (pol != null && ill != null) { - val line = com.ffii.fpsms.modules.stock.entity.StockOutLine().apply { - this.stockOut = savedStockOut - this.pickOrderLine = pol - this.inventoryLotLine = ill - this.item = pol.item - this.status = com.ffii.fpsms.modules.stock.web.model.StockOutLineStatus.PENDING.status - this.qty = 0.0 + inventoryLotLineRepository.saveAll(inventoryLotLines) + + var precreated = 0 + saveSuggestedPickLots.forEach { lot -> + val polId = lot.pickOrderLine?.id + val illId = lot.suggestedLotLine?.id + if (polId != null && illId != null) { + val existing = stockOutLIneRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse(polId, illId) + if (existing.isEmpty()) { + val pol = pickOrderLineRepository.findById(polId).orElse(null) + val ill = inventoryLotLineRepository.findById(illId).orElse(null) + if (pol != null && ill != null) { + val line = com.ffii.fpsms.modules.stock.entity.StockOutLine().apply { + this.stockOut = savedStockOut + this.pickOrderLine = pol + this.inventoryLotLine = ill + this.item = pol.item + this.status = com.ffii.fpsms.modules.stock.web.model.StockOutLineStatus.PENDING.status + this.qty = 0.0 + } + stockOutLIneRepository.save(line) + precreated++ } - stockOutLIneRepository.save(line) - precreated++ } } } + println("Precreated $precreated stock out lines for store $storeId") } - println("Precreated $precreated stock out lines for store $storeId") - } - - // Assign user (both pending->released and already released) - selected.assignTo = user - pickOrderRepository.saveAndFlush(selected) - val deliveryOrder = selected.deliveryOrder - if (deliveryOrder != null) { - val targetDate = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now() - val datePrefix = targetDate.format(DateTimeFormatter.ofPattern("ddMMyy")) - - println("�� DEBUG: Target date: $targetDate, Date prefix: $datePrefix") - - val storeId = if (deliveryOrder.supplier?.code == "P06B") "4/F" else "2/F" - println("🔍 DEBUG: Determined store ID: $storeId") - - // Get next ticket number for this date and store - val nextTicketNumber = doPickOrderService.getNextTicketNumber(datePrefix, storeId) - println("🔍 DEBUG: Next ticket number: $nextTicketNumber") + + // Assign user (both pending->released and already released) + selected.assignTo = user + pickOrderRepository.saveAndFlush(selected) - // ✅ Find truck by shop ID with earliest departure time - val truck = deliveryOrder.shop?.id?.let { shopId -> - println("🔍 DEBUG: Looking for truck with shop ID: $shopId") - val trucks = truckRepository.findByShopIdAndDeletedFalse(shopId) - println("🔍 DEBUG: Found ${trucks.size} trucks for shop $shopId") - val selectedTruck = trucks.minByOrNull { it.departureTime ?: LocalTime.MAX } - println("🔍 DEBUG: Selected truck: ID=${selectedTruck?.id}, DepartureTime=${selectedTruck?.departureTime}") - selectedTruck + // ✅ 更新 DoPickOrderRecord,填充新字段 + val deliveryOrder = selected.deliveryOrder + if (deliveryOrder != null) { + val targetDate = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now() + val datePrefix = targetDate.format(DateTimeFormatter.ofPattern("ddMMyy")) + + println("🔍 DEBUG: Target date: $targetDate, Date prefix: $datePrefix") + + // ✅ Find truck by shop ID with earliest departure time + val truck = deliveryOrder.shop?.id?.let { shopId -> + println("🔍 DEBUG: Looking for truck with shop ID: $shopId") + val trucks = truckRepository.findByShopIdAndDeletedFalse(shopId) + println("🔍 DEBUG: Found ${trucks.size} trucks for shop $shopId") + val selectedTruck = trucks.minByOrNull { it.departureTime ?: LocalTime.MAX } + println("🔍 DEBUG: Selected truck: ID=${selectedTruck?.id}, DepartureTime=${selectedTruck?.departureTime}") + selectedTruck + } + + // ✅ 根据 truck 的 Store_id 字段确定 storeId + val determinedStoreId = when (truck?.storeId) { + 4 -> "4/F" + 2 -> "2/F" + else -> "2/F" + } + + // Get next ticket number for this date and store + val nextTicketNumber = doPickOrderService.getNextTicketNumber(datePrefix, determinedStoreId) + println("🔍 DEBUG: Next ticket number: $nextTicketNumber") + + println("🔍 DEBUG: Processing ${deliveryOrder.deliveryOrderLines.size} delivery order lines") + + // ✅ UPDATE existing do_pick_order_record entries instead of creating new ones + val existingRecords = doPickOrderRecordRepository.findByPickOrderId(selected.id!!) + println("🔍 DEBUG: Found ${existingRecords.size} existing DoPickOrderRecord entries for pick order ${selected.id}") + + if (existingRecords.isNotEmpty()) { + // ✅ Update existing records + existingRecords.forEach { record -> + record.handledBy = user.id + record.ticketStatus = DoPickOrderStatus.released + // ✅ 填充新字段 + record.truckLanceCode = truck?.truckLanceCode + record.shopCode = deliveryOrder.shop?.code + record.shopName = deliveryOrder.shop?.name + record.requiredDeliveryDate = targetDate + println("🔍 DEBUG: Updating existing DoPickOrderRecord ID: ${record.id} - handledBy: ${user.id}, status: released") + } + doPickOrderRecordRepository.saveAll(existingRecords) + println("✅ Updated ${existingRecords.size} existing DoPickOrderRecord entries") + } else { + // ✅ Only create new records if none exist (fallback) + println("⚠️ No existing DoPickOrderRecord entries found, creating new ones") + deliveryOrder.deliveryOrderLines.forEach { line -> + println("🔍 DEBUG: Processing line - Store ID: $determinedStoreId") + + val doPickOrderRecord = DoPickOrderRecord( + storeId = determinedStoreId, + ticketNo = nextTicketNumber, + ticketStatus = DoPickOrderStatus.released, + truckId = truck?.id, + pickOrderId = selected.id, + truckDepartureTime = truck?.departureTime, + shopId = deliveryOrder.shop?.id, + handledBy = user.id, + // ✅ 填充新增字段 + truckLanceCode = truck?.truckLanceCode, + shopCode = deliveryOrder.shop?.code, + shopName = deliveryOrder.shop?.name, + requiredDeliveryDate = targetDate + ) + + println("🔍 DEBUG: Creating new DoPickOrderRecord - Store: $determinedStoreId, Ticket: $nextTicketNumber, Truck: ${truck?.id}") + + val savedDoPickOrderRecord = doPickOrderRecordRepository.save(doPickOrderRecord) + println("🔍 DEBUG: Saved new DoPickOrderRecord - ID: ${savedDoPickOrderRecord.id}") + } + } } - println("🔍 DEBUG: Processing ${deliveryOrder.deliveryOrderLines.size} delivery order lines") + doPickOrderService.updateHandledByForPickOrder(selected.id!!, user.id!!) + println("✅ Updated DoPickOrder handledBy to user $userId for pick order ${selected.id}") - // Replace lines 2253-2275 with this: -// ✅ UPDATE existing do_pick_order_record entries instead of creating new ones -val existingRecords = doPickOrderRecordRepository.findByPickOrderId(selected.id!!) -println("🔍 DEBUG: Found ${existingRecords.size} existing DoPickOrderRecord entries for pick order ${selected.id}") - -if (existingRecords.isNotEmpty()) { - // ✅ Update existing records - existingRecords.forEach { record -> - record.handledBy = user.id - record.ticketStatus = DoPickOrderStatus.released - println("🔍 DEBUG: Updating existing DoPickOrderRecord ID: ${record.id} - handledBy: ${user.id}, status: released") - } - doPickOrderRecordRepository.saveAll(existingRecords) - println("✅ Updated ${existingRecords.size} existing DoPickOrderRecord entries") -} else { - // ✅ Only create new records if none exist (fallback) - println("⚠️ No existing DoPickOrderRecord entries found, creating new ones") - deliveryOrder.deliveryOrderLines.forEach { line -> - val storeId = if (deliveryOrder.supplier?.code == "P06B") "4/F" else "2/F" - println(" DEBUG: Processing line - Item ID: ${line.item?.id}, Store ID: $storeId") - - val doPickOrderRecord = DoPickOrderRecord( - storeId = storeId, - ticketNo = nextTicketNumber, - ticketStatus = DoPickOrderStatus.released, // ✅ Set to released - truckId = truck?.id, - pickOrderId = selected.id, - truckDepartureTime = truck?.departureTime, - itemId = line.item?.id, - shopId = deliveryOrder.shop?.id, - shopPoSupplierId = deliveryOrder.shop?.id, - handledBy = user.id - ) - - println(" DEBUG: Creating new DoPickOrderRecord - Store: $storeId, Ticket: $nextTicketNumber, Truck: ${truck?.id}") - - val savedDoPickOrderRecord = doPickOrderRecordRepository.save(doPickOrderRecord) - println("🔍 DEBUG: Saved new DoPickOrderRecord - ID: ${savedDoPickOrderRecord.id}") - } -} + return MessageResponse( + id = null, + name = "Pick order assigned", + code = "SUCCESS", + type = "pickorder", + message = "Assigned to user $userId for store $storeId", + errorPosition = null, + entity = mapOf("pickOrderIds" to listOf(selected.id!!), "storeId" to storeId, "status" to selected.status?.value) + ) + } catch (e: Exception) { + e.printStackTrace() + return MessageResponse( + id = null, name = "Failed to auto-assign by store", code = "ERROR", type = "pickorder", + message = "Failed to auto-assign by store: ${e.message}", errorPosition = null + ) } - doPickOrderService.updateHandledByForPickOrder(selected.id!!, user.id!!) - println("✅ Updated DoPickOrder handledBy to user $userId for pick order ${selected.id}") - return MessageResponse( - id = null, - name = "Pick order assigned", - code = "SUCCESS", - type = "pickorder", - message = "Assigned to user $userId for store $storeId", - errorPosition = null, - entity = mapOf("pickOrderIds" to listOf(selected.id!!), "storeId" to storeId, "status" to selected.status?.value) - ) - } catch (e: Exception) { - e.printStackTrace() - return MessageResponse( - id = null, name = "Failed to auto-assign by store", code = "ERROR", type = "pickorder", - message = "Failed to auto-assign by store: ${e.message}", errorPosition = null - ) } -} open fun getAllPickOrderLotsWithDetailsWithAutoAssign(userId: Long): List> { println("=== Debug: getAllPickOrderLotsWithDetailsWithAutoAssign ===") println("today: ${LocalDate.now()}") @@ -2642,13 +2647,13 @@ if (existingRecords.isNotEmpty()) { val router = routerRepository.findFirstByInventoryLotIdAndDeletedFalse(inventoryLotId.toInt()) if (router != null) { mapOf( - "routerIndex" to (router.index ?: 0), - "routerRoute" to (router.route ?: ""), - "routerArea" to (router.area ?: ""), + "routerIndex" to (router.routerOrder?.order ?: 0), + "routerRoute" to "${router.routerOrder?.routeArea ?: ""}${router.route ?: ""}", + "routerArea" to (router.routerOrder?.routeArea ?: ""), "routerItemCode" to (router.itemCode ?: 0), "routerItemName" to (router.itemName ?: ""), "routerUomId" to (router.uomId ?: 0), - "routerNoofCarton" to (router.noofCarton ?: 0) + ) } else { mapOf( @@ -2715,7 +2720,7 @@ if (existingRecords.isNotEmpty()) { val truckInfo = if (shop?.id != null) { try { jdbcDao.queryForMap(""" - SELECT truckNo, DepartureTime + SELECT TruckLanceCode, DepartureTime FROM truck WHERE shopId = :shopId AND deleted = false LIMIT 1 @@ -2741,7 +2746,7 @@ if (existingRecords.isNotEmpty()) { "shopAddress" to buildShopAddress(shop), "shopPoNo" to (supplier?.code ?: ""), "numberOfCartons" to (po.pickOrderLines.size), - "truckNo" to (truckInfo?.get("truckNo") ?: ""), // ✅ Add truck number + "TruckLanceCode" to (truckInfo?.get("TruckLanceCode") ?: ""), // ✅ Add truck number "DepartureTime" to (truckInfo?.get("DepartureTime") ?: ""), // ✅ Add departure time "qrCodeData" to (po.id ?: 0L) ) @@ -2767,10 +2772,7 @@ if (existingRecords.isNotEmpty()) { println("❌ Pick order not found with ID: $pickOrderId") return emptyList() } - if (doPickOrderRepository.findByPickOrderId(pickOrderId).firstOrNull()?.hide == true) { - println("🔍 Pick order $pickOrderId is hidden, returning empty list") - return emptyList() - } + println("🔍 Found pick order: ${pickOrder.code}, type: ${pickOrder.type?.value}, status: ${pickOrder.status?.value}") if (pickOrder.type?.value != "do") { @@ -2801,14 +2803,14 @@ if (existingRecords.isNotEmpty()) { val trucksForShop = truckRepository.findByShopIdAndDeletedFalse(shop.id) println("🔍 Trucks for shop ${shop.id}: ${trucksForShop.size}") trucksForShop.forEach { t -> - println(" - Truck ID: ${t.id}, TruckNo: ${t.truckNo}, ShopId: ${t.shop?.id}, Deleted: ${t.deleted}") + println(" - Truck ID: ${t.id}, truckLanceCode: ${t.truckLanceCode}, ShopId: ${t.shop?.id}, Deleted: ${t.deleted}") } // Take the first truck (or null if none found) val selectedTruck = trucksForShop.firstOrNull() if (selectedTruck != null) { - println("✅ Selected truck: ID=${selectedTruck.id}, TruckNo=${selectedTruck.truckNo}, DepartureTime=${selectedTruck.departureTime}") + println("✅ Selected truck: ID=${selectedTruck.id}, truckLanceCode=${selectedTruck.truckLanceCode}, DepartureTime=${selectedTruck.departureTime}") } else { println("❌ No truck found for shopId ${shop.id}") } @@ -2854,7 +2856,7 @@ if (existingRecords.isNotEmpty()) { "shopAddress" to buildShopAddress(shop), "shopPoNo" to (supplier?.code ?: ""), "numberOfCartons" to (pickOrder.pickOrderLines.size), - "truckNo" to (truck?.truckNo ?: ""), // ✅ Use entity property + "truckLanceCode" to (truck?.truckLanceCode ?: ""), // ✅ Use entity property "DepartureTime" to (truck?.departureTime?.toString() ?: ""), "ticketNo" to ticketNo, "storeId" to dpoStoreId, @@ -2880,10 +2882,7 @@ if (existingRecords.isNotEmpty()) { println("❌ Pick order not found with ID: $pickOrderId") return emptyList() } - if (doPickOrderRepository.findByPickOrderId(pickOrderId).firstOrNull()?.hide == true) { - println("🔍 Pick order $pickOrderId is hidden, returning empty list") - return emptyList() - } + println("🔍 Found pick order: ${pickOrder.code}, type: ${pickOrder.type?.value}, status: ${pickOrder.status?.value}") if (pickOrder.type?.value != "do") { @@ -2914,14 +2913,14 @@ if (existingRecords.isNotEmpty()) { val trucksForShop = truckRepository.findByShopIdAndDeletedFalse(shop.id) println("🔍 Trucks for shop ${shop.id}: ${trucksForShop.size}") trucksForShop.forEach { t -> - println(" - Truck ID: ${t.id}, TruckNo: ${t.truckNo}, ShopId: ${t.shop?.id}, Deleted: ${t.deleted}") + println(" - Truck ID: ${t.id}, TruckLanceCode: ${t.truckLanceCode}, ShopId: ${t.shop?.id}, Deleted: ${t.deleted}") } // Take the first truck (or null if none found) val selectedTruck = trucksForShop.firstOrNull() if (selectedTruck != null) { - println("✅ Selected truck: ID=${selectedTruck.id}, TruckNo=${selectedTruck.truckNo}, DepartureTime=${selectedTruck.departureTime}") + println("✅ Selected truck: ID=${selectedTruck.id}, TruckLanceCode=${selectedTruck.truckLanceCode}, DepartureTime=${selectedTruck.departureTime}") } else { println("❌ No truck found for shopId ${shop.id}") } @@ -2967,7 +2966,7 @@ if (existingRecords.isNotEmpty()) { "shopAddress" to buildShopAddress(shop), "shopPoNo" to (supplier?.code ?: ""), "numberOfCartons" to (pickOrder.pickOrderLines.size), - "truckNo" to (truck?.truckNo ?: ""), // ✅ Use entity property + "TruckLanceCode" to (truck?.truckLanceCode ?: ""), // ✅ Use entity property "DepartureTime" to (truck?.departureTime?.toString() ?: ""), "ticketNo" to ticketNo, "storeId" to dpoStoreId, @@ -3093,16 +3092,18 @@ open fun getAllPickOrderLotsWithDetailsWithoutAutoAssign(userId: Long): List - val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrder.id!!) - doPickOrders.none { it.hide } // 只显示 hide = false 的订单 - } + // ✅ NEW LOGIC: Filter based on assignment and status - val filteredPickOrders = if (visiblePickOrders.isNotEmpty()) { + val filteredPickOrders = if (allAssignedPickOrders.isNotEmpty()) { // Check if there are any RELEASED orders assigned to this user (active work) val assignedReleasedOrders = allAssignedPickOrders.filter { it.status == PickOrderStatus.RELEASED && it.assignTo?.id == userId @@ -3315,7 +3314,7 @@ open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map - doPickOrder.hide = hide - doPickOrderRepository.save(doPickOrder) - } - - MessageResponse( - id = null, - name = "Hide status updated", - code = "SUCCESS", - type = "pickorder", - message = "Updated hide status for ${doPickOrders.size} do_pick_order records to $hide", - errorPosition = null - ) - } - } catch (e: Exception) { - println("❌ Error in updateDoPickOrderHideStatus: ${e.message}") - e.printStackTrace() - MessageResponse( - id = null, - name = "Failed to update hide status", - code = "ERROR", - type = "pickorder", - message = "Failed to update hide status: ${e.message}", - errorPosition = null - ) - } -} + open fun getCompletedDoPickOrders( userId: Long, pickOrderCode: String?, @@ -3914,7 +3874,7 @@ open fun getCompletedDoPickOrders( "ticketNo" to firstFgOrder["ticketNo"], "shopPoNo" to firstFgOrder["shopPoNo"], "numberOfCartons" to firstFgOrder["numberOfCartons"], - "truckNo" to firstFgOrder["truckNo"], + "TruckLanceCode" to firstFgOrder["TruckLanceCode"], "storeId" to firstFgOrder["storeId"], "completedDate" to (pickOrder.completeDate?.toString() ?: pickOrder.modified?.toString()), "fgPickOrders" to fgPickOrders @@ -3990,8 +3950,9 @@ open fun getLotDetailsByPickOrderId(pickOrderId: Long): List> { -- Router Information r.id as routerId, - r.index as routerIndex, - r.route as routerRoute, + ro.`order` as routerIndex, + CONCAT(COALESCE(ro.route_area, ''), COALESCE(r.route, '')) as routerRoute, + -- Set quantities to NULL for rejected lots CASE @@ -4080,7 +4041,8 @@ open fun getLotDetailsByPickOrderId(pickOrderId: Long): List> { AND (spl.pickOrderLineId IS NOT NULL OR sol.pickOrderLineId IS NOT NULL) ORDER BY CASE WHEN sol.status = 'rejected' THEN 0 ELSE 1 END, -- Show rejected lots first - COALESCE(r.index, 0) ASC, + COALESCE(ro.`order`, 999999) ASC, + COALESCE(r.route, 999999) ASC, po.code ASC, i.code ASC, il.expiryDate ASC, diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt index 504d1d4..de897eb 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt @@ -287,13 +287,7 @@ fun getPickOrdersByStore(@PathVariable storeId: String): Map { fun confirmLotSubstitution(@RequestBody req: LotSubstitutionConfirmRequest): MessageResponse { return pickOrderService.confirmLotSubstitution(req) } -@PostMapping("/update-hide-status/{pickOrderId}") -fun updatePickOrderHideStatus( - @PathVariable pickOrderId: Long, - @RequestParam hide: Boolean -): MessageResponse { - return pickOrderService.updateDoPickOrderHideStatus(pickOrderId, hide) -} + @GetMapping("/completed-do-pick-orders/{userId}") fun getCompletedDoPickOrders( @PathVariable userId: Long, diff --git a/src/main/resources/db/changelog/changes/202511005_01_enson/01_altertable_enson.sql b/src/main/resources/db/changelog/changes/202511005_01_enson/01_altertable_enson.sql new file mode 100644 index 0000000..e4e14a8 --- /dev/null +++ b/src/main/resources/db/changelog/changes/202511005_01_enson/01_altertable_enson.sql @@ -0,0 +1,27 @@ +--liquibase formatted sql + +--changeset enson:update + +CREATE TABLE router_order ( + id int AUTO_INCREMENT PRIMARY KEY, + route_area varchar(255), + `order` int, + created datetime DEFAULT CURRENT_TIMESTAMP, + createdBy varchar(30), + version int DEFAULT 1, + modified datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + modifiedBy varchar(30), + deleted tinyint(1) DEFAULT 0 +); +ALTER TABLE router MODIFY COLUMN route VARCHAR(50) NULL; +-- Clear route data first (separate statement) +UPDATE router SET route = NULL WHERE route IS NOT NULL; + +-- All ALTER TABLE operations in one statement +ALTER TABLE router +ADD COLUMN router_id int, +ADD FOREIGN KEY (router_id) REFERENCES router_order(id), +CHANGE COLUMN `route` `route` INT NULL, +DROP COLUMN `index`, +DROP COLUMN area, +DROP COLUMN noofCarton; \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/202511005_01_enson/02_altertable_enson.sql b/src/main/resources/db/changelog/changes/202511005_01_enson/02_altertable_enson.sql new file mode 100644 index 0000000..43a5842 --- /dev/null +++ b/src/main/resources/db/changelog/changes/202511005_01_enson/02_altertable_enson.sql @@ -0,0 +1,68 @@ +--liquibase formatted sql + +--changeset enson:update + +ALTER TABLE truck +CHANGE COLUMN truckNo TruckLanceCode VARCHAR(50); + +-- Add new columns to truck +ALTER TABLE truck +ADD COLUMN ShopName VARCHAR(255), +ADD COLUMN ShopCode VARCHAR(50), +ADD COLUMN LoadingSequence INT, +ADD COLUMN Store_id INT; + +-- Drop columns from truck +ALTER TABLE truck +DROP COLUMN capacity, +DROP COLUMN status, +DROP COLUMN truckName; + +-- ========================================== +-- 2. Modify do_pick_order table +-- ========================================== + +-- Add new columns to do_pick_order +ALTER TABLE do_pick_order +ADD COLUMN ticketCompleteDateTime DATETIME, +ADD COLUMN TruckLanceCode VARCHAR(50), +ADD COLUMN ShopCode VARCHAR(50), +ADD COLUMN ShopName VARCHAR(255), +ADD COLUMN RequiredDeliveryDate DATE; + +-- Drop foreign key constraints first +ALTER TABLE do_pick_order +DROP FOREIGN KEY FK_DO_PICK_ORDER_ON_ITEM; + +ALTER TABLE do_pick_order +DROP FOREIGN KEY FK_DO_PICK_ORDER_ON_SHOP_PO_SUPPLIER; + +-- Drop columns from do_pick_order +ALTER TABLE do_pick_order +DROP COLUMN item_id, +DROP COLUMN shop_po_supplier_id, +DROP COLUMN hide; + +-- ========================================== +-- 3. Modify do_pick_order_record table +-- ========================================== + +-- Add new columns to do_pick_order_record +ALTER TABLE do_pick_order_record +ADD COLUMN ticketCompleteDateTime DATETIME, +ADD COLUMN TruckLanceCode VARCHAR(50), +ADD COLUMN ShopCode VARCHAR(50), +ADD COLUMN ShopName VARCHAR(255), +ADD COLUMN RequiredDeliveryDate DATE; + +-- Drop foreign key constraints for do_pick_order_record +ALTER TABLE do_pick_order_record +DROP FOREIGN KEY FK_DO_PICK_ORDER_REC_ON_ITEM; + +ALTER TABLE do_pick_order_record +DROP FOREIGN KEY FK_DO_PICK_ORDER_REC_ON_SHOP_PO_SUPPLIER; + +-- Drop columns from do_pick_order_record +ALTER TABLE do_pick_order_record +DROP COLUMN item_id, +DROP COLUMN shop_po_supplier_id; \ No newline at end of file