Magento Payment flow

zokibtmkd picture zokibtmkd · Mar 20, 2011 · Viewed 25.6k times · Source

I am working on implementing a new payment module for Magento and want to understand the core concept behind this logic. I know I have to extend from Mage_Payment_Model_Method_Abstract or any of its children classes, but my problem is when to use and how to use capture and authorize methods in my model. For example if I split the whole process in steps like this:

  1. User comes to the shopping cart and choses lets say some payment method which is gateway.
  2. The system intercepts the request, collects all submitted data and sends the user to the gateway url.
  3. User places his order (or cancels) at the gateway site which sends information about it to my store.
  4. My store does some more modifications to the order with the received data and saves the order with status completed or canceled.

Where in these steps will I have to use authorize and capture methods ? I would appreciate if someone could explain to me what authorize and capture means?

Answer

Alan Storm picture Alan Storm · Mar 20, 2011

Here's the way I've always understood the concepts, and what you'll need to know to implement a payment module in Magento. Answers to your specific "where does this happen" are bolded below, although it's not quite as simple as you're hoping for.

Pre-internet, brick and mortar credit card transactions were a two stage process.

At the time of a sale, when the merchant took a consumer's credit card for a purchase they'd slide it through a point of sale device which would call into the credit card's central office and ask "is this card authorized for this network, and is this particular consumer's line of available credit large enough to allow this purchase".

If the purchase was accepted (as opposed to declined), the charge was said to be authorized. The consumer would take their product, and the point of sale system/cash-register would note that the transaction was authorized. Then, at the end of a the day, or the end of the week, at some other predetermined regular schedule, or when the owner decided to stop drinking, the merchant would go though all their authorized receipts and send another request to the central office to capture the funds from the authorized transaction. Capturing the funds is what puts money in the merchant's account.

This is still the model in use by most gateways, and is the domain model that Magento Inc. chose to implement for their payment modules.

The way things are supposed to run is, when a consumer reaches the final checkout steps in a system like Magento, Magento issues an authorization request to the gateway's API. If the transaction is successful, the order is accepted into the system, and a unique ID from the authorization request is stored. Next, when the consumer's goods ship, a store owner uses the Magento admin to create an invoice. The creation of this invoice issues a capture request (using a store id returned from the authorization request). This is where these method calls are issued in Magento.

However, things get tricky because every payment gateway interprets these concepts a little differently, and every merchant interprets their "don't capture until we've shipped" responsibilities differently. In addition to the scenario described above, payment modules have a system configuration value known as a Payment Action. This can be set to Authorize Only, which will implement the flow described above. It can also be set to Authorize and Capture, which will both authorize and capture a payment when the order is placed. It gets even more confusing because although the method is called Authorize and Capture, current versions of Magento will only issue the capture request when set in this mode (at least for Authorize.net), and Authorize.net will, internally, leave capture requests in an authorized but not captured state for most of the day. How Magento handles orders and payments and invoices is one area of the codebase that changes a lot from version to version.

So, the idea behind the Magento payment module system is to shield you from the Cluster F--- that is programming payment Gateway logic. In your authorize method you implement a call to your payment gateway's authorize API (or perform whatever checks and logic you want to happen at this point). This method is passed a payment object and an amount. If you make you request/perform-your-logic and determine it's invalid for whatever reason, you throw an Exception with

Mage::throwException('...');

This tells Magento the authorization failed, and it will act accordingly (show an error message, etc.). Otherwise, you set data members on the Payment object and issue a

return $this;

The data members are things you'll need later, when capturing the payment. Which brings us to the capture method of your Payment module. This method is also sent a payment object and an amount. In this method you issue your capture request. The payment object will have cc_trans_id data member

$payment->getCcTransId()

which will allow you to issue a capture against your gateway. This is one of the data members you're responsible for saving up in authorize. Again, if your code determines the capture has failed, you throw an exception. Otherwise, you return $this.

The authorize.net payment module has good examples of how this is done.

app/code/core/Mage/Paygate/Model/Authorizenet.php

For example, consider this part of the capture method

public function capture(Varien_Object $payment, $amount)
{
    if ($payment->getCcTransId()) {
        $payment->setAnetTransType(self::REQUEST_TYPE_PRIOR_AUTH_CAPTURE);
    } else {
        $payment->setAnetTransType(self::REQUEST_TYPE_AUTH_CAPTURE);
    }   

    $payment->setAmount($amount);
    $request= $this->_buildRequest($payment);
    $result = $this->_postRequest($request);
    //...

Here the capture method is checking if the payment has a cc_trans_id. Depending on the result, it sets anet_trans_type to either:

self::REQUEST_TYPE_PRIOR_AUTH_CAPTURE
self::REQUEST_TYPE_AUTH_CAPTURE

This value is then used by the API request object to send an API call for either

  1. Capturing a pre-authorized transaction
  2. Immediate capture

Hope that helps, and good luck!