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 04a65f3..1f800a0 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 @@ -182,14 +182,25 @@ interface InventoryLotLineRepository : AbstractRepository + /** + * Same business key as transfer merge target lookup; restricted to [status] (e.g. AVAILABLE). + * Returns a list — never single-result — so duplicate unavailable rows elsewhere do not cause NonUniqueResultException. + */ @Query(""" SELECT ill FROM InventoryLotLine ill WHERE ill.inventoryLot.lotNo = :lotNo AND ill.inventoryLot.item.id = :itemId AND ill.warehouse.id = :warehouseId AND ill.deleted = false + AND ill.status = :status + ORDER BY ill.id ASC """) - fun findByLotNoAndItemIdAndWarehouseId(lotNo: String, itemId: Long, warehouseId: Long): InventoryLotLine? + fun findAllByLotNoAndItemIdAndWarehouseIdAndStatus( + @Param("lotNo") lotNo: String, + @Param("itemId") itemId: Long, + @Param("warehouseId") warehouseId: Long, + @Param("status") status: InventoryLotLineStatus, + ): List @Query(""" SELECT ill FROM InventoryLotLine ill diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/StockTransferRecordService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/StockTransferRecordService.kt index 99c8a2a..36dd5aa 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/StockTransferRecordService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/StockTransferRecordService.kt @@ -13,6 +13,8 @@ import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository import com.ffii.fpsms.modules.stock.entity.enum.InventoryLotLineStatus +import org.springframework.http.HttpStatus +import org.springframework.web.server.ResponseStatusException @Service @@ -110,21 +112,28 @@ open class StockTransferRecordService( warehouseId = request.warehouseId ) - val existingTargetLotLine = inventoryLotLineRepository.findByLotNoAndItemIdAndWarehouseId( + val warehouseId = request.warehouseId + val mergeCandidates = inventoryLotLineRepository.findAllByLotNoAndItemIdAndWarehouseIdAndStatus( lotNo = lotNo, itemId = itemId, - warehouseId = request.warehouseId - ) - - return if ( - existingTargetLotLine != null && - existingTargetLotLine.status == InventoryLotLineStatus.AVAILABLE && - existingTargetLotLine.id != inventoryLotLine.id - ) { - stockInLineService.createStockInForExistingInventoryLotLine(stockInRequest, existingTargetLotLine) to - TransferStockInMode.MERGED_EXISTING_LOT - } else { - stockInLineService.createStockIn(stockInRequest) to TransferStockInMode.CREATED_NEW_LOT + warehouseId = warehouseId, + status = InventoryLotLineStatus.AVAILABLE, + ).filter { it.id != inventoryLotLine.id } + + return when { + mergeCandidates.isEmpty() -> + stockInLineService.createStockIn(stockInRequest) to TransferStockInMode.CREATED_NEW_LOT + mergeCandidates.size == 1 -> + stockInLineService.createStockInForExistingInventoryLotLine( + stockInRequest, + mergeCandidates.single(), + ) to TransferStockInMode.MERGED_EXISTING_LOT + else -> + throw ResponseStatusException( + HttpStatus.BAD_REQUEST, + "目標倉在同一品項與批號下有多筆可用的庫存批號行,無法自動併批;請檢查資料。" + + " (Multiple AVAILABLE inventory lot lines for same warehouse, item, lotNo.)", + ) } }