Criando um módulo de frete para Magento
Hoje vou explicar como desenvolver um módulo de frete para o Magento, sem se preocupar com o cálculo do frete em si, mas sim com a estrutura do módulo.
Recentemente tive que implantar uma loja sobre o Open Source Magento, que estava em seu início e não existia praticamente nada “brasileiro” para ele.
Comecei do zero e a primeira coisa que desenvolvi foi o módulo de frete, que postei para a comunidade e houveram várias melhorias, quem quiser conferir, dê uma passada no Fórum do Magento.
Primeiro temos que criar a estrutura de pastas do módulo, que será colocada dentro da pasta “app/code/community”. Abra essa pasta e crie a seguinte estrutura dentro:
| Correio
-- Shipping
|-- etc
|-- Helper
|-- Model
|-- Carrier
|-- sql
|-- shipping_setup
Com a estrutura criada vamos ao desenvolvimento. Abra a pasta “Correio/Shipping/etc” e crie os seguintes arquivos dentro:
system.xml
<?xml version="1.0"?>
<config>
<sections>
<carriers>
<groups>
<correiopost translate="label" module="shipping">
<label>Correios</label>
<frontend_type>text</frontend_type>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
<fields>
<teste_method translate="label">
<label>Método de teste</label>
<frontend_type>select</frontend_type>
<frontend_class>free-method</frontend_class>
<source_model>correio_shipping_model_testemethod</source_model>
<sort_order>11</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</teste_method>
<active translate="label">
<label>Habilitado</label>
<frontend_type>select</frontend_type>
<source_model>adminhtml/system_config_source_yesno</source_model>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</active>
<handling_fee translate="label">
<label>Taxa de Postagem</label>
<frontend_type>text</frontend_type>
<sort_order>9</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</handling_fee>
<free_method translate="label">
<label>Método para entrega gratuita</label>
<frontend_type>text</frontend_type>
<sort_order>200</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</free_method>
<showmethod translate="label">
<label>Mostra métodos se não aplicável</label>
<frontend_type>select</frontend_type>
<sort_order>92</sort_order>
<source_model>adminhtml/system_config_source_yesno</source_model>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</showmethod>
<sort_order translate="label">
<label>Ordenar por</label>
<frontend_type>text</frontend_type>
<sort_order>100</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</sort_order>
</fields>
</correiopost>
</groups>
</carriers>
</sections>
</config>
Esse arquivo explica para o Magento como a área administrativa do módulo deve se comportar, que campos de configuração deve ter e por aí vai. Se você olhar bem vai ver que o arquivo XML é bem simples, depois que falamos o nome do módulo começamos a explicar os campos que o administrador deve ter, e cada campo tem seu nome, tipo, ordem e se deve ser exibido no padrão, site e loja.
Crie esse arquivo também no “Correio/Shipping/etc”.
config.xml
<?xml version="1.0"?>
<config>
<modules>
<Correio_Shipping>
<version>0.1.0</version>
<depends>
<Mage_Shipping />
</depends>
</Correio_Shipping>
</modules>
<global>
<models>
<tmshipping>
<class>Correio_Shipping</class>
</tmshipping>
</models>
<resources>
<tmshipping_setup>
<setup>
<module>Correio_Shipping</module>
</setup>
<connection>
<use>directory_setup</use>
</connection>
</tmshipping_setup>
<tmshipping_read>
<connection>
<use>local_read</use>
</connection>
</tmshipping_read>
</resources>
<sales>
<shipping>
<carriers>
<correiopost>
<class>Correio_Shipping_Model_Carrier_CorreioPost</class>
</correiopost>
</carriers>
</shipping>
</sales>
</global>
<default>
<carriers>
<correiopost>
<active>1</active>
<model>Correio_Shipping_Model_Carrier_CorreioPost</model>
<title>Correios</title>
<name>Correios</name>
<handling_fee>0</handling_fee>
<showmethod>0</showmethod>
<free_method>sedex</free_method>
</correiopost>
</carriers>
</default>
</config>
Esse arquivo ajudará o Magento a entender seu módulo e como utilizá-lo, não irei me aprofundar. No final do arquivo definimos os valores padrões dos campos criados no arquivo “system.xml”.
Com isso a configuração do módulo está certa.
Dentro da pasta “Correio/Shipping/Helper” crie o seguinte arquivo:
Data.php
/**
* Pedro Teixeira
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL).
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category Correio
* @package Correio_Shipping
* @copyright Copyright (c) 2009 Pedro Teixeira
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/
class Correio_Shipping_Helper_Data extends Mage_Core_Helper_Abstract
{
}
Agora dentro da pasta “Correio/Shipping/sql/shipping_setup” crie o seguinte arquivo:
mysql4-install-0.1.0.php
/**
* Pedro Teixeira
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL).
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category Correio
* @package Correio_Shipping
* @copyright Copyright (c) 2009 Pedro Teixeira
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/
Certo, agora temos as configurações já definidas, vamos ao módulo!
Dentro da pasta “Correio/Shipping/Model” crie o arquivo:
Testemethod.php
/**
* Pedro Teixeira
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL).
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category Correio
* @package Correio_Shipping
* @copyright Copyright (c) 2009 Pedro Teixeira
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/
class Correio_Shipping_Model_TestesMethod
{
public function toOptionArray()
{
return array(
array('value'=>1, 'label'=>Mage::helper('adminhtml')->__('Teste 1')),
array('value'=>0, 'label'=>Mage::helper('adminhtml')->__('Teste 2')),
);
}
}
Esse arquivo é um tipo de campo! Como assim? Lembra do arquivo “system.xml” que define os campos que o administrador do módulo deve ter? Então, esse arquivo define um tipo especial de campo, nesse caso um dropdown com algumas opções. E na linha 14 do “system.xml” falamos que o campo utiliza essa configuração.
Agora dentro do “Correio/Shipping/Model/Carrier” criamos o seguinte arquivo:
CorreioPost.php
/**
* Pedro Teixeira
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL).
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category Correio
* @package Correio_Shipping
* @copyright Copyright (c) 2009 Pedro Teixeira
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/
class Correio_Shipping_Model_Carrier_CorreioPost
extends Mage_Shipping_Model_Carrier_Abstract
implements Mage_Shipping_Model_Carrier_Interface
{
protected $_code = 'correiopost';
protected $_result = null;
public function collectRates(Mage_Shipping_Model_Rate_Request $request)
{
if (!$this->getConfigFlag('active'))
{
//Desabilitado
return false;
}
$result = Mage::getModel('shipping/rate_result');
$error = Mage::getModel('shipping/rate_result_error');
$error->setCarrier($this->_code);
$error->setCarrierTitle($this->getConfigData('title'));
$packagevalue = $request->getBaseCurrency()->convert($request->getPackageValue(), $request->getPackageCurrency());
$frompcode = Mage::getStoreConfig('shipping/origin/postcode', $this->getStore());
$topcode = $request->getDestPostcode();
if(!ereg("^[0-9]{8}$", $topcode))
{
//CEP está errado
$error->setErrorMessage('O CEP está errado');
$result->append($error);
Mage::helper('customer')->__('Invalid ZIP CODE');
return $result;
}
$sweight = $request->getPackageWeight();
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier($this->_code);
$method->setCarrierTitle($this->getConfigData('name'));
$method->setMethod('sedex');
$method->setMethodTitle('Sedex');
$method->setPrice(10 + $this->getConfigData('handling_fee'));
$method->setCost(10);
$result->append($method);
$this->_result = $result;
$this->_updateFreeMethodQuote($request);
return $this->_result;
}
public function getAllowedMethods()
{
return array($this->_code => $this->getConfigData('title'));
}
}
Esse é o cara que podemos chamar de módulo mesmo, pois é ele quem faz o cálculo do frete. Bom, vou explicar linha por linha o que ele faz, primeiro o número da linha e depois a explicação.
- 16 Nomeia a classe. Lembre que se trata de Zend e o nome da classe deve seguir um padrão.
- 25 Nomeia a função “collectRates”, que será chamada pelo Magento quando ele quiser calcular o frete.
- 27 até 31 Faço uma verificação, um exemplo.
- 27 Ele verifica se o campo “active” na administração está habilitado, esse comando pode ser usado com qualquer outro campo da administração.
- 33 Pega o modelo do XML de resposta.
- 35 Pega o modelo do XML de resposta com erro.
- 39 Recupera o valor dos produtos que estão no carrinho.
- 41 Pega o CEP da sua loja, da configuração do site.
- 42 Pega o CEP digitado pelo usuário.
- 45 Checa se o CEP digitado está correto.
- 46 até 51 Trata um erro criando uma forma do Magento não explodir o erro, e sim tratar uma mensagem.
- 54 Recupera o peso dos produtos no carrinho.
- 66 Diz ao Magento qual será o valor do frete, nesse caso, R$ 10 mais a taxa de postagem, que será definida no administrador.
- 68 Grava o custo do frete. Note a diferença entre preço e custo, o preço é o que irá para o usuário e custo é uma informação sua, que não será exibida.
- 74 Caso você tenha definido uma promoção ou um cartão de desconto que o frete seja gratuito essa função fará o trabalho para você.
- 76 Restorna o XML com todo o resultado para o Magento.
Pronto! Temos todo o módulo criado e configurado, porém ainda falta avisar o Magento da existência dele. Dentro da pasta “app/etc/modules” crie o seguinte arquivo:
Correio_Shipping.xml
<?xml version="1.0"?>
<config>
<modules>
<Correio_Shipping>
<active>true</active>
<codePool>community</codePool>
</Correio_Shipping>
</modules>
</config>
Agora basta atualizar seu cache e adaptar o módulo para o seu uso!
Foi clara minha explicação? Se não, poste sua dúvida que tento ajudar.
Obrigado a até mais!
Espaço reservado para perguntas que levam muito código#
A pergunta do Ronaldo é de como adaptar meu módulo para calcular o frete de acordo com faixas de CEP, ou cidades.
Olá Ronaldo
Obrigado por sua visita e por seu comentário, vou tentar ajudá-lo.
Bom, desconheço um módulo que já tenha o que você quer implementado, mas não é impossível adaptar um módulo para fazer isso.
O CEP é divido por faixas, onde por exemplo (não estou usando dados reais) do número 01300-000 até o 01499-999 é a cidade de São Paulo. Você pode ter mais informações sobre isso no link abaixo, e eu sei que ligando nos Correios eles te ajudam também.
http://www.correios.com.br/servicos/dnec/menuAction.do?Metodo=menuFaixaCep
Então nosso frete será calculado de acordo com o CEP do usuário, para isso a primeira coisa que devemos fazer e pegar o CEP:
$topcode = $request->getDestPostcode();
Depois devemos fazer uma sequência de if e elseif para ver qual o valor do frete e o nome da transportadora, por exemplo:
if($topcode >= 01300000 && $topcode <= 01499999){
$method->setMethod('trans1');
$method->setMethodTitle('Transportadora 1');
$method->setPrice(10 + $this->getConfigData('handling_fee'));
$method->setCost(10);
}elseif($topcode >= 01500000 && $topcode <= 01699999){
$method->setMethod('trans2');
$method->setMethodTitle('Transportadora 2');
$method->setPrice(20 + $this->getConfigData('handling_fee'));
$method->setCost(20);
}else{
$error->setErrorMessage('Não trabalhamos com o CEP digitado');
$result->append($error);
return $result;
}
E pronto, agora seu valor de frete já está calculado basta responder o módulo.
Seu módulo completo ficaria da seguinte forma:
class Trans_Shipping_Model_Carrier_TransPost
extends Mage_Shipping_Model_Carrier_Abstract
implements Mage_Shipping_Model_Carrier_Interface
{
protected $_code = 'transpost';
protected $_result = null;
public function collectRates(Mage_Shipping_Model_Rate_Request $request)
{
if (!$this->getConfigFlag('active'))
{
//Desabilitado
return false;
}
$result = Mage::getModel('shipping/rate_result');
$error = Mage::getModel('shipping/rate_result_error');
$error->setCarrier($this->_code);
$error->setCarrierTitle($this->getConfigData('title'));
$packagevalue = $request->getBaseCurrency()->convert($request->getPackageValue(), $request->getPackageCurrency());
$frompcode = Mage::getStoreConfig('shipping/origin/postcode', $this->getStore());
$topcode = $request->getDestPostcode();
if(!ereg("^[0-9]{8}$", $topcode))
{
//CEP está errado
$error->setErrorMessage('O CEP está errado');
$result->append($error);
Mage::helper('customer')->__('Invalid ZIP CODE');
return $result;
}
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier($this->_code);
$method->setCarrierTitle($this->getConfigData('name'));
if($topcode >= 01300000 && $topcode <= 01499999){
//Seta o código, nome, valor e custo do frete para essa faixa de CEP
$method->setMethod('trans1');
$method->setMethodTitle('Transportadora 1');
$method->setPrice(10 + $this->getConfigData('handling_fee'));
$method->setCost(10);
}elseif($topcode >= 01500000 && $topcode <= 01699999){
//Seta o código, nome, valor e custo do frete para essa faixa de CEP
$method->setMethod('trans2');
$method->setMethodTitle('Transportadora 2');
$method->setPrice(20 + $this->getConfigData('handling_fee'));
$method->setCost(20);
}else{
$error->setErrorMessage('Não trabalhamos com o CEP digitado');
$result->append($error);
return $result;
}
$result->append($method);
$this->_result = $result;
$this->_updateFreeMethodQuote($request);
return $this->_result;
}
public function getAllowedMethods()
{
return array($this->_code => $this->getConfigData('title'));
}
}
Claro que você precisa editar também os arquivos xml que serão a configuração do módulo na área administrativa. Sabe fazer isso? Está explicado no post.
Pelo que entendi isso resolveria seu problema, me avise caso eu tenha entendido errado.
Volte sempre!
Abraços!
A pergunta do Wagner é referente ao módulo de frete do Magento que postei na comunidade, não ao módulo desse post.
Olá Wagner
Obrigado pelo comentário!
Bom, vou responder suas perguntas separadas.
Para sumir o módulo depois de um certo peso
Para isso você deve fazer uma verificação dentro do módulo de qual é o peso do carrinho e caso seja maior que 30 kg, por exemplo, que ele retorne FALSE.
Vou exemplificar, dentro do arquivo “CorreioPost.php”:
$sweight = $request->getPackageWeight(); // Pega o peso total do carrinho
if($sweight > 30) // Verifica se o peso é maior que 30
{
return false; // Desabilita o módulo
}
Para fazer o método de frete gratuito funcionar a partir apenas de certo peso
Isso pode ser feito no menu “Promoções” -> “Regras de Preço do Carrinho de Compras”. Basta clicar em “Acrescentar Nova Regra”, em condições selecione “Peso Total” e defina o quanto você deseja.
Agora vamos supor que você quer que as promoções só sejam aplicadas apenas a partir de um peso, aí vai:
Da mesma forma que a pergunta anterior, basta fazer uma verificação no método e depois cancelar o método do próprio Magento que habilita o frete grátis.
Novamente dentro do “CorreioPost.php”:
$sweight = $request->getPackageWeight(); // Pega o peso total do carrinho
if($sweight <= 30) // Verifica se o peso é menor que 30
{
$this->_updateFreeMethodQuote($request); // Método que habilita o frete grátis. Agora funcionará apenas com carrinho com peso abaixo de 30.
}
Dar frete grátis para carrinhos a partir de certo peso
Também é na regra de preços, da mesma forma que fiz a cima. Se não funcionar faça uma validação no módulo, vou exemplificar:
$sweight = $request->getPackageWeight(); // Pega o peso total do carrinho
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier($this->_code);
$method->setCarrierTitle($this->getConfigData('name'));
$method->setMethod('sedex');
$method->setMethodTitle('Sedex');
if($sweight > 30) // Verifica se o peso é maior que 30
{
$method->setPrice(0 + $this->getConfigData('handling_fee')); // Seta o valor do frete como 0 (zero) caso o peso seja maior que 30
}else}
$method->setPrice(10 + $this->getConfigData('handling_fee')); // Seta o valor do frete como 10 caso o peso seja menor que 30
}
$method->setCost(10); // Seta o custo do frete, diferente do preço, não é mostrado ao cliente
$result->append($method);
$this->_result = $result;
Fazer o módulo continuar funcionando depois dos 30 Kg
Na área administrativa do módulo existe um campo “Peso Máximo Permitido Pelos Correios”, aqui você pode definir quanto é o máximo que você aceitará nesse módulo, pode colocar o quanto achar melhor. Se não funcionar, basta tirar a validação desse campo no método, basta apagar o código abaixo do seu módulo:
$sweight = $request->getPackageWeight();
if ($sweight > $this->getConfigData('maxweight')){
//Weight exceeded limit
$error->setErrorMessage($this->getConfigData('maxweighterror'));
$result->append($error);
return $result;
}