Skip to content

Conversation

@mamhoff
Copy link
Contributor

@mamhoff mamhoff commented Nov 17, 2025

Summary

This PR changes the new promotion system to calculate discounts entirely via adjustments rather than using in-memory ItemDiscount objects.

The advantage of this approach is that it allows to a) calculate discountable amounts for line items outside of the DiscountOrder loop. This is useful for calculating discounted prices, a feature I have on the roadmap. It specifically covers needs like the one addressed in this commit. This way, we have one system of record, not two.

The other advantage is that we can remove the pretty complex PersistDiscountedOrder code, and just rely on order.save! to do the right thing.

It also dovetails nicely with the work on the in-memory order updater.

Checklist

Check out our PR guidelines for more details.

The following are mandatory for all PRs:

The following are not always needed:

  • 📖 I have updated the README to account for my changes.
  • 📑 I have documented new code with YARD.
  • 🛣️ I have opened a PR to update the guides.
  • ✅ I have added automated tests to cover my changes.
  • 📸 I have attached screenshots to demo visual changes.

@github-actions github-actions bot added changelog:solidus_core Changes to the solidus_core gem changelog:solidus_promotions Changes to the solidus_promotions gem labels Nov 17, 2025
@codecov
Copy link

codecov bot commented Nov 17, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.49%. Comparing base (f8779d6) to head (ac699f3).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6371      +/-   ##
==========================================
+ Coverage   89.48%   89.49%   +0.01%     
==========================================
  Files         980      981       +1     
  Lines       20438    20471      +33     
==========================================
+ Hits        18289    18321      +32     
- Misses       2149     2150       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mamhoff mamhoff force-pushed the discountable-amounts-by-adjustments branch from 5f2c828 to fc5b38b Compare November 20, 2025 21:15
@mamhoff mamhoff force-pushed the discountable-amounts-by-adjustments branch from fc5b38b to bd24d6b Compare November 22, 2025 11:19
@github-actions github-actions bot removed the changelog:solidus_core Changes to the solidus_core gem label Nov 22, 2025
@mamhoff mamhoff force-pushed the discountable-amounts-by-adjustments branch 2 times, most recently from 67487b3 to ea30703 Compare December 3, 2025 13:49
Prior to this, the `adjustment_label` method on
`SolidusPromotions::Benefit` could only output a relatively static
string. This commit allows calculators to define one of these methods:

- `#line_item_adjustment_label(line_item, options = {})`
- `#shipment_adjustment_label(shipment, options = {})`
- `#shipping_rate_adjustment_label(shipping_rate, options = {})`
- `#price_adjustment_label(price, options = {})`

These have access to the inner workings of the calculator, so they can
provide dynamic labels (to reflect e.g. which tier a promotion chooses,
making that transparent to the customer.
If a promotion calculator implements a dynamic
`#{adjustable}_adjustment_label` method, we need to update the
adjustment label when it changes. This makes sure that is the case.
@mamhoff mamhoff force-pushed the discountable-amounts-by-adjustments branch 2 times, most recently from 96fab42 to 00fec51 Compare December 20, 2025 16:38
@mamhoff mamhoff marked this pull request as ready for review December 20, 2025 16:38
@mamhoff mamhoff requested a review from a team as a code owner December 20, 2025 16:38
@mamhoff mamhoff force-pushed the discountable-amounts-by-adjustments branch from 00fec51 to e3c0bbf Compare December 20, 2025 17:12
Copy link
Member

@tvdeyen tvdeyen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really great improvement. I have some nits about naming and overall API design, because I would like to make sure that the introduced classes are not used publicly.

@mamhoff mamhoff force-pushed the discountable-amounts-by-adjustments branch 2 times, most recently from b3e5d37 to 7872e08 Compare December 22, 2025 13:44
Copy link
Contributor Author

@mamhoff mamhoff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some comments after rebasing

@mamhoff mamhoff force-pushed the discountable-amounts-by-adjustments branch from 7872e08 to 5377e72 Compare December 22, 2025 13:49
Copy link
Member

@tvdeyen tvdeyen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reads extremely well and is a great change


module SolidusPromotions
class OrderAdjuster
class SetDiscountsToZero
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could now be a module, no?

@tvdeyen tvdeyen added this to the 4.7 milestone Dec 22, 2025
@tvdeyen tvdeyen moved this to In Progress in Solidus Public Roadmap Dec 22, 2025
This module recalculates all promo totals after promotion calculation
has finished, and marks any adjustments with an amount of zero for
destruction.
Now that the promotion order adjuster does not persist things to the
database any longer, we can calculate promo totals even in dry runs (and
get better results).

The `PersistDiscountedOrder` class is slated for deletion, but that is
the next commit.
This service object sets all discounts on an order - adjustments on
shipments and line items, and shipping rate discounts on shipping rates
- to an amount of zero. This service module is intended to run within the
order adjuster, before promotion calculation. Promotion calculation will
then re-calculate the amounts, with the effect that adjustments that
need to change will be changed, while adjustments that do not need to
change will not have changes (and will therefore also not be saved).
We want the individual benefits to issue exactly the kind of object that
will discount the adjustable object, so we need to generate the right kind
of discount object for each adjustable type.

This allows us to remove the `PersistDiscountedOrder` class, and it
makes the promotion system more understandable and more in line with the
rest of Solidus. Specifically, we can now check for adjustments when
calculating promotion discounts (this is pretty big!), and
`promotion.discounted_amount` can be called from outside the promotion
calculation loop.
@mamhoff mamhoff force-pushed the discountable-amounts-by-adjustments branch from 5377e72 to ac699f3 Compare December 23, 2025 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog:solidus_promotions Changes to the solidus_promotions gem

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants