Opencart cart not cleared after Paypal purchase

Yesterday we had a customer complaining that when they logged on to Opencart to place an order, their previous order was still showing in their cart.

On investigation, this occurs where a customer makes a Paypal payment, but then does not return to Opencart after completing the Paypal transaction. In fact most of our customers seem to do this – why bother returning, I suppose. However, it’s the checkout/success page which clears the customer’s cart. In the absence of this, the cart remains stored against the customer’s record, and hence appears next time they log on.

Now, this has never been mentioned before, and this particular Opencart installation has been live for over 18 months, so it’s obviously not a massive issue, but it’s still not quite what you’d want. We’re still running a (heavily customised) OC 1.4.9.5, but in fact the problem remains on OC 1.5.4, and presumably, although I haven’t tested, with any other payment gateway where the payment is handled offsite.

It seemed to me that it would be better to clear the cart when the IPN message is returned from Paypal (this is what sets the order status and updates stock etc). The important cases are where a payment comes through as Completed, or as Pending (complete but waiting Paypal confirmation), so I edited catalog/controller/payment/pp_standard.php, adding the code in red:

		switch($data['payment_status']){
			case 'Completed':
				if ($this->order_info['customer_id']){//only run this if the customer has created an account, not for guest checkouts
					$this->model_checkout_order->clearCustomerCart($this->order_info['customer_id']);
				}
				if ($verified) {
					if ($this->order_info['order_status_id'] == '0') {
						$this->model_checkout_order->confirm($order_id, $this->config->get('pp_standard_order_status_id'), 'Thank you for your Paypal payment');
					} elseif (isset($data['payment_type']) && $data['payment_type'] == 'echeck') {
						$this->model_checkout_order->update($order_id, $this->config->get('pp_standard_order_status_id'), $data['payment_status'], TRUE);
					} elseif ($this->order_info['order_status_id'] != $this->config->get('pp_standard_order_status_id')) {
						$this->model_checkout_order->update($order_id, $this->config->get('pp_standard_order_status_id'), $data['payment_status'], FALSE);
					}

and similarly, a little further down:

			case 'Pending':
				if ($this->order_info['customer_id']){
					$this->model_checkout_order->clearCustomerCart($this->order_info['customer_id']);
				}
				if ($this->order_info['order_status_id'] == '0') {
					$this->model_checkout_order->confirm($order_id, $this->config->get('pp_standard_order_status_id_pending'), 'This payment is subject to a review by Paypal');
				} else {
					$this->model_checkout_order->update($order_id, $this->config->get('pp_standard_order_status_id_pending'), $comment, TRUE);
				}
				break;

In turn, this calls the following code appended to catalog/model/checkout/order.php:

	public function clearCustomerCart($customer_id){
	
		$this->db->query("UPDATE `" . DB_PREFIX . "customer` SET cart = '' WHERE customer_id = '" . (int)$customer_id . "'");
		$this->session->data['cart'] = array();
	
	}

I’ve shown here direct edits in OC1.4.9.5, but you could just as easily apply this via vQmod. This fix has now been working for several weeks with no problem.

vQmod for OC1.5.x

This code works with minor adjustments in OC1.5.x. Here’s a vQmod, tested in OC1.5.6.1:

<modification>
	<id>vQmods for Opencart mobile theme</id>
	<version>For OC 1.5.6</version>
	<vqmver>1.0</vqmver>
	<author>Simon Battersby</author>
	<file name="catalog/controller/payment/pp_standard.php">
		<operation>
			<search position="after"><![CDATA[$order_status_id = $this->config->get('pp_standard_completed_status_id');]]></search>
			<add><![CDATA[
				//Completed status
				$this->clearCustomerCart($order_info['customer_id']);
			]]></add>
		</operation>
		<operation>
			<search position="after"><![CDATA[case 'Pending':]]></search>
			<add><![CDATA[
				//Completed status
				$this->clearCustomerCart($order_info['customer_id']);
			]]></add>
		</operation>
		<operation>
			<search position="after" offset="2"><![CDATA[curl_close($curl);]]></search>
			<add><![CDATA[
				//function to clear cart
				public function clearCustomerCart($customer_id){
				
					if($customer_id){
						$this->db->query("UPDATE `" . DB_PREFIX . "customer` SET cart = '' WHERE customer_id = '" . (int)$customer_id . "'");
						$this->session->data['cart'] = array();
					}
				
				}			
			]]></add>
		</operation>		
	</file>
</modification>

Linked to this, I also noticed that the default session expiry, set via php.ini is 138 days:

session.gc_maxlifetime = 12000000;

This seems excessive….I’ve set mine to the more reasonable 24 hours.

Tags:

9 responses to “Opencart cart not cleared after Paypal purchase”

  1. Simon says:

    Was this a one-off problem – in that other orders have been processed OK? If so it’s probably due to a temporary network problem or a problem at your server. Check your error log for any record of the transaction.

    If it’s happening all the time then there’s a problem with your setup somewhere.

    When the Paypal transaction is completed, Paypal sends an IPN message to your server which is processed independently from anything the customer subsequently does. This message generates emails and changes the status of the order.

  2. Drago says:

    Opencart 1.5.6.x after payment with paypal standard there is no order.

    Order is in “missing orders”

    can you help me?

    many people have problem with this

  3. Mac says:

    Superb Simon, thank you very much. There is an existing extension called ‘Force Clear Cart’ which handles the session data, checking on login whether your session contains a cart with the same ID as a previous order, and clearing if so. Combined with your code above I think it’s all covered.

  4. Simon says:

    Yes, see the vQmod above.

  5. steve says:

    Hi Simon, i am having the same problem with customers carts not clearing using paypal if they close there browser before being redirected to the site, is there a fix for 1.5.5.1
    regards
    steve

  6. Simon says:

    Hi James
    The code needs some minor tweaks for OC1.5.x, specifically the customer_id is accessed slightly differently. I’ve added a vQmod above which tests fine in OC1.5.6.1. Note that even though the cart is deleted, if the customer does not return to OC the session data is retained, so if the customer does return to OC without the session ending (e.g. by closing the browser) then the cart will still be shown. If the browser is closed and the customer subsequently logs back on to OC, then the cart will be empty.

  7. James Bean says:

    Thanks for sharing the code but it doesn’t seems to work in 1.5.6.1

  8. Simon says:

    John

    That sounds like you might have the edit to catalog/model/checkout/order.php right at the end of the file, after the final closing }. I think the following vQmod is what you want for OC 1.5.5.:

    	<file name="catalog/model/checkout/order.php">
    		<operation>
    			<search position="before"><![CDATA[public function update]]></search>
    			<add><![CDATA[
    				public function clearCustomerCart($customer_id){
    					
    						$this->db->query("UPDATE `" . DB_PREFIX . "customer` SET cart = '' WHERE customer_id = '" . (int)$customer_id . "'");
    						$this->session->data['cart'] = array();
    					
    				}		
    			]]></add>
    		</operation>
    	</file>

    Not tested, so if this doesn’t work, let me know.

  9. John says:

    Thanks for the post!
    This is still an issue with 1.5.5.1, and I haven’t been able to get your code changes to work yet, but that could be my fault as I’m no coder and might be putting the last snippet for catalog/model/checkout/order.php in the wrong spot.
    I placed it in a VQmod to be on the safe side, and keep getting a Parse error: syntax error, unexpected T_PUBLIC in /home/user/public_html/vqmod/vqcache/vq2-catalog_model_checkout_order.php on line 674

Useful? Interesting? Leave me a comment

I've yet to find a way of allowing code snippets to be pasted into Wordpress comments - so if you're trying to do this you'd be better off using the contact form.