Creating Your Own Payment Gateway For Magento – Part 2

So in my previous blog, I had mentioned about an admin panel and basic configuration for creating a simple module. This is the second part and I will try to explain you how you can implement your own payment gateway and getting the values we have set on the database. If you have not read the first part, go take a look.

So we have three things to do now: First we should create something which will handle the payment, define the “thing” we have done in the configuration and finally an html file which will hold specific forms for us. However the third one is optional.

So first let’s get to the configuration file. As you know remember our moduleCreator had already created an etc/config.xml file for us. So we open it up and add these lines under the config node:

    
        
            
                1 
                pos/payment
                1
                Kartaca Payment Gateway
                
                VI,MC
                authorize 
                0
            
        
    

And also add these lines under global/blocks node (we will need this one later to customize the from seen):

            
                Kartaca_Pos_Block
                Mage_Payment_Block
            

There are two classes because if you only define one, you won’t be able to reach the other namespace!

This part is for the curious ones who wants to learn how I have found out these, for others, just get to the next paragraph. Well, open up your file browser, and go to the /app/code/core/Mage. Make your best bet on finding the module related to the “payment”!. As all the modules created by the Varien itself are modules too, like all 3rd party modules including this one, they also must have configuration files. Open up /app/code/core/Mage/Payment/etc/config.xml. You will notice first the blocks/payment part defined. This is where the second part of the config modification is coming. I should define my own blocks to the payment blocks! This was what I did. Secondly, you will notice the default part with exactly the same things we have done. Defining some default values. For more curios people; “ccsave”, “checkmo” and others like this are equivalent to the “pos” and of course, $_code variable for the class below. You should also notice that the payment method is defined in a “model” node. That’s interesting. When I said, “pos/payment” I have pointed to a class named Kartaca_Pos_Model_Payment. “pos” was the namespace defining Kartaca_Pos, Model came from the “model” node and of course, Payment came from the “payment”.

Magento approches the payment methods as “models” too. So we should define our own payment method as a model. So we create a file in Kartaca/Pos/Model/Payment.php:

/**
 * Notice we are not creating a totally new payment type, but extend the original Credit card payment
 * To write something totally new, you should extend from the Abstract one!
 */
class Kartaca_Pos_Model_Payment extends Mage_Payment_Model_Method_Cc
{
    protected $_isGateway = true;
    protected $_canAuthorize = true;
    protected $_canUseCheckout = true;

    protected $_code = "pos";
    protected $_formBlockType = 'pos/payment_form_pos';

    public function authorize(Varien_Object $payment, $amount)
    {
        $orderId = $payment->getOrder()->getIncrementId();
        try {
            $paymentValues = array("cardType" => $payment->getCcCid(),
                                   "expiresMonth" => $payment->getCcExpMonth(),
                                   "expiresYear" => $payment->getCcExpYear(),
                                   "cardHolderName" => $payment->getCcOwner(),
                                   "cardNumber" => $payment->getCcNumber(),
                                   "amount" => $amount,
                                   "orderId" => $orderId,
                                  );
            //FIXME: Find a way to define this part in the $payment object which is Magento_Sales_Info or something like that.                      
            $bankid = $_POST['bank_id']; //FIXME: Do not forget to sanitise this...
            if ($bankid == 12) { //Different banks...
                $paymentValues['username'] = "my_bank_username";
                $paymentValues['password'] = "my_secret_password_generally_not_that_secret";
                $paymentValues['clientid'] = "my_clientid_given_to_me_by_the_bank";
            } else if ($bankid == 14) { //... can require different values to be sent to them
                $paymentValues['username'] = "my_second_bank_username";
                $paymentValues['password'] = "my_secret_password_generally_not_that_secret";
                $paymentValues['clientid'] = "my_clientid_given_to_me_by_the_bank";
                $paymentValues['additionalSecondBankField'] = "additional_info";
            } else {
                throw new Exception("Invalid bankid: $bankid");
            }
            //Define the url where I'm making the request...                      
            $urlToPost = "https://my.bank.com/pos/service/address/";
            //Now Create the request which I will send via Post Method...
            //Create a string like: cardType=VI&expiresMonth=12&expiresYear=2011&amount=100.50
            $postData = "";
            foreach ($paymentValues as $key => $val) {
                $posData .= "{$key}=" . urlencode($val) . "&";
            }
            //Let's create a curl request and send the values above to the bank...
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $urlToPost);
            curl_setopt($ch, CURLOPT_TIMEOUT, 180);
            curl_setopt($ch, CURLOPT_HEADER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); //Put the created string here in use...
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            $data = curl_exec($ch); //This value is the string returned from the bank...
            if (!$data) {
                throw new Exception(curl_error($ch));
            }
            $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            if ($httpcode && substr($httpcode, 0, 2) != "20") { //Unsuccessful post request...
                throw new Exception("Returned HTTP CODE: " . $httpcode . " for this URL: " . $urlToPost);
            }
            curl_close($ch);
        } catch (Exception $e) {
            $payment->setStatus(self::STATUS_ERROR);
            $payment->setAmount($amount);
            $payment->setLastTransId($orderId);
            $this->setStore($payment->getOrder()->getStoreId());
            Mage::throwException($e->getMessage());
        }
        /*
         * Data outputted from the curl request
         *  is generally an xml string.
         * Assume that it is something like:
         *
         * 
         *   1
         *   1234233241
         * 
         *
         * However no bank response is never this simple by the way...
         * But this one gives you a general view of the thing.
         */
        $xmlResponse = new SimpleXmlElement($data); //Simple way to parse xml, Magento might have an equivalent class
        $isPaymentAccepted = $xmlResponse->isPaymentAccepted == 1;
        if ($isPaymentAccepted) {
            $this->setStore($payment->getOrder()->getStoreId());
            $payment->setStatus(self::STATUS_APPROVED);
            $payment->setAmount($amount);
            $payment->setLastTransId($orderId);
        } else {
            $this->setStore($payment->getOrder()->getStoreId());
            $payment->setStatus(self::STATUS_DECLINED);
            $payment->setAmount($amount);
            $payment->setLastTransId($orderId);
        }
        return $this;
    }
}

