feat: Add DiscountConditions (#1230)
* feat: Add DiscountCondition entity + Join table per relation (#1146) * feat: Convert DiscountService to TypeScript (#1149) * feat: Add DiscountRepository + bulk insert and remove (#1156) * feat: Add `conditions` to payload in `POST /discounts` and `POST /discounts/:id` (#1170) * feat: Add DiscountRuleCondition entity * fix relation * fix join key * Add discount rule condition repo * add join table per relation * Convert DiscountService to TypeScript * feat: Add DiscountConditionRepository * Add migration + remove use of valid_for * revert changes to files, not done yet * init work on create discount endpoint * Add conditions to create discount endpoint * Add conditions to update discount endpoint * Add unique constraint to discount condition * integration tests passing * fix imports of models * fix tests (excluding totals calculations) * Fix commented code * add unique constraint on discount condition * Add generic way of generating retrieve configs * Requested changes + ExactlyOne validator * Remove isLocal flag from error handler * Use postgres error constant * remove commented code * feat: Add `isValidForProduct` to check if Discount is valid for a given Product (#1172) * feat: Add `canApplyForCustomer` to check if Discount is valid for customer groups (#1212) * feat: Add `calculateDiscountForLineItem` (#1224) * feat: Adds discount condition test factory (#1228) * Remove use of valid_for * Tests passing * Remove valid_for form relations * Add integration tests for applying discounts to cart
This commit is contained in:
@@ -16,6 +16,16 @@ const { initDb, useDb } = require("../../../helpers/use-db")
|
||||
const cartSeeder = require("../../helpers/cart-seeder")
|
||||
const productSeeder = require("../../helpers/product-seeder")
|
||||
const swapSeeder = require("../../helpers/swap-seeder")
|
||||
const { simpleCartFactory } = require("../../factories")
|
||||
const {
|
||||
simpleDiscountFactory,
|
||||
} = require("../../factories/simple-discount-factory")
|
||||
const {
|
||||
simpleCustomerFactory,
|
||||
} = require("../../factories/simple-customer-factory")
|
||||
const {
|
||||
simpleCustomerGroupFactory,
|
||||
} = require("../../factories/simple-customer-group-factory")
|
||||
|
||||
jest.setTimeout(30000)
|
||||
|
||||
@@ -354,6 +364,348 @@ describe("/store/carts", () => {
|
||||
})
|
||||
})
|
||||
|
||||
it("successfully passes customer conditions with `in` operator and applies discount", async () => {
|
||||
const api = useApi()
|
||||
|
||||
await simpleCustomerFactory(dbConnection, {
|
||||
id: "cus_1234",
|
||||
email: "oli@medusajs.com",
|
||||
groups: [
|
||||
{
|
||||
id: "customer-group-1",
|
||||
name: "VIP Customer",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
await simpleCustomerGroupFactory(dbConnection, {
|
||||
id: "customer-group-2",
|
||||
name: "Loyal",
|
||||
})
|
||||
|
||||
await simpleCartFactory(
|
||||
dbConnection,
|
||||
{
|
||||
id: "test-customer-discount",
|
||||
region: {
|
||||
id: "test-region",
|
||||
name: "Test region",
|
||||
tax_rate: 12,
|
||||
},
|
||||
customer: "cus_1234",
|
||||
line_items: [
|
||||
{
|
||||
variant_id: "test-variant",
|
||||
unit_price: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
100
|
||||
)
|
||||
|
||||
await simpleDiscountFactory(dbConnection, {
|
||||
id: "test-discount",
|
||||
code: "TEST",
|
||||
regions: ["test-region"],
|
||||
rule: {
|
||||
type: "percentage",
|
||||
value: "10",
|
||||
allocation: "total",
|
||||
conditions: [
|
||||
{
|
||||
type: "customer_groups",
|
||||
operator: "in",
|
||||
customer_groups: ["customer-group-1", "customer-group-2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const response = await api.post("/store/carts/test-customer-discount", {
|
||||
discounts: [{ code: "TEST" }],
|
||||
})
|
||||
|
||||
const cartRes = response.data.cart
|
||||
expect(cartRes.discounts).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
code: "TEST",
|
||||
}),
|
||||
])
|
||||
)
|
||||
expect(response.status).toEqual(200)
|
||||
})
|
||||
|
||||
it("successfully passes customer conditions with `not_in` operator and applies discount", async () => {
|
||||
const api = useApi()
|
||||
|
||||
await simpleCustomerFactory(dbConnection, {
|
||||
id: "cus_1234",
|
||||
email: "oli@medusajs.com",
|
||||
groups: [
|
||||
{
|
||||
id: "customer-group-2",
|
||||
name: "VIP Customer",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
await simpleCustomerGroupFactory(dbConnection, {
|
||||
id: "customer-group-1",
|
||||
name: "Customer group 1",
|
||||
})
|
||||
|
||||
await simpleCustomerGroupFactory(dbConnection, {
|
||||
id: "customer-group-3",
|
||||
name: "Customer group 3",
|
||||
})
|
||||
|
||||
await simpleCartFactory(
|
||||
dbConnection,
|
||||
{
|
||||
id: "test-customer-discount",
|
||||
region: {
|
||||
id: "test-region",
|
||||
name: "Test region",
|
||||
tax_rate: 12,
|
||||
},
|
||||
customer: "cus_1234",
|
||||
line_items: [
|
||||
{
|
||||
variant_id: "test-variant",
|
||||
unit_price: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
100
|
||||
)
|
||||
|
||||
await simpleDiscountFactory(dbConnection, {
|
||||
id: "test-discount",
|
||||
code: "TEST",
|
||||
regions: ["test-region"],
|
||||
rule: {
|
||||
type: "percentage",
|
||||
value: "10",
|
||||
allocation: "total",
|
||||
conditions: [
|
||||
{
|
||||
type: "customer_groups",
|
||||
operator: "not_in",
|
||||
customer_groups: ["customer-group-1", "customer-group-3"],
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const response = await api.post("/store/carts/test-customer-discount", {
|
||||
discounts: [{ code: "TEST" }],
|
||||
})
|
||||
|
||||
const cartRes = response.data.cart
|
||||
expect(cartRes.discounts).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
code: "TEST",
|
||||
}),
|
||||
])
|
||||
)
|
||||
expect(response.status).toEqual(200)
|
||||
})
|
||||
|
||||
it("successfully applies discount in case no conditions is defined for group", async () => {
|
||||
const api = useApi()
|
||||
|
||||
await simpleCustomerFactory(dbConnection, {
|
||||
id: "cus_1234",
|
||||
email: "oli@medusajs.com",
|
||||
groups: [
|
||||
{
|
||||
id: "customer-group-1",
|
||||
name: "VIP Customer",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
await simpleCartFactory(
|
||||
dbConnection,
|
||||
{
|
||||
id: "test-customer-discount",
|
||||
region: {
|
||||
id: "test-region",
|
||||
name: "Test region",
|
||||
tax_rate: 12,
|
||||
},
|
||||
customer: "cus_1234",
|
||||
line_items: [
|
||||
{
|
||||
variant_id: "test-variant",
|
||||
unit_price: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
100
|
||||
)
|
||||
|
||||
await simpleDiscountFactory(dbConnection, {
|
||||
id: "test-discount",
|
||||
code: "TEST",
|
||||
regions: ["test-region"],
|
||||
rule: {
|
||||
type: "percentage",
|
||||
value: "10",
|
||||
allocation: "total",
|
||||
},
|
||||
})
|
||||
|
||||
const response = await api.post("/store/carts/test-customer-discount", {
|
||||
discounts: [{ code: "TEST" }],
|
||||
})
|
||||
|
||||
const cartRes = response.data.cart
|
||||
expect(cartRes.discounts).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
code: "TEST",
|
||||
}),
|
||||
])
|
||||
)
|
||||
expect(response.status).toEqual(200)
|
||||
})
|
||||
|
||||
it("fails to apply discount if customer group is part of `not_in` conditions", async () => {
|
||||
const api = useApi()
|
||||
|
||||
await simpleCustomerFactory(dbConnection, {
|
||||
id: "cus_1234",
|
||||
email: "oli@medusajs.com",
|
||||
groups: [
|
||||
{
|
||||
id: "customer-group-1",
|
||||
name: "VIP Customer",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
await simpleCartFactory(
|
||||
dbConnection,
|
||||
{
|
||||
id: "test-customer-discount",
|
||||
region: {
|
||||
id: "test-region",
|
||||
name: "Test region",
|
||||
tax_rate: 12,
|
||||
},
|
||||
customer: "cus_1234",
|
||||
line_items: [
|
||||
{
|
||||
variant_id: "test-variant",
|
||||
unit_price: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
100
|
||||
)
|
||||
|
||||
await simpleDiscountFactory(dbConnection, {
|
||||
id: "test-discount",
|
||||
code: "TEST",
|
||||
regions: ["test-region"],
|
||||
rule: {
|
||||
type: "percentage",
|
||||
value: "10",
|
||||
allocation: "total",
|
||||
conditions: [
|
||||
{
|
||||
type: "customer_groups",
|
||||
operator: "not_in",
|
||||
customer_groups: ["customer-group-1"],
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
try {
|
||||
await api.post("/store/carts/test-customer-discount", {
|
||||
discounts: [{ code: "TEST" }],
|
||||
})
|
||||
} catch (error) {
|
||||
expect(error.response.status).toEqual(400)
|
||||
expect(error.response.data.message).toEqual(
|
||||
"Discount is not valid for customer"
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("fails to apply discount if customer group is not part of `in` conditions", async () => {
|
||||
const api = useApi()
|
||||
|
||||
await simpleCustomerFactory(dbConnection, {
|
||||
id: "cus_1234",
|
||||
email: "oli@medusajs.com",
|
||||
groups: [
|
||||
{
|
||||
id: "customer-group-2",
|
||||
name: "VIP Customer",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
await simpleCustomerGroupFactory(dbConnection, {
|
||||
id: "customer-group-1",
|
||||
name: "Customer group 1",
|
||||
})
|
||||
|
||||
await simpleCartFactory(
|
||||
dbConnection,
|
||||
{
|
||||
id: "test-customer-discount",
|
||||
region: {
|
||||
id: "test-region",
|
||||
name: "Test region",
|
||||
tax_rate: 12,
|
||||
},
|
||||
customer: "cus_1234",
|
||||
line_items: [
|
||||
{
|
||||
variant_id: "test-variant",
|
||||
unit_price: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
100
|
||||
)
|
||||
|
||||
await simpleDiscountFactory(dbConnection, {
|
||||
id: "test-discount",
|
||||
code: "TEST",
|
||||
regions: ["test-region"],
|
||||
rule: {
|
||||
type: "percentage",
|
||||
value: "10",
|
||||
allocation: "total",
|
||||
conditions: [
|
||||
{
|
||||
type: "customer_groups",
|
||||
operator: "in",
|
||||
customer_groups: ["customer-group-1"],
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
try {
|
||||
await api.post("/store/carts/test-customer-discount", {
|
||||
discounts: [{ code: "TEST" }],
|
||||
})
|
||||
} catch (error) {
|
||||
expect(error.response.status).toEqual(400)
|
||||
expect(error.response.data.message).toEqual(
|
||||
"Discount is not valid for customer"
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("fails to apply expired discount", async () => {
|
||||
expect.assertions(2)
|
||||
const api = useApi()
|
||||
|
||||
Reference in New Issue
Block a user