| @@ -13,8 +13,6 @@ 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 | |||
| @@ -30,6 +28,8 @@ open class StockTransferRecordService( | |||
| ) { | |||
| private enum class TransferStockInMode { | |||
| MERGED_EXISTING_LOT, | |||
| /** Merged into smallest-id AVAILABLE line among several with same expiry (same lot key at target). */ | |||
| MERGED_EXISTING_LOT_AMBIGUOUS, | |||
| CREATED_NEW_LOT | |||
| } | |||
| @@ -49,12 +49,17 @@ open class StockTransferRecordService( | |||
| name = "Stock Transfer Record", | |||
| code = when (stockInMode) { | |||
| TransferStockInMode.MERGED_EXISTING_LOT -> "MERGED_EXISTING_LOT" | |||
| TransferStockInMode.MERGED_EXISTING_LOT_AMBIGUOUS -> "MERGED_EXISTING_LOT_AMBIGUOUS" | |||
| TransferStockInMode.CREATED_NEW_LOT -> "CREATED_NEW_LOT" | |||
| }, | |||
| type = "success", | |||
| message = when (stockInMode) { | |||
| TransferStockInMode.MERGED_EXISTING_LOT -> "Stock transfer completed successfully (merged into existing target lot)" | |||
| TransferStockInMode.CREATED_NEW_LOT -> "Stock transfer completed successfully (created new target lot)" | |||
| TransferStockInMode.MERGED_EXISTING_LOT -> | |||
| "Stock transfer completed successfully (merged into existing target lot)" | |||
| TransferStockInMode.MERGED_EXISTING_LOT_AMBIGUOUS -> | |||
| "已併入較早建立的批次(同批號有多筆可用)" | |||
| TransferStockInMode.CREATED_NEW_LOT -> | |||
| "Stock transfer completed successfully (created new target lot)" | |||
| }, | |||
| errorPosition = null | |||
| ) | |||
| @@ -120,20 +125,29 @@ open class StockTransferRecordService( | |||
| status = InventoryLotLineStatus.AVAILABLE, | |||
| ).filter { it.id != inventoryLotLine.id } | |||
| // Same expiry as source required to merge; repository orders by ill.id ASC — first = earliest-created line | |||
| val sameExpiryMergeable = mergeCandidates.filter { | |||
| val targetExpiry = it.inventoryLot?.expiryDate | |||
| targetExpiry != null && targetExpiry == expiryDate | |||
| } | |||
| return when { | |||
| mergeCandidates.isEmpty() -> | |||
| stockInLineService.createStockIn(stockInRequest) to TransferStockInMode.CREATED_NEW_LOT | |||
| mergeCandidates.size == 1 -> | |||
| sameExpiryMergeable.isEmpty() -> | |||
| stockInLineService.createStockIn(stockInRequest) to TransferStockInMode.CREATED_NEW_LOT | |||
| sameExpiryMergeable.size == 1 -> | |||
| stockInLineService.createStockInForExistingInventoryLotLine( | |||
| stockInRequest, | |||
| mergeCandidates.single(), | |||
| sameExpiryMergeable.single(), | |||
| ) to TransferStockInMode.MERGED_EXISTING_LOT | |||
| else -> | |||
| throw ResponseStatusException( | |||
| HttpStatus.BAD_REQUEST, | |||
| "目標倉在同一品項與批號下有多筆可用的庫存批號行,無法自動併批;請檢查資料。" + | |||
| " (Multiple AVAILABLE inventory lot lines for same warehouse, item, lotNo.)", | |||
| ) | |||
| else -> { | |||
| val targetLine = sameExpiryMergeable.first() | |||
| stockInLineService.createStockInForExistingInventoryLotLine( | |||
| stockInRequest, | |||
| targetLine, | |||
| ) to TransferStockInMode.MERGED_EXISTING_LOT_AMBIGUOUS | |||
| } | |||
| } | |||
| } | |||