feat(medusa,pricing): Cart pricing context with customer group (#10579)

* fix(carts): Fixes cart modifications not accounting for certain price lists (#10493)

*What*

* Fixes #10490
* Expands any available customer_id into its customer_group_ids for cart
  updates that add line items.

*Why*

* Cart updates from the storefront were overriding any valid price lists
  that were correctly being shown in the storefront's product pages.

*How*

* Adds a new workflow step that expands an optional customer_id into the
  customer_group_ids it belongs to.
* Uses this step in the addToCartWorkflow and
  updateLineItemInCartWorkflow workflows.

*Testing*
* Using medusa-dev to test on a local backend.
* Adds integration tests for the addToCart and updateLineItemInCart
  workflows.

Co-authored-by: Riqwan Thamir <rmthamir@gmail.com>

* chore: update cart workflows to accept new pricing context

* chore: add transfer specs

* chore: fix specs

* chore: modify types + specs

* chore: add data migration + dashboard changes

* chore: fix update line item workflow

* chore: add changeset + unskip spec

---------

Co-authored-by: Sergio Campamá <sergiocampama@gmail.com>
This commit is contained in:
Riqwan Thamir
2024-12-17 11:10:30 +01:00
committed by GitHub
parent 0c49470066
commit 6367bccde8
29 changed files with 1090 additions and 166 deletions

View File

@@ -271,7 +271,7 @@ medusaIntegrationTestRunner({
shipping_address: shippingAddressData,
items: [{ variant_id: product.variants[0].id, quantity: 1 }],
},
storeHeadersWithCustomer
storeHeaders
)
expect(response.status).toEqual(200)
@@ -414,7 +414,7 @@ medusaIntegrationTestRunner({
items: [{ variant_id: product.variants[0].id, quantity: 1 }],
promo_codes: [promotion.code],
},
storeHeadersWithCustomer
storeHeaders
)
).data.cart
})
@@ -643,28 +643,61 @@ medusaIntegrationTestRunner({
})
describe("with sale price lists", () => {
let priceList
beforeEach(async () => {
priceList = (
await api.post(
`/admin/price-lists`,
{
title: "test price list",
description: "test",
status: PriceListStatus.ACTIVE,
type: PriceListType.SALE,
prices: [
{
amount: 350,
currency_code: "usd",
variant_id: product.variants[0].id,
},
],
},
adminHeaders
)
const customerGroup = (
await api.post(
`/admin/price-lists`,
{
title: "test price list",
description: "test",
status: PriceListStatus.ACTIVE,
type: PriceListType.SALE,
prices: [
{
amount: 350,
currency_code: "usd",
variant_id: product.variants[0].id,
},
],
},
"/admin/customer-groups",
{ name: "VIP" },
adminHeaders
)
).data.price_list
).data.customer_group
await api.post(
`/admin/customer-groups/${customerGroup.id}/customers`,
{
add: [customer.id],
},
adminHeaders
)
await api.post(
`/admin/price-lists`,
{
title: "test price list",
description: "test",
status: PriceListStatus.ACTIVE,
type: PriceListType.SALE,
prices: [
{
amount: 200,
currency_code: "usd",
variant_id: product.variants[0].id,
},
],
rules: {
"customer.groups.id": [customerGroup.id],
},
},
adminHeaders
)
})
it("should add price from price list and set compare_at_unit_price", async () => {
@@ -709,6 +742,158 @@ medusaIntegrationTestRunner({
})
)
})
it("should add price from price list associated to a customer group when customer rules match", async () => {
const transferredCart = (
await api.post(
`/store/carts/${cart.id}/customer`,
{},
storeHeadersWithCustomer
)
).data.cart
expect(transferredCart).toEqual(
expect.objectContaining({
id: cart.id,
items: expect.arrayContaining([
expect.objectContaining({
unit_price: 200,
compare_at_unit_price: 1500,
is_tax_inclusive: true,
quantity: 1,
}),
]),
})
)
let response = await api.post(
`/store/carts/${cart.id}/line-items`,
{
variant_id: product.variants[0].id,
quantity: 1,
},
storeHeadersWithCustomer
)
expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: cart.id,
currency_code: "usd",
items: expect.arrayContaining([
expect.objectContaining({
unit_price: 200,
compare_at_unit_price: 1500,
is_tax_inclusive: true,
quantity: 2,
}),
]),
})
)
})
})
})
describe("POST /store/carts/:id/line-items/:id", () => {
let item, customerGroup
beforeEach(async () => {
cart = (
await api.post(
`/store/carts`,
{
currency_code: "usd",
sales_channel_id: salesChannel.id,
region_id: region.id,
shipping_address: shippingAddressData,
items: [{ variant_id: product.variants[0].id, quantity: 1 }],
},
storeHeadersWithCustomer
)
).data.cart
item = cart.items[0]
customerGroup = (
await api.post(
"/admin/customer-groups",
{ name: "VIP" },
adminHeaders
)
).data.customer_group
await api.post(
`/admin/customer-groups/${customerGroup.id}/customers`,
{
add: [customer.id],
},
adminHeaders
)
})
it("should update cart's line item", async () => {
let response = await api.post(
`/store/carts/${cart.id}/line-items/${item.id}`,
{
quantity: 2,
},
storeHeaders
)
expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: cart.id,
currency_code: "usd",
items: expect.arrayContaining([
expect.objectContaining({
unit_price: 1500,
quantity: 2,
}),
]),
})
)
await api.post(
`/admin/price-lists`,
{
title: "test price list",
description: "test",
status: PriceListStatus.ACTIVE,
type: PriceListType.SALE,
prices: [
{
amount: 200,
currency_code: "usd",
variant_id: product.variants[0].id,
},
],
rules: {
"customer.groups.id": [customerGroup.id],
},
},
adminHeaders
)
response = await api.post(
`/store/carts/${cart.id}/line-items/${item.id}`,
{ quantity: 3 },
storeHeaders
)
expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: cart.id,
currency_code: "usd",
items: expect.arrayContaining([
expect.objectContaining({
unit_price: 200,
quantity: 3,
}),
]),
})
)
})
})

