/** * Process payment refund notification * Updates transactions hierarchy, if required * Prevents transaction double processing * Updates payment totals, updates order status and adds proper comments * TODO: potentially a full capture can be refunded. In this case if there was only one invoice for that transaction * then we should create a creditmemo from invoice and also refund it offline * TODO: implement logic of chargebacks reimbursements (via negative amount) * * @param float $amount * @return Mage_Sales_Model_Order_Payment */ public function registerRefundNotification($amount) { $notificationAmount = $amount; $this->_generateTransactionId(Mage_Sales_Model_Order_Payment_Transaction::TYPE_REFUND, $this->_lookupTransaction($this->getParentTransactionId())); if ($this->_isTransactionExists()) { return $this; } $order = $this->getOrder(); $invoice = $this->_getInvoiceForTransactionId($this->getParentTransactionId()); if ($invoice) { $baseGrandTotal = $invoice->getBaseGrandTotal(); $amountRefundLeft = $baseGrandTotal - $invoice->getBaseTotalRefunded(); } else { $baseGrandTotal = $order->getBaseGrandTotal(); $amountRefundLeft = $baseGrandTotal - $order->getBaseTotalRefunded(); } if ($amountRefundLeft < $amount) { $amount = $amountRefundLeft; } if ($amount != $baseGrandTotal) { $transaction = new Varien_Object(array('txn_id' => $this->getTransactionId())); Mage::dispatchEvent('sales_html_txn_id', array('transaction' => $transaction, 'payment' => $this)); $transactionId = $transaction->getHtmlTxnId() ? $transaction->getHtmlTxnId() : $transaction->getTxnId(); $order->addStatusHistoryComment(Mage::helper('sales')->__('IPN "Refunded". Refund issued by merchant. Registered notification about refunded amount of %s. Transaction ID: "%s". Credit Memo has not been created. Please create offline Credit Memo.', $this->_formatPrice($notificationAmount), $transactionId), false); return $this; } $serviceModel = Mage::getModel('sales/service_order', $order); if ($invoice) { if ($invoice->getBaseTotalRefunded() > 0) { $adjustment = array('adjustment_positive' => $amount); } else { $adjustment = array('adjustment_negative' => $baseGrandTotal - $amount); } $creditmemo = $serviceModel->prepareInvoiceCreditmemo($invoice, $adjustment); if ($creditmemo) { $totalRefunded = $invoice->getBaseTotalRefunded() + $creditmemo->getBaseGrandTotal(); $this->setShouldCloseParentTransaction($invoice->getBaseGrandTotal() <= $totalRefunded); } } else { if ($order->getBaseTotalRefunded() > 0) { $adjustment = array('adjustment_positive' => $amount); } else { $adjustment = array('adjustment_negative' => $baseGrandTotal - $amount); } $creditmemo = $serviceModel->prepareCreditmemo($adjustment); if ($creditmemo) { $totalRefunded = $order->getBaseTotalRefunded() + $creditmemo->getBaseGrandTotal(); $this->setShouldCloseParentTransaction($order->getBaseGrandTotal() <= $totalRefunded); } } $creditmemo->setPaymentRefundDisallowed(true)->setAutomaticallyCreated(true)->register()->addComment(Mage::helper('sales')->__('Credit memo has been created automatically'))->save(); $this->_updateTotals(array('amount_refunded' => $creditmemo->getGrandTotal(), 'base_amount_refunded_online' => $amount)); $this->setCreatedCreditmemo($creditmemo); // update transactions and order state $transaction = $this->_addTransaction(Mage_Sales_Model_Order_Payment_Transaction::TYPE_REFUND, $creditmemo); $message = $this->_prependMessage(Mage::helper('sales')->__('Registered notification about refunded amount of %s.', $this->_formatPrice($amount))); $message = $this->_appendTransactionToMessage($transaction, $message); $order->setState(Mage_Sales_Model_Order::STATE_PROCESSING, true, $message); return $this; }