feat(core-flows,types,promotion): register promotion campaign usage upon cart completion (#8970)
* feat(core-flows,types,promotion): register promotion campaign usage upon cart completion * Apply suggestions from code review Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com> --------- Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
@@ -1812,6 +1812,7 @@ medusaIntegrationTestRunner({
|
||||
let paymentSession
|
||||
let stockLocation
|
||||
let inventoryItem
|
||||
let promotion
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupTaxStructure(taxModule)
|
||||
@@ -1925,6 +1926,43 @@ medusaIntegrationTestRunner({
|
||||
},
|
||||
])
|
||||
|
||||
promotion = (
|
||||
await api.post(
|
||||
`/admin/promotions`,
|
||||
{
|
||||
code: "TEST",
|
||||
type: PromotionType.STANDARD,
|
||||
is_automatic: true,
|
||||
campaign: {
|
||||
campaign_identifier: "test",
|
||||
name: "test",
|
||||
budget: {
|
||||
type: "spend",
|
||||
limit: 1000,
|
||||
currency_code: region.currency_code,
|
||||
},
|
||||
},
|
||||
application_method: {
|
||||
target_type: "items",
|
||||
type: "fixed",
|
||||
allocation: "each",
|
||||
currency_code: region.currency_code,
|
||||
value: 10,
|
||||
max_quantity: 1,
|
||||
target_rules: [
|
||||
{
|
||||
attribute: "product_id",
|
||||
operator: "eq",
|
||||
values: [product.id],
|
||||
},
|
||||
],
|
||||
},
|
||||
rules: [],
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
).data.promotion
|
||||
|
||||
await api.post(
|
||||
`/admin/stock-locations/${stockLocation.id}/fulfillment-providers`,
|
||||
{ add: ["manual_test-provider"] },
|
||||
@@ -2015,16 +2053,16 @@ medusaIntegrationTestRunner({
|
||||
type: "order",
|
||||
order: expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
total: 106,
|
||||
total: 94.764,
|
||||
subtotal: 100,
|
||||
tax_total: 6,
|
||||
discount_total: 0,
|
||||
discount_tax_total: 0,
|
||||
original_total: 106,
|
||||
tax_total: 5.364,
|
||||
discount_total: 10.6,
|
||||
discount_tax_total: 0.636,
|
||||
original_total: 95.4,
|
||||
original_tax_total: 6,
|
||||
item_total: 106,
|
||||
item_total: 94.764,
|
||||
item_subtotal: 100,
|
||||
item_tax_total: 6,
|
||||
item_tax_total: 5.364,
|
||||
original_item_total: 106,
|
||||
original_item_subtotal: 100,
|
||||
original_item_tax_total: 6,
|
||||
@@ -2040,17 +2078,27 @@ medusaIntegrationTestRunner({
|
||||
product_id: product.id,
|
||||
unit_price: 100,
|
||||
quantity: 1,
|
||||
tax_total: 6,
|
||||
tax_total: 5.364,
|
||||
total: 94.764,
|
||||
subtotal: 100,
|
||||
total: 106,
|
||||
original_total: 106,
|
||||
discount_total: 0,
|
||||
discount_total: 10.6,
|
||||
discount_tax_total: 0.636,
|
||||
original_tax_total: 6,
|
||||
tax_lines: [
|
||||
expect.objectContaining({
|
||||
rate: 6,
|
||||
}),
|
||||
],
|
||||
adjustments: [],
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 10,
|
||||
promotion_id: promotion.id,
|
||||
code: promotion.code,
|
||||
subtotal: 10,
|
||||
total: 10.6,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
shipping_address: expect.objectContaining({
|
||||
@@ -2062,6 +2110,12 @@ medusaIntegrationTestRunner({
|
||||
}),
|
||||
})
|
||||
|
||||
promotion = (
|
||||
await api.get(`/admin/promotions/${promotion.id}`, adminHeaders)
|
||||
).data.promotion
|
||||
|
||||
expect(promotion.campaign.budget.used).toEqual(10)
|
||||
|
||||
const reservation = await api.get(`/admin/reservations`, adminHeaders)
|
||||
const reservationItem = reservation.data.reservations[0]
|
||||
|
||||
@@ -2086,7 +2140,7 @@ medusaIntegrationTestRunner({
|
||||
payment_collections: [
|
||||
expect.objectContaining({
|
||||
currency_code: "usd",
|
||||
amount: 106,
|
||||
amount: 94.764,
|
||||
status: "authorized",
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { OrderDTO } from "@medusajs/types"
|
||||
import {
|
||||
CartWorkflowDTO,
|
||||
OrderDTO,
|
||||
UsageComputedActions,
|
||||
} from "@medusajs/types"
|
||||
import { Modules, OrderStatus, OrderWorkflowEvents } from "@medusajs/utils"
|
||||
import {
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
createWorkflow,
|
||||
parallelize,
|
||||
transform,
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import {
|
||||
createRemoteLinkStep,
|
||||
@@ -14,6 +18,7 @@ import {
|
||||
} from "../../common"
|
||||
import { createOrdersStep } from "../../order/steps/create-orders"
|
||||
import { authorizePaymentSessionStep } from "../../payment/steps/authorize-payment-session"
|
||||
import { registerUsageStep } from "../../promotion/steps/register-usage"
|
||||
import { updateCartsStep, validateCartPaymentsStep } from "../steps"
|
||||
import { reserveInventoryStep } from "../steps/reserve-inventory"
|
||||
import { validateCartStep } from "../steps/validate-cart"
|
||||
@@ -61,7 +66,8 @@ export const completeCartWorkflow = createWorkflow(
|
||||
(data) => {
|
||||
const allItems: any[] = []
|
||||
const allVariants: any[] = []
|
||||
data.cart.items.forEach((item) => {
|
||||
|
||||
data.cart?.items?.forEach((item) => {
|
||||
allItems.push({
|
||||
id: item.id,
|
||||
variant_id: item.variant_id,
|
||||
@@ -188,6 +194,39 @@ export const completeCartWorkflow = createWorkflow(
|
||||
})
|
||||
)
|
||||
|
||||
const promotionUsage = transform(
|
||||
{ cart },
|
||||
({ cart }: { cart: CartWorkflowDTO }) => {
|
||||
const promotionUsage: UsageComputedActions[] = []
|
||||
|
||||
const itemAdjustments = (cart.items ?? [])
|
||||
.map((item) => item.adjustments ?? [])
|
||||
.flat(1)
|
||||
|
||||
const shippingAdjustments = (cart.shipping_methods ?? [])
|
||||
.map((item) => item.adjustments ?? [])
|
||||
.flat(1)
|
||||
|
||||
for (const adjustment of itemAdjustments) {
|
||||
promotionUsage.push({
|
||||
amount: adjustment.amount,
|
||||
code: adjustment.code!,
|
||||
})
|
||||
}
|
||||
|
||||
for (const adjustment of shippingAdjustments) {
|
||||
promotionUsage.push({
|
||||
amount: adjustment.amount,
|
||||
code: adjustment.code!,
|
||||
})
|
||||
}
|
||||
|
||||
return promotionUsage
|
||||
}
|
||||
)
|
||||
|
||||
registerUsageStep(promotionUsage)
|
||||
|
||||
return new WorkflowResponse(order)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { IPromotionModuleService, UsageComputedActions } from "@medusajs/types"
|
||||
import { ModuleRegistrationName } from "@medusajs/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
export const registerUsageStepId = "register-usage"
|
||||
/**
|
||||
* This step registers usage for promotion campaigns
|
||||
*/
|
||||
export const registerUsageStep = createStep(
|
||||
registerUsageStepId,
|
||||
async (data: UsageComputedActions[], { container }) => {
|
||||
if (!data.length) {
|
||||
return new StepResponse(null, [])
|
||||
}
|
||||
|
||||
const promotionModule = container.resolve<IPromotionModuleService>(
|
||||
ModuleRegistrationName.PROMOTION
|
||||
)
|
||||
|
||||
await promotionModule.registerUsage(data)
|
||||
|
||||
return new StepResponse(null, data)
|
||||
},
|
||||
async (revertData, { container }) => {
|
||||
if (!revertData?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const promotionModule = container.resolve<IPromotionModuleService>(
|
||||
ModuleRegistrationName.PROMOTION
|
||||
)
|
||||
|
||||
await promotionModule.revertUsage(revertData)
|
||||
}
|
||||
)
|
||||
@@ -13,9 +13,17 @@ export type ComputeActions =
|
||||
/**
|
||||
* These computed action types can affect a campaign's budget.
|
||||
*/
|
||||
export type UsageComputedActions =
|
||||
| AddShippingMethodAdjustment
|
||||
| AddItemAdjustmentAction
|
||||
export type UsageComputedActions = {
|
||||
/**
|
||||
* The amount to remove off the shipping method's total.
|
||||
*/
|
||||
amount: BigNumberInput
|
||||
|
||||
/**
|
||||
* The promotion's code.
|
||||
*/
|
||||
code: string
|
||||
}
|
||||
|
||||
/**
|
||||
* This action indicates that the promotions within a campaign can no longer be used
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
PromotionRuleDTO,
|
||||
UpdatePromotionDTO,
|
||||
UpdatePromotionRuleDTO,
|
||||
UsageComputedActions,
|
||||
} from "./common"
|
||||
import {
|
||||
AddPromotionsToCampaignDTO,
|
||||
@@ -32,26 +33,42 @@ export interface IPromotionModuleService extends IModuleService {
|
||||
* It adjusts the `used` property of a `CampaignBudget` to account for the adjustment amounts in the specified associated
|
||||
* computed actions.
|
||||
*
|
||||
* @param {ComputeActions[]} computedActions - The computed actions to adjust their promotion's campaign budget.
|
||||
* @param {UsageComputedActions[]} computedActions - The computed actions to adjust their promotion's campaign budget.
|
||||
* @returns {Promise<void>} Resolves when the campaign budgets have been adjusted successfully.
|
||||
*
|
||||
* @example
|
||||
* await promotionModuleService.registerUsage([
|
||||
* {
|
||||
* action: "addItemAdjustment",
|
||||
* item_id: "cali_123",
|
||||
* amount: 50,
|
||||
* code: "50OFF",
|
||||
* },
|
||||
* {
|
||||
* action: "addShippingMethodAdjustment",
|
||||
* shipping_method_id: "casm_123",
|
||||
* amount: 5000,
|
||||
* code: "FREESHIPPING",
|
||||
* },
|
||||
* ])
|
||||
*/
|
||||
registerUsage(computedActions: ComputeActions[]): Promise<void>
|
||||
registerUsage(computedActions: UsageComputedActions[]): Promise<void>
|
||||
|
||||
/**
|
||||
* This method is used to revert the changes made by registerUsage action
|
||||
*
|
||||
* @param {UsageComputedActions[]} computedActions - The computed actions to adjust their promotion's campaign budget.
|
||||
* @returns {Promise<void>} Resolves when the campaign budgets have been adjusted successfully.
|
||||
*
|
||||
* @example
|
||||
* await promotionModuleService.revertUsage([
|
||||
* {
|
||||
* amount: 50,
|
||||
* code: "50OFF",
|
||||
* },
|
||||
* {
|
||||
* amount: 5000,
|
||||
* code: "FREESHIPPING",
|
||||
* },
|
||||
* ])
|
||||
*/
|
||||
revertUsage(computedActions: UsageComputedActions[]): Promise<void>
|
||||
|
||||
/**
|
||||
* This method provides the actions to perform on a cart based on the specified promotions
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
import { IPromotionModuleService } from "@medusajs/types"
|
||||
import { Modules } from "@medusajs/utils"
|
||||
import { moduleIntegrationTestRunner, SuiteOptions } from "medusa-test-utils"
|
||||
import { createCampaigns } from "../../../__fixtures__/campaigns"
|
||||
import { createDefaultPromotion } from "../../../__fixtures__/promotion"
|
||||
|
||||
jest.setTimeout(30000)
|
||||
|
||||
moduleIntegrationTestRunner({
|
||||
moduleName: Modules.PROMOTION,
|
||||
testSuite: ({
|
||||
MikroOrmWrapper,
|
||||
service,
|
||||
}: SuiteOptions<IPromotionModuleService>) => {
|
||||
describe("Promotion Service: campaign usage", () => {
|
||||
beforeEach(async () => {
|
||||
await createCampaigns(MikroOrmWrapper.forkManager())
|
||||
})
|
||||
|
||||
describe("revertUsage", () => {
|
||||
it("should revert usage for type spend", async () => {
|
||||
const createdPromotion = await createDefaultPromotion(service, {})
|
||||
const createdPromotion2 = await createDefaultPromotion(service, {
|
||||
code: "PROMO_2",
|
||||
campaign_id: createdPromotion.campaign?.id,
|
||||
})
|
||||
const createdPromotion3 = await createDefaultPromotion(service, {
|
||||
code: "PROMO_3",
|
||||
campaign_id: createdPromotion.campaign?.id,
|
||||
})
|
||||
|
||||
await service.registerUsage([
|
||||
{ amount: 200, code: createdPromotion.code! },
|
||||
{ amount: 100, code: createdPromotion.code! },
|
||||
])
|
||||
|
||||
await service.registerUsage([
|
||||
{ amount: 100, code: createdPromotion2.code! },
|
||||
{ amount: 200, code: createdPromotion2.code! },
|
||||
])
|
||||
|
||||
await service.registerUsage([
|
||||
{ amount: 50, code: createdPromotion3.code! },
|
||||
{ amount: 250, code: createdPromotion3.code! },
|
||||
])
|
||||
|
||||
await service.revertUsage([
|
||||
{ amount: 200, code: createdPromotion.code! },
|
||||
{ amount: 100, code: createdPromotion.code! },
|
||||
])
|
||||
|
||||
await service.revertUsage([
|
||||
{ amount: 50, code: createdPromotion3.code! },
|
||||
{ amount: 250, code: createdPromotion3.code! },
|
||||
])
|
||||
|
||||
const campaign = await service.retrieveCampaign(
|
||||
createdPromotion.campaign?.id!,
|
||||
{ relations: ["budget"] }
|
||||
)
|
||||
|
||||
expect(campaign.budget).toEqual(
|
||||
expect.objectContaining({
|
||||
type: "spend",
|
||||
limit: 1000,
|
||||
used: 300,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should revert usage for type usage", async () => {
|
||||
const campaignId = "campaign-id-2"
|
||||
const createdPromotion = await createDefaultPromotion(service, {
|
||||
code: "PROMO_1",
|
||||
campaign_id: campaignId,
|
||||
})
|
||||
const createdPromotion2 = await createDefaultPromotion(service, {
|
||||
code: "PROMO_2",
|
||||
campaign_id: campaignId,
|
||||
})
|
||||
const createdPromotion3 = await createDefaultPromotion(service, {
|
||||
code: "PROMO_3",
|
||||
campaign_id: campaignId,
|
||||
})
|
||||
|
||||
await service.registerUsage([
|
||||
{ amount: 200, code: createdPromotion.code! },
|
||||
{ amount: 500, code: createdPromotion.code! },
|
||||
])
|
||||
|
||||
await service.registerUsage([
|
||||
{ amount: 200, code: createdPromotion2.code! },
|
||||
{ amount: 500, code: createdPromotion3.code! },
|
||||
])
|
||||
|
||||
await service.revertUsage([
|
||||
{ amount: 200, code: createdPromotion.code! },
|
||||
{ amount: 500, code: createdPromotion.code! },
|
||||
])
|
||||
|
||||
await service.revertUsage([
|
||||
{ amount: 200, code: createdPromotion2.code! },
|
||||
{ amount: 500, code: createdPromotion3.code! },
|
||||
])
|
||||
|
||||
const campaign = await service.retrieveCampaign(campaignId, {
|
||||
relations: ["budget"],
|
||||
})
|
||||
|
||||
expect(campaign.budget).toEqual(
|
||||
expect.objectContaining({
|
||||
type: "usage",
|
||||
limit: 1000,
|
||||
used: 0,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should not throw an error when compute action with code does not exist", async () => {
|
||||
const response = await service
|
||||
.revertUsage([{ amount: 200, code: "DOESNOTEXIST" }])
|
||||
.catch((e) => e)
|
||||
|
||||
expect(response).toEqual(undefined)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -123,33 +123,39 @@ export default class PromotionModuleService
|
||||
@InjectManager("baseRepository_")
|
||||
async registerUsage(
|
||||
computedActions: PromotionTypes.UsageComputedActions[],
|
||||
@MedusaContext()
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<void> {
|
||||
const promotionCodes = computedActions
|
||||
.map((computedAction) => computedAction.code)
|
||||
.filter(Boolean)
|
||||
|
||||
const promotionCodeCampaignBudgetMap = new Map<
|
||||
string,
|
||||
UpdateCampaignBudgetDTO
|
||||
>()
|
||||
const campaignBudgetMap = new Map<string, UpdateCampaignBudgetDTO>()
|
||||
const promotionCodeUsageMap = new Map<string, boolean>()
|
||||
|
||||
const existingPromotions = await this.listPromotions(
|
||||
{ code: promotionCodes },
|
||||
{ relations: ["application_method", "campaign", "campaign.budget"] },
|
||||
{
|
||||
relations: ["campaign", "campaign.budget"],
|
||||
take: null,
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
for (const promotion of existingPromotions) {
|
||||
if (promotion.campaign?.budget) {
|
||||
campaignBudgetMap.set(
|
||||
promotion.campaign?.budget.id,
|
||||
promotion.campaign?.budget
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const existingPromotionsMap = new Map<string, PromotionTypes.PromotionDTO>(
|
||||
existingPromotions.map((promotion) => [promotion.code!, promotion])
|
||||
)
|
||||
|
||||
for (let computedAction of computedActions) {
|
||||
if (!ComputeActionUtils.canRegisterUsage(computedAction)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const promotion = existingPromotionsMap.get(computedAction.code)
|
||||
|
||||
if (!promotion) {
|
||||
@@ -163,9 +169,11 @@ export default class PromotionModuleService
|
||||
}
|
||||
|
||||
if (campaignBudget.type === CampaignBudgetType.SPEND) {
|
||||
const campaignBudgetData = promotionCodeCampaignBudgetMap.get(
|
||||
campaignBudget.id
|
||||
) || { id: campaignBudget.id, used: campaignBudget.used ?? 0 }
|
||||
const campaignBudgetData = campaignBudgetMap.get(campaignBudget.id)
|
||||
|
||||
if (!campaignBudgetData) {
|
||||
continue
|
||||
}
|
||||
|
||||
campaignBudgetData.used = MathBN.add(
|
||||
campaignBudgetData.used ?? 0,
|
||||
@@ -179,10 +187,7 @@ export default class PromotionModuleService
|
||||
continue
|
||||
}
|
||||
|
||||
promotionCodeCampaignBudgetMap.set(
|
||||
campaignBudget.id,
|
||||
campaignBudgetData
|
||||
)
|
||||
campaignBudgetMap.set(campaignBudget.id, campaignBudgetData)
|
||||
}
|
||||
|
||||
if (campaignBudget.type === CampaignBudgetType.USAGE) {
|
||||
@@ -205,17 +210,105 @@ export default class PromotionModuleService
|
||||
continue
|
||||
}
|
||||
|
||||
promotionCodeCampaignBudgetMap.set(
|
||||
campaignBudget.id,
|
||||
campaignBudgetData
|
||||
)
|
||||
campaignBudgetMap.set(campaignBudget.id, campaignBudgetData)
|
||||
|
||||
promotionCodeUsageMap.set(promotion.code!, true)
|
||||
}
|
||||
|
||||
const campaignBudgetsData: UpdateCampaignBudgetDTO[] = []
|
||||
|
||||
for (const [_, campaignBudgetData] of promotionCodeCampaignBudgetMap) {
|
||||
for (const [_, campaignBudgetData] of campaignBudgetMap) {
|
||||
campaignBudgetsData.push(campaignBudgetData)
|
||||
}
|
||||
|
||||
await this.campaignBudgetService_.update(
|
||||
campaignBudgetsData,
|
||||
sharedContext
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async revertUsage(
|
||||
computedActions: PromotionTypes.UsageComputedActions[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<void> {
|
||||
const promotionCodeUsageMap = new Map<string, boolean>()
|
||||
const campaignBudgetMap = new Map<string, UpdateCampaignBudgetDTO>()
|
||||
|
||||
const existingPromotions = await this.listPromotions(
|
||||
{
|
||||
code: computedActions
|
||||
.map((computedAction) => computedAction.code)
|
||||
.filter(Boolean),
|
||||
},
|
||||
{
|
||||
relations: ["campaign", "campaign.budget"],
|
||||
take: null,
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
for (const promotion of existingPromotions) {
|
||||
if (promotion.campaign?.budget) {
|
||||
campaignBudgetMap.set(
|
||||
promotion.campaign?.budget.id,
|
||||
promotion.campaign?.budget
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const existingPromotionsMap = new Map<string, PromotionTypes.PromotionDTO>(
|
||||
existingPromotions.map((promotion) => [promotion.code!, promotion])
|
||||
)
|
||||
|
||||
for (let computedAction of computedActions) {
|
||||
const promotion = existingPromotionsMap.get(computedAction.code)
|
||||
|
||||
if (!promotion) {
|
||||
continue
|
||||
}
|
||||
|
||||
const campaignBudget = promotion.campaign?.budget
|
||||
|
||||
if (!campaignBudget) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (campaignBudget.type === CampaignBudgetType.SPEND) {
|
||||
const campaignBudgetData = campaignBudgetMap.get(campaignBudget.id)
|
||||
|
||||
if (!campaignBudgetData) {
|
||||
continue
|
||||
}
|
||||
|
||||
campaignBudgetData.used = MathBN.sub(
|
||||
campaignBudgetData.used ?? 0,
|
||||
computedAction.amount
|
||||
)
|
||||
|
||||
campaignBudgetMap.set(campaignBudget.id, campaignBudgetData)
|
||||
}
|
||||
|
||||
if (campaignBudget.type === CampaignBudgetType.USAGE) {
|
||||
const promotionAlreadyUsed =
|
||||
promotionCodeUsageMap.get(promotion.code!) || false
|
||||
|
||||
if (promotionAlreadyUsed) {
|
||||
continue
|
||||
}
|
||||
|
||||
campaignBudgetMap.set(campaignBudget.id, {
|
||||
id: campaignBudget.id,
|
||||
used: MathBN.sub(campaignBudget.used ?? 0, 1),
|
||||
})
|
||||
|
||||
promotionCodeUsageMap.set(promotion.code!, true)
|
||||
}
|
||||
|
||||
const campaignBudgetsData: UpdateCampaignBudgetDTO[] = []
|
||||
|
||||
for (const [_, campaignBudgetData] of campaignBudgetMap) {
|
||||
campaignBudgetsData.push(campaignBudgetData)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,10 @@
|
||||
import {
|
||||
BigNumberInput,
|
||||
CampaignBudgetExceededAction,
|
||||
ComputeActions,
|
||||
PromotionDTO,
|
||||
} from "@medusajs/types"
|
||||
import { CampaignBudgetType, ComputedActions, MathBN } from "@medusajs/utils"
|
||||
|
||||
export function canRegisterUsage(computedAction: ComputeActions): boolean {
|
||||
return (
|
||||
[
|
||||
ComputedActions.ADD_ITEM_ADJUSTMENT,
|
||||
ComputedActions.ADD_SHIPPING_METHOD_ADJUSTMENT,
|
||||
] as string[]
|
||||
).includes(computedAction.action)
|
||||
}
|
||||
|
||||
export function computeActionForBudgetExceeded(
|
||||
promotion: PromotionDTO,
|
||||
amount: BigNumberInput
|
||||
|
||||
Reference in New Issue
Block a user