From f3eca7734e39c7622610343cdcc3c859291fc1ad Mon Sep 17 00:00:00 2001
From: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
Date: Wed, 18 Dec 2024 10:09:35 +0100
Subject: [PATCH 1/5] fix(medusa): Missing metadata field on order (#10651)
---
integration-tests/modules/__tests__/order/order.spec.ts | 6 ++++++
packages/medusa/src/api/admin/orders/query-config.ts | 8 +-------
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/integration-tests/modules/__tests__/order/order.spec.ts b/integration-tests/modules/__tests__/order/order.spec.ts
index 8e0bc18afc55a..cbe798789f093 100644
--- a/integration-tests/modules/__tests__/order/order.spec.ts
+++ b/integration-tests/modules/__tests__/order/order.spec.ts
@@ -30,6 +30,9 @@ medusaIntegrationTestRunner({
const created = await orderModule.createOrders({
region_id: "test_region_id",
email: "foo@bar.com",
+ metadata: {
+ foo: "bar",
+ },
items: [
{
title: "Custom Item 2",
@@ -108,6 +111,9 @@ medusaIntegrationTestRunner({
payment_status: "not_paid",
region_id: "test_region_id",
fulfillments: [],
+ metadata: {
+ foo: "bar",
+ },
fulfillment_status: "not_fulfilled",
summary: expect.objectContaining({
// TODO: add all summary fields
diff --git a/packages/medusa/src/api/admin/orders/query-config.ts b/packages/medusa/src/api/admin/orders/query-config.ts
index d05a504951260..eb6efcd2323cc 100644
--- a/packages/medusa/src/api/admin/orders/query-config.ts
+++ b/packages/medusa/src/api/admin/orders/query-config.ts
@@ -10,12 +10,8 @@ export const defaultAdminOrderFields = [
]
export const defaultAdminRetrieveOrderFields = [
- "id",
- "display_id",
+ ...defaultAdminOrderFields,
"region_id",
- "status",
- "version",
- "summary",
"total",
"subtotal",
"tax_total",
@@ -36,8 +32,6 @@ export const defaultAdminRetrieveOrderFields = [
"original_shipping_tax_total",
"original_shipping_subtotal",
"original_shipping_total",
- "created_at",
- "updated_at",
"*items",
"*items.tax_lines",
"*items.adjustments",
From bde4b82194f736ff6acdb0f3656ed0dbc42beae2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Frane=20Poli=C4=87?=
<16856471+fPolic@users.noreply.github.com>
Date: Wed, 18 Dec 2024 10:16:26 +0100
Subject: [PATCH 2/5] feat(core-flows,dashboard,js-sdk,medusa,types): support
Fulfillment Options (#10622)
**What**
- add a list point for fetching fulfillment options for a provider
- add FO support on SO create & update on dashboard
- pass `cart` and `stockLocation` to `validateFufillmentData` context
---
CLOSES CMRC-789
CLOSES CMRC-790
---
.../src/hooks/api/fulfillment-providers.tsx | 28 +
.../dashboard/src/hooks/use-combobox-data.tsx | 3 +-
.../src/i18n/translations/$schema.json | 1976 +++++++++++++----
.../dashboard/src/i18n/translations/en.json | 3 +-
.../create-shipping-option-details-form.tsx | 55 +-
.../create-shipping-options-form.tsx | 21 +-
.../create-shipping-options-form/schema.ts | 1 +
.../edit-shipping-option-form.tsx | 50 +-
.../steps/validate-shipping-methods-data.ts | 30 +-
.../workflows/add-shipping-method-to-cart.ts | 15 +-
.../list-shipping-options-for-cart.ts | 44 +-
.../js-sdk/src/admin/fulfillment-provider.ts | 37 +-
packages/core/js-sdk/src/store/index.ts | 17 +
.../fulfillment-provider/admin/entities.ts | 8 +-
.../fulfillment-provider/admin/responses.ts | 10 +-
.../src/http/fulfillment-provider/common.ts | 11 +
.../[id]/options/route.ts | 27 +
.../fulfillment-providers/middlewares.ts | 5 +
.../services/fulfillment-module-service.ts | 3 +-
.../src/services/fulfillment-provider.ts | 3 +-
20 files changed, 1855 insertions(+), 492 deletions(-)
create mode 100644 packages/medusa/src/api/admin/fulfillment-providers/[id]/options/route.ts
diff --git a/packages/admin/dashboard/src/hooks/api/fulfillment-providers.tsx b/packages/admin/dashboard/src/hooks/api/fulfillment-providers.tsx
index 5d17085c504b9..12129496ed0bd 100644
--- a/packages/admin/dashboard/src/hooks/api/fulfillment-providers.tsx
+++ b/packages/admin/dashboard/src/hooks/api/fulfillment-providers.tsx
@@ -9,6 +9,12 @@ export const fulfillmentProvidersQueryKeys = queryKeysFactory(
FULFILLMENT_PROVIDERS_QUERY_KEY
)
+const FULFILLMENT_PROVIDER_OPTIONS_QUERY_KEY =
+ "fulfillment_provider_options" as const
+export const fulfillmentProviderOptionsQueryKeys = queryKeysFactory(
+ FULFILLMENT_PROVIDER_OPTIONS_QUERY_KEY
+)
+
export const useFulfillmentProviders = (
query?: HttpTypes.AdminFulfillmentProviderListParams,
options?: Omit<
@@ -29,3 +35,25 @@ export const useFulfillmentProviders = (
return { ...data, ...rest }
}
+
+export const useFulfillmentProviderOptions = (
+ providerId: string,
+ options?: Omit<
+ UseQueryOptions<
+ HttpTypes.AdminFulfillmentProviderOptionsListResponse,
+ FetchError,
+ HttpTypes.AdminFulfillmentProviderOptionsListResponse,
+ QueryKey
+ >,
+ "queryFn" | "queryKey"
+ >
+) => {
+ const { data, ...rest } = useQuery({
+ queryFn: () =>
+ sdk.admin.fulfillmentProvider.listFulfillmentOptions(providerId),
+ queryKey: fulfillmentProviderOptionsQueryKeys.list(providerId),
+ ...options,
+ })
+
+ return { ...data, ...rest }
+}
diff --git a/packages/admin/dashboard/src/hooks/use-combobox-data.tsx b/packages/admin/dashboard/src/hooks/use-combobox-data.tsx
index 159bf0e9e2226..1488dec0c73b8 100644
--- a/packages/admin/dashboard/src/hooks/use-combobox-data.tsx
+++ b/packages/admin/dashboard/src/hooks/use-combobox-data.tsx
@@ -20,7 +20,7 @@ type ComboboxQueryParams = {
export const useComboboxData = <
TResponse extends ComboboxExternalData,
- TParams extends ComboboxQueryParams
+ TParams extends ComboboxQueryParams,
>({
queryKey,
queryFn,
@@ -50,7 +50,6 @@ export const useComboboxData = <
enabled: !!defaultValue,
})
-
const { data, ...rest } = useInfiniteQuery({
queryKey: [...queryKey, query],
queryFn: async ({ pageParam = 0 }) => {
diff --git a/packages/admin/dashboard/src/i18n/translations/$schema.json b/packages/admin/dashboard/src/i18n/translations/$schema.json
index 2579af1ee867d..d755ecd0d0e86 100644
--- a/packages/admin/dashboard/src/i18n/translations/$schema.json
+++ b/packages/admin/dashboard/src/i18n/translations/$schema.json
@@ -258,7 +258,11 @@
"type": "string"
}
},
- "required": ["header_one", "header_other", "description"],
+ "required": [
+ "header_one",
+ "header_other",
+ "description"
+ ],
"additionalProperties": false
}
},
@@ -307,7 +311,11 @@
"type": "string"
}
},
- "required": ["insertRowAbove", "insertRowBelow", "deleteRow"],
+ "required": [
+ "insertRowAbove",
+ "insertRowBelow",
+ "deleteRow"
+ ],
"additionalProperties": false
},
"labels": {
@@ -320,7 +328,10 @@
"type": "string"
}
},
- "required": ["key", "value"],
+ "required": [
+ "key",
+ "value"
+ ],
"additionalProperties": false
},
"complexRow": {
@@ -336,7 +347,11 @@
"type": "string"
}
},
- "required": ["label", "description", "tooltip"],
+ "required": [
+ "label",
+ "description",
+ "tooltip"
+ ],
"additionalProperties": false
}
},
@@ -351,7 +366,12 @@
"additionalProperties": false
}
},
- "required": ["header", "numberOfKeys_one", "numberOfKeys_other", "edit"],
+ "required": [
+ "header",
+ "numberOfKeys_one",
+ "numberOfKeys_other",
+ "edit"
+ ],
"additionalProperties": false
},
"validation": {
@@ -364,7 +384,10 @@
"type": "string"
}
},
- "required": ["mustBeInt", "mustBePositive"],
+ "required": [
+ "mustBeInt",
+ "mustBePositive"
+ ],
"additionalProperties": false
},
"actions": {
@@ -550,7 +573,9 @@
"type": "string"
}
},
- "required": ["in"],
+ "required": [
+ "in"
+ ],
"additionalProperties": false
},
"app": {
@@ -901,7 +926,12 @@
"type": "string"
}
},
- "required": ["label", "dark", "light", "system"],
+ "required": [
+ "label",
+ "dark",
+ "light",
+ "system"
+ ],
"additionalProperties": false
}
},
@@ -924,7 +954,10 @@
"type": "string"
}
},
- "required": ["label", "storeSettings"],
+ "required": [
+ "label",
+ "storeSettings"
+ ],
"additionalProperties": false
},
"actions": {
@@ -934,11 +967,17 @@
"type": "string"
}
},
- "required": ["logout"],
+ "required": [
+ "logout"
+ ],
"additionalProperties": false
}
},
- "required": ["user", "store", "actions"],
+ "required": [
+ "user",
+ "store",
+ "actions"
+ ],
"additionalProperties": false
},
"nav": {
@@ -954,7 +993,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"common": {
@@ -964,7 +1006,9 @@
"type": "string"
}
},
- "required": ["extensions"],
+ "required": [
+ "extensions"
+ ],
"additionalProperties": false
},
"main": {
@@ -977,7 +1021,10 @@
"type": "string"
}
},
- "required": ["store", "storeSettings"],
+ "required": [
+ "store",
+ "storeSettings"
+ ],
"additionalProperties": false
},
"settings": {
@@ -996,15 +1043,30 @@
"type": "string"
}
},
- "required": ["header", "general", "developer", "myAccount"],
+ "required": [
+ "header",
+ "general",
+ "developer",
+ "myAccount"
+ ],
"additionalProperties": false
}
},
- "required": ["accessibility", "common", "main", "settings"],
+ "required": [
+ "accessibility",
+ "common",
+ "main",
+ "settings"
+ ],
"additionalProperties": false
}
},
- "required": ["search", "keyboardShortcuts", "menus", "nav"],
+ "required": [
+ "search",
+ "keyboardShortcuts",
+ "menus",
+ "nav"
+ ],
"additionalProperties": false
},
"dataGrid": {
@@ -1023,7 +1085,11 @@
"type": "string"
}
},
- "required": ["view", "resetToDefault", "disabled"],
+ "required": [
+ "view",
+ "resetToDefault",
+ "disabled"
+ ],
"additionalProperties": false
},
"shortcuts": {
@@ -1117,7 +1183,10 @@
"additionalProperties": false
}
},
- "required": ["label", "commands"],
+ "required": [
+ "label",
+ "commands"
+ ],
"additionalProperties": false
},
"errors": {
@@ -1133,11 +1202,19 @@
"type": "string"
}
},
- "required": ["fixError", "count_one", "count_other"],
+ "required": [
+ "fixError",
+ "count_one",
+ "count_other"
+ ],
"additionalProperties": false
}
},
- "required": ["columns", "shortcuts", "errors"],
+ "required": [
+ "columns",
+ "shortcuts",
+ "errors"
+ ],
"additionalProperties": false
},
"filters": {
@@ -1223,7 +1300,11 @@
"type": "string"
}
},
- "required": ["date", "compare", "addFilter"],
+ "required": [
+ "date",
+ "compare",
+ "addFilter"
+ ],
"additionalProperties": false
},
"errorBoundary": {
@@ -1293,7 +1374,12 @@
"type": "string"
}
},
- "required": ["header", "editHeader", "editLabel", "label"],
+ "required": [
+ "header",
+ "editHeader",
+ "editLabel",
+ "label"
+ ],
"additionalProperties": false
},
"billingAddress": {
@@ -1352,7 +1438,11 @@
"type": "string"
}
},
- "required": ["editHeader", "editLabel", "label"],
+ "required": [
+ "editHeader",
+ "editLabel",
+ "label"
+ ],
"additionalProperties": false
},
"transferOwnership": {
@@ -1374,7 +1464,10 @@
"type": "string"
}
},
- "required": ["order", "draft"],
+ "required": [
+ "order",
+ "draft"
+ ],
"additionalProperties": false
},
"currentOwner": {
@@ -1387,7 +1480,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
},
"newOwner": {
@@ -1400,7 +1496,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
},
"validation": {
@@ -1413,7 +1512,10 @@
"type": "string"
}
},
- "required": ["mustBeDifferent", "required"],
+ "required": [
+ "mustBeDifferent",
+ "required"
+ ],
"additionalProperties": false
}
},
@@ -1434,7 +1536,9 @@
"type": "string"
}
},
- "required": ["availableIn"],
+ "required": [
+ "availableIn"
+ ],
"additionalProperties": false
},
"products": {
@@ -1450,7 +1554,9 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
},
"edit": {
@@ -1466,7 +1572,11 @@
"type": "string"
}
},
- "required": ["header", "description", "successToast"],
+ "required": [
+ "header",
+ "description",
+ "successToast"
+ ],
"additionalProperties": false
},
"create": {
@@ -1497,7 +1607,12 @@
"type": "string"
}
},
- "required": ["details", "organize", "variants", "inventory"],
+ "required": [
+ "details",
+ "organize",
+ "variants",
+ "inventory"
+ ],
"additionalProperties": false
},
"errors": {
@@ -1513,7 +1628,11 @@
"type": "string"
}
},
- "required": ["variants", "options", "uniqueSku"],
+ "required": [
+ "variants",
+ "options",
+ "uniqueSku"
+ ],
"additionalProperties": false
},
"inventory": {
@@ -1559,7 +1678,9 @@
"type": "string"
}
},
- "required": ["placeholder"],
+ "required": [
+ "placeholder"
+ ],
"additionalProperties": false
},
"optionValues": {
@@ -1569,7 +1690,9 @@
"type": "string"
}
},
- "required": ["placeholder"],
+ "required": [
+ "placeholder"
+ ],
"additionalProperties": false
},
"productVariants": {
@@ -1588,7 +1711,12 @@
"type": "string"
}
},
- "required": ["label", "hint", "alert", "tip"],
+ "required": [
+ "label",
+ "hint",
+ "alert",
+ "tip"
+ ],
"additionalProperties": false
},
"productOptions": {
@@ -1601,7 +1729,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
}
},
@@ -1651,7 +1782,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"filters": {
@@ -1664,7 +1798,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"columns": {
@@ -1677,7 +1814,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
@@ -1715,7 +1855,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"upload": {
@@ -1756,7 +1899,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
@@ -1850,7 +1996,11 @@
"type": "string"
}
},
- "required": ["header", "description", "action"],
+ "required": [
+ "header",
+ "description",
+ "action"
+ ],
"additionalProperties": false
},
"successToast": {
@@ -1909,7 +2059,12 @@
"type": "string"
}
},
- "required": ["draft", "published", "proposed", "rejected"],
+ "required": [
+ "draft",
+ "published",
+ "proposed",
+ "rejected"
+ ],
"additionalProperties": false
},
"fields": {
@@ -1925,7 +2080,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
},
"subtitle": {
@@ -1935,7 +2093,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"handle": {
@@ -1948,7 +2108,10 @@
"type": "string"
}
},
- "required": ["label", "tooltip"],
+ "required": [
+ "label",
+ "tooltip"
+ ],
"additionalProperties": false
},
"description": {
@@ -1961,7 +2124,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
},
"discountable": {
@@ -1974,7 +2140,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
},
"type": {
@@ -1984,7 +2153,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"collection": {
@@ -1994,7 +2165,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"categories": {
@@ -2004,7 +2177,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"tags": {
@@ -2014,7 +2189,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"sales_channels": {
@@ -2027,7 +2204,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
},
"countryOrigin": {
@@ -2037,7 +2217,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"material": {
@@ -2047,7 +2229,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"width": {
@@ -2057,7 +2241,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"length": {
@@ -2067,7 +2253,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"height": {
@@ -2077,7 +2265,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"weight": {
@@ -2087,7 +2277,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"options": {
@@ -2136,7 +2328,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
},
"mid_code": {
@@ -2146,7 +2341,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"hs_code": {
@@ -2156,7 +2353,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
}
},
@@ -2197,7 +2396,10 @@
"type": "string"
}
},
- "required": ["header", "success"],
+ "required": [
+ "header",
+ "success"
+ ],
"additionalProperties": false
},
"create": {
@@ -2207,7 +2409,9 @@
"type": "string"
}
},
- "required": ["header"],
+ "required": [
+ "header"
+ ],
"additionalProperties": false
},
"deleteWarning": {
@@ -2253,7 +2457,10 @@
"type": "string"
}
},
- "required": ["inventoryItems", "inventoryKit"],
+ "required": [
+ "inventoryItems",
+ "inventoryKit"
+ ],
"additionalProperties": false
},
"inventoryKit": {
@@ -2272,7 +2479,10 @@
"type": "string"
}
},
- "required": ["itemId", "quantity"],
+ "required": [
+ "itemId",
+ "quantity"
+ ],
"additionalProperties": false
},
"header": {
@@ -2367,7 +2577,10 @@
"type": "string"
}
},
- "required": ["header", "successToast"],
+ "required": [
+ "header",
+ "successToast"
+ ],
"additionalProperties": false
},
"create": {
@@ -2380,14 +2593,22 @@
"type": "string"
}
},
- "required": ["header", "successToast"],
+ "required": [
+ "header",
+ "successToast"
+ ],
"additionalProperties": false
},
"deleteWarning": {
"type": "string"
}
},
- "required": ["header", "edit", "create", "deleteWarning"],
+ "required": [
+ "header",
+ "edit",
+ "create",
+ "deleteWarning"
+ ],
"additionalProperties": false
},
"organization": {
@@ -2409,15 +2630,23 @@
"type": "string"
}
},
- "required": ["success"],
+ "required": [
+ "success"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "toasts"],
+ "required": [
+ "header",
+ "toasts"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "edit"],
+ "required": [
+ "header",
+ "edit"
+ ],
"additionalProperties": false
},
"toasts": {
@@ -2436,7 +2665,10 @@
"type": "string"
}
},
- "required": ["header", "description"],
+ "required": [
+ "header",
+ "description"
+ ],
"additionalProperties": false
},
"error": {
@@ -2446,15 +2678,22 @@
"type": "string"
}
},
- "required": ["header"],
+ "required": [
+ "header"
+ ],
"additionalProperties": false
}
},
- "required": ["success", "error"],
+ "required": [
+ "success",
+ "error"
+ ],
"additionalProperties": false
}
},
- "required": ["delete"],
+ "required": [
+ "delete"
+ ],
"additionalProperties": false
}
},
@@ -2532,7 +2771,9 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
},
"add": {
@@ -2545,7 +2786,10 @@
"type": "string"
}
},
- "required": ["successToast_one", "successToast_other"],
+ "required": [
+ "successToast_one",
+ "successToast_other"
+ ],
"additionalProperties": false
},
"remove": {
@@ -2558,11 +2802,18 @@
"type": "string"
}
},
- "required": ["successToast_one", "successToast_other"],
+ "required": [
+ "successToast_one",
+ "successToast_other"
+ ],
"additionalProperties": false
}
},
- "required": ["list", "add", "remove"],
+ "required": [
+ "list",
+ "add",
+ "remove"
+ ],
"additionalProperties": false
}
},
@@ -2610,14 +2861,22 @@
"type": "string"
}
},
- "required": ["details", "organize"],
+ "required": [
+ "details",
+ "organize"
+ ],
"additionalProperties": false
},
"successToast": {
"type": "string"
}
},
- "required": ["header", "hint", "tabs", "successToast"],
+ "required": [
+ "header",
+ "hint",
+ "tabs",
+ "successToast"
+ ],
"additionalProperties": false
},
"edit": {
@@ -2633,7 +2892,11 @@
"type": "string"
}
},
- "required": ["header", "description", "successToast"],
+ "required": [
+ "header",
+ "description",
+ "successToast"
+ ],
"additionalProperties": false
},
"delete": {
@@ -2646,7 +2909,10 @@
"type": "string"
}
},
- "required": ["confirmation", "successToast"],
+ "required": [
+ "confirmation",
+ "successToast"
+ ],
"additionalProperties": false
},
"products": {
@@ -2703,11 +2969,17 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
- "required": ["add", "remove", "list"],
+ "required": [
+ "add",
+ "remove",
+ "list"
+ ],
"additionalProperties": false
},
"organize": {
@@ -2720,7 +2992,10 @@
"type": "string"
}
},
- "required": ["header", "action"],
+ "required": [
+ "header",
+ "action"
+ ],
"additionalProperties": false
},
"fields": {
@@ -2739,7 +3014,11 @@
"type": "string"
}
},
- "required": ["label", "internal", "public"],
+ "required": [
+ "label",
+ "internal",
+ "public"
+ ],
"additionalProperties": false
},
"status": {
@@ -2755,7 +3034,11 @@
"type": "string"
}
},
- "required": ["label", "active", "inactive"],
+ "required": [
+ "label",
+ "active",
+ "inactive"
+ ],
"additionalProperties": false
},
"path": {
@@ -2768,7 +3051,10 @@
"type": "string"
}
},
- "required": ["label", "tooltip"],
+ "required": [
+ "label",
+ "tooltip"
+ ],
"additionalProperties": false
},
"children": {
@@ -2778,7 +3064,9 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
},
"new": {
@@ -2788,11 +3076,19 @@
"type": "string"
}
},
- "required": ["label"],
+ "required": [
+ "label"
+ ],
"additionalProperties": false
}
},
- "required": ["visibility", "status", "path", "children", "new"],
+ "required": [
+ "visibility",
+ "status",
+ "path",
+ "children",
+ "new"
+ ],
"additionalProperties": false
}
},
@@ -2942,8 +3238,11 @@
"type": "string"
}
},
- "required": ["noAvaliableQuantity", "quantityOutOfRange"],
- "additionalProperties": false
+ "required": [
+ "noAvaliableQuantity",
+ "quantityOutOfRange"
+ ],
+ "additionalProperties": false
}
},
"required": [
@@ -2978,11 +3277,15 @@
"type": "string"
}
},
- "required": ["stockedQuantity"],
+ "required": [
+ "stockedQuantity"
+ ],
"additionalProperties": false
}
},
- "required": ["errors"],
+ "required": [
+ "errors"
+ ],
"additionalProperties": false
},
"toast": {
@@ -2998,7 +3301,11 @@
"type": "string"
}
},
- "required": ["updateLocations", "updateLevel", "updateItem"],
+ "required": [
+ "updateLocations",
+ "updateLevel",
+ "updateItem"
+ ],
"additionalProperties": false
}
},
@@ -3104,7 +3411,9 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
},
"create": {
@@ -3120,7 +3429,11 @@
"type": "string"
}
},
- "required": ["header", "hint", "successToast"],
+ "required": [
+ "header",
+ "hint",
+ "successToast"
+ ],
"additionalProperties": false
},
"groups": {
@@ -3145,7 +3458,9 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
},
"add": {
@@ -3161,11 +3476,16 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
- "required": ["success", "list"],
+ "required": [
+ "success",
+ "list"
+ ],
"additionalProperties": false
},
"removed": {
@@ -3181,11 +3501,16 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
- "required": ["success", "list"],
+ "required": [
+ "success",
+ "list"
+ ],
"additionalProperties": false
}
},
@@ -3213,7 +3538,11 @@
"type": "string"
}
},
- "required": ["header", "emailDisabledTooltip", "successToast"],
+ "required": [
+ "header",
+ "emailDisabledTooltip",
+ "successToast"
+ ],
"additionalProperties": false
},
"delete": {
@@ -3229,7 +3558,11 @@
"type": "string"
}
},
- "required": ["title", "description", "successToast"],
+ "required": [
+ "title",
+ "description",
+ "successToast"
+ ],
"additionalProperties": false
},
"fields": {
@@ -3245,7 +3578,11 @@
"type": "string"
}
},
- "required": ["guest", "registered", "groups"],
+ "required": [
+ "guest",
+ "registered",
+ "groups"
+ ],
"additionalProperties": false
},
"registered": {
@@ -3294,7 +3631,11 @@
"type": "string"
}
},
- "required": ["header", "hint", "successToast"],
+ "required": [
+ "header",
+ "hint",
+ "successToast"
+ ],
"additionalProperties": false
},
"edit": {
@@ -3307,7 +3648,10 @@
"type": "string"
}
},
- "required": ["header", "successToast"],
+ "required": [
+ "header",
+ "successToast"
+ ],
"additionalProperties": false
},
"delete": {
@@ -3323,7 +3667,11 @@
"type": "string"
}
},
- "required": ["title", "description", "successToast"],
+ "required": [
+ "title",
+ "description",
+ "successToast"
+ ],
"additionalProperties": false
},
"customers": {
@@ -3348,11 +3696,17 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
- "required": ["successToast_one", "successToast_other", "list"],
+ "required": [
+ "successToast_one",
+ "successToast_other",
+ "list"
+ ],
"additionalProperties": false
},
"remove": {
@@ -3386,11 +3740,18 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
- "required": ["alreadyAddedTooltip", "add", "remove", "list"],
+ "required": [
+ "alreadyAddedTooltip",
+ "add",
+ "remove",
+ "list"
+ ],
"additionalProperties": false
}
},
@@ -3432,7 +3793,9 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
},
"summary": {
@@ -3724,7 +4087,10 @@
"type": "string"
}
},
- "required": ["title", "titlePending"],
+ "required": [
+ "title",
+ "titlePending"
+ ],
"additionalProperties": false
},
"toast": {
@@ -3737,7 +4103,10 @@
"type": "string"
}
},
- "required": ["canceledSuccessfully", "confirmedSuccessfully"],
+ "required": [
+ "canceledSuccessfully",
+ "confirmedSuccessfully"
+ ],
"additionalProperties": false
},
"validation": {
@@ -3747,7 +4116,9 @@
"type": "string"
}
},
- "required": ["quantityLowerThanFulfillment"],
+ "required": [
+ "quantityLowerThanFulfillment"
+ ],
"additionalProperties": false
}
},
@@ -3788,7 +4159,10 @@
"type": "string"
}
},
- "required": ["title", "requestSuccess"],
+ "required": [
+ "title",
+ "requestSuccess"
+ ],
"additionalProperties": false
},
"shippingAddress": {
@@ -3801,7 +4175,10 @@
"type": "string"
}
},
- "required": ["title", "requestSuccess"],
+ "required": [
+ "title",
+ "requestSuccess"
+ ],
"additionalProperties": false
},
"billingAddress": {
@@ -3814,11 +4191,18 @@
"type": "string"
}
},
- "required": ["title", "requestSuccess"],
+ "required": [
+ "title",
+ "requestSuccess"
+ ],
"additionalProperties": false
}
},
- "required": ["email", "shippingAddress", "billingAddress"],
+ "required": [
+ "email",
+ "shippingAddress",
+ "billingAddress"
+ ],
"additionalProperties": false
},
"returns": {
@@ -3924,7 +4308,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"placeholders": {
@@ -3940,7 +4327,10 @@
"type": "string"
}
},
- "required": ["title", "hint"],
+ "required": [
+ "title",
+ "hint"
+ ],
"additionalProperties": false
},
"outboundShippingOptions": {
@@ -3953,7 +4343,10 @@
"type": "string"
}
},
- "required": ["title", "hint"],
+ "required": [
+ "title",
+ "hint"
+ ],
"additionalProperties": false
}
},
@@ -4038,7 +4431,10 @@
"type": "string"
}
},
- "required": ["canceledSuccessfully", "confirmedSuccessfully"],
+ "required": [
+ "canceledSuccessfully",
+ "confirmedSuccessfully"
+ ],
"additionalProperties": false
},
"panel": {
@@ -4051,7 +4447,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
@@ -4140,11 +4539,15 @@
"type": "string"
}
},
- "required": ["successToast"],
+ "required": [
+ "successToast"
+ ],
"additionalProperties": false
}
},
- "required": ["cancelClaim"],
+ "required": [
+ "cancelClaim"
+ ],
"additionalProperties": false
},
"cancel": {
@@ -4157,7 +4560,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"tooltips": {
@@ -4167,7 +4573,9 @@
"type": "string"
}
},
- "required": ["onlyReturnShippingOptions"],
+ "required": [
+ "onlyReturnShippingOptions"
+ ],
"additionalProperties": false
},
"toast": {
@@ -4180,7 +4588,10 @@
"type": "string"
}
},
- "required": ["canceledSuccessfully", "confirmedSuccessfully"],
+ "required": [
+ "canceledSuccessfully",
+ "confirmedSuccessfully"
+ ],
"additionalProperties": false
},
"panel": {
@@ -4193,7 +4604,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
@@ -4263,11 +4677,15 @@
"type": "string"
}
},
- "required": ["successToast"],
+ "required": [
+ "successToast"
+ ],
"additionalProperties": false
}
},
- "required": ["cancelExchange"],
+ "required": [
+ "cancelExchange"
+ ],
"additionalProperties": false
},
"cancel": {
@@ -4280,7 +4698,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"tooltips": {
@@ -4290,7 +4711,9 @@
"type": "string"
}
},
- "required": ["onlyReturnShippingOptions"],
+ "required": [
+ "onlyReturnShippingOptions"
+ ],
"additionalProperties": false
},
"toast": {
@@ -4303,7 +4726,10 @@
"type": "string"
}
},
- "required": ["canceledSuccessfully", "confirmedSuccessfully"],
+ "required": [
+ "canceledSuccessfully",
+ "confirmedSuccessfully"
+ ],
"additionalProperties": false
},
"panel": {
@@ -4316,7 +4742,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
@@ -4350,7 +4779,10 @@
"type": "string"
}
},
- "required": ["allocatedLabel", "notAllocatedLabel"],
+ "required": [
+ "allocatedLabel",
+ "notAllocatedLabel"
+ ],
"additionalProperties": false
},
"allocateItems": {
@@ -4387,7 +4819,9 @@
"type": "string"
}
},
- "required": ["created"],
+ "required": [
+ "created"
+ ],
"additionalProperties": false
},
"error": {
@@ -4397,7 +4831,9 @@
"type": "string"
}
},
- "required": ["quantityNotAllocated"],
+ "required": [
+ "quantityNotAllocated"
+ ],
"additionalProperties": false
}
},
@@ -4520,7 +4956,11 @@
"type": "string"
}
},
- "required": ["wrongQuantity", "wrongQuantity_other", "noItems"],
+ "required": [
+ "wrongQuantity",
+ "wrongQuantity_other",
+ "noItems"
+ ],
"additionalProperties": false
},
"status": {
@@ -4666,7 +5106,11 @@
"type": "string"
}
},
- "required": ["amountToLarge", "amountNegative", "reasonRequired"],
+ "required": [
+ "amountToLarge",
+ "amountNegative",
+ "reasonRequired"
+ ],
"additionalProperties": false
}
},
@@ -4762,7 +5206,10 @@
"type": "string"
}
},
- "required": ["toReturn", "toSend"],
+ "required": [
+ "toReturn",
+ "toSend"
+ ],
"additionalProperties": false
},
"placed": {
@@ -4775,7 +5222,10 @@
"type": "string"
}
},
- "required": ["title", "fromSalesChannel"],
+ "required": [
+ "title",
+ "fromSalesChannel"
+ ],
"additionalProperties": false
},
"canceled": {
@@ -4785,7 +5235,9 @@
"type": "string"
}
},
- "required": ["title"],
+ "required": [
+ "title"
+ ],
"additionalProperties": false
},
"payment": {
@@ -4804,7 +5256,12 @@
"type": "string"
}
},
- "required": ["awaiting", "captured", "canceled", "refunded"],
+ "required": [
+ "awaiting",
+ "captured",
+ "canceled",
+ "refunded"
+ ],
"additionalProperties": false
},
"fulfillment": {
@@ -4877,7 +5334,10 @@
"type": "string"
}
},
- "required": ["comment", "byLine"],
+ "required": [
+ "comment",
+ "byLine"
+ ],
"additionalProperties": false
},
"claim": {
@@ -4938,7 +5398,10 @@
"type": "string"
}
},
- "required": ["requested", "confirmed"],
+ "required": [
+ "requested",
+ "confirmed"
+ ],
"additionalProperties": false
},
"transfer": {
@@ -4954,7 +5417,11 @@
"type": "string"
}
},
- "required": ["requested", "confirmed", "declined"],
+ "required": [
+ "requested",
+ "confirmed",
+ "declined"
+ ],
"additionalProperties": false
},
"update_order": {
@@ -4970,7 +5437,11 @@
"type": "string"
}
},
- "required": ["shipping_address", "billing_address", "email"],
+ "required": [
+ "shipping_address",
+ "billing_address",
+ "email"
+ ],
"additionalProperties": false
}
},
@@ -5015,7 +5486,11 @@
"type": "string"
}
},
- "required": ["displayId", "refundableAmount", "returnableQuantity"],
+ "required": [
+ "displayId",
+ "refundableAmount",
+ "returnableQuantity"
+ ],
"additionalProperties": false
}
},
@@ -5074,7 +5549,11 @@
"type": "string"
}
},
- "required": ["label", "warningTitle", "warningDescription"],
+ "required": [
+ "label",
+ "warningTitle",
+ "warningDescription"
+ ],
"additionalProperties": false
},
"status": {
@@ -5087,7 +5566,10 @@
"type": "string"
}
},
- "required": ["open", "completed"],
+ "required": [
+ "open",
+ "completed"
+ ],
"additionalProperties": false
},
"create": {
@@ -5228,7 +5710,9 @@
"type": "string"
}
},
- "required": ["description"],
+ "required": [
+ "description"
+ ],
"additionalProperties": false
},
"create": {
@@ -5244,7 +5728,11 @@
"type": "string"
}
},
- "required": ["header", "hint", "successToast"],
+ "required": [
+ "header",
+ "hint",
+ "successToast"
+ ],
"additionalProperties": false
},
"edit": {
@@ -5260,7 +5748,11 @@
"type": "string"
}
},
- "required": ["header", "viewInventory", "successToast"],
+ "required": [
+ "header",
+ "viewInventory",
+ "successToast"
+ ],
"additionalProperties": false
},
"delete": {
@@ -5270,7 +5762,9 @@
"type": "string"
}
},
- "required": ["confirmation"],
+ "required": [
+ "confirmation"
+ ],
"additionalProperties": false
},
"fulfillmentProviders": {
@@ -5319,7 +5813,9 @@
"type": "string"
}
},
- "required": ["header"],
+ "required": [
+ "header"
+ ],
"additionalProperties": false
},
"shipping": {
@@ -5329,7 +5825,9 @@
"type": "string"
}
},
- "required": ["header"],
+ "required": [
+ "header"
+ ],
"additionalProperties": false
},
"disable": {
@@ -5345,7 +5843,11 @@
"type": "string"
}
},
- "required": ["confirmation", "pickup", "shipping"],
+ "required": [
+ "confirmation",
+ "pickup",
+ "shipping"
+ ],
"additionalProperties": false
},
"enable": {
@@ -5358,11 +5860,19 @@
"type": "string"
}
},
- "required": ["pickup", "shipping"],
+ "required": [
+ "pickup",
+ "shipping"
+ ],
"additionalProperties": false
}
},
- "required": ["pickup", "shipping", "disable", "enable"],
+ "required": [
+ "pickup",
+ "shipping",
+ "disable",
+ "enable"
+ ],
"additionalProperties": false
},
"sidebar": {
@@ -5381,11 +5891,17 @@
"type": "string"
}
},
- "required": ["label", "description"],
+ "required": [
+ "label",
+ "description"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "shippingProfiles"],
+ "required": [
+ "header",
+ "shippingProfiles"
+ ],
"additionalProperties": false
},
"salesChannels": {
@@ -5442,7 +5958,12 @@
"type": "string"
}
},
- "required": ["header", "hint", "label", "successToast"],
+ "required": [
+ "header",
+ "hint",
+ "label",
+ "successToast"
+ ],
"additionalProperties": false
},
"returns": {
@@ -5461,7 +5982,12 @@
"type": "string"
}
},
- "required": ["header", "hint", "label", "successToast"],
+ "required": [
+ "header",
+ "hint",
+ "label",
+ "successToast"
+ ],
"additionalProperties": false
},
"tabs": {
@@ -5474,14 +6000,22 @@
"type": "string"
}
},
- "required": ["details", "prices"],
+ "required": [
+ "details",
+ "prices"
+ ],
"additionalProperties": false
},
"action": {
"type": "string"
}
},
- "required": ["shipping", "returns", "tabs", "action"],
+ "required": [
+ "shipping",
+ "returns",
+ "tabs",
+ "action"
+ ],
"additionalProperties": false
},
"delete": {
@@ -5494,7 +6028,10 @@
"type": "string"
}
},
- "required": ["confirmation", "successToast"],
+ "required": [
+ "confirmation",
+ "successToast"
+ ],
"additionalProperties": false
},
"edit": {
@@ -5510,7 +6047,11 @@
"type": "string"
}
},
- "required": ["header", "action", "successToast"],
+ "required": [
+ "header",
+ "action",
+ "successToast"
+ ],
"additionalProperties": false
},
"pricing": {
@@ -5520,7 +6061,9 @@
"type": "string"
}
},
- "required": ["action"],
+ "required": [
+ "action"
+ ],
"additionalProperties": false
},
"conditionalPrices": {
@@ -5539,7 +6082,9 @@
"type": "string"
}
},
- "required": ["cartItemTotal"],
+ "required": [
+ "cartItemTotal"
+ ],
"additionalProperties": false
},
"summaries": {
@@ -5555,7 +6100,11 @@
"type": "string"
}
},
- "required": ["range", "greaterThan", "lessThan"],
+ "required": [
+ "range",
+ "greaterThan",
+ "lessThan"
+ ],
"additionalProperties": false
},
"actions": {
@@ -5568,7 +6117,10 @@
"type": "string"
}
},
- "required": ["addPrice", "manageConditionalPrices"],
+ "required": [
+ "addPrice",
+ "manageConditionalPrices"
+ ],
"additionalProperties": false
},
"rules": {
@@ -5584,7 +6136,11 @@
"type": "string"
}
},
- "required": ["amount", "gte", "lte"],
+ "required": [
+ "amount",
+ "gte",
+ "lte"
+ ],
"additionalProperties": false
},
"customRules": {
@@ -5606,7 +6162,13 @@
"type": "string"
}
},
- "required": ["label", "tooltip", "eq", "gt", "lt"],
+ "required": [
+ "label",
+ "tooltip",
+ "eq",
+ "gt",
+ "lt"
+ ],
"additionalProperties": false
},
"errors": {
@@ -5696,7 +6258,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
},
"calculated": {
@@ -5709,15 +6274,24 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["fixed", "calculated"],
+ "required": [
+ "fixed",
+ "calculated"
+ ],
"additionalProperties": false
}
},
- "required": ["label", "options"],
+ "required": [
+ "label",
+ "options"
+ ],
"additionalProperties": false
},
"enableInStore": {
@@ -5730,7 +6304,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
},
"provider": {
@@ -5738,6 +6315,9 @@
},
"profile": {
"type": "string"
+ },
+ "fulfillmentOption": {
+ "type": "string"
}
},
"required": [
@@ -5745,7 +6325,8 @@
"priceType",
"enableInStore",
"provider",
- "profile"
+ "profile",
+ "fulfillmentOption"
],
"additionalProperties": false
}
@@ -5797,7 +6378,10 @@
"type": "string"
}
},
- "required": ["header", "successToast"],
+ "required": [
+ "header",
+ "successToast"
+ ],
"additionalProperties": false
},
"delete": {
@@ -5810,7 +6394,10 @@
"type": "string"
}
},
- "required": ["confirmation", "successToast"],
+ "required": [
+ "confirmation",
+ "successToast"
+ ],
"additionalProperties": false
},
"manageAreas": {
@@ -5832,7 +6419,13 @@
"type": "string"
}
},
- "required": ["header", "action", "label", "hint", "successToast"],
+ "required": [
+ "header",
+ "action",
+ "label",
+ "hint",
+ "successToast"
+ ],
"additionalProperties": false
},
"fields": {
@@ -5845,11 +6438,20 @@
"type": "string"
}
},
- "required": ["noRecords", "tip"],
+ "required": [
+ "noRecords",
+ "tip"
+ ],
"additionalProperties": false
}
},
- "required": ["create", "edit", "delete", "manageAreas", "fields"],
+ "required": [
+ "create",
+ "edit",
+ "delete",
+ "manageAreas",
+ "fields"
+ ],
"additionalProperties": false
}
},
@@ -5890,7 +6492,11 @@
"type": "string"
}
},
- "required": ["header", "hint", "successToast"],
+ "required": [
+ "header",
+ "hint",
+ "successToast"
+ ],
"additionalProperties": false
},
"delete": {
@@ -5906,21 +6512,33 @@
"type": "string"
}
},
- "required": ["title", "description", "successToast"],
- "additionalProperties": false
- },
- "tooltip": {
- "type": "object",
+ "required": [
+ "title",
+ "description",
+ "successToast"
+ ],
+ "additionalProperties": false
+ },
+ "tooltip": {
+ "type": "object",
"properties": {
"type": {
"type": "string"
}
},
- "required": ["type"],
+ "required": [
+ "type"
+ ],
"additionalProperties": false
}
},
- "required": ["domain", "subtitle", "create", "delete", "tooltip"],
+ "required": [
+ "domain",
+ "subtitle",
+ "create",
+ "delete",
+ "tooltip"
+ ],
"additionalProperties": false
},
"taxRegions": {
@@ -5936,7 +6554,9 @@
"type": "string"
}
},
- "required": ["hint"],
+ "required": [
+ "hint"
+ ],
"additionalProperties": false
},
"delete": {
@@ -5949,7 +6569,10 @@
"type": "string"
}
},
- "required": ["confirmation", "successToast"],
+ "required": [
+ "confirmation",
+ "successToast"
+ ],
"additionalProperties": false
},
"create": {
@@ -5971,14 +6594,22 @@
"type": "string"
}
},
- "required": ["rateIsRequired", "nameIsRequired"],
+ "required": [
+ "rateIsRequired",
+ "nameIsRequired"
+ ],
"additionalProperties": false
},
"successToast": {
"type": "string"
}
},
- "required": ["header", "hint", "errors", "successToast"],
+ "required": [
+ "header",
+ "hint",
+ "errors",
+ "successToast"
+ ],
"additionalProperties": false
},
"province": {
@@ -5997,11 +6628,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"state": {
@@ -6020,11 +6657,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"stateOrTerritory": {
@@ -6043,11 +6686,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"county": {
@@ -6066,11 +6715,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"region": {
@@ -6089,11 +6744,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"department": {
@@ -6112,11 +6773,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"territory": {
@@ -6135,11 +6802,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"prefecture": {
@@ -6158,11 +6831,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"district": {
@@ -6181,11 +6860,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"governorate": {
@@ -6204,11 +6889,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"canton": {
@@ -6227,11 +6918,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"emirate": {
@@ -6250,11 +6947,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"sublevel": {
@@ -6273,11 +6976,17 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create"],
+ "required": [
+ "header",
+ "create"
+ ],
"additionalProperties": false
},
"taxOverrides": {
@@ -6296,7 +7005,10 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
},
"edit": {
@@ -6309,11 +7021,18 @@
"type": "string"
}
},
- "required": ["header", "hint"],
+ "required": [
+ "header",
+ "hint"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "create", "edit"],
+ "required": [
+ "header",
+ "create",
+ "edit"
+ ],
"additionalProperties": false
},
"taxRates": {
@@ -6332,7 +7051,11 @@
"type": "string"
}
},
- "required": ["header", "hint", "successToast"],
+ "required": [
+ "header",
+ "hint",
+ "successToast"
+ ],
"additionalProperties": false
},
"edit": {
@@ -6348,7 +7071,11 @@
"type": "string"
}
},
- "required": ["header", "hint", "successToast"],
+ "required": [
+ "header",
+ "hint",
+ "successToast"
+ ],
"additionalProperties": false
},
"delete": {
@@ -6361,11 +7088,18 @@
"type": "string"
}
},
- "required": ["confirmation", "successToast"],
+ "required": [
+ "confirmation",
+ "successToast"
+ ],
"additionalProperties": false
}
},
- "required": ["create", "edit", "delete"],
+ "required": [
+ "create",
+ "edit",
+ "delete"
+ ],
"additionalProperties": false
},
"fields": {
@@ -6387,7 +7121,12 @@
"type": "string"
}
},
- "required": ["label", "hint", "true", "false"],
+ "required": [
+ "label",
+ "hint",
+ "true",
+ "false"
+ ],
"additionalProperties": false
},
"defaultTaxRate": {
@@ -6403,7 +7142,11 @@
"type": "string"
}
},
- "required": ["label", "tooltip", "action"],
+ "required": [
+ "label",
+ "tooltip",
+ "action"
+ ],
"additionalProperties": false
},
"taxRate": {
@@ -6462,7 +7205,11 @@
"type": "string"
}
},
- "required": ["in", "on", "and"],
+ "required": [
+ "in",
+ "on",
+ "and"
+ ],
"additionalProperties": false
},
"placeholders": {
@@ -6528,7 +7275,9 @@
"type": "string"
}
},
- "required": ["header"],
+ "required": [
+ "header"
+ ],
"additionalProperties": false
},
"values_one": {
@@ -6700,7 +7449,10 @@
"type": "string"
}
},
- "required": ["sublevel", "notPartOfCountry"],
+ "required": [
+ "sublevel",
+ "notPartOfCountry"
+ ],
"additionalProperties": false
},
"alert": {
@@ -6716,11 +7468,20 @@
"type": "string"
}
},
- "required": ["header", "description", "action"],
+ "required": [
+ "header",
+ "description",
+ "action"
+ ],
"additionalProperties": false
}
},
- "required": ["labels", "placeholders", "tooltips", "alert"],
+ "required": [
+ "labels",
+ "placeholders",
+ "tooltips",
+ "alert"
+ ],
"additionalProperties": false
},
"noDefaultRate": {
@@ -6733,7 +7494,10 @@
"type": "string"
}
},
- "required": ["label", "tooltip"],
+ "required": [
+ "label",
+ "tooltip"
+ ],
"additionalProperties": false
}
},
@@ -6786,7 +7550,9 @@
"type": "string"
}
},
- "required": ["details"],
+ "required": [
+ "details"
+ ],
"additionalProperties": false
},
"tabs": {
@@ -6802,7 +7568,11 @@
"type": "string"
}
},
- "required": ["template", "details", "campaign"],
+ "required": [
+ "template",
+ "details",
+ "campaign"
+ ],
"additionalProperties": false
},
"fields": {
@@ -6839,7 +7609,9 @@
"type": "string"
}
},
- "required": ["tooltip"],
+ "required": [
+ "tooltip"
+ ],
"additionalProperties": false
},
"conditions": {
@@ -6855,7 +7627,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"target-rules": {
@@ -6868,7 +7643,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"buy-rules": {
@@ -6881,11 +7659,18 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
- "required": ["rules", "target-rules", "buy-rules"],
+ "required": [
+ "rules",
+ "target-rules",
+ "buy-rules"
+ ],
"additionalProperties": false
}
},
@@ -6910,7 +7695,9 @@
"type": "string"
}
},
- "required": ["campaignType"],
+ "required": [
+ "campaignType"
+ ],
"additionalProperties": false
},
"errors": {
@@ -6923,7 +7710,10 @@
"type": "string"
}
},
- "required": ["requiredField", "promotionTabError"],
+ "required": [
+ "requiredField",
+ "promotionTabError"
+ ],
"additionalProperties": false
},
"toasts": {
@@ -6933,7 +7723,9 @@
"type": "string"
}
},
- "required": ["promotionCreateSuccess"],
+ "required": [
+ "promotionCreateSuccess"
+ ],
"additionalProperties": false
},
"create": {
@@ -6955,7 +7747,9 @@
"type": "string"
}
},
- "required": ["title"],
+ "required": [
+ "title"
+ ],
"additionalProperties": false
},
"target-rules": {
@@ -6965,7 +7759,9 @@
"type": "string"
}
},
- "required": ["title"],
+ "required": [
+ "title"
+ ],
"additionalProperties": false
},
"buy-rules": {
@@ -6975,11 +7771,18 @@
"type": "string"
}
},
- "required": ["title"],
+ "required": [
+ "title"
+ ],
"additionalProperties": false
}
},
- "required": ["title", "rules", "target-rules", "buy-rules"],
+ "required": [
+ "title",
+ "rules",
+ "target-rules",
+ "buy-rules"
+ ],
"additionalProperties": false
},
"campaign": {
@@ -6998,7 +7801,10 @@
"type": "string"
}
},
- "required": ["header", "successToast"],
+ "required": [
+ "header",
+ "successToast"
+ ],
"additionalProperties": false
},
"actions": {
@@ -7008,11 +7814,17 @@
"type": "string"
}
},
- "required": ["goToCampaign"],
+ "required": [
+ "goToCampaign"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "edit", "actions"],
+ "required": [
+ "header",
+ "edit",
+ "actions"
+ ],
"additionalProperties": false
},
"campaign_currency": {
@@ -7022,7 +7834,9 @@
"type": "string"
}
},
- "required": ["tooltip"],
+ "required": [
+ "tooltip"
+ ],
"additionalProperties": false
},
"form": {
@@ -7059,11 +7873,18 @@
"type": "string"
}
},
- "required": ["title", "desc"],
+ "required": [
+ "title",
+ "desc"
+ ],
"additionalProperties": false
}
},
- "required": ["title", "description", "placeholder"],
+ "required": [
+ "title",
+ "description",
+ "placeholder"
+ ],
"additionalProperties": false
},
"new": {
@@ -7076,7 +7897,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"none": {
@@ -7089,11 +7913,18 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
- "required": ["existing", "new", "none"],
+ "required": [
+ "existing",
+ "new",
+ "none"
+ ],
"additionalProperties": false
},
"status": {
@@ -7103,7 +7934,9 @@
"type": "string"
}
},
- "required": ["title"],
+ "required": [
+ "title"
+ ],
"additionalProperties": false
},
"method": {
@@ -7122,7 +7955,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"automatic": {
@@ -7135,11 +7971,18 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
- "required": ["label", "code", "automatic"],
+ "required": [
+ "label",
+ "code",
+ "automatic"
+ ],
"additionalProperties": false
},
"max_quantity": {
@@ -7152,7 +7995,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"type": {
@@ -7168,7 +8014,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"buyget": {
@@ -7181,11 +8030,17 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
- "required": ["standard", "buyget"],
+ "required": [
+ "standard",
+ "buyget"
+ ],
"additionalProperties": false
},
"allocation": {
@@ -7201,7 +8056,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"across": {
@@ -7214,11 +8072,17 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
- "required": ["each", "across"],
+ "required": [
+ "each",
+ "across"
+ ],
"additionalProperties": false
},
"code": {
@@ -7231,7 +8095,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"value": {
@@ -7241,7 +8108,9 @@
"type": "string"
}
},
- "required": ["title"],
+ "required": [
+ "title"
+ ],
"additionalProperties": false
},
"value_type": {
@@ -7257,7 +8126,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"percentage": {
@@ -7270,11 +8142,17 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
- "required": ["fixed", "percentage"],
+ "required": [
+ "fixed",
+ "percentage"
+ ],
"additionalProperties": false
}
},
@@ -7316,11 +8194,16 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
- "required": ["add", "list"],
+ "required": [
+ "add",
+ "list"
+ ],
"additionalProperties": false
}
},
@@ -7366,7 +8249,11 @@
"type": "string"
}
},
- "required": ["active", "expired", "scheduled"],
+ "required": [
+ "active",
+ "expired",
+ "scheduled"
+ ],
"additionalProperties": false
},
"delete": {
@@ -7382,7 +8269,11 @@
"type": "string"
}
},
- "required": ["title", "description", "successToast"],
+ "required": [
+ "title",
+ "description",
+ "successToast"
+ ],
"additionalProperties": false
},
"edit": {
@@ -7398,7 +8289,11 @@
"type": "string"
}
},
- "required": ["header", "description", "successToast"],
+ "required": [
+ "header",
+ "description",
+ "successToast"
+ ],
"additionalProperties": false
},
"configuration": {
@@ -7420,11 +8315,18 @@
"type": "string"
}
},
- "required": ["header", "description", "successToast"],
+ "required": [
+ "header",
+ "description",
+ "successToast"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "edit"],
+ "required": [
+ "header",
+ "edit"
+ ],
"additionalProperties": false
},
"create": {
@@ -7486,7 +8388,9 @@
"type": "string"
}
},
- "required": ["hint"],
+ "required": [
+ "hint"
+ ],
"additionalProperties": false
}
},
@@ -7515,7 +8419,10 @@
"type": "string"
}
},
- "required": ["hint", "header"],
+ "required": [
+ "hint",
+ "header"
+ ],
"additionalProperties": false
},
"details": {
@@ -7537,7 +8444,12 @@
"type": "string"
}
},
- "required": ["type", "currency", "limit", "used"],
+ "required": [
+ "type",
+ "currency",
+ "limit",
+ "used"
+ ],
"additionalProperties": false
},
"type": {
@@ -7553,7 +8465,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"usage": {
@@ -7566,11 +8481,17 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
}
},
- "required": ["spend", "usage"],
+ "required": [
+ "spend",
+ "usage"
+ ],
"additionalProperties": false
},
"edit": {
@@ -7580,11 +8501,19 @@
"type": "string"
}
},
- "required": ["header"],
+ "required": [
+ "header"
+ ],
"additionalProperties": false
}
},
- "required": ["create", "details", "fields", "type", "edit"],
+ "required": [
+ "create",
+ "details",
+ "fields",
+ "type",
+ "edit"
+ ],
"additionalProperties": false
},
"promotions": {
@@ -7600,7 +8529,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"alreadyAdded": {
@@ -7619,7 +8551,9 @@
"type": "string"
}
},
- "required": ["success"],
+ "required": [
+ "success"
+ ],
"additionalProperties": false
},
"add": {
@@ -7632,11 +8566,15 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
- "required": ["list"],
+ "required": [
+ "list"
+ ],
"additionalProperties": false
},
"list": {
@@ -7646,7 +8584,9 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
@@ -7703,7 +8643,10 @@
"type": "string"
}
},
- "required": ["confirmation", "successToast"],
+ "required": [
+ "confirmation",
+ "successToast"
+ ],
"additionalProperties": false
},
"create": {
@@ -7728,7 +8671,11 @@
"type": "string"
}
},
- "required": ["details", "products", "prices"],
+ "required": [
+ "details",
+ "products",
+ "prices"
+ ],
"additionalProperties": false
},
"successToast": {
@@ -7744,11 +8691,15 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
- "required": ["list"],
+ "required": [
+ "list"
+ ],
"additionalProperties": false
}
},
@@ -7771,7 +8722,10 @@
"type": "string"
}
},
- "required": ["header", "successToast"],
+ "required": [
+ "header",
+ "successToast"
+ ],
"additionalProperties": false
},
"configuration": {
@@ -7793,11 +8747,18 @@
"type": "string"
}
},
- "required": ["header", "description", "successToast"],
+ "required": [
+ "header",
+ "description",
+ "successToast"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "edit"],
+ "required": [
+ "header",
+ "edit"
+ ],
"additionalProperties": false
},
"products": {
@@ -7816,7 +8777,10 @@
"type": "string"
}
},
- "required": ["addProducts", "editPrices"],
+ "required": [
+ "addProducts",
+ "editPrices"
+ ],
"additionalProperties": false
},
"delete": {
@@ -7850,7 +8814,9 @@
"type": "string"
}
},
- "required": ["successToast"],
+ "required": [
+ "successToast"
+ ],
"additionalProperties": false
},
"edit": {
@@ -7860,11 +8826,19 @@
"type": "string"
}
},
- "required": ["successToast"],
+ "required": [
+ "successToast"
+ ],
"additionalProperties": false
}
},
- "required": ["header", "actions", "delete", "add", "edit"],
+ "required": [
+ "header",
+ "actions",
+ "delete",
+ "add",
+ "edit"
+ ],
"additionalProperties": false
},
"fields": {
@@ -7880,7 +8854,10 @@
"type": "string"
}
},
- "required": ["label", "header"],
+ "required": [
+ "label",
+ "header"
+ ],
"additionalProperties": false
},
"status": {
@@ -7905,11 +8882,19 @@
"type": "string"
}
},
- "required": ["active", "draft", "expired", "scheduled"],
+ "required": [
+ "active",
+ "draft",
+ "expired",
+ "scheduled"
+ ],
"additionalProperties": false
}
},
- "required": ["label", "options"],
+ "required": [
+ "label",
+ "options"
+ ],
"additionalProperties": false
},
"type": {
@@ -7934,7 +8919,10 @@
"type": "string"
}
},
- "required": ["label", "description"],
+ "required": [
+ "label",
+ "description"
+ ],
"additionalProperties": false
},
"override": {
@@ -7947,15 +8935,25 @@
"type": "string"
}
},
- "required": ["label", "description"],
+ "required": [
+ "label",
+ "description"
+ ],
"additionalProperties": false
}
},
- "required": ["sale", "override"],
+ "required": [
+ "sale",
+ "override"
+ ],
"additionalProperties": false
}
},
- "required": ["label", "hint", "options"],
+ "required": [
+ "label",
+ "hint",
+ "options"
+ ],
"additionalProperties": false
},
"startsAt": {
@@ -7968,7 +8966,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
},
"endsAt": {
@@ -7981,7 +8982,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
},
"customerAvailability": {
@@ -8055,7 +9059,10 @@
"type": "string"
}
},
- "required": ["languageLabel", "usageInsightsLabel"],
+ "required": [
+ "languageLabel",
+ "usageInsightsLabel"
+ ],
"additionalProperties": false
},
"edit": {
@@ -8089,7 +9096,9 @@
"type": "string"
}
},
- "required": ["edit"],
+ "required": [
+ "edit"
+ ],
"additionalProperties": false
}
},
@@ -8154,7 +9163,11 @@
"type": "string"
}
},
- "required": ["accepted", "pending", "expired"],
+ "required": [
+ "accepted",
+ "pending",
+ "expired"
+ ],
"additionalProperties": false
},
"roles": {
@@ -8170,7 +9183,11 @@
"type": "string"
}
},
- "required": ["admin", "developer", "member"],
+ "required": [
+ "admin",
+ "developer",
+ "member"
+ ],
"additionalProperties": false
},
"deleteUserWarning": {
@@ -8255,7 +9272,9 @@
"type": "string"
}
},
- "required": ["header"],
+ "required": [
+ "header"
+ ],
"additionalProperties": false
},
"toast": {
@@ -8377,7 +9396,9 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
},
"toast": {
@@ -8396,7 +9417,12 @@
"type": "string"
}
},
- "required": ["delete", "edit", "create", "countries"],
+ "required": [
+ "delete",
+ "edit",
+ "create",
+ "countries"
+ ],
"additionalProperties": false
},
"shippingOption": {
@@ -8430,7 +9456,12 @@
"type": "string"
}
},
- "required": ["outbound", "outboundHint", "return", "returnHint"],
+ "required": [
+ "outbound",
+ "outboundHint",
+ "return",
+ "returnHint"
+ ],
"additionalProperties": false
},
"priceType": {
@@ -8446,7 +9477,11 @@
"type": "string"
}
},
- "required": ["label", "flatRate", "calculated"],
+ "required": [
+ "label",
+ "flatRate",
+ "calculated"
+ ],
"additionalProperties": false
},
"availability": {
@@ -8459,7 +9494,10 @@
"type": "string"
}
},
- "required": ["adminOnly", "adminOnlyHint"],
+ "required": [
+ "adminOnly",
+ "adminOnlyHint"
+ ],
"additionalProperties": false
},
"taxInclusiveHint": {
@@ -8475,7 +9513,10 @@
"type": "string"
}
},
- "required": ["label", "hint"],
+ "required": [
+ "label",
+ "hint"
+ ],
"additionalProperties": false
}
},
@@ -8537,7 +9578,9 @@
"type": "string"
}
},
- "required": ["taxCountriesHint"],
+ "required": [
+ "taxCountriesHint"
+ ],
"additionalProperties": false
},
"settings": {
@@ -8591,7 +9634,9 @@
"type": "string"
}
},
- "required": ["sectionTitle"],
+ "required": [
+ "sectionTitle"
+ ],
"additionalProperties": false
},
"taxRate": {
@@ -8741,7 +9786,11 @@
"type": "string"
}
},
- "required": ["create", "update", "removeChannel"],
+ "required": [
+ "create",
+ "update",
+ "removeChannel"
+ ],
"additionalProperties": false
}
},
@@ -8771,7 +9820,11 @@
"type": "string"
}
},
- "required": ["domain", "subtitle", "deleteWarning"],
+ "required": [
+ "domain",
+ "subtitle",
+ "deleteWarning"
+ ],
"additionalProperties": false
},
"salesChannels": {
@@ -8823,7 +9876,11 @@
"type": "string"
}
},
- "required": ["create", "update", "delete"],
+ "required": [
+ "create",
+ "update",
+ "delete"
+ ],
"additionalProperties": false
},
"tooltip": {
@@ -8833,7 +9890,9 @@
"type": "string"
}
},
- "required": ["cannotDeleteDefault"],
+ "required": [
+ "cannotDeleteDefault"
+ ],
"additionalProperties": false
},
"products": {
@@ -8846,7 +9905,9 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
},
"add": {
@@ -8859,15 +9920,22 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
- "required": ["list"],
+ "required": [
+ "list"
+ ],
"additionalProperties": false
}
},
- "required": ["list", "add"],
+ "required": [
+ "list",
+ "add"
+ ],
"additionalProperties": false
}
},
@@ -8902,7 +9970,10 @@
"type": "string"
}
},
- "required": ["publishable", "secret"],
+ "required": [
+ "publishable",
+ "secret"
+ ],
"additionalProperties": false
},
"subtitle": {
@@ -8915,7 +9986,10 @@
"type": "string"
}
},
- "required": ["publishable", "secret"],
+ "required": [
+ "publishable",
+ "secret"
+ ],
"additionalProperties": false
},
"status": {
@@ -8928,7 +10002,10 @@
"type": "string"
}
},
- "required": ["active", "revoked"],
+ "required": [
+ "active",
+ "revoked"
+ ],
"additionalProperties": false
},
"type": {
@@ -8941,7 +10018,10 @@
"type": "string"
}
},
- "required": ["publishable", "secret"],
+ "required": [
+ "publishable",
+ "secret"
+ ],
"additionalProperties": false
},
"create": {
@@ -9001,7 +10081,11 @@
"type": "string"
}
},
- "required": ["header", "description", "successToast"],
+ "required": [
+ "header",
+ "description",
+ "successToast"
+ ],
"additionalProperties": false
},
"salesChannels": {
@@ -9029,7 +10113,9 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
@@ -9053,7 +10139,10 @@
"type": "string"
}
},
- "required": ["warning", "successToast"],
+ "required": [
+ "warning",
+ "successToast"
+ ],
"additionalProperties": false
},
"revoke": {
@@ -9066,7 +10155,10 @@
"type": "string"
}
},
- "required": ["warning", "successToast"],
+ "required": [
+ "warning",
+ "successToast"
+ ],
"additionalProperties": false
},
"addSalesChannels": {
@@ -9079,11 +10171,15 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
}
},
- "required": ["list"],
+ "required": [
+ "list"
+ ],
"additionalProperties": false
},
"removeSalesChannel": {
@@ -9131,7 +10227,11 @@
"type": "string"
}
},
- "required": ["revoke", "copy", "copySuccessToast"],
+ "required": [
+ "revoke",
+ "copy",
+ "copySuccessToast"
+ ],
"additionalProperties": false
},
"table": {
@@ -9144,7 +10244,10 @@
"type": "string"
}
},
- "required": ["lastUsedAtHeader", "createdAtHeader"],
+ "required": [
+ "lastUsedAtHeader",
+ "createdAtHeader"
+ ],
"additionalProperties": false
},
"fields": {
@@ -9221,7 +10324,12 @@
"type": "string"
}
},
- "required": ["header", "subtitle", "hint", "successToast"],
+ "required": [
+ "header",
+ "subtitle",
+ "hint",
+ "successToast"
+ ],
"additionalProperties": false
},
"edit": {
@@ -9237,7 +10345,11 @@
"type": "string"
}
},
- "required": ["header", "subtitle", "successToast"],
+ "required": [
+ "header",
+ "subtitle",
+ "successToast"
+ ],
"additionalProperties": false
},
"delete": {
@@ -9250,7 +10362,10 @@
"type": "string"
}
},
- "required": ["confirmation", "successToast"],
+ "required": [
+ "confirmation",
+ "successToast"
+ ],
"additionalProperties": false
},
"fields": {
@@ -9269,7 +10384,11 @@
"type": "string"
}
},
- "required": ["label", "placeholder", "tooltip"],
+ "required": [
+ "label",
+ "placeholder",
+ "tooltip"
+ ],
"additionalProperties": false
},
"label": {
@@ -9282,7 +10401,10 @@
"type": "string"
}
},
- "required": ["label", "placeholder"],
+ "required": [
+ "label",
+ "placeholder"
+ ],
"additionalProperties": false
},
"description": {
@@ -9295,11 +10417,18 @@
"type": "string"
}
},
- "required": ["label", "placeholder"],
+ "required": [
+ "label",
+ "placeholder"
+ ],
"additionalProperties": false
}
},
- "required": ["value", "label", "description"],
+ "required": [
+ "value",
+ "label",
+ "description"
+ ],
"additionalProperties": false
}
},
@@ -9328,7 +10457,11 @@
"type": "string"
}
},
- "required": ["forgotPassword", "title", "hint"],
+ "required": [
+ "forgotPassword",
+ "title",
+ "hint"
+ ],
"additionalProperties": false
},
"invite": {
@@ -9380,7 +10513,9 @@
"type": "string"
}
},
- "required": ["accepted"],
+ "required": [
+ "accepted"
+ ],
"additionalProperties": false
}
},
@@ -9525,7 +10660,9 @@
"type": "string"
}
},
- "required": ["noRecordsMessage"],
+ "required": [
+ "noRecordsMessage"
+ ],
"additionalProperties": false
},
"history": {
@@ -9622,11 +10759,15 @@
"type": "string"
}
},
- "required": ["waitingToCompensate"],
+ "required": [
+ "waitingToCompensate"
+ ],
"additionalProperties": false
}
},
- "required": ["state"],
+ "required": [
+ "state"
+ ],
"additionalProperties": false
},
"step": {
@@ -9648,11 +10789,18 @@
"type": "string"
}
},
- "required": ["skipped", "skippedFailure", "dormant", "timeout"],
+ "required": [
+ "skipped",
+ "skippedFailure",
+ "dormant",
+ "timeout"
+ ],
"additionalProperties": false
}
},
- "required": ["state"],
+ "required": [
+ "state"
+ ],
"additionalProperties": false
}
},
@@ -9694,7 +10842,11 @@
"type": "string"
}
},
- "required": ["header", "hint", "successToast"],
+ "required": [
+ "header",
+ "hint",
+ "successToast"
+ ],
"additionalProperties": false
},
"edit": {
@@ -9707,7 +10859,10 @@
"type": "string"
}
},
- "required": ["header", "successToast"],
+ "required": [
+ "header",
+ "successToast"
+ ],
"additionalProperties": false
},
"delete": {
@@ -9720,7 +10875,10 @@
"type": "string"
}
},
- "required": ["confirmation", "successToast"],
+ "required": [
+ "confirmation",
+ "successToast"
+ ],
"additionalProperties": false
},
"fields": {
@@ -9730,11 +10888,20 @@
"type": "string"
}
},
- "required": ["value"],
+ "required": [
+ "value"
+ ],
"additionalProperties": false
}
},
- "required": ["domain", "subtitle", "create", "edit", "delete", "fields"],
+ "required": [
+ "domain",
+ "subtitle",
+ "create",
+ "edit",
+ "delete",
+ "fields"
+ ],
"additionalProperties": false
},
"productTags": {
@@ -9756,7 +10923,11 @@
"type": "string"
}
},
- "required": ["header", "subtitle", "successToast"],
+ "required": [
+ "header",
+ "subtitle",
+ "successToast"
+ ],
"additionalProperties": false
},
"edit": {
@@ -9772,7 +10943,11 @@
"type": "string"
}
},
- "required": ["header", "subtitle", "successToast"],
+ "required": [
+ "header",
+ "subtitle",
+ "successToast"
+ ],
"additionalProperties": false
},
"delete": {
@@ -9785,7 +10960,10 @@
"type": "string"
}
},
- "required": ["confirmation", "successToast"],
+ "required": [
+ "confirmation",
+ "successToast"
+ ],
"additionalProperties": false
},
"fields": {
@@ -9795,11 +10973,19 @@
"type": "string"
}
},
- "required": ["value"],
+ "required": [
+ "value"
+ ],
"additionalProperties": false
}
},
- "required": ["domain", "create", "edit", "delete", "fields"],
+ "required": [
+ "domain",
+ "create",
+ "edit",
+ "delete",
+ "fields"
+ ],
"additionalProperties": false
},
"notifications": {
@@ -9818,7 +11004,10 @@
"type": "string"
}
},
- "required": ["title", "description"],
+ "required": [
+ "title",
+ "description"
+ ],
"additionalProperties": false
},
"accessibility": {
@@ -9828,11 +11017,17 @@
"type": "string"
}
},
- "required": ["description"],
+ "required": [
+ "description"
+ ],
"additionalProperties": false
}
},
- "required": ["domain", "emptyState", "accessibility"],
+ "required": [
+ "domain",
+ "emptyState",
+ "accessibility"
+ ],
"additionalProperties": false
},
"errors": {
@@ -9845,7 +11040,10 @@
"type": "string"
}
},
- "required": ["serverError", "invalidCredentials"],
+ "required": [
+ "serverError",
+ "invalidCredentials"
+ ],
"additionalProperties": false
},
"statuses": {
@@ -9867,7 +11065,13 @@
"type": "string"
}
},
- "required": ["scheduled", "expired", "active", "enabled", "disabled"],
+ "required": [
+ "scheduled",
+ "expired",
+ "active",
+ "enabled",
+ "disabled"
+ ],
"additionalProperties": false
},
"labels": {
@@ -10662,4 +11866,4 @@
"dateTime"
],
"additionalProperties": false
-}
+}
\ No newline at end of file
diff --git a/packages/admin/dashboard/src/i18n/translations/en.json b/packages/admin/dashboard/src/i18n/translations/en.json
index d1889efe557c7..b77d2de08eed6 100644
--- a/packages/admin/dashboard/src/i18n/translations/en.json
+++ b/packages/admin/dashboard/src/i18n/translations/en.json
@@ -1523,7 +1523,8 @@
"hint": "Whether customers can use this option during checkout."
},
"provider": "Fulfillment provider",
- "profile": "Shipping profile"
+ "profile": "Shipping profile",
+ "fulfillmentOption": "Fulfillment option"
}
},
"serviceZones": {
diff --git a/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/create-shipping-option-details-form.tsx b/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/create-shipping-option-details-form.tsx
index dd95fb5f1c6f4..6fba5c25ef619 100644
--- a/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/create-shipping-option-details-form.tsx
+++ b/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/create-shipping-option-details-form.tsx
@@ -1,8 +1,9 @@
-import { Heading, Input, RadioGroup, Text } from "@medusajs/ui"
+import { Heading, Input, RadioGroup, Select, Text } from "@medusajs/ui"
import { UseFormReturn } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { HttpTypes } from "@medusajs/types"
+
import { Divider } from "../../../../../components/common/divider"
import { Form } from "../../../../../components/common/form"
import { SwitchBox } from "../../../../../components/common/switch-box"
@@ -18,6 +19,8 @@ type CreateShippingOptionDetailsFormProps = {
isReturn?: boolean
zone: HttpTypes.AdminServiceZone
locationId: string
+ fulfillmentProviderOptions: HttpTypes.AdminFulfillmentProviderOption[]
+ selectedProviderId?: string
}
export const CreateShippingOptionDetailsForm = ({
@@ -25,6 +28,8 @@ export const CreateShippingOptionDetailsForm = ({
isReturn = false,
zone,
locationId,
+ fulfillmentProviderOptions,
+ selectedProviderId,
}: CreateShippingOptionDetailsFormProps) => {
const { t } = useTranslation()
@@ -134,9 +139,6 @@ export const CreateShippingOptionDetailsForm = ({
)
}}
/>
-
-
-
+
+
{
+ field.onChange(e)
+ form.setValue("fulfillment_option_id", "")
+ }}
options={fulfillmentProviders.options}
searchValue={fulfillmentProviders.searchValue}
onSearchValueChange={
@@ -190,6 +198,45 @@ export const CreateShippingOptionDetailsForm = ({
)
}}
/>
+
+ {
+ return (
+
+
+ {t(
+ "stockLocations.shippingOptions.fields.fulfillmentOption"
+ )}
+
+
+
+
+
+
+ )
+ }}
+ />
diff --git a/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/create-shipping-options-form.tsx b/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/create-shipping-options-form.tsx
index 1ed449e6c8533..838fae3740ead 100644
--- a/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/create-shipping-options-form.tsx
+++ b/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/create-shipping-options-form.tsx
@@ -1,7 +1,7 @@
import { zodResolver } from "@hookform/resolvers/zod"
import { HttpTypes } from "@medusajs/types"
import { Button, ProgressStatus, ProgressTabs, toast } from "@medusajs/ui"
-import { useForm } from "react-hook-form"
+import { useForm, useWatch } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { useState } from "react"
@@ -20,6 +20,7 @@ import {
CreateShippingOptionDetailsSchema,
CreateShippingOptionSchema,
} from "./schema"
+import { useFulfillmentProviderOptions } from "../../../../../hooks/api"
enum Tab {
DETAILS = "details",
@@ -50,6 +51,7 @@ export function CreateShippingOptionsForm({
enabled_in_store: true,
shipping_profile_id: "",
provider_id: "",
+ fulfillment_option_id: "",
region_prices: {},
currency_prices: {},
conditional_region_prices: {},
@@ -58,6 +60,16 @@ export function CreateShippingOptionsForm({
resolver: zodResolver(CreateShippingOptionSchema),
})
+ const selectedProviderId = useWatch({
+ control: form.control,
+ name: "provider_id",
+ })
+
+ const { fulfillment_options: fulfillmentProviderOptions } =
+ useFulfillmentProviderOptions(selectedProviderId, {
+ enabled: !!selectedProviderId,
+ })
+
const isCalculatedPriceType =
form.watch("price_type") === ShippingOptionPriceType.Calculated
@@ -123,6 +135,10 @@ export function CreateShippingOptionsForm({
...conditionalRegionPrices,
]
+ const fulfillmentOptionData = fulfillmentProviderOptions?.find(
+ (fo) => fo.id === data.fulfillment_option_id
+ )!
+
await mutateAsync(
{
name: data.name,
@@ -131,6 +147,7 @@ export function CreateShippingOptionsForm({
shipping_profile_id: data.shipping_profile_id,
provider_id: data.provider_id,
prices: allPrices,
+ data: fulfillmentOptionData as unknown as Record,
rules: [
{
// eslint-disable-next-line
@@ -293,6 +310,8 @@ export function CreateShippingOptionsForm({
zone={zone}
isReturn={isReturn}
locationId={locationId}
+ fulfillmentProviderOptions={fulfillmentProviderOptions || []}
+ selectedProviderId={selectedProviderId}
/>
diff --git a/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/schema.ts b/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/schema.ts
index 442e2920dc1ef..34f188a3cd796 100644
--- a/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/schema.ts
+++ b/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-create/components/create-shipping-options-form/schema.ts
@@ -12,6 +12,7 @@ export const CreateShippingOptionDetailsSchema = z.object({
enabled_in_store: z.boolean(),
shipping_profile_id: z.string().min(1),
provider_id: z.string().min(1),
+ fulfillment_option_id: z.string().min(1),
})
export const ShippingOptionConditionalPriceSchema = z.object({
diff --git a/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-edit/components/edit-region-form/edit-shipping-option-form.tsx b/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-edit/components/edit-region-form/edit-shipping-option-form.tsx
index 3d31e7efac25d..3df1f5be5564a 100644
--- a/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-edit/components/edit-region-form/edit-shipping-option-form.tsx
+++ b/packages/admin/dashboard/src/routes/locations/location-service-zone-shipping-option-edit/components/edit-region-form/edit-shipping-option-form.tsx
@@ -2,6 +2,7 @@ import { HttpTypes } from "@medusajs/types"
import { Button, Input, RadioGroup, toast } from "@medusajs/ui"
import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
+import { zodResolver } from "@hookform/resolvers/zod"
import * as zod from "zod"
import { Divider } from "../../../../../components/common/divider"
@@ -14,7 +15,6 @@ import { useUpdateShippingOptions } from "../../../../../hooks/api/shipping-opti
import { useComboboxData } from "../../../../../hooks/use-combobox-data"
import { sdk } from "../../../../../lib/client"
import { pick } from "../../../../../lib/common"
-import { formatProvider } from "../../../../../lib/format-provider"
import { isOptionEnabledInStore } from "../../../../../lib/shipping-options"
import { ShippingOptionPriceType } from "../../../common/constants"
@@ -28,7 +28,6 @@ const EditShippingOptionSchema = zod.object({
price_type: zod.nativeEnum(ShippingOptionPriceType),
enabled_in_store: zod.boolean().optional(),
shipping_profile_id: zod.string(),
- provider_id: zod.string(),
})
export const EditShippingOptionForm = ({
@@ -49,29 +48,14 @@ export const EditShippingOptionForm = ({
defaultValue: shippingOption.shipping_profile_id,
})
- const fulfillmentProviders = useComboboxData({
- queryFn: (params) =>
- sdk.admin.fulfillmentProvider.list({
- ...params,
- stock_location_id: locationId,
- }),
- queryKey: ["fulfillment_providers"],
- getOptions: (data) =>
- data.fulfillment_providers.map((provider) => ({
- label: formatProvider(provider.id),
- value: provider.id,
- })),
- defaultValue: shippingOption.provider_id,
- })
-
const form = useForm>({
defaultValues: {
name: shippingOption.name,
price_type: shippingOption.price_type as ShippingOptionPriceType,
enabled_in_store: isOptionEnabledInStore(shippingOption),
shipping_profile_id: shippingOption.shipping_profile_id,
- provider_id: shippingOption.provider_id,
},
+ resolver: zodResolver(EditShippingOptionSchema),
})
const { mutateAsync, isPending: isLoading } = useUpdateShippingOptions(
@@ -101,7 +85,6 @@ export const EditShippingOptionForm = ({
name: values.name,
price_type: values.price_type,
shipping_profile_id: values.shipping_profile_id,
- provider_id: values.provider_id,
rules,
},
{
@@ -209,35 +192,6 @@ export const EditShippingOptionForm = ({
)
}}
/>
- {
- return (
-
-
- {t("stockLocations.shippingOptions.fields.provider")}
-
-
-
-
-
-
- )
- }}
- />
diff --git a/packages/core/core-flows/src/cart/steps/validate-shipping-methods-data.ts b/packages/core/core-flows/src/cart/steps/validate-shipping-methods-data.ts
index eec94e9f8730e..ca78740559802 100644
--- a/packages/core/core-flows/src/cart/steps/validate-shipping-methods-data.ts
+++ b/packages/core/core-flows/src/cart/steps/validate-shipping-methods-data.ts
@@ -1,16 +1,18 @@
import { Modules, promiseAll } from "@medusajs/framework/utils"
-import { IFulfillmentModuleService } from "@medusajs/types"
+import {
+ CartDTO,
+ IFulfillmentModuleService,
+ StockLocationDTO,
+} from "@medusajs/types"
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
-export interface ValidateShippingMethodsDataInput {
- context: Record
- options_to_validate: {
- id: string
- provider_id: string
- option_data: Record
- method_data: Record
- }[]
-}
+export type ValidateShippingMethodsDataInput = {
+ id: string
+ provider_id: string
+ option_data: Record
+ method_data: Record
+ context: CartDTO & { from_location: StockLocationDTO; [k: string]: unknown }
+}[]
export const validateAndReturnShippingMethodsDataStepId =
"validate-and-return-shipping-methods-data"
@@ -20,9 +22,9 @@ export const validateAndReturnShippingMethodsDataStepId =
export const validateAndReturnShippingMethodsDataStep = createStep(
validateAndReturnShippingMethodsDataStepId,
async (data: ValidateShippingMethodsDataInput, { container }) => {
- const { options_to_validate = [] } = data
+ const optionsToValidate = data ?? []
- if (!options_to_validate.length) {
+ if (!optionsToValidate.length) {
return new StepResponse(void 0)
}
@@ -31,12 +33,12 @@ export const validateAndReturnShippingMethodsDataStep = createStep(
)
const validatedData = await promiseAll(
- options_to_validate.map(async (option) => {
+ optionsToValidate.map(async (option) => {
const validated = await fulfillmentModule.validateFulfillmentData(
option.provider_id,
option.option_data,
option.method_data,
- data.context
+ option.context
)
return {
diff --git a/packages/core/core-flows/src/cart/workflows/add-shipping-method-to-cart.ts b/packages/core/core-flows/src/cart/workflows/add-shipping-method-to-cart.ts
index f49da2c7fafc2..65329c7a6549e 100644
--- a/packages/core/core-flows/src/cart/workflows/add-shipping-method-to-cart.ts
+++ b/packages/core/core-flows/src/cart/workflows/add-shipping-method-to-cart.ts
@@ -68,8 +68,8 @@ export const addShippingMethodToCartWorkflow = createWorkflow(
validateCartShippingOptionsPriceStep({ shippingOptions })
const validateShippingMethodsDataInput = transform(
- { input, shippingOptions },
- ({ input, shippingOptions }) => {
+ { input, shippingOptions, cart },
+ ({ input, shippingOptions, cart }) => {
return input.options.map((inputOption) => {
const shippingOption = shippingOptions.find(
(so) => so.id === inputOption.id
@@ -80,15 +80,18 @@ export const addShippingMethodToCartWorkflow = createWorkflow(
provider_id: shippingOption?.provider_id,
option_data: shippingOption?.data ?? {},
method_data: inputOption.data ?? {},
+ context: {
+ ...cart,
+ from_location: shippingOption?.stock_location ?? {},
+ },
}
})
}
)
- const validatedMethodData = validateAndReturnShippingMethodsDataStep({
- options_to_validate: validateShippingMethodsDataInput,
- context: {}, // TODO: Add cart, when we have a better idea about what's appropriate to pass
- })
+ const validatedMethodData = validateAndReturnShippingMethodsDataStep(
+ validateShippingMethodsDataInput
+ )
const shippingMethodInput = transform(
{ input, shippingOptions, validatedMethodData },
diff --git a/packages/core/core-flows/src/cart/workflows/list-shipping-options-for-cart.ts b/packages/core/core-flows/src/cart/workflows/list-shipping-options-for-cart.ts
index f4a897dfb699d..ac41df245b479 100644
--- a/packages/core/core-flows/src/cart/workflows/list-shipping-options-for-cart.ts
+++ b/packages/core/core-flows/src/cart/workflows/list-shipping-options-for-cart.ts
@@ -1,4 +1,3 @@
-import { deepFlatMap } from "@medusajs/framework/utils"
import {
createWorkflow,
transform,
@@ -41,7 +40,12 @@ export const listShippingOptionsForCartWorkflow = createWorkflow(
const scFulfillmentSetQuery = useQueryGraphStep({
entity: "sales_channels",
filters: { id: cart.sales_channel_id },
- fields: ["stock_locations.fulfillment_sets.id"],
+ fields: [
+ "stock_locations.fulfillment_sets.id",
+ "stock_locations.id",
+ "stock_locations.name",
+ "stock_locations.address.*",
+ ],
}).config({ name: "sales_channels-fulfillment-query" })
const scFulfillmentSets = transform(
@@ -49,22 +53,23 @@ export const listShippingOptionsForCartWorkflow = createWorkflow(
({ scFulfillmentSetQuery }) => scFulfillmentSetQuery.data[0]
)
- const fulfillmentSetIds = transform(
- { options: scFulfillmentSets },
- (data) => {
+ const { fulfillmentSetIds, fulfillmentSetLocationMap } = transform(
+ { scFulfillmentSets },
+ ({ scFulfillmentSets }) => {
const fulfillmentSetIds = new Set()
+ const fulfillmentSetLocationMap = {}
- deepFlatMap(
- data.options,
- "stock_locations.fulfillment_sets",
- ({ fulfillment_sets: fulfillmentSet }) => {
- if (fulfillmentSet?.id) {
- fulfillmentSetIds.add(fulfillmentSet.id)
- }
- }
- )
+ scFulfillmentSets.stock_locations.forEach((stockLocation) => {
+ stockLocation.fulfillment_sets.forEach((fulfillmentSet) => {
+ fulfillmentSetLocationMap[fulfillmentSet.id] = stockLocation
+ fulfillmentSetIds.add(fulfillmentSet.id)
+ })
+ })
- return Array.from(fulfillmentSetIds)
+ return {
+ fulfillmentSetIds: Array.from(fulfillmentSetIds),
+ fulfillmentSetLocationMap,
+ }
}
)
@@ -103,6 +108,7 @@ export const listShippingOptionsForCartWorkflow = createWorkflow(
"shipping_profile_id",
"provider_id",
"data",
+ "service_zone.fulfillment_set_id",
"type.id",
"type.label",
@@ -124,15 +130,19 @@ export const listShippingOptionsForCartWorkflow = createWorkflow(
}).config({ name: "shipping-options-query" })
const shippingOptionsWithPrice = transform(
- { shippingOptions },
- ({ shippingOptions }) =>
+ { shippingOptions, fulfillmentSetLocationMap },
+ ({ shippingOptions, fulfillmentSetLocationMap }) =>
shippingOptions.map((shippingOption) => {
const price = shippingOption.calculated_price
+ const fulfillmentSetId =
+ shippingOption.service_zone.fulfillment_set_id
+ const stockLocation = fulfillmentSetLocationMap[fulfillmentSetId]
return {
...shippingOption,
amount: price?.calculated_amount,
is_tax_inclusive: !!price?.is_calculated_price_tax_inclusive,
+ stock_location: stockLocation,
}
})
)
diff --git a/packages/core/js-sdk/src/admin/fulfillment-provider.ts b/packages/core/js-sdk/src/admin/fulfillment-provider.ts
index c18ff9214b83d..dce206e026b9e 100644
--- a/packages/core/js-sdk/src/admin/fulfillment-provider.ts
+++ b/packages/core/js-sdk/src/admin/fulfillment-provider.ts
@@ -18,25 +18,25 @@ export class FulfillmentProvider {
* This method retrieves a paginated list of fulfillment providers. It sends a request to the
* [List Fulfillment Providers](https://docs.medusajs.com/api/admin#fulfillment-providers_getfulfillmentproviders)
* API route.
- *
+ *
* @param query - Filters and pagination configurations.
* @param headers - Headers to pass in the request.
* @returns The paginated list of providers.
- *
+ *
* @example
* To retrieve the list of fulfillment providers:
- *
+ *
* ```ts
* sdk.admin.fulfillmentProvider.list()
* .then(({ fulfillment_providers, count, limit, offset }) => {
* console.log(fulfillment_providers)
* })
* ```
- *
+ *
* To configure the pagination, pass the `limit` and `offset` query parameters.
- *
+ *
* For example, to retrieve only 10 items and skip 10 items:
- *
+ *
* ```ts
* sdk.admin.fulfillmentProvider.list({
* limit: 10,
@@ -46,10 +46,10 @@ export class FulfillmentProvider {
* console.log(fulfillment_providers)
* })
* ```
- *
+ *
* Using the `fields` query parameter, you can specify the fields and relations to retrieve
* in each fulfillment provider:
- *
+ *
* ```ts
* sdk.admin.fulfillmentProvider.list({
* fields: "id"
@@ -58,7 +58,7 @@ export class FulfillmentProvider {
* console.log(fulfillment_providers)
* })
* ```
- *
+ *
* Learn more about the `fields` property in the [API reference](https://docs.medusajs.com/api/store#select-fields-and-relations).
*/
async list(
@@ -74,4 +74,23 @@ export class FulfillmentProvider {
}
)
}
+
+ /**
+ * This method retrieves a list of fulfillment options for a given fulfillment provider. It sends a request to the
+ * [List Fulfillment Options](https://docs.medusajs.com/api/admin#fulfillment-providers_getfulfillmentprovideroptions)
+ * API route.
+ *
+ * @param id - The ID of the fulfillment provider.
+ * @param headers - Headers to pass in the request.
+ * @returns The list of fulfillment options.
+ */
+ async listFulfillmentOptions(id: string, headers?: ClientHeaders) {
+ return await this.client.fetch(
+ `/admin/fulfillment-providers/${id}/options`,
+ {
+ method: "GET",
+ headers,
+ }
+ )
+ }
}
diff --git a/packages/core/js-sdk/src/store/index.ts b/packages/core/js-sdk/src/store/index.ts
index d475427e905b2..c08786f11de57 100644
--- a/packages/core/js-sdk/src/store/index.ts
+++ b/packages/core/js-sdk/src/store/index.ts
@@ -834,6 +834,23 @@ export class Store {
}
)
},
+
+ calculate: async (
+ id: string,
+ body: HttpTypes.StoreCalculateShippingOptionPrice,
+ query?: HttpTypes.SelectParams,
+ headers?: ClientHeaders
+ ) => {
+ return await this.client.fetch(
+ `/store/shipping-options/${id}/calculate`,
+ {
+ method: "POST",
+ headers,
+ body,
+ query,
+ }
+ )
+ },
}
public payment = {
diff --git a/packages/core/types/src/http/fulfillment-provider/admin/entities.ts b/packages/core/types/src/http/fulfillment-provider/admin/entities.ts
index 1f56c491fcd63..fa0f14769e04c 100644
--- a/packages/core/types/src/http/fulfillment-provider/admin/entities.ts
+++ b/packages/core/types/src/http/fulfillment-provider/admin/entities.ts
@@ -1,3 +1,9 @@
-import { BaseFulfillmentProvider } from "../common"
+import {
+ BaseFulfillmentProvider,
+ BaseFulfillmentProviderOption,
+} from "../common"
export interface AdminFulfillmentProvider extends BaseFulfillmentProvider {}
+
+export interface AdminFulfillmentProviderOption
+ extends BaseFulfillmentProviderOption {}
diff --git a/packages/core/types/src/http/fulfillment-provider/admin/responses.ts b/packages/core/types/src/http/fulfillment-provider/admin/responses.ts
index 6d88a194c304d..979700e0e053d 100644
--- a/packages/core/types/src/http/fulfillment-provider/admin/responses.ts
+++ b/packages/core/types/src/http/fulfillment-provider/admin/responses.ts
@@ -1,5 +1,8 @@
import { PaginatedResponse } from "../../common"
-import { AdminFulfillmentProvider } from "./entities"
+import {
+ AdminFulfillmentProvider,
+ AdminFulfillmentProviderOption,
+} from "./entities"
export interface AdminFulfillmentProviderListResponse
extends PaginatedResponse<{
@@ -8,3 +11,8 @@ export interface AdminFulfillmentProviderListResponse
*/
fulfillment_providers: AdminFulfillmentProvider[]
}> {}
+
+export interface AdminFulfillmentProviderOptionsListResponse
+ extends PaginatedResponse<{
+ fulfillment_options: AdminFulfillmentProviderOption[]
+ }> {}
diff --git a/packages/core/types/src/http/fulfillment-provider/common.ts b/packages/core/types/src/http/fulfillment-provider/common.ts
index a89e79175c6ce..b54102ecc3301 100644
--- a/packages/core/types/src/http/fulfillment-provider/common.ts
+++ b/packages/core/types/src/http/fulfillment-provider/common.ts
@@ -8,3 +8,14 @@ export interface BaseFulfillmentProvider {
*/
is_enabled: boolean
}
+
+export interface BaseFulfillmentProviderOption {
+ /**
+ * The fulfillment provider option's ID.
+ */
+ id: string
+ /**
+ * Whether the fulfillment provider option can be used for returns.
+ */
+ is_return: boolean
+}
diff --git a/packages/medusa/src/api/admin/fulfillment-providers/[id]/options/route.ts b/packages/medusa/src/api/admin/fulfillment-providers/[id]/options/route.ts
new file mode 100644
index 0000000000000..5b5b1ec946fca
--- /dev/null
+++ b/packages/medusa/src/api/admin/fulfillment-providers/[id]/options/route.ts
@@ -0,0 +1,27 @@
+import {
+ AdminFulfillmentProviderOption,
+ HttpTypes,
+} from "@medusajs/framework/types"
+import { Modules } from "@medusajs/framework/utils"
+import {
+ AuthenticatedMedusaRequest,
+ MedusaResponse,
+} from "@medusajs/framework/http"
+
+export const GET = async (
+ req: AuthenticatedMedusaRequest,
+ res: MedusaResponse
+) => {
+ const fulfillmentProviderService = req.scope.resolve(Modules.FULFILLMENT)
+
+ const fulfillmentOptions =
+ await fulfillmentProviderService.retrieveFulfillmentOptions(req.params.id)
+
+ res.json({
+ fulfillment_options:
+ fulfillmentOptions as unknown as AdminFulfillmentProviderOption[],
+ count: fulfillmentOptions.length,
+ limit: fulfillmentOptions.length,
+ offset: 0,
+ })
+}
diff --git a/packages/medusa/src/api/admin/fulfillment-providers/middlewares.ts b/packages/medusa/src/api/admin/fulfillment-providers/middlewares.ts
index 82b3a22d47db1..ea5875f280997 100644
--- a/packages/medusa/src/api/admin/fulfillment-providers/middlewares.ts
+++ b/packages/medusa/src/api/admin/fulfillment-providers/middlewares.ts
@@ -20,4 +20,9 @@ export const adminFulfillmentProvidersRoutesMiddlewares: MiddlewareRoute[] = [
}),
],
},
+ {
+ method: ["GET"],
+ matcher: "/admin/fulfillment-providers/:id/options",
+ middlewares: [],
+ },
]
diff --git a/packages/modules/fulfillment/src/services/fulfillment-module-service.ts b/packages/modules/fulfillment/src/services/fulfillment-module-service.ts
index 741db5405ea64..63e6513e0d134 100644
--- a/packages/modules/fulfillment/src/services/fulfillment-module-service.ts
+++ b/packages/modules/fulfillment/src/services/fulfillment-module-service.ts
@@ -5,6 +5,7 @@ import {
FilterableFulfillmentSetProps,
FindConfig,
FulfillmentDTO,
+ FulfillmentOption,
FulfillmentTypes,
IFulfillmentModuleService,
InternalModuleDeclaration,
@@ -1946,7 +1947,7 @@ export default class FulfillmentModuleService
async retrieveFulfillmentOptions(
providerId: string
- ): Promise[]> {
+ ): Promise {
return await this.fulfillmentProviderService_.getFulfillmentOptions(
providerId
)
diff --git a/packages/modules/fulfillment/src/services/fulfillment-provider.ts b/packages/modules/fulfillment/src/services/fulfillment-provider.ts
index ea205a95f75e1..f61a6625b473f 100644
--- a/packages/modules/fulfillment/src/services/fulfillment-provider.ts
+++ b/packages/modules/fulfillment/src/services/fulfillment-provider.ts
@@ -2,6 +2,7 @@ import {
CalculateShippingOptionPriceDTO,
Constructor,
DAL,
+ FulfillmentOption,
FulfillmentTypes,
IFulfillmentProvider,
Logger,
@@ -81,7 +82,7 @@ export default class FulfillmentProviderService extends ModulesSdkUtils.MedusaIn
async getFulfillmentOptions(
providerId: string
- ): Promise[]> {
+ ): Promise {
const provider = this.retrieveProviderRegistration(providerId)
return await provider.getFulfillmentOptions()
}
From c9b8db04c1b35f1cf129bb9ad74789fbc2881815 Mon Sep 17 00:00:00 2001
From: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
Date: Wed, 18 Dec 2024 12:53:57 +0100
Subject: [PATCH 3/5] feat: Custom line items (#10408)
* feat: Custom line items
* fix tests
* fix migration
* Allow custom items in update line item workflow
* throw if line item doesn't have a price
* minor things
* wip
* fix flows
* fix test
* add default
* add to type
---
.changeset/gorgeous-tools-enjoy.md | 9 +
.../http/__tests__/order/admin/order.spec.ts | 2 +-
.../cart/store/cart.workflows.spec.ts | 1138 ++++++++++++++---
.../__tests__/order/draft-order.spec.ts | 8 +-
.../cart/steps/validate-line-item-prices.ts | 36 +
.../src/cart/steps/validate-variant-prices.ts | 4 +
.../src/cart/utils/prepare-line-item-data.ts | 149 ++-
.../src/cart/workflows/add-to-cart.ts | 68 +-
.../src/cart/workflows/complete-cart.ts | 16 +-
.../src/cart/workflows/create-carts.ts | 76 +-
.../src/cart/workflows/refresh-cart-items.ts | 53 +-
.../src/cart/workflows/update-cart.ts | 45 +-
.../workflows/update-line-item-in-cart.ts | 63 +-
.../src/common/steps/use-remote-query.ts | 4 +-
.../utils/prepare-custom-line-item-data.ts | 68 -
.../src/order/workflows/add-line-items.ts | 86 +-
.../src/order/workflows/create-order.ts | 78 +-
packages/core/types/src/cart/common.ts | 5 +
packages/core/types/src/cart/mutations.ts | 5 +
packages/core/types/src/cart/workflows.ts | 2 +-
.../core/utils/src/common/deep-flat-map.ts | 2 +-
.../src/api/admin/draft-orders/validators.ts | 36 +-
.../services/cart-module/index.spec.ts | 2 +
.../src/migrations/.snapshot-medusa-cart.json | 10 +
.../src/migrations/Migration20241218091938.ts | 13 +
packages/modules/cart/src/models/line-item.ts | 3 +-
26 files changed, 1470 insertions(+), 511 deletions(-)
create mode 100644 .changeset/gorgeous-tools-enjoy.md
create mode 100644 packages/core/core-flows/src/cart/steps/validate-line-item-prices.ts
delete mode 100644 packages/core/core-flows/src/order/utils/prepare-custom-line-item-data.ts
create mode 100644 packages/modules/cart/src/migrations/Migration20241218091938.ts
diff --git a/.changeset/gorgeous-tools-enjoy.md b/.changeset/gorgeous-tools-enjoy.md
new file mode 100644
index 0000000000000..f3c99bd03f047
--- /dev/null
+++ b/.changeset/gorgeous-tools-enjoy.md
@@ -0,0 +1,9 @@
+---
+"@medusajs/core-flows": patch
+"@medusajs/cart": patch
+"@medusajs/types": patch
+"@medusajs/utils": patch
+"@medusajs/medusa": patch
+---
+
+chore: Support custom line items
diff --git a/integration-tests/http/__tests__/order/admin/order.spec.ts b/integration-tests/http/__tests__/order/admin/order.spec.ts
index 1bb66dd8f5a42..092b033f228bb 100644
--- a/integration-tests/http/__tests__/order/admin/order.spec.ts
+++ b/integration-tests/http/__tests__/order/admin/order.spec.ts
@@ -1,5 +1,5 @@
-import { ModuleRegistrationName } from "@medusajs/utils"
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
+import { ModuleRegistrationName } from "@medusajs/utils"
import {
adminHeaders,
createAdminUser,
diff --git a/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts b/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts
index c60fef4d6d7c0..9500c804f73af 100644
--- a/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts
+++ b/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts
@@ -1,13 +1,16 @@
import {
addShippingMethodToCartWorkflow,
addToCartWorkflow,
+ completeCartWorkflow,
createCartWorkflow,
createPaymentCollectionForCartWorkflow,
+ createPaymentSessionsWorkflow,
deleteLineItemsStepId,
deleteLineItemsWorkflow,
findOrCreateCustomerStepId,
listShippingOptionsForCartWorkflow,
refreshPaymentCollectionForCartWorkflow,
+ updateCartWorkflow,
updateLineItemInCartWorkflow,
updateLineItemsStepId,
updatePaymentCollectionStepId,
@@ -61,7 +64,8 @@ medusaIntegrationTestRunner({
let stockLocationModule: IStockLocationService
let inventoryModule: IInventoryService
let fulfillmentModule: IFulfillmentModuleService
- let remoteLink, remoteQuery, storeHeaders
+ let remoteLink, remoteQuery, query
+ let storeHeaders
let salesChannel
let defaultRegion
let customer, storeHeadersWithCustomer
@@ -82,6 +86,7 @@ medusaIntegrationTestRunner({
remoteQuery = appContainer.resolve(
ContainerRegistrationKeys.REMOTE_QUERY
)
+ query = appContainer.resolve(ContainerRegistrationKeys.QUERY)
})
beforeEach(async () => {
@@ -695,6 +700,336 @@ medusaIntegrationTestRunner({
})
})
+ describe("CompleteCartWorkflow", () => {
+ it("should complete cart with custom item", async () => {
+ const salesChannel = await scModuleService.createSalesChannels({
+ name: "Webshop",
+ })
+
+ const location = await stockLocationModule.createStockLocations({
+ name: "Warehouse",
+ })
+
+ const region = await regionModuleService.createRegions({
+ name: "US",
+ currency_code: "usd",
+ })
+
+ let cart = await cartModuleService.createCarts({
+ currency_code: "usd",
+ sales_channel_id: salesChannel.id,
+ region_id: region.id,
+ })
+
+ await remoteLink.create([
+ {
+ [Modules.SALES_CHANNEL]: {
+ sales_channel_id: salesChannel.id,
+ },
+ [Modules.STOCK_LOCATION]: {
+ stock_location_id: location.id,
+ },
+ },
+ ])
+
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ select: ["id", "region_id", "currency_code", "sales_channel_id"],
+ })
+
+ await addToCartWorkflow(appContainer).run({
+ input: {
+ items: [
+ {
+ title: "Test item",
+ subtitle: "Test subtitle",
+ thumbnail: "some-url",
+ requires_shipping: true,
+ is_discountable: false,
+ is_tax_inclusive: false,
+ unit_price: 3000,
+ metadata: {
+ foo: "bar",
+ },
+ quantity: 1,
+ },
+ ],
+ cart_id: cart.id,
+ },
+ })
+
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ relations: ["items"],
+ })
+
+ await createPaymentCollectionForCartWorkflow(appContainer).run({
+ input: {
+ cart_id: cart.id,
+ },
+ })
+
+ const [paymentCollection] =
+ await paymentModule.listPaymentCollections({})
+
+ await createPaymentSessionsWorkflow(appContainer).run({
+ input: {
+ payment_collection_id: paymentCollection.id,
+ provider_id: "pp_system_default",
+ context: {},
+ data: {},
+ },
+ })
+
+ await completeCartWorkflow(appContainer).run({
+ input: {
+ id: cart.id,
+ },
+ })
+
+ const { data } = await query.graph({
+ entity: "cart",
+ filters: {
+ id: cart.id,
+ },
+ fields: ["id", "currency_code", "completed_at", "items.*"],
+ })
+
+ expect(data[0]).toEqual(
+ expect.objectContaining({
+ id: cart.id,
+ currency_code: "usd",
+ completed_at: expect.any(Date),
+ items: [
+ {
+ cart_id: cart.id,
+ compare_at_unit_price: null,
+ created_at: expect.any(Date),
+ deleted_at: null,
+ id: expect.any(String),
+ is_discountable: false,
+ is_tax_inclusive: false,
+ is_custom_price: true,
+ metadata: {
+ foo: "bar",
+ },
+ product_collection: null,
+ product_description: null,
+ product_handle: null,
+ product_id: null,
+ product_subtitle: null,
+ product_title: null,
+ product_type: null,
+ product_type_id: null,
+ quantity: 1,
+ raw_compare_at_unit_price: null,
+ raw_unit_price: {
+ precision: 20,
+ value: "3000",
+ },
+ requires_shipping: true,
+ subtitle: "Test subtitle",
+ thumbnail: "some-url",
+ title: "Test item",
+ unit_price: 3000,
+ updated_at: expect.any(Date),
+ variant_barcode: null,
+ variant_id: null,
+ variant_option_values: null,
+ variant_sku: null,
+ variant_title: null,
+ },
+ ],
+ })
+ )
+ })
+ })
+
+ describe("UpdateCartWorkflow", () => {
+ it("should remove item with custom price when region is updated", async () => {
+ const salesChannel = await scModuleService.createSalesChannels({
+ name: "Webshop",
+ })
+
+ const location = await stockLocationModule.createStockLocations({
+ name: "Warehouse",
+ })
+
+ const regions = await regionModuleService.createRegions([
+ {
+ name: "US",
+ currency_code: "usd",
+ },
+ {
+ name: "EU",
+ currency_code: "eur",
+ },
+ ])
+
+ let cart = await cartModuleService.createCarts({
+ currency_code: "usd",
+ sales_channel_id: salesChannel.id,
+ region_id: regions.find((r) => r.currency_code === "usd")!.id,
+ })
+
+ const [product] = await productModule.createProducts([
+ {
+ title: "Test product",
+ variants: [
+ {
+ title: "Test variant",
+ manage_inventory: false,
+ },
+ ],
+ },
+ ])
+
+ const priceSet = await pricingModule.createPriceSets({
+ prices: [
+ {
+ amount: 3000,
+ currency_code: "usd",
+ },
+ {
+ amount: 2000,
+ currency_code: "eur",
+ },
+ ],
+ })
+
+ await pricingModule.createPricePreferences([
+ {
+ attribute: "currency_code",
+ value: "usd",
+ is_tax_inclusive: true,
+ },
+ ])
+
+ await remoteLink.create([
+ {
+ [Modules.PRODUCT]: {
+ variant_id: product.variants[0].id,
+ },
+ [Modules.PRICING]: {
+ price_set_id: priceSet.id,
+ },
+ },
+ {
+ [Modules.SALES_CHANNEL]: {
+ sales_channel_id: salesChannel.id,
+ },
+ [Modules.STOCK_LOCATION]: {
+ stock_location_id: location.id,
+ },
+ },
+ ])
+
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ select: ["id", "region_id", "currency_code", "sales_channel_id"],
+ })
+
+ await addToCartWorkflow(appContainer).run({
+ input: {
+ items: [
+ {
+ variant_id: product.variants[0].id,
+ quantity: 1,
+ },
+ {
+ title: "Test item",
+ subtitle: "Test subtitle",
+ thumbnail: "some-url",
+ requires_shipping: true,
+ is_discountable: false,
+ is_tax_inclusive: false,
+ unit_price: 1500,
+ metadata: {
+ foo: "bar",
+ },
+ quantity: 1,
+ },
+ ],
+ cart_id: cart.id,
+ },
+ })
+
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ relations: ["items"],
+ })
+
+ expect(cart).toEqual(
+ expect.objectContaining({
+ id: cart.id,
+ currency_code: "usd",
+ items: expect.arrayContaining([
+ expect.objectContaining({
+ // Regular line item
+ id: expect.any(String),
+ is_discountable: true,
+ is_tax_inclusive: true,
+ is_custom_price: false,
+ quantity: 1,
+ requires_shipping: true,
+ subtitle: "Test product",
+ title: "Test variant",
+ unit_price: 3000,
+ updated_at: expect.any(Date),
+ }),
+ expect.objectContaining({
+ // Custom line item
+ id: expect.any(String),
+ is_discountable: false,
+ is_tax_inclusive: false,
+ is_custom_price: true,
+ quantity: 1,
+ metadata: {
+ foo: "bar",
+ },
+ requires_shipping: true,
+ subtitle: "Test subtitle",
+ thumbnail: "some-url",
+ title: "Test item",
+ unit_price: 1500,
+ updated_at: expect.any(Date),
+ }),
+ ]),
+ })
+ )
+
+ await updateCartWorkflow(appContainer).run({
+ input: {
+ id: cart.id,
+ region_id: regions.find((r) => r.currency_code === "eur")!.id,
+ },
+ })
+
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ relations: ["items"],
+ })
+
+ expect(cart).toEqual(
+ expect.objectContaining({
+ id: cart.id,
+ currency_code: "eur",
+ items: expect.arrayContaining([
+ expect.objectContaining({
+ // Regular line item
+ id: expect.any(String),
+ is_discountable: true,
+ is_tax_inclusive: false,
+ is_custom_price: false,
+ quantity: 1,
+ requires_shipping: true,
+ subtitle: "Test product",
+ title: "Test variant",
+ unit_price: 2000,
+ updated_at: expect.any(Date),
+ }),
+ ]),
+ })
+ )
+ expect(cart.items?.length).toEqual(1)
+ })
+ })
+
describe("AddToCartWorkflow", () => {
it("should add item to cart", async () => {
const salesChannel = await scModuleService.createSalesChannels({
@@ -780,39 +1115,492 @@ medusaIntegrationTestRunner({
select: ["id", "region_id", "currency_code", "sales_channel_id"],
})
- await addToCartWorkflow(appContainer).run({
+ await addToCartWorkflow(appContainer).run({
+ input: {
+ items: [
+ {
+ variant_id: product.variants[0].id,
+ quantity: 1,
+ },
+ ],
+ cart_id: cart.id,
+ },
+ })
+
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ relations: ["items"],
+ })
+
+ expect(cart).toEqual(
+ expect.objectContaining({
+ id: cart.id,
+ currency_code: "usd",
+ items: expect.arrayContaining([
+ expect.objectContaining({
+ unit_price: 3000,
+ is_tax_inclusive: true,
+ quantity: 1,
+ title: "Test variant",
+ }),
+ ]),
+ })
+ )
+ })
+
+ it("should add custom item to cart", async () => {
+ const salesChannel = await scModuleService.createSalesChannels({
+ name: "Webshop",
+ })
+
+ const location = await stockLocationModule.createStockLocations({
+ name: "Warehouse",
+ })
+
+ let cart = await cartModuleService.createCarts({
+ currency_code: "usd",
+ sales_channel_id: salesChannel.id,
+ })
+
+ await remoteLink.create([
+ {
+ [Modules.SALES_CHANNEL]: {
+ sales_channel_id: salesChannel.id,
+ },
+ [Modules.STOCK_LOCATION]: {
+ stock_location_id: location.id,
+ },
+ },
+ ])
+
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ select: ["id", "region_id", "currency_code", "sales_channel_id"],
+ })
+
+ await addToCartWorkflow(appContainer).run({
+ input: {
+ items: [
+ {
+ title: "Test item",
+ subtitle: "Test subtitle",
+ thumbnail: "some-url",
+ requires_shipping: true,
+ is_discountable: false,
+ is_tax_inclusive: false,
+ unit_price: 3000,
+ metadata: {
+ foo: "bar",
+ },
+ quantity: 1,
+ },
+ ],
+ cart_id: cart.id,
+ },
+ })
+
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ relations: ["items"],
+ })
+
+ expect(cart).toEqual(
+ expect.objectContaining({
+ id: cart.id,
+ currency_code: "usd",
+ items: [
+ {
+ cart_id: expect.any(String),
+ compare_at_unit_price: null,
+ created_at: expect.any(Date),
+ deleted_at: null,
+ id: expect.any(String),
+ is_discountable: false,
+ is_tax_inclusive: false,
+ is_custom_price: true,
+ metadata: {
+ foo: "bar",
+ },
+ product_collection: null,
+ product_description: null,
+ product_handle: null,
+ product_id: null,
+ product_subtitle: null,
+ product_title: null,
+ product_type: null,
+ product_type_id: null,
+ quantity: 1,
+ raw_compare_at_unit_price: null,
+ raw_unit_price: {
+ precision: 20,
+ value: "3000",
+ },
+ requires_shipping: true,
+ subtitle: "Test subtitle",
+ thumbnail: "some-url",
+ title: "Test item",
+ unit_price: 3000,
+ updated_at: expect.any(Date),
+ variant_barcode: null,
+ variant_id: null,
+ variant_option_values: null,
+ variant_sku: null,
+ variant_title: null,
+ },
+ ],
+ })
+ )
+ })
+
+ it("should add item to cart with price list", async () => {
+ const salesChannel = await scModuleService.createSalesChannels({
+ name: "Webshop",
+ })
+
+ const customer = await customerModule.createCustomers({
+ first_name: "Test",
+ last_name: "Test",
+ })
+
+ const customer_group = await customerModule.createCustomerGroups({
+ name: "Test Group",
+ })
+
+ await customerModule.addCustomerToGroup({
+ customer_id: customer.id,
+ customer_group_id: customer_group.id,
+ })
+
+ const location = await stockLocationModule.createStockLocations({
+ name: "Warehouse",
+ })
+
+ let cart = await cartModuleService.createCarts({
+ currency_code: "usd",
+ sales_channel_id: salesChannel.id,
+ customer_id: customer.id,
+ })
+
+ const [product] = await productModule.createProducts([
+ {
+ title: "Test product",
+ variants: [
+ {
+ title: "Test variant",
+ },
+ ],
+ },
+ ])
+
+ const inventoryItem = await inventoryModule.createInventoryItems({
+ sku: "inv-1234",
+ })
+
+ await inventoryModule.createInventoryLevels([
+ {
+ inventory_item_id: inventoryItem.id,
+ location_id: location.id,
+ stocked_quantity: 2,
+ },
+ ])
+
+ const priceSet = await pricingModule.createPriceSets({
+ prices: [
+ {
+ amount: 3000,
+ currency_code: "usd",
+ },
+ ],
+ })
+
+ await pricingModule.createPricePreferences({
+ attribute: "currency_code",
+ value: "usd",
+ is_tax_inclusive: true,
+ })
+
+ await pricingModule.createPriceLists([
+ {
+ title: "test price list",
+ description: "test",
+ status: PriceListStatus.ACTIVE,
+ type: PriceListType.OVERRIDE,
+ prices: [
+ {
+ amount: 1500,
+ currency_code: "usd",
+ price_set_id: priceSet.id,
+ },
+ ],
+ rules: {
+ "customer.groups.id": [customer_group.id],
+ },
+ },
+ ])
+
+ await remoteLink.create([
+ {
+ [Modules.PRODUCT]: {
+ variant_id: product.variants[0].id,
+ },
+ [Modules.PRICING]: {
+ price_set_id: priceSet.id,
+ },
+ },
+ {
+ [Modules.SALES_CHANNEL]: {
+ sales_channel_id: salesChannel.id,
+ },
+ [Modules.STOCK_LOCATION]: {
+ stock_location_id: location.id,
+ },
+ },
+ {
+ [Modules.PRODUCT]: {
+ variant_id: product.variants[0].id,
+ },
+ [Modules.INVENTORY]: {
+ inventory_item_id: inventoryItem.id,
+ },
+ },
+ ])
+
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ select: ["id", "region_id", "currency_code", "sales_channel_id"],
+ })
+
+ await addToCartWorkflow(appContainer).run({
+ input: {
+ items: [
+ {
+ variant_id: product.variants[0].id,
+ quantity: 1,
+ },
+ ],
+ cart_id: cart.id,
+ },
+ })
+
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ relations: ["items"],
+ })
+
+ expect(cart).toEqual(
+ expect.objectContaining({
+ id: cart.id,
+ currency_code: "usd",
+ items: expect.arrayContaining([
+ expect.objectContaining({
+ unit_price: 1500,
+ is_tax_inclusive: true,
+ quantity: 1,
+ title: "Test variant",
+ }),
+ ]),
+ })
+ )
+ })
+
+ it("should throw if no price sets for variant exist", async () => {
+ const salesChannel = await scModuleService.createSalesChannels({
+ name: "Webshop",
+ })
+
+ const location = await stockLocationModule.createStockLocations({
+ name: "Warehouse",
+ })
+
+ let cart = await cartModuleService.createCarts({
+ currency_code: "usd",
+ sales_channel_id: salesChannel.id,
+ })
+
+ const [product] = await productModule.createProducts([
+ {
+ title: "Test product",
+ variants: [
+ {
+ title: "Test variant",
+ },
+ ],
+ },
+ ])
+
+ const inventoryItem = await inventoryModule.createInventoryItems({
+ sku: "inv-1234",
+ })
+
+ await inventoryModule.createInventoryLevels([
+ {
+ inventory_item_id: inventoryItem.id,
+ location_id: location.id,
+ stocked_quantity: 2,
+ reserved_quantity: 0,
+ },
+ ])
+
+ await remoteLink.create([
+ {
+ [Modules.SALES_CHANNEL]: {
+ sales_channel_id: salesChannel.id,
+ },
+ [Modules.STOCK_LOCATION]: {
+ stock_location_id: location.id,
+ },
+ },
+ {
+ [Modules.PRODUCT]: {
+ variant_id: product.variants[0].id,
+ },
+ [Modules.INVENTORY]: {
+ inventory_item_id: inventoryItem.id,
+ },
+ },
+ ])
+
+ const { errors } = await addToCartWorkflow(appContainer).run({
+ input: {
+ items: [
+ {
+ variant_id: product.variants[0].id,
+ quantity: 1,
+ },
+ ],
+ cart_id: cart.id,
+ },
+ throwOnError: false,
+ })
+
+ expect(errors).toEqual([
+ {
+ action: "validate-variant-prices",
+ handlerType: "invoke",
+ error: expect.objectContaining({
+ message: expect.stringContaining(
+ `Variants with IDs ${product.variants[0].id} do not have a price`
+ ),
+ }),
+ },
+ ])
+ })
+ })
+
+ describe("updateLineItemInCartWorkflow", () => {
+ it("should update item in cart", async () => {
+ const salesChannel = await scModuleService.createSalesChannels({
+ name: "Webshop",
+ })
+
+ const location = await stockLocationModule.createStockLocations({
+ name: "Warehouse",
+ })
+
+ const [product] = await productModule.createProducts([
+ {
+ title: "Test product",
+ variants: [
+ {
+ title: "Test variant",
+ },
+ ],
+ },
+ ])
+
+ const inventoryItem = await inventoryModule.createInventoryItems({
+ sku: "inv-1234",
+ })
+
+ await inventoryModule.createInventoryLevels([
+ {
+ inventory_item_id: inventoryItem.id,
+ location_id: location.id,
+ stocked_quantity: 2,
+ reserved_quantity: 0,
+ },
+ ])
+
+ const priceSet = await pricingModule.createPriceSets({
+ prices: [
+ {
+ amount: 3000,
+ currency_code: "usd",
+ },
+ ],
+ })
+
+ await remoteLink.create([
+ {
+ [Modules.PRODUCT]: {
+ variant_id: product.variants[0].id,
+ },
+ [Modules.PRICING]: {
+ price_set_id: priceSet.id,
+ },
+ },
+ {
+ [Modules.SALES_CHANNEL]: {
+ sales_channel_id: salesChannel.id,
+ },
+ [Modules.STOCK_LOCATION]: {
+ stock_location_id: location.id,
+ },
+ },
+ {
+ [Modules.PRODUCT]: {
+ variant_id: product.variants[0].id,
+ },
+ [Modules.INVENTORY]: {
+ inventory_item_id: inventoryItem.id,
+ },
+ },
+ ])
+
+ let cart = await cartModuleService.createCarts({
+ currency_code: "usd",
+ sales_channel_id: salesChannel.id,
+ items: [
+ {
+ variant_id: product.variants[0].id,
+ quantity: 1,
+ unit_price: 5000,
+ is_custom_price: true,
+ title: "Test variant",
+ },
+ ],
+ })
+
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ select: ["id", "region_id", "currency_code"],
+ relations: ["items", "items.variant_id", "items.metadata"],
+ })
+
+ const item = cart.items?.[0]!
+
+ await updateLineItemInCartWorkflow(appContainer).run({
input: {
- items: [
- {
- variant_id: product.variants[0].id,
- quantity: 1,
+ item_id: item.id,
+ update: {
+ metadata: {
+ foo: "bar",
},
- ],
+ quantity: 2,
+ },
cart_id: cart.id,
},
+ throwOnError: false,
})
- cart = await cartModuleService.retrieveCart(cart.id, {
- relations: ["items"],
- })
+ const updatedItem = await cartModuleService.retrieveLineItem(item.id)
- expect(cart).toEqual(
+ expect(updatedItem).toEqual(
expect.objectContaining({
- id: cart.id,
- currency_code: "usd",
- items: expect.arrayContaining([
- expect.objectContaining({
- unit_price: 3000,
- is_tax_inclusive: true,
- quantity: 1,
- title: "Test variant",
- }),
- ]),
+ id: item.id,
+ unit_price: 5000,
+ is_custom_price: true,
+ quantity: 2,
+ title: "Test variant",
})
)
})
- it("should throw if no price sets for variant exist", async () => {
+ it("should update custom item in cart", async () => {
const salesChannel = await scModuleService.createSalesChannels({
name: "Webshop",
})
@@ -824,32 +1612,25 @@ medusaIntegrationTestRunner({
let cart = await cartModuleService.createCarts({
currency_code: "usd",
sales_channel_id: salesChannel.id,
- })
-
- const [product] = await productModule.createProducts([
- {
- title: "Test product",
- variants: [
- {
- title: "Test variant",
+ items: [
+ {
+ title: "Test item",
+ subtitle: "Test subtitle",
+ thumbnail: "some-url",
+ requires_shipping: true,
+ is_discountable: false,
+ is_tax_inclusive: false,
+ is_custom_price: true,
+ variant_id: "some_random_id",
+ unit_price: 3000,
+ metadata: {
+ foo: "bar",
},
- ],
- },
- ])
-
- const inventoryItem = await inventoryModule.createInventoryItems({
- sku: "inv-1234",
+ quantity: 1,
+ },
+ ],
})
- await inventoryModule.createInventoryLevels([
- {
- inventory_item_id: inventoryItem.id,
- location_id: location.id,
- stocked_quantity: 2,
- reserved_quantity: 0,
- },
- ])
-
await remoteLink.create([
{
[Modules.SALES_CHANNEL]: {
@@ -859,100 +1640,146 @@ medusaIntegrationTestRunner({
stock_location_id: location.id,
},
},
- {
- [Modules.PRODUCT]: {
- variant_id: product.variants[0].id,
- },
- [Modules.INVENTORY]: {
- inventory_item_id: inventoryItem.id,
- },
- },
])
- const { errors } = await addToCartWorkflow(appContainer).run({
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ select: ["id", "region_id", "currency_code", "sales_channel_id"],
+ relations: ["items"],
+ })
+
+ await updateLineItemInCartWorkflow(appContainer).run({
input: {
- items: [
- {
- variant_id: product.variants[0].id,
- quantity: 1,
- },
- ],
cart_id: cart.id,
+ item_id: cart.items?.[0]!.id!,
+ update: {
+ quantity: 2,
+ title: "Some other title",
+ },
},
- throwOnError: false,
})
- expect(errors).toEqual([
- {
- action: "validate-variant-prices",
- handlerType: "invoke",
- error: expect.objectContaining({
- message: expect.stringContaining(
- `Variants with IDs ${product.variants[0].id} do not have a price`
- ),
- }),
- },
- ])
- })
-
- it("should throw if variant does not exist", async () => {
- const cart = await cartModuleService.createCarts({
- currency_code: "usd",
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ relations: ["items"],
})
- const { errors } = await addToCartWorkflow(appContainer).run({
- input: {
+ expect(cart).toEqual(
+ expect.objectContaining({
+ id: cart.id,
+ currency_code: "usd",
items: [
{
- variant_id: "prva_foo",
- quantity: 1,
+ cart_id: expect.any(String),
+ compare_at_unit_price: null,
+ created_at: expect.any(Date),
+ deleted_at: null,
+ id: expect.any(String),
+ is_discountable: false,
+ is_tax_inclusive: false,
+ is_custom_price: true,
+ metadata: {
+ foo: "bar",
+ },
+ product_collection: null,
+ product_description: null,
+ product_handle: null,
+ product_id: null,
+ product_subtitle: null,
+ product_title: null,
+ product_type: null,
+ product_type_id: null,
+ quantity: 2,
+ raw_compare_at_unit_price: null,
+ raw_unit_price: {
+ precision: 20,
+ value: "3000",
+ },
+ requires_shipping: true,
+ subtitle: "Test subtitle",
+ thumbnail: "some-url",
+ title: "Some other title",
+ unit_price: 3000,
+ updated_at: expect.any(Date),
+ variant_barcode: null,
+ variant_id: "some_random_id",
+ variant_option_values: null,
+ variant_sku: null,
+ variant_title: null,
},
],
+ })
+ )
+
+ await updateLineItemInCartWorkflow(appContainer).run({
+ input: {
cart_id: cart.id,
+ item_id: cart.items?.[0]!.id!,
+ update: {
+ quantity: 4,
+ },
},
- throwOnError: false,
})
- expect(errors).toEqual([
- {
- action: "use-remote-query",
- handlerType: "invoke",
- error: expect.objectContaining({
- message: `ProductVariant id not found: prva_foo`,
- }),
- },
- ])
+ cart = await cartModuleService.retrieveCart(cart.id, {
+ relations: ["items"],
+ })
+
+ expect(cart).toEqual(
+ expect.objectContaining({
+ id: cart.id,
+ currency_code: "usd",
+ items: [
+ {
+ cart_id: expect.any(String),
+ compare_at_unit_price: null,
+ created_at: expect.any(Date),
+ deleted_at: null,
+ id: expect.any(String),
+ is_discountable: false,
+ is_tax_inclusive: false,
+ is_custom_price: true,
+ metadata: {
+ foo: "bar",
+ },
+ product_collection: null,
+ product_description: null,
+ product_handle: null,
+ product_id: null,
+ product_subtitle: null,
+ product_title: null,
+ product_type: null,
+ product_type_id: null,
+ quantity: 4,
+ raw_compare_at_unit_price: null,
+ raw_unit_price: {
+ precision: 20,
+ value: "3000",
+ },
+ requires_shipping: true,
+ subtitle: "Test subtitle",
+ thumbnail: "some-url",
+ title: "Some other title",
+ unit_price: 3000,
+ updated_at: expect.any(Date),
+ variant_barcode: null,
+ variant_id: "some_random_id",
+ variant_option_values: null,
+ variant_sku: null,
+ variant_title: null,
+ },
+ ],
+ })
+ )
})
- it("should add item to cart with price list", async () => {
+ it("should update unit price of regular item in cart", async () => {
const salesChannel = await scModuleService.createSalesChannels({
name: "Webshop",
})
- const customer = await customerModule.createCustomers({
- first_name: "Test",
- last_name: "Test",
- })
-
- const customer_group = await customerModule.createCustomerGroups({
- name: "Test Group",
- })
-
- await customerModule.addCustomerToGroup({
- customer_id: customer.id,
- customer_group_id: customer_group.id,
- })
-
const location = await stockLocationModule.createStockLocations({
name: "Warehouse",
})
- let cart = await cartModuleService.createCarts({
- currency_code: "usd",
- sales_channel_id: salesChannel.id,
- customer_id: customer.id,
- })
-
const [product] = await productModule.createProducts([
{
title: "Test product",
@@ -973,6 +1800,7 @@ medusaIntegrationTestRunner({
inventory_item_id: inventoryItem.id,
location_id: location.id,
stocked_quantity: 2,
+ reserved_quantity: 0,
},
])
@@ -985,31 +1813,6 @@ medusaIntegrationTestRunner({
],
})
- await pricingModule.createPricePreferences({
- attribute: "currency_code",
- value: "usd",
- is_tax_inclusive: true,
- })
-
- await pricingModule.createPriceLists([
- {
- title: "test price list",
- description: "test",
- status: PriceListStatus.ACTIVE,
- type: PriceListType.OVERRIDE,
- prices: [
- {
- amount: 1500,
- currency_code: "usd",
- price_set_id: priceSet.id,
- },
- ],
- rules: {
- "customer.groups.id": [customer_group.id],
- },
- },
- ])
-
await remoteLink.create([
{
[Modules.PRODUCT]: {
@@ -1037,38 +1840,49 @@ medusaIntegrationTestRunner({
},
])
+ let cart = await cartModuleService.createCarts({
+ currency_code: "usd",
+ sales_channel_id: salesChannel.id,
+ items: [
+ {
+ variant_id: product.variants[0].id,
+ quantity: 1,
+ unit_price: 5000,
+ title: "Test item",
+ },
+ ],
+ })
+
cart = await cartModuleService.retrieveCart(cart.id, {
- select: ["id", "region_id", "currency_code", "sales_channel_id"],
+ select: ["id", "region_id", "currency_code"],
+ relations: ["items", "items.variant_id", "items.metadata"],
})
- await addToCartWorkflow(appContainer).run({
+ const item = cart.items?.[0]!
+
+ await updateLineItemInCartWorkflow(appContainer).run({
input: {
- items: [
- {
- variant_id: product.variants[0].id,
- quantity: 1,
- },
- ],
cart_id: cart.id,
+ item_id: item.id,
+ update: {
+ metadata: {
+ foo: "bar",
+ },
+ unit_price: 4000,
+ quantity: 2,
+ },
},
})
- cart = await cartModuleService.retrieveCart(cart.id, {
- relations: ["items"],
- })
+ const updatedItem = await cartModuleService.retrieveLineItem(item.id)
- expect(cart).toEqual(
+ expect(updatedItem).toEqual(
expect.objectContaining({
- id: cart.id,
- currency_code: "usd",
- items: expect.arrayContaining([
- expect.objectContaining({
- unit_price: 1500,
- is_tax_inclusive: true,
- quantity: 1,
- title: "Test variant",
- }),
- ]),
+ id: item.id,
+ unit_price: 4000,
+ is_custom_price: true,
+ quantity: 2,
+ title: "Test variant",
})
)
})
@@ -1184,8 +1998,8 @@ medusaIntegrationTestRunner({
{
variant_id: product.variants[0].id,
quantity: 1,
- unit_price: 5000,
title: "Test item",
+ unit_price: 5000,
},
],
})
@@ -1197,9 +2011,7 @@ medusaIntegrationTestRunner({
const item = cart.items?.[0]!
- const { errors } = await updateLineItemInCartWorkflow(
- appContainer
- ).run({
+ await updateLineItemInCartWorkflow(appContainer).run({
input: {
cart_id: cart.id,
item_id: item.id,
diff --git a/integration-tests/modules/__tests__/order/draft-order.spec.ts b/integration-tests/modules/__tests__/order/draft-order.spec.ts
index b097ed54c0cc2..e11bf06c43ed3 100644
--- a/integration-tests/modules/__tests__/order/draft-order.spec.ts
+++ b/integration-tests/modules/__tests__/order/draft-order.spec.ts
@@ -207,8 +207,8 @@ medusaIntegrationTestRunner({
},
{
title: "Custom Item",
- sku: "sku123",
- barcode: "barcode123",
+ variant_sku: "sku123",
+ variant_barcode: "barcode123",
unit_price: 2200,
quantity: 1,
},
@@ -254,6 +254,7 @@ medusaIntegrationTestRunner({
requires_shipping: true,
is_discountable: true,
is_tax_inclusive: true,
+ is_custom_price: false,
raw_compare_at_unit_price: null,
raw_unit_price: expect.objectContaining({
value: "3000",
@@ -323,7 +324,8 @@ medusaIntegrationTestRunner({
title: "Custom Item",
variant_sku: "sku123",
variant_barcode: "barcode123",
- variant_title: "Custom Item",
+ variant_title: null,
+ is_custom_price: true,
raw_unit_price: expect.objectContaining({
value: "2200",
}),
diff --git a/packages/core/core-flows/src/cart/steps/validate-line-item-prices.ts b/packages/core/core-flows/src/cart/steps/validate-line-item-prices.ts
new file mode 100644
index 0000000000000..9241e1d1cfac2
--- /dev/null
+++ b/packages/core/core-flows/src/cart/steps/validate-line-item-prices.ts
@@ -0,0 +1,36 @@
+import { MedusaError, isPresent } from "@medusajs/framework/utils"
+import { createStep } from "@medusajs/framework/workflows-sdk"
+
+export interface ValidateLineItemPricesStepInput {
+ items: {
+ unit_price?: number | null
+ title: string
+ }[]
+}
+
+export const validateLineItemPricesStepId = "validate-line-item-prices"
+/**
+ * This step validates the specified line item objects to ensure they have prices.
+ */
+export const validateLineItemPricesStep = createStep(
+ validateLineItemPricesStepId,
+ async (data: ValidateLineItemPricesStepInput, { container }) => {
+ if (!data.items?.length) {
+ return
+ }
+
+ const priceNotFound: string[] = []
+ for (const item of data.items) {
+ if (!isPresent(item?.unit_price)) {
+ priceNotFound.push(item.title)
+ }
+ }
+
+ if (priceNotFound.length > 0) {
+ throw new MedusaError(
+ MedusaError.Types.INVALID_DATA,
+ `Items ${priceNotFound.join(", ")} do not have a price`
+ )
+ }
+ }
+)
diff --git a/packages/core/core-flows/src/cart/steps/validate-variant-prices.ts b/packages/core/core-flows/src/cart/steps/validate-variant-prices.ts
index b5731a765e1aa..fe34300bf5098 100644
--- a/packages/core/core-flows/src/cart/steps/validate-variant-prices.ts
+++ b/packages/core/core-flows/src/cart/steps/validate-variant-prices.ts
@@ -18,6 +18,10 @@ export const validateVariantPricesStepId = "validate-variant-prices"
export const validateVariantPricesStep = createStep(
validateVariantPricesStepId,
async (data: ValidateVariantPricesStepInput, { container }) => {
+ if (!data.variants?.length) {
+ return
+ }
+
const priceNotFound: string[] = []
for (const variant of data.variants) {
if (!isPresent(variant?.calculated_price?.calculated_amount)) {
diff --git a/packages/core/core-flows/src/cart/utils/prepare-line-item-data.ts b/packages/core/core-flows/src/cart/utils/prepare-line-item-data.ts
index 433e36a8db790..74d216f576948 100644
--- a/packages/core/core-flows/src/cart/utils/prepare-line-item-data.ts
+++ b/packages/core/core-flows/src/cart/utils/prepare-line-item-data.ts
@@ -1,61 +1,106 @@
import {
BigNumberInput,
- CartLineItemDTO,
CreateOrderAdjustmentDTO,
CreateOrderLineItemTaxLineDTO,
InventoryItemDTO,
+ LineItemAdjustmentDTO,
+ LineItemTaxLineDTO,
ProductVariantDTO,
} from "@medusajs/framework/types"
-import { isDefined, MathBN, PriceListType } from "@medusajs/framework/utils"
-
-interface Input {
- item?: CartLineItemDTO
+import {
+ isDefined,
+ isPresent,
+ MathBN,
+ PriceListType,
+} from "@medusajs/framework/utils"
+
+interface PrepareItemLineItemInput {
+ title?: string
+ subtitle?: string
+ thumbnail?: string
quantity: BigNumberInput
- metadata?: Record
- unitPrice: BigNumberInput
- compareAtUnitPrice?: BigNumberInput | null
- isTaxInclusive?: boolean
- variant: ProductVariantDTO & {
- inventory_items: { inventory: InventoryItemDTO }[]
+
+ product_id?: string
+ product_title?: string
+ product_description?: string
+ product_subtitle?: string
+ product_type?: string
+ product_type_id?: string
+ product_collection?: string
+ product_handle?: string
+
+ variant_id?: string
+ variant_sku?: string
+ variant_barcode?: string
+ variant_title?: string
+ variant_option_values?: Record
+
+ requires_shipping?: boolean
+
+ is_discountable?: boolean
+ is_tax_inclusive?: boolean
+
+ raw_compare_at_unit_price?: BigNumberInput
+ compare_at_unit_price?: BigNumberInput
+ unit_price?: BigNumberInput
+
+ tax_lines?: LineItemTaxLineDTO[]
+ adjustments?: LineItemAdjustmentDTO[]
+ cart_id?: string
+ metadata?: Record | null
+}
+
+export interface PrepareVariantLineItemInput extends ProductVariantDTO {
+ inventory_items: { inventory: InventoryItemDTO }[]
+ calculated_price: {
calculated_price: {
- calculated_price: {
- price_list_type: string
- }
- original_amount: BigNumberInput
- calculated_amount: BigNumberInput
+ price_list_type: string
}
+ is_calculated_price_tax_inclusive: boolean
+ original_amount: BigNumberInput
+ calculated_amount: BigNumberInput
}
+}
+
+export interface PrepareLineItemDataInput {
+ item?: PrepareItemLineItemInput
+ isCustomPrice?: boolean
+ variant?: PrepareVariantLineItemInput
taxLines?: CreateOrderLineItemTaxLineDTO[]
adjustments?: CreateOrderAdjustmentDTO[]
cartId?: string
+ unitPrice?: BigNumberInput
+ isTaxInclusive: boolean
}
-export function prepareLineItemData(data: Input) {
+export function prepareLineItemData(data: PrepareLineItemDataInput) {
const {
item,
variant,
- unitPrice,
- isTaxInclusive,
- quantity,
- metadata,
cartId,
taxLines,
adjustments,
+ isCustomPrice,
+ unitPrice,
+ isTaxInclusive,
} = data
- if (!variant.product) {
+ if (variant && !variant.product) {
throw new Error("Variant does not have a product")
}
- let compareAtUnitPrice = data.compareAtUnitPrice
+ let compareAtUnitPrice = item?.compare_at_unit_price
+
+ const isSalePrice =
+ variant?.calculated_price?.calculated_price?.price_list_type ===
+ PriceListType.SALE
if (
- !isDefined(compareAtUnitPrice) &&
- variant.calculated_price.calculated_price.price_list_type ===
- PriceListType.SALE &&
+ !isPresent(compareAtUnitPrice) &&
+ isSalePrice &&
!MathBN.eq(
- variant.calculated_price.original_amount,
- variant.calculated_price.calculated_amount
+ variant.calculated_price?.original_amount,
+ variant.calculated_price?.calculated_amount
)
) {
compareAtUnitPrice = variant.calculated_price.original_amount
@@ -63,9 +108,8 @@ export function prepareLineItemData(data: Input) {
// Note: If any of the items require shipping, we enable fulfillment
// unless explicitly set to not require shipping by the item in the request
- const { inventory_items: inventoryItems } = variant
- const someInventoryRequiresShipping = inventoryItems.length
- ? inventoryItems.some(
+ const someInventoryRequiresShipping = variant?.inventory_items?.length
+ ? variant.inventory_items.some(
(inventoryItem) => !!inventoryItem.inventory.requires_shipping
)
: true
@@ -74,37 +118,42 @@ export function prepareLineItemData(data: Input) {
? item.requires_shipping
: someInventoryRequiresShipping
- const lineItem: any = {
- quantity,
- title: variant.title ?? item?.title,
- subtitle: variant.product.title ?? item?.subtitle,
- thumbnail: variant.product.thumbnail ?? item?.thumbnail,
+ let lineItem: any = {
+ quantity: item?.quantity,
+ title: variant?.title ?? item?.title,
+ subtitle: variant?.product?.title ?? item?.subtitle,
+ thumbnail: variant?.product?.thumbnail ?? item?.thumbnail,
- product_id: variant.product.id ?? item?.product_id,
- product_title: variant.product.title ?? item?.product_title,
+ product_id: variant?.product?.id ?? item?.product_id,
+ product_title: variant?.product?.title ?? item?.product_title,
product_description:
- variant.product.description ?? item?.product_description,
- product_subtitle: variant.product.subtitle ?? item?.product_subtitle,
- product_type: variant.product.type?.value ?? item?.product_type ?? null,
- product_type_id: variant.product.type?.id ?? item?.product_type_id ?? null,
+ variant?.product?.description ?? item?.product_description,
+ product_subtitle: variant?.product?.subtitle ?? item?.product_subtitle,
+ product_type: variant?.product?.type?.value ?? item?.product_type ?? null,
+ product_type_id:
+ variant?.product?.type?.id ?? item?.product_type_id ?? null,
product_collection:
- variant.product.collection?.title ?? item?.product_collection ?? null,
- product_handle: variant.product.handle ?? item?.product_handle,
+ variant?.product?.collection?.title ?? item?.product_collection ?? null,
+ product_handle: variant?.product?.handle ?? item?.product_handle,
- variant_id: variant.id,
- variant_sku: variant.sku ?? item?.variant_sku,
- variant_barcode: variant.barcode ?? item?.variant_barcode,
- variant_title: variant.title ?? item?.variant_title,
+ variant_id: variant?.id,
+ variant_sku: variant?.sku ?? item?.variant_sku,
+ variant_barcode: variant?.barcode ?? item?.variant_barcode,
+ variant_title: variant?.title ?? item?.variant_title,
variant_option_values: item?.variant_option_values,
- is_discountable: variant.product.discountable ?? item?.is_discountable,
+ is_discountable: variant?.product?.discountable ?? item?.is_discountable,
requires_shipping: requiresShipping,
unit_price: unitPrice,
compare_at_unit_price: compareAtUnitPrice,
is_tax_inclusive: !!isTaxInclusive,
- metadata,
+ metadata: item?.metadata ?? {},
+ }
+
+ if (isCustomPrice) {
+ lineItem.is_custom_price = !!isCustomPrice
}
if (taxLines) {
diff --git a/packages/core/core-flows/src/cart/workflows/add-to-cart.ts b/packages/core/core-flows/src/cart/workflows/add-to-cart.ts
index 22beb5f262865..737305b5a99e9 100644
--- a/packages/core/core-flows/src/cart/workflows/add-to-cart.ts
+++ b/packages/core/core-flows/src/cart/workflows/add-to-cart.ts
@@ -1,13 +1,11 @@
+import { AddToCartWorkflowInputDTO } from "@medusajs/framework/types"
+import { CartWorkflowEvents, isDefined } from "@medusajs/framework/utils"
import {
- AddToCartWorkflowInputDTO,
- CreateLineItemForCartDTO,
-} from "@medusajs/framework/types"
-import { CartWorkflowEvents } from "@medusajs/framework/utils"
-import {
- WorkflowData,
createWorkflow,
parallelize,
transform,
+ when,
+ WorkflowData,
} from "@medusajs/framework/workflows-sdk"
import { useQueryGraphStep } from "../../common"
import { emitEventStep } from "../../common/steps/emit-event"
@@ -18,12 +16,16 @@ import {
updateLineItemsStep,
} from "../steps"
import { validateCartStep } from "../steps/validate-cart"
+import { validateLineItemPricesStep } from "../steps/validate-line-item-prices"
import { validateVariantPricesStep } from "../steps/validate-variant-prices"
import {
cartFieldsForPricingContext,
productVariantsFields,
} from "../utils/fields"
-import { prepareLineItemData } from "../utils/prepare-line-item-data"
+import {
+ prepareLineItemData,
+ PrepareLineItemDataInput,
+} from "../utils/prepare-line-item-data"
import { confirmVariantInventoryWorkflow } from "./confirm-variant-inventory"
import { refreshCartItemsWorkflow } from "./refresh-cart-items"
@@ -50,41 +52,55 @@ export const addToCartWorkflow = createWorkflow(
validateCartStep({ cart })
const variantIds = transform({ input }, (data) => {
- return (data.input.items ?? []).map((i) => i.variant_id)
+ return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
})
- const variants = useRemoteQueryStep({
- entry_point: "variants",
- fields: productVariantsFields,
- variables: {
- id: variantIds,
- calculated_price: { context: cart },
- },
- throw_if_key_not_found: true,
+ const variants = when({ variantIds }, ({ variantIds }) => {
+ return !!variantIds.length
+ }).then(() => {
+ return useRemoteQueryStep({
+ entry_point: "variants",
+ fields: productVariantsFields,
+ variables: {
+ id: variantIds,
+ calculated_price: {
+ context: cart,
+ },
+ },
+ })
})
validateVariantPricesStep({ variants })
const lineItems = transform({ input, variants }, (data) => {
const items = (data.input.items ?? []).map((item) => {
- const variant = data.variants.find((v) => v.id === item.variant_id)!
+ const variant = (data.variants ?? []).find(
+ (v) => v.id === item.variant_id
+ )!
- return prepareLineItemData({
+ const input: PrepareLineItemDataInput = {
+ item,
variant: variant,
- unitPrice:
- item.unit_price || variant.calculated_price.calculated_amount,
+ cartId: data.input.cart_id,
+ unitPrice: item.unit_price,
isTaxInclusive:
- item.is_tax_inclusive ||
- variant.calculated_price.is_calculated_price_tax_inclusive,
- quantity: item.quantity,
- metadata: item?.metadata ?? {},
- cartId: input.cart_id,
- }) as CreateLineItemForCartDTO
+ item.is_tax_inclusive ??
+ variant?.calculated_price?.is_calculated_price_tax_inclusive,
+ isCustomPrice: isDefined(item?.unit_price),
+ }
+
+ if (variant && !input.unitPrice) {
+ input.unitPrice = variant.calculated_price?.calculated_amount
+ }
+
+ return prepareLineItemData(input)
})
return items
})
+ validateLineItemPricesStep({ items: lineItems })
+
const { itemsToCreate = [], itemsToUpdate = [] } = getLineItemActionsStep({
id: cart.id,
items: lineItems,
diff --git a/packages/core/core-flows/src/cart/workflows/complete-cart.ts b/packages/core/core-flows/src/cart/workflows/complete-cart.ts
index 42c28e1b5bdf7..b0d199c860eac 100644
--- a/packages/core/core-flows/src/cart/workflows/complete-cart.ts
+++ b/packages/core/core-flows/src/cart/workflows/complete-cart.ts
@@ -5,7 +5,7 @@ import {
import {
Modules,
OrderStatus,
- OrderWorkflowEvents,
+ OrderWorkflowEvents
} from "@medusajs/framework/utils"
import {
createWorkflow,
@@ -31,6 +31,7 @@ import { prepareConfirmInventoryInput } from "../utils/prepare-confirm-inventory
import {
prepareAdjustmentsData,
prepareLineItemData,
+ PrepareLineItemDataInput,
prepareTaxLinesData,
} from "../utils/prepare-line-item-data"
@@ -115,18 +116,17 @@ export const completeCartWorkflow = createWorkflow(
}) ?? []
const allItems = (cart.items ?? []).map((item) => {
- return prepareLineItemData({
+ const input: PrepareLineItemDataInput = {
item,
variant: item.variant,
- unitPrice: item.raw_unit_price ?? item.unit_price,
- compareAtUnitPrice:
- item.raw_compare_at_unit_price ?? item.compare_at_unit_price,
+ cartId: cart.id,
+ unitPrice: item.unit_price,
isTaxInclusive: item.is_tax_inclusive,
- quantity: item.raw_quantity ?? item.quantity,
- metadata: item?.metadata,
taxLines: item.tax_lines ?? [],
adjustments: item.adjustments ?? [],
- })
+ }
+
+ return prepareLineItemData(input)
})
const shippingMethods = (cart.shipping_methods ?? []).map((sm) => {
diff --git a/packages/core/core-flows/src/cart/workflows/create-carts.ts b/packages/core/core-flows/src/cart/workflows/create-carts.ts
index ddec635c2bcce..b1e107549942c 100644
--- a/packages/core/core-flows/src/cart/workflows/create-carts.ts
+++ b/packages/core/core-flows/src/cart/workflows/create-carts.ts
@@ -2,14 +2,19 @@ import {
AdditionalData,
CreateCartWorkflowInputDTO,
} from "@medusajs/framework/types"
-import { CartWorkflowEvents, MedusaError } from "@medusajs/framework/utils"
import {
- WorkflowData,
- WorkflowResponse,
+ CartWorkflowEvents,
+ isDefined,
+ MedusaError,
+} from "@medusajs/framework/utils"
+import {
createHook,
createWorkflow,
parallelize,
transform,
+ when,
+ WorkflowData,
+ WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import { emitEventStep } from "../../common/steps/emit-event"
import { useRemoteQueryStep } from "../../common/steps/use-remote-query"
@@ -18,11 +23,14 @@ import {
findOneOrAnyRegionStep,
findOrCreateCustomerStep,
findSalesChannelStep,
- getVariantPriceSetsStep,
} from "../steps"
+import { validateLineItemPricesStep } from "../steps/validate-line-item-prices"
import { validateVariantPricesStep } from "../steps/validate-variant-prices"
import { productVariantsFields } from "../utils/fields"
-import { prepareLineItemData } from "../utils/prepare-line-item-data"
+import {
+ prepareLineItemData,
+ PrepareLineItemDataInput,
+} from "../utils/prepare-line-item-data"
import { confirmVariantInventoryWorkflow } from "./confirm-variant-inventory"
import { refreshPaymentCollectionForCartWorkflow } from "./refresh-payment-collection"
import { updateCartPromotionsWorkflow } from "./update-cart-promotions"
@@ -36,7 +44,7 @@ export const createCartWorkflow = createWorkflow(
createCartWorkflowId,
(input: WorkflowData) => {
const variantIds = transform({ input }, (data) => {
- return (data.input.items ?? []).map((i) => i.variant_id)
+ return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
})
const [salesChannel, region, customerData] = parallelize(
@@ -68,16 +76,19 @@ export const createCartWorkflow = createWorkflow(
}
)
- const variants = useRemoteQueryStep({
- entry_point: "variants",
- fields: productVariantsFields,
- variables: {
- id: variantIds,
- calculated_price: {
- context: pricingContext,
+ const variants = when({ variantIds }, ({ variantIds }) => {
+ return !!variantIds.length
+ }).then(() => {
+ return useRemoteQueryStep({
+ entry_point: "variants",
+ fields: productVariantsFields,
+ variables: {
+ id: variantIds,
+ calculated_price: {
+ context: pricingContext,
+ },
},
- },
- throw_if_key_not_found: true,
+ })
})
validateVariantPricesStep({ variants })
@@ -90,11 +101,6 @@ export const createCartWorkflow = createWorkflow(
},
})
- const priceSets = getVariantPriceSetsStep({
- variantIds,
- context: pricingContext,
- })
-
const cartInput = transform(
{ input, region, customerData, salesChannel },
(data) => {
@@ -131,26 +137,34 @@ export const createCartWorkflow = createWorkflow(
}
)
- const lineItems = transform({ priceSets, input, variants }, (data) => {
+ const lineItems = transform({ input, variants }, (data) => {
const items = (data.input.items ?? []).map((item) => {
- const variant = data.variants.find((v) => v.id === item.variant_id)!
+ const variant = (data.variants ?? []).find(
+ (v) => v.id === item.variant_id
+ )!
- return prepareLineItemData({
+ const input: PrepareLineItemDataInput = {
+ item,
variant: variant,
- unitPrice:
- item.unit_price ||
- data.priceSets[item.variant_id].calculated_amount,
+ unitPrice: item.unit_price,
isTaxInclusive:
- item.is_tax_inclusive ||
- data.priceSets[item.variant_id].is_calculated_price_tax_inclusive,
- quantity: item.quantity,
- metadata: item?.metadata ?? {},
- })
+ item.is_tax_inclusive ??
+ variant?.calculated_price?.is_calculated_price_tax_inclusive,
+ isCustomPrice: isDefined(item?.unit_price),
+ }
+
+ if (variant && !input.unitPrice) {
+ input.unitPrice = variant.calculated_price?.calculated_amount
+ }
+
+ return prepareLineItemData(input)
})
return items
})
+ validateLineItemPricesStep({ items: lineItems })
+
const cartToCreate = transform({ lineItems, cartInput }, (data) => {
return {
...data.cartInput,
diff --git a/packages/core/core-flows/src/cart/workflows/refresh-cart-items.ts b/packages/core/core-flows/src/cart/workflows/refresh-cart-items.ts
index ac5724c6c2bb7..722cd2a6252d1 100644
--- a/packages/core/core-flows/src/cart/workflows/refresh-cart-items.ts
+++ b/packages/core/core-flows/src/cart/workflows/refresh-cart-items.ts
@@ -6,6 +6,7 @@ import {
import {
createWorkflow,
transform,
+ when,
WorkflowData,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
@@ -17,7 +18,10 @@ import {
cartFieldsForRefreshSteps,
productVariantsFields,
} from "../utils/fields"
-import { prepareLineItemData } from "../utils/prepare-line-item-data"
+import {
+ prepareLineItemData,
+ PrepareLineItemDataInput,
+} from "../utils/prepare-line-item-data"
import { refreshCartShippingMethodsWorkflow } from "./refresh-cart-shipping-methods"
import { refreshPaymentCollectionForCartWorkflow } from "./refresh-payment-collection"
import { updateCartPromotionsWorkflow } from "./update-cart-promotions"
@@ -43,40 +47,49 @@ export const refreshCartItemsWorkflow = createWorkflow(
})
const variantIds = transform({ cart }, (data) => {
- return (data.cart.items ?? []).map((i) => i.variant_id)
+ return (data.cart.items ?? []).map((i) => i.variant_id).filter(Boolean)
})
const cartPricingContext = transform({ cart }, ({ cart }) => {
return filterObjectByKeys(cart, cartFieldsForPricingContext)
})
- const variants = useRemoteQueryStep({
- entry_point: "variants",
- fields: productVariantsFields,
- variables: {
- id: variantIds,
- calculated_price: {
- context: cartPricingContext,
+ const variants = when({ variantIds }, ({ variantIds }) => {
+ return !!variantIds.length
+ }).then(() => {
+ return useRemoteQueryStep({
+ entry_point: "variants",
+ fields: productVariantsFields,
+ variables: {
+ id: variantIds,
+ calculated_price: {
+ context: cartPricingContext,
+ },
},
- },
- throw_if_key_not_found: true,
- }).config({ name: "fetch-variants" })
+ }).config({ name: "fetch-variants" })
+ })
validateVariantPricesStep({ variants })
const lineItems = transform({ cart, variants }, ({ cart, variants }) => {
const items = cart.items.map((item) => {
- const variant = variants.find((v) => v.id === item.variant_id)!
+ const variant = (variants ?? []).find((v) => v.id === item.variant_id)!
- const preparedItem = prepareLineItemData({
+ const input: PrepareLineItemDataInput = {
+ item,
variant: variant,
- unitPrice: variant.calculated_price.calculated_amount,
- isTaxInclusive:
- variant.calculated_price.is_calculated_price_tax_inclusive,
- quantity: item.quantity,
- metadata: item.metadata,
cartId: cart.id,
- })
+ unitPrice: item.unit_price,
+ isTaxInclusive: item.is_tax_inclusive,
+ }
+
+ if (variant && !item.is_custom_price) {
+ input.unitPrice = variant.calculated_price?.calculated_amount
+ input.isTaxInclusive =
+ variant.calculated_price?.is_calculated_price_tax_inclusive
+ }
+
+ const preparedItem = prepareLineItemData(input)
return {
selector: { id: item.id },
diff --git a/packages/core/core-flows/src/cart/workflows/update-cart.ts b/packages/core/core-flows/src/cart/workflows/update-cart.ts
index 9114ed6f574cd..2733ea15958f9 100644
--- a/packages/core/core-flows/src/cart/workflows/update-cart.ts
+++ b/packages/core/core-flows/src/cart/workflows/update-cart.ts
@@ -16,7 +16,12 @@ import {
WorkflowData,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
-import { emitEventStep, useRemoteQueryStep } from "../../common"
+import {
+ emitEventStep,
+ useQueryGraphStep,
+ useRemoteQueryStep,
+} from "../../common"
+import { deleteLineItemsStep } from "../../line-item"
import {
findOrCreateCustomerStep,
findSalesChannelStep,
@@ -167,11 +172,18 @@ export const updateCartWorkflow = createWorkflow(
})
*/
- when({ input, cartToUpdate }, ({ input, cartToUpdate }) => {
- return (
- isDefined(input.region_id) &&
- input.region_id !== cartToUpdate?.region?.id
- )
+ const regionUpdated = transform(
+ { input, cartToUpdate },
+ ({ input, cartToUpdate }) => {
+ return (
+ isDefined(input.region_id) &&
+ input.region_id !== cartToUpdate?.region?.id
+ )
+ }
+ )
+
+ when({ regionUpdated }, ({ regionUpdated }) => {
+ return !!regionUpdated
}).then(() => {
emitEventStep({
eventName: CartWorkflowEvents.REGION_UPDATED,
@@ -187,6 +199,27 @@ export const updateCartWorkflow = createWorkflow(
})
)
+ // In case the region is updated, we might have a new currency OR tax inclusivity setting
+ // Therefore, we need to delete line items with a custom price for good measure
+ when({ regionUpdated }, ({ regionUpdated }) => {
+ return !!regionUpdated
+ }).then(() => {
+ const lineItems = useQueryGraphStep({
+ entity: "line_items",
+ filters: {
+ cart_id: input.id,
+ is_custom_price: true,
+ },
+ fields: ["id"],
+ })
+
+ const lineItemIds = transform({ lineItems }, ({ lineItems }) => {
+ return lineItems.data.map((i) => i.id)
+ })
+
+ deleteLineItemsStep(lineItemIds)
+ })
+
const cart = refreshCartItemsWorkflow.runAsStep({
input: { cart_id: cartInput.id, promo_codes: input.promo_codes },
})
diff --git a/packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts b/packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts
index 95f6e359af115..630f085d5d5f6 100644
--- a/packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts
+++ b/packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts
@@ -1,8 +1,10 @@
import { UpdateLineItemInCartWorkflowInputDTO } from "@medusajs/framework/types"
+import { isDefined, MedusaError } from "@medusajs/framework/utils"
import {
- WorkflowData,
createWorkflow,
transform,
+ when,
+ WorkflowData,
} from "@medusajs/framework/workflows-sdk"
import { useQueryGraphStep } from "../../common"
import { useRemoteQueryStep } from "../../common/steps/use-remote-query"
@@ -40,19 +42,22 @@ export const updateLineItemInCartWorkflow = createWorkflow(
validateCartStep({ cart })
const variantIds = transform({ item }, ({ item }) => {
- return [item.variant_id]
+ return [item.variant_id].filter(Boolean)
})
- const variants = useRemoteQueryStep({
- entry_point: "variants",
- fields: productVariantsFields,
- variables: {
- id: variantIds,
- calculated_price: {
- context: cart,
+ const variants = when({ variantIds }, ({ variantIds }) => {
+ return !!variantIds.length
+ }).then(() => {
+ return useRemoteQueryStep({
+ entry_point: "variants",
+ fields: productVariantsFields,
+ variables: {
+ id: variantIds,
+ calculated_price: {
+ context: cart,
+ },
},
- },
- throw_if_key_not_found: true,
+ }).config({ name: "fetch-variants" })
})
validateVariantPricesStep({ variants })
@@ -69,16 +74,36 @@ export const updateLineItemInCartWorkflow = createWorkflow(
},
})
- const lineItemUpdate = transform({ input, variants }, (data) => {
- const variant = data.variants[0]
+ const lineItemUpdate = transform({ input, variants, item }, (data) => {
+ const variant = data.variants?.[0] ?? undefined
+ const item = data.item
+
+ const updateData = {
+ ...data.input.update,
+ unit_price: isDefined(data.input.update.unit_price)
+ ? data.input.update.unit_price
+ : item.unit_price,
+ is_custom_price: isDefined(data.input.update.unit_price)
+ ? true
+ : item.is_custom_price,
+ is_tax_inclusive:
+ item.is_tax_inclusive ||
+ variant?.calculated_price?.is_calculated_price_tax_inclusive,
+ }
+
+ if (variant && !updateData.is_custom_price) {
+ updateData.unit_price = variant.calculated_price.calculated_amount
+ }
+
+ if (!isDefined(updateData.unit_price)) {
+ throw new MedusaError(
+ MedusaError.Types.INVALID_DATA,
+ `Line item ${item.title} has no unit price`
+ )
+ }
return {
- data: {
- ...data.input.update,
- unit_price: variant.calculated_price.calculated_amount,
- is_tax_inclusive:
- !!variant.calculated_price.is_calculated_price_tax_inclusive,
- },
+ data: updateData,
selector: {
id: data.input.item_id,
},
diff --git a/packages/core/core-flows/src/common/steps/use-remote-query.ts b/packages/core/core-flows/src/common/steps/use-remote-query.ts
index 27045d394c952..6392745c31fc7 100644
--- a/packages/core/core-flows/src/common/steps/use-remote-query.ts
+++ b/packages/core/core-flows/src/common/steps/use-remote-query.ts
@@ -53,9 +53,9 @@ export const useRemoteQueryStepId = "use-remote-query"
* Learn more in the [Remote Query documentation](https://docs.medusajs.com/learn/fundamentals/module-links/query).
*
* :::note
- *
+ *
* This step is deprecated. Use {@link useQueryGraphStep} instead.
- *
+ *
* :::
*
* @example
diff --git a/packages/core/core-flows/src/order/utils/prepare-custom-line-item-data.ts b/packages/core/core-flows/src/order/utils/prepare-custom-line-item-data.ts
deleted file mode 100644
index 16410cd31bc95..0000000000000
--- a/packages/core/core-flows/src/order/utils/prepare-custom-line-item-data.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import {
- BigNumberInput,
- CreateOrderAdjustmentDTO,
- CreateOrderLineItemTaxLineDTO,
-} from "@medusajs/framework/types"
-import {
- prepareAdjustmentsData,
- prepareTaxLinesData,
-} from "../../cart/utils/prepare-line-item-data"
-
-interface Input {
- quantity: BigNumberInput
- metadata?: Record
- unitPrice: BigNumberInput
- isTaxInclusive?: boolean
- taxLines?: CreateOrderLineItemTaxLineDTO[]
- adjustments?: CreateOrderAdjustmentDTO[]
- variant: {
- title: string
- sku?: string
- barcode?: string
- }
-}
-
-interface Output {
- quantity: BigNumberInput
- title: string
- variant_sku?: string
- variant_barcode?: string
- variant_title?: string
- unit_price: BigNumberInput
- is_tax_inclusive: boolean
- metadata?: Record
-}
-
-export function prepareCustomLineItemData(data: Input): Output {
- const {
- variant,
- unitPrice,
- isTaxInclusive,
- quantity,
- metadata,
- taxLines,
- adjustments,
- } = data
-
- const lineItem: any = {
- quantity,
- title: variant.title,
- variant_sku: variant.sku,
- variant_barcode: variant.barcode,
- variant_title: variant.title,
-
- unit_price: unitPrice,
- is_tax_inclusive: !!isTaxInclusive,
- metadata,
- }
-
- if (taxLines) {
- lineItem.tax_lines = prepareTaxLinesData(taxLines)
- }
-
- if (adjustments) {
- lineItem.adjustments = prepareAdjustmentsData(adjustments)
- }
-
- return lineItem
-}
diff --git a/packages/core/core-flows/src/order/workflows/add-line-items.ts b/packages/core/core-flows/src/order/workflows/add-line-items.ts
index ce7f2dfb2d2b7..3ac6d2f0df3de 100644
--- a/packages/core/core-flows/src/order/workflows/add-line-items.ts
+++ b/packages/core/core-flows/src/order/workflows/add-line-items.ts
@@ -1,59 +1,48 @@
import { OrderLineItemDTO, OrderWorkflow } from "@medusajs/framework/types"
-import { MathBN, MedusaError } from "@medusajs/framework/utils"
+import { isDefined, MedusaError } from "@medusajs/framework/utils"
import {
- WorkflowData,
- WorkflowResponse,
createWorkflow,
parallelize,
transform,
+ when,
+ WorkflowData,
+ WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import { findOneOrAnyRegionStep } from "../../cart/steps/find-one-or-any-region"
import { findOrCreateCustomerStep } from "../../cart/steps/find-or-create-customer"
import { findSalesChannelStep } from "../../cart/steps/find-sales-channel"
-import { getVariantPriceSetsStep } from "../../cart/steps/get-variant-price-sets"
+import { validateLineItemPricesStep } from "../../cart/steps/validate-line-item-prices"
import { validateVariantPricesStep } from "../../cart/steps/validate-variant-prices"
-import { prepareLineItemData } from "../../cart/utils/prepare-line-item-data"
+import {
+ prepareLineItemData,
+ PrepareLineItemDataInput,
+} from "../../cart/utils/prepare-line-item-data"
import { confirmVariantInventoryWorkflow } from "../../cart/workflows/confirm-variant-inventory"
import { useRemoteQueryStep } from "../../common"
import { createOrderLineItemsStep } from "../steps"
import { productVariantsFields } from "../utils/fields"
-import { prepareCustomLineItemData } from "../utils/prepare-custom-line-item-data"
function prepareLineItems(data) {
const items = (data.input.items ?? []).map((item) => {
const variant = data.variants.find((v) => v.id === item.variant_id)!
- if (!variant) {
- return prepareCustomLineItemData({
- variant: {
- ...item,
- },
- unitPrice: MathBN.max(0, item.unit_price),
- isTaxInclusive:
- item.is_tax_inclusive ??
- data.priceSets[item.variant_id!]?.is_calculated_price_tax_inclusive,
- quantity: item.quantity as number,
- metadata: item?.metadata,
- taxLines: item.tax_lines || [],
- adjustments: item.adjustments || [],
- })
- }
-
- return prepareLineItemData({
+ const input: PrepareLineItemDataInput = {
+ item,
variant: variant,
- unitPrice: MathBN.max(
- 0,
- item.unit_price ??
- data.priceSets[item.variant_id!]?.raw_calculated_amount
- ),
+ unitPrice: item.unit_price,
isTaxInclusive:
item.is_tax_inclusive ??
- data.priceSets[item.variant_id!]?.is_calculated_price_tax_inclusive,
- quantity: item.quantity as number,
- metadata: item?.metadata,
+ variant?.calculated_price?.is_calculated_price_tax_inclusive,
+ isCustomPrice: isDefined(item?.unit_price),
taxLines: item.tax_lines || [],
adjustments: item.adjustments || [],
- })
+ }
+
+ if (variant && !input.unitPrice) {
+ input.unitPrice = variant.calculated_price?.calculated_amount
+ }
+
+ return prepareLineItemData(input)
})
return items
@@ -117,17 +106,20 @@ export const addOrderLineItemsWorkflow = createWorkflow(
}
)
- const variants = useRemoteQueryStep({
- entry_point: "variants",
- fields: productVariantsFields,
- variables: {
- id: variantIds,
- calculated_price: {
- context: pricingContext,
+ const variants = when({ variantIds }, ({ variantIds }) => {
+ return !!variantIds.length
+ }).then(() => {
+ return useRemoteQueryStep({
+ entry_point: "variants",
+ fields: productVariantsFields,
+ variables: {
+ id: variantIds,
+ calculated_price: {
+ context: pricingContext,
+ },
},
- },
- throw_if_key_not_found: true,
- }).config({ name: "variants-query" })
+ })
+ })
validateVariantPricesStep({ variants })
@@ -139,15 +131,9 @@ export const addOrderLineItemsWorkflow = createWorkflow(
},
})
- const priceSets = getVariantPriceSetsStep({
- variantIds,
- context: pricingContext,
- })
+ const lineItems = transform({ input, variants }, prepareLineItems)
- const lineItems = transform(
- { priceSets, input, variants },
- prepareLineItems
- )
+ validateLineItemPricesStep({ items: lineItems })
return new WorkflowResponse(
createOrderLineItemsStep({
diff --git a/packages/core/core-flows/src/order/workflows/create-order.ts b/packages/core/core-flows/src/order/workflows/create-order.ts
index 80a015051143c..4ccd369b275b0 100644
--- a/packages/core/core-flows/src/order/workflows/create-order.ts
+++ b/packages/core/core-flows/src/order/workflows/create-order.ts
@@ -1,5 +1,5 @@
import { AdditionalData, CreateOrderDTO } from "@medusajs/framework/types"
-import { MathBN, MedusaError, isPresent } from "@medusajs/framework/utils"
+import { MedusaError, isDefined, isPresent } from "@medusajs/framework/utils"
import {
WorkflowData,
WorkflowResponse,
@@ -7,51 +7,44 @@ import {
createWorkflow,
parallelize,
transform,
+ when,
} from "@medusajs/framework/workflows-sdk"
import { findOneOrAnyRegionStep } from "../../cart/steps/find-one-or-any-region"
import { findOrCreateCustomerStep } from "../../cart/steps/find-or-create-customer"
import { findSalesChannelStep } from "../../cart/steps/find-sales-channel"
-import { getVariantPriceSetsStep } from "../../cart/steps/get-variant-price-sets"
+import { validateLineItemPricesStep } from "../../cart/steps/validate-line-item-prices"
import { validateVariantPricesStep } from "../../cart/steps/validate-variant-prices"
-import { prepareLineItemData } from "../../cart/utils/prepare-line-item-data"
+import {
+ PrepareLineItemDataInput,
+ prepareLineItemData,
+} from "../../cart/utils/prepare-line-item-data"
import { confirmVariantInventoryWorkflow } from "../../cart/workflows/confirm-variant-inventory"
import { useRemoteQueryStep } from "../../common"
import { createOrdersStep } from "../steps"
import { productVariantsFields } from "../utils/fields"
-import { prepareCustomLineItemData } from "../utils/prepare-custom-line-item-data"
import { updateOrderTaxLinesWorkflow } from "./update-tax-lines"
function prepareLineItems(data) {
const items = (data.input.items ?? []).map((item) => {
const variant = data.variants.find((v) => v.id === item.variant_id)!
- if (!variant) {
- return prepareCustomLineItemData({
- variant: {
- ...item,
- },
- unitPrice: MathBN.max(0, item.unit_price),
- isTaxInclusive: item.is_tax_inclusive,
- quantity: item.quantity as number,
- metadata: item?.metadata ?? {},
- })
- }
-
- return prepareLineItemData({
+ const input: PrepareLineItemDataInput = {
+ item,
variant: variant,
- unitPrice: MathBN.max(
- 0,
- item.unit_price ??
- data.priceSets[item.variant_id!]?.raw_calculated_amount
- ),
+ unitPrice: item.unit_price ?? undefined,
isTaxInclusive:
item.is_tax_inclusive ??
- data.priceSets[item.variant_id!]?.is_calculated_price_tax_inclusive,
- quantity: item.quantity as number,
- metadata: item?.metadata ?? {},
+ variant?.calculated_price?.is_calculated_price_tax_inclusive,
+ isCustomPrice: isDefined(item?.unit_price),
taxLines: item.tax_lines || [],
adjustments: item.adjustments || [],
- })
+ }
+
+ if (variant && !input.unitPrice) {
+ input.unitPrice = variant.calculated_price?.calculated_amount
+ }
+
+ return prepareLineItemData(input)
})
return items
@@ -126,16 +119,19 @@ export const createOrderWorkflow = createWorkflow(
}
)
- const variants = useRemoteQueryStep({
- entry_point: "variants",
- fields: productVariantsFields,
- variables: {
- id: variantIds,
- calculated_price: {
- context: pricingContext,
+ const variants = when({ variantIds }, ({ variantIds }) => {
+ return !!variantIds.length
+ }).then(() => {
+ return useRemoteQueryStep({
+ entry_point: "variants",
+ fields: productVariantsFields,
+ variables: {
+ id: variantIds,
+ calculated_price: {
+ context: pricingContext,
+ },
},
- },
- throw_if_key_not_found: true,
+ })
})
validateVariantPricesStep({ variants })
@@ -148,20 +144,14 @@ export const createOrderWorkflow = createWorkflow(
},
})
- const priceSets = getVariantPriceSetsStep({
- variantIds,
- context: pricingContext,
- })
-
const orderInput = transform(
{ input, region, customerData, salesChannel },
getOrderInput
)
- const lineItems = transform(
- { priceSets, input, variants },
- prepareLineItems
- )
+ const lineItems = transform({ input, variants }, prepareLineItems)
+
+ validateLineItemPricesStep({ items: lineItems })
const orderToCreate = transform({ lineItems, orderInput }, (data) => {
return {
diff --git a/packages/core/types/src/cart/common.ts b/packages/core/types/src/cart/common.ts
index d066c491468b4..87f063beec0fe 100644
--- a/packages/core/types/src/cart/common.ts
+++ b/packages/core/types/src/cart/common.ts
@@ -663,6 +663,11 @@ export interface CartLineItemDTO extends CartLineItemTotalsDTO {
*/
is_tax_inclusive: boolean
+ /**
+ * Whether the line item price is a custom price.
+ */
+ is_custom_price: boolean
+
/**
* The calculated price of the line item.
*/
diff --git a/packages/core/types/src/cart/mutations.ts b/packages/core/types/src/cart/mutations.ts
index 3d51cd8cb6051..d961b57b53e6b 100644
--- a/packages/core/types/src/cart/mutations.ts
+++ b/packages/core/types/src/cart/mutations.ts
@@ -555,6 +555,11 @@ export interface CreateLineItemDTO {
*/
is_tax_inclusive?: boolean
+ /**
+ * Whether the line item's amount is a custom price.
+ */
+ is_custom_price?: boolean
+
/**
* The calculated price of the line item after applying promotions.
*/
diff --git a/packages/core/types/src/cart/workflows.ts b/packages/core/types/src/cart/workflows.ts
index c5f94c36fa111..194e575fef297 100644
--- a/packages/core/types/src/cart/workflows.ts
+++ b/packages/core/types/src/cart/workflows.ts
@@ -13,7 +13,7 @@ import {
export interface CreateCartCreateLineItemDTO {
quantity: BigNumberInput
- variant_id: string
+ variant_id?: string
title?: string
subtitle?: string
diff --git a/packages/core/utils/src/common/deep-flat-map.ts b/packages/core/utils/src/common/deep-flat-map.ts
index 3be83e3a174db..e1336c810ed73 100644
--- a/packages/core/utils/src/common/deep-flat-map.ts
+++ b/packages/core/utils/src/common/deep-flat-map.ts
@@ -68,7 +68,7 @@ export function deepFlatMap(
const currentKey = path[0]
const remainingPath = path.slice(1)
- if (!isDefined(element[currentKey])) {
+ if (!isDefined(element?.[currentKey])) {
callback({ ...context })
continue
}
diff --git a/packages/medusa/src/api/admin/draft-orders/validators.ts b/packages/medusa/src/api/admin/draft-orders/validators.ts
index 4581538f97f3a..800f1579122fe 100644
--- a/packages/medusa/src/api/admin/draft-orders/validators.ts
+++ b/packages/medusa/src/api/admin/draft-orders/validators.ts
@@ -37,23 +37,25 @@ const ShippingMethod = z.object({
amount: BigNumberInput,
})
-const Item = z
- .object({
- title: z.string().nullish(),
- sku: z.string().nullish(),
- barcode: z.string().nullish(),
- variant_id: z.string().nullish(),
- unit_price: BigNumberInput.nullish(),
- quantity: z.number(),
- metadata: z.record(z.unknown()).nullish(),
- })
- .refine((data) => {
- if (!data.variant_id) {
- return data.title && (data.sku || data.barcode)
- }
-
- return true
- })
+const Item = z.object({
+ title: z.string().nullish(),
+ variant_sku: z.string().nullish(),
+ variant_barcode: z.string().nullish(),
+ /**
+ * Use variant_sku instead
+ * @deprecated
+ */
+ sku: z.string().nullish(),
+ /**
+ * Use variant_barcode instead
+ * @deprecated
+ */
+ barcode: z.string().nullish(),
+ variant_id: z.string().nullish(),
+ unit_price: BigNumberInput.nullish(),
+ quantity: z.number(),
+ metadata: z.record(z.unknown()).nullish(),
+})
export type AdminCreateDraftOrderType = z.infer
const CreateDraftOrder = z
diff --git a/packages/modules/cart/integration-tests/__tests__/services/cart-module/index.spec.ts b/packages/modules/cart/integration-tests/__tests__/services/cart-module/index.spec.ts
index 5d276268af8d6..4977a3e0dd396 100644
--- a/packages/modules/cart/integration-tests/__tests__/services/cart-module/index.spec.ts
+++ b/packages/modules/cart/integration-tests/__tests__/services/cart-module/index.spec.ts
@@ -2512,6 +2512,7 @@ moduleIntegrationTestRunner({
requires_shipping: true,
is_discountable: true,
is_tax_inclusive: false,
+ is_custom_price: false,
raw_compare_at_unit_price: null,
raw_unit_price: {
value: "100",
@@ -2617,6 +2618,7 @@ moduleIntegrationTestRunner({
requires_shipping: true,
is_discountable: true,
is_tax_inclusive: false,
+ is_custom_price: false,
raw_compare_at_unit_price: null,
raw_unit_price: {
value: "200",
diff --git a/packages/modules/cart/src/migrations/.snapshot-medusa-cart.json b/packages/modules/cart/src/migrations/.snapshot-medusa-cart.json
index 1b02c64962622..bcdc0b173dc73 100644
--- a/packages/modules/cart/src/migrations/.snapshot-medusa-cart.json
+++ b/packages/modules/cart/src/migrations/.snapshot-medusa-cart.json
@@ -617,6 +617,16 @@
"default": "false",
"mappedType": "boolean"
},
+ "is_custom_price": {
+ "name": "is_custom_price",
+ "type": "boolean",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "default": "false",
+ "mappedType": "boolean"
+ },
"compare_at_unit_price": {
"name": "compare_at_unit_price",
"type": "numeric",
diff --git a/packages/modules/cart/src/migrations/Migration20241218091938.ts b/packages/modules/cart/src/migrations/Migration20241218091938.ts
new file mode 100644
index 0000000000000..d4314e8c5cd3c
--- /dev/null
+++ b/packages/modules/cart/src/migrations/Migration20241218091938.ts
@@ -0,0 +1,13 @@
+import { Migration } from '@mikro-orm/migrations';
+
+export class Migration20241218091938 extends Migration {
+
+ async up(): Promise {
+ this.addSql('alter table if exists "cart_line_item" add column if not exists "is_custom_price" boolean not null default false;');
+ }
+
+ async down(): Promise {
+ this.addSql('alter table if exists "cart_line_item" drop column if exists "is_custom_price";');
+ }
+
+}
diff --git a/packages/modules/cart/src/models/line-item.ts b/packages/modules/cart/src/models/line-item.ts
index b37a13211d148..65d842b5402d6 100644
--- a/packages/modules/cart/src/models/line-item.ts
+++ b/packages/modules/cart/src/models/line-item.ts
@@ -1,7 +1,7 @@
import { model } from "@medusajs/framework/utils"
import Cart from "./cart"
-import LineItemTaxLine from "./line-item-tax-line"
import LineItemAdjustment from "./line-item-adjustment"
+import LineItemTaxLine from "./line-item-tax-line"
const LineItem = model
.define(
@@ -28,6 +28,7 @@ const LineItem = model
requires_shipping: model.boolean().default(true),
is_discountable: model.boolean().default(true),
is_tax_inclusive: model.boolean().default(false),
+ is_custom_price: model.boolean().default(false),
compare_at_unit_price: model.bigNumber().nullable(),
unit_price: model.bigNumber(),
metadata: model.json().nullable(),
From c7008bb569292f0e56aecb10b86e4b2d15b96878 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Frane=20Poli=C4=87?=
<16856471+fPolic@users.noreply.github.com>
Date: Wed, 18 Dec 2024 12:56:18 +0100
Subject: [PATCH 4/5] fix: order details status (#10650)
---
.../order-general-section/order-general-section.tsx | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/packages/admin/dashboard/src/routes/orders/order-detail/components/order-general-section/order-general-section.tsx b/packages/admin/dashboard/src/routes/orders/order-detail/components/order-general-section/order-general-section.tsx
index ac8f9e00970a3..e32ae907e3635 100644
--- a/packages/admin/dashboard/src/routes/orders/order-detail/components/order-general-section/order-general-section.tsx
+++ b/packages/admin/dashboard/src/routes/orders/order-detail/components/order-general-section/order-general-section.tsx
@@ -61,7 +61,6 @@ export const OrderGeneralSection = ({ order }: OrderGeneralSectionProps) => {
- {/*TODO: SHOW ORDER STATUS INSTEAD OF FULFILLMENT STATUS HERE - if the last fulfillment is canceled it looks like the order is canceled*/}
{
{
label: t("actions.cancel"),
onClick: handleCancel,
+ disabled: !!order.canceled_at,
icon: ,
},
],
@@ -100,11 +100,6 @@ const FulfillmentBadge = ({ order }: { order: HttpTypes.AdminOrder }) => {
const PaymentBadge = ({ order }: { order: HttpTypes.AdminOrder }) => {
const { t } = useTranslation()
- /**
- * TODO: revisit when Order<>Payment are linked
- */
- return null
-
const { label, color } = getOrderPaymentStatus(t, order.payment_status)
return (
From 9133957a947b80d9a466727eb5c33ab5105c1db2 Mon Sep 17 00:00:00 2001
From: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
Date: Wed, 18 Dec 2024 13:59:12 +0100
Subject: [PATCH 5/5] fix(notification): Only use enabled providers for notis
(#10659)
---
.../notification/src/services/notification-provider.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/packages/modules/notification/src/services/notification-provider.ts b/packages/modules/notification/src/services/notification-provider.ts
index adb07b7904a5d..26fdb3f81b15c 100644
--- a/packages/modules/notification/src/services/notification-provider.ts
+++ b/packages/modules/notification/src/services/notification-provider.ts
@@ -68,7 +68,9 @@ export default class NotificationProviderService extends ModulesSdkUtils.MedusaI
TOutput = TChannel extends string[] ? Provider[] : Provider | undefined
>(channels: TChannel): Promise {
if (!this.providersCache) {
- const providers = await this.notificationProviderRepository_.find()
+ const providers = await this.notificationProviderRepository_.find({
+ where: { is_enabled: true },
+ })
this.providersCache = new Map(
providers.flatMap((provider) =>