|
|
|
@@ -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<PickOrder, Long, PickOrderRepository>(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<Map |
|
|
|
// 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: Found ${allAssignedPickOrders.size} pick orders assigned to user $userId") |
|
|
|
allAssignedPickOrders.forEach { po -> |
|
|
|
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<Map |
|
|
|
w.name as location, |
|
|
|
COALESCE(uc.udfudesc, 'N/A') as stockUnit, |
|
|
|
|
|
|
|
-- Router Information |
|
|
|
r.id as routerId, |
|
|
|
r.index as routerIndex, |
|
|
|
r.route as routerRoute, |
|
|
|
-- ✅ FIXED: Set quantities to NULL for rejected lots |
|
|
|
CASE |
|
|
|
WHEN sol.status = 'rejected' THEN NULL |
|
|
|
@@ -2768,20 +2915,23 @@ open fun getAllPickOrderLotsWithDetailsWithoutAutoAssign(userId: Long): List<Map |
|
|
|
JOIN fpsmsdb.items i ON i.id = pol.itemId |
|
|
|
LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = pol.uomId |
|
|
|
LEFT JOIN fpsmsdb.suggested_pick_lot spl ON pol.id = spl.pickOrderLineId |
|
|
|
|
|
|
|
LEFT JOIN fpsmsdb.inventory_lot_line ill ON spl.suggestedLotLineId = ill.id |
|
|
|
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.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ill.id AND sol.deleted = false |
|
|
|
WHERE po.deleted = false |
|
|
|
WHERE po.deleted = false |
|
|
|
AND po.id IN ($pickOrderIdsStr) |
|
|
|
AND pol.deleted = false |
|
|
|
AND po.status IN ('PENDING', 'RELEASED') |
|
|
|
AND po.status IN ('PENDING', 'RELEASED', 'COMPLETED') |
|
|
|
AND po.assignTo = :userId |
|
|
|
AND ill.deleted = false |
|
|
|
AND il.deleted = false |
|
|
|
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, |
|
|
|
po.code ASC, |
|
|
|
i.code ASC, |
|
|
|
il.expiryDate ASC, |
|
|
|
|