Я новичок в Drupal, и мне нужно сделать внешний платежный шлюз (с Drupal Commerce 2). Все работает, но иногда нет.
Сервер поставщика удаленных платежей отправляет на сервер запросы уведомлений о статусе платежа, поэтому у меня есть оба по возвращению
и onNotify
в классе PaymentGateway.
С по возвращению
не гарантируется вызов (клиент может закрыть браузер и т. д., и провайдер не обязательно отправляет его обратно в моем случае), но onNotify
гарантированно вызывается, я создаю и сохраняю Оплата
объект в onNotify
, не в по возвращению
, когда платеж будет завершен. (Это также то, что предлагает документация: https://docs.drupalcommerce.org/commerce2/developer-guide/payments/create-payment-gateway/off-site-gateways/handling-ipn)
Итак, мой код выглядит примерно так. (Это очень упрощенный псевдокод, проверки не включены.)
class RedirectCheckout расширяет OffsitePaymentGatewayBase, реализует SupportsNotificationsInterface {
публичная функция onReturn () {
$is_order_accepted = /* Проверяем, что поставщик удаленных платежей принял заказ */
если (!$is_order_accepted) {
бросить новое исключение NeedsRedirectException()
}
// Если все хорошо, ничего не делать.
}
публичная функция onNotify() {
/** @var OrderInterface $заказ */
$order = /* Загрузить заказ, о котором идет уведомление */
$is_order_accepted = /* Проверяем, что поставщик удаленных платежей принял заказ */
если ($ is_order_accepted) {
$payment = $payment_storage->create();
$платеж->сохранить();
$order->setData('transaction_id', $transactionId);
$ заказ-> сохранить(); // Думаю, это то, что иногда перезаписывается onReturn().
}
}
}
Обратите внимание, что мне нужно сохранить некоторые данные о заказе, когда заказ принят (что недоступно при создании заказа, только после успешной оплаты).
В документации Drupal Commerce говорится, что вам «не нужно (и не следует)» касаться заказа, но я должен сохранить некоторые дополнительные данные о заказе, которые ожидают другие части системы.
Это часто работает. Тем не менее, два по возвращению
и onNotify
запросы с удаленного сервера иногда поступают почти одновременно, что, как я полагаю, приводит к состоянию гонки.
К сожалению, хотя я ничего не делаю для заказа в по возвращению
, Коммерция вроде еще спасает заказ. Я считаю, что это может когда-нибудь перезаписать данные, сохраненные в заказе, onNotify
. Например:
по возвращению
начинает работать и загружает заказ (это делает сама коммерческая библиотека, поэтому я ничего не могу с этим поделать).
- Приходит запрос на уведомление, поэтому
onNotify
начинает работать, загружает и сохраняет заказ и возвращает
- После этого
по возвращению
возвращает метод, возвращает управление Commerce, который снова сохраняет заказ; так как он загрузил объект заказа раньше onNotify
сохранил его, он перезаписывает все onNotify
писал со старыми данными
(Возможно, обратный порядок также может быть проблематичным, где onNotify
может перезаписать любые данные, сохраненные в заказе Drupal Commerce за кулисами, если таковые имеются, во время по возвращению
запрос.)
Есть ли хороший способ справиться с этим, например, обойти состояние гонки, чтобы иметь возможность сохранять данные заказа в onNotify
?
Я использую Друпал 8.6.