In the last lesson, we learnt how to add a custom total when checkout and creating order. Now we will examine how to create Invoice and Refund for order as well as practice adding custom total to Invoice and Creditmemo.

This lesson lasts for two hours and comprises four sections:

  • Adding custom total to Invoice and Creditmemo
  • Declaring totals for Invoice and Creditmemo
  • Creating totals for Invoice and Creditmemo
  • Showing totals on view pages: Invoice and Creditmemo

1. Adding custom total to Invoice and Creditmemo

There are many ways to calculate value of custom total for Invoice and Creditmemo in order process, but the simplest way is to save more data about custom total in necessary tables.

We create Magestore_Lesson24 module, the content in setting file of this module (app\code\local\Magestore\Lesson24\sql\lesson24_setup\mysql4-install-0.1.0.php) is:

$installer->run("

ALTER TABLE {$this->getTable('sales/order')}
ADD COLUMN `custom_discount` decimal(12,4) NOT NULL default '0',
ADD COLUMN `base_custom_discount` decimal(12,4) NOT NULL default '0';

ALTER TABLE {$this->getTable('sales/order_item')}
ADD COLUMN `custom_discount` decimal(12,4) NOT NULL default '0',
ADD COLUMN `base_custom_discount` decimal(12,4) NOT NULL default '0';

ALTER TABLE {$this->getTable('sales/invoice')}
ADD COLUMN `custom_discount` decimal(12,4) NOT NULL default '0',
ADD COLUMN `base_custom_discount` decimal(12,4) NOT NULL default '0';

ALTER TABLE {$this->getTable('sales/creditmemo')}
ADD COLUMN `custom_discount` decimal(12,4) NOT NULL default '0',
ADD COLUMN `base_custom_discount` decimal(12,4) NOT NULL default '0';

");

You can add two fields – custom_discount and base_custom_discount – to many tables:

  • Sales/order table: These fields save value of custom discount for each order.
  • Sales/order_item table: These fields save custom discount value corresponding to each item. Magento supports partial invoice and partial creditmemo, so they are used to calculate in creating partial invoice and partial creditmemo process.
  • Sales/invoice table: These fields save custom discount for each invoice
  • Sales/creditmemo table: These fields save custom discount for each creditmemo.

Next, we declare totals for Invoice and Creditmemo. You can see how to declare for Order in the previous lesson.

2. Declaring totals for Invoice and Creditmemo

After we declare, Magento receives custom totals from config.xml file of module and they are in app\code\local\Magestore\Lesson24\etc\config.xml folder:

<config>
...
<global>
<sales>
<quote>
<totals>
<custom_discount>
<class>lesson24/total_quote_discount</class>
<after>grand_total</after>
</custom_discount>
</totals>
</quote>
<order_invoice>
<totals>
<custom_discount>
<class>lesson24/total_invoice_discount</class>
<after>grand_total</after>
</custom_discount>
</totals>
</order_invoice>
<order_creditmemo>
<totals>
<custom_discount>
<class>lesson24/total_creditmemo_discount</class>
<after>grand_total</after>
</custom_discount>
</totals>
</order_creditmemo>
</sales>
...
</global>
</config>

In this code block, look at two XPath – global/sales/order_invoice and global/sales/order_creditmemo – which are used to declare totals for Invoice and Creditmemo:

  • totals: Declare totals for invoice/ creditmemo
  • custom_discount: Identify for custom total (here I use custom_discount, you can change it depending on your purpose)
  • class: Class to declare model for this total
  • before: List of totals (in their identifier) custom total runs before
  • after: List of totals (in their identifier) custom total runs after these above totals

Additionally, we need to declare to save total fields for each item with the code block in config.xml file:

<config>
...
<global>
...
<fieldsets>
...
<sales_convert_quote_item>
<custom_discount>
<to_order_item>*</to_order_item>
</custom_discount>
<base_custom_discount>
<to_order_item>*</to_order_item>
</base_custom_discount>
</sales_convert_quote_item>
</fieldsets>
</global>
</config>

3. Creating totals model for Invoice and Creditmemo

Create layer Magestore_Lesson24_Model_Total_Invoice_Discount in app\code\local\Magestore\Lesson24\Model\Total\Invoice\Discount.php file to calculate total for Invoice when it is created. The content of this layer is:

class Magestore_Lesson24_Model_Total_Invoice_Discount extends Mage_Sales_Model_Order_Total_Abstract
{
/**
* Collect total when create Invoice
*
* @param Mage_Sales_Model_Order_Invoice $invoice
*/
public function collect(Mage_Sales_Model_Order_Invoice $invoice)
{
$order = $invoice->getOrder();
if ($order->getCustomDiscount() <= 0.0) {
return $this;
}
$baseDiscount = 0;
$discount = 0;
foreach ($invoice->getAllItems() as $item) {
$orderItem = $item->getOrderItem();
if ($orderItem->isDummy()) {
continue;
}
$baseDiscount += $orderItem->getBaseCustomDiscount() * $item->getQty() / $orderItem->getQtyOrdered();
$discount += $orderItem->getCustomDiscount() * $item->getQty() / $orderItem->getQtyOrdered();
}
$invoice->setBaseCustomDiscount($baseDiscount);
$invoice->setCustomDiscount($discount);

$invoice->setBaseGrandTotal($invoice->getBaseGrandTotal() - $baseDiscount);
$invoice->setGrandTotal($invoice->getGrandTotal() - $discount);
return $this;
}
}

Calculating total for Invoice depends on items it has and database from order items:

$baseDiscount += $orderItem->getBaseCustomDiscount() * $item->getQty() / $orderItem->getQtyOrdered();
$discount += $orderItem->getCustomDiscount() * $item->getQty() / $orderItem->getQtyOrdered();

Then, custom discount is subtracted from grand total in Invoice:

$invoice->setBaseGrandTotal($invoice->getBaseGrandTotal() - $baseDiscount);
$invoice->setGrandTotal($invoice->getGrandTotal() - $discount);

For example, I place an order and then create Invoice in backend. With the above functions, results are:

checkout totals

After updating the number of items for Invoice:

invoice and refund

Like Invoice, create model corresponding to Creditmemo. Here I do not show code sample, you can do the same as above.

4. Showing totals on view pages: Invoice and Creditmemo

The database shown in screenshots in section 3 in the previous post only appears after you finish the following steps.

To show custom total for view pages Invoice and Creditmemo, add these code block to layout backend (in file app\design\adminhtml\default\default\layout\lesson24.xml)

<layout version="0.1.0">
...
<!-- Invoice Totals -->
<adminhtml_sales_order_invoice_new>
<reference name="invoice_totals">
<block type="lesson24/adminhtml_totals_invoice_discount" name="lesson24.total.discount" />
</reference>
</adminhtml_sales_order_invoice_new>
<adminhtml_sales_order_invoice_updateqty>
<reference name="invoice_totals">
<block type="lesson24/adminhtml_totals_invoice_discount" name="lesson24.total.discount" />
</reference>
</adminhtml_sales_order_invoice_updateqty>

<adminhtml_sales_order_invoice_view>
<reference name="invoice_totals">
<block type="lesson24/adminhtml_totals_invoice_discount" name="lesson24.total.discount" />
</reference>
</adminhtml_sales_order_invoice_view>

<!-- Creditmemo Totals -->
<adminhtml_sales_order_creditmemo_new>
<reference name="creditmemo_totals">
<block type="lesson24/adminhtml_totals_creditmemo_discount" name="lesson24.total.discount" />
</reference>
</adminhtml_sales_order_creditmemo_new>
<adminhtml_sales_order_creditmemo_updateqty>
<reference name="creditmemo_totals">
<block type="lesson24/adminhtml_totals_creditmemo_discount" name="lesson24.total.discount" />
</reference>
</adminhtml_sales_order_creditmemo_updateqty>

<adminhtml_sales_order_creditmemo_view>
<reference name="creditmemo_totals">
<block type="lesson24/adminhtml_totals_creditmemo_discount" name="lesson24.total.discount" />
</reference>
</adminhtml_sales_order_creditmemo_view>
</layout>

Then, write blocks for totals, and these blocks are nearly similar to each other.

Code for a view invoice block in file

app\code\local\Magestore\Lesson24\Block\Adminhtml\Totals\Invoice\Discount.php:

class Magestore_Lesson24_Block_Adminhtml_Totals_Invoice_Discount
extends Mage_Adminhtml_Block_Sales_Order_Totals_Item
{
public function initTotals()
{
$totalsBlock = $this->getParentBlock();
$invoice = $totalsBlock->getInvoice();

if ($invoice->getCustomDiscount()) {
$totalsBlock->addTotal(new Varien_Object(array(
'code' => 'rewardpoints',
'label' => $this->__('Custom Discount'),
'value' => -$invoice->getCustomDiscount(),
)), 'subtotal');
}
}
}

In block, use addTotal method to add custom discount to totals block of Magento. In view invoice page of admin, custom total is as follows: 

checkout totals invoice

For frontend, we do the same process to add layout and block. The content of frontend: 

<layout version="0.1.0">
...
<!-- Invoice Layout -->
<sales_order_invoice>
<reference name="invoice_totals">
<block type="lesson24/totals_invoice_discount" name="lesson24.total.discount" />
</reference>
</sales_order_invoice>
<sales_order_printinvoice>
<reference name="invoice_totals">
<block type="lesson24/totals_invoice_discount" name="lesson24.total.discount" />
</reference>
</sales_order_printinvoice>
<sales_email_order_invoice_items>
<reference name="invoice_totals">
<block type="lesson24/totals_invoice_discount" name="lesson24.total.discount" />
</reference>
</sales_email_order_invoice_items>

<!-- Creditmemo Layout -->
<sales_order_creditmemo>
<reference name="creditmemo_totals">
<block type="lesson24/totals_creditmemo_discount" name="lesson24.total.discount" />
</reference>
</sales_order_creditmemo>
<sales_order_printcreditmemo>
<reference name="creditmemo_totals">
<block type="lesson24/totals_creditmemo_discount" name="lesson24.total.discount" />
</reference>
</sales_order_printcreditmemo>
<sales_email_order_creditmemo_items>
<reference name="creditmemo_totals">
<block type="lesson24/totals_creditmemo_discount" name="lesson24.total.discount" />
</reference>
</sales_email_order_creditmemo_items>
</layout>

The block is added to file app\code\local\Magestore\Lesson24\Block\Totals\Invoice\Discount.php:

class Magestore_Lesson24_Block_Totals_Invoice_Discount extends Mage_Core_Block_Template
{
public function initTotals()
{
$totalsBlock = $this->getParentBlock();
$invoice = $totalsBlock->getInvoice();

if ($invoice->getCustomDiscount()) {
$totalsBlock->addTotal(new Varien_Object(array(
'code' => 'rewardpoints',
'label' => $this->__('Custom Discount'),
'value' => -$invoice->getCustomDiscount(),
)), 'subtotal');
}
}
}

Result in frontend:

checkout-total-invoice-result

Let’s finish all of the blocks declared in layout in the same way as the above block.

So, in this lesson, we gained in creating a custom total for invoice and refund in Magento. Especially, the custom totals support partial invoice and partial refund. In the next lesson, we will learn how to process shipping in Magento. Enjoy coding and see you later. Follow us in Magento Open Course for Magento Tutorial.

Author

Why Magestore? We believe in building a meaningful & long-term relationship with you.

Write A Comment