Puncte:2

Salvați în siguranță datele în comandă în onNotify()

drapel jp

Sunt nou în Drupal și trebuie să fac un gateway de plată în afara site-ului (cu Drupal Commerce 2). Totul funcționează, dar uneori nu.

Serverul furnizorului de plăți la distanță trimite cereri de notificare către server, despre starea plății, așa că le am pe ambele onReturn și onNotify în clasa PaymentGateway.

De cand onReturn nu se garantează că va fi apelat (clientul ar putea închide browserul etc., iar furnizorul nu îl trimite neapărat înapoi în cazul meu), dar onNotify este garantat să fie apelat, creez și salvez Plată obiect în onNotify, nu în onReturn, când plata este finalizată. (Acesta este și ceea ce sugerează documentația să faceți: https://docs.drupalcommerce.org/commerce2/developer-guide/payments/create-payment-gateway/off-site-gateways/handling-ipn)

Deci codul meu arată cam așa. (Este un pseudo-cod foarte simplificat; verificările de validare nu sunt incluse.)

clasa RedirectCheckout extinde OffsitePaymentGatewayBase implementează SuportsNotificationsInterface {

  funcție publică onReturn() {
    $is_order_accepted = /* Verificați dacă furnizorul de plăți la distanță a acceptat comanda */
    dacă (!$este_comanda_acceptată) {
       aruncați o nouă excepție NeedsRedirectException()
    }
    // Dacă totul este bine, nu faceți nimic.
  }

  funcția publică onNotify() {
    /** @var OrderInterface $comanda */
    $comanda = /* Încarcă comanda despre care este notificarea */

    $is_order_accepted = /* Verificați dacă furnizorul de plăți la distanță a acceptat comanda */
    dacă ($is_order_accepted) {
      $plata = $payment_storage->create();
      $plata->salvare();
      $comanda->setData('transaction_id', $transactionId);
      $comanda->salvare(); // Aceasta este ceea ce uneori este suprascris de onReturn(), cred.
    }
  }
}

Observați că trebuie să salvez câteva date despre comandă, atunci când o comandă este acceptată (care nu este disponibilă la crearea comenzii, doar când o plată a reușit).
Documentația Drupal Commerce spune că „nu trebuie (și nu ar trebui)” să atingeți comanda, dar trebuie să salvez câteva date suplimentare despre comanda pe care alte părți din sistem se așteaptă să fie acolo.

Acest lucru funcționează adesea. Cu toate acestea, cei doi onReturn și onNotify solicitările de la serverul de la distanță ajung uneori aproape în același timp, ceea ce cred că duce la o condiție de cursă.

Din păcate, chiar dacă nu fac nimic la comanda în onReturn, Comerțul pare să salveze în continuare comanda. Cred că acest lucru poate suprascrie uneori datele salvate în comanda de onNotify. De exemplu:

  • onReturn începe să ruleze și încarcă comanda (Acest lucru este făcut de biblioteca comercială în sine, așa că nu pot face nimic în acest sens.)
  • Sosește cererea de notificare, deci onNotify începe să ruleze, încarcă și salvează comanda și revine
  • După aceasta, onReturn metoda revine, redă controlul către Commerce, care salvează din nou comanda; deoarece a încărcat obiectul de comandă înainte onNotify l-a salvat, suprascrie orice onNotify scris cu date vechi

(Poate că ordinea inversă poate fi, de asemenea, problematică, unde onNotify poate suprascrie orice date salvate în comandă de Drupal Commerce în culise, dacă există, în timpul onReturn cerere.)

Există o modalitate bună de a gestiona acest lucru, de exemplu, să rezolvăm condițiile de cursă pentru a putea salva datele comenzii onNotify?

Folosesc Drupal 8.6.

Gabriel Fernandez avatar
drapel cn
Ați încercat să utilizați evenimente, cum ar fi `commerce_order.place.post_transition`?
drapel jp
Idee interesantă - voi analiza cum funcționează
drapel jp
Bună sugestie! Din păcate, conform testelor mele, onNotify() nu plasează comanda de la sine (deci acest eveniment nu este declanșat), atunci când este adăugată plata.Deci, singura modalitate de a plasa comanda în onNotify(), este să „aplicați tranziția” la comandă și apoi să salvați comanda singur - dar apoi ne întoarcem la problema concurenței de mai sus, din păcate, deoarece atât onNotify() cât și onReturn() salvează comanda. (Și cred că am fi revenit și la această problemă, dacă comerțul ar fi plasat comanda de la sine)
Puncte:1
drapel cn

Aveți dreptate în privința condiției de cursă, dar onReturn nu modifică deloc ordinea

Iată ce se întâmplă în fundal:

  • cel commerce_payment.checkout.return ruta pe plata comertului se numește modul care la început permitea comandă plugin-ul gateway de plată pentru a crea o plată pentru comandă
  • atunci indiferent de ceea ce se întâmplă în metoda onReturn a fluxului de plată a comenzii pluginului va fi redirecționat într-o altă etapă (dacă onReturn aruncă o excepție, acesta va fi redirecționat către etapa anterioară, altfel va fi redirecționat către etapa următoare)
  • în această situaţie metoda redirectToStep în Drupal\commerce_checkout\Plugin\Commerce\CheckoutFlow\CheckoutFlowBase va modifica și salva ordinea, unde apare problema.

aceasta este implementarea redirectToStep:

/**
 * {@inheritdoc}
 */
funcția publică redirectToStep($step_id) {
  dacă (!$this->isStepVisible($step_id)) {
    arunca noua \InvalidArgumentException(sprintf('ID pas invalid "%s" transmis la redirectToStep().', $step_id));
  }

  $this->order->set('checkout_step', $step_id);
  $this->onStepChange($step_id);
  $aceasta->comanda->salvare();

  aruncați o nouă excepție NeedsRedirectException(Url::fromRoute('commerce_checkout.form', [
    'commerce_order' => $this->order->id(),
    'step' => $step_id,
  ])->toString());
}

deci, pentru a rezolva problema în metoda onReturn, ar trebui să așteptați ca modificările onNotify să fie făcute (o buclă while care așteaptă până când modificările la comandă sunt setate)

speră că ajută.

drapel jp
Mulțumesc pentru răspunsul tău bun! Cu toate acestea, o întrebare - chiar dacă în onReturn aștept ca modificările onNotify să fie făcute, „$this->order” nu va mai conține valorile vechi de înainte de rularea onNotify? (deci redirectToStep va salva valorile vechi). Dacă da, există o modalitate de a reîncărca „$this->order” în onReturn (după așteptare)?
drapel jp
(Hmm...Și nu s-ar putea salva comanda în onNotify, de fapt, schimbarea la „checkout_step” în comanda, a făcut-o redirecționatToStep la vechea ei valoare?)
Alireza Tabatabaeian avatar
drapel cn
De fapt, nu sunt destul de sigur de această situație, dar cred că va funcționa. Ok, încearcă și dacă lucrurile nu au mers foarte bine, atunci ne putem gândi la alte abordări.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.