У клиента сайт на wordpress + woocommerce, внутри множество модулей (которые в админке выдают уведомления разного рода notice
- error
, просто трэш) среди которых модуль интернет-эквайринга от Тинькофф Банк.
Наш модуль реагирует на хуки woocommerce и осуществляет на основании этого свою работу. Однако, логика модуля зависит от того, как отработает модуль эквайринга ... и как следствие все работало не так как надо.
Доступа к ЛК клиента экваринга банка нет, так же нет доступа по ftp
и к базе данных сайта клиента, однако, есть наш модуль на сайте клиента, который может обновляться, и есть доступ к админке.
На протяжении всего процесса решения проблем включили не раз проверенный метод отладки print_r/file-put-contents, из-за чего выкатили 15 патчей за 2 дня (на самом деле их было больше, потому что иногда забывали обновлять патч-версию, в следствии чего приходилось переустанвливать модуль).
Проблемы конечно решены, клиент доволен, но само решение на скорую руку, которое естественно будет переделываться.
Первым делом выяснилось что экваринг в ЛК банка был не полностью настроен (юзеры такие юзеры), из-за чего не приходили http
уведомления о приеме оплаты. После включения этой функции модуль все-равно не хотел работать так как ожидалось - пришлось лезть в код модуля эквайринга и смотреть (исходники можно взять здесь).
В модуле интернет-эквайринга при
http
нотификации (на файлsuccess.php
) в случае успешно проведенной оплаты, нет вызова хука woocommerce_payment_complete, который вызывается payment_complete методом объекта WC_Order, что не давало нашему модулю фискализации обработать совершение платежа в интернет-магазине клиента.
Также нет информации об идентификаторах транзакций (внутри банка) совершенных клиентом, что делает почти невозможным отслеживание оплат для других модулей (все-таки есть).
Однако, модуль эквайринга производит смену статуса заказа, если такая опция включена в настройках. Полагаться на обновление статуса заказа нам показалось сомнительной идеей, но с другой стороны мы не можем вмешиваться в код модуля эквайринга (можем только составить рекомендацию к реализации для банка, с примером).
Совершенно случайным образом был найден лог файл внутри модуля эквайринга, в который модуль записывает данные о проведенных платежах (кстати файл общедоступный, что не очень конфиденциально).
Проверив другие места мы убедились что нет иного источника о транзакциях кроме лога, и решили временным решением сделать обработку этого файла (да, жуткий костыль), каждый раз когда происходит оплата.
Однако, если полагаться на этот файл, то это замедлит работу сайта, так как файл не очищается и со временем будет становится все больше и больше, но перед нами стояла задача за 3 дня в промежутках между основной работой решить проблему любой ценой.
Реализация этого костыля так же была не без прикола. Оказалось что при http
оповещении сайта со стороны банка, скрипт модуля эквайринга на сайте ставит свой обработчик ошибок:
set_error_handler('exceptions_error_handler', E_ALL);
function exceptions_error_handler($severity)
{
if (error_reporting() == 0) {
return;
}
if (error_reporting() & $severity) {
die('NOTOK1');
}
}
И так как это wordpress
с кучей плагинов (естественно возникают ошибки уровня ниже критичности E_ERROR), очень часто обработчик заходит во вторую ветку условия и не дает отработать другим модулям, в том числе нашему.
На помощь пришел другой костыль error_reporting(0) прямо в нашем модуле, чтобы заткнуть обработку ошибок и не давать скрипту возможности упасть с ошибкой.
Эта идея плоха сама по себе, но в такой среде видимо это единственный вариант.
Проблема с клиентом решена, можно сдавать работу, но очень захотелось и руковдство попросило надо эту проблему как-то решить уровнем выше - на стороне модуля эквайринга. Поэтому следующей задачей была разработка решения проблем, которые привносил данный модуль экваринга банка, с сохранением концепции этого модуля, но с правильной работой, без авторитарного подхода к контролю ошибок.
В первую очередь нужно решить обработку ошибок, но так как с wordpress
и woocommerce
на таком глубоком уровне я работал впервые, то затык в виде error_reporting(0)
временно закрыл эту проблему, и начались выяснения как правильно фикировать оплату и сохранять статусы.
Модуль эквайринга осуществляет обработку статуса заказа так:
if ($request['Status'] === 'CONFIRMED' && $settings['auto_complete'] === 'yes') {
$order_status = 'wc-completed';
}
$order->update_status($order_status);
do_action('woocommerce_order_edit_status', (int)$request['OrderId'], $order_status);
Здесь видно что модуль использует вызов хука woocommerce_order_edit_status, который не вызывается из set_status, который должен вызваться из update_status потому что модуль не сообщает что это manual/ручное изменение статуса.
Подписавшись на хук
woocommerce_order_edit_status
можно узнать статус заказа, но нельзя узнать о статусе оплаты (потому что нет фиксации посредствомpayment_complete
). Если копнуть глубже, то можно узнать о способе оплаты (есть инфа о том, что оплата прошла через банк), но статуса все-равно не найти.
Так как банк присылает http
уведомления не только об успешной оплате, но и промежуточные этапы ее осуществления, то надо оставить возможность смены статуса заказа и отдельно смену статуса оплаты:
if ($request['Status'] === 'CONFIRMED') {
if($settings['auto_complete'] === 'yes') {
$order_status = 'wc-completed';
$order->set_status($order_status);
}
$order->payment_complete($request['PaymentId']);
}
else {
$order->set_status($order_status);
$order->save();
}
Теперь настал момент решения следующей проблемы: демократизировать обработчик ошибок, сделать его более лояльным к wordpress и плагинам.
Ранее мы уже выяснили что в продакшене интернет-магазин может вполне работать на этом движке, даже если внутри есть ошибки ниже уровня критичности E_ERROR
, поэтому немного изменил обработчик:
set_error_handler('exceptions_error_handler', E_ALL);
function exceptions_error_handler($errno, $errstr, $errfile, $errline)
{
if (error_reporting() == 0 || $errno != E_ERROR) {
return;
}
die('NOTOK1');
}
Теперь если вообще отключен вывод ошибок или ошибки уровня не E_ERROR
, то обработчик будет их пропускать, а на E_ERROR
будет реагировать как и раньше.
Протестировав множество раз, правленный модуль подружился с wordpress и другими модулями, в том числе и с нашим :)
Проблема клиента при использовании нашего модуля фискализации продаж с интернет экрвайрингом решена. Письмо банку сформированно, предлагаемые правки модуля эквайринга написаны. Осталось передать банку данные и ожидать реакции :)
UPDATE 25.07.2021
С момента написания статья вышло несколько обновлений модуля, обработка ошибок исправлена, однако сохранение статуса оплаты так и не появилось.