* add: medusa admin hooks + tests * fix: remove unneeded props * fix: deps * fix: deps * fix: deps * fix: failing tests * fix: failing tests * fix: query key * add: yarn workspaces * fix: linting medusa-react * fix: add prepare script * fix: buildOptions * fix: useAdminShippingOptions query * fix: use qs instead for query params (#1019) * fix: formatting * debug: ci pipeline * debug: log node_modules structure * debug: use lerna bootstrap * debug: update node version * debug: print pkgs in workspace * debug: print pkgs in workspace * debug: print pkgs in workspace * debug: print pkgs in workspace * debug: add explicit build step * fix: jsdoc * debug: run build step * debug: fix build errors * debug: add build step to integration tests * fix: failing test * cleanup Co-authored-by: Sebastian Rindom <seb@medusajs.com> Co-authored-by: Sebastian Rindom <skrindom@gmail.com>
168 lines
3.7 KiB
TypeScript
168 lines
3.7 KiB
TypeScript
import { isEmpty } from "lodash"
|
|
import { RegionInfo, ProductVariantInfo } from "../types"
|
|
|
|
type FormatVariantPriceParams = {
|
|
variant: ProductVariantInfo
|
|
region: RegionInfo
|
|
includeTaxes?: boolean
|
|
minimumFractionDigits?: number
|
|
maximumFractionDigits?: number
|
|
locale?: string
|
|
}
|
|
|
|
/**
|
|
* Takes a product variant and a region, and converts the variant's price to a localized decimal format
|
|
*/
|
|
export const formatVariantPrice = ({
|
|
variant,
|
|
region,
|
|
includeTaxes = true,
|
|
...rest
|
|
}: FormatVariantPriceParams) => {
|
|
const amount = computeVariantPrice({ variant, region, includeTaxes })
|
|
|
|
return convertToLocale({
|
|
amount,
|
|
currency_code: region?.currency_code,
|
|
...rest,
|
|
})
|
|
}
|
|
|
|
type ComputeVariantPriceParams = {
|
|
variant: ProductVariantInfo
|
|
region: RegionInfo
|
|
includeTaxes?: boolean
|
|
}
|
|
|
|
/**
|
|
* Takes a product variant and region, and returns the variant price as a decimal number
|
|
* @param params.variant - product variant
|
|
* @param params.region - region
|
|
* @param params.includeTaxes - whether to include taxes or not
|
|
*/
|
|
export const computeVariantPrice = ({
|
|
variant,
|
|
region,
|
|
includeTaxes = true,
|
|
}: ComputeVariantPriceParams) => {
|
|
const amount = getVariantPrice(variant, region)
|
|
|
|
return computeAmount({
|
|
amount,
|
|
region,
|
|
includeTaxes,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Finds the price amount correspoding to the region selected
|
|
* @param variant - the product variant
|
|
* @param region - the region
|
|
* @returns - the price's amount
|
|
*/
|
|
export const getVariantPrice = (
|
|
variant: ProductVariantInfo,
|
|
region: RegionInfo
|
|
) => {
|
|
let price = variant?.prices?.find(
|
|
p => p.currency_code.toLowerCase() === region?.currency_code?.toLowerCase()
|
|
)
|
|
|
|
return price?.amount || 0
|
|
}
|
|
|
|
type ComputeAmountParams = {
|
|
amount: number
|
|
region: RegionInfo
|
|
includeTaxes?: boolean
|
|
}
|
|
|
|
/**
|
|
* Takes an amount, a region, and returns the amount as a decimal including or excluding taxes
|
|
*/
|
|
export const computeAmount = ({
|
|
amount,
|
|
region,
|
|
includeTaxes = true,
|
|
}: ComputeAmountParams) => {
|
|
const toDecimal = convertToDecimal(amount, region)
|
|
|
|
const taxRate = includeTaxes ? getTaxRate(region) : 0
|
|
|
|
const amountWithTaxes = toDecimal * (1 + taxRate)
|
|
|
|
return amountWithTaxes
|
|
}
|
|
|
|
type FormatAmountParams = {
|
|
amount: number
|
|
region: RegionInfo
|
|
includeTaxes?: boolean
|
|
minimumFractionDigits?: number
|
|
maximumFractionDigits?: number
|
|
locale?: string
|
|
}
|
|
|
|
/**
|
|
* Takes an amount and a region, and converts the amount to a localized decimal format
|
|
*/
|
|
export const formatAmount = ({
|
|
amount,
|
|
region,
|
|
includeTaxes = true,
|
|
...rest
|
|
}: FormatAmountParams) => {
|
|
const taxAwareAmount = computeAmount({
|
|
amount,
|
|
region,
|
|
includeTaxes,
|
|
})
|
|
return convertToLocale({
|
|
amount: taxAwareAmount,
|
|
currency_code: region.currency_code,
|
|
...rest,
|
|
})
|
|
}
|
|
|
|
// we should probably add a more extensive list
|
|
const noDivisionCurrencies = ["krw", "jpy", "vnd"]
|
|
|
|
const convertToDecimal = (amount: number, region: RegionInfo) => {
|
|
const divisor = noDivisionCurrencies.includes(
|
|
region?.currency_code?.toLowerCase()
|
|
)
|
|
? 1
|
|
: 100
|
|
|
|
return Math.floor(amount) / divisor
|
|
}
|
|
|
|
const getTaxRate = (region?: RegionInfo) => {
|
|
return region && !isEmpty(region) ? region?.tax_rate / 100 : 0
|
|
}
|
|
|
|
const convertToLocale = ({
|
|
amount,
|
|
currency_code,
|
|
minimumFractionDigits,
|
|
maximumFractionDigits,
|
|
locale = "en-US",
|
|
}: ConvertToLocaleParams) => {
|
|
return currency_code && !isEmpty(currency_code)
|
|
? new Intl.NumberFormat(locale, {
|
|
style: "currency",
|
|
currency: currency_code,
|
|
minimumFractionDigits,
|
|
maximumFractionDigits,
|
|
}).format(amount)
|
|
: amount.toString()
|
|
}
|
|
|
|
type ConvertToLocaleParams = {
|
|
amount: number
|
|
currency_code: string
|
|
minimumFractionDigits?: number
|
|
maximumFractionDigits?: number
|
|
locale?: string
|
|
}
|