Magento - Единый купон, обозначенный как используемый при ожидании оплаты

У меня возникла проблема с единственным кодом купона Magento, который помечается как используемый в момент, когда клиент нажимает кнопку Разместить заказ. Если платеж Paypal не удался или клиент покинул страницу до завершения заказа, он не сможет вернуться и повторно заказать этот купон, который установлен только один раз и уже отмечен.

Я нашел фрагмент кода, который уменьшает количество раз, когда купоны использовались пользователем и позволяет ему повторно использовать купон. К сожалению, он получает сообщение об ошибке при попытке подключения страницы Paypal при нажатии кнопки выбора места. Чтобы иметь возможность использовать купон в другой раз и получить доступ к странице Paypal, мне необходимо удалить строки в базе данных SQL в таблицах salesrule_coupon_usage и salesrule_customer с этим идентификатором клиента.

Вот код, который мне нужно изменить, чтобы автоматически удалять информацию об использовании купона для идентификатора клиента:

public function cancel($observer)
{
    $order = $observer->getEvent()->getPayment()->getOrder();
    if ($order->canCancel()) {
        if ($code = $order->getCouponCode()) {
            $coupon = Mage::getModel('salesrule/coupon')->load($code, 'code');
            if ($coupon->getTimesUsed() > 0) {
                $coupon->setTimesUsed($coupon->getTimesUsed() - 1);
                $coupon->save();
            }

            $rule = Mage::getModel('salesrule/rule')->load($coupon->getRuleId());
            error_log("\nrule times used=" . $rule->getTimesUsed(), 3, "var/log/debug.log");
            if ($rule->getTimesUsed() > 0) {
                $rule->setTimesUsed($rule->getTimesUsed()-1);
                $rule->save();
            }

            if ($customerId = $order->getCustomerId()) {
                if ($customerCoupon = Mage::getModel('salesrule/rule_customer')->loadByCustomerRule($customerId, $rule->getId())) {
                    $couponUsage = new Varien_Object();
                    Mage::getResourceModel('salesrule/coupon_usage')->loadByCustomerCoupon($couponUsage, $customerId, $coupon->getId());

                    if ($couponUsage->getTimesUsed() > 0) {
                        /* I can't find any #@[email protected]$ interface to do anything but increment a coupon_usage record */
                        $resource = Mage::getSingleton('core/resource');
                        $writeConnection = $resource->getConnection('core_write');
                        $tableName = $resource->getTableName('salesrule_coupon_usage');

                        $query = "UPDATE {$tableName} SET times_used = times_used-1 "
                            .  "WHERE coupon_id = {$coupon->getId()} AND customer_id = {$customerId} AND times_used > 0";

                        $writeConnection->query($query);
                    }

                    if ($customerCoupon->getTimesUsed() > 0) {
                        $customerCoupon->setTimesUsed($customerCoupon->getTimesUsed()-1);
                        $customerCoupon->save();
                    }
                }
            }
        }
    }
}

Ответы

Ответ 1

Я считаю, что это была старая ошибка от 1.4 до 1.6. Но есть ли у вас старая версия или нет, это можно довольно легко устранить, если вы знаете свой путь вокруг Magento.

Проблема заключается в том, что у вас есть код, который обновляет таблицу salesrule_coupon_usage сразу, когда они нажимают кнопку оплаты. На самом деле это совсем не то, чего вы хотите. Вы хотите, чтобы это было включено в транзакцию платежа. Я не знаю, происходит ли эта ошибка, потому что у вас есть собственный код или используется более старая версия Magento, но я расскажу вам, как я исправлю проблему. Тогда я дам вам исправление, подобное тому, что вы предложили:

Magento уже имеет абстракцию, называемую "транзакцией". Транзакция используется для объединения и группирования объектов, которые необходимы либо всем, либо всем, либо не выполняются, а не полумеры. Magento проведет транзакцию и попытается сохранить каждый из объектов, которые вы разместили в ней. Если какой-либо из них не работает (например, оплата не проходит), все события, которые уже были сохранены, "откат".

К счастью, Magento уже создает объект транзакции для обработки платежа за различные вещи, которые необходимо обновлять вместе при успешной оплате. Вы можете использовать эту транзакцию и использовать ее для правильного обновления использования купона.

Вот вам 10 000 футов, что вам нужно сделать.

  • Найти то, что обновляет таблицу salesrule_coupon_usage слишком рано и убить. Мы собираемся добавить нашу собственную безопасную для транзакции версию, поэтому мы не хотим, чтобы она была сохранена в другом месте. Самый простой способ сделать это - выяснить, какая модель подключается к этой таблице и искать создание этой модели. Для 1.7 и 1.8 это модель правила/клиента.
  • Создайте наблюдателя, чтобы поймать начало транзакции платежа. В большинстве современных версий magento это событие называется sales_order_payment_place_start и может быть засвидетельствовано в app/code/core/Mage/Sales/Model/Order/Payment.php
  • Вытяните заказ из события и вытащите код купона из события.
  • Потяните фактическую модель, которую вы хотите обновить. Похоже, кто-то не смог найти его в вашем коде, но должна быть какая-то модель, которая где-то скрывает таблицу salesrule_coupon_usage. Найдите хотя .xml файлы для "salesrule_coupon_usage" и посмотрите, какая модель использует эту таблицу. Опять же, для меня, на 1.7, это модель правила/клиента.
  • Загрузите эту модель, при этом клиент изменит значение, в котором ваш код купона будет указывать на то, что клиент использовал купон, но не сохраняет его.
  • Вывести транзакцию из события и зарегистрировать обновленный объект купона с помощью метода addObject.

И твоя работа. Транзакция автоматически попытается сохранить все объекты, которые были добавлены к ней. Если какая-либо часть не удалась (включая неудачный платеж), она откатит весь процесс, и ваш купон не будет использоваться. Ура!

Теперь, на мой взгляд, это лучший способ справиться с этой проблемой, но если у вас возникли проблемы по какой-то причине, вот альтернатива, основанная на улавливании неуспешного платежа и последующем использовании вашего кода.

Опять же, здесь вид 10 000 футов:

  • Создайте наблюдателя, чтобы поймать неудавшееся событие платежа. В большинстве версий событие, которое вы хотите, - sales_order_payment_cancel.
  • Запустите код, который у вас есть... он должен это сделать. Но прояснить для других:
    • Вытяните заказ из события, вытащите код купона и идентификатор клиента.
    • Обновите таблицу клиентов, правил и salesrule_coupon_usage. (Хотя для этого действительно должна быть модель, я уверен, что вы ее можете найти)

Теперь, когда продажа не удалась, вы возвращаетесь назад и разматываете все вручную. Это не так чисто, как мое первое решение, но может быть проще для вас в зависимости от вашего знакомства с Magento.

Я уверен, что новые, чистые версии Magento не имеют этой проблемы, поэтому позвольте мне предложить довольно очевидное предложение в качестве третьего решения.

  • Обновить Magento
  • Если Magento обновлен, попробуйте отключить какие-либо пользовательские модули, потому что что-то сломало его. Я заметил, что плагины купонов Amasty особенно неэффективны.
  • Если вы внесли пользовательские изменения в ядро ​​Magento... удачи с этим.

Удачи!