Chore(): localised improvement to promotion module (#13446)
**What** - Remove overserialization withing transaction and rely more on internal service or protected method instead which does not serialize and work with Infered entity type - Slightly rework loop complexity Overall, this gives a good spare of resources and time spent for serialization
This commit is contained in:
1 parent
d978749603
commit
ac09b3cbef
9 files changed
+129
-67
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/promotion": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Chore/localised improvement to promotion module
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
"resolve:aliases": "tsc --showConfig -p tsconfig.json > tsconfig.resolved.json && tsc-alias -p tsconfig.resolved.json && rimraf tsconfig.resolved.json",
|
"resolve:aliases": "tsc --showConfig -p tsconfig.json > tsconfig.resolved.json && tsc-alias -p tsconfig.resolved.json && rimraf tsconfig.resolved.json",
|
||||||
"build": "rimraf dist && tsc --build && npm run resolve:aliases",
|
"build": "rimraf dist && tsc --build && npm run resolve:aliases",
|
||||||
"test": "jest --runInBand --passWithNoTests --bail --forceExit -- src",
|
"test": "jest --runInBand --passWithNoTests --bail --forceExit -- src",
|
||||||
"test:integration": "jest --forceExit ",
|
"test:integration": "jest --forceExit -- integration-tests/__tests__/**/*.spec.ts",
|
||||||
"migration:initial": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create --initial",
|
"migration:initial": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create --initial",
|
||||||
"migration:create": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create",
|
"migration:create": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create",
|
||||||
"migration:up": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:up",
|
"migration:up": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:up",
|
||||||
|
|||||||
@@ -139,11 +139,26 @@ export default class PromotionModuleService
|
|||||||
}
|
}
|
||||||
|
|
||||||
@InjectManager()
|
@InjectManager()
|
||||||
listActivePromotions(
|
async listActivePromotions(
|
||||||
filters?: FilterablePromotionProps,
|
filters?: FilterablePromotionProps,
|
||||||
config?: FindConfig<PromotionDTO>,
|
config?: FindConfig<PromotionDTO>,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<PromotionDTO[]> {
|
): Promise<PromotionDTO[]> {
|
||||||
|
const activePromotions = await this.listActivePromotions_(
|
||||||
|
filters,
|
||||||
|
config,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
return this.baseRepository_.serialize<PromotionDTO[]>(activePromotions)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectManager()
|
||||||
|
protected async listActivePromotions_(
|
||||||
|
filters?: FilterablePromotionProps,
|
||||||
|
config?: FindConfig<PromotionDTO>,
|
||||||
|
@MedusaContext() sharedContext?: Context
|
||||||
|
): Promise<InferEntityType<typeof Promotion>[]> {
|
||||||
// Ensure we share the same now date across all filters
|
// Ensure we share the same now date across all filters
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const activeFilters = {
|
const activeFilters = {
|
||||||
@@ -170,7 +185,11 @@ export default class PromotionModuleService
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.listPromotions(activeFilters, config, sharedContext)
|
return await this.promotionService_.list(
|
||||||
|
activeFilters,
|
||||||
|
config,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@InjectTransactionManager()
|
@InjectTransactionManager()
|
||||||
@@ -185,7 +204,7 @@ export default class PromotionModuleService
|
|||||||
const campaignBudgetMap = new Map<string, UpdateCampaignBudgetDTO>()
|
const campaignBudgetMap = new Map<string, UpdateCampaignBudgetDTO>()
|
||||||
const promotionCodeUsageMap = new Map<string, boolean>()
|
const promotionCodeUsageMap = new Map<string, boolean>()
|
||||||
|
|
||||||
const existingPromotions = await this.listActivePromotions(
|
const existingPromotions = await this.listActivePromotions_(
|
||||||
{ code: promotionCodes },
|
{ code: promotionCodes },
|
||||||
{ relations: ["campaign", "campaign.budget"] },
|
{ relations: ["campaign", "campaign.budget"] },
|
||||||
sharedContext
|
sharedContext
|
||||||
@@ -200,9 +219,10 @@ export default class PromotionModuleService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingPromotionsMap = new Map<string, PromotionTypes.PromotionDTO>(
|
const existingPromotionsMap = new Map<
|
||||||
existingPromotions.map((promotion) => [promotion.code!, promotion])
|
string,
|
||||||
)
|
InferEntityType<typeof Promotion>
|
||||||
|
>(existingPromotions.map((promotion) => [promotion.code!, promotion]))
|
||||||
|
|
||||||
for (let computedAction of computedActions) {
|
for (let computedAction of computedActions) {
|
||||||
const promotion = existingPromotionsMap.get(computedAction.code)
|
const promotion = existingPromotionsMap.get(computedAction.code)
|
||||||
@@ -293,7 +313,7 @@ export default class PromotionModuleService
|
|||||||
const promotionCodeUsageMap = new Map<string, boolean>()
|
const promotionCodeUsageMap = new Map<string, boolean>()
|
||||||
const campaignBudgetMap = new Map<string, UpdateCampaignBudgetDTO>()
|
const campaignBudgetMap = new Map<string, UpdateCampaignBudgetDTO>()
|
||||||
|
|
||||||
const existingPromotions = await this.listActivePromotions(
|
const existingPromotions = await this.listActivePromotions_(
|
||||||
{
|
{
|
||||||
code: computedActions
|
code: computedActions
|
||||||
.map((computedAction) => computedAction.code)
|
.map((computedAction) => computedAction.code)
|
||||||
@@ -312,9 +332,10 @@ export default class PromotionModuleService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingPromotionsMap = new Map<string, PromotionTypes.PromotionDTO>(
|
const existingPromotionsMap = new Map<
|
||||||
existingPromotions.map((promotion) => [promotion.code!, promotion])
|
string,
|
||||||
)
|
InferEntityType<typeof Promotion>
|
||||||
|
>(existingPromotions.map((promotion) => [promotion.code!, promotion]))
|
||||||
|
|
||||||
for (let computedAction of computedActions) {
|
for (let computedAction of computedActions) {
|
||||||
const promotion = existingPromotionsMap.get(computedAction.code)
|
const promotion = existingPromotionsMap.get(computedAction.code)
|
||||||
@@ -433,27 +454,19 @@ export default class PromotionModuleService
|
|||||||
|
|
||||||
const methodIdPromoValueMap = new Map<string, number>()
|
const methodIdPromoValueMap = new Map<string, number>()
|
||||||
|
|
||||||
const automaticPromotions = preventAutoPromotions
|
const promotionCodesToApply = [...promotionCodes, ...appliedCodes]
|
||||||
? []
|
|
||||||
: await this.listActivePromotions(
|
|
||||||
{ is_automatic: true },
|
|
||||||
{ select: ["code"] },
|
|
||||||
sharedContext
|
|
||||||
)
|
|
||||||
|
|
||||||
const automaticPromotionCodes = automaticPromotions.map((p) => p.code!)
|
|
||||||
const promotionCodesToApply = [
|
|
||||||
...promotionCodes,
|
|
||||||
...automaticPromotionCodes,
|
|
||||||
...appliedCodes,
|
|
||||||
]
|
|
||||||
|
|
||||||
const uniquePromotionCodes = Array.from(new Set(promotionCodesToApply))
|
const uniquePromotionCodes = Array.from(new Set(promotionCodesToApply))
|
||||||
|
|
||||||
const promotions = await this.listActivePromotions(
|
const queryFilter = preventAutoPromotions
|
||||||
{ code: uniquePromotionCodes },
|
? { code: uniquePromotionCodes }
|
||||||
|
: {
|
||||||
|
$or: [{ code: uniquePromotionCodes }, { is_automatic: true }],
|
||||||
|
}
|
||||||
|
|
||||||
|
const promotions = await this.listActivePromotions_(
|
||||||
|
queryFilter,
|
||||||
{
|
{
|
||||||
take: null,
|
|
||||||
order: { application_method: { value: "DESC" } },
|
order: { application_method: { value: "DESC" } },
|
||||||
relations: [
|
relations: [
|
||||||
"application_method",
|
"application_method",
|
||||||
@@ -470,9 +483,18 @@ export default class PromotionModuleService
|
|||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
const existingPromotionsMap = new Map<string, PromotionTypes.PromotionDTO>(
|
const existingPromotionsMap = new Map<
|
||||||
promotions.map((promotion) => [promotion.code!, promotion])
|
string,
|
||||||
)
|
InferEntityType<typeof Promotion>
|
||||||
|
>(promotions.map((promotion) => [promotion.code!, promotion]))
|
||||||
|
|
||||||
|
const automaticPromotionCodes: string[] = []
|
||||||
|
|
||||||
|
for (const promotion of promotions) {
|
||||||
|
if (promotion.is_automatic) {
|
||||||
|
automaticPromotionCodes.push(promotion.code!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const [code, adjustments] of codeAdjustmentMap.entries()) {
|
for (const [code, adjustments] of codeAdjustmentMap.entries()) {
|
||||||
for (const adjustment of adjustments.items) {
|
for (const adjustment of adjustments.items) {
|
||||||
@@ -492,11 +514,14 @@ export default class PromotionModuleService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const promotionCodeSet = new Set<string>(promotionCodes)
|
||||||
|
const automaticPromotionCodeSet = new Set<string>(automaticPromotionCodes)
|
||||||
|
|
||||||
const sortedPromotionsToApply = promotions
|
const sortedPromotionsToApply = promotions
|
||||||
.filter(
|
.filter(
|
||||||
(p) =>
|
(p) =>
|
||||||
promotionCodes.includes(p.code!) ||
|
promotionCodeSet.has(p.code!) ||
|
||||||
automaticPromotionCodes.includes(p.code!)
|
automaticPromotionCodeSet.has(p.code!)
|
||||||
)
|
)
|
||||||
.sort(ComputeActionUtils.sortByBuyGetType)
|
.sort(ComputeActionUtils.sortByBuyGetType)
|
||||||
|
|
||||||
@@ -511,15 +536,15 @@ export default class PromotionModuleService
|
|||||||
|
|
||||||
for (const promotionToApply of sortedPromotionsToApply) {
|
for (const promotionToApply of sortedPromotionsToApply) {
|
||||||
const promotion = existingPromotionsMap.get(promotionToApply.code!)!
|
const promotion = existingPromotionsMap.get(promotionToApply.code!)!
|
||||||
|
if (!promotion.application_method) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
application_method: applicationMethod,
|
application_method: applicationMethod,
|
||||||
rules: promotionRules = [],
|
rules: promotionRules = [],
|
||||||
} = promotion
|
} = promotion
|
||||||
|
|
||||||
if (!applicationMethod) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const isCurrencyCodeValid =
|
const isCurrencyCodeValid =
|
||||||
!isPresent(applicationMethod.currency_code) ||
|
!isPresent(applicationMethod.currency_code) ||
|
||||||
applicationContext.currency_code === applicationMethod.currency_code
|
applicationContext.currency_code === applicationMethod.currency_code
|
||||||
@@ -1040,15 +1065,24 @@ export default class PromotionModuleService
|
|||||||
) {
|
) {
|
||||||
const promotionRuleIds = data.map((d) => d.id)
|
const promotionRuleIds = data.map((d) => d.id)
|
||||||
|
|
||||||
const promotionRules = await this.listPromotionRules(
|
const promotionRules = await this.promotionRuleService_.list(
|
||||||
{ id: promotionRuleIds },
|
{ id: promotionRuleIds },
|
||||||
{ relations: ["values"] },
|
{ relations: ["values"] },
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const existingPromotionRuleIds: string[] = []
|
||||||
|
const promotionRulesMap: Map<string, PromotionTypes.PromotionRuleDTO> =
|
||||||
|
new Map()
|
||||||
|
|
||||||
|
for (const promotionRule of promotionRules) {
|
||||||
|
existingPromotionRuleIds.push(promotionRule.id)
|
||||||
|
promotionRulesMap.set(promotionRule.id, promotionRule)
|
||||||
|
}
|
||||||
|
|
||||||
const invalidRuleId = arrayDifference(
|
const invalidRuleId = arrayDifference(
|
||||||
deduplicate(promotionRuleIds),
|
deduplicate(promotionRuleIds),
|
||||||
promotionRules.map((pr) => pr.id)
|
existingPromotionRuleIds
|
||||||
)
|
)
|
||||||
|
|
||||||
if (invalidRuleId.length) {
|
if (invalidRuleId.length) {
|
||||||
@@ -1058,10 +1092,6 @@ export default class PromotionModuleService
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const promotionRulesMap = new Map<string, PromotionTypes.PromotionRuleDTO>(
|
|
||||||
promotionRules.map((pr) => [pr.id, pr])
|
|
||||||
)
|
|
||||||
|
|
||||||
const rulesToUpdate: PromotionTypes.UpdatePromotionRuleDTO[] = []
|
const rulesToUpdate: PromotionTypes.UpdatePromotionRuleDTO[] = []
|
||||||
const ruleValueIdsToDelete: string[] = []
|
const ruleValueIdsToDelete: string[] = []
|
||||||
const ruleValuesToCreate: CreatePromotionRuleValueDTO[] = []
|
const ruleValuesToCreate: CreatePromotionRuleValueDTO[] = []
|
||||||
@@ -1489,15 +1519,16 @@ export default class PromotionModuleService
|
|||||||
const updateBudgetData: UpdateCampaignBudgetDTO[] = []
|
const updateBudgetData: UpdateCampaignBudgetDTO[] = []
|
||||||
const createBudgetData: CreateCampaignBudgetDTO[] = []
|
const createBudgetData: CreateCampaignBudgetDTO[] = []
|
||||||
|
|
||||||
const existingCampaigns = await this.listCampaigns(
|
const existingCampaigns = await this.campaignService_.list(
|
||||||
{ id: campaignIds },
|
{ id: campaignIds },
|
||||||
{ relations: ["budget"] },
|
{ relations: ["budget"] },
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
const existingCampaignsMap = new Map<string, PromotionTypes.CampaignDTO>(
|
const existingCampaignsMap = new Map<
|
||||||
existingCampaigns.map((campaign) => [campaign.id, campaign])
|
string,
|
||||||
)
|
InferEntityType<typeof Campaign>
|
||||||
|
>(existingCampaigns.map((campaign) => [campaign.id, campaign]))
|
||||||
|
|
||||||
for (const updateCampaignData of data) {
|
for (const updateCampaignData of data) {
|
||||||
const { budget: budgetData, ...campaignData } = updateCampaignData
|
const { budget: budgetData, ...campaignData } = updateCampaignData
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
BigNumberInput,
|
BigNumberInput,
|
||||||
ComputeActionItemLine,
|
ComputeActionItemLine,
|
||||||
|
InferEntityType,
|
||||||
PromotionTypes,
|
PromotionTypes,
|
||||||
} from "@medusajs/framework/types"
|
} from "@medusajs/framework/types"
|
||||||
import {
|
import {
|
||||||
@@ -12,6 +13,7 @@ import {
|
|||||||
} from "@medusajs/framework/utils"
|
} from "@medusajs/framework/utils"
|
||||||
import { areRulesValidForContext } from "../validations"
|
import { areRulesValidForContext } from "../validations"
|
||||||
import { computeActionForBudgetExceeded } from "./usage"
|
import { computeActionForBudgetExceeded } from "./usage"
|
||||||
|
import { Promotion } from "@models"
|
||||||
|
|
||||||
export type EligibleItem = {
|
export type EligibleItem = {
|
||||||
item_id: string
|
item_id: string
|
||||||
@@ -23,7 +25,7 @@ function sortByPrice(a: ComputeActionItemLine, b: ComputeActionItemLine) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isValidPromotionContext(
|
function isValidPromotionContext(
|
||||||
promotion: PromotionTypes.PromotionDTO,
|
promotion: PromotionTypes.PromotionDTO | InferEntityType<typeof Promotion>,
|
||||||
itemsContext: ComputeActionItemLine[]
|
itemsContext: ComputeActionItemLine[]
|
||||||
): boolean {
|
): boolean {
|
||||||
if (!itemsContext) {
|
if (!itemsContext) {
|
||||||
@@ -52,7 +54,7 @@ function isValidPromotionContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizePromotionApplicationConfiguration(
|
function normalizePromotionApplicationConfiguration(
|
||||||
promotion: PromotionTypes.PromotionDTO
|
promotion: PromotionTypes.PromotionDTO | InferEntityType<typeof Promotion>
|
||||||
) {
|
) {
|
||||||
const minimumBuyQuantity = MathBN.convert(
|
const minimumBuyQuantity = MathBN.convert(
|
||||||
promotion.application_method?.buy_rules_min_quantity ?? 0
|
promotion.application_method?.buy_rules_min_quantity ?? 0
|
||||||
@@ -275,7 +277,7 @@ function applyPromotionToTargetItems(
|
|||||||
targetItems: EligibleItem[],
|
targetItems: EligibleItem[],
|
||||||
itemIdPromotionAmountMap: Map<string, BigNumberInput>,
|
itemIdPromotionAmountMap: Map<string, BigNumberInput>,
|
||||||
methodIdPromoValueMap: Map<string, BigNumberInput>,
|
methodIdPromoValueMap: Map<string, BigNumberInput>,
|
||||||
promotion: PromotionTypes.PromotionDTO,
|
promotion: PromotionTypes.PromotionDTO | InferEntityType<typeof Promotion>,
|
||||||
itemsMap: Map<string, ComputeActionItemLine>,
|
itemsMap: Map<string, ComputeActionItemLine>,
|
||||||
applicationConfig: PromotionConfig
|
applicationConfig: PromotionConfig
|
||||||
): {
|
): {
|
||||||
@@ -456,7 +458,7 @@ function filterItemsByPromotionRules(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getComputedActionsForBuyGet(
|
export function getComputedActionsForBuyGet(
|
||||||
promotion: PromotionTypes.PromotionDTO,
|
promotion: PromotionTypes.PromotionDTO | InferEntityType<typeof Promotion>,
|
||||||
itemsContext: ComputeActionItemLine[],
|
itemsContext: ComputeActionItemLine[],
|
||||||
methodIdPromoValueMap: Map<string, BigNumberInput>,
|
methodIdPromoValueMap: Map<string, BigNumberInput>,
|
||||||
eligibleBuyItemMap: Map<string, EligibleItem[]>,
|
eligibleBuyItemMap: Map<string, EligibleItem[]>,
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
import { ApplicationMethodAllocationValues, BigNumberInput, PromotionTypes, } from "@medusajs/framework/types"
|
import {
|
||||||
|
ApplicationMethodAllocationValues,
|
||||||
|
BigNumberInput,
|
||||||
|
InferEntityType,
|
||||||
|
PromotionTypes,
|
||||||
|
} from "@medusajs/framework/types"
|
||||||
import {
|
import {
|
||||||
ApplicationMethodAllocation,
|
ApplicationMethodAllocation,
|
||||||
ApplicationMethodTargetType,
|
ApplicationMethodTargetType,
|
||||||
@@ -10,6 +15,7 @@ import {
|
|||||||
} from "@medusajs/framework/utils"
|
} from "@medusajs/framework/utils"
|
||||||
import { areRulesValidForContext } from "../validations"
|
import { areRulesValidForContext } from "../validations"
|
||||||
import { computeActionForBudgetExceeded } from "./usage"
|
import { computeActionForBudgetExceeded } from "./usage"
|
||||||
|
import { Promotion } from "@models"
|
||||||
|
|
||||||
function validateContext(
|
function validateContext(
|
||||||
contextKey: string,
|
contextKey: string,
|
||||||
@@ -24,7 +30,7 @@ function validateContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getComputedActionsForItems(
|
export function getComputedActionsForItems(
|
||||||
promotion: PromotionTypes.PromotionDTO,
|
promotion: PromotionTypes.PromotionDTO | InferEntityType<typeof Promotion>,
|
||||||
items: PromotionTypes.ComputeActionContext[TargetType.ITEMS],
|
items: PromotionTypes.ComputeActionContext[TargetType.ITEMS],
|
||||||
appliedPromotionsMap: Map<string, number>,
|
appliedPromotionsMap: Map<string, number>,
|
||||||
allocationOverride?: ApplicationMethodAllocationValues
|
allocationOverride?: ApplicationMethodAllocationValues
|
||||||
@@ -40,7 +46,7 @@ export function getComputedActionsForItems(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function applyPromotionToItems(
|
function applyPromotionToItems(
|
||||||
promotion: PromotionTypes.PromotionDTO,
|
promotion: PromotionTypes.PromotionDTO | InferEntityType<typeof Promotion>,
|
||||||
items: PromotionTypes.ComputeActionContext[TargetType.ITEMS],
|
items: PromotionTypes.ComputeActionContext[TargetType.ITEMS],
|
||||||
appliedPromotionsMap: Map<string, BigNumberInput>,
|
appliedPromotionsMap: Map<string, BigNumberInput>,
|
||||||
allocationOverride?: ApplicationMethodAllocationValues
|
allocationOverride?: ApplicationMethodAllocationValues
|
||||||
@@ -149,7 +155,7 @@ function getValidItemsForPromotion(
|
|||||||
items:
|
items:
|
||||||
| PromotionTypes.ComputeActionContext[TargetType.ITEMS]
|
| PromotionTypes.ComputeActionContext[TargetType.ITEMS]
|
||||||
| PromotionTypes.ComputeActionContext[TargetType.SHIPPING_METHODS],
|
| PromotionTypes.ComputeActionContext[TargetType.SHIPPING_METHODS],
|
||||||
promotion: PromotionTypes.PromotionDTO
|
promotion: PromotionTypes.PromotionDTO | InferEntityType<typeof Promotion>
|
||||||
) {
|
) {
|
||||||
if (!items?.length || !promotion?.application_method) {
|
if (!items?.length || !promotion?.application_method) {
|
||||||
return []
|
return []
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { BigNumberInput, PromotionTypes } from "@medusajs/framework/types"
|
import {
|
||||||
|
BigNumberInput,
|
||||||
|
InferEntityType,
|
||||||
|
PromotionTypes,
|
||||||
|
} from "@medusajs/framework/types"
|
||||||
import {
|
import {
|
||||||
ApplicationMethodAllocation,
|
ApplicationMethodAllocation,
|
||||||
ApplicationMethodTargetType,
|
ApplicationMethodTargetType,
|
||||||
@@ -9,9 +13,10 @@ import {
|
|||||||
} from "@medusajs/framework/utils"
|
} from "@medusajs/framework/utils"
|
||||||
import { areRulesValidForContext } from "../validations"
|
import { areRulesValidForContext } from "../validations"
|
||||||
import { computeActionForBudgetExceeded } from "./usage"
|
import { computeActionForBudgetExceeded } from "./usage"
|
||||||
|
import { Promotion } from "@models"
|
||||||
|
|
||||||
export function getComputedActionsForShippingMethods(
|
export function getComputedActionsForShippingMethods(
|
||||||
promotion: PromotionTypes.PromotionDTO,
|
promotion: PromotionTypes.PromotionDTO | InferEntityType<typeof Promotion>,
|
||||||
shippingMethodApplicationContext: PromotionTypes.ComputeActionContext[ApplicationMethodTargetType.SHIPPING_METHODS],
|
shippingMethodApplicationContext: PromotionTypes.ComputeActionContext[ApplicationMethodTargetType.SHIPPING_METHODS],
|
||||||
methodIdPromoValueMap: Map<string, number>
|
methodIdPromoValueMap: Map<string, number>
|
||||||
): PromotionTypes.ComputeActions[] {
|
): PromotionTypes.ComputeActions[] {
|
||||||
@@ -47,7 +52,7 @@ export function getComputedActionsForShippingMethods(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyPromotionToShippingMethods(
|
export function applyPromotionToShippingMethods(
|
||||||
promotion: PromotionTypes.PromotionDTO,
|
promotion: PromotionTypes.PromotionDTO | InferEntityType<typeof Promotion>,
|
||||||
shippingMethods: PromotionTypes.ComputeActionContext[ApplicationMethodTargetType.SHIPPING_METHODS],
|
shippingMethods: PromotionTypes.ComputeActionContext[ApplicationMethodTargetType.SHIPPING_METHODS],
|
||||||
methodIdPromoValueMap: Map<string, BigNumberInput>
|
methodIdPromoValueMap: Map<string, BigNumberInput>
|
||||||
): PromotionTypes.ComputeActions[] {
|
): PromotionTypes.ComputeActions[] {
|
||||||
@@ -126,10 +131,16 @@ export function applyPromotionToShippingMethods(
|
|||||||
const appliedPromoValue = methodIdPromoValueMap.get(method.id) ?? 0
|
const appliedPromoValue = methodIdPromoValueMap.get(method.id) ?? 0
|
||||||
const applicableTotal = MathBN.sub(method.subtotal, appliedPromoValue)
|
const applicableTotal = MathBN.sub(method.subtotal, appliedPromoValue)
|
||||||
|
|
||||||
let applicablePromotionValue = MathBN.mult(MathBN.div(applicableTotal, totalApplicableValue), promotionValue)
|
let applicablePromotionValue = MathBN.mult(
|
||||||
|
MathBN.div(applicableTotal, totalApplicableValue),
|
||||||
|
promotionValue
|
||||||
|
)
|
||||||
|
|
||||||
if (applicationMethod?.type === ApplicationMethodType.PERCENTAGE) {
|
if (applicationMethod?.type === ApplicationMethodType.PERCENTAGE) {
|
||||||
applicablePromotionValue = MathBN.mult(MathBN.div(promotionValue, 100), applicableTotal)
|
applicablePromotionValue = MathBN.mult(
|
||||||
|
MathBN.div(promotionValue, 100),
|
||||||
|
applicableTotal
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const amount = MathBN.min(applicablePromotionValue, applicableTotal)
|
const amount = MathBN.min(applicablePromotionValue, applicableTotal)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
BigNumberInput,
|
BigNumberInput,
|
||||||
CampaignBudgetExceededAction,
|
CampaignBudgetExceededAction,
|
||||||
|
InferEntityType,
|
||||||
PromotionDTO,
|
PromotionDTO,
|
||||||
} from "@medusajs/framework/types"
|
} from "@medusajs/framework/types"
|
||||||
import {
|
import {
|
||||||
@@ -8,9 +9,10 @@ import {
|
|||||||
ComputedActions,
|
ComputedActions,
|
||||||
MathBN,
|
MathBN,
|
||||||
} from "@medusajs/framework/utils"
|
} from "@medusajs/framework/utils"
|
||||||
|
import { Promotion } from "@models"
|
||||||
|
|
||||||
export function computeActionForBudgetExceeded(
|
export function computeActionForBudgetExceeded(
|
||||||
promotion: PromotionDTO,
|
promotion: PromotionDTO | InferEntityType<typeof Promotion>,
|
||||||
amount: BigNumberInput
|
amount: BigNumberInput
|
||||||
): CampaignBudgetExceededAction | void {
|
): CampaignBudgetExceededAction | void {
|
||||||
const campaignBudget = promotion.campaign?.budget
|
const campaignBudget = promotion.campaign?.budget
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
ApplicationMethodTargetTypeValues,
|
ApplicationMethodTargetTypeValues,
|
||||||
|
InferEntityType,
|
||||||
PromotionRuleDTO,
|
PromotionRuleDTO,
|
||||||
PromotionRuleOperatorValues,
|
PromotionRuleOperatorValues,
|
||||||
} from "@medusajs/framework/types"
|
} from "@medusajs/framework/types"
|
||||||
@@ -12,6 +13,7 @@ import {
|
|||||||
isString,
|
isString,
|
||||||
pickValueFromObject,
|
pickValueFromObject,
|
||||||
} from "@medusajs/framework/utils"
|
} from "@medusajs/framework/utils"
|
||||||
|
import { PromotionRule } from "@models"
|
||||||
import { CreatePromotionRuleDTO } from "@types"
|
import { CreatePromotionRuleDTO } from "@types"
|
||||||
|
|
||||||
export function validatePromotionRuleAttributes(
|
export function validatePromotionRuleAttributes(
|
||||||
@@ -51,7 +53,7 @@ export function validatePromotionRuleAttributes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function areRulesValidForContext(
|
export function areRulesValidForContext(
|
||||||
rules: PromotionRuleDTO[],
|
rules: PromotionRuleDTO[] | InferEntityType<typeof PromotionRule>[],
|
||||||
context: Record<string, any>,
|
context: Record<string, any>,
|
||||||
contextScope: ApplicationMethodTargetTypeValues
|
contextScope: ApplicationMethodTargetTypeValues
|
||||||
): boolean {
|
): boolean {
|
||||||
@@ -63,14 +65,17 @@ export function areRulesValidForContext(
|
|||||||
const isShippingScope =
|
const isShippingScope =
|
||||||
contextScope === ApplicationMethodTargetType.SHIPPING_METHODS
|
contextScope === ApplicationMethodTargetType.SHIPPING_METHODS
|
||||||
|
|
||||||
return rules.every((rule) => {
|
return ("initialized" in rules ? [...rules] : rules).every((rule) => {
|
||||||
if (!rule.attribute || !rule.values?.length) {
|
if (!rule.attribute || !rule.values?.length) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const validRuleValues = rule.values
|
const validRuleValues: string[] = []
|
||||||
.filter((v) => isString(v.value))
|
for (const value of rule.values) {
|
||||||
.map((v) => v.value as string)
|
if (isString(value.value)) {
|
||||||
|
validRuleValues.push(value.value as string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!validRuleValues.length) {
|
if (!validRuleValues.length) {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -539,7 +539,7 @@ moduleIntegrationTestRunner<IWorkflowEngineService>({
|
|||||||
throwOnError: false,
|
throwOnError: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
await setTimeout(1000)
|
await setTimeout(4000)
|
||||||
|
|
||||||
expect(lastExepectHaveBeenCalledTimes).toEqual(1)
|
expect(lastExepectHaveBeenCalledTimes).toEqual(1)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in new issue
Block a user