Skip to content

feat(promotion): minimum purchase requirements and maximum discount amounts#16121

Open
Ligament wants to merge 4 commits into
medusajs:developfrom
Ligament:feat/promotion-minimum-purchase-rule
Open

feat(promotion): minimum purchase requirements and maximum discount amounts#16121
Ligament wants to merge 4 commits into
medusajs:developfrom
Ligament:feat/promotion-minimum-purchase-rule

Conversation

@Ligament

Copy link
Copy Markdown
Contributor

What

  • Minimum purchase requirements for all promotion types: item_subtotal becomes a first-class promotion rule attribute with numeric operators (gte, gt, eq, lte, lt).
  • Maximum discount amounts for percentage promotions: a new max_amount on the application method caps the total discount, e.g. "10% off, up to 50".
  • An "Amount off shipping" dashboard template, making fixed-amount shipping discounts (already supported by the engine) configurable from the UI.

Why

"Spend 100, get X" thresholds and capped percentage discounts are common merchant needs that currently require custom code. The compute engine already evaluates numeric rules against the cart context, but the admin rule options, dashboard, and order-edit contexts didn't expose them, and percentage discounts couldn't be capped.

How

  • packages/medusa: expose item_subtotal with numeric operators in rule-attribute options; return number-attribute rules from the promotion rules endpoint (scalar values, matching the disguised-rule convention); accept max_amount in application method validators.
  • packages/modules/promotion: nullable max_amount bigNumber column + migration; compute actions clamp item/shipping adjustments to the cap; validation requires percentage type, currency code, positive amount; rejected for buyget.
  • packages/core/types: item_subtotal on ComputeActionContext; max_amount on DTOs and HTTP payloads.
  • packages/core/core-flows: order-edit/draft-order compute context now includes item_subtotal, so minimum purchase promotions survive order changes.
  • packages/admin/dashboard: numeric operators and number inputs in the rule form; "Maximum Discount Amount" input for percentage promotions; new shipping template.

Testing

  • promotion-minimum-purchase.spec.ts (8 tests): fixed/percentage/shipping/free-shipping promotions gated on item_subtotal gte 100, promo-code application below/above threshold, rule metadata endpoints.
  • promotion-max-amount.spec.ts (3 tests): cap applied below/above threshold, validation errors.
  • Regressions: promotions.spec.ts and the order-edits promotion suite pass.

Ligament and others added 3 commits July 19, 2026 10:20
…uirements on promotions

Adds item_subtotal as a first-class promotion rule attribute with numeric
operators (gte, gt, eq, lte, lt) so every promotion type can be gated on a
minimum purchase amount, e.g. spend 100 or more to get a fixed discount, a
percentage discount, a shipping discount, or free shipping.

- Expose item_subtotal with numeric operators in the admin rule attribute
  options, and render number-valued rules in the promotion rules endpoints
- Return a clean invalid_data error from rule-value-options for attributes
  without entity-backed value options
- Type item_subtotal on ComputeActionContext
- Include item_subtotal in the order edit / draft order promotion compute
  context so minimum purchase promotions survive order changes
- Reset number rule values correctly in the dashboard rule form when
  switching operators

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Number-typed rule attributes (e.g. item_subtotal) now return a scalar value
from GET /admin/promotions/:id/:rule_type, matching the disguised number
rule convention the dashboard renders. Returning an array of value objects
crashed the promotion detail page (objects are not valid as a React child).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…and fixed shipping discounts

Adds max_amount to promotion application methods so percentage promotions
can be capped at a fixed amount, e.g. 10% off up to a maximum of 50.

- New nullable bigNumber max_amount column on promotion_application_method
  with migration
- computeActions clamps item and shipping adjustments so a promotion's
  cumulative discount never exceeds max_amount
- Validation: max_amount requires percentage type and a currency code, is
  not allowed for buyget promotions, and must be positive
- Dashboard create flow exposes a Maximum Discount Amount input for
  percentage promotions and a new "Amount off shipping" template for
  fixed-amount shipping discounts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Ligament
Ligament requested a review from a team as a code owner July 20, 2026 02:00
@changeset-bot

