For example,

- Payment type: SIBS_MULTIBANCO
- Land on widget page with a rectangular button with SIBS symbol
- Cancel (go back)
- Proceed again to Land on widget
- Press the widget button

The payment instructions with payment references are lost.
Even on e-mail the instructions don't appear.

If we don't press Cancel hyperlinks it works fine.

I don't know if it's a upstream (SIBS) problem or if it's a problem with commerce_opp that looses or erases the information about payment references.

Comments

jrochate created an issue. See original summary.

agoradesign’s picture

This is by design. When you cancel a payment, this try gets voided. If you then choose again the same brand again, a new checkout ID is created. Naturally all old input is lost.. but what do you mean with the e-mail instructions, that won't appear?

jrochate’s picture

on the second try, the thank you page won't show the MULTIBANCO references. Just a normal thank you page, without the references for the client to pay. Also, there is an email sent to client that has no references to pay.

But when we pay straight, without going back, the thank you and the email got references.

it seams they are lost somehow in the process of going back and forth again.

agoradesign’s picture

hmmm plz look at the cart's payments tab (or in the database) - there should be a new payment entity created for every time you enter the SIBS widget

jrochate’s picture

StatusFileSize
new26.38 KB

Sure, there is a new payment ID every time I go back and forth.

But when I finally press the MULITBANCO button, I got no instructions multibanco instructions (references). only the normal thank you without references.

agoradesign’s picture

hmmm is the pmt_ref field of the payment entity in Drupal empty here in this case? and if, do you see any warnings in the Drupal log about missing MULTIBANCO parameters?

jrochate’s picture

StatusFileSize
new22.48 KB

The pmt_ref_value has valid data for the same entity_id as payment.

In this last test, now I get authorization_voided on the state field of commerce_payment.

Steps:
- go for widget
- see the multibanco button, but don't press
- press cancel link below widget
- press again the button to finish order and go for widget
- see the multibanco button, and press
- thank you page, no instructions

agoradesign’s picture

maybe it's a MULTIBANCO specific thing!? maybe this brand has problems with referencing the same order ID multiple times? other brands won't care

jrochate’s picture

Well, I think the platform doesn't care much about order ID, but transaction ID (payment ID).
And every time a new try is done, there is a new payment ID, so I'm confused.

Anyway... if commece_opp module do not show the payment ref BUT the field has data, something is going on and the module knows it.

Why the module don't show the info? Because it detected it's voided? If yes, we should not show a thank you page, but an error page and tell user to order again.

At the moment the user thinks it's OK, but he don't get the payment ref.

agoradesign’s picture

strange.. for voided payments, you always get redirected back to checkout normally. are there any logs in watchdog produced at the same time?

jrochate’s picture

Nop, no logs on that,

agoradesign’s picture

hmmm maybe some very weird caching problem!? we'll hopefully find out

agoradesign’s picture

I know what's going on here. I can provide a partial solution only. The rest is wrong behaviour/expectation from Commerce side imho, and I'll discuss this with Centarro asap:

Here's the code part, how commerce_payment is adding the payment instructions on the checkout complete page:

function commerce_payment_preprocess_commerce_checkout_completion_message(&$variables) {
  /** @var Drupal\commerce_order\Entity\OrderInterface $order */
  $order = $variables['order_entity'];
  if ($order->get('payment_gateway')->isEmpty()) {
    return;
  }

  /** @var \Drupal\commerce_payment\Entity\PaymentGatewayInterface $payment_gateway */
  $payment_gateway = $order->get('payment_gateway')->entity;
  /** @var \Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\HasPaymentInstructionsInterface $payment_gateway_plugin */
  $payment_gateway_plugin = $payment_gateway->getPlugin();
  if ($payment_gateway_plugin instanceof HasPaymentInstructionsInterface) {
    $payment_storage = \Drupal::entityTypeManager()->getStorage('commerce_payment');
    $payments = $payment_storage->loadMultipleByOrder($order);
    $payments = array_filter($payments, function ($payment) use ($payment_gateway) {
      return $payment->getPaymentGatewayId() == $payment_gateway->id();
    });
    $payment = reset($payments);
    if ($payment) {
      $variables['payment_instructions'] = $payment_gateway_plugin->buildPaymentInstructions($payment);
    }
  }
}

So, due to the nature of the checkout flow, we have only the order entity loaded as page argument. Hence, the payment entity has to be found and loaded first. And this is the point, that is done wrong imho: every payment belonging to the given order is loaded and iterated. The first payment entity that equals the payment gateway referenced by the order (because this reference is saved within the order object, but not the payment entity unfortunately), is used to display the payment instructions. So if we have more than one payment entity of the same payment gateway ID, always the oldest one is assumed to be the right one. This is 99% of time wrong imho. As long as noone as implemented partial payments, only the newest one can be the actually used one to place the order. And even if we had partial payments, then we always need the newest payment entity in this situation.

I know that ideally the payment entity is not created until onReturn() or onNotify(), but for most offsite payment gateways this ain't possible. At least for our module, we need to do this upon initializing the COPYandPAY widget, as we need to store the checkout ID somewhere in order to be able to identify the payment later. This results in unused payment entities that remain in authorization state, everytime I don't finish a payment and return to checkout then. This is why we already offer the possiblity to delete expired authorizations on cron.

What we can do now, is to delete the unneeded payment entity, if the user clicks on the cancel link. This would be an useful improvement of our module. But if the user does not click the cancel but rather re-enter the checkout review url by hand (or most likely uses the back button to navigate back to the review page, or even if the user refreshes the payment page), then we do not have the cancel action triggered.

We could still discuss, if we want to go even further and delete unused payment authorizations directly in our plugin form, before we initizalize a new payment entity. This feels a little bit hackish however

EDIT: regarding the last paragraph - I had already convinced myself that we really should delete the old unneeded entities first in the plugin form, but what if we run into an edge case, where somebody is copy & pasting the checkout payment page url into a new browser tab, then continuing the older tab to actually pay? If we had already deleted the payment entity, we would have a problem

  • agoradesign committed 184f98e on 8.x-1.x
    Issue #3166175 by jrochate, agoradesign: When we land on OPP widget, go...

  • agoradesign committed 6cf961a on 8.x-1.x
    Issue #3166175 by jrochate, agoradesign: When we land on OPP widget, go...

  • agoradesign committed 9b65aec on 8.x-1.x
    Issue #3166175 by jrochate, agoradesign: When we land on OPP widget, go...
agoradesign’s picture

Status: Active » Fixed

ok, finally I've implemented this solution:

  • on cancel action, remove all pending authorizations of the same gateway ID
  • on return action, remove all pending authorizations of the same gateway ID, excluding the current payment that was identified on return page

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.