Does anyone have a working example of Omnipay and Sagepay Server or Sagepay Direct (with 3D Secure)?

会有一股神秘感。 提交于 2019-12-08 08:01:42

问题


I'm struggling to get either to work and Omnipay doesn't come with much documentation. I've successfully used it for other payment gateways but not with Sagepay. I'm trying to integrate it into CodeIgniter but can work from examples in other frameworks - I'm getting desperate!


回答1:


Thanks to some great help on github (see comments in my original post for the thread link), I now have some workable code which I will share here in case it helps someone else in the future.

<?php 

use Omnipay\Omnipay;

class PaymentGateway  {

    //live details
    private $live_vendor = 'xxx';
    //test details
    private $test_vendor= 'xxx';

    //payment settings
    private $testMode = true;
    private $api_vendor = '';
    private $gateway = null;

    public function __construct()
    {
        parent::__construct();
        //setup api details for test or live
        if ($this->testMode) :
            $this->api_vendor = $this->test_vendor;
        else :
            $this->api_vendor = $this->live_vendor;
        endif;

        //initialise the payment gateway
        $this->gateway = Omnipay::create('SagePay_Server');
        $this->gateway->setVendor($this->api_vendor);
        $this->gateway->setTestMode($this->testMode);



    }


    public function initiate()
    {

        //get order details
        $orderNo = customFunctionToGetOrderNo(); //get the order number from your system however you store and retrieve it

        $params = array(
            'description'=> 'Online order',
            'currency'=> 'GBP',
            'transactionId'=> $orderNo,
            'amount'=> customFunctionToGetOrderTotal($orderNo)
        );


        $customer = customFunctionToGetCustomerDetails($orderNo);

        $params['returnUrl'] = '/payment-gateway-process/' . $orderNo .  '/'; //this is the Sagepay NotificationURL

        $params['card'] = array(
            'firstName' => $customer['billing_firstname'],
            'lastName' => $customer['billing_lastname'],
            'email' => $customer['billing_email'],
            'billingAddress1' => $customer['billing_address1'],
            'billingAddress2' => $customer['billing_address2'],
            'billingCity' => $customer['billing_town'],
            'billingPostcode' => $customer['billing_postcode'],
            'billingCountry' => $customer['billing_country'],
            'billingPhone' => $customer['billing_telephone'],
            'shippingAddress1' => $customer['delivery_address1'],
            'shippingAddress2' => $customer['delivery_address2'],
            'shippingCity' => $customer['delivery_town'],
            'shippingPostcode' => $customer['delivery_postcode'],
            'shippingCountry' => $customer['delivery_country']
        );


        try {
            $response = $this->gateway->purchase($params)->send();


            if ($response->isSuccessful()) :

                //not using this part

            elseif ($response->isRedirect()) :

                $reference = $response->getTransactionReference();
                customFunctionToSaveTransactionReference($orderNo, $reference);
                $response->redirect();

            else :
                //do something with an error
                echo $response->getMessage();

            endif;

        } catch (\Exception $e) {

            //do something with this if an error has occurred
            echo 'Sorry, there was an error processing your payment. Please try again later.';
        }



    }


    public function processPayment($orderNo)
    {

        $params = array(
            'description'=> 'Online order',
            'currency'=> 'GBP',
            'transactionId'=> $orderNo,
            'amount'=> customFunctionToGetOrderTotal($orderNo)
        );

        $customer = customFunctionToGetCustomerDetails($orderNo);


        $transactionReference = customFunctionToGetTransactionReference($orderNo);


        try {
            $response = $this->gateway->completePurchase(array(
                'transactionId' => $orderNo,
                'transactionReference' => $transactionReference,
            ))->send();

            customFunctionToSaveStatus($orderNo, array('payment_status' => $response->getStatus()));
            customFunctionToSaveMessage($orderNo, array('gateway_response' => $response->getMessage()));

            //encrypt it to stop anyone being able to view other orders
            $encodeOrderNo = customFunctionToEncodeOrderNo($orderNo);
            $response->confirm('/payment-gateway-response/' . $encodeOrderNo);

        } catch(InvalidResponseException $e) {
            // Send "INVALID" response back to SagePay.
            $request = $this->gateway->completePurchase(array());
            $response = new \Omnipay\SagePay\Message\ServerCompleteAuthorizeResponse($request, array());

            customFunctionToSaveStatus($orderNo, array('payment_status' => $response->getStatus()));
            customFunctionToSaveMessage($orderNo, array('gateway_response' => $response->getMessage()));

            redirect('/payment-error-response/');
        }



    }


    public function paymentResponse($encodedOrderNo)
    {
        $orderNo = customFunctionToDecode($encodedOrderNo);
        $sessionOrderNo = customFunctionToGetOrderNo(); 
        if ($orderNo != $sessionOrderNo) :
            //do something here as someone is trying to fake a successful order
        endif;
        $status = customFunctionToGetOrderStatus($orderNo);

        switch(strtolower($status)) :
            case 'ok' :
                customFunctionToHandleSuccess($orderNo);
            break;

            case 'rejected' :
            case 'notauthed' :
                //do something to handle failed payments
            break;

            case 'error' :
               //do something to handle errors

            break;

            default:

                //do something if it ever reaches here

        endswitch;


    }

 }



回答2:


I gave a talk last night about this, and have put the working demo scripts on github here:

https://github.com/academe/OmniPay-SagePay-Demo

SagePay Direct is a one-off action - OmniPay sends the transaction details and gets an immediate response.

SagePay Server involves a redirect of the user to the SagePay website to authorise the transaction using their card details. This API uses a notify message, where SagePay will call your application directly with the authorisation results. This happens outside of the user's session, and so requires the transaction to be stored in the database so it can be shared between the two transactions.

All this is in the scripts linked above. authorize.php will do the authorisation. Edit that to use SagePay\Direct or SagePay\Server to see how it works. The notification handler for SagePay\Server is sagepay-confirm.php and that ultimately sends the user to final.php where the result can be read from the transaction stored in the database.

The scripts are all commented and should make sense, but feel free to ask more questions about them here or in the issue tracker of that github repository.

I've not tried SagePay\Direct with 3D-Secure though. The scripts may need some modification to support that, assuming that combination is a thing.



来源:https://stackoverflow.com/questions/29370534/does-anyone-have-a-working-example-of-omnipay-and-sagepay-server-or-sagepay-dire

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!