So this code block is modified from the parent. By doing these things, you have already created your own payment gateway! When user selects this payment type (disable the rest of them and only enable this one, so they can only select this!), authorize method will be called and you can change the whatever way you like it! I’m not getting on the details on using of curl or Zend_Soap.

However, don’t forget that we also had a bank_id thing. We also want to send this info or save this info somewhere in the magento. What then? When I select the Kartaca Payment Gateway, I do not see the bank information selector. Ww should change the form and add some files and lines of code of course! First let’s create a file in /app/design/frontend/default/default/template/pos/payment/form/pos.phtml (some directories should already be created by the module creator):


getMethodCode() ?>

This part is copy-paste from /app/design/frontend/default/default/template/payment/form/cc.phtml. However I have removed the card holder name which I did not require and also added a bank_id select box. Ah did you notice the method getBankAvailableTypes()? Well what now? First let’s get back to our payment class and define some required info. Open it up and add an attribute like this:

class Kartaca_Pos_Model_Payment extends Mage_Payment_Model_Method_Cc
{
    protected $_isGateway = true;
    protected $_canAuthorize = true;
    protected $_canUseCheckout = true;
    protected $_code = "pos";
    //The lines above are already defined...

    protected $_formBlockType = 'pos/payment_form_pos'; //Another file? Yes, sadly!
//more code...

So if you have already read my blog about customizing magento cms pages with custom php code or really understood the part 1, a bright light bulb should be seen around your head. If not, let me explain you. We have changed the “block” called by the method and now our “block” will be called by our payment class and the value “pos/payment_form_pos” defines the class: Kartaca_Pos_Block_Payment_Form_Pos!

We create it like this:

class Kartaca_Pos_Block_Payment_Form_Pos extends Mage_Payment_Block_Form_Cc
{
    protected function _construct()
    {
        parent::_construct();
        //Where do you think the association with phtml and classes were made?
        $this->setTemplate('pos/payment/form/pos.phtml'); //This time "/" does not define the namespace but file system!
    }
    //So we found the missing method right!
    public function getBankAvailableTypes()
    {
        return Mage::getSingleton("pos/bank")->getCollection(); //Alien? Read the part 1!
    }
}

Finally you will be able to see the bank selector there too! Notice that you won’t be able to call it via $payment->getBankId(). You should either change the Order model used (Mage_Sales_Order_Payment) by extending it and adding it to the config file. Or just use $_POST. I might get into the details on a third part. However, this is all the time I can spare right now (I have used my whole two days to write these articles and develop the module:)

Hope that helps. If you need some help about Magento or payment gateways, feel free to contact me or post a comment. If you require support and want to pay for it (I doubt you want to pay however:) please send an email to me or post a comment and someone from my company will get in touch with you.

Update: I have uploaded the code for this module to my github account here. You can download the full code there.
Update: I have updated the code for the payment part. I have added a part with a simple bank request. I have updated the code on the github to. There can be some errors on the code so feel free to point them as I may have missed something.

