0

There seem to be a few bugs in Commerce (8.x-2.17) related to admins making payments against a Cart. I am trying to fix some of these in my own custom module (rather than wait for people to agree these are bugs). Some, but not all, include:

  1. payments made are not reflected anywhere.
  2. when paid in full the order is not "completed" (not sure if this is correct term, in D7 i think the term was "checked out").
  3. payments can be made beyond the full amount of the order (or the balance)

I think it should be possible to address some of these by subscribing to a Payment event and going in and cleaning things up (not sure where or how to clean up; but baby steps).

I have seen a post listing: commerce_order.order.paid as an event that is fired when the order is paid in full; but this is not fired (as far as i can tell) when a payment is made which completes the order (neither from admin paying or standard checkout flow).

I have also seen commerce_payment.commerce_payment.insert, which is also not fired during payment or checkout flow. To be honest i don't understand the naming related to payments: add payment, insert, update? Why is this not "make" a payment as this is more grammatically correct.

Does anyone know what event is triggered when a payment is made (or ideally when a payment covers the balance owing on an order)?

1 Answer 1

2

You seem to misunderstand the term payment here. It should not be seen in the context of a regular payment that you make or complete in a store. In this context payments are entities and the events match those of database transactions (insert, update, delete, etc.).

Theoretically the combination of these 3 events should allow you to determine if a payment has been made or altered or deleted, but you need to subscribe to all of them to be updated on all changes. (If you only subscribe to inserts (new payments) but not to deletes (removed payments) you might miss data.)

The commerce_order.order.paid or the safer \Drupal\commerce_order\Event\OrderEvents::ORDER_PAID event has the following documentation:

/**
 * Name of the event fired after the order has been fully paid.
 *
 * Guaranteed to only fire once, when the order balance reaches zero.
 * Subsequent changes to the balance won't redispatch the event (e.g. in case
 * of a refund followed by an additional payment).
 *
 * Fired before the order is saved.
 *
 * @Event
 *
 * @see \Drupal\commerce_order\OrderInterface::getBalance()
 * @see \Drupal\commerce_order\Event\OrderEvent
 */ 
const ORDER_PAID = 'commerce_order.order.paid';

It is called from doOrderPreSave() in OrderStorage.php, but only if the event has not dispatched before:

  if ($order->getData('paid_event_dispatched') === FALSE) {
    $event = new OrderEvent($order);
    $this->eventDispatcher->dispatch(OrderEvents::ORDER_PAID, $event);
    $order->setData('paid_event_dispatched', TRUE);
  }

When a payment is made, the order is listed in the commerce_payment.order_updater service which during its destruct will update and save all listed orders. Those in turn will determine if the total order balance has been reduced to zero and emit the event. It looks sensible to me.

Could it be that you have been testing with the same order over and over and that event already fired once?

4
  • thank you for the detailed answer, but perhaps I made my question too complicated. I simply want to know how to respond to payment being made in full (by an admin). Yes, I have only subscribed to commerce_payment.commerce_payment.insert so far, but since i am trying to detect when a payment is "made", that seems like the closest one. And yes, i had read comments on commerce_order.order.paid which is why it sounded correct; but it does not fire either. I have done many many tests; safe to say some are on existing orders but most are on new orders.
    – liquidcms
    Commented Mar 27, 2020 at 19:32
  • This event: commerce_order.order.paid does seem to work now; not sure why it wasn't before. Now to figure out how to set the order completed.
    – liquidcms
    Commented Mar 28, 2020 at 5:26
  • You need something like $order->getState()->doTransition('complete') I am not at the computer now, so I might be a few letters off. Commented Mar 28, 2020 at 7:05
  • 1
    @Neograoh734, not quite.. but got me searching code to find the right answer. Not sure why this is so hard to find. $order->getState()->applyTransitionById('place'); $order->save();
    – liquidcms
    Commented Mar 29, 2020 at 3:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.