Skip to content

Commit

Permalink
feat(utils): add campaign + promotion create / update (#6077)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
riqwan authored Jan 16, 2024
1 parent 5d1965f commit e28fa7f
Show file tree
Hide file tree
Showing 11 changed files with 460 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/lazy-shoes-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@medusajs/types": patch
---

feat(types): add campaign + promotion operations
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export async function createPromotions(
let promotion = manager.create(Promotion, promotionData)

manager.persist(promotion)

await manager.flush()
promotions.push(promotion)
}

return promotions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { IPromotionModuleService } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { initialize } from "../../../../src"
import { createCampaigns } from "../../../__fixtures__/campaigns"
import { createPromotions } from "../../../__fixtures__/promotion"
import { DB_URL, MikroOrmWrapper } from "../../../utils"

jest.setTimeout(30000)
Expand Down Expand Up @@ -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", () => {
Expand Down Expand Up @@ -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", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { IPromotionModuleService } from "@medusajs/types"
import { PromotionType } from "@medusajs/utils"
import { CampaignBudgetType, PromotionType } from "@medusajs/utils"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { initialize } from "../../../../src"
import { createCampaigns } from "../../../__fixtures__/campaigns"
import { createPromotions } from "../../../__fixtures__/promotion"
import { DB_URL, MikroOrmWrapper } from "../../../utils"

Expand Down Expand Up @@ -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 () => {
const error = await service
.create([
Expand Down Expand Up @@ -488,6 +595,33 @@ describe("Promotion Service", () => {
`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", () => {
Expand Down
Loading

1 comment on commit e28fa7f

@vercel
Copy link

@vercel vercel bot commented on e28fa7f Jan 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

medusa-dashboard – ./packages/admin-next/dashboard

admin-preview.medusajs.com
medusa-dashboard-medusajs.vercel.app
medusa-dashboard.vercel.app
medusa-dashboard-git-develop-medusajs.vercel.app

Please sign in to comment.