From faae150a589bb29d08719ebb1d2617234e1f5e3a Mon Sep 17 00:00:00 2001 From: William Bouchard <46496014+willbouch@users.noreply.github.com> Date: Wed, 3 Sep 2025 13:45:41 -0400 Subject: [PATCH] fix(utils): big bumber should give numeric value of 0 for small numbers (#13394) * fix(utils): big bumber should give numeric value of 0 for small numbers * circular dep * fix imports * fix infinite loop * fix test * changeset --- .changeset/good-points-play.md | 5 ++++ .../modules/__tests__/order/order.spec.ts | 26 +++++----------- packages/core/utils/src/totals/big-number.ts | 30 +++++++++++++++---- .../utils/src/totals/credit-lines/index.ts | 4 +-- packages/core/utils/src/totals/math.ts | 4 --- .../core/utils/src/totals/promotion/index.ts | 8 ++--- 6 files changed, 42 insertions(+), 35 deletions(-) create mode 100644 .changeset/good-points-play.md diff --git a/.changeset/good-points-play.md b/.changeset/good-points-play.md new file mode 100644 index 0000000000..41b9400679 --- /dev/null +++ b/.changeset/good-points-play.md @@ -0,0 +1,5 @@ +--- +"@medusajs/utils": patch +--- + +fix(utils): big bumber should give numeric value of 0 for small numbers diff --git a/integration-tests/modules/__tests__/order/order.spec.ts b/integration-tests/modules/__tests__/order/order.spec.ts index 384d4c1d01..fabde67833 100644 --- a/integration-tests/modules/__tests__/order/order.spec.ts +++ b/integration-tests/modules/__tests__/order/order.spec.ts @@ -1,18 +1,8 @@ -import { - createOrderChangeWorkflow, - createOrderWorkflow, -} from "@medusajs/core-flows" +import { createOrderChangeWorkflow, createOrderWorkflow, } from "@medusajs/core-flows" import { medusaIntegrationTestRunner } from "@medusajs/test-utils" -import { - CreateOrderLineItemDTO, - IOrderModuleService, - OrderDTO, -} from "@medusajs/types" +import { CreateOrderLineItemDTO, IOrderModuleService, OrderDTO, } from "@medusajs/types" import { Modules, ProductStatus } from "@medusajs/utils" -import { - adminHeaders, - createAdminUser, -} from "../../../helpers/create-admin-user" +import { adminHeaders, createAdminUser, } from "../../../helpers/create-admin-user" jest.setTimeout(50000) @@ -375,9 +365,9 @@ medusaIntegrationTestRunner({ updated_at: expect.any(String), deleted_at: null, item_id: expect.any(String), - amount: 5e-18, - subtotal: 5e-18, - total: 5e-18, + amount: 0, + subtotal: 0, + total: 0, raw_subtotal: { value: "5e-18", precision: 20, @@ -443,9 +433,9 @@ medusaIntegrationTestRunner({ subtotal: 50, total: 50, original_total: 50, - discount_total: 5e-18, + discount_total: 0, discount_tax_total: 0, - discount_subtotal: 5e-18, + discount_subtotal: 0, tax_total: 0, original_tax_total: 0, refundable_total: 50, diff --git a/packages/core/utils/src/totals/big-number.ts b/packages/core/utils/src/totals/big-number.ts index 214ef6ab4f..9fb76b0392 100644 --- a/packages/core/utils/src/totals/big-number.ts +++ b/packages/core/utils/src/totals/big-number.ts @@ -1,6 +1,7 @@ import { BigNumberInput, BigNumberRawValue, IBigNumber } from "@medusajs/types" import { BigNumber as BigNumberJS } from "bignumber.js" -import { isBigNumber, isString } from "../common" +import { isBigNumber } from "../common/is-big-number" +import { isString } from "../common/is-string" export class BigNumber implements IBigNumber { static DEFAULT_PRECISION = 20 @@ -80,12 +81,19 @@ export class BigNumber implements IBigNumber { } get numeric(): number { + let value: number let raw = this.raw_ as BigNumberRawValue if (raw) { - return new BigNumberJS(raw.value).toNumber() + value = new BigNumberJS(raw.value).toNumber() } else { - return this.numeric_ + value = this.numeric_ } + + if (Math.abs(value) <= MEDUSA_EPSILON.numeric_) { + return 0 + } + + return value } set numeric(value: BigNumberInput) { @@ -111,15 +119,21 @@ export class BigNumber implements IBigNumber { } toJSON(): number { - return this.bignumber_ + const value = this.bignumber_ ? this.bignumber_?.toNumber() : this.raw_ ? new BigNumberJS(this.raw_.value).toNumber() : this.numeric_ + + if (Math.abs(value) <= MEDUSA_EPSILON.numeric_) { + return 0 + } + + return value } valueOf(): number { - return this.numeric_ + return this.numeric } [Symbol.toPrimitive](hint) { @@ -127,6 +141,10 @@ export class BigNumber implements IBigNumber { return this.raw?.value } - return this.numeric_ + return this.numeric } } + +export const MEDUSA_EPSILON = new BigNumber( + process.env.MEDUSA_EPSILON || "0.0001" +) diff --git a/packages/core/utils/src/totals/credit-lines/index.ts b/packages/core/utils/src/totals/credit-lines/index.ts index ac17217637..0cfed6457c 100644 --- a/packages/core/utils/src/totals/credit-lines/index.ts +++ b/packages/core/utils/src/totals/credit-lines/index.ts @@ -1,7 +1,7 @@ import { BigNumberInput } from "@medusajs/types" import { isDefined } from "../../common" -import { BigNumber } from "../big-number" -import { MathBN, MEDUSA_EPSILON } from "../math" +import { BigNumber, MEDUSA_EPSILON } from "../big-number" +import { MathBN } from "../math" export function calculateCreditLinesTotal({ creditLines, diff --git a/packages/core/utils/src/totals/math.ts b/packages/core/utils/src/totals/math.ts index 626ed2db06..458ea39102 100644 --- a/packages/core/utils/src/totals/math.ts +++ b/packages/core/utils/src/totals/math.ts @@ -3,10 +3,6 @@ import { BigNumber as BigNumberJS } from "bignumber.js" import { isDefined } from "../common" import { BigNumber } from "./big-number" -export const MEDUSA_EPSILON = new BigNumber( - process.env.MEDUSA_EPSILON || "0.0001" -) - type BNInput = BigNumberInput | BigNumber export class MathBN { static convert(num: BNInput, decimalPlaces?: number): BigNumberJS { diff --git a/packages/core/utils/src/totals/promotion/index.ts b/packages/core/utils/src/totals/promotion/index.ts index ab52ab12ba..41be77d56f 100644 --- a/packages/core/utils/src/totals/promotion/index.ts +++ b/packages/core/utils/src/totals/promotion/index.ts @@ -1,9 +1,7 @@ import { BigNumberInput } from "@medusajs/types" -import { - ApplicationMethodAllocation, - ApplicationMethodType, -} from "../../promotion" -import { MathBN, MEDUSA_EPSILON } from "../math" +import { ApplicationMethodAllocation, ApplicationMethodType, } from "../../promotion" +import { MathBN } from "../math" +import { MEDUSA_EPSILON } from "../big-number" function getPromotionValueForPercentage(promotion, lineItemAmount) { return MathBN.mult(MathBN.div(promotion.value, 100), lineItemAmount)