fix: Handle region updates on cart (1/n) (#9369)
**What**
On cart creation:
- If region only has one country -> create cart with country code
On cart updates:
- If shipping address country code is provided in input ->
- If cart region doesn't include that country -> throw
- If cart includes the country -> update shipping address
- If region is provided in input and is different from the one currently on the cart ->
- If there is a shipping address on the cart -> clear the address
- If the region only has one country -> set country code of address
- If there is not a shipping address on the cart ->
- If the region only has one country -> set country code of address
Closes CC-545
This commit is contained in:
1 parent
ed174826a4
commit
a114f90358
5 files changed
+542
-79
No files matched your search
@@ -316,6 +316,49 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should create cart with shipping address country code when there is only one country assigned to the region", async () => {
|
||||||
|
const region = await regionModule.createRegions({
|
||||||
|
name: "US",
|
||||||
|
currency_code: "usd",
|
||||||
|
countries: ["us"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/store/carts`,
|
||||||
|
{
|
||||||
|
email: "tony@stark.com",
|
||||||
|
currency_code: "usd",
|
||||||
|
region_id: region.id,
|
||||||
|
},
|
||||||
|
storeHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.cart).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: response.data.cart.id,
|
||||||
|
currency_code: "usd",
|
||||||
|
email: "tony@stark.com",
|
||||||
|
region: expect.objectContaining({
|
||||||
|
id: region.id,
|
||||||
|
}),
|
||||||
|
shipping_address: {
|
||||||
|
id: expect.any(String),
|
||||||
|
country_code: "us",
|
||||||
|
first_name: null,
|
||||||
|
last_name: null,
|
||||||
|
company: null,
|
||||||
|
address_1: null,
|
||||||
|
address_2: null,
|
||||||
|
city: null,
|
||||||
|
province: null,
|
||||||
|
postal_code: null,
|
||||||
|
phone: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it("should create cart with default store sales channel", async () => {
|
it("should create cart with default store sales channel", async () => {
|
||||||
const sc = await scModule.createSalesChannels({
|
const sc = await scModule.createSalesChannels({
|
||||||
name: "Webshop",
|
name: "Webshop",
|
||||||
@@ -711,12 +754,6 @@ medusaIntegrationTestRunner({
|
|||||||
it("should not generate tax lines if region is not present or automatic taxes is false", async () => {
|
it("should not generate tax lines if region is not present or automatic taxes is false", async () => {
|
||||||
await setupTaxStructure(taxModule)
|
await setupTaxStructure(taxModule)
|
||||||
|
|
||||||
const region = await regionModule.createRegions({
|
|
||||||
name: "US",
|
|
||||||
currency_code: "usd",
|
|
||||||
automatic_taxes: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
const cart = await cartModule.createCarts({
|
const cart = await cartModule.createCarts({
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
email: "tony@stark.com",
|
email: "tony@stark.com",
|
||||||
@@ -759,13 +796,15 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
await cartModule.updateCarts(cart.id, {
|
const region = await regionModule.createRegions({
|
||||||
region_id: region.id,
|
name: "US",
|
||||||
|
currency_code: "usd",
|
||||||
|
automatic_taxes: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
updated = await api.post(
|
updated = await api.post(
|
||||||
`/store/carts/${cart.id}`,
|
`/store/carts/${cart.id}`,
|
||||||
{ email: "another@tax.com" },
|
{ email: "another@tax.com", region_id: region.id },
|
||||||
storeHeaders
|
storeHeaders
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -790,6 +829,7 @@ medusaIntegrationTestRunner({
|
|||||||
const region = await regionModule.createRegions({
|
const region = await regionModule.createRegions({
|
||||||
name: "us",
|
name: "us",
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
|
countries: ["us"],
|
||||||
})
|
})
|
||||||
|
|
||||||
const salesChannel = await scModule.createSalesChannels({
|
const salesChannel = await scModule.createSalesChannels({
|
||||||
@@ -917,19 +957,21 @@ medusaIntegrationTestRunner({
|
|||||||
}),
|
}),
|
||||||
sales_channel_id: salesChannel.id,
|
sales_channel_id: salesChannel.id,
|
||||||
shipping_address: expect.objectContaining({
|
shipping_address: expect.objectContaining({
|
||||||
city: "ny",
|
// We clear the shipping address on region update and only set the country code if the region has one country
|
||||||
|
city: null,
|
||||||
country_code: "us",
|
country_code: "us",
|
||||||
province: "ny",
|
province: null,
|
||||||
}),
|
}),
|
||||||
shipping_methods: expect.arrayContaining([
|
shipping_methods: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
shipping_option_id: shippingOption2.id,
|
shipping_option_id: shippingOption2.id,
|
||||||
amount: 500,
|
amount: 500,
|
||||||
tax_lines: [
|
tax_lines: [
|
||||||
|
// Since we clear the shipping address on region update, the tax lines are computed based on the new country code
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
description: "NY Default Rate",
|
description: "US Default Rate",
|
||||||
code: "NYDEFAULT",
|
code: "US_DEF",
|
||||||
rate: 6,
|
rate: 2,
|
||||||
provider_id: "system",
|
provider_id: "system",
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -939,10 +981,11 @@ medusaIntegrationTestRunner({
|
|||||||
shipping_option_id: shippingOption.id,
|
shipping_option_id: shippingOption.id,
|
||||||
amount: 500,
|
amount: 500,
|
||||||
tax_lines: [
|
tax_lines: [
|
||||||
|
// Since we clear the shipping address on region update, the tax lines are computed based on the new country code
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
description: "NY Default Rate",
|
description: "US Default Rate",
|
||||||
code: "NYDEFAULT",
|
code: "US_DEF",
|
||||||
rate: 6,
|
rate: 2,
|
||||||
provider_id: "system",
|
provider_id: "system",
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -954,9 +997,9 @@ medusaIntegrationTestRunner({
|
|||||||
id: "item-1",
|
id: "item-1",
|
||||||
tax_lines: [
|
tax_lines: [
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
description: "NY Default Rate",
|
description: "US Default Rate",
|
||||||
code: "NYDEFAULT",
|
code: "US_DEF",
|
||||||
rate: 6,
|
rate: 2,
|
||||||
provider_id: "system",
|
provider_id: "system",
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -966,39 +1009,39 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
updated = await api.post(
|
// updated = await api.post(
|
||||||
`/store/carts/${cart.id}`,
|
// `/store/carts/${cart.id}`,
|
||||||
{
|
// {
|
||||||
email: null,
|
// email: null,
|
||||||
sales_channel_id: null,
|
// sales_channel_id: null,
|
||||||
},
|
// },
|
||||||
storeHeaders
|
// storeHeaders
|
||||||
)
|
// )
|
||||||
|
|
||||||
expect(updated.status).toEqual(200)
|
// expect(updated.status).toEqual(200)
|
||||||
expect(updated.data.cart).toEqual(
|
// expect(updated.data.cart).toEqual(
|
||||||
expect.objectContaining({
|
// expect.objectContaining({
|
||||||
id: cart.id,
|
// id: cart.id,
|
||||||
currency_code: "usd",
|
// currency_code: "usd",
|
||||||
email: null,
|
// email: null,
|
||||||
customer_id: null,
|
// customer_id: null,
|
||||||
sales_channel_id: null,
|
// sales_channel_id: null,
|
||||||
items: [
|
// items: [
|
||||||
expect.objectContaining({
|
// expect.objectContaining({
|
||||||
id: "item-1",
|
// id: "item-1",
|
||||||
tax_lines: [
|
// tax_lines: [
|
||||||
expect.objectContaining({
|
// expect.objectContaining({
|
||||||
description: "NY Default Rate",
|
// description: "NY Default Rate",
|
||||||
code: "NYDEFAULT",
|
// code: "NYDEFAULT",
|
||||||
rate: 6,
|
// rate: 6,
|
||||||
provider_id: "system",
|
// provider_id: "system",
|
||||||
}),
|
// }),
|
||||||
],
|
// ],
|
||||||
adjustments: [],
|
// adjustments: [],
|
||||||
}),
|
// }),
|
||||||
],
|
// ],
|
||||||
})
|
// })
|
||||||
)
|
// )
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should update tax lines on cart items when region changes", async () => {
|
it("should update tax lines on cart items when region changes", async () => {
|
||||||
@@ -1132,6 +1175,364 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should update tax inclusivity on cart items when region changes", async () => {
|
||||||
|
await setupTaxStructure(taxModule)
|
||||||
|
|
||||||
|
const [region, otherRegion] = await regionModule.createRegions([
|
||||||
|
{
|
||||||
|
name: "us",
|
||||||
|
currency_code: "usd",
|
||||||
|
countries: ["us"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dk",
|
||||||
|
currency_code: "dkk",
|
||||||
|
countries: ["dk"],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const salesChannel = await scModule.createSalesChannels({
|
||||||
|
name: "Webshop",
|
||||||
|
})
|
||||||
|
|
||||||
|
const [productWithDefaultTax] = await productModule.createProducts([
|
||||||
|
{
|
||||||
|
title: "Test product default tax",
|
||||||
|
variants: [
|
||||||
|
{ title: "Test variant default tax", manage_inventory: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const [priceSetDefaultTax] = await pricingModule.createPriceSets([
|
||||||
|
{
|
||||||
|
prices: [{ amount: 2000, currency_code: "usd" }],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
await remoteLink.create([
|
||||||
|
{
|
||||||
|
Product: {
|
||||||
|
variant_id: productWithDefaultTax.variants[0].id,
|
||||||
|
},
|
||||||
|
Pricing: { price_set_id: priceSetDefaultTax.id },
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
await api.post(
|
||||||
|
"/admin/price-preferences",
|
||||||
|
{
|
||||||
|
attribute: "currency_code",
|
||||||
|
value: "usd",
|
||||||
|
is_tax_inclusive: true,
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
let response = await api.post(
|
||||||
|
`/store/carts`,
|
||||||
|
{
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
|
shipping_address: {
|
||||||
|
country_code: "us",
|
||||||
|
},
|
||||||
|
region_id: region.id,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
variant_id: productWithDefaultTax.variants[0].id,
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
storeHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.data.cart).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: response.data.cart.id,
|
||||||
|
currency_code: "usd",
|
||||||
|
region_id: region.id,
|
||||||
|
items: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
unit_price: 2000,
|
||||||
|
quantity: 1,
|
||||||
|
title: "Test variant default tax",
|
||||||
|
tax_lines: [
|
||||||
|
// Uses the california default rate
|
||||||
|
expect.objectContaining({
|
||||||
|
description: "US Default Rate",
|
||||||
|
code: "US_DEF",
|
||||||
|
rate: 2,
|
||||||
|
provider_id: "system",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
response = await api.post(
|
||||||
|
`/store/carts/${response.data.cart.id}`,
|
||||||
|
{
|
||||||
|
region_id: otherRegion.id,
|
||||||
|
shipping_address: {
|
||||||
|
country_code: "dk",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
storeHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.data.cart).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: response.data.cart.id,
|
||||||
|
currency_code: "dkk",
|
||||||
|
region_id: otherRegion.id,
|
||||||
|
items: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
unit_price: 2000,
|
||||||
|
quantity: 1,
|
||||||
|
title: "Test variant default tax",
|
||||||
|
tax_lines: [
|
||||||
|
// Uses the danish default rate
|
||||||
|
expect.objectContaining({
|
||||||
|
description: "Denmark Default Rate",
|
||||||
|
code: "DK_DEF",
|
||||||
|
rate: 25,
|
||||||
|
provider_id: "system",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should update region + set shipping address country code to dk when region has only one country", async () => {
|
||||||
|
await setupTaxStructure(taxModule)
|
||||||
|
|
||||||
|
const region = await regionModule.createRegions({
|
||||||
|
name: "us",
|
||||||
|
currency_code: "usd",
|
||||||
|
countries: ["us"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const otherRegion = await regionModule.createRegions({
|
||||||
|
name: "dk",
|
||||||
|
currency_code: "usd",
|
||||||
|
countries: ["dk"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const cart = await cartModule.createCarts({
|
||||||
|
currency_code: "eur",
|
||||||
|
region_id: region.id,
|
||||||
|
email: "tony@stark.com",
|
||||||
|
shipping_address: {
|
||||||
|
country_code: "us",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const updated = await api.post(
|
||||||
|
`/store/carts/${cart.id}`,
|
||||||
|
{
|
||||||
|
region_id: otherRegion.id,
|
||||||
|
},
|
||||||
|
storeHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(updated.status).toEqual(200)
|
||||||
|
expect(updated.data.cart).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: cart.id,
|
||||||
|
currency_code: "usd",
|
||||||
|
region: expect.objectContaining({
|
||||||
|
id: otherRegion.id,
|
||||||
|
currency_code: "usd",
|
||||||
|
countries: [expect.objectContaining({ iso_2: "dk" })],
|
||||||
|
}),
|
||||||
|
shipping_address: expect.objectContaining({
|
||||||
|
country_code: "dk",
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should update region + set shipping address to null when region has more than one country", async () => {
|
||||||
|
await setupTaxStructure(taxModule)
|
||||||
|
|
||||||
|
const region = await regionModule.createRegions({
|
||||||
|
name: "us",
|
||||||
|
currency_code: "usd",
|
||||||
|
countries: ["us"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const otherRegion = await regionModule.createRegions({
|
||||||
|
name: "dk",
|
||||||
|
currency_code: "eur",
|
||||||
|
countries: ["dk", "no"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const cart = await cartModule.createCarts({
|
||||||
|
currency_code: "eur",
|
||||||
|
region_id: region.id,
|
||||||
|
email: "tony@stark.com",
|
||||||
|
shipping_address: {
|
||||||
|
country_code: "us",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const updated = await api.post(
|
||||||
|
`/store/carts/${cart.id}`,
|
||||||
|
{
|
||||||
|
region_id: otherRegion.id,
|
||||||
|
},
|
||||||
|
storeHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(updated.status).toEqual(200)
|
||||||
|
expect(updated.data.cart).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: cart.id,
|
||||||
|
currency_code: "eur",
|
||||||
|
region: expect.objectContaining({
|
||||||
|
id: otherRegion.id,
|
||||||
|
currency_code: "eur",
|
||||||
|
countries: [
|
||||||
|
expect.objectContaining({ iso_2: "dk" }),
|
||||||
|
expect.objectContaining({ iso_2: "no" }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
shipping_address: null,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should update region and shipping address when country code is within region", async () => {
|
||||||
|
await setupTaxStructure(taxModule)
|
||||||
|
|
||||||
|
const region = await regionModule.createRegions({
|
||||||
|
name: "us",
|
||||||
|
currency_code: "usd",
|
||||||
|
countries: ["us"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const otherRegion = await regionModule.createRegions({
|
||||||
|
name: "dk",
|
||||||
|
currency_code: "eur",
|
||||||
|
countries: ["dk", "no"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const cart = await cartModule.createCarts({
|
||||||
|
currency_code: "eur",
|
||||||
|
region_id: region.id,
|
||||||
|
email: "tony@stark.com",
|
||||||
|
shipping_address: {
|
||||||
|
country_code: "us",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const updated = await api.post(
|
||||||
|
`/store/carts/${cart.id}`,
|
||||||
|
{
|
||||||
|
region_id: otherRegion.id,
|
||||||
|
shipping_address: {
|
||||||
|
country_code: "dk",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
storeHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(updated.status).toEqual(200)
|
||||||
|
expect(updated.data.cart).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: cart.id,
|
||||||
|
currency_code: "eur",
|
||||||
|
region: expect.objectContaining({
|
||||||
|
id: otherRegion.id,
|
||||||
|
currency_code: "eur",
|
||||||
|
countries: [
|
||||||
|
expect.objectContaining({ iso_2: "dk" }),
|
||||||
|
expect.objectContaining({ iso_2: "no" }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
shipping_address: expect.objectContaining({
|
||||||
|
country_code: "dk",
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw when updating shipping address country code when country is not within region", async () => {
|
||||||
|
await setupTaxStructure(taxModule)
|
||||||
|
|
||||||
|
const region = await regionModule.createRegions({
|
||||||
|
name: "Unites States",
|
||||||
|
currency_code: "usd",
|
||||||
|
countries: ["us"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const cart = await cartModule.createCarts({
|
||||||
|
currency_code: "eur",
|
||||||
|
email: "tony@stark.com",
|
||||||
|
region_id: region.id,
|
||||||
|
shipping_address: {
|
||||||
|
country_code: "us",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
let errResponse = await api
|
||||||
|
.post(
|
||||||
|
`/store/carts/${cart.id}`,
|
||||||
|
{
|
||||||
|
shipping_address: {
|
||||||
|
country_code: "dk",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
storeHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(errResponse.response.status).toEqual(400)
|
||||||
|
expect(errResponse.response.data.message).toEqual(
|
||||||
|
`Country with code dk is not within region ${region.name}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw when updating region and shipping address, but shipping address country code is not within region", async () => {
|
||||||
|
await setupTaxStructure(taxModule)
|
||||||
|
|
||||||
|
const region = await regionModule.createRegions({
|
||||||
|
name: "Unites States",
|
||||||
|
currency_code: "usd",
|
||||||
|
countries: ["us"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const cart = await cartModule.createCarts({
|
||||||
|
currency_code: "eur",
|
||||||
|
email: "tony@stark.com",
|
||||||
|
shipping_address: {
|
||||||
|
country_code: "us",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
let errResponse = await api
|
||||||
|
.post(
|
||||||
|
`/store/carts/${cart.id}`,
|
||||||
|
{
|
||||||
|
region_id: region.id,
|
||||||
|
shipping_address: {
|
||||||
|
country_code: "dk",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
storeHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(errResponse.response.status).toEqual(400)
|
||||||
|
expect(errResponse.response.data.message).toEqual(
|
||||||
|
`Country with code dk is not within region ${region.name}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it("should remove invalid shipping methods", async () => {
|
it("should remove invalid shipping methods", async () => {
|
||||||
await setupTaxStructure(taxModule)
|
await setupTaxStructure(taxModule)
|
||||||
|
|
||||||
@@ -1714,9 +2115,10 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.cart.items).toHaveLength(2)
|
||||||
expect(response.data.cart).toEqual(
|
expect(response.data.cart).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
items: [
|
items: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
unit_price: 1500,
|
unit_price: 1500,
|
||||||
quantity: 2,
|
quantity: 2,
|
||||||
@@ -1727,7 +2129,7 @@ medusaIntegrationTestRunner({
|
|||||||
quantity: 1,
|
quantity: 1,
|
||||||
title: "S / Black",
|
title: "S / Black",
|
||||||
}),
|
}),
|
||||||
],
|
]),
|
||||||
subtotal: 4500,
|
subtotal: 4500,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ export const findOneOrAnyRegionStep = createStep(
|
|||||||
|
|
||||||
if (data.regionId) {
|
if (data.regionId) {
|
||||||
try {
|
try {
|
||||||
const region = await service.retrieveRegion(data.regionId)
|
const region = await service.retrieveRegion(data.regionId, {
|
||||||
|
relations: ["countries"],
|
||||||
|
})
|
||||||
return new StepResponse(region)
|
return new StepResponse(region)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return new StepResponse(null)
|
return new StepResponse(null)
|
||||||
@@ -31,9 +33,12 @@ export const findOneOrAnyRegionStep = createStep(
|
|||||||
throw new MedusaError(MedusaError.Types.NOT_FOUND, "Store not found")
|
throw new MedusaError(MedusaError.Types.NOT_FOUND, "Store not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
const [region] = await service.listRegions({
|
const [region] = await service.listRegions(
|
||||||
|
{
|
||||||
id: store.default_region_id,
|
id: store.default_region_id,
|
||||||
})
|
},
|
||||||
|
{ relations: ["countries"] }
|
||||||
|
)
|
||||||
|
|
||||||
if (!region) {
|
if (!region) {
|
||||||
return new StepResponse(null)
|
return new StepResponse(null)
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ import { refreshPaymentCollectionForCartWorkflow } from "./refresh-payment-colle
|
|||||||
import { updateCartPromotionsWorkflow } from "./update-cart-promotions"
|
import { updateCartPromotionsWorkflow } from "./update-cart-promotions"
|
||||||
import { updateTaxLinesWorkflow } from "./update-tax-lines"
|
import { updateTaxLinesWorkflow } from "./update-tax-lines"
|
||||||
|
|
||||||
// TODO: The createCartWorkflow are missing the following steps:
|
|
||||||
// - Refresh/delete shipping methods (fulfillment module)
|
|
||||||
|
|
||||||
export const createCartWorkflowId = "create-cart"
|
export const createCartWorkflowId = "create-cart"
|
||||||
/**
|
/**
|
||||||
* This workflow creates a cart.
|
* This workflow creates a cart.
|
||||||
@@ -119,6 +116,13 @@ export const createCartWorkflow = createWorkflow(
|
|||||||
data_.sales_channel_id = data.salesChannel.id
|
data_.sales_channel_id = data.salesChannel.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there is only one country in the region, we prepare a shipping address with that country's code.
|
||||||
|
if (!data.input.shipping_address && data.region.countries.length === 1) {
|
||||||
|
data_.shipping_address = {
|
||||||
|
country_code: data.region.countries[0].iso_2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return data_
|
return data_
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,11 +2,7 @@ import {
|
|||||||
AdditionalData,
|
AdditionalData,
|
||||||
UpdateCartWorkflowInputDTO,
|
UpdateCartWorkflowInputDTO,
|
||||||
} from "@medusajs/framework/types"
|
} from "@medusajs/framework/types"
|
||||||
import {
|
import { MedusaError, PromotionActions } from "@medusajs/framework/utils"
|
||||||
MedusaError,
|
|
||||||
PromotionActions,
|
|
||||||
isPresent,
|
|
||||||
} from "@medusajs/framework/utils"
|
|
||||||
import {
|
import {
|
||||||
WorkflowData,
|
WorkflowData,
|
||||||
WorkflowResponse,
|
WorkflowResponse,
|
||||||
@@ -14,10 +10,10 @@ import {
|
|||||||
createWorkflow,
|
createWorkflow,
|
||||||
parallelize,
|
parallelize,
|
||||||
transform,
|
transform,
|
||||||
|
when,
|
||||||
} from "@medusajs/framework/workflows-sdk"
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
import { useRemoteQueryStep } from "../../common"
|
import { useRemoteQueryStep } from "../../common"
|
||||||
import {
|
import {
|
||||||
findOneOrAnyRegionStep,
|
|
||||||
findOrCreateCustomerStep,
|
findOrCreateCustomerStep,
|
||||||
findSalesChannelStep,
|
findSalesChannelStep,
|
||||||
refreshCartShippingMethodsStep,
|
refreshCartShippingMethodsStep,
|
||||||
@@ -35,35 +31,85 @@ export const updateCartWorkflowId = "update-cart"
|
|||||||
export const updateCartWorkflow = createWorkflow(
|
export const updateCartWorkflow = createWorkflow(
|
||||||
updateCartWorkflowId,
|
updateCartWorkflowId,
|
||||||
(input: WorkflowData<UpdateCartWorkflowInputDTO & AdditionalData>) => {
|
(input: WorkflowData<UpdateCartWorkflowInputDTO & AdditionalData>) => {
|
||||||
const [salesChannel, region, customerData] = parallelize(
|
const cartToUpdate = useRemoteQueryStep({
|
||||||
|
entry_point: "cart",
|
||||||
|
variables: { id: input.id },
|
||||||
|
fields: ["id", "shipping_address.*", "region.*", "region.countries.*"],
|
||||||
|
list: false,
|
||||||
|
throw_if_key_not_found: true,
|
||||||
|
}).config({ name: "get-cart" })
|
||||||
|
|
||||||
|
const [salesChannel, customerData] = parallelize(
|
||||||
findSalesChannelStep({
|
findSalesChannelStep({
|
||||||
salesChannelId: input.sales_channel_id,
|
salesChannelId: input.sales_channel_id,
|
||||||
}),
|
}),
|
||||||
findOneOrAnyRegionStep({
|
|
||||||
regionId: input.region_id,
|
|
||||||
}),
|
|
||||||
findOrCreateCustomerStep({
|
findOrCreateCustomerStep({
|
||||||
customerId: input.customer_id,
|
customerId: input.customer_id,
|
||||||
email: input.email,
|
email: input.email,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const newRegion = when({ input }, (data) => {
|
||||||
|
return !!data.input.region_id
|
||||||
|
}).then(() => {
|
||||||
|
return useRemoteQueryStep({
|
||||||
|
entry_point: "region",
|
||||||
|
variables: { id: input.region_id },
|
||||||
|
fields: ["id", "countries.*", "currency_code", "name"],
|
||||||
|
list: false,
|
||||||
|
throw_if_key_not_found: true,
|
||||||
|
}).config({ name: "get-region" })
|
||||||
|
})
|
||||||
|
|
||||||
|
const region = transform({ cartToUpdate, newRegion }, (data) => {
|
||||||
|
return data.newRegion ?? data.cartToUpdate.region
|
||||||
|
})
|
||||||
|
|
||||||
const cartInput = transform(
|
const cartInput = transform(
|
||||||
{ input, region, customerData, salesChannel },
|
{ input, region, customerData, salesChannel, cartToUpdate },
|
||||||
(data) => {
|
(data) => {
|
||||||
const { promo_codes, ...updateCartData } = data.input
|
const { promo_codes, ...updateCartData } = data.input
|
||||||
const data_ = { ...updateCartData }
|
|
||||||
|
|
||||||
if (isPresent(updateCartData.region_id)) {
|
const data_ = {
|
||||||
if (!data.region) {
|
...updateCartData,
|
||||||
|
currency_code: data.region?.currency_code,
|
||||||
|
region_id: data.region?.id, // This is either the region from the input or the region from the cart or null
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the region is updated, we do a few things:
|
||||||
|
// - We need to make sure the provided shipping address country code is in the new region
|
||||||
|
// - We clear the shipping address if the new region has more than one country
|
||||||
|
const regionIsNew = data.region?.id !== data.cartToUpdate.region?.id
|
||||||
|
const shippingAddress = data.input.shipping_address
|
||||||
|
|
||||||
|
if (shippingAddress?.country_code) {
|
||||||
|
const country = data.region.countries.find(
|
||||||
|
(c) => c.iso_2 === shippingAddress.country_code
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!country) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.NOT_FOUND,
|
MedusaError.Types.INVALID_DATA,
|
||||||
"Region not found"
|
`Country with code ${shippingAddress.country_code} is not within region ${data.region.name}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
data_.currency_code = data.region.currency_code
|
data_.shipping_address = {
|
||||||
data_.region_id = data.region.id
|
...shippingAddress,
|
||||||
|
country_code: country.iso_2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regionIsNew) {
|
||||||
|
if (data.region.countries.length === 1) {
|
||||||
|
data_.shipping_address = {
|
||||||
|
country_code: data.region.countries[0].iso_2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data_.shipping_address?.country_code) {
|
||||||
|
data_.shipping_address = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -5,7 +5,11 @@ import { ProductDTO } from "../product"
|
|||||||
import { RegionDTO } from "../region"
|
import { RegionDTO } from "../region"
|
||||||
import { BigNumberInput } from "../totals"
|
import { BigNumberInput } from "../totals"
|
||||||
import { CartDTO, CartLineItemDTO } from "./common"
|
import { CartDTO, CartLineItemDTO } from "./common"
|
||||||
import { UpdateLineItemDTO } from "./mutations"
|
import {
|
||||||
|
CreateAddressDTO,
|
||||||
|
UpdateAddressDTO,
|
||||||
|
UpdateLineItemDTO,
|
||||||
|
} from "./mutations"
|
||||||
|
|
||||||
export interface CreateCartCreateLineItemDTO {
|
export interface CreateCartCreateLineItemDTO {
|
||||||
quantity: BigNumberInput
|
quantity: BigNumberInput
|
||||||
@@ -89,6 +93,8 @@ export interface UpdateCartWorkflowInputDTO {
|
|||||||
email?: string | null
|
email?: string | null
|
||||||
currency_code?: string
|
currency_code?: string
|
||||||
metadata?: Record<string, unknown> | null
|
metadata?: Record<string, unknown> | null
|
||||||
|
shipping_address?: CreateAddressDTO | UpdateAddressDTO | null
|
||||||
|
billing_address?: CreateAddressDTO | UpdateAddressDTO | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreatePaymentCollectionForCartWorkflowInputDTO {
|
export interface CreatePaymentCollectionForCartWorkflowInputDTO {
|
||||||
|
|||||||
Reference in new issue
Block a user