diff --git a/.changeset/honest-zoos-play.md b/.changeset/honest-zoos-play.md new file mode 100644 index 0000000000..7d7389309f --- /dev/null +++ b/.changeset/honest-zoos-play.md @@ -0,0 +1,7 @@ +--- +"@medusajs/core-flows": patch +"@medusajs/medusa": patch +"@medusajs/types": patch +--- + +feat(medusa,core-flows,types): added a basic endpoint for complete cart diff --git a/integration-tests/modules/__tests__/cart/store/carts.spec.ts b/integration-tests/modules/__tests__/cart/store/carts.spec.ts index 7ef8849415..23d27cee78 100644 --- a/integration-tests/modules/__tests__/cart/store/carts.spec.ts +++ b/integration-tests/modules/__tests__/cart/store/carts.spec.ts @@ -16,18 +16,20 @@ import { ITaxModuleService, } from "@medusajs/types" import { + ContainerRegistrationKeys, PromotionRuleOperator, PromotionType, RuleOperator, } from "@medusajs/utils" import { medusaIntegrationTestRunner } from "medusa-test-utils" -import adminSeeder from "../../../../helpers/admin-seeder" +import { createAdminUser } from "../../../../helpers/create-admin-user" import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer" import { setupTaxStructure } from "../../fixtures" jest.setTimeout(100000) const env = { MEDUSA_FF_MEDUSA_V2: true } +const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } medusaIntegrationTestRunner({ env, @@ -44,8 +46,11 @@ medusaIntegrationTestRunner({ let promotionModule: IPromotionModuleService let taxModule: ITaxModuleService let fulfillmentModule: IFulfillmentModuleService + let remoteLinkService + let regionService: IRegionModuleService let defaultRegion + let region beforeAll(async () => { appContainer = getContainer() @@ -58,13 +63,17 @@ medusaIntegrationTestRunner({ remoteLink = appContainer.resolve(LinkModuleUtils.REMOTE_LINK) promotionModule = appContainer.resolve(ModuleRegistrationName.PROMOTION) taxModule = appContainer.resolve(ModuleRegistrationName.TAX) + regionService = appContainer.resolve(ModuleRegistrationName.REGION) fulfillmentModule = appContainer.resolve( ModuleRegistrationName.FULFILLMENT ) + remoteLinkService = appContainer.resolve( + ContainerRegistrationKeys.REMOTE_LINK + ) }) beforeEach(async () => { - await adminSeeder(dbConnection) + await createAdminUser(dbConnection, adminHeaders, appContainer) // Here, so we don't have to create a region for each test defaultRegion = await regionModule.create({ @@ -1389,6 +1398,196 @@ medusaIntegrationTestRunner({ ) }) }) + + describe("POST /store/carts/:id/complete", () => { + let salesChannel + let product + let shippingProfile + let fulfillmentSet + let shippingOption + + beforeEach(async () => { + await setupTaxStructure(taxModule) + region = await regionService.create({ + name: "Test region", + countries: ["US"], + currency_code: "usd", + }) + + salesChannel = ( + await api.post( + "/admin/sales-channels", + { name: "first channel", description: "channel" }, + adminHeaders + ) + ).data.sales_channel + + product = ( + await api.post( + "/admin/products", + { + title: "Test fixture", + tags: [{ value: "123" }, { value: "456" }], + options: [ + { title: "size", values: ["large", "small"] }, + { title: "color", values: ["green"] }, + ], + variants: [ + { + title: "Test variant", + inventory_quantity: 10, + prices: [ + { + currency_code: "usd", + amount: 100, + }, + ], + options: { + size: "large", + color: "green", + }, + }, + ], + }, + adminHeaders + ) + ).data.product + + const stockLocation = ( + await api.post( + `/admin/stock-locations`, + { name: "test location" }, + adminHeaders + ) + ).data.stock_location + + await api.post( + `/admin/stock-locations/${stockLocation.id}/sales-channels`, + { add: [salesChannel.id] }, + adminHeaders + ) + + shippingProfile = await fulfillmentModule.createShippingProfiles({ + name: "Test", + type: "default", + }) + + fulfillmentSet = await fulfillmentModule.create({ + name: "Test", + type: "test-type", + service_zones: [ + { + name: "Test", + geo_zones: [{ type: "country", country_code: "us" }], + }, + ], + }) + + await remoteLinkService.create([ + { + [Modules.FULFILLMENT]: { fulfillment_set_id: fulfillmentSet.id }, + [Modules.STOCK_LOCATION]: { stock_location_id: stockLocation.id }, + }, + ]) + + shippingOption = ( + await api.post( + `/admin/shipping-options`, + { + name: "Test shipping option", + service_zone_id: fulfillmentSet.service_zones[0].id, + shipping_profile_id: shippingProfile.id, + provider_id: "manual_test-provider", + price_type: "flat", + type: { + label: "Test type", + description: "Test description", + code: "test-code", + }, + prices: [ + { currency_code: "usd", amount: 1000 }, + { region_id: region.id, amount: 1100 }, + ], + rules: [], + }, + adminHeaders + ) + ).data.shipping_option + }) + + it("should create an order", async () => { + const cartResponse = await api.post(`/store/carts`, { + currency_code: "usd", + email: "tony@stark-industries.com", + shipping_address: { + address_1: "test address 1", + address_2: "test address 2", + city: "ny", + country_code: "us", + province: "ny", + postal_code: "94016", + }, + // TODO: inventory isn't being managed on a product level + // sales_channel_id: salesChannel.id, + items: [{ quantity: 1, variant_id: product.variants[0].id }], + }) + + const response = await api.post( + `/store/carts/${cartResponse.data.cart.id}/complete`, + {} + ) + + expect(response.status).toEqual(200) + expect(response.data.order).toEqual( + expect.objectContaining({ + id: expect.any(String), + total: 106, + subtotal: 100, + tax_total: 6, + discount_total: 0, + discount_tax_total: 0, + original_total: 106, + original_tax_total: 6, + item_total: 106, + item_subtotal: 100, + item_tax_total: 6, + original_item_total: 106, + original_item_subtotal: 100, + original_item_tax_total: 6, + shipping_total: 0, + shipping_subtotal: 0, + shipping_tax_total: 0, + original_shipping_tax_total: 0, + original_shipping_tax_subtotal: 0, + original_shipping_total: 0, + items: [ + expect.objectContaining({ + product_id: product.id, + unit_price: 100, + quantity: 1, + tax_total: 6, + subtotal: 100, + total: 106, + original_total: 106, + discount_total: 0, + tax_lines: [ + expect.objectContaining({ + rate: 6, + }), + ], + adjustments: [], + }), + ], + shipping_address: expect.objectContaining({ + city: "ny", + country_code: "us", + province: "ny", + postal_code: "94016", + }), + }) + ) + }) + }) }) }, }) diff --git a/packages/core-flows/src/definition/cart/steps/create-order-from-cart.ts b/packages/core-flows/src/definition/cart/steps/create-order-from-cart.ts new file mode 100644 index 0000000000..f2dac943d1 --- /dev/null +++ b/packages/core-flows/src/definition/cart/steps/create-order-from-cart.ts @@ -0,0 +1,57 @@ +import { CartWorkflowDTO } from "@medusajs/types" +import { OrderStatus } from "@medusajs/utils" +import { StepResponse, createStep } from "@medusajs/workflows-sdk" +import { createOrdersWorkflow } from "../../../order/workflows/create-orders" + +interface StepInput { + cart: CartWorkflowDTO +} + +export const createOrderFromCartStepId = "create-order-from-cart" +export const createOrderFromCartStep = createStep( + createOrderFromCartStepId, + async (input: StepInput, { container }) => { + const { cart } = input + + const itemAdjustments = (cart.items || []) + ?.map((item) => item.adjustments || []) + .flat(1) + const shippingAdjustments = (cart.shipping_methods || []) + ?.map((sm) => sm.adjustments || []) + .flat(1) + + const promoCodes = [...itemAdjustments, ...shippingAdjustments] + .map((adjustment) => adjustment.code) + .filter((code) => Boolean) as string[] + + const { transaction, result } = await createOrdersWorkflow(container).run({ + input: { + region_id: cart.region?.id, + customer_id: cart.customer?.id, + sales_channel_id: cart.sales_channel_id, + status: OrderStatus.PENDING, + email: cart.email, + currency_code: cart.currency_code, + shipping_address: cart.shipping_address, + billing_address: cart.billing_address, + // TODO: This should be handle correctly + no_notification: false, + items: cart.items, + shipping_methods: cart.shipping_methods, + metadata: cart.metadata, + promo_codes: promoCodes, + }, + }) + + return new StepResponse(result, { transaction }) + }, + async (flow, { container }) => { + if (!flow) { + return + } + + await createOrdersWorkflow(container).cancel({ + transaction: flow.transaction, + }) + } +) diff --git a/packages/core-flows/src/definition/cart/steps/index.ts b/packages/core-flows/src/definition/cart/steps/index.ts index 3e7680c1f2..4d19d7592c 100644 --- a/packages/core-flows/src/definition/cart/steps/index.ts +++ b/packages/core-flows/src/definition/cart/steps/index.ts @@ -3,6 +3,7 @@ export * from "./add-to-cart" export * from "./confirm-inventory" export * from "./create-carts" export * from "./create-line-item-adjustments" +export * from "./create-order-from-cart" export * from "./create-shipping-method-adjustments" export * from "./find-one-or-any-region" export * from "./find-or-create-customer" diff --git a/packages/core-flows/src/definition/cart/utils/fields.ts b/packages/core-flows/src/definition/cart/utils/fields.ts index e213d83bfd..f2cefdacf7 100644 --- a/packages/core-flows/src/definition/cart/utils/fields.ts +++ b/packages/core-flows/src/definition/cart/utils/fields.ts @@ -10,3 +10,43 @@ export const cartFieldsForRefreshSteps = [ "customer.*", "customer.groups.*", ] + +export const completeCartFields = [ + "id", + "currency_code", + "email", + "created_at", + "updated_at", + "total", + "subtotal", + "tax_total", + "discount_total", + "discount_tax_total", + "original_total", + "original_tax_total", + "item_total", + "item_subtotal", + "item_tax_total", + "sales_channel_id", + "original_item_total", + "original_item_subtotal", + "original_item_tax_total", + "shipping_total", + "shipping_subtotal", + "shipping_tax_total", + "original_shipping_tax_total", + "original_shipping_tax_subtotal", + "original_shipping_total", + "items.*", + "items.tax_lines.*", + "items.adjustments.*", + "customer.*", + "shipping_methods.*", + "shipping_methods.tax_lines.*", + "shipping_methods.adjustments.*", + "shipping_address.*", + "billing_address.*", + "region.*", + "payment_collection.*", + "payment_collection.payment_sessions.*", +] diff --git a/packages/core-flows/src/definition/cart/utils/prepare-line-item-data.ts b/packages/core-flows/src/definition/cart/utils/prepare-line-item-data.ts index e4af0bbc8e..622954699c 100644 --- a/packages/core-flows/src/definition/cart/utils/prepare-line-item-data.ts +++ b/packages/core-flows/src/definition/cart/utils/prepare-line-item-data.ts @@ -1,15 +1,30 @@ -import { BigNumberInput, ProductVariantDTO } from "@medusajs/types" +import { + BigNumberInput, + CreateOrderAdjustmentDTO, + CreateOrderLineItemTaxLineDTO, + ProductVariantDTO, +} from "@medusajs/types" interface Input { quantity: BigNumberInput metadata?: Record unitPrice: BigNumberInput variant: ProductVariantDTO + taxLines?: CreateOrderLineItemTaxLineDTO[] + adjustments?: CreateOrderAdjustmentDTO[] cartId?: string } export function prepareLineItemData(data: Input) { - const { variant, unitPrice, quantity, metadata, cartId } = data + const { + variant, + unitPrice, + quantity, + metadata, + cartId, + taxLines, + adjustments, + } = data if (!variant.product) { throw new Error("Variant does not have a product") @@ -39,9 +54,37 @@ export function prepareLineItemData(data: Input) { metadata, } + if (taxLines) { + lineItem.tax_lines = prepareTaxLinesData(taxLines) + } + + if (adjustments) { + lineItem.adjustments = prepareAdjustmentsData(adjustments) + } + if (cartId) { lineItem.cart_id = cartId } return lineItem } + +export function prepareTaxLinesData(data: CreateOrderLineItemTaxLineDTO[]) { + return data.map((d) => ({ + description: d.description, + tax_rate_id: d.tax_rate_id, + code: d.code, + rate: d.rate, + provider_id: d.provider_id, + })) +} + +export function prepareAdjustmentsData(data: CreateOrderAdjustmentDTO[]) { + return data.map((d) => ({ + code: d.code, + amount: d.amount, + description: d.description, + promotion_id: d.promotion_id, + provider_id: d.promotion_id, + })) +} diff --git a/packages/core-flows/src/definition/cart/workflows/complete-cart.ts b/packages/core-flows/src/definition/cart/workflows/complete-cart.ts new file mode 100644 index 0000000000..c035b9cd1f --- /dev/null +++ b/packages/core-flows/src/definition/cart/workflows/complete-cart.ts @@ -0,0 +1,43 @@ +import { CompleteCartWorkflowInputDTO, OrderDTO } from "@medusajs/types" +import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" +import { useRemoteQueryStep } from "../../../common" +import { createOrderFromCartStep } from "../steps" +import { updateTaxLinesStep } from "../steps/update-tax-lines" +import { completeCartFields } from "../utils/fields" + +/* + - [] Create Tax Lines + - [] Authorize Payment + - fail: + - [] Delete Tax lines + - [] Reserve Item from inventory (if enabled) + - fail: + - [] Delete reservations + - [] Cancel Payment + - [] Create order +*/ +export const completeCartWorkflowId = "complete-cart" +export const completeCartWorkflow = createWorkflow( + completeCartWorkflowId, + ( + input: WorkflowData + ): WorkflowData => { + const cart = useRemoteQueryStep({ + entry_point: "cart", + fields: completeCartFields, + variables: { id: input.id }, + list: false, + }) + + updateTaxLinesStep({ cart_or_cart_id: cart, force_tax_calculation: true }) + + const finalCart = useRemoteQueryStep({ + entry_point: "cart", + fields: completeCartFields, + variables: { id: input.id }, + list: false, + }).config({ name: "final-cart" }) + + return createOrderFromCartStep({ cart: finalCart }) + } +) diff --git a/packages/core-flows/src/definition/cart/workflows/index.ts b/packages/core-flows/src/definition/cart/workflows/index.ts index 63bd15dff6..a69e51fa09 100644 --- a/packages/core-flows/src/definition/cart/workflows/index.ts +++ b/packages/core-flows/src/definition/cart/workflows/index.ts @@ -1,5 +1,6 @@ export * from "./add-shipping-method-to-cart" export * from "./add-to-cart" +export * from "./complete-cart" export * from "./create-carts" export * from "./create-payment-collection-for-cart" export * from "./list-shipping-options-for-cart" diff --git a/packages/core-flows/src/order/workflows/create-orders.ts b/packages/core-flows/src/order/workflows/create-orders.ts index 3c0600fbbd..75fba6f0e3 100644 --- a/packages/core-flows/src/order/workflows/create-orders.ts +++ b/packages/core-flows/src/order/workflows/create-orders.ts @@ -7,15 +7,13 @@ import { transform, } from "@medusajs/workflows-sdk" import { useRemoteQueryStep } from "../../common" -import { - confirmInventoryStep, - findOneOrAnyRegionStep, - findOrCreateCustomerStep, - findSalesChannelStep, - getVariantPriceSetsStep, - getVariantsStep, - validateVariantsExistStep, -} from "../../definition/cart" +import { confirmInventoryStep } from "../../definition/cart/steps/confirm-inventory" +import { findOneOrAnyRegionStep } from "../../definition/cart/steps/find-one-or-any-region" +import { findOrCreateCustomerStep } from "../../definition/cart/steps/find-or-create-customer" +import { findSalesChannelStep } from "../../definition/cart/steps/find-sales-channel" +import { getVariantPriceSetsStep } from "../../definition/cart/steps/get-variant-price-sets" +import { getVariantsStep } from "../../definition/cart/steps/get-variants" +import { validateVariantsExistStep } from "../../definition/cart/steps/validate-variants-existence" import { prepareConfirmInventoryInput } from "../../definition/cart/utils/prepare-confirm-inventory-input" import { prepareLineItemData } from "../../definition/cart/utils/prepare-line-item-data" import { createOrdersStep, updateOrderTaxLinesStep } from "../steps" @@ -174,6 +172,8 @@ export const createOrdersWorkflow = createWorkflow( ), quantity: item.quantity as number, metadata: item?.metadata ?? {}, + taxLines: item.tax_lines || [], + adjustments: item.adjustments || [], }) }) diff --git a/packages/medusa/src/api-v2/store/carts/[id]/complete/route.ts b/packages/medusa/src/api-v2/store/carts/[id]/complete/route.ts new file mode 100644 index 0000000000..89f8930ea7 --- /dev/null +++ b/packages/medusa/src/api-v2/store/carts/[id]/complete/route.ts @@ -0,0 +1,34 @@ +import { completeCartWorkflow } from "@medusajs/core-flows" +import { MedusaRequest, MedusaResponse } from "../../../../../types/routing" +import { refetchOrder } from "../../../orders/helpers" +import { StoreCompleteCartType } from "../../validators" + +export const POST = async ( + req: MedusaRequest, + res: MedusaResponse +) => { + const { idempotency_key: idempotencyKey } = req.validatedBody + + // If the idempotencyKey is present: + // - is workflow is running? + // = throw error + // - else + // - re-run the workflow at the failed step + + const { errors, result } = await completeCartWorkflow(req.scope).run({ + input: { id: req.params.id }, + throwOnError: false, + }) + + if (Array.isArray(errors) && errors[0]) { + throw errors[0].error + } + + const order = await refetchOrder( + result.id, + req.scope, + req.remoteQueryConfig.fields + ) + + res.status(200).json({ order }) +} diff --git a/packages/medusa/src/api-v2/store/carts/middlewares.ts b/packages/medusa/src/api-v2/store/carts/middlewares.ts index 7acd360b8c..1dc2e89724 100644 --- a/packages/medusa/src/api-v2/store/carts/middlewares.ts +++ b/packages/medusa/src/api-v2/store/carts/middlewares.ts @@ -2,12 +2,15 @@ import { MiddlewareRoute } from "../../../loaders/helpers/routing/types" import { authenticate } from "../../../utils/authenticate-middleware" import { validateAndTransformBody } from "../../utils/validate-body" import { validateAndTransformQuery } from "../../utils/validate-query" +import * as OrderQueryConfig from "../orders/query-config" +import { StoreGetOrder } from "../orders/validators" import * as QueryConfig from "./query-config" import { StoreAddCartLineItem, StoreAddCartPromotions, StoreAddCartShippingMethods, StoreCalculateCartTaxes, + StoreCompleteCart, StoreCreateCart, StoreGetCartsCart, StoreRemoveCartPromotions, @@ -144,4 +147,15 @@ export const storeCartRoutesMiddlewares: MiddlewareRoute[] = [ ), ], }, + { + method: ["POST"], + matcher: "/store/carts/:id/complete", + middlewares: [ + validateAndTransformBody(StoreCompleteCart), + validateAndTransformQuery( + StoreGetOrder, + OrderQueryConfig.retrieveTransformQueryConfig + ), + ], + }, ] diff --git a/packages/medusa/src/api-v2/store/carts/validators.ts b/packages/medusa/src/api-v2/store/carts/validators.ts index 057ae0eb9f..97bcc7eba5 100644 --- a/packages/medusa/src/api-v2/store/carts/validators.ts +++ b/packages/medusa/src/api-v2/store/carts/validators.ts @@ -82,3 +82,10 @@ export const StoreAddCartShippingMethods = z data: z.record(z.unknown()).optional(), }) .strict() + +export const StoreCompleteCart = z + .object({ + idempotency_key: z.string().optional(), + }) + .strict() +export type StoreCompleteCartType = z.infer diff --git a/packages/medusa/src/api-v2/store/orders/helpers.ts b/packages/medusa/src/api-v2/store/orders/helpers.ts new file mode 100644 index 0000000000..1a9afaade7 --- /dev/null +++ b/packages/medusa/src/api-v2/store/orders/helpers.ts @@ -0,0 +1,10 @@ +import { MedusaContainer } from "@medusajs/types" +import { refetchEntity } from "../../utils/refetch-entity" + +export const refetchOrder = async ( + idOrFilter: string | object, + scope: MedusaContainer, + fields: string[] +) => { + return await refetchEntity("order", idOrFilter, scope, fields) +} diff --git a/packages/medusa/src/api-v2/store/orders/query-config.ts b/packages/medusa/src/api-v2/store/orders/query-config.ts new file mode 100644 index 0000000000..1a497dee63 --- /dev/null +++ b/packages/medusa/src/api-v2/store/orders/query-config.ts @@ -0,0 +1,55 @@ +// TODO: This is copied over from admin. Scope what fields and relations are allowed for store + +export const defaultStoreOrderFields = [ + "id", + "status", + "version", + "summary", + "metadata", + "created_at", + "updated_at", +] + +export const defaultStoreRetrieveOrderFields = [ + "id", + "status", + "version", + "summary", + "total", + "subtotal", + "tax_total", + "discount_total", + "discount_tax_total", + "original_total", + "original_tax_total", + "item_total", + "item_subtotal", + "item_tax_total", + "original_item_total", + "original_item_subtotal", + "original_item_tax_total", + "shipping_total", + "shipping_subtotal", + "shipping_tax_total", + "original_shipping_tax_total", + "original_shipping_tax_subtotal", + "original_shipping_total", + "created_at", + "updated_at", + "*items", + "*items.tax_lines", + "*items.adjustments", + "*items.detail", + "*items.tax_lines", + "*items.adjustments", + "*shipping_address", + "*billing_address", + "*shipping_methods", + "*shipping_methods.tax_lines", + "*shipping_methods.adjustments", +] + +export const retrieveTransformQueryConfig = { + defaultFields: defaultStoreRetrieveOrderFields, + isList: false, +} diff --git a/packages/medusa/src/api-v2/store/orders/validators.ts b/packages/medusa/src/api-v2/store/orders/validators.ts new file mode 100644 index 0000000000..aa878fb0aa --- /dev/null +++ b/packages/medusa/src/api-v2/store/orders/validators.ts @@ -0,0 +1,5 @@ +import { z } from "zod" +import { createSelectParams } from "../../utils/validators" + +export const StoreGetOrder = createSelectParams() +export type StoreGetOrderType = z.infer diff --git a/packages/modules/order/src/types/order-detail.ts b/packages/modules/order/src/types/order-detail.ts index 9058bde787..6dc8de1bc4 100644 --- a/packages/modules/order/src/types/order-detail.ts +++ b/packages/modules/order/src/types/order-detail.ts @@ -12,7 +12,7 @@ export interface PartialUpsertOrderItemDTO { return_dismissed_quantity?: BigNumberInput written_off_quantity?: BigNumberInput - metadata?: Record + metadata?: Record | null } export interface CreateOrderItemDTO extends PartialUpsertOrderItemDTO { diff --git a/packages/modules/order/src/types/order.ts b/packages/modules/order/src/types/order.ts index d51272f8f5..b23483764f 100644 --- a/packages/modules/order/src/types/order.ts +++ b/packages/modules/order/src/types/order.ts @@ -8,7 +8,7 @@ export interface CreateOrderDTO { currency_code: string status?: OrderStatus no_notification?: boolean - metadata?: Record + metadata?: Record | null } export interface UpdateOrderDTO { @@ -21,5 +21,5 @@ export interface UpdateOrderDTO { currency_code?: string status?: OrderStatus no_notification?: boolean - metadata?: Record + metadata?: Record | null } diff --git a/packages/types/src/cart/workflows.ts b/packages/types/src/cart/workflows.ts index 9635720d77..af03fe629e 100644 --- a/packages/types/src/cart/workflows.ts +++ b/packages/types/src/cart/workflows.ts @@ -118,3 +118,7 @@ export interface ListShippingOptionsForCartWorkflowInputDTO { export interface PricedShippingOptionDTO extends ShippingOptionDTO { amount: BigNumberInput } + +export interface CompleteCartWorkflowInputDTO { + id: string +} diff --git a/packages/types/src/order/mutations.ts b/packages/types/src/order/mutations.ts index 7240d667a9..61ef62c21c 100644 --- a/packages/types/src/order/mutations.ts +++ b/packages/types/src/order/mutations.ts @@ -14,7 +14,7 @@ export interface UpsertOrderAddressDTO { province?: string postal_code?: string phone?: string - metadata?: Record + metadata?: Record | null } export interface UpdateOrderAddressDTO extends UpsertOrderAddressDTO { @@ -41,7 +41,7 @@ export interface CreateOrderDTO { items?: CreateOrderLineItemDTO[] shipping_methods?: Omit[] transactions?: Omit[] - metadata?: Record + metadata?: Record | null promo_codes?: string[] } @@ -57,7 +57,7 @@ export interface UpdateOrderDTO { billing_address?: CreateOrderAddressDTO | UpdateOrderAddressDTO email?: string no_notification?: boolean - metadata?: Record + metadata?: Record | null } /** ORDER END */ @@ -167,7 +167,7 @@ export interface CreateOrderLineItemDTO { tax_lines?: CreateOrderTaxLineDTO[] adjustments?: CreateOrderAdjustmentDTO[] - metadata?: Record + metadata?: Record | null } export interface CreateOrderLineItemForOrderDTO extends CreateOrderLineItemDTO { @@ -248,7 +248,7 @@ export interface CreateOrderChangeDTO { requested_by?: string requested_at?: Date created_by?: string - metadata?: Record + metadata?: Record | null actions?: CreateOrderChangeActionDTO[] } @@ -265,25 +265,25 @@ export interface UpdateOrderChangeDTO { declined_reason?: string declined_at?: Date canceled_by?: string - metadata?: Record + metadata?: Record | null } export interface CancelOrderChangeDTO { id: string canceled_by?: string - metadata?: Record + metadata?: Record | null } export interface DeclineOrderChangeDTO { id: string declined_by?: string - metadata?: Record + metadata?: Record | null } export interface ConfirmOrderChangeDTO { id: string confirmed_by?: string - metadata?: Record + metadata?: Record | null } /** ORDER CHANGE END */ @@ -314,7 +314,7 @@ export interface CreateOrderTransactionDTO { currency_code: string reference?: string reference_id?: string - metadata?: Record + metadata?: Record | null } export interface UpdateOrderTransactionDTO { @@ -323,7 +323,7 @@ export interface UpdateOrderTransactionDTO { currency_code?: string reference?: string reference_id?: string - metadata?: Record + metadata?: Record | null } /** ORDER TRANSACTION END */ @@ -340,7 +340,7 @@ export interface UpdateOrderItemDTO { return_received_quantity?: BigNumberInput return_dismissed_quantity?: BigNumberInput written_off_quantity?: BigNumberInput - metadata?: Record + metadata?: Record | null } export interface UpdateOrderItemWithSelectorDTO { @@ -363,9 +363,9 @@ export interface RegisterOrderFulfillmentDTO { id: string quantity: BigNumberInput internal_note?: string - metadata?: Record + metadata?: Record | null }[] - metadata?: Record + metadata?: Record | null } export interface RegisterOrderShipmentDTO { @@ -379,9 +379,9 @@ export interface RegisterOrderShipmentDTO { id: string quantity: BigNumberInput internal_note?: string - metadata?: Record + metadata?: Record | null }[] - metadata?: Record + metadata?: Record | null } export interface CreateOrderReturnDTO { @@ -395,9 +395,9 @@ export interface CreateOrderReturnDTO { id: string quantity: BigNumberInput internal_note?: string - metadata?: Record + metadata?: Record | null }[] - metadata?: Record + metadata?: Record | null } /** ORDER bundled action flows */