@lodashventure/medusa-campaign 1.3.11 → 1.3.13
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 +3031 -6990
- package/.medusa/server/src/admin/index.mjs +3016 -6977
- package/.medusa/server/src/api/admin/campaigns/[id]/detail/route.js +67 -0
- package/.medusa/server/src/api/admin/campaigns/[id]/image/route.js +80 -0
- package/.medusa/server/src/api/admin/campaigns/[id]/thumbnail/route.js +80 -0
- package/.medusa/server/src/api/admin/campaigns/sync/route.js +8 -6
- package/.medusa/server/src/api/admin/flash-sales/[id]/route.js +22 -4
- package/.medusa/server/src/api/middlewares.js +24 -1
- package/.medusa/server/src/api/store/buy-x-get-y/[id]/route.js +1 -1
- package/.medusa/server/src/api/store/buy-x-get-y/products/[productId]/route.js +1 -1
- package/.medusa/server/src/api/store/buy-x-get-y/route.js +3 -1
- package/.medusa/server/src/api/store/campaigns/[id]/route.js +40 -12
- package/.medusa/server/src/modules/custom-campaigns/migrations/Migration20251024000000.js +53 -0
- package/.medusa/server/src/modules/custom-campaigns/migrations/Migration20251025000000.js +22 -0
- package/.medusa/server/src/modules/custom-campaigns/models/campaign-detail.js +26 -0
- package/.medusa/server/src/modules/custom-campaigns/service.js +3 -1
- package/.medusa/server/src/subscribers/order-placed.js +2 -2
- package/.medusa/server/src/workflows/buy-x-get-y/applyBuyXGetYToCartWorkflow.js +16 -4
- package/.medusa/server/src/workflows/campaign-detail/update-campaign-detail.js +55 -0
- package/.medusa/server/src/workflows/campaign-detail/upload-campaign-images.js +120 -0
- package/.medusa/server/src/workflows/custom-campaign/createBuyXGetYCampaignWorkflow.js +13 -14
- package/.medusa/server/src/workflows/index.js +6 -3
- package/package.json +23 -19
- package/src/admin/components/campaign-detail-form.tsx +407 -0
- package/src/admin/components/campaign-image-uploader.tsx +313 -0
- package/src/admin/components/markdown-editor.tsx +298 -0
- package/src/admin/routes/flash-sales/[id]/page.tsx +51 -14
- package/src/admin/widgets/campaign-detail-widget.tsx +299 -0
- package/src/admin/widgets/campaign-stats-widget.tsx +238 -0
- package/src/api/admin/campaigns/[id]/detail/route.ts +77 -0
- package/src/api/admin/campaigns/[id]/image/route.ts +87 -0
- package/src/api/admin/campaigns/[id]/thumbnail/route.ts +87 -0
- package/src/api/admin/campaigns/sync/route.ts +53 -28
- package/src/api/admin/flash-sales/[id]/route.ts +50 -19
- package/src/api/middlewares.ts +21 -0
- package/src/api/store/buy-x-get-y/[id]/route.ts +10 -10
- package/src/api/store/buy-x-get-y/products/[productId]/route.ts +11 -12
- package/src/api/store/buy-x-get-y/route.ts +12 -5
- package/src/api/store/campaigns/[id]/route.ts +54 -24
- package/src/modules/custom-campaigns/migrations/Migration20251024000000.ts +53 -0
- package/src/modules/custom-campaigns/migrations/Migration20251025000000.ts +19 -0
- package/src/modules/custom-campaigns/models/campaign-detail.ts +25 -0
- package/src/modules/custom-campaigns/service.ts +2 -0
- package/src/subscribers/order-placed.ts +0 -2
- package/src/types/index.d.ts +46 -0
- package/src/workflows/buy-x-get-y/applyBuyXGetYToCartWorkflow.ts +41 -18
- package/src/workflows/campaign-detail/update-campaign-detail.ts +85 -0
- package/src/workflows/campaign-detail/upload-campaign-images.ts +163 -0
- package/src/workflows/custom-campaign/createBuyXGetYCampaignWorkflow.ts +23 -22
- package/src/workflows/index.ts +3 -2
- package/.medusa/server/src/api/admin/campaigns/fix-dates/route.js +0 -103
- package/.medusa/server/src/api/admin/force-fix/route.js +0 -176
- package/.medusa/server/src/api/admin/test-campaign/route.js +0 -132
- package/src/api/admin/campaigns/fix-dates/route.ts +0 -107
- package/src/api/admin/force-fix/route.ts +0 -184
- package/src/api/admin/test-campaign/route.ts +0 -141
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createStep,
|
|
3
|
+
createWorkflow,
|
|
4
|
+
StepResponse,
|
|
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
|
+
import {
|
|
10
|
+
deleteFilesWorkflow,
|
|
11
|
+
uploadFilesWorkflow,
|
|
12
|
+
UploadFilesWorkflowInput,
|
|
13
|
+
} from "@medusajs/medusa/core-flows";
|
|
14
|
+
|
|
15
|
+
type UploadCampaignImagesWorkflowInput = {
|
|
16
|
+
campaign_id: string;
|
|
17
|
+
files: UploadFilesWorkflowInput["files"];
|
|
18
|
+
image_type: "image" | "thumbnail";
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const uploadCampaignImagesStep = createStep(
|
|
22
|
+
"upload-campaign-images",
|
|
23
|
+
async (
|
|
24
|
+
{ campaign_id, files, image_type }: UploadCampaignImagesWorkflowInput,
|
|
25
|
+
{ container },
|
|
26
|
+
) => {
|
|
27
|
+
const logger = container.resolve("logger");
|
|
28
|
+
const customCampaignModuleService: CustomCampaignModuleService =
|
|
29
|
+
container.resolve(CUSTOM_CAMPAIGN_MODULE);
|
|
30
|
+
|
|
31
|
+
if (files.length === 0) {
|
|
32
|
+
throw new Error("at least 1 file is required");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
logger.info(`Uploading ${files.length} campaign ${image_type}(s)`);
|
|
36
|
+
|
|
37
|
+
const { result } = await uploadFilesWorkflow(container).run({
|
|
38
|
+
input: {
|
|
39
|
+
files: files.map((file) => ({
|
|
40
|
+
...file,
|
|
41
|
+
filename: `campaign-${campaign_id}-${image_type}-${file.filename.replace(/ /g, "_")}`,
|
|
42
|
+
})),
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (result.some((file) => !file.id || !file.url)) {
|
|
47
|
+
throw new Error(`some files don't have an id or url`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Decode the URL to fix path separators (%2F -> /)
|
|
51
|
+
const decodedUrl = decodeURIComponent(result[0].url);
|
|
52
|
+
|
|
53
|
+
// Get or create campaign detail
|
|
54
|
+
const [existingDetail] =
|
|
55
|
+
await customCampaignModuleService.listCampaignDetails({
|
|
56
|
+
campaign_id,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
let campaignDetail;
|
|
60
|
+
|
|
61
|
+
if (existingDetail) {
|
|
62
|
+
// Delete old image if exists
|
|
63
|
+
const oldFileId =
|
|
64
|
+
image_type === "image"
|
|
65
|
+
? existingDetail.image_file_id
|
|
66
|
+
: existingDetail.thumbnail_file_id;
|
|
67
|
+
|
|
68
|
+
if (oldFileId) {
|
|
69
|
+
try {
|
|
70
|
+
await deleteFilesWorkflow(container).run({
|
|
71
|
+
input: {
|
|
72
|
+
ids: [oldFileId],
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
} catch (error) {
|
|
76
|
+
logger.warn(`Failed to delete old ${image_type} file: ${oldFileId}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Update existing detail
|
|
81
|
+
const updateData =
|
|
82
|
+
image_type === "image"
|
|
83
|
+
? {
|
|
84
|
+
id: existingDetail.id,
|
|
85
|
+
image_url: decodedUrl,
|
|
86
|
+
image_file_id: result[0].id,
|
|
87
|
+
}
|
|
88
|
+
: {
|
|
89
|
+
id: existingDetail.id,
|
|
90
|
+
thumbnail_url: decodedUrl,
|
|
91
|
+
thumbnail_file_id: result[0].id,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const updated = await customCampaignModuleService.updateCampaignDetails([
|
|
95
|
+
updateData,
|
|
96
|
+
]);
|
|
97
|
+
campaignDetail = updated[0];
|
|
98
|
+
} else {
|
|
99
|
+
// Create new detail
|
|
100
|
+
const createData =
|
|
101
|
+
image_type === "image"
|
|
102
|
+
? {
|
|
103
|
+
campaign_id,
|
|
104
|
+
image_url: decodedUrl,
|
|
105
|
+
image_file_id: result[0].id,
|
|
106
|
+
}
|
|
107
|
+
: {
|
|
108
|
+
campaign_id,
|
|
109
|
+
thumbnail_url: decodedUrl,
|
|
110
|
+
thumbnail_file_id: result[0].id,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
campaignDetail =
|
|
114
|
+
await customCampaignModuleService.createCampaignDetails(createData);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return new StepResponse(campaignDetail, {
|
|
118
|
+
fileId: result[0].id,
|
|
119
|
+
oldDetail: existingDetail,
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
async (rollbackData, { container }) => {
|
|
123
|
+
const logger = container.resolve("logger");
|
|
124
|
+
const customCampaignModuleService: CustomCampaignModuleService =
|
|
125
|
+
container.resolve(CUSTOM_CAMPAIGN_MODULE);
|
|
126
|
+
|
|
127
|
+
if (rollbackData) {
|
|
128
|
+
// Delete the newly uploaded file
|
|
129
|
+
try {
|
|
130
|
+
await deleteFilesWorkflow(container).run({
|
|
131
|
+
input: {
|
|
132
|
+
ids: [rollbackData.fileId],
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
} catch (error) {
|
|
136
|
+
logger.warn(
|
|
137
|
+
`Failed to delete file during rollback: ${rollbackData.fileId}`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Restore old detail if existed
|
|
142
|
+
if (rollbackData.oldDetail) {
|
|
143
|
+
try {
|
|
144
|
+
await customCampaignModuleService.updateCampaignDetails([
|
|
145
|
+
{
|
|
146
|
+
...rollbackData.oldDetail,
|
|
147
|
+
},
|
|
148
|
+
]);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
logger.warn("Failed to restore old campaign detail during rollback");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
export const uploadCampaignImagesWorkflow = createWorkflow(
|
|
158
|
+
"upload-campaign-images",
|
|
159
|
+
(input: UploadCampaignImagesWorkflowInput) => {
|
|
160
|
+
const detail = uploadCampaignImagesStep(input);
|
|
161
|
+
return new WorkflowResponse(detail);
|
|
162
|
+
},
|
|
163
|
+
);
|
|
@@ -106,8 +106,10 @@ const createBuyXGetYCampaignStep = createStep(
|
|
|
106
106
|
application_method: {
|
|
107
107
|
target_type: "items",
|
|
108
108
|
allocation: "each",
|
|
109
|
-
type:
|
|
110
|
-
|
|
109
|
+
type:
|
|
110
|
+
rule.rewardType === "percentage" ? "percentage" : "fixed",
|
|
111
|
+
value:
|
|
112
|
+
rule.rewardType === "free" ? 0 : (rule.rewardValue ?? 0),
|
|
111
113
|
buy_rules_min_quantity: rule.triggerQuantity,
|
|
112
114
|
apply_to_quantity: rule.rewardQuantity,
|
|
113
115
|
target_rules: [
|
|
@@ -118,7 +120,7 @@ const createBuyXGetYCampaignStep = createStep(
|
|
|
118
120
|
},
|
|
119
121
|
],
|
|
120
122
|
} satisfies CreateApplicationMethodDTO,
|
|
121
|
-
} satisfies CreatePromotionDTO
|
|
123
|
+
}) satisfies CreatePromotionDTO,
|
|
122
124
|
),
|
|
123
125
|
},
|
|
124
126
|
});
|
|
@@ -132,21 +134,20 @@ const createBuyXGetYCampaignStep = createStep(
|
|
|
132
134
|
});
|
|
133
135
|
|
|
134
136
|
// Create Buy X Get Y configurations
|
|
135
|
-
buyXGetYConfigs =
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
);
|
|
137
|
+
buyXGetYConfigs = await customCampaignModuleService.createBuyXGetYConfigs(
|
|
138
|
+
data.rules.map((rule, index) => ({
|
|
139
|
+
campaign_id: campaign.id,
|
|
140
|
+
promotion_id: promotions![index].id,
|
|
141
|
+
trigger_product_id: rule.triggerProduct.id,
|
|
142
|
+
trigger_quantity: rule.triggerQuantity,
|
|
143
|
+
reward_product_id: rule.rewardProduct.id,
|
|
144
|
+
reward_quantity: rule.rewardQuantity,
|
|
145
|
+
reward_type: rule.rewardType,
|
|
146
|
+
reward_value: rule.rewardValue ?? null,
|
|
147
|
+
limit: rule.limit ?? null,
|
|
148
|
+
used: 0,
|
|
149
|
+
})),
|
|
150
|
+
);
|
|
150
151
|
|
|
151
152
|
// Link campaign type
|
|
152
153
|
await link.create([
|
|
@@ -185,19 +186,19 @@ const createBuyXGetYCampaignStep = createStep(
|
|
|
185
186
|
|
|
186
187
|
if (customCampaignType) {
|
|
187
188
|
await customCampaignModuleService.deleteCustomCampaignTypes(
|
|
188
|
-
customCampaignType.id
|
|
189
|
+
customCampaignType.id,
|
|
189
190
|
);
|
|
190
191
|
}
|
|
191
192
|
|
|
192
193
|
if (buyXGetYConfigs) {
|
|
193
194
|
await customCampaignModuleService.deleteBuyXGetYConfigs(
|
|
194
|
-
buyXGetYConfigs.map((config) => config.id)
|
|
195
|
+
buyXGetYConfigs.map((config) => config.id),
|
|
195
196
|
);
|
|
196
197
|
}
|
|
197
198
|
|
|
198
199
|
throw error;
|
|
199
200
|
}
|
|
200
|
-
}
|
|
201
|
+
},
|
|
201
202
|
);
|
|
202
203
|
|
|
203
204
|
export const createBuyXGetYCampaignWorkflow = createWorkflow(
|
|
@@ -206,5 +207,5 @@ export const createBuyXGetYCampaignWorkflow = createWorkflow(
|
|
|
206
207
|
const campaign = createBuyXGetYCampaignStep(data);
|
|
207
208
|
|
|
208
209
|
return new WorkflowResponse(campaign);
|
|
209
|
-
}
|
|
210
|
+
},
|
|
210
211
|
);
|
package/src/workflows/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { createCustomFlashSaleWorkflow } from "./custom-campaign/createCustomCampaignWorkflow";
|
|
1
|
+
export { createCustomCampaignWorkflow, createCustomCampaignWorkflow as createCustomFlashSaleWorkflow } from "./custom-campaign/createCustomCampaignWorkflow";
|
|
2
2
|
export { updateCustomFlashSaleWorkflow } from "./custom-campaign/updateCustomFlashSaleWorkflow";
|
|
3
|
-
export { updatePromotionUsageWorkflow } from "./custom-campaign/updatePromotionUsageWorkflow";
|
|
3
|
+
export { updatePromotionUsageWorkflow } from "./custom-campaign/updatePromotionUsageWorkflow";
|
|
4
|
+
export { applyBuyXGetYToCartWorkflow } from "./buy-x-get-y/applyBuyXGetYToCartWorkflow";
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GET = exports.POST = void 0;
|
|
4
|
-
const framework_1 = require("@medusajs/framework");
|
|
5
|
-
const utils_1 = require("@medusajs/framework/utils");
|
|
6
|
-
const core_flows_1 = require("@medusajs/medusa/core-flows");
|
|
7
|
-
/**
|
|
8
|
-
* POST handler to fix campaign dates - makes all campaigns active for testing
|
|
9
|
-
*/
|
|
10
|
-
const POST = async (req, res) => {
|
|
11
|
-
const promotionService = framework_1.container.resolve(utils_1.Modules.PROMOTION);
|
|
12
|
-
try {
|
|
13
|
-
// Get all campaigns
|
|
14
|
-
const allCampaigns = await promotionService.listCampaigns({});
|
|
15
|
-
console.log(`Found ${allCampaigns.length} campaigns to fix`);
|
|
16
|
-
const updatedCampaigns = [];
|
|
17
|
-
// Update each campaign to be active for the whole year
|
|
18
|
-
for (const campaign of allCampaigns) {
|
|
19
|
-
try {
|
|
20
|
-
const result = await core_flows_1.updateCampaignsWorkflow.run({
|
|
21
|
-
input: {
|
|
22
|
-
campaignsData: [
|
|
23
|
-
{
|
|
24
|
-
id: campaign.id,
|
|
25
|
-
starts_at: new Date("2024-01-01T00:00:00Z"),
|
|
26
|
-
ends_at: new Date("2025-12-31T23:59:59Z"),
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
updatedCampaigns.push({
|
|
32
|
-
id: campaign.id,
|
|
33
|
-
name: campaign.name,
|
|
34
|
-
old_starts_at: campaign.starts_at,
|
|
35
|
-
old_ends_at: campaign.ends_at,
|
|
36
|
-
new_starts_at: "2024-01-01T00:00:00Z",
|
|
37
|
-
new_ends_at: "2025-12-31T23:59:59Z",
|
|
38
|
-
});
|
|
39
|
-
console.log(`✅ Fixed dates for campaign: ${campaign.name}`);
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
console.error(`❌ Failed to update campaign ${campaign.id}:`, error);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
res.status(200).json({
|
|
46
|
-
success: true,
|
|
47
|
-
message: `Updated ${updatedCampaigns.length} campaigns`,
|
|
48
|
-
campaigns: updatedCampaigns,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
console.error("Error fixing campaign dates:", error);
|
|
53
|
-
res.status(500).json({
|
|
54
|
-
error: "Failed to fix campaign dates",
|
|
55
|
-
details: error instanceof Error ? error.message : String(error),
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
exports.POST = POST;
|
|
60
|
-
/**
|
|
61
|
-
* GET handler to show current campaign dates
|
|
62
|
-
*/
|
|
63
|
-
const GET = async (req, res) => {
|
|
64
|
-
const promotionService = framework_1.container.resolve(utils_1.Modules.PROMOTION);
|
|
65
|
-
const now = new Date();
|
|
66
|
-
try {
|
|
67
|
-
const allCampaigns = await promotionService.listCampaigns({});
|
|
68
|
-
const campaignDates = allCampaigns.map((campaign) => {
|
|
69
|
-
const startsAt = new Date(campaign.starts_at);
|
|
70
|
-
const endsAt = new Date(campaign.ends_at);
|
|
71
|
-
const isActive = startsAt <= now && endsAt >= now;
|
|
72
|
-
return {
|
|
73
|
-
id: campaign.id,
|
|
74
|
-
name: campaign.name,
|
|
75
|
-
starts_at: campaign.starts_at,
|
|
76
|
-
ends_at: campaign.ends_at,
|
|
77
|
-
isActive,
|
|
78
|
-
reason: !isActive
|
|
79
|
-
? (startsAt > now ? "Not started yet" : "Already ended")
|
|
80
|
-
: "Active",
|
|
81
|
-
};
|
|
82
|
-
});
|
|
83
|
-
res.status(200).json({
|
|
84
|
-
currentTime: now.toISOString(),
|
|
85
|
-
campaigns: campaignDates,
|
|
86
|
-
summary: {
|
|
87
|
-
total: campaignDates.length,
|
|
88
|
-
active: campaignDates.filter((c) => c.isActive).length,
|
|
89
|
-
notStarted: campaignDates.filter((c) => c.reason === "Not started yet").length,
|
|
90
|
-
ended: campaignDates.filter((c) => c.reason === "Already ended").length,
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
catch (error) {
|
|
95
|
-
console.error("Error checking campaign dates:", error);
|
|
96
|
-
res.status(500).json({
|
|
97
|
-
error: "Failed to check campaign dates",
|
|
98
|
-
details: error instanceof Error ? error.message : String(error),
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
exports.GET = GET;
|
|
103
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2NhbXBhaWducy9maXgtZGF0ZXMvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbURBQStFO0FBQy9FLHFEQUFvRDtBQUNwRCw0REFBc0U7QUFFdEU7O0dBRUc7QUFDSSxNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsR0FBa0IsRUFBRSxHQUFtQixFQUFFLEVBQUU7SUFDcEUsTUFBTSxnQkFBZ0IsR0FBRyxxQkFBUyxDQUFDLE9BQU8sQ0FBQyxlQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7SUFFOUQsSUFBSSxDQUFDO1FBQ0gsb0JBQW9CO1FBQ3BCLE1BQU0sWUFBWSxHQUFHLE1BQU0sZ0JBQWdCLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRTlELE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxZQUFZLENBQUMsTUFBTSxtQkFBbUIsQ0FBQyxDQUFDO1FBRTdELE1BQU0sZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO1FBRTVCLHVEQUF1RDtRQUN2RCxLQUFLLE1BQU0sUUFBUSxJQUFJLFlBQVksRUFBRSxDQUFDO1lBQ3BDLElBQUksQ0FBQztnQkFDSCxNQUFNLE1BQU0sR0FBRyxNQUFNLG9DQUF1QixDQUFDLEdBQUcsQ0FBQztvQkFDL0MsS0FBSyxFQUFFO3dCQUNMLGFBQWEsRUFBRTs0QkFDYjtnQ0FDRSxFQUFFLEVBQUUsUUFBUSxDQUFDLEVBQUU7Z0NBQ2YsU0FBUyxFQUFFLElBQUksSUFBSSxDQUFDLHNCQUFzQixDQUFDO2dDQUMzQyxPQUFPLEVBQUUsSUFBSSxJQUFJLENBQUMsc0JBQXNCLENBQUM7NkJBQzFDO3lCQUNGO3FCQUNGO2lCQUNGLENBQUMsQ0FBQztnQkFFSCxnQkFBZ0IsQ0FBQyxJQUFJLENBQUM7b0JBQ3BCLEVBQUUsRUFBRSxRQUFRLENBQUMsRUFBRTtvQkFDZixJQUFJLEVBQUUs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
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.POST = void 0;
|
|
4
|
-
const framework_1 = require("@medusajs/framework");
|
|
5
|
-
const utils_1 = require("@medusajs/framework/utils");
|
|
6
|
-
const core_flows_1 = require("@medusajs/medusa/core-flows");
|
|
7
|
-
const campaign_type_enum_1 = require("../../../modules/custom-campaigns/types/campaign-type.enum");
|
|
8
|
-
/**
|
|
9
|
-
* POST handler to force fix all campaigns in one go
|
|
10
|
-
* This will sync types and fix dates
|
|
11
|
-
*/
|
|
12
|
-
const POST = async (req, res) => {
|
|
13
|
-
const promotionService = framework_1.container.resolve(utils_1.Modules.PROMOTION);
|
|
14
|
-
const results = {
|
|
15
|
-
timestamp: new Date().toISOString(),
|
|
16
|
-
steps: []
|
|
17
|
-
};
|
|
18
|
-
try {
|
|
19
|
-
// Step 1: Get all campaigns
|
|
20
|
-
const allCampaigns = await promotionService.listCampaigns({});
|
|
21
|
-
results.steps.push({
|
|
22
|
-
step: "Get campaigns",
|
|
23
|
-
status: "✅",
|
|
24
|
-
count: allCampaigns.length
|
|
25
|
-
});
|
|
26
|
-
if (allCampaigns.length === 0) {
|
|
27
|
-
return res.status(200).json({
|
|
28
|
-
...results,
|
|
29
|
-
message: "No campaigns found to fix"
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
// Step 2: Try to get custom campaign module
|
|
33
|
-
let customModule;
|
|
34
|
-
try {
|
|
35
|
-
customModule = framework_1.container.resolve("customCampaign");
|
|
36
|
-
results.steps.push({
|
|
37
|
-
step: "Resolve custom module",
|
|
38
|
-
status: "✅"
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
results.steps.push({
|
|
43
|
-
step: "Resolve custom module",
|
|
44
|
-
status: "❌",
|
|
45
|
-
message: "Module not available - creating types manually"
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
// Step 3: Fix dates for all campaigns
|
|
49
|
-
const dateFixResults = [];
|
|
50
|
-
for (const campaign of allCampaigns) {
|
|
51
|
-
try {
|
|
52
|
-
await core_flows_1.updateCampaignsWorkflow.run({
|
|
53
|
-
input: {
|
|
54
|
-
campaignsData: [{
|
|
55
|
-
id: campaign.id,
|
|
56
|
-
starts_at: new Date("2024-01-01T00:00:00Z"),
|
|
57
|
-
ends_at: new Date("2025-12-31T23:59:59Z")
|
|
58
|
-
}]
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
dateFixResults.push({
|
|
62
|
-
id: campaign.id,
|
|
63
|
-
name: campaign.name,
|
|
64
|
-
status: "✅ Dates fixed"
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
catch (e) {
|
|
68
|
-
dateFixResults.push({
|
|
69
|
-
id: campaign.id,
|
|
70
|
-
name: campaign.name,
|
|
71
|
-
status: "❌ Failed",
|
|
72
|
-
error: e instanceof Error ? e.message : String(e)
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
results.steps.push({
|
|
77
|
-
step: "Fix campaign dates",
|
|
78
|
-
status: "✅",
|
|
79
|
-
fixed: dateFixResults.filter(r => r.status.includes("✅")).length,
|
|
80
|
-
failed: dateFixResults.filter(r => r.status.includes("❌")).length,
|
|
81
|
-
details: dateFixResults
|
|
82
|
-
});
|
|
83
|
-
// Step 4: Create custom types if module is available
|
|
84
|
-
if (customModule) {
|
|
85
|
-
const existingTypes = await customModule.listCustomCampaignTypes({});
|
|
86
|
-
const existingCampaignIds = new Set(existingTypes.map((t) => t.campaign_id));
|
|
87
|
-
const typeCreationResults = [];
|
|
88
|
-
for (const campaign of allCampaigns) {
|
|
89
|
-
if (existingCampaignIds.has(campaign.id)) {
|
|
90
|
-
typeCreationResults.push({
|
|
91
|
-
id: campaign.id,
|
|
92
|
-
name: campaign.name,
|
|
93
|
-
status: "⏭️ Already has type"
|
|
94
|
-
});
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
try {
|
|
98
|
-
// Determine type based on name
|
|
99
|
-
const type = campaign.name?.toLowerCase().includes("bogo") ||
|
|
100
|
-
campaign.name?.toLowerCase().includes("buy") && campaign.name?.toLowerCase().includes("get")
|
|
101
|
-
? campaign_type_enum_1.CampaignTypeEnum.BuyXGetY
|
|
102
|
-
: campaign_type_enum_1.CampaignTypeEnum.FlashSale;
|
|
103
|
-
await customModule.createCustomCampaignTypes({
|
|
104
|
-
campaign_id: campaign.id,
|
|
105
|
-
type: type
|
|
106
|
-
});
|
|
107
|
-
typeCreationResults.push({
|
|
108
|
-
id: campaign.id,
|
|
109
|
-
name: campaign.name,
|
|
110
|
-
type: type,
|
|
111
|
-
status: "✅ Type created"
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
catch (e) {
|
|
115
|
-
typeCreationResults.push({
|
|
116
|
-
id: campaign.id,
|
|
117
|
-
name: campaign.name,
|
|
118
|
-
status: "❌ Failed",
|
|
119
|
-
error: e instanceof Error ? e.message : String(e)
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
results.steps.push({
|
|
124
|
-
step: "Create custom types",
|
|
125
|
-
status: "✅",
|
|
126
|
-
created: typeCreationResults.filter(r => r.status.includes("✅")).length,
|
|
127
|
-
skipped: typeCreationResults.filter(r => r.status.includes("⏭️")).length,
|
|
128
|
-
failed: typeCreationResults.filter(r => r.status.includes("❌")).length,
|
|
129
|
-
details: typeCreationResults
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
// Step 5: Direct database update as fallback
|
|
133
|
-
if (!customModule) {
|
|
134
|
-
try {
|
|
135
|
-
const db = framework_1.container.resolve("__pg_connection__");
|
|
136
|
-
for (const campaign of allCampaigns) {
|
|
137
|
-
const type = campaign.name?.toLowerCase().includes("bogo") ||
|
|
138
|
-
campaign.name?.toLowerCase().includes("buy") && campaign.name?.toLowerCase().includes("get")
|
|
139
|
-
? "buy-x-get-y"
|
|
140
|
-
: "flash-sale";
|
|
141
|
-
await db.raw(`
|
|
142
|
-
INSERT INTO custom_campaign_type (id, campaign_id, type, created_at, updated_at)
|
|
143
|
-
VALUES (?, ?, ?, NOW(), NOW())
|
|
144
|
-
ON CONFLICT (campaign_id) WHERE deleted_at IS NULL
|
|
145
|
-
DO UPDATE SET type = EXCLUDED.type, updated_at = NOW()
|
|
146
|
-
`, [`cct_${Date.now()}_${campaign.id}`, campaign.id, type]);
|
|
147
|
-
}
|
|
148
|
-
results.steps.push({
|
|
149
|
-
step: "Direct DB insert for custom types",
|
|
150
|
-
status: "✅"
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
catch (e) {
|
|
154
|
-
results.steps.push({
|
|
155
|
-
step: "Direct DB insert for custom types",
|
|
156
|
-
status: "❌",
|
|
157
|
-
error: e instanceof Error ? e.message : String(e)
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
results.success = true;
|
|
162
|
-
results.message = "Force fix completed";
|
|
163
|
-
res.status(200).json(results);
|
|
164
|
-
}
|
|
165
|
-
catch (error) {
|
|
166
|
-
res.status(500).json({
|
|
167
|
-
...results,
|
|
168
|
-
success: false,
|
|
169
|
-
error: "Failed to force fix campaigns",
|
|
170
|
-
details: error instanceof Error ? error.message : String(error),
|
|
171
|
-
stack: error instanceof Error ? error.stack : undefined
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
exports.POST = POST;
|
|
176
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2ZvcmNlLWZpeC9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxtREFBK0U7QUFDL0UscURBQW9EO0FBQ3BELDREQUFzRTtBQUN0RSxtR0FBOEY7QUFFOUY7OztHQUdHO0FBQ0ksTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3BFLE1BQU0sZ0JBQWdCLEdBQUcscUJBQVMsQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzlELE1BQU0sT0FBTyxHQUFRO1FBQ25CLFNBQVMsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRTtRQUNuQyxLQUFLLEVBQUUsRUFBRTtLQUNWLENBQUM7SUFFRixJQUFJLENBQUM7UUFDSCw0QkFBNEI7UUFDNUIsTUFBTSxZQUFZLEdBQUcsTUFBTSxnQkFBZ0IsQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDOUQsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7WUFDakIsSUFBSSxFQUFFLGVBQWU7WUFDckIsTUFBTSxFQUFFLEdBQUc7WUFDWCxLQUFLLEVBQUUsWUFBWSxDQUFDLE1BQU07U0FDM0IsQ0FBQyxDQUFDO1FBRUgsSUFBSSxZQUFZLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzlCLE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7Z0JBQzFCLEdBQUcsT0FBTztnQkFDVixPQUFPLEVBQUUsMkJBQTJCO2FBQ3JDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFFRCw0Q0FBNEM7UUFDNUMsSUFBSSxZQUFpQixDQUFDO1FBQ3RCLElBQUksQ0FBQztZQUNILFlBQVksR0FBRyxxQkFBUyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0Is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
|