@lodashventure/medusa-campaign 1.3.12 → 1.4.0

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.
Files changed (54) hide show
  1. package/.medusa/server/src/admin/index.js +1238 -16
  2. package/.medusa/server/src/admin/index.mjs +1240 -18
  3. package/.medusa/server/src/api/admin/campaigns/[id]/detail/route.js +67 -0
  4. package/.medusa/server/src/api/admin/campaigns/[id]/image/route.js +80 -0
  5. package/.medusa/server/src/api/admin/campaigns/[id]/thumbnail/route.js +80 -0
  6. package/.medusa/server/src/api/admin/campaigns/sync/route.js +8 -6
  7. package/.medusa/server/src/api/admin/flash-sales/[id]/route.js +22 -4
  8. package/.medusa/server/src/api/middlewares.js +24 -1
  9. package/.medusa/server/src/api/store/buy-x-get-y/[id]/route.js +1 -1
  10. package/.medusa/server/src/api/store/buy-x-get-y/products/[productId]/route.js +1 -1
  11. package/.medusa/server/src/api/store/buy-x-get-y/route.js +3 -1
  12. package/.medusa/server/src/api/store/campaigns/[id]/route.js +40 -12
  13. package/.medusa/server/src/modules/custom-campaigns/migrations/Migration20251024000000.js +53 -0
  14. package/.medusa/server/src/modules/custom-campaigns/migrations/Migration20251025000000.js +22 -0
  15. package/.medusa/server/src/modules/custom-campaigns/models/campaign-detail.js +26 -0
  16. package/.medusa/server/src/modules/custom-campaigns/service.js +3 -1
  17. package/.medusa/server/src/subscribers/order-placed.js +2 -2
  18. package/.medusa/server/src/workflows/buy-x-get-y/applyBuyXGetYToCartWorkflow.js +16 -4
  19. package/.medusa/server/src/workflows/campaign-detail/update-campaign-detail.js +55 -0
  20. package/.medusa/server/src/workflows/campaign-detail/upload-campaign-images.js +120 -0
  21. package/.medusa/server/src/workflows/custom-campaign/createBuyXGetYCampaignWorkflow.js +13 -14
  22. package/package.json +7 -5
  23. package/src/admin/components/campaign-detail-form.tsx +407 -0
  24. package/src/admin/components/campaign-image-uploader.tsx +313 -0
  25. package/src/admin/components/markdown-editor.tsx +298 -0
  26. package/src/admin/routes/flash-sales/[id]/page.tsx +51 -14
  27. package/src/admin/widgets/campaign-detail-widget.tsx +299 -0
  28. package/src/admin/widgets/campaign-stats-widget.tsx +238 -0
  29. package/src/api/admin/campaigns/[id]/detail/route.ts +77 -0
  30. package/src/api/admin/campaigns/[id]/image/route.ts +87 -0
  31. package/src/api/admin/campaigns/[id]/thumbnail/route.ts +87 -0
  32. package/src/api/admin/campaigns/sync/route.ts +53 -28
  33. package/src/api/admin/flash-sales/[id]/route.ts +50 -19
  34. package/src/api/middlewares.ts +21 -0
  35. package/src/api/store/buy-x-get-y/[id]/route.ts +10 -10
  36. package/src/api/store/buy-x-get-y/products/[productId]/route.ts +11 -12
  37. package/src/api/store/buy-x-get-y/route.ts +12 -5
  38. package/src/api/store/campaigns/[id]/route.ts +54 -24
  39. package/src/modules/custom-campaigns/migrations/Migration20251024000000.ts +53 -0
  40. package/src/modules/custom-campaigns/migrations/Migration20251025000000.ts +19 -0
  41. package/src/modules/custom-campaigns/models/campaign-detail.ts +25 -0
  42. package/src/modules/custom-campaigns/service.ts +2 -0
  43. package/src/subscribers/order-placed.ts +0 -2
  44. package/src/types/index.d.ts +46 -0
  45. package/src/workflows/buy-x-get-y/applyBuyXGetYToCartWorkflow.ts +41 -18
  46. package/src/workflows/campaign-detail/update-campaign-detail.ts +85 -0
  47. package/src/workflows/campaign-detail/upload-campaign-images.ts +163 -0
  48. package/src/workflows/custom-campaign/createBuyXGetYCampaignWorkflow.ts +23 -22
  49. package/.medusa/server/src/api/admin/campaigns/fix-dates/route.js +0 -103
  50. package/.medusa/server/src/api/admin/force-fix/route.js +0 -176
  51. package/.medusa/server/src/api/admin/test-campaign/route.js +0 -132
  52. package/src/api/admin/campaigns/fix-dates/route.ts +0 -107
  53. package/src/api/admin/force-fix/route.ts +0 -184
  54. package/src/api/admin/test-campaign/route.ts +0 -141
