Jump to content

How to set order status on return from external payment gateway


James Ellerman

Recommended Posts

I am running CubeCart v6, and have been writing a payment gateway module to interface with Paypal's Payflow Link website.  Payflow Link is simply an external web page that takes an HTTP POST with various variables like a transaction value, merchant details, or any other values I choose sent to it from CubeCart, and presents fields to accept the user's credit card details.  On completion of processing on the Payflow Link website, Payflow Link can be configured to perform either an HTTP GET or HTTP POST back to a URL on the CubeCart website with an AUTHCODE value (0 = success, >0 means failure).  Payflow Link can also be configured to return any of the values that were sent to it by CubeCart for that transaction (eg: CubeCart order ID, or anything else you want to have returned back to you that originally came from CubeCart).

Currently, I have managed to get this payment gateway working, up to the point that Payflow Link sends back an HTTP POST to CubeCart with the transaction details, including the original CubeCart order ID, to a separate PHP script I have created that currently just redirects to CubeCart at /index.php?_a=complete&cart_order_id=$cart_order_id".  This successfully clears the user's cart, and displays a nice page saying that the order is pending, which is all well and good, as the order is in the system with a PENDING status.

The problem I have been stuck on is how to change the order status from PENDING to either PROCESSING or DECLINED, depending on the AUTHCODE variable and CubeCart order ID that is sent back from the Payflow Link website.  If this could be done with a simple HTTP POST to index.php, or some other module, that would be nice and simple.  At present, the current setup would require the admin to manually check the Payflow reports and reconcile the CubeCart order ID with the Payflow transaction log, and manually change the order status in CubeCart according to whether the credit card transaction is listed as successful or not. 

Note that I am a novice with PHP and CubeCart, having never programmed in this language before (or any language for the last 20 years for that matter), so I'm pretty pleased to have made it this far!

I have tried using pieces of code that I have found in other modules, without luck, as there appears to be classes and functions that are available in calling modules that are not available when a module is run directly from an HTTP POST.  I have tried including the order.class.php module and then call the function orderStatus that I believe should be able to modify the status, but I get "Call to member function get() on a non-object in /order.class.php" errors in the error.log file (this is where my understanding of how PHP works begins to break down).

If there is not an HTTP POST method to change the order status (when I have the CubeCart order ID as a variable), could someone assist with some code that could allow my PHP module to change the order status when all I have are variable values like order ID?  Note that I can pass anything I like to Payflow and get it echoed back to my module through an HTTP POST from Payflow in the return URL.

Alternatively, is there a better way of doing this, either with HTTP GET or HTTP POST from Payflow?

Link to comment
Share on other sites

In this setup, the payment processor returns a "remote message". CubeCart has existing code that watches for an RM and will initialize the specified module. The URL that the payment gateway will use is:

$GLOBALS['storeURL']/index.php?_g=rm&type=gateway&cmd=process&module=Payflow

where $GLOBALS['storeURL'] is your store's web address and Payflow is the name of the folder that has the gateway code (which may be Playflow or Payflow_Link - whichever, do not use spaces). If the processor uses GET, then there will be additional key/values appended after the module value.

In the gateway class, there will be a function called process() that matches the cmd parameter above. You can then use the GET or POST key/values (e.g., AUTHCODE) to decide what you want to do.

Somewhere in the gateway class, you will need to instantiate the Order class. This can be done in the class declarations:

class Gateway {
	private $_module;
	private $_basket;
    private $_order_class;
    
	public function __construct($module = false, $basket = false) {
		$this->_module	= $module;
		$this->_basket =& $GLOBALS['cart']->basket;
		$this->_order_class = Order::getInstance();
	}

or instantiate it directly in the process() function:

		$order = Order::getInstance();

In the process() function, when deciding what you want to do based on the result of the transaction, you will call at least these two methods:

$order->orderStatus(Order::ORDER_PROCESS, $cart_order_id);
$order->paymentStatus(Order::PAYMENT_SUCCESS, $cart_order_id);

where ORDER_PROCESS is any of the constants of the Order class.

Link to comment
Share on other sites

Sir, you are a legend!  Thanks so much for taking the time to post this information, I now have a fully functioning module! It was those little details about the return URL and which modules called which that made all the difference.

I would like to share this module in case there is anyone else who may want to use it, since it was created using other modules as templates, along with your advice.  There may only be a few people who may need or use it, but as I have struggled to find many e-commerce solutions that offer a Paypal Payflow Link shipping module, it may provide a solution for them.

Any idea what the official process is to verify and actually share this code?  I have also attached the module to this post (use at your own risk).

 

 

Link to comment
Share on other sites

  • 2 weeks later...

On further testing, it would appear there is some more work that I need to do to complete this module.  Currently, for Payflow Link to correctly process a failed transaction, it needs to be able to send the HTTP POST to the Cubecart website, and receive a "200 OK" reply from Cubecart.  There appears to be a problem with Payflow Link receiving this OK message back from Cubecart.

Presently, the Payflow Link return message is sending a POST to /index.php?_g=rm&type=gateway&cmd=process&module=Payflow along with numerous other fields, including &DESCRIPTION=$cart_order_id, and &RESULT=$result, which I use in the payment gateway module to link the original order.  Because Payflow must be configured to do a silent POST message and receive a 200 OK message in return, when it does not receive this, it voids the credit card transaction, but sets the status of the Cubecart order to PROCESSING.

Is the missing 200 OK return code something that needs to be added to the payment processing module, or is this something that Cubecart needs to do but does not (or requires a configuration change to be able to do)?  How do I get Cubecart to send an OK message in reply to the Payflow POST message?

Link to comment
Share on other sites

There is a module for UPG that does this. I don't know how up to date the coding is, but it is a solution.

For PayFlow, then, essentially, the return message URL will point to /modules/gateway/Payflow/class.php. The code in this file will add to PHP's $_GET array what there is now for the ReturnURL (use cmd=call instead of cmd=process). Then it will include() CubeCart's index.php file which simulates CubeCart receiving the postback from Payflow.

Picking up normal processing at this point, Payflow's call() function (need to move the code from process() to call() function) will determine the transaction state and update the order's status.

Payflow's call() then loads a header("HTTP/1.1 200 OK") and returns out of the function true, where CubeCart finishes up.

Thus, Payflow gets its 200 OK message.

Link to comment
Share on other sites

I think that's done it.  There is some strange behaviour on the Payflow side that makes users get stuck in the Payflow page when a transaction is declined. Rather than presenting them with a button to return back to the store, it only gives them a back button to re-enter their credit card details.  As such, their store cart is not cleared, but on the plus side, a silent URL return sets the status on the order to DECLINED, which is good.  I'll need to work out if there is a way to fix the Payflow side of things.

I will update the Payflow module to 1.0.1, and post it on to the plugins store.  Instructions on how to set the Payflow URL will be included in that file.

Thanks again :)

 

 

 

 

Link to comment
Share on other sites

For the information of those reading this post, my further testing showed that the URLs that are automatically embedded into the emails sent to customers end up all messed up when information is merged into the return URL (they have /modules/gateway/payflow added to them.  

Fortunately, Payflow Link has the option to ignore the 200 OK return code from Cubecart, but the information above allowed me to correct a problem with the version 1.0.0 of the module to allow the payment module to update the status of the order correctly if the Payflow transaction failed.  I did this by having a separate function to process the order, and another to silently update the status using a silent POST within Payflow to update the status.  That way, we simply return to the index.php code with either cmd=process or cmd=call used, depending on whether we are updating the order status (silent post) or returning the user to the store site (post).

Instructions for use are with the plugin in the plugin marketplace.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...