|
|
|
@@ -35,6 +35,18 @@ import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus |
|
|
|
import java.time.format.DateTimeFormatter |
|
|
|
import com.ffii.fpsms.modules.pickOrder.entity.TruckRepository |
|
|
|
import java.time.LocalTime |
|
|
|
import com.ffii.fpsms.modules.stock.service.SuggestedPickLotService |
|
|
|
import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository |
|
|
|
import com.ffii.fpsms.modules.stock.entity.StockOutRepository |
|
|
|
import com.ffii.fpsms.modules.stock.entity.StockOutLIneRepository |
|
|
|
import com.ffii.fpsms.modules.stock.entity.StockOut |
|
|
|
import com.ffii.fpsms.modules.stock.entity.StockOutLine |
|
|
|
import com.ffii.fpsms.modules.stock.web.model.StockOutStatus |
|
|
|
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 |
|
|
|
|
|
|
|
@Service |
|
|
|
open class DeliveryOrderService( |
|
|
|
private val deliveryOrderRepository: DeliveryOrderRepository, |
|
|
|
@@ -46,7 +58,13 @@ open class DeliveryOrderService( |
|
|
|
private val userRepository: UserRepository, |
|
|
|
private val pickOrderService: PickOrderService, |
|
|
|
private val doPickOrderService: DoPickOrderService, |
|
|
|
private val truckRepository: TruckRepository |
|
|
|
private val truckRepository: TruckRepository, |
|
|
|
private val pickOrderRepository: PickOrderRepository, |
|
|
|
private val suggestedPickLotService: SuggestedPickLotService, |
|
|
|
private val inventoryLotLineRepository: InventoryLotLineRepository, |
|
|
|
private val stockOutRepository: StockOutRepository, |
|
|
|
private val stockOutLineRepository: StockOutLIneRepository, |
|
|
|
private val pickOrderLineRepository: PickOrderLineRepository |
|
|
|
) { |
|
|
|
|
|
|
|
open fun findByM18DataLogId(m18DataLogId: Long): DeliveryOrder? { |
|
|
|
@@ -302,93 +320,179 @@ open class DeliveryOrderService( |
|
|
|
return savedDeliveryOrder |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Transactional(rollbackFor = [Exception::class]) |
|
|
|
open fun releaseDeliveryOrder(request: ReleaseDoRequest): MessageResponse { |
|
|
|
println("�� DEBUG: Starting releaseDeliveryOrder for DO ID: ${request.id}, User ID: ${request.userId}") |
|
|
|
|
|
|
|
val deliveryOrder = deliveryOrderRepository.findByIdAndDeletedIsFalse(request.id) |
|
|
|
?: throw NoSuchElementException("Delivery Order not found") |
|
|
|
|
|
|
|
println("�� DEBUG: Found delivery order - ID: ${deliveryOrder.id}, Shop: ${deliveryOrder.shop?.code}, Status: ${deliveryOrder.status}") |
|
|
|
|
|
|
|
deliveryOrder.apply { |
|
|
|
status = DeliveryOrderStatus.PENDING |
|
|
|
} |
|
|
|
deliveryOrderRepository.save(deliveryOrder) |
|
|
|
open fun releaseDeliveryOrder(request: ReleaseDoRequest): MessageResponse { |
|
|
|
println("�� DEBUG: Starting releaseDeliveryOrder for DO ID: ${request.id}, User ID: ${request.userId}") |
|
|
|
|
|
|
|
val deliveryOrder = deliveryOrderRepository.findByIdAndDeletedIsFalse(request.id) |
|
|
|
?: throw NoSuchElementException("Delivery Order not found") |
|
|
|
|
|
|
|
println("�� DEBUG: Found delivery order - ID: ${deliveryOrder.id}, Shop: ${deliveryOrder.shop?.code}, Status: ${deliveryOrder.status}") |
|
|
|
|
|
|
|
deliveryOrder.apply { |
|
|
|
status = DeliveryOrderStatus.PENDING |
|
|
|
} |
|
|
|
deliveryOrderRepository.save(deliveryOrder) |
|
|
|
|
|
|
|
val pols = deliveryOrder.deliveryOrderLines.map { |
|
|
|
SavePickOrderLineRequest( |
|
|
|
itemId = it.item?.id, |
|
|
|
qty = it.qty ?: BigDecimal.ZERO, |
|
|
|
uomId = it.uom?.id, |
|
|
|
val pols = deliveryOrder.deliveryOrderLines.map { |
|
|
|
SavePickOrderLineRequest( |
|
|
|
itemId = it.item?.id, |
|
|
|
qty = it.qty ?: BigDecimal.ZERO, |
|
|
|
uomId = it.uom?.id, |
|
|
|
) |
|
|
|
} |
|
|
|
val po = SavePickOrderRequest( |
|
|
|
doId = deliveryOrder.id, |
|
|
|
type = PickOrderType.DELIVERY_ORDER, |
|
|
|
targetDate = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now(), |
|
|
|
pickOrderLine = pols |
|
|
|
) |
|
|
|
} |
|
|
|
val po = SavePickOrderRequest( |
|
|
|
doId = deliveryOrder.id, |
|
|
|
type = PickOrderType.DELIVERY_ORDER, |
|
|
|
targetDate = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now(), |
|
|
|
pickOrderLine = pols |
|
|
|
) |
|
|
|
|
|
|
|
val createdPickOrder = pickOrderService.create(po) |
|
|
|
println("🔍 DEBUG: Created pick order - ID: ${createdPickOrder.id}") |
|
|
|
|
|
|
|
// ✅ 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") |
|
|
|
|
|
|
|
// 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") |
|
|
|
trucks.forEach { t -> |
|
|
|
println("🔍 DEBUG: Truck ID: ${t.id}, DepartureTime: ${t.departureTime}") |
|
|
|
|
|
|
|
val createdPickOrder = pickOrderService.create(po) |
|
|
|
println("🔍 DEBUG: Created pick order - ID: ${createdPickOrder.id}") |
|
|
|
|
|
|
|
val consoCode = pickOrderService.assignConsoCode() |
|
|
|
val pickOrderEntity = pickOrderRepository.findById(createdPickOrder.id!!).orElse(null) |
|
|
|
|
|
|
|
if (pickOrderEntity != null) { |
|
|
|
pickOrderEntity.consoCode = consoCode |
|
|
|
pickOrderEntity.status = com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus.RELEASED |
|
|
|
pickOrderRepository.saveAndFlush(pickOrderEntity) |
|
|
|
println("�� DEBUG: Assigned consoCode $consoCode to pick order ${createdPickOrder.id}") |
|
|
|
|
|
|
|
// ✅ Debug: Check pick order lines |
|
|
|
println("�� DEBUG: Pick order has ${pickOrderEntity.pickOrderLines?.size ?: 0} pick order lines") |
|
|
|
pickOrderEntity.pickOrderLines?.forEach { line -> |
|
|
|
println("🔍 DEBUG: Pick order line - Item ID: ${line.item?.id}, Qty: ${line.qty}") |
|
|
|
} |
|
|
|
val lines = pickOrderLineRepository.findAllByPickOrderId(pickOrderEntity.id!!) |
|
|
|
println("🔍 DEBUG: Loaded ${lines.size} pick order lines from DB") |
|
|
|
if (lines.isEmpty()) { |
|
|
|
println("⚠️ No pick order lines found; suggestions will be empty") |
|
|
|
} |
|
|
|
// ✅ Create suggested pick lots and hold inventory (like normal release) |
|
|
|
println("🔍 DEBUG: About to call suggestionForPickOrderLines for pick order ${pickOrderEntity.id}") |
|
|
|
val suggestions = suggestedPickLotService.suggestionForPickOrderLines( |
|
|
|
SuggestedPickLotForPolRequest(pickOrderLines = lines) |
|
|
|
) |
|
|
|
println("🔍 DEBUG: Got ${suggestions.suggestedList.size} suggested pick lots") |
|
|
|
|
|
|
|
if (suggestions.suggestedList.isEmpty()) { |
|
|
|
println("⚠️ WARNING: No suggested pick lots generated - this might be due to no inventory available") |
|
|
|
} |
|
|
|
|
|
|
|
val saveSuggestedPickLots = suggestedPickLotService.saveAll(suggestions.suggestedList) |
|
|
|
println("🔍 DEBUG: Saved ${saveSuggestedPickLots.size} suggested pick lots") |
|
|
|
|
|
|
|
|
|
|
|
// ✅ Hold inventory quantities |
|
|
|
val inventoryLotLines = inventoryLotLineRepository.findAllByIdIn( |
|
|
|
saveSuggestedPickLots.mapNotNull { it.suggestedLotLine?.id } |
|
|
|
) |
|
|
|
|
|
|
|
saveSuggestedPickLots.forEach { lot -> |
|
|
|
if (lot.suggestedLotLine != null && lot.suggestedLotLine?.id != null && lot.suggestedLotLine!!.id!! > 0) { |
|
|
|
val lineIndex = inventoryLotLines.indexOf(lot.suggestedLotLine) |
|
|
|
if (lineIndex >= 0) { |
|
|
|
inventoryLotLines[lineIndex].holdQty = |
|
|
|
(inventoryLotLines[lineIndex].holdQty ?: BigDecimal.ZERO).plus(lot.qty ?: BigDecimal.ZERO) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
inventoryLotLineRepository.saveAll(inventoryLotLines) |
|
|
|
|
|
|
|
// ✅ Create stock out record and pre-create stock out lines |
|
|
|
val stockOut = StockOut().apply { |
|
|
|
this.type = "job" |
|
|
|
this.consoPickOrderCode = consoCode |
|
|
|
this.status = StockOutStatus.PENDING.status |
|
|
|
this.handler = request.userId |
|
|
|
} |
|
|
|
val savedStockOut = stockOutRepository.saveAndFlush(stockOut) |
|
|
|
|
|
|
|
// ✅ Pre-create stock out lines for suggested lots |
|
|
|
saveSuggestedPickLots.forEach { lot -> |
|
|
|
val polId = lot.pickOrderLine?.id |
|
|
|
val illId = lot.suggestedLotLine?.id |
|
|
|
if (polId != null && illId != null) { |
|
|
|
val existingLines = stockOutLineRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse(polId, illId) |
|
|
|
if (existingLines.isEmpty()) { |
|
|
|
val pickOrderLine = pickOrderLineRepository.findById(polId).orElse(null) |
|
|
|
val inventoryLotLine = inventoryLotLineRepository.findById(illId).orElse(null) |
|
|
|
|
|
|
|
if (pickOrderLine != null && inventoryLotLine != null) { |
|
|
|
val line = StockOutLine().apply { |
|
|
|
this.stockOut = savedStockOut |
|
|
|
this.pickOrderLine = pickOrderLine |
|
|
|
this.inventoryLotLine = inventoryLotLine |
|
|
|
this.item = pickOrderLine.item |
|
|
|
this.status = StockOutLineStatus.PENDING.status |
|
|
|
this.qty = 0.0 |
|
|
|
} |
|
|
|
stockOutLineRepository.save(line) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
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") |
|
|
|
|
|
|
|
deliveryOrder.deliveryOrderLines.forEach { line -> |
|
|
|
val storeId = if (deliveryOrder.shop?.code == "P06B") "2/F" else "4/F" |
|
|
|
println("�� DEBUG: Processing line - Item ID: ${line.item?.id}, Store ID: $storeId") |
|
|
|
|
|
|
|
// ✅ CREATE do_pick_order_record entries |
|
|
|
val targetDate = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now() |
|
|
|
val datePrefix = targetDate.format(DateTimeFormatter.ofPattern("ddMMyy")) |
|
|
|
|
|
|
|
val doPickOrder = DoPickOrder( |
|
|
|
storeId = storeId, |
|
|
|
ticketNo = nextTicketNumber, |
|
|
|
ticketStatus = DoPickOrderStatus.pending, |
|
|
|
truckId = truck?.id, |
|
|
|
truckDepartureTime = truck?.departureTime, |
|
|
|
itemId = line.item?.id, |
|
|
|
shopId = deliveryOrder.shop?.id, |
|
|
|
shopPoSupplierId = deliveryOrder.shop?.id, |
|
|
|
handledBy = request.userId |
|
|
|
) |
|
|
|
println("�� DEBUG: Target date: $targetDate, Date prefix: $datePrefix") |
|
|
|
|
|
|
|
println("�� DEBUG: Creating DoPickOrder - Store: $storeId, Ticket: $nextTicketNumber, Truck: ${truck?.id}") |
|
|
|
// Get next ticket number for this date |
|
|
|
val nextTicketNumber = doPickOrderService.getNextTicketNumber(datePrefix) |
|
|
|
println("🔍 DEBUG: Next ticket number: $nextTicketNumber") |
|
|
|
|
|
|
|
val savedDoPickOrder = doPickOrderService.save(doPickOrder) |
|
|
|
println("🔍 DEBUG: Saved DoPickOrder - ID: ${savedDoPickOrder.id}") |
|
|
|
// ✅ 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") |
|
|
|
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") |
|
|
|
|
|
|
|
deliveryOrder.deliveryOrderLines.forEach { line -> |
|
|
|
val storeId = if (deliveryOrder.shop?.code == "P06B") "2/F" else "4/F" |
|
|
|
println("�� DEBUG: Processing line - Item ID: ${line.item?.id}, Store ID: $storeId") |
|
|
|
|
|
|
|
val doPickOrder = DoPickOrder( |
|
|
|
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 = request.userId |
|
|
|
) |
|
|
|
|
|
|
|
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) |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
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) |
|
|
|
) |
|
|
|
} |
|
|
|
} |