| @@ -186,4 +186,25 @@ class SetupController( | |||||
| return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse) | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse) | ||||
| } | } | ||||
| } | } | ||||
| @PostMapping("/inventory/print-lot-stockin-labels-by-item-ids") | |||||
| fun printLotStockInLabelsByItemIds(@RequestBody request: Map<String, Any>): ResponseEntity<Map<String, Any>> { | |||||
| val printerId = (request["printerId"] as? Number)?.toLong() | |||||
| val printQty = (request["printQty"] as? Number)?.toInt() ?: 1 | |||||
| val fromIndex = (request["fromIndex"] as? Number)?.toInt() | |||||
| val toIndex = (request["toIndex"] as? Number)?.toInt() | |||||
| val itemIds = (request["itemIds"] as? List<*>)?.mapNotNull { (it as? Number)?.toLong() } ?: emptyList() | |||||
| if (printerId == null) return ResponseEntity.badRequest().body(mapOf("success" to false, "error" to "printerId is required")) | |||||
| if (itemIds.isEmpty()) return ResponseEntity.badRequest().body(mapOf("success" to false, "error" to "itemIds is required")) | |||||
| val printedCount = inventorySetup.printLotStockInLabelsByItemIds( | |||||
| printerId = printerId, | |||||
| itemIds = itemIds, | |||||
| printQty = printQty, | |||||
| fromIndex = fromIndex, | |||||
| toIndex = toIndex | |||||
| ) | |||||
| return ResponseEntity.ok(mapOf("success" to true, "message" to "Lot stock-in labels printed successfully", "printedCount" to printedCount)) | |||||
| } | |||||
| } | } | ||||
| @@ -141,7 +141,7 @@ open class InventorySetup { | |||||
| for (data in inventoryDataList) { | for (data in inventoryDataList) { | ||||
| try { | try { | ||||
| // Find item by code (itemNo) | // Find item by code (itemNo) | ||||
| val item = itemsRepository.findByCodeAndDeletedFalse(data.itemNo) | |||||
| val item = itemsRepository.findFirstByCodeAndDeletedFalse(data.itemNo) | |||||
| if (item == null) { | if (item == null) { | ||||
| println("NOT FOUND - Item with code '${data.itemNo}' does not exist") | println("NOT FOUND - Item with code '${data.itemNo}' does not exist") | ||||
| @@ -311,4 +311,47 @@ open class InventorySetup { | |||||
| return printedCount | return printedCount | ||||
| } | } | ||||
| @Transactional(rollbackFor = [Exception::class]) | |||||
| open fun printLotStockInLabelsByItemIds( | |||||
| printerId: Long, | |||||
| itemIds: List<Long>, | |||||
| printQty: Int = 1, | |||||
| fromIndex: Int? = null, | |||||
| toIndex: Int? = null | |||||
| ): Int { | |||||
| if (itemIds.isEmpty()) return 0 | |||||
| val allInventoryLotLines = inventoryLotLineRepository | |||||
| .findAllByItemIdIn(itemIds) | |||||
| .filter { it.deleted == false && it.inventoryLot?.stockInLine != null } | |||||
| if (allInventoryLotLines.isEmpty()) return 0 | |||||
| val inventoryLotLinesToPrint = if (fromIndex != null && toIndex != null) { | |||||
| val startIndex = fromIndex.coerceAtLeast(0) | |||||
| val endIndex = toIndex.coerceAtMost(allInventoryLotLines.size - 1) | |||||
| if (startIndex > endIndex || startIndex >= allInventoryLotLines.size) return 0 | |||||
| allInventoryLotLines.subList(startIndex, endIndex + 1) | |||||
| } else { | |||||
| allInventoryLotLines | |||||
| } | |||||
| var printedCount = 0 | |||||
| for ((index, inventoryLotLine) in inventoryLotLinesToPrint.withIndex()) { | |||||
| val stockInLineId = inventoryLotLine.inventoryLot?.stockInLine?.id | |||||
| ?: throw IllegalArgumentException("Stock in line missing") | |||||
| val actualIndex = if (fromIndex != null) fromIndex + index else index | |||||
| println("Processing lot ${actualIndex + 1}/${allInventoryLotLines.size}: Lot No: ${inventoryLotLine.inventoryLot?.lotNo}, StockInLineId: $stockInLineId") | |||||
| stockInLineService.printQrCode( | |||||
| PrintQrCodeForSilRequest( | |||||
| stockInLineId = stockInLineId, | |||||
| printerId = printerId, | |||||
| printQty = printQty | |||||
| ) | |||||
| ) | |||||
| printedCount++ | |||||
| } | |||||
| return printedCount | |||||
| } | |||||
| } | } | ||||
| @@ -112,10 +112,10 @@ fun searchDoLite( | |||||
| fun searchDoLitePage( | fun searchDoLitePage( | ||||
| @Param("code") code: String?, | @Param("code") code: String?, | ||||
| @Param("shopName") shopName: String?, | @Param("shopName") shopName: String?, | ||||
| @Param("status") status: DeliveryOrderStatus?, // 直接用枚举最稳 | |||||
| @Param("status") status: DeliveryOrderStatus?, | |||||
| @Param("etaStart") etaStart: LocalDateTime?, | @Param("etaStart") etaStart: LocalDateTime?, | ||||
| @Param("etaEnd") etaEnd: LocalDateTime?, | @Param("etaEnd") etaEnd: LocalDateTime?, | ||||
| pageable: Pageable | pageable: Pageable | ||||
| ): Page<DeliveryOrderInfo> | |||||
| ): Page<DeliveryOrderInfoLite> | |||||
| } | } | ||||
| @@ -54,4 +54,10 @@ interface ItemsRepository : AbstractRepository<Items, Long> { | |||||
| """ | """ | ||||
| ) | ) | ||||
| fun findByM18BomCode(m18BomCode: String): Items?; | fun findByM18BomCode(m18BomCode: String): Items?; | ||||
| @Query( | |||||
| nativeQuery = true, | |||||
| value = "SELECT * FROM items i WHERE i.code = :code AND i.deleted = false ORDER BY i.id LIMIT 1" | |||||
| ) | |||||
| fun findFirstByCodeAndDeletedFalse(code: String): Items? | |||||
| } | } | ||||
| @@ -318,7 +318,9 @@ open class SuggestedPickLotService( | |||||
| if (doPreferredFloor != null && warehouseStoreId != doPreferredFloor) { | if (doPreferredFloor != null && warehouseStoreId != doPreferredFloor) { | ||||
| return@forEachIndexed | return@forEachIndexed | ||||
| } | } | ||||
| if (doPreferredFloor != null && warehouseStoreId != "1F" && warehouseStoreId != doPreferredFloor) { | |||||
| return@forEachIndexed | |||||
| } | |||||
| val availableQtyInBaseUnits = calculateRemainingQtyForInfo(lotLine) | val availableQtyInBaseUnits = calculateRemainingQtyForInfo(lotLine) | ||||
| val holdQtyInBaseUnits = holdQtyMap[lotLine.id] ?: zero | val holdQtyInBaseUnits = holdQtyMap[lotLine.id] ?: zero | ||||
| val availableQtyInSalesUnits = availableQtyInBaseUnits | val availableQtyInSalesUnits = availableQtyInBaseUnits | ||||