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;

}
comments powered by Disqus