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:  *
  6:  * NOTICE OF LICENSE
  7:  *
  8:  * This source file is subject to the Open Software License (OSL 3.0)
  9:  * or OpenGPL v3 license (GNU Public License V3.0)
 10:  * that is bundled with this package in the file LICENSE.txt.
 11:  * It is also available through the world-wide-web at this URL:
 12:  * http://opensource.org/licenses/osl-3.0.php
 13:  * or
 14:  * http://www.gnu.org/licenses/gpl-3.0.txt
 15:  * If you did not receive a copy of the license and are unable to
 16:  * obtain it through the world-wide-web, please send an email
 17:  * to info@e-abi.ee so we can send you a copy immediately.
 18:  *
 19:  * DISCLAIMER
 20:  *
 21:  * Do not edit or add to this file if you wish to upgrade this module to newer
 22:  * versions in the future.
 23:  *
 24:  * @category   Eabi
 25:  * @package    Eabi_Dpd
 26:  * @copyright  Copyright (c) 2014 Aktsiamaailm LLC (http://en.e-abi.ee/)
 27:  * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 28:  * @license    http://www.gnu.org/licenses/gpl-3.0.txt  GNU Public License V3.0
 29:  * @author     Matis Halmann
 30:  * 
 31: 
 32:  */
 33: if (!defined('_PS_VERSION_')) {
 34:     exit;
 35: }
 36: 
 37: if (!class_exists('eabi_dpd_courier', false)) {
 38:     Module::getInstanceByName('eabi_dpd_courier');
 39: }
 40: 
 41: 
 42: /**
 43:  * <p>Handles automatic data sending functions between PrestaShop order and DPD api</p>
 44:  * <p>Performs following:</p>
 45:  * <ul>
 46:      <li>Adds extra fields to current shipping method configuration with appropriate validator rules.</li>
 47:      <li>Sends data to DPD parcel terminal (op=order)</li>
 48:      <li>Fetches PDF packing slip for the carrier</li>
 49:  </ul>
 50:  *
 51:  * @author Matis
 52:  */
 53: class eabi_dpd_parcelstore_data_send_executor {
 54:     /**
 55:      * If order comment starts with prefix marked here and is not visible on the frontend, then it is considered as extra data order comment.
 56:      */
 57:     const ORDER_COMMENT_START_PREFIX = '-----EABI_DPDEE-----';
 58:     
 59:     /**
 60:      * <p>Shipping method code where current executor runs in</p>
 61:      * @var string
 62:      */
 63:     protected $_code;
 64:     
 65:     /**
 66:      * <p>Configuration prefix for the current executor</p>
 67:      * @var string 
 68:      */
 69:     protected $_configPrefix;
 70:     
 71:     /**
 72:      * <p>Carrier method instance</p>
 73:      * @var eabi_dpd_parcelstore
 74:      */
 75:     protected $_baseInstance;
 76:     
 77:     /**
 78:      * <p>Makes sure that extra info displayed for a maximum of 1 time</p>
 79:      * @var bool
 80:      */
 81:     protected static $_infoByCartDisplayed;
 82:     
 83:     /**
 84:      * <p>If current executor has configuration form, then fields are store here</p>
 85:      * @var array 
 86:      */
 87:     protected $form_fields = array();
 88:     
 89:     protected static $_paymentConfirmRun = false;
 90:     
 91:     
 92:     
 93:     
 94: 
 95:     /**
 96:      * <p>Carrier method instance for this data send executor</p>
 97:      * @param eabi_dpd_parcelstore $baseInstance
 98:      */
 99:     public function __construct($baseInstance) {
100:         $this->_baseInstance = $baseInstance;
101:         $this->_code = $this->_baseInstance->name;
102:         $this->_configPrefix = constant(get_class($this->_baseInstance).'::CONST_PREFIX');
103:         
104:     }
105:     
106:     /**
107:      * <p>Adds ability to change Shipping method configuration prefix after construction</p>
108:      * @param type $configPrefix
109:      * @return eabi_dpd_parcelstore_data_send_executor
110:      */
111:     public function setConfigPrefix($configPrefix) {
112:         $this->_configPrefix = $configPrefix;
113:         return $this;
114:     }
115:     
116:     /**
117:      * <p>Returns always true</p>
118:      * @return boolean
119:      */
120:     public function install() {
121:         return true;
122:     }
123: 
124:     /**
125:      * <p>Returns always true</p>
126:      * @return boolean
127:      */
128:     public function uninstall() {
129:         return true;
130:     }
131:     
132:     /**
133:      * <p>Returns always true</p>
134:      * @return boolean
135:      */
136:     public function _postProcess() {
137:         return true;
138:     }
139:     
140:     /**
141:      * <p>Does nothing, was included because earlier versions had postValidation in here.</p>
142:      * @return boolean
143:      */
144:     public function _postValidation(&$postErrors) {
145:         
146:     }
147:     
148:     /**
149:      * <p>Here is displayed extra info (if any) is related to the executor.</p>
150:      * @param type $cart_id
151:      * @return string
152:      */
153:     public function displayInfoByCart($cart_id) {
154:         $data = '';
155:         if (is_null(self::$_infoByCartDisplayed)) {
156:             //TODO handle data display here, make sure it is displayed only once...
157:             /* @var $order OrderCore */
158:             $order = new Order(Order::getOrderByCartId($cart_id));
159:             $orderData = $this->getDataFromOrder($order);
160: //            echo '<pre>'.htmlspecialchars(print_r($order, true)).'</pre>';
161:             if (isset($orderData['Parcel_numbers'])) {
162:                 $data .= '<div class="eabi_dpd_parcelstore_track">';
163:                 foreach ($orderData['Parcel_numbers'] as $trackingNumber) {
164:                     $data .= '<p><a target="_blank" href="'.htmlspecialchars(str_replace('@', $trackingNumber, eabi_dpd_parcelstore::TRACKING_URL)).'">'.  htmlspecialchars(sprintf($this->l('Track shipment: %s'), $trackingNumber)).'</a></p>';
165:                 }
166:                 $data .= '</div>';
167:             }
168:             
169:             self::$_infoByCartDisplayed = TRUE;
170:             
171:         }
172:         return $data;
173:         
174:     }
175:     
176:     /**
177:      * <p>At the moment, when order is marked as paid, data is sent to remote server.</p>
178:      * <p>This Prestashop hook <code>paymentConfirm</code> uses following parameters:</p>
179:      * <ul>
180:          <li><code>id_order</code> - id of the order, which is being currently marked as paid.</li>
181:      </ul>
182:      * <p>Data is sent when <code>SENDDATA_ENABLE</code> is valued as <code>yes</code> and data has not already been sent previously</p>
183:      * <p>Data is sent separately for each order address.</p>
184:      * <p>If no exceptions occur then information about data sending is added to order comments</p>
185:      * <p>If exceptions occur, then exceptions are added to order comments</p>
186:      * <p>Order comments are not visible in the frontend.</p>
187:      * 
188:      * @param array $params
189:      * @return bool
190:      */
191:     public function hookpaymentConfirm(&$params) {
192:         if (self::$_paymentConfirmRun) {
193:             //avoid running twice in same request
194:             return;
195:         }
196:         $order = new Order($params['id_order']);
197:         if ($this->_baseInstance->getConfigData('SENDDATA_ENABLE') != 'yes') {
198:             return;
199:         }
200:         
201:         /* @var $order OrderCore */
202:         $order = new Order($params['id_order']);
203:         if (!Validate::isLoadedObject($order)) {
204:             return;
205:         }
206:         //check if carrier matches
207:         /* @var $carrier CarrierCore */
208:         $carrier = new Carrier($order->id_carrier);
209:         if (!Validate::isLoadedObject($carrier)) {
210:             return;
211:         }
212:         
213:         //run this hook only if order carrier matches baseinstance name
214:         if ($this->_baseInstance->name != $carrier->name) {
215:             return;
216:         }
217:         
218:         if (!in_array($carrier->name, array(eabi_dpd_parcelstore::NAME, eabi_dpd_courier::NAME))) {
219:             return;
220:         }
221:         
222:         //check if data is already sent
223:         if ($this->isDataSent($order)) {
224:             return;
225:         }
226:         
227:         //data is not sent, find selected parcel terminal
228:         $selectedParcelTerminals = $this->_baseInstance->_getHelperModule()->getOfficesFromCart($order->id_cart);
229:         
230:         $forceCod = isset($params['is_eabi_dpd_cod'])? (bool) $params['is_eabi_dpd_cod'] : false;
231:         
232:         foreach ($selectedParcelTerminals as $addressId => $selectedParcelTerminal) {
233:             try {
234:                 $autoSendResult = $this->autoSendData($order, new Address($addressId), $selectedParcelTerminal, $forceCod);
235:                 //success
236:                 $this->_addOrderComment($order->id, $order->id_customer, sprintf($this->_baseInstance->ls('Parcel data sent to server, barcode: %s'), $autoSendResult['barcode']));
237:                 
238:             } catch (Exception $ex) {
239:                 //failure
240:                 $this->_addOrderComment($order->id, $order->id_customer, $this->_baseInstance->ls('Parcel data send to server failed: ').$ex->getMessage());
241: 
242:             }
243:         }
244:         self::$_paymentConfirmRun = true;
245:         
246:         
247:     }
248:     
249:     /**
250:      * <p>Returns Packing slip PDF file, which can be echoed to browser for current order if one exists.</p>
251:      * @param OrderCore $order
252:      * @return string
253:      */
254:     public function getBarcodePdf($order) {
255:         $orderData = $this->getDataFromOrder($order);
256:         if (isset($orderData['PDF_URL']) && $orderData['PDF_URL']) {
257:             return file_get_contents(urldecode($orderData['PDF_URL']));
258:         }
259:     }
260:     
261:     
262:     /**
263:      * <p>Returns packing slip URL if data is sent or false otherwise.</p>
264:      * @param OrderCore $order
265:      * @return boolean|string
266:      */
267:     public function getBarcode($order) {
268:         $orderData = $this->getDataFromOrder($order);
269:         if (isset($orderData['PDF_URL']) && $orderData['PDF_URL']) {
270:             return $orderData['PDF_URL'];
271:         }
272:         return false;
273:     }
274:     
275:     
276:     /**
277:      * <p>Returns number or parcels for the order according to Maximum Package Weight defined in DPD settings</p>
278:      * @param OrderCore $order
279:      * @return int
280:      */
281:     protected function _getNumberOfPackagesForOrder($order) {
282:         $productWeights = array();
283:         $orderItems = $order->getProducts();
284:         foreach ($orderItems as $orderItem) {
285:             /* @var $orderItem Mage_Sales_Model_Order_Item */
286:             for ($i = 0; $i < ($orderItem['product_quantity'] - $orderItem['product_quantity_refunded']); $i++) {
287:                 $productWeights[] = $orderItem['product_weight'];
288:             }
289:             
290:         }
291:         return $this->_getDpdHelper()->getNumberOfPackagesFromItemWeights($productWeights, $this->_baseInstance->getConfigData('MAX_PACKAGE_WEIGHT'));
292:     }
293:     
294:     
295:     /**
296:      * <p>Adds comment for the order</p>
297:      * @param int $id_order
298:      * @param int $id_customer
299:      * @param string $message
300:      * @return null
301:      */
302:     protected function _addOrderComment($id_order, $id_customer, $message) {
303:         $db = Db::getInstance();
304:         
305:         return $db->insert('message', array(
306:             'id_order' => $id_order,
307:             'message' => $db->escape($message),
308:             'private' => 1,
309:             'id_customer' => $id_customer,
310:             'date_add' => date('Y-m-d H:i:s'),
311:         ));
312:         
313:     }
314:     
315:     
316:     /**
317:      * <p>Returns true if parcel data is sent to DPD server for specified order.</p>
318:      * @param OrderCore $order
319:      * @return boolean
320:      */
321:     public function isDataSent($order) {
322:         $orderData = $this->getDataFromOrder($order);
323:         if (isset($orderData['DPD_OrderID'])) {
324:             return true;
325:         }
326:         return false;
327:     }
328:     
329:     
330:     
331:     
332:     /**
333:      * 
334:      * @return eabi_postoffice_dialcode_helper
335:      */
336:     protected function _getDialCodeHelper() {
337:         return $this->_baseInstance->_getHelperModule()->helper('dialcode_helper', 'eabi_postoffice');
338:     }
339:     
340:     
341:     
342:     /**
343:      * <p>Sends parcel data to DPD server for specified order and selected parcel terminal id.</p>
344:      * @param OrderCore $order
345:      * @param AddressCore $address
346:      * @param int $selectedOfficeId
347:      * @param bool $forceCod true, if request should be forced to cash on delivery request
348:      * @return array comma separated parcel numbers in array key of 'barcode'
349:      */
350:     public function autoSendData($order, $address, $selectedOfficeId, $forceCod = false) {
351:         
352:         
353:         
354:         $requestResult = $this->_getDpdHelper()->getApi(Context::getContext()->shop->id, $this->_configPrefix)
355:                 ->autoSendData($this->_baseInstance->getRequestForAutoSendData($order, $address, $selectedOfficeId, $forceCod));
356:         
357:         $this->setDataToOrder($order, $requestResult);
358:         
359:         $db = Db::getInstance();
360:         $db->update('orders', array('shipping_number' => $db->escape(implode('', $requestResult['Parcel_numbers']))), 'id_order = '.$db->escape($order->id));
361:         $db->update('order_carrier', array('tracking_number' => $db->escape(implode('', $requestResult['Parcel_numbers']))), 'id_order = '.$db->escape($order->id));
362:         
363: //        $this->_addOrderComment($order->id, $order->id_customer, sprintf($this->_baseInstance->ls('Response log is: %s'), print_r($this->_getDpdHelper()->getApi(Context::getContext()->shop->id, $this->_configPrefix)->getLoggedRequests(), true)));
364:         
365:         
366:         //on failure return false
367:         //is success
368:         return array('barcode' => '##'.  implode(',', $requestResult['Parcel_numbers']).'##');
369:     }
370:     
371:     
372:     /**
373:      * 
374:      * @return eabi_dpd_parcelstore_dpd_helper
375:      */
376:     protected function _getDpdHelper() {
377:         return $this->_baseInstance->_getHelperModule()->helper('dpd_helper', eabi_dpd_parcelstore::NAME);
378:     }
379:     
380:     
381:     
382:     /**
383:      * <p>Creates or returns cached instance of Admin Form Configuration fields for this instance.</p>
384:      * @return array
385:      */
386:     public function initFormFields() {
387:         if (count($this->form_fields)) {
388:             return $this->form_fields;
389:         }
390:         $yesno = array(
391:             'yes' => $this->l('Yes'),
392:             'no' => $this->l('No'),
393:         );
394:         $labelPositions = array(
395:             '1234' => sprintf($this->l('Position %s'), '1234'),
396:             '4123' => sprintf($this->l('Position %s'), '4123'),
397:             '3412' => sprintf($this->l('Position %s'), '3412'),
398:             '3421' => sprintf($this->l('Position %s'), '3421'),
399:         );
400: 
401:         $this->form_fields = array(
402:             'senddata_enable' => array(
403:                 'title' => $this->l('Auto send data to DPD server'),
404:                 'type' => 'select',
405:                 'description' => $this->l('Only if the order has been paid for or the order is COD'),
406:                 'default' => 'no',
407:                 'css' => 'width: 300px;',
408:                 'options' => $yesno,
409:             ),
410:             'courier_enable' => array(
411:                 'title' => $this->l('Allow courier pickup'),
412:                 'type' => 'select',
413:                 'description' => $this->l('Only if the order has been paid for or the order is COD'),
414:                 'default' => 'yes',
415:                 'css' => 'width: 300px;',
416:                 'options' => $yesno,
417:                 'validate-if' => array('senddata_enable' => 'yes'),
418:             ),
419:             'sendpackage_username' => array(
420:                 'title' => $this->l('DPD Self service username'),
421:                 'type' => 'text',
422:                 'description' => '',
423:                 'default' => '',
424:                 'css' => 'width: 300px;',
425:                 'validate' => array('required_entry'),
426:                 'validate-if' => array('senddata_enable' => 'yes'),
427:             ),
428:             'sendpackage_password' => array(
429:                 'title' => $this->l('DPD Self-service password'),
430:                 'type' => 'password',
431:                 'description' => '',
432:                 'default' => '',
433:                 'css' => 'width: 300px;',
434:                 'validate' => array('required_entry'),
435:                 'validate-if' => array('senddata_enable' => 'yes'),
436:             ),
437:             'http_request_timeout' => array(
438:                 'title' => $this->l('Http request timeout'),
439:                 'type' => 'text',
440:                 'description' => $this->_baseInstance->ls('If timeout is greater than 10 seconds, then parcel data can only be sent manually. This field with the limitation will be removed latest 17th of February'),
441:                 'default' => '60',
442:                 'css' => 'width: 300px;',
443:                 'validate' => array('required_entry', 'validate_digit'),
444:                 'validate-if' => array('senddata_enable' => 'yes'),
445:             ),
446:             'return_name' => array(
447:                 'title' => $this->l('Pickup address name'),
448:                 'type' => 'text',
449:                 'description' => '',
450:                 'default' => '',
451:                 'css' => 'width: 300px;',
452:                 'validate' => array('required_entry'),
453:                 'validate-if' => array('senddata_enable' => 'yes'),
454:             ),
455:             'return_company' => array(
456:                 'title' => $this->l('Pickup address company'),
457:                 'type' => 'text',
458:                 'description' => '',
459:                 'default' => '',
460:                 'css' => 'width: 300px;',
461:                 'validate' => array('required_entry'),
462:                 'validate-if' => array('senddata_enable' => 'yes'),
463:             ),
464:             'return_email' => array(
465:                 'title' => $this->l('Pickup address e-mail'),
466:                 'type' => 'text',
467:                 'description' => '',
468:                 'default' => '',
469:                 'css' => 'width: 300px;',
470:                 'validate' => array('required_entry', 'validate_email'),
471:                 'validate-if' => array('senddata_enable' => 'yes'),
472:             ),
473:             'return_phone' => array(
474:                 'title' => $this->l('Pickup address phone'),
475:                 'type' => 'text',
476:                 'description' => '',
477:                 'default' => '',
478:                 'css' => 'width: 300px;',
479:                 'validate' => array('required_entry'),
480:                 'validate-if' => array('senddata_enable' => 'yes'),
481:             ),
482:             'return_street' => array(
483:                 'title' => $this->l('Pickup address street'),
484:                 'type' => 'text',
485:                 'description' => '',
486:                 'default' => '',
487:                 'css' => 'width: 300px;',
488:                 'validate' => array('required_entry'),
489:                 'validate-if' => array('senddata_enable' => 'yes'),
490:             ),
491:             'return_citycounty' => array(
492:                 'title' => $this->l('Pickup address city, county'),
493:                 'type' => 'text',
494:                 'description' => '',
495:                 'default' => '',
496:                 'css' => 'width: 300px;',
497:                 'validate' => array('required_entry'),
498:                 'validate-if' => array('senddata_enable' => 'yes'),
499:             ),
500:             'return_postcode' => array(
501:                 'title' => $this->l('Pickup address zip code'),
502:                 'type' => 'text',
503:                 'description' => '',
504:                 'default' => '',
505:                 'css' => 'width: 300px;',
506:                 'validate' => array('required_entry'),
507:                 'validate-if' => array('senddata_enable' => 'yes'),
508:             ),
509:             'return_country' => array(
510:                 'title' => $this->l('Pickup address country'),
511:                 'type' => 'select',
512:                 'description' => '',
513:                 'default' => 'EE',
514:                 'css' => 'width: 300px;',
515:                 'options' => $this->_baseInstance->_getHelperModule()->getCountriesAsOptions(),
516:                 'validate' => array('required_entry'),
517:                 'validate-if' => array('senddata_enable' => 'yes'),
518:             ),
519:             'po_show_on_label' => array(
520:                 'title' => $this->l('Show pickup address on packing label'),
521:                 'type' => 'select',
522:                 'description' => '',
523:                 'default' => 'no',
524:                 'css' => 'width: 300px;',
525:                 'options' => $yesno,
526:                 'validate-if' => array('senddata_enable' => 'yes'),
527:             ),
528:             'label_position' => array(
529:                 'title' => $this->l('Labels position on packing slip'),
530:                 'type' => 'select',
531:                 'description' => '',
532:                 'default' => 'no',
533:                 'css' => 'width: 300px;',
534:                 'options' => $labelPositions,
535:                 'validate-if' => array('senddata_enable' => 'yes'),
536:             ),
537:             'api_url' => array(
538:                 'title' => $this->l('Api URL'),
539:                 'type' => 'text',
540:                 'description' => '<b>Live:</b> http://www.pakivedu.ee/rpc/gateway<br/><b>Test:</b> http://demo.surflink.ee:51680/rpc/gateway/',
541:                 'default' => 'http://www.pakivedu.ee/rpc/gateway',
542:                 'css' => 'width: 300px;',
543:                 'validate' => array('required_entry'),
544:                 'validate-if' => array('senddata_enable' => 'yes'),
545:             ),
546:             'enable_log' => array(
547:                 'title' => $this->l('Log API requests'),
548:                 'type' => 'select',
549:                 'description' => '',
550:                 'default' => 'no',
551:                 'css' => 'width: 300px;',
552:                 'options' => $yesno,
553:                 'validate-if' => array('senddata_enable' => 'yes'),
554:             ),
555:             
556:             /*
557:             'tt_offset' => array(
558:                 'title' => $this->l('Timestamp Offset in seconds'),
559:                 'type' => 'text',
560:                 'description' => 'Use only if using PHP5.2 and you are experiencing problems with courier call times.',
561:                 'default' => '0',
562:                 'css' => 'width: 300px;',
563:                 'validate' => array(),
564:                 'validate-if' => array(),
565:             ),
566:              * 
567:              */
568:             
569:         );
570:         return $this->form_fields;
571:         
572:     }
573:     
574:     /**
575:      * <p>Attempts to decode extra data stored within order commetns and return it as array.</p>
576:      * @param OrderCore $order
577:      * @return array
578:      */
579:     public function getDataFromOrder($order) {
580:         return $this->_baseInstance->_getHelperModule()->getDataFromOrder($order, self::ORDER_COMMENT_START_PREFIX);
581:     }
582:     
583:     /**
584:      * <p>Sets extra data to order and creates specialized order comment for it when neccessary.</p>
585:      * @param OrderCore $order
586:      * @param array $data
587:      * @return array
588:      */
589:     public function setDataToOrder($order, $data = array()) {
590:         return $this->_baseInstance->_getHelperModule()->setDataToOrder($order, $data, self::ORDER_COMMENT_START_PREFIX);
591:     }
592:     
593:     
594:     /**
595:      * <p>Wrapper for <code>$this->l()</code> (was protected in 1.4)</p>
596:      * <p>Kept for compatiblity reasons</p>
597:      * @param string $string
598:      * @return string
599:      */
600:     public function l($string) {
601:         return $this->_baseInstance->ls($string);
602:     }
603:     
604:     
605:     
606:     
607:     
608:     
609:     
610: 
611: }
612: 
613: 
API documentation generated by ApiGen 2.8.0