docs: document conditional shipping option prices + expand on price rules (#12217)

* docs: document conditional shipping option prices + expand on price rules

* fix errors
This commit is contained in:
Shahed Nasser
2025-04-17 17:52:10 +03:00
committed by GitHub
parent e180253d60
commit c9fd0422c8
13 changed files with 14318 additions and 13984 deletions
File diff suppressed because it is too large Load Diff
@@ -34,6 +34,12 @@ Service zones can be more restrictive, such as restricting to certain cities or
You can restrict shipping options by custom rules, such as the items weight or the customers group.
<Note title="Tip">
You can also restrict a shipping option's price based on specific conditions. For example, you can make a shipping option's price free based on the cart's total. Learn more in the Pricing Module's [Price Rules](../../pricing/price-rules/page.mdx#how-to-set-rules-on-a-price) guide.
</Note>
These rules are represented by the [ShippingOptionRule data model](/references/fulfillment/models/ShippingOptionRule). Its properties define the custom rule:
- `attribute`: The name of a property or table that the rule applies to. For example, `customer_group`.
@@ -1,10 +1,19 @@
---
tags:
- name: product
label: "Variant Price Rules"
- name: fulfillment
label: "Shipping Option Price Rules"
- concept
---
export const metadata = {
title: `Price Rules`,
}
# {metadata.title}
In this document, you'll learn about price rules for price sets and price lists.
In this Pricing Module guide, you'll learn about price rules for price sets and price lists, and how to add rules to a price.
## Price Rule
@@ -31,3 +40,142 @@ Rules applied to a price list are represented by the [PriceListRule data model](
The `rules_count` property of a `PriceList` indicates how many rules are applied to it.
![A diagram showcasing the relation between the PriceSet, PriceList, Price, RuleType, and PriceListRuleValue](https://res.cloudinary.com/dza7lstvk/image/upload/v1709641999/Medusa%20Resources/price-list_zd10yd.jpg)
---
## How to Set Rules on a Price?
### Using Workflows
Medusa uses the Pricing Module to store prices of different resources, such as product variants and shipping options.
When you manage one of these resources using [Medusa's workflows](../../../medusa-workflows-reference/page.mdx) or using the API routes that use them, you can set rules on a price using the `rules` property of the price object.
For example, when creating a shipping option using the [createShippingOptionsWorkflow](!resources!/references/medusa-workflows/createShippingOptionsWorkflow) to create a shipping option, you can make the shipping price free based on the cart total:
export const workflowHighlights = [
["19", "rules", "The default price doesn't have rules."],
["26", "item_total", "Apply the price if the cart or order's total matches the condition."]
]
```ts highlights={workflowHighlights}
const { result } = await createShippingOptionsWorkflow(container)
.run({
input: [{
name: "Standard Shipping",
service_zone_id: "serzo_123",
shipping_profile_id: "sp_123",
provider_id: "prov_123",
type: {
label: "Standard",
description: "Standard shipping",
code: "standard",
},
price_type: "flat",
prices: [
// default price
{
currency_code: "usd",
amount: 10,
rules: {},
},
// price if cart total >= $100
{
currency_code: "usd",
amount: 0,
rules: {
item_total: {
operator: "gte",
value: 100,
},
},
},
],
}],
})
```
In this example, you create a shipping option whose default price is `$10`. When the total of the cart or order using this shipping option is greater than `$100`, the shipping option's price becomes free.
### Using Pricing Module's Service
<Note>
For most use cases, it's recommended to use [workflows](#using-workflows) instead of directly using the module's service.
</Note>
When adding a price using the [addPrices](!resources!/references/pricing/addPrices) method of the Pricing Module's service, pass the `rules` property to a price object.
For example:
```ts
const priceSet = await pricingModule.addPrices({
priceSetId: "pset_1",
prices: [
// default price
{
currency_code: "usd",
amount: 10,
rules: {},
},
// price if cart total >= $100
{
currency_code: "usd",
amount: 0,
rules: {
item_total: {
operator: "gte",
value: 100,
},
},
},
],
})
```
In this example, you set the default price of a resource (for example, a shipping option), to `$10`. You also add a conditioned price that sets the price to `0` when the cart or order's total is greater than or equal to `$100`.
### How is the Price Rule Applied?
The [price calculation](../price-calculation/page.mdx) mechanism considers a price applicable when the resource that this price is in matches the specified rules.
For example, a [cart object](!api!/store#carts_cart_schema) has an `item_total` property. So, if a shipping option has the following price:
```json
{
"currency_code": "usd",
"amount": 0,
"rules": {
"item_total": {
"operator": "gte",
"value": 100,
}
}
}
```
The shipping option's price is applied when the cart's `item_total` is greater than or equal to `$100`.
You can also apply the rule on nested relations and properties. For example, to apply a shipping option's price based on the customer's group, you can apply a rule on the `customer.group.id` attribute:
```json
{
"currency_code": "usd",
"amount": 0,
"rules": {
"customer.group.id": {
"operator": "eq",
"value": "cusgrp_123"
}
}
}
```
In this example, the price is only applied if a cart's customer belongs to the customer group of ID `cusgrp_123`.
<Note>
These same rules apply to product variant prices as well, or any other resource that has a price.
</Note>
@@ -628,7 +628,7 @@ export const deductStepHighlights = [
```ts title="src/workflows/steps/deduct-purchase-points.ts" highlights={deductStepHighlights} collapsibleLines="1-7" expandButtonLabel="Show Imports"
import {
createStep,
StepResponse
StepResponse,
} from "@medusajs/framework/workflows-sdk"
import { LOYALTY_MODULE } from "../../modules/loyalty"
import LoyaltyModuleService from "../../modules/loyalty/service"
@@ -641,7 +641,7 @@ type DeductPurchasePointsInput = {
export const deductPurchasePointsStep = createStep(
"deduct-purchase-points",
async ({
customer_id, amount
customer_id, amount,
}: DeductPurchasePointsInput, { container }) => {
const loyaltyModuleService: LoyaltyModuleService = container.resolve(
LOYALTY_MODULE
@@ -658,7 +658,7 @@ export const deductPurchasePointsStep = createStep(
return new StepResponse(result, {
customer_id,
points: pointsToDeduct
points: pointsToDeduct,
})
},
async (data, { container }) => {
@@ -748,7 +748,7 @@ export const addPurchaseAsPointsStep = createStep(
return new StepResponse(result, {
customer_id: input.customer_id,
points: pointsToAdd
points: pointsToAdd,
})
},
async (data, { container }) => {
@@ -868,18 +868,18 @@ export const handleOrderPointsWorkflow = createWorkflow(
"cart.promotions.*",
"cart.promotions.rules.*",
"cart.promotions.rules.values.*",
"cart.promotions.application_method.*"
"cart.promotions.application_method.*",
],
filters: {
id: order_id
id: order_id,
},
options: {
throwIfKeyNotFound: true
}
throwIfKeyNotFound: true,
},
})
validateCustomerExistsStep({
customer: orders[0].customer
customer: orders[0].customer,
} as ValidateCustomerExistsStepInput)
const loyaltyPointsPromotion = getCartLoyaltyPromoStep({
@@ -893,14 +893,14 @@ export const handleOrderPointsWorkflow = createWorkflow(
.then(() => {
deductPurchasePointsStep({
customer_id: orders[0].customer!.id,
amount: loyaltyPointsPromotion.application_method!.value as number
amount: loyaltyPointsPromotion.application_method!.value as number,
})
updatePromotionsStep([
{
id: loyaltyPointsPromotion.id,
status: "inactive",
}
},
])
})
@@ -912,7 +912,7 @@ export const handleOrderPointsWorkflow = createWorkflow(
.then(() => {
addPurchaseAsPointsStep({
customer_id: orders[0].customer!.id,
amount: orders[0].total
amount: orders[0].total,
})
})
}
@@ -1056,10 +1056,10 @@ So, to create an API route at the path `/store/customers/me/loyalty-points`, cre
import {
AuthenticatedMedusaRequest,
MedusaResponse
} from "@medusajs/framework/http";
import { LOYALTY_MODULE } from "../../../../../modules/loyalty";
import LoyaltyModuleService from "../../../../../modules/loyalty/service";
MedusaResponse,
} from "@medusajs/framework/http"
import { LOYALTY_MODULE } from "../../../../../modules/loyalty"
import LoyaltyModuleService from "../../../../../modules/loyalty/service"
export async function GET(
req: AuthenticatedMedusaRequest,
@@ -1405,17 +1405,17 @@ import {
createPromotionsStep,
updateCartPromotionsWorkflow,
updateCartsStep,
useQueryGraphStep
useQueryGraphStep,
} from "@medusajs/medusa/core-flows"
import {
validateCustomerExistsStep,
ValidateCustomerExistsStepInput
ValidateCustomerExistsStepInput,
} from "./steps/validate-customer-exists"
import {
getCartLoyaltyPromoAmountStep,
GetCartLoyaltyPromoAmountStepInput
GetCartLoyaltyPromoAmountStepInput,
} from "./steps/get-cart-loyalty-promo-amount"
import { CartData, CUSTOMER_ID_PROMOTION_RULE_ATTRIBUTE, } from "../utils/promo"
import { CartData, CUSTOMER_ID_PROMOTION_RULE_ATTRIBUTE } from "../utils/promo"
import { CreatePromotionDTO } from "@medusajs/framework/types"
import { PromotionActions } from "@medusajs/framework/utils"
import { getCartLoyaltyPromoStep } from "./steps/get-cart-loyalty-promo"
@@ -1433,7 +1433,7 @@ const fields = [
"promotions.rules.values.*",
"currency_code",
"total",
"metadata"
"metadata",
]
export const applyLoyaltyOnCartWorkflow = createWorkflow(
@@ -1444,24 +1444,24 @@ export const applyLoyaltyOnCartWorkflow = createWorkflow(
entity: "cart",
fields,
filters: {
id: input.cart_id
id: input.cart_id,
},
options: {
throwIfKeyNotFound: true
}
throwIfKeyNotFound: true,
},
})
validateCustomerExistsStep({
customer: carts[0].customer
customer: carts[0].customer,
} as ValidateCustomerExistsStepInput)
getCartLoyaltyPromoStep({
cart: carts[0] as unknown as CartData,
throwErrorOn: "found"
throwErrorOn: "found",
})
const amount = getCartLoyaltyPromoAmountStep({
cart: carts[0]
cart: carts[0],
} as unknown as GetCartLoyaltyPromoAmountStepInput)
// TODO create and apply the promotion on the cart
@@ -1491,7 +1491,7 @@ export const prepareLoyaltyPromoDataHighlights = [
```ts title="src/workflows/apply-loyalty-on-cart.ts" highlights={prepareLoyaltyPromoDataHighlights}
const promoToCreate = transform({
carts,
amount
amount,
}, (data) => {
const randomStr = Math.random().toString(36).substring(2, 8)
const uniqueId = (
@@ -1512,8 +1512,8 @@ const promoToCreate = transform({
{
attribute: CUSTOMER_ID_PROMOTION_RULE_ATTRIBUTE,
operator: "eq",
values: [data.carts[0].customer!.id]
}
values: [data.carts[0].customer!.id],
},
],
campaign: {
name: uniqueId,
@@ -1521,9 +1521,9 @@ const promoToCreate = transform({
campaign_identifier: uniqueId,
budget: {
type: "usage",
limit: 1
}
}
limit: 1,
},
},
}
})
@@ -1559,17 +1559,17 @@ export const createLoyaltyPromoStepHighlights = [
```ts title="src/workflows/apply-loyalty-on-cart.ts" highlights={createLoyaltyPromoStepHighlights}
const loyaltyPromo = createPromotionsStep([
promoToCreate
promoToCreate,
] as CreatePromotionDTO[])
const { metadata, ...updatePromoData } = transform({
carts,
promoToCreate,
loyaltyPromo
loyaltyPromo,
}, (data) => {
const promos = [
...(data.carts[0].promotions?.map((promo) => promo?.code).filter(Boolean) || []) as string[],
data.promoToCreate.code
data.promoToCreate.code,
]
return {
@@ -1577,20 +1577,20 @@ const { metadata, ...updatePromoData } = transform({
promo_codes: promos,
action: PromotionActions.ADD,
metadata: {
loyalty_promo_id: data.loyaltyPromo[0].id
}
loyalty_promo_id: data.loyaltyPromo[0].id,
},
}
})
updateCartPromotionsWorkflow.runAsStep({
input: updatePromoData
input: updatePromoData,
})
updateCartsStep([
{
id: input.cart_id,
metadata
}
metadata,
},
])
// retrieve cart with updated promotions
@@ -1621,8 +1621,8 @@ Next, you'll create the API route that executes this workflow.
To create the API route, create the file `src/api/store/carts/[id]/loyalty-points/route.ts` with the following content:
```ts title="src/api/store/carts/[id]/loyalty-points/route.ts"
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
import { applyLoyaltyOnCartWorkflow } from "../../../../../workflows/apply-loyalty-on-cart";
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { applyLoyaltyOnCartWorkflow } from "../../../../../workflows/apply-loyalty-on-cart"
export async function POST(
req: MedusaRequest,
@@ -1633,8 +1633,8 @@ export async function POST(
const { result: cart } = await applyLoyaltyOnCartWorkflow(req.scope)
.run({
input: {
cart_id
}
cart_id,
},
})
res.json({ cart })
@@ -1808,13 +1808,13 @@ export const removeLoyaltyFromCartWorkflowHighlights = [
import {
createWorkflow,
transform,
WorkflowResponse
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import {
useQueryGraphStep,
updateCartPromotionsWorkflow,
updateCartsStep,
updatePromotionsStep
updatePromotionsStep,
} from "@medusajs/medusa/core-flows"
import { getCartLoyaltyPromoStep } from "./steps/get-cart-loyalty-promo"
import { PromotionActions } from "@medusajs/framework/utils"
@@ -1833,7 +1833,7 @@ const fields = [
"promotions.rules.values.*",
"currency_code",
"total",
"metadata"
"metadata",
]
export const removeLoyaltyFromCartWorkflow = createWorkflow(
@@ -1844,46 +1844,46 @@ export const removeLoyaltyFromCartWorkflow = createWorkflow(
entity: "cart",
fields,
filters: {
id: input.cart_id
}
id: input.cart_id,
},
})
const loyaltyPromo = getCartLoyaltyPromoStep({
cart: carts[0] as unknown as CartData,
throwErrorOn: "not-found"
throwErrorOn: "not-found",
})
updateCartPromotionsWorkflow.runAsStep({
input: {
cart_id: input.cart_id,
promo_codes: [loyaltyPromo.code!],
action: PromotionActions.REMOVE
}
action: PromotionActions.REMOVE,
},
})
const newMetadata = transform({
carts
carts,
}, (data) => {
const { loyalty_promo_id, ...rest } = data.carts[0].metadata || {}
return {
...rest,
loyalty_promo_id: null
loyalty_promo_id: null,
}
})
updateCartsStep([
{
id: input.cart_id,
metadata: newMetadata
}
metadata: newMetadata,
},
])
updatePromotionsStep([
{
id: loyaltyPromo.id,
status: "inactive"
}
status: "inactive",
},
])
// retrieve cart with updated promotions
@@ -1920,7 +1920,7 @@ To create the API route, add the following in `src/api/store/carts/[id]/loyalty-
```ts title="src/api/store/carts/[id]/loyalty-points/route.ts"
// other imports...
import { removeLoyaltyFromCartWorkflow } from "../../../../../workflows/remove-loyalty-from-cart";
import { removeLoyaltyFromCartWorkflow } from "../../../../../workflows/remove-loyalty-from-cart"
// ...
export async function DELETE(
@@ -1932,8 +1932,8 @@ export async function DELETE(
const { result: cart } = await removeLoyaltyFromCartWorkflow(req.scope)
.run({
input: {
cart_id
}
cart_id,
},
})
res.json({ cart })
@@ -2033,11 +2033,11 @@ export const completeCartWorkflowHookHighlights = [
]
```ts title="src/workflows/hooks/complete-cart.ts" highlights={completeCartWorkflowHookHighlights} collapsibleLines="1-6" expandButtonLabel="Show Imports"
import { completeCartWorkflow } from "@medusajs/medusa/core-flows";
import LoyaltyModuleService from "../../modules/loyalty/service";
import { LOYALTY_MODULE } from "../../modules/loyalty";
import { CartData, getCartLoyaltyPromotion } from "../../utils/promo";
import { MedusaError } from "@medusajs/framework/utils";
import { completeCartWorkflow } from "@medusajs/medusa/core-flows"
import LoyaltyModuleService from "../../modules/loyalty/service"
import { LOYALTY_MODULE } from "../../modules/loyalty"
import { CartData, getCartLoyaltyPromotion } from "../../utils/promo"
import { MedusaError } from "@medusajs/framework/utils"
completeCartWorkflow.hooks.validate(
async ({ cart }, { container }) => {
@@ -2055,13 +2055,13 @@ completeCartWorkflow.hooks.validate(
"promotions.rules.*",
"promotions.rules.values.*",
"promotions.application_method.*",
"metadata"
"metadata",
],
filters: {
id: cart.id
}
id: cart.id,
},
}, {
throwIfKeyNotFound: true
throwIfKeyNotFound: true,
})
const loyaltyPromo = getCartLoyaltyPromotion(
+3 -3
View File
@@ -24,7 +24,7 @@ export const generatedEditDates = {
"app/commerce-modules/fulfillment/fulfillment-provider/page.mdx": "2025-02-26T11:21:56.242Z",
"app/commerce-modules/fulfillment/item-fulfillment/page.mdx": "2024-10-08T14:38:15.496Z",
"app/commerce-modules/fulfillment/module-options/page.mdx": "2024-10-15T12:51:56.118Z",
"app/commerce-modules/fulfillment/shipping-option/page.mdx": "2024-10-08T14:36:02.660Z",
"app/commerce-modules/fulfillment/shipping-option/page.mdx": "2025-04-17T13:51:40.980Z",
"app/commerce-modules/fulfillment/page.mdx": "2025-04-17T08:48:19.367Z",
"app/commerce-modules/inventory/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/inventory/_events/page.mdx": "2024-07-03T19:27:13+03:00",
@@ -57,7 +57,7 @@ export const generatedEditDates = {
"app/commerce-modules/pricing/_events/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/pricing/concepts/page.mdx": "2024-10-09T13:37:25.678Z",
"app/commerce-modules/pricing/price-calculation/page.mdx": "2024-10-09T13:43:14.038Z",
"app/commerce-modules/pricing/price-rules/page.mdx": "2024-10-09T13:38:47.112Z",
"app/commerce-modules/pricing/price-rules/page.mdx": "2025-04-17T14:31:26.650Z",
"app/commerce-modules/pricing/tax-inclusive-pricing/page.mdx": "2024-10-09T13:48:23.261Z",
"app/commerce-modules/pricing/page.mdx": "2025-04-17T08:48:29.165Z",
"app/commerce-modules/product/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00",
@@ -6072,7 +6072,7 @@ export const generatedEditDates = {
"app/integrations/guides/algolia/page.mdx": "2025-04-17T08:29:01.433Z",
"app/integrations/guides/magento/page.mdx": "2025-04-17T08:29:01.500Z",
"app/js-sdk/auth/overview/page.mdx": "2025-03-28T08:05:32.622Z",
"app/how-to-tutorials/tutorials/loyalty-points/page.mdx": "2025-04-17T08:48:07.930Z",
"app/how-to-tutorials/tutorials/loyalty-points/page.mdx": "2025-04-17T14:31:04.727Z",
"references/js_sdk/admin/Admin/properties/js_sdk.admin.Admin.plugin/page.mdx": "2025-04-11T09:04:55.084Z",
"references/js_sdk/admin/Customer/methods/js_sdk.admin.Customer.createAddress/page.mdx": "2025-04-11T09:04:54.010Z",
"references/js_sdk/admin/Customer/methods/js_sdk.admin.Customer.deleteAddress/page.mdx": "2025-04-11T09:04:54.015Z",
@@ -3283,7 +3283,7 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"isPathHref": true,
"type": "category",
"title": "Concepts",
"autogenerate_tags": "concept+fulfillment",
"autogenerate_tags": "fulfillment+concept",
"autogenerate_as_ref": true,
"children": [
{
@@ -3326,6 +3326,14 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"title": "Links to Other Modules",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "Shipping Option Price Rules",
"path": "https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -11018,7 +11026,7 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"isPathHref": true,
"type": "category",
"title": "Concepts",
"autogenerate_tags": "concept+product",
"autogenerate_tags": "product+concept",
"autogenerate_as_ref": true,
"children": [
{
@@ -11052,6 +11060,14 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"title": "Inventory Kits",
"path": "https://docs.medusajs.com/resources/commerce-modules/inventory/inventory-kit",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "Variant Price Rules",
"path": "https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules",
"children": []
}
]
},
+1 -1
View File
@@ -21,7 +21,7 @@ export const fulfillmentSidebar = [
{
type: "category",
title: "Concepts",
autogenerate_tags: "concept+fulfillment",
autogenerate_tags: "fulfillment+concept",
autogenerate_as_ref: true,
children: [
{
+1 -1
View File
@@ -16,7 +16,7 @@ export const productSidebar = [
{
type: "category",
title: "Concepts",
autogenerate_tags: "concept+product",
autogenerate_tags: "product+concept",
autogenerate_as_ref: true,
children: [
{
@@ -9,7 +9,7 @@ tags:
label: "Manage Shipping Options"
---
import { EllipsisHorizontal, TaxExclusive, TaxInclusive } from "@medusajs/icons"
import { EllipsisHorizontal, TaxExclusive, TaxInclusive, ArrowsPointingOut, Plus } from "@medusajs/icons"
export const metadata = {
title: `Manage Locations in Medusa Admin`,
@@ -133,9 +133,9 @@ To create a shipping option:
If you chose a "Calculated" price type, you can click the "Save" button to create the shipping option. Otherwise click Continue to proceed to the Prices step.
In the Prices step, use the [Bulk Editor](../../../tips/bulk-editor/page.mdx) to enter the shipping option's prices for every currency and region in your store. Once you're done, click the Save button.
#### Fixed and Conditional Shipping Option Prices
Learn how you can further manage the shipping option in the [Manage Shipping Options section](#manage-shipping-options).
In the Prices step, use the [Bulk Editor](../../../tips/bulk-editor/page.mdx) to enter the shipping option's prices for every currency and region in your store.
<Note title="Tips">
@@ -148,6 +148,29 @@ Tax-inclusive pricing is configured in the [currency's](../../store/page.mdx#edi
![Create shipping option form step 2](https://res.cloudinary.com/dza7lstvk/image/upload/v1739983344/User%20Guide/Screenshot_2025-02-19_at_6.42.12_PM_u3dk2g.png)
Shipping option prices can also be conditioned based on the cart's total. For example, you can make the shipping option free if the cart's total exceeds `$100`. So, you can set a fixed price for a shipping option, and then set a conditioned price based on the cart's total.
To set a conditioned price for the shipping option:
1. Hover over a cell in the Bulk Editor based on the currency or region you want to set the conditioned price for.
2. Click the <InlineIcon Icon={ArrowsPointingOut} alt="arrows-pointing-out" /> icon that appears to open the conditional pricing form.
3. In the form that opens:
- Conditional pricing card will appear, and you can add another one by clicking the "Add price" button.
- Enter in the "Shipping option price" field the price when this condition is satisfied.
- To set the minimum cart total required for this price to apply:
- Click the <InlineIcon Icon={Plus} alt="plus" /> next to "Minimum cart total".
- In the field that shows, enter the minimum cart total required for this price to apply.
- To set the maximum cart total required for this price to apply:
- Click the <InlineIcon Icon={Plus} alt="plus" /> next to "Maximum cart total".
- In the field that shows, enter the maximum cart total required for this price to apply.
- Once you're done, click the Save button.
Once you're done, click the Save button.
![Conditional shipping option price form](https://res.cloudinary.com/dza7lstvk/image/upload/v1744889619/User%20Guide/Screenshot_2025-04-17_at_2.33.14_PM_wcqinw.png)
Learn how you can further manage the shipping option in the [Manage Shipping Options section](#manage-shipping-options).
---
## Manage Service Zones
@@ -222,6 +245,7 @@ To edit the prices of shipping options whose price type is Fixed:
2. In the "Pickup" or "Shipping" sections, find the shipping option and click on the <InlineIcon Icon={EllipsisHorizontal} alt="three-dots" /> icon at its right.
3. Choose "Edit prices" from the dropdown.
4. In the [Bulk Editor](../../../tips/bulk-editor/page.mdx) that opens, you can edit the shipping option's price for every currency and region in your store.
- Refer to the [Fixed and Conditional Shipping Option Prices](#fixed-and-conditional-shipping-option-prices) section to learn how to set a conditional price for the shipping option.
5. Once you're done, click the Save button.
<Note title="Tips">
+1 -1
View File
@@ -47,7 +47,7 @@ export const generatedEditDates = {
"app/price-lists/manage/page.mdx": "2025-02-19T10:35:49.881Z",
"app/price-lists/page.mdx": "2025-02-19T09:51:32.546Z",
"app/settings/tax-regions/page.mdx": "2025-02-19T17:33:43.806Z",
"app/settings/locations-and-shipping/locations/page.mdx": "2025-02-25T15:02:02.164Z",
"app/settings/locations-and-shipping/locations/page.mdx": "2025-04-17T13:47:40.883Z",
"app/settings/locations-and-shipping/page.mdx": "2025-02-19T17:23:45.824Z",
"app/settings/locations-and-shipping/shipping-profiles/page.mdx": "2025-02-19T17:36:46.339Z",
"app/settings/product-tags/page.mdx": "2025-02-19T17:36:25.102Z",
+4
View File
@@ -3,6 +3,10 @@ export const concept = [
"title": "Inventory Kits",
"path": "https://docs.medusajs.com/resources/commerce-modules/inventory/inventory-kit"
},
{
"title": "Price Rules",
"path": "https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules"
},
{
"title": "Product Shipping Requirement",
"path": "https://docs.medusajs.com/resources/commerce-modules/product/selling-products"
@@ -15,6 +15,10 @@ export const fulfillment = [
"title": "Manage Shipping Profiles",
"path": "https://docs.medusajs.com/user-guide/settings/locations-and-shipping/shipping-profiles"
},
{
"title": "Shipping Option Price Rules",
"path": "https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules"
},
{
"title": "Product Shipping Requirement",
"path": "https://docs.medusajs.com/resources/commerce-modules/product/selling-products"
+4
View File
@@ -51,6 +51,10 @@ export const product = [
"title": "Inventory Kits",
"path": "https://docs.medusajs.com/resources/commerce-modules/inventory/inventory-kit"
},
{
"title": "Variant Price Rules",
"path": "https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules"
},
{
"title": "Extend Product",
"path": "https://docs.medusajs.com/resources/commerce-modules/product/extend"