View File

@@ -1,7 +1,7 @@
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
import {
createAdminUser,
adminHeaders,
createAdminUser,
} from "../../../../helpers/create-admin-user"
import {
getPricelistFixture,
@@ -102,7 +102,7 @@ medusaIntegrationTestRunner({
description:
"Summer sale for VIP customers. 25% off selected items.",
rules: {
customer_group_id: [customerGroup1.id],
"customer.groups.id": [customerGroup1.id],
},
prices: [
{
@@ -139,7 +139,7 @@ medusaIntegrationTestRunner({
starts_at: "2022-07-01T00:00:00.000Z",
ends_at: "2022-07-31T00:00:00.000Z",
rules: {
customer_group_id: [expect.stringContaining("cusgroup_")],
"customer.groups.id": [expect.stringContaining("cusgroup_")],
},
prices: [
expect.objectContaining({
@@ -335,7 +335,7 @@ medusaIntegrationTestRunner({
starts_at: "2022-09-01T00:00:00.000Z",
ends_at: "2022-12-31T00:00:00.000Z",
rules: {
customer_group_id: [customerGroup1.id],
"customer.groups.id": [customerGroup1.id],
},
}
@@ -372,7 +372,7 @@ medusaIntegrationTestRunner({
}),
]),
rules: {
customer_group_id: [customerGroup1.id],
"customer.groups.id": [customerGroup1.id],
},
created_at: expect.any(String),
updated_at: expect.any(String),

View File

@@ -1105,7 +1105,7 @@ medusaIntegrationTestRunner({
variant_id: product.variants[0].id,
},
],
rules: { customer_group_id: [customerGroup.id] },
rules: { "customer.groups.id": [customerGroup.id] },
},
adminHeaders
)
@@ -1188,7 +1188,7 @@ medusaIntegrationTestRunner({
variant_id: product.variants[0].id,
},
],
rules: { customer_group_id: [customerGroup.id] },
rules: { "customer.groups.id": [customerGroup.id] },
},
adminHeaders
)
@@ -1783,7 +1783,7 @@ medusaIntegrationTestRunner({
variant_id: product.variants[0].id,
},
],
rules: { customer_group_id: [customerGroup.id] },
rules: { "customer.groups.id": [customerGroup.id] },
},
adminHeaders
)
@@ -1863,7 +1863,7 @@ medusaIntegrationTestRunner({
variant_id: product.variants[0].id,
},
],
rules: { customer_group_id: [customerGroup.id] },
rules: { "customer.groups.id": [customerGroup.id] },
},
adminHeaders
)