My problem is as follows. I created a payment module for prestashop 1.7. The order is checked // created at the beginning of the payment. This happens in the payment.php controller using the validateOrder method:
$this->module->validateOrder( (int) $cartId, $this->module->statuses[$orderStatus], $prestaTotal, 'paymentmodule', null, array(), null, false, $customer->secure_key );
So, a new order is created, and now the cart is connected to the order. And the customer is redirected to the payment provider. They can pay or click the "Cancel" button.
Webhook.php receives the order status from the payment provider and updates the order status in advance. If the order is paid, they are redirected to the order confirmation page. But if it is canceled, the cart is gone.
This happens because prestashop checks if order exists. And if that happens, the cart will be removed. The init () method in FronController.php answers for this:
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; }
So, I created a method in the return.php controller to make a copy of the cart that belongs to an existing order, so you have a new cart:
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'); } } }
A copy of the basket will be created, it will be redirected for verification.
So, cheers, the cart didn’t go away (which usually happens if the order exists for the basket), they can choose a different payment method and create a new order.
But the client can also click the "back to previous page" button of the browser when they are on the page of payment providers.

They will be redirected back for verification, but in this case my method is not called, so the cart is gone. This is because the init () method in Frontcontroller.php is called. And since the order is confirmed // created, the cart is deleted.
So, I added a new controller in the payment module named checkout:
$this->controllers = array('payment, return, webhook, checkout');
and put checkout.php in the folder controllers / in front of my module.
I extended the FrontController class and created an override for the init () method. My code is:
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 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(); } }
I have no idea what I'm doing wrong, because it works fine for my return controller, but it will delete the trash anyway if I go back to the previous page using the browser button.
Can I use my code in the hook that is used on the checkout / order page and add it to my PaymentModule class?
importantly, I want to install this without creating an override file for FrontController.php, so I need to do this using the module controller or my Class payment module.
I hope someone helps me figure this out.