feat(shipping): weight-based shipping with weight_total totals and conditional price rules - #16799
feat(shipping): weight-based shipping with weight_total totals and conditional price rules#16799pmwheatley wants to merge 7 commits into
Conversation
- add unit_weight column to line item model, types and migration - add weight_total to cart totals types - whitelist weight_total as shipping option price rule attribute - unit tests for totals and validators (failing until implementation)
- compute weight_total in cart and line item totals - persist unit_weight through line item preparation - expose weight_total when listing cart shipping options - allow weight_total price rule attribute in admin validators
- checkout flow applies weight_total price rules (store carts) - weight_total and item_total rules combine with AND semantics - listing store shipping options filters by weight_total - admin api accepts weight_total rules and rejects removed price_total - cart module service returns weight_total
- weight_total option in conditional price form with overlap validation - price rule helpers and form schema for weight conditions - translations for weight-based pricing labels
- document weight_total as a price rule attribute with examples - explain how unit_weight is inherited from the product variant - add weight_total and unit_weight to cart totals reference
🦋 Changeset detectedLatest commit: 6564486 The changes in this PR will be included in the next version bump. This PR includes changesets to release 83 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Thanks for the contribution! A few items need to be addressed before this can move forward: The contributor (pmwheatley) adds weight-based shipping support to Medusa: a new nullable unit_weight column on cart_line_item, a weight_total computed total on line items and carts, weight_total accepted as a shipping-option price-rule attribute in the admin validator, corresponding admin dashboard UI for weight-based conditional prices (with range-overlap validation and full i18n coverage), and documentation updates. The implementation logic is correct: weight flows from product-variant data through prepareLineItemData, is rounded to an integer before persistence, and is aggregated by the existing BigNumber-safe totals utilities. No security issues, performance regressions, or bugs were found. Two required changes are listed below.
Triggered by: new PR opened |
|
Thanks for the contribution! A few items need to be addressed before this can move forward: The contributor adds weight-based shipping support: a new nullable unit_weight column on cart_line_item, a server-side computed weight_total total (sum of each line item's unit_weight × quantity), an extension of the shipping-option price-rule Zod validator to accept weight_total as a valid attribute, corresponding admin dashboard UI with i18n coverage across all supported locales, and documentation updates. The implementation approach is sound — weights flow from product/variant data through prepareLineItemData, are rounded to integers on persistence in the cart module service, and are aggregated with the existing BigNumber-safe math utilities. No security issues, N+1 queries, or correctness bugs were found in this review. Two required changes from the previous review remain unresolved.
Triggered by: PR description updated |
Summary
What — What changes are introduced in this PR?
Adds weight-based shipping support to Medusa:
unit_weightcolumn oncart_line_item(migrationMigration20260911100000)weight_totalon line item totals (unit_weight × quantity) and cart totals (Σ line items), exposed asweight_total/raw_weight_totalonCartLineItemDTOandCartDTOweight_totalaccepted as a shipping option price rule attribute in the admin API (alongsideitem_total), participating in calculated-price context when listing cart shipping optionsweight_totaloption in the conditional price form for shipping options, with range-overlap validation and i18n labels for all localesweight_totalrule attribute and totals documented in the pricing price-rules and cart totals referencesWhy — Why are these changes relevant or necessary?
Merchants currently can't price shipping by cart weight, a standard carrier requirement. Shipping prices can only condition on
item_total. This adds weight as a first-class conditional dimension, computed automatically from line item weights (a product variant'sweightis carried onto cart line items asunit_weight). Resolves #16800.How — How have these changes been implemented?
unit_weightpersisted throughprepareLineItemDatain cart workflows, inherited fromvariant.weight ?? product.weight; aggregated by the totals utils (@medusajs/utils) using BigNumber-safe mathweight_totaladded to the cart query fields (core-flows) and store cart query config so it reaches the price-calculation context inlistShippingOptionsForCartWithPricingweight_totalin the price-rule attribute enum (z.enum(["item_total", "weight_total"]))conditional-price-formgains a weight condition type;price-rule-helpershandle weight range normalization and overlap detection across mixeditem_total/weight_totalrulesTesting — How have these changes been tested, or how can the reviewer test the feature?
packages/core/utils/src/totals/__tests__/totals.ts(weight_total calculation, zero default),packages/medusa/src/api/admin/shipping-options/__tests__/validators.spec.ts(attribute whitelist, operator/value validation), dashboardprice-rule-helpers.spec.tsintegration-tests/http/__tests__/cart/store/cart.spec.ts(weight rule applied at checkout, AND semantics withitem_total, store listing filter, exclusion case),integration-tests/http/__tests__/shipping-option/admin/shipping-option.spec.ts(create withweight_totalrules,price_total/unknown attributes rejected with 400), cart module service spec (weight_totalin totals)Examples
Creating a flat shipping option with a weight-based conditional price (via the JS SDK):
The cart's
weight_totalis the sum of its line items' weights, where each line item's weight is itsunit_weightmultiplied by its quantity.unit_weightis inherited from theweightproperty of the product variant.Checklist
Additional Context
The branch is staged as small, isolated commits: types/model/migration + red unit tests → implementation → integration tests → dashboard UI → docs → changeset.
We've been maintaining this feature internally across several Medusa versions now, and now propose it as a logical addition to the core. The implementation pattern follows that of the existing item_totals-based conditional pricing work as closely as possible, and would make a valuable addition to Medusa.