Overview

Packages

  • Eabi
    • Dpd
  • None
  • PHP

Classes

  • dpdcodpayment
  • eabi_dpd_courier
  • Eabi_dpd_courierCourierModuleFrontController
  • eabi_dpd_parcelstore
  • eabi_dpd_parcelstore_data_send_executor
  • eabi_dpd_parcelstore_dpd_api
  • eabi_dpd_parcelstore_dpd_helper
  • eabi_dpd_parcelstore_html_helper
  • eabi_dpd_parcelstore_validator_helper
  • Eabi_dpd_parcelstoreCourierModuleFrontController
  • Eabi_Postoffice
  • eabi_postoffice_dialcode_helper
  • Eabi_PostofficePostofficeModuleFrontController

Functions

  • upgrade_module_0_3
  • upgrade_module_0_6
  • upgrade_module_0_8
  • Overview
  • Package
  • Class
  • Tree
   1: <?php
   2: /*
   3:   
   4:  *
   5:  * NOTICE OF LICENSE
   6:  *
   7:  * This source file is subject to the Open Software License (OSL 3.0)
   8:  * or OpenGPL v3 license (GNU Public License V3.0)
   9:  * that is bundled with this package in the file LICENSE.txt.
  10:  * It is also available through the world-wide-web at this URL:
  11:  * http://opensource.org/licenses/osl-3.0.php
  12:  * or
  13:  * http://www.gnu.org/licenses/gpl-3.0.txt
  14:  * If you did not receive a copy of the license and are unable to
  15:  * obtain it through the world-wide-web, please send an email
  16:  * to info@e-abi.ee so we can send you a copy immediately.
  17:  *
  18:  * DISCLAIMER
  19:  *
  20:  * Do not edit or add to this file if you wish to upgrade this module to newer
  21:  * versions in the future.
  22:  *
  23:  * @category   Eabi
  24:  * @package    Eabi_Dpd
  25:  * @copyright  Copyright (c) 2014 Aktsiamaailm LLC (http://en.e-abi.ee/)
  26:  * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  27:  * @license    http://www.gnu.org/licenses/gpl-3.0.txt  GNU Public License V3.0
  28:  * @author     Matis Halmann
  29:  * 
  30: 
  31:  */
  32: 
  33: if (!defined('_PS_VERSION_')) {
  34:     exit;
  35: }
  36: /**
  37:  * <p>Base class for carriers, which ask customer to pick parcel terminal of choice from dropdown list.</p>
  38:  * <p>Offers following business functions:</p>
  39:  * <ul>
  40:      <li>Chosen parcel terminal is forwarded to the Merchant</li>
  41:      <li>Offers auto update functionality for parcel terminals if subclasses implement actual parcel terminal fetch procedure</li>
  42:  </ul>
  43:  * @author Matis
  44:  */
  45: class Eabi_Postoffice extends Module {
  46:     protected static $_carrierModules;
  47:     private static $clientGroups;
  48:     protected static $_carriersByCode;
  49:     protected static $_officesInSession;
  50:     
  51:     
  52:     
  53:     /**
  54:      * <p>For adding ability to overload getPostoffices function in the deeper modules</p>
  55:      * @var ModuleCore
  56:      */
  57:     protected $_shippingModel;
  58:     /**
  59:      * <p>Cached helper instances</p>
  60:      * @var array
  61:      */
  62:     protected static $_helpers = array();
  63:     
  64:     
  65:     /**
  66:      * Default constructor
  67:      */
  68:     public function __construct() {
  69:         $this->tab = 'shipping_logistics';
  70:         $this->name = 'eabi_postoffice';
  71:         $this->version = '0.7';
  72:         $this->ps_versions_compliancy = array('min' => '1.5', 'max' => '1.7');
  73:         parent::__construct();
  74:         $this->displayName = $this->l('E-Abi Generic Office plugin');
  75:         $this->description = $this->l('Base plugin for shipping methods, where customer has to pick a parcel terminal from a list');
  76:         $this->confirmUninstall = $this->l('Are you sure you want to delete your details?');
  77:         
  78:     }
  79:     
  80:     
  81:     /**
  82:      * <p>Performs following actions:</p>
  83:      * <ul>
  84:          <li>Creates database table <code>eabi_carriermodule</code> for holding list of carriers using this class</li>
  85:          <li>Creates database table <code>eabi_postoffice</code> for holding pickup points for the carrier modules</li>
  86:          <li>Creates database table <code>eabi_cart_shipping</code> for holding information which shipping address in the cart has selected which parcel terminal</li>
  87:          <li>Adds hook <code>actionCarrierProcess</code> - for validation, that terminal was selected</li>
  88:          <li>Adds hook <code>orderConfirmation</code> - for displaying selected parcel terminal in some emails</li>
  89:      </ul>
  90:      * @return boolean
  91:      */
  92:     public function install() {
  93:         if (!parent::install()
  94:                 || !$this->_createCarrierModuleTable()
  95:                 || !$this->_createPostofficeTable()
  96:                 || !$this->_createSelectedShippingOptionInCartTable()
  97:                 || !$this->_createIndexes()
  98:                 || !$this->registerHook('actionCarrierProcess')
  99:                 || !$this->registerHook('orderConfirmation')
 100:                 || !$this->upgrade_module_0_6()) {
 101:             return false;
 102:         }
 103:         return true;
 104:     }
 105:     
 106:     /**
 107:      * <p>Drops all the information that was created in the install process.</p>
 108:      * @return boolean
 109:      */
 110:     public function uninstall() {
 111:         if (!parent::uninstall()
 112:                 || !$this->unregisterHook('actionCarrierProcess')
 113:                 || !$this->unregisterHook('orderConfirmation')
 114:                 || !$this->unregisterHook('displayOrderDetail')
 115:                 || !$this->unregisterHook('displayPDFInvoice')
 116:                 || !$this->_dropTables()) {
 117:             return false;
 118:         }
 119:         return true;
 120:     }
 121:     
 122:     /**
 123:      * <p>Updates <code>carrier_lang.delay</code> descriptions, required for the carrier to be displayed.</p>
 124:      * @param string $code carrier.external_module_name
 125:      * @param string $displayName new name
 126:      * @return bool
 127:      */
 128:     public function setDisplayName($code, $displayName) {
 129:         $db = Db::getInstance();
 130:         if (!$displayName) {
 131:             $displayName = $code;
 132:         }
 133:         
 134:         $sql = "UPDATE "._DB_PREFIX_ ."carrier_lang ".
 135:                 " SET delay = '{$db->escape($displayName)}' " .
 136:                 " WHERE id_carrier IN (SELECT id_carrier from "._DB_PREFIX_ ."carrier WHERE external_module_name = '{$db->escape($code)}' and deleted = 0)"
 137:                 ;
 138:         return $db->execute($sql);
 139:     }
 140:     
 141:     /**
 142:      * <p>Sets tax group for current carrier.external_module_name</p>
 143:      * @param string $code shipping method code
 144:      * @param int $tax tax id
 145:      */
 146:     public function setTaxGroup($code, $tax) {
 147:         $db = Db::getInstance();
 148:         
 149:         $qu = 'UPDATE `' . _DB_PREFIX_ .
 150:                 "carrier` set id_tax_rules_group = '{$db->escape($tax)}' where name = '{$db->escape($code)}' and deleted = 0;";
 151: 
 152:         $db->execute($qu);
 153:         
 154:         $qu = 'SELECT * FROM `' . _DB_PREFIX_ .
 155:                 "carrier` where name = '{$db->escape($code)}' and deleted = 0;";
 156: 
 157:         $res = $db->executeS($qu);
 158:         if (count($res) !== 1) {
 159:             Tools::displayError(sprintf('Carrier for code %s could not be found', $code));
 160:         }
 161:         $id = $res[0]['id_carrier'];
 162:         
 163:         
 164:         //check the carrier_shops
 165:         $res = $db->executeS('select id_shop from ' . _DB_PREFIX_ . 'shop where active = 1');
 166:         $qu = 'DELETE FROM `' . _DB_PREFIX_ . "carrier_tax_rules_group_shop` WHERE id_carrier = $id";
 167:         $db->execute($qu);
 168:         foreach ($res as $re) {
 169:             //insert the langs
 170: 
 171:             if ($tax > 0) {
 172:                 $qu = 'REPLACE INTO `' . _DB_PREFIX_ . "carrier_tax_rules_group_shop` (id_carrier, id_tax_rules_group, id_shop)";
 173:                 $qu .= " values ($id, $tax, " . $re['id_shop'] . ")";
 174:                 $db->execute($qu);
 175:             } else {
 176:                 $qu = 'REPLACE INTO `' . _DB_PREFIX_ . "carrier_tax_rules_group_shop` (id_carrier, id_tax_rules_group, id_shop)";
 177:                 $qu .= " values ($id, 0, " . $re['id_shop'] . ")";
 178:                 $db->execute($qu);
 179:                 /*
 180:                 $qu = 'DELETE FROM `' . _DB_PREFIX_ . "carrier_tax_rules_group_shop` ";
 181:                 $qu .= " WHERE id_carrier = $id and id_shop =  " . $re['id_shop'] . "";
 182:                 $db->execute($qu);
 183:                  */
 184:             }
 185:         }
 186:         
 187:         
 188:     }
 189:     
 190: 
 191:     /**
 192:      * <p>For allowing to overload <code>getPostoffices</code> method in shipping model instance with name <code>__getPostoffices</code></p>
 193:      * @param ModuleCore $shippingModel
 194:      * @return Eabi_Postoffice
 195:      */
 196:     public function setShippingModel($shippingModel) {
 197:         $this->_shippingModel = $shippingModel;
 198:         return $this;
 199:     }
 200:     
 201:     /**
 202:      *  <p>Returns assoc array which should contain the actual postoffices
 203:      * which belong to the selected group_id in alplabetically sorted order.</p>
 204:      * <p>If no $groupId is supplied, then all the postoffices are returned.</p>
 205:      * <p>Offices are sorted by</p>
 206:      * <ul>
 207:          <li>group_sort descending</li>
 208:          <li>group_name ascending</li>
 209:          <li>name ascending</li>
 210:      </ul>
 211:      * 
 212:      * @param string $code carrier.external_module_name
 213:      * @param int $groupId
 214:      * @param int $officeId when only requesting one specific office
 215:      * @param int $addressId when supplied then only offices from the addressId country are returned.
 216:      * @return array
 217:      */
 218:     public function getPostOffices($code, $groupId = null, $officeId = null, $addressId = null) {
 219:         if ($this->_shippingModel && method_exists($this->_shippingModel, '__getPostoffices')) {
 220:             $this->_shippingModel->__getPostOffices($code, $groupId, $officeId, $addressId);
 221:         }
 222:         $db = Db::getInstance();
 223:         $sql = "SELECT * FROM " . _DB_PREFIX_ . "eabi_postoffice "
 224:                 . " WHERE remote_module_name = '{$db->escape($code)}'"
 225:         ;
 226: 
 227:         if ($groupId !== null) {
 228:             $sql .= " AND group_id = '{$db->escape($groupId)}'";
 229:         }
 230:         if ($addressId) {
 231:             $address = new AddressCore($addressId);
 232:             if ($address->id_country) {
 233:                 $sql .= " AND country = '{$db->escape(Country::getIsoById($address->id_country))}'";
 234:             }
 235:         }
 236: 
 237: 
 238:         if ($officeId !== null) {
 239:             $sql .= " AND remote_place_id = '{$db->escape($officeId)}'";
 240:         }
 241:         
 242:         
 243:         if ($groupId == null && $officeId == null) {
 244:             $sql .= " ORDER BY group_sort DESC, group_name ASC, name ASC";
 245:         } else {
 246:             $sql .= " ORDER BY group_sort DESC, name ASC";
 247:         }
 248:                 
 249:         $res = $db->executeS($sql);
 250:         
 251:         return $res;
 252:         
 253:     }
 254:     
 255:     
 256:     /**
 257:      *  <p>Returns distinct group_name,group_id,group_sort as Eabi_Postoffice_Model_Mysql4_Office_Collection of 'eabi_postoffice/office' models</p>
 258:      * <p>Result of this function is used to render the first select menu (county/city) for this carrier.</p>
 259:      * <p>If no groups can be found, then this function returns boolean false.</p>
 260:      * 
 261:      * @param string $code carrier.external_module_name
 262:      * @param int $addressId when supplied then only groups from the addressId country are returned
 263:      * @return boolean|array
 264:      */
 265:     public function getPostOfficeGroups($code, $addressId = null) {
 266:         $db = Db::getInstance();
 267:         $sql = "SELECT DISTINCT group_id, group_name, group_sort FROM "._DB_PREFIX_."eabi_postoffice "
 268:                 ." WHERE remote_module_name = '{$db->escape($code)}'"
 269:                 ." ORDER BY group_sort DESC, group_name ASC"
 270:                 ;
 271:                 
 272:         if ($addressId) {
 273:             $address = new Address($addressId);
 274:             if ($address->id_country) {
 275:                 $sql = "SELECT DISTINCT group_id, group_name, group_sort FROM " . _DB_PREFIX_ . "eabi_postoffice "
 276:                         . " WHERE remote_module_name = '{$db->escape($code)}'"
 277:                         . " AND country = '{$db->escape(Country::getIsoById($address->id_country))}'"
 278:                         . " ORDER BY group_sort DESC, group_name ASC"
 279:                 ;
 280:             }
 281:         }
 282:                 
 283:         $res = $db->executeS($sql);
 284:         if (count($res) <= 1) {
 285:             return false;
 286:         }
 287:         return $res;
 288:     }
 289:     
 290:     
 291: 
 292:     /**
 293:      * <p>Once the user selects the actual office, an AJAX callback is performed and this one inserts the selected office to the database <code>eabi_cart_shipping</code>
 294:      * and also to the session, in order the customer would easily reach latest selected offices and the order itself could be placed.</p>
 295:      * 
 296:      * @param type $code
 297:      * @param type $addressId
 298:      * @param type $placeId
 299:      * @param type $groupId
 300:      */
 301:     public function setOfficeToSession($code, $addressId, $placeId, $groupId = null) {
 302:         /*
 303:          * 
 304:     `id_cart` int(11) unsigned NOT NULL,
 305:     `id_address` int(11) unsigned NOT NULL,
 306:     `remote_module_id` int(11) unsigned NOT NULL,
 307:     `remote_place_id` int(11) unsigned NOT NULL,
 308:          * ps_eabi_cart_shipping
 309:          */
 310:         $id_cart = Context::getContext()->cart->id;
 311:         $db = Db::getInstance();
 312:         $sql = "SELECT * FROM ". _DB_PREFIX_ ."eabi_cart_shipping ";
 313:         $sql .= " WHERE id_cart = '{$db->escape($id_cart)}' ";
 314: //        $sql .= " AND id_address = '{$db->escape($addressId)}' ";
 315:         $oldInserts = $db->executeS($sql);
 316:         $data = array(
 317:             'id_cart' => $db->escape($id_cart),
 318:             'id_address' => $db->escape($addressId),
 319:             'remote_module_id' => $db->escape($this->idFromCode($code)),
 320:             'remote_place_id' => $db->escape($placeId),
 321:         );
 322:         if (is_array(self::$_officesInSession) && isset(self::$_officesInSession[$addressId])) {
 323:             unset(self::$_officesInSession[$addressId]);
 324:         }
 325:         if (count($oldInserts)) {
 326:             //update
 327: //            $db->update('eabi_cart_shipping', $data, " id_cart = '{$db->escape($id_cart)}' AND id_address = '{$db->escape($addressId)}' ");
 328:             $db->update('eabi_cart_shipping', $data, " id_cart = '{$db->escape($id_cart)}' ");
 329:         } else {
 330:             //insert
 331:             $db->insert('eabi_cart_shipping', $data);
 332:         }
 333:         
 334:     }
 335:     
 336:     
 337:     
 338:     /**
 339:      * <p>Returns array of selected parcel terminal names for the specified id_cart</p>
 340:      * <p>Array keys are address ids and array values are parcel terminal names</p>
 341:      * @param int $id_cart
 342:      * @return array
 343:      */
 344:     public function getOfficesFromCart($id_cart) {
 345:         $db = Db::getInstance();
 346:         $sql = "SELECT * FROM " . _DB_PREFIX_ . "eabi_cart_shipping ";
 347:         $sql .= " WHERE id_cart = '{$db->escape($id_cart)}' ";
 348:         $officesInCart = $db->executeS($sql);
 349:         $resultingPlaces = array();
 350:         foreach ($officesInCart as $officeInCart) {
 351:             $code = $this->codeFromId($officeInCart['remote_module_id']);
 352:             $place = array(
 353:                 'group_id' => null,
 354:             );
 355:             $places = $this->getPostOffices($code, null, $officeInCart['remote_place_id']);
 356:             if (count($places)) {
 357:                 $resultingPlaces[$officeInCart['id_address']] = $places[0];
 358:             }
 359:         }
 360:         return $resultingPlaces;
 361:     }
 362:     
 363:     /**
 364:      * <p>Returns information about selected parcel terminal for the specified address, if any exist.</p>
 365:      * <p>Return format is following:</p>
 366:      * <ul>
 367:          <li><code>code</code> - carrier method code for selected parcel terminal</li>
 368:          <li><code>place_id</code> - selected parcel terminal remote id</li>
 369:          <li><code>address_id</code> - address id reflected back</li>
 370:          <li><code>group_id</code> - group_id where this terminal belongs to.</li>
 371:      </ul>
 372:      * <p>If no parcel terminal is found, then same element is returned, but it's values are empty strings</p>
 373:      * @param int $addressId
 374:      * @return array
 375:      */
 376:     public function getOfficeFromSession($addressId) {
 377:         if (is_null(self::$_officesInSession)) {
 378:             self::$_officesInSession = array();
 379:         }
 380:         if (isset(self::$_officesInSession[$addressId])) {
 381:             return self::$_officesInSession[$addressId];
 382:         }
 383:         $id_cart = Context::getContext()->cart->id;
 384:         $db = Db::getInstance();
 385:         $sql = "SELECT * FROM " . _DB_PREFIX_ . "eabi_cart_shipping ";
 386:         $sql .= " WHERE id_cart = '{$db->escape($id_cart)}' ";
 387:         $sql .= " AND id_address = '{$db->escape($addressId)}' ";
 388:         $oldInserts = $db->executeS($sql);
 389:         if (count($oldInserts)) {
 390:             $code = $this->codeFromId($oldInserts[0]['remote_module_id']);
 391:             $place = array(
 392:                 'group_id' => null,
 393:             );
 394:             $places = $this->getPostOffices($code, null, $oldInserts[0]['remote_place_id']);
 395:             if (count($places)) {
 396:                 $place = $places[0];
 397:             }
 398:             self::$_officesInSession[(string)$addressId] = array(
 399:                 'code' => $code,
 400:                 'place_id' => $oldInserts[0]['remote_place_id'],
 401:                 'address_id' => $oldInserts[0]['id_address'],
 402:                 'group_id' => $place['group_id'],
 403:             );
 404:             return self::$_officesInSession[$addressId];
 405:             
 406:         }
 407:         self::$_officesInSession[(string)$addressId] = array(
 408:                 'code' => null,
 409:                 'place_id' => null,
 410:                 'address_id' => null,
 411:                 'group_id' => null,
 412:         );
 413:         return self::$_officesInSession[$addressId];
 414:     }
 415:     
 416:     
 417:     /**
 418:      * <p>Registers carrier to <code>eabi_carriermodule</code> table as:</p>
 419:      * <ul>
 420:          <li>Carrier based on price with range from €0 to €10000</li>
 421:          <li>Adds Carrier to every shop</li>
 422:          <li>Adds Carrier to every available language</li>
 423:          <li>Adds Carrier to every available zone</li>
 424:          <li>Adds Carrier to every available delivery option</li>
 425:      </ul>
 426:      * @param string $code
 427:      * @param string $class
 428:      * @param string $trackingUrl
 429:      * @return boolean
 430:      */
 431:     public function addCarrierModule($code, $class, $trackingUrl = '') {
 432:         $db = Db::getInstance();
 433:         /*
 434:          * 
 435:         `id_eabi_carriermodule` int(11) unsigned NOT NULL auto_increment,
 436:         `carrier_code` varchar(255) NOT NULL,
 437:         `class_name` varchar(255) NOT NULL,
 438:         `update_time` datetime NULL,
 439:          * 
 440:          */
 441:         //check if module exists
 442:         $res = $db->getRow('select * from ' . _DB_PREFIX_ . 'eabi_carriermodule where carrier_code = \''.$db->escape($code)."'");
 443:         if (!$res) {
 444:             //if module does not exist, then insert it
 445:             $data = array(
 446:                 'carrier_code' => $db->escape($code),
 447:                 'class_name' => $db->escape($class),
 448:                 'update_time' => $db->escape(date('Y-m-d H:i:s')),
 449:             );
 450:             $res = $db->insert('eabi_carriermodule', $data);
 451: 
 452:             if (!$res) {
 453:                 return false;
 454:             }
 455:         }
 456: 
 457: 
 458: 
 459:         $tax = 0;
 460:         $qu = 'INSERT INTO `' . _DB_PREFIX_ .
 461:                 "carrier` (id_tax_rules_group, id_reference, name, active, shipping_handling, range_behavior, is_module, external_module_name, shipping_external, shipping_method, need_range, url)";
 462:         $qu .= " values (0, 0, '{$code}', 1, 0, 0, 1, '{$code}', 1, 2, 1, '{$db->escape($trackingUrl)}')";
 463: 
 464:         $db->execute($qu);
 465:         $id = $db->Insert_ID();
 466:         
 467:         //update id_reference
 468:         $qu = 'UPDATE `' . _DB_PREFIX_ .
 469:                 "carrier` SET id_reference = {$db->escape($id)} WHERE id_carrier = {$db->escape($id)}";
 470:         $db->execute($qu);
 471:         
 472:         
 473:         if ($id == '' || $id == 0) {
 474:             echo 'error getting next insert id';
 475:             Tools::p($qu);
 476:             //                      print_r($qu);
 477:             die();
 478:         }
 479:         //insert default price range for current carrier
 480:         $res = $db->insert('range_price', array(
 481:             'id_carrier' => $db->escape($id),
 482:             'delimiter1' => 0,
 483:             'delimiter2' => 10000,
 484:         ));
 485:         if (!$res) {
 486:             return false;
 487:         }
 488:         $range_price_id = $db->Insert_ID();
 489: 
 490:         //check the groups and enter group id-s
 491:         $res = $db->executeS('SELECT id_group FROM ' . _DB_PREFIX_ . 'group');
 492:         foreach ($res as $re) {
 493:             //insert the langs
 494:             $qu = 'INSERT INTO `' . _DB_PREFIX_ . "carrier_group` (id_carrier, id_group)";
 495:             $qu .= " values ($id, " . $re['id_group'] . ")";
 496:             $db->execute($qu);
 497:         }
 498: 
 499:         //check the langs, and get the lang id-s
 500:         $res = $db->executeS('SELECT id_lang FROM ' . _DB_PREFIX_ . 'lang WHERE active=1');
 501:         foreach ($res as $re) {
 502:             //insert the langs
 503:             $qu = 'INSERT INTO `' . _DB_PREFIX_ . "carrier_lang` (id_carrier, id_lang, delay)";
 504:             $qu .= " values ($id, " . $re['id_lang'] . ", '" . $db->escape($code) . "')";
 505:             $db->execute($qu);
 506:         }
 507: 
 508:         //check the carrier_shops
 509:         $res = $db->executeS('select id_shop from ' . _DB_PREFIX_ . 'shop where active = 1');
 510:         foreach ($res as $re) {
 511:             //insert the langs
 512:             $qu = 'INSERT INTO `' . _DB_PREFIX_ . "carrier_shop` (id_carrier, id_shop)";
 513:             $qu .= " values ($id, " . $re['id_shop'] . ")";
 514:             $db->execute($qu);
 515: 
 516:             if ($tax > 0) {
 517:                 $qu = 'INSERT INTO `' . _DB_PREFIX_ . "carrier_tax_rules_group_shop` (id_carrier, id_tax_rules_group, id_shop)";
 518:                 $qu .= " values ($id, $tax, " . $re['id_shop'] . ")";
 519:                 $db->execute($qu);
 520:             }
 521:         }
 522: 
 523: 
 524:         //insert the zones
 525:         $res = $db->executeS('select id_zone from ' . _DB_PREFIX_ . 'zone where active = 1');
 526:         foreach ($res as $re) {
 527:             //insert the langs
 528:             $qu = 'INSERT INTO `' . _DB_PREFIX_ . "carrier_zone` (id_carrier, id_zone)";
 529:             $qu .= " values ($id, " . $re['id_zone'] . ")";
 530:             $db->execute($qu);
 531: 
 532:             //insert ps_delivery
 533:             $res = $db->insert('delivery', array(
 534:                 'id_carrier' => $db->escape($id),
 535:                 'id_range_price' => $range_price_id,
 536:                 'id_zone' => $re['id_zone'],
 537:                 'price' => 0,
 538:             ));
 539:             if (!$res) {
 540:                 return false;
 541:             }
 542:         }
 543:         
 544:         return true;
 545:         
 546:     }
 547:     
 548:     /**
 549:      * <p>Removes carrier from the system, only <code>eabi_carriermodule</code> entry is kept so when reinstalling carrier, then selected parcel terminal names would be restored</p>
 550:      * @param string $code
 551:      * @return boolean
 552:      */
 553:     public function removeCarrierModule($code) {
 554:         $db = Db::getInstance();
 555:         $id_carrier = $this->idFromCode($code);
 556:         $res = $db->delete('eabi_postoffice', 'remote_module_id = \''.$db->escape($id_carrier).'\'');
 557:         if (!$res) {
 558:             return false;
 559:         }
 560:         
 561:         $db->execute('DELETE FROM `' . _DB_PREFIX_ .
 562:                 "carrier_zone` WHERE id_carrier in (select id_carrier FROM `" . _DB_PREFIX_ .
 563:                 "carrier` WHERE name like '{$code}')");
 564:         //delete only carries, which have not been used to place orders
 565:         $db->execute('DELETE FROM `' . _DB_PREFIX_ .
 566:                 "carrier_shop` WHERE id_carrier in (select id_carrier FROM `" . _DB_PREFIX_ .
 567:                 "carrier` WHERE name like '{$code}')");
 568:         $db->execute('DELETE FROM `' . _DB_PREFIX_ .
 569:                 "carrier_group` WHERE id_carrier in (select id_carrier FROM `" . _DB_PREFIX_ .
 570:                 "carrier` WHERE name like '{$code}')");
 571: 
 572: 
 573:         $db->execute('DELETE FROM `' . _DB_PREFIX_ .
 574:                 "carrier_lang` WHERE id_carrier in (select id_carrier FROM `" . _DB_PREFIX_ .
 575:                 "carrier` WHERE name like '{$code}' and id_carrier not in (select id_carrier from `" .
 576:                 _DB_PREFIX_ . "cart`) and id_carrier not in (select id_carrier from `" .
 577:                 _DB_PREFIX_ . "orders`))");
 578:         $db->execute('DELETE FROM `' . _DB_PREFIX_ .
 579:                 "carrier_tax_rules_group_shop` WHERE id_carrier in (select id_carrier FROM `" . _DB_PREFIX_ .
 580:                 "carrier` WHERE name like '{$code}')");
 581: 
 582: 
 583:         //and the ones which have been used to place orders, update them to "deleted=1"
 584:         $db->execute('UPDATE `' . _DB_PREFIX_ .
 585:                 "carrier` set deleted = 1, active = 0 WHERE name like '{$code}' and deleted = 0");
 586:         
 587:         return true;
 588:     }
 589:     
 590: 
 591:     protected $_cachedInstances = array();
 592:     public function getCarrierInstanceFromIdCarrier($id_carrier) {
 593:         if (isset($this->_cachedInstances[$id_carrier])) {
 594:             return $this->_cachedInstances[$id_carrier];
 595:         }
 596:         $carrier = new Carrier($id_carrier);
 597:         $carrierInstance = null;
 598:         if (isset($carrier->external_module_name) && $carrier->external_module_name && $this->_verifyCode($carrier->external_module_name)) {
 599:             $carrierInstance = Module::getInstanceByName($carrier->external_module_name);
 600:         }
 601:         return $carrierInstance;
 602:     }
 603:     
 604:     
 605:     /**
 606:      * <p>If cart contains addresses, which require parcel terminal to be selected (Use help of this module) then parcel terminals are validated.</p>
 607:      * <p>If onepage checkout is active, then response is returned as json string and displayed like alert in the checkout.</p>
 608:      * <p>When checkout is 5 steps, then on error script exits and user is redirected back to shipping method page, where get parameter <code>shipping_method_id</code> with erroneus <code>carrier.external_module_name</code> is returned</p>
 609:      * <p>This PrestaShop hook uses following parameters:</p>
 610:      * <ul>
 611:          <li><code>cart</code> - Current shopping cart instance for the customer</li>
 612:      </ul>
 613:      * @param array $params
 614:      * @return boolean|string
 615:      */
 616:     public function hookActionCarrierProcess($params) {
 617:         //
 618:         $cart = $params['cart'];
 619:         
 620:         $shipping_method = $cart->id_carrier;
 621:         $this->l('-- select --');
 622:         
 623:         //detect if shipping method is registered and enabled.....
 624:         $carrier = new Carrier($shipping_method);
 625:         
 626:         
 627:         $id_address = $this->_getIdAddress($cart->id_address_delivery);
 628:         
 629:         
 630:         $errors = array();
 631:         if ($shipping_method && $id_address && $carrier->is_module && $carrier->external_module_name && $this->_verifyCode($carrier->external_module_name)) {
 632:             $selected_parcel_terminal = $this->getOfficeFromSession($id_address);
 633:             
 634:             //clear terminal, when carrier names do not match with the one in the session.
 635:             if ($selected_parcel_terminal['code'] != $carrier->external_module_name) {
 636:                 $selected_parcel_terminal['place_id'] = false;
 637:             }
 638: //            echo '<pre>'.htmlspecialchars(print_r($v, true)).'</pre>';
 639:             
 640:             
 641:             //check if only one carrier instance
 642:             if (!$selected_parcel_terminal['place_id'] && ($singleParcelTerminal = $this->_getSingleTerminal($carrier->external_module_name))) {
 643:                 if ($singleParcelTerminal) {
 644:                     $this->setOfficeToSession($carrier->external_module_name, $id_address, $singleParcelTerminal['remote_place_id']);
 645:                     $selected_parcel_terminal = $this->getOfficeFromSession($id_address);
 646:                 }
 647:             }
 648: 
 649:             if (!$this->_verifySelectedTerminal($carrier->external_module_name, $selected_parcel_terminal['place_id'])) {
 650: 
 651:                 //0 = standard
 652:                 //1 = onestep checkout
 653:                 if (Configuration::get('PS_ORDER_PROCESS_TYPE') === '0') {
 654:                     $errors[] = Tools::displayError($this->l('Please select parcel terminal'));
 655:                     Tools::redirectLink(Tools::redirectLink('index.php?controller=order&step=2&shipping_method_id='.$carrier->external_module_name));
 656:                 } else {
 657:                     $errors[] = Tools::displayError($this->l('Please select parcel terminal'));
 658:                     die('{"hasError" : true, "errors" : ["' . implode('\',\'', $errors) . '"]}');
 659:                 }
 660: 
 661:                 return false;
 662:             }
 663:             $module = Module::getInstanceByName($carrier->external_module_name);
 664:             if (!$module->active) {
 665:                 $errors[] = Tools::displayError(sprintf($this->l('Module %s is not active'), $carrier->external_module_name));
 666:                 die('{"hasError" : true, "errors" : ["'.implode('\',\'', $errors).'"]}');
 667:                 return false;
 668:             }
 669:             
 670:             
 671:         } else if (!$cart->isVirtualCart() && !$cart->delivery_option) {
 672:                 $errors[] = Tools::displayError(sprintf($this->l('Shipping is required for this order %s'), ''));
 673:                 
 674:                 die('{"hasError" : true, "errors" : ["'.implode('\',\'', $errors).'"]}');
 675:                 return false;
 676:         }
 677:     }
 678:     
 679:     
 680:     /**
 681:      * <p>Fix display bug right after login</p>
 682:      * <p>select menu of pickup points not displayed after entering customer address and then logging in instead</p>
 683:      * @param int $origIdAddress default cart->id_address_delivery
 684:      * @return int
 685:      */
 686:     protected function _getIdAddress($origIdAddress) {
 687:         //fix display bug right after login.
 688:         //select menu of pickup points not displayed after entering customer address and then logging in instead
 689:         $products = Context::getContext()->cart->getProducts();
 690:         foreach ($products as $product) {
 691:             if (!$product['is_virtual']) {
 692:                 if ($product['id_address_delivery'] != $origIdAddress && $product['id_address_delivery']) {
 693:                     $origIdAddress = $product['id_address_delivery'];
 694:                 }
 695:                 break;
 696:             }
 697:         }
 698: 
 699:         //end fix display bug right after login
 700:         return $origIdAddress;
 701:     }
 702: 
 703:     /**
 704:      * <p>Renders ajax select menu for the current carrier specified by template parameters.</p>
 705:      * <p>Params are in following format:</p>
 706:      * <pre>
 707:      * $params = array(
 708:      *  id_address_delivery
 709:      *  price
 710:      *  title
 711:      *  logo
 712:      *  id_address_invoice
 713:      *  error_message
 714:      *  is_default
 715:      * )
 716:      * </pre>
 717:      * 
 718:      * @param string $code carrier code
 719:      * @param array $params supplied parametes
 720:      * @param bool $shouldHide true, when carrier should not be available to the customer
 721:      * @return string html
 722:      */
 723:     public function displayExtraCarrier($code, $params, $shouldHide = false) {
 724:         /* @var $prestaCarrierValue CarrierCore */
 725:         $prestaCarrierValue = $this->getCarrierFromCode($code);
 726:         //fix display bug right after login.
 727:         //select menu of pickup points not displayed after entering customer address and then logging in instead
 728:         $params['id_address_delivery'] = $this->_getIdAddress($params['id_address_delivery']);
 729: 
 730:         //end fix display bug right after login
 731:         
 732:         
 733:         $implodedJs = 'input[name=delivery_option\\\[' . $params['id_address_delivery'] . '\\\]][value="' . $prestaCarrierValue->id . ',"]:visible';
 734:         $implodedJsMultishipping = 'input[name=id_carrier][value="' . $prestaCarrierValue->id . '"]:hidden';
 735:         $jsHideSelector = '.parent()';
 736:         if (substr(_PS_VERSION_, 0, 3) == "1.6") {
 737:             $jsHideSelector = ".parentsUntil('div.delivery_option')";
 738:         }
 739:         
 740: 
 741:         if ($shouldHide) {
 742:             return <<<EOT
 743:    <script type="text/javascript">
 744: //       <![CDATA[
 745:     (function() {
 746:         var implodedJs = \$('{$implodedJs}');
 747:         jQuery.each(implodedJs, function(i, val) {
 748:             jQuery(val){$jsHideSelector}.hide();
 749:         });
 750:         
 751:             \$('div.delivery_option').removeClass('item').removeClass('alternate_item');
 752:             \$('div.delivery_option:visible:even').addClass('item');
 753:             \$('div.delivery_option:visible:odd').addClass('alternate_item');
 754: 
 755:     }());
 756: //       ]>
 757:    </script>
 758:   
 759: EOT;
 760:             
 761:         }
 762:         
 763:         $this->refresh($code);
 764:         
 765:         
 766:         $js = '';
 767:         $isOnepageCheckout = false;
 768:         if (Configuration::get('PS_ORDER_PROCESS_TYPE') == '1') {
 769:             $isOnepageCheckout = true;
 770:             $js = 'updateCarrierSelectionAndGift();';
 771:         }
 772:         
 773:         $list = '<div id="eabi_carrier_' . $code . '" style="display:inline-block;"></div>';
 774:         
 775:         //make the price
 776:         $finalPrice = $params['price'];
 777:         $carrier_tax = 0;
 778:         if (!Tax::excludeTaxeOption()) {
 779:             if (Configuration::get('PS_TAX_ADDRESS_TYPE') == 'id_address_invoice') {
 780:                 $taxAddressId = $params['id_address_invoice'];
 781:             } else {
 782:                 $taxAddressId = $params['id_address_delivery'];
 783:             }
 784:             if (!Address::addressExists($taxAddressId)) {
 785:                 $taxAddressId = null;
 786:             }
 787:             $carrier_tax = $prestaCarrierValue->getTaxesRate(new Address((int) $taxAddressId));
 788:             // Apply tax
 789:             if (isset($carrier_tax)) {
 790:                 $finalPrice *= 1 + ($carrier_tax / 100);
 791:             }
 792:         }
 793:         $isDefault = (isset($params['is_default']) && $params['is_default'])?true:false;
 794:         $errorMessage = (isset($params['error_message']) && $params['error_message'])?$params['error_message']:'';
 795:         if (!$errorMessage && Tools::getValue('shipping_method_id', '') === $code) {
 796:             $errorMessage = $this->l('Please select parcel terminal');
 797:         }
 798: 
 799: 
 800:         $arr = array(
 801:             'price' => round($finalPrice, 2),
 802:             'id_address' => $params['id_address_delivery'],
 803:             'name' => $this->l($params['title']),
 804:             'delay' => $list,
 805:             'img' => $params['logo'],
 806:             'id_carrier' => '_' . $code . '',
 807:             'isDefault' => $isDefault,
 808:             'js' => $js,
 809:             'opc' => $isOnepageCheckout,
 810:         );
 811:         
 812:         $isSelected = false;
 813:         
 814:         $selectedOffice = $this->getOfficeFromSession($params['id_address_delivery']);
 815:         $containsSelection = false;
 816:         if ($selectedOffice['place_id'] != '' && $selectedOffice['code'] == $code) {
 817:             $containsSelection = true;
 818:         }
 819:         $cart = Context::getContext()->cart;
 820:         if ($prestaCarrierValue->id == $cart->id_carrier) {
 821:             $isSelected = true;
 822:         }
 823:         
 824:         $templateName = $this->name;
 825:         $jsSelector = '.parent()';
 826:         $jsSelectorMulti = '.parents("tr")';
 827:         $extraJs = <<<EOT
 828:    jQuery('#id_carrier_{$code}').attr('checked', 'checked');
 829:    if (!window.eabi_carrier_checked) {
 830:         jQuery('#id_carrier_{$code}').click();
 831:         window.eabi_carrier_checked = true;
 832:    }
 833: EOT;
 834:         if (substr(_PS_VERSION_, 0, 3) == "1.6") {
 835:             $templateName = $this->name .'_16';
 836:             $jsSelector = ".parentsUntil('tbody')";
 837:         $extraJs = <<<EOT
 838:    jQuery('span.checked').removeClass('checked');
 839:    jQuery('#id_carrier_{$code}').attr('checked', 'checked');
 840:    jQuery('#id_carrier_{$code}').parent().addClass('checked');
 841:    if (!window.eabi_carrier_checked) {
 842:         jQuery('#id_carrier_{$code}').click();
 843:         window.eabi_carrier_checked = true;
 844:    }
 845: EOT;
 846:             
 847:         }
 848:         
 849:         $eabiCarrierValue = $prestaCarrierValue->id . ',';
 850: 
 851: 
 852: 
 853:         $smarty = Context::getContext()->smarty;
 854:         $smarty->assign(array(
 855:             'eabi_carrier' => $arr,
 856:             'eabi_ERROR_MESSAGE' => $errorMessage,
 857:             'eabi_url' => str_replace('/'.Language::getIsoById(Context::getContext()->language->id).'/', '/', $this->context->link->getModuleLink($this->name, 'postoffice', array(), true)),
 858:             'eabi_divId' => 'eabi_carrier_' . $code,
 859:             'eabi_carrierId' => $code . '\\\\,',
 860:             'eabi_carrierCode' => $code,
 861:             'eabi_addressId' => $params['id_address_delivery'],
 862:             'eabi_carrierValue' => $containsSelection ? $eabiCarrierValue : '',
 863:             'eabi_extraJs' => $isSelected ? $extraJs : '',
 864:             'eabi_priceDisplay' => $carrier_tax == 0,
 865:         ));
 866:         
 867:         $html = '';
 868:         
 869:         $html .= <<<JS
 870:    <script type="text/javascript">
 871: //       <![CDATA[
 872:     (function() {
 873:         var implodedJs = \$('{$implodedJs}'),
 874:             implodedJsMultishipping = \$('{$implodedJsMultishipping}'),
 875:             firstItem = false,
 876:             firstItemMultishipping = false;
 877: //        console.log(implodedJs);
 878: //        console.log(implodedJsMultishipping);
 879:         jQuery.each(implodedJs, function(i, val) {
 880:             \$(val).parent().hide();
 881:             if (!firstItem) {
 882:                 firstItem = \$(val){$jsSelector};
 883: //                console.log(firstItem);
 884:             }
 885:         });
 886:         jQuery.each(implodedJsMultishipping, function(i, val) {
 887: //            \$(val).parent().hide();
 888:             if (!firstItemMultishipping) {
 889:                 firstItemMultishipping = \$(val){$jsSelectorMulti};
 890: //                console.log(firstItemMultishipping);
 891:             }
 892:         });
 893:         if (firstItem) {
 894:             //html update for....
 895:             \$(firstItem).html({$this->encodeToJson($this->display(__FILE__, $templateName . '.tpl'))});
 896:             //make the alternation
 897:                 
 898: 
 899: 
 900:             \$(firstItem).show();
 901:             \$('div.delivery_option').removeClass('item').removeClass('alternate_item');
 902:             \$('div.delivery_option:visible:even').addClass('item');
 903:             \$('div.delivery_option:visible:odd').addClass('alternate_item');
 904:             
 905:         }
 906:         if (firstItemMultishipping) {
 907:             //html update for....
 908: //            console.log($(firstItemMultishipping));
 909:             \$(firstItemMultishipping).find("td").eq(1).html({$this->encodeToJson($this->display(__FILE__, $templateName . '_multi.tpl'))});
 910:             //make the alternation
 911:                 
 912: 
 913: 
 914:             \$(firstItem).show();
 915:             \$('div.delivery_option').removeClass('item').removeClass('alternate_item');
 916:             \$('div.delivery_option:visible:even').addClass('item');
 917:             \$('div.delivery_option:visible:odd').addClass('alternate_item');
 918:             
 919:         }
 920:         
 921: 
 922: 
 923:     })();
 924: //       ]>
 925:    </script>
 926: JS;
 927: 
 928: 
 929:         //hide old terminals
 930:         return $html;
 931:         
 932:         
 933:         
 934:         
 935:     }
 936:     
 937:     /**
 938:      * <p>Displays selected carrier info at the order detail view</p>
 939:      * <p><code>$params</code> is assoc array, which must contain at least <code>order</code> key, which should be instance of <code>Order</code></p>
 940:      * @param array $params
 941:      */
 942:     public function hookDisplayOrderDetail($params) {
 943:         /* @var $order OrderCore */
 944:         $order = $params['order'];
 945:         
 946:         $template = <<<HTML
 947: <table class="detail_step_by_step table table-bordered">
 948:     <thead>
 949:         <tr>
 950:             <th class="first_item">%TEXT%</th>
 951:             <th class="last_item">%TERMINAL%</th>
 952:         </tr>
 953:     </thead>
 954: </table>
 955:                     
 956: HTML;
 957:         $suppliedParams = array(
 958:             'objOrder' => $order,
 959:             'eabi_template' => $template,
 960:         );
 961:         
 962:         return $this->hookOrderConfirmation($suppliedParams);
 963:         
 964:     }
 965: 
 966:     public function hookDisplayPDFInvoice($params) {
 967:         if (!isset($params['order'])) {
 968:             return false;
 969:         }
 970:         /* @var $order OrderCore */
 971:         $order = $params['order'];
 972:         $suppliedParams = array(
 973:             'objOrder' => $order,
 974:         );
 975:         return $this->hookOrderConfirmation($suppliedParams);
 976:         
 977:     }
 978:     
 979:     /**
 980:      * <p>Renders information about chosen parcel terminal as HTML string.</p>
 981:      * <p>This PrestaShop hook reads following parameters:</p>
 982:      * <ul>
 983:          <li><code>objOrder</code> - Order instance which should render selected parcel terminal</li>
 984:      </ul>
 985:      * @param array $params
 986:      * @return string|boolean
 987:      */
 988:     public function hookOrderConfirmation($params) {
 989:         $template = null;
 990:         if (isset($params['eabi_template']) && $params['eabi_template']) {
 991:             $template = $params['eabi_template'];
 992:         }
 993:         if (isset($params['objOrder']) && $params['objOrder'] && Validate::isLoadedObject($params['objOrder'])) {
 994:             $objOrderExists = true;
 995:             $order = $params['objOrder'];
 996:             $id_carrier = $order->id_carrier;
 997:             $id_cart = $order->id_cart;
 998:         } else {
 999:             $objOrderExists = false;
1000:         }
1001:         if (!$objOrderExists) {
1002:             //try to load the carrier from cart
1003:             $id_carrier = Context::getContext()->cart->id_carrier;
1004:             $id_cart = Context::getContext()->cart->id;
1005:         }
1006:         if ($id_carrier) {
1007:             $carrier = new Carrier($id_carrier);
1008:             if ($carrier->is_module && $carrier->external_module_name && $this->_verifyCode($carrier->external_module_name)) {
1009:                 $carrierInstance = Module::getInstanceByName($carrier->external_module_name);
1010: //                $data = $carrierInstance->displayInfoByCart($order->id_cart);
1011: 
1012:                 $offices = $this->getOfficesFromCart($id_cart);
1013:                 $terminals = array();
1014:                 foreach ($offices as $address_id => $office) {
1015:                     $terminals[] = $carrierInstance->getAdminTerminalTitle($office);
1016:                 }
1017:                 if ($template && is_string($template) && strlen($template)) {
1018:                     $data = str_replace(array('%TEXT%', '%TERMINAL%'), array($this->l('Chosen parcel terminal:'), implode(', ', $terminals)), $template);
1019:                 } else {
1020:                     $data = '<p>'.$this->l('Chosen parcel terminal:') . ' <b>' . implode(', ', $terminals) . '</b></p>';
1021:                     
1022:                 }
1023: 
1024:                 return $data;
1025:             }
1026:         }
1027:         return false;
1028:     }
1029:     
1030:     /**
1031:      * If there is only one terminal in the list and it is not in the session, then it would be loaded using this function.
1032:      * In every other case this function returns false
1033:      * @param string $code
1034:      * @return array|bool
1035:      */
1036:     protected function _getSingleTerminal($code) {
1037:         $db = Db::getInstance();
1038:         $sql = 'SELECT count(id_eabi_postoffice) as cnt FROM `' . _DB_PREFIX_ . 'eabi_postoffice` where `remote_module_name` = \''.$db->escape($code).'\' ';
1039:         $res = $db->executeS($sql);
1040:         if (is_array($res) && count($res) && $res[0]['cnt'] == '1') {
1041:             //fetch
1042:             $sql = 'SELECT * FROM `' . _DB_PREFIX_ . 'eabi_postoffice` where `remote_module_name` = \''.$db->escape($code).'\' LIMIT 1';
1043:             $terminal = $db->executeS($sql);
1044:             return $terminal[0];
1045:         }
1046:         return false;
1047:     }
1048:     
1049: 
1050:     /**
1051:      * <p>Returns true if pickup point id is registered in local databse</p>
1052:      * @param string $code shipping method code
1053:      * @param int $terminal remote place id for the parcel terminal
1054:      * @return boolean
1055:      */
1056:     protected function _verifySelectedTerminal($code, $terminal) {
1057:         $db = Db::getInstance();
1058:         $sql = 'SELECT * FROM `' . _DB_PREFIX_ . 'eabi_postoffice` where `remote_module_name` = \''.$db->escape($code).'\' and remote_place_id = \''.$db->escape($terminal).'\' LIMIT 1';
1059:         $res = $db->executeS($sql);
1060:         if (is_array($res) && count($res)) {
1061:             return true;
1062:         }
1063:         return false;
1064:     }
1065:     
1066:     /**
1067:      * <p>Returns carrier module id from its remote code</p>
1068:      * @param string $code carrier code
1069:      * @return int
1070:      */
1071:     public function idFromCode($code) {
1072:         if (is_null(self::$_carrierModules)) {
1073:             $db = Db::getInstance();
1074:             $sql = 'SELECT * FROM `' . _DB_PREFIX_ . 'eabi_carriermodule`';
1075:             $res = $db->executeS($sql);
1076:             self::$_carrierModules = array();
1077:             foreach ($res as $r) {
1078:                 self::$_carrierModules[$r['carrier_code']] = $r['id_eabi_carriermodule'];
1079:             }
1080:         }
1081:         if (isset(self::$_carrierModules[$code])) {
1082:             return self::$_carrierModules[$code];
1083:         }
1084:         return null;
1085:     }
1086:     
1087:     /**
1088:      * <p>Returns <code>carrier</code> table entry from external_module_name</p>
1089:      * <p>Returns false, when not found</p>
1090:      * @param string $code
1091:      * @return array|boolean
1092:      */
1093:     public function getCarrierFromCode($code) {
1094:         if (is_null(self::$_carriersByCode)) {
1095:             self::$_carriersByCode = array();
1096:         }
1097:         if (isset(self::$_carriersByCode[$code])) {
1098:             return self::$_carriersByCode[$code];
1099:         }
1100:         $db = Db::getInstance();
1101:         $sql = 'SELECT * FROM `' . _DB_PREFIX_ . "carrier` where external_module_name = '{$code}' and deleted = 0";
1102:         $res = $db->executeS($sql);
1103:         if (count($res)) {
1104:             self::$_carriersByCode[$code] = new Carrier($res[0]['id_carrier']);
1105:             return self::$_carriersByCode[$code];
1106:         }
1107:         return false;
1108:     }
1109: 
1110:     /**
1111:      * <p>Returns carrier_code for the selected carrier id, if it is registered with this module</p>
1112:      * @param int $id
1113:      * @return string
1114:      */
1115:     public function codeFromId($id) {
1116:         if (is_null(self::$_carrierModules)) {
1117:             $db = Db::getInstance();
1118:             $sql = 'SELECT * FROM `' . _DB_PREFIX_ . 'eabi_carriermodule`';
1119:             $res = $db->executeS($sql);
1120:             self::$_carrierModules = array();
1121:             foreach ($res as $r) {
1122:                 self::$_carrierModules[$r['carrier_code']] = $r['id_eabi_carriermodule'];
1123:             }
1124:         }
1125:         foreach (self::$_carrierModules as $code => $internalId) {
1126:             if ($internalId == $id ) {
1127:                 return $code;
1128:             }
1129:         }
1130:         return null;
1131:     }
1132:     
1133:     
1134:     
1135:     /**
1136:      * 
1137:      * <p>Attempts to synchronize list of parcel terminals with remote server if update time was earlier than update interval for the current carrier.</p>
1138:      * @param string $code carrier code
1139:      * @param bool $byPassTimeCheck when set to true, then data is updated anyway
1140:      * @return null
1141:      */
1142:     public function refresh($code, $byPassTimeCheck = false) {
1143:         $carrier = Module::getInstanceByName($code);
1144:         $lastUpdated = $carrier->getLastUpdated();
1145:         $updateInterval = $carrier->getUpdateInterval();
1146:         $date = time();
1147:         if ($lastUpdated + ($updateInterval * 60) < $date || $byPassTimeCheck) {
1148:             $officeList = $carrier->getOfficeList();
1149:             $oldData = array();
1150:             $db = Db::getInstance();
1151: 
1152:             //sql query....
1153:             $oldDataCollection = $db->executeS("select * from " . _DB_PREFIX_ . "eabi_postoffice where remote_module_name = '" . $db->escape($code) . "'");
1154:             $groups = array();
1155: 
1156:             foreach ($oldDataCollection as $oldDataElement) {
1157:                 $oldData[(string) $oldDataElement['remote_place_id']] = $oldDataElement;
1158: 
1159:                 if ($oldDataElement['group_name'] != '' && $oldDataElement['group_id'] > 0) {
1160:                     $groups[(string) $oldDataElement['group_id']] = $oldDataElement['group_name'];
1161:                 }
1162:             }
1163: 
1164:             if (!is_array($officeList)) {
1165:                 $carrier->setLastUpdated($date);
1166:                 return;
1167:             } else {
1168:                 $processedPlaceIds = array();
1169: 
1170:                 foreach ($officeList as $newDataElement) {
1171: 
1172:                     if (!isset($newDataElement['group_id']) || !isset($newDataElement['group_name'])
1173:                             || $newDataElement['group_id'] == '' || $newDataElement['group_name'] == '') {
1174:                         $this->assignGroup($newDataElement, $groups);
1175:                     }
1176: 
1177:                     if (!isset($newDataElement['group_sort'])) {
1178:                         $newDataElement['group_sort'] = $carrier->getGroupSort($newDataElement['group_name']);
1179:                     }
1180: 
1181:                     if (!isset($oldData[(string) $newDataElement['place_id']])) {
1182: 
1183:                         $oldData[(string) $newDataElement['place_id']] = $this->fromOfficeElement($newDataElement, $code);
1184:                     } else {
1185:                         $oldData[(string) $newDataElement['place_id']] = $this->fromOfficeElement($newDataElement, $code, $oldData[(string) $newDataElement['place_id']]);
1186:                     }
1187: 
1188:                     $processedPlaceIds[(string) $newDataElement['place_id']] = (string) $newDataElement['place_id'];
1189:                 }
1190:                 foreach ($oldData as $placeId => $oldDataElement) {
1191:                     if (!isset($processedPlaceIds[(string) $placeId])) {
1192:                         //delete oldDataElement
1193:                         $db->execute("delete from " . _DB_PREFIX_ . "eabi_postoffice where id_eabi_postoffice = " . $db->escape($oldDataElement['id_eabi_postoffice']));
1194:                     } else {
1195:                         //save OldDataElement
1196:                         if (!isset($oldDataElement['id_eabi_postoffice'])) {
1197:                             //insert
1198:                             $dataToInsert = array();
1199:                             $oldDataElement['created_time'] = date("Y-m-d H:i:s");
1200:                             $oldDataElement['update_time'] = date("Y-m-d H:i:s");
1201:                             foreach ($oldDataElement as $key => $value) {
1202:                                 $dataToInsert[$key] = "'" . $db->escape($value) . "'";
1203:                             }
1204:                             $db->execute("insert into " . _DB_PREFIX_ . "eabi_postoffice (" . implode(',', array_keys($dataToInsert)) . ") VALUES (" . implode(',', $dataToInsert) . ");");
1205:                             
1206:                         } else {
1207:                             //update
1208:                             $dataToInsert = array();
1209:                             $oldDataElement['update_time'] = date("Y-m-d H:i:s");
1210:                             foreach ($oldDataElement as $key => $value) {
1211:                                 $dataToInsert[$key] = $key . " = '" . $db->escape($value) . "'";
1212:                             }
1213:                             $db->execute("update " . _DB_PREFIX_ . "eabi_postoffice set " . implode(', ', $dataToInsert) . " where id_eabi_postoffice = " . $db->escape($oldDataElement['id_eabi_postoffice']));
1214: //                            exit;
1215:                         }
1216:                     }
1217:                 }
1218:                 $carrier->setLastUpdated($date);
1219:             }
1220:         }
1221:     }
1222:     
1223:     /**
1224:      * <p>Synchronizes remote pickup point with old data for specified module code.</p>
1225:      * @param array $officeElement
1226:      * @param string $moduleCode
1227:      * @param array $oldData
1228:      * @return array
1229:      * @throws Exception
1230:      */
1231:     protected function fromOfficeElement($officeElement, $moduleCode, $oldData = null) {
1232:         $db = DB::getInstance();
1233:         $newData = array();
1234:         if (is_array($oldData)) {
1235:             if (isset($oldData['id_eabi_postoffice'])) {
1236:                 $newData['id_eabi_postoffice'] = $oldData['id_eabi_postoffice'];
1237:                 
1238:             }
1239:         }
1240:         if ($moduleCode != '') {
1241:             //load the remote module
1242:             
1243:             $remoteModule = $db->executeS("select * from ". _DB_PREFIX_. "eabi_carriermodule where carrier_code = '".$db->escape($moduleCode)."'");
1244:             
1245:             if (!count($remoteModule)) {
1246:                 throw new Exception('Carrier could not be detected');
1247:             }
1248:             $newData['remote_module_id'] = $remoteModule[0]['id_eabi_carriermodule'];
1249:             $newData['remote_module_name'] = $remoteModule[0]['carrier_code'];
1250:             
1251:             
1252:         } else {
1253:             if (!is_array($oldData) || !isset($oldData['remote_module_id']) 
1254:                     ||!isset($oldData['remote_module_name'])) {
1255:                 throw new Exception('Remote module ID and remote module name have to be defined');
1256:             }
1257:             $newData['id'] = $oldData['id'];
1258:             $newData['remote_module_id'] = $oldData['remote_module_id'];
1259:             $newData['remote_module_name'] = $oldData['remote_module_name'];
1260:         }
1261:         
1262:         $newData['remote_place_id'] = $officeElement['place_id'];
1263:         $newData['name'] = $officeElement['name'];
1264:         
1265: 
1266:         if (isset($officeElement['servicing_place_id'])) {
1267:             $newData['remote_servicing_place_id'] = $officeElement['servicing_place_id'];
1268:         }
1269:         if (isset($officeElement['city'])) {
1270:             $newData['city'] = $officeElement['city'];
1271:         }
1272:         if (isset($officeElement['county'])) {
1273:             $newData['county'] = $officeElement['county'];
1274:         }
1275:         if (isset($officeElement['zip'])) {
1276:             $newData['zip_code'] = $officeElement['zip'];
1277:         }
1278:         if (isset($officeElement['country'])) {
1279:             $newData['country'] = $officeElement['country'];
1280:         }
1281:         if (isset($officeElement['description'])) {
1282:             $newData['description'] = $officeElement['description'];
1283:         }
1284:         if (isset($officeElement['group_id']) && isset($officeElement['group_name'])) {
1285:             $newData['group_id'] = $officeElement['group_id'];
1286:             $newData['group_name'] = $officeElement['group_name'];
1287:             if (isset($officeElement['group_sort'])) {
1288:                 $newData['group_sort'] = $officeElement['group_sort'];
1289:             }
1290:         }
1291: 
1292:         if (isset($officeElement['extra']) && is_array($officeElement['extra'])) {
1293:             $newData['cached_attributes'] = serialize($officeElement['extra']);
1294:         }
1295:         
1296: 
1297: 
1298: 
1299:         return $newData;
1300:     }
1301:     
1302:     /**
1303:      * 
1304:      * <p>Keeps track of generated group_id-s based on the group_names, making sure that each group has it's unique id.</p>
1305:      * @param array $dataElement
1306:      * @param type $groups
1307:      */
1308:     protected function assignGroup(array &$dataElement, &$groups) {
1309:         $groupNames = array();
1310:         if (isset($dataElement['county']) && !empty($dataElement['county'])) {
1311:             $groupNames[] = $dataElement['county'];
1312:         }
1313:         if (isset($dataElement['city']) && !empty($dataElement['city'])) {
1314:             $groupNames[] = $dataElement['city'];
1315:         }
1316:         if (count($groupNames) > 0) {
1317:             $groupName = implode('/', $groupNames);
1318:             if (in_array($groupName, $groups)) {
1319:                 $dataElement['group_name'] = $groupName;
1320:                 $dataElement['group_id'] = array_search($groupName, $groups);
1321:             } else {
1322:                 $new_id = 1;
1323:                 if (count($groups) > 0) {
1324:                     $new_id = max(array_keys($groups)) + 1;
1325:                     
1326:                 }
1327:                 $groups[(string)$new_id] = $groupName;
1328:                 $dataElement['group_name'] = $groupName;
1329:                 $dataElement['group_id'] = array_search($groupName, $groups);
1330:             }
1331:         }
1332:     }
1333: 
1334:     /**
1335:      * <p>Makes sure that carrier is registered with this module</p>
1336:      * @param string $code carrier code
1337:      * @return boolean
1338:      */
1339:     protected function _verifyCode($code) {
1340:         $db = Db::getInstance();
1341:         $sql = 'SELECT * FROM `' . _DB_PREFIX_ . 'eabi_carriermodule` where `carrier_code` = \''.$db->escape($code).'\' LIMIT 1';
1342:         $res = $db->executeS($sql);
1343:         if (!$res) {
1344:             return false;
1345:         }
1346:         if (!count($res)) {
1347:             return false;
1348:         }
1349:         return true;
1350:     }
1351:     
1352:     
1353:     
1354:     /**
1355:      * <p>Drops all the tables which were created during the install process</p>
1356:      * @return bool
1357:      */
1358:     private function _dropTables() {
1359:         $sql = 'DROP TABLE
1360:             `'._DB_PREFIX_.'eabi_carriermodule`,
1361:             `'._DB_PREFIX_.'eabi_postoffice`,
1362:             `'._DB_PREFIX_.'eabi_cart_shipping`
1363:             ';
1364: 
1365:         return Db::getInstance()->execute($sql);
1366:         
1367:     }
1368:     
1369:     private function _createSelectedShippingOptionInCartTable() {
1370:         $sql = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'eabi_cart_shipping`(
1371:     `id_eabi_cart_shipping` int(11) unsigned NOT NULL auto_increment,
1372:     `id_cart` int(11) unsigned NOT NULL,
1373:     `id_address` int(11) unsigned NOT NULL,
1374:     `remote_module_id` int(11) unsigned NOT NULL,
1375:     `remote_place_id` int(11) unsigned NOT NULL,
1376:     PRIMARY KEY (`id_eabi_cart_shipping`)
1377:     ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8';
1378:         $result = Db::getInstance()->execute($sql);
1379:         if ($result === false) {
1380:             return false;
1381:         }
1382:         $indexSql = "ALTER TABLE `"._DB_PREFIX_."eabi_cart_shipping` ADD INDEX ( `id_cart` , `id_address` ) ;";
1383:         $indexSqlResult = Db::getInstance()->execute($indexSql);
1384:         return $indexSqlResult;
1385:     }
1386: 
1387:     private function _createCarrierModuleTable() {
1388:         $sql = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'eabi_carriermodule`(
1389:         `id_eabi_carriermodule` int(11) unsigned NOT NULL auto_increment,
1390:         `carrier_code` varchar(255) NOT NULL,
1391:         `class_name` varchar(255) NOT NULL,
1392:         `update_time` datetime NULL,
1393:     PRIMARY KEY (`id_eabi_carriermodule`)
1394:     ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8';
1395:         return Db::getInstance()->execute($sql);
1396:         
1397:     }
1398:     
1399:     private function _createPostofficeTable() {
1400:         $sql = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'eabi_postoffice`(
1401:         `id_eabi_postoffice` int(11) unsigned NOT NULL auto_increment,
1402:         `remote_module_id` int(11) unsigned NOT NULL,
1403:         `remote_module_name` varchar(255) NOT NULL,
1404:         `remote_place_id` int(11) unsigned NOT NULL,
1405:         `remote_servicing_place_id` int(11) unsigned NULL,
1406: 
1407:         `name` varchar(255) NOT NULL,
1408:         `city` varchar(255) NULL,
1409:         `county` varchar(255) NULL,
1410:         `zip_code` varchar(255) NULL,
1411:         `country` varchar(2) NULL,
1412:         `description` text NULL,
1413: 
1414:         `group_id` int(11) unsigned NULL,
1415:         `group_name` varchar(255) NULL,
1416:         `group_sort` int(11) unsigned NULL,
1417: 
1418:         `local_carrier_id` int(11) unsigned NULL,
1419:     
1420:         `created_time` datetime NULL,
1421:         `update_time` datetime NULL,
1422:         `cached_attributes` text NULL,
1423:     PRIMARY KEY (`id_eabi_postoffice`)
1424:     ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8';
1425:         return Db::getInstance()->execute($sql);
1426:         
1427:     }
1428:     
1429:     private function _createIndexes() {
1430:         $sql = '    ALTER TABLE `' . _DB_PREFIX_ . 'eabi_postoffice` ADD UNIQUE (
1431:         `remote_module_id`,
1432:         `remote_place_id`
1433:     );
1434:         ';
1435:         return Db::getInstance()->execute($sql);
1436:         
1437:     }
1438:     
1439:     /**
1440:      * <p>Returns HTML select list based on assoc array inputs and marks <code>$selected</code> as active option</p>
1441:      * @param array $array
1442:      * @param mixed $selected
1443:      * @return string html select list
1444:      */
1445:     public function getOptionList($array, $selected) {
1446:         $r = '';
1447:         foreach ($array as $k => $v) {
1448:             $r .= '<option value="' . $k . '"';
1449:             if ($k == $selected) {
1450:                 $r .= ' selected="selected"';
1451:             }
1452:             $r .= '>' . htmlspecialchars($v) . '</option>' . "\r\n";
1453:         }
1454:         return $r;
1455:     }
1456: 
1457:     /**
1458:      * <p>Returns HTML select[multiple=multiple] list based on assoc array inputs and marks <code>$selected</code> as active option</p>
1459:      * @param array $array
1460:      * @param mixed $selected
1461:      * @return string html select list
1462:      */
1463:     public function getMultiselectList($array, $selected) {
1464:         if (is_string($selected)) {
1465:             $selectedValues = explode(',', $selected);
1466:         } else {
1467:             $selectedValues = $selected;
1468:         }
1469:         $r = '';
1470:         if (!is_array($selectedValues)) {
1471:             $selectedValues = array();
1472:         }
1473:         foreach ($array as $k => $v) {
1474:             $r .= '<option value="' . $k . '"';
1475:             if (in_array($k, $selectedValues)) {
1476:                 $r .= ' selected="selected"';
1477:             }
1478:             $r .= '>' . htmlspecialchars($v) . '</option>' . "\r\n";
1479:         }
1480:         return $r;
1481:     }
1482:     
1483:     
1484:     /**
1485:      * <p>Returns list of alphabetically sorted countries as assoc array where array keys are country ISO codes and values are localized country names</p>
1486:      * @param bool $emptyOption -  adds text to the first place of countries list designated as empty option
1487:      * @return array
1488:      */
1489:     public function getCountriesAsOptions($emptyOption = false) {
1490:         $countries = Country::getCountries($this->context->language->id);
1491:         $countriesInSelect = array();
1492:         if ($emptyOption) {
1493:             $countriesInSelect[''] = $emptyOption;
1494:         }
1495:         foreach ($countries as $country) {
1496:             $countriesInSelect[$country['iso_code']] = $country['name'];
1497:         }
1498:         asort($countriesInSelect, SORT_STRING);
1499:         return $countriesInSelect;
1500:     }
1501:     
1502:     /**
1503:      * <p>Returns all the available tax groups as assoc array where array keys are tax_ids and values are tax names</p>
1504:      * @return array
1505:      */
1506:     public function getTaxes() {
1507:         $qu = "SELECT p.id_tax_rules_group as id_tax, p.name FROM `" . _DB_PREFIX_ . "tax_rules_group` p WHERE p.active = 1";
1508: 
1509:         $res = Db::getInstance()->executeS($qu);
1510:         $taxes = array('0' => $this->l('No Tax'));
1511:         foreach ($res as $r) {
1512:             $taxes[$r['id_tax']] = $r['name'];
1513:         }
1514:         return $taxes;
1515:     }
1516:     
1517:     /**
1518:      * <p>Returns assoc array of client groups where array keys are group_ids and values are client group names</p>
1519:      * @return array
1520:      */
1521:     public function getClientGroups() {
1522:         if (self::$clientGroups == null) {
1523:             //fetch the client groups from database
1524:             $id_lang = $this->context->language->id;
1525:             $qu = "SELECT g.id_group, gl.name FROM `" . _DB_PREFIX_ . "group` g,`" . _DB_PREFIX_ .
1526:                     "group_lang` gl  WHERE g.id_group = gl.id_group and gl.id_lang = " .
1527:                     DB::getInstance()->escape($id_lang);
1528:             $res = Db::getInstance()->ExecuteS($qu);
1529:             self::$clientGroups = array();
1530:             foreach ($res as $r) {
1531:                 self::$clientGroups[$r['id_group']] = $r['name'];
1532:             }
1533:         }
1534:         return self::$clientGroups;
1535:     }
1536:     
1537:     /**
1538:      * <p><code>json_encode</code> wrapper for using in <code>heredoc</code> syntax</p>
1539:      * @param mixed $input
1540:      * @return string
1541:      */
1542:     public function encodeToJson($input) {
1543:         return json_encode($input);
1544:     }
1545:     
1546:     /**
1547:      * <p>Wraps input string with div.conf+confirm html string</p>
1548:      * @param string $message
1549:      * @return string
1550:      */
1551:     public function addSuccess($message) {
1552:         return '<div class="conf confirm"><img src="../img/admin/ok.gif" alt="' .
1553:                 $this->l('ok') . '" /> ' . $message . '</div>';
1554:     }
1555:     
1556:     
1557:     /**
1558:      * <p>Attempts to fetch data from order that is stored by carriers extending Eabi_Postoffice_Model_Carrier_Abstract</p>
1559:      * <p>Data is stored in not visible on front order comment base64 encoded form and starting with specified prefix.</p>
1560:      * <p>If matching comment is found, it is decoded and returned as assoc array</p>
1561:      * @param OrderCore $order instance to look up the data for
1562:      * @param string $prefix unique string prefix order comment should start with.
1563:      * @return array
1564:      */
1565:     public function getDataFromOrder($order, $prefix) {
1566:         $db = Db::getInstance();
1567:         $orderComments = $db->executeS("SELECT * FROM `"._DB_PREFIX_."message` where id_order = {$db->escape($order->id)}");
1568:         
1569:         
1570:         $orderData = array();
1571:         foreach ($orderComments as $statusHistory) {
1572: //            echo '<pre>'.htmlspecialchars(print_r($statusHistory, true)).'</pre>';
1573:             /* @var $statusHistory Mage_Sales_Model_Order_Status_History */
1574:             if ($statusHistory['message'] && $statusHistory['private']) {
1575:                 if ($this->_commentContainsValidData($statusHistory['message'], $prefix)) {
1576:                     $orderData = @json_decode(@gzuncompress(@base64_decode($this->_getFromComment($statusHistory['message'], $prefix))), true);
1577:                     if (!is_array($orderData)) {
1578:                         //unserialize error on recognized pattern, should throw error or at least log
1579:                         $orderData = array();
1580:                     }
1581:                 }
1582:             }
1583:             
1584:             
1585:         }
1586:         return $orderData;
1587:         
1588:     }
1589:     
1590:     
1591:     
1592:     /**
1593:      * <p>Stores extra data for specified order in single order comment, which will start with specified prefix.</p>
1594:      * <p>If no matching order comment is found, then it is created automatically, otherwise old one is updated.</p>
1595:      * <p>Order comment is stored using following procedure:</p>
1596:      * <ul>
1597:          <li>If old data is found, then it is merged with new data</li>
1598:          <li>Data is json encoded and after that gzcompressed</li>
1599:          <li>Now it is base64 encoded and divided into 40 char long lines and prefixed with $prefix</li>
1600:          <li>Result is stored to one of the comments contained within the order.</li>
1601:      </ul>
1602:      * @param OrderCore $order Magento order instance to set up the data for
1603:      * @param array $data
1604:      * @param string $prefix
1605:      * @return array
1606:      */
1607:     public function setDataToOrder($order, array $data, $prefix) {
1608:         $db = Db::getInstance();
1609:         $oldOrderData = $this->getDataFromOrder($order, $prefix);
1610:         if (isset($data['comment_id'])) {
1611:             unset($data['comment_id']);
1612:         }
1613:         if (count($oldOrderData) && isset($oldOrderData['comment_id'])) {
1614:             //we have old data
1615:             $history = $db->getRow("SELECT * FROM `"._DB_PREFIX_."message` where id_message = {$db->escape($oldOrderData['comment_id'])}");
1616:             
1617:             if ($history && $history['id_message']) {
1618:                 foreach ($data as $k => $v) {
1619:                     $oldOrderData[$k] = $v;
1620:                 }
1621:                 $history['message'] = $this->_getCommentFromData($oldOrderData, $prefix);
1622:                 $db->update('message', $history, "id_message = {$db->escape($oldOrderData['comment_id'])}");
1623:                 
1624:             }
1625:             //comment id for example.....
1626:         } else {
1627:             //we do not have old data, so add new comment
1628:             //set the id also
1629:             $history = array(
1630:                 'id_order' => $order->id,
1631:                 'private' => 1,
1632:                 'id_customer' => $order->id_customer,
1633:                 'date_add' => date('Y-m-d H:i:s'),
1634:                 'message' => $db->escape($this->_getCommentFromData($data, $prefix)),
1635:             );
1636: 
1637:             $db->insert('message', $history);
1638:             $commentId = $db->Insert_ID();
1639:             
1640:             $data['comment_id'] = $commentId;
1641:             $history['message'] = $db->escape($this->_getCommentFromData($data, $prefix));
1642:             $db->update('message', $history, "id_message = {$db->escape($data['comment_id'])}");
1643:         }
1644: 
1645: 
1646: 
1647:         return $history;
1648:     }
1649:     
1650:     
1651:     
1652:     protected function _getCommentFromData($data, $prefix) {
1653:         return $prefix ."\n". chunk_split(base64_encode(gzcompress(json_encode($data))), 40, "\n");
1654:     }
1655:     
1656:     protected function _getFromComment($comment, $prefix) {
1657:         return str_replace($prefix, '', str_replace("\n", '', $comment));
1658:     }
1659: 
1660: 
1661:     
1662:     protected function _commentContainsValidData($comment, $prefix) {
1663:         //TODO: refactor to something better
1664:         return strpos($comment, $prefix) === 0 && strlen($comment) > strlen($prefix);
1665:     }
1666: 
1667: 
1668:     
1669:     /**
1670:      * <p>Returns new or cached class instance by prestashop module name and helper name</p>
1671:      * <p>How to build helper class?</p>
1672:      * <ul>
1673:          <li>Create PHP file with name $name.php</li>
1674:          <li>Give it class name asi $prefix_$name</li>
1675:          <li>Place given file in the modules root folder</li>
1676:      </ul>
1677:      * @param string $name requested helper name
1678:      * @param type $prefix PrestaShop  module name, where helper should belong.
1679:      * @return false|mixed  false, when helper could not be found. Class instance otherwise.
1680:      */
1681:     public function helper($name, $prefix) {
1682:         //check if instance exists
1683:         //auto load class
1684: 
1685:         if (!isset(self::$_helpers[$name])) {
1686:             $helper = false;
1687:             if (file_exists(_PS_MODULE_DIR_ . $prefix . '/' . $name . '.php')) {
1688:                 require_once(_PS_MODULE_DIR_ . $prefix . '/' . $name . '.php');
1689:                 $executorClass = $prefix . '_' . $name;
1690: 
1691:                 //if after require class does not exist, then exit
1692:                 if (!class_exists($executorClass, false)) {
1693:                     exit('Class could not be loaded');
1694:                 }
1695: 
1696:                 $helper = new $executorClass();
1697:             }
1698:             self::$_helpers[$name] = $helper;
1699:         }
1700: 
1701:         return self::$_helpers[$name];
1702:     }
1703:     
1704:     
1705:     /* module upgrades */
1706:     /**
1707:      * <ul>
1708:          <li>Registers hook <code>displayOrderDetail</code> - for displaying selected pickup point on the order at the customer side</li>
1709:          <li>Registers hook with name <code>displayPDFInvoice</code> - for displaying selected pickup point on the PDF invoice</li>
1710:      </ul>
1711:      * @return bool
1712:      */
1713:     public function upgrade_module_0_6() {
1714:         //register hook for displaying selected carrier detail on orders and invoices
1715:         $this->registerHook('displayOrderDetail');
1716:         $this->registerHook('displayPDFInvoice');
1717:         return true;
1718:     }
1719: 
1720: }
1721: 
1722: 
API documentation generated by ApiGen 2.8.0