fix(): Pricing preference context loss (#13626)
**What** The context reference is being mutated by the repository leading to an empty context. Also, the filter is built from the pricing context instead of pricing context -> context leading to always fetch all preferences all the time
This commit is contained in:
1 parent
087887fefb
commit
9c7c1d48c7
7 files changed
+111
-65
No files matched your search
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/pricing": patch
|
||||||
|
"@medusajs/draft-order": patch
|
||||||
|
"@medusajs/types": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(): Pricing preference context loss
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BaseFilterable } from "../../dal"
|
import { BaseFilterable, OperatorMap } from "../../dal"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @interface
|
* @interface
|
||||||
@@ -83,13 +83,13 @@ export interface FilterablePricePreferenceProps
|
|||||||
/**
|
/**
|
||||||
* The IDs to filter the price preferences by.
|
* The IDs to filter the price preferences by.
|
||||||
*/
|
*/
|
||||||
id?: string[]
|
id?: string | string[] | OperatorMap<string | string[]>
|
||||||
/**
|
/**
|
||||||
* Attributes to filter price preferences by.
|
* Attributes to filter price preferences by.
|
||||||
*/
|
*/
|
||||||
attribute?: string | string[]
|
attribute?: string | string[] | OperatorMap<string | string[]>
|
||||||
/**
|
/**
|
||||||
* Values to filter price preferences by.
|
* Values to filter price preferences by.
|
||||||
*/
|
*/
|
||||||
value?: string | string[]
|
value?: string | string[] | OperatorMap<string | string[]>
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BaseFilterable } from "../../dal"
|
import { BaseFilterable, OperatorMap } from "../../dal"
|
||||||
import { PriceSetDTO } from "./price-set"
|
import { PriceSetDTO } from "./price-set"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,15 +123,20 @@ export interface FilterablePriceRuleProps
|
|||||||
/**
|
/**
|
||||||
* The IDs to filter price rules by.
|
* The IDs to filter price rules by.
|
||||||
*/
|
*/
|
||||||
id?: string[]
|
id?: string | string[] | OperatorMap<string | string[]>
|
||||||
/**
|
/**
|
||||||
* The names to filter price rules by.
|
* The names to filter price rules by.
|
||||||
*/
|
*/
|
||||||
name?: string[]
|
name?: string | string[] | OperatorMap<string | string[]>
|
||||||
/**
|
/**
|
||||||
* The IDs to filter the price rule's associated price set.
|
* The IDs to filter the price rule's associated price set.
|
||||||
*/
|
*/
|
||||||
price_set_id?: string[]
|
price_set_id?: string | string[] | OperatorMap<string | string[]>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The IDs to filter the price rule's associated price.
|
||||||
|
*/
|
||||||
|
price_id?: string | string[] | OperatorMap<string | string[]>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -145,21 +150,21 @@ export type PricingRuleOperatorValues = "gt" | "lt" | "eq" | "lte" | "gte"
|
|||||||
export interface PriceRule {
|
export interface PriceRule {
|
||||||
/**
|
/**
|
||||||
* The attribute to compare.
|
* The attribute to compare.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* amount
|
* amount
|
||||||
*/
|
*/
|
||||||
attribute: string
|
attribute: string
|
||||||
/**
|
/**
|
||||||
* The operator to use in the comparison.
|
* The operator to use in the comparison.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* gt
|
* gt
|
||||||
*/
|
*/
|
||||||
operator: PricingRuleOperatorValues
|
operator: PricingRuleOperatorValues
|
||||||
/**
|
/**
|
||||||
* The value to compare against.
|
* The value to compare against.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* 100
|
* 100
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export class PricingRepository
|
|||||||
): Promise<CalculatedPriceSetDTO[]> {
|
): Promise<CalculatedPriceSetDTO[]> {
|
||||||
const manager = this.getActiveManager<SqlEntityManager>(sharedContext)
|
const manager = this.getActiveManager<SqlEntityManager>(sharedContext)
|
||||||
const knex = manager.getKnex()
|
const knex = manager.getKnex()
|
||||||
const context = pricingContext.context || {}
|
const context = { ...(pricingContext.context || {}) }
|
||||||
|
|
||||||
// Extract quantity and currency from context
|
// Extract quantity and currency from context
|
||||||
const quantity = context.quantity
|
const quantity = context.quantity
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
FindConfig,
|
FindConfig,
|
||||||
InferEntityType,
|
InferEntityType,
|
||||||
InternalModuleDeclaration,
|
InternalModuleDeclaration,
|
||||||
|
MedusaContainer,
|
||||||
ModuleJoinerConfig,
|
ModuleJoinerConfig,
|
||||||
ModulesSdkTypes,
|
ModulesSdkTypes,
|
||||||
PricePreferenceDTO,
|
PricePreferenceDTO,
|
||||||
@@ -95,6 +96,7 @@ export default class PricingModuleService
|
|||||||
extends BaseClass
|
extends BaseClass
|
||||||
implements PricingTypes.IPricingModuleService
|
implements PricingTypes.IPricingModuleService
|
||||||
{
|
{
|
||||||
|
protected readonly container_: MedusaContainer
|
||||||
protected baseRepository_: DAL.RepositoryService
|
protected baseRepository_: DAL.RepositoryService
|
||||||
protected readonly pricingRepository_: PricingRepositoryService & {
|
protected readonly pricingRepository_: PricingRepositoryService & {
|
||||||
clearAvailableAttributes?: () => Promise<void>
|
clearAvailableAttributes?: () => Promise<void>
|
||||||
@@ -134,6 +136,7 @@ export default class PricingModuleService
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
super(...arguments)
|
super(...arguments)
|
||||||
|
|
||||||
|
this.container_ = arguments[0]
|
||||||
this.baseRepository_ = baseRepository
|
this.baseRepository_ = baseRepository
|
||||||
this.pricingRepository_ = pricingRepository
|
this.pricingRepository_ = pricingRepository
|
||||||
this.priceSetService_ = priceSetService
|
this.priceSetService_ = priceSetService
|
||||||
@@ -327,6 +330,62 @@ export default class PricingModuleService
|
|||||||
return [serializedPriceSets, count]
|
return [serializedPriceSets, count]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@InjectManager()
|
||||||
|
// @ts-expect-error
|
||||||
|
async listPriceRules(
|
||||||
|
filters: PricingTypes.FilterablePriceRuleProps,
|
||||||
|
config: FindConfig<PricingTypes.PriceRuleDTO> = {},
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<PricingTypes.PriceRuleDTO[]> {
|
||||||
|
const priceRules = await this.listPriceRules_(
|
||||||
|
filters,
|
||||||
|
config,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
return await this.baseRepository_.serialize<PricingTypes.PriceRuleDTO[]>(
|
||||||
|
priceRules
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async listPriceRules_(
|
||||||
|
filters: PricingTypes.FilterablePriceRuleProps,
|
||||||
|
config: FindConfig<PricingTypes.PriceRuleDTO> = {},
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<InferEntityType<typeof PriceRule>[]> {
|
||||||
|
return await this.priceRuleService_.list(filters, config, sharedContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectManager()
|
||||||
|
// @ts-expect-error
|
||||||
|
async listPricePreferences(
|
||||||
|
filters: PricingTypes.FilterablePricePreferenceProps,
|
||||||
|
config: FindConfig<PricingTypes.PricePreferenceDTO> = {},
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<PricingTypes.PricePreferenceDTO[]> {
|
||||||
|
const pricePreferences = await this.listPricePreferences_(
|
||||||
|
filters,
|
||||||
|
{ ...config, select: [...(config.select || []), "id"] },
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
return await this.baseRepository_.serialize<
|
||||||
|
PricingTypes.PricePreferenceDTO[]
|
||||||
|
>(pricePreferences)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async listPricePreferences_(
|
||||||
|
filters: PricingTypes.FilterablePricePreferenceProps,
|
||||||
|
config: FindConfig<PricingTypes.PricePreferenceDTO> = {},
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<InferEntityType<typeof PricePreference>[]> {
|
||||||
|
return await this.pricePreferenceService_.list(
|
||||||
|
filters,
|
||||||
|
config,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@InjectManager()
|
@InjectManager()
|
||||||
async calculatePrices(
|
async calculatePrices(
|
||||||
pricingFilters: PricingFilters,
|
pricingFilters: PricingFilters,
|
||||||
@@ -395,29 +454,37 @@ export default class PricingModuleService
|
|||||||
)
|
)
|
||||||
|
|
||||||
// We use the price rules to get the right preferences for the price
|
// We use the price rules to get the right preferences for the price
|
||||||
const priceRulesForPrices = await this.priceRuleService_.list(
|
const priceRulesForPrices = await this.listPriceRules(
|
||||||
{ price_id: priceIds },
|
{ price_id: priceIds },
|
||||||
{}
|
{},
|
||||||
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
const priceRulesPriceMap = groupBy(priceRulesForPrices, "price_id")
|
const priceRulesPriceMap = groupBy(priceRulesForPrices, "price_id")
|
||||||
|
|
||||||
// Note: For now the preferences are intentionally kept very simple and explicit - they use either the region or currency,
|
// Note: For now the preferences are intentionally kept very simple and explicit - they use either the region or currency,
|
||||||
// so we hard-code those as the possible filters here. This can be made more flexible if needed later on.
|
// so we hard-code those as the possible filters here. This can be made more flexible if needed later on.
|
||||||
const pricingPreferences = await this.pricePreferenceService_.list(
|
const preferenceContext = Object.entries(
|
||||||
{
|
pricingContext.context ?? {}
|
||||||
$or: Object.entries(pricingContext)
|
).filter(([key, val]) => {
|
||||||
.filter(([key, val]) => {
|
return key === "region_id" || key === "currency_code"
|
||||||
return key === "region_id" || key === "currency_code"
|
})
|
||||||
})
|
let pricingPreferences: InferEntityType<typeof PricePreference>[] = []
|
||||||
.map(([key, val]) => ({
|
if (preferenceContext.length) {
|
||||||
attribute: key,
|
const preferenceFilters = preferenceContext.length
|
||||||
value: val,
|
? {
|
||||||
})),
|
$or: preferenceContext.map(([key, val]) => ({
|
||||||
},
|
attribute: key,
|
||||||
{},
|
value: val,
|
||||||
sharedContext
|
})),
|
||||||
)
|
}
|
||||||
|
: {}
|
||||||
|
pricingPreferences = await this.listPricePreferences_(
|
||||||
|
preferenceFilters as PricingTypes.FilterablePricePreferenceProps,
|
||||||
|
{},
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const calculatedPrices: PricingTypes.CalculatedPriceSet[] = []
|
const calculatedPrices: PricingTypes.CalculatedPriceSet[] = []
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
"@medusajs/icons": "2.10.3",
|
"@medusajs/icons": "2.10.3",
|
||||||
"@medusajs/test-utils": "2.10.3",
|
"@medusajs/test-utils": "2.10.3",
|
||||||
"@medusajs/types": "2.10.3",
|
"@medusajs/types": "2.10.3",
|
||||||
"@medusajs/ui": "4.0.21",
|
"@medusajs/ui": "4.0.23",
|
||||||
"@medusajs/ui-preset": "2.10.3",
|
"@medusajs/ui-preset": "2.10.3",
|
||||||
"@swc/core": "1.5.7",
|
"@swc/core": "1.5.7",
|
||||||
"@types/lodash": "^4.17.15",
|
"@types/lodash": "^4.17.15",
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
"@medusajs/framework": "2.10.3",
|
"@medusajs/framework": "2.10.3",
|
||||||
"@medusajs/icons": "2.10.3",
|
"@medusajs/icons": "2.10.3",
|
||||||
"@medusajs/test-utils": "2.10.3",
|
"@medusajs/test-utils": "2.10.3",
|
||||||
"@medusajs/ui": "4.0.21",
|
"@medusajs/ui": "4.0.23",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react-router-dom": "6.20.1"
|
"react-router-dom": "6.20.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6417,7 +6417,7 @@ __metadata:
|
|||||||
"@medusajs/js-sdk": 2.10.3
|
"@medusajs/js-sdk": 2.10.3
|
||||||
"@medusajs/test-utils": 2.10.3
|
"@medusajs/test-utils": 2.10.3
|
||||||
"@medusajs/types": 2.10.3
|
"@medusajs/types": 2.10.3
|
||||||
"@medusajs/ui": 4.0.21
|
"@medusajs/ui": 4.0.23
|
||||||
"@medusajs/ui-preset": 2.10.3
|
"@medusajs/ui-preset": 2.10.3
|
||||||
"@swc/core": 1.5.7
|
"@swc/core": 1.5.7
|
||||||
"@tanstack/react-query": 5.64.2
|
"@tanstack/react-query": 5.64.2
|
||||||
@@ -6445,7 +6445,7 @@ __metadata:
|
|||||||
"@medusajs/framework": 2.10.3
|
"@medusajs/framework": 2.10.3
|
||||||
"@medusajs/icons": 2.10.3
|
"@medusajs/icons": 2.10.3
|
||||||
"@medusajs/test-utils": 2.10.3
|
"@medusajs/test-utils": 2.10.3
|
||||||
"@medusajs/ui": 4.0.21
|
"@medusajs/ui": 4.0.23
|
||||||
lodash: ^4.17.21
|
lodash: ^4.17.21
|
||||||
react-router-dom: 6.20.1
|
react-router-dom: 6.20.1
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
@@ -6663,15 +6663,6 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@medusajs/icons@npm:2.10.1":
|
|
||||||
version: 2.10.1
|
|
||||||
resolution: "@medusajs/icons@npm:2.10.1"
|
|
||||||
peerDependencies:
|
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
|
||||||
checksum: 280e7174376a1e36db5376a2efee659a6b4f1002bd9136a6966c039587373688c4f1239830873c9d592bc570592ddc014037d7af6d9d075e5093ae6c74d0f351
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@medusajs/index@2.10.3, @medusajs/index@workspace:packages/modules/index":
|
"@medusajs/index@2.10.3, @medusajs/index@workspace:packages/modules/index":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@medusajs/index@workspace:packages/modules/index"
|
resolution: "@medusajs/index@workspace:packages/modules/index"
|
||||||
@@ -7404,30 +7395,6 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@medusajs/ui@npm:4.0.21":
|
|
||||||
version: 4.0.21
|
|
||||||
resolution: "@medusajs/ui@npm:4.0.21"
|
|
||||||
dependencies:
|
|
||||||
"@medusajs/icons": 2.10.1
|
|
||||||
"@tanstack/react-table": 8.20.5
|
|
||||||
clsx: ^1.2.1
|
|
||||||
copy-to-clipboard: ^3.3.3
|
|
||||||
cva: 1.0.0-beta.1
|
|
||||||
prism-react-renderer: ^2.0.6
|
|
||||||
prismjs: ^1.29.0
|
|
||||||
radix-ui: 1.1.2
|
|
||||||
react-aria: ^3.33.1
|
|
||||||
react-currency-input-field: ^3.6.11
|
|
||||||
react-stately: ^3.31.1
|
|
||||||
sonner: ^1.5.0
|
|
||||||
tailwind-merge: ^2.2.1
|
|
||||||
peerDependencies:
|
|
||||||
react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
|
||||||
react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
|
||||||
checksum: 9e5af539201aa2e50090134a492a992e01233943a39c7d21e8193469c4d379c6a0fce55cc2541cb4ce4e93813bb76015e9256043769a551a8c0cad338774512d
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@medusajs/user@2.10.3, @medusajs/user@workspace:^, @medusajs/user@workspace:packages/modules/user":
|
"@medusajs/user@2.10.3, @medusajs/user@workspace:^, @medusajs/user@workspace:packages/modules/user":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@medusajs/user@workspace:packages/modules/user"
|
resolution: "@medusajs/user@workspace:packages/modules/user"
|
||||||
|
|||||||
Reference in new issue
Block a user