  • I get it. Simply you post your order info to somewhere else and then that site makes the actual payment and credit card things and later it makes another post request to your site returning if the payment is successful or not.

    That was one of the questions asked about enabling 3D payments about what to do to handle the ongoing and incoming requests. I do not honestly know how to integrate it with the current payment gateway however I just have a suggestion that might work.

    In one of my previous posts. I had explained about custom php codes on magento. Allowing you to write your own php codes in a page. With this in mind, you should make some modification to the current module. Delete the part where you get the credit card info etc and don’t take anything as an input, just let him select that payment method. Once he clicks on place order button, our _authorize() method will be run and in that method, make your post request to the moneybookers. Now your site is no more! So in order to moneybookers to return to you, you should give them a link which they can use to return the info. So this link will be the page which you have added your custom php codes :) Write any logic you want in their and show an approved or not approved information there.

    I suppose this might solve your problem. Even though this is not a very elegant solution, but it might work. I suppose I will have to look for a solution for this kind of problems as many people are asking for it and I will need it too. I will try to find some time to find it out.

    Hope this helps.

  • Victor

    Hey,
    Thanks for the quick reply :)

    Forgot to mention something… in the initial form-post that takes a customer to the gateway, “return URLs” are also specified in hidden form fiels:: one return url for the case where a payment was approved, and another for the case where the customer canceled the payment process at the gateway site…

    However, the payment-notification (in the post from the gateway servers to the merchant server) is always a parallel process, and is initiated as soon as the cutomser approves the payment.

    The “return url” for a successful payment would simply just take the customer back to the merchant site… like to a page that simply thanks the customer for the purchase or something like that. the payment-notification would, however, be handled independently and parallel to this process.

    found something that might help though: i’ve been looking at the official moneybookers’ magento module (its available pre-installed in magento 1.4. The file is::
    xxx\magento\app\code\community\Phoenix\Moneybookers\Model\Event.php)

    the class in that file appears to handle the payment-notification from moneybookers… but by the looks of it, that class in instantiated by magento itself. It seems the payment-notification data is sent directly to magento, which then raises some event that’s handled by that class.

    … and that could be a really neat way of handling the notifications; custom php files may not be the best solution given magento’s complicated handling of orders… as opposed to a module class which would allow you to make simple method calls to invoice ordes correctly.

    The initial posting [from merchant to gateway] looks kinda easy… its the handling of the payment notification that’ll be tricky to solve. I’ll try the post first, then perhaps share that code the guys here later.

    cheers!

  • DekBudi

    Hi … thanks for your module …
    But hwen install it I get error :

    There has been an error processing your request

    Exception printing is disabled by default for security reasons.

    Error log record number: 22198847

  • there is a log in the magento folder named 22198847 or something like that. In that file you will see what caused the error. There is probably a missing file or a parse error or a fatal error. Then you can solve the problem I suppose you can also enable magento to show errors but I don’t remember where.

  • magento_user

    Thanks for your good tutorial. Can I ask some question what is the difference between Sale and authorize in payment action of magento? Can I create my own action regarding redirection to the third party site?

    For those who managed to create a module with redirection to the third party site can you explain and give some examples how it works.

  • Victor

    hey magento_user,
    … am actually working edirection thing too ryt now… been practicing with it following this tutorial, and ive been able to build my own payment module from scratch

    my payment gateway provider requires that i access their site via a html-post containing certain specific variables, and i imagine thats the same with u… the htmlp-post will e-route me to their site.

    anyway… i’ll inform you of my progress. needlesstosay, roy’s tut was of IMMENSE help.

  • Victor

    @ magento_user

    By the way… have you looked at the moneybookers module. Moneybookers normally requiers a page-redirection too, but in their module, they use an IFrame… its pretty neat. Looking at that too, esp coz it meets the redirection requirement while keeping u on the merchant site.

    Later… I hope to get back to you with positive results in a few hours.

  • magento_user

    @Victor

    I haven’t take a look at moneybookers module, but I will after posting this message.

    Yes, we have the same specs of my payment gateway. Their API requires variables to be sent to them via POST and also they want me to provide them the name of the script sending and receiving requests from them. The receiving script I believe will be the one who will interpret the response of the request I made.

  • Victor

    @magento_user

    hey… just tried responding to u “response script” thing. My response got quite long, and i guess its why i’ve been unable to post it…

    I’d like to email the message to you though. my email is:

    kipmasi [at] gmail [dot com]

    cheers

  • magento_user

    @victor

    I sent you message on your email.

  • magento_user

    @victor

    I found moneybookers module pre-installed in magento 1.4 very similar to what I want to handle my payment through third party gateway. I will study its flow and try to create a new one as moneybookers as a basis.

    Thank you guys for this great tutorial.

  • Volkan

    günlerdir uğraşıyorum yapamadım bir türlü.
    yarım edebilecek birisi varmı arkadaşlar?

    jack2@mowonline.net

    teşekkürler

  • pankaj

    Hello Sir,
    I want to integrate cybersource payment gateway in magento .Can you please help me out .I am able to configure it in core php but facing problems with magento can you suggest how should i proceed . I am new to magento .Any help from your side will be highly appriciated.

  • @pankaj and your problem is?

  • pankaj

    Sir ,
    I am really thankful to you for reply.I have created the module with module creator.I have also created the database table .I am able to see my module in configuration->Advanced but i am unable to see the form in admin which I can modify accordingly to enter my Merchant Datails and other fields.Please help me.

    Thanks Pankaj

  • pankaj

    I have also downloaded your code and kept in my magento installation as per you directory structure .Still I am unable to see any option from where i can navigate to the form in admin.

  • @pankaj perhaps you haven’t made your configurations right or you might have copied and pasted to the wrong place.

  • pankaj

    Sir
    Is this code compatible with magento 1.4.0.1 version.Please guide me how should i proceed with cybersource(payment gateway) implementation.I am new to magento.And really thanks for quick reply.

  • I have no idea what you can do about cybersource. And yes I think it’s compatible with 1.4. I do not remember if I tested it however it should work without any problem.

    I really don’t know what your problem is. If you have done anything accordingly and haven’t missed anything it should work. Check out the other comments in this post and other 2, perhaps there will be something meaningful there.

    You might have copied and pasted to the wrong locations (file structure has changed I think in the version 1.4 so perhaps there is a problem there.)

  • pankaj

    Thanks a lot for reply.Yes this code is not compatible version 1.4. When i pasted the same code in version 1.3 i am able to see pos tab in top navigation and grid view where i can add title etc.But now my issue is that i am unable to see the Kartaca Payment Gateway option under payment methods where i can unable it and proceed .

    I have also added the below code in my etc/config.xml file

    1

    pos/payment

    1

    Kartaca Payment Gateway
    VI,MC
    authorize
    0

    Please guide me if i am doing any thing wrong .Again thanks for your reply.

  • pankaj

    Thanks a lot for reply.Yes this code is not compatible version 1.4. When i pasted the same code in version 1.3 i am able to see pos tab in top navigation and grid view where i can add title etc.But now my issue is that i am unable to see the Kartaca Payment Gateway option under payment methods where i can unable the gateway option and proceed .

  • pankaj

    I am able to see the Kartaca Payment Gateway option in front end.It seem to be directly configured from etc/config file.i have one issue now when i select the payment option in front end and fill all the details and clicks on continue i am stuck.I am unable to move to place order tab.And how will it redirect to (authorize function) in Model/Payment.php file.

    Thanks for great tutorial.

    Pankaj

  • Man! your code saved me.. Hope i can complete the task now.

  • Wow, this is really a wonderfully elaborate guide to a very complex task, thank you Roy; I’ve bookmarked it for future projects. You can’t help but love the flexibility of Magento and the community’s support for it. :)

  • Kartal Goksel

    I am wondering if this thread is still active. I have a problem. I wrote a new payment module and most of everything is just like how it is described here. I use OnePageCheckout and my problem is this, I get the payment object as

    $payment = Mage::getSingleton(‘checkout/session’)->getQuote()->getPayment()

    and then call the $payment->getCcNumber() and get nothing in return. Is there another payment object that I should be using.

    Thanks for your help in advance.

    KG

  • Hi Roy,
    I trying to implement your code its working fine. But My requirement is little bit different. I need to redirect user to the payment gateway page. This is how I am trying to implement

    When user clicks on Place Order Our Kartaca_Pos_Model_Payment >> authorize method gets called. My gateway Says send an initial request, Based on details given gateway send a URL & Payment id. On this Url user must be redirected Where customer actually makes the payment. I have two actions in Controller success & error.

    As, this code is getting called in an ajax request, I can’t redirect user to another website. Can u please guide me how to accomplish it?

  • A better way might be to provide a restful web service for your actual payment page if you can do it. By doing this all you will need to do will be to implement the web service api.

    If you are thinking of 3D payments, I did not yet to look out for it and I don’t know how you can redirect it. Sorry I was not much of a help here.

  • Amit Saurabh

    Hello,
    I followed your tutorial.
    But I dont understand how do I pass variable and its values (like some hidden variables ,field name as required for my payment gateway) while checkout etc.

    If I try to use default code then I am getting msg saying “Invalid bankid:” while pressing the “Place Order” button ,I don’t know what is happening in the backend of magento,
    I will really appreciate if anyone could help me.

    Thanks!

  • Manish Prakash

    i have written a detailed blog post on how to create payment method in magento
    http://www.excellencemagentoblog.com/magento-create-custom-payment-method

  • White_horse2040

    hello i did every thing you said but i did not find any thing in the front end
    can you tell me why?

  • Syed

    Hi Roy,

    Thank you for the great tutorial.

    I have just followed your code line by line, and created a module, I can see the moudle on the top of the admin menu and can manage items through it. Also I can enable/disable the module from advance menu. But when I try to click system->configuration->payment methods this error is thrown
    C:xampphtdocsmagentoappcodecoreMageAdminhtmlBlockSystemConfigForm.php on line 421

    Is there anything I am missing? Could you please guide me in this regard.

    Thanks

  • roysimkes

    What’s the error by the way, you put the line but not the error. Are you sure that there is no problem with your xml files?

  • Syed

    Thanks for the reply roy.

    I am sorry for the delayed reply and also for skipping the error part. I have pasted the full string below

    Fatal error: Call to a member function toOptionArray() on a non-object in C:xampphtdocsmagentoappcodecoreMageAdminhtmlBlockSystemConfigForm.php on line 421.
    Regarding xml, I just followed the way as shown in blog. Also I have downloaded your files from GIT. Do we need a system.xml as mentioned in other blogs?

    Thanks again.

  • roysimkes

    You don’t need to create a system.xl file if you don’t want to add some configuration on the default

  • Syed

    Thanks roy, yes before your tutorials I installed one module but that didnt work anyhow, I will uninstall and will try once again maybe from begining :).

  • Syed

    Hi Roy,

    I have reinstalled everything, as per your blog I have disabled other payment gateways and enable the one I created. But when I dont see my Payment Gateway on the front-end, When I try to checkout this error is throw:
    Fatal error: Call to a member function setMethod() on a non-object in C:xampphtdocsmagentoappcodecoreMagePaymentHelperData.php on line 106. I checked the config files and I have named the helpers and blocks properly.Could you please help me on this? fixing this may show my payment gateway on front end Hopefully :)

  • roysimkes

    Is there a method named setMethod somewhere? If you perhaps you were not able to override some of the core Mage models in the config file.

  • Elvar

    I cant make it right. How to get CC details from the form in the class which I first extended from Abstract method?

  • roysimkes

    If I understand what you ask correctly, in the Kartaca_Pos_Model_Payment class, the method authorize takes a parameter named, $payment. It contains the card information. Check the 3rd code block

  • Divya

    Hi,

    Im having a huge trouble trying to build out a payment gateway by myself even after following all the instructions here.

    Can someone get in touch with me, id like to have this built instead of breaking my head over it anymore!
    P

  • Elvar

    I have succesfully implemented 2 modules for myself. Maybe it can be adjusted for your needs… Please send me an info over shop.larimarcode.com…

  • mlivan

    You safe my live. Thanks a lot!!!

  • mlivan

    Sorry for bad English. :)
    You saved my life. Thanks a lot!!!

  • GigaDon

    I got this errors while trying to create a Module using the ModuleCreator:

    Error:
    Uncaught exception ‘Exception’ with message ‘Warning: copy(): The first argument to copy() function cannot be a directory on line 116

  • Gonzo8021

    Great! I’ll try today…

  • Скач от

    Hello…

    Thank you very much for putting a lot of effort in this… I have been following the steps from page one, at the end I had the module in my backend, but when I completed the second page my module magically disappeared from the admin panel. I’m quite confused now…

  • Tiago

    Hi, i need to create one payment module, but i cant found this moduleCreator

    can you post the link on magento connect?

  • roysimkes
  • Akhilesh Thakur

    I have created a module for custom payment. Every thing is working but I am not able to link form.phtml for take card information from user. My “Block” folder code of /app/code/local/CompanyName/ModuleName/Block/Form.php
    this->setTemplate(‘paymentgateway/form.phtml’);

    Please advice.Thanks In Advance

  • Ayush Mittal

    Any tutorial for redirection based payment gateway in magento 2