|
|
@@ -501,28 +501,41 @@ open class ProductProcessService( |
|
|
val itemIds = bomMaterials.mapNotNull { it.item?.id } |
|
|
val itemIds = bomMaterials.mapNotNull { it.item?.id } |
|
|
|
|
|
|
|
|
// calculate each item's available stock |
|
|
// calculate each item's available stock |
|
|
val stockQtyMap = bomMaterials.mapNotNull { material -> |
|
|
|
|
|
val itemId = material.item?.id ?: return@mapNotNull null |
|
|
|
|
|
val availableLots = inventoryLotLineRepository |
|
|
|
|
|
.findAllByInventoryLotItemIdAndStatus(itemId, InventoryLotLineStatus.AVAILABLE) |
|
|
|
|
|
val stockQty = availableLots.sumOf { lot -> |
|
|
|
|
|
(lot.inQty ?: BigDecimal.ZERO) |
|
|
|
|
|
.minus(lot.outQty ?: BigDecimal.ZERO) |
|
|
|
|
|
.minus(lot.holdQty ?: BigDecimal.ZERO) |
|
|
|
|
|
} |
|
|
|
|
|
// Get the stockUom from the first available lot line |
|
|
|
|
|
// stockItemUomId is the ItemUom id, we need to get the UomConversion id from it |
|
|
|
|
|
val stockItemUom = availableLots.firstOrNull()?.stockUom |
|
|
|
|
|
if (stockItemUom == null) { |
|
|
|
|
|
println("WARNING: No stockUom found for itemId=$itemId in available lots") |
|
|
|
|
|
} |
|
|
|
|
|
val stockUomId = stockItemUom?.uom?.id |
|
|
|
|
|
if (stockUomId == null && stockItemUom != null) { |
|
|
|
|
|
println("WARNING: stockItemUom.id=${stockItemUom.id} exists but has no uom (UomConversion)") |
|
|
|
|
|
} |
|
|
|
|
|
println("DEBUG itemId=$itemId: stockItemUom.id=${stockItemUom?.id}, stockUom.uom.id=$stockUomId, availableLots count=${availableLots.size}") |
|
|
|
|
|
itemId to Pair(stockQty, stockUomId) |
|
|
|
|
|
}.toMap() |
|
|
|
|
|
|
|
|
// Around line 504-524, update the stockQtyMap calculation |
|
|
|
|
|
val stockQtyMap = bomMaterials.mapNotNull { material -> |
|
|
|
|
|
val itemId = material.item?.id ?: return@mapNotNull null |
|
|
|
|
|
val availableLots = inventoryLotLineRepository |
|
|
|
|
|
.findAllByInventoryLotItemIdAndStatus(itemId, InventoryLotLineStatus.AVAILABLE) |
|
|
|
|
|
val stockQty = availableLots.sumOf { lot -> |
|
|
|
|
|
(lot.inQty ?: BigDecimal.ZERO) |
|
|
|
|
|
.minus(lot.outQty ?: BigDecimal.ZERO) |
|
|
|
|
|
.minus(lot.holdQty ?: BigDecimal.ZERO) |
|
|
|
|
|
} |
|
|
|
|
|
// Get the stockUom from the first available lot line |
|
|
|
|
|
// stockItemUomId is the ItemUom id, we need to get the UomConversion id from it |
|
|
|
|
|
val stockItemUom = availableLots.firstOrNull()?.stockUom |
|
|
|
|
|
var stockUomId = stockItemUom?.uom?.id |
|
|
|
|
|
|
|
|
|
|
|
// Fallback: If no lots exist, get stockUom from item's stockUnit ItemUom |
|
|
|
|
|
if (stockUomId == null && availableLots.isEmpty()) { |
|
|
|
|
|
val stockUnitItemUom = itemUomService.findStockUnitByItemId(itemId) |
|
|
|
|
|
stockUomId = stockUnitItemUom?.uom?.id |
|
|
|
|
|
if (stockUomId != null) { |
|
|
|
|
|
println("DEBUG itemId=$itemId: Using fallback stockUnit ItemUom - stockUom.uom.id=$stockUomId") |
|
|
|
|
|
} else { |
|
|
|
|
|
println("WARNING: No stockUom found for itemId=$itemId in available lots and no stockUnit ItemUom configured") |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
if (stockItemUom == null) { |
|
|
|
|
|
println("WARNING: No stockUom found for itemId=$itemId in available lots") |
|
|
|
|
|
} |
|
|
|
|
|
if (stockUomId == null && stockItemUom != null) { |
|
|
|
|
|
println("WARNING: stockItemUom.id=${stockItemUom.id} exists but has no uom (UomConversion)") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
println("DEBUG itemId=$itemId: stockItemUom.id=${stockItemUom?.id}, stockUom.uom.id=$stockUomId, availableLots count=${availableLots.size}") |
|
|
|
|
|
itemId to Pair(stockQty, stockUomId) |
|
|
|
|
|
}.toMap() |
|
|
|
|
|
|
|
|
// calculate statistics |
|
|
// calculate statistics |
|
|
val totalStockQty = stockQtyMap.values.sumOf { (qty, _) -> qty.toInt() } |
|
|
val totalStockQty = stockQtyMap.values.sumOf { (qty, _) -> qty.toInt() } |
|
|
@@ -690,28 +703,10 @@ val sufficientStockQty = bomMaterials |
|
|
println("Converting reqQty: ${line.reqQty} from UOM id=$reqUomId to baseUnit") |
|
|
println("Converting reqQty: ${line.reqQty} from UOM id=$reqUomId to baseUnit") |
|
|
println(" Source ItemUom - ratioN: ${sourceItemUom?.ratioN}, ratioD: ${sourceItemUom?.ratioD}") |
|
|
println(" Source ItemUom - ratioN: ${sourceItemUom?.ratioN}, ratioD: ${sourceItemUom?.ratioD}") |
|
|
println(" Target ItemUom (baseUnit) - ratioN: ${targetItemUom?.ratioN}, ratioD: ${targetItemUom?.ratioD}") |
|
|
println(" Target ItemUom (baseUnit) - ratioN: ${targetItemUom?.ratioN}, ratioD: ${targetItemUom?.ratioD}") |
|
|
|
|
|
println(" Base Unit UOM id: ${targetItemUom?.uom?.id}") |
|
|
|
|
|
|
|
|
if (sourceItemUom == null) { |
|
|
|
|
|
println("WARNING: No ItemUom found for itemId=$itemId, uomId=$reqUomId (UomConversion id). Cannot convert reqQty.") |
|
|
|
|
|
println(" This means the item doesn't have this UOM configured in item_uom table.") |
|
|
|
|
|
println(" Calculation: Cannot calculate - missing Source ItemUom with ratioN and ratioD") |
|
|
|
|
|
null |
|
|
|
|
|
} else if (targetItemUom == null) { |
|
|
|
|
|
println("WARNING: No baseUnit ItemUom found for itemId=$itemId. Cannot convert reqQty.") |
|
|
|
|
|
println(" Calculation: Cannot calculate - missing Target ItemUom (baseUnit)") |
|
|
|
|
|
null |
|
|
|
|
|
} else { |
|
|
|
|
|
val sourceRatioN = sourceItemUom.ratioN ?: BigDecimal.ONE |
|
|
|
|
|
val sourceRatioD = sourceItemUom.ratioD ?: BigDecimal.ONE |
|
|
|
|
|
val targetRatioN = targetItemUom.ratioN ?: BigDecimal.ONE |
|
|
|
|
|
val targetRatioD = targetItemUom.ratioD ?: BigDecimal.ONE |
|
|
|
|
|
|
|
|
|
|
|
val baseQty = (line.reqQty ?: BigDecimal.ZERO).multiply(sourceRatioN).divide(sourceRatioD, 2, RoundingMode.HALF_UP) |
|
|
|
|
|
val finalQty = baseQty.multiply(targetRatioD).divide(targetRatioN, 2, RoundingMode.HALF_UP) |
|
|
|
|
|
|
|
|
|
|
|
println(" Calculation: baseQty = ${line.reqQty} * $sourceRatioN / $sourceRatioD = $baseQty") |
|
|
|
|
|
println(" Calculation: finalQty = $baseQty * $targetRatioD / $targetRatioN = $finalQty") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Try conversion first - it may have special case handling |
|
|
|
|
|
try { |
|
|
val result = itemUomService.convertUomByItem( |
|
|
val result = itemUomService.convertUomByItem( |
|
|
ConvertUomByItemRequest( |
|
|
ConvertUomByItemRequest( |
|
|
itemId = itemId, |
|
|
itemId = itemId, |
|
|
@@ -722,6 +717,17 @@ val sufficientStockQty = bomMaterials |
|
|
) |
|
|
) |
|
|
println("Converted reqQty result: ${result.newQty} in base UOM: ${result.udfudesc}") |
|
|
println("Converted reqQty result: ${result.newQty} in base UOM: ${result.udfudesc}") |
|
|
result |
|
|
result |
|
|
|
|
|
} catch (e: IllegalArgumentException) { |
|
|
|
|
|
// If conversion fails, check if it's because sourceItemUom is missing |
|
|
|
|
|
if (sourceItemUom == null) { |
|
|
|
|
|
println("WARNING: No ItemUom found for itemId=$itemId, uomId=$reqUomId (UomConversion id). Cannot convert reqQty.") |
|
|
|
|
|
println(" This means the item doesn't have this UOM configured in item_uom table.") |
|
|
|
|
|
println(" Calculation: Cannot calculate - missing Source ItemUom with ratioN and ratioD") |
|
|
|
|
|
null |
|
|
|
|
|
} else { |
|
|
|
|
|
// Re-throw if it's a different error |
|
|
|
|
|
throw e |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} catch (e: Exception) { |
|
|
} catch (e: Exception) { |
|
|
println("Error converting reqQty: ${e.message}") |
|
|
println("Error converting reqQty: ${e.message}") |
|
|
|