feat(utils): add campaign + promotion create / update (#6077)
* chore: add campaign + promotion operations * chore: update type * chore: added validation for campaign_id and campaign * chore: added update promotions for campaigns * chore: update campaign on promotion * chore: fix lint * chore: add test to remove promotions
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/types": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(types): add campaign + promotion operations
|
||||||
@@ -15,8 +15,8 @@ export async function createPromotions(
|
|||||||
let promotion = manager.create(Promotion, promotionData)
|
let promotion = manager.create(Promotion, promotionData)
|
||||||
|
|
||||||
manager.persist(promotion)
|
manager.persist(promotion)
|
||||||
|
|
||||||
await manager.flush()
|
await manager.flush()
|
||||||
|
promotions.push(promotion)
|
||||||
}
|
}
|
||||||
|
|
||||||
return promotions
|
return promotions
|
||||||
|
|||||||
+98
@@ -2,6 +2,7 @@ import { IPromotionModuleService } from "@medusajs/types"
|
|||||||
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||||
import { initialize } from "../../../../src"
|
import { initialize } from "../../../../src"
|
||||||
import { createCampaigns } from "../../../__fixtures__/campaigns"
|
import { createCampaigns } from "../../../__fixtures__/campaigns"
|
||||||
|
import { createPromotions } from "../../../__fixtures__/promotion"
|
||||||
import { DB_URL, MikroOrmWrapper } from "../../../utils"
|
import { DB_URL, MikroOrmWrapper } from "../../../utils"
|
||||||
|
|
||||||
jest.setTimeout(30000)
|
jest.setTimeout(30000)
|
||||||
@@ -101,6 +102,43 @@ describe("Promotion Module Service: Campaigns", () => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should create a basic campaign with promotions successfully", async () => {
|
||||||
|
await createPromotions(repositoryManager)
|
||||||
|
|
||||||
|
const startsAt = new Date("01/01/2024")
|
||||||
|
const endsAt = new Date("01/01/2025")
|
||||||
|
const [createdCampaign] = await service.createCampaigns([
|
||||||
|
{
|
||||||
|
name: "test",
|
||||||
|
campaign_identifier: "test",
|
||||||
|
starts_at: startsAt,
|
||||||
|
ends_at: endsAt,
|
||||||
|
promotions: [{ id: "promotion-id-1" }, { id: "promotion-id-2" }],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const campaign = await service.retrieveCampaign(createdCampaign.id, {
|
||||||
|
relations: ["promotions"],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(campaign).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
name: "test",
|
||||||
|
campaign_identifier: "test",
|
||||||
|
starts_at: startsAt,
|
||||||
|
ends_at: endsAt,
|
||||||
|
promotions: [
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "promotion-id-1",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "promotion-id-2",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("updateCampaigns", () => {
|
describe("updateCampaigns", () => {
|
||||||
@@ -163,6 +201,66 @@ describe("Promotion Module Service: Campaigns", () => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should update promotions of a campaign successfully", async () => {
|
||||||
|
await createCampaigns(repositoryManager)
|
||||||
|
await createPromotions(repositoryManager)
|
||||||
|
|
||||||
|
const [updatedCampaign] = await service.updateCampaigns([
|
||||||
|
{
|
||||||
|
id: "campaign-id-1",
|
||||||
|
description: "test description 1",
|
||||||
|
currency: "EUR",
|
||||||
|
campaign_identifier: "new",
|
||||||
|
starts_at: new Date("01/01/2024"),
|
||||||
|
ends_at: new Date("01/01/2025"),
|
||||||
|
promotions: [{ id: "promotion-id-1" }, { id: "promotion-id-2" }],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(updatedCampaign).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
description: "test description 1",
|
||||||
|
currency: "EUR",
|
||||||
|
campaign_identifier: "new",
|
||||||
|
starts_at: new Date("01/01/2024"),
|
||||||
|
ends_at: new Date("01/01/2025"),
|
||||||
|
promotions: [
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "promotion-id-1",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "promotion-id-2",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should remove promotions of the campaign successfully", async () => {
|
||||||
|
await createCampaigns(repositoryManager)
|
||||||
|
await createPromotions(repositoryManager)
|
||||||
|
|
||||||
|
await service.updateCampaigns({
|
||||||
|
id: "campaign-id-1",
|
||||||
|
promotions: [{ id: "promotion-id-1" }, { id: "promotion-id-2" }],
|
||||||
|
})
|
||||||
|
|
||||||
|
const updatedCampaign = await service.updateCampaigns({
|
||||||
|
id: "campaign-id-1",
|
||||||
|
promotions: [{ id: "promotion-id-1" }],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(updatedCampaign).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
promotions: [
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "promotion-id-1",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("retrieveCampaign", () => {
|
describe("retrieveCampaign", () => {
|
||||||
|
|||||||
+135
-1
@@ -1,7 +1,8 @@
|
|||||||
import { IPromotionModuleService } from "@medusajs/types"
|
import { IPromotionModuleService } from "@medusajs/types"
|
||||||
import { PromotionType } from "@medusajs/utils"
|
import { CampaignBudgetType, PromotionType } from "@medusajs/utils"
|
||||||
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||||
import { initialize } from "../../../../src"
|
import { initialize } from "../../../../src"
|
||||||
|
import { createCampaigns } from "../../../__fixtures__/campaigns"
|
||||||
import { createPromotions } from "../../../__fixtures__/promotion"
|
import { createPromotions } from "../../../__fixtures__/promotion"
|
||||||
import { DB_URL, MikroOrmWrapper } from "../../../utils"
|
import { DB_URL, MikroOrmWrapper } from "../../../utils"
|
||||||
|
|
||||||
@@ -99,6 +100,112 @@ describe("Promotion Service", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should throw an error when both campaign and campaign_id are provided", async () => {
|
||||||
|
const startsAt = new Date("01/01/2023")
|
||||||
|
const endsAt = new Date("01/01/2023")
|
||||||
|
|
||||||
|
const error = await service
|
||||||
|
.create({
|
||||||
|
code: "PROMOTION_TEST",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
campaign_id: "campaign-id-1",
|
||||||
|
campaign: {
|
||||||
|
name: "test",
|
||||||
|
campaign_identifier: "test-promotion-test",
|
||||||
|
starts_at: startsAt,
|
||||||
|
ends_at: endsAt,
|
||||||
|
budget: {
|
||||||
|
type: CampaignBudgetType.SPEND,
|
||||||
|
used: 100,
|
||||||
|
limit: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(error.message).toContain(
|
||||||
|
"Provide either the 'campaign' or 'campaign_id' parameter; both cannot be used simultaneously."
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create a basic promotion with campaign successfully", async () => {
|
||||||
|
const startsAt = new Date("01/01/2023")
|
||||||
|
const endsAt = new Date("01/01/2023")
|
||||||
|
|
||||||
|
await createCampaigns(repositoryManager)
|
||||||
|
|
||||||
|
const createdPromotion = await service.create({
|
||||||
|
code: "PROMOTION_TEST",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
campaign: {
|
||||||
|
name: "test",
|
||||||
|
campaign_identifier: "test-promotion-test",
|
||||||
|
starts_at: startsAt,
|
||||||
|
ends_at: endsAt,
|
||||||
|
budget: {
|
||||||
|
type: CampaignBudgetType.SPEND,
|
||||||
|
used: 100,
|
||||||
|
limit: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const [promotion] = await service.list(
|
||||||
|
{ id: [createdPromotion.id] },
|
||||||
|
{ relations: ["campaign.budget"] }
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(promotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
code: "PROMOTION_TEST",
|
||||||
|
is_automatic: false,
|
||||||
|
type: "standard",
|
||||||
|
campaign: expect.objectContaining({
|
||||||
|
name: "test",
|
||||||
|
campaign_identifier: "test-promotion-test",
|
||||||
|
starts_at: startsAt,
|
||||||
|
ends_at: endsAt,
|
||||||
|
budget: expect.objectContaining({
|
||||||
|
type: CampaignBudgetType.SPEND,
|
||||||
|
used: 100,
|
||||||
|
limit: 100,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create a basic promotion with an existing campaign successfully", async () => {
|
||||||
|
await createCampaigns(repositoryManager)
|
||||||
|
|
||||||
|
const createdPromotion = await service.create({
|
||||||
|
code: "PROMOTION_TEST",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
campaign_id: "campaign-id-1",
|
||||||
|
})
|
||||||
|
|
||||||
|
const [promotion] = await service.list(
|
||||||
|
{ id: [createdPromotion.id] },
|
||||||
|
{ relations: ["campaign.budget"] }
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(promotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
code: "PROMOTION_TEST",
|
||||||
|
is_automatic: false,
|
||||||
|
type: "standard",
|
||||||
|
campaign: expect.objectContaining({
|
||||||
|
id: "campaign-id-1",
|
||||||
|
budget: expect.objectContaining({
|
||||||
|
type: CampaignBudgetType.SPEND,
|
||||||
|
limit: 1000,
|
||||||
|
used: 0,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it("should throw error when creating an item application method without allocation", async () => {
|
it("should throw error when creating an item application method without allocation", async () => {
|
||||||
const error = await service
|
const error = await service
|
||||||
.create([
|
.create([
|
||||||
@@ -488,6 +595,33 @@ describe("Promotion Service", () => {
|
|||||||
`application_method.type should be one of fixed, percentage`
|
`application_method.type should be one of fixed, percentage`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should update campaign of the promotion", async () => {
|
||||||
|
await createCampaigns(repositoryManager)
|
||||||
|
const [createdPromotion] = await createPromotions(repositoryManager, [
|
||||||
|
{
|
||||||
|
is_automatic: true,
|
||||||
|
code: "TEST",
|
||||||
|
type: PromotionType.BUYGET,
|
||||||
|
campaign_id: "campaign-id-1",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const [updatedPromotion] = await service.update([
|
||||||
|
{
|
||||||
|
id: createdPromotion.id,
|
||||||
|
campaign_id: "campaign-id-2",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(updatedPromotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
campaign: expect.objectContaining({
|
||||||
|
id: "campaign-id-2",
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("retrieve", () => {
|
describe("retrieve", () => {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import { Context } from "@medusajs/types"
|
||||||
import { DALUtils } from "@medusajs/utils"
|
import { DALUtils } from "@medusajs/utils"
|
||||||
import { Campaign } from "@models"
|
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||||
|
import { Campaign, Promotion } from "@models"
|
||||||
import { CreateCampaignDTO, UpdateCampaignDTO } from "@types"
|
import { CreateCampaignDTO, UpdateCampaignDTO } from "@types"
|
||||||
|
|
||||||
export class CampaignRepository extends DALUtils.mikroOrmBaseRepositoryFactory<
|
export class CampaignRepository extends DALUtils.mikroOrmBaseRepositoryFactory<
|
||||||
@@ -8,4 +10,138 @@ export class CampaignRepository extends DALUtils.mikroOrmBaseRepositoryFactory<
|
|||||||
create: CreateCampaignDTO
|
create: CreateCampaignDTO
|
||||||
update: UpdateCampaignDTO
|
update: UpdateCampaignDTO
|
||||||
}
|
}
|
||||||
>(Campaign) {}
|
>(Campaign) {
|
||||||
|
async create(
|
||||||
|
data: CreateCampaignDTO[],
|
||||||
|
context: Context = {}
|
||||||
|
): Promise<Campaign[]> {
|
||||||
|
const manager = this.getActiveManager<SqlEntityManager>(context)
|
||||||
|
const promotionIdsToUpsert: string[] = []
|
||||||
|
const campaignIdentifierPromotionsMap = new Map<string, string[]>()
|
||||||
|
|
||||||
|
data.forEach((campaignData) => {
|
||||||
|
const campaignPromotionIds =
|
||||||
|
campaignData.promotions?.map((p) => p.id) || []
|
||||||
|
|
||||||
|
promotionIdsToUpsert.push(...campaignPromotionIds)
|
||||||
|
|
||||||
|
campaignIdentifierPromotionsMap.set(
|
||||||
|
campaignData.campaign_identifier,
|
||||||
|
campaignPromotionIds
|
||||||
|
)
|
||||||
|
|
||||||
|
delete campaignData.promotions
|
||||||
|
})
|
||||||
|
|
||||||
|
const existingPromotions = await manager.find(Promotion, {
|
||||||
|
id: promotionIdsToUpsert,
|
||||||
|
})
|
||||||
|
|
||||||
|
const existingPromotionsMap = new Map<string, Promotion>(
|
||||||
|
existingPromotions.map((promotion) => [promotion.id, promotion])
|
||||||
|
)
|
||||||
|
|
||||||
|
const createdCampaigns = await super.create(data, context)
|
||||||
|
|
||||||
|
for (const createdCampaign of createdCampaigns) {
|
||||||
|
const campaignPromotionIds =
|
||||||
|
campaignIdentifierPromotionsMap.get(
|
||||||
|
createdCampaign.campaign_identifier
|
||||||
|
) || []
|
||||||
|
|
||||||
|
for (const campaignPromotionId of campaignPromotionIds) {
|
||||||
|
const promotion = existingPromotionsMap.get(campaignPromotionId)
|
||||||
|
|
||||||
|
if (!promotion) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
createdCampaign.promotions.add(promotion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return createdCampaigns
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(
|
||||||
|
data: UpdateCampaignDTO[],
|
||||||
|
context: Context = {}
|
||||||
|
): Promise<Campaign[]> {
|
||||||
|
const manager = this.getActiveManager<SqlEntityManager>(context)
|
||||||
|
const promotionIdsToUpsert: string[] = []
|
||||||
|
const campaignIds: string[] = []
|
||||||
|
const campaignPromotionIdsMap = new Map<string, string[]>()
|
||||||
|
|
||||||
|
data.forEach((campaignData) => {
|
||||||
|
const campaignPromotionIds =
|
||||||
|
campaignData.promotions?.map((p) => p.id) || []
|
||||||
|
|
||||||
|
campaignIds.push(campaignData.id)
|
||||||
|
promotionIdsToUpsert.push(...campaignPromotionIds)
|
||||||
|
campaignPromotionIdsMap.set(campaignData.id, campaignPromotionIds)
|
||||||
|
|
||||||
|
delete campaignData.promotions
|
||||||
|
})
|
||||||
|
|
||||||
|
const existingCampaigns = await manager.find(
|
||||||
|
Campaign,
|
||||||
|
{ id: campaignIds },
|
||||||
|
{ populate: ["promotions"] }
|
||||||
|
)
|
||||||
|
|
||||||
|
const promotionIds = existingCampaigns
|
||||||
|
.map((campaign) => campaign.promotions?.map((p) => p.id))
|
||||||
|
.flat(1)
|
||||||
|
.concat(promotionIdsToUpsert)
|
||||||
|
|
||||||
|
const existingPromotions = await manager.find(Promotion, {
|
||||||
|
id: promotionIds,
|
||||||
|
})
|
||||||
|
|
||||||
|
const existingCampaignsMap = new Map<string, Campaign>(
|
||||||
|
existingCampaigns.map((campaign) => [campaign.id, campaign])
|
||||||
|
)
|
||||||
|
|
||||||
|
const existingPromotionsMap = new Map<string, Promotion>(
|
||||||
|
existingPromotions.map((promotion) => [promotion.id, promotion])
|
||||||
|
)
|
||||||
|
|
||||||
|
const updatedCampaigns = await super.update(data, context)
|
||||||
|
|
||||||
|
for (const updatedCampaign of updatedCampaigns) {
|
||||||
|
const upsertPromotionIds =
|
||||||
|
campaignPromotionIdsMap.get(updatedCampaign.id) || []
|
||||||
|
const existingPromotionIds = (
|
||||||
|
existingCampaignsMap.get(updatedCampaign.id)?.promotions || []
|
||||||
|
).map((p) => p.id)
|
||||||
|
|
||||||
|
for (const existingPromotionId of existingPromotionIds) {
|
||||||
|
const promotion = existingPromotionsMap.get(existingPromotionId)
|
||||||
|
|
||||||
|
if (!promotion) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!upsertPromotionIds.includes(existingPromotionId)) {
|
||||||
|
updatedCampaign.promotions.remove(promotion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const promotionIdToAdd of upsertPromotionIds) {
|
||||||
|
const promotion = existingPromotionsMap.get(promotionIdToAdd)
|
||||||
|
|
||||||
|
if (!promotion) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingPromotionIds.includes(promotionIdToAdd)) {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
updatedCampaign.promotions.add(promotion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedCampaigns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -314,6 +314,7 @@ export default class PromotionModuleService<
|
|||||||
"application_method.target_rules.values",
|
"application_method.target_rules.values",
|
||||||
"rules",
|
"rules",
|
||||||
"rules.values",
|
"rules.values",
|
||||||
|
"campaign",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
sharedContext
|
sharedContext
|
||||||
@@ -329,12 +330,12 @@ export default class PromotionModuleService<
|
|||||||
) {
|
) {
|
||||||
const promotionsData: CreatePromotionDTO[] = []
|
const promotionsData: CreatePromotionDTO[] = []
|
||||||
const applicationMethodsData: CreateApplicationMethodDTO[] = []
|
const applicationMethodsData: CreateApplicationMethodDTO[] = []
|
||||||
|
const campaignsData: CreateCampaignDTO[] = []
|
||||||
|
|
||||||
const promotionCodeApplicationMethodDataMap = new Map<
|
const promotionCodeApplicationMethodDataMap = new Map<
|
||||||
string,
|
string,
|
||||||
PromotionTypes.CreateApplicationMethodDTO
|
PromotionTypes.CreateApplicationMethodDTO
|
||||||
>()
|
>()
|
||||||
|
|
||||||
const promotionCodeRulesDataMap = new Map<
|
const promotionCodeRulesDataMap = new Map<
|
||||||
string,
|
string,
|
||||||
PromotionTypes.CreatePromotionRuleDTO[]
|
PromotionTypes.CreatePromotionRuleDTO[]
|
||||||
@@ -343,10 +344,16 @@ export default class PromotionModuleService<
|
|||||||
string,
|
string,
|
||||||
PromotionTypes.CreatePromotionRuleDTO[]
|
PromotionTypes.CreatePromotionRuleDTO[]
|
||||||
>()
|
>()
|
||||||
|
const promotionCodeCampaignMap = new Map<
|
||||||
|
string,
|
||||||
|
PromotionTypes.CreateCampaignDTO
|
||||||
|
>()
|
||||||
|
|
||||||
for (const {
|
for (const {
|
||||||
application_method: applicationMethodData,
|
application_method: applicationMethodData,
|
||||||
rules: rulesData,
|
rules: rulesData,
|
||||||
|
campaign: campaignData,
|
||||||
|
campaign_id: campaignId,
|
||||||
...promotionData
|
...promotionData
|
||||||
} of data) {
|
} of data) {
|
||||||
if (applicationMethodData) {
|
if (applicationMethodData) {
|
||||||
@@ -360,7 +367,21 @@ export default class PromotionModuleService<
|
|||||||
promotionCodeRulesDataMap.set(promotionData.code, rulesData)
|
promotionCodeRulesDataMap.set(promotionData.code, rulesData)
|
||||||
}
|
}
|
||||||
|
|
||||||
promotionsData.push(promotionData)
|
if (campaignData && campaignId) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Provide either the 'campaign' or 'campaign_id' parameter; both cannot be used simultaneously.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (campaignData) {
|
||||||
|
promotionCodeCampaignMap.set(promotionData.code, campaignData)
|
||||||
|
}
|
||||||
|
|
||||||
|
promotionsData.push({
|
||||||
|
...promotionData,
|
||||||
|
campaign: campaignId,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const createdPromotions = await this.promotionService_.create(
|
const createdPromotions = await this.promotionService_.create(
|
||||||
@@ -373,6 +394,15 @@ export default class PromotionModuleService<
|
|||||||
promotion.code
|
promotion.code
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const campaignData = promotionCodeCampaignMap.get(promotion.code)
|
||||||
|
|
||||||
|
if (campaignData) {
|
||||||
|
campaignsData.push({
|
||||||
|
...campaignData,
|
||||||
|
promotions: [promotion],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (applMethodData) {
|
if (applMethodData) {
|
||||||
const {
|
const {
|
||||||
target_rules: targetRulesData = [],
|
target_rules: targetRulesData = [],
|
||||||
@@ -416,6 +446,10 @@ export default class PromotionModuleService<
|
|||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (campaignsData.length) {
|
||||||
|
await this.createCampaigns(campaignsData, sharedContext)
|
||||||
|
}
|
||||||
|
|
||||||
for (const applicationMethod of createdApplicationMethods) {
|
for (const applicationMethod of createdApplicationMethods) {
|
||||||
await this.createPromotionRulesAndValues(
|
await this.createPromotionRulesAndValues(
|
||||||
applicationMethodRuleMap.get(applicationMethod.promotion.id) || [],
|
applicationMethodRuleMap.get(applicationMethod.promotion.id) || [],
|
||||||
@@ -456,6 +490,7 @@ export default class PromotionModuleService<
|
|||||||
"application_method.target_rules",
|
"application_method.target_rules",
|
||||||
"rules",
|
"rules",
|
||||||
"rules.values",
|
"rules.values",
|
||||||
|
"campaign",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
sharedContext
|
sharedContext
|
||||||
@@ -471,13 +506,10 @@ export default class PromotionModuleService<
|
|||||||
) {
|
) {
|
||||||
const promotionIds = data.map((d) => d.id)
|
const promotionIds = data.map((d) => d.id)
|
||||||
const existingPromotions = await this.promotionService_.list(
|
const existingPromotions = await this.promotionService_.list(
|
||||||
{
|
{ id: promotionIds },
|
||||||
id: promotionIds,
|
{ relations: ["application_method"] }
|
||||||
},
|
|
||||||
{
|
|
||||||
relations: ["application_method"],
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const existingPromotionsMap = new Map<string, Promotion>(
|
const existingPromotionsMap = new Map<string, Promotion>(
|
||||||
existingPromotions.map((promotion) => [promotion.id, promotion])
|
existingPromotions.map((promotion) => [promotion.id, promotion])
|
||||||
)
|
)
|
||||||
@@ -487,9 +519,14 @@ export default class PromotionModuleService<
|
|||||||
|
|
||||||
for (const {
|
for (const {
|
||||||
application_method: applicationMethodData,
|
application_method: applicationMethodData,
|
||||||
|
campaign_id: campaignId,
|
||||||
...promotionData
|
...promotionData
|
||||||
} of data) {
|
} of data) {
|
||||||
promotionsData.push(promotionData)
|
if (campaignId) {
|
||||||
|
promotionsData.push({ ...promotionData, campaign: campaignId })
|
||||||
|
} else {
|
||||||
|
promotionsData.push(promotionData)
|
||||||
|
}
|
||||||
|
|
||||||
if (!applicationMethodData) {
|
if (!applicationMethodData) {
|
||||||
continue
|
continue
|
||||||
@@ -820,7 +857,19 @@ export default class PromotionModuleService<
|
|||||||
>()
|
>()
|
||||||
|
|
||||||
for (const createCampaignData of data) {
|
for (const createCampaignData of data) {
|
||||||
const { budget: campaignBudgetData, ...campaignData } = createCampaignData
|
const {
|
||||||
|
budget: campaignBudgetData,
|
||||||
|
promotions,
|
||||||
|
...campaignData
|
||||||
|
} = createCampaignData
|
||||||
|
|
||||||
|
const promotionsToAdd = promotions
|
||||||
|
? await this.list(
|
||||||
|
{ id: promotions.map((p) => p.id) },
|
||||||
|
{},
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
: []
|
||||||
|
|
||||||
if (campaignBudgetData) {
|
if (campaignBudgetData) {
|
||||||
campaignIdentifierBudgetMap.set(
|
campaignIdentifierBudgetMap.set(
|
||||||
@@ -829,7 +878,10 @@ export default class PromotionModuleService<
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
campaignsData.push(campaignData)
|
campaignsData.push({
|
||||||
|
...campaignData,
|
||||||
|
promotions: promotionsToAdd,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const createdCampaigns = await this.campaignService_.create(
|
const createdCampaigns = await this.campaignService_.create(
|
||||||
@@ -882,7 +934,7 @@ export default class PromotionModuleService<
|
|||||||
const campaigns = await this.listCampaigns(
|
const campaigns = await this.listCampaigns(
|
||||||
{ id: updatedCampaigns.map((p) => p!.id) },
|
{ id: updatedCampaigns.map((p) => p!.id) },
|
||||||
{
|
{
|
||||||
relations: ["budget"],
|
relations: ["budget", "promotions"],
|
||||||
},
|
},
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import { PromotionDTO } from "@medusajs/types"
|
||||||
|
import { Promotion } from "@models"
|
||||||
|
|
||||||
export interface CreateCampaignDTO {
|
export interface CreateCampaignDTO {
|
||||||
name: string
|
name: string
|
||||||
description?: string
|
description?: string
|
||||||
@@ -5,6 +8,7 @@ export interface CreateCampaignDTO {
|
|||||||
campaign_identifier: string
|
campaign_identifier: string
|
||||||
starts_at: Date
|
starts_at: Date
|
||||||
ends_at: Date
|
ends_at: Date
|
||||||
|
promotions?: (PromotionDTO | Promotion)[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateCampaignDTO {
|
export interface UpdateCampaignDTO {
|
||||||
@@ -15,4 +19,5 @@ export interface UpdateCampaignDTO {
|
|||||||
campaign_identifier?: string
|
campaign_identifier?: string
|
||||||
starts_at?: Date
|
starts_at?: Date
|
||||||
ends_at?: Date
|
ends_at?: Date
|
||||||
|
promotions?: (PromotionDTO | Promotion)[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export interface CreatePromotionDTO {
|
|||||||
code: string
|
code: string
|
||||||
type: PromotionType
|
type: PromotionType
|
||||||
is_automatic?: boolean
|
is_automatic?: boolean
|
||||||
|
campaign?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdatePromotionDTO {
|
export interface UpdatePromotionDTO {
|
||||||
@@ -12,4 +13,5 @@ export interface UpdatePromotionDTO {
|
|||||||
// TODO: add this when buyget is available
|
// TODO: add this when buyget is available
|
||||||
// type: PromotionType
|
// type: PromotionType
|
||||||
is_automatic?: boolean
|
is_automatic?: boolean
|
||||||
|
campaign?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,25 +31,25 @@ export interface RemoveShippingMethodAdjustment {
|
|||||||
adjustment_id: string
|
adjustment_id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ComputeActionAdjustmentLine {
|
export interface ComputeActionAdjustmentLine extends Record<string, unknown> {
|
||||||
id: string
|
id: string
|
||||||
code: string
|
code: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ComputeActionItemLine {
|
export interface ComputeActionItemLine extends Record<string, unknown> {
|
||||||
id: string
|
id: string
|
||||||
quantity: number
|
quantity: number
|
||||||
unit_price: number
|
unit_price: number
|
||||||
adjustments?: ComputeActionAdjustmentLine[]
|
adjustments?: ComputeActionAdjustmentLine[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ComputeActionShippingLine {
|
export interface ComputeActionShippingLine extends Record<string, unknown> {
|
||||||
id: string
|
id: string
|
||||||
unit_price: number
|
unit_price: number
|
||||||
adjustments?: ComputeActionAdjustmentLine[]
|
adjustments?: ComputeActionAdjustmentLine[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ComputeActionContext {
|
export interface ComputeActionContext extends Record<string, unknown> {
|
||||||
items?: ComputeActionItemLine[]
|
items?: ComputeActionItemLine[]
|
||||||
shipping_methods?: ComputeActionShippingLine[]
|
shipping_methods?: ComputeActionShippingLine[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { BaseFilterable } from "../../dal"
|
import { BaseFilterable } from "../../dal"
|
||||||
|
import { CreateCampaignDTO } from "../mutations"
|
||||||
import {
|
import {
|
||||||
ApplicationMethodDTO,
|
ApplicationMethodDTO,
|
||||||
CreateApplicationMethodDTO,
|
CreateApplicationMethodDTO,
|
||||||
@@ -23,6 +24,8 @@ export interface CreatePromotionDTO {
|
|||||||
is_automatic?: boolean
|
is_automatic?: boolean
|
||||||
application_method?: CreateApplicationMethodDTO
|
application_method?: CreateApplicationMethodDTO
|
||||||
rules?: CreatePromotionRuleDTO[]
|
rules?: CreatePromotionRuleDTO[]
|
||||||
|
campaign?: CreateCampaignDTO
|
||||||
|
campaign_id?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdatePromotionDTO {
|
export interface UpdatePromotionDTO {
|
||||||
@@ -31,6 +34,7 @@ export interface UpdatePromotionDTO {
|
|||||||
code?: string
|
code?: string
|
||||||
type?: PromotionType
|
type?: PromotionType
|
||||||
application_method?: UpdateApplicationMethodDTO
|
application_method?: UpdateApplicationMethodDTO
|
||||||
|
campaign_id?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FilterablePromotionProps
|
export interface FilterablePromotionProps
|
||||||
@@ -39,4 +43,5 @@ export interface FilterablePromotionProps
|
|||||||
code?: string[]
|
code?: string[]
|
||||||
is_automatic?: boolean
|
is_automatic?: boolean
|
||||||
type?: PromotionType[]
|
type?: PromotionType[]
|
||||||
|
budget_id?: string[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { CampaignBudgetTypeValues } from "./common"
|
import { CampaignBudgetTypeValues, PromotionDTO } from "./common"
|
||||||
|
|
||||||
export interface CreateCampaignBudgetDTO {
|
export interface CreateCampaignBudgetDTO {
|
||||||
type: CampaignBudgetTypeValues
|
type: CampaignBudgetTypeValues
|
||||||
@@ -21,6 +21,7 @@ export interface CreateCampaignDTO {
|
|||||||
starts_at: Date
|
starts_at: Date
|
||||||
ends_at: Date
|
ends_at: Date
|
||||||
budget?: CreateCampaignBudgetDTO
|
budget?: CreateCampaignBudgetDTO
|
||||||
|
promotions?: Pick<PromotionDTO, "id">[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateCampaignDTO {
|
export interface UpdateCampaignDTO {
|
||||||
@@ -32,4 +33,5 @@ export interface UpdateCampaignDTO {
|
|||||||
starts_at?: Date
|
starts_at?: Date
|
||||||
ends_at?: Date
|
ends_at?: Date
|
||||||
budget?: Omit<UpdateCampaignBudgetDTO, "id">
|
budget?: Omit<UpdateCampaignBudgetDTO, "id">
|
||||||
|
promotions?: Pick<PromotionDTO, "id">[]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user