|
|
|
@@ -224,6 +224,27 @@ open class ItemUomService( |
|
|
|
return stockQty.setScale(0, RoundingMode.DOWN) |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Count-type stock units must be whole numbers: PCS/CTN…, 包, 箱, 件, 個, PCS, CTN, etc. |
|
|
|
* Weight/volume units (克, 公斤, 升…) keep 2 decimals. |
|
|
|
*/ |
|
|
|
open fun isIntegerCountStockUom(stockUnit: ItemUom?): Boolean { |
|
|
|
if (stockUnit == null) return false |
|
|
|
val code = stockUnit.uom?.code?.trim().orEmpty() |
|
|
|
if (code.startsWith("PCS/CTN", ignoreCase = true)) return true |
|
|
|
val short = stockUnit.uom?.udfShortDesc?.trim().orEmpty() |
|
|
|
return isIntegerCountUnitToken(short) || isIntegerCountUnitToken(code) |
|
|
|
} |
|
|
|
|
|
|
|
private fun isIntegerCountUnitToken(raw: String): Boolean { |
|
|
|
val token = raw.trim() |
|
|
|
if (token.isEmpty()) return false |
|
|
|
if (token == "包" || token == "箱" || token == "件" || token == "個") return true |
|
|
|
val upper = token.uppercase() |
|
|
|
return upper == "PCS" || upper == "PC" || upper == "CTN" || upper == "EA" || |
|
|
|
upper == "PK" || upper == "PKT" || upper == "BOX" |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Stock UOM code [PCS/CTN]* denotes pieces-per-carton; displayed stock qty should be whole cartons (integer). |
|
|
|
*/ |
|
|
|
@@ -232,9 +253,9 @@ open class ItemUomService( |
|
|
|
return code.startsWith("PCS/CTN", ignoreCase = true) |
|
|
|
} |
|
|
|
|
|
|
|
/** After ratio math: 2 decimals, or integer when stock unit is PCS/CTN… */ |
|
|
|
/** After ratio math: integer HALF_UP for count units (包/箱/PCS…), else 2 decimals. */ |
|
|
|
private fun finalizePreciseStockQty(stockUnit: ItemUom?, stockQty: BigDecimal): BigDecimal { |
|
|
|
if (isPiecesPerCartonStockUomCode(stockUnit)) { |
|
|
|
if (isIntegerCountStockUom(stockUnit) || isPiecesPerCartonStockUomCode(stockUnit)) { |
|
|
|
return stockQty.setScale(0, RoundingMode.HALF_UP) |
|
|
|
} |
|
|
|
return stockQty.setScale(2, RoundingMode.HALF_UP) |
|
|
|
|