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
This commit is contained in:
William Bouchard
2025-09-03 13:45:41 -04:00
committed by GitHub
parent 115a1deb49
commit faae150a58
6 changed files with 42 additions and 35 deletions

View File

@@ -0,0 +1,5 @@
---
"@medusajs/utils": patch
---
fix(utils): big bumber should give numeric value of 0 for small numbers

View File

@@ -1,18 +1,8 @@
import { import { createOrderChangeWorkflow, createOrderWorkflow, } from "@medusajs/core-flows"
createOrderChangeWorkflow,
createOrderWorkflow,
} from "@medusajs/core-flows"
import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
import { import { CreateOrderLineItemDTO, IOrderModuleService, OrderDTO, } from "@medusajs/types"
CreateOrderLineItemDTO,
IOrderModuleService,
OrderDTO,
} from "@medusajs/types"
import { Modules, ProductStatus } from "@medusajs/utils" import { Modules, ProductStatus } from "@medusajs/utils"
import { import { adminHeaders, createAdminUser, } from "../../../helpers/create-admin-user"
adminHeaders,
createAdminUser,
} from "../../../helpers/create-admin-user"
jest.setTimeout(50000) jest.setTimeout(50000)
@@ -375,9 +365,9 @@ medusaIntegrationTestRunner({
updated_at: expect.any(String), updated_at: expect.any(String),
deleted_at: null, deleted_at: null,
item_id: expect.any(String), item_id: expect.any(String),
amount: 5e-18, amount: 0,
subtotal: 5e-18, subtotal: 0,
total: 5e-18, total: 0,
raw_subtotal: { raw_subtotal: {
value: "5e-18", value: "5e-18",
precision: 20, precision: 20,
@@ -443,9 +433,9 @@ medusaIntegrationTestRunner({
subtotal: 50, subtotal: 50,
total: 50, total: 50,
original_total: 50, original_total: 50,
discount_total: 5e-18, discount_total: 0,
discount_tax_total: 0, discount_tax_total: 0,
discount_subtotal: 5e-18, discount_subtotal: 0,
tax_total: 0, tax_total: 0,
original_tax_total: 0, original_tax_total: 0,
refundable_total: 50, refundable_total: 50,

View File

@@ -1,6 +1,7 @@
import { BigNumberInput, BigNumberRawValue, IBigNumber } from "@medusajs/types" import { BigNumberInput, BigNumberRawValue, IBigNumber } from "@medusajs/types"
import { BigNumber as BigNumberJS } from "bignumber.js" 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 { export class BigNumber implements IBigNumber {
static DEFAULT_PRECISION = 20 static DEFAULT_PRECISION = 20
@@ -80,12 +81,19 @@ export class BigNumber implements IBigNumber {
} }
get numeric(): number { get numeric(): number {
let value: number
let raw = this.raw_ as BigNumberRawValue let raw = this.raw_ as BigNumberRawValue
if (raw) { if (raw) {
return new BigNumberJS(raw.value).toNumber() value = new BigNumberJS(raw.value).toNumber()
} else { } else {
return this.numeric_ value = this.numeric_
} }
if (Math.abs(value) <= MEDUSA_EPSILON.numeric_) {
return 0
}
return value
} }
set numeric(value: BigNumberInput) { set numeric(value: BigNumberInput) {
@@ -111,15 +119,21 @@ export class BigNumber implements IBigNumber {
} }
toJSON(): number { toJSON(): number {
return this.bignumber_ const value = this.bignumber_
? this.bignumber_?.toNumber() ? this.bignumber_?.toNumber()
: this.raw_ : this.raw_
? new BigNumberJS(this.raw_.value).toNumber() ? new BigNumberJS(this.raw_.value).toNumber()
: this.numeric_ : this.numeric_
if (Math.abs(value) <= MEDUSA_EPSILON.numeric_) {
return 0
}
return value
} }
valueOf(): number { valueOf(): number {
return this.numeric_ return this.numeric
} }
[Symbol.toPrimitive](hint) { [Symbol.toPrimitive](hint) {
@@ -127,6 +141,10 @@ export class BigNumber implements IBigNumber {
return this.raw?.value return this.raw?.value
} }
return this.numeric_ return this.numeric
} }
} }
export const MEDUSA_EPSILON = new BigNumber(
process.env.MEDUSA_EPSILON || "0.0001"
)

View File

@@ -1,7 +1,7 @@
import { BigNumberInput } from "@medusajs/types" import { BigNumberInput } from "@medusajs/types"
import { isDefined } from "../../common" import { isDefined } from "../../common"
import { BigNumber } from "../big-number" import { BigNumber, MEDUSA_EPSILON } from "../big-number"
import { MathBN, MEDUSA_EPSILON } from "../math" import { MathBN } from "../math"
export function calculateCreditLinesTotal({ export function calculateCreditLinesTotal({
creditLines, creditLines,

View File

@@ -3,10 +3,6 @@ import { BigNumber as BigNumberJS } from "bignumber.js"
import { isDefined } from "../common" import { isDefined } from "../common"
import { BigNumber } from "./big-number" import { BigNumber } from "./big-number"
export const MEDUSA_EPSILON = new BigNumber(
process.env.MEDUSA_EPSILON || "0.0001"
)
type BNInput = BigNumberInput | BigNumber type BNInput = BigNumberInput | BigNumber
export class MathBN { export class MathBN {
static convert(num: BNInput, decimalPlaces?: number): BigNumberJS { static convert(num: BNInput, decimalPlaces?: number): BigNumberJS {

View File

@@ -1,9 +1,7 @@
import { BigNumberInput } from "@medusajs/types" import { BigNumberInput } from "@medusajs/types"
import { import { ApplicationMethodAllocation, ApplicationMethodType, } from "../../promotion"
ApplicationMethodAllocation, import { MathBN } from "../math"
ApplicationMethodType, import { MEDUSA_EPSILON } from "../big-number"
} from "../../promotion"
import { MathBN, MEDUSA_EPSILON } from "../math"
function getPromotionValueForPercentage(promotion, lineItemAmount) { function getPromotionValueForPercentage(promotion, lineItemAmount) {
return MathBN.mult(MathBN.div(promotion.value, 100), lineItemAmount) return MathBN.mult(MathBN.div(promotion.value, 100), lineItemAmount)