feat: Completely revamp the pricing module (#7852)
* feat: Completely revamp the pricing module * chore: Update all places to the new pricing interfaces * fix: Remove unnecessary join to itself * chore: Add data migration for existing users * fix: Apply the correct index to price rule
This commit is contained in:
@@ -92,22 +92,6 @@ medusaIntegrationTestRunner({
|
||||
adminHeaders
|
||||
)
|
||||
).data.price_list
|
||||
|
||||
// BREAKING: You need to register rule types before you can use them
|
||||
await api.post(
|
||||
"/admin/pricing/rule-types",
|
||||
{ name: "Region ID", rule_attribute: "region_id", default_priority: 0 },
|
||||
adminHeaders
|
||||
)
|
||||
await api.post(
|
||||
"/admin/pricing/rule-types",
|
||||
{
|
||||
name: "Customer Group ID",
|
||||
rule_attribute: "customer_group_id",
|
||||
default_priority: 0,
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
})
|
||||
|
||||
describe("/admin/price-lists", () => {
|
||||
|
||||
@@ -808,12 +808,6 @@ medusaIntegrationTestRunner({
|
||||
// },
|
||||
// async () => {
|
||||
// const variantId = baseProduct.variants[0].id
|
||||
// await pricingService.createRuleTypes([
|
||||
// {
|
||||
// name: "Region ID",
|
||||
// rule_attribute: "region_id",
|
||||
// },
|
||||
// ])
|
||||
// const priceSet = await createVariantPriceSet({
|
||||
// container,
|
||||
// variantId,
|
||||
@@ -1228,16 +1222,6 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
|
||||
it("creates a product variant with price rules", async () => {
|
||||
await api.post(
|
||||
`/admin/pricing/rule-types`,
|
||||
{
|
||||
name: "Region",
|
||||
rule_attribute: "region_id",
|
||||
default_priority: 1,
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
const response = await api.post(
|
||||
"/admin/products",
|
||||
{
|
||||
|
||||
@@ -96,12 +96,6 @@ medusaIntegrationTestRunner({
|
||||
|
||||
describe("updates a variant's default prices (ignores prices associated with a Price List)", () => {
|
||||
it("successfully updates a variant's default prices by changing an existing price (currency_code)", async () => {
|
||||
await api.post(
|
||||
`/admin/pricing/rule-types`,
|
||||
{ name: "Region", rule_attribute: "region_id", default_priority: 1 },
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
const data = {
|
||||
prices: [
|
||||
{
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
createAdminUser,
|
||||
} from "../../../../helpers/create-admin-user"
|
||||
import { getProductFixture } from "../../../../helpers/fixtures"
|
||||
import { createDefaultRuleTypes } from "../../../../modules/helpers/create-default-rule-types"
|
||||
|
||||
jest.setTimeout(30000)
|
||||
|
||||
@@ -83,7 +82,6 @@ medusaIntegrationTestRunner({
|
||||
beforeEach(async () => {
|
||||
appContainer = getContainer()
|
||||
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||
await createDefaultRuleTypes(appContainer)
|
||||
|
||||
const storeModule: IStoreModuleService = appContainer.resolve(
|
||||
ModuleRegistrationName.STORE
|
||||
|
||||
@@ -46,16 +46,8 @@ medusaIntegrationTestRunner({
|
||||
},
|
||||
])
|
||||
|
||||
await pricingModule.createRuleTypes([
|
||||
{
|
||||
name: "customer_group_id",
|
||||
rule_attribute: "customer_group_id",
|
||||
},
|
||||
])
|
||||
|
||||
const [priceSet1, priceSet2] = await pricingModule.createPriceSets([
|
||||
{
|
||||
rules: [{ rule_attribute: "customer_group_id" }],
|
||||
prices: [
|
||||
{
|
||||
amount: 3000,
|
||||
@@ -71,7 +63,6 @@ medusaIntegrationTestRunner({
|
||||
],
|
||||
},
|
||||
{
|
||||
rules: [{ rule_attribute: "customer_group_id" }],
|
||||
prices: [
|
||||
{
|
||||
amount: 400,
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
simpleRegionFactory,
|
||||
} from "../../../../factories"
|
||||
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
||||
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
|
||||
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
|
||||
|
||||
jest.setTimeout(50000)
|
||||
@@ -37,7 +36,6 @@ medusaIntegrationTestRunner({
|
||||
|
||||
beforeEach(async () => {
|
||||
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||
await createDefaultRuleTypes(appContainer)
|
||||
|
||||
await simpleRegionFactory(dbConnection, {
|
||||
id: "test-region",
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
|
||||
import { IPricingModuleService } from "@medusajs/types"
|
||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
|
||||
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
|
||||
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
||||
|
||||
@@ -39,7 +38,6 @@ medusaIntegrationTestRunner({
|
||||
|
||||
beforeEach(async () => {
|
||||
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||
await createDefaultRuleTypes(appContainer)
|
||||
|
||||
await simpleRegionFactory(dbConnection, {
|
||||
id: "test-region",
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
|
||||
import { IPricingModuleService } from "@medusajs/types"
|
||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
|
||||
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
|
||||
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
||||
|
||||
@@ -37,7 +36,6 @@ medusaIntegrationTestRunner({
|
||||
|
||||
beforeEach(async () => {
|
||||
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||
await createDefaultRuleTypes(appContainer)
|
||||
|
||||
await simpleRegionFactory(dbConnection, {
|
||||
id: "test-region",
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
|
||||
import { IPricingModuleService } from "@medusajs/types"
|
||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
|
||||
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
|
||||
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
||||
|
||||
@@ -37,7 +36,6 @@ medusaIntegrationTestRunner({
|
||||
|
||||
beforeEach(async () => {
|
||||
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||
await createDefaultRuleTypes(appContainer)
|
||||
|
||||
await simpleRegionFactory(dbConnection, {
|
||||
id: "test-region",
|
||||
|
||||
@@ -66,11 +66,6 @@ medusaIntegrationTestRunner({
|
||||
|
||||
variant = product.variants[0]
|
||||
variant2 = product.variants[1]
|
||||
|
||||
await pricingModule.createRuleTypes([
|
||||
{ name: "Customer Group ID", rule_attribute: "customer_group_id" },
|
||||
{ name: "Region ID", rule_attribute: "region_id" },
|
||||
])
|
||||
})
|
||||
|
||||
describe("GET /admin/price-lists", () => {
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
simpleRegionFactory,
|
||||
} from "../../../../factories"
|
||||
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
||||
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
|
||||
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
|
||||
|
||||
jest.setTimeout(50000)
|
||||
@@ -37,7 +36,6 @@ medusaIntegrationTestRunner({
|
||||
|
||||
beforeEach(async () => {
|
||||
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||
await createDefaultRuleTypes(appContainer)
|
||||
|
||||
await simpleRegionFactory(dbConnection, {
|
||||
id: "test-region",
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IPricingModuleService, RuleTypeDTO } from "@medusajs/types"
|
||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
||||
|
||||
jest.setTimeout(50000)
|
||||
|
||||
const env = { MEDUSA_FF_MEDUSA_V2: true }
|
||||
const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } }
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
env,
|
||||
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||
describe("Admin: Pricing Rule Types API", () => {
|
||||
let appContainer
|
||||
let pricingModule: IPricingModuleService
|
||||
let ruleTypes: RuleTypeDTO[]
|
||||
|
||||
beforeAll(async () => {
|
||||
appContainer = getContainer()
|
||||
pricingModule = appContainer.resolve(ModuleRegistrationName.PRICING)
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||
|
||||
ruleTypes = await pricingModule.createRuleTypes([
|
||||
{ name: "Customer Group ID", rule_attribute: "customer_group_id" },
|
||||
{ name: "Region ID", rule_attribute: "region_id" },
|
||||
])
|
||||
})
|
||||
|
||||
describe("GET /admin/pricing", () => {
|
||||
it("should get all rule types and its prices with rules", async () => {
|
||||
let response = await api.get(
|
||||
`/admin/pricing/rule-types`,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data.count).toEqual(2)
|
||||
expect(response.data.rule_types).toEqual([
|
||||
expect.objectContaining({ id: expect.any(String) }),
|
||||
expect.objectContaining({ id: expect.any(String) }),
|
||||
])
|
||||
|
||||
response = await api.get(
|
||||
`/admin/pricing/rule-types?fields=id,rule_attribute,created_at`,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data.count).toEqual(2)
|
||||
expect(response.data.rule_types).toEqual(
|
||||
expect.arrayContaining([
|
||||
{
|
||||
id: ruleTypes[0].id,
|
||||
rule_attribute: ruleTypes[0].rule_attribute,
|
||||
created_at: expect.any(String),
|
||||
},
|
||||
{
|
||||
id: ruleTypes[1].id,
|
||||
rule_attribute: ruleTypes[1].rule_attribute,
|
||||
created_at: expect.any(String),
|
||||
},
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("GET /admin/pricing/:id", () => {
|
||||
it("should retrieve a rule type and its prices with rules", async () => {
|
||||
const ruleType = ruleTypes[0]
|
||||
|
||||
let response = await api.get(
|
||||
`/admin/pricing/rule-types/${ruleType.id}`,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data.rule_type).toEqual(
|
||||
expect.objectContaining({
|
||||
id: ruleType.id,
|
||||
})
|
||||
)
|
||||
|
||||
response = await api.get(
|
||||
`/admin/pricing/rule-types/${ruleType.id}?fields=id,created_at`,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.data.rule_type).toEqual({
|
||||
id: ruleType.id,
|
||||
created_at: expect.any(String),
|
||||
})
|
||||
})
|
||||
|
||||
it("should throw an error when rule type is not found", async () => {
|
||||
const error = await api
|
||||
.get(`/admin/pricing/rule-types/does-not-exist`, adminHeaders)
|
||||
.catch((e) => e)
|
||||
|
||||
expect(error.response.status).toBe(404)
|
||||
expect(error.response.data).toEqual({
|
||||
type: "not_found",
|
||||
message: "RuleType with id: does-not-exist was not found",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /admin/pricing/rule-types", () => {
|
||||
it("should throw an error if required params are not passed", async () => {
|
||||
const { response } = await api
|
||||
.post(
|
||||
`/admin/pricing/rule-types`,
|
||||
{
|
||||
rule_attribute: "rule_attr_test1",
|
||||
default_priority: 7,
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
.catch((e) => e)
|
||||
|
||||
expect(response.status).toEqual(400)
|
||||
// expect(response.data.message).toEqual(
|
||||
// "name must be a string, name should not be empty"
|
||||
// )
|
||||
})
|
||||
|
||||
it("should create a rule type successfully", async () => {
|
||||
const response = await api.post(
|
||||
`/admin/pricing/rule-types`,
|
||||
{
|
||||
name: "test",
|
||||
rule_attribute: "rule_attr_test",
|
||||
default_priority: 6,
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data.rule_type).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
name: "test",
|
||||
rule_attribute: "rule_attr_test",
|
||||
default_priority: 6,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /admin/pricing/rule-types/:id", () => {
|
||||
it("should throw an error if id does not exist", async () => {
|
||||
const { response } = await api
|
||||
.post(`/admin/pricing/rule-types/does-not-exist`, {}, adminHeaders)
|
||||
.catch((e) => e)
|
||||
|
||||
expect(response.status).toEqual(404)
|
||||
expect(response.data.message).toEqual(
|
||||
`RuleType with id "does-not-exist" not found`
|
||||
)
|
||||
})
|
||||
|
||||
it("should update a rule type successfully", async () => {
|
||||
const [ruleType] = ruleTypes
|
||||
|
||||
const response = await api.post(
|
||||
`/admin/pricing/rule-types/${ruleType.id}`,
|
||||
{
|
||||
name: "test update",
|
||||
rule_attribute: "test_update",
|
||||
default_priority: 7,
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data.rule_type).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
name: "test update",
|
||||
rule_attribute: "test_update",
|
||||
default_priority: 7,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("DELETE /admin/pricing/rule-types/:id", () => {
|
||||
it("should delete rule type successfully", async () => {
|
||||
const [ruleType] = ruleTypes
|
||||
const response = await api.delete(
|
||||
`/admin/pricing/rule-types/${ruleType.id}`,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data).toEqual({
|
||||
id: ruleType.id,
|
||||
object: "rule_type",
|
||||
deleted: true,
|
||||
})
|
||||
|
||||
const deletedRuleTypes = await pricingModule.listRuleTypes({
|
||||
id: [ruleType.id],
|
||||
})
|
||||
|
||||
expect(deletedRuleTypes.length).toEqual(0)
|
||||
})
|
||||
|
||||
it("should return 200 when id does not exist", async () => {
|
||||
const response = await api.delete(
|
||||
`/admin/pricing/rule-types/does-not-exist`,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data).toEqual({
|
||||
id: "does-not-exist",
|
||||
object: "rule_type",
|
||||
deleted: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -1,7 +1,6 @@
|
||||
import { simpleCartFactory, simpleRegionFactory } from "../../../factories"
|
||||
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { createDefaultRuleTypes } from "../../helpers/create-default-rule-types"
|
||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||
import { createAdminUser } from "../../../helpers/create-admin-user"
|
||||
|
||||
@@ -33,7 +32,6 @@ medusaIntegrationTestRunner({
|
||||
medusaContainer = getContainer()
|
||||
})
|
||||
beforeEach(async () => {
|
||||
await createDefaultRuleTypes(medusaContainer)
|
||||
await createAdminUser(dbConnection, adminHeaders, medusaContainer)
|
||||
await simpleRegionFactory(dbConnection, {
|
||||
id: "region-1",
|
||||
@@ -78,12 +76,7 @@ medusaIntegrationTestRunner({
|
||||
productId = response.data.product.id
|
||||
const variant = response.data.product.variants[0]
|
||||
|
||||
ruleType = await pricingModuleService.createRuleTypes([
|
||||
{ name: "region_id", rule_attribute: "region_id" },
|
||||
])
|
||||
|
||||
priceSet = await pricingModuleService.createPriceSets({
|
||||
rules: [{ rule_attribute: "region_id" }],
|
||||
prices: [
|
||||
{
|
||||
amount: 1000,
|
||||
|
||||
@@ -6,7 +6,6 @@ import { getContainer } from "../../../../environment-helpers/use-container"
|
||||
import { initDb, useDb } from "../../../../environment-helpers/use-db"
|
||||
import { simpleSalesChannelFactory } from "../../../../factories"
|
||||
import productSeeder from "../../../../helpers/product-seeder"
|
||||
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
|
||||
import {
|
||||
adminHeaders,
|
||||
createAdminUser,
|
||||
@@ -65,7 +64,6 @@ describe.skip("Batch job of product-export type", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
const container = getContainer()
|
||||
await createDefaultRuleTypes(container)
|
||||
await productSeeder(dbConnection)
|
||||
await createAdminUser(dbConnection, adminHeaders, container)
|
||||
await userSeeder(dbConnection)
|
||||
|
||||
@@ -8,7 +8,6 @@ import { initDb, useDb } from "../../../../environment-helpers/use-db"
|
||||
import { simpleProductFactory } from "../../../../factories"
|
||||
import { simpleProductCollectionFactory } from "../../../../factories/simple-product-collection-factory"
|
||||
import batchJobSeeder from "../../../../helpers/batch-job-seeder"
|
||||
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
|
||||
import {
|
||||
adminHeaders,
|
||||
createAdminUser,
|
||||
@@ -99,7 +98,6 @@ describe.skip("Product import batch job", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
const container = getContainer()
|
||||
await createDefaultRuleTypes(container)
|
||||
await batchJobSeeder(dbConnection)
|
||||
await createAdminUser(dbConnection, adminHeaders, container)
|
||||
await userSeeder(dbConnection)
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { IPricingModuleService } from "@medusajs/types"
|
||||
|
||||
export const createDefaultRuleTypes = async (container) => {
|
||||
const pricingModuleService: IPricingModuleService = container.resolve(
|
||||
"pricingModuleService"
|
||||
)
|
||||
|
||||
return await pricingModuleService.createRuleTypes([
|
||||
{
|
||||
name: "region_id",
|
||||
rule_attribute: "region_id",
|
||||
},
|
||||
{
|
||||
name: "customer_group_id",
|
||||
rule_attribute: "customer_group_id",
|
||||
},
|
||||
])
|
||||
}
|
||||
@@ -13,18 +13,14 @@ const defaultPrices = [
|
||||
},
|
||||
]
|
||||
|
||||
const defaultPriceSetRules = [{ rule_attribute: "region_id" }]
|
||||
|
||||
export const createVariantPriceSet = async ({
|
||||
container,
|
||||
variantId,
|
||||
prices = defaultPrices,
|
||||
rules = defaultPriceSetRules,
|
||||
}: {
|
||||
container: MedusaContainer
|
||||
variantId: string
|
||||
prices?: CreatePriceSetDTO["prices"]
|
||||
rules?: CreatePriceSetDTO["rules"]
|
||||
}): Promise<PriceSetDTO> => {
|
||||
const remoteLink = container.resolve("remoteLink")
|
||||
const pricingModuleService: IPricingModuleService = container.resolve(
|
||||
@@ -32,7 +28,6 @@ export const createVariantPriceSet = async ({
|
||||
)
|
||||
|
||||
const priceSet = await pricingModuleService.createPriceSets({
|
||||
rules,
|
||||
prices,
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user