1

Is it possible to do online refund with paypal in magento communtiy. if yes, which paypal api supports this feature in magento and how can i use that?

  • anyone please ? – vibhu Apr 1 '14 at 12:47
  • did you ever find this out? – David Manners May 24 '14 at 7:33
  • no. still looking for solution :( – vibhu May 28 '14 at 7:45
  • did you contact paypal about this maybe they could make a suggestion – David Manners May 28 '14 at 7:46
2

PayPal Direct and PayPal Express Checkout has this feature, as you can see in the payment models:

protected $_canRefund                   = true;
protected $_canRefundInvoicePartial     = true;

Whereas PayPal Standard doesn't have these settings.

You should be able to use the online refund from the invoice view in the backend.

0

I put together a GIST showing the important parts to a custom implementation of online refunds with Paypal Standard for Magento 1.x https://gist.github.com/bubach/ed86611c634b401e5d66392cf32c2f6e

Copy+paste of main methods:

<?php
class Namespace_Modulename_Model_Paypal extends Mage_Paypal_Model_Standard
{

    protected $_canRefund               = true;
    protected $_canRefundInvoicePartial = true;
    protected $_canVoid                 = true;

    /**
     * Custom model extending Mage_Paypal_Model_Standard (no need for config rewrite, internal use)
     *
     * https://developer.paypal.com/webapps/developer/docs/classic/api/merchant/RefundTransaction_API_Operation_NVP/
     */
    public function tryRefund(Varien_Object $payment, $amount)
    {
        $transactionId = $payment->getLastTransId();
        if ($transactionId) {
            $order          = $payment->getOrder();
            $storeId        = $order->getStoreId();
            $refundType     = "Partial";
            $invoiceFee = $payment->getMethodInstance()->getInfoInstance()->getAdditionalInformation('invoice_fee');
            $remaining  = $order->getTotalInvoiced() - ($order->getTotalOfflineRefunded() + $order->getTotalOnlineRefunded()) - $invoiceFee;
            if (abs($remaining - $amount) < 0.00001) {
                $refundType = "Full";
            }
            $currencyCode   = $order->getBaseCurrencyCode();
            $invoiceId      = $order->getIncrementId();
            $params = array(
                "METHOD"        => "RefundTransaction",
                "VERSION"       => "72.0",
                "TRANSACTIONID" => $transactionId,
                "INVOICEID"     => $invoiceId,
                "REFUNDTYPE"    => $refundType,
                "AMT"           => $amount,
                "CURRENCYCODE"  => $currencyCode,
                "USER"          => Mage::getStoreConfig('paypal/wpp/api_username', $storeId),
                "PWD"           => Mage::getStoreConfig('paypal/wpp/api_password', $storeId),
                "SIGNATURE"     => Mage::getStoreConfig('paypal/wpp/api_signature', $storeId)
            );
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, "https://api-3t.paypal.com/nvp");
            curl_setopt($ch, CURLOPT_HEADER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS,  http_build_query($params));
            $response = curl_exec($ch);
            if (curl_errno($ch)) {
                curl_close($ch);
                throw new Mage_Core_Exception('Impossible to issue a refund transaction because of cURL error.');
            } else  {
                curl_close($ch);
                $responseArray = array();
                parse_str($response, $responseArray); // Break the NVP string to an array
                if ($responseArray['ACK'] == "Success") {
                    return array(0, "Paypal refunded successfully");
                } else {
                    return array(-1, "Paypal refund failed!");
                }
            }
        } else {
            Mage::throwException(Mage::helper('paypal')->__('Impossible to issue a refund transaction because the capture transaction does not exist.'));
        }
    }
}

Observer listening to sales_order_payment_refund-event:

<?php
/**
 * app/code/local/Namespace/Modulename/Model/Namespace_Modulename_Model_Observer.php
 */
class Namespace_Modulename_Model_Model_Observer
{

    /**
     * Observer for paypal standard payments refund
     *
     * @param Varien_Event_Observer $observer
     * @throws Mage_Core_Exception
     */
    public function creditMemo(Varien_Event_Observer $observer)
    {
        $payment     = $observer->getEvent()->getPayment();
        $paymentCode = $payment->getMethod();
        $storeId     = $payment->getOrder()->getStoreId();

        // check if we should handle paypal refunds
        if (Mage::getStoreConfigFlag('modulename/paypal/active', storeId)) {
            if ($paymentCode == "paypal_standard") {
                $creditmemo = $observer->getEvent()->getCreditmemo();
                // instantiate our model directly instead of keeping rewrite in config (why not)
                $paypal     = Mage::getModel('modulename/paypal');
                //$paypal     = Mage::getModel('paypal/pro');
                if ($paypal && method_exists($paypal, 'tryRefund')) {
                    $ares = $paypal->tryRefund($payment, $creditmemo->getGrandTotal());
                    if ($ares[0] == 0) {
                        Mage::getSingleton('adminhtml/session')->addSuccess($ares[1]);
                    } elseif ($ares[0] > 1) {
                        throw new Mage_Core_Exception($ares[1]);
                    } elseif ($ares[0] < 0) {
                        throw new Mage_Core_Exception($ares[1]);
                    }
                    $payment
                        ->getOrder()
                        ->addStatusToHistory($payment
                            ->getOrder()
                            ->getStatus(), $ares[1]);
                }
            }
        }
    }

    /**
     * Observer for paypal standard payments cancel order
     *
     * @param Varien_Event_Observer $observer
     * @throws Mage_Core_Exception
     */
    public function orderCancel(Varien_Event_Observer $observer)
    {
        $payment     = $observer->getEvent()->getPayment();
        $paymentCode = $payment->getMethod();
        $storeId     = $payment->getOrder()->getStoreId();

        // check if we should handle paypal refunds
        if (Mage::getStoreConfigFlag('paymentaddon/paypal/active', $storeId)) {
            if ($paymentCode == "paypal_standard") {
                // if payment is pending, then we have no money to return
                $order = $payment->getOrder();
                if ($order && $order->getState() == 'pending_payment') {
                    return;
                }
                // instantiate our model directly instead of keeping rewrite in config (why not)
                $paypal = Mage::getModel('paymentaddon/paypal');
                //$paypal = Mage::getModel('paypal/pro');

                if ($paypal && method_exists($paypal, 'tryCancel')) {
                    $ares = $paypal->tryCancel($payment);
                    if ($ares[0] == 0) {
                        if ($ares[1] != "") {
                            Mage::getSingleton('adminhtml/session')->addSuccess($ares[1]);
                        }
                    } elseif ($ares[0] > 1) {
                        throw new Mage_Core_Exception($ares[1]);
                    } elseif ($ares[0] < 0) {
                        throw new Mage_Core_Exception($ares[1]);
                    }
                    $payment
                        ->getOrder()
                        ->addStatusToHistory($payment
                            ->getOrder()
                            ->getStatus(), $ares[1]);
                }
            }
        }
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.