Allow to disable the recalculation of an order

Created on 25 October 2019, over 5 years ago
Updated 3 July 2025, 3 days ago

Every time an order is saved recalculateTotalPrice() is called. At first glance it makes sense to do this, but we run into problems with this when we implement a custom "Early bird" price resolver. Let me explain.

We allow the user to set an "Early bird" date on the product. Until this time a customer gets a discount. This is achieved through a price resolver and works just fine.

Let's take following example into consideration:

  1. Until 24th of Oct the product price is 300 USD
  2. After 24th of Oct the product price goes up to 390 USD
  3. The user starts the checkout process on the 23rd of Oct and gets an early bird price
  4. The user gets redirected to the external payment provider and chooses to pay the 300 USD with a bank transfer
  5. The user gets redirected back to the site, and the order transitions to the state "completed"
  6. 3-4 days later the external payment provider sends us a notification the bank transfer was completed
  7. onNotify() is called and the balance of the order is updated, which initiates an order save() and a recalculateTotalPrice()
  8. At this point the early bird price has already expired (we are now 27th of Oct), the prices are recalculated and the total order prices displays 390 USD while the customer only paid (rightfully) 300 USD

We have currently tackled this issue by implementing:

/**
 * Implements hook_entity_type_alter().
 */
function my_module_entity_type_alter(array &$entity_types) {
  // We have to override the commerce order class, to manipulate the recalculate function.
  $entity_types['commerce_order']->setClass('Drupal\my_module\Entity\Order');
}

And then override the recalculateTotalPrice() method like so:

  /**
   * {@inheritdoc}
   */
  public function recalculateTotalPrice() {
      if (($state = $this->getState()) && $state->getId() == 'completed') {
        // Never recalculate prices when order is completed.
        return $this;
      }

      if ($this->isLocked()) {
        // Do not recalculate prices when order is locked (when user is redirected to payment provider).
        return $this;
      }
    
      return parent::recalculateTotalPrice();
  }

Is there any mechanism we could add so custom module developers can add functionality which let's the order entity know "Hey, please in this case, do not recalculate the price of the order". Maybe through an event subscriber?

Or am I missing something completely and is this already possible?

Feature request
Status

Closed: outdated

Version

2.0

Component

Order

Created by

🇧🇪Belgium robin.ingelbrecht

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇮🇱Israel jsacksick

    This is probably outdated, if the order is locked it shouldn't be refreshed and therefore the price shouldn't be refreshed.
    Since this is from 2019 I'm going to close this and mark it as outdated.

Production build 0.71.5 2024