Skip to content

Commit

Permalink
feat(types,utils): added promotion create with rules and application …
Browse files Browse the repository at this point in the history
…target rules (#5957)

* feat(types,utils): added promotion create with rules

* chore: add rules to promotion and application method

* chore: use common code for rule and values

* chore: address pr reviews

* chore: fix test
  • Loading branch information
riqwan authored Jan 3, 2024
1 parent d16d106 commit 42cc8ae
Show file tree
Hide file tree
Showing 33 changed files with 1,562 additions and 124 deletions.
6 changes: 6 additions & 0 deletions .changeset/breezy-horses-destroy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@medusajs/types": patch
"@medusajs/utils": patch
---

feat(types,utils): added promotion create with rules
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,82 @@ describe("Promotion Service", () => {
},
])

const [promotion] = await service.list({
id: [createdPromotion.id],
})
const [promotion] = await service.list(
{
id: [createdPromotion.id],
},
{
relations: ["application_method"],
}
)

expect(promotion).toEqual(
expect.objectContaining({
code: "PROMOTION_TEST",
is_automatic: false,
type: "standard",
application_method: expect.objectContaining({
type: "fixed",
target_type: "order",
value: 100,
}),
})
)
})

it("should create a promotion with order application method with rules successfully", async () => {
const [createdPromotion] = await service.create([
{
code: "PROMOTION_TEST",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "order",
value: 100,
target_rules: [
{
attribute: "product_id",
operator: "eq",
values: ["prod_tshirt"],
},
],
},
},
])

const [promotion] = await service.list(
{
id: [createdPromotion.id],
},
{
relations: [
"application_method",
"application_method.target_rules.values",
],
}
)

expect(promotion).toEqual(
expect.objectContaining({
code: "PROMOTION_TEST",
is_automatic: false,
type: "standard",
application_method: expect.objectContaining({
type: "fixed",
target_type: "order",
value: 100,
target_rules: [
expect.objectContaining({
attribute: "product_id",
operator: "eq",
values: expect.arrayContaining([
expect.objectContaining({
value: "prod_tshirt",
}),
]),
}),
],
}),
})
)
})
Expand Down Expand Up @@ -128,5 +195,156 @@ describe("Promotion Service", () => {
"application_method.max_quantity is required when application_method.allocation is 'each'"
)
})

it("should create a promotion with rules successfully", async () => {
const [createdPromotion] = await service.create([
{
code: "PROMOTION_TEST",
type: PromotionType.STANDARD,
rules: [
{
attribute: "customer_group_id",
operator: "in",
values: ["VIP", "top100"],
},
],
},
])

const [promotion] = await service.list(
{
id: [createdPromotion.id],
},
{
relations: ["rules", "rules.values"],
}
)

expect(promotion).toEqual(
expect.objectContaining({
code: "PROMOTION_TEST",
is_automatic: false,
type: "standard",
rules: [
expect.objectContaining({
attribute: "customer_group_id",
operator: "in",
values: expect.arrayContaining([
expect.objectContaining({
value: "VIP",
}),
expect.objectContaining({
value: "top100",
}),
]),
}),
],
})
)
})

it("should create a promotion with rules with single value successfully", async () => {
const [createdPromotion] = await service.create([
{
code: "PROMOTION_TEST",
type: PromotionType.STANDARD,
rules: [
{
attribute: "customer_group_id",
operator: "eq",
values: "VIP",
},
],
},
])

const [promotion] = await service.list(
{
id: [createdPromotion.id],
},
{
relations: ["rules", "rules.values"],
}
)

expect(promotion).toEqual(
expect.objectContaining({
code: "PROMOTION_TEST",
is_automatic: false,
type: "standard",
rules: [
expect.objectContaining({
attribute: "customer_group_id",
operator: "eq",
values: expect.arrayContaining([
expect.objectContaining({
value: "VIP",
}),
]),
}),
],
})
)
})

it("should throw an error when rule attribute is invalid", async () => {
const error = await service
.create([
{
code: "PROMOTION_TEST",
type: PromotionType.STANDARD,
rules: [
{
attribute: "",
operator: "eq",
values: "VIP",
} as any,
],
},
])
.catch((e) => e)

expect(error.message).toContain("rules[].attribute is a required field")
})

it("should throw an error when rule operator is invalid", async () => {
let error = await service
.create([
{
code: "PROMOTION_TEST",
type: PromotionType.STANDARD,
rules: [
{
attribute: "customer_group",
operator: "",
values: "VIP",
} as any,
],
},
])
.catch((e) => e)

expect(error.message).toContain("rules[].operator is a required field")

error = await service
.create([
{
code: "PROMOTION_TEST",
type: PromotionType.STANDARD,
rules: [
{
attribute: "customer_group",
operator: "doesnotexist",
values: "VIP",
} as any,
],
},
])
.catch((e) => e)

expect(error.message).toContain(
"rules[].operator (doesnotexist) is invalid. It should be one of gte, lte, gt, lt, eq, ne, in"
)
})
})
})
12 changes: 12 additions & 0 deletions packages/promotion/src/loaders/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ export default async ({

container.register({
promotionService: asClass(defaultServices.PromotionService).singleton(),
promotionRuleService: asClass(
defaultServices.PromotionRuleService
).singleton(),
promotionRuleValueService: asClass(
defaultServices.PromotionRuleValueService
).singleton(),
applicationMethodService: asClass(
defaultServices.ApplicationMethodService
).singleton(),
Expand All @@ -44,5 +50,11 @@ function loadDefaultRepositories({ container }) {
promotionRepository: asClass(
defaultRepositories.PromotionRepository
).singleton(),
promotionRuleRepository: asClass(
defaultRepositories.PromotionRuleRepository
).singleton(),
promotionRuleValueRepository: asClass(
defaultRepositories.PromotionRuleValueRepository
).singleton(),
})
}
Loading

0 comments on commit 42cc8ae

Please sign in to comment.