| @@ -79,4 +79,22 @@ fun findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( | |||||
| @Param("requiredDate") requiredDate: LocalDate, | @Param("requiredDate") requiredDate: LocalDate, | ||||
| @Param("statuses") statuses: List<DoPickOrderStatus>, | @Param("statuses") statuses: List<DoPickOrderStatus>, | ||||
| ): List<DoPickOrder> | ): List<DoPickOrder> | ||||
| @Query(""" | |||||
| SELECT dpo FROM DoPickOrder dpo | |||||
| WHERE dpo.storeId = :storeId | |||||
| AND dpo.requiredDeliveryDate = :requiredDeliveryDate | |||||
| AND dpo.ticketStatus IN :statuses | |||||
| AND EXISTS ( | |||||
| SELECT 1 FROM DoPickOrderLine dpol | |||||
| WHERE dpol.doPickOrderId = dpo.id | |||||
| AND dpol.deleted = false | |||||
| AND (dpol.status IS NULL OR dpol.status != 'issue') | |||||
| ) | |||||
| """) | |||||
| fun findByStoreIdAndRequiredDeliveryDateAndTicketStatusInWithNonIssueLines( | |||||
| storeId: String, | |||||
| requiredDeliveryDate: LocalDate, | |||||
| statuses: List<DoPickOrderStatus> | |||||
| ): List<DoPickOrder> | |||||
| } | } | ||||
| @@ -81,6 +81,9 @@ import org.springframework.data.domain.Page | |||||
| import org.springframework.data.domain.Pageable | import org.springframework.data.domain.Pageable | ||||
| import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfoLite | import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfoLite | ||||
| import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfoLiteDto | import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfoLiteDto | ||||
| import com.ffii.fpsms.modules.stock.entity.InventoryLotLine | |||||
| import com.ffii.fpsms.modules.stock.entity.projection.StockOutLineInfo | |||||
| import java.util.Locale | |||||
| @Service | @Service | ||||
| open class DeliveryOrderService( | open class DeliveryOrderService( | ||||
| private val deliveryOrderRepository: DeliveryOrderRepository, | private val deliveryOrderRepository: DeliveryOrderRepository, | ||||
| @@ -1133,107 +1136,133 @@ open class DeliveryOrderService( | |||||
| fields: MutableList<MutableMap<String, Any>>, | fields: MutableList<MutableMap<String, Any>>, | ||||
| params: MutableMap<String, Any> | params: MutableMap<String, Any> | ||||
| ): Map<String, Any> { | ): Map<String, Any> { | ||||
| val doPickOrderRecord = doPickOrderRecordRepository.findById(request.doPickOrderId).orElseThrow { | val doPickOrderRecord = doPickOrderRecordRepository.findById(request.doPickOrderId).orElseThrow { | ||||
| NoSuchElementException("DoPickOrderRecord not found with ID: ${request.doPickOrderId}") | NoSuchElementException("DoPickOrderRecord not found with ID: ${request.doPickOrderId}") | ||||
| } | } | ||||
| val doPickOrderLineRecords = doPickOrderLineRecordRepository.findByDoPickOrderId(doPickOrderRecord.recordId) | val doPickOrderLineRecords = doPickOrderLineRecordRepository.findByDoPickOrderId(doPickOrderRecord.recordId) | ||||
| val pickOrderIds = doPickOrderLineRecords.mapNotNull { it.pickOrderId }.distinct() | val pickOrderIds = doPickOrderLineRecords.mapNotNull { it.pickOrderId }.distinct() | ||||
| if (pickOrderIds.isEmpty()) { | if (pickOrderIds.isEmpty()) { | ||||
| throw IllegalStateException("DoPickOrderRecord ${request.doPickOrderId} has no associated pick orders") | throw IllegalStateException("DoPickOrderRecord ${request.doPickOrderId} has no associated pick orders") | ||||
| } | } | ||||
| val deliveryOrderIds = doPickOrderLineRecords.mapNotNull { it.doOrderId }.distinct() | val deliveryOrderIds = doPickOrderLineRecords.mapNotNull { it.doOrderId }.distinct() | ||||
| if (deliveryOrderIds.isEmpty()) { | if (deliveryOrderIds.isEmpty()) { | ||||
| throw IllegalStateException("DoPickOrderRecord ${request.doPickOrderId} has no associated delivery orders") | throw IllegalStateException("DoPickOrderRecord ${request.doPickOrderId} has no associated delivery orders") | ||||
| } | } | ||||
| val deliveryNoteInfo = deliveryOrderIds.flatMap { deliveryOrderId -> | val deliveryNoteInfo = deliveryOrderIds.flatMap { deliveryOrderId -> | ||||
| deliveryOrderRepository.findDeliveryOrderInfoById(deliveryOrderId) | deliveryOrderRepository.findDeliveryOrderInfoById(deliveryOrderId) | ||||
| }.toMutableList() | }.toMutableList() | ||||
| val pickOrderId = pickOrderIds.first() | val pickOrderId = pickOrderIds.first() | ||||
| val truckNo = doPickOrderRecord.truckLanceCode ?: "" | val truckNo = doPickOrderRecord.truckLanceCode ?: "" | ||||
| val selectedPickOrder = pickOrderRepository.findById(pickOrderId).orElse(null) | val selectedPickOrder = pickOrderRepository.findById(pickOrderId).orElse(null) | ||||
| val allLines = deliveryNoteInfo.flatMap { info -> | val allLines = deliveryNoteInfo.flatMap { info -> | ||||
| info.deliveryOrderLines.map { line -> line } | info.deliveryOrderLines.map { line -> line } | ||||
| } | } | ||||
| val pickOrderLines = pickOrderIds.flatMap { pickOrderId -> | |||||
| pickOrderLineRepository.findAllByPickOrderId(pickOrderId) | |||||
| val pickOrderLines = pickOrderIds.flatMap { pid -> | |||||
| pickOrderLineRepository.findAllByPickOrderId(pid) | |||||
| } | } | ||||
| val pickOrderLineIdsByItemId = pickOrderLines | val pickOrderLineIdsByItemId = pickOrderLines | ||||
| .groupBy { it.item?.id } | .groupBy { it.item?.id } | ||||
| .mapValues { (_, lines) -> lines.mapNotNull { it.id } } | .mapValues { (_, lines) -> lines.mapNotNull { it.id } } | ||||
| val allPickOrderLineIds = pickOrderLines.mapNotNull { it.id } | val allPickOrderLineIds = pickOrderLines.mapNotNull { it.id } | ||||
| val stockOutLinesByPickOrderLineId = if (allPickOrderLineIds.isNotEmpty()) { | |||||
| allPickOrderLineIds.associateWith { pickOrderLineId -> | |||||
| stockOutLineRepository.findAllByPickOrderLineIdAndDeletedFalse(pickOrderLineId) | |||||
| val stockOutLinesByPickOrderLineId: Map<Long, List<StockOutLineInfo>> = | |||||
| if (allPickOrderLineIds.isNotEmpty()) { | |||||
| allPickOrderLineIds.associateWith { polId -> | |||||
| stockOutLineRepository.findAllByPickOrderLineIdAndDeletedFalse(polId) | |||||
| } | |||||
| } else { | |||||
| emptyMap() | |||||
| } | } | ||||
| val doStoreFloorKey = doPickOrderRecord.storeId?.toString()?.trim()?.uppercase(Locale.ROOT) | |||||
| ?.replace("/", "") | |||||
| ?.replace(" ", "") | |||||
| ?: "" | |||||
| val uniqueItemIdsForSort = allLines.mapNotNull { it.itemId }.distinct() | |||||
| val itemsById = if (uniqueItemIdsForSort.isNotEmpty()) { | |||||
| itemsRepository.findAllById(uniqueItemIdsForSort).associateBy { it.id!! } | |||||
| } else { | } else { | ||||
| emptyMap() | emptyMap() | ||||
| } | } | ||||
| val sortedLines = allLines.sortedBy { line -> | |||||
| line.itemId?.let { itemId -> | |||||
| getWarehouseOrderByItemId(itemId) | |||||
| } ?: Int.MAX_VALUE | |||||
| val sortedLines = when (doStoreFloorKey) { | |||||
| "2F" -> allLines.sortedWith( | |||||
| compareBy( | |||||
| { line -> itemsById[line.itemId]?.item_Order ?: Int.MAX_VALUE }, | |||||
| { line -> line.itemNo }, | |||||
| ), | |||||
| ) | |||||
| "4F" -> allLines.sortedBy { line -> | |||||
| line.itemId?.let { getWarehouseOrderByItemId(it) } ?: Int.MAX_VALUE | |||||
| } | |||||
| else -> allLines.sortedBy { line -> | |||||
| line.itemId?.let { getWarehouseOrderByItemId(it) } ?: Int.MAX_VALUE | |||||
| } | |||||
| } | } | ||||
| val uniqueItemIds = sortedLines.mapNotNull { it.itemId }.distinct() | |||||
| val itemsMap = if (uniqueItemIds.isNotEmpty()) { | |||||
| itemsRepository.findAllById(uniqueItemIds).associateBy { it.id } | |||||
| val allIllIds = stockOutLinesByPickOrderLineId.values | |||||
| .flatMap { lines -> lines.mapNotNull { it.inventoryLotLineId } } | |||||
| .distinct() | |||||
| val illById: Map<Long, InventoryLotLine> = if (allIllIds.isNotEmpty()) { | |||||
| inventoryLotLineRepository.findAllById(allIllIds).associateBy { it.id!! } | |||||
| } else { | } else { | ||||
| emptyMap() | emptyMap() | ||||
| } | } | ||||
| val itemsMap = itemsById | |||||
| sortedLines.forEach { line -> | sortedLines.forEach { line -> | ||||
| val field = mutableMapOf<String, Any>() | val field = mutableMapOf<String, Any>() | ||||
| field["sequenceNumber"] = (fields.size + 1).toString() | field["sequenceNumber"] = (fields.size + 1).toString() | ||||
| field["itemNo"] = line.itemNo | field["itemNo"] = line.itemNo | ||||
| field["itemName"] = line.itemName ?: "" | field["itemName"] = line.itemName ?: "" | ||||
| field["uom"] = line.uom ?: "" | field["uom"] = line.uom ?: "" | ||||
| val actualPickQty = if (line.itemId != null) { | val actualPickQty = if (line.itemId != null) { | ||||
| val pickOrderLineIdsForItem = pickOrderLineIdsByItemId[line.itemId] ?: emptyList() | val pickOrderLineIdsForItem = pickOrderLineIdsByItemId[line.itemId] ?: emptyList() | ||||
| val totalQty = pickOrderLineIdsForItem.sumOf { pickOrderLineId -> | |||||
| val stockOutLines = stockOutLinesByPickOrderLineId[pickOrderLineId] ?: emptyList() | |||||
| stockOutLines.sumOf { it.qty } | |||||
| val totalQty = pickOrderLineIdsForItem.sumOf { polId -> | |||||
| stockOutLinesByPickOrderLineId[polId].orEmpty().sumOf { it.qty } | |||||
| } | } | ||||
| totalQty.toString() | totalQty.toString() | ||||
| } else { | } else { | ||||
| line.qty.toString() | line.qty.toString() | ||||
| } | } | ||||
| field["qty"] = actualPickQty | field["qty"] = actualPickQty | ||||
| field["shortName"] = line.uomShortDesc ?: "" | field["shortName"] = line.uomShortDesc ?: "" | ||||
| val route = line.itemId?.let { itemId -> | val route = line.itemId?.let { itemId -> | ||||
| getWarehouseCodeByItemId(itemId) | |||||
| routeFromStockOutsForItem( | |||||
| itemId, | |||||
| pickOrderLineIdsByItemId, | |||||
| stockOutLinesByPickOrderLineId, | |||||
| illById, | |||||
| ).takeIf { it != "-" } ?: getWarehouseCodeByItemId(itemId) | |||||
| } ?: "-" | } ?: "-" | ||||
| field["route"] = route | field["route"] = route | ||||
| //USE STOCK OUT LINE | |||||
| val lotNo = line.itemId?.let { itemId -> | val lotNo = line.itemId?.let { itemId -> | ||||
| val pickOrderLineIdsForItem = pickOrderLineIdsByItemId[itemId] ?: emptyList() | val pickOrderLineIdsForItem = pickOrderLineIdsByItemId[itemId] ?: emptyList() | ||||
| val lotNumbers = pickOrderLineIdsForItem.flatMap { pickOrderLineId -> | |||||
| val stockOutLines = stockOutLinesByPickOrderLineId[pickOrderLineId] ?: emptyList() | |||||
| stockOutLines.mapNotNull { it.lotNo } | |||||
| val lotNumbers = pickOrderLineIdsForItem.flatMap { polId -> | |||||
| stockOutLinesByPickOrderLineId[polId].orEmpty().mapNotNull { it.lotNo } | |||||
| }.distinct().joinToString(", ") | }.distinct().joinToString(", ") | ||||
| lotNumbers.ifBlank { | |||||
| "沒有庫存" | |||||
| } | |||||
| lotNumbers.ifBlank { "沒有庫存" } | |||||
| } ?: "沒有庫存" | } ?: "沒有庫存" | ||||
| field["lotNo"] = lotNo | field["lotNo"] = lotNo | ||||
| val signOff = line.itemId?.let { itemId -> | val signOff = line.itemId?.let { itemId -> | ||||
| val item = itemsMap[itemId] | val item = itemsMap[itemId] | ||||
| if (item?.isEgg == true) { | if (item?.isEgg == true) { | ||||
| @@ -1243,21 +1272,21 @@ open class DeliveryOrderService( | |||||
| } | } | ||||
| } ?: "" | } ?: "" | ||||
| field["signOff"] = signOff | field["signOff"] = signOff | ||||
| fields.add(field) | fields.add(field) | ||||
| } | } | ||||
| params["dnTitle"] = "送貨單" | params["dnTitle"] = "送貨單" | ||||
| params["colQty"] = "已提數量" | params["colQty"] = "已提數量" | ||||
| params["totalCartonTitle"] = "總箱數:" | params["totalCartonTitle"] = "總箱數:" | ||||
| params["deliveryNoteCodeTitle"] = "送貨單編號:" | params["deliveryNoteCodeTitle"] = "送貨單編號:" | ||||
| params["deliveryNoteCode"] = doPickOrderRecord.deliveryNoteCode ?: "" | params["deliveryNoteCode"] = doPickOrderRecord.deliveryNoteCode ?: "" | ||||
| params["numOfCarton"] = request.numOfCarton.toString() | params["numOfCarton"] = request.numOfCarton.toString() | ||||
| if (params["numOfCarton"] == "0") { | if (params["numOfCarton"] == "0") { | ||||
| params["numOfCarton"] = "" | params["numOfCarton"] = "" | ||||
| } | } | ||||
| params["shopName"] = doPickOrderRecord.shopName ?: deliveryNoteInfo[0].shopName ?: "" | params["shopName"] = doPickOrderRecord.shopName ?: deliveryNoteInfo[0].shopName ?: "" | ||||
| params["shopAddress"] = deliveryNoteInfo[0].shopAddress ?: "" | params["shopAddress"] = deliveryNoteInfo[0].shopAddress ?: "" | ||||
| params["deliveryDate"] = | params["deliveryDate"] = | ||||
| @@ -1269,13 +1298,30 @@ open class DeliveryOrderService( | |||||
| params["loadingSequence"] = doPickOrderRecord.loadingSequence?.let { | params["loadingSequence"] = doPickOrderRecord.loadingSequence?.let { | ||||
| "裝載順序:$it" | "裝載順序:$it" | ||||
| } ?: "" | } ?: "" | ||||
| return mapOf( | return mapOf( | ||||
| "report" to PdfUtils.fillReport(deliveryNote, fields, params), | "report" to PdfUtils.fillReport(deliveryNote, fields, params), | ||||
| "filename" to deliveryNoteInfo.joinToString("_") { it.code } | "filename" to deliveryNoteInfo.joinToString("_") { it.code } | ||||
| ) | ) | ||||
| } | } | ||||
| private fun routeFromStockOutsForItem( | |||||
| itemId: Long, | |||||
| pickOrderLineIdsByItemId: Map<Long?, List<Long>>, | |||||
| stockOutLinesByPickOrderLineId: Map<Long, List<StockOutLineInfo>>, | |||||
| illById: Map<Long, InventoryLotLine>, | |||||
| ): String { | |||||
| val polIds = pickOrderLineIdsByItemId[itemId] ?: return "-" | |||||
| val codes = linkedSetOf<String>() | |||||
| for (polId in polIds) { | |||||
| for (sol in stockOutLinesByPickOrderLineId[polId].orEmpty()) { | |||||
| val illId = sol.inventoryLotLineId ?: continue | |||||
| val ill = illById[illId] ?: continue | |||||
| ill.warehouse?.code?.takeIf { it.isNotBlank() }?.let { codes.add(it) } | |||||
| } | |||||
| } | |||||
| return if (codes.isEmpty()) "-" else codes.joinToString(", ") | |||||
| } | |||||
| //Print Delivery Note | //Print Delivery Note | ||||
| @Transactional | @Transactional | ||||
| open fun printDeliveryNote(request: PrintDeliveryNoteRequest) { | open fun printDeliveryNote(request: PrintDeliveryNoteRequest) { | ||||
| @@ -1674,6 +1720,144 @@ val inventoryLotLine = illId?.let { inventoryLotLineMap[it] } | |||||
| ) | ) | ||||
| } | } | ||||
| /** | |||||
| * Workbench NO-HOLD release: | |||||
| * - Create pick_order + stock_out | |||||
| * - Do NOT create suggested_pick_lot / stock_out_line | |||||
| * - Do NOT update inventory_lot_line.holdQty | |||||
| * | |||||
| * Downstream should be handled by workbench services (no-hold suggestion + stock_out_line creation). | |||||
| */ | |||||
| @Transactional(rollbackFor = [Exception::class]) | |||||
| open fun releaseDeliveryOrderWithoutTicketNoHold(request: ReleaseDoRequest): ReleaseDoResult { | |||||
| println(" DEBUG: Starting releaseDeliveryOrderWithoutTicketNoHold for DO ID: ${request.id}") | |||||
| val deliveryOrder = deliveryOrderRepository.findByIdAndDeletedIsFalse(request.id) | |||||
| ?: throw NoSuchElementException("Delivery Order not found") | |||||
| if (deliveryOrder.status == DeliveryOrderStatus.COMPLETED || deliveryOrder.status == DeliveryOrderStatus.RECEIVING) { | |||||
| throw IllegalStateException("Delivery Order ${deliveryOrder.id} is already ${deliveryOrder.status?.value}, skipping release") | |||||
| } | |||||
| // Mark released (same semantics as normal release) | |||||
| deliveryOrder.status = DeliveryOrderStatus.RECEIVING | |||||
| deliveryOrderRepository.save(deliveryOrder) | |||||
| // Create pick order (same as normal release) | |||||
| val pols = deliveryOrder.deliveryOrderLines | |||||
| .filter { it.deleted != true } | |||||
| .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 createdPickOrder = pickOrderService.create(po) | |||||
| 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) | |||||
| // Create stock out header only; stock_out_line is created by workbench service | |||||
| val stockOut = StockOut().apply { | |||||
| this.type = "do" | |||||
| this.consoPickOrderCode = consoCode | |||||
| this.status = StockOutStatus.PENDING.status | |||||
| this.handler = request.userId | |||||
| } | |||||
| stockOutRepository.saveAndFlush(stockOut) | |||||
| } | |||||
| // Truck selection (reuse normal logic) | |||||
| val targetDate = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now() | |||||
| val supplierCode = deliveryOrder.supplier?.code | |||||
| val preferredFloor = when (supplierCode) { | |||||
| "P06B" -> "4F" | |||||
| "P07", "P06D" -> "2F" | |||||
| else -> "2F" | |||||
| } | |||||
| val truck = deliveryOrder.shop?.id?.let { shopId -> | |||||
| val trucks = truckRepository.findByShopIdAndDeletedFalse(shopId) | |||||
| val preferredStoreId = when (preferredFloor) { | |||||
| "2F" -> "2F" | |||||
| "4F" -> "4F" | |||||
| "3F" -> "3F" | |||||
| else -> "2F" | |||||
| } | |||||
| val matchedTrucks = trucks.filter { it.storeId == preferredStoreId } | |||||
| if (matchedTrucks.isEmpty()) { | |||||
| null | |||||
| } else { | |||||
| if (preferredStoreId == "4F" && matchedTrucks.size > 1) { | |||||
| deliveryOrder.estimatedArrivalDate?.let { estimatedArrivalDate -> | |||||
| val targetDate2 = estimatedArrivalDate.toLocalDate() | |||||
| val dayAbbr = when (targetDate2.dayOfWeek) { | |||||
| java.time.DayOfWeek.MONDAY -> "Mon" | |||||
| java.time.DayOfWeek.TUESDAY -> "Tue" | |||||
| java.time.DayOfWeek.WEDNESDAY -> "Wed" | |||||
| java.time.DayOfWeek.THURSDAY -> "Thu" | |||||
| java.time.DayOfWeek.FRIDAY -> "Fri" | |||||
| java.time.DayOfWeek.SATURDAY -> "Sat" | |||||
| java.time.DayOfWeek.SUNDAY -> "Sun" | |||||
| } | |||||
| val dayMatchedTrucks = matchedTrucks.filter { | |||||
| it.truckLanceCode?.contains(dayAbbr, ignoreCase = true) == true | |||||
| } | |||||
| if (dayMatchedTrucks.isNotEmpty()) { | |||||
| dayMatchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } | |||||
| } else { | |||||
| matchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } | |||||
| } | |||||
| } ?: run { | |||||
| matchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } | |||||
| } | |||||
| } else { | |||||
| matchedTrucks.minByOrNull { it.departureTime ?: LocalTime.of(23, 59, 59) } | |||||
| } | |||||
| } | |||||
| } | |||||
| val defaultTruckId = 5577L | |||||
| val effectiveTruck = truck ?: truckRepository.findById(defaultTruckId).orElse(null) | |||||
| val usedDefaultTruck = (truck == null) | |||||
| if (effectiveTruck == null) { | |||||
| val errorMsg = "No matching truck for preferredFloor ($preferredFloor) and default truck $defaultTruckId not found. Skipping DO ${deliveryOrder.id}." | |||||
| throw IllegalStateException(errorMsg) | |||||
| } | |||||
| return ReleaseDoResult( | |||||
| deliveryOrderId = deliveryOrder.id!!, | |||||
| deliveryOrderCode = deliveryOrder.code, | |||||
| pickOrderId = createdPickOrder.id!!, | |||||
| pickOrderCode = pickOrderEntity?.code, | |||||
| shopId = deliveryOrder.shop?.id, | |||||
| shopCode = deliveryOrder.shop?.code, | |||||
| shopName = deliveryOrder.shop?.name, | |||||
| estimatedArrivalDate = targetDate, | |||||
| preferredFloor = preferredFloor, | |||||
| truckId = effectiveTruck.id, | |||||
| truckDepartureTime = effectiveTruck.departureTime, | |||||
| truckLanceCode = effectiveTruck.truckLanceCode, | |||||
| loadingSequence = effectiveTruck.loadingSequence, | |||||
| usedDefaultTruck = usedDefaultTruck | |||||
| ) | |||||
| } | |||||
| private fun getDayOfWeekAbbr(date: LocalDate): String = | private fun getDayOfWeekAbbr(date: LocalDate): String = | ||||
| when (date.dayOfWeek) { | when (date.dayOfWeek) { | ||||
| java.time.DayOfWeek.MONDAY -> "Mon" | java.time.DayOfWeek.MONDAY -> "Mon" | ||||
| @@ -379,7 +379,7 @@ open class DoPickOrderService( | |||||
| } | } | ||||
| fun getSummaryByStore(storeId: String, requiredDate: LocalDate?, releaseType: String): StoreLaneSummary { | fun getSummaryByStore(storeId: String, requiredDate: LocalDate?, releaseType: String): StoreLaneSummary { | ||||
| val targetDate = requiredDate ?: LocalDate.now() | val targetDate = requiredDate ?: LocalDate.now() | ||||
| println(" DEBUG: Getting summary for store=$storeId, date=$targetDate") | |||||
| //println(" DEBUG: Getting summary for store=$storeId, date=$targetDate") | |||||
| val actualStoreId = when (storeId) { | val actualStoreId = when (storeId) { | ||||
| "2/F" -> "2/F" | "2/F" -> "2/F" | ||||
| @@ -387,11 +387,18 @@ open class DoPickOrderService( | |||||
| else -> storeId | else -> storeId | ||||
| } | } | ||||
| /* | |||||
| val allRecords = doPickOrderRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( | val allRecords = doPickOrderRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( | ||||
| actualStoreId, | actualStoreId, | ||||
| targetDate, | targetDate, | ||||
| listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed) | listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed) | ||||
| ) | ) | ||||
| */ | |||||
| val allRecords = doPickOrderRepository | |||||
| .findByStoreIdAndRequiredDeliveryDateAndTicketStatusInWithNonIssueLines( | |||||
| actualStoreId, targetDate, | |||||
| listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed) | |||||
| ) | |||||
| val filteredByReleaseType = when (releaseType.lowercase()) { | val filteredByReleaseType = when (releaseType.lowercase()) { | ||||
| "batch" -> allRecords.filter { it.releaseType == "batch" } | "batch" -> allRecords.filter { it.releaseType == "batch" } | ||||
| "single" -> allRecords.filter { it.releaseType == "single" } | "single" -> allRecords.filter { it.releaseType == "single" } | ||||
| @@ -408,9 +415,9 @@ open class DoPickOrderService( | |||||
| "single" -> finishedRecords.filter { it.releaseType == "single" } | "single" -> finishedRecords.filter { it.releaseType == "single" } | ||||
| else -> finishedRecords // "all" 或其他值,不过滤 | else -> finishedRecords // "all" 或其他值,不过滤 | ||||
| } | } | ||||
| println(" DEBUG: Found ${allRecords.size} records for date $targetDate") | |||||
| println(" DEBUG: Found ${finishedRecords.size} finished records for date $targetDate") | |||||
| //println(" DEBUG: Found ${allRecords.size} records for date $targetDate") | |||||
| // println(" DEBUG: Found ${finishedRecords.size} finished records for date $targetDate") | |||||
| /* | |||||
| val filteredRecords = filteredByReleaseType.filter { doPickOrder -> | val filteredRecords = filteredByReleaseType.filter { doPickOrder -> | ||||
| val hasNonIssueLines = checkDoPickOrderHasNonIssueLines(doPickOrder.id!!) | val hasNonIssueLines = checkDoPickOrderHasNonIssueLines(doPickOrder.id!!) | ||||
| if (!hasNonIssueLines) { | if (!hasNonIssueLines) { | ||||
| @@ -418,20 +425,24 @@ open class DoPickOrderService( | |||||
| } | } | ||||
| hasNonIssueLines | hasNonIssueLines | ||||
| } | } | ||||
| */ | |||||
| // println(" DEBUG: After filtering, ${filteredRecords.size} records remain") | |||||
| println(" DEBUG: After filtering, ${filteredRecords.size} records remain") | |||||
| val grouped = filteredRecords.groupBy { it.truckDepartureTime to it.truckLanceCode } | |||||
| val grouped = filteredByReleaseType.groupBy { it.truckDepartureTime to it.truckLanceCode } | |||||
| .mapValues { (key, list) -> | .mapValues { (key, list) -> | ||||
| val (truckDepartureTime, truckLanceCode) = key | val (truckDepartureTime, truckLanceCode) = key | ||||
| // 计算匹配的 finishedRecords 数量 | // 计算匹配的 finishedRecords 数量 | ||||
| val matchingFinishedCount = finishedRecords.count { record -> | |||||
| (record.truckDepartureTime == truckDepartureTime) && | |||||
| (record.truckLanceCode == truckLanceCode) | |||||
| } | |||||
| println(" DEBUG: Group key - truckDepartureTime: $truckDepartureTime, truckLanceCode: $truckLanceCode") | |||||
| println(" DEBUG: Found ${list.size} active records in this group") | |||||
| println(" DEBUG: Found $matchingFinishedCount finished records matching this group") | |||||
| // val matchingFinishedCount = finishedRecords.count { record -> | |||||
| //(record.truckDepartureTime == truckDepartureTime) && | |||||
| // (record.truckLanceCode == truckLanceCode) | |||||
| // } | |||||
| val matchingFinishedCount = filteredFinishedRecords.count { record -> | |||||
| record.truckDepartureTime == truckDepartureTime && | |||||
| record.truckLanceCode == truckLanceCode | |||||
| } | |||||
| // println(" DEBUG: Group key - truckDepartureTime: $truckDepartureTime, truckLanceCode: $truckLanceCode") | |||||
| //println(" DEBUG: Found ${list.size} active records in this group") | |||||
| //println(" DEBUG: Found $matchingFinishedCount finished records matching this group") | |||||
| LaneBtn( | LaneBtn( | ||||
| truckLanceCode = list.first().truckLanceCode ?: "", | truckLanceCode = list.first().truckLanceCode ?: "", | ||||
| unassigned = list.count { it.handledBy == null }, | unassigned = list.count { it.handledBy == null }, | ||||
| @@ -3512,10 +3512,10 @@ ORDER BY | |||||
| val enrichedResults = filteredResults | val enrichedResults = filteredResults | ||||
| return enrichedResults | return enrichedResults | ||||
| } | } | ||||
| /* | |||||
| open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, Any?> { | open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, Any?> { | ||||
| println("=== Debug: getAllPickOrderLotsWithDetailsHierarchical (NEW STRUCTURE) ===") | |||||
| println("userId filter: $userId") | |||||
| //println("=== Debug: getAllPickOrderLotsWithDetailsHierarchical (NEW STRUCTURE) ===") | |||||
| // println("userId filter: $userId") | |||||
| val user = userService.find(userId).orElse(null) | val user = userService.find(userId).orElse(null) | ||||
| if (user == null) { | if (user == null) { | ||||
| @@ -3889,6 +3889,332 @@ println("DEBUG sol polIds in linesResults: " + linesResults.mapNotNull { it["sto | |||||
| "pickOrders" to listOfNotNull(mergedPickOrder) | "pickOrders" to listOfNotNull(mergedPickOrder) | ||||
| ) | ) | ||||
| } | } | ||||
| */ | |||||
| open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, Any?> { | |||||
| val user = userService.find(userId).orElse(null) | |||||
| if (user == null) { | |||||
| println("❌ User not found: $userId") | |||||
| return emptyMap() | |||||
| } | |||||
| // Step 1: 找到該 user 目前處理中的 do_pick_order(你原本就是 LIMIT 1) | |||||
| val doPickOrderSql = """ | |||||
| SELECT DISTINCT | |||||
| dpo.id as do_pick_order_id, | |||||
| dpo.ticket_no, | |||||
| dpo.store_id, | |||||
| dpo.TruckLanceCode, | |||||
| dpo.truck_departure_time, | |||||
| dpo.ShopCode, | |||||
| dpo.ShopName, | |||||
| dpo.ticket_status as doTicketStatus | |||||
| FROM fpsmsdb.do_pick_order dpo | |||||
| INNER JOIN fpsmsdb.do_pick_order_line dpol ON dpol.do_pick_order_id = dpo.id AND dpol.deleted = 0 | |||||
| INNER JOIN fpsmsdb.pick_order po ON po.id = dpol.pick_order_id | |||||
| WHERE po.assignTo = :userId | |||||
| AND po.type = 'do' | |||||
| AND EXISTS ( | |||||
| SELECT 1 | |||||
| FROM fpsmsdb.do_pick_order_line dpol2 | |||||
| INNER JOIN fpsmsdb.pick_order po2 ON po2.id = dpol2.pick_order_id | |||||
| WHERE dpol2.do_pick_order_id = dpo.id | |||||
| AND dpol2.deleted = 0 | |||||
| AND po2.status IN ('assigned', 'released', 'picking') | |||||
| AND po2.deleted = false | |||||
| ) | |||||
| AND dpo.handled_by = :userId | |||||
| AND dpo.ticket_status IN ('released','picking') | |||||
| AND po.deleted = false | |||||
| AND dpo.deleted = false | |||||
| LIMIT 1 | |||||
| """.trimIndent() | |||||
| val doPickOrderInfo = jdbcDao.queryForMap(doPickOrderSql, mapOf("userId" to userId)).orElse(null) | |||||
| ?: return mapOf("fgInfo" to null, "pickOrders" to emptyList<Any>()) | |||||
| val doPickOrderId = (doPickOrderInfo["do_pick_order_id"] as? Number)?.toLong() | |||||
| ?: return mapOf("fgInfo" to null, "pickOrders" to emptyList<Any>()) | |||||
| val doTicketStatus = doPickOrderInfo["doTicketStatus"] | |||||
| // Step 2: 找到該 do_pick_order 底下所有 pick orders | |||||
| val pickOrdersSql = """ | |||||
| SELECT DISTINCT | |||||
| dpol.pick_order_id, | |||||
| dpol.pick_order_code, | |||||
| dpol.do_order_id, | |||||
| dpol.delivery_order_code, | |||||
| po.consoCode, | |||||
| po.status, | |||||
| DATE_FORMAT(po.targetDate, '%Y-%m-%d') as targetDate | |||||
| FROM fpsmsdb.do_pick_order_line dpol | |||||
| INNER JOIN fpsmsdb.pick_order po ON po.id = dpol.pick_order_id | |||||
| WHERE dpol.do_pick_order_id = :doPickOrderId | |||||
| AND dpol.deleted = 0 | |||||
| AND po.deleted = false | |||||
| ORDER BY dpol.pick_order_id | |||||
| """.trimIndent() | |||||
| val pickOrdersInfo = jdbcDao.queryForList(pickOrdersSql, mapOf("doPickOrderId" to doPickOrderId)) | |||||
| if (pickOrdersInfo.isEmpty()) { | |||||
| val fgInfo = mapOf( | |||||
| "doPickOrderId" to doPickOrderId, | |||||
| "ticketNo" to doPickOrderInfo["ticket_no"], | |||||
| "storeId" to doPickOrderInfo["store_id"], | |||||
| "shopCode" to doPickOrderInfo["ShopCode"], | |||||
| "shopName" to doPickOrderInfo["ShopName"], | |||||
| "truckLanceCode" to doPickOrderInfo["TruckLanceCode"], | |||||
| "departureTime" to doPickOrderInfo["truck_departure_time"], | |||||
| ) | |||||
| return mapOf("fgInfo" to fgInfo, "pickOrders" to emptyList<Any>()) | |||||
| } | |||||
| val pickOrderIds = pickOrdersInfo.mapNotNull { (it["pick_order_id"] as? Number)?.toLong() }.distinct() | |||||
| val pickOrderCodes = pickOrdersInfo.mapNotNull { it["pick_order_code"] as? String } | |||||
| val doOrderIds = pickOrdersInfo.mapNotNull { (it["do_order_id"] as? Number)?.toLong() } | |||||
| val deliveryOrderCodes = pickOrdersInfo.mapNotNull { it["delivery_order_code"] as? String } | |||||
| val allConsoCodes = pickOrdersInfo.mapNotNull { it["consoCode"] as? String }.distinct() | |||||
| // Step 3: 一次查完所有 pickOrder 的 line/lot/stockout 明細(避免 N+1) | |||||
| val linesSqlAll = """ | |||||
| SELECT | |||||
| po.id as pickOrderId, | |||||
| po.code as pickOrderCode, | |||||
| po.consoCode as pickOrderConsoCode, | |||||
| DATE_FORMAT(po.targetDate, '%Y-%m-%d') as pickOrderTargetDate, | |||||
| po.type as pickOrderType, | |||||
| po.status as pickOrderStatus, | |||||
| po.assignTo as pickOrderAssignTo, | |||||
| pol.id as pickOrderLineId, | |||||
| pol.qty as pickOrderLineRequiredQty, | |||||
| pol.status as pickOrderLineStatus, | |||||
| i.id as itemId, | |||||
| i.code as itemCode, | |||||
| i.name as itemName, | |||||
| i.item_Order as itemOrder, | |||||
| uc.code as uomCode, | |||||
| uc.udfudesc as uomDesc, | |||||
| uc.udfShortDesc as uomShortDesc, | |||||
| ill.id as lotId, | |||||
| il.lotNo, | |||||
| DATE_FORMAT(il.expiryDate, '%Y-%m-%d') as expiryDate, | |||||
| w.name as location, | |||||
| COALESCE(uc.udfudesc, 'N/A') as stockUnit, | |||||
| il.stockInLineId as stockInLineId, | |||||
| w.`order` as routerIndex, | |||||
| w.code as routerRoute, | |||||
| CASE | |||||
| WHEN sol.status = 'rejected' THEN NULL | |||||
| ELSE (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) | |||||
| END as availableQty, | |||||
| COALESCE(spl.qty, 0) as requiredQty, | |||||
| COALESCE(sol.qty, 0) as actualPickQty, | |||||
| spl.id as suggestedPickLotId, | |||||
| ill.status as lotStatus, | |||||
| sol.id as stockOutLineId, | |||||
| sol.status as stockOutLineStatus, | |||||
| COALESCE(sol.qty, 0) as stockOutLineQty, | |||||
| COALESCE(ill.inQty, 0) as inQty, | |||||
| COALESCE(ill.outQty, 0) as outQty, | |||||
| COALESCE(ill.holdQty, 0) as holdQty, | |||||
| CASE | |||||
| WHEN (il.expiryDate IS NOT NULL AND il.expiryDate < CURDATE()) THEN 'expired' | |||||
| WHEN sol.status = 'rejected' THEN 'rejected' | |||||
| WHEN (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) <= 0 THEN 'insufficient_stock' | |||||
| WHEN ill.status = 'unavailable' THEN 'status_unavailable' | |||||
| ELSE 'available' | |||||
| END as lotAvailability, | |||||
| CASE | |||||
| WHEN sol.status = 'completed' THEN 'completed' | |||||
| WHEN sol.status = 'rejected' THEN 'rejected' | |||||
| WHEN sol.status = 'created' THEN 'pending' | |||||
| ELSE 'pending' | |||||
| END as processingStatus | |||||
| FROM fpsmsdb.pick_order po | |||||
| JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||||
| JOIN fpsmsdb.items i ON i.id = pol.itemId | |||||
| LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = pol.uomId | |||||
| LEFT JOIN ( | |||||
| SELECT spl.pickOrderLineId, spl.suggestedLotLineId AS lotLineId | |||||
| FROM fpsmsdb.suggested_pick_lot spl | |||||
| UNION | |||||
| SELECT sol.pickOrderLineId, sol.inventoryLotLineId | |||||
| FROM fpsmsdb.stock_out_line sol | |||||
| WHERE sol.deleted = false | |||||
| ) ll ON ll.pickOrderLineId = pol.id | |||||
| LEFT JOIN fpsmsdb.suggested_pick_lot spl | |||||
| ON spl.pickOrderLineId = pol.id AND spl.suggestedLotLineId = ll.lotLineId | |||||
| LEFT JOIN fpsmsdb.stock_out_line sol | |||||
| ON sol.pickOrderLineId = pol.id | |||||
| AND ( (sol.inventoryLotLineId = ll.lotLineId) | |||||
| OR (sol.inventoryLotLineId IS NULL AND ll.lotLineId IS NULL) ) | |||||
| AND sol.deleted = false | |||||
| LEFT JOIN fpsmsdb.inventory_lot_line ill ON ill.id = ll.lotLineId AND ill.deleted = false | |||||
| LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId AND il.deleted = false | |||||
| LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId | |||||
| WHERE po.id IN (:pickOrderIds) | |||||
| AND po.deleted = false | |||||
| ORDER BY | |||||
| po.id ASC, | |||||
| COALESCE(w.`order`, 999999) ASC, | |||||
| pol.id ASC, | |||||
| il.lotNo ASC | |||||
| """.trimIndent() | |||||
| val allLineRows = jdbcDao.queryForList(linesSqlAll, mapOf("pickOrderIds" to pickOrderIds)) | |||||
| // Kotlin 端組裝:pickOrderId -> lineId -> rows | |||||
| val byPickOrderId = allLineRows.groupBy { (it["pickOrderId"] as? Number)?.toLong() } | |||||
| // 用來計算每個 pick order 的 lineCounts(保持你原本回傳欄位) | |||||
| val lineCountsPerPickOrder = mutableListOf<Int>() | |||||
| val allPickOrderLines = mutableListOf<Map<String, Any?>>() | |||||
| // 依照 Step2 的 pickOrdersInfo 順序處理(避免順序變動) | |||||
| pickOrdersInfo.forEach { poInfo -> | |||||
| val pickOrderId = (poInfo["pick_order_id"] as? Number)?.toLong() ?: return@forEach | |||||
| val rows = byPickOrderId[pickOrderId].orEmpty() | |||||
| val lineGroups = rows.groupBy { (it["pickOrderLineId"] as? Number)?.toLong() } | |||||
| val pickOrderLines = lineGroups.mapNotNull { (lineId, lineRows) -> | |||||
| val first = lineRows.firstOrNull() ?: return@mapNotNull null | |||||
| val lots = if (lineRows.any { it["lotId"] != null }) { | |||||
| lineRows | |||||
| .filter { it["lotId"] != null } | |||||
| .map { lotRow -> | |||||
| mapOf( | |||||
| "id" to lotRow["lotId"], | |||||
| "lotNo" to lotRow["lotNo"], | |||||
| "expiryDate" to lotRow["expiryDate"], | |||||
| "location" to lotRow["location"], | |||||
| "stockUnit" to lotRow["stockUnit"], | |||||
| "availableQty" to lotRow["availableQty"], | |||||
| "requiredQty" to lotRow["requiredQty"], | |||||
| "actualPickQty" to lotRow["actualPickQty"], | |||||
| "inQty" to lotRow["inQty"], | |||||
| "outQty" to lotRow["outQty"], | |||||
| "holdQty" to lotRow["holdQty"], | |||||
| "lotStatus" to lotRow["lotStatus"], | |||||
| "lotAvailability" to lotRow["lotAvailability"], | |||||
| "processingStatus" to lotRow["processingStatus"], | |||||
| "suggestedPickLotId" to lotRow["suggestedPickLotId"], | |||||
| "stockOutLineId" to lotRow["stockOutLineId"], | |||||
| "stockOutLineStatus" to lotRow["stockOutLineStatus"], | |||||
| "stockOutLineQty" to lotRow["stockOutLineQty"], | |||||
| "stockInLineId" to lotRow["stockInLineId"], | |||||
| "router" to mapOf( | |||||
| "id" to null, | |||||
| "index" to lotRow["routerIndex"], | |||||
| "route" to lotRow["routerRoute"], | |||||
| "area" to lotRow["routerRoute"], | |||||
| "itemCode" to lotRow["itemId"], | |||||
| "itemName" to lotRow["itemName"], | |||||
| "uomId" to lotRow["uomCode"], | |||||
| "noofCarton" to lotRow["requiredQty"] | |||||
| ) | |||||
| ) | |||||
| } | |||||
| } else emptyList() | |||||
| val stockouts = lineRows | |||||
| .filter { it["stockOutLineId"] != null } | |||||
| .distinctBy { it["stockOutLineId"] } | |||||
| .map { row -> | |||||
| val lotId = row["lotId"] | |||||
| val noLot = (lotId == null) | |||||
| mapOf( | |||||
| "id" to row["stockOutLineId"], | |||||
| "status" to row["stockOutLineStatus"], | |||||
| "qty" to row["stockOutLineQty"], | |||||
| "lotId" to lotId, | |||||
| "lotNo" to (row["lotNo"] ?: ""), | |||||
| "location" to (row["location"] ?: ""), | |||||
| "availableQty" to row["availableQty"], | |||||
| "stockInLineId" to row["stockInLineId"], | |||||
| "noLot" to noLot | |||||
| ) | |||||
| } | |||||
| mapOf( | |||||
| "id" to lineId, | |||||
| "requiredQty" to first["pickOrderLineRequiredQty"], | |||||
| "status" to first["pickOrderLineStatus"], | |||||
| "itemOrder" to first["itemOrder"], | |||||
| "item" to mapOf( | |||||
| "id" to first["itemId"], | |||||
| "code" to first["itemCode"], | |||||
| "name" to first["itemName"], | |||||
| "uomCode" to first["uomCode"], | |||||
| "uomDesc" to first["uomDesc"], | |||||
| "uomShortDesc" to first["uomShortDesc"], | |||||
| ), | |||||
| "lots" to lots, | |||||
| "stockouts" to stockouts | |||||
| ) | |||||
| } | |||||
| lineCountsPerPickOrder.add(pickOrderLines.size) | |||||
| allPickOrderLines.addAll(pickOrderLines) | |||||
| } | |||||
| // 保留你原本按 store 樓層的排序規則 | |||||
| val doStoreFloorKey = doPickOrderInfo["store_id"]?.toString()?.trim()?.uppercase(Locale.ROOT) | |||||
| ?.replace("/", "") | |||||
| ?.replace(" ", "") | |||||
| ?: "" | |||||
| when (doStoreFloorKey) { | |||||
| "2F" -> { | |||||
| allPickOrderLines.sortWith( | |||||
| compareBy( | |||||
| { line -> | |||||
| val v = line["itemOrder"] ?: line["itemorder"] | |||||
| when (v) { | |||||
| is Number -> v.toInt() | |||||
| else -> 999999 | |||||
| } | |||||
| }, | |||||
| { line -> (line["id"] as? Number)?.toLong() ?: Long.MAX_VALUE } | |||||
| ) | |||||
| ) | |||||
| } | |||||
| "4F" -> { | |||||
| // 4F:保留 SQL 順序,不做二次排序 | |||||
| } | |||||
| else -> { | |||||
| allPickOrderLines.sortWith( | |||||
| compareBy { line -> | |||||
| val lots = line["lots"] as? List<Map<String, Any?>> | |||||
| val firstLot = lots?.firstOrNull() | |||||
| val router = firstLot?.get("router") as? Map<String, Any?> | |||||
| val indexValue = router?.get("index") | |||||
| when (indexValue) { | |||||
| is Number -> indexValue.toInt() | |||||
| is String -> indexValue.toIntOrNull() ?: 999999 | |||||
| else -> 999999 | |||||
| } | |||||
| } | |||||
| ) | |||||
| } | |||||
| } | |||||
| val fgInfo = mapOf( | |||||
| "doPickOrderId" to doPickOrderId, | |||||
| "ticketNo" to doPickOrderInfo["ticket_no"], | |||||
| "storeId" to doPickOrderInfo["store_id"], | |||||
| "shopCode" to doPickOrderInfo["ShopCode"], | |||||
| "shopName" to doPickOrderInfo["ShopName"], | |||||
| "truckLanceCode" to doPickOrderInfo["TruckLanceCode"], | |||||
| "departureTime" to doPickOrderInfo["truck_departure_time"] | |||||
| ) | |||||
| val mergedPickOrder = run { | |||||
| val firstPickOrderInfo = pickOrdersInfo.first() | |||||
| mapOf( | |||||
| "pickOrderIds" to pickOrderIds, | |||||
| "pickOrderCodes" to pickOrderCodes, | |||||
| "doOrderIds" to doOrderIds, | |||||
| "deliveryOrderCodes" to deliveryOrderCodes, | |||||
| "lineCountsPerPickOrder" to lineCountsPerPickOrder, | |||||
| "consoCodes" to allConsoCodes, | |||||
| "status" to doTicketStatus, | |||||
| "targetDate" to firstPickOrderInfo["targetDate"], | |||||
| "pickOrderLines" to allPickOrderLines | |||||
| ) | |||||
| } | |||||
| return mapOf( | |||||
| "fgInfo" to fgInfo, | |||||
| "pickOrders" to listOf(mergedPickOrder) | |||||
| ) | |||||
| } | |||||
| // Fix the type issues in the getPickOrdersByDateAndStore method | // Fix the type issues in the getPickOrdersByDateAndStore method | ||||
| open fun getPickOrdersByDateAndStore(storeId: String): Map<String, Any?> { | open fun getPickOrdersByDateAndStore(storeId: String): Map<String, Any?> { | ||||
| println("=== Debug: getPickOrdersByDateAndStore ===") | println("=== Debug: getPickOrdersByDateAndStore ===") | ||||