BLOG

Custom reports on Magento

Mon, 02/14/2011 - 16:41
I've never found a realy good tutorial on how to create a custom report on Magento, so I hope you'll find this helpful. - First of all, you need to generate a custom module, create the following files: /app/etc/modules/Mycompany_Mymodule.xml /app/design/adminhtml/default/default/layout/mymodule.xml /app/code/local/Mycompany/Mymodule/Block/adminhtml/Mymodule/Grid.php /app/code/local/Mycompany/Mymodule/Block/adminhtml/Mymodule.php /app/code/local/Mycompany/Mymodule/Block/Mymodule.php /app/code/local/Mycompany/Mymodule/controllers/Adminhtml/MymoduleController.php /app/code/local/Mycompany/Mymodule/etc/config.xml /app/code/local/Mycompany/Mymodule/Helper/Data.php /app/code/local/Mycompany/Mymodule/Model/Mymodule.php - Define your module on /app/etc/modules/Mycompany_Mymodule.xml: {syntaxhighlighter brush: xml;} true local {/syntaxhighlighter} - Complete the layout file which will update the admin view (I always do this first because I don't want to forget it). {syntaxhighlighter brush: xml;} {/syntaxhighlighter} - Create the config file with this content /app/code/local/Mycompany/Mymodule/etc/config.xml: {syntaxhighlighter brush: xml;} 0.1.0 admin Mycompany_Mymodule mymodule Mymodule Report mymodule/adminhtml_mymodule Allow Everything Mymodule Report mymodule/adminhtml_mymodule mymodule.xml Mycompany_Mymodule_Model mymodule Mycompany_Mymodule core_setup core_write core_read Mycompany_Mymodule_Block Mycompany_Mymodule_Helper {/syntaxhighlighter} Here we define the controller, the menu access and permisions, the model, the blocks and the helper. - Create the grid and specify all the columns /app/code/local/Mycompany/Mymodule/Block/adminhtml/Mymodule/Grid.php: {syntaxhighlighter brush: php;} setId('mymoduleGrid'); $this->setDefaultSort('created_at'); $this->setDefaultDir('ASC'); $this->setSaveParametersInSession(true); $this->setSubReportSize(false); } protected function _prepareCollection() { parent::_prepareCollection(); $this->getCollection()->initReport('mymodule/mymodule'); return $this; } protected function _prepareColumns() { $this->addColumn('ordered_qty', array( 'header' =>Mage::helper('reports')->__('Quantity Ordered'), 'align' =>'right', 'index' =>'ordered_qty', 'total' =>'sum', 'type' =>'number' )); $this->addColumn('item_id', array( 'header' => Mage::helper('mymodule')->__('Item ID'), 'align' => 'right', 'index' => 'item_id', 'type' => 'number', 'total' => 'sum', )); $this->addExportType('*/*/exportCsv', Mage::helper('mymodule')->__('CSV')); $this->addExportType('*/*/exportXml', Mage::helper('mymodule')->__('XML')); return parent::_prepareColumns(); } public function getRowUrl($row) { return false; } public function getReport($from, $to) { if ($from == '') { $from = $this->getFilter('report_from'); } if ($to == '') { $to = $this->getFilter('report_to'); } $totalObj = Mage::getModel('reports/totals'); $totals = $totalObj->countTotals($this, $from, $to); $this->setTotals($totals); $this->addGrandTotals($totals); return $this->getCollection()->getReport($from, $to); } } {/syntaxhighlighter} This file is clearest but I give you some tips about specific lines: // this line indicates the model to use for get the data. $this->getCollection()->initReport('mymodule/mymodule'); // it's used to indicate that this field must be totalized at the end. 'total' =>'sum', // this is executed when you click on the rows grid, in case you return false (like the example) nothing will happen when you click on the rows grid. public function getRowUrl($row) { - For the next step, create the grid container block /app/code/local/Mycompany/Mymodule/Block/adminhtml/Mymodule.php: {syntaxhighlighter brush: php;} _controller = 'adminhtml_mymodule'; $this->_blockGroup = 'mymodule'; $this->_headerText = Mage::helper('mymodule')->__('Mymodule Report'); parent::__construct(); $this->_removeButton('add'); } } {/syntaxhighlighter} Here we add this line to remove the add button: // This must be always after the parent::__construct(); line. $this->_removeButton('add'); - Create the block container /app/code/local/Mycompany/Mymodule/Block/Mymodule.php: {syntaxhighlighter brush: php;} hasData('mymodule')) { $this->setData('mymodule', Mage::registry('mymodule')); } return $this->getData('mymodule'); } } {/syntaxhighlighter} - Create the controller /app/code/local/Mycompany/Mymodule/controllers/Adminhtml/MymoduleController.php: {syntaxhighlighter brush: php;} loadLayout(); return $this; } public function indexAction() { $this->_initAction() ->renderLayout(); } public function exportCsvAction() { $fileName = 'mymodule.csv'; $content = $this->getLayout()->createBlock('mymodule/adminhtml_mymodule_grid') ->getCsv(); $this->_sendUploadResponse($fileName, $content); } public function exportXmlAction() { $fileName = 'mymodule.xml'; $content = $this->getLayout()->createBlock('mymodule/adminhtml_mymodule_grid') ->getXml(); $this->_sendUploadResponse($fileName, $content); } protected function _sendUploadResponse($fileName, $content, $contentType='application/octet-stream') { $response = $this->getResponse(); $response->setHeader('HTTP/1.1 200 OK', ''); $response->setHeader('Pragma', 'public', true); $response->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true); $response->setHeader('Content-Disposition', 'attachment; filename=' . $fileName); $response->setHeader('Last-Modified', date('r')); $response->setHeader('Accept-Ranges', 'bytes'); $response->setHeader('Content-Length', strlen($content)); $response->setHeader('Content-type', $contentType); $response->setBody($content); $response->sendResponse(); die; } } {/syntaxhighlighter} - Then the empty helper /app/code/local/Mycompany/Mymodule/Helper/Data.php: {syntaxhighlighter brush: php;} setResourceModel('sales/order_item'); $this->_init('sales/order_item','item_id'); } public function setDateRange($from, $to) { $this->_reset(); $this->getSelect() ->joinInner(array( 'i' => $this->getTable('sales/order_item')), 'i.order_id = main_table.entity_id' ) ->where('i.parent_item_id is null') ->where("i.created_at BETWEEN '".$from."' AND '".$to."'") ->where('main_table.state = \'complete\'') ->columns(array('ordered_qty' => 'count(distinct `main_table`.`entity_id`)')); // uncomment next line to get the query log: // Mage::log('SQL: '.$this->getSelect()->__toString()); return $this; } public function setStoreIds($storeIds) { return $this; } } ?> {/syntaxhighlighter} This is a custom model that get the data from Magento core models, here you can define any model or if you already got your own DB/tables you can get the report data from it. // this line reset the original query that comes by default. $this->_reset(); All done!