The Problem:
You want to issue a refund, electronically, through your payment gateway from Magento.
The Solution:
By default, the community edition of Magento has refunds disabled in the Paygate Models. In order to enable them you need to create a custom Model and overwrite a protected variable. Refer to Part IV: Extending Models for more details on extending a Model.
First, lets take a look at the native Model so that you can understand what’s standing in the way. I’m going to use the Authorize.net gateway as my example.
The top portion of Mage_Paygate_Model_Authorizenet (/Mage/Paygate/Model/Authorizenet.php)
class Mage_Paygate_Model_Authorizenet extends Mage_Payment_Model_Method_Cc
{
const CGI_URL = 'https://secure.authorize.net/gateway/transact.dll';
const REQUEST_METHOD_CC = 'CC';
const REQUEST_METHOD_ECHECK = 'ECHECK';
const REQUEST_TYPE_AUTH_CAPTURE = 'AUTH_CAPTURE';
const REQUEST_TYPE_AUTH_ONLY = 'AUTH_ONLY';
const REQUEST_TYPE_CAPTURE_ONLY = 'CAPTURE_ONLY';
const REQUEST_TYPE_CREDIT = 'CREDIT';
const REQUEST_TYPE_VOID = 'VOID';
const REQUEST_TYPE_PRIOR_AUTH_CAPTURE = 'PRIOR_AUTH_CAPTURE';
const ECHECK_ACCT_TYPE_CHECKING = 'CHECKING';
const ECHECK_ACCT_TYPE_BUSINESS = 'BUSINESSCHECKING';
const ECHECK_ACCT_TYPE_SAVINGS = 'SAVINGS';
const ECHECK_TRANS_TYPE_CCD = 'CCD';
const ECHECK_TRANS_TYPE_PPD = 'PPD';
const ECHECK_TRANS_TYPE_TEL = 'TEL';
const ECHECK_TRANS_TYPE_WEB = 'WEB';
const RESPONSE_DELIM_CHAR = ',';
const RESPONSE_CODE_APPROVED = 1;
const RESPONSE_CODE_DECLINED = 2;
const RESPONSE_CODE_ERROR = 3;
const RESPONSE_CODE_HELD = 4;
protected $_code = 'authorizenet';
/**
* Availability options
*/
protected $_isGateway = true;
protected $_canAuthorize = true;
protected $_canCapture = true;
protected $_canCapturePartial = false;
protected $_canRefund = false;
protected $_canVoid = true;
protected $_canUseInternal = true;
protected $_canUseCheckout = true;
protected $_canUseForMultishipping = true;
protected $_canSaveCc = false;
protected $_allowCurrencyCode = array('USD');
The variable that we’re interested in is _canRefund. The game plan is to create a custom Model that overrides Mage_Paygate_Model_Authorizenet and in that Model, override _canRefund. If you’re thinking, why not just change false to true right here, right now! Well my friend, you certainly could, but you’d certainly break your upgrade path too, check out Part IV: Extending Models and Part I: Custom Module.
I’m going to create the class: Spinonesolutions_Paygate_Model_Authorizenet (/local/Spineonesolutions/Paygate/Model/Authorizenet.php) and extend Mage_Paygate_Model_Authorizenet. Now I just override _canRefund and we’re halfway there.
<?php
class Spinonesolutions_Paygate_Model_Authorizenet extends Mage_Paygate_Model_Authorizenet
{
//Override Mage_Paygate_Model_Authorizenet
protected $_canRefund = true;
}
?>
If you read Part IV: Extending Models you’ll know that there’s one last step, and that is to modify config.xml so that our custom Model overrides the native Model.
/Spinonesolutions/Paygate/etc/config.xml
<global>
<models>
...
<paygate>
<rewrite>
<authorizenet>Spinonesolutions_Paygate_Model_Authorizenet</authorizenet>
</rewrite>
</paygate>
...
</models>
</global>
That should do it! If you’ve got everything else setup correctly this should enable the Model to post refunds electronically to your gateway. Of course, if you want to enable more than one gateway, or perhaps a gateway that’s not Authorize.net you can do that by just following the same steps above with the Model for the gateway of your choice.
As always, questions and comments are welcome!
Update: From Commenter Cindy
Afer doing the above (and not forgetting to fill in app/etc/modules/MyNameSpace_All.xml to activate the new module), I still wasn’t getting authorize.net to really refund the cc.
I found that I needed to add the CC to the request, and then add the actual amount to be refunded. Now issuing a credit memo on the invoice will cause authorize.net to issue a refund to the CC.
Also, it appears that the ‘refund’ button only shows up if you click credit memo from an invoice – it doesn’t show up if you click credit memo on an order (only ‘refund offline’ shows up then).
Anyway, this is the code to make this work for me:
//
// Override Mage_Paygate_Model_Authorizenet
// enable online refunds via credit memos
// enable partial refunds
//
class Sbr_Paygate_Model_Authorizenet extends Mage_Paygate_Model_Authorizenet {
protected $_canCapturePartial = true;
protected $_canRefund = true;
//
// override _buildRequest to fill in the CC number as it is required yet not set peviously
//
protected function _buildRequest (Varien_Object $payment) {
if (($payment->getAnetTransMethod() == self::REQUEST_METHOD_CC) &&($payment->getCcLast4()))
$payment->setCcNumber($payment->getCcLast4());
return parent::_buildRequest($payment);
}
// Override refund in order to fill out the amount
//
public function refund(Varien_Object $payment, $amount) {
$error = false;
if ($payment->getRefundTransactionId() && $amount>0) {
$payment->setAnetTransType(self::REQUEST_TYPE_CREDIT);
$request = $this->_buildRequest($payment);
// set the amount (beginning of changes)
$order = $payment->getOrder();
$request->setXAmount($amount,2);
$request->setXCurrencyCode($order->getBaseCurrencyCode());
// (end of changes)
$request->setXTransId($payment->getRefundTransactionId());
$result = $this->_postRequest($request);
if ($result->getResponseCode() == self::RESPONSE_CODE_APPROVED) {
$payment->setStatus(self::STATUS_SUCCESS);
} else {
$error = $result->getResponseReasonText();
}
} else {
$error = Mage::helper(’paygate’)->__(’Error in refunding the payment’);
}
if ($error !== false) {
Mage::throwException($error);
}
return $this;
}
17 Comments for Magento – Enable Paygate Refunds
Cindy | October 30, 2009 at 1:10 pm
erictr1ck | December 4, 2009 at 1:24 pm
followed all the above instructions and am getting “Can not save credit memo”. ideas?
Haroon | December 17, 2009 at 10:44 am
Hello,
I want to use the same solution for Paypal what attributes do i ahve to change in order to get that working.
Regards
Haroon
Jeremiah Lewis | January 15, 2010 at 7:59 am
For the config.xml file, do we just need that bit of code in a config.xml file in the local directory, or is that code snippet added to (or replacing a section) of the whole original config.xml file?
If the latter, which section is it replacing?
Will Wright | January 18, 2010 at 8:06 am
That snippet goes in the local “etc” folder. In my example it’s /app/code/local/SpinoneSolutions/etc/ .
That snippet is an addition to whatever else you may have in your config.xml. You’ll need to copy and paste the “paygate” block into your “models” block.
Note that the actual class path that you wrap with “authorizenet” could be different based on the namespaces that you choose.
Ravi Kishore | April 1, 2010 at 1:52 am
Hi Will,
Thanks for the above information.
We have followed the above changes and the module is enabled perfectly. But for the orders, which are having invoice also showing the button as REFUND OFFLINE.
We are unable to go forward on this.
Waiting for your reply. Thanks in advance.
Ravi Kishore. V
Will Wright | April 5, 2010 at 7:10 am
I think you’re OK there. If you trace that button down into the code you’ll find that it’s in /app/code/core/Mage/Adminhtml/BlockSales/Order/Creditmemo/Create/Items.php line 71, canRefund().
If I had to guess I’d say everything is working properly, it’s just that the button is mislabeled.
elam | August 26, 2010 at 7:29 am
I have the same problem as Will. And it does not fire the refund function. The button does as it says. Version 1.4.0.1. I’m using a custom Payment Modulle but the canRefund = true is the first thing that I tried and it doesn’t work. I’m thinking of using the event sales_order_creditmemo_refund unless there is a better solution.
Will Wright | August 31, 2010 at 7:32 am
You enabled canRefund, but the refund() function still isn’t firing? Have you verified that your override is working?
phillcollier | September 3, 2010 at 9:55 am
I am having the same problem… the only button that shows up is the “refund offline”. I don’t see the “refund”
Will Wright | September 17, 2010 at 6:13 am
Can you check System -> Configuration -> Advanced and verify that your custom module is showing up?
Is the invoice an online invoice opposed to an offline invoice?
Ernie | October 14, 2010 at 9:21 pm
Sorry for such an annoying question, but it seems your revised Authorizenet.php code is missing a closing curly brace somewhere.
My assumption is it’d go after the refund() function’s return $this… but the last thing I want to do is shove braces where they don’t belong. Can you please double-check for me?
Thank you so much for this code it’s fantastic!
Ernie | October 14, 2010 at 9:25 pm
Actually, you weren’t wrong… my IDE was! Sorry and thanks again!
subhas | October 15, 2010 at 11:55 pm
can someone pls clarify, what does refund memo in magento actually mean ?
there is an option to do a offline refund and a invoice refund ? what’s the difference.
does the refund actually re-credit the customers credit card, or is this just a for a accounting objective ?
does the credit memo actually trigger a email to the client saying he has been refunded ?
Will Wright | October 18, 2010 at 6:15 am
There are basically two types of “refunds” and you’ll get one or the other depending on how your store is setup and what type of invoice you’re dealing with.
If the store is setup with an online payment gateway AND the invoice was placed using the online payment gateway, then you should be able to issue a “online refund” meaning that Magento will both keep track of the refund internally and attempt to issue a refund against the payment gateway.
If the store is not setup with an online payment gateway, or you’re dealing with a invoice that was collected offline than you should see “offline refund” in which case Magento will only keep track of the refund internally since it assumes that you will manually handle the refunding of funds.
There should be a checkbox at the end of the creditmemo form asking whether or not you’d like to notify the customer. Also note that some payment gateways will notify the customer as well.
Ray | February 24, 2011 at 3:44 pm
Will – your site is a great resource. I’ve installed Cindy’s code, I see it in the admin, the Refund button displays. However I get a “cc not valid error”. In the debug log [x_card_num] => ****. I’m running 1.4.2.0. Do you know if something has changed that makes it impossible to retrieve the cc? Thanks again for your site.
Deepeddie | June 26, 2011 at 9:09 am
Thanks for the great article.
BTW I think the link the “Part IV: Extending Models” is broken within the page.


Thank you!
I followed your very clear instructions and it worked. Thank you for saving me so much time and frustration!