Wednesday , 16 April 2014
Topic 9 – Part 2: Invoice

Topic 9 – Part 2: Invoice

Glad to see you again in our Magento blog. This week, I would like to focus on invoice. The invoice is created when a customer pays for his order. If the order uses an online payment method, the invoice will be created automatically. Else, invoices are manually created  by the administrator in back-end.

1. Invoice Model

Invoice model (Mage_Sales_Model_Order_Invoice) works with invoice data. Magento allows creating many invoices for an order. With each invoice, you can pay for some items of your order. You can get invoiced items by method getAllItems():

    public function getAllItems()
{
$items = array();
foreach ($this->getItemsCollection() as $item) {
if (!$item->isDeleted()) {
$items[] =  $item;
}
}
return $items;
}

In the topic 8, I mentioned about invoice total. It’s collected by the method collectTotals() in this model:

    /**
* Invoice totals collecting
*
* @return Mage_Sales_Model_Order_Invoice
*/
public function collectTotals()
{
foreach ($this->getConfig()->getTotalModels() as $model) {
$model->collect($this);
}
return $this;
}

Specially, invoice model has two important methods which are Capture and Pay. Method Pay affects the order; it’ll pay for the invoice’s order.

/**
* Pay invoice
*
* @return Mage_Sales_Model_Order_Invoice
*/
public function pay()
{
if ($this->_wasPayCalled) {
return $this;
}
$this-&gt;_wasPayCalled = true;</p>
$invoiceState = self::STATE_PAID;
if ($this-&gt;getOrder()-&gt;getPayment()-&gt;hasForcedState()) {
$invoiceState = $this-&gt;getOrder()-&gt;getPayment()-&gt;getForcedState();
}

$this-&gt;setState($invoiceState);

$this-&gt;getOrder()-&gt;getPayment()-&gt;pay($this);
$this-&gt;getOrder()-&gt;setTotalPaid(
$this-&gt;getOrder()-&gt;getTotalPaid()+$this-&gt;getGrandTotal()
);
$this-&gt;getOrder()-&gt;setBaseTotalPaid(
$this-&gt;getOrder()-&gt;getBaseTotalPaid()+$this-&gt;getBaseGrandTotal()
);
Mage::dispatchEvent('sales_order_invoice_pay', array($this-&gt;_eventObject=&gt;$this));
return $this;
}

Method Capture includes triggering the payment method to capture and pay for the order:

/**
* Capture invoice
*
* @return Mage_Sales_Model_Order_Invoice
*/
public function capture()
{
$this->getOrder()->getPayment()->capture($this);
if ($this->getIsPaid()) {
$this->pay();
}
return $this;
}

You can find more methods of this model in file: app\code\core\Mage\Sales\Model\Order\Invoice.php

2. Create an invoice for online capture payment

When you create an invoice in the back-end manual, the payment will be captured offline and the invoice is created. But if your customer uses an online payment to pay for his order, how and when an invoice is created?

I will take the payment method Paypal as an example. When a customer pays for his order by PayPal, his order information is sent to the Paypal gateway. When his payment in PayPal is completed, PayPal will call back to a link address. In Magento, it’s linked to the Paypal/Ipn Controller. In this controller, the payment is processed and the invoice is created as follows:

/**
* Instantiate IPN model and pass IPN request to it
*/
public function indexAction()
{
if (!$this-&gt;getRequest()-&gt;isPost()) {
return;
}</p>
try {
$data = $this-&gt;getRequest()-&gt;getPost();
Mage::getModel('paypal/ipn')-&gt;processIpnRequest($data, new Varien_Http_Adapter_Curl());
} catch (Exception $e) {
Mage::logException($e);
}
}

You can view the code to create the invoice in model paypal/ipn:

protected function _registerPaymentCapture()
{
if ($this-&gt;getRequestData('transaction_entity') == 'auth') {
return;
}
$this-&gt;_importPaymentInformation();
$payment = $this-&gt;_order-&gt;getPayment();
$payment-&gt;setTransactionId($this-&gt;getRequestData('txn_id'))
-&gt;setPreparedMessage($this-&gt;_createIpnComment(''))
-&gt;setParentTransactionId($this-&gt;getRequestData('parent_txn_id'))
-&gt;setShouldCloseParentTransaction('Completed' === $this-&gt;getRequestData('auth_status'))
-&gt;setIsTransactionClosed(0)
-&gt;registerCaptureNotification($this-&gt;getRequestData('mc_gross'));
$this-&gt;_order-&gt;save();</p>
// notify customer
if ($invoice = $payment-&gt;getCreatedInvoice() &amp;&amp; !$this-&gt;_order-&gt;getEmailSent()) {
$comment = $this-&gt;_order-&gt;sendNewOrderEmail()-&gt;addStatusHistoryComment(
Mage::helper('paypal')-&gt;__('Notified customer about invoice #%s.', $invoice-&gt;getIncrementId())
)
-&gt;setIsCustomerNotified(true)
-&gt;save();
}
}

3. Store invoice information

Magento stores invoice information in 4 following tables:

Magento blog tutorial on invoice1

Table sales_flat_invoice stores main information of invoices.

Table sales_flat_invoice_comment stores comments on an invoice.

Table sales_flat_invoice_item stores the list of items of invoice.

Specially, table sales_flat_invoice_grid stores some information of invoices to increase load speed when showing a grid invoice.

That’s enough for today. Hope it helpful for you! You can view more interesting certificate on Magento blog.

 

About David

David has been developing many great extensions in Magestore. He has a strong passion on programming and want to create product/service that serve society.

6 comments

  1. HI david,

    Thaks for great tutorial i read all your topics and i take date for examination. i am going to give exan on 24th dec. thanks again.

  2. Thanks David and all magestore team. I have passed exam yesterday.

  3. Thanks David. I have passed exam yesterday.

  4. Hey David,
    I am trying to edit the order and invoice emails generated by magento 1.7.
    Which files do I edit??

    • Hi Dave,

      You can find those template in folder app\locale\en_US\template\email\sales. In orther locals, for example fr_FR, you can change this folder to app\locale\fr_FR\template\email\sales
      Hope it helps