覆盖frontcontroller或modulefrontcontroller init()方法以进行检出

Aur*_*ora 8 php prestashop prestashop-1.6 prestashop-1.7

我的问题如下.我为prestashop 1.7创建了一个支付模块.验证订单//在启动付款时创建.这通过使用validateOrder方法在payment.php控制器中发生:

        $this->module->validateOrder(
                (int) $cartId,
                $this->module->statuses[$orderStatus],
                $prestaTotal,
                'paymentmodule',
                null,
                array(),
                null,
                false,
                $customer->secure_key
                );
Run Code Online (Sandbox Code Playgroud)

因此,创建了新订单,现在购物车与订单相关.并且客户被重定向到支付提供商.他们可以付钱,或按"取消"按钮.

webhook.php从支付提供商处收到订单状态,并在prestashop中更新订单状态.如果订单已付款,则会将其重定向到订单确认页面.但如果它被取消,那么购物车就不见了.

发生这种情况,因为prestashop检查订单是否存在.如果是这样,购物车将被删除.FronController.php中的init()方法负责:

/* Cart already exists */
    if ((int) $this->context->cookie->id_cart) {
        if (!isset($cart)) {
            $cart = new Cart($this->context->cookie->id_cart);
        }

        if (Validate::isLoadedObject($cart) && $cart->OrderExists()) {
            PrestaShopLogger::addLog('Frontcontroller::init - Cart cannot be loaded or an order has already been placed using this cart', 1, null, 'Cart', (int) $this->context->cookie->id_cart, true);
            unset($this->context->cookie->id_cart, $cart, $this->context->cookie->checkedTOS);
            $this->context->cookie->check_cgv = false;
        }
Run Code Online (Sandbox Code Playgroud)

所以我在return.php控制器中创建了一个Method来制作属于现有订单的购物车的副本,所以你有一个新的购物车:

class PaymentModuleFrontController extends ModuleFrontController
{

    public function initContent()
    {
        parent::initContent();
        $cartId = Tools::getValue('cart_id');
        $cart = new Cart((int) $cartId);
        $data['info'] = $this->module->getPaymentBy('cart_id', (int)$cartId);
                $orderId = Order::getOrderByCartId($cartId);
                $orderStatus = $data['info']['bank_status'];

                if (Validate::isLoadedObject($cart) && 
                $cart->OrderExists() && 
                $orderStatus === 'cancelled')
                {
                    $oldCart = new Cart(Order::getCartIdStatic($orderId, $this->context->customer->id));
                    $duplication = $oldCart->duplicate();
                    if (!$duplication || !Validate::isLoadedObject($duplication['cart'])) 
                    {
                        $this->errors[] = Tools::displayError('Sorry. We cannot renew your order.');
                    } 
                    elseif (!$duplication['success']) 
                    {
                        $this->errors[] = Tools::displayError('Some items are no longer available, and we are unable to renew your order.');
                    } 
                    else 
                    {
                        $this->context->cookie->id_cart = $duplication['cart']->id;
                        $context = $this->context;
                        $context->cart = $duplication['cart'];
                        CartRule::autoAddToCart($context);
                        $this->context->cookie->write();
                        if (Configuration::get('PS_ORDER_PROCESS_TYPE') == 1) 
                        {
                            Tools::redirect('index.php?controller=order-opc');
                        }
                    Tools::redirect('index.php?controller=order');
                    }   

                }
      }
Run Code Online (Sandbox Code Playgroud)

将创建购物车的副本,然后将其重定向到结帐.

如此苛刻,购物车没有消失(如果购物车有订单通常会发生),他们可以选择不同的付款方式,并创建一个全新的订单.

但是,客户也可以在支付提供商页面上按下浏览器的"返回上一页"按钮.

在此输入图像描述

他们将被重定向回结账,但在这种情况下,我的方法没有被调用,因此购物车已经消失.发生这种情况是因为调用了Frontcontroller.php中的init()方法.并且由于订单已经过验证//已创建,因此购物车会被删除.

所以,我在支付模块中添加了一个名为checkout的新控制器:

$this->controllers = array('payment, return, webhook, checkout');
Run Code Online (Sandbox Code Playgroud)

并将checkout.php放在我的模块的文件夹controller/front中.

我扩展了类FrontController并为init()方法创建了一个覆盖.我的代码:

class PaymentModuleFrontController extends FrontController
{

    public function init()
    {

        $data = array();
        $cartId = $this->context->cart->id;
        $cart = new Cart($cartId);
        $orderId = Order::getOrderByCartId($cartId);
        $data['info'] = $this->module->getPaymentBy('cart_id', (int)$cartId); //gets payment from db. I checked it and this is correct
        $orderStatus = $data['info']['status']; //gets the status. I checked it and it's correct

        if (Validate::isLoadedObject($cart) && 
        $cart->OrderExists() && 
        $orderStatus === 'open') 
        {
            $oldCart = new Cart(Order::getCartIdStatic($orderId, $this->context->customer->id));
            $duplication = $oldCart->duplicate();
            if (!$duplication || !Validate::isLoadedObject($duplication['cart'])) 
            {
                $this->errors[] = Tools::displayError('Problem duplicating cart.');
            } 
            elseif (!$duplication['success']) 
            {
                $this->errors[] = Tools::displayError('Problem duplicating cart.');
            } 
            else 
            {
                $this->context->cookie->id_cart = $duplication['cart']->id;
                $context = $this->context;
                $context->cart = $duplication['cart'];
                CartRule::autoAddToCart($context);
                $this->context->cookie->write();
                if (Configuration::get('PS_ORDER_PROCESS_TYPE') == 1) 
                {
                Tools::redirect('index.php?controller=order-opc');
              }
              Tools::redirect('index.php?controller=order');
            }
        }
        parent::init();

    }


}
Run Code Online (Sandbox Code Playgroud)

我不知道我做错了什么,因为这对我的返回控制器工作正常但是如果我用浏览器按钮回到上一页,它仍然会移除购物车.

我可以在结账/订单页面上使用的钩子中使用我的代码并将其添加到我的PaymentModule类中吗?

重要的是,我想在没有为FrontController.php创建覆盖文件的情况下建立它,因此必须使用模块控制器或我的支付模块Class来完成.

我希望有人可以帮我解决这个问题.

Wol*_*ack 1

您创建订单所遵循的方法不正确。您应该根据从支付提供商收到的响应来创建订单,而不是在用户重定向到支付提供商时创建订单。

这意味着仅当付款成功时才会生成订单,否则用户将在结帐页面上看到错误,并且购物车也将保持原样。

您所遵循的方法非常危险,因为您正在覆盖 PrestaShop 中每个页面上调用的方法,我的建议是您不应该这样做。