Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(utils): bignumber util considers nullable options when setting value #6499

Merged
merged 4 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/itchy-bags-play.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@medusajs/utils": patch
---

fix(utils): bignumber util considers nullable options when setting value
2 changes: 1 addition & 1 deletion packages/cart/src/models/line-item-adjustment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import LineItem from "./line-item"
export default class LineItemAdjustment extends AdjustmentLine {
@ManyToOne({
entity: () => LineItem,
cascade: [Cascade.REMOVE, Cascade.PERSIST, "soft-remove"] as any,
cascade: [Cascade.REMOVE, Cascade.PERSIST],
})
item: LineItem

Expand Down
2 changes: 1 addition & 1 deletion packages/cart/src/models/shipping-method-adjustment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import ShippingMethod from "./shipping-method"
export default class ShippingMethodAdjustment extends AdjustmentLine {
@ManyToOne({
entity: () => ShippingMethod,
cascade: [Cascade.REMOVE, Cascade.PERSIST, "soft-remove"] as any,
cascade: [Cascade.REMOVE, Cascade.PERSIST],
})
shipping_method: ShippingMethod

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { IPaymentModuleService } from "@medusajs/types"
import { Modules } from "@medusajs/modules-sdk"
import { IPaymentModuleService } from "@medusajs/types"

import {
moduleIntegrationTestRunner,
SuiteOptions,
} from "medusa-test-utils/dist"
import {
createPaymentCollections,
createPayments,
createPaymentSessions,
} from "../../../__fixtures__"
import {
moduleIntegrationTestRunner,
SuiteOptions,
} from "medusa-test-utils/dist"

jest.setTimeout(30000)

Expand Down Expand Up @@ -466,7 +466,7 @@ moduleIntegrationTestRunner({
id: expect.any(String),
currency_code: "usd",
amount: 100,
raw_amount: { value: "100.00000000000000000", precision: 20 },
raw_amount: { value: "100", precision: 20 },
provider_id: "system",
data: {},
status: "authorized",
Expand Down
7 changes: 4 additions & 3 deletions packages/utils/src/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export * from "./alter-columns-helper"
export * from "./array-difference"
export * from "./get-set-difference"
export * from "./build-query"
export * from "./camel-to-snake-case"
export * from "./container"
Expand All @@ -12,8 +11,10 @@ export * from "./errors"
export * from "./generate-entity-id"
export * from "./generate-linkable-keys-map"
export * from "./get-config-file"
export * from "./get-duplicates"
export * from "./get-iso-string-from-date"
export * from "./get-selects-and-relations-from-object-array"
export * from "./get-set-difference"
export * from "./group-by"
export * from "./handle-postgres-database-error"
export * from "./is-big-number"
Expand All @@ -35,6 +36,7 @@ export * from "./promise-all"
export * from "./remote-query-object-from-string"
export * from "./remote-query-object-to-string"
export * from "./remove-nullisih"
export * from "./remove-undefined"
export * from "./selector-constraints-to-string"
export * from "./set-metadata"
export * from "./simple-hash"
Expand All @@ -45,7 +47,6 @@ export * from "./to-camel-case"
export * from "./to-kebab-case"
export * from "./to-pascal-case"
export * from "./transaction"
export * from "./trim-zeros"
export * from "./upper-case-first"
export * from "./wrap-handler"
export * from "./remove-undefined"
export * from "./get-duplicates"
15 changes: 15 additions & 0 deletions packages/utils/src/common/trim-zeros.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export function trimZeros(value: string) {
const [whole, fraction] = value.split(".")

if (fraction) {
const decimal = fraction.replace(/0+$/, "")

if (!decimal) {
return whole
}

return `${whole}.${decimal}`
}

return whole
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MikroOrmBigNumberProperty } from "../big-number-field"
import { BigNumberRawValue } from "@medusajs/types"
import { BigNumber } from "../../../totals/big-number"
import { MikroOrmBigNumberProperty } from "../big-number-field"

describe("@MikroOrmBigNumberProperty", () => {
it("should correctly assign and update BigNumber values", () => {
Expand All @@ -9,6 +9,11 @@ describe("@MikroOrmBigNumberProperty", () => {
amount: BigNumber | number

raw_amount: BigNumberRawValue

@MikroOrmBigNumberProperty({ nullable: true })
nullable_amount: BigNumber | number | null = null

raw_nullable_amount: BigNumberRawValue | null = null
}

const testAmount = new TestAmount()
Expand All @@ -21,18 +26,28 @@ describe("@MikroOrmBigNumberProperty", () => {
expect(testAmount.amount).toEqual(100)
expect((testAmount as any).amount_).toEqual(100)
expect(testAmount.raw_amount).toEqual({
value: "100.00000000000000000",
value: "100",
precision: 20,
})

try {
;(testAmount as any).amount = null
} catch (e) {
expect(e.message).toEqual(
"Invalid BigNumber value: null. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
)
}

testAmount.nullable_amount = null
expect(testAmount.nullable_amount).toEqual(null)
// Update the amount

testAmount.amount = 200

expect(testAmount.amount).toEqual(200)
expect((testAmount as any).amount_).toEqual(200)
expect(testAmount.raw_amount).toEqual({
value: "200.00000000000000000",
value: "200",
precision: 20,
})

Expand All @@ -42,6 +57,6 @@ describe("@MikroOrmBigNumberProperty", () => {

expect(testAmount.amount).toEqual(300)
expect((testAmount as any).amount_).toEqual(300)
expect(testAmount.raw_amount).toEqual({ value: "300.00", precision: 5 })
expect(testAmount.raw_amount).toEqual({ value: "300", precision: 5 })
})
})
29 changes: 23 additions & 6 deletions packages/utils/src/dal/mikro-orm/big-number-field.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BigNumber } from "../../totals/big-number"
import { Property } from "@mikro-orm/core"
import { BigNumberInput } from "@medusajs/types"
import { Property } from "@mikro-orm/core"
import { isPresent, trimZeros } from "../../common"
import { BigNumber } from "../../totals/big-number"

export function MikroOrmBigNumberProperty(
options: Parameters<typeof Property>[0] & {
Expand All @@ -16,21 +17,37 @@ export function MikroOrmBigNumberProperty(
return this[targetColumn]
},
set(value: BigNumberInput) {
if (options?.nullable && !isPresent(value)) {
this[targetColumn] = null
this[rawColumnName] = null

return
}

let bigNumber: BigNumber

if (value instanceof BigNumber) {
bigNumber = value
} else if (this[rawColumnName]) {
const precision = this[rawColumnName].precision
this[rawColumnName].value = new BigNumber(value, {
precision,
}).raw!.value

this[rawColumnName].value = trimZeros(
new BigNumber(value, {
precision,
}).raw!.value as string
)

bigNumber = new BigNumber(this[rawColumnName])
} else {
bigNumber = new BigNumber(value)
}

this[targetColumn] = bigNumber.numeric
this[rawColumnName] = bigNumber.raw

const raw = bigNumber.raw!
raw.value = trimZeros(raw.value as string)

this[rawColumnName] = raw
},
})

Expand Down
10 changes: 9 additions & 1 deletion packages/utils/src/totals/__tests__/big-number.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,15 @@ describe("BigNumber", function () {
it("should throw if not correct type", function () {
// @ts-ignore
expect(() => new BigNumber([])).toThrow(
"Invalid BigNumber value. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
"Invalid BigNumber value: . Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
)

expect(() => new BigNumber(null as any)).toThrow(
"Invalid BigNumber value: null. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
)

expect(() => new BigNumber(undefined as any)).toThrow(
"Invalid BigNumber value: undefined. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
)
})
})
Expand Down
46 changes: 23 additions & 23 deletions packages/utils/src/totals/big-number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,61 +8,61 @@ export class BigNumber {
private numeric_: number
private raw_?: BigNumberRawValue

constructor(rawPrice: BigNumberInput, options?: { precision?: number }) {
this.setRawPriceOrThrow(rawPrice, options)
constructor(rawValue: BigNumberInput, options?: { precision?: number }) {
this.setRawValueOrThrow(rawValue, options)
}

setRawPriceOrThrow(
rawPrice: BigNumberInput,
setRawValueOrThrow(
rawValue: BigNumberInput,
{ precision }: { precision?: number } = {}
) {
precision ??= BigNumber.DEFAULT_PRECISION

if (BigNumberJS.isBigNumber(rawPrice)) {
if (BigNumberJS.isBigNumber(rawValue)) {
/**
* Example:
* const bnUnitPrice = new BigNumberJS("10.99")
* const unitPrice = new BigNumber(bnUnitPrice)
* const bnUnitValue = new BigNumberJS("10.99")
* const unitValue = new BigNumber(bnUnitValue)
*/
this.numeric_ = rawPrice.toNumber()
this.numeric_ = rawValue.toNumber()
this.raw_ = {
value: rawPrice.toPrecision(precision),
value: rawValue.toPrecision(precision),
precision,
}
} else if (isString(rawPrice)) {
} else if (isString(rawValue)) {
/**
* Example: const unitPrice = "1234.1234"
* Example: const unitValue = "1234.1234"
*/
const bigNum = new BigNumberJS(rawPrice)
const bigNum = new BigNumberJS(rawValue)

this.numeric_ = bigNum.toNumber()
this.raw_ = this.raw_ = {
value: bigNum.toPrecision(precision),
precision,
}
} else if (isBigNumber(rawPrice)) {
} else if (isBigNumber(rawValue)) {
/**
* Example: const unitPrice = { value: "1234.1234" }
* Example: const unitValue = { value: "1234.1234" }
*/
this.numeric_ = BigNumberJS(rawPrice.value).toNumber()

const definedPrecision = rawValue.precision ?? precision
this.numeric_ = BigNumberJS(rawValue.value).toNumber()
this.raw_ = {
...rawPrice,
precision,
...rawValue,
precision: definedPrecision,
}
} else if (typeof rawPrice === `number` && !Number.isNaN(rawPrice)) {
} else if (typeof rawValue === `number` && !Number.isNaN(rawValue)) {
/**
* Example: const unitPrice = 1234
* Example: const unitValue = 1234
*/
this.numeric_ = rawPrice as number
this.numeric_ = rawValue as number

this.raw_ = {
value: BigNumberJS(rawPrice as number).toPrecision(precision),
value: BigNumberJS(rawValue as number).toPrecision(precision),
precision,
}
} else {
throw new Error(
"Invalid BigNumber value. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
`Invalid BigNumber value: ${rawValue}. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue`
)
}
}
Expand Down
Loading