Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>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.</p> <p>Pre-internet, brick and mortar credit card transactions were a two stage process.</p> <p>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". </p> <p>If the purchase was accepted (as opposed to declined), the charge was said to be <em>authorized</em>. 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 <strong>another</strong> request to the central office to <em>capture</em> the funds from the <em>authorized</em> transaction. Capturing the funds is what puts money in the merchant's account. </p> <p>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. </p> <p>The way things are supposed to run is, <strong>when a consumer reaches the final checkout steps</strong> 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 <strong>uses the Magento admin to create an invoice</strong>. The creation of this invoice issues a capture request (using a store id returned from the authorization request). <strong>This is where these method calls are issued in Magento</strong>.</p> <p>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 <em>Payment Action</em>. This can be set to <em>Authorize Only</em>, which will implement the flow described above. It can also be set to <em>Authorize and Capture</em>, which will both authorize and capture a payment when the order is placed. It gets even <strong>more</strong> 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.</p> <p>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 <code>authorize</code> 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</p> <pre><code>Mage::throwException('...'); </code></pre> <p>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 </p> <pre><code>return $this; </code></pre> <p>The data members are things you'll need later, when capturing the payment. Which brings us to the <code>capture</code> 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 <code>cc_trans_id</code> data member </p> <pre><code>$payment-&gt;getCcTransId() </code></pre> <p>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 <code>authorize</code>. Again, if your code determines the capture has failed, you throw an exception. Otherwise, you <code>return $this</code>.</p> <p>The authorize.net payment module has good examples of how this is done.</p> <pre><code>app/code/core/Mage/Paygate/Model/Authorizenet.php </code></pre> <p>For example, consider this part of the <code>capture</code> method </p> <pre><code>public function capture(Varien_Object $payment, $amount) { if ($payment-&gt;getCcTransId()) { $payment-&gt;setAnetTransType(self::REQUEST_TYPE_PRIOR_AUTH_CAPTURE); } else { $payment-&gt;setAnetTransType(self::REQUEST_TYPE_AUTH_CAPTURE); } $payment-&gt;setAmount($amount); $request= $this-&gt;_buildRequest($payment); $result = $this-&gt;_postRequest($request); //... </code></pre> <p>Here the capture method is checking if the payment has a <code>cc_trans_id</code>. Depending on the result, it sets <code>anet_trans_type</code> to either:</p> <pre><code>self::REQUEST_TYPE_PRIOR_AUTH_CAPTURE self::REQUEST_TYPE_AUTH_CAPTURE </code></pre> <p>This value is then used by the API request object to send an API call for either</p> <ol> <li>Capturing a pre-authorized transaction</li> <li>Immediate capture</li> </ol> <p>Hope that helps, and good luck!</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload