| @@ -97,6 +97,29 @@ open class ItemUomService( | |||||
| return stockQty.setScale(0, RoundingMode.UP) | return stockQty.setScale(0, RoundingMode.UP) | ||||
| } | } | ||||
| /** | |||||
| * Convert purchase qty -> stock qty (PO display / acceptedQty calculation) | |||||
| * with round-down to integer stock qty. | |||||
| */ | |||||
| open fun convertPurchaseQtyToStockQtyRoundDown(itemId: Long, purchaseQty: BigDecimal): BigDecimal { | |||||
| val purchaseUnit = findPurchaseUnitByItemId(itemId) ?: return purchaseQty | |||||
| val stockUnit = findStockUnitByItemId(itemId) ?: return purchaseQty | |||||
| val one = BigDecimal.ONE | |||||
| // Use high precision for intermediate steps, and round down only at the end. | |||||
| val calcScale = 10 | |||||
| val baseQty = purchaseQty | |||||
| .multiply(purchaseUnit.ratioN ?: one) | |||||
| .divide(purchaseUnit.ratioD ?: one, calcScale, RoundingMode.HALF_UP) | |||||
| val stockQty = baseQty | |||||
| .multiply(stockUnit.ratioD ?: one) | |||||
| .divide(stockUnit.ratioN ?: one, calcScale, RoundingMode.HALF_UP) | |||||
| return stockQty.setScale(0, RoundingMode.DOWN) | |||||
| } | |||||
| /** Inverse of convertPurchaseQtyToStockQty: stock qty -> purchase qty (for PO-origin StockInLine display). */ | /** Inverse of convertPurchaseQtyToStockQty: stock qty -> purchase qty (for PO-origin StockInLine display). */ | ||||
| open fun convertStockQtyToPurchaseQty(itemId: Long, stockQty: BigDecimal): BigDecimal { | open fun convertStockQtyToPurchaseQty(itemId: Long, stockQty: BigDecimal): BigDecimal { | ||||
| val purchaseUnit = findPurchaseUnitByItemId(itemId) ?: return stockQty | val purchaseUnit = findPurchaseUnitByItemId(itemId) ?: return stockQty | ||||
| @@ -143,13 +143,7 @@ open class ItemQcFailReportService( | |||||
| COALESCE(qi.code, '') | COALESCE(qi.code, '') | ||||
| """.trimIndent() | """.trimIndent() | ||||
| val result = jdbcDao.queryForList(sql, args) | val result = jdbcDao.queryForList(sql, args) | ||||
| println("qcTemplate: ${result[0]["qcTemplate"]}") | |||||
| println("qcDefectCriteria: ${result[0]["qcDefectCriteria"]}") | |||||
| println("lotQty: ${result[0]["lotQty"]}") | |||||
| println("defectQty: ${result[0]["defectQty"]}") | |||||
| println("refData: ${result[0]["refData"]}") | |||||
| println("remark: ${result[0]["remark"]}") | |||||
| println("orderRefNo: ${result[0]["orderRefNo"]}") | |||||
| return result | return result | ||||
| } | } | ||||
| @@ -28,7 +28,7 @@ interface StockInLineInfo { | |||||
| val receivedQty: BigDecimal? | val receivedQty: BigDecimal? | ||||
| val demandQty: BigDecimal? | val demandQty: BigDecimal? | ||||
| val acceptedQty: BigDecimal | val acceptedQty: BigDecimal | ||||
| @get:Value("#{target.purchaseOrderLine != null && target.item != null && target.acceptedQty != null ? @itemUomService.convertStockQtyToPurchaseQty(target.item.id, target.acceptedQty) : null}") | |||||
| @get:Value("#{target.acceptedQtyM18 != null ? new java.math.BigDecimal(target.acceptedQtyM18) : null}") | |||||
| val purchaseAcceptedQty: BigDecimal? | val purchaseAcceptedQty: BigDecimal? | ||||
| @get:Value("#{target.purchaseOrderLine?.qty}") | @get:Value("#{target.purchaseOrderLine?.qty}") | ||||
| val qty: BigDecimal? | val qty: BigDecimal? | ||||
| @@ -245,11 +245,18 @@ open class StockInLineService( | |||||
| this.item = item | this.item = item | ||||
| itemNo = item.code | itemNo = item.code | ||||
| this.stockIn = stockIn | this.stockIn = stockIn | ||||
| // PO-origin: store in stock qty; others: store as received | |||||
| acceptedQty = if (pol != null && item.id != null) { | |||||
| itemUomService.convertPurchaseQtyToStockQty(item.id!!, request.acceptedQty ?: BigDecimal.ZERO) | |||||
| // PO-origin: | |||||
| // 1) store user-input qty in acceptedQtyM18 (purchase unit) | |||||
| // 2) calculate stock acceptedQty with round-down | |||||
| if (pol != null && item.id != null) { | |||||
| acceptedQtyM18 = request.acceptedQty.toInt() | |||||
| acceptedQty = itemUomService.convertPurchaseQtyToStockQtyRoundDown( | |||||
| item.id!!, | |||||
| request.acceptedQty | |||||
| ) | |||||
| } else { | } else { | ||||
| request.acceptedQty | |||||
| // Non-PO flows: keep legacy behavior | |||||
| acceptedQty = request.acceptedQty | |||||
| } | } | ||||
| // Set demandQty based on source | // Set demandQty based on source | ||||
| if (jo != null && jo?.bom != null) { | if (jo != null && jo?.bom != null) { | ||||