changeset-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: af7ce0b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 79 packages
Name Type
@medusajs/promotion Patch
@medusajs/medusa Patch
@medusajs/types Patch
@medusajs/dashboard Patch
@medusajs/core-flows Patch
@medusajs/test-utils Patch
@medusajs/loyalty-plugin Patch
@medusajs/medusa-oas-cli Patch
integration-tests-http Patch
@medusajs/event-bus-redis Patch
@medusajs/draft-order Patch
@medusajs/framework Patch
@medusajs/js-sdk Patch
@medusajs/modules-sdk Patch
@medusajs/orchestration Patch
@medusajs/query Patch
@medusajs/utils Patch
@medusajs/workflows-sdk Patch
@medusajs/admin-bundler Patch
@medusajs/analytics Patch
@medusajs/api-key Patch
@medusajs/auth Patch
@medusajs/caching Patch
@medusajs/cart Patch
@medusajs/currency Patch
@medusajs/customer Patch
@medusajs/file Patch
@medusajs/fulfillment Patch
@medusajs/index Patch
@medusajs/inventory Patch
@medusajs/link-modules Patch
@medusajs/locking Patch
@medusajs/notification Patch
@medusajs/order Patch
@medusajs/payment Patch
@medusajs/pricing Patch
@medusajs/product Patch
@medusajs/rbac Patch
@medusajs/region Patch
@medusajs/sales-channel Patch
@medusajs/settings Patch
@medusajs/stock-location Patch
@medusajs/store Patch
@medusajs/tax Patch
@medusajs/translation Patch
@medusajs/user Patch
@medusajs/workflow-engine-inmemory Patch
@medusajs/workflow-engine-redis Patch
@medusajs/oas-github-ci Patch
@medusajs/cache-inmemory Patch
@medusajs/cache-redis Patch
@medusajs/event-bus-local Patch
@medusajs/analytics-local Patch
@medusajs/analytics-posthog Patch
@medusajs/auth-emailpass Patch
@medusajs/auth-github Patch
@medusajs/auth-google Patch
@medusajs/caching-redis Patch
@medusajs/file-local Patch
@medusajs/file-s3 Patch
@medusajs/fulfillment-manual Patch
@medusajs/locking-postgres Patch
@medusajs/locking-redis Patch
@medusajs/notification-local Patch
@medusajs/notification-sendgrid Patch
@medusajs/payment-stripe Patch
@medusajs/http-types-generator Patch
@medusajs/cli Patch
@medusajs/deps Patch
@medusajs/eslint-plugin Patch
@medusajs/telemetry Patch
@medusajs/admin-sdk Patch
@medusajs/admin-shared Patch
@medusajs/admin-vite-plugin Patch
@medusajs/icons Patch
@medusajs/toolbox Patch
@medusajs/ui-preset Patch
create-medusa-app Patch
@medusajs/ui Patch

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

@medusa-os-bot

medusa-os-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

Thanks for the contribution! A few items need to be addressed before this can move forward:

Clean, well-tested feature adding an item_subtotal minimum-purchase rule attribute and a max_amount cap for percentage promotions (migration, types, dashboard, compute engine). Template is complete and tests are included. Two concerns before merge: (1) it's a large change (24 files, ~1150 lines) that adds a new DB column plus new public rule/API surface and touches the core promotion compute engine, with no linked pre-approved issue — large features should be scoped/aligned with the team first per CONTRIBUTING.md; (2) the order-edit item_subtotal derivation may resolve to 0 if previewed items

  • Large change (24 files, ~1150 LOC) adds a new DB column and public rule/API surface in the core promotion engine with no linked pre-approved issue; align scope with the team first (CONTRIBUTING.md).
  • prepare-order-compute-action-context.ts: item_subtotal reads item.subtotal, but the comment says preview lacks decorated totals; if so it resolves to 0 and min-purchase rules never apply on order edit
  • No test verifies minimum-purchase promotions re-evaluate correctly during order edits/draft orders, though that is a stated goal of the PR. Add coverage for that path.

Triggered by: new PR opened

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant