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:
User comes to the shopping cart and choses lets say some payment method which is gateway.
The system intercepts the request, collects all submitted data and sends the user to the gateway url.
User places his order (or cancels) at the gateway site which sends information about it to my store.
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?
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
Capturing a pre-authorized transaction
Immediate capture
Related
I want to integrate recurring payment using Payeezy in codeigniter. I have implement the single time payment using curl and now i want to recurring payment with acknowledgement to update my DB.
I created a WordPress plugin for Payeezy that also handles recurring. You should be able to use the underlying PHP code for CodeIgniter.
https://wordpress.org/plugins/wp-payeezy-pay/
I can explain the process that will get you the least PCI compliance issues, and that's the token-based API.
1. Generate Token in Payment Form
So basically you'll use the Javascript API to generate your authorize token. An authorize token doesn't charge the card. It's for validating the card and returning a token for better PCI compliance. This API source code and explanation is here:
https://github.com/payeezy/payeezy_js
2. Post Form To Your Server for the Curl Call to FirstData
Then, once you have this token, you post it back to your controller file with a standard form post, but remove the name attribute on your credit card number and credit card CVC fields so that these do not post to your server. Note that you'll need to store this data (but not card number and CVC) because on refunds (and subscription cancellations) you'll need to reply back with the last purchase token, cardholder name, card type, card expiration date, amount spent, and currency code. You may wonder why FirstData/PayEezy is asking you to store cardholder name, card type, and card expiration date. Well, there's a perfectly good explanation for that. Your call center may need that detail for troubleshooting an issue over the phone with a customer. Also, you need that for refunds. And, most importantly, if you're doing a recurring subscription payment, your code needs to look at the expiration date ahead of time before charging because the API call will fail if the card is past expiration. Last, because you're not storing the credit card number and credit card validation (CVC) code, you're going to be in stronger PCI compliance.
From there, since you are already familiar with the Curl process for a single-purchase, it's just a minor single field change (transaction_type becomes 'recurring') in the Curl to do the recurring. For anyone not familiar with the Curl process, it's explained here:
https://developer.payeezy.com/payeezy-api/apis/post/transactions-4
Also, for those unfamiliar people, you'll need to read up on how FirstData/PayEezy wants you to send in the Curl request with a special header that includes Content-Type: application/json, apikey, token, Authorization, nonce, and timestamp. You can see more detail about that here:
https://github.com/payeezy/payeezy_direct_API/blob/master/payeezy_php/example/src/Payeezy.php
(What I did to make that code simpler was intercept the Curl calls from that script into a log file so that I could make it much more straightforward in a single function instead of breaking it up into all these little functions. That made it far easier to understand what was going on.)
3. Switching Curl Call for Recurring Payments
So, as you discovered in your Curl call, you saw how to do a one-time purchase by setting the transaction_type to 'purchase'. For doing recurring, you set transaction_type to 'recurring'. You have to do that from the start. So, if I'm selling something for $29.99 monthly, the very first month charge needs to still be set to type 'recurring', as would any subsequent month.
4. Your Responsibilities for Recurring Payments
Now, this is where everyone gets hung up because it's poorly documented unless you check the PayEezy Developer Support Forum. For subscriptions, PayEezy doesn't have a system for setting payment plans with varying durations, nor setting up automatic (set-it-and-forget-it) subscriptions for you. (I think I read that they have something experimental on Apple Pay, but nothing else yet.) So, to achieve this, you have 2 choices:
Use Chargify.com. Unfortunately, though, this increases CPA (Cost Per Acquisition) of your product or service. You'll have to factor that in if you want to use that. This basically is a SaaS service that you send the transaction to and they handle the automatic subscription plan for you against FirstData/PayEezy.
Roll your own cron job solution. To do this, you basically take the Curl code for a single transaction, and change the transaction type from 'purchase' to 'recurring'. (Do that from the start -- don't start with 'purchase' on a recurring charge.) From there, it's up to you with your own cron job to check for product or service expiration terms, and then send the API call back off to FirstData/PayEezy for charging that card again with the 'recurring' transaction_type.
On either of those options, the customer never gets asked to enter in credit card data past the first time unless their card expires or unless you have some problem billing that card (like insufficient funds).
Of course, doing your own cron job route for the recurring payment has implications you'll need to prepare for:
Add some failsafe code so that you prevent the possibility of duplicate transactions, such as a database field.
Add some failsafe code such that if you have cancelled a subscription, you won't charge them again.
Add some failsafe code such that if they cancel their subscription, yet purchase it again as a subscription at a later time, that you do charge them again and don't block it from your other failsafe code.
Add some sort of grace period on your product or service such that even if you "say" that the term expired, you have like a 2 day grace period so that your API has a chance to do a renewal.
It's probably a good idea to email the customer before their renewal period so that they can make certain they have money in their account and have a way to cancel that charge (like call your office or call center, or have a link to click where you provide a way to cancel).
If their card has expired before the renewal, and you detect that in the warning email that comes before renewal, then you'll want to let them know this.
If their card has been declined for any reason at the point of renewal, then you'll want to let them know this and give them a link to go through the cart again to buy it again, or some other way to save that transaction in your code.
How To Do Subscription Cancellations / Stop Recurring Payments
To stop a recurring payment, you treat it just like a refund on a single purchase, but use the transaction ID of the last purchase. This is documented with this Curl example here:
https://developer.payeezy.com/payeezy-api/apis/post/transactions/%7Bid%7D-0
Look under "Refund" and choose Token.
I can see that the capture has been processed successfully:
But then on the "transactions" screen, "Is Closed" column is saying "no" next to capture. I think I just don't understand the role of this column. Can someone help explain it to me?
A little background on the credit card payment transaction process flow helps make sense of this. These are the basic flow actions of the transaction lifecycle:
Authorization
Capture
Settlement
These flow actions are broken down into more specific operations that can be called against the payment gateway. Here are some basic ones that are relevant:
Authorize (AUTH_ONLY):
Run the card for a given amount and obtain a unique authorization code. The amount will be put on hold and you are guaranteed these funds as long as you use the authorization code in a Capture transaction within 30 days. (How long before an authorization code expires varies by company. Check with your payment gateway)
Customers don't see the authorization as a charge on their statement, but they will see their available funds decrease by the amount you ran the authorization for.
If you don't use the authorization code in a follow-up Capture transaction, the authorization is "dropped", funds returned to the customer's balance and you can no longer use it.
Capture (PRIOR_AUTH_CAPTURE):
Use a previously obtained authorization code to complete the transaction.
The amount captured can be lower than the originally obtained authorization amount (this is useful in cases like our example where you don't know the total order amount ahead of time).
Source: http://www.softwareprojects.com/resources/conversion-traffic-to-cash/t-processing-payments-authorize-vs-capture-vs-settle-2030.html
Settlement: This is the process merchants must complete ... to be paid for their transactions.
The product or service must be delivered or performed before settlement can take place. In the case of mail order/telephone order, this specifically means the goods must be shipped before the settlement process is performed.
Source: http://www.shift4.com/insight/glossary/
In Magento, the is_closed flag signifies that a transaction is settled and no other operations may be performed against it. The reason a transaction would be left open until settlement is so that you can do partial shipments of goods (multiple captures), as well as void or refund the transaction.
To use Magento’s Mage_Authorizenet_Model_Directpost as an example, the capture() operation leaves the current transaction open, while void() and _refund() operations close it.
I've implemented a custom payment method in magento. In short, it works the following way:
upon checkout, the user gets redirected to the bank
he enters his credit card info, returns to a landing page
landing page querys the bank for the results and sets the order/payment status accordingly
Also, since the user might not return:
a cron querys the bank every minute for the status of the pending payments and updates them if neccessary
The problem: when the cron runs at the same time the user is returning, the payment statuses get updated twice, two invoices are generated, two emails are sent, etc.
There must be a proper way of handling this. Maybe locking the order/payment entity somehow? I'm kind of new to magento. Please share your knowledge!
Hi I was using this article
http://www.codeproject.com/Articles/152280/Online-Credit-Card-Transaction-in-ASP-NET-Using-Pa?msg=3753796#xx3753796xx
to understand the PayFlow Transaction Process and how to develope it.
After doing some successful tests from the example, I had some doubts about how I should be developing it for the release version.
1.- I'm planning to use the SDK methods and NVP call just like in the example for the release version. However, I don't know if I should be using something more like secure certificates or services call (I tried calling the wsdl service from .Net Wizard but I couldnt find any service that had to do with PayFlow Transactions).
2.- Also, in the PDF:
https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_PayflowPro_Guide.pdf
There are some examples, like the one in page 29, that state:
//Typical Sale Transaction Parameter String
//The following is a typical PARMLIST string passed in a Sale transaction.
"TRXTYPE=S&TENDER=C&USER=SuperUser&PWD=SuperUserPassword&VENDOR=SuperUser&PA
RTNER=PayPal&ACCT=5105105105105100&EXPDATE=1209&CVV2=123&AMT=99.00&FIRSTNAM
E=John&LASTNAME=Smith&STREET=123 Main St.&CITY=San
Jose&STATE=CA&ZIP=12345&COMMENT1=Reservation&INVNUM=1234567890&PONUM=C12345
&CVV2=567&VERBOSITY=MEDIUM"
//Note that, besides the required parameters that you pass in a Sale transaction, this string
//includes other typical parameters. The COMMENT1 (and COMMENT2) fields help to track
//transaction information. The customer’s street address (STREET) and zip should be passed to
//use address verification service. CVV2 is needed for card security code validation.
What I dont understand in that example is why is using the CCV2 parameter twice. Also, I dont know what the INVNUM and PONUM parameters mean. Furthermore, I know the test will be successful if I dont pass the CCV2 (security code) parameter and the adress parameters, but arent these mandatory? It gets me a bit confused, since for the DirectPayment Service, they are.
3.- In the PDF, there is a section called "Submitting Purchasing Card Level 2 and Level 3 Transactions" in page 99. In page 100, it says:
//Level 2 and Level 3 data is generally considered non-financial data. Lack of adequate data
//may cause a transaction to be downgraded.PayPal generally requires up to Level 2 information in
//an Authorization transaction followed by additional Level 3 data in the associated
//Delayed Capture transaction. A Sale transaction should include all Level 3 data
//since it is authorized and later settled.
Does this means that I "Need" to use more parameters than the required ones for a Sale transaction; otherwise, the transaction might be downgraded?
1) PayPal provides PayFlow documentation that covers all of that. You'll basically need to send the same login credentials used at manager.paypal.com along with your API requests.
2) I think that's just a mistake that they have the CVV2 parameter included twice. You only want to include it once. The documentation I linked to before will cover what all the request parameters mean, but the INVNUM is what you can use to track your own invoices within the PayFlow/Paypal system. PONUM is similar, but would be a PO number instead of an invoice number. You could search on these values in the future if you need to find them in the PayPal system.
With both PayFlow and Direct Payment, the requirement of CVV2 and a matching billing address depends on your account's Fraud Filter settings. If you've set it up to require them then you'd get an error without it. If it's setup to accept failures/mis-matches then it'll do so accordingly.
3) No, you won't need to worry about this.
I have a requirement to be able to accept different forms of payment within the same order - ie not just the usual credit card or paypal for the whole thing, but perhaps paypal for one item, cheque for another. I know this sounds quite crazy, but there is a good business reason for the requirement so I can't just push back.
The best way I can think of implementing it at the moment is to have kind of a hub page, where you can "launch off" into multiple flows for each of the payments by opening new windows. I can't figure out a way of doing this in a linear flow as for example you can't guarantee that a user will come back from paypal, so you'd then lose the user completely.
Is there a neater way of doing this that anyone can think of, or can anyone point me to an example of a site that does somethign similar for inspiration?
Even when opening several windows at once, there is no guarantee that the user will complete all payment methods. So you are most probably going to lose a few users or payments. Be sure to send automated e-mail follow-ups for missing payments to minimize this problem. The e-mails could contain links to your payment providers for easy accesss to their outstanding payment operations.
This is a difficult problem, but how many payment processors do you have to go offsite for? Should only be paypal.
In any case, I'd give the user all their payment options on one page, and let them fill in the amount for each processor or payment type. Then the next page would list those they chose, the amount for each, and a link to "Complete this payment".
The link would open in a new window.
You'll have to have a good back end and javascript, as well as user warnings so that the payment page gets updated as each payment is processed. Consider using popup dialogs to show that a payment has completed, or that the order has sat idle for more than 10-30 minutes without complete payment.
Also, consider sending emails and letting the user complete the payments through links in the emails. Send a new email each time a payment is completed, and a final email if all payments are complete and the order is moving forward.
Send an email one hour, and one day later for uncompleted orders with remaining payments required, that also give them the option of choosing different payment options for the remainder.
Email isn't best (lose more orders that way due to changing minds) but it's good for the type of transactions you're thinking about.
Personally, I'd do it like this:
Let the user fill their basket in the ususal way
Allow them to add payment types and amounts to a list (2nd basket almost)
When the payments balance against the basket, start processing the payments
For external sites, try a frame which has a progress indicator at the top.
In an ideal world it wouldn't be linear. But a lot of users might lose a spawned window, or get confused by the parallelism.
Better to stick to established IxD principals and rely on good feedback instead. Give the user control from the outset and keep it transparent.
Lastly, start the payment process with the most immediate (e.g. paypal) to reduce users giving up. (COD should come last!)
Hope this helps,
Tom
If possible, just separate your order into separate smaller orders based off of the payment selections of the user.
And don't do it linearly. If anything you could open up each payment processor in a separate window so that you maintain presence.
I would take an approach where the whole order is broken down into sub-orders for each of the necessary payment methods. You can load the PayPal portion, the check portion, etc. and process them separately. It's important for the user to know how much is being charged to each of their payment methods, so it makes sense in this case to present the whole order as broken down by payment method (versus displaying as a unified order).
Implementation would be easiest if it's always a certain subset of items that is forced to any payment method. If this differs by user, or if it's when the order reaches a certain amount, the situation could become much more complicated. Can you be more specific about your approach?
Processing Multiple Order Payments
Give the user the option to make a payment for a pending order using any of your payment types.
Let the user specify an (Amount <= [Order Total] - [Payments Received]), if that is part of your requirement.
If the order is still pending after you process the payment (see how below), take them back to step 1 to rinse and repeat.
How to store and process each payment made:
Use a Payments table to store all order payments, the PaymentMethod used and its Amount with its CurrencyCode.
When a payment is received for an order, store the payment and sum all received amounts converted into your base currency as [Payments Received].
If [Payments Received] >= [Order Total], mark the order as Paid. Or, if dealing with double-converted foreign exchange rates, check if it is correct to within a small-enough margin, eg 0.5%.
Optionally, convert any overpayment into prepaid credit for the client.