feat(types): added computed actions for automatic promotions (#6272)
what: - compute actions account for automatic promotions (RESOLVES CORE-1701) RESOLVES CORE-1689
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@medusajs/types": patch
|
||||
---
|
||||
|
||||
feat(types): added computed actions for automatic promotions
|
||||
+448
-2
@@ -1,11 +1,11 @@
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import { IPromotionModuleService } from "@medusajs/types"
|
||||
import { PromotionType } from "@medusajs/utils"
|
||||
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||
import { initModules } from "medusa-test-utils"
|
||||
import { createCampaigns } from "../../../__fixtures__/campaigns"
|
||||
import { MikroOrmWrapper } from "../../../utils"
|
||||
import { getInitModuleConfig } from "../../../utils/get-init-module-config"
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import { initModules } from "medusa-test-utils"
|
||||
|
||||
jest.setTimeout(30000)
|
||||
|
||||
@@ -239,6 +239,84 @@ describe("Promotion Service: computeActions", () => {
|
||||
])
|
||||
})
|
||||
|
||||
it("should compute the correct item amendments when promotion is automatic", async () => {
|
||||
const [createdPromotion] = await service.create([
|
||||
{
|
||||
code: "PROMOTION_TEST",
|
||||
is_automatic: true,
|
||||
type: PromotionType.STANDARD,
|
||||
rules: [
|
||||
{
|
||||
attribute: "customer.customer_group.id",
|
||||
operator: "in",
|
||||
values: ["VIP", "top100"],
|
||||
},
|
||||
],
|
||||
application_method: {
|
||||
type: "fixed",
|
||||
target_type: "items",
|
||||
allocation: "each",
|
||||
value: "200",
|
||||
max_quantity: 1,
|
||||
target_rules: [
|
||||
{
|
||||
attribute: "product_category.id",
|
||||
operator: "eq",
|
||||
values: ["catg_cotton"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const result = await service.computeActions([], {
|
||||
customer: {
|
||||
customer_group: {
|
||||
id: "VIP",
|
||||
},
|
||||
},
|
||||
items: [
|
||||
{
|
||||
id: "item_cotton_tshirt",
|
||||
quantity: 1,
|
||||
unit_price: 100,
|
||||
product_category: {
|
||||
id: "catg_cotton",
|
||||
},
|
||||
product: {
|
||||
id: "prod_tshirt",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "item_cotton_sweater",
|
||||
quantity: 5,
|
||||
unit_price: 150,
|
||||
product_category: {
|
||||
id: "catg_cotton",
|
||||
},
|
||||
product: {
|
||||
id: "prod_sweater",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
action: "addItemAdjustment",
|
||||
item_id: "item_cotton_tshirt",
|
||||
amount: 100,
|
||||
code: "PROMOTION_TEST",
|
||||
},
|
||||
{
|
||||
action: "addItemAdjustment",
|
||||
item_id: "item_cotton_sweater",
|
||||
amount: 150,
|
||||
code: "PROMOTION_TEST",
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("should compute the correct item amendments when there are multiple promotions to apply", async () => {
|
||||
const [createdPromotion] = await service.create([
|
||||
{
|
||||
@@ -666,6 +744,83 @@ describe("Promotion Service: computeActions", () => {
|
||||
])
|
||||
})
|
||||
|
||||
it("should compute the correct item amendments when promotion is automatic", async () => {
|
||||
const [createdPromotion] = await service.create([
|
||||
{
|
||||
code: "PROMOTION_TEST",
|
||||
type: PromotionType.STANDARD,
|
||||
is_automatic: true,
|
||||
rules: [
|
||||
{
|
||||
attribute: "customer.customer_group.id",
|
||||
operator: "in",
|
||||
values: ["VIP", "top100"],
|
||||
},
|
||||
],
|
||||
application_method: {
|
||||
type: "fixed",
|
||||
target_type: "items",
|
||||
allocation: "across",
|
||||
value: "400",
|
||||
target_rules: [
|
||||
{
|
||||
attribute: "product_category.id",
|
||||
operator: "eq",
|
||||
values: ["catg_cotton"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const result = await service.computeActions([], {
|
||||
customer: {
|
||||
customer_group: {
|
||||
id: "VIP",
|
||||
},
|
||||
},
|
||||
items: [
|
||||
{
|
||||
id: "item_cotton_tshirt",
|
||||
quantity: 2,
|
||||
unit_price: 100,
|
||||
product_category: {
|
||||
id: "catg_cotton",
|
||||
},
|
||||
product: {
|
||||
id: "prod_tshirt",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "item_cotton_sweater",
|
||||
quantity: 2,
|
||||
unit_price: 300,
|
||||
product_category: {
|
||||
id: "catg_cotton",
|
||||
},
|
||||
product: {
|
||||
id: "prod_sweater",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
action: "addItemAdjustment",
|
||||
item_id: "item_cotton_tshirt",
|
||||
amount: 100,
|
||||
code: "PROMOTION_TEST",
|
||||
},
|
||||
{
|
||||
action: "addItemAdjustment",
|
||||
item_id: "item_cotton_sweater",
|
||||
amount: 300,
|
||||
code: "PROMOTION_TEST",
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("should compute the correct item amendments when there are multiple promotions to apply", async () => {
|
||||
const [createdPromotion] = await service.create([
|
||||
{
|
||||
@@ -1099,6 +1254,151 @@ describe("Promotion Service: computeActions", () => {
|
||||
])
|
||||
})
|
||||
|
||||
it("should compute the correct shipping_method amendments when promotion is automatic", async () => {
|
||||
const [createdPromotion] = await service.create([
|
||||
{
|
||||
code: "PROMOTION_TEST",
|
||||
type: PromotionType.STANDARD,
|
||||
is_automatic: true,
|
||||
rules: [
|
||||
{
|
||||
attribute: "customer.customer_group.id",
|
||||
operator: "in",
|
||||
values: ["VIP", "top100"],
|
||||
},
|
||||
],
|
||||
application_method: {
|
||||
type: "fixed",
|
||||
target_type: "shipping_methods",
|
||||
allocation: "each",
|
||||
value: "200",
|
||||
max_quantity: 2,
|
||||
target_rules: [
|
||||
{
|
||||
attribute: "shipping_option.id",
|
||||
operator: "in",
|
||||
values: ["express", "standard"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const result = await service.computeActions([], {
|
||||
customer: {
|
||||
customer_group: {
|
||||
id: "VIP",
|
||||
},
|
||||
},
|
||||
shipping_methods: [
|
||||
{
|
||||
id: "shipping_method_express",
|
||||
unit_price: 250,
|
||||
shipping_option: {
|
||||
id: "express",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "shipping_method_standard",
|
||||
unit_price: 150,
|
||||
shipping_option: {
|
||||
id: "standard",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "shipping_method_snail",
|
||||
unit_price: 200,
|
||||
shipping_option: {
|
||||
id: "snail",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
action: "addShippingMethodAdjustment",
|
||||
shipping_method_id: "shipping_method_express",
|
||||
amount: 200,
|
||||
code: "PROMOTION_TEST",
|
||||
},
|
||||
{
|
||||
action: "addShippingMethodAdjustment",
|
||||
shipping_method_id: "shipping_method_standard",
|
||||
amount: 150,
|
||||
code: "PROMOTION_TEST",
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("should compute the correct shipping_method amendments when promotion is automatic and prevent_auto_promotions is false", async () => {
|
||||
const [createdPromotion] = await service.create([
|
||||
{
|
||||
code: "PROMOTION_TEST",
|
||||
type: PromotionType.STANDARD,
|
||||
is_automatic: true,
|
||||
rules: [
|
||||
{
|
||||
attribute: "customer.customer_group.id",
|
||||
operator: "in",
|
||||
values: ["VIP", "top100"],
|
||||
},
|
||||
],
|
||||
application_method: {
|
||||
type: "fixed",
|
||||
target_type: "shipping_methods",
|
||||
allocation: "each",
|
||||
value: "200",
|
||||
max_quantity: 2,
|
||||
target_rules: [
|
||||
{
|
||||
attribute: "shipping_option.id",
|
||||
operator: "in",
|
||||
values: ["express", "standard"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const result = await service.computeActions(
|
||||
[],
|
||||
{
|
||||
customer: {
|
||||
customer_group: {
|
||||
id: "VIP",
|
||||
},
|
||||
},
|
||||
shipping_methods: [
|
||||
{
|
||||
id: "shipping_method_express",
|
||||
unit_price: 250,
|
||||
shipping_option: {
|
||||
id: "express",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "shipping_method_standard",
|
||||
unit_price: 150,
|
||||
shipping_option: {
|
||||
id: "standard",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "shipping_method_snail",
|
||||
unit_price: 200,
|
||||
shipping_option: {
|
||||
id: "snail",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{ prevent_auto_promotions: true }
|
||||
)
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
it("should compute the correct item amendments when there are multiple promotions to apply", async () => {
|
||||
const [createdPromotion] = await service.create([
|
||||
{
|
||||
@@ -1509,6 +1809,82 @@ describe("Promotion Service: computeActions", () => {
|
||||
])
|
||||
})
|
||||
|
||||
it("should compute the correct shipping_method amendments when promotion is automatic", async () => {
|
||||
const [createdPromotion] = await service.create([
|
||||
{
|
||||
code: "PROMOTION_TEST",
|
||||
type: PromotionType.STANDARD,
|
||||
is_automatic: true,
|
||||
rules: [
|
||||
{
|
||||
attribute: "customer.customer_group.id",
|
||||
operator: "in",
|
||||
values: ["VIP", "top100"],
|
||||
},
|
||||
],
|
||||
application_method: {
|
||||
type: "fixed",
|
||||
target_type: "shipping_methods",
|
||||
allocation: "across",
|
||||
value: "200",
|
||||
target_rules: [
|
||||
{
|
||||
attribute: "shipping_option.id",
|
||||
operator: "in",
|
||||
values: ["express", "standard"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const result = await service.computeActions([], {
|
||||
customer: {
|
||||
customer_group: {
|
||||
id: "VIP",
|
||||
},
|
||||
},
|
||||
shipping_methods: [
|
||||
{
|
||||
id: "shipping_method_express",
|
||||
unit_price: 500,
|
||||
shipping_option: {
|
||||
id: "express",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "shipping_method_standard",
|
||||
unit_price: 100,
|
||||
shipping_option: {
|
||||
id: "standard",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "shipping_method_snail",
|
||||
unit_price: 200,
|
||||
shipping_option: {
|
||||
id: "snail",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
action: "addShippingMethodAdjustment",
|
||||
shipping_method_id: "shipping_method_express",
|
||||
amount: 166.66666666666669,
|
||||
code: "PROMOTION_TEST",
|
||||
},
|
||||
{
|
||||
action: "addShippingMethodAdjustment",
|
||||
shipping_method_id: "shipping_method_standard",
|
||||
amount: 33.33333333333333,
|
||||
code: "PROMOTION_TEST",
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("should compute the correct item amendments when there are multiple promotions to apply", async () => {
|
||||
const [createdPromotion] = await service.create([
|
||||
{
|
||||
@@ -1913,6 +2289,76 @@ describe("Promotion Service: computeActions", () => {
|
||||
])
|
||||
})
|
||||
|
||||
it("should compute the correct item amendments when promotion is automatic", async () => {
|
||||
const [createdPromotion] = await service.create([
|
||||
{
|
||||
code: "PROMOTION_TEST",
|
||||
type: PromotionType.STANDARD,
|
||||
is_automatic: true,
|
||||
rules: [
|
||||
{
|
||||
attribute: "customer.customer_group.id",
|
||||
operator: "in",
|
||||
values: ["VIP", "top100"],
|
||||
},
|
||||
],
|
||||
application_method: {
|
||||
type: "fixed",
|
||||
target_type: "order",
|
||||
value: "200",
|
||||
max_quantity: 2,
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const result = await service.computeActions([], {
|
||||
customer: {
|
||||
customer_group: {
|
||||
id: "VIP",
|
||||
},
|
||||
},
|
||||
items: [
|
||||
{
|
||||
id: "item_cotton_tshirt",
|
||||
quantity: 1,
|
||||
unit_price: 100,
|
||||
product_category: {
|
||||
id: "catg_cotton",
|
||||
},
|
||||
product: {
|
||||
id: "prod_tshirt",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "item_cotton_sweater",
|
||||
quantity: 2,
|
||||
unit_price: 150,
|
||||
product_category: {
|
||||
id: "catg_cotton",
|
||||
},
|
||||
product: {
|
||||
id: "prod_sweater",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
action: "addItemAdjustment",
|
||||
item_id: "item_cotton_tshirt",
|
||||
amount: 50,
|
||||
code: "PROMOTION_TEST",
|
||||
},
|
||||
{
|
||||
action: "addItemAdjustment",
|
||||
item_id: "item_cotton_sweater",
|
||||
amount: 150,
|
||||
code: "PROMOTION_TEST",
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("should compute the correct item amendments when there are multiple promotions to apply", async () => {
|
||||
const [createdPromotion] = await service.create([
|
||||
{
|
||||
|
||||
@@ -216,11 +216,11 @@ export default class PromotionModuleService<
|
||||
}
|
||||
|
||||
async computeActions(
|
||||
promotionCodesToApply: string[],
|
||||
promotionCodes: string[],
|
||||
applicationContext: PromotionTypes.ComputeActionContext,
|
||||
// TODO: specify correct type with options
|
||||
options: Record<string, any> = {}
|
||||
options: PromotionTypes.ComputeActionOptions = {}
|
||||
): Promise<PromotionTypes.ComputeActions[]> {
|
||||
const { prevent_auto_promotions: preventAutoPromotions } = options
|
||||
const computedActions: PromotionTypes.ComputeActions[] = []
|
||||
const { items = [], shipping_methods: shippingMethods = [] } =
|
||||
applicationContext
|
||||
@@ -231,6 +231,15 @@ export default class PromotionModuleService<
|
||||
PromotionTypes.ComputeActionAdjustmentLine
|
||||
>()
|
||||
const methodIdPromoValueMap = new Map<string, number>()
|
||||
const automaticPromotions = preventAutoPromotions
|
||||
? []
|
||||
: await this.list({ is_automatic: true }, { select: ["code"] })
|
||||
|
||||
const automaticPromotionCodes = automaticPromotions.map((p) => p.code!)
|
||||
const promotionCodesToApply = [
|
||||
...promotionCodes,
|
||||
...automaticPromotionCodes,
|
||||
]
|
||||
|
||||
items.forEach((item) => {
|
||||
item.adjustments?.forEach((adjustment) => {
|
||||
@@ -291,7 +300,7 @@ export default class PromotionModuleService<
|
||||
)
|
||||
}
|
||||
|
||||
if (promotionCodesToApply.includes(appliedCode)) {
|
||||
if (promotionCodes.includes(appliedCode)) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -65,3 +65,7 @@ export interface ComputeActionContext extends Record<string, unknown> {
|
||||
items?: ComputeActionItemLine[]
|
||||
shipping_methods?: ComputeActionShippingLine[]
|
||||
}
|
||||
|
||||
export interface ComputeActionOptions {
|
||||
prevent_auto_promotions?: boolean
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user