feat(core-flows,dashboard,types,fulfillment,medusa): uses requires shipping throughout lifecycle (#9170)
what: - uses requires shipping throughout lifecycle https://github.com/user-attachments/assets/d5ba89d3-5ea0-49c4-b2d5-490c4764933e
This commit is contained in:
@@ -1,10 +1,30 @@
|
||||
import {
|
||||
AdminInventoryItem,
|
||||
AdminProduct,
|
||||
AdminStockLocation,
|
||||
MedusaContainer,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
adminHeaders,
|
||||
generatePublishableKey,
|
||||
generateStoreHeaders,
|
||||
} from "../../../helpers/create-admin-user"
|
||||
|
||||
export async function createOrderSeeder({ api, container }) {
|
||||
export async function createOrderSeeder({
|
||||
api,
|
||||
container,
|
||||
productOverride,
|
||||
additionalProducts,
|
||||
stockChannelOverride,
|
||||
inventoryItemOverride,
|
||||
}: {
|
||||
api: any
|
||||
container: MedusaContainer
|
||||
productOverride?: AdminProduct
|
||||
stockChannelOverride?: AdminStockLocation
|
||||
additionalProducts?: AdminProduct[]
|
||||
inventoryItemOverride?: AdminInventoryItem
|
||||
}) {
|
||||
const publishableKey = await generatePublishableKey(container)
|
||||
const storeHeaders = generateStoreHeaders({ publishableKey })
|
||||
|
||||
@@ -24,21 +44,25 @@ export async function createOrderSeeder({ api, container }) {
|
||||
)
|
||||
).data.sales_channel
|
||||
|
||||
const stockLocation = (
|
||||
await api.post(
|
||||
`/admin/stock-locations`,
|
||||
{ name: "test location" },
|
||||
adminHeaders
|
||||
)
|
||||
).data.stock_location
|
||||
const stockLocation =
|
||||
stockChannelOverride ??
|
||||
(
|
||||
await api.post(
|
||||
`/admin/stock-locations`,
|
||||
{ name: "test location" },
|
||||
adminHeaders
|
||||
)
|
||||
).data.stock_location
|
||||
|
||||
const inventoryItem = (
|
||||
await api.post(
|
||||
`/admin/inventory-items`,
|
||||
{ sku: "test-variant" },
|
||||
adminHeaders
|
||||
)
|
||||
).data.inventory_item
|
||||
const inventoryItem =
|
||||
inventoryItemOverride ??
|
||||
(
|
||||
await api.post(
|
||||
`/admin/inventory-items`,
|
||||
{ sku: "test-variant" },
|
||||
adminHeaders
|
||||
)
|
||||
).data.inventory_item
|
||||
|
||||
await api.post(
|
||||
`/admin/inventory-items/${inventoryItem.id}/location-levels`,
|
||||
@@ -63,41 +87,43 @@ export async function createOrderSeeder({ api, container }) {
|
||||
)
|
||||
).data.shipping_profile
|
||||
|
||||
const product = (
|
||||
await api.post(
|
||||
"/admin/products",
|
||||
{
|
||||
title: `Test fixture ${shippingProfile.id}`,
|
||||
options: [
|
||||
{ title: "size", values: ["large", "small"] },
|
||||
{ title: "color", values: ["green"] },
|
||||
],
|
||||
variants: [
|
||||
{
|
||||
title: "Test variant",
|
||||
sku: "test-variant",
|
||||
inventory_items: [
|
||||
{
|
||||
inventory_item_id: inventoryItem.id,
|
||||
required_quantity: 1,
|
||||
const product =
|
||||
productOverride ??
|
||||
(
|
||||
await api.post(
|
||||
"/admin/products",
|
||||
{
|
||||
title: `Test fixture ${shippingProfile.id}`,
|
||||
options: [
|
||||
{ title: "size", values: ["large", "small"] },
|
||||
{ title: "color", values: ["green"] },
|
||||
],
|
||||
variants: [
|
||||
{
|
||||
title: "Test variant",
|
||||
sku: "test-variant",
|
||||
inventory_items: [
|
||||
{
|
||||
inventory_item_id: inventoryItem.id,
|
||||
required_quantity: 1,
|
||||
},
|
||||
],
|
||||
prices: [
|
||||
{
|
||||
currency_code: "usd",
|
||||
amount: 100,
|
||||
},
|
||||
],
|
||||
options: {
|
||||
size: "large",
|
||||
color: "green",
|
||||
},
|
||||
],
|
||||
prices: [
|
||||
{
|
||||
currency_code: "usd",
|
||||
amount: 100,
|
||||
},
|
||||
],
|
||||
options: {
|
||||
size: "large",
|
||||
color: "green",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
).data.product
|
||||
],
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
).data.product
|
||||
|
||||
const fulfillmentSets = (
|
||||
await api.post(
|
||||
@@ -167,7 +193,13 @@ export async function createOrderSeeder({ api, container }) {
|
||||
postal_code: "94016",
|
||||
},
|
||||
sales_channel_id: salesChannel.id,
|
||||
items: [{ quantity: 1, variant_id: product.variants[0].id }],
|
||||
items: [
|
||||
{ quantity: 1, variant_id: product.variants[0].id },
|
||||
...(additionalProducts || []).map((p) => ({
|
||||
quantity: 1,
|
||||
variant_id: p.variants?.[0]?.id,
|
||||
})),
|
||||
],
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
@@ -18,13 +18,192 @@ medusaIntegrationTestRunner({
|
||||
|
||||
await setupTaxStructure(container.resolve(ModuleRegistrationName.TAX))
|
||||
await createAdminUser(dbConnection, adminHeaders, container)
|
||||
seeder = await createOrderSeeder({ api, container })
|
||||
order = seeder.order
|
||||
order = (await api.get(`/admin/orders/${order.id}`, adminHeaders)).data
|
||||
.order
|
||||
})
|
||||
|
||||
describe("POST /orders/:id/fulfillments", () => {
|
||||
beforeEach(async () => {
|
||||
const stockChannelOverride = (
|
||||
await api.post(
|
||||
`/admin/stock-locations`,
|
||||
{ name: "test location" },
|
||||
adminHeaders
|
||||
)
|
||||
).data.stock_location
|
||||
|
||||
const inventoryItemOverride = (
|
||||
await api.post(
|
||||
`/admin/inventory-items`,
|
||||
{ sku: "test-variant", requires_shipping: true },
|
||||
adminHeaders
|
||||
)
|
||||
).data.inventory_item
|
||||
|
||||
const productOverride = (
|
||||
await api.post(
|
||||
"/admin/products",
|
||||
{
|
||||
title: `Test fixture`,
|
||||
options: [
|
||||
{ title: "size", values: ["large", "small"] },
|
||||
{ title: "color", values: ["green"] },
|
||||
],
|
||||
variants: [
|
||||
{
|
||||
title: "Test variant",
|
||||
sku: "test-variant",
|
||||
inventory_items: [
|
||||
{
|
||||
inventory_item_id: inventoryItemOverride.id,
|
||||
required_quantity: 1,
|
||||
},
|
||||
],
|
||||
prices: [
|
||||
{
|
||||
currency_code: "usd",
|
||||
amount: 100,
|
||||
},
|
||||
],
|
||||
options: {
|
||||
size: "large",
|
||||
color: "green",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
).data.product
|
||||
|
||||
const inventoryItemOverride2 = (
|
||||
await api.post(
|
||||
`/admin/inventory-items`,
|
||||
{ sku: "test-variant-2", requires_shipping: false },
|
||||
adminHeaders
|
||||
)
|
||||
).data.inventory_item
|
||||
|
||||
await api.post(
|
||||
`/admin/inventory-items/${inventoryItemOverride2.id}/location-levels`,
|
||||
{
|
||||
location_id: stockChannelOverride.id,
|
||||
stocked_quantity: 10,
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
const productOverride2 = (
|
||||
await api.post(
|
||||
"/admin/products",
|
||||
{
|
||||
title: `Test fixture 2`,
|
||||
options: [
|
||||
{ title: "size", values: ["large", "small"] },
|
||||
{ title: "color", values: ["green"] },
|
||||
],
|
||||
variants: [
|
||||
{
|
||||
title: "Test variant 2",
|
||||
sku: "test-variant-2",
|
||||
inventory_items: [
|
||||
{
|
||||
inventory_item_id: inventoryItemOverride2.id,
|
||||
required_quantity: 1,
|
||||
},
|
||||
],
|
||||
prices: [
|
||||
{
|
||||
currency_code: "usd",
|
||||
amount: 100,
|
||||
},
|
||||
],
|
||||
options: {
|
||||
size: "large",
|
||||
color: "green",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
).data.product
|
||||
|
||||
seeder = await createOrderSeeder({
|
||||
api,
|
||||
container: getContainer(),
|
||||
productOverride,
|
||||
additionalProducts: [productOverride2],
|
||||
stockChannelOverride,
|
||||
inventoryItemOverride,
|
||||
})
|
||||
order = seeder.order
|
||||
order = (await api.get(`/admin/orders/${order.id}`, adminHeaders)).data
|
||||
.order
|
||||
})
|
||||
|
||||
it("should only create fulfillments grouped by shipping requirement", async () => {
|
||||
const {
|
||||
response: { data },
|
||||
} = await api
|
||||
.post(
|
||||
`/admin/orders/${order.id}/fulfillments`,
|
||||
{
|
||||
location_id: seeder.stockLocation.id,
|
||||
items: [
|
||||
{
|
||||
id: order.items[0].id,
|
||||
quantity: 1,
|
||||
},
|
||||
{
|
||||
id: order.items[1].id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
.catch((e) => e)
|
||||
|
||||
expect(data).toEqual({
|
||||
type: "invalid_data",
|
||||
message: `Fulfillment can only be created entirely with items with shipping or items without shipping. Split this request into 2 fulfillments.`,
|
||||
})
|
||||
|
||||
const {
|
||||
data: { order: fulfillableOrder },
|
||||
} = await api.post(
|
||||
`/admin/orders/${order.id}/fulfillments?fields=+fulfillments.id,fulfillments.requires_shipping`,
|
||||
{
|
||||
location_id: seeder.stockLocation.id,
|
||||
items: [{ id: order.items[0].id, quantity: 1 }],
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(fulfillableOrder.fulfillments).toHaveLength(1)
|
||||
|
||||
const {
|
||||
data: { order: fulfillableOrder2 },
|
||||
} = await api.post(
|
||||
`/admin/orders/${order.id}/fulfillments?fields=+fulfillments.id,fulfillments.requires_shipping`,
|
||||
{
|
||||
location_id: seeder.stockLocation.id,
|
||||
items: [{ id: order.items[1].id, quantity: 1 }],
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(fulfillableOrder2.fulfillments).toHaveLength(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /orders/:id/fulfillments/:id/mark-as-delivered", () => {
|
||||
beforeEach(async () => {
|
||||
seeder = await createOrderSeeder({ api, container: getContainer() })
|
||||
order = seeder.order
|
||||
order = (await api.get(`/admin/orders/${order.id}`, adminHeaders)).data
|
||||
.order
|
||||
})
|
||||
|
||||
it("should mark fulfillable item as delivered", async () => {
|
||||
let fulfillableItem = order.items.find(
|
||||
(item) => item.detail.fulfilled_quantity < item.detail.quantity
|
||||
|
||||
Reference in New Issue
Block a user