From 23e1ff5c5fd11affe84034464e2c8ad723b98da2 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Sat, 8 Nov 2025 17:28:58 +0800 Subject: [PATCH] update --- .../service/DoPickOrderQueryService.kt | 101 ++++++++++++- .../service/DoPickOrderService.kt | 1 + .../web/models/DoDetailResponse.kt | 7 +- .../pickOrder/service/PickOrderService.kt | 7 +- .../stock/service/SuggestedPickLotService.kt | 140 ++++++++++++------ .../20251106_01_enson/01_altertable_enson.sql | 9 ++ 6 files changed, 211 insertions(+), 54 deletions(-) create mode 100644 src/main/resources/db/changelog/changes/20251106_01_enson/01_altertable_enson.sql diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt index 7f3c7cd..816b1fe 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt @@ -6,13 +6,16 @@ import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus import com.ffii.fpsms.modules.deliveryOrder.web.models.LaneBtn import com.ffii.fpsms.modules.deliveryOrder.web.models.LaneRow import com.ffii.fpsms.modules.deliveryOrder.web.models.StoreLaneSummary +import com.ffii.fpsms.modules.deliveryOrder.web.models.DoPickOrderSummaryItem import org.springframework.stereotype.Service import java.time.LocalDate +import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecordRepository @Service class DoPickOrderQueryService( private val doPickOrderRepository: DoPickOrderRepository, - private val jdbcDao: JdbcDao + private val jdbcDao: JdbcDao, + private val doPickOrderRecordRepository: DoPickOrderRecordRepository ) { fun getSummaryByStore(storeId: String, requiredDate: LocalDate?): StoreLaneSummary { @@ -25,15 +28,25 @@ class DoPickOrderQueryService( else -> storeId } - val allRecords = doPickOrderRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( + // Query active do_pick_order records (pending, released, completed that haven't been moved yet) + val activeRecords = doPickOrderRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( actualStoreId, targetDate, listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed) ) - println("๐Ÿ” DEBUG: Found ${allRecords.size} records for date $targetDate") + // Query completed records from do_pick_order_record table + val completedRecords = doPickOrderRecordRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( + actualStoreId, + targetDate, + listOf(DoPickOrderStatus.completed) + ) - val filteredRecords = allRecords.filter { doPickOrder -> + println("๐Ÿ” DEBUG: Found ${activeRecords.size} active records for date $targetDate") + println("๐Ÿ” DEBUG: Found ${completedRecords.size} completed records for date $targetDate") + + // Filter active records (check for non-issue lines) + val filteredActiveRecords = activeRecords.filter { doPickOrder -> val hasNonIssueLines = checkDoPickOrderHasNonIssueLines(doPickOrder.id!!) if (!hasNonIssueLines) { println("๐Ÿ” DEBUG: Filtering out DoPickOrder ${doPickOrder.id} - all lines are issues") @@ -41,9 +54,34 @@ class DoPickOrderQueryService( hasNonIssueLines } - println("๐Ÿ” DEBUG: After filtering, ${filteredRecords.size} records remain") + // For completed records, check if they have non-issue lines in the record table + val filteredCompletedRecords = completedRecords.filter { record -> + val hasNonIssueLines = checkDoPickOrderRecordHasNonIssueLines(record.id!!) + if (!hasNonIssueLines) { + println("๐Ÿ” DEBUG: Filtering out DoPickOrderRecord ${record.id} - all lines are issues") + } + hasNonIssueLines + } + + // Combine both lists - need to create a common interface or convert to a common type + // Since both have the same fields we need, we can create a wrapper or use a data class + val allRecords = filteredActiveRecords.map { + DoPickOrderSummaryItem( + truckDepartureTime = it.truckDepartureTime, + truckLanceCode = it.truckLanceCode, + handledBy = it.handledBy + ) + } + filteredCompletedRecords.map { + DoPickOrderSummaryItem( + truckDepartureTime = it.truckDepartureTime, + truckLanceCode = it.truckLanceCode, + handledBy = it.handledBy + ) + } + + println("๐Ÿ” DEBUG: After filtering, ${allRecords.size} records remain (${filteredActiveRecords.size} active + ${filteredCompletedRecords.size} completed)") - val grouped = filteredRecords.groupBy { it.truckDepartureTime to it.truckLanceCode } + val grouped = allRecords.groupBy { it.truckDepartureTime to it.truckLanceCode } .mapValues { (_, list) -> LaneBtn( truckLanceCode = list.first().truckLanceCode ?: "", @@ -72,6 +110,7 @@ class DoPickOrderQueryService( return StoreLaneSummary(storeId = storeId, rows = timeGroups) } + private fun checkDoPickOrderHasNonIssueLines(doPickOrderId: Long): Boolean { return try { val totalLinesSql = """ @@ -105,4 +144,54 @@ class DoPickOrderQueryService( true } } + + // Add new method to check non-issue lines for records + private fun checkDoPickOrderRecordHasNonIssueLines(recordId: Long): Boolean { + return try { + // First get the record_id from do_pick_order_record + val recordSql = """ + SELECT record_id + FROM fpsmsdb.do_pick_order_record dpor + WHERE dpor.id = :recordId + """.trimIndent() + + val recordResult = jdbcDao.queryForList(recordSql, mapOf("recordId" to recordId)) + val recordIdValue = (recordResult.firstOrNull()?.get("record_id") as? Number)?.toLong() + + if (recordIdValue == null) { + return true // If no record_id, assume it's valid + } + + // Check do_pick_order_line_record table + val totalLinesSql = """ + SELECT COUNT(*) as total_lines + FROM fpsmsdb.do_pick_order_line_record dpolr + WHERE dpolr.record_id = :recordId + AND dpolr.deleted = 0 + """.trimIndent() + + val totalLinesResult = jdbcDao.queryForList(totalLinesSql, mapOf("recordId" to recordIdValue)) + val totalLines = (totalLinesResult.firstOrNull()?.get("total_lines") as? Number)?.toInt() ?: 0 + + if (totalLines == 0) { + return true + } + + val nonIssueLinesSql = """ + SELECT COUNT(*) as non_issue_lines + FROM fpsmsdb.do_pick_order_line_record dpolr + WHERE dpolr.record_id = :recordId + AND dpolr.deleted = 0 + AND (dpolr.status IS NULL OR dpolr.status != 'issue') + """.trimIndent() + + val nonIssueLinesResult = jdbcDao.queryForList(nonIssueLinesSql, mapOf("recordId" to recordIdValue)) + val nonIssueLines = (nonIssueLinesResult.firstOrNull()?.get("non_issue_lines") as? Number)?.toInt() ?: 0 + + nonIssueLines > 0 + } catch (e: Exception) { + println("โŒ Error checking non-issue lines for record: ${e.message}") + true + } + } } \ No newline at end of file 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 e9f6c40..32d0bcf 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 @@ -56,6 +56,7 @@ open class DoPickOrderService( private val truckRepository: TruckRepository, private val doPickOrderLineRepository: DoPickOrderLineRepository, @Lazy private val deliveryOrderRepository: DeliveryOrderRepository, + private val doPickOrderLineRecordRepository: DoPickOrderLineRecordRepository ) { open fun findReleasedDoPickOrders(): List { diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/DoDetailResponse.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/DoDetailResponse.kt index 8f90068..3e71f4d 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/DoDetailResponse.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/models/DoDetailResponse.kt @@ -52,4 +52,9 @@ data class AssignByLaneRequest( val truckDepartureTime: String?, // ๅฏ้€‰๏ผš้™ๅฎšๅ‡บ่ฝฆๆ—ถ้—ด val truckLanceCode: String , val requiredDate: LocalDate? // ๅฟ…ๅกซ๏ผš่ฝฆ้“็ผ–ๅท -) \ No newline at end of file +) +data class DoPickOrderSummaryItem( + val truckDepartureTime: java.time.LocalTime?, + val truckLanceCode: String?, + val handledBy: Long? + ) \ 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 903de83..2acbd8a 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 @@ -3570,7 +3570,10 @@ ORDER BY it.deleted == false && it.assignTo?.id == userId && it.type?.value == "do" && - (it.status == PickOrderStatus.RELEASED || it.status == PickOrderStatus.PENDING) + (it.status == PickOrderStatus.RELEASED || + it.status == PickOrderStatus.PENDING || + it.status == PickOrderStatus.PICKING || + it.status == PickOrderStatus.ASSIGNED) } if (userPickOrders.isEmpty()) { @@ -3867,6 +3870,8 @@ ORDER BY mapOf( "id" to lineId, + "pickOrderLineId" to lineId, + "pickOrderId" to po.id, "requiredQty" to pol.qty, "status" to pol.status?.value, "item" to mapOf( diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/SuggestedPickLotService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/SuggestedPickLotService.kt index d3887c0..b6e27c2 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/SuggestedPickLotService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/SuggestedPickLotService.kt @@ -38,6 +38,7 @@ import com.ffii.fpsms.modules.master.entity.ItemsRepository import com.ffii.fpsms.modules.pickOrder.enums.PickOrderLineStatus import com.ffii.fpsms.modules.stock.entity.projection.StockOutLineInfo import com.ffii.fpsms.modules.stock.entity.StockOutLIneRepository +import com.ffii.fpsms.modules.stock.web.model.StockOutStatus @Service open class SuggestedPickLotService( val suggestedPickLotRepository: SuggestPickLotRepository, @@ -282,71 +283,118 @@ open class SuggestedPickLotService( return suggestedPickLotRepository.saveAllAndFlush(request) } private fun createStockOutLineForSuggestion( - suggestion: SuggestedPickLot, - pickOrder: PickOrder - ): StockOutLine? { - try { - val suggestedLotLine = suggestion.suggestedLotLine - val pickOrderLine = suggestion.pickOrderLine - - if (suggestedLotLine == null || pickOrderLine == null) { - println("Cannot create stock out line: missing suggestedLotLine or pickOrderLine") - return null - } + suggestion: SuggestedPickLot, + pickOrder: PickOrder +): StockOutLine? { + try { + val suggestedLotLine = suggestion.suggestedLotLine + val pickOrderLine = suggestion.pickOrderLine + + // FIX: Allow creating stock out line even when suggestedLotLine is null (insufficient stock case) + if (pickOrderLine == null) { + println("Cannot create stock out line: missing pickOrderLine") + return null + } + + // Get pick order type value (do, job, material, etc.) + val pickOrderTypeValue = pickOrder.type?.value ?: "do" + + // If suggestedLotLine is null, create stock out line with inventoryLotLineId = null + if (suggestedLotLine == null) { + println("Creating stock out line with no lot (insufficient stock) for pickOrderLineId: ${pickOrderLine.id}, type: $pickOrderTypeValue") - // Check if stock out line already exists - val existingStockOutLine = stockOutLIneRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse( - pickOrderLine.id!!, - suggestedLotLine.id!! - ) + // Check if stock out line already exists for this pick order line with null lot + val existingStockOutLineInfo = stockOutLIneRepository + .findAllByPickOrderLineIdAndDeletedFalse(pickOrderLine.id!!) + .find { it.inventoryLotLineId == null } - if (existingStockOutLine.isNotEmpty()) { - println("Stock out line already exists for pickOrderLineId: ${pickOrderLine.id}, inventoryLotLineId: ${suggestedLotLine.id}") - return existingStockOutLine.first() + if (existingStockOutLineInfo != null) { + println("Stock out line already exists for pickOrderLineId: ${pickOrderLine.id} with no lot") + // Get the actual entity by ID + return stockOutLIneRepository.findById(existingStockOutLineInfo.id!!).orElse(null) } // Get or create StockOut val stockOut = stockOutRepository.findByConsoPickOrderCode(pickOrder.consoCode ?: "") .orElseGet { - // Create new StockOut if it doesn't exist val newStockOut = StockOut().apply { this.consoPickOrderCode = pickOrder.consoCode ?: "" - + this.type = pickOrderTypeValue // Use pick order type (do, job, material, etc.) + this.status = StockOutStatus.PENDING.status } stockOutRepository.save(newStockOut) } - - // Update pick order line status to PICKING - val updatedPickOrderLine = pickOrderLineRepository.saveAndFlush( - pickOrderLine.apply { - this.status = PickOrderLineStatus.PICKING - } - ) - - // Get item - val item = itemRepository.findById(updatedPickOrderLine.item!!.id!!).orElseThrow() - - // Create stock out line + val item = pickOrderLine.item ?: itemRepository.findById(pickOrderLine.item!!.id!!).orElseThrow() + // Create stock out line with inventoryLotLineId = null val stockOutLine = StockOutLine().apply { - this.item = item - this.qty = 0.0 this.stockOut = stockOut - this.inventoryLotLine = suggestedLotLine - this.pickOrderLine = updatedPickOrderLine + this.pickOrderLine = pickOrderLine + this.inventoryLotLine = null // No lot available + this.qty = (suggestion.qty ?: BigDecimal.ZERO).toDouble() this.status = StockOutLineStatus.PENDING.status + this.deleted = false } - val savedStockOutLine = stockOutLIneRepository.saveAndFlush(stockOutLine) - println(" Created stock out line ID: ${savedStockOutLine.id} for suggestion ID: ${suggestion.id}") - + val savedStockOutLine = stockOutLIneRepository.save(stockOutLine) + println("Created stock out line ${savedStockOutLine.id} with no lot for pickOrderLineId: ${pickOrderLine.id}") return savedStockOutLine - - } catch (e: Exception) { - println("โŒ Error creating stock out line for suggestion: ${e.message}") - e.printStackTrace() - return null } + + // Original logic for when suggestedLotLine is not null + // Check if stock out line already exists + val existingStockOutLine = stockOutLIneRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse( + pickOrderLine.id!!, + suggestedLotLine.id!! + ) + + if (existingStockOutLine.isNotEmpty()) { + println("Stock out line already exists for pickOrderLineId: ${pickOrderLine.id}, inventoryLotLineId: ${suggestedLotLine.id}") + return existingStockOutLine.first() + } + + // Get or create StockOut + val stockOut = stockOutRepository.findByConsoPickOrderCode(pickOrder.consoCode ?: "") + .orElseGet { + // Create new StockOut if it doesn't exist + val newStockOut = StockOut().apply { + this.consoPickOrderCode = pickOrder.consoCode ?: "" + this.type = pickOrderTypeValue // Use pick order type (do, job, material, etc.) + this.status = StockOutStatus.PENDING.status + } + stockOutRepository.save(newStockOut) + } + + // Update pick order line status to PICKING + val updatedPickOrderLine = pickOrderLineRepository.saveAndFlush( + pickOrderLine.apply { + this.status = PickOrderLineStatus.PICKING + } + ) + + // Get item + val item = itemRepository.findById(updatedPickOrderLine.item!!.id!!).orElseThrow() + + // Create stock out line + val stockOutLine = StockOutLine().apply { + this.item = item + this.qty = 0.0 + this.stockOut = stockOut + this.inventoryLotLine = suggestedLotLine + this.pickOrderLine = updatedPickOrderLine + this.status = StockOutLineStatus.PENDING.status + } + + val savedStockOutLine = stockOutLIneRepository.saveAndFlush(stockOutLine) + println(" Created stock out line ID: ${savedStockOutLine.id} for suggestion ID: ${suggestion.id}") + + return savedStockOutLine + + } catch (e: Exception) { + println("โŒ Error creating stock out line for suggestion: ${e.message}") + e.printStackTrace() + return null } +} @Transactional(rollbackFor = [Exception::class]) open fun resuggestPickOrder(pickOrderId: Long): MessageResponse { try { @@ -379,7 +427,7 @@ open class SuggestedPickLotService( // Only resuggest if the pick order has rejected stock out lines pickOrderToCheck.pickOrderLines.any { pol -> val stockOutLines = stockOutLIneRepository.findAllByPickOrderLineIdAndDeletedFalse(pol.id!!) - val hasRejectedStockOutLine = stockOutLines.any { it.status == "rejected" } + val hasRejectedStockOutLine = stockOutLines.any { it.status.equals("rejected", ignoreCase = true)} if (hasRejectedStockOutLine) { println("Pick Order ${pickOrderToCheck.code} has rejected stock out lines - will resuggest") diff --git a/src/main/resources/db/changelog/changes/20251106_01_enson/01_altertable_enson.sql b/src/main/resources/db/changelog/changes/20251106_01_enson/01_altertable_enson.sql new file mode 100644 index 0000000..b1a5d5c --- /dev/null +++ b/src/main/resources/db/changelog/changes/20251106_01_enson/01_altertable_enson.sql @@ -0,0 +1,9 @@ +-- liquibase formatted sql +-- changeset enson:altertable_enson + +ALTER TABLE `fpsmsdb`.`items` +ADD COLUMN `store_id` VARCHAR(255) After `type`, +ADD COLUMN `MTMSPickRoutingID` INT After `store_id`; + +ALTER TABLE `fpsmsdb`.`truck` +ADD COLUMN `districtReference` INT After `LoadingSequence`;