@lodashventure/medusa-campaign 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.medusa/server/src/admin/index.js +1 -67
- package/.medusa/server/src/admin/index.mjs +1 -67
- package/.medusa/server/src/workflows/index.js +10 -0
- package/package.json +4 -4
- package/src/admin/README.md +31 -0
- package/src/admin/components/FlashSaleForm.tsx +379 -0
- package/src/admin/components/FlashSalePage.tsx +113 -0
- package/src/admin/components/ProductSelector.tsx +88 -0
- package/src/admin/hooks/useFlashSaleById.ts +21 -0
- package/src/admin/hooks/useFlashSales.ts +25 -0
- package/src/admin/lib/sdk.ts +10 -0
- package/src/admin/routes/flash-sales/[id]/page.tsx +105 -0
- package/src/admin/routes/flash-sales/create/page.tsx +51 -0
- package/src/admin/routes/flash-sales/page.tsx +15 -0
- package/src/admin/tsconfig.json +24 -0
- package/src/admin/types/campaign.ts +25 -0
- package/src/admin/vite-env.d.ts +1 -0
- package/src/api/README.md +133 -0
- package/src/api/admin/flash-sales/[id]/route.ts +164 -0
- package/src/api/admin/flash-sales/route.ts +87 -0
- package/src/api/middlewares.ts +32 -0
- package/src/api/store/campaigns/[id]/route.ts +133 -0
- package/src/api/store/campaigns/route.ts +36 -0
- package/src/jobs/README.md +36 -0
- package/src/links/README.md +26 -0
- package/src/links/campaign-type.ts +8 -0
- package/src/modules/README.md +116 -0
- package/src/modules/custom-campaigns/index.ts +8 -0
- package/src/modules/custom-campaigns/migrations/.snapshot-medusa-custom-campaign.json +235 -0
- package/src/modules/custom-campaigns/migrations/Migration20250524150901.ts +23 -0
- package/src/modules/custom-campaigns/migrations/Migration20250526010310.ts +20 -0
- package/src/modules/custom-campaigns/migrations/Migration20250529011904.ts +13 -0
- package/src/modules/custom-campaigns/models/custom-campaign-type.ts +10 -0
- package/src/modules/custom-campaigns/models/promotion-usage-limit.ts +14 -0
- package/src/modules/custom-campaigns/service.ts +10 -0
- package/src/modules/custom-campaigns/types/campaign-type.enum.ts +3 -0
- package/src/providers/README.md +30 -0
- package/src/subscribers/README.md +59 -0
- package/src/subscribers/order-placed.ts +17 -0
- package/src/workflows/README.md +79 -0
- package/src/workflows/custom-campaign/createCustomCampaignWorkflow.ts +181 -0
- package/src/workflows/custom-campaign/updateCustomFlashSaleWorkflow.ts +185 -0
- package/src/workflows/custom-campaign/updatePromotionUsageWorkflow.ts +70 -0
- package/src/workflows/hooks/deletePromotionOnCampaignDelete.ts +49 -0
- package/src/workflows/index.ts +3 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { container } from "@medusajs/framework";
|
|
2
|
+
import {
|
|
3
|
+
CampaignDTO,
|
|
4
|
+
CreateApplicationMethodDTO,
|
|
5
|
+
CreatePromotionDTO,
|
|
6
|
+
PromotionDTO,
|
|
7
|
+
} from "@medusajs/framework/types";
|
|
8
|
+
import {
|
|
9
|
+
ContainerRegistrationKeys,
|
|
10
|
+
MedusaError,
|
|
11
|
+
Modules,
|
|
12
|
+
} from "@medusajs/framework/utils";
|
|
13
|
+
import {
|
|
14
|
+
createStep,
|
|
15
|
+
createWorkflow,
|
|
16
|
+
StepResponse,
|
|
17
|
+
WorkflowResponse,
|
|
18
|
+
} from "@medusajs/framework/workflows-sdk";
|
|
19
|
+
import {
|
|
20
|
+
createCampaignsWorkflow,
|
|
21
|
+
createPromotionsWorkflow,
|
|
22
|
+
deleteCampaignsWorkflow,
|
|
23
|
+
deletePromotionsWorkflow,
|
|
24
|
+
} from "@medusajs/medusa/core-flows";
|
|
25
|
+
import { CustomCampaign } from "../../api/admin/flash-sales/route";
|
|
26
|
+
import { CUSTOM_CAMPAIGN_MODULE } from "../../modules/custom-campaigns";
|
|
27
|
+
import CustomCampaignModuleService from "../../modules/custom-campaigns/service";
|
|
28
|
+
|
|
29
|
+
const createCustomCampaignStep = createStep(
|
|
30
|
+
"create-custom-campaign-step",
|
|
31
|
+
async (data: CustomCampaign) => {
|
|
32
|
+
const link = container.resolve(ContainerRegistrationKeys.LINK);
|
|
33
|
+
const customCampaignModuleService =
|
|
34
|
+
container.resolve<CustomCampaignModuleService>(CUSTOM_CAMPAIGN_MODULE);
|
|
35
|
+
const campaignIdentifier = `${data.type}-${Date.now()}`;
|
|
36
|
+
|
|
37
|
+
let campaign: CampaignDTO | undefined;
|
|
38
|
+
let promotions: PromotionDTO[] | undefined;
|
|
39
|
+
let customCampaignType:
|
|
40
|
+
| Awaited<
|
|
41
|
+
ReturnType<CustomCampaignModuleService["createCustomCampaignTypes"]>
|
|
42
|
+
>[number]
|
|
43
|
+
| undefined;
|
|
44
|
+
let promotionUsageLimit:
|
|
45
|
+
| Awaited<
|
|
46
|
+
ReturnType<CustomCampaignModuleService["createPromotionUsageLimits"]>
|
|
47
|
+
>
|
|
48
|
+
| undefined;
|
|
49
|
+
|
|
50
|
+
const {
|
|
51
|
+
result: [_campaign],
|
|
52
|
+
} = await createCampaignsWorkflow.run({
|
|
53
|
+
input: {
|
|
54
|
+
campaignsData: [
|
|
55
|
+
{
|
|
56
|
+
name: data.name,
|
|
57
|
+
campaign_identifier: campaignIdentifier,
|
|
58
|
+
description: data.description,
|
|
59
|
+
starts_at: new Date(data.starts_at),
|
|
60
|
+
ends_at: new Date(data.ends_at),
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
campaign = _campaign;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const { result: _promotions } = await createPromotionsWorkflow.run({
|
|
69
|
+
input: {
|
|
70
|
+
promotionsData: data.products.map(
|
|
71
|
+
(product) =>
|
|
72
|
+
({
|
|
73
|
+
code: `${campaignIdentifier}-${product.product.id}`,
|
|
74
|
+
type: "standard",
|
|
75
|
+
status: "active",
|
|
76
|
+
is_automatic: true,
|
|
77
|
+
campaign_id: campaign.id,
|
|
78
|
+
application_method: {
|
|
79
|
+
target_type: "items",
|
|
80
|
+
allocation: "each",
|
|
81
|
+
type: product.discountType,
|
|
82
|
+
value: product.discountValue,
|
|
83
|
+
max_quantity: product.maxQty,
|
|
84
|
+
target_rules: [
|
|
85
|
+
{
|
|
86
|
+
attribute: "items.product.id",
|
|
87
|
+
operator: "eq",
|
|
88
|
+
values: [product.product.id],
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
} satisfies CreateApplicationMethodDTO,
|
|
92
|
+
} satisfies CreatePromotionDTO)
|
|
93
|
+
),
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
promotions = _promotions;
|
|
97
|
+
|
|
98
|
+
const productPromotionMap = new Map<string, string>();
|
|
99
|
+
promotions.forEach((promotion) => {
|
|
100
|
+
const productId = promotion.code?.split("-").at(-1);
|
|
101
|
+
if (!productId) {
|
|
102
|
+
throw new MedusaError(
|
|
103
|
+
MedusaError.Types.INVALID_DATA,
|
|
104
|
+
"Invalid product id"
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
productPromotionMap.set(productId, promotion.id);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
customCampaignType =
|
|
111
|
+
await customCampaignModuleService.createCustomCampaignTypes({
|
|
112
|
+
campaign_id: campaign.id,
|
|
113
|
+
type: data.type,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
promotionUsageLimit =
|
|
117
|
+
await customCampaignModuleService.createPromotionUsageLimits(
|
|
118
|
+
data.products.map((product) => ({
|
|
119
|
+
campaign_id: campaign.id,
|
|
120
|
+
promotion_id: productPromotionMap.get(product.product.id),
|
|
121
|
+
product_id: product.product.id,
|
|
122
|
+
limit: product.limit,
|
|
123
|
+
used: 0,
|
|
124
|
+
}))
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// link campaign type
|
|
128
|
+
await link.create([
|
|
129
|
+
{
|
|
130
|
+
[Modules.PROMOTION]: {
|
|
131
|
+
campaign_id: campaign.id,
|
|
132
|
+
},
|
|
133
|
+
[CUSTOM_CAMPAIGN_MODULE]: {
|
|
134
|
+
custom_campaign_type_id: customCampaignType.id,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
|
|
139
|
+
return new StepResponse({
|
|
140
|
+
campaign,
|
|
141
|
+
promotions,
|
|
142
|
+
});
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.log({ error });
|
|
145
|
+
await deleteCampaignsWorkflow.run({
|
|
146
|
+
input: {
|
|
147
|
+
ids: campaign.id,
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
if (promotions) {
|
|
152
|
+
await deletePromotionsWorkflow.run({
|
|
153
|
+
input: {
|
|
154
|
+
ids: promotions.map((promotion) => promotion.id),
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (customCampaignType) {
|
|
160
|
+
await customCampaignModuleService.deleteCustomCampaignTypes(
|
|
161
|
+
customCampaignType.id
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (promotionUsageLimit) {
|
|
166
|
+
await customCampaignModuleService.deletePromotionUsageLimits(
|
|
167
|
+
promotionUsageLimit.map((limit) => limit.id)
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
export const createCustomCampaignWorkflow = createWorkflow(
|
|
175
|
+
"create-custom-campaign",
|
|
176
|
+
(data: CustomCampaign) => {
|
|
177
|
+
const customCampaign = createCustomCampaignStep(data);
|
|
178
|
+
|
|
179
|
+
return new WorkflowResponse(customCampaign);
|
|
180
|
+
}
|
|
181
|
+
);
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { container } from "@medusajs/framework";
|
|
2
|
+
import {
|
|
3
|
+
CreateApplicationMethodDTO,
|
|
4
|
+
CreatePromotionDTO,
|
|
5
|
+
UpdateCampaignDTO,
|
|
6
|
+
UpdatePromotionDTO,
|
|
7
|
+
} from "@medusajs/framework/types";
|
|
8
|
+
import { MedusaError, Modules } from "@medusajs/framework/utils";
|
|
9
|
+
import {
|
|
10
|
+
createStep,
|
|
11
|
+
createWorkflow,
|
|
12
|
+
StepResponse,
|
|
13
|
+
WorkflowResponse,
|
|
14
|
+
} from "@medusajs/framework/workflows-sdk";
|
|
15
|
+
import {
|
|
16
|
+
createPromotionsWorkflow,
|
|
17
|
+
deletePromotionsWorkflow,
|
|
18
|
+
updateCampaignsWorkflow,
|
|
19
|
+
updatePromotionsWorkflow,
|
|
20
|
+
} from "@medusajs/medusa/core-flows";
|
|
21
|
+
import { CustomCampaign } from "../../api/admin/flash-sales/route";
|
|
22
|
+
import { CUSTOM_CAMPAIGN_MODULE } from "../../modules/custom-campaigns";
|
|
23
|
+
import CustomCampaignModuleService from "../../modules/custom-campaigns/service";
|
|
24
|
+
|
|
25
|
+
interface UpdateFlashSaleInput extends CustomCampaign {
|
|
26
|
+
id: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const updateCustomFlashSaleStep = createStep(
|
|
30
|
+
"update-custom-flash-sale-step",
|
|
31
|
+
async (data: UpdateFlashSaleInput) => {
|
|
32
|
+
const campaign_id = data.id;
|
|
33
|
+
|
|
34
|
+
const customCampaignModuleService =
|
|
35
|
+
container.resolve<CustomCampaignModuleService>(CUSTOM_CAMPAIGN_MODULE);
|
|
36
|
+
const promotionService = container.resolve(Modules.PROMOTION);
|
|
37
|
+
|
|
38
|
+
if (!campaign_id) {
|
|
39
|
+
throw new MedusaError(
|
|
40
|
+
MedusaError.Types.INVALID_DATA,
|
|
41
|
+
"Campaign ID is required"
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Fetch the existing campaign
|
|
46
|
+
const campaign = await promotionService.retrieveCampaign(campaign_id);
|
|
47
|
+
|
|
48
|
+
// Fetch existing promotion usage limits
|
|
49
|
+
const promotionUsageLimits =
|
|
50
|
+
await customCampaignModuleService.listPromotionUsageLimits({
|
|
51
|
+
campaign_id: campaign_id,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Create maps for existing promotions and usage limits
|
|
55
|
+
const existingPromotionUsageMapByProductId = new Map(
|
|
56
|
+
promotionUsageLimits.map((limit) => [limit.product_id, limit])
|
|
57
|
+
);
|
|
58
|
+
const promotionsToBeCreate = data.products.filter(
|
|
59
|
+
(product) => !existingPromotionUsageMapByProductId.has(product.product.id)
|
|
60
|
+
);
|
|
61
|
+
const productPromotionsToBeUpdate = data.products.filter((product) =>
|
|
62
|
+
existingPromotionUsageMapByProductId.has(product.product.id)
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const inputProductIdSet = new Set(
|
|
66
|
+
data.products.map((product) => product.product.id)
|
|
67
|
+
);
|
|
68
|
+
const promotionsToBeDelete = promotionUsageLimits.filter(
|
|
69
|
+
(limit) => !inputProductIdSet.has(limit.product_id)
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
console.log("update campaign");
|
|
73
|
+
// 1. Update the campaign details
|
|
74
|
+
await updateCampaignsWorkflow.run({
|
|
75
|
+
input: {
|
|
76
|
+
campaignsData: [
|
|
77
|
+
{
|
|
78
|
+
id: campaign_id,
|
|
79
|
+
name: data.name,
|
|
80
|
+
description: data.description,
|
|
81
|
+
starts_at: new Date(data.starts_at),
|
|
82
|
+
ends_at: new Date(data.ends_at),
|
|
83
|
+
} satisfies UpdateCampaignDTO,
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// 2.1 Update promotions to be updated
|
|
89
|
+
await promotionService.updatePromotions(
|
|
90
|
+
productPromotionsToBeUpdate.map((product) => {
|
|
91
|
+
const promotion_id =
|
|
92
|
+
existingPromotionUsageMapByProductId.get(product.product.id)
|
|
93
|
+
?.promotion_id ?? "";
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
id: promotion_id,
|
|
97
|
+
application_method: {
|
|
98
|
+
value: product.discountValue,
|
|
99
|
+
max_quantity: product.maxQty,
|
|
100
|
+
},
|
|
101
|
+
} satisfies UpdatePromotionDTO;
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// 2.2 Update promotion usage limits to be updated
|
|
106
|
+
await customCampaignModuleService.updatePromotionUsageLimits(
|
|
107
|
+
productPromotionsToBeUpdate.map((product) => ({
|
|
108
|
+
id:
|
|
109
|
+
existingPromotionUsageMapByProductId.get(product.product.id)?.id ??
|
|
110
|
+
"",
|
|
111
|
+
limit: product.limit,
|
|
112
|
+
}))
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
// 3. Delete promotions to be deleted
|
|
116
|
+
await deletePromotionsWorkflow.run({
|
|
117
|
+
input: {
|
|
118
|
+
ids: promotionsToBeDelete.map((limit) => limit.promotion_id),
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
await customCampaignModuleService.softDeletePromotionUsageLimits(
|
|
122
|
+
promotionsToBeDelete.map((limit) => limit.id)
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// 4. Create promotions to be created
|
|
126
|
+
const { result: createdPromotions } = await createPromotionsWorkflow.run({
|
|
127
|
+
input: {
|
|
128
|
+
promotionsData: promotionsToBeCreate.map(
|
|
129
|
+
(product) =>
|
|
130
|
+
({
|
|
131
|
+
code: `${campaign.campaign_identifier}-${product.product.id}`,
|
|
132
|
+
type: "standard",
|
|
133
|
+
status: "active",
|
|
134
|
+
is_automatic: true,
|
|
135
|
+
campaign_id: campaign_id,
|
|
136
|
+
application_method: {
|
|
137
|
+
target_type: "items",
|
|
138
|
+
allocation: "each",
|
|
139
|
+
type: product.discountType,
|
|
140
|
+
value: product.discountValue,
|
|
141
|
+
max_quantity: product.maxQty,
|
|
142
|
+
target_rules: [
|
|
143
|
+
{
|
|
144
|
+
attribute: "items.product.id",
|
|
145
|
+
operator: "eq",
|
|
146
|
+
values: [product.product.id],
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
} satisfies CreateApplicationMethodDTO,
|
|
150
|
+
} satisfies CreatePromotionDTO)
|
|
151
|
+
),
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
const productPromotionMap = new Map<string, string>();
|
|
155
|
+
createdPromotions.forEach((promotion) => {
|
|
156
|
+
const productId = promotion.code?.split("-").at(-1);
|
|
157
|
+
if (!productId) {
|
|
158
|
+
throw new MedusaError(
|
|
159
|
+
MedusaError.Types.INVALID_DATA,
|
|
160
|
+
"Invalid product id"
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
productPromotionMap.set(productId, promotion.id);
|
|
164
|
+
});
|
|
165
|
+
await customCampaignModuleService.createPromotionUsageLimits(
|
|
166
|
+
promotionsToBeCreate.map((product) => ({
|
|
167
|
+
campaign_id: campaign.id,
|
|
168
|
+
promotion_id: productPromotionMap.get(product.product.id) ?? "",
|
|
169
|
+
product_id: product.product.id,
|
|
170
|
+
limit: product.limit,
|
|
171
|
+
used: 0,
|
|
172
|
+
}))
|
|
173
|
+
);
|
|
174
|
+
return new StepResponse();
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
export const updateCustomFlashSaleWorkflow = createWorkflow(
|
|
179
|
+
"update-custom-flash-sale",
|
|
180
|
+
(data: UpdateFlashSaleInput) => {
|
|
181
|
+
const updatedFlashSale = updateCustomFlashSaleStep(data);
|
|
182
|
+
|
|
183
|
+
return new WorkflowResponse(updatedFlashSale);
|
|
184
|
+
}
|
|
185
|
+
);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Modules } from "@medusajs/framework/utils";
|
|
2
|
+
import {
|
|
3
|
+
createStep,
|
|
4
|
+
createWorkflow,
|
|
5
|
+
WorkflowResponse,
|
|
6
|
+
} from "@medusajs/framework/workflows-sdk";
|
|
7
|
+
import { CUSTOM_CAMPAIGN_MODULE } from "../../modules/custom-campaigns";
|
|
8
|
+
import CustomCampaignModuleService from "../../modules/custom-campaigns/service";
|
|
9
|
+
|
|
10
|
+
interface UpdatePromotionUsageInput {
|
|
11
|
+
order_id: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const updatePromotionUsageStep = createStep(
|
|
15
|
+
"update-promotion-usage-step",
|
|
16
|
+
async ({ order_id }: UpdatePromotionUsageInput, { container }) => {
|
|
17
|
+
const orderService = await container.resolve(Modules.ORDER);
|
|
18
|
+
|
|
19
|
+
const promotionService = await container.resolve(Modules.PROMOTION);
|
|
20
|
+
const customCampaignTypeService =
|
|
21
|
+
container.resolve<CustomCampaignModuleService>(CUSTOM_CAMPAIGN_MODULE);
|
|
22
|
+
|
|
23
|
+
const order = await orderService.retrieveOrder(order_id, {
|
|
24
|
+
relations: ["items.adjustments"],
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const promotionSet = new Set(
|
|
28
|
+
order.items
|
|
29
|
+
?.map((item) =>
|
|
30
|
+
item.adjustments?.map((adjustment) => adjustment.promotion_id)
|
|
31
|
+
)
|
|
32
|
+
.flat()
|
|
33
|
+
);
|
|
34
|
+
const promotionIds = Array.from(promotionSet);
|
|
35
|
+
const promotionUsageLimits =
|
|
36
|
+
await customCampaignTypeService.listPromotionUsageLimits({
|
|
37
|
+
promotion_id: promotionIds,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const updatePromotionUsagePayload = promotionUsageLimits.map((limit) => ({
|
|
41
|
+
...limit,
|
|
42
|
+
used: limit.used + 1,
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
const limitReachedPromotions = updatePromotionUsagePayload.filter(
|
|
46
|
+
(limit) => limit.used >= limit.limit
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
if (limitReachedPromotions.length > 0) {
|
|
50
|
+
await promotionService.updatePromotions(
|
|
51
|
+
limitReachedPromotions.map((limit) => ({
|
|
52
|
+
id: limit.promotion_id,
|
|
53
|
+
status: "inactive",
|
|
54
|
+
}))
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
await customCampaignTypeService.updatePromotionUsageLimits(
|
|
59
|
+
updatePromotionUsagePayload
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
export const updatePromotionUsageWorkflow = createWorkflow(
|
|
65
|
+
"update-promotion-usage",
|
|
66
|
+
(data: UpdatePromotionUsageInput) => {
|
|
67
|
+
updatePromotionUsageStep(data);
|
|
68
|
+
return new WorkflowResponse({ success: true });
|
|
69
|
+
}
|
|
70
|
+
);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deleteCampaignsWorkflow,
|
|
3
|
+
deletePromotionsWorkflow
|
|
4
|
+
} from "@medusajs/medusa/core-flows";
|
|
5
|
+
import { CUSTOM_CAMPAIGN_MODULE } from "../../modules/custom-campaigns";
|
|
6
|
+
import CustomCampaignModuleService from "../../modules/custom-campaigns/service";
|
|
7
|
+
|
|
8
|
+
deleteCampaignsWorkflow.hooks.campaignsDeleted(
|
|
9
|
+
async ({ ids }, { container }) => {
|
|
10
|
+
const customCampaignModuleService =
|
|
11
|
+
container.resolve<CustomCampaignModuleService>(CUSTOM_CAMPAIGN_MODULE);
|
|
12
|
+
|
|
13
|
+
const promotionLimits =
|
|
14
|
+
await customCampaignModuleService.listPromotionUsageLimits(
|
|
15
|
+
{
|
|
16
|
+
campaign_id: ids,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
select: ["id", "promotion_id"],
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
await deletePromotionsWorkflow.run({
|
|
24
|
+
input: {
|
|
25
|
+
ids: promotionLimits.map((limit) => limit.promotion_id),
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
await customCampaignModuleService.softDeletePromotionUsageLimits(
|
|
30
|
+
promotionLimits.map((limit) => limit.id)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const customCampaignIds =
|
|
34
|
+
await customCampaignModuleService.listCustomCampaignTypes(
|
|
35
|
+
{
|
|
36
|
+
campaign_id: Array.from(
|
|
37
|
+
new Set(promotionLimits.map((limit) => limit.campaign_id))
|
|
38
|
+
),
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
select: ["id"],
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
await customCampaignModuleService.softDeleteCustomCampaignTypes(
|
|
46
|
+
customCampaignIds.map((campaign) => campaign.id)
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
);
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { createCustomFlashSaleWorkflow } from "./custom-campaign/createCustomCampaignWorkflow";
|
|
2
|
+
export { updateCustomFlashSaleWorkflow } from "./custom-campaign/updateCustomFlashSaleWorkflow";
|
|
3
|
+
export { updatePromotionUsageWorkflow } from "./custom-campaign/updatePromotionUsageWorkflow";
|