diff --git a/src/main/java/com/ffii/fpsms/modules/common/internalSetup/SetupController.kt b/src/main/java/com/ffii/fpsms/modules/common/internalSetup/SetupController.kt index f21a9b4..960aa27 100644 --- a/src/main/java/com/ffii/fpsms/modules/common/internalSetup/SetupController.kt +++ b/src/main/java/com/ffii/fpsms/modules/common/internalSetup/SetupController.kt @@ -274,4 +274,69 @@ class SetupController( ) } } + @PostMapping("/inventory/print-lot-stockin-labels-by-store-ids") +fun printLotStockInLabelsByStoreIds( + @RequestBody request: Map +): ResponseEntity> { + + 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() + // storeIds: ["2F","4F"] + val storeIds = (request["storeIds"] as? List<*>)?.mapNotNull { it?.toString() } ?: emptyList() + + if (printerId == null) { + return ResponseEntity.badRequest().body( + mapOf( + "success" to false, + "message" to "printerId is required" + ) + ) + } + if (storeIds.isEmpty()) { + return ResponseEntity.badRequest().body( + mapOf( + "success" to false, + "message" to "storeIds is required" + ) + ) + } + + return try { + val result = inventorySetup.printLotStockInLabelsByStoreIdsV1( + printerId = printerId, + storeIds = storeIds, + printQty = printQty, + fromIndex = fromIndex, + toIndex = toIndex + ) + + val body = + if (result.success) { + mapOf( + "success" to true, + "message" to "Lot stock-in labels printed successfully", + "lastIndex" to result.lastIndex, + "totalLots" to result.totalLots + ) + } else { + mapOf( + "success" to false, + "message" to (result.errorMessage ?: "Printer error"), + "lastIndex" to result.lastIndex, + "totalLots" to result.totalLots + ) + } + + ResponseEntity.ok(body) + } catch (e: Exception) { + ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + mapOf( + "success" to false, + "message" to (e.message ?: "Unknown error occurred while printing lot stock-in labels") + ) + ) + } +} } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/common/internalSetup/inventorySetup.kt b/src/main/java/com/ffii/fpsms/modules/common/internalSetup/inventorySetup.kt index 2fb88c6..fdc84d6 100644 --- a/src/main/java/com/ffii/fpsms/modules/common/internalSetup/inventorySetup.kt +++ b/src/main/java/com/ffii/fpsms/modules/common/internalSetup/inventorySetup.kt @@ -471,4 +471,97 @@ open class InventorySetup { errorMessage = null ) } + @Transactional(rollbackFor = [Exception::class]) +open fun printLotStockInLabelsByStoreIdsV1( + printerId: Long, + storeIds: List, + printQty: Int = 1, + fromIndex: Int? = null, + toIndex: Int? = null +): PrintProgressResult { + + if (storeIds.isEmpty()) { + return PrintProgressResult( + success = false, + lastIndex = -1, + totalLots = 0, + errorMessage = "storeIds is empty" + ) + } + + // 1. 查出对应 store_id 的 lot line + val allInventoryLotLines = inventoryLotLineRepository + .findAllByStoreIdsAndHasStockInLine(storeIds) + + if (allInventoryLotLines.isEmpty()) { + return PrintProgressResult( + success = false, + lastIndex = -1, + totalLots = 0, + errorMessage = "no lots found for given storeIds" + ) + } + + val effectiveTotal = allInventoryLotLines.size + + // 2. 计算要打印的 index 范围 + val startIndex = (fromIndex ?: 0).coerceAtLeast(0) + val endIndex = (toIndex ?: (effectiveTotal - 1)).coerceAtMost(effectiveTotal - 1) + + if (startIndex > endIndex || startIndex >= effectiveTotal) { + return PrintProgressResult( + success = false, + lastIndex = startIndex - 1, + totalLots = effectiveTotal, + errorMessage = "invalid index range" + ) + } + + var lastIndex = startIndex - 1 + + // 3. 逐张打印,遇到打印机错误就立即返回,支持断点续打 + for (globalIndex in startIndex..endIndex) { + val inventoryLotLine = allInventoryLotLines[globalIndex] + val stockInLineId = inventoryLotLine.inventoryLot?.stockInLine?.id + ?: return PrintProgressResult( + success = false, + lastIndex = lastIndex, + totalLots = effectiveTotal, + errorMessage = "Stock in line missing for inventoryLotLineId=${inventoryLotLine.id}" + ) + + try { + stockInLineService.printQrCode( + PrintQrCodeForSilRequest( + stockInLineId = stockInLineId, + printerId = printerId, + printQty = printQty + ) + ) + lastIndex = globalIndex + } catch (e: Exception) { + val msg = when { + e.message?.contains("paper", ignoreCase = true) == true -> + "Printer error (maybe out of paper): ${e.message}" + else -> + "Printer error: ${e.message}" + } + + return PrintProgressResult( + success = false, + lastIndex = lastIndex, + totalLots = effectiveTotal, + errorMessage = msg + ) + } + } + + // 全部打印成功 + return PrintProgressResult( + success = true, + lastIndex = lastIndex, + totalLots = effectiveTotal, + errorMessage = null + ) +} } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLineRepository.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLineRepository.kt index 36be207..b5c6711 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLineRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLineRepository.kt @@ -106,5 +106,16 @@ fun findExpiredItems(@Param("today") today: LocalDate): List """) fun findAllByDeletedIsFalseAndHasStockInLine(): List - + @Query(""" + SELECT ill FROM InventoryLotLine ill + JOIN ill.warehouse w + JOIN ill.inventoryLot il + WHERE w.store_id IN :storeIds + AND ill.deleted = false + AND il.stockInLine IS NOT NULL + ORDER BY w.store_id, il.item.code, il.lotNo +""") +fun findAllByStoreIdsAndHasStockInLine( + @Param("storeIds") storeIds: List +): List } \ No newline at end of file