chore(utils): currency epsilon (#14225)

* chore(utils): currency epsilon

* pending diff

* getEpsilonFromDecimalPrecision
This commit is contained in:
Carlos R. L. Rodrigues
2025-12-12 06:46:07 -03:00
committed by GitHub
parent 8bb2ac654c
commit b3cb904e9b
6 changed files with 65 additions and 9 deletions

View File

@@ -1,6 +1,7 @@
import { BigNumberInput, BigNumberRawValue, IBigNumber } from "@medusajs/types"
import { BigNumber as BigNumberConstructor } from "bignumber.js"
import { isBigNumber } from "../common/is-big-number"
import { isDefined } from "../common/is-defined"
import { isString } from "../common/is-string"
type BigNumberJS = InstanceType<typeof BigNumberConstructor>
@@ -150,3 +151,18 @@ export class BigNumber implements IBigNumber {
export const MEDUSA_EPSILON = new BigNumber(
process.env.MEDUSA_EPSILON || "0.0001"
)
export const MEDUSA_DEFAULT_CURRENCY_EPSILON = new BigNumber(
process.env.MEDUSA_DEFAULT_CURRENCY_EPSILON || "0.01"
)
export const getEpsilonFromDecimalPrecision = (decimalDigits?: number) => {
if (!isDefined(decimalDigits)) {
return MEDUSA_DEFAULT_CURRENCY_EPSILON
}
const epsilon = new BigNumberJS(1).dividedBy(
new BigNumberJS(10).pow(decimalDigits)
)
return new BigNumber(epsilon.toString())
}

View File

@@ -1,5 +1,6 @@
import { BigNumberInput, CartLikeWithTotals } from "@medusajs/types"
import { BigNumber } from "../big-number"
import { defaultCurrencies } from "../../defaults/currencies"
import { BigNumber, getEpsilonFromDecimalPrecision } from "../big-number"
import { calculateCreditLinesTotal } from "../credit-lines"
import { GetItemTotalInput, getLineItemsTotals } from "../line-item"
import { MathBN } from "../math"
@@ -14,6 +15,7 @@ interface TotalsConfig {
}
export interface DecorateCartLikeInputDTO {
currency_code?: string
credit_lines?: {
amount: BigNumberInput
}[]
@@ -198,6 +200,7 @@ export function decorateCartTotals(
creditLines,
includesTax: false,
taxRate: creditLinesSumTaxRate,
currencyCode: cartLike.currency_code,
})
const taxTotal = MathBN.add(itemsTaxTotal, shippingTaxTotal)
@@ -276,6 +279,11 @@ export function decorateCartTotals(
...(cart.items?.map((item) => item.return_requested_total ?? 0) ?? [0])
)
const upperCurCode = cart.currency_code?.toUpperCase() as string
const currencyEpsilon = getEpsilonFromDecimalPrecision(
defaultCurrencies[upperCurCode]?.decimal_digits
)
const pendingDifference = new BigNumber(
MathBN.sub(
MathBN.sub(cart.total, pendingReturnTotal),
@@ -283,7 +291,12 @@ export function decorateCartTotals(
)
)
cart.summary.pending_difference = pendingDifference
cart.summary.pending_difference = MathBN.lte(
MathBN.abs(pendingDifference),
currencyEpsilon
)
? MathBN.convert(0)
: pendingDifference
}
return cart

View File

@@ -1,16 +1,19 @@
import { BigNumberInput } from "@medusajs/types"
import { isDefined } from "../../common"
import { BigNumber, MEDUSA_EPSILON } from "../big-number"
import { defaultCurrencies } from "../../defaults/currencies"
import { BigNumber, getEpsilonFromDecimalPrecision } from "../big-number"
import { MathBN } from "../math"
export function calculateCreditLinesTotal({
creditLines,
includesTax,
taxRate,
currencyCode,
}: {
creditLines: { amount: BigNumberInput }[]
includesTax?: boolean
taxRate?: BigNumberInput
currencyCode?: string
}) {
// the sum of all creditLine amounts excluding tax
let creditLinesSubtotal = MathBN.convert(0)
@@ -46,7 +49,12 @@ export function calculateCreditLinesTotal({
}
}
const isZero = MathBN.lte(creditLinesTotal, MEDUSA_EPSILON)
const upperCurCode = currencyCode?.toUpperCase() as string
const currencyEpsilon = getEpsilonFromDecimalPrecision(
defaultCurrencies[upperCurCode]?.decimal_digits
)
const isZero = MathBN.lte(creditLinesTotal, currencyEpsilon)
return {
creditLinesTotal: isZero ? MathBN.convert(0) : creditLinesTotal,
creditLinesSubtotal: isZero ? MathBN.convert(0) : creditLinesSubtotal,