feat(core-flows, types): calculated shipping in RMA flows (#11533)
* wip: calculated SO pricing in RMA flows * fix: types * chore: small refactor * feat: caluclated shipping in return flow * fix: module integrations * fix: array containing * feat: refresh shipping on update item quantity * rm: log * rm: log2 * feat: update interface, remove flag * fix: revert change on OE for now * fix: import * feat: refactor flwos, cleanup cacluation cotext data model, wip exchanges * feat: refreshing inbound/outbound shipping on items change * feat: refresh exchange shipping on return item add, test * feat: refresh shipping on exchange/return item remove * fix: check optional * feat: test recalculation on quantity update * feat: calculated shipping on claims * fix: comment * wip: address comments * fix: more remote query, fix build * refactor: claim refresh workflow * fix: remove throw option * fix: deconstruct param --------- Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
1 parent
053326950d
commit
de8c034d1b
31 files changed
+1864
-86
No files matched your search
@@ -33,9 +33,15 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.fulfillment_providers).toEqual([
|
expect(response.data.fulfillment_providers).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
{ id: "manual_test-provider", is_enabled: true },
|
{ id: "manual_test-provider", is_enabled: true },
|
||||||
|
{
|
||||||
|
id: "manual-calculated_test-provider-calculated",
|
||||||
|
is_enabled: true,
|
||||||
|
},
|
||||||
])
|
])
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,14 +13,22 @@ import {
|
|||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
|
|
||||||
const providerId = "manual_test-provider"
|
const providerId = "manual_test-provider"
|
||||||
|
const providerIdCalculated = "manual-calculated_test-provider-calculated"
|
||||||
|
|
||||||
export async function prepareDataFixtures({ container }) {
|
export async function prepareDataFixtures({ container }) {
|
||||||
const fulfillmentService = container.resolve(Modules.FULFILLMENT)
|
const fulfillmentService = container.resolve(Modules.FULFILLMENT)
|
||||||
const salesChannelService = container.resolve(Modules.SALES_CHANNEL)
|
const salesChannelService = container.resolve(Modules.SALES_CHANNEL)
|
||||||
const stockLocationModule: IStockLocationService = container.resolve(
|
const stockLocationModule: IStockLocationService = container.resolve(
|
||||||
Modules.STOCK_LOCATION
|
Modules.STOCK_LOCATION
|
||||||
)
|
)
|
||||||
|
const pricingModule = container.resolve(Modules.PRICING)
|
||||||
const productModule = container.resolve(Modules.PRODUCT)
|
const productModule = container.resolve(Modules.PRODUCT)
|
||||||
const inventoryModule = container.resolve(Modules.INVENTORY)
|
const inventoryModule = container.resolve(Modules.INVENTORY)
|
||||||
|
const customerService = container.resolve(Modules.CUSTOMER)
|
||||||
|
|
||||||
|
const customer = await customerService.createCustomers({
|
||||||
|
email: "foo@bar.com",
|
||||||
|
})
|
||||||
|
|
||||||
const shippingProfile = await fulfillmentService.createShippingProfiles({
|
const shippingProfile = await fulfillmentService.createShippingProfiles({
|
||||||
name: "test",
|
name: "test",
|
||||||
@@ -71,6 +79,18 @@ export async function prepareDataFixtures({ container }) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const priceSets = await pricingModule.createPriceSets([
|
||||||
|
{
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
amount: 10,
|
||||||
|
region_id: region.id,
|
||||||
|
currency_code: "usd",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
const [product] = await productModule.createProducts([
|
const [product] = await productModule.createProducts([
|
||||||
{
|
{
|
||||||
title: "Test product",
|
title: "Test product",
|
||||||
@@ -91,7 +111,7 @@ export async function prepareDataFixtures({ container }) {
|
|||||||
{
|
{
|
||||||
inventory_item_id: inventoryItem.id,
|
inventory_item_id: inventoryItem.id,
|
||||||
location_id: location.id,
|
location_id: location.id,
|
||||||
stocked_quantity: 2,
|
stocked_quantity: 10,
|
||||||
reserved_quantity: 0,
|
reserved_quantity: 0,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@@ -123,6 +143,14 @@ export async function prepareDataFixtures({ container }) {
|
|||||||
inventory_item_id: inventoryItem.id,
|
inventory_item_id: inventoryItem.id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
[Modules.PRODUCT]: {
|
||||||
|
variant_id: product.variants[0].id,
|
||||||
|
},
|
||||||
|
[Modules.PRICING]: {
|
||||||
|
price_set_id: priceSets[0].id,
|
||||||
|
},
|
||||||
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
await remoteLink.create([
|
await remoteLink.create([
|
||||||
@@ -131,7 +159,16 @@ export async function prepareDataFixtures({ container }) {
|
|||||||
stock_location_id: location.id,
|
stock_location_id: location.id,
|
||||||
},
|
},
|
||||||
[Modules.FULFILLMENT]: {
|
[Modules.FULFILLMENT]: {
|
||||||
fulfillment_provider_id: "manual_test-provider",
|
fulfillment_provider_id: providerId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
[Modules.STOCK_LOCATION]: {
|
||||||
|
stock_location_id: location.id,
|
||||||
|
},
|
||||||
|
[Modules.FULFILLMENT]: {
|
||||||
|
fulfillment_provider_id: providerIdCalculated,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@@ -160,14 +197,29 @@ export async function prepareDataFixtures({ container }) {
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const shippingOptionCalculatedData: FulfillmentWorkflow.CreateShippingOptionsWorkflowInput =
|
||||||
|
{
|
||||||
|
name: "Calculated shipping option",
|
||||||
|
service_zone_id: serviceZone.id,
|
||||||
|
shipping_profile_id: shippingProfile.id,
|
||||||
|
provider_id: providerIdCalculated,
|
||||||
|
price_type: "calculated",
|
||||||
|
type: {
|
||||||
|
label: "Test type",
|
||||||
|
description: "Test description",
|
||||||
|
code: "test-code",
|
||||||
|
},
|
||||||
|
rules: [],
|
||||||
|
}
|
||||||
|
|
||||||
const { result } = await createShippingOptionsWorkflow(container).run({
|
const { result } = await createShippingOptionsWorkflow(container).run({
|
||||||
input: [shippingOptionData],
|
input: [shippingOptionData, shippingOptionCalculatedData],
|
||||||
})
|
})
|
||||||
|
|
||||||
const remoteQueryObject = remoteQueryObjectFromString({
|
const remoteQueryObject = remoteQueryObjectFromString({
|
||||||
entryPoint: "shipping_option",
|
entryPoint: "shipping_option",
|
||||||
variables: {
|
variables: {
|
||||||
id: result[0].id,
|
id: result.map((r) => r.id),
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
"id",
|
"id",
|
||||||
@@ -189,13 +241,17 @@ export async function prepareDataFixtures({ container }) {
|
|||||||
|
|
||||||
const remoteQuery = container.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
const remoteQuery = container.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
|
||||||
const [createdShippingOption] = await remoteQuery(remoteQueryObject)
|
const shippingOptions = await remoteQuery(remoteQueryObject)
|
||||||
return {
|
return {
|
||||||
shippingOption: createdShippingOption,
|
shippingOption: shippingOptions.find((s) => s.price_type === "flat"),
|
||||||
|
shippingOptionCalculated: shippingOptions.find(
|
||||||
|
(s) => s.price_type === "calculated"
|
||||||
|
),
|
||||||
region,
|
region,
|
||||||
salesChannel,
|
salesChannel,
|
||||||
location,
|
location,
|
||||||
product,
|
product,
|
||||||
|
customer,
|
||||||
inventoryItem,
|
inventoryItem,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,18 +261,31 @@ export async function createOrderFixture({
|
|||||||
product,
|
product,
|
||||||
location,
|
location,
|
||||||
inventoryItem,
|
inventoryItem,
|
||||||
|
region,
|
||||||
|
salesChannel,
|
||||||
|
customer,
|
||||||
|
overrides,
|
||||||
|
}: {
|
||||||
|
container: any
|
||||||
|
product: any
|
||||||
|
location: any
|
||||||
|
inventoryItem: any
|
||||||
|
salesChannel?: any
|
||||||
|
customer?: any
|
||||||
|
region?: any
|
||||||
|
overrides?: { quantity?: number }
|
||||||
}) {
|
}) {
|
||||||
const orderService: IOrderModuleService = container.resolve(Modules.ORDER)
|
const orderService: IOrderModuleService = container.resolve(Modules.ORDER)
|
||||||
|
|
||||||
let order = await orderService.createOrders({
|
let order = await orderService.createOrders({
|
||||||
region_id: "test_region_id",
|
region_id: region?.id || "test_region_id",
|
||||||
email: "foo@bar.com",
|
email: customer?.email || "foo@bar.com",
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
title: "Custom Item 2",
|
title: "Custom Item 2",
|
||||||
variant_sku: product.variants[0].sku,
|
variant_sku: product.variants[0].sku,
|
||||||
variant_title: product.variants[0].title,
|
variant_title: product.variants[0].title,
|
||||||
quantity: 1,
|
quantity: overrides?.quantity ?? 1,
|
||||||
unit_price: 50,
|
unit_price: 50,
|
||||||
adjustments: [
|
adjustments: [
|
||||||
{
|
{
|
||||||
@@ -235,7 +304,7 @@ export async function createOrderFixture({
|
|||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
sales_channel_id: "test",
|
sales_channel_id: salesChannel?.id || "test",
|
||||||
shipping_address: {
|
shipping_address: {
|
||||||
first_name: "Test",
|
first_name: "Test",
|
||||||
last_name: "Test",
|
last_name: "Test",
|
||||||
@@ -277,7 +346,7 @@ export async function createOrderFixture({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
customer_id: "joe",
|
customer_id: customer?.id || "joe",
|
||||||
})
|
})
|
||||||
|
|
||||||
const inventoryModule = container.resolve(Modules.INVENTORY)
|
const inventoryModule = container.resolve(Modules.INVENTORY)
|
||||||
|
|||||||
@@ -0,0 +1,212 @@
|
|||||||
|
import {
|
||||||
|
beginClaimOrderWorkflow,
|
||||||
|
createClaimShippingMethodWorkflow,
|
||||||
|
createOrderFulfillmentWorkflow,
|
||||||
|
orderClaimAddNewItemWorkflow,
|
||||||
|
orderClaimRequestItemReturnWorkflow,
|
||||||
|
updateClaimAddItemWorkflow,
|
||||||
|
} from "@medusajs/core-flows"
|
||||||
|
import { IFulfillmentModuleService, OrderDTO } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
Modules,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||||
|
import { createOrderFixture, prepareDataFixtures } from "../__fixtures__"
|
||||||
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
|
medusaIntegrationTestRunner({
|
||||||
|
env: { MEDUSA_FF_MEDUSA_V2: true },
|
||||||
|
testSuite: ({ getContainer }) => {
|
||||||
|
let container
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
container = getContainer()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Order change: Claim shipping", () => {
|
||||||
|
let order: OrderDTO
|
||||||
|
let service: IFulfillmentModuleService
|
||||||
|
let fixtures
|
||||||
|
|
||||||
|
let claimOrder: OrderDTO
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
fixtures = await prepareDataFixtures({ container })
|
||||||
|
|
||||||
|
order = await createOrderFixture({
|
||||||
|
container,
|
||||||
|
product: fixtures.product,
|
||||||
|
location: fixtures.location,
|
||||||
|
inventoryItem: fixtures.inventoryItem,
|
||||||
|
salesChannel: fixtures.salesChannel,
|
||||||
|
customer: fixtures.customer,
|
||||||
|
region: fixtures.region,
|
||||||
|
overrides: { quantity: 2 },
|
||||||
|
})
|
||||||
|
|
||||||
|
await createOrderFulfillmentWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
order_id: order.id,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
quantity: 2,
|
||||||
|
id: order.items![0].id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await beginClaimOrderWorkflow(container).run({
|
||||||
|
input: { order_id: order.id, type: "replace" },
|
||||||
|
throwOnError: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const remoteQuery = container.resolve(
|
||||||
|
ContainerRegistrationKeys.REMOTE_QUERY
|
||||||
|
)
|
||||||
|
|
||||||
|
const remoteQueryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "order_claim",
|
||||||
|
variables: { order_id: order.id },
|
||||||
|
fields: ["order_id", "id", "status", "order_change_id"],
|
||||||
|
})
|
||||||
|
|
||||||
|
service = container.resolve(Modules.FULFILLMENT)
|
||||||
|
;[claimOrder] = await remoteQuery(remoteQueryObject)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("createClaimShippingMethodWorkflow", () => {
|
||||||
|
it("should successfully add caluclated inbound and outbound shipping to order changes", async () => {
|
||||||
|
const { result } = await orderClaimAddNewItemWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
claim_id: claimOrder.id,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
variant_id: fixtures.product.variants[0].id,
|
||||||
|
quantity: 1,
|
||||||
|
internal_note: "test",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const shippingOptionId = fixtures.shippingOptionCalculated.id
|
||||||
|
|
||||||
|
const { result: orderChangePreview } =
|
||||||
|
await createClaimShippingMethodWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
claim_id: claimOrder.id,
|
||||||
|
shipping_option_id: shippingOptionId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Original shipping + outbound
|
||||||
|
expect(orderChangePreview.shipping_methods).toHaveLength(2)
|
||||||
|
|
||||||
|
const outboundShippingMethod =
|
||||||
|
orderChangePreview.shipping_methods?.find(
|
||||||
|
(sm) => sm.shipping_option_id === shippingOptionId
|
||||||
|
)
|
||||||
|
|
||||||
|
expect((outboundShippingMethod as any).actions).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
reference: "order_shipping_method",
|
||||||
|
reference_id: expect.any(String),
|
||||||
|
raw_amount: { value: "2.5", precision: 20 },
|
||||||
|
return_id: null,
|
||||||
|
claim_id: claimOrder.id,
|
||||||
|
applied: false,
|
||||||
|
action: "SHIPPING_ADD",
|
||||||
|
amount: 2.5,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
const { result: orderChangePreview2 } =
|
||||||
|
await orderClaimRequestItemReturnWorkflow.run({
|
||||||
|
container,
|
||||||
|
input: {
|
||||||
|
claim_id: claimOrder.id,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: result.items[0].id,
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const associatedReturnId = orderChangePreview2.order_change.return_id
|
||||||
|
|
||||||
|
const { result: orderChangePreview3 } =
|
||||||
|
await createClaimShippingMethodWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
claim_id: claimOrder.id,
|
||||||
|
return_id: associatedReturnId,
|
||||||
|
shipping_option_id: shippingOptionId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(orderChangePreview3.shipping_methods).toHaveLength(3)
|
||||||
|
|
||||||
|
const inboundShippingMethod =
|
||||||
|
orderChangePreview3.shipping_methods?.find(
|
||||||
|
(sm) =>
|
||||||
|
sm.shipping_option_id === shippingOptionId &&
|
||||||
|
sm.actions?.find(
|
||||||
|
(a) =>
|
||||||
|
a.action === "SHIPPING_ADD" &&
|
||||||
|
a.return_id === associatedReturnId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(inboundShippingMethod!.actions![0]).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
return_id: associatedReturnId,
|
||||||
|
claim_id: claimOrder.id,
|
||||||
|
applied: false,
|
||||||
|
action: "SHIPPING_ADD",
|
||||||
|
amount: 2,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update outbound quantity to test refresh caluclation
|
||||||
|
|
||||||
|
const { result: orderChangePreview4 } =
|
||||||
|
await updateClaimAddItemWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
claim_id: claimOrder.id,
|
||||||
|
action_id: result.items.find(
|
||||||
|
(i) => i.variant_id === fixtures.product.variants[0].id
|
||||||
|
)?.actions?.[0]?.id as string,
|
||||||
|
data: {
|
||||||
|
quantity: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const outboundShippingMethod2 =
|
||||||
|
orderChangePreview4.shipping_methods?.find(
|
||||||
|
(sm) => sm.shipping_option_id === shippingOptionId
|
||||||
|
)
|
||||||
|
|
||||||
|
expect((outboundShippingMethod2 as any).actions).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
reference: "order_shipping_method",
|
||||||
|
reference_id: expect.any(String),
|
||||||
|
raw_amount: { value: "5", precision: 20 },
|
||||||
|
return_id: null,
|
||||||
|
claim_id: claimOrder.id,
|
||||||
|
applied: false,
|
||||||
|
action: "SHIPPING_ADD",
|
||||||
|
amount: 5,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
+214
@@ -0,0 +1,214 @@
|
|||||||
|
import {
|
||||||
|
beginExchangeOrderWorkflow,
|
||||||
|
createExchangeShippingMethodWorkflow,
|
||||||
|
createOrderFulfillmentWorkflow,
|
||||||
|
orderExchangeAddNewItemWorkflow,
|
||||||
|
orderExchangeRequestItemReturnWorkflow,
|
||||||
|
updateExchangeAddItemWorkflow,
|
||||||
|
} from "@medusajs/core-flows"
|
||||||
|
import { IFulfillmentModuleService, OrderDTO } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
Modules,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||||
|
import { createOrderFixture, prepareDataFixtures } from "../__fixtures__"
|
||||||
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
|
medusaIntegrationTestRunner({
|
||||||
|
env: { MEDUSA_FF_MEDUSA_V2: true },
|
||||||
|
testSuite: ({ getContainer }) => {
|
||||||
|
let container
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
container = getContainer()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Order change: Exchange shipping", () => {
|
||||||
|
let order: OrderDTO
|
||||||
|
let service: IFulfillmentModuleService
|
||||||
|
let fixtures
|
||||||
|
|
||||||
|
let exchangeOrder: OrderDTO
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
fixtures = await prepareDataFixtures({ container })
|
||||||
|
|
||||||
|
order = await createOrderFixture({
|
||||||
|
container,
|
||||||
|
product: fixtures.product,
|
||||||
|
location: fixtures.location,
|
||||||
|
inventoryItem: fixtures.inventoryItem,
|
||||||
|
salesChannel: fixtures.salesChannel,
|
||||||
|
customer: fixtures.customer,
|
||||||
|
region: fixtures.region,
|
||||||
|
overrides: { quantity: 2 },
|
||||||
|
})
|
||||||
|
|
||||||
|
await createOrderFulfillmentWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
order_id: order.id,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
quantity: 2,
|
||||||
|
id: order.items![0].id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await beginExchangeOrderWorkflow(container).run({
|
||||||
|
input: { order_id: order.id },
|
||||||
|
throwOnError: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const remoteQuery = container.resolve(
|
||||||
|
ContainerRegistrationKeys.REMOTE_QUERY
|
||||||
|
)
|
||||||
|
|
||||||
|
const remoteQueryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "order_exchange",
|
||||||
|
variables: { order_id: order.id },
|
||||||
|
fields: ["order_id", "id", "status", "order_change_id"],
|
||||||
|
})
|
||||||
|
|
||||||
|
service = container.resolve(Modules.FULFILLMENT)
|
||||||
|
;[exchangeOrder] = await remoteQuery(remoteQueryObject)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("createExchangeShippingMethodWorkflow", () => {
|
||||||
|
it("should successfully add caluclated inbound and outbound shipping to order changes", async () => {
|
||||||
|
const { result } = await orderExchangeAddNewItemWorkflow(
|
||||||
|
container
|
||||||
|
).run({
|
||||||
|
input: {
|
||||||
|
exchange_id: exchangeOrder.id,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
variant_id: fixtures.product.variants[0].id,
|
||||||
|
quantity: 1,
|
||||||
|
internal_note: "test",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const shippingOptionId = fixtures.shippingOptionCalculated.id
|
||||||
|
|
||||||
|
const { result: orderChangePreview } =
|
||||||
|
await createExchangeShippingMethodWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
exchange_id: exchangeOrder.id,
|
||||||
|
shipping_option_id: shippingOptionId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Original shipping + outbound
|
||||||
|
expect(orderChangePreview.shipping_methods).toHaveLength(2)
|
||||||
|
|
||||||
|
const outboundShippingMethod =
|
||||||
|
orderChangePreview.shipping_methods?.find(
|
||||||
|
(sm) => sm.shipping_option_id === shippingOptionId
|
||||||
|
)
|
||||||
|
|
||||||
|
expect((outboundShippingMethod as any).actions).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
reference: "order_shipping_method",
|
||||||
|
reference_id: expect.any(String),
|
||||||
|
raw_amount: { value: "2.5", precision: 20 },
|
||||||
|
return_id: null,
|
||||||
|
exchange_id: exchangeOrder.id,
|
||||||
|
applied: false,
|
||||||
|
action: "SHIPPING_ADD",
|
||||||
|
amount: 2.5,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
const { result: orderChangePreview2 } =
|
||||||
|
await orderExchangeRequestItemReturnWorkflow.run({
|
||||||
|
container,
|
||||||
|
input: {
|
||||||
|
exchange_id: exchangeOrder.id,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: result.items[0].id,
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const associatedReturnId = orderChangePreview2.order_change.return_id
|
||||||
|
|
||||||
|
const { result: orderChangePreview3 } =
|
||||||
|
await createExchangeShippingMethodWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
exchange_id: exchangeOrder.id,
|
||||||
|
return_id: associatedReturnId,
|
||||||
|
shipping_option_id: shippingOptionId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(orderChangePreview3.shipping_methods).toHaveLength(3)
|
||||||
|
|
||||||
|
const inboundShippingMethod =
|
||||||
|
orderChangePreview3.shipping_methods?.find(
|
||||||
|
(sm) =>
|
||||||
|
sm.shipping_option_id === shippingOptionId &&
|
||||||
|
sm.actions?.find(
|
||||||
|
(a) =>
|
||||||
|
a.action === "SHIPPING_ADD" &&
|
||||||
|
a.return_id === associatedReturnId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(inboundShippingMethod!.actions![0]).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
return_id: associatedReturnId,
|
||||||
|
exchange_id: exchangeOrder.id,
|
||||||
|
applied: false,
|
||||||
|
action: "SHIPPING_ADD",
|
||||||
|
amount: 2,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update outbound quantity to test refresh caluclation
|
||||||
|
|
||||||
|
const { result: orderChangePreview4 } =
|
||||||
|
await updateExchangeAddItemWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
exchange_id: exchangeOrder.id,
|
||||||
|
action_id: result.items.find(
|
||||||
|
(i) => i.variant_id === fixtures.product.variants[0].id
|
||||||
|
)?.actions?.[0]?.id as string,
|
||||||
|
data: {
|
||||||
|
quantity: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const outboundShippingMethod2 =
|
||||||
|
orderChangePreview4.shipping_methods?.find(
|
||||||
|
(sm) => sm.shipping_option_id === shippingOptionId
|
||||||
|
)
|
||||||
|
|
||||||
|
expect((outboundShippingMethod2 as any).actions).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
reference: "order_shipping_method",
|
||||||
|
reference_id: expect.any(String),
|
||||||
|
raw_amount: { value: "5", precision: 20 },
|
||||||
|
return_id: null,
|
||||||
|
exchange_id: exchangeOrder.id,
|
||||||
|
applied: false,
|
||||||
|
action: "SHIPPING_ADD",
|
||||||
|
amount: 5,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
+131
-1
@@ -1,6 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
beginReturnOrderWorkflow,
|
beginReturnOrderWorkflow,
|
||||||
|
createOrderFulfillmentWorkflow,
|
||||||
createReturnShippingMethodWorkflow,
|
createReturnShippingMethodWorkflow,
|
||||||
|
requestItemReturnWorkflow,
|
||||||
|
updateRequestItemReturnWorkflow,
|
||||||
} from "@medusajs/core-flows"
|
} from "@medusajs/core-flows"
|
||||||
import { IFulfillmentModuleService, OrderDTO, ReturnDTO } from "@medusajs/types"
|
import { IFulfillmentModuleService, OrderDTO, ReturnDTO } from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
@@ -10,7 +13,6 @@ import {
|
|||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||||
import { createOrderFixture, prepareDataFixtures } from "../__fixtures__"
|
import { createOrderFixture, prepareDataFixtures } from "../__fixtures__"
|
||||||
|
|
||||||
jest.setTimeout(50000)
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
medusaIntegrationTestRunner({
|
medusaIntegrationTestRunner({
|
||||||
@@ -37,6 +39,19 @@ medusaIntegrationTestRunner({
|
|||||||
product: fixtures.product,
|
product: fixtures.product,
|
||||||
location: fixtures.location,
|
location: fixtures.location,
|
||||||
inventoryItem: fixtures.inventoryItem,
|
inventoryItem: fixtures.inventoryItem,
|
||||||
|
overrides: { quantity: 2 },
|
||||||
|
})
|
||||||
|
|
||||||
|
await createOrderFulfillmentWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
order_id: order.id,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
quantity: 2,
|
||||||
|
id: order.items![0].id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
await beginReturnOrderWorkflow(container).run({
|
await beginReturnOrderWorkflow(container).run({
|
||||||
@@ -115,6 +130,121 @@ medusaIntegrationTestRunner({
|
|||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should successfully add calculated return shipping to order changes", async () => {
|
||||||
|
const shippingOptionId = fixtures.shippingOptionCalculated.id
|
||||||
|
|
||||||
|
const { result: orderChangePreview } =
|
||||||
|
await createReturnShippingMethodWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
return_id: returnOrder.id,
|
||||||
|
shipping_option_id: shippingOptionId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const shippingMethod = orderChangePreview.shipping_methods?.find(
|
||||||
|
(sm) => sm.shipping_option_id === shippingOptionId
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shipping is 0 because the shipping option is calculated based on the return items
|
||||||
|
* and currently there are no return items.
|
||||||
|
*/
|
||||||
|
|
||||||
|
expect((shippingMethod as any).actions).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
reference: "order_shipping_method",
|
||||||
|
reference_id: expect.any(String),
|
||||||
|
raw_amount: { value: "0", precision: 20 },
|
||||||
|
applied: false,
|
||||||
|
action: "SHIPPING_ADD",
|
||||||
|
amount: 0,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
const { result } = await requestItemReturnWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
return_id: returnOrder.id,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: order.items![0].id,
|
||||||
|
quantity: 1,
|
||||||
|
internal_note: "test",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(result.items[0].actions)
|
||||||
|
|
||||||
|
let updatedShippingMethod = result.shipping_methods?.find(
|
||||||
|
(sm) => sm.shipping_option_id === shippingOptionId
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caluclated shipping is 2$ per return item.
|
||||||
|
*/
|
||||||
|
expect(updatedShippingMethod).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
shipping_option_id: shippingOptionId,
|
||||||
|
amount: 2,
|
||||||
|
actions: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
reference: "order_shipping_method",
|
||||||
|
reference_id: expect.any(String),
|
||||||
|
raw_amount: { value: "2", precision: 20 },
|
||||||
|
applied: false,
|
||||||
|
action: "SHIPPING_ADD",
|
||||||
|
amount: 2,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
/**
|
||||||
|
* Update the return item quantity to 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { result: updatedResult } =
|
||||||
|
await updateRequestItemReturnWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
return_id: returnOrder.id,
|
||||||
|
action_id: result.items
|
||||||
|
.find((i) =>
|
||||||
|
i.actions?.find((a) => a.action === "RETURN_ITEM")
|
||||||
|
)
|
||||||
|
?.actions?.find((a) => a.action === "RETURN_ITEM")?.id!,
|
||||||
|
data: {
|
||||||
|
quantity: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
updatedShippingMethod = updatedResult.shipping_methods?.find(
|
||||||
|
(sm) => sm.shipping_option_id === shippingOptionId
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(updatedShippingMethod).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
shipping_option_id: shippingOptionId,
|
||||||
|
amount: 4,
|
||||||
|
actions: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
reference: "order_shipping_method",
|
||||||
|
reference_id: expect.any(String),
|
||||||
|
raw_amount: { value: "4", precision: 20 },
|
||||||
|
applied: false,
|
||||||
|
action: "SHIPPING_ADD",
|
||||||
|
amount: 4,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ const customFulfillmentProvider = {
|
|||||||
id: "test-provider",
|
id: "test-provider",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customFulfillmentProviderCalculated = {
|
||||||
|
resolve: require("./dist/utils/providers/fulfillment-manual-calculated")
|
||||||
|
.default,
|
||||||
|
id: "test-provider-calculated",
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
admin: {
|
admin: {
|
||||||
disable: true,
|
disable: true,
|
||||||
@@ -96,7 +102,10 @@ module.exports = {
|
|||||||
[Modules.FULFILLMENT]: {
|
[Modules.FULFILLMENT]: {
|
||||||
/** @type {import('@medusajs/fulfillment').FulfillmentModuleOptions} */
|
/** @type {import('@medusajs/fulfillment').FulfillmentModuleOptions} */
|
||||||
options: {
|
options: {
|
||||||
providers: [customFulfillmentProvider],
|
providers: [
|
||||||
|
customFulfillmentProvider,
|
||||||
|
customFulfillmentProviderCalculated,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[Modules.NOTIFICATION]: {
|
[Modules.NOTIFICATION]: {
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { ModuleProvider, Modules } from "@medusajs/framework/utils"
|
||||||
|
import { ManualFulfillmentService } from "./services/manual-fulfillment"
|
||||||
|
|
||||||
|
const services = [ManualFulfillmentService]
|
||||||
|
|
||||||
|
export default ModuleProvider(Modules.FULFILLMENT, {
|
||||||
|
services,
|
||||||
|
})
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
import { AbstractFulfillmentProviderService } from "@medusajs/framework/utils"
|
||||||
|
|
||||||
|
export class ManualFulfillmentService extends AbstractFulfillmentProviderService {
|
||||||
|
static identifier = "manual-calculated"
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFulfillmentOptions() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: "manual-fulfillment-calculated",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "manual-fulfillment-return-calculated",
|
||||||
|
is_return: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
async validateFulfillmentData(optionData, data, context) {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
async calculatePrice(optionData, data, context) {
|
||||||
|
if (context.exchange_id) {
|
||||||
|
return {
|
||||||
|
calculated_amount:
|
||||||
|
context.exchange_items.reduce((acc, i) => acc + i.quantity, 0) * 2.5, // mock return cost as 2 per item
|
||||||
|
is_calculated_price_tax_inclusive: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (context.claim_id) {
|
||||||
|
return {
|
||||||
|
calculated_amount:
|
||||||
|
context.claim_items.reduce((acc, i) => acc + i.quantity, 0) * 2.5, // mock return cost as 2 per item
|
||||||
|
is_calculated_price_tax_inclusive: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.return_id) {
|
||||||
|
return {
|
||||||
|
calculated_amount:
|
||||||
|
context.return_items.reduce((acc, i) => acc + i.quantity, 0) * 2, // mock return cost as 2 per item
|
||||||
|
is_calculated_price_tax_inclusive: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
calculated_amount:
|
||||||
|
context.items.reduce((acc, i) => acc + i.quantity, 0) * 1.5, // mock caluclation as 1.5 per item
|
||||||
|
is_calculated_price_tax_inclusive: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async canCalculate() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
async validateOption(data) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
async createFulfillment() {
|
||||||
|
// No data is being sent anywhere
|
||||||
|
return {
|
||||||
|
data: {},
|
||||||
|
labels: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async cancelFulfillment() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
async createReturnFulfillment() {
|
||||||
|
return { data: {}, labels: [] }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,8 @@ import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
|||||||
/**
|
/**
|
||||||
* The data to calculate the prices for one or more shipping options.
|
* The data to calculate the prices for one or more shipping options.
|
||||||
*/
|
*/
|
||||||
export type CalculateShippingOptionsPriceStepInput = CalculateShippingOptionPriceDTO[]
|
export type CalculateShippingOptionsPriceStepInput =
|
||||||
|
CalculateShippingOptionPriceDTO[]
|
||||||
|
|
||||||
export const calculateShippingOptionsPricesStepId =
|
export const calculateShippingOptionsPricesStepId =
|
||||||
"calculate-shipping-options-prices"
|
"calculate-shipping-options-prices"
|
||||||
|
|||||||
@@ -0,0 +1,210 @@
|
|||||||
|
import {
|
||||||
|
BigNumberInput,
|
||||||
|
CalculatedRMAShippingContext,
|
||||||
|
CalculateShippingOptionPriceDTO,
|
||||||
|
ShippingOptionDTO,
|
||||||
|
} from "@medusajs/framework/types"
|
||||||
|
import {
|
||||||
|
WorkflowResponse,
|
||||||
|
createWorkflow,
|
||||||
|
transform,
|
||||||
|
when,
|
||||||
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { BigNumber, ShippingOptionPriceType } from "@medusajs/framework/utils"
|
||||||
|
import { calculateShippingOptionsPricesStep } from "../../fulfillment/steps"
|
||||||
|
import { useRemoteQueryStep } from "../../common"
|
||||||
|
|
||||||
|
const COMMON_OPTIONS_FIELDS = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"price_type",
|
||||||
|
"service_zone_id",
|
||||||
|
"service_zone.fulfillment_set_id",
|
||||||
|
"service_zone.fulfillment_set.type",
|
||||||
|
"service_zone.fulfillment_set.location.*",
|
||||||
|
"service_zone.fulfillment_set.location.address.*",
|
||||||
|
"shipping_profile_id",
|
||||||
|
"provider_id",
|
||||||
|
"data",
|
||||||
|
|
||||||
|
"type.id",
|
||||||
|
"type.label",
|
||||||
|
"type.description",
|
||||||
|
"type.code",
|
||||||
|
|
||||||
|
"provider.id",
|
||||||
|
"provider.is_enabled",
|
||||||
|
|
||||||
|
"rules.attribute",
|
||||||
|
"rules.value",
|
||||||
|
"rules.operator",
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data to create a shipping method for an order edit.
|
||||||
|
*/
|
||||||
|
export type FetchShippingOptionForOrderWorkflowInput = {
|
||||||
|
/**
|
||||||
|
* The ID of the shipping option to create the shipping method from.
|
||||||
|
*/
|
||||||
|
shipping_option_id: string
|
||||||
|
/**
|
||||||
|
* The custom amount to create the shipping method with.
|
||||||
|
* If not provided, the shipping option's amount is used.
|
||||||
|
*/
|
||||||
|
custom_amount?: BigNumberInput | null
|
||||||
|
/**
|
||||||
|
* The currency code of the order.
|
||||||
|
*/
|
||||||
|
currency_code: string
|
||||||
|
/**
|
||||||
|
* The ID of the order.
|
||||||
|
*/
|
||||||
|
order_id: string
|
||||||
|
/**
|
||||||
|
* The context of the order.
|
||||||
|
*/
|
||||||
|
context: CalculatedRMAShippingContext
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The output of the fetch shipping option for order workflow.
|
||||||
|
*/
|
||||||
|
export type FetchShippingOptionForOrderWorkflowOutput = ShippingOptionDTO & {
|
||||||
|
calculated_price: {
|
||||||
|
calculated_amount: BigNumber
|
||||||
|
is_calculated_price_tax_inclusive: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const createOrderEditShippingMethodWorkflowId = "fetch-shipping-option"
|
||||||
|
/**
|
||||||
|
* This workflows fetches a shipping option for an order (used in RMA flows).
|
||||||
|
*
|
||||||
|
* There can be 3 cases:
|
||||||
|
* 1. The shipping option is a flat rate shipping option.
|
||||||
|
* In this case, pricing calculation context is not used.
|
||||||
|
* 2. The shipping option is a calculated shipping option.
|
||||||
|
* In this case, calculate shipping price method from the provider is called.
|
||||||
|
* 3. The shipping option is a custom shipping option. -- TODO
|
||||||
|
* In this case, we don't need to do caluclations above and just return the shipping option with the custom amount.
|
||||||
|
*/
|
||||||
|
export const fetchShippingOptionForOrderWorkflow = createWorkflow(
|
||||||
|
createOrderEditShippingMethodWorkflowId,
|
||||||
|
function (
|
||||||
|
input: FetchShippingOptionForOrderWorkflowInput
|
||||||
|
): WorkflowResponse<FetchShippingOptionForOrderWorkflowOutput> {
|
||||||
|
const initialOption = useRemoteQueryStep({
|
||||||
|
entry_point: "shipping_option",
|
||||||
|
variables: { id: input.shipping_option_id },
|
||||||
|
fields: ["id", "price_type"],
|
||||||
|
list: false,
|
||||||
|
}).config({ name: "shipping-option-query" })
|
||||||
|
|
||||||
|
const isCalculatedPriceShippingOption = transform(
|
||||||
|
initialOption,
|
||||||
|
(option) => option.price_type === ShippingOptionPriceType.CALCULATED
|
||||||
|
)
|
||||||
|
|
||||||
|
const calculatedPriceShippingOption = when(
|
||||||
|
"option-calculated",
|
||||||
|
{ isCalculatedPriceShippingOption },
|
||||||
|
({ isCalculatedPriceShippingOption }) => isCalculatedPriceShippingOption
|
||||||
|
).then(() => {
|
||||||
|
const order = useRemoteQueryStep({
|
||||||
|
entry_point: "orders",
|
||||||
|
fields: ["id", "shipping_address", "items.*", "items.variant.*"],
|
||||||
|
variables: { id: input.order_id },
|
||||||
|
list: false,
|
||||||
|
throw_if_key_not_found: true,
|
||||||
|
}).config({ name: "order-query" })
|
||||||
|
|
||||||
|
const shippingOption = useRemoteQueryStep({
|
||||||
|
entry_point: "shipping_option",
|
||||||
|
fields: [...COMMON_OPTIONS_FIELDS],
|
||||||
|
variables: { id: input.shipping_option_id },
|
||||||
|
list: false,
|
||||||
|
}).config({ name: "calculated-option" })
|
||||||
|
|
||||||
|
const calculateShippingOptionsPricesData = transform(
|
||||||
|
{
|
||||||
|
shippingOption,
|
||||||
|
order,
|
||||||
|
input,
|
||||||
|
},
|
||||||
|
({ shippingOption, order, input }) => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: shippingOption.id as string,
|
||||||
|
optionData: shippingOption.data,
|
||||||
|
context: {
|
||||||
|
...order,
|
||||||
|
...input.context,
|
||||||
|
from_location:
|
||||||
|
shippingOption.service_zone.fulfillment_set.location,
|
||||||
|
},
|
||||||
|
// data: {}, // TODO: add data
|
||||||
|
provider_id: shippingOption.provider_id,
|
||||||
|
} as CalculateShippingOptionPriceDTO,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const prices = calculateShippingOptionsPricesStep(
|
||||||
|
calculateShippingOptionsPricesData
|
||||||
|
)
|
||||||
|
|
||||||
|
const shippingOptionsWithPrice = transform(
|
||||||
|
{
|
||||||
|
shippingOption,
|
||||||
|
prices,
|
||||||
|
},
|
||||||
|
({ shippingOption, prices }) => {
|
||||||
|
return {
|
||||||
|
id: shippingOption.id,
|
||||||
|
name: shippingOption.name,
|
||||||
|
calculated_price: prices[0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return shippingOptionsWithPrice
|
||||||
|
})
|
||||||
|
|
||||||
|
const flatRateShippingOption = when(
|
||||||
|
"option-flat",
|
||||||
|
{ isCalculatedPriceShippingOption },
|
||||||
|
({ isCalculatedPriceShippingOption }) => !isCalculatedPriceShippingOption
|
||||||
|
).then(() => {
|
||||||
|
const shippingOption = useRemoteQueryStep({
|
||||||
|
entry_point: "shipping_option",
|
||||||
|
fields: [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"calculated_price.calculated_amount",
|
||||||
|
"calculated_price.is_calculated_price_tax_inclusive",
|
||||||
|
],
|
||||||
|
variables: {
|
||||||
|
id: input.shipping_option_id,
|
||||||
|
calculated_price: {
|
||||||
|
context: { currency_code: input.currency_code },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
list: false,
|
||||||
|
}).config({ name: "flat-reate-option" })
|
||||||
|
|
||||||
|
return shippingOption
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = transform(
|
||||||
|
{
|
||||||
|
calculatedPriceShippingOption,
|
||||||
|
flatRateShippingOption,
|
||||||
|
},
|
||||||
|
({ calculatedPriceShippingOption, flatRateShippingOption }) => {
|
||||||
|
return calculatedPriceShippingOption ?? flatRateShippingOption
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return new WorkflowResponse(result)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
import {
|
||||||
|
CalculatedRMAShippingContext,
|
||||||
|
CalculateShippingOptionPriceDTO,
|
||||||
|
} from "@medusajs/framework/types"
|
||||||
|
import {
|
||||||
|
WorkflowResponse,
|
||||||
|
createWorkflow,
|
||||||
|
parallelize,
|
||||||
|
transform,
|
||||||
|
when,
|
||||||
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
|
import { ShippingOptionPriceType } from "@medusajs/framework/utils"
|
||||||
|
import { calculateShippingOptionsPricesStep } from "../../fulfillment/steps"
|
||||||
|
import {
|
||||||
|
updateOrderChangeActionsStep,
|
||||||
|
updateOrderShippingMethodsStep,
|
||||||
|
} from "../steps"
|
||||||
|
import { useQueryGraphStep } from "../../common"
|
||||||
|
|
||||||
|
const COMMON_OPTIONS_FIELDS = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"price_type",
|
||||||
|
"service_zone_id",
|
||||||
|
"service_zone.fulfillment_set_id",
|
||||||
|
"service_zone.fulfillment_set.type",
|
||||||
|
"service_zone.fulfillment_set.location.*",
|
||||||
|
"service_zone.fulfillment_set.location.address.*",
|
||||||
|
"shipping_profile_id",
|
||||||
|
"provider_id",
|
||||||
|
"data",
|
||||||
|
|
||||||
|
"type.id",
|
||||||
|
"type.label",
|
||||||
|
"type.description",
|
||||||
|
"type.code",
|
||||||
|
|
||||||
|
"provider.id",
|
||||||
|
"provider.is_enabled",
|
||||||
|
|
||||||
|
"rules.attribute",
|
||||||
|
"rules.value",
|
||||||
|
"rules.operator",
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data to create a shipping method for an order edit.
|
||||||
|
*/
|
||||||
|
export type MaybeRefreshShippingMethodsWorkflowInput = {
|
||||||
|
/**
|
||||||
|
* The ID of the shipping method to refresh.
|
||||||
|
*/
|
||||||
|
shipping_method_id: string
|
||||||
|
/**
|
||||||
|
* The ID of the order.
|
||||||
|
*/
|
||||||
|
order_id: string
|
||||||
|
/**
|
||||||
|
* The ID of the ADD SHIPPING action to update.
|
||||||
|
*/
|
||||||
|
action_id: string
|
||||||
|
/**
|
||||||
|
* Data to pass for the shipping calculation.
|
||||||
|
*/
|
||||||
|
context: CalculatedRMAShippingContext
|
||||||
|
}
|
||||||
|
|
||||||
|
export const maybeRefreshShippingMethodsWorkflowId =
|
||||||
|
"maybe-refresh-shipping-methods"
|
||||||
|
/**
|
||||||
|
* This workflows refreshes shipping method an order (used in RMA flows).
|
||||||
|
* The shipping method and the action is updated if the shipping option is calculated.
|
||||||
|
*/
|
||||||
|
export const maybeRefreshShippingMethodsWorkflow = createWorkflow(
|
||||||
|
maybeRefreshShippingMethodsWorkflowId,
|
||||||
|
function (
|
||||||
|
input: MaybeRefreshShippingMethodsWorkflowInput
|
||||||
|
): WorkflowResponse<void> {
|
||||||
|
const shippingMethodQuery = useQueryGraphStep({
|
||||||
|
entity: "order_shipping_method",
|
||||||
|
fields: ["id", "shipping_option_id"],
|
||||||
|
filters: {
|
||||||
|
id: input.shipping_method_id,
|
||||||
|
},
|
||||||
|
}).config({ name: "fetch-shipping-method" })
|
||||||
|
|
||||||
|
const shippingMethod = transform(shippingMethodQuery, ({ data }) => data[0])
|
||||||
|
|
||||||
|
const shippingOptionQuery = useQueryGraphStep({
|
||||||
|
entity: "shipping_option",
|
||||||
|
fields: [...COMMON_OPTIONS_FIELDS],
|
||||||
|
filters: { id: shippingMethod.shipping_option_id },
|
||||||
|
}).config({ name: "calculated-option" })
|
||||||
|
|
||||||
|
const shippingOption = transform(shippingOptionQuery, ({ data }) => data[0])
|
||||||
|
|
||||||
|
const isCalculatedPriceShippingOption = transform(
|
||||||
|
shippingOption,
|
||||||
|
(option) => option?.price_type === ShippingOptionPriceType.CALCULATED
|
||||||
|
)
|
||||||
|
|
||||||
|
when(
|
||||||
|
{ isCalculatedPriceShippingOption, shippingOption },
|
||||||
|
({ isCalculatedPriceShippingOption, shippingOption }) =>
|
||||||
|
isCalculatedPriceShippingOption
|
||||||
|
).then(() => {
|
||||||
|
const orderQuery = useQueryGraphStep({
|
||||||
|
entity: "order",
|
||||||
|
fields: ["id", "shipping_address", "items.*", "items.variant.*"],
|
||||||
|
filters: { id: input.order_id },
|
||||||
|
options: { throwIfKeyNotFound: true },
|
||||||
|
}).config({ name: "order-query" })
|
||||||
|
|
||||||
|
const order = transform(orderQuery, (data) => data[0])
|
||||||
|
|
||||||
|
const calculateShippingOptionsPricesData = transform(
|
||||||
|
{
|
||||||
|
shippingOption,
|
||||||
|
order,
|
||||||
|
input,
|
||||||
|
},
|
||||||
|
({ shippingOption, order, input }) => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: shippingOption.id as string,
|
||||||
|
optionData: shippingOption.data,
|
||||||
|
context: {
|
||||||
|
...order,
|
||||||
|
...input.context,
|
||||||
|
from_location:
|
||||||
|
shippingOption.service_zone.fulfillment_set.location,
|
||||||
|
},
|
||||||
|
// data: {}, // TODO: add data
|
||||||
|
provider_id: shippingOption.provider_id,
|
||||||
|
} as CalculateShippingOptionPriceDTO,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const prices = calculateShippingOptionsPricesStep(
|
||||||
|
calculateShippingOptionsPricesData
|
||||||
|
)
|
||||||
|
|
||||||
|
const updateData = transform(
|
||||||
|
{
|
||||||
|
shippingOption,
|
||||||
|
prices,
|
||||||
|
input,
|
||||||
|
},
|
||||||
|
({ prices, input }) => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: input.action_id,
|
||||||
|
amount: prices[0].calculated_amount,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: input.shipping_method_id,
|
||||||
|
amount: prices[0].calculated_amount,
|
||||||
|
is_custom_amount: false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
parallelize(
|
||||||
|
updateOrderChangeActionsStep([updateData[0]]),
|
||||||
|
updateOrderShippingMethodsStep([updateData[1]!])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
return new WorkflowResponse(void 0)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
import { addOrderLineItemsWorkflow } from "../add-line-items"
|
import { addOrderLineItemsWorkflow } from "../add-line-items"
|
||||||
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
||||||
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
|
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
|
||||||
|
import { refreshClaimShippingWorkflow } from "./refresh-shipping"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate adding new items to a claim.
|
* The data to validate adding new items to a claim.
|
||||||
@@ -191,6 +192,21 @@ export const orderClaimAddNewItemWorkflow = createWorkflow(
|
|||||||
input: orderChangeActionInput,
|
input: orderChangeActionInput,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ orderChange, orderClaim },
|
||||||
|
({ orderChange, orderClaim }) => {
|
||||||
|
return {
|
||||||
|
order_change_id: orderChange.id,
|
||||||
|
claim_id: orderClaim.id,
|
||||||
|
order_id: orderClaim.order_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshClaimShippingWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(previewOrderChangeStep(orderClaim.order_id))
|
return new WorkflowResponse(previewOrderChangeStep(orderClaim.order_id))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
throwIfOrderChangeIsNotActive,
|
throwIfOrderChangeIsNotActive,
|
||||||
} from "../../utils/order-validation"
|
} from "../../utils/order-validation"
|
||||||
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
||||||
|
import { refreshClaimShippingWorkflow } from "./refresh-shipping"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that items can be requested to return as part of a claim.
|
* The data to validate that items can be requested to return as part of a claim.
|
||||||
@@ -258,6 +259,21 @@ export const orderClaimRequestItemReturnWorkflow = createWorkflow(
|
|||||||
input: orderChangeActionInput,
|
input: orderChangeActionInput,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ orderChange, orderClaim },
|
||||||
|
({ orderChange, orderClaim }) => {
|
||||||
|
return {
|
||||||
|
order_change_id: orderChange.id,
|
||||||
|
claim_id: orderClaim.id,
|
||||||
|
order_id: orderClaim.order_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshClaimShippingWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(previewOrderChangeStep(orderClaim.order_id))
|
return new WorkflowResponse(previewOrderChangeStep(orderClaim.order_id))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
+52
-22
@@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
BigNumberInput,
|
BigNumberInput,
|
||||||
|
CalculatedRMAShippingContext,
|
||||||
OrderChangeDTO,
|
OrderChangeDTO,
|
||||||
OrderClaimDTO,
|
OrderClaimDTO,
|
||||||
OrderDTO,
|
OrderDTO,
|
||||||
@@ -22,6 +23,7 @@ import {
|
|||||||
import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
|
import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
|
||||||
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
||||||
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
|
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
|
||||||
|
import { fetchShippingOptionForOrderWorkflow } from "../../utils/fetch-shipping-option"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that a shipping method can be created for a claim.
|
* The data to validate that a shipping method can be created for a claim.
|
||||||
@@ -147,7 +149,9 @@ export const createClaimShippingMethodWorkflowId =
|
|||||||
*/
|
*/
|
||||||
export const createClaimShippingMethodWorkflow = createWorkflow(
|
export const createClaimShippingMethodWorkflow = createWorkflow(
|
||||||
createClaimShippingMethodWorkflowId,
|
createClaimShippingMethodWorkflowId,
|
||||||
function (input: CreateClaimShippingMethodWorkflowInput): WorkflowResponse<OrderPreviewDTO> {
|
function (
|
||||||
|
input: CreateClaimShippingMethodWorkflowInput
|
||||||
|
): WorkflowResponse<OrderPreviewDTO> {
|
||||||
const orderClaim: OrderClaimDTO = useRemoteQueryStep({
|
const orderClaim: OrderClaimDTO = useRemoteQueryStep({
|
||||||
entry_point: "order_claim",
|
entry_point: "order_claim",
|
||||||
fields: ["id", "status", "order_id", "canceled_at"],
|
fields: ["id", "status", "order_id", "canceled_at"],
|
||||||
@@ -164,25 +168,9 @@ export const createClaimShippingMethodWorkflow = createWorkflow(
|
|||||||
throw_if_key_not_found: true,
|
throw_if_key_not_found: true,
|
||||||
}).config({ name: "order-query" })
|
}).config({ name: "order-query" })
|
||||||
|
|
||||||
const shippingOptions = useRemoteQueryStep({
|
|
||||||
entry_point: "shipping_option",
|
|
||||||
fields: [
|
|
||||||
"id",
|
|
||||||
"name",
|
|
||||||
"calculated_price.calculated_amount",
|
|
||||||
"calculated_price.is_calculated_price_tax_inclusive",
|
|
||||||
],
|
|
||||||
variables: {
|
|
||||||
id: input.shipping_option_id,
|
|
||||||
calculated_price: {
|
|
||||||
context: { currency_code: order.currency_code },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).config({ name: "fetch-shipping-option" })
|
|
||||||
|
|
||||||
const orderChange: OrderChangeDTO = useRemoteQueryStep({
|
const orderChange: OrderChangeDTO = useRemoteQueryStep({
|
||||||
entry_point: "order_change",
|
entry_point: "order_change",
|
||||||
fields: ["id", "status", "version"],
|
fields: ["id", "status", "version", "actions.*"],
|
||||||
variables: {
|
variables: {
|
||||||
filters: {
|
filters: {
|
||||||
order_id: orderClaim.order_id,
|
order_id: orderClaim.order_id,
|
||||||
@@ -193,6 +181,52 @@ export const createClaimShippingMethodWorkflow = createWorkflow(
|
|||||||
list: false,
|
list: false,
|
||||||
}).config({ name: "order-change-query" })
|
}).config({ name: "order-change-query" })
|
||||||
|
|
||||||
|
const isReturn = transform(input, (data) => {
|
||||||
|
return !!data.return_id
|
||||||
|
})
|
||||||
|
|
||||||
|
const fetchShippingOptionInput = transform(
|
||||||
|
{ input, isReturn, orderChange, order },
|
||||||
|
(data) => {
|
||||||
|
const changeActionType = data.isReturn
|
||||||
|
? ChangeActionType.RETURN_ITEM
|
||||||
|
: ChangeActionType.ITEM_ADD
|
||||||
|
|
||||||
|
const items = data.orderChange.actions
|
||||||
|
.filter((action) => action.action === changeActionType)
|
||||||
|
.map((a) => ({
|
||||||
|
id: a.details?.reference_id,
|
||||||
|
quantity: a.details?.quantity,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const context = data.isReturn
|
||||||
|
? {
|
||||||
|
return_id: data.input.return_id,
|
||||||
|
return_items: items,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
claim_id: data.input.claim_id,
|
||||||
|
claim_items: items,
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
order_id: data.order.id,
|
||||||
|
currency_code: data.order.currency_code,
|
||||||
|
shipping_option_id: data.input.shipping_option_id,
|
||||||
|
custom_amount: data.input.custom_amount,
|
||||||
|
context: context as CalculatedRMAShippingContext,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const shippingOption = fetchShippingOptionForOrderWorkflow.runAsStep({
|
||||||
|
input: fetchShippingOptionInput,
|
||||||
|
})
|
||||||
|
|
||||||
|
const shippingOptions = transform(shippingOption, (shippingOption) => {
|
||||||
|
return [shippingOption]
|
||||||
|
})
|
||||||
|
|
||||||
createClaimShippingMethodValidationStep({ order, orderClaim, orderChange })
|
createClaimShippingMethodValidationStep({ order, orderClaim, orderChange })
|
||||||
|
|
||||||
const shippingMethodInput = transform(
|
const shippingMethodInput = transform(
|
||||||
@@ -214,10 +248,6 @@ export const createClaimShippingMethodWorkflow = createWorkflow(
|
|||||||
return createdMethods.map((item) => item.id)
|
return createdMethods.map((item) => item.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
const isReturn = transform(input, (data) => {
|
|
||||||
return !!data.return_id
|
|
||||||
})
|
|
||||||
|
|
||||||
updateOrderTaxLinesWorkflow.runAsStep({
|
updateOrderTaxLinesWorkflow.runAsStep({
|
||||||
input: {
|
input: {
|
||||||
order_id: order.id,
|
order_id: order.id,
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
|
||||||
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
WorkflowResponse,
|
||||||
|
createWorkflow,
|
||||||
|
transform,
|
||||||
|
when,
|
||||||
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
|
|
||||||
|
import { maybeRefreshShippingMethodsWorkflow } from "../../utils/maybe-refresh-shipping-methods"
|
||||||
|
import { useQueryGraphStep } from "../../../common"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data to refresh the shipping methods for an claim.
|
||||||
|
*/
|
||||||
|
export type RefreshClaimShippingWorkflowInput = {
|
||||||
|
/**
|
||||||
|
* The order change's ID.
|
||||||
|
*/
|
||||||
|
order_change_id: string
|
||||||
|
/**
|
||||||
|
* The claim's details.
|
||||||
|
*/
|
||||||
|
claim_id: string
|
||||||
|
/**
|
||||||
|
* The order's ID.
|
||||||
|
*/
|
||||||
|
order_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const refreshClaimShippingWorkflowId = "refresh-claim-shipping"
|
||||||
|
/**
|
||||||
|
* This workflow refreshes the shipping methods for an claim in case the shipping option is calculated.
|
||||||
|
* It refreshes both inbound and outbound shipping methods.
|
||||||
|
*
|
||||||
|
* @summary
|
||||||
|
*
|
||||||
|
* Refresh claim shipping.
|
||||||
|
*/
|
||||||
|
export const refreshClaimShippingWorkflow = createWorkflow(
|
||||||
|
refreshClaimShippingWorkflowId,
|
||||||
|
function (
|
||||||
|
input: WorkflowData<RefreshClaimShippingWorkflowInput>
|
||||||
|
): WorkflowResponse<void> {
|
||||||
|
const orderChangeQuery = useQueryGraphStep({
|
||||||
|
entity: "order_change",
|
||||||
|
fields: [
|
||||||
|
"id",
|
||||||
|
"status",
|
||||||
|
"order_id",
|
||||||
|
"claim_id",
|
||||||
|
"return_id",
|
||||||
|
"actions.*",
|
||||||
|
],
|
||||||
|
filters: {
|
||||||
|
order_id: input.order_id,
|
||||||
|
claim_id: input.claim_id,
|
||||||
|
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
|
||||||
|
},
|
||||||
|
}).config({ name: "order-change-query" })
|
||||||
|
|
||||||
|
const orderChange = transform(orderChangeQuery, ({ data }) => data[0])
|
||||||
|
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ input, orderChange, orderChangeQuery },
|
||||||
|
({ input, orderChange, orderChangeQuery }) => {
|
||||||
|
const shippingToRefresh = {} as Record<"inbound" | "outbound", any>
|
||||||
|
|
||||||
|
const inboundShippingAction = orderChange.actions.find(
|
||||||
|
(action) =>
|
||||||
|
action.action === ChangeActionType.SHIPPING_ADD &&
|
||||||
|
!!action.return_id
|
||||||
|
)
|
||||||
|
|
||||||
|
const outboundShippingAction = orderChange.actions.find(
|
||||||
|
(action) =>
|
||||||
|
action.action === ChangeActionType.SHIPPING_ADD && !action.return_id
|
||||||
|
)
|
||||||
|
|
||||||
|
if (inboundShippingAction) {
|
||||||
|
const items = orderChange.actions
|
||||||
|
.filter((action) => action.action === ChangeActionType.RETURN_ITEM)
|
||||||
|
.map((a) => ({
|
||||||
|
id: a.details?.reference_id as string,
|
||||||
|
quantity: a.details?.quantity as number,
|
||||||
|
}))
|
||||||
|
|
||||||
|
shippingToRefresh.inbound = {
|
||||||
|
shipping_method_id: inboundShippingAction.reference_id,
|
||||||
|
order_id: orderChange.order_id,
|
||||||
|
action_id: inboundShippingAction.id,
|
||||||
|
context: {
|
||||||
|
return_id: inboundShippingAction.return_id,
|
||||||
|
return_items: items,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outboundShippingAction) {
|
||||||
|
const items = orderChange.actions
|
||||||
|
.filter((action) => action.action === ChangeActionType.ITEM_ADD)
|
||||||
|
.map((a) => ({
|
||||||
|
id: a.details?.reference_id as string,
|
||||||
|
quantity: a.details?.quantity as number,
|
||||||
|
}))
|
||||||
|
|
||||||
|
shippingToRefresh.outbound = {
|
||||||
|
shipping_method_id: outboundShippingAction.reference_id,
|
||||||
|
order_id: orderChange.order_id,
|
||||||
|
action_id: outboundShippingAction.id,
|
||||||
|
context: {
|
||||||
|
claim_id: outboundShippingAction.claim_id,
|
||||||
|
claim_items: items,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shippingToRefresh
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
when({ refreshArgs }, ({ refreshArgs }) => !!refreshArgs.inbound).then(() =>
|
||||||
|
maybeRefreshShippingMethodsWorkflow
|
||||||
|
.runAsStep({
|
||||||
|
input: refreshArgs.inbound,
|
||||||
|
})
|
||||||
|
.config({ name: "refresh-inbound-shipping-method" })
|
||||||
|
)
|
||||||
|
|
||||||
|
when({ refreshArgs }, ({ refreshArgs }) => !!refreshArgs.outbound).then(
|
||||||
|
() =>
|
||||||
|
maybeRefreshShippingMethodsWorkflow
|
||||||
|
.runAsStep({
|
||||||
|
input: refreshArgs.outbound,
|
||||||
|
})
|
||||||
|
.config({ name: "refresh-outbound-shipping-method" })
|
||||||
|
)
|
||||||
|
|
||||||
|
return new WorkflowResponse(void 0)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
WorkflowResponse,
|
WorkflowResponse,
|
||||||
createStep,
|
createStep,
|
||||||
createWorkflow,
|
createWorkflow,
|
||||||
|
transform,
|
||||||
} from "@medusajs/framework/workflows-sdk"
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
import { useRemoteQueryStep } from "../../../common"
|
import { useRemoteQueryStep } from "../../../common"
|
||||||
import {
|
import {
|
||||||
@@ -22,6 +23,7 @@ import {
|
|||||||
throwIfIsCancelled,
|
throwIfIsCancelled,
|
||||||
throwIfOrderChangeIsNotActive,
|
throwIfOrderChangeIsNotActive,
|
||||||
} from "../../utils/order-validation"
|
} from "../../utils/order-validation"
|
||||||
|
import { refreshClaimShippingWorkflow } from "./refresh-shipping"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that claim items can be removed.
|
* The data to validate that claim items can be removed.
|
||||||
@@ -110,7 +112,8 @@ export const removeClaimItemActionValidationStep = createStep(
|
|||||||
* You can find the action name `WRITE_OFF_ITEM` using its `action` property,
|
* You can find the action name `WRITE_OFF_ITEM` using its `action` property,
|
||||||
* and use the value of its `id` property.
|
* and use the value of its `id` property.
|
||||||
*/
|
*/
|
||||||
export type RemoveItemClaimActionWorkflowInput = OrderWorkflow.DeleteOrderClaimItemActionWorkflowInput
|
export type RemoveItemClaimActionWorkflowInput =
|
||||||
|
OrderWorkflow.DeleteOrderClaimItemActionWorkflowInput
|
||||||
|
|
||||||
export const removeItemClaimActionWorkflowId = "remove-item-claim-action"
|
export const removeItemClaimActionWorkflowId = "remove-item-claim-action"
|
||||||
/**
|
/**
|
||||||
@@ -176,6 +179,21 @@ export const removeItemClaimActionWorkflow = createWorkflow(
|
|||||||
|
|
||||||
deleteOrderChangeActionsStep({ ids: [input.action_id] })
|
deleteOrderChangeActionsStep({ ids: [input.action_id] })
|
||||||
|
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ orderChange, orderClaim },
|
||||||
|
({ orderChange, orderClaim }) => {
|
||||||
|
return {
|
||||||
|
order_change_id: orderChange.id,
|
||||||
|
claim_id: orderClaim.id,
|
||||||
|
order_id: orderClaim.order_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshClaimShippingWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
throwIfIsCancelled,
|
throwIfIsCancelled,
|
||||||
throwIfOrderChangeIsNotActive,
|
throwIfOrderChangeIsNotActive,
|
||||||
} from "../../utils/order-validation"
|
} from "../../utils/order-validation"
|
||||||
|
import { refreshClaimShippingWorkflow } from "./refresh-shipping"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that a claim's outbound item can be updated.
|
* The data to validate that a claim's outbound item can be updated.
|
||||||
@@ -190,6 +191,21 @@ export const updateClaimAddItemWorkflow = createWorkflow(
|
|||||||
|
|
||||||
updateOrderChangeActionsStep([updateData])
|
updateOrderChangeActionsStep([updateData])
|
||||||
|
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ orderChange, orderClaim },
|
||||||
|
({ orderChange, orderClaim }) => {
|
||||||
|
return {
|
||||||
|
order_change_id: orderChange.id,
|
||||||
|
claim_id: orderClaim.id,
|
||||||
|
order_id: orderClaim.order_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshClaimShippingWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
+51
-21
@@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
BigNumberInput,
|
BigNumberInput,
|
||||||
|
CalculatedRMAShippingContext,
|
||||||
OrderChangeDTO,
|
OrderChangeDTO,
|
||||||
OrderDTO,
|
OrderDTO,
|
||||||
OrderExchangeDTO,
|
OrderExchangeDTO,
|
||||||
@@ -22,6 +23,7 @@ import {
|
|||||||
import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
|
import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
|
||||||
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
||||||
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
|
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
|
||||||
|
import { fetchShippingOptionForOrderWorkflow } from "../../utils/fetch-shipping-option"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that a shipping method can be created for an exchange.
|
* The data to validate that a shipping method can be created for an exchange.
|
||||||
@@ -148,7 +150,9 @@ export const createExchangeShippingMethodWorkflowId =
|
|||||||
*/
|
*/
|
||||||
export const createExchangeShippingMethodWorkflow = createWorkflow(
|
export const createExchangeShippingMethodWorkflow = createWorkflow(
|
||||||
createExchangeShippingMethodWorkflowId,
|
createExchangeShippingMethodWorkflowId,
|
||||||
function (input: CreateExchangeShippingMethodWorkflowInput): WorkflowResponse<OrderPreviewDTO> {
|
function (
|
||||||
|
input: CreateExchangeShippingMethodWorkflowInput
|
||||||
|
): WorkflowResponse<OrderPreviewDTO> {
|
||||||
const orderExchange: OrderExchangeDTO = useRemoteQueryStep({
|
const orderExchange: OrderExchangeDTO = useRemoteQueryStep({
|
||||||
entry_point: "order_exchange",
|
entry_point: "order_exchange",
|
||||||
fields: ["id", "status", "order_id", "canceled_at"],
|
fields: ["id", "status", "order_id", "canceled_at"],
|
||||||
@@ -165,25 +169,13 @@ export const createExchangeShippingMethodWorkflow = createWorkflow(
|
|||||||
throw_if_key_not_found: true,
|
throw_if_key_not_found: true,
|
||||||
}).config({ name: "order-query" })
|
}).config({ name: "order-query" })
|
||||||
|
|
||||||
const shippingOptions = useRemoteQueryStep({
|
const isReturn = transform(input, (data) => {
|
||||||
entry_point: "shipping_option",
|
return !!data.return_id
|
||||||
fields: [
|
})
|
||||||
"id",
|
|
||||||
"name",
|
|
||||||
"calculated_price.calculated_amount",
|
|
||||||
"calculated_price.is_calculated_price_tax_inclusive",
|
|
||||||
],
|
|
||||||
variables: {
|
|
||||||
id: input.shipping_option_id,
|
|
||||||
calculated_price: {
|
|
||||||
context: { currency_code: order.currency_code },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).config({ name: "fetch-shipping-option" })
|
|
||||||
|
|
||||||
const orderChange: OrderChangeDTO = useRemoteQueryStep({
|
const orderChange: OrderChangeDTO = useRemoteQueryStep({
|
||||||
entry_point: "order_change",
|
entry_point: "order_change",
|
||||||
fields: ["id", "status", "version"],
|
fields: ["id", "status", "version", "actions.*"],
|
||||||
variables: {
|
variables: {
|
||||||
filters: {
|
filters: {
|
||||||
order_id: orderExchange.order_id,
|
order_id: orderExchange.order_id,
|
||||||
@@ -194,6 +186,48 @@ export const createExchangeShippingMethodWorkflow = createWorkflow(
|
|||||||
list: false,
|
list: false,
|
||||||
}).config({ name: "order-change-query" })
|
}).config({ name: "order-change-query" })
|
||||||
|
|
||||||
|
const fetchShippingOptionInput = transform(
|
||||||
|
{ input, isReturn, orderChange, order },
|
||||||
|
(data) => {
|
||||||
|
const changeActionType = data.isReturn
|
||||||
|
? ChangeActionType.RETURN_ITEM
|
||||||
|
: ChangeActionType.ITEM_ADD
|
||||||
|
|
||||||
|
const items = data.orderChange.actions
|
||||||
|
.filter((action) => action.action === changeActionType)
|
||||||
|
.map((a) => ({
|
||||||
|
id: a.details?.reference_id,
|
||||||
|
quantity: a.details?.quantity,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const context = data.isReturn
|
||||||
|
? {
|
||||||
|
return_id: data.input.return_id,
|
||||||
|
return_items: items,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
exchange_id: data.input.exchange_id,
|
||||||
|
exchange_items: items,
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
order_id: data.order.id,
|
||||||
|
currency_code: data.order.currency_code,
|
||||||
|
shipping_option_id: data.input.shipping_option_id,
|
||||||
|
custom_amount: data.input.custom_amount,
|
||||||
|
context: context as CalculatedRMAShippingContext,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const shippingOption = fetchShippingOptionForOrderWorkflow.runAsStep({
|
||||||
|
input: fetchShippingOptionInput,
|
||||||
|
})
|
||||||
|
|
||||||
|
const shippingOptions = transform(shippingOption, (shippingOption) => {
|
||||||
|
return [shippingOption]
|
||||||
|
})
|
||||||
|
|
||||||
createExchangeShippingMethodValidationStep({
|
createExchangeShippingMethodValidationStep({
|
||||||
order,
|
order,
|
||||||
orderExchange,
|
orderExchange,
|
||||||
@@ -219,10 +253,6 @@ export const createExchangeShippingMethodWorkflow = createWorkflow(
|
|||||||
return createdMethods.map((item) => item.id)
|
return createdMethods.map((item) => item.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
const isReturn = transform(input, (data) => {
|
|
||||||
return !!data.return_id
|
|
||||||
})
|
|
||||||
|
|
||||||
updateOrderTaxLinesWorkflow.runAsStep({
|
updateOrderTaxLinesWorkflow.runAsStep({
|
||||||
input: {
|
input: {
|
||||||
order_id: order.id,
|
order_id: order.id,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
import { addOrderLineItemsWorkflow } from "../add-line-items"
|
import { addOrderLineItemsWorkflow } from "../add-line-items"
|
||||||
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
||||||
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
|
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
|
||||||
|
import { refreshExchangeShippingWorkflow } from "./refresh-shipping"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that new or outbound items can be added to an exchange.
|
* The data to validate that new or outbound items can be added to an exchange.
|
||||||
@@ -191,6 +192,21 @@ export const orderExchangeAddNewItemWorkflow = createWorkflow(
|
|||||||
input: orderChangeActionInput,
|
input: orderChangeActionInput,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ orderChange, orderExchange },
|
||||||
|
({ orderChange, orderExchange }) => {
|
||||||
|
return {
|
||||||
|
order_change_id: orderChange.id,
|
||||||
|
exchange_id: orderExchange.id,
|
||||||
|
order_id: orderExchange.order_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshExchangeShippingWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(previewOrderChangeStep(orderExchange.order_id))
|
return new WorkflowResponse(previewOrderChangeStep(orderExchange.order_id))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
throwIfOrderChangeIsNotActive,
|
throwIfOrderChangeIsNotActive,
|
||||||
} from "../../utils/order-validation"
|
} from "../../utils/order-validation"
|
||||||
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
||||||
|
import { refreshExchangeShippingWorkflow } from "./refresh-shipping"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that items can be returned as part of an exchange.
|
* The data to validate that items can be returned as part of an exchange.
|
||||||
@@ -260,6 +261,21 @@ export const orderExchangeRequestItemReturnWorkflow = createWorkflow(
|
|||||||
input: orderChangeActionInput,
|
input: orderChangeActionInput,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ orderChange, orderExchange },
|
||||||
|
({ orderChange, orderExchange }) => {
|
||||||
|
return {
|
||||||
|
order_change_id: orderChange.id,
|
||||||
|
exchange_id: orderExchange.id,
|
||||||
|
order_id: orderExchange.order_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshExchangeShippingWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(previewOrderChangeStep(orderExchange.order_id))
|
return new WorkflowResponse(previewOrderChangeStep(orderExchange.order_id))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
import { OrderChangeDTO } from "@medusajs/framework/types"
|
||||||
|
import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
|
||||||
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
WorkflowResponse,
|
||||||
|
createWorkflow,
|
||||||
|
transform,
|
||||||
|
when,
|
||||||
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
|
|
||||||
|
import { maybeRefreshShippingMethodsWorkflow } from "../../utils/maybe-refresh-shipping-methods"
|
||||||
|
import { useQueryGraphStep } from "../../../common"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data to refresh the shipping methods for an exchange.
|
||||||
|
*/
|
||||||
|
export type RefreshExchangeShippingWorkflowInput = {
|
||||||
|
/**
|
||||||
|
* The order change's ID.
|
||||||
|
*/
|
||||||
|
order_change_id: string
|
||||||
|
/**
|
||||||
|
* The exchange's details.
|
||||||
|
*/
|
||||||
|
exchange_id: string
|
||||||
|
/**
|
||||||
|
* The order's ID.
|
||||||
|
*/
|
||||||
|
order_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const refreshExchangeShippingWorkflowId = "refresh-exchange-shipping"
|
||||||
|
/**
|
||||||
|
* This workflow refreshes the shipping methods for an exchange in case the shipping option is calculated.
|
||||||
|
* It refreshes both inbound and outbound shipping methods.
|
||||||
|
*
|
||||||
|
* @summary
|
||||||
|
*
|
||||||
|
* Refresh exchange shipping.
|
||||||
|
*/
|
||||||
|
export const refreshExchangeShippingWorkflow = createWorkflow(
|
||||||
|
refreshExchangeShippingWorkflowId,
|
||||||
|
function (
|
||||||
|
input: WorkflowData<RefreshExchangeShippingWorkflowInput>
|
||||||
|
): WorkflowResponse<void> {
|
||||||
|
const orderChangeQuery = useQueryGraphStep({
|
||||||
|
entity: "order_change",
|
||||||
|
fields: [
|
||||||
|
"id",
|
||||||
|
"status",
|
||||||
|
"order_id",
|
||||||
|
"exchange_id",
|
||||||
|
"return_id",
|
||||||
|
"actions.*",
|
||||||
|
],
|
||||||
|
filters: {
|
||||||
|
order_id: input.order_id,
|
||||||
|
exchange_id: input.exchange_id,
|
||||||
|
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
|
||||||
|
},
|
||||||
|
}).config({ name: "order-change-query" })
|
||||||
|
|
||||||
|
const orderChange: OrderChangeDTO = transform(
|
||||||
|
orderChangeQuery,
|
||||||
|
({ data }) => data[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
const shippingToRefresh = transform(
|
||||||
|
{ input, orderChange },
|
||||||
|
({ input, orderChange }) => {
|
||||||
|
const shippingToRefresh = {} as Record<"inbound" | "outbound", any>
|
||||||
|
|
||||||
|
const inboundShippingAction = orderChange.actions.find(
|
||||||
|
(action) =>
|
||||||
|
action.action === ChangeActionType.SHIPPING_ADD &&
|
||||||
|
!!action.return_id
|
||||||
|
)
|
||||||
|
|
||||||
|
const outboundShippingAction = orderChange.actions.find(
|
||||||
|
(action) =>
|
||||||
|
action.action === ChangeActionType.SHIPPING_ADD && !action.return_id
|
||||||
|
)
|
||||||
|
|
||||||
|
if (inboundShippingAction) {
|
||||||
|
const items = orderChange.actions
|
||||||
|
.filter((action) => action.action === ChangeActionType.RETURN_ITEM)
|
||||||
|
.map((a) => ({
|
||||||
|
id: a.details?.reference_id as string,
|
||||||
|
quantity: a.details?.quantity as number,
|
||||||
|
}))
|
||||||
|
|
||||||
|
shippingToRefresh.inbound = {
|
||||||
|
shipping_method_id: inboundShippingAction.reference_id,
|
||||||
|
order_id: orderChange.order_id,
|
||||||
|
action_id: inboundShippingAction.id,
|
||||||
|
context: {
|
||||||
|
return_id: inboundShippingAction.return_id,
|
||||||
|
return_items: items,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outboundShippingAction) {
|
||||||
|
const items = orderChange.actions
|
||||||
|
.filter((action) => action.action === ChangeActionType.ITEM_ADD)
|
||||||
|
.map((a) => ({
|
||||||
|
id: a.details?.reference_id as string,
|
||||||
|
quantity: a.details?.quantity as number,
|
||||||
|
}))
|
||||||
|
|
||||||
|
shippingToRefresh.outbound = {
|
||||||
|
shipping_method_id: outboundShippingAction.reference_id,
|
||||||
|
order_id: orderChange.order_id,
|
||||||
|
action_id: outboundShippingAction.id,
|
||||||
|
context: {
|
||||||
|
exchange_id: outboundShippingAction.exchange_id,
|
||||||
|
exchange_items: items,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shippingToRefresh
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
when(
|
||||||
|
{ shippingToRefresh },
|
||||||
|
({ shippingToRefresh }) => !!shippingToRefresh.inbound
|
||||||
|
).then(() =>
|
||||||
|
maybeRefreshShippingMethodsWorkflow
|
||||||
|
.runAsStep({
|
||||||
|
input: shippingToRefresh.inbound,
|
||||||
|
})
|
||||||
|
.config({ name: "refresh-inbound-shipping-method" })
|
||||||
|
)
|
||||||
|
|
||||||
|
when(
|
||||||
|
{ shippingToRefresh },
|
||||||
|
({ shippingToRefresh }) => !!shippingToRefresh.outbound
|
||||||
|
).then(() =>
|
||||||
|
maybeRefreshShippingMethodsWorkflow
|
||||||
|
.runAsStep({
|
||||||
|
input: shippingToRefresh.outbound,
|
||||||
|
})
|
||||||
|
.config({ name: "refresh-outbound-shipping-method" })
|
||||||
|
)
|
||||||
|
|
||||||
|
return new WorkflowResponse(void 0)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
throwIfOrderChangeIsNotActive,
|
throwIfOrderChangeIsNotActive,
|
||||||
} from "../../utils/order-validation"
|
} from "../../utils/order-validation"
|
||||||
import { removeExchangeShippingMethodWorkflow } from "./remove-exchange-shipping-method"
|
import { removeExchangeShippingMethodWorkflow } from "./remove-exchange-shipping-method"
|
||||||
|
import { refreshExchangeShippingWorkflow } from "./refresh-shipping"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that an outbound item can be removed from an exchange.
|
* The data to validate that an outbound item can be removed from an exchange.
|
||||||
@@ -227,6 +228,28 @@ export const removeItemExchangeActionWorkflow = createWorkflow(
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
when(
|
||||||
|
{ actionIdToDelete, orderExchange, orderChange },
|
||||||
|
({ actionIdToDelete }) => {
|
||||||
|
return !actionIdToDelete
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ orderChange, orderExchange },
|
||||||
|
({ orderChange, orderExchange }) => {
|
||||||
|
return {
|
||||||
|
order_change_id: orderChange.id,
|
||||||
|
exchange_id: orderExchange.id,
|
||||||
|
order_id: orderExchange.order_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshExchangeShippingWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
throwIfIsCancelled,
|
throwIfIsCancelled,
|
||||||
throwIfOrderChangeIsNotActive,
|
throwIfOrderChangeIsNotActive,
|
||||||
} from "../../utils/order-validation"
|
} from "../../utils/order-validation"
|
||||||
|
import { refreshExchangeShippingWorkflow } from "./refresh-shipping"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that an outbound or new item in an exchange can be updated.
|
* The data to validate that an outbound or new item in an exchange can be updated.
|
||||||
@@ -195,6 +196,21 @@ export const updateExchangeAddItemWorkflow = createWorkflow(
|
|||||||
|
|
||||||
updateOrderChangeActionsStep([updateData])
|
updateOrderChangeActionsStep([updateData])
|
||||||
|
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ orderChange, orderExchange },
|
||||||
|
({ orderChange, orderExchange }) => {
|
||||||
|
return {
|
||||||
|
order_change_id: orderChange.id,
|
||||||
|
exchange_id: orderExchange.id,
|
||||||
|
order_id: orderExchange.order_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshExchangeShippingWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
-2
@@ -185,7 +185,6 @@ export const createOrderEditShippingMethodWorkflow = createWorkflow(
|
|||||||
createdMethods,
|
createdMethods,
|
||||||
customPrice: input.custom_amount,
|
customPrice: input.custom_amount,
|
||||||
orderChange,
|
orderChange,
|
||||||
input,
|
|
||||||
},
|
},
|
||||||
({
|
({
|
||||||
shippingOptions,
|
shippingOptions,
|
||||||
@@ -193,7 +192,6 @@ export const createOrderEditShippingMethodWorkflow = createWorkflow(
|
|||||||
createdMethods,
|
createdMethods,
|
||||||
customPrice,
|
customPrice,
|
||||||
orderChange,
|
orderChange,
|
||||||
input,
|
|
||||||
}) => {
|
}) => {
|
||||||
const shippingOption = shippingOptions[0]
|
const shippingOption = shippingOptions[0]
|
||||||
const createdMethod = createdMethods[0]
|
const createdMethod = createdMethods[0]
|
||||||
|
|||||||
+35
-18
@@ -22,6 +22,7 @@ import {
|
|||||||
import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
|
import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
|
||||||
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
||||||
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
|
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
|
||||||
|
import { fetchShippingOptionForOrderWorkflow } from "../../utils/fetch-shipping-option"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that a shipping method can be created for a return.
|
* The data to validate that a shipping method can be created for a return.
|
||||||
@@ -132,7 +133,9 @@ export const createReturnShippingMethodWorkflowId =
|
|||||||
*/
|
*/
|
||||||
export const createReturnShippingMethodWorkflow = createWorkflow(
|
export const createReturnShippingMethodWorkflow = createWorkflow(
|
||||||
createReturnShippingMethodWorkflowId,
|
createReturnShippingMethodWorkflowId,
|
||||||
function (input: CreateReturnShippingMethodWorkflowInput): WorkflowResponse<OrderPreviewDTO> {
|
function (
|
||||||
|
input: CreateReturnShippingMethodWorkflowInput
|
||||||
|
): WorkflowResponse<OrderPreviewDTO> {
|
||||||
const orderReturn: ReturnDTO = useRemoteQueryStep({
|
const orderReturn: ReturnDTO = useRemoteQueryStep({
|
||||||
entry_point: "return",
|
entry_point: "return",
|
||||||
fields: [
|
fields: [
|
||||||
@@ -156,25 +159,9 @@ export const createReturnShippingMethodWorkflow = createWorkflow(
|
|||||||
throw_if_key_not_found: true,
|
throw_if_key_not_found: true,
|
||||||
}).config({ name: "order-query" })
|
}).config({ name: "order-query" })
|
||||||
|
|
||||||
const shippingOptions = useRemoteQueryStep({
|
|
||||||
entry_point: "shipping_option",
|
|
||||||
fields: [
|
|
||||||
"id",
|
|
||||||
"name",
|
|
||||||
"calculated_price.calculated_amount",
|
|
||||||
"calculated_price.is_calculated_price_tax_inclusive",
|
|
||||||
],
|
|
||||||
variables: {
|
|
||||||
id: input.shipping_option_id,
|
|
||||||
calculated_price: {
|
|
||||||
context: { currency_code: order.currency_code },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).config({ name: "fetch-shipping-option" })
|
|
||||||
|
|
||||||
const orderChange: OrderChangeDTO = useRemoteQueryStep({
|
const orderChange: OrderChangeDTO = useRemoteQueryStep({
|
||||||
entry_point: "order_change",
|
entry_point: "order_change",
|
||||||
fields: ["id", "status", "version"],
|
fields: ["id", "status", "version", "actions.*"],
|
||||||
variables: {
|
variables: {
|
||||||
filters: {
|
filters: {
|
||||||
order_id: orderReturn.order_id,
|
order_id: orderReturn.order_id,
|
||||||
@@ -185,6 +172,36 @@ export const createReturnShippingMethodWorkflow = createWorkflow(
|
|||||||
list: false,
|
list: false,
|
||||||
}).config({ name: "order-change-query" })
|
}).config({ name: "order-change-query" })
|
||||||
|
|
||||||
|
const shippingOptionFetchInput = transform(
|
||||||
|
{ orderChange, input, order, orderReturn },
|
||||||
|
({ orderChange, input, order, orderReturn }) => {
|
||||||
|
return {
|
||||||
|
order_id: order.id,
|
||||||
|
shipping_option_id: input.shipping_option_id,
|
||||||
|
currency_code: order.currency_code,
|
||||||
|
context: {
|
||||||
|
return_id: orderReturn.id,
|
||||||
|
return_items: orderChange.actions
|
||||||
|
.filter(
|
||||||
|
(action) => action.action === ChangeActionType.RETURN_ITEM
|
||||||
|
)
|
||||||
|
.map((a) => ({
|
||||||
|
id: a.details?.reference_id as string,
|
||||||
|
quantity: a.details?.quantity as number,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const shippingOption = fetchShippingOptionForOrderWorkflow.runAsStep({
|
||||||
|
input: shippingOptionFetchInput,
|
||||||
|
})
|
||||||
|
|
||||||
|
const shippingOptions = transform(shippingOption, (shippingOption) => {
|
||||||
|
return [shippingOption]
|
||||||
|
})
|
||||||
|
|
||||||
createReturnShippingMethodValidationStep({
|
createReturnShippingMethodValidationStep({
|
||||||
order,
|
order,
|
||||||
orderReturn,
|
orderReturn,
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import { OrderChangeDTO } from "@medusajs/framework/types"
|
||||||
|
import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
|
||||||
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
WorkflowResponse,
|
||||||
|
createWorkflow,
|
||||||
|
transform,
|
||||||
|
when,
|
||||||
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
|
|
||||||
|
import { maybeRefreshShippingMethodsWorkflow } from "../../utils/maybe-refresh-shipping-methods"
|
||||||
|
import { useQueryGraphStep } from "../../../common"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data to validate that items can be added to a return.
|
||||||
|
*/
|
||||||
|
export type RequestItemReturnValidationStepInput = {
|
||||||
|
/**
|
||||||
|
* The order change's ID.
|
||||||
|
*/
|
||||||
|
order_change_id: string
|
||||||
|
/**
|
||||||
|
* The return's details.
|
||||||
|
*/
|
||||||
|
return_id: string
|
||||||
|
/**
|
||||||
|
* The order's ID.
|
||||||
|
*/
|
||||||
|
order_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const refreshReturnShippingWorkflowId = "refresh-return-shipping"
|
||||||
|
/**
|
||||||
|
* This workflow refreshes the shipping method for a return in case the shipping option is calculated.
|
||||||
|
*
|
||||||
|
* @summary
|
||||||
|
*
|
||||||
|
* Refresh return shipping.
|
||||||
|
*/
|
||||||
|
export const refreshReturnShippingWorkflow = createWorkflow(
|
||||||
|
refreshReturnShippingWorkflowId,
|
||||||
|
function (
|
||||||
|
input: WorkflowData<RequestItemReturnValidationStepInput>
|
||||||
|
): WorkflowResponse<void> {
|
||||||
|
const orderChangeQuery = useQueryGraphStep({
|
||||||
|
entity: "order_change",
|
||||||
|
fields: ["id", "status", "order_id", "return_id", "actions.*"],
|
||||||
|
filters: {
|
||||||
|
order_id: input.order_id,
|
||||||
|
return_id: input.return_id,
|
||||||
|
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
|
||||||
|
},
|
||||||
|
}).config({ name: "order-change-query" })
|
||||||
|
|
||||||
|
const orderChange: OrderChangeDTO = transform(
|
||||||
|
orderChangeQuery,
|
||||||
|
({ data }) => data[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ input, orderChange },
|
||||||
|
({ input, orderChange }) => {
|
||||||
|
const shippingAction = orderChange.actions.find(
|
||||||
|
(action) => action.action === ChangeActionType.SHIPPING_ADD
|
||||||
|
)
|
||||||
|
|
||||||
|
const items = orderChange.actions
|
||||||
|
.filter((action) => action.action === ChangeActionType.RETURN_ITEM)
|
||||||
|
.map((a) => ({
|
||||||
|
id: a.details?.reference_id as string,
|
||||||
|
quantity: a.details?.quantity as number,
|
||||||
|
}))
|
||||||
|
|
||||||
|
if (shippingAction) {
|
||||||
|
return {
|
||||||
|
shipping_method_id: shippingAction.reference_id,
|
||||||
|
order_id: orderChange.order_id,
|
||||||
|
action_id: shippingAction.id,
|
||||||
|
context: {
|
||||||
|
return_id: input.return_id,
|
||||||
|
return_items: items,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
when({ refreshArgs }, ({ refreshArgs }) => refreshArgs !== null).then(() =>
|
||||||
|
maybeRefreshShippingMethodsWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return new WorkflowResponse(void 0)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
} from "../../utils/order-validation"
|
} from "../../utils/order-validation"
|
||||||
import { removeReturnShippingMethodWorkflow } from "./remove-return-shipping-method"
|
import { removeReturnShippingMethodWorkflow } from "./remove-return-shipping-method"
|
||||||
import { updateReturnWorkflow } from "./update-return"
|
import { updateReturnWorkflow } from "./update-return"
|
||||||
|
import { refreshReturnShippingWorkflow } from "./refresh-shipping"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that a return item can be removed.
|
* The data to validate that a return item can be removed.
|
||||||
@@ -249,6 +250,25 @@ export const removeItemReturnActionWorkflow = createWorkflow(
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
when({ actionIdToDelete }, ({ actionIdToDelete }) => {
|
||||||
|
return !actionIdToDelete
|
||||||
|
}).then(() => {
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ orderChange, orderReturn },
|
||||||
|
({ orderChange, orderReturn }) => {
|
||||||
|
return {
|
||||||
|
order_change_id: orderChange.id,
|
||||||
|
return_id: orderReturn.id,
|
||||||
|
order_id: orderReturn.order_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshReturnShippingWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -22,7 +22,7 @@ import {
|
|||||||
} from "../../utils/order-validation"
|
} from "../../utils/order-validation"
|
||||||
import { validateReturnReasons } from "../../utils/validate-return-reason"
|
import { validateReturnReasons } from "../../utils/validate-return-reason"
|
||||||
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
|
||||||
|
import { refreshReturnShippingWorkflow } from "./refresh-shipping"
|
||||||
/**
|
/**
|
||||||
* The data to validate that items can be added to a return.
|
* The data to validate that items can be added to a return.
|
||||||
*/
|
*/
|
||||||
@@ -201,6 +201,21 @@ export const requestItemReturnWorkflow = createWorkflow(
|
|||||||
input: orderChangeActionInput,
|
input: orderChangeActionInput,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ orderChange, orderReturn },
|
||||||
|
({ orderChange, orderReturn }) => {
|
||||||
|
return {
|
||||||
|
order_change_id: orderChange.id,
|
||||||
|
return_id: orderReturn.id,
|
||||||
|
order_id: orderReturn.order_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshReturnShippingWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
throwIfOrderChangeIsNotActive,
|
throwIfOrderChangeIsNotActive,
|
||||||
} from "../../utils/order-validation"
|
} from "../../utils/order-validation"
|
||||||
import { validateReturnReasons } from "../../utils/validate-return-reason"
|
import { validateReturnReasons } from "../../utils/validate-return-reason"
|
||||||
|
import { refreshReturnShippingWorkflow } from "./refresh-shipping"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate that an item in a return can be updated.
|
* The data to validate that an item in a return can be updated.
|
||||||
@@ -216,6 +217,21 @@ export const updateRequestItemReturnWorkflow = createWorkflow(
|
|||||||
|
|
||||||
updateOrderChangeActionsStep([updateData])
|
updateOrderChangeActionsStep([updateData])
|
||||||
|
|
||||||
|
const refreshArgs = transform(
|
||||||
|
{ orderChange, orderReturn },
|
||||||
|
({ orderChange, orderReturn }) => {
|
||||||
|
return {
|
||||||
|
order_change_id: orderChange.id,
|
||||||
|
return_id: orderReturn.id,
|
||||||
|
order_id: orderReturn.order_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshReturnShippingWorkflow.runAsStep({
|
||||||
|
input: refreshArgs,
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
return new WorkflowResponse(previewOrderChangeStep(order.id))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -36,10 +36,7 @@ export const refundPaymentsStepId = "refund-payments-step"
|
|||||||
*/
|
*/
|
||||||
export const refundPaymentsStep = createStep(
|
export const refundPaymentsStep = createStep(
|
||||||
refundPaymentsStepId,
|
refundPaymentsStepId,
|
||||||
async (
|
async (input: RefundPaymentsStepInput, { container }) => {
|
||||||
input: RefundPaymentsStepInput,
|
|
||||||
{ container }
|
|
||||||
) => {
|
|
||||||
const logger = container.resolve<Logger>(ContainerRegistrationKeys.LOGGER)
|
const logger = container.resolve<Logger>(ContainerRegistrationKeys.LOGGER)
|
||||||
const paymentModule = container.resolve<IPaymentModuleService>(
|
const paymentModule = container.resolve<IPaymentModuleService>(
|
||||||
Modules.PAYMENT
|
Modules.PAYMENT
|
||||||
|
|||||||
@@ -120,6 +120,22 @@ export interface UpdateShippingOptionDTO {
|
|||||||
*/
|
*/
|
||||||
export interface UpsertShippingOptionDTO extends UpdateShippingOptionDTO {}
|
export interface UpsertShippingOptionDTO extends UpdateShippingOptionDTO {}
|
||||||
|
|
||||||
|
type CalculateShippingItems = {
|
||||||
|
/**
|
||||||
|
* The ID of the order item. Lookup in context.items for the details about variant / product.
|
||||||
|
*/
|
||||||
|
id: string
|
||||||
|
/**
|
||||||
|
* The quantity to ship.
|
||||||
|
*/
|
||||||
|
quantity: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CalculatedRMAShippingContext =
|
||||||
|
| { return_id: string; return_items: CalculateShippingItems[] }
|
||||||
|
| { exchange_id: string; exchange_items: CalculateShippingItems[] }
|
||||||
|
| { claim_id: string; claim_items: CalculateShippingItems[] }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data needed for the associated fulfillment provider to calculate the price of a shipping option.
|
* The data needed for the associated fulfillment provider to calculate the price of a shipping option.
|
||||||
*/
|
*/
|
||||||
@@ -149,11 +165,12 @@ export interface CalculateShippingOptionPriceDTO {
|
|||||||
*/
|
*/
|
||||||
context: CartPropsForFulfillment & {
|
context: CartPropsForFulfillment & {
|
||||||
/**
|
/**
|
||||||
* The location that the items will be shipped from.
|
* The location that the items will be shipped from (or to if it is a return).
|
||||||
*/
|
*/
|
||||||
from_location?: StockLocationDTO
|
from_location?: StockLocationDTO
|
||||||
|
|
||||||
[k: string]: unknown
|
[k: string]: unknown
|
||||||
}
|
} & CalculatedRMAShippingContext
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in new issue
Block a user