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 new file mode 100644 index 0000000..9f01462 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrderRecord.kt @@ -0,0 +1,97 @@ +package com.ffii.fpsms.modules.deliveryOrder.entity + +import jakarta.persistence.* +import java.time.LocalDateTime +import java.time.LocalTime +import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus +import org.hibernate.annotations.CreationTimestamp +import org.hibernate.annotations.UpdateTimestamp + +@Entity +@Table(name = "do_pick_order_record") +class DoPickOrderRecord { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + + @Column(name = "store_id", length = 10) + var storeId: String? = null + + @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 + + @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 + + @CreationTimestamp + @Column(name = "created") + var created: LocalDateTime? = null + + @Column(name = "createdBy", length = 30) + var createdBy: String? = null + + @Version + var version: Int = 0 + + @UpdateTimestamp + @Column(name = "modified") + var modified: LocalDateTime? = null + + @Column(name = "modifiedBy", length = 30) + var modifiedBy: String? = null + + @Column(name = "deleted") + var deleted: Boolean = false + + // Default constructor for Hibernate + constructor() + + // Constructor for creating new instances + constructor( + storeId: String, + ticketNo: String, + ticketStatus: DoPickOrderStatus, + truckId: Long? = null, + truckDepartureTime: LocalTime? = null, + pickOrderId: Long? = null, + itemId: Long? = null, + shopId: Long? = null, + shopPoSupplierId: Long? = null, + handledBy: Long? = null, + createdBy: String? = null, + modifiedBy: String? = null + ) { + this.storeId = storeId + this.ticketNo = ticketNo + this.pickOrderId = pickOrderId + this.ticketStatus = ticketStatus + this.truckId = truckId + this.truckDepartureTime = truckDepartureTime + this.itemId = itemId + this.shopId = shopId + this.shopPoSupplierId = shopPoSupplierId + this.handledBy = handledBy + this.createdBy = createdBy + this.modifiedBy = modifiedBy + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrderRecordRepository.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrderRecordRepository.kt new file mode 100644 index 0000000..d75e929 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/entity/DoPickOrderRecordRepository.kt @@ -0,0 +1,18 @@ +package com.ffii.fpsms.modules.deliveryOrder.entity + +import com.ffii.core.support.AbstractRepository +import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfo +import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderStatus +import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus +import com.ffii.fpsms.modules.master.entity.projections.SearchId +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.stereotype.Repository +import java.io.Serializable +import java.time.LocalDateTime + +@Repository +interface DoPickOrderRecordRepository : JpaRepository { + fun findByPickOrderId(pickOrderId: Long): List + fun findByTicketNoStartingWith(ticketPrefix: String): List +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/enums/DoPickOrderStatus.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/enums/DoPickOrderStatus.kt index c00f717..d7a6f70 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/enums/DoPickOrderStatus.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/enums/DoPickOrderStatus.kt @@ -2,5 +2,6 @@ package com.ffii.fpsms.modules.deliveryOrder.enums enum class DoPickOrderStatus(val value: String) { pending("pending"), + released("released"), completed("completed") } \ No newline at end of file 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 c54d035..7eaa7ec 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 @@ -46,7 +46,8 @@ import com.ffii.fpsms.modules.stock.web.model.StockOutLineStatus import com.ffii.fpsms.modules.stock.web.model.SuggestedPickLotForPolRequest import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository - +import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecord +import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecordRepository @Service open class DeliveryOrderService( private val deliveryOrderRepository: DeliveryOrderRepository, @@ -64,7 +65,8 @@ open class DeliveryOrderService( private val inventoryLotLineRepository: InventoryLotLineRepository, private val stockOutRepository: StockOutRepository, private val stockOutLineRepository: StockOutLIneRepository, - private val pickOrderLineRepository: PickOrderLineRepository + private val pickOrderLineRepository: PickOrderLineRepository, + private val doPickOrderRecordRepository: DoPickOrderRecordRepository ) { open fun findByM18DataLogId(m18DataLogId: Long): DeliveryOrder? { @@ -463,9 +465,9 @@ open class DeliveryOrderService( 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") + println(" DEBUG: Processing line - Item ID: ${line.item?.id}, Store ID: $storeId") - val doPickOrder = DoPickOrder( + val doPickOrderRecord = DoPickOrderRecord( // ✅ Use DoPickOrderRecord instead of DoPickOrder storeId = storeId, ticketNo = nextTicketNumber, ticketStatus = DoPickOrderStatus.pending, @@ -478,12 +480,32 @@ open class DeliveryOrderService( handledBy = null ) + println(" DEBUG: Creating DoPickOrderRecord - Store: $storeId, Ticket: $nextTicketNumber, Truck: ${truck?.id}") + + val savedDoPickOrderRecord = doPickOrderRecordRepository.save(doPickOrderRecord) // ✅ Now types match + println("🔍 DEBUG: Saved DoPickOrderRecord - ID: ${savedDoPickOrderRecord.id}") + + } + deliveryOrder.deliveryOrderLines.forEach { line -> + val storeId = if (deliveryOrder.supplier?.code == "P06B") "4/F" else "2/F" println("�� DEBUG: Creating DoPickOrder - Store: $storeId, Ticket: $nextTicketNumber, Truck: ${truck?.id}") + val doPickOrder = DoPickOrder( // ✅ Create DoPickOrder for assignment + 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 + ) + val savedDoPickOrder = doPickOrderService.save(doPickOrder) println("🔍 DEBUG: Saved DoPickOrder - ID: ${savedDoPickOrder.id}") } - return MessageResponse( id = deliveryOrder.id, code = deliveryOrder.code, 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 a2c64ad..a00380e 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 @@ -33,9 +33,12 @@ import java.math.BigDecimal import com.ffii.fpsms.modules.master.web.models.MessageResponse import java.time.LocalDateTime import com.ffii.fpsms.modules.deliveryOrder.web.models.AssignByStoreRequest +import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecord +import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecordRepository @Service class DoPickOrderService( - private val doPickOrderRepository: DoPickOrderRepository + private val doPickOrderRepository: DoPickOrderRepository, + private val doPickOrderRecordRepository: DoPickOrderRecordRepository ) { fun getNextTicketNumber(datePrefix: String): String { @@ -94,7 +97,52 @@ class DoPickOrderService( } fun updateHandledByForPickOrder(pickOrderId: Long, userId: Long): List { val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) - doPickOrders.forEach { it.handledBy = userId } + doPickOrders.forEach { it.handledBy = userId + it.ticketStatus = DoPickOrderStatus.released } return doPickOrderRepository.saveAll(doPickOrders) } + fun completeDoPickOrdersForPickOrder(pickOrderId: Long): List { + val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) + doPickOrders.forEach { + it.ticketStatus = DoPickOrderStatus.completed // ✅ Update status to "completed" + } + 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) + if (doPickOrders.isNotEmpty()) { + // Mark as deleted instead of physically deleting + doPickOrders.forEach { + it.ticketStatus = DoPickOrderStatus.completed + it.deleted = true } + doPickOrderRepository.saveAll(doPickOrders) + return doPickOrders.size + } + return 0 + } + + fun saveRecord(record: DoPickOrderRecord): DoPickOrderRecord { + return doPickOrderRecordRepository.save(record) + } + + // ✅ Add method to update DoPickOrderRecord status + fun updateRecordHandledByForPickOrder(pickOrderId: Long, userId: Long): List { + val doPickOrderRecords = doPickOrderRecordRepository.findByPickOrderId(pickOrderId) + doPickOrderRecords.forEach { + it.handledBy = userId + it.ticketStatus = DoPickOrderStatus.released + } + return doPickOrderRecordRepository.saveAll(doPickOrderRecords) + } + + // ✅ Add method to complete DoPickOrderRecord + fun completeDoPickOrderRecordsForPickOrder(pickOrderId: Long): List { + val doPickOrderRecords = doPickOrderRecordRepository.findByPickOrderId(pickOrderId) + doPickOrderRecords.forEach { + it.ticketStatus = DoPickOrderStatus.completed + } + return doPickOrderRecordRepository.saveAll(doPickOrderRecords) + } } \ 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 287379a..1cd13cd 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 @@ -10,6 +10,8 @@ import com.ffii.fpsms.modules.master.entity.UomConversionRepository import com.ffii.fpsms.modules.master.service.ItemUomService import com.ffii.fpsms.modules.master.web.models.MessageResponse import com.ffii.fpsms.modules.pickOrder.entity.PickOrder +import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus +import java.time.LocalTime import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLine import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository @@ -51,6 +53,9 @@ import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrderRepository import com.ffii.fpsms.modules.pickOrder.entity.TruckRepository import com.ffii.fpsms.modules.pickOrder.entity.RouterRepository import com.ffii.fpsms.modules.deliveryOrder.service.DoPickOrderService +import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrder +import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecord +import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecordRepository @Service open class PickOrderService( private val jdbcDao: JdbcDao, @@ -70,8 +75,10 @@ open class PickOrderService( private val itemUomService: ItemUomService, private val deliveryOrderRepository: DeliveryOrderRepository, private val truckRepository: TruckRepository, - private val routerRepository: RouterRepository, private val doPickOrderService: DoPickOrderService, + private val routerRepository: RouterRepository, + private val doPickOrderRecordRepository: DoPickOrderRecordRepository + ) : AbstractBaseEntityService(jdbcDao, pickOrderRepository) { open fun create(request: SavePickOrderRequest): MessageResponse { val code = assignPickCode() @@ -1209,9 +1216,17 @@ logger.info("Precreated $precreated stock out lines for suggested lots on releas pickOrder.completeDate = LocalDateTime.now() pickOrderRepository.save(pickOrder) println("✅ Updated pick order ${pickOrder.code} to COMPLETED status") + val removedCount = doPickOrderService.removeDoPickOrdersForPickOrder(pickOrderId) + println("✅ Removed $removedCount do_pick_order records for completed pick order ${pickOrderId}") + + // ✅ Update do_pick_order_record status to completed (don't remove) + doPickOrderService.completeDoPickOrderRecordsForPickOrder(pickOrderId) + println("✅ Updated do_pick_order_record status to COMPLETED for pick order ${pickOrderId}") } } } + // After updating pick order to COMPLETED status, add: + } return MessageResponse( @@ -2124,7 +2139,37 @@ open fun autoAssignAndReleasePickOrderByStore(userId: Long, storeId: String): Me 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}") + } + 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!!) } @@ -2212,7 +2257,70 @@ open fun autoAssignAndReleasePickOrderByStore(userId: Long, storeId: String): Me // 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") + + // Get next ticket number for this date + val nextTicketNumber = doPickOrderService.getNextTicketNumber(datePrefix) + println("�� DEBUG: Next ticket number: $nextTicketNumber") + + // ✅ 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 + } + + println("🔍 DEBUG: Processing ${deliveryOrder.deliveryOrderLines.size} delivery order lines") + + // 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}") + } +} + } doPickOrderService.updateHandledByForPickOrder(selected.id!!, user.id!!) println("✅ Updated DoPickOrder handledBy to user $userId for pick order ${selected.id}") return MessageResponse( @@ -2251,11 +2359,12 @@ open fun autoAssignAndReleasePickOrderByStore(userId: Long, storeId: String): Me // Get all pick orders assigned to user with PENDING or RELEASED status that have doId val allAssignedPickOrders = pickOrderRepository.findAllByAssignToAndStatusIn( user, - listOf(PickOrderStatus.PENDING, PickOrderStatus.RELEASED) + listOf(PickOrderStatus.PENDING, PickOrderStatus.RELEASED,PickOrderStatus.COMPLETED) + ).filter { it.deliveryOrder != null } // Only pick orders with doId - + println("🔍 DEBUG: All assigned pick orders: ${allAssignedPickOrders.size}") val pickOrderIds = allAssignedPickOrders.map { it.id!! } - + println("🔍 DEBUG: All assigned pick orders: ${pickOrderIds.size}") println(" Pick order IDs to fetch: $pickOrderIds") if (pickOrderIds.isEmpty()) { @@ -2546,7 +2655,7 @@ open fun autoAssignAndReleasePickOrderByStore(userId: Long, storeId: String): Me return emptyList() } - if (pickOrder.status?.value !in listOf("assigned", "released", "picking")) { + if (pickOrder.status?.value !in listOf("assigned", "released", "picking", "completed")) { println("❌ Pick order status is not in allowed states: ${pickOrder.status?.value}") return emptyList() } @@ -2650,11 +2759,45 @@ open fun getAllPickOrderLotsWithDetailsWithoutAutoAssign(userId: Long): List + println("🔍 DEBUG: Pick order ${po.id}: code=${po.code}, status=${po.status}, assignTo=${po.assignTo?.id}, doId=${po.deliveryOrder?.id}") + } + // ✅ NEW LOGIC: Filter based on assignment and status + 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 + } + + if (assignedReleasedOrders.isNotEmpty()) { + // ✅ If there are assigned RELEASED orders, show only those + println("🔍 DEBUG: Found ${assignedReleasedOrders.size} assigned RELEASED orders, showing only those") + assignedReleasedOrders + } else { + // ✅ If no assigned RELEASED orders, show only the latest COMPLETED order + val completedOrders = allAssignedPickOrders.filter { it.status == PickOrderStatus.COMPLETED } + if (completedOrders.isNotEmpty()) { + val latestCompleted = completedOrders.maxByOrNull { it.completeDate ?: it.modified ?: LocalDateTime.MIN } + println("�� DEBUG: No assigned RELEASED orders, showing latest completed order: ${latestCompleted?.code}") + listOfNotNull(latestCompleted) + } else { + println("🔍 DEBUG: No orders found") + emptyList() + } + } + } else { + emptyList() + } - val pickOrderIds = allAssignedPickOrders.map { it.id!! } + println("�� DEBUG: After assignment filtering, ${filteredPickOrders.size} pick orders remain") + filteredPickOrders.forEach { po -> + println("�� DEBUG: Final pick order ${po.id}: code=${po.code}, status=${po.status}, assignTo=${po.assignTo?.id}, doId=${po.deliveryOrder?.id}") + } + val pickOrderIds = filteredPickOrders.map { it.id!! } println(" Pick order IDs to fetch: $pickOrderIds") if (pickOrderIds.isEmpty()) { @@ -2694,6 +2837,10 @@ open fun getAllPickOrderLotsWithDetailsWithoutAutoAssign(userId: Long): List