Paczkomaty InPost to bardzo popularna forma wysyłki i z pewnością większość wdrożeń Magento uwzględnia ją w projekcie. Wykonawcą modułu jest znana na rynku polskim i nie tylko firma ORBA. Nie jestem ekspertem, ale jak dla mnie moduł jest napisany bardzo dobrze i działa świetnie. W tym artykule chciałbym podzielić się kilkoma informacjami dotyczącymi uruchomienia Paczkomatów InPost z nietypowym koszykiem Magento. W jednym z wdrożeń Magento zastosowałem moduł koszyka o nazwie Lotus Breath - One Step Checkout. Jest to całkiem niezły darmowy moduł Magento oferujący bardzo dobry jednostronny koszyk. Jednak pojawiły się problemy z uruchomieniem metody wysyłki Paczkomaty Inpost w module One Step Checkout.

Integracja modułu One Step Checkout z Paczkomaty Inpost

Aby połączyć funkcjonalności tych dwóch modułów potrzeba zmodyfikować dwa pliki w module Paczkomaty Inpost:
  1. w pliku /app/design/frontend/base/default/layout/inpost.xml
  2.  w pliku /app/code/community/Inpost/ParcelLocker/Model/Observer/Block.php
W przypadku pliku config.xml należy go rozbudować o następujący fragment struktury danych, który zaznaczyłem na czerwono: <?xml version="1.0"?> <layout version="0.1.0"> <checkout_onepage_index> <reference name="head"> <!-- action method="addItem"> <type>js</type> <name>inpost/jquery-1.11.3.min.js</name> </action> <action method="addItem"> <type>js</type> <name>inpost/noconflict.js</name> </action --> <action method="addItem"> <type>js</type> <name>inpost/checkout.js</name> </action> <action method="addItem"> <type>js</type> <name>inpost/validation.js</name> </action> <action method="addCss"> <name>css/inpost.css</name> </action> </reference> </checkout_onepage_index> <lotusbreath_onestepcheckout_index_index> <reference name="head"> <!-- action method="addItem"> <type>js</type> <name>inpost/jquery-1.11.3.min.js</name> </action> <action method="addItem"> <type>js</type> <name>inpost/noconflict.js</name> </action --> <action method="addItem"> <type>js</type> <name>inpost/checkout.js</name> </action> <action method="addItem"> <type>js</type> <name>inpost/validation.js</name> </action> <action method="addCss"> <name>css/inpost.css</name> </action> </reference> </lotusbreath_onestepcheckout_index_index> <inpost_return_index translate="label" module="inpost_parcellocker"> <reference name="head"> <action method="addCss"> <name>css/inpost.css</name> </action> </reference> <update handle="customer_account"/> <reference name="my.account.wrapper"> <block type="inpost_parcellocker/customer_account_return" name="inpost_customer_account_return" /> </reference> </inpost_return_index> <inpost_market_pl> <reference name="customer_account_navigation"> <action method="addLink" translate="label" module="inpost_parcellocker"> <name>inpost_returns</name> <path>inpost/return/index</path> <label>InPost - Fast Returns</label> </action> </reference> </inpost_market_pl> </layout> Dodatkowo dałem w komentarz akcję dodającą plik jQuery gdyż użyty szablon w projekcie już zaczytuje ten plik, nie ma więc potrzeby dodawać go ponownie. Kolejne zmiany wprowadzamy w pliku Block.php: <?php class Inpost_ParcelLocker_Model_Observer_Block { const SHIPPING_METHOD_BLOCK_TYPE = 'checkout/onepage_shipping_method_available'; const SHIPPING_METHOD_BLOCK_TYPE_LOTUS = 'lotusbreath_onestepcheckout/onepage_shipping_method_available'; const FRONTEND_HEAD_BLOCK_TYPE = 'page/html_head'; const BACKEND_HEAD_BLOCK_TYPE = 'adminhtml/page_head'; const SHIPPING_METHOD_INPOST_PARCELLOCKER_DESCRIPTION = 'inpost_parcellocker/checkout_shipping_method_parcellocker_description'; const SHIPPING_METHOD_INPOST_PARCELLOCKER_FORM = 'inpost_parcellocker/checkout_shipping_method_parcellocker_form'; const SHIPPING_METHOD_INPOST_CROSSBORDER_DESCRIPTION = 'inpost_parcellocker/checkout_shipping_method_crossborder_description'; const SHIPPING_METHOD_INPOST_CROSSBORDER_FORM = 'inpost_parcellocker/checkout_shipping_method_crossborder_form'; const GEO_WIDGET_PL = 'https://geowidget-pl.easypack24.net/dropdown.php'; const GEO_WIDGET_FR = 'https://geowidget-fr.easypack24.net/dropdown.php'; const GEO_WIDGET_IT = 'https://geowidget-it.easypack24.net/dropdown.php'; const GEO_WIDGET_CROSSBORDER = 'https://widget-xborder-inpost.sheepla.com/js/SheeplaLib.js'; const GEO_WIDGET_CROSSBORDER_STYLE = 'https://widget-xborder-inpost.sheepla.com/css/SheeplaCrossBorder.css'; const GEO_WIDGET_MAIN_CONFIG_SELECT_NAME = 'groups[sender_address][fields][default_parcellocker][value]'; const GEO_WIDGET_MAIN_CONFIG_SELECT_ID = 'inpost_parcellocker_sender_address_default_parcellocker'; protected $_parcellockerCode = 'inpostparcellockers'; protected $_crossborderCode = 'inpostcrossborder'; protected $geoWidgetParams = array( 'dropdown_class' => 'required-entry', 'dropdown_name' => 'inpost_parcellocker_id', 'dropdown_id' => 'inpost_parcellocker_id' ); /** * @return Inpost_ParcelLocker_Model_Config */ public function getConfig() { return Mage::getSingleton('inpost_parcellocker/config'); } /** * Insert Inpost needed blocks to magento * @param Varien_Event_Observer $observer */ public function insertInpostBlocks(Varien_Event_Observer $observer) { $event = $observer->getEvent(); $block = $event->getBlock(); $blockType = $block->getType(); if ($blockType == self::SHIPPING_METHOD_BLOCK_TYPE || $blockType == self::SHIPPING_METHOD_BLOCK_TYPE_LOTUS) { $this->insertShippingMethodsBlocks($event); } elseif ($blockType == self::FRONTEND_HEAD_BLOCK_TYPE) { $this->insertFrontendGeowidget($event); } elseif ($blockType == self::BACKEND_HEAD_BLOCK_TYPE) { $this->insertBackendGeowidget($event); } } /** * Insert Inpost needed code to magento * @param Varien_Event_Observer $observer */ public function adminhtmlWidgetContainerHtmlBefore(Varien_Event_Observer $observer) { if ($this->getConfig()->moduleAvailable()) { $event = $observer->getEvent(); $block = $event->getBlock(); if ($block instanceof Mage_Adminhtml_Block_Sales_Order_Shipment_View) { $this->insertShipmentLabelButton($block); $this->updateShipmentBackButton($block); } } } /** * Change back button * @param object $block */ protected function updateShipmentBackButton($block) { if ($block->getShipment()->getInpostParcelId()) { $params = Mage::app()->getRequest()->getParams(); if (!empty($params['come_from'])) { switch ($params['come_from']) { case 'inpost_shipment_list': $block->removeButton('back'); $block->addButton('back', array( 'label' => __('Back'), 'onclick' => 'setLocation(\'' . $block->getUrl('*/inpost_shipment_list/index') . '\')', 'class' => 'back' ), 0, -1, 'header'); break; } } } } /** * Insert "Generate/Download Shipment Label" button to shipment view page * @param object $block */ protected function insertShipmentLabelButton($block) { $helper = Mage::helper('inpost_parcellocker'); $shipment = $block->getShipment(); if ($shipment->getInpostParcelId()) { if ($shipment->getInpostShippingLabelGenerated()) { /* Make payment for parcel in InPost service */ $url = $block->getUrl('*/inpost_shipment/label', array('shipment_id' => $block->getShipment()->getId())); $block->addButton('inpost_shipping_label', array( 'label' => $helper->__('Download Shipping Label'), 'class' => 'save', 'onclick' => 'setLocation(\'' . $url . '\')' ) ); } else { /* Generate shipment label */ $url = $block->getUrl('*/inpost_shipment/label', array('shipment_id' => $block->getShipment()->getId())); $block->addButton('inpost_shipping_label', array( 'label' => $helper->__('Generate Shipping Label'), 'class' => 'save', 'onclick' => 'setLocation(\'' . $url . '\')' ) ); } } } /** * Insert frontend geowidget on checkout pages * @param object $event */ protected function insertFrontendGeowidget($event) { if ($this->getConfig()->moduleAvailable()) { $request = Mage::app()->getRequest(); $moduleName = $request->getModuleName(); if ($moduleName == 'checkout' || $moduleName == 'onestepcheckout') { $this->getInsertGeowidgetJs($event, true); } } } /** * Insert backend geowidget * @param object $event */ protected function insertBackendGeowidget($event) { $request = Mage::app()->getRequest(); $controller = $request->getControllerName(); $params = $request->getParams(); $section = isset($params['section']) ? $params['section'] : null; if ($controller == 'inpost_shipment') { /* Insert geowidget in shipment information edit page */ $this->getInsertGeowidgetJs($event, false); } elseif ($section == 'inpost_parcellocker') { /* Insert geowidget in module configuration page */ $params = array( 'dropdown_class' => 'required-entry', 'dropdown_name' => self::GEO_WIDGET_MAIN_CONFIG_SELECT_NAME, 'dropdown_id' => self::GEO_WIDGET_MAIN_CONFIG_SELECT_ID ); $this->getInsertGeowidgetJs($event, false, $params); } } /** * Get geowidget javascript depends on market type * @return string */ protected function getInsertGeowidgetJs($event, $front, $params = null) { $html = $event->getTransport()->getHtml(); $geoWidgetParams = isset($params) ? $params : $this->geoWidgetParams; $marketType = $this->getConfig()->getMarketType(); $widget = null; $paramsString = '?'; /* Create params string for url */ foreach ($geoWidgetParams as $key => $value) { $paramsString .= $key . '=' . $value . '&'; } /* Select geowidget depends on market type */ if ($marketType == 'pl') { $widget = '<script type="text/javascript" src="' . self::GEO_WIDGET_PL . $paramsString . '"></script>'; } elseif ($marketType == 'it') { $widget = '<script type="text/javascript" src="' . self::GEO_WIDGET_IT . $paramsString . '"></script>'; } elseif ($marketType == 'fr') { $widget = '<script type="text/javascript" src="' . self::GEO_WIDGET_FR . $paramsString . '"></script>'; } if ($front) { /* insert crossborder geowidget and css */ $widget .= '<script type="text/javascript" src="' . self::GEO_WIDGET_CROSSBORDER . '"></script>'; $widget .= '<link rel="stylesheet" type="text/css" href="' . self::GEO_WIDGET_CROSSBORDER_STYLE . '" media="all">'; } $event->getTransport()->setHtml($html . $widget); } /** * Insert blocks with module description and logotype in shipping methods checkout section * @param object $event */ protected function insertShippingMethodsBlocks($event) { if ($this->getConfig()->moduleAvailable()) { $blocks = array(); if ($this->getConfig()->shippingMethodAvailable($this->_parcellockerCode)) { $blocks['parcellocker_description'] = array( 'block' => self::SHIPPING_METHOD_INPOST_PARCELLOCKER_DESCRIPTION, 'block_name' => 'inpost.parcellocker.description' ); $blocks['parcellocker_form'] = array( 'block' => self::SHIPPING_METHOD_INPOST_PARCELLOCKER_FORM, 'block_name' => 'inpost.parcellocker.form' ); } if ($this->getConfig()->isCrossborderAvailable() && $this->getConfig()->shippingMethodAvailable($this->_crossborderCode)) { $blocks['crossborder_description'] = array( 'block' => self::SHIPPING_METHOD_INPOST_CROSSBORDER_DESCRIPTION, 'block_name' => 'inpost.crossborder.description' ); $blocks['crossborder_form'] = array( 'block' => self::SHIPPING_METHOD_INPOST_CROSSBORDER_FORM, 'block_name' => 'inpost.crossborder.form' ); } if (!empty($blocks)) { foreach ($blocks as $block) { $html = $event->getTransport()->getHtml(); $frame = $event->getBlock()->getLayout() ->createBlock($block['block'], $block['block_name']) ->toHtml(); $event->getTransport()->setHtml($html . $frame); } } } } /** * Add layout handle depends on market type * @param Varien_Event_Observer $observer */ public function addMarketHandle(Varien_Event_Observer $observer) { if ($this->getConfig()->moduleAvailable()) { $market = $this->getConfig()->getMarketType(); /* @var $update Mage_Core_Model_Layout_Update */ $update = $observer->getEvent()->getLayout()->getUpdate(); $update->addHandle('inpost_market_' . $market); } } /** * Throw InPost Exception * @param string $message * @throws Inpost_ParcelLocker_Model_Exception */ protected function throwException($message) { throw new Inpost_ParcelLocker_Model_Exception($message); } } W zasadzie to tyle - po tych zmianach wszystko działa jak trzeba. Przypuszczam, że miejsca w kodzie, które zmodyfikowałem są kluczowe do integracji modułu z dowolnym modułem koszyka Magento.