@@ -1,132 +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 custom_campaigns_1 = require("../../../modules/custom-campaigns");
7
- const campaign_type_enum_1 = require("../../../modules/custom-campaigns/types/campaign-type.enum");
8
- const createBuyXGetYCampaignWorkflow_1 = require("../../../workflows/custom-campaign/createBuyXGetYCampaignWorkflow");
9
- /**
10
- * POST handler to create a test Buy X Get Y campaign
11
- * This creates a campaign with test data to verify the system is working
12
- */
13
- const POST = async (req, res) => {
14
- const productService = framework_1.container.resolve(utils_1.Modules.PRODUCT);
15
- try {
16
- // Get first two products from the system
17
- const products = await productService.listProducts({}, { take: 2 });
18
- if (products.length < 2) {
19
- return res.status(400).json({
20
- error: "Need at least 2 products in the system to create a test campaign",
21
- productsFound: products.length
22
- });
23
- }
24
- const [triggerProduct, rewardProduct] = products;
25
- // Create a test campaign that is active for the whole year
26
- const testCampaignData = {
27
- name: `Test BOGO Campaign ${Date.now()}`,
28
- description: "Test Buy 1 Get 1 Free campaign for debugging",
29
- type: campaign_type_enum_1.CampaignTypeEnum.BuyXGetY,
30
- starts_at: new Date("2024-01-01T00:00:00Z"),
31
- ends_at: new Date("2025-12-31T23:59:59Z"),
32
- rules: [
33
- {
34
- triggerProduct: {
35
- id: triggerProduct.id,
36
- title: triggerProduct.title || "Test Product A"
37
- },
38
- triggerQuantity: 1,
39
- rewardProduct: {
40
- id: rewardProduct.id,
41
- title: rewardProduct.title || "Test Product B"
42
- },
43
- rewardQuantity: 1,
44
- rewardType: "free",
45
- rewardValue: undefined,
46
- limit: undefined
47
- }
48
- ]
49
- };
50
- console.log("Creating test campaign with data:", JSON.stringify(testCampaignData, null, 2));
51
- const result = await createBuyXGetYCampaignWorkflow_1.createBuyXGetYCampaignWorkflow.run({
52
- input: testCampaignData
53
- });
54
- console.log("Test campaign created successfully:", result);
55
- res.status(201).json({
56
- success: true,
57
- message: "Test campaign created successfully",
58
- campaign: result.result?.campaign,
59
- promotions: result.result?.promotions,
60
- configs: result.result?.buyXGetYConfigs,
61
- testData: {
62
- triggerProduct: {
63
- id: triggerProduct.id,
64
- title: triggerProduct.title
65
- },
66
- rewardProduct: {
67
- id: rewardProduct.id,
68
- title: rewardProduct.title
69
- }
70
- }
71
- });
72
- }
73
- catch (error) {
74
- console.error("Error creating test campaign:", error);
75
- res.status(500).json({
76
- error: "Failed to create test campaign",
77
- details: error instanceof Error ? error.message : String(error),
78
- stack: error instanceof Error ? error.stack : undefined
79
- });
80
- }
81
- };
82
- exports.POST = POST;
83
- /**
84
- * GET handler to verify test campaign exists
85
- */
86
- const GET = async (req, res) => {
87
- const customCampaignModuleService = framework_1.container.resolve(custom_campaigns_1.CUSTOM_CAMPAIGN_MODULE);
88
- const promotionService = framework_1.container.resolve(utils_1.Modules.PROMOTION);
89
- try {
90
- // Get all Buy X Get Y campaigns
91
- const customCampaignTypes = await customCampaignModuleService.listCustomCampaignTypes({
92
- type: campaign_type_enum_1.CampaignTypeEnum.BuyXGetY
93
- });
94
- const campaignDetails = [];
95
- for (const ct of customCampaignTypes) {
96
- try {
97
- const campaign = await promotionService.retrieveCampaign(ct.campaign_id);
98
- const configs = await customCampaignModuleService.listBuyXGetYConfigs({
99
- campaign_id: ct.campaign_id
100
- });
101
- campaignDetails.push({
102
- customCampaignType: ct,
103
- campaign: {
104
- id: campaign.id,
105
- name: campaign.name,
106
- description: campaign.description,
107
- starts_at: campaign.starts_at,
108
- ends_at: campaign.ends_at,
109
- campaign_identifier: campaign.campaign_identifier
110
- },
111
- bogoConfigs: configs
112
- });
113
- }
114
- catch (e) {
115
- console.error(`Error fetching campaign ${ct.campaign_id}:`, e);
116
- }
117
- }
118
- res.status(200).json({
119
- totalBuyXGetYCampaigns: customCampaignTypes.length,
120
- campaigns: campaignDetails
121
- });
122
- }
123
- catch (error) {
124
- console.error("Error verifying test campaigns:", error);
125
- res.status(500).json({
126
- error: "Failed to verify test campaigns",
127
- details: error instanceof Error ? error.message : String(error)
128
- });
129
- }
130
- };
131
- exports.GET = GET;
132
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3Rlc3QtY2FtcGFpZ24vcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbURBQStFO0FBQy9FLHFEQUFvRDtBQUNwRCx3RUFBMkU7QUFFM0UsbUdBQThGO0FBQzlGLHNIQUFtSDtBQUVuSDs7O0dBR0c7QUFDSSxNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsR0FBa0IsRUFBRSxHQUFtQixFQUFFLEVBQUU7SUFDcEUsTUFBTSxjQUFjLEdBQUcscUJBQVMsQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBRTFELElBQUksQ0FBQztRQUNILHlDQUF5QztRQUN6QyxNQUFNLFFBQVEsR0FBRyxNQUFNLGNBQWMsQ0FBQyxZQUFZLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFcEUsSUFBSSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3hCLE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7Z0JBQzFCLEtBQUssRUFBRSxrRUFBa0U7Z0JBQ3pFLGFBQWEsRUFBRSxRQUFRLENBQUMsTUFBTTthQUMvQixDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsTUFBTSxDQUFDLGNBQWMsRUFBRSxhQUFhLENBQUMsR0FBRyxRQUFRLENBQUM7UUFFakQsMkRBQTJEO1FBQzNELE1BQU0sZ0JBQWdCLEdBQUc7WUFDdkIsSUFBSSxFQUFFLHNCQUFzQixJQUFJLENBQUMsR0FBRyxFQUFFLEVBQUU7WUFDeEMsV0FBVyxFQUFFLDhDQUE4QztZQUMzRCxJQUFJLEVBQUUscUNBQWdCLENBQUMsUUFBUTtZQUMvQixTQUFTLEVBQUUsSUFBSSxJQUFJLENBQUMsc0JBQXNCLENBQUM7WUFDM0MsT0FBTyxFQUFFLElBQUks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
@@ -1,107 +0,0 @@
1
- import { container, MedusaRequest, MedusaResponse } from "@medusajs/framework";
2
- import { Modules } from "@medusajs/framework/utils";
3
- import { updateCampaignsWorkflow } from "@medusajs/medusa/core-flows";
4
-
5
- /**
6
- * POST handler to fix campaign dates - makes all campaigns active for testing
7
- */
8
- export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
9
- const promotionService = container.resolve(Modules.PROMOTION);
10
-
11
- try {
12
- // Get all campaigns
13
- const allCampaigns = await promotionService.listCampaigns({});
14
-
15
- console.log(`Found ${allCampaigns.length} campaigns to fix`);
16
-
17
- const updatedCampaigns = [];
18
-
19
- // Update each campaign to be active for the whole year
20
- for (const campaign of allCampaigns) {
21
- try {
22
- const result = await updateCampaignsWorkflow.run({
23
- input: {
24
- campaignsData: [
25
- {
26
- id: campaign.id,
27
- starts_at: new Date("2024-01-01T00:00:00Z"),
28
- ends_at: new Date("2025-12-31T23:59:59Z"),
29
- },
30
- ],
31
- },
32
- });
33
-
34
- updatedCampaigns.push({
35
- id: campaign.id,
36
- name: campaign.name,
37
- old_starts_at: campaign.starts_at,
38
- old_ends_at: campaign.ends_at,
39
- new_starts_at: "2024-01-01T00:00:00Z",
40
- new_ends_at: "2025-12-31T23:59:59Z",
41
- });
42
-
43
- console.log(`✅ Fixed dates for campaign: ${campaign.name}`);
44
- } catch (error) {
45
- console.error(`❌ Failed to update campaign ${campaign.id}:`, error);
46
- }
47
- }
48
-
49
- res.status(200).json({
50
- success: true,
51
- message: `Updated ${updatedCampaigns.length} campaigns`,
52
- campaigns: updatedCampaigns,
53
- });
54
- } catch (error) {
55
- console.error("Error fixing campaign dates:", error);
56
- res.status(500).json({
57
- error: "Failed to fix campaign dates",
58
- details: error instanceof Error ? error.message : String(error),
59
- });
60
- }
61
- };
62
-
63
- /**
64
- * GET handler to show current campaign dates
65
- */
66
- export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
67
- const promotionService = container.resolve(Modules.PROMOTION);
68
- const now = new Date();
69
-
70
- try {
71
- const allCampaigns = await promotionService.listCampaigns({});
72
-
73
- const campaignDates = allCampaigns.map((campaign: any) => {
74
- const startsAt = new Date(campaign.starts_at);
75
- const endsAt = new Date(campaign.ends_at);
76
- const isActive = startsAt <= now && endsAt >= now;
77
-
78
- return {
79
- id: campaign.id,
80
- name: campaign.name,
81
- starts_at: campaign.starts_at,
82
- ends_at: campaign.ends_at,
83
- isActive,
84
- reason: !isActive
85
- ? (startsAt > now ? "Not started yet" : "Already ended")
86
- : "Active",
87
- };
88
- });
89
-
90
- res.status(200).json({
91
- currentTime: now.toISOString(),
92
- campaigns: campaignDates,
93
- summary: {
94
- total: campaignDates.length,
95
- active: campaignDates.filter((c: any) => c.isActive).length,
96
- notStarted: campaignDates.filter((c: any) => c.reason === "Not started yet").length,
97
- ended: campaignDates.filter((c: any) => c.reason === "Already ended").length,
98
- },
99
- });
100
- } catch (error) {
101
- console.error("Error checking campaign dates:", error);
102
- res.status(500).json({
103
- error: "Failed to check campaign dates",
104
- details: error instanceof Error ? error.message : String(error),
105
- });
106
- }
107
- };
@@ -1,184 +0,0 @@
1
- import { container, MedusaRequest, MedusaResponse } from "@medusajs/framework";
2
- import { Modules } from "@medusajs/framework/utils";
3
- import { updateCampaignsWorkflow } from "@medusajs/medusa/core-flows";
4
- import { CampaignTypeEnum } from "../../../modules/custom-campaigns/types/campaign-type.enum";
5
-
6
- /**
7
- * POST handler to force fix all campaigns in one go
8
- * This will sync types and fix dates
9
- */
10
- export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
11
- const promotionService = container.resolve(Modules.PROMOTION);
12
- const results: any = {
13
- timestamp: new Date().toISOString(),
14
- steps: []
15
- };
16
-
17
- try {
18
- // Step 1: Get all campaigns
19
- const allCampaigns = await promotionService.listCampaigns({});
20
- results.steps.push({
21
- step: "Get campaigns",
22
- status: "✅",
23
- count: allCampaigns.length
24
- });
25
-
26
- if (allCampaigns.length === 0) {
27
- return res.status(200).json({
28
- ...results,
29
- message: "No campaigns found to fix"
30
- });
31
- }
32
-
33
- // Step 2: Try to get custom campaign module
34
- let customModule: any;
35
- try {
36
- customModule = container.resolve("customCampaign");
37
- results.steps.push({
38
- step: "Resolve custom module",
39
- status: "✅"
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
-
49
- // Step 3: Fix dates for all campaigns
50
- const dateFixResults = [];
51
- for (const campaign of allCampaigns) {
52
- try {
53
- await updateCampaignsWorkflow.run({
54
- input: {
55
- campaignsData: [{
56
- id: campaign.id,
57
- starts_at: new Date("2024-01-01T00:00:00Z"),
58
- ends_at: new Date("2025-12-31T23:59:59Z")
59
- }]
60
- }
61
- });
62
- dateFixResults.push({
63
- id: campaign.id,
64
- name: campaign.name,
65
- status: "✅ Dates fixed"
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
-
77
- results.steps.push({
78
- step: "Fix campaign dates",
79
- status: "✅",
80
- fixed: dateFixResults.filter(r => r.status.includes("✅")).length,
81
- failed: dateFixResults.filter(r => r.status.includes("❌")).length,
82
- details: dateFixResults
83
- });
84
-
85
- // Step 4: Create custom types if module is available
86
- if (customModule) {
87
- const existingTypes = await customModule.listCustomCampaignTypes({});
88
- const existingCampaignIds = new Set(existingTypes.map((t: any) => t.campaign_id));
89
-
90
- const typeCreationResults = [];
91
- for (const campaign of allCampaigns) {
92
- if (existingCampaignIds.has(campaign.id)) {
93
- typeCreationResults.push({
94
- id: campaign.id,
95
- name: campaign.name,
96
- status: "⏭️ Already has type"
97
- });
98
- continue;
99
- }
100
-
101
- try {
102
- // Determine type based on name
103
- const type = campaign.name?.toLowerCase().includes("bogo") ||
104
- campaign.name?.toLowerCase().includes("buy") && campaign.name?.toLowerCase().includes("get")
105
- ? CampaignTypeEnum.BuyXGetY
106
- : CampaignTypeEnum.FlashSale;
107
-
108
- await customModule.createCustomCampaignTypes({
109
- campaign_id: campaign.id,
110
- type: type
111
- });
112
-
113
- typeCreationResults.push({
114
- id: campaign.id,
115
- name: campaign.name,
116
- type: type,
117
- status: "✅ Type created"
118
- });
119
- } catch (e) {
120
- typeCreationResults.push({
121
- id: campaign.id,
122
- name: campaign.name,
123
- status: "❌ Failed",
124
- error: e instanceof Error ? e.message : String(e)
125
- });
126
- }
127
- }
128
-
129
- results.steps.push({
130
- step: "Create custom types",
131
- status: "✅",
132
- created: typeCreationResults.filter(r => r.status.includes("✅")).length,
133
- skipped: typeCreationResults.filter(r => r.status.includes("⏭️")).length,
134
- failed: typeCreationResults.filter(r => r.status.includes("❌")).length,
135
- details: typeCreationResults
136
- });
137
- }
138
-
139
- // Step 5: Direct database update as fallback
140
- if (!customModule) {
141
- try {
142
- const db = container.resolve("__pg_connection__");
143
-
144
- for (const campaign of allCampaigns) {
145
- const type = campaign.name?.toLowerCase().includes("bogo") ||
146
- campaign.name?.toLowerCase().includes("buy") && campaign.name?.toLowerCase().includes("get")
147
- ? "buy-x-get-y"
148
- : "flash-sale";
149
-
150
- await db.raw(`
151
- INSERT INTO custom_campaign_type (id, campaign_id, type, created_at, updated_at)
152
- VALUES (?, ?, ?, NOW(), NOW())
153
- ON CONFLICT (campaign_id) WHERE deleted_at IS NULL
154
- DO UPDATE SET type = EXCLUDED.type, updated_at = NOW()
155
- `, [`cct_${Date.now()}_${campaign.id}`, campaign.id, type]);
156
- }
157
-
158
- results.steps.push({
159
- step: "Direct DB insert for custom types",
160
- status: "✅"
161
- });
162
- } catch (e) {
163
- results.steps.push({
164
- step: "Direct DB insert for custom types",
165
- status: "❌",
166
- error: e instanceof Error ? e.message : String(e)
167
- });
168
- }
169
- }
170
-
171
- results.success = true;
172
- results.message = "Force fix completed";
173
-
174
- res.status(200).json(results);
175
- } catch (error) {
176
- res.status(500).json({
177
- ...results,
178
- success: false,
179
- error: "Failed to force fix campaigns",
180
- details: error instanceof Error ? error.message : String(error),
181
- stack: error instanceof Error ? error.stack : undefined
182
- });
183
- }
184
- };
@@ -1,141 +0,0 @@
1
- import { container, MedusaRequest, MedusaResponse } from "@medusajs/framework";
2
- import { Modules } from "@medusajs/framework/utils";
3
- import { CUSTOM_CAMPAIGN_MODULE } from "../../../modules/custom-campaigns";
4
- import CustomCampaignModuleService from "../../../modules/custom-campaigns/service";
5
- import { CampaignTypeEnum } from "../../../modules/custom-campaigns/types/campaign-type.enum";
6
- import { createBuyXGetYCampaignWorkflow } from "../../../workflows/custom-campaign/createBuyXGetYCampaignWorkflow";
7
-
8
- /**
9
- * POST handler to create a test Buy X Get Y campaign
10
- * This creates a campaign with test data to verify the system is working
11
- */
12
- export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
13
- const productService = container.resolve(Modules.PRODUCT);
14
-
15
- try {
16
- // Get first two products from the system
17
- const products = await productService.listProducts({}, { take: 2 });
18
-
19
- if (products.length < 2) {
20
- return res.status(400).json({
21
- error: "Need at least 2 products in the system to create a test campaign",
22
- productsFound: products.length
23
- });
24
- }
25
-
26
- const [triggerProduct, rewardProduct] = products;
27
-
28
- // Create a test campaign that is active for the whole year
29
- const testCampaignData = {
30
- name: `Test BOGO Campaign ${Date.now()}`,
31
- description: "Test Buy 1 Get 1 Free campaign for debugging",
32
- type: CampaignTypeEnum.BuyXGetY,
33
- starts_at: new Date("2024-01-01T00:00:00Z"),
34
- ends_at: new Date("2025-12-31T23:59:59Z"),
35
- rules: [
36
- {
37
- triggerProduct: {
38
- id: triggerProduct.id,
39
- title: triggerProduct.title || "Test Product A"
40
- },
41
- triggerQuantity: 1,
42
- rewardProduct: {
43
- id: rewardProduct.id,
44
- title: rewardProduct.title || "Test Product B"
45
- },
46
- rewardQuantity: 1,
47
- rewardType: "free" as const,
48
- rewardValue: undefined,
49
- limit: undefined
50
- }
51
- ]
52
- };
53
-
54
- console.log("Creating test campaign with data:", JSON.stringify(testCampaignData, null, 2));
55
-
56
- const result = await createBuyXGetYCampaignWorkflow.run({
57
- input: testCampaignData
58
- });
59
-
60
- console.log("Test campaign created successfully:", result);
61
-
62
- res.status(201).json({
63
- success: true,
64
- message: "Test campaign created successfully",
65
- campaign: result.result?.campaign,
66
- promotions: result.result?.promotions,
67
- configs: result.result?.buyXGetYConfigs,
68
- testData: {
69
- triggerProduct: {
70
- id: triggerProduct.id,
71
- title: triggerProduct.title
72
- },
73
- rewardProduct: {
74
- id: rewardProduct.id,
75
- title: rewardProduct.title
76
- }
77
- }
78
- });
79
- } catch (error) {
80
- console.error("Error creating test campaign:", error);
81
- res.status(500).json({
82
- error: "Failed to create test campaign",
83
- details: error instanceof Error ? error.message : String(error),
84
- stack: error instanceof Error ? error.stack : undefined
85
- });
86
- }
87
- };
88
-
89
- /**
90
- * GET handler to verify test campaign exists
91
- */
92
- export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
93
- const customCampaignModuleService =
94
- container.resolve<CustomCampaignModuleService>(CUSTOM_CAMPAIGN_MODULE);
95
- const promotionService = container.resolve(Modules.PROMOTION);
96
-
97
- try {
98
- // Get all Buy X Get Y campaigns
99
- const customCampaignTypes =
100
- await customCampaignModuleService.listCustomCampaignTypes({
101
- type: CampaignTypeEnum.BuyXGetY
102
- });
103
-
104
- const campaignDetails = [];
105
-
106
- for (const ct of customCampaignTypes) {
107
- try {
108
- const campaign = await promotionService.retrieveCampaign(ct.campaign_id);
109
- const configs = await customCampaignModuleService.listBuyXGetYConfigs({
110
- campaign_id: ct.campaign_id
111
- });
112
-
113
- campaignDetails.push({
114
- customCampaignType: ct,
115
- campaign: {
116
- id: campaign.id,
117
- name: campaign.name,
118
- description: campaign.description,
119
- starts_at: campaign.starts_at,
120
- ends_at: campaign.ends_at,
121
- campaign_identifier: campaign.campaign_identifier
122
- },
123
- bogoConfigs: configs
124
- });
125
- } catch (e) {
126
- console.error(`Error fetching campaign ${ct.campaign_id}:`, e);
127
- }
128
- }
129
-
130
- res.status(200).json({
131
- totalBuyXGetYCampaigns: customCampaignTypes.length,
132
- campaigns: campaignDetails
133
- });
134
- } catch (error) {
135
- console.error("Error verifying test campaigns:", error);
136
- res.status(500).json({
137
- error: "Failed to verify test campaigns",
138
- details: error instanceof Error ? error.message : String(error)
139
- });
140
- }
141
- };