Apesar do Magento possuir um módulo de relatórios básicos, quem precisa administrar uma loja online logo percebe que estes relatórios são insuficientes para suprir as necessidades de uma boa administração.
E algumas pessoas preferem acreditar que a falta destes relatórios não influencia nos resultados e que podem sobreviver sem eles. Mas a verdade é que aprender a criar relatórios para Magento pode ser um diferencial enorme para sua empresa.
Por isso neste post iremos desenvolver um exemplo bem prático e simples de relatório que lista todos os clientes que optaram por serem alertados quando determinado produto voltar ao estoque (produto não disponível – avise-me quando chegar).
Atenção! Esse artigo NÃO é para vender o módulo, e sim ensinar como criar uma extensão simples dos relatórios de backend do Magento.
Entendendo a funcionalidade
O sistema possui um módulo de alertas para os clientes, que avisam sobre alterações nos produtos. Um destes alertas avisa ao cliente quando o produto retorna ao estoque. Para habilitar essa funcionalidade vá em:
Sistema > Configuração > Catálogo [ Aviso de Produtos ]
Na opção “Avisar quando houver produto em estoque” marque “Sim“.
Agora sempre que um produto aparecer como esgotado no frontend, o cliente tem a opção de se cadastrar em uma lista, para ser avisado quando este produto retornar ao estoque (depende do template/tema).
Acontece que, não existe um relatório no Magento que mostre ao gerente de forma simples, quais produtos esgotados possuem lista de espera, ou mesmo quantas pessoas estão aguardando determinado produto.
No momento, a única forma de verificar essas informações, é acessando produto por produto, e olhando as informações no menu “Alerta de Produtos“.
Essa tarefa se torna impraticável quando você possui centenas de produtos.
Iniciando um novo módulo
Sempre que criamos um novo módulo no sistema, precisamos informar ao Magento que é preciso carregar as informações do novo módulo. Para isso precisamos criar o arquivo MarioSAM_RelatorioAviseme.xml na pasta:
app > etc > modules
E dentro deste arquivo coloque o conteúdo:
true local //local <<--tem q ficar assim, se estiver apenas "local" é bug!
Com isso informamos ao sistema que existe um novo módulo ativo na pasta local com nome MarioSAM_RelatorioAviseme.
Dica! Siga todos os passos à risca e veja funcionar na sua aplicação antes de efetuar suas customizações.
Organizando o módulo
Sempre que informamos ao sistema que existe um novo módulo, o mesmo vai procurar no diretório indicado (acima) pelo arquivo de configuração, que recebe o nome de config.xml. Então vamos criar a estrutura/arquivo em:
app/code/local/MarioSAM/RelatorioAviseme/etc/config.xml
É neste arquivo que você informa ao sistema a estrutura do seu módulo, as ações, rotinas, template, acessos, menus, etc. Vou mostrar abaixo nosso arquivo completo para este exemplo, na sequência do post você vai entender o que significa cada bloco.
0.1.0 MarioSAM_RelatorioAviseme_Block admin MarioSAM_RelatorioAviseme relatorioaviseme
O primeiro bloco é auto-explicativo. Ele apenas informa ao sistema qual a versão do módulo. Quando você passa a distribuir o módulo pela internet, essa informação é extremamente importante.
Como nasceu o menu no backend
Eu já mostrei no arquivo acima como criar o menu, mas é importante explicar essa etapa, pois é mais complicado do que parece.
Como estou usando apenas um menu simples, eu resolvi criar o bloco dentro do arquivo config.xml, mas se você pretende criar uma lista de menu, com configurações diversas, então o correto é criar um arquivo adminhtml.xml para controlar apenas o menu e suas ações.
O que eu fiz foi trazer as configurações do adminhtml para dentro do config:
Veja que dentro da tag adminhtml eu crio a estrutura de menu, informando que será incluido em report e dentro dele (children), no menu products e dentro dele (children), então eu crio a minha tag (nome do meu módulo) com a descrição e ação a ser executada quando alguém clicar no menu.
Essa ação contém uma URL que não existe para o sistema. Eu preciso informar nas configurações do módulo que aquela url deve iniciar os trabalhos de uma classe. E isso é feito com o bloco:
admin MarioSAM_RelatorioAviseme relatorioaviseme
Onde eu informo o frontName (que deve ser igual ao usado na action do menu), e esta url vai executar um controlador que esteja dentro da pasta module informada, e vai carregar todas as informações na área de admin.
Criando o controle de ações
Seguindo os padrões de desenvolvimento do Magento, agora nós precisamos criar um controlador (controller), que é responsável por gerenciar as ações a serem executadas. Então crie a estrutura/arquivo:
app/code/local/MarioSAM/RelatorioAviseme/controllers/Report/ProductController.php
Esse caminho é relativo ao informado na action do menu, sendo que a última parte “/avisar” é o nome do método a ser executado dentro do ProductController.
Observe que ele não executa nenhuma ação, ele apenas gerencia as ações que devem ser executadas. Insira o código abaixo:
getRequest()->getActionName(); $this->loadLayout() ->_addBreadcrumb(Mage::helper('reports')->__('Reports'), Mage::helper('reports')->__('Reports')) ->_addBreadcrumb(Mage::helper('reports')->__('Products'), Mage::helper('reports')->__('Products')); return $this; } public function avisarAction() { $this->_title($this->__('Reports')) ->_title($this->__('Products')) ->_title($this->__('Avisar Clientes')); $this->_initAction() ->_setActiveMenu('report/product/relatorioaviseme') ->_addBreadcrumb($this->__('Avisar Clientes'), $this-->__('Avisar Clientes')) ->_addContent($this->getLayout()->createBlock('relatorioaviseme/report_product_avisar')) ->renderLayout(); } }
Aqui também não é difícil de entender o que foi feito. A função começa informando o título da página “_title“, e na sequência inicia as ações que vão montar a página. Ele informa “_setActiveMenu” qual opção do menu foi clicado. Em “_addBreadcrumb” ele informa a migalha (caminho percorrido). A parte mais importante “_addContent” é informado qual bloco vai carregar as informações da página. E em “_renderLayout” ele finaliza imprimindo toda essa informação no navegador.
Criando o bloco de conteúdo
No controller nós informamos um block em “_addContent” que ainda não existe. É exatamente este bloco que iremos criar agora, então devemos seguir o caminho de diretórios indicados no controle. Crie o seguinte arquivo:
app/code/local/MarioSAM/RelatorioAviseme/Block/Report/Product/Avisar.php
Lembrando que para usar blocos criados para seu módulo, nós informamos no config.xml uma tag block indicando onde estão os arquivos.
Compare com o conteúdo informado em “->createBlock“, veja que é o mesmo caminho. Os blocos são responsáveis por construir as páginas do sistema (frontend e backend). Então vamos ver o código dessa página:
_blockGroup = 'relatorioaviseme'; $this->_controller = 'report_product_avisar'; $this->_headerText = $this->__('Lista de Espera'); parent::__construct(); $this->_removeButton('add'); } protected function _prepareLayout() { return parent::_prepareLayout(); } public function getGridHtml() { return parent::getGridHtml(); } }
Essa classe estende uma super-classe, então muita coisa não precisa ser reescrita. Basicamente informamos as particularidades de nosso bloco.
O importante de ressaltar nesse código é a função “getGridHtml()“, que ao ser declarada informa ao sistema que deve ser carregado uma grid neste bloco para ser apresentado na tela.
E uma variável extremamente importante, declarada logo no início do código “$this->_blockGroup” que deve receber o nome do nosso módulo. Caso contrário ele perde a conexão com seu controller.
Criando a grid de resultados
Estamos chegando ao fim deste tutorial. Já criamos o menu, criamos o controlador com sua action, criamos o bloco responsável por montar a página, e agora vamos criar a grid que carrega o conteúdo na página. Para isso crie o diretório/arquivo:
app/code/local/MarioSAM/RelatorioAviseme/Block/Report/Product/Avisar/Grid.php
Nossa grid possui três funções importantes. Como veremos no código abaixo:
setId('gridAvisar'); $this->setDefaultSort('add_date'); $this->setDefaultSort('desc'); $this->setUseAjax(true); $this->setFilterVisibility(false); $this->setEmptyText(Mage::helper('catalog')->__('There are no customers for this alert.')); } protected function _prepareCollection() { $collection = new Varien_Data_Collection(); $dados = Mage::getModel( 'productalert/stock' )->getCollection(); foreach ( $dados as $col ) { $pro = Mage::getModel('catalog/product')->getCollection()->addFieldToFilter('entity_id',$col->getProductId() ); $cli = Mage::getModel('customer/customer')->getCollection()->addFieldToFilter('entity_id',$col->getCustomerId() ); $col->setCustomerId( $cli->getFirstItem()->getEmail() ); $col->setProductId( $pro->getFirstItem()->getSku() ); $collection->addItem( $col ); } $this->setCollection( $collection ); return parent::_prepareCollection(); } protected function _prepareColumns() { $this->addColumn('product_id', array( 'header'=> $this->__('Sku do Produto'), 'index' => 'product_id' )); $this->addColumn('customer_id', array( 'header'=> $this->__('Email Cliente'), 'index' => 'customer_id', )); $this->addColumn('add_date', array( 'header'=> $this->__('Aguardando Desde'), 'index' => 'add_date', 'type' => 'date' )); $this->addColumn('send_count', array( 'header'=> $this->__('Avisado x'), 'index' => 'send_count' )); return parent::_prepareColumns(); } }
A primeira função importante é “_construct()“. Como o nome sugere, são informações usadas na construção da grid, como ordem de exibição dos dados, filtros, uso de ajax, mensagens de resultados nulos, etc.
A segunda função também muito importante é “_prepareCollection()“. Onde a coleção de dados é carregada, ou seja, onde é feita a consulta de dados nas tabelas. Nesse exemplo foi preciso percorrer a coleção para adicionar informações de “nome do produto/email do cliente”.
E por último, mas não menos importante “_prepareColumns()“. Que correspondem as colunas das grids apresentadas na tela. Aqui podemos configurar cada coluna com dados de configuração (como máscaras e alinhamentos).
A consulta ao banco de dados no Magento não é feita usando SQL. Pelos padrões MVC adotados no desenvolvimento desta ferramenta, o acesso é feito por modelos (Models). Mas, sempre existe a possibilidade de usar SQL caso seja necessário.
E agora José?
Com isso encerramos nosso módulo de relatórios. Agora você possui uma base sólida para entender o processo de criação de relatórios, aproveite para explorar o código dos relatórios padrões do Magento.
Caso seu interesse nesse tutorial não seja o de aprender a criar relatórios, e sim ter essa funcionalidade aplicada a sua loja, você pode fazer o download dos arquivos usados neste exemplo no final da página.
Criado na versão 1.4.x e testado na versão 1.7.x
Sucesso!