Подтвердить что ты не робот

Проблема с созданием промежуточного отложенного ордера

Я создал пользовательский модуль оплаты и в настоящее время он вызывает validateOrder() после перенаправления с веб-сайта платежа, и этот метод создает заказ, отправляет электронную почту и т.д. Но проблема в том, что пользователь закрыл веб-сайт платежа, прежде чем он сможет перенаправить обратно на сайт PrestaShop заказ не будет создан в этом случае. Итак, я хочу создать заказ (скажем, с статусом "pending"), прежде чем перенаправить на сайт оплаты и после перенаправления с веб-сайта платежа я могу просто отметить тот же платеж, что и сделанный, и отправить письма и т.д.

В настоящее время для этого я пытался дважды вызвать validateOrder, один раз в hookdisplayPayment (здесь я установил статус как "pending") и один раз после перенаправления. Но теперь, после перенаправления, я получаю: "Тележка не может быть загружена или заказ уже размещен с помощью этой тележки". Я думаю, что потому, что я не могу обновить один и тот же порядок дважды, используя тот же идентификатор карты.

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

Какое хорошее обходное решение для этого?

Я бы хотел поддерживать версии 1.5+ и 1.6+, если это имеет значение.

4b9b3361

Ответ 1

Лучший способ сделать это, чем мой первый ответ, - создать переопределение в вашем модуле функции validateOrder. Вы будете изменять:

/** @var Order $order */
$order = new Order();

В:

/** @var Order $order */
$order = new Order($this->currentOrder);

Затем проверьте, загружен ли объект, пропустите часть, где он устанавливает поля порядка. Если он не загружен, установите соответствующие поля порядка с ожидающим статусом. Также проверьте, установлено ли $this- > currentOrder, куда отправляется электронное письмо, если оно не задано, пропустите часть электронной почты. Если он установлен, это означает, что заказ находится на рассмотрении, и вы должны изменить статус и отправить электронное письмо.

После переопределения функции вы можете вызвать validateOrder дважды, до и после перенаправления.

Ответ 2

Вы можете попробовать что-то вроде этого:

Перед выполнением перенаправления вы можете вызвать функцию validateOrder и установить статус как pending. Это установит для вашего модуля переменную $this->currentOrder с идентификатором отложенного ордера. После перенаправления не вызывайте снова validateOrder, но создайте свою собственную функцию для вызова, например. validateOrderAfterRedirect, в котором вы проверяете, был ли произведен платеж, и измените статус текущего заказа. Это будет примерно так:

// your way of checking that te payment was made
$payment_completed = $this->paymentIsComplete();
if($payment_completed) {
    $order = new Order($this->currentOrder);
    if(Validate::isLoadedObject($order) && $order->getCurrentOrderState() == [id of pending status]) {
        $order->setCurrentState([id of payment accepted status]);
    }
}

Ответ 3

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

Ответ 4

Многие платежные шлюзы предоставляют механизм, в котором при завершенном или неудачном платеже они отправляют данные, включая оплаченную сумму и идентификатор корзины, к URL-адресу, который вы им предоставляете.

При обработке этой информации с помощью серверной стороны script на этом этапе вы можете проверить порядок. Это должно произойти до того, как пользователь будет перенаправлен обратно на ваш сайт. Как только они будут перенаправлены на ваш сайт, у него уже будет подтвержден платеж в фоновом режиме.

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

Ответ 5

Вы можете сделать это, добавив несколько таких

$result = $this->validateOrder((int) $cart->id, Configuration::get('PPQ_CREATED_STATUS'), $total, $this->displayName, NULL, array(), (int) $currency->id, false, $customer->secure_key);

в любых играх, где вам нужно до перенаправления (где $это экземпляр платежного модуля)

И после перенаправления на страницу подтверждения у меня есть использование этого

public function hookPaymentReturn($params)
{
    $id_module = (int) Tools::getValue('id_module');
    if ($id_module === (int) $this->id) {
        $orderHistory = new OrderHistory();
        $orderHistory->changeIdOrderState(Configuration::get('PPQ_SUCCESS_STATUS'), $params['objOrder']);
    }
}

Для отправки почты вы можете настроить необходимый статус заказа

Для моего случая (нужно работать только с paypal, у меня есть изменение, напишите мой собственный модуль проверки на одну страницу и напишите мой собственный платежный модуль и befour redirect to paypal, я написал это

public function hookPayment($params)
{
    $customer = &$this->context->customer;
    $cart = &$this->context->cart;
    $currency = &$this->context->currency;
    if (
            $customer->isLogged(true) &&
            $cart->nbProducts()
    ) {
        $total = (float) $cart->getOrderTotal(true, Cart::BOTH);

        $result = $this->validateOrder((int) $cart->id, Configuration::get('PPQ_CREATED_STATUS'), $total, $this->displayName, NULL, array(), (int) $currency->id, false, $customer->secure_key);
        if ($result) {
            if (!Configuration::get('PPQ_TEST_MODE')) {
                $paypal_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=' . Configuration::get('PPQ_PROFILE');
            } else {
                $paypal_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_xclick&business=' . Configuration::get('PPQ_PROFILE');
            }
            $order_confirmation_url = $this->context->link->getPageLink('order-confirmation', null, null, array(
                'id_cart' => (int) $cart->id,
                'id_module' => (int) $this->id,
                'id_order' => (int) $this->currentOrder,
                'key' => $customer->secure_key,
            ));
            $this->context->smarty->assign(array(
                'paypal_url' => $paypal_url,
                'order_confirmation_url' => $order_confirmation_url,
                'order_id' => (int) $this->currentOrder,
                'shop_name' => $this->context->shop->name,
                'total_without_shipping' => Tools::convertPriceFull((float) $cart->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING)),
                'total_shipping' => Tools::convertPriceFull((float) $cart->getOrderTotal(true, Cart::ONLY_SHIPPING)),
                'currency_iso' => Tools::strtoupper($currency->iso_code)
            ));
            return $this->display(__FILE__, 'paypalquick.tpl');
        } else {
            $this->context->controller->errors[] = $this->l('Can\'t create order. Pleas contact with us');
        }
    } else {
        $this->context->controller->errors[] = $this->l('Problem with loginin or cart empty');
    }
}

и tpl

<form id="paypalquick" action="{$paypal_url}" method="post" enctype="multipart/form-data">
<input type="hidden" value="{l s='%s order #%s' sprintf=[$shop_name|escape:'html':'UTF-8', $order_id|intval] mod='paypalquick'}" name="item_name"/>
<input type="hidden" value="{$total_without_shipping}" name="amount"/>
<input type="hidden" value="{$total_shipping}" name="shipping"/>
<input type="hidden" value="{$currency_iso}" name="currency_code"/>
<input type="hidden" value="{$order_confirmation_url}" name="return"/>
<div class="text-center">
    <button class="submit">{l s='Go to PayPal for payment' mod='paypalquick'}</button>
</div>

Но это был мой частный cas, вы не можете использовать его по умолчанию, но вы можете видеть, как это сделать.

Ответ 6

Я думаю, нам нужно, чтобы вы вызывали еще один крючок (который вы создавали) во время проверки на сайте (перед тем как оставить это дело), ​​который положил статус ожидания, и сохраните hooked() ValidateOrder() до подтвержденного платежа

Привет,

Артур