¿Cómo crear un método de envío personalizado en Magento 2X?
A menudo hemos topado con el escenario en el cual un cliente va a trabajar con un operador logístico que no posee integración con Magento. Cuando esto sucede, lo más práctico es crear un método de envío que integre toda su operativa al máximo posible, para que el flujo diario sea transparente para el cliente.
Incluso en los casos que el operador no tenga un Api al cual conectar, nos puede venir bien hacer un método personalizado para tener nuestro cálculo de portes, ya que es posible que ninguno de los módulos de envío genéricos de Magento nos acople al 100%.
Vamos a hacer un método de envío sencillo, y explicaremos las funciones mínimas para integrar el servicio en Magento.
Estructura del módulo
app/code/ Gsoft / Cps /etc/ config.xml
app/code/ Gsoft / Cps /etc/adminhtml/system.xml
app/code/ Gsoft / Cps /Model/Carrier/Shipping.php
app/code/ Gsoft / Cps /composer.php
app/code/ Gsoft / Cps /registration.php
Solo con estos archivos ya tenemos un módulo de envío plenamente funcional. Vamos a ver el contenido de cada uno de ellos:
Los 2 primeros archivos son de sobra conocidos, y son requeridos en todos los módulos:
app/code/ Gsoft / Cps /registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
‘Gsoft_Cps’,
__DIR__
);
app/code/ Gsoft / Cps /composer.php
{
«name»: «gsoft/cps»,
«description»: «»,
«require»: {
«php»: «~5.5.0|~5.6.0|~7.0.0»,
«magento/magento-composer-installer»: «*»
},
«suggest»: {
},
«type»: «magento2-module»,
«version»: «0.1.0»,
«license»: [
],
«autoload»: {
«files»: [
«registration.php»
],
«psr-4»: {
«Gsoft\\Cps\\»: «»
}
},
«extra»: {
«map»: [
[
«*»,
«Gsoft/Cps»
]
]
}
}
app/code/ Gsoft / Cps /etc/adminhtml/System/config.xml
<?xml version=»1.0″?>
<config xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance» xsi:noNamespaceSchemaLocation=»urn:magento:module:Magento_Config:etc/system_file.xsd»>
<system>
<section id=»carriers» translate=»label» type=»text» sortOrder=»320″ showInDefault=»1″ showInWebsite=»1″ showInStore=»1″>
<group id=»cps» translate=»label» type=»text» sortOrder=»0″ showInDefault=»1″ showInWebsite=»1″ showInStore=»1″>
<label>CPS Shipping Method</label>
<field id=»active» translate=»label» type=»select» sortOrder=»1″ showInDefault=»1″ showInWebsite=»1″ showInStore=»0″ canRestore=»1″>
<label>Enabled</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id=»name» translate=»label» type=»text» sortOrder=»3″ showInDefault=»1″ showInWebsite=»1″ showInStore=»1″ canRestore=»1″>
<label>Method Name</label>
</field>
<field id=»handling_type» translate=»label» type=»select» sortOrder=»7″ showInDefault=»1″ showInWebsite=»1″ showInStore=»0″ canRestore=»1″>
<label>Calculate Handling Fee</label>
<source_model>Magento\Shipping\Model\Source\HandlingType</source_model>
</field>
<field id=»handling_fee» translate=»label» type=»text» sortOrder=»8″ showInDefault=»1″ showInWebsite=»1″ showInStore=»0″>
<label>Handling Fee</label>
<validate>validate-number validate-zero-or-greater</validate>
</field>
<field id=»sort_order» translate=»label» type=»text» sortOrder=»100″ showInDefault=»1″ showInWebsite=»1″ showInStore=»0″>
<label>Sort Order</label>
</field>
<field id=»title» translate=»label» type=»text» sortOrder=»2″ showInDefault=»1″ showInWebsite=»1″ showInStore=»1″ canRestore=»1″>
<label>Title</label>
</field>
<field id=»sallowspecific» translate=»label» type=»select» sortOrder=»90″ showInDefault=»1″ showInWebsite=»1″ showInStore=»0″ canRestore=»1″>
<label>Ship to Applicable Countries</label>
<frontend_class>shipping-applicable-country</frontend_class>
<source_model>Magento\Shipping\Model\Config\Source\Allspecificcountries</source_model>
</field>
<field id=»specificcountry» translate=»label» type=»multiselect» sortOrder=»91″ showInDefault=»1″ showInWebsite=»1″ showInStore=»0″>
<label>Ship to Specific Countries</label>
<source_model>Magento\Directory\Model\Config\Source\Country</source_model>
<can_be_empty>1</can_be_empty>
</field>
<field id=»showmethod» translate=»label» type=»select» sortOrder=»92″ showInDefault=»1″ showInWebsite=»1″ showInStore=»0″>
<label>Show Method if Not Applicable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<frontend_class>shipping-skip-hide</frontend_class>
</field>
<field id=»specificerrmsg» translate=»label» type=»textarea» sortOrder=»80″ showInDefault=»1″ showInWebsite=»1″ showInStore=»1″ canRestore=»1″>
<label>Displayed Error Message</label>
</field>
</group>
</section>
</system>
</config>
Este fichero define todas las opciones disponibles que tendrá el módulo dentro del apartado ventas > métodos de envío de Magento:
app/code/ Gsoft / Cps /etc/config.xml
<?xml version=»1.0″?>
<config xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance» xsi:noNamespaceSchemaLocation=»urn:magento:module:Magento_Store:etc/config.xsd»>
<default>
<carriers>
<cps>
<active>1</active>
<sallowspecific>0</sallowspecific>
<model>Gsoft\Cps\Model\Carrier\Shipping</model>
<name>Envío personalizado</name>
<title>Cps</title>
<specificerrmsg>This shipping method is not available. To use this shipping method, please contact us.</specificerrmsg>
<handling_type>F</handling_type>
</cps>
</carriers>
</default>
</config>
Este fichero declara nuestro módulo, y preasigna el valor de las opciones definidas en el fichero system.xml
app/code/ Gsoft / Cps /Model/Carrier/Shipping.php
<?php
namespace Gsoft\Cps\Model\Carrier;
use Magento\Quote\Model\Quote\Address\RateRequest;
use Magento\Shipping\Model\Rate\Result;
class Shipping extends \Magento\Shipping\Model\Carrier\AbstractCarrier implements
\Magento\Shipping\Model\Carrier\CarrierInterface
{
/**
* @var string
*/
protected $_code = ‘cps’;
/**
* @var \Magento\Shipping\Model\Rate\ResultFactory
*/
protected $_rateResultFactory;
/**
* @var \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory
*/
protected $_rateMethodFactory;
protected $quote;
/**
* Shipping constructor.
*
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory
* @param \Magento\Shipping\Model\Rate\ResultFactory $rateResultFactory
* @param array $data
*/
public function __construct(
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Shipping\Model\Rate\ResultFactory $rateResultFactory,
\Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory, array $data = []
) {
$this->_rateResultFactory = $rateResultFactory;
$this->_rateMethodFactory = $rateMethodFactory;
parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);
}
/**
* get allowed methods
* @return array
*/
public function getAllowedMethods()
{
$methods=[‘custom’=>’Custom’];
return $methods;
}
/**
* @return float
*/
private function getShippingPrice(RateRequest $request)
{
//Esta función es la que se encargará de calcular la tarifa, en función de los parámetros recibidos en $request
$shippingPrice = 5;//precio fijo a 5
return $shippingPrice;
}
/**
* @param RateRequest $request
* @return bool|Result
*/
public function collectRates(RateRequest $request)
{
if (!$this->getConfigFlag(‘active’)) {
return false;
}
/** @var \Magento\Shipping\Model\Rate\Result $result */
$result = $this->_rateResultFactory->create();
foreach($this->getAllowedMethods() as $code=>$name) {
/** @var \Magento\Quote\Model\Quote\Address\RateResult\Method $method */
$method = $this->_rateMethodFactory->create();
$method->setCarrier($this->_code);
$method->setCarrierTitle($this->getConfigData(‘title’));
$method->setMethod($code);
$method->setMethodTitle($name);
$amount = $this->getShippingPrice($request);
if ($amount === false) return false;
$method->setPrice($amount);
$method->setCost($amount);
$result->append($method);
}
return $result;
} public function isTrackingAvailable(){ return false; }
}
Este fichero contiene la funcionalidad de nuestro método de envío. La función getShippingPrice es la que se encarga de hacer el cálculo de la tarifa en base a los parámetros recibidos en la variable $request. Esta variable contiene todos los datos de destino del pedido, así como el peso del pedido.
Si pudiéramos hacer una integración con el operador logístico, querríamos que el tracking se pudiera sincronizar con Magento, para poder enviarle los emails al cliente con su código de tracking incorporado. Para ello, deberíamos devolver true en la función “isTrackingAvailable”, y añadir una nueva función:
public function getTrackingInfo($tracking)
{
$info = array();
$result = {FUNCION QUE CONECTA AL API Y OBTIENE TODO EL TRACKING LOG}
if ($result instanceof Mage_Shipping_Model_Tracking_Result) {
if ($trackings = $result->getAllTrackings()) {
return $trackings[0];
}
} elseif (is_string($result) && !empty($result)) {
return $result;
}
return false;
}
Esta función devuelve un array con todos los cambios de estado de la mercancía, y Magento la utilizará para mostrar el historial del tracking en el pedido, tanto en la zona de cliente como en el backend.
Sólo con estos ficheros ya tenemos un módulo de envío personalizado operativo para Magento 2X. Magento te facilita mucho la operativa, pero que te puedas concentrar en la complejidad que requiera el cálculo de tarifas o la integración con el operador logístico.
Si necesitas integrar un operador logístico con tu Magento 1 o Magento 2, contacta con Gsoft Innova. Tenemos múltiples módulos ya desarrollados, ampliamente testeados y en funcionamiento desde hace tiempo para operadores como GLS o Spring entre otros.