Nektria_ReCS - Version 1.0.1

Version Notes

First stable release

Download this release

Release Info

Developer Digio Soluciones Digitales
Extension Nektria_ReCS
Version 1.0.1
Comparing to
See all releases


Version 1.0.1

Files changed (84) hide show
  1. app/code/community/Nektria/ReCS/Block/Config.php +24 -0
  2. app/code/community/Nektria/ReCS/Block/Registration.php +54 -0
  3. app/code/community/Nektria/ReCS/Helper/Data.php +244 -0
  4. app/code/community/Nektria/ReCS/Model/Carrier.php +258 -0
  5. app/code/community/Nektria/ReCS/Model/Lastmile.php +11 -0
  6. app/code/community/Nektria/ReCS/Model/Observer.php +150 -0
  7. app/code/community/Nektria/ReCS/Model/Paymentmethods.php +9 -0
  8. app/code/community/Nektria/ReCS/Model/Resource/Lastmile.php +12 -0
  9. app/code/community/Nektria/ReCS/Model/Resource/Lastmile/Collection.php +12 -0
  10. app/code/community/Nektria/ReCS/Model/Sales/Order.php +13 -0
  11. app/code/community/Nektria/ReCS/etc/config.xml +183 -0
  12. app/code/community/Nektria/ReCS/etc/system.xml +150 -0
  13. app/code/community/Nektria/ReCS/lib/Nektria.php +537 -0
  14. app/code/community/Nektria/ReCS/lib/Nektria/.editorconfig +9 -0
  15. app/code/community/Nektria/ReCS/lib/Nektria/.gitignore +6 -0
  16. app/code/community/Nektria/ReCS/lib/Nektria/CHANGELOG.md +193 -0
  17. app/code/community/Nektria/ReCS/lib/Nektria/LICENSE.md +141 -0
  18. app/code/community/Nektria/ReCS/lib/Nektria/README.md +658 -0
  19. app/code/community/Nektria/ReCS/lib/Nektria/composer.json +43 -0
  20. app/code/community/Nektria/ReCS/lib/Nektria/src/Address.php +377 -0
  21. app/code/community/Nektria/ReCS/lib/Nektria/src/Client.php +223 -0
  22. app/code/community/Nektria/ReCS/lib/Nektria/src/Description.php +13 -0
  23. app/code/community/Nektria/ReCS/lib/Nektria/src/Exceptions/ApiClientException.php +9 -0
  24. app/code/community/Nektria/ReCS/lib/Nektria/src/Exceptions/ApiResponseException.php +34 -0
  25. app/code/community/Nektria/ReCS/lib/Nektria/src/Price.php +26 -0
  26. app/code/community/Nektria/ReCS/lib/Nektria/src/Product.php +289 -0
  27. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/BackendAccessRequest.php +35 -0
  28. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/BaseRequest.php +127 -0
  29. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/ClassicAvailabilityRequest.php +53 -0
  30. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/ClassicConfirmationRequest.php +28 -0
  31. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/CoverageRequest.php +23 -0
  32. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/KeepAliveRequest.php +38 -0
  33. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/LastMileAvailabilityRequest.php +76 -0
  34. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/LastMileBestPriceRequest.php +38 -0
  35. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/LastMileConfirmationRequest.php +36 -0
  36. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/LastMileValidationRequest.php +37 -0
  37. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/RegistrationAccessRequest.php +44 -0
  38. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/ServiceCreationRequest.php +33 -0
  39. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/ShowShippingRequest.php +36 -0
  40. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/TestRequest.php +21 -0
  41. app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/getAssetsRequest.php +38 -0
  42. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/BackendAccessResponse.php +33 -0
  43. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/BaseResponse.php +24 -0
  44. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/ClassicAvailabilityResponse.php +52 -0
  45. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/ClassicConfirmationResponse.php +32 -0
  46. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/CoverageResponse.php +14 -0
  47. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/LastMileAvailabilityResponse.php +164 -0
  48. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/LastMileBestPriceResponse.php +38 -0
  49. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/LastMileConfirmationResponse.php +37 -0
  50. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/NullResponse.php +8 -0
  51. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/RegistrationAccessResponse.php +33 -0
  52. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/ResponseBodyWrapper.php +76 -0
  53. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/ServiceCreationResponse.php +56 -0
  54. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/ShowShippingResponse.php +116 -0
  55. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/TransitAvailabilityResponse.php +8 -0
  56. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/TransitConfirmationResponse.php +8 -0
  57. app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/getAssetsResponse.php +45 -0
  58. app/code/community/Nektria/ReCS/lib/Nektria/src/ShowShippingHelper.php +63 -0
  59. app/code/community/Nektria/ReCS/lib/Nektria/src/TimeWindow.php +59 -0
  60. app/code/community/Nektria/ReCS/lib/Nektria/src/TimeWindowPrice.php +42 -0
  61. app/code/community/Nektria/ReCS/lib/Nektria/src/services/services.json +262 -0
  62. app/code/community/Nektria/ReCS/lib/Nektria/test.php +210 -0
  63. app/code/community/Nektria/ReCS/sql/nektria_recs_setup/install-1.0.0.php +36 -0
  64. app/code/community/Nektria/ReCS/sql/nektria_recs_setup/install-1.0.1.php +45 -0
  65. app/design/adminhtml/default/default/layout/recs.xml +43 -0
  66. app/design/adminhtml/default/default/template/recs/sales/order/creditmemo/create/form.phtml +92 -0
  67. app/design/adminhtml/default/default/template/recs/sales/order/creditmemo/view/form.phtml +101 -0
  68. app/design/adminhtml/default/default/template/recs/sales/order/invoice/create/form.phtml +123 -0
  69. app/design/adminhtml/default/default/template/recs/sales/order/invoice/view/form.phtml +97 -0
  70. app/design/adminhtml/default/default/template/recs/sales/order/shipment/create/form.phtml +117 -0
  71. app/design/adminhtml/default/default/template/recs/sales/order/shipment/view/form.phtml +122 -0
  72. app/design/adminhtml/default/default/template/recs/sales/order/view/info.phtml +139 -0
  73. app/design/adminhtml/default/default/template/recs/sales/order/view/lastmile.phtml +42 -0
  74. app/design/frontend/base/default/layout/recs.xml +94 -0
  75. app/design/frontend/base/default/template/recs/email/lastmile.phtml +38 -0
  76. app/design/frontend/base/default/template/recs/progress/shipping_method.phtml +64 -0
  77. app/design/frontend/base/default/template/recs/shipping_method/available.phtml +293 -0
  78. app/design/frontend/base/default/template/recs/totals/gomage.phtml +62 -0
  79. app/design/frontend/base/default/template/recs/totals/lastmile.phtml +43 -0
  80. app/design/frontend/base/default/template/recs/totals/onepage.phtml +62 -0
  81. app/design/frontend/base/default/template/recs/totals/success.phtml +58 -0
  82. app/etc/modules/Nektria_ReCS.xml +12 -0
  83. app/locale/es_ES/Nektria_Translations.csv +17 -0
  84. package.xml +26 -0
app/code/community/Nektria/ReCS/Block/Config.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once (Mage::getModuleDir('', 'Nektria_ReCS') . DS . 'lib' . DS .'Nektria.php');
4
+
5
+ class Nektria_Recs_Block_Config extends Mage_Adminhtml_Block_System_Config_Form_Field
6
+ {
7
+
8
+ /**
9
+ * Returns html part of the setting
10
+ *
11
+ * @param Varien_Data_Form_Element_Abstract $element
12
+ * @return string
13
+ */
14
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
15
+ {
16
+ $this->setElement($element);
17
+ $recs = new NektriaSdk();
18
+
19
+ $url = $recs->getBackendUrl();
20
+
21
+ $html = '<input onclick="window.open(\''.$url.'\', \'\', \'location=no,menubar=no,toolbar=no,width=600,height=400\');" type="button" value="'.$this->__('Nektria Configuration').'" class="button" />';
22
+ return $html;
23
+ }
24
+ }
app/code/community/Nektria/ReCS/Block/Registration.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once (Mage::getModuleDir('', 'Nektria_ReCS') . DS . 'lib' . DS .'Nektria.php');
4
+
5
+ class Nektria_Recs_Block_Registration extends Mage_Adminhtml_Block_System_Config_Form_Field
6
+ {
7
+
8
+ /**
9
+ * Returns html part of the setting
10
+ *
11
+ * @param Varien_Data_Form_Element_Abstract $element
12
+ * @return string
13
+ */
14
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
15
+ {
16
+ $this->setElement($element);
17
+ $recs = new NektriaSdk();
18
+
19
+ $url = $recs->getRegistrationUrl();
20
+ $nektria_signup = $this->__('Nektria Signup');
21
+ $html = <<<EOT
22
+ <script type="text/javascript">
23
+ function nektria_registration_onload(){
24
+ $.noConflict();
25
+ jQuery("#carriers_nektria_recs_apikey").change(function(){
26
+ if (this.value != ''){
27
+ jQuery("#row_carriers_nektria_recs_registration").hide();
28
+ }else{
29
+ jQuery("#row_carriers_nektria_recs_registration").show();
30
+ }
31
+ });
32
+
33
+ if(jQuery("#carriers_nektria_recs_apikey").val()!=''){
34
+ jQuery("#row_carriers_nektria_recs_registration").hide();
35
+ }
36
+ }
37
+
38
+ if(typeof(jQuery)== "undefined"){
39
+ var script = document.createElement("script");
40
+ script.src = "https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js";
41
+ script.onload = nektria_registration_onload;
42
+ document.getElementsByTagName('head')[0].appendChild(script);
43
+ }else{
44
+ jQuery(document).ready(nektria_registration_onload);
45
+ }
46
+
47
+
48
+ </script>
49
+ <input onclick="window.open('$url', '', 'location=no,menubar=no,toolbar=no,width=600,height=400');" type="button" value="$nektria_signup" class="button" />
50
+ EOT;
51
+
52
+ return $html;
53
+ }
54
+ }
app/code/community/Nektria/ReCS/Helper/Data.php ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Nektria_ReCS_Helper_Data extends Mage_Core_Helper_Abstract
3
+ {
4
+ const CONFIG_KEY = 'carriers/nektria_recs';
5
+ const CARRIER = 'nektria_recs';
6
+ const ASSETS_VERSION = 1;
7
+ const CONNECT_TIMEOUT = 1.5;
8
+ const TIMEOUT = 2;
9
+
10
+ /**
11
+ * Return checkout config value by key and store
12
+ *
13
+ * @param string $key
14
+ * @return variant|null
15
+ */
16
+ public function getConfig($key='', $store = null)
17
+ {
18
+ if( !isset ( $this->_configs) ){
19
+ $this->_configs = Mage::getStoreConfig(self::CONFIG_KEY, $store);
20
+ }
21
+ return (isset($this->_configs[$key])?$this->_configs[$key] : NULL );
22
+ }
23
+
24
+ public function getReCSMethods(){
25
+ return array(
26
+ 'lastmile' => $this->__('RECS: elige día y hora'),
27
+ 'classic' => $this->__('RECS: Servicio Estándar')
28
+ );
29
+ }
30
+
31
+ /**
32
+ * Get configured parameters of the service from backend
33
+ * @param array $params of configuration
34
+ * @return array Merged params with defaults
35
+ */
36
+ public function getServiceParams($params){
37
+ return array_merge( array(
38
+ 'APIKEY' => self::getConfig('apikey'),
39
+ 'environment'=>(self::getConfig('sandbox'))?'sandbox':'production',
40
+ //'secure'=>(self::getConfig('sandbox'))?FALSE : TRUE,
41
+ 'timeout' => self::TIMEOUT,
42
+ 'connect_timeout' => self::CONNECT_TIMEOUT
43
+ ), $params );
44
+ }
45
+
46
+ /**
47
+ * Get carrier name
48
+ * @return string
49
+ */
50
+ public function getCode(){
51
+ return self::CARRIER;
52
+ }
53
+
54
+ /**
55
+ * Get the number of assets version
56
+ * @return int the version
57
+ */
58
+ public function getAssetsVersion(){
59
+ return self::ASSETS_VERSION;
60
+ }
61
+
62
+ /**
63
+ * Get if the extension is active and get an apikey from config
64
+ * @return bool
65
+ */
66
+ public function getEnabled(){
67
+ return (Mage::helper('nektria')->getConfig('active') && ! is_null(Mage::helper('nektria')->getConfig('apikey')) );
68
+ }
69
+
70
+ /**
71
+ * Get if LightCheckout is installed and enabled
72
+ * @return bool
73
+ */
74
+ public function getGomageLightCheckoutEnabled(){
75
+ return Mage::getStoreConfig('gomage_checkout/general/enabled');
76
+ }
77
+
78
+ /**
79
+ * Get the last timeWindow selection for Last Mile used in template view
80
+ * @return JSON Stringify
81
+ */
82
+ public function getLastSelection(){
83
+ return Mage::getSingleton('checkout/session')->getNektriaUserSelection(FALSE);
84
+ }
85
+
86
+ /**
87
+ * Get if nektria last mile shipping method is selected
88
+ * @return bool
89
+ */
90
+ public function getLastMileSelected(){
91
+ $shipping_method = self::getShippingMethod();
92
+
93
+ //Switch with method type
94
+ if ($shipping_method == 'nektria_recs_lastmile'){
95
+ return TRUE;
96
+ }else{
97
+ return FALSE;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Returns the last Mile selected Price
103
+ * @return string price with currency code
104
+ */
105
+ public function getLastMileSelectedPrice(){
106
+ if ( self::getLastMileSelected() ){
107
+ $selectedPrice = Mage::helper('core')->jsonDecode(self::getLastSelection());
108
+ return Mage::helper('core')->currency( $selectedPrice['total_price'] );
109
+ }else{
110
+ return '';
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Get the selected shipping method
116
+ * @return bool
117
+ */
118
+ public function getShippingMethod(){
119
+ $quote = $checkout = Mage::getSingleton('checkout/session')->getQuote();
120
+ $address = $quote->getShippingAddress();
121
+ return $address->getShippingMethod();
122
+ }
123
+
124
+ /**
125
+ * Get the selected payment method
126
+ * @return string code of the method
127
+ */
128
+ public function getPaymentMethod(){
129
+ $quote = $checkout = Mage::getSingleton('checkout/session')->getQuote();
130
+ return $quote->getPayment()->getMethodInstance()->getCode();
131
+ }
132
+
133
+ /**
134
+ * Get direct payment methods from magento usetting offline methods
135
+ * @return array of payment methods
136
+ */
137
+ public function getDirectPaymentMethods(){
138
+ $methods = Mage::helper('payment')->getPaymentMethodList(TRUE, TRUE, TRUE);
139
+ unset($methods['offline']);
140
+ return $methods;
141
+ }
142
+
143
+ /**
144
+ * Returns the list of offline payment methods names
145
+ * @return array of names
146
+ */
147
+ public function getOfflinePaymentMethods(){
148
+ $methods = Mage::helper('payment')->getPaymentMethodList(TRUE, TRUE, TRUE);
149
+ $methods = array_keys( $methods['offline']['value'] );
150
+
151
+ return $methods;
152
+ }
153
+
154
+ /**
155
+ * Get backend disabled by the admin payment methods
156
+ * @return array
157
+ */
158
+ public function getDisabledPaymentMethods(){
159
+ $paymentsallow = self::getConfig('paymentsallow');
160
+ //convert variable to array
161
+ $paymentsallow = ($paymentsallow)?explode( ',', $paymentsallow ) : array();
162
+
163
+ //returns selected direct payment methods and all offline payment methods
164
+ return array_merge( $paymentsallow, self::getOfflinePaymentMethods() );
165
+ }
166
+
167
+ /**
168
+ * Check if the payment method selected allow Nektria Last Mile
169
+ * @param string $method Payment method
170
+ * @return bool if allow this method for last mile
171
+ */
172
+ public function checkAllowPaymentMethod($method){
173
+ //Todo: remove this to check allow methods
174
+ return TRUE;
175
+ if ( in_array( $method, self::getDisabledPaymentMethods() ) ){
176
+ return FALSE;
177
+ }else{
178
+ return TRUE;
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Write html template with the Last Mile Selection
184
+ * @return string html
185
+ */
186
+ public function htmlLastMileSelection(){
187
+ $template = Mage::app()->getLayout()->createBlock('core/template')
188
+ ->setTemplate('recs/totals/lastmile.phtml');
189
+ return $template->toHtml();
190
+ }
191
+
192
+ /**
193
+ * Write html template with the Last Mile Selection
194
+ * @return string html
195
+ */
196
+ public function htmlAdminLastMileSelection($order){
197
+ $template = Mage::app()->getLayout()->createBlock('core/template')
198
+ ->setData('order', $order)
199
+ ->setTemplate('recs/sales/order/view/lastmile.phtml');
200
+ return $template->toHtml();
201
+ }
202
+
203
+ /**
204
+ * Helper function for translations
205
+ * @param string $string Traslate to string
206
+ * @return string translation
207
+ */
208
+ public function _($string){
209
+ return self::__($string);
210
+ }
211
+
212
+ /**
213
+ * Returns the session timeout in seconds
214
+ * @param int store id
215
+ * @return int seconds
216
+ */
217
+ public function getSessionTimeout($store = NULL){
218
+ return Mage::getStoreConfig( 'web/cookie/cookie_lifetime' , $store);
219
+
220
+ }
221
+
222
+ /**
223
+ * Log into file var exporting
224
+ * @param var $object
225
+ * @param string $title The title of the log section
226
+ * @param string $file the name of the log file
227
+ * @return void
228
+ */
229
+ public function log($object, $title = NULL, $file = NULL){
230
+ if ($title){
231
+ Mage::log('----------------------'.$title.'--------------------------', null, $file);
232
+ }
233
+ Mage::log(var_export($object, TRUE), null, $file);
234
+ }
235
+
236
+ /**
237
+ * Gets the currency symbol associated to a Currency Code
238
+ * @return string currency symbol
239
+ */
240
+ public function getCurrencySymbol(){
241
+ $currency_code = Mage::app()->getStore()->getCurrentCurrencyCode();
242
+ return Mage::app()->getLocale()->currency( $currency_code )->getSymbol();
243
+ }
244
+ }
app/code/community/Nektria/ReCS/Model/Carrier.php ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once (Mage::getModuleDir('', 'Nektria_ReCS') . DS . 'lib' . DS .'Nektria.php');
4
+
5
+ class Nektria_ReCS_Model_Carrier extends Mage_Shipping_Model_Carrier_Abstract implements Mage_Shipping_Model_Carrier_Interface {
6
+ protected $logfile = 'shipping_nektria.log';
7
+ protected $apikey;
8
+
9
+ public function collectRates(Mage_Shipping_Model_Rate_Request $request) {
10
+ //check if carrier is enabled
11
+ if (! Mage::helper('nektria')->getEnabled() ) {
12
+ return FALSE;
13
+ }
14
+
15
+ //if it's called before returns cached
16
+ if (isset($GLOBALS['lastCollectRates'])){
17
+ return $GLOBALS['lastCollectRates'];
18
+ }
19
+
20
+ $this->apikey = Mage::helper('nektria')->getConfig('apikey');
21
+ $this->log($this->apikey, 'apikey');
22
+
23
+ $result = Mage::getModel('shipping/rate_result');
24
+
25
+ //Check availability
26
+
27
+ //Preparing the products array
28
+ $products = array();
29
+
30
+ $cart = Mage::getModel('checkout/cart')->getQuote();
31
+
32
+ foreach ($cart->getAllVisibleItems() as $item) {
33
+ $producto = array (
34
+ "name" => $item->getProduct()->getName(),
35
+ "reference" => $item->getProduct()->getSku(),
36
+ "quantity" => $item->getQty(),
37
+ "weight_kg" => $item->getProduct()->getWeight()
38
+ );
39
+ $products[] = $producto;
40
+ }
41
+
42
+ $this->log($products, 'Product list for Nektria');
43
+
44
+ //Preparing shipping address data from Magento
45
+ $checkout = Mage::getSingleton('checkout/session')->getQuote();
46
+
47
+ $shippingAddress = array (
48
+ "postal_code" => $checkout->getShippingAddress()->getPostcode(),
49
+ "street_type" => "",
50
+ "street_name" => $checkout->getShippingAddress()->getStreet(1),
51
+ "street_number" => $checkout->getShippingAddress()->getStreet(2),
52
+ "city" => $checkout->getShippingAddress()->getCity(),
53
+ "country_code" => $checkout->getShippingAddress()->getCountry()
54
+ );
55
+
56
+ $this->log($shippingAddress, 'Shipping Address sent to Nektria');
57
+
58
+ //Preparing buyer data
59
+ //If it's a registered user get user data
60
+ if (Mage::getSingleton('customer/session')->isLoggedIn()) {
61
+ $customer = Mage::getSingleton('customer/session')->getCustomer();
62
+
63
+ $user = array (
64
+ "name" => $customer->getFirstname(),
65
+ "surname" => $customer->getLastname(),
66
+ "email" => $customer->getEmail(),
67
+ "phone" => $checkout->getBillingAddress()->getTelephone()
68
+ );
69
+
70
+ $this->log($user, 'User data sent to Nektria');
71
+ }
72
+
73
+ //On the other hand, get user data from billing input
74
+ else {
75
+ $user = array (
76
+ "name" => $checkout->getBillingAddress()->getFirstname(),
77
+ "surname" => $checkout->getBillingAddress()->getLastname(),
78
+ "email" => $checkout->getBillingAddress()->getEmail(),
79
+ "phone" => $checkout->getBillingAddress()->getTelephone()
80
+ );
81
+ $this->log($user, 'User data for Nektria');
82
+ }
83
+
84
+ $recs = new NektriaSdk();
85
+
86
+ //If the country is not available for Nektria, returns empty array
87
+ if (! $recs->checkCoveredCountry($shippingAddress['country_code']) ){
88
+ return array();
89
+ }
90
+
91
+ //check Nektria Country availability
92
+ $recs->getCoveredCountries();
93
+
94
+ $serviceId = $recs->getServiceId();
95
+ $service_type = $recs->getServiceType();
96
+ $lastPostalCode = $recs->getLastPostalCode();
97
+
98
+ $this->log($serviceId,'The service ID');
99
+ $this->log($service_type,'The service type');
100
+ $this->log($lastPostalCode,'The lastPostalCode');
101
+
102
+ $serviceParams = array(
103
+ 'services' => ['last-mile', 'classic'],
104
+ 'shopper' => $user,
105
+ 'destination_address' => $shippingAddress,
106
+ 'products' => $products
107
+ );
108
+
109
+ //check if we have a serviceId, and postal Code and Country code
110
+ //hasn't been changed in other case renew serviceId
111
+ if ($serviceId && ($lastPostalCode===$shippingAddress['postal_code']) && ($recs->getLastCountryCode() === $shippingAddress['country_code'])){
112
+ $this->log(FALSE, 'Inside to KeepAliveRequest');
113
+
114
+ $working_service = $recs->keepAlive();
115
+
116
+ if ( ! $working_service && $recs->getLastError()->getCode()==400){
117
+ //If we have problems with keepAlive, and serviceId is timeout renew serviceId
118
+ $working_service = $recs->createService( $serviceParams );
119
+ //set Error if costumer doesn't refresh shipping
120
+ $recs->validateSecurity(TRUE);
121
+ }
122
+ }else{
123
+ $this->log(FALSE, 'No session serviceID, create service');
124
+
125
+ //cleans recs session cache
126
+ $recs->clean();
127
+ //create a new service
128
+ $working_service = $recs->createService( $serviceParams );
129
+ }
130
+
131
+ //checks first if the nektria service is working in serviceCreation and serviceType after
132
+ $this->log($working_service, 'Working Service' );
133
+ $currency_code = Mage::app()->getStore()->getCurrentCurrencyCode();
134
+
135
+ if ($working_service && $shippingAddress['postal_code']==''){
136
+ //If it's first call and only have country, and no postal code then lastmile by default
137
+ $response = $recs->lastMileBestPriceRequest(array(
138
+ 'destination_address' => $shippingAddress,
139
+ 'products' => $products
140
+ ));
141
+ if ($currency_code === $response['currency_code']){
142
+ $result->append($this->_getLastMile($response['best_price']));
143
+ }
144
+ }else{
145
+ //if web get postal code, then normal process
146
+ if ($working_service && $recs->getServiceType() == 'classic'){
147
+ // Availability - Classic
148
+ if ($lastPostalCode!=$shippingAddress['postal_code'] || ! $shippingAddress['postal_code']){
149
+ //gets request
150
+ $response = $recs->classicAvailabilityRequest();
151
+
152
+ if($response->isAvailable() && ( $currency_code === $response->getPrice()->getCurrency())){
153
+ $result->append($this->_getClassic($response->getPrice()->getAmount() ));
154
+ }
155
+ }else{
156
+ //gets the cached response
157
+ $response = $recs->getAvailabilityRequest('classic');
158
+
159
+ if( $response && $response['available'] && ($currency_code === $response['currency_code'] )){
160
+ $result->append($this->_getClassic($response['price'] ));
161
+ }
162
+ }
163
+ }else if($working_service && $recs->getServiceType() !== 'unavailable' ){
164
+ // Availability - Last Mile
165
+ if ($lastPostalCode==$shippingAddress['postal_code']){
166
+ //gets the cached response
167
+ $response = $recs->getAvailabilityRequest('lastmile');
168
+
169
+ if( $response && $response['available'] && ($currency_code === $response['currency_code'] )){
170
+ $lastUserSelection = $recs->getUserSelection();
171
+
172
+ if(!$lastUserSelection){
173
+ $result->append($this->_getLastMile( $response['price'] ));
174
+ }else{
175
+ $selectedPrice = Mage::helper('core')->jsonDecode($lastUserSelection);
176
+ $result->append($this->_getLastMile($selectedPrice['total_price']));
177
+ }
178
+ }
179
+ }else{
180
+ //gets new request
181
+ $response = $recs->lastMileAvailabilityRequest();
182
+ $this->log($response->isAvailable(), 'LastMileAvailabilityRequest availability');
183
+ if($response->isAvailable() && ( $currency_code === $response->getBestPrice()->getCurrency()) )
184
+ {
185
+ $lastUserSelection = $recs->getUserSelection();
186
+
187
+ if(!$lastUserSelection){
188
+ $result->append($this->_getLastMile( $response->getBestPrice()->getAmount() ));
189
+ }else{
190
+ $selectedPrice = Mage::helper('core')->jsonDecode($lastUserSelection);
191
+ $result->append($this->_getLastMile($selectedPrice['total_price']));
192
+ }
193
+ }
194
+ }
195
+ }
196
+
197
+ }
198
+
199
+
200
+
201
+
202
+ if ( $working_service )
203
+ $recs->assetsRequest();
204
+
205
+ //saves in globals as cache in one request
206
+ $GLOBALS['lastCollectRates'] = $result;
207
+ return $result;
208
+ }
209
+
210
+ protected function _getLastMile($lm_best_price)
211
+ {
212
+ $this->log($lm_best_price, 'Nektria lastmile best price');
213
+
214
+ $rate = Mage::getModel('shipping/rate_result_method');
215
+ /* @var $rate Mage_Shipping_Model_Rate_Result_Method */
216
+
217
+ $rate->setCarrier(Mage::helper('nektria')->getCode());
218
+ $rate->setCarrierTitle($this->getConfigData('title'));
219
+
220
+ $methods = $this->getAllowedMethods();
221
+
222
+ $rate->setMethod('lastmile');
223
+ $rate->setMethodTitle($methods['lastmile']);
224
+
225
+ //Set the best price
226
+ $rate->setPrice($lm_best_price);
227
+
228
+ return $rate;
229
+ }
230
+
231
+ protected function _getClassic($c_price)
232
+ {
233
+ $rate = Mage::getModel('shipping/rate_result_method');
234
+ /* @var $rate Mage_Shipping_Model_Rate_Result_Method */
235
+ $rate->setCarrier(Mage::helper('nektria')->getCode());
236
+ $rate->setCarrierTitle($this->getConfigData('title'));
237
+
238
+ $methods = $this->getAllowedMethods();
239
+
240
+ $rate->setMethod('classic');
241
+ $rate->setMethodTitle($methods['classic']);
242
+
243
+ $rate->setPrice($c_price);
244
+
245
+ return $rate;
246
+ }
247
+
248
+ public function getAllowedMethods() {
249
+ return Mage::helper('nektria')->getReCSMethods();
250
+ }
251
+
252
+
253
+ private function log($obj, $msg=''){
254
+ if (! Mage::getStoreConfig('dev/log/active'))
255
+ return FALSE;
256
+ Mage::helper('nektria')->log($obj, $msg, $this->logfile);
257
+ }
258
+ }
app/code/community/Nektria/ReCS/Model/Lastmile.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ */
5
+
6
+ class Nektria_ReCS_Model_Lastmile extends Mage_Core_Model_Abstract
7
+ {
8
+ protected function _construct(){
9
+ $this->_init( 'nektria_recs/lastmile' );
10
+ }
11
+ }
app/code/community/Nektria/ReCS/Model/Observer.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once (Mage::getModuleDir('', 'Nektria_ReCS') . DS . 'lib' . DS .'Nektria.php');
4
+
5
+ class Nektria_ReCS_Model_Observer
6
+ {
7
+ protected $_code = 'nektria_recs';
8
+ private static $logfile = 'shipping_nektria_events.log';
9
+
10
+ /**
11
+ * This method save in session the user selection. Magento refresh shipping rates in each step.
12
+ * @param [type] $observer event parameter
13
+ */
14
+ public function checkout_controller_onepage_save_shipping_method($observer){
15
+ $this->log('Inside OnePage Save Shipping', 'SaveShipping method');
16
+ //check if carrier is enabled
17
+ if (! Mage::helper('nektria')->getEnabled() ) {
18
+ return false;
19
+ }
20
+ $this->savelog = Mage::getStoreConfig('debug/options/enable');
21
+
22
+ //get Quote from session and rescue shipping method
23
+ $quote = $checkout = Mage::getSingleton('checkout/session')->getQuote();
24
+ $address = $quote->getShippingAddress();
25
+ $shipping_method = $address->getShippingMethod();
26
+
27
+ //Switch with method type
28
+
29
+ $recs = new NektriaSdk();
30
+
31
+ if ($shipping_method == 'nektria_recs_lastmile'){
32
+ //get nektria lastmile selecction
33
+ $request = $observer->getRequest();
34
+ $pickup = $request->getParam('nektria_selection',false);
35
+
36
+ //save in session the user selection
37
+ //If not saved yet then save, ignore in other case
38
+ if ( (! $detectSel = $recs->getUserSelection() ) || ($pickup !== '{}' && $pickup !== $detectSel ) ){
39
+ self::log($pickup, 'Saving the new nektria shipping selection');
40
+ $recs->setUserSelection( $pickup );
41
+ }
42
+
43
+
44
+ $recs->validateSecurity(FALSE);
45
+
46
+ }else if($shipping_method == 'nektria_recs_classic'){
47
+ $recs->validateSecurity(FALSE);
48
+ }
49
+ //nothing with other shipping methods...
50
+ }
51
+
52
+ /**
53
+ * Saves the shipment to nektria and clean session data
54
+ * @param variant $observer Event paramenters
55
+ */
56
+ public function checkout_submit_all_after($observer){
57
+ //check if carrier is enabled
58
+ if (! Mage::helper('nektria')->getEnabled() ) {
59
+ return false;
60
+ }
61
+
62
+ //get shipping method
63
+ $shipping_method = Mage::helper('nektria')->getShippingMethod();
64
+
65
+ //Gets current order id
66
+ $order = $observer->getEvent()->getOrder();
67
+ $order_id = $order->getIncrementId();
68
+
69
+ $lastOrderId = Mage::getSingleton('checkout/session')->getLastOrderNektria(false);
70
+
71
+ //checks if the order has been processed one time
72
+ if (!$lastOrderId || $order_id != $lastOrderId){
73
+ $apikey = Mage::helper('nektria')->getConfig('apikey');
74
+ $recs = new NektriaSdk();
75
+
76
+ if ($shipping_method == 'nektria_recs_lastmile'){
77
+ //Saves user selection into database
78
+ $lastmile_db = Mage::getModel('nektria_recs/lastmile');
79
+ $lastmile_db->setOrderId( $order_id );
80
+ $lastmile_db->setUserSelection( $recs->getUserSelection() );
81
+ $lastmile_db->save();
82
+
83
+ //If selected method and carrier is nektria and lastmile
84
+ $recs->saveLastMile($order_id);
85
+
86
+ }else if ($shipping_method == 'nektria_recs_classic'){
87
+ //If selected method and carrier is nektria and classic
88
+
89
+ $recs->saveClassic($order_id);
90
+ }
91
+ //Save last order id because this event is called 2 times
92
+ Mage::getSingleton('checkout/session')->setLastOrderNektria( $order_id );
93
+ $recs->clean();
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Checks if the shipping has been changed for security
99
+ * @param Variant $observer Event param
100
+ */
101
+ public function sales_order_place_before($observer){
102
+ //check if carrier is enabled
103
+ if (! Mage::helper('nektria')->getEnabled() ) {
104
+ return false;
105
+ }
106
+ //if validate security stops the payment process
107
+ $recs = new NektriaSdk();
108
+ //Check errors
109
+ if ($recs->validateSecurity())
110
+ Mage::throwException(Mage::helper('nektria')->__('Shipping method choices have timed out, please select your delivery windows again'));
111
+
112
+ //Forbidden offline payment methods
113
+ if (Mage::helper('nektria')->getLastMileSelected() && ! Mage::helper('nektria')->checkAllowPaymentMethod( Mage::helper('nektria')->getPaymentMethod() ) )
114
+ Mage::throwException(Mage::helper('nektria')->__('Last Mile shipping method is not compatible with the selected payment method'));
115
+
116
+ //Check last validation lastmile before payment
117
+ if (Mage::helper('nektria')->getLastMileSelected() && !$recs->validateLastMile())
118
+ Mage::throwException(Mage::helper('nektria')->__('An error has ocurred during Last Mile Shipping Method validation. Please change your selection'));
119
+ }
120
+
121
+ /**
122
+ * Cleans session data
123
+ * @param variant $observer Event paramenters
124
+ */
125
+ public function checkout_quote_destroy($observer){
126
+ //check if carrier is enabled
127
+ if (! Mage::helper('nektria')->getEnabled() ) {
128
+ return false;
129
+ }
130
+ //remove sessions variables from nektria shipping
131
+ $recs = new NektriaSdk();
132
+ $recs->clean();
133
+ }
134
+
135
+
136
+ /* ************************************************************************************** */
137
+ static function log($obj, $msg=''){
138
+ if (! Mage::getStoreConfig('dev/log/active'))
139
+ return FALSE;
140
+ Mage::helper('nektria')->log($obj, $msg, self::$logfile);
141
+ }
142
+
143
+ /** Logging events debugger */
144
+ public function controller_action_predispatch($observer) {
145
+ self::log(
146
+ 'event', //$observer ,
147
+ $observer->getEvent ()->getControllerAction ()->getFullActionName ()
148
+ );
149
+ }
150
+ }
app/code/community/Nektria/ReCS/Model/Paymentmethods.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Nektria_ReCS_Model_Paymentmethods
4
+ {
5
+ public function toOptionArray()
6
+ {
7
+ return Mage::helper('nektria')->getDirectPaymentMethods();
8
+ }
9
+ }
app/code/community/Nektria/ReCS/Model/Resource/Lastmile.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ */
5
+
6
+ class Nektria_ReCS_Model_Resource_Lastmile extends Mage_Core_Model_Resource_Db_Abstract
7
+ {
8
+ // Initialize connection and define main table and primary key
9
+ protected function _construct(){
10
+ $this->_init( 'nektria_recs/lastmile', 'lastmile_id' );
11
+ }
12
+ }
app/code/community/Nektria/ReCS/Model/Resource/Lastmile/Collection.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ */
5
+
6
+ class Nektria_ReCS_Model_Resource_Lastmile_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract
7
+ {
8
+ // Initialize connection and define main table and primary key
9
+ protected function _construct(){
10
+ $this->_init( 'nektria_recs/lastmile' );
11
+ }
12
+ }
app/code/community/Nektria/ReCS/Model/Sales/Order.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Nektria_ReCS_Model_Sales_Order extends Mage_Sales_Model_Order{
3
+ public function getShippingDescription(){
4
+ $desc = parent::getShippingDescription();
5
+ // Mage::helper('nektria')->log($userSelection, 'userSelection', 'test.log');
6
+ // Mage::helper('nektria')->log($this->getIncrementId(), 'getIncrementId', 'test.log');
7
+ // Mage::helper('nektria')->log($json, 'json', 'test.log');
8
+ // Mage::helper('nektria')->log(Mage::getSingleton('checkout/session')->getNektriaUserSelection(FALSE), 'json from Session', 'test.log');
9
+ $lastmile = Mage::app()->getLayout()->createBlock('core/template')->setTemplate('recs/email/lastmile.phtml');
10
+
11
+ return $lastmile->toHtml().$desc;
12
+ }
13
+ }
app/code/community/Nektria/ReCS/etc/config.xml ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8" standalone="no"?>
2
+ <config>
3
+ <modules>
4
+ <Nektria_ReCS>
5
+ <version>1.0.1</version>
6
+ </Nektria_ReCS>
7
+ </modules>
8
+
9
+ <frontend>
10
+ <routers>
11
+ <recs>
12
+ <use>standard</use>
13
+ <args>
14
+ <module>Nektria</module>
15
+ <frontName>ReCS</frontName>
16
+ </args>
17
+ </recs>
18
+ </routers>
19
+ <layout>
20
+ <updates>
21
+ <recs>
22
+ <file>recs.xml</file>
23
+ </recs>
24
+ </updates>
25
+ </layout>
26
+ <translate>
27
+ <modules>
28
+ <nektria_recs>
29
+ <files>
30
+ <default>Nektria_Translations.csv</default>
31
+ </files>
32
+ </nektria_recs>
33
+ </modules>
34
+ </translate>
35
+ </frontend>
36
+
37
+ <adminhtml>
38
+ <translate>
39
+ <modules>
40
+ <translations>
41
+ <files>
42
+ <default>Nektria_Translations.csv</default>
43
+ </files>
44
+ </translations>
45
+ </modules>
46
+ </translate>
47
+ <layout>
48
+ <updates>
49
+ <recs>
50
+ <file>recs.xml</file>
51
+ </recs>
52
+ </updates>
53
+ </layout>
54
+ </adminhtml>
55
+
56
+ <global>
57
+ <blocks>
58
+ <nektria_recs>
59
+ <class>Nektria_ReCS_Block</class>
60
+ </nektria_recs>
61
+ </blocks>
62
+ <helpers>
63
+ <nektria>
64
+ <class>Nektria_ReCS_Helper</class>
65
+ </nektria>
66
+ </helpers>
67
+ <models>
68
+ <nektria_recs>
69
+ <class>Nektria_ReCS_Model</class>
70
+ <resourceModel>nektria_recs_resource</resourceModel>
71
+ </nektria_recs>
72
+ <nektria_recs_resource>
73
+ <class>Nektria_ReCS_Model_Resource</class>
74
+ <entities>
75
+ <lastmile>
76
+ <table>nektria_recs_lastmile</table>
77
+ </lastmile>
78
+ </entities>
79
+ </nektria_recs_resource>
80
+ <sales>
81
+ <rewrite>
82
+ <order>Nektria_ReCS_Model_Sales_Order</order>
83
+ </rewrite>
84
+ </sales>
85
+ </models>
86
+
87
+ <resources>
88
+ <nektria_recs_setup>
89
+ <setup>
90
+ <module>Nektria_ReCS</module>
91
+ </setup>
92
+ <connection>
93
+ <use>core_setup</use>
94
+ </connection>
95
+ </nektria_recs_setup>
96
+ <nektria_recs_read>
97
+ <connection>
98
+ <use>core_read</use>
99
+ </connection>
100
+ </nektria_recs_read>
101
+ <nektria_recs_write>
102
+ <connection>
103
+ <use>core_write</use>
104
+ </connection>
105
+ </nektria_recs_write>
106
+
107
+ </resources>
108
+
109
+ <events>
110
+ <checkout_controller_onepage_save_shipping_method>
111
+ <observers>
112
+ <nektria_recs_shipping>
113
+ <type>singleton</type>
114
+ <class>Nektria_ReCS_Model_Observer</class>
115
+ <method>checkout_controller_onepage_save_shipping_method</method>
116
+ </nektria_recs_shipping>
117
+ </observers>
118
+ </checkout_controller_onepage_save_shipping_method>
119
+ <checkout_submit_all_after>
120
+ <observers>
121
+ <nektria_recs_shipping>
122
+ <type>singleton</type>
123
+ <class>Nektria_ReCS_Model_Observer</class>
124
+ <method>checkout_submit_all_after</method>
125
+ </nektria_recs_shipping>
126
+ </observers>
127
+ </checkout_submit_all_after>
128
+ <checkout_quote_destroy>
129
+ <observers>
130
+ <nektria_recs_shipping>
131
+ <type>singleton</type>
132
+ <class>Nektria_ReCS_Model_Observer</class>
133
+ <method>checkout_quote_destroy</method>
134
+ </nektria_recs_shipping>
135
+ </observers>
136
+ </checkout_quote_destroy>
137
+ <sales_order_place_before>
138
+ <observers>
139
+ <nektria_recs_shipping>
140
+ <type>singleton</type>
141
+ <class>Nektria_ReCS_Model_Observer</class>
142
+ <method>sales_order_place_before</method>
143
+ </nektria_recs_shipping>
144
+ </observers>
145
+ </sales_order_place_before>
146
+ <gomage_checkout_save_quote_before>
147
+ <observers>
148
+ <nektria_recs_shipping>
149
+ <type>singleton</type>
150
+ <class>Nektria_ReCS_Model_Observer</class>
151
+ <method>sales_order_place_before</method>
152
+ </nektria_recs_shipping>
153
+ </observers>
154
+ </gomage_checkout_save_quote_before>
155
+ <!-- Logging all events
156
+ <controller_action_predispatch>
157
+ <observers>
158
+ <nektria_recs_observer_log>
159
+ <type>singleton</type>
160
+ <class>Nektria_ReCS_Model_Observer</class>
161
+ <method>controller_action_predispatch</method>
162
+ </nektria_recs_observer_log>
163
+ </observers>
164
+ </controller_action_predispatch>
165
+ -->
166
+ </events>
167
+ </global>
168
+
169
+ <default>
170
+ <carriers>
171
+ <nektria_recs>
172
+ <active>1</active>
173
+ <model>nektria_recs/carrier</model>
174
+ <title>Recs by Nektria</title>
175
+ <sort_order>1</sort_order>
176
+ <sallowspecific>0</sallowspecific>
177
+ <!-- default demo apikey -->
178
+ <apikey></apikey>
179
+ <sandbox>1</sandbox>
180
+ </nektria_recs>
181
+ </carriers>
182
+ </default>
183
+ </config>
app/code/community/Nektria/ReCS/etc/system.xml ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <config>
3
+ <sections>
4
+ <carriers translate="label" module="shipping">
5
+ <groups>
6
+ <nektria_recs translate="label">
7
+ <label>Nektria</label>
8
+ <frontend_type>text</frontend_type>
9
+ <sort_order>2</sort_order>
10
+ <show_in_default>1</show_in_default>
11
+ <show_in_website>1</show_in_website>
12
+ <show_in_store>1</show_in_store>
13
+ <fields>
14
+ <!--
15
+ The following fields are available
16
+ to modify in the admin panel.
17
+ The values are saved in the
18
+ database.
19
+
20
+ This shipping carrier abstract checks
21
+ this value to determine whether
22
+ the carrier should be shown.
23
+ -->
24
+ <active translate="label">
25
+ <label>Enabled</label>
26
+ <frontend_type>select</frontend_type>
27
+ <source_model>adminhtml/system_config_source_yesno</source_model>
28
+ <sort_order>1</sort_order>
29
+ <show_in_default>1</show_in_default>
30
+ <show_in_website>1</show_in_website>
31
+ <show_in_store>0</show_in_store>
32
+ </active>
33
+ <!--
34
+ This value can be used to specify a
35
+ custom title for our method.
36
+ -->
37
+ <title translate="label">
38
+ <label>Custom title</label>
39
+ <frontend_type>text</frontend_type>
40
+ <sort_order>2</sort_order>
41
+ <show_in_default>1</show_in_default>
42
+ <show_in_website>1</show_in_website>
43
+ <show_in_store>1</show_in_store>
44
+ <can_be_empty>0</can_be_empty>
45
+ </title>
46
+
47
+ <registration translate="label">
48
+ <label>Sign up and get your API Key</label>
49
+ <frontend_class>nektria_registration</frontend_class>
50
+ <frontend_model>nektria_recs/registration</frontend_model>
51
+ <sort_order>3</sort_order>
52
+ <show_in_default>1</show_in_default>
53
+ <show_in_website>1</show_in_website>
54
+ </registration>
55
+
56
+ <apikey translate="label">
57
+ <label>API Key</label>
58
+ <frontend_type>text</frontend_type>
59
+ <sort_order>4</sort_order>
60
+ <show_in_default>1</show_in_default>
61
+ <show_in_website>1</show_in_website>
62
+ <show_in_store>1</show_in_store>
63
+ </apikey>
64
+
65
+ <sandbox translate="label">
66
+ <label>Sandbox</label>
67
+ <frontend_type>select</frontend_type>
68
+ <source_model>adminhtml/system_config_source_yesno</source_model>
69
+ <sort_order>5</sort_order>
70
+ <show_in_default>1</show_in_default>
71
+ <show_in_website>1</show_in_website>
72
+ <show_in_store>0</show_in_store>
73
+ </sandbox>
74
+
75
+ <paymentsallow translate="label">
76
+ <label>Disable LastMile for these payment methods</label>
77
+ <frontend_type>multiselect</frontend_type>
78
+ <sort_order>6</sort_order>
79
+ <source_model>nektria_recs/paymentmethods</source_model>
80
+ <show_in_default>1</show_in_default>
81
+ <show_in_website>1</show_in_website>
82
+ <show_in_store>0</show_in_store>
83
+ <can_be_empty>0</can_be_empty>
84
+ </paymentsallow>
85
+
86
+ <backendconf translate="label">
87
+ <label>Open Nektria ReCS backend configuration</label>
88
+ <frontend_class>nektria_config</frontend_class>
89
+ <frontend_model>nektria_recs/config</frontend_model>
90
+ <sort_order>7</sort_order>
91
+ <show_in_default>1</show_in_default>
92
+ <show_in_website>1</show_in_website>
93
+ </backendconf>
94
+
95
+ <!--
96
+ The sort order is used in Magento
97
+ to determine what order the carrier
98
+ will appear in relative to the
99
+ other carriers available.
100
+
101
+ <sort_order translate="label">
102
+ <label>Sort Order</label>
103
+ <frontend_type>text</frontend_type>
104
+ <sort_order>100</sort_order>
105
+ <show_in_default>1</show_in_default>
106
+ <show_in_website>1</show_in_website>
107
+ <show_in_store>0</show_in_store>
108
+ </sort_order>
109
+
110
+ This value is used to specify whether
111
+ the carrier is available only for
112
+ specific countries or all countries
113
+ available in the current Magento
114
+ installation.
115
+
116
+ <sallowspecific translate="label">
117
+ <label>Countries for which to apply the shipping method</label>
118
+ <frontend_type>select</frontend_type>
119
+ <sort_order>90</sort_order>
120
+ <frontend_class>shipping-applicable-country</frontend_class>
121
+ <source_model>adminhtml/system_config_source_shipping_allspecificcountries</source_model>
122
+ <show_in_default>1</show_in_default>
123
+ <show_in_website>1</show_in_website>
124
+ <show_in_store>0</show_in_store>
125
+ </sallowspecific>
126
+ -->
127
+ <!--
128
+ If 'specific countries' is chosen
129
+ in the previous option, then this field
130
+ allows the administrator to specify
131
+ which specific countries this carrier
132
+ should be available for.
133
+
134
+ <specificcountry translate="label">
135
+ <label>Ship to Specific Countries</label>
136
+ <frontend_type>multiselect</frontend_type>
137
+ <sort_order>91</sort_order>
138
+ <source_model>adminhtml/system_config_source_country</source_model>
139
+ <show_in_default>1</show_in_default>
140
+ <show_in_website>1</show_in_website>
141
+ <show_in_store>0</show_in_store>
142
+ <can_be_empty>1</can_be_empty>
143
+ </specificcountry>
144
+ -->
145
+ </fields>
146
+ </nektria_recs>
147
+ </groups>
148
+ </carriers>
149
+ </sections>
150
+ </config>
app/code/community/Nektria/ReCS/lib/Nektria.php ADDED
@@ -0,0 +1,537 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once('Nektria/vendor/autoload.php');
4
+
5
+ class NektriaExtensionException extends Exception{
6
+ public function getError(){
7
+ return FALSE;
8
+ }
9
+ }
10
+
11
+ class NektriaSdk{
12
+ protected $id = NULL;
13
+ protected $logfile = 'nektria.sdk.log';
14
+ protected $lastError = NULL;
15
+ protected $lastPrice = NULL;
16
+ protected $assets = NULL;
17
+
18
+ protected $options = array(
19
+ 'APIKEY' => '',
20
+ 'secure' => false,
21
+ 'environment'=> 'sandbox'
22
+ );
23
+ protected $lastResponse = NULL;
24
+
25
+ function __construct(){}
26
+
27
+ public function setOptions(array $options){
28
+ $this->options = array_merge($this->options, $options);
29
+ $this->log($this->options,'setOptions');
30
+ return TRUE;
31
+ }
32
+
33
+ /**
34
+ * Gets call options of the service
35
+ * @return array The options saved
36
+ */
37
+ public function getOptions(){
38
+ $lastServiceId = Mage::getSingleton('checkout/session')->getNektriaServiceNumber();
39
+ if ($lastServiceId)
40
+ $this->id = $lastServiceId;
41
+
42
+ $this->options = array_merge(
43
+ $this->options ,
44
+ Mage::helper('nektria')->getServiceParams(array())
45
+ );
46
+
47
+ $this->log(array('options'=>$this->options ,'id'=>$this->id),'getOptions and id');
48
+
49
+ if (! is_null($this->id))
50
+ return array_merge($this->options, array('id'=>$this->id));
51
+ else
52
+ return $this->options;
53
+ }
54
+
55
+ /**
56
+ * Cleans Nektria session variables
57
+ * @return void
58
+ */
59
+ public function clean(){
60
+ $this->log(FALSE, 'Called Clean Method');
61
+ //remove sessions variables from nektria shipping
62
+ Mage::getSingleton('checkout/session')->unsNektriaUserSelection();
63
+ Mage::getSingleton('checkout/session')->unsNektriaServiceNumber();
64
+ Mage::getSingleton('checkout/session')->unsNektriaServiceType();
65
+ Mage::getSingleton('checkout/session')->unsNektriaLastPostalCode();
66
+ Mage::getSingleton('checkout/session')->unsNektriaLastCountryCode();
67
+ Mage::getSingleton('checkout/session')->unsClassicPrice();
68
+ Mage::getSingleton('checkout/session')->unsPriceMatrix();
69
+ Mage::getSingleton('checkout/session')->unsNektriaSecurityError();
70
+ Mage::getSingleton('checkout/session')->unsOldLastmileRequest();
71
+ Mage::getSingleton('checkout/session')->unsOldClassicRequest();
72
+ Mage::getSingleton('checkout/session')->unsCoveredCountries();
73
+ Mage::getSingleton('checkout/session')->unsNektriaBackendUrl();
74
+ Mage::getSingleton('checkout/session')->unsNektriaRegistrationUrl();
75
+
76
+ $this->id=NULL;
77
+ $this->lastResponse=NULL;
78
+ $this->lastError=NULL;
79
+ $this->lastPrice=NULL;
80
+ $this->assets=NULL;
81
+ }
82
+
83
+ /**
84
+ * Sets user LastMile Selection in the session
85
+ * @param string JSON stringify
86
+ */
87
+ public function setUserSelection($pickup){
88
+ $this->log($pickup,'setUserSelection');
89
+ //ignore default value
90
+ if($pickup && $pickup != '{}')
91
+ Mage::getSingleton('checkout/session')->setNektriaUserSelection($pickup);
92
+ }
93
+
94
+ /**
95
+ * Returns LastMile user selection from the session
96
+ * @return string JSON Stringify
97
+ */
98
+ public function getUserSelection(){
99
+ $userSelection = Mage::getSingleton('checkout/session')->getNektriaUserSelection(FALSE);
100
+ $this->log($userSelection, 'getUserSelection');
101
+ return (string) $userSelection;
102
+ }
103
+
104
+ /**
105
+ * Get the last response of the API Call
106
+ * @return Variant the last response
107
+ */
108
+ public function getLastResponse(){
109
+ return $this->lastResponse;
110
+ }
111
+
112
+ /**
113
+ * Get the ServiceID saved in the session
114
+ * @return int ServiceID
115
+ */
116
+ public function getServiceId(){
117
+ return ($this->id)?
118
+ $this->id :
119
+ Mage::getSingleton('checkout/session')->getNektriaServiceNumber(FALSE);
120
+ }
121
+
122
+ /**
123
+ * Get the serviceType returned "classic|last-mile"
124
+ * @return string ServiceType
125
+ */
126
+ public function getServiceType(){
127
+ return Mage::getSingleton('checkout/session')->getNektriaServiceType(FALSE);
128
+ }
129
+
130
+ /**
131
+ * Get the Postal Code from the session
132
+ * @return string PostalCode
133
+ */
134
+ public function getLastPostalCode(){
135
+ return Mage::getSingleton('checkout/session')->getNektriaLastPostalCode(FALSE);
136
+ }
137
+
138
+ /**
139
+ * Get the Country code from the session
140
+ * @return string Country Code
141
+ */
142
+ public function getLastCountryCode(){
143
+ return Mage::getSingleton('checkout/session')->getNektriaLastCountryCode(FALSE);
144
+ }
145
+
146
+ /**
147
+ * get the LastError generated
148
+ * @return Exception error
149
+ */
150
+ public function getLastError(){
151
+ return $this->lastError;
152
+ }
153
+
154
+ /**
155
+ * Get the priceMatrix of LastMile execution
156
+ * @return object PriceMatix
157
+ */
158
+ public function getPriceMatrix(){
159
+ return Mage::getSingleton('checkout/session')->getPriceMatrix(FALSE);
160
+ }
161
+
162
+ /**
163
+ * Get the lastPrice returned from Classic or LastMile availability
164
+ * @return float Price
165
+ */
166
+ public function getLastPrice(){
167
+ return $this->lastPrice;
168
+ }
169
+
170
+ /**
171
+ * Check or set security checks
172
+ */
173
+ public function validateSecurity($setValue = NULL){
174
+ if ($setValue){
175
+ Mage::getSingleton('checkout/session')->setNektriaSecurityError( $setValue );
176
+ }else if(is_null($setValue)){
177
+ return Mage::getSingleton('checkout/session')->getNektriaSecurityError(FALSE);
178
+ }else{
179
+ Mage::getSingleton('checkout/session')->unsNektriaSecurityError();
180
+ }
181
+ }
182
+
183
+ /* ------------------------------------------------- API CALLS -------------------------------------------------------- */
184
+
185
+ /**
186
+ * Call to ServiceCreationRequest and saves values in sesion
187
+ * @param array $nektriaParams User and shipping data
188
+ * @return bool true or false if success
189
+ */
190
+ public function createService(array $nektriaParams){
191
+ //Add cookie session
192
+ $nektriaParams['session_timeout'] = Mage::helper('nektria')->getSessionTimeout();
193
+ //Add current currency code
194
+ $nektriaParams['currency_code'] = Mage::app()->getStore()->getCurrentCurrencyCode();
195
+
196
+ //Send the request of service Nektria SDK
197
+ $this->log($nektriaParams,'User and Shipping Address for createService');
198
+ $sr = new Nektria\Recs\MerchantApi\Requests\ServiceCreationRequest($this->getOptions());
199
+
200
+ try{
201
+ $this->lastResponse = $sr->execute($nektriaParams);
202
+ $this->log($this->lastResponse, 'createService response');
203
+ }catch(Exception $e){
204
+ $this->lastError = $e;
205
+ $this->log($e->getCode().$e->getMessage(), 'createService ERROR');
206
+ return FALSE;
207
+ }
208
+
209
+ //Saving service_id in the session
210
+ $this->id = $this->lastResponse->getServiceNumber();
211
+ Mage::getSingleton('checkout/session')->setNektriaServiceNumber($this->id);
212
+ Mage::getSingleton('checkout/session')->setNektriaServiceType( $this->lastResponse->getServiceType() );
213
+ Mage::getSingleton('checkout/session')->setNektriaLastPostalCode($nektriaParams['destination_address']['postal_code']);
214
+ Mage::getSingleton('checkout/session')->setNektriaLastCountryCode($nektriaParams['destination_address']['country_code']);
215
+
216
+ return TRUE;
217
+ }
218
+
219
+ /**
220
+ * Remains nektria session alive
221
+ * @return bool true or false if success
222
+ */
223
+ public function keepAlive(){
224
+ $lastKeepAlive = Mage::getSingleton('checkout/session')->getLastKeepAlive(FALSE);
225
+
226
+ //if last KeepAlive was more than five minutes then callit
227
+ if($lastKeepAlive && ( (time() - (int)$lastKeepAlive) < (60*5) )){
228
+ return TRUE;
229
+ }
230
+
231
+ try{
232
+ $kar = new Nektria\Recs\MerchantApi\Requests\KeepAliveRequest($this->getOptions());
233
+ $this->lastResponse = $kar->execute();
234
+ $this->log($this->lastResponse, 'keepAlive');
235
+ }catch(Exception $e){
236
+ $this->lastError = $e;
237
+ $this->log($e->getCode().$e->getMessage(), 'keepAlive ERROR');
238
+ return FALSE;
239
+ }
240
+
241
+ $this->keepAliveCalled = TRUE;
242
+ Mage::getSingleton('checkout/session')->setLastKeepAlive(time());
243
+ return TRUE;
244
+ }
245
+
246
+ /**
247
+ * Call to LastMile availability
248
+ * @return object Response from the method
249
+ */
250
+ public function lastMileAvailabilityRequest(){
251
+ try{
252
+ $lmar = new Nektria\Recs\MerchantApi\Requests\LastMileAvailabilityRequest($this->getOptions());
253
+ $this->lastResponse = $lmar->execute(array("service_type" => $this->getServiceType() ));
254
+ $this->log($this->lastResponse, 'lastMileAvailabilityRequest');
255
+ }catch(Exception $e){
256
+ $this->lastError = $e;
257
+ $this->log($e->getCode().$e->getMessage(), 'lastMileAvailabilityRequest ERROR');
258
+ return FALSE;
259
+ }
260
+ $lastPriceMatrix = Mage::getSingleton('checkout/session')->getPriceMatrix(FALSE);
261
+ if (! $lastPriceMatrix){
262
+ Mage::getSingleton('checkout/session')->setPriceMatrix($this->lastResponse->getPriceMatrix());
263
+ }
264
+ $this->lastPrice = $this->lastResponse->getBestPrice()->getAmount();
265
+
266
+ $this->setAvailabilityRequest('lastmile', array(
267
+ 'available'=>$this->lastResponse->isAvailable(),
268
+ 'price'=>$this->lastPrice,
269
+ 'currency_code'=>$this->lastResponse->getBestPrice()->getCurrency(),
270
+ 'priceMatrix'=>Mage::getSingleton('checkout/session')->getPriceMatrix(FALSE)
271
+ ) );
272
+
273
+ return $this->lastResponse;
274
+ }
275
+
276
+ public function lastMileBestPriceRequest($params){
277
+ try{
278
+ $scr = new Nektria\Recs\MerchantApi\Requests\LastMileBestPriceRequest($this->getOptions());
279
+
280
+ $this->lastResponse = $scr->execute($params);
281
+ $this->log($this->lastResponse, 'lastMileBestPriceRequest');
282
+ }catch(Exception $e){
283
+ $this->lastError = $e;
284
+ $this->log($e->getCode().$e->getMessage(), 'lastMileAvailabilityRequest ERROR');
285
+ return FALSE;
286
+ }
287
+
288
+ return array(
289
+ 'best_price' => $this->lastResponse->getBestPrice(),
290
+ 'currency_code' => $this->lastResponse->getBestPriceCurrency(),
291
+ 'best_price_currency' => $this->lastResponse->getBestPriceCurrency()
292
+ );
293
+ }
294
+
295
+ /**
296
+ * Save the lastMileAvailability or classicAvailability Request stored from session
297
+ * @param string classic | lastmile
298
+ * @return void
299
+ */
300
+ public function setAvailabilityRequest($type, $values){
301
+ $method = 'setOld'.ucwords( $type).'Request';
302
+ Mage::getSingleton('checkout/session')->$method(serialize($values));
303
+ }
304
+
305
+ /**
306
+ * Get the lastMileAvailability or classicAvailability Request stored from session
307
+ * @param string classic | lastmile
308
+ * @return associative array
309
+ */
310
+ public function getAvailabilityRequest($type){
311
+ $response = array();
312
+
313
+ $method = 'getOld'.ucwords( $type).'Request';
314
+ $response = Mage::getSingleton('checkout/session')->$method(FALSE);
315
+
316
+ return ($response)?unserialize($response):FALSE;
317
+ }
318
+
319
+ /**
320
+ * Calls to Classic availability
321
+ * @return object Response from the method
322
+ */
323
+ public function classicAvailabilityRequest(){
324
+ try{
325
+ $lmar = new Nektria\Recs\MerchantApi\Requests\ClassicAvailabilityRequest($this->getOptions());
326
+ $this->lastResponse = $lmar->execute(array("service_type" => $this->getServiceType() ));
327
+ $this->log($this->getServiceType(), 'classicAvailabilityRequest type');
328
+ $this->log($this->lastResponse, 'classicAvailabilityRequest');
329
+ }catch(Exception $e){
330
+ $this->lastError = $e;
331
+ $this->log($e->getCode().$e->getMessage(), 'classicAvailabilityRequest ERROR');
332
+ return FALSE;
333
+ }
334
+ $this->lastPrice = $this->lastResponse->getPrice()->getAmount();
335
+ Mage::getSingleton('checkout/session')->setClassicPrice($this->lastResponse->getPrice());
336
+
337
+ $this->setAvailabilityRequest('classic', array(
338
+ 'available'=>$this->lastResponse->isAvailable(),
339
+ 'currency_code'=>$this->lastResponse->getPrice()->getCurrency(),
340
+ 'price'=>$this->lastPrice
341
+ ));
342
+ return $this->lastResponse;
343
+ }
344
+
345
+ /**
346
+ * Sends Validation and Confirmation for LastMile
347
+ * @param int $order_id
348
+ * @return bool true or false if success
349
+ */
350
+ public function saveLastMile($order_id){
351
+ $this->log($order_id, 'Order ID for saveLastMile');
352
+
353
+ try{
354
+ $lmcr = new Nektria\Recs\MerchantApi\Requests\LastMileConfirmationRequest($this->getOptions());
355
+ $this->lastResponse = $lmcr->execute(array(
356
+ "order_number" => $order_id
357
+ ));
358
+ }catch(Exception $e){
359
+ $this->lastError = $e;
360
+ $this->log($e->getCode().$e->getMessage(), 'LastMileConfirmationRequest ERROR');
361
+ return FALSE;
362
+ }
363
+
364
+ $this->log($this->lastResponse, 'saveLastMile');
365
+ return TRUE;
366
+ }
367
+
368
+ public function validateLastMile(){
369
+ $userSelection = $this->getUserSelection();
370
+ $this->log($userSelection, 'UserSelection for validateLastMile');
371
+ try{
372
+ $lmvr = new Nektria\Recs\MerchantApi\Requests\LastMileValidationRequest($this->getOptions());
373
+ $this->lastResponse = $lmvr->execute($userSelection);
374
+ }catch(Exception $e){
375
+ $this->lastError = $e;
376
+ $this->log($e->getCode().$e->getMessage(), 'LastMileValidationRequest ERROR');
377
+ return FALSE;
378
+ }
379
+
380
+ $this->log($this->lastResponse, 'validateLastMile');
381
+ return TRUE;
382
+ }
383
+
384
+ /**
385
+ * Sends Classic Confirmation
386
+ * @param int $order_id
387
+ * @return bool true or false if success
388
+ */
389
+ public function saveClassic($order_id){
390
+ $this->log($order_id, 'Order ID for saveClassic');
391
+ try{
392
+ $ccr = new Nektria\Recs\MerchantApi\Requests\ClassicConfirmationRequest($this->getOptions());
393
+ $this->lastResponse = $ccr->execute(array("order_number" => $order_id));
394
+ }catch(Exception $e){
395
+ $this->lastError = $e;
396
+ $this->log($e->getCode().$e->getMessage(), 'saveClassic ERROR');
397
+ return FALSE;
398
+ }
399
+
400
+ $this->log($this->lastResponse, 'saveClassic');
401
+ return TRUE;
402
+ }
403
+
404
+ /**
405
+ * get Nektria Assets and save in session
406
+ * @return bool check if error
407
+ */
408
+ public function assetsRequest(){
409
+ //ObjectCache
410
+ if ( Mage::getSingleton('checkout/session')->getNektriaJs(FALSE) ){
411
+ return TRUE;
412
+ }
413
+
414
+ try{
415
+ $ar = new Nektria\Recs\MerchantApi\Requests\getAssetsRequest( $this->getOptions() );
416
+ $params = array(
417
+ 'version' => Mage::helper('nektria')->getAssetsVersion(),
418
+ 'language' => Mage::app()->getLocale()->getLocaleCode()
419
+ );
420
+ $this->lastResponse = $ar->execute( $params );
421
+ }catch(Exception $e){
422
+ $this->lastError = $e;
423
+ $this->log($e->getCode().$e->getMessage(), 'assetsRequest ERROR');
424
+ return FALSE;
425
+ }
426
+
427
+ $this->log(array($this->lastResponse), 'getAssetsRequest response');
428
+
429
+ Mage::getSingleton('checkout/session')->setNektriaJs( $this->lastResponse->getJsUrl() );
430
+ Mage::getSingleton('checkout/session')->setNektriaCss( $this->lastResponse->getCssUrl() );
431
+ Mage::getSingleton('checkout/session')->setNektriaHtml( $this->lastResponse->getHtmlUrl() );
432
+
433
+ return TRUE;
434
+ }
435
+
436
+ /**
437
+ * Get the list of covered countries for Nektria
438
+ * @return array list of ISO 3166 2 letters codes
439
+ */
440
+ public function getCoveredCountries(){
441
+ if ($return_value = Mage::getSingleton('checkout/session')->getCoveredCountries( FALSE ) ){
442
+ return $return_value;
443
+ }
444
+
445
+ try{
446
+ $cr = new Nektria\Recs\MerchantApi\Requests\CoverageRequest( $this->getOptions() );
447
+ $this->lastResponse = $cr->execute();
448
+ }catch(Exception $e){
449
+ $this->lastError = $e;
450
+ $this->log($e->getCode().$e->getMessage(), 'getCoveredCountries ERROR');
451
+ return FALSE;
452
+ }
453
+
454
+ $response = $this->lastResponse->getCoveredCountries();
455
+ $this->log($response, 'getCoveredCountries response');
456
+ Mage::getSingleton('checkout/session')->setCoveredCountries( $response );
457
+
458
+ return $response;
459
+ }
460
+
461
+ /**
462
+ * Check if the country code is available for Nektria
463
+ * @param string ISO 3166 2 letters codes
464
+ * @return bool
465
+ */
466
+ public function checkCoveredCountry($country_code){
467
+ $coveredCountries = $this->getCoveredCountries();
468
+
469
+ if ($coveredCountries && in_array($country_code, $coveredCountries)){
470
+ return TRUE;
471
+ }else{
472
+ return FALSE;
473
+ }
474
+ }
475
+
476
+
477
+ /**
478
+ * Get the popup Nektria Backend Configuration
479
+ * @return string url
480
+ */
481
+ public function getBackendUrl(){
482
+ if ($return_value = Mage::getSingleton('checkout/session')->getNektriaBackendUrl( FALSE ) ){
483
+ return $return_value;
484
+ }
485
+
486
+ try{
487
+ $cr = new Nektria\Recs\MerchantApi\Requests\BackendAccessRequest( $this->getOptions() );
488
+ $this->lastResponse = $cr->execute();
489
+ }catch(Exception $e){
490
+ $this->lastError = $e;
491
+ $this->log($e->getCode().$e->getMessage(), 'getBackendUrl ERROR');
492
+ return FALSE;
493
+ }
494
+
495
+ $response = $this->lastResponse->getBackendUrl();
496
+ $this->log($response, 'getBackendUrl response');
497
+ Mage::getSingleton('checkout/session')->setNektriaBackendUrl( $response );
498
+
499
+ return $response;
500
+ }
501
+
502
+ public function getRegistrationUrl(){
503
+ if ($return_value = Mage::getSingleton('checkout/session')->getNektriaRegistrationUrl( FALSE ) ){
504
+ return $return_value;
505
+ }
506
+
507
+ try{
508
+ $cr = new Nektria\Recs\MerchantApi\Requests\RegistrationAccessRequest( );
509
+ $this->lastResponse = $cr->execute();
510
+ }catch(Exception $e){
511
+ $this->lastError = $e;
512
+ $this->log($e->getCode().$e->getMessage(), 'getRegistrationUrl ERROR');
513
+ return FALSE;
514
+ }
515
+
516
+ $response = $this->lastResponse->getRegistrationUrl();
517
+ $this->log($response, 'getRegistrationUrl response');
518
+ Mage::getSingleton('checkout/session')->setNektriaRegistrationUrl( $response );
519
+
520
+ return $response;
521
+ }
522
+
523
+
524
+ /* ---------------------------------------------------------- HELPER ----------------------------------------------------------- */
525
+
526
+ /**
527
+ * Helper method for logging, only if dev log is active
528
+ * @param $obj Object to pass to logging file
529
+ * @param string $msg "Indentificated text"
530
+ */
531
+ private function log($obj, $msg=''){
532
+ if (! Mage::getStoreConfig('dev/log/active'))
533
+ return FALSE;
534
+ Mage::log('----------------------'.$msg.'--------------------------', null, $this->logfile);
535
+ Mage::log(var_export($obj, TRUE), null, $this->logfile);
536
+ }
537
+ }
app/code/community/Nektria/ReCS/lib/Nektria/.editorconfig ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ # top-most EditorConfig file
2
+ root = true
3
+
4
+ [*]
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ indent_style = tab
8
+ indent_size = 4
9
+ trim_trailing_whitespace = true
app/code/community/Nektria/ReCS/lib/Nektria/.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ composer.lock
2
+ .buildpath
3
+ .idea
4
+ .project
5
+ .settings
6
+ vendor
app/code/community/Nektria/ReCS/lib/Nektria/CHANGELOG.md ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+ Note that the SDK calls files that are provided by a service that is under development. Thus, changes in the service may be reflected in the pages using the SDK when no actual change have been performed.
4
+ This project adheres to [Semantic Versioning](http://semver.org/).
5
+
6
+ ## Unreleased
7
+ ### To Add
8
+ - Asset version number is managed in the getAssetsRequest - we need this to make sure that changes in the API do not break existing implementations.
9
+ => pending implementation from the API side.
10
+ - Manage multi language configuration.
11
+ - The getAssetsResponse::getJsUrl function should take a $locale variable to return a file corresponding to the user environment language.
12
+ - Find and include language specific initializations for used languages (es, ca, en)
13
+ - setup javascript included file to read query string and display dates in specified language.
14
+ - change repo name to recs-merchant-sdk-php & update composer.json accordingly.
15
+ - Get list of operating countries from an API call.
16
+
17
+ ### To Fix
18
+ - Work with a tag an not a helper to display html. Full html should be initialized via javascript.
19
+
20
+ ### [1.1.13] - 2015-11-27
21
+ ### Fix
22
+ - in LastMileBestPriceResponse, modified getBestPriceCurrency method to return currency code, and not currency sign. Added other method to get the sign.
23
+
24
+ ### [1.1.12] - 2015-11-27
25
+ ### Fix
26
+ - Set staging environment to herokuapp.com domain instead of nektria.com
27
+ - Refactored Client class
28
+ ### Added
29
+ - Removed secure parameter - all requests to staging and prod go over https.
30
+
31
+ ## [1.1.11] - 2015-11-27
32
+ ### Added
33
+ - Added currency_code parameter in the service creation request.
34
+
35
+ ## [1.1.10] - 2015-11-24
36
+ ### Added
37
+ - Added session_timeout parameter in the service creation request.
38
+
39
+
40
+ ## [1.1.9] - 2015-11-23
41
+ ### Fix
42
+ - Removed composer.lock from the project
43
+
44
+ ## [1.1.8] - 2015-11-23
45
+ ### Added
46
+ - New parameters for language and version in assets retrieval process. To start with, version should be '1' and language should be 'es_ES'.
47
+
48
+ ## [1.1.7] - 2015-11-20
49
+ ### Added
50
+ - API calls timeout
51
+ - options to control these timeouts
52
+
53
+ ## [1.1.6] - 2015-11-19
54
+ ### Fix
55
+ - getRegistrationUrl is not asking for API key anymore.
56
+
57
+ ## [1.1.5] - 2015-11-18
58
+ ### Fix
59
+ - set APIKEY compulsory parameter to empty value for getRegistrationUrl (where no api key is needed).
60
+
61
+ ## [1.1.4] - 2015-11-12
62
+ ### Fix
63
+ - tipo en LastMileBestPriceRequest
64
+
65
+ ## [1.1.3] - 2015-11-11
66
+ ### Added
67
+ - Registration Access Request
68
+
69
+ ## [1.1.2] - 2015-11-10
70
+ ### Added
71
+ - README: Explained how registration link request will work.
72
+
73
+ ## [1.1.1] - 2015-11-09
74
+ ### Added
75
+ - Functionality: Set up lastMileBestPriceRequest and LastMileBestPriceResponse
76
+ - README:
77
+ - use of lastMileBestPriceRequest description
78
+ - widget javascript function to update calendar with previously selected timeslots.
79
+
80
+ ### Fixed
81
+ - README: layout for correct pdf display
82
+
83
+ ## [1.1] - 2015-10-23
84
+ ### Added
85
+ - Set production to point to production environment.
86
+
87
+ ## [1.0.2.alpha] - 2015-10-23
88
+ ### Added
89
+ - Backend Access for eCommerce Advanced Configuration is now available.
90
+
91
+ ## [1.0.1.alpha] - 2015-10-22
92
+ ### Added
93
+ - README: details about how to get list of operating countries and how to setup backend access for advanced configuration.
94
+ - Set up objects to return list of operating countries (hardcoded).
95
+
96
+ ## [1.0.alpha] - 2015-10-08
97
+ ### Added
98
+ - Exception dealing with api responses, providing all information we get from the server.
99
+
100
+
101
+ ## [0.9.3] - 2015-10-07
102
+ ### Fixed
103
+ - Validation Request execute method now accepts both plain json string and array format as parameters. Readme suggests plain json string should be used.
104
+
105
+ ## [0.9.2] - 2015-10-07
106
+ ### Fixed
107
+ - Fixed missing use statement for exceptions in Response Body Wrapper.
108
+
109
+ ## [0.9.1] - 2015-10-07
110
+ ### Fixed
111
+ - Fixed Guzzle throwing own exceptions. Now all exceptions thrown by the SDK are children of Nektria\Recs\MerchantApi\Exceptions\ApiClientException
112
+
113
+ ## [0.9] - 2015-10-06
114
+ ### Added
115
+ - Show Shipping Request Helper provides methods to show localized windows and status information.
116
+
117
+ ## ? - ?
118
+ ### Fixed
119
+ - Submit button (Confirmar)
120
+
121
+ ## [0.8] - 2015-09-23
122
+ ### Added
123
+ - Show Shipping Request.
124
+
125
+ ## [0.7.6] - 2015-09-25
126
+ ### Changed
127
+ - Updating readme to reflect changes with javascript callback function.
128
+ - Added checkup of basket shipping price on server side.
129
+
130
+ ## [0.7.5] - 2015-09-15
131
+ ### Added
132
+ - Configuration parameters for environments and secure urls
133
+
134
+
135
+ ## [0.7.4] - 2015-09-15
136
+ ### Added
137
+ - Last Mile Confirmation Response now deals with response content.
138
+
139
+ ## [0.7.3] - 2015-09-15
140
+ ### Fixed
141
+ - proof read README.md
142
+
143
+ ## [0.7.2] - 2015-09-15
144
+ ### Fixed
145
+ - order_number in the confirmation messages is taken into account for when the order is created (last mile).
146
+
147
+ ## [0.7.1] - 2015-09-15
148
+ ### Fixed
149
+ - changed service url for nektria recs api staging url.
150
+ - Last mile availability response data is returned by javascript method call.
151
+ - Ids are Initialized in the array. Data provided by previous method call is injected.
152
+ - get order_number in the confirmation message
153
+ - typo in ClassicAvailabilityRequest (missing new).
154
+
155
+ ### Added
156
+ - modal displays information about terms and conditions and FAQs.
157
+ - unselect all button works.
158
+
159
+ ## [0.7] - 2015-09-15
160
+ ### Added
161
+ - getPriceMatrix built with response from the availability request (used to be dummy data).
162
+ - Time Windows chosen by the shopper is returned by the getUserCalendarSelection method.
163
+ - Availabilities submitted to the addOnloadInit method are displayed in the calendar.
164
+ - Calendar appear without prices for shopper preselection, and after clicking "ver precios de envio" it appears with the prices. Both selections are stored and returned later.
165
+
166
+ ### Fixed
167
+ - fixed wrong index in ServiceCreationResponse
168
+
169
+ ## [0.6.1] - 2015-09-15
170
+ ### Changed
171
+
172
+ - order_number is no more compulsory in service request
173
+
174
+ ## [0.6] - 2015-09-04
175
+ ### Changed
176
+ - updated README.md to reflect new format in js asset: function calls prefixed by recs_ have been replaced by method calls of the object nektria_recs without prefix. Example: recs_showTimeWindowArea is now recs_nektria.showTimeWindowArea().
177
+ - nektria_recs.getTotalPrice() has been added and documented in the README.md, step 8).
178
+ - created CHANGELOG.md
179
+
180
+ ## [0.2] - 2015-09-03
181
+ ### Changed
182
+ - API side: all css styles now are prefixed with the id of the div containing the widget: rec-timewindow.
183
+ - recs_getTotalPrice() (now nektria_recs.getTotalPrice()) function in the javascript asset provided by the API is now returning the actual total price. On the other hand, it has been documented in the README.md
184
+ - updated test.php so that it works fine with newly released API.
185
+
186
+ ## [0.1] - 2015-08-22
187
+ ### Added
188
+ - first release
189
+
190
+
191
+ [0.1]: https://bitbucket.org/nektria/merchant-api-client/commits/1e0b69613401a2e58dde192c0fd94ef4fa5bb2ae
192
+ [0.2]: https://bitbucket.org/nektria/merchant-api-client/commits/27fb81a76df2ce2d77fff94248909769d91c9dae
193
+ [0.3]: #
app/code/community/Nektria/ReCS/lib/Nektria/LICENSE.md ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Apache License
2
+ Version 2.0, January 2004
3
+
4
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5
+
6
+ ## 1. Definitions.
7
+
8
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1
9
+ through 9 of this document.
10
+
11
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the
12
+ License.
13
+
14
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled
15
+ by, or are under common control with that entity. For the purposes of this definition, "control" means
16
+ (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract
17
+ or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial
18
+ ownership of such entity.
19
+
20
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
21
+
22
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software
23
+ source code, documentation source, and configuration files.
24
+
25
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form,
26
+ including but not limited to compiled object code, generated documentation, and conversions to other media
27
+ types.
28
+
29
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License,
30
+ as indicated by a copyright notice that is included in or attached to the work (an example is provided in the
31
+ Appendix below).
32
+
33
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from)
34
+ the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent,
35
+ as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not
36
+ include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work
37
+ and Derivative Works thereof.
38
+
39
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any
40
+ modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to
41
+ Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to
42
+ submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of
43
+ electronic, verbal, or written communication sent to the Licensor or its representatives, including but not
44
+ limited to communication on electronic mailing lists, source code control systems, and issue tracking systems
45
+ that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but
46
+ excluding communication that is conspicuously marked or otherwise designated in writing by the copyright
47
+ owner as "Not a Contribution."
48
+
49
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been
50
+ received by Licensor and subsequently incorporated within the Work.
51
+
52
+ ## 2. Grant of Copyright License.
53
+
54
+ Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
55
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
56
+ Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such
57
+ Derivative Works in Source or Object form.
58
+
59
+ ## 3. Grant of Patent License.
60
+
61
+ Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
62
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent
63
+ license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such
64
+ license applies only to those patent claims licensable by such Contributor that are necessarily infringed by
65
+ their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such
66
+ Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim
67
+ or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work
68
+ constitutes direct or contributory patent infringement, then any patent licenses granted to You under this
69
+ License for that Work shall terminate as of the date such litigation is filed.
70
+
71
+ ## 4. Redistribution.
72
+
73
+ You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without
74
+ modifications, and in Source or Object form, provided that You meet the following conditions:
75
+
76
+ 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
77
+
78
+ 2. You must cause any modified files to carry prominent notices stating that You changed the files; and
79
+
80
+ 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent,
81
+ trademark, and attribution notices from the Source form of the Work, excluding those notices that do
82
+ not pertain to any part of the Derivative Works; and
83
+
84
+ 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that
85
+ You distribute must include a readable copy of the attribution notices contained within such NOTICE
86
+ file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one
87
+ of the following places: within a NOTICE text file distributed as part of the Derivative Works; within
88
+ the Source form or documentation, if provided along with the Derivative Works; or, within a display
89
+ generated by the Derivative Works, if and wherever such third-party notices normally appear. The
90
+ contents of the NOTICE file are for informational purposes only and do not modify the License. You may
91
+ add Your own attribution notices within Derivative Works that You distribute, alongside or as an
92
+ addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be
93
+ construed as modifying the License.
94
+
95
+ You may add Your own copyright statement to Your modifications and may provide additional or different license
96
+ terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative
97
+ Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the
98
+ conditions stated in this License.
99
+
100
+ ## 5. Submission of Contributions.
101
+
102
+ Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by
103
+ You to the Licensor shall be under the terms and conditions of this License, without any additional terms or
104
+ conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate
105
+ license agreement you may have executed with Licensor regarding such Contributions.
106
+
107
+ ## 6. Trademarks.
108
+
109
+ This License does not grant permission to use the trade names, trademarks, service marks, or product names of
110
+ the Licensor, except as required for reasonable and customary use in describing the origin of the Work and
111
+ reproducing the content of the NOTICE file.
112
+
113
+ ## 7. Disclaimer of Warranty.
114
+
115
+ Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor
116
+ provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
117
+ or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT,
118
+ MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the
119
+ appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of
120
+ permissions under this License.
121
+
122
+ ## 8. Limitation of Liability.
123
+
124
+ In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless
125
+ required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any
126
+ Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential
127
+ damages of any character arising as a result of this License or out of the use or inability to use the Work
128
+ (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or
129
+ any and all other commercial damages or losses), even if such Contributor has been advised of the possibility
130
+ of such damages.
131
+
132
+ ## 9. Accepting Warranty or Additional Liability.
133
+
134
+ While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for,
135
+ acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this
136
+ License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole
137
+ responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold
138
+ each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason
139
+ of your accepting any such warranty or additional liability.
140
+
141
+ END OF TERMS AND CONDITIONS
app/code/community/Nektria/ReCS/lib/Nektria/README.md ADDED
@@ -0,0 +1,658 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##Merchant API Client Library for PHP
2
+
3
+ This is a Software Development Kit for Merchants that want to use Nektria Responsive eCommerce Shipping Services. After explaining the basics of the API, we provide the full integration workflow that needs to be followed to propose Nektria Delivery Service to the eCommerce shoppers.
4
+
5
+
6
+ ## Test and Configuration
7
+
8
+ A test request is made available to verify the connection to the SDK for a given API key. All requests implement the exectute method which will throw an ApiClientException if the API returns an error response (status code 4xx and 5xx).
9
+
10
+ ### Create and Run a Test Request
11
+
12
+ ```
13
+ $request = new Nektria\Recs\MerchantApi\Requests\TestRequest([
14
+ 'APIKEY' => 'dGVzdDp0ZXN0'
15
+ ]);
16
+
17
+ // Execute the 'test' method to check the connection with the API
18
+ try {
19
+ $response = $request->execute();
20
+ } catch (ApiClientException $e) {
21
+ echo "There was an error connecting with the API : ".$e->getMessage();
22
+ }
23
+
24
+ ```
25
+
26
+ ### Debug mode
27
+
28
+ example
29
+
30
+ ```
31
+ $recsClient = new Nektria\Recs\MerchantApi\Client([
32
+ 'debug' => true
33
+ ]);
34
+ ```
35
+ Default value is false.
36
+
37
+ ### Environment and Sandbox
38
+
39
+
40
+ All requests are run against the live environment. In order to make requests that will not result in real orders, you can use the sandbox service using the following parameter:
41
+
42
+ ```
43
+ $recsClient = new Nektria\Recs\MerchantApi\Client([
44
+ 'environment' => 'sandbox'
45
+ ]);
46
+ ```
47
+ Default value is 'production'.
48
+
49
+ ### Request Timeouts
50
+
51
+ The `timeout` and `connect\_timeout` options set the maximum time API requests will wait for the connection or the reply.
52
+ The default values are 3 seconds for connection, and 5 seconds for a reply.
53
+
54
+ ```
55
+ $recsClient = new Nektria\Recs\MerchantApi\Client([
56
+ 'timeout' => 2.25,
57
+ 'connect_timeout' => 1.5
58
+ ]);
59
+ ```
60
+
61
+ ### More Request and Response examples
62
+
63
+ Here is a service creation request run against the sandbox with debug information.
64
+
65
+ ```
66
+ $sr = new Nektria\Recs\MerchantApi\Requests\ServiceCreationRequest([
67
+ 'APIKEY' => 'dGVzdDp0ZXN0',
68
+ 'environment' => 'sandbox',
69
+ 'debug' => true
70
+ ]);
71
+
72
+ $response = $sr->execute([
73
+ "session_timeout" => 600,
74
+ "currency_code" => "EUR",
75
+ "shopper" => [
76
+ "name" => "Roberto",
77
+ "surname" => "Rodríguez",
78
+ "email" => "roberto.rodriguez@gmail.com",
79
+ "phone" => "83486923409"
80
+ ],
81
+ "destination_address" => [
82
+ "postal_code" => "08022",
83
+ "street_name" => "Urquinaona",
84
+ "street_number" => "5",
85
+ "city" => "Barcelona",
86
+ "country_code" => "ES"
87
+ ],
88
+ "products" => [
89
+ [
90
+ "name" => "T-shirt Monashee",
91
+ "reference" => "PQR48-D",
92
+ "quantity" => 1,
93
+ "weight_kg" => 0.5
94
+ ],
95
+ [
96
+ "name" => "Jeans Lemon pie",
97
+ "reference" => "WDV48-D",
98
+ "quantity" => 2,
99
+ "weight_kg" => 0.5
100
+ ]
101
+ ]
102
+ ]);
103
+ ```
104
+
105
+ or a last mile availability request run in production
106
+
107
+ ```
108
+ $lmar = new Nektria\Recs\MerchantApi\Requests\LastMileAvailabilityRequest([
109
+ 'APIKEY' => 'dGVzdDp0ZXN0',
110
+ 'id' => '1234'
111
+ ]);
112
+
113
+ $request_body_params = array("service_type" => "last-mile-only");
114
+ $response = $lmar->execute($request_body_params);
115
+ ```
116
+
117
+ ### Exceptions
118
+
119
+ All SDK exceptions are children of the base exception Nektria\Recs\MerchantApi\Exceptions\ApiClientException.
120
+
121
+ Any request that receives an error response when executed (http status code 4xx or 5xx) throws a Nektria\Recs\MerchantApi\Exceptions\ApiResponseException. This exception provides the following methods:
122
+
123
+ - exact http status code: __getCode__ method
124
+ - api specific error code: __getApiErrorCode__ method.
125
+ - error message: __getMessage__ method
126
+ - (sometimes) details about the error: __getApiMessageBody__ method.
127
+
128
+ Here comes a list of API specific error codes, along with the corresponding http error code:
129
+
130
+ - \#1. Formato de mensaje incorrecto. (HTTP 400 Bad Request)
131
+ - \#2. ContentType no válido. (HTTP 415 Unsupported Media Type)
132
+ - \#3. Falta cuerpo del mensaje. (HTTP 400 Bad Request)
133
+ - \#4. El usuario o la contraseña no son correctos. (HTTP 401 Unauthorized)
134
+ - \#5. No puede acceder a este recurso. (HTTP 403 Forbidden)
135
+ - \#6. El método que se quiere aplicar a este recurso ha expirado (http 400 Bad Request)
136
+ - \#7. El formato o los datos de la petición son incorrectos. (HTTP 422 Unprocesable Entity)
137
+ - \#20. Código de moneda incorrecto (HTTP 422 Unprocesable Entity)
138
+ - \#21. Código de moneda no soportado (HTTP 422 Unprocesable Entity)
139
+ - \#22. Código de país incorrecto (HTTP 422 Unprocesable Entity)
140
+ - \#23. Código de país no soportado (HTTP 422 Unprocesable Entity)
141
+ - \#24. Código Postal incorrecto (HTTP 422 Unprocesable Entity)
142
+ - \#25. Ventana horaria incorrecta (HTTP 422 Unprocesable Entity)
143
+
144
+ ## Workflow for merchant modules
145
+
146
+ Here follows a list of steps to integrate the module with a user checkout process.
147
+
148
+ ### Initialize carriers availabilities
149
+
150
+ 0) Find price to be displayed for the last mile option (whenever we need to display this price before we know shopper's address)
151
+ 1) Setup the service, get service number and service type (_HOOK\_GATHER\_CARRIERS_)<br/>
152
+ 2) Hook the classic delivery carrier module<br/>
153
+ 3) Hook the last mile delivery carrier module
154
+
155
+ ```
156
+ // 0) Last Mile Price
157
+ $scr = new Nektria\Recs\MerchantApi\Requests\LastMileBestPriceRequest([
158
+ 'APIKEY' => 'dGVzdDp0ZXN0'
159
+ ]);
160
+
161
+ $response = $scr->execute([
162
+ "destination_address" => $basket->getShopperAddress(),
163
+ "products" => $basket->getProductsDetails()
164
+ ]);
165
+
166
+ $best_price = $response->getBestPrice();
167
+ $best_price_currency = $response->getBestPriceCurrency();
168
+ ```
169
+ ...
170
+
171
+ ```
172
+ // 1) Service Setup
173
+ $scr = new Nektria\Recs\MerchantApi\Requests\ServiceCreationRequest([
174
+ 'APIKEY' => 'dGVzdDp0ZXN0'
175
+ ]);
176
+
177
+ $response = $scr->execute([
178
+ "session_timeout" => 600,
179
+ "currency_code" => "EUR",
180
+ "shopper" => $basket->getShopperDetails(),
181
+ "destination_address" => $basket->getShopperAddress(),
182
+ "products" => $basket->getProductsDetails()
183
+ ]);
184
+
185
+ $id = $response->getServiceNumber();
186
+ $service_type = $response->getServiceType();
187
+ ```
188
+ ...
189
+
190
+ ```
191
+ // 2) Classic carrier hook
192
+ $car = new Nektria\Recs\MerchantApi\Requests\ClassicAvailabilityRequest([
193
+ 'APIKEY' => 'dGVzdDp0ZXN0',
194
+ 'id' => $id
195
+ ]);
196
+
197
+ $response = $car->execute(array(
198
+ "service_type" => $service_type
199
+ ));
200
+
201
+ if($response->isAvailable())
202
+ your_display_classic_carrier($response->getPrice());
203
+ ```
204
+ ...
205
+
206
+ ```
207
+
208
+ // 3) Last Mile carrier hook
209
+ $lmar = new Nektria\Recs\MerchantApi\Requests\LastMileAvailabilityRequest([
210
+ 'APIKEY' => 'dGVzdDp0ZXN0',
211
+ 'id' => $id
212
+ ]);
213
+
214
+ $response = $lmar->execute(array(
215
+ "service_type" => $service_type
216
+ ));
217
+
218
+ if($response->isAvailable())
219
+ {
220
+ your_display_last_mile_carrier($response->getBestPrice());
221
+ $price_matrix = $response->getPriceMatrix();
222
+ your_store_string_into_session($price_matrix);
223
+ }
224
+
225
+ ```
226
+
227
+ ### Initialize last mile widget
228
+
229
+ This needs to be done only if the last mile availability request has returned some availability. There is no harm if it is always done, however, since it will stay hidden.
230
+
231
+ 4) Get the list of resources (_HOOK\_SHOW\_LM\_CARRIER_), specifying language settings and version number. At the moment, the only version version we manage is '1', and the only
232
+ language is 'es_ES'.<br/>
233
+ 5) Place the resources in the layout
234
+
235
+ - a) js
236
+ - b) css
237
+ - c) html
238
+
239
+ 6) Setup javascript to manage widget information:
240
+
241
+ - a) Setup the selection of last mile carrier to trigger the javascript method `nektria_recs.showTimeWindowArea()`<br/>
242
+ - b) Setup the unselection of last mile carrier to trigger the javascript method `nektria_recs.hideTimeWindowArea()`<br/>
243
+ - c) Setup callback function:
244
+
245
+ ***It performs the following tasks***
246
+
247
+ * Update shopping cart with transportation information provided
248
+ * Update total cost corresponding to selected option
249
+
250
+ ***And takes two parameters***
251
+
252
+ * @param string `user_calendar_selection` json that needs to be stored and passed to last mile validation request
253
+ * @param float `total_price` price of the selected transportation option
254
+
255
+ - d) Once the widget html has been loaded, call javascript method that initializes available windows `nektria_recs.initTimeWindowPrices(<?php echo $price_matrix; ?>, callback_function);`
256
+
257
+ The Controller could go like this
258
+
259
+ ```
260
+ // 4) After carriers are loaded, get resources
261
+ $ar = new Nektria\Recs\MerchantApi\Requests\getAssetsRequest([
262
+ 'APIKEY' => 'dGVzdDp0ZXN0',
263
+ 'id' => $id,
264
+ ]);
265
+
266
+ $response = $ar->execute(array('version' => 1, 'language' => 'es_ES'));
267
+ $css_url = $response->getCssUrl();
268
+ $js_url = $response->getJsUrl();
269
+ $html_url = $response->getHtmlUrl();
270
+ ```
271
+
272
+ Here is how it may look like in the Template
273
+
274
+ ```
275
+ <head>
276
+ ....
277
+ <!-- 5a) place js -->
278
+ <script src="<?php print $js_url; ?>"></script>
279
+ <!-- 5b) place css -->
280
+ <link rel="stylesheet" href="<?php print $css_url; ?>" />
281
+
282
+ <!-- 6c) Create callback function -->
283
+ <script>
284
+ your_cbfunction_8473028 = function(user_calendar_selection, total_price)
285
+ {
286
+ // Add to the basket: user_calendar_selection;
287
+ (...)
288
+ // update_total_price
289
+ (...)
290
+ }
291
+ </script>
292
+ ```
293
+ ....
294
+
295
+ ```
296
+ </head>
297
+ <body>
298
+
299
+ <li>
300
+ <!-- 6a) show price grid when last mile selected -->
301
+ <input name="shipping_method" type="radio" value="nektria" id="s_method_matrixrate_matrixrate_10046" class="radio validate-one-required-by-name" onclick="nektria_recs.showTimeWindowArea()">
302
+ <label for="s_method_matrixrate_matrixrate_10046">ReCS <span class="price">8,16 €</span> </label>
303
+ </li>
304
+ <li>
305
+ <!-- 6b) hide price grid when last mile selected -->
306
+ <input name="shipping_method" type="radio" value="nacex" id="s_method_matrixrate_matrixrate_10041" class="radio" onclick="nektria_recs.hideTimeWindowArea()">
307
+ <label for="s_method_matrixrate_matrixrate_10041">NACEX <span class="price">8,12 €</span> </label>
308
+ </li>
309
+ ```
310
+ ....
311
+
312
+ ```
313
+ <!-- 5c) place html -->
314
+ <?php print file_get_contents($html_url); ?>
315
+ ....
316
+ </body>
317
+
318
+ ```
319
+ ....
320
+
321
+ ```
322
+ <!-- 6d) Init widget -->
323
+
324
+ <script type="text/javascript">
325
+ nektria_recs.initTimeWindowPrices(<?php print $price_matrix; ?>, your_cbfunction_8473028);
326
+ </script>
327
+
328
+ ```
329
+
330
+ 7) If the page is being reloaded and a selection was done previously, call the `nektria_recs.updateSelectedWindows(user_calendar_selection)` method to
331
+ make sure the calendar appears with correctly selected cells. The parameter `user_calendar_selection` is the one that was passed by the widget to the callback function.
332
+
333
+ ### If classic carrier is chosen by the shopper
334
+
335
+ 8) Confirm Classic Carrier after the user has made the payment (_HOOK\_ORDER\_CONFIRMED_).
336
+
337
+ ```
338
+ // 8) Order Confirmed hook
339
+ $ccr = new Nektria\Recs\MerchantApi\Requests\ClassicConfirmationRequest([
340
+ 'APIKEY' => 'dGVzdDp0ZXN0',
341
+ 'id' => $id
342
+ ]);
343
+
344
+ $response = $ccr->execute(array("order_number" => $basket->getOrderNumber()));
345
+ ```
346
+
347
+ __And your are done !__
348
+
349
+ ### If last mile carrier is chosen by the shopper
350
+
351
+ 8) !! Make sure the price provided in the user selection for the API matches the price in the shopper basket
352
+ 9) Validate last mile request with information retrieved from final selection.<br/>
353
+ 10) Just before the payment, refresh the shipping order. (_HOOK\_PRE\_PAYMENT_)<br/>
354
+ 11) After the payment, confirm the shipping order. (_HOOK\_ORDER\_CONFRIMED_)
355
+
356
+
357
+ ```
358
+ // 8) Check basket shipping price matches the one provided to the API
359
+ $user_selection = your_get_user_calendar_selection_from_the_basket();
360
+ $a = json_decode($user_selection ,true);
361
+ $shipping_price = $a["total_price"];
362
+ basket_shipping_price = your_pickup_basket_shipping_price();
363
+ if($shipping_price != $basket_shipping_price)
364
+ throw new BookingException("Price mismatch - the price in the basket is incorrect");
365
+
366
+ // 9) When carrier is chosen, validate the shipping order
367
+ $lmvr = new Nektria\Recs\MerchantApi\Requests\LastMileValidationRequest([
368
+ 'APIKEY' => 'dGVzdDp0ZXN0',
369
+ 'id' => $id
370
+ ]);
371
+
372
+ $response = $lmvr->execute($user_selection);
373
+ ```
374
+ ...
375
+
376
+ ```
377
+ // 10) Before payment, make sure shipping order does not expire
378
+ $kar = new Nektria\Recs\MerchantApi\Requests\KeepAliveRequest([
379
+ 'APIKEY' => 'dGVzdDp0ZXN0',
380
+ 'id' => $id
381
+ ]);
382
+
383
+ $response = $kar->execute();
384
+ ```
385
+ ...
386
+
387
+ ```
388
+ // 11) When order is confirmed, confirm shipping
389
+ $lmcr = new Nektria\Recs\MerchantApi\Requests\LastMileConfirmationRequest([
390
+ 'APIKEY' => 'dGVzdDp0ZXN0',
391
+ 'id' => $id
392
+ ]);
393
+
394
+ $response = $lmcr->execute(array(
395
+ "order_number" => $basket->getOrderNumber()
396
+ ));
397
+ ```
398
+
399
+ __And your are done !__
400
+
401
+ ## eCommerce Backend
402
+
403
+ ### Configuration
404
+
405
+ In the eCommerce config panel, we will see the following options:
406
+
407
+ - api key
408
+ - sandbox mode
409
+
410
+ ### Registration link
411
+
412
+ The registration link must be made available next to the api key field: with a label "Sing up or Log In", the link will
413
+ open a full window popup to a page where the user will be able to create an account. If he is already registered, he will
414
+ be able to access a control panel with his credentials.
415
+
416
+ ```
417
+ // Module configuration controller
418
+ $rar = new Nektria\Recs\MerchantApi\Requests\RegistrationAccessRequest(
419
+ // no API key is needed
420
+ );
421
+
422
+ $response = $rar->execute();
423
+
424
+ $url = $response->getRegistrationUrl();
425
+ ```
426
+
427
+ then in the view we may have something like this (new tab trick version)
428
+
429
+ ```
430
+ <!-- Module configuration view -->
431
+ <script type="text/javascript">
432
+ function OpenInNewTab(url) {
433
+ var win = window.open(url, '_blank');
434
+ win.focus();
435
+ }
436
+ </script>
437
+ <div onclick='OpenInNewTab("<?php echo $url ?>");'>Sign up or Log In</div>
438
+ ```
439
+
440
+ ### Advanced Configuration
441
+
442
+ Advanced configuration options are made available on a specific webpage. This url will be retrieved calling the getBackendUrl
443
+ method of a BackendAccessResponse object. It will be made available to the merchant ideally via an iframe in a modal window,
444
+ though a simple popup would cover the needs. This url will have a timeout, ideally bigger than the session timeout of
445
+ Magento backend.
446
+
447
+ ```
448
+ // Module configuration controller
449
+ $br = new Nektria\Recs\MerchantApi\Requests\BackendAccessRequest([
450
+ 'APIKEY' => 'dGVzdDp0ZXN0'
451
+ ]);
452
+
453
+ $response = $br->execute();
454
+
455
+ $url = $response->getBackendUrl();
456
+ ```
457
+
458
+ then in the view we may have something like this (popup version)
459
+
460
+ ```
461
+ <!-- Module configuration view -->
462
+ <a href="<?php echo $url ?>" target="_blank" onClick="window.open(this.href, this.target, 'width=800,height=600'); return false;">
463
+ Advanced Configuration
464
+ onboiarding&co cs</a>
465
+ ```
466
+
467
+ ### Shipping information
468
+
469
+ Information about a given shipping can be displayed using the ShowShippingRequest object, which will generate a ShowShippingResponse. The ShowShippingHelper provides methods to display this response in the backend.
470
+ Note: if a shipping has no last mile, then nothing should be shown.
471
+
472
+ ```
473
+ // Show Shipping Controller
474
+ $ccr = new Nektria\Recs\MerchantApi\Requests\ShowShippingRequest([
475
+ 'APIKEY' => 'dGVzdDp0ZXN0',
476
+ 'id' => $id
477
+ ]);
478
+
479
+ $response = $ccr->execute();
480
+ $recs_shipping_info = new Nektria\Recs\MerchantApi\ShowShippingHelper($response, $locale);
481
+ ```
482
+
483
+ ```
484
+ // Show Shipping View
485
+ <? if($recs_shipping_info->hasLastMile())
486
+ {
487
+ echo "Estado del envío: ".$recs_shipping_info->getStatus()."<br/>";
488
+ echo "Franjas horarias de entrega: "
489
+ foreach($recs_shipping_info->getDeliveryWindows() as $window)
490
+ echo $window."<br/>";
491
+ }
492
+ ]);
493
+
494
+ $response = $ccr->execute();
495
+ ```
496
+
497
+ ### List of countries where we have operations
498
+
499
+ You can get a list of the countries where we have operations. This will come as a list of ISO 3166 2 letters codes when
500
+ running the getCoveredCountries method of the CoverageResponse object, obtained as follow
501
+
502
+ ```
503
+ // Module configuration controller
504
+ $cr = new Nektria\Recs\MerchantApi\Requests\CoverageRequest([
505
+ 'APIKEY' => 'dGVzdDp0ZXN0'
506
+ ]);
507
+
508
+ $response = $cr->execute();
509
+
510
+ $countries = $response->getCoveredCountries();
511
+ ```
512
+
513
+ ## Data Formats used in the requests
514
+
515
+
516
+ ### Addresses
517
+
518
+ The addresses will be used to identify where to deliver the products. They are structured as follow:
519
+
520
+ - postal_code
521
+ - Type: String
522
+ - Required: Yes
523
+ - Description: postal code
524
+ - street_type
525
+ - Type: String
526
+ - Required: No
527
+ - Description: street type (street, place, etc.)
528
+ - street_name
529
+ - Type: String
530
+ - Required: Yes
531
+ - Description: street name.
532
+ - street_number
533
+ - Type: Integer
534
+ - Required: No
535
+ - Description: street number
536
+ - floor
537
+ - Type: String
538
+ - Required: No
539
+ - Description: floor
540
+ - door
541
+ - Type: String
542
+ - Required: No
543
+ - Description: door
544
+ - city
545
+ - Type: String
546
+ - Required: Yes
547
+ - Description: city name
548
+ - province
549
+ - Type: String
550
+ - Required: No
551
+ - Description: province
552
+ - country_code
553
+ - Type: CountryCode
554
+ - Required: Yes
555
+ - Description: 2 letter ISO3166 code of the country.
556
+
557
+ ### Shoppers
558
+
559
+ Shopper information is used to identify the shopper and provides contact information.
560
+
561
+ - name
562
+ - Type: String
563
+ - Required: Yes
564
+ - Description: name
565
+ - surname
566
+ - Type: String
567
+ - Required: Yes
568
+ - Description: surnames.
569
+ - email
570
+ - Type: String
571
+ - Required: Yes
572
+ - Description: email
573
+ - phone
574
+ - Type: String
575
+ - Required: No
576
+ - Description: phone number
577
+
578
+ ### Products
579
+
580
+ Products are identified by their type, their availability, price and size.
581
+
582
+ - name
583
+ - Type: String
584
+ - Required: Yes
585
+ - Description: product name
586
+ - reference
587
+ - Type: String
588
+ - Required: Yes
589
+ - Description: product reference in eCommerce.
590
+ - quantity
591
+ - Type: Integer
592
+ - Required: Yes
593
+ - Description: number of products of this type in the basket
594
+ - Size
595
+ - Type: SizeType
596
+ - Required: No
597
+ - Description: product size
598
+ - weight_kg
599
+ - Type: Float
600
+ - Required: No
601
+ - Description: peso de un producto en kg - origin_information
602
+ - price
603
+ - Type: Price (float with 2 decimal digits maximum)
604
+ - Required: No
605
+ - Description: price of one product.
606
+ - currency_code
607
+ - Type: Currency Code
608
+ - Required: No
609
+ - Description: currency code as defined in ISO4217. For now, we will only accept transactions in euros ("EUR")
610
+
611
+ ### Size
612
+
613
+ Product Size is defined as follow:
614
+
615
+ - height_cm
616
+ - Type: Integer
617
+ - Required: Yes
618
+ - Description: height in cm
619
+ - width_cm
620
+ - Type: Integer
621
+ - Required: Yes
622
+ - Description: width in cm
623
+ - depth_cm
624
+ - Type: Integer
625
+ - Required: Yes
626
+ - Description: depth in cm
627
+
628
+
629
+ ## Appendix - Under the hood
630
+
631
+ All the following method calls are used in the Nektria\Recs\MerchantApi\Requests\BaseRequest class. All SDK requests inherit from BaseRequest, and use transparently these methods, transmitting all the parameters that are passed in the constructor.
632
+
633
+ ### Create the ReCS API client
634
+
635
+ ```
636
+ <?php
637
+ // Require the Composer autoloader.
638
+ require 'vendor/autoload.php';
639
+
640
+ // Instantiate an ReCS client using your API KEY.
641
+ $recsClient = new Nektria\Recs\MerchantApi\Client([
642
+ 'APIKEY' => 'my-own-api-key'
643
+ ]);
644
+ ```
645
+
646
+ ### Run a configured request
647
+
648
+ For example, the test request.
649
+
650
+ ```
651
+ <?php
652
+ // Execute the 'test' method to check the connection with the API
653
+ try {
654
+ $recsClient->test();
655
+ } catch (Exception $e) {
656
+ echo "There was an error connecting with the API : ".$e->getMessage();
657
+ }
658
+ ```
app/code/community/Nektria/ReCS/lib/Nektria/composer.json ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name" : "nektria/recs-sdk-php",
3
+ "homepage" : "http://recs.nektria.com",
4
+ "description" : "Nektria Responsive eCommerce Shipping (ReCS) SDK for PHP",
5
+ "keywords" : [
6
+ "recs",
7
+ "nektria",
8
+ "sdk",
9
+ "shipping",
10
+ "lastmile",
11
+ "carrier",
12
+ "ecommerce"
13
+ ],
14
+ "type" : "library",
15
+ "license" : "Apache-2.0",
16
+ "authors" : [{
17
+ "name" : "Nektria",
18
+ "homepage" : "http://www.nektria.com/"
19
+ }
20
+ ],
21
+ "require" : {
22
+ "php" : ">=5.4",
23
+ "guzzlehttp/guzzle" : "5.3",
24
+ "guzzlehttp/guzzle-services" : "0.5.*",
25
+ "guzzlehttp/log-subscriber" : "~1.0"
26
+ },
27
+ "require-dev" : {
28
+ "phpunit/phpunit" : "4.*"
29
+ },
30
+ "suggest" : {
31
+ "ext-curl" : "To send requests using cURL"
32
+ },
33
+ "autoload" : {
34
+ "psr-4" : {
35
+ "Nektria\\Recs\\MerchantApi\\" : "src/"
36
+ }
37
+ },
38
+ "autoload-dev" : {
39
+ "psr-4" : {
40
+ "Nektria\\Recs\\MerchantApi\\Test\\" : "tests/"
41
+ }
42
+ }
43
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Address.php ADDED
@@ -0,0 +1,377 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi;
4
+
5
+ /**
6
+ * Address
7
+ *
8
+ */
9
+ class Address
10
+ {
11
+ /**
12
+ * @var string
13
+ */
14
+ private $streetType;
15
+
16
+ /**
17
+ * @var string
18
+ */
19
+ private $streetName;
20
+
21
+ /**
22
+ * @var string
23
+ */
24
+ private $streetNumber;
25
+
26
+ /**
27
+ * @var string
28
+ */
29
+ private $stairBuilding;
30
+
31
+ /**
32
+ * @var string
33
+ */
34
+ private $floor;
35
+
36
+ /**
37
+ * @var string
38
+ */
39
+ private $door;
40
+
41
+ /**
42
+ * @var string
43
+ */
44
+ private $city;
45
+
46
+ /**
47
+ * @var string
48
+ */
49
+ private $province;
50
+
51
+ /**
52
+ * @var string
53
+ */
54
+ private $country_code;
55
+
56
+ /**
57
+ * @var string
58
+ */
59
+ private $postalCode;
60
+
61
+ /**
62
+ * Build this Location from a array
63
+ * @param array $params
64
+ */
65
+ public function __construct(array $params = null)
66
+ {
67
+ if(is_null($params)) return;
68
+
69
+ foreach(array("postal_code", "street_name", "city", "country_code") as $key)
70
+ if(! array_key_exists($key, $params))
71
+ throw new \Exception("key $key is compulsory in Address constructor.");
72
+
73
+ $this->setPostalCode($params["postal_code"])
74
+ ->setStreetType($params["street_type"])
75
+ ->setStreetName($params["street_name"])
76
+ ->setCity($params["city"])
77
+ ->setCountryCode($params["country_code"]);
78
+
79
+ if(array_key_exists("street_type", $params))
80
+ $this->setStreetType($params["street_type"]);
81
+ if(array_key_exists("street_number", $params))
82
+ $this->setStreetNumber($params["street_number"]);
83
+ if(array_key_exists("floor", $params))
84
+ $this->setFloor($params["floor"]);
85
+ if(array_key_exists("door", $params))
86
+ $this->setDoor($params["door"]);
87
+ }
88
+
89
+ public function asArray()
90
+ {
91
+ $result = array(
92
+ "postal_code" => $this->getPostalCode(),
93
+ "street_type" => $this->getStreetType(),
94
+ "street_name" => $this->getStreetName(),
95
+ "city" => $this->getCity(),
96
+ "country_code" => $this->getCountryCode()
97
+ );
98
+
99
+ if($this->hasStreetNumber())
100
+ $result["street_number"] = $this->getStreetNumber();
101
+
102
+ if($this->hasFloor())
103
+ $result["floor"] = $this->getFloor();
104
+
105
+ if($this->hasDoor())
106
+ $result["door"] = $this->getDoor();
107
+
108
+ return $result;
109
+ }
110
+
111
+ /**
112
+ * Set streetName
113
+ *
114
+ * @param string $streetName
115
+ * @return Address
116
+ */
117
+ public function setStreetName($streetName)
118
+ {
119
+ $this->streetName = $streetName;
120
+
121
+ return $this;
122
+ }
123
+
124
+ public function hasStreetName()
125
+ {
126
+ return ! is_null($this->streetName);
127
+ }
128
+
129
+ /**
130
+ * Get streetName
131
+ *
132
+ * @return string
133
+ */
134
+ public function getStreetName()
135
+ {
136
+ return $this->streetName;
137
+ }
138
+
139
+ /**
140
+ * Set streetType
141
+ *
142
+ * @param string $streetType
143
+ * @return Address
144
+ */
145
+ public function setStreetType($streetType)
146
+ {
147
+ $this->streetType = $streetType;
148
+
149
+ return $this;
150
+ }
151
+
152
+ public function hasStreetType()
153
+ {
154
+ return ! is_null($this->streetType);
155
+ }
156
+
157
+ /**
158
+ * Get streetType
159
+ *
160
+ * @return string
161
+ */
162
+ public function getStreetType()
163
+ {
164
+ return $this->streetType;
165
+ }
166
+
167
+ /**
168
+ * Set streetNumber
169
+ *
170
+ * @param string $streetNumber
171
+ * @return Address
172
+ */
173
+ public function setStreetNumber($streetNumber)
174
+ {
175
+ $this->streetNumber = $streetNumber;
176
+
177
+ return $this;
178
+ }
179
+
180
+ /**
181
+ * Get streetNumber
182
+ *
183
+ * @return string
184
+ */
185
+ public function getStreetNumber()
186
+ {
187
+ return $this->streetNumber;
188
+ }
189
+
190
+ private function hasStreetNumber(){ return ! is_null($this->streetNumber); }
191
+
192
+ /**
193
+ * Set stairBuilding
194
+ *
195
+ * @param string $stairBuilding
196
+ * @return Address
197
+ */
198
+ public function setStairBuilding($stairBuilding)
199
+ {
200
+ $this->stairBuilding = $stairBuilding;
201
+
202
+ return $this;
203
+ }
204
+
205
+ /**
206
+ * Get stairBuilding
207
+ *
208
+ * @return string
209
+ */
210
+ public function getStairBuilding()
211
+ {
212
+ return $this->stairBuilding;
213
+ }
214
+
215
+ public function hasStairBuilding(){ return ! $this->stairBuilding == ""; }
216
+ /**
217
+ * Set floor
218
+ *
219
+ * @param string $floor
220
+ * @return Address
221
+ */
222
+ public function setFloor($floor)
223
+ {
224
+ $this->floor = $floor;
225
+
226
+ return $this;
227
+ }
228
+
229
+ /**
230
+ * Get floor
231
+ *
232
+ * @return string
233
+ */
234
+ public function getFloor()
235
+ {
236
+ return $this->floor;
237
+ }
238
+
239
+ private function hasFloor(){ return ! is_null($this->floor); }
240
+
241
+ /**
242
+ * Set door
243
+ *
244
+ * @param string $door
245
+ * @return Address
246
+ */
247
+ public function setDoor($door)
248
+ {
249
+ $this->door = $door;
250
+
251
+ return $this;
252
+ }
253
+
254
+ /**
255
+ * Get door
256
+ *
257
+ * @return string
258
+ */
259
+ public function getDoor()
260
+ {
261
+ return $this->door;
262
+ }
263
+
264
+ private function hasDoor(){ return ! is_null($this->door); }
265
+
266
+ /**
267
+ * Set city
268
+ *
269
+ * @param string $city
270
+ * @return Address
271
+ */
272
+ public function setCity($city)
273
+ {
274
+ $this->city = $city;
275
+
276
+ return $this;
277
+ }
278
+
279
+ /**
280
+ * Get city
281
+ *
282
+ * @return string
283
+ */
284
+ public function getCity()
285
+ {
286
+ return $this->city;
287
+ }
288
+
289
+ public function hasCity()
290
+ {
291
+ return ! is_null($this->city);
292
+ }
293
+
294
+ /**
295
+ * Set province
296
+ *
297
+ * @param string $province
298
+ * @return Address
299
+ */
300
+ public function setProvince($province)
301
+ {
302
+ $this->province = $province;
303
+
304
+ return $this;
305
+ }
306
+
307
+ /**
308
+ * Get province
309
+ *
310
+ * @return string
311
+ */
312
+ public function getProvince()
313
+ {
314
+ return $this->province;
315
+ }
316
+
317
+ public function hasProvince()
318
+ {
319
+ return ! is_null($this->province);
320
+ }
321
+
322
+ /**
323
+ * Set country_code
324
+ *
325
+ * @param string $country_code
326
+ * @return Address
327
+ */
328
+ public function setCountryCode($country_code)
329
+ {
330
+ $this->country_code = $country_code;
331
+
332
+ return $this;
333
+ }
334
+
335
+ /**
336
+ * Get country_code
337
+ *
338
+ * @return string
339
+ */
340
+ public function getCountryCode()
341
+ {
342
+ return $this->country_code;
343
+ }
344
+
345
+ public function hasCountryCode()
346
+ {
347
+ return ! is_null($this->country_code);
348
+ }
349
+
350
+ /**
351
+ * Set postalCode
352
+ *
353
+ * @param string $postalCode
354
+ * @return Address
355
+ */
356
+ public function setPostalCode($postalCode)
357
+ {
358
+ $this->postalCode = $postalCode;
359
+
360
+ return $this;
361
+ }
362
+
363
+ /**
364
+ * Get postalCode
365
+ *
366
+ * @return string
367
+ */
368
+ public function getPostalCode()
369
+ {
370
+ return $this->postalCode;
371
+ }
372
+
373
+ public function hasPostalCode()
374
+ {
375
+ return ! is_null($this->postalCode);
376
+ }
377
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Client.php ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi;
4
+
5
+ use GuzzleHttp\Subscriber\Log\LogSubscriber;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
7
+
8
+ class Client
9
+ {
10
+ private $api_key;
11
+ private $debug=false;
12
+ private $secure=true;
13
+ private $environment="production";
14
+
15
+ /**
16
+ * Settings for base client
17
+ * timeout - request timeout in seconds, default is 5 seconds
18
+ * connect_timeout - connection timeout in seconds, default is 3 seconds
19
+ * exceptions - always set to false (cannot be edited)
20
+ * other ? we would need to specify this manually in initBaseClientSettings
21
+ *
22
+ * @var array
23
+ */
24
+ private $base_client_settings = ['timeout' => 5, 'connect_timeout' => 3, 'exceptions' => false];
25
+
26
+ /**
27
+ * Default settings for service description
28
+ * @var array
29
+ */
30
+ private $service_description_default_settings = [];
31
+
32
+ /**
33
+ * Guzzle service description
34
+ * @var \Nektria\Recs\MerchantApi\Description
35
+ */
36
+ private $serviceDescription;
37
+
38
+ /**
39
+ * Guzzle base client
40
+ * @var \GuzzleHttp\Client
41
+ */
42
+ private $baseClient;
43
+
44
+ /**
45
+ * Api client services
46
+ * @var \GuzzleHttp\Command\Guzzle\GuzzleClient
47
+ */
48
+ private $serviceClient;
49
+
50
+ /**
51
+ * Config settings - for client, among others...
52
+ * APIKEY - compulsory
53
+ * debug - optional, default value false
54
+ * secure - optional, default value no
55
+ * environment - optional, default value production
56
+ * timeout - request timeout in seconds, default is 5 seconds
57
+ * connect_timeout - connection timeout in seconds, default is 3 seconds
58
+ *
59
+ * @param array $settings Each assigned to the relevant attribute
60
+ * @throws ApiClientException
61
+ */
62
+ public function __construct(array $settings = array())
63
+ {
64
+ if( ! array_key_exists('APIKEY', $settings))
65
+ throw new ApiClientException("APIKEY parameter is needed to use the API");
66
+
67
+ $this->api_key = $settings["APIKEY"];
68
+
69
+ if(array_key_exists("debug", $settings)){
70
+ $this->debug = $settings["debug"];
71
+ }
72
+
73
+ if(array_key_exists("environment", $settings)){
74
+ $this->setEnvironment($settings["environment"]);
75
+ }
76
+
77
+ $this->initBaseClientSettings($settings);
78
+ $this->initServiceDescriptionDefaultSettings($settings);
79
+ }
80
+
81
+ /**
82
+ * Environment setter - tied to 'secure' attribute
83
+ * All non development enviroments go over https (secure=true)
84
+ */
85
+ private function setEnvironment($value){
86
+ $this->environment = $value;
87
+ $this->secure = ($value == "development" ? false : true);
88
+ return $this;
89
+ }
90
+
91
+ private function setBaseClientSetting($key, $value){
92
+ $this->base_client_settings[$key] = $value;
93
+ return $this;
94
+ }
95
+
96
+ private function setServiceDescriptionDefaultSetting($key, $value){
97
+ $this->service_description_default_settings[$key] = $value;
98
+ return $this;
99
+ }
100
+
101
+ /**
102
+ * Get settings for the base client
103
+ * exceptions is always set to false
104
+ *
105
+ * @return array
106
+ */
107
+ private function getBaseClientSettings(){
108
+ return $this->base_client_settings;
109
+ }
110
+
111
+ private function getApiKey(){
112
+ return $this->api_key;
113
+ }
114
+
115
+ private function getServiceDescriptionDefaultSettings(){
116
+ return $this->service_description_default_settings;
117
+ }
118
+
119
+
120
+ /**
121
+ * Extract settings related to base client, init corresponding attribute
122
+ * @param array $settings list of all settings
123
+ */
124
+ private function initBaseClientSettings($settings)
125
+ {
126
+ foreach(['timeout', 'connect_timeout'] as $base_setting_key){
127
+ if(array_key_exists($base_setting_key, $settings)){
128
+ $this->setBaseClientSetting($base_setting_key, $settings[$base_setting_key]);
129
+ }
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Filter settings related to service description, init corresponding attribute
135
+ * @param array $settings list of all settings
136
+ */
137
+ private function initServiceDescriptionDefaultSettings($settings){
138
+ $excluded_keys = ["APIKEY", "environment", "timeout", "connect_timeout"];
139
+ $default_settings = array_diff_key ($settings, array_flip($excluded_keys));
140
+ foreach($default_settings as $key => $value){
141
+ $this->setServiceDescriptionDefaultSetting($key, $value);
142
+ }
143
+ }
144
+
145
+ public function __call($method, $parameters)
146
+ {
147
+ $this->buildClientIfNeeded();
148
+
149
+ return call_user_func_array([$this->serviceClient, $method], $parameters);
150
+ }
151
+
152
+ private function buildClientIfNeeded()
153
+ {
154
+ $this->baseClient = new \GuzzleHttp\Client(['defaults' => $this->getBaseClientSettings()]);
155
+
156
+ $this->baseClient->setDefaultOption('headers/Authorization', 'Basic '.$this->getApiKey());
157
+
158
+ $this->buildServiceDescription();
159
+
160
+ $this->serviceClient = new \GuzzleHttp\Command\Guzzle\GuzzleClient(
161
+ $this->baseClient,
162
+ $this->serviceDescription,
163
+ [
164
+ 'emitter' => $this->baseClient->getEmitter(),
165
+ 'defaults' => $this->getServiceDescriptionDefaultSettings()
166
+ ]
167
+ );
168
+
169
+ if($this->debug===true)
170
+ $this->serviceClient->getEmitter()->attach(new LogSubscriber());
171
+ }
172
+
173
+ /**
174
+ * Build base url based on corresponding settings.
175
+ * @return string
176
+ */
177
+ private function buildBaseUrl()
178
+ {
179
+ $protocol = ($this->secure === true) ? "https" : "http";
180
+ switch($this->environment)
181
+ {
182
+ case "development":
183
+ $domain = "localhost:8000";
184
+ break;
185
+ case "sandbox":
186
+ $domain = "recs-staging.herokuapp.com";
187
+ break;
188
+ case "production":
189
+ $domain = "recs.nektria.com";
190
+ break;
191
+ case "timeout":
192
+ $domain = "10.255.255.1";
193
+ break;
194
+ default:
195
+ $domain = "recs.nektria.com";
196
+ }
197
+ return $protocol."://".$domain."/api/";
198
+ }
199
+
200
+ /**
201
+ * Build service description
202
+ * Hook on settings to build the base url
203
+ *
204
+ */
205
+ private function buildServiceDescription()
206
+ {
207
+ $apiDescription = $this->getServiceDefinition('services');
208
+ $apiDescription["baseUrl"] = $this->buildBaseUrl();
209
+
210
+ $this->serviceDescription = new Description($apiDescription);
211
+ }
212
+
213
+ /**
214
+ * Load resource configuration JSON into an array
215
+ * @param string $name - at the moment, always 'services'
216
+ * @return mixed
217
+ */
218
+ private function getServiceDefinition($name)
219
+ {
220
+ $json = file_get_contents(__DIR__.'/services/'.$name.'.json');
221
+ return json_decode($json,true);
222
+ }
223
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Description.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi;
4
+
5
+ use GuzzleHttp\Command\Guzzle\Description as GuzzleDescription;
6
+
7
+ class Description extends GuzzleDescription
8
+ {
9
+ public function setBaseUrl($url)
10
+ {
11
+ $this->baseUrl = $url;
12
+ }
13
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Exceptions/ApiClientException.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Exceptions;
4
+
5
+
6
+ class ApiClientException extends \Exception
7
+ {
8
+
9
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Exceptions/ApiResponseException.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Exceptions;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
7
+
8
+ class ApiResponseException extends ApiClientException
9
+ {
10
+ private $response;
11
+
12
+ /**
13
+ *
14
+ * @param string $status_code
15
+ * @param ResponseBodyWrapper $response
16
+ */
17
+ public function __construct($status_code, ResponseBodyWrapper $response)
18
+ {
19
+ parent::__construct($response->getMessage(), $status_code);
20
+
21
+ $this->response = $response;
22
+ }
23
+
24
+ public function hasApiErrorCode(){ return $this->response->hasCode(); }
25
+ public function hasApiMessageBody(){ return $this->response->hasContent(); }
26
+
27
+ public function getApiErrorCode(){ return $this->response->getCode(); }
28
+ public function getApiMessageBody(){ return $this->response->getContent(); }
29
+
30
+ /**
31
+ * @return string - fail for 4xx, error for 5xx
32
+ */
33
+ public function getApiStatus(){ return $this->response->getStatus(); }
34
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Price.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi;
4
+
5
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
6
+
7
+ class Price
8
+ {
9
+ private $amount;
10
+ private $currency;
11
+
12
+ public function __construct($amount, $currency)
13
+ {
14
+ if($currency != "EUR")
15
+ throw new ApiClientException("Our only accepted currency is EUR.");
16
+
17
+ $this->amount = $amount;
18
+ $this->currency = $currency;
19
+ }
20
+
21
+ public function getAmount(){ return $this->amount; }
22
+ public function getCurrency(){ return $this->currency; }
23
+ public function getCurrencySign(){ return "€"; }
24
+
25
+ public function __toString(){ return $this->getAmount().$this->getCurrencySign(); }
26
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Product.php ADDED
@@ -0,0 +1,289 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi;
4
+
5
+ /**
6
+ * Product
7
+ **/
8
+ class Product
9
+ {
10
+
11
+ /**
12
+ * @var string
13
+ *
14
+ */
15
+ private $reference;
16
+
17
+ /**
18
+ * @var string
19
+ *
20
+ */
21
+ private $name;
22
+
23
+ /**
24
+ * @var float
25
+ */
26
+ private $price;
27
+
28
+ /**
29
+ * @var integer
30
+ */
31
+ private $height;
32
+
33
+ /**
34
+ * @var integer
35
+ */
36
+ private $width;
37
+
38
+ /**
39
+ * @var integer
40
+ */
41
+ private $depth;
42
+
43
+ /**
44
+ * @var float
45
+ */
46
+ private $weight;
47
+
48
+ /**
49
+ * Initialize ride collection
50
+ * Initialized from array format if supplied
51
+ * Note: we do NOT take into account origin_information, as this is another entity.
52
+ *
53
+ * Constructor
54
+ */
55
+ public function __construct(array $params = null)
56
+ {
57
+ if(is_null($params)) return;
58
+
59
+ foreach(array("name", "reference") as $key)
60
+ if(! array_key_exists($key, $params))
61
+ throw new \Exception("key $key is compulsory in Product entity constructor.");
62
+
63
+ if(array_key_exists("size", $params))
64
+ foreach(array("height_cm", "width_cm", "depth_cm") as $key)
65
+ if(! array_key_exists($key, $params["size"]))
66
+ throw new \Exception("key $key is compulsory in Product Size entity constructor (whenever a size is specified).");
67
+
68
+ $this->setName($params["name"]);
69
+ $this->setReference($params["reference"]);
70
+
71
+ if(array_key_exists("size", $params))
72
+ {
73
+ $this->setHeight($params["size"]["height_cm"]);
74
+ $this->setWidth($params["size"]["width_cm"]);
75
+ $this->setDepth($params["size"]["depth_cm"]);
76
+ }
77
+
78
+ $this->setWeight($params["weight_kg"]);
79
+
80
+ if(array_key_exists("price", $params))
81
+ $this->setPrice($params["price"]);
82
+ }
83
+
84
+ public function asArray()
85
+ {
86
+ $result = array(
87
+ "name" => $this->getName(),
88
+ "reference" => $this->getReference(),
89
+ );
90
+
91
+ if($this->hasSize())
92
+ $result["size"] = array(
93
+ "height" => $this->getHeight(),
94
+ "width" => $this->getWidth(),
95
+ "depth" => $this->getDepth()
96
+ );
97
+
98
+ if($this->hasWeight())
99
+ $result["weight"] = $this->getWeight();
100
+
101
+ if($this->hasPrice())
102
+ {
103
+ $result["price"] = $this->getPrice();
104
+ $result["currency_code"] = $this->getCurrencyCode();
105
+ }
106
+
107
+ return $result;
108
+ }
109
+
110
+ /**
111
+ * Set product number
112
+ *
113
+ * @param string $number
114
+ * @return Product
115
+ */
116
+ public function setReference($number)
117
+ {
118
+ $this->reference = $number;
119
+
120
+ return $this;
121
+ }
122
+
123
+ /**
124
+ * Get name
125
+ *
126
+ * @return string
127
+ */
128
+ public function getReference()
129
+ {
130
+ return $this->reference;
131
+ }
132
+
133
+ /**
134
+ * Set name
135
+ *
136
+ * @param string $name
137
+ * @return Product
138
+ */
139
+ public function setName($name)
140
+ {
141
+ $this->name = $name;
142
+
143
+ return $this;
144
+ }
145
+
146
+ /**
147
+ * Get name
148
+ *
149
+ * @return string
150
+ */
151
+ public function getName()
152
+ {
153
+ return $this->name;
154
+ }
155
+
156
+ /**
157
+ * Set price
158
+ *
159
+ * @param float $price
160
+ * @return Product
161
+ */
162
+ public function setPrice($price)
163
+ {
164
+ $this->price = $price;
165
+
166
+ return $this;
167
+ }
168
+
169
+ /**
170
+ * Get price
171
+ *
172
+ * @return string
173
+ */
174
+ public function getPrice()
175
+ {
176
+ return $this->price;
177
+ }
178
+
179
+ public function hasPrice(){ return ! is_null($this->price); }
180
+
181
+ /**
182
+ * Set height
183
+ *
184
+ * @param integer $height
185
+ * @return Product
186
+ */
187
+ public function setHeight($height)
188
+ {
189
+ $this->height = $height;
190
+
191
+ return $this;
192
+ }
193
+
194
+ /**
195
+ * Get height
196
+ *
197
+ * @return integer
198
+ */
199
+ public function getHeight()
200
+ {
201
+ return $this->height;
202
+ }
203
+
204
+ private function hasHeight(){ return ! is_null($this->height); }
205
+
206
+ /**
207
+ * Set width
208
+ *
209
+ * @param integer $width
210
+ * @return Product
211
+ */
212
+ public function setWidth($width)
213
+ {
214
+ $this->width = $width;
215
+
216
+ return $this;
217
+ }
218
+
219
+ /**
220
+ * Get width
221
+ *
222
+ * @return integer
223
+ */
224
+ public function getWidth()
225
+ {
226
+ return $this->width;
227
+ }
228
+
229
+ private function hasWidth(){ return ! is_null($this->width); }
230
+
231
+ /**
232
+ * Set depth
233
+ *
234
+ * @param integer $depth
235
+ * @return Product
236
+ */
237
+ public function setDepth($depth)
238
+ {
239
+ $this->depth = $depth;
240
+
241
+ return $this;
242
+ }
243
+
244
+ /**
245
+ * Get depth
246
+ *
247
+ * @return integer
248
+ */
249
+ public function getDepth()
250
+ {
251
+ return $this->depth;
252
+ }
253
+
254
+ private function hasDepth(){ return ! is_null($this->depth); }
255
+
256
+ public function hasSize()
257
+ {
258
+ if(!$this->hasHeight()) return false;
259
+ if(!$this->hasWidth()) return false;
260
+ if($this->hasDepth()) return false;
261
+
262
+ return true;
263
+ }
264
+
265
+ /**
266
+ * Set weight
267
+ *
268
+ * @param float $weight
269
+ * @return Product
270
+ */
271
+ public function setWeight($weight)
272
+ {
273
+ $this->weight = $weight;
274
+
275
+ return $this;
276
+ }
277
+
278
+ /**
279
+ * Get weight
280
+ *
281
+ * @return float
282
+ */
283
+ public function getWeight()
284
+ {
285
+ return $this->weight;
286
+ }
287
+
288
+ public function hasWeight(){ return ! is_null($this->weight); }
289
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/BackendAccessRequest.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
7
+
8
+ /**
9
+ * Retrieve url to access merchant configuration parameters.
10
+ * @author mika
11
+ *
12
+ */
13
+ class BackendAccessRequest extends BaseRequest
14
+ {
15
+ /**
16
+ * (non-PHPdoc)
17
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
18
+ * @return \Nektria\Recs\MerchantApi\Responses\BackendAccessResponse
19
+ * @throws ApiResponseException
20
+ */
21
+ protected function unsafe_execute(array $params)
22
+ {
23
+ $params = $this->mergeRequestSettings($params);
24
+
25
+ $response = $this->client->backendAccess($params);
26
+ $wrapped_response = new ResponseBodyWrapper($response);
27
+ if( ! $wrapped_response->isSuccessfull())
28
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
29
+
30
+ $response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\BackendAccessResponse");
31
+ return $response_message;
32
+
33
+ }
34
+
35
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/BaseRequest.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Client;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
7
+
8
+ /**
9
+ * Base request deals with client creation
10
+ *
11
+ * @author mika
12
+ *
13
+ */
14
+ abstract class BaseRequest
15
+ {
16
+ protected $client;
17
+
18
+ private $request_keys;
19
+ protected $request_settings;
20
+
21
+ /**
22
+ * Split settings into client settings and request settings
23
+ * @param array $settings
24
+ */
25
+ public function __construct(array $settings = array())
26
+ {
27
+ $this->request_keys = array("id"); // more to come?
28
+ list($client_settings, $request_settings) = $this->split($settings);
29
+
30
+ $this->request_settings = $request_settings;
31
+ $this->client = new Client($client_settings);
32
+ }
33
+
34
+ /**
35
+ * Separate keys related to client settings from keys related to the request
36
+ *
37
+ * @param array $settings
38
+ * @return multitype: array split into an array of settings and an array
39
+ * of request settings
40
+ */
41
+ private function split(array $settings)
42
+ {
43
+ $request_keys = $this->request_keys;
44
+ $request_settings = array();
45
+ foreach($request_keys as $rq)
46
+ {
47
+ if( ! array_key_exists($rq, $settings)) continue;
48
+ $request_settings[$rq] = $settings[$rq];
49
+ unset($settings[$rq]);
50
+ }
51
+ return array($settings, $request_settings);
52
+
53
+ }
54
+
55
+ protected function mergeRequestSettings($params)
56
+ {
57
+ return array_merge($params, $this->request_settings);
58
+ }
59
+
60
+ protected function getRequestSettings(){ return $this->request_settings; }
61
+
62
+ /**
63
+ * Shoot the request, get response
64
+ * @param $params string or array of parameters in the body
65
+ * @return BaseResponse
66
+ */
67
+ abstract protected function unsafe_execute(array $params);
68
+
69
+ /**
70
+ * Get to execute specific workload catching Guzzle exception and converting them to
71
+ * more readable exceptions of our flavour.
72
+ *
73
+ * OBSOLETE as we exectue guzzle with option to throw no exception.
74
+ *
75
+ * @param string $params json parame ters
76
+ * @return \Nektria\Recs\MerchantApi\Responses\BaseResponse
77
+ * @throws ApiClientException
78
+ */
79
+ public function execute($params=array())
80
+ {
81
+ if(! is_array($params))
82
+ $params = json_decode($params, true);
83
+
84
+ if(! is_array($params))
85
+ throw new ApiClientException("Invalid parameter format in the request execution call.");
86
+
87
+ try
88
+ {
89
+ return $this->unsafe_execute($params);
90
+ }
91
+ catch(GuzzleHttp\Command\Exception\CommandClientException $e)
92
+ {
93
+ $message = "Error ".$e->getResponse()->getStatusCode().":".$e->getResponse()->getBody()->getContents();
94
+ // var_dump($e->getResponse()->getEffectiveUrl());
95
+ throw new ApiClientException($message, $e->getResponse()->getStatusCode());
96
+ }
97
+ catch(GuzzleHttp\Command\Exception\CommandServerException $e)
98
+ {
99
+ $message = "Error ".$e->getResponse()->getStatusCode().":".$e->getResponse()->getBody()->getContents();
100
+ // var_dump($e->getResponse()->getEffectiveUrl());
101
+ throw new ApiClientException($message, $e->getResponse()->getStatusCode());
102
+ }
103
+ catch(GuzzleHttp\Command\Exception\CommandException $e)
104
+ {
105
+ $message = "Error ".$e->getResponse()->getStatusCode().":".$e->getResponse()->getBody()->getContents();
106
+ throw new ApiClientException($message, $e->getResponse()->getStatusCode());
107
+ }
108
+ catch(GuzzleHttp\Exception\RequestException $e)
109
+ {
110
+ error_log($e->getResponse()->getContent());
111
+ var_dump($e->getResponse()->getContent());
112
+ throw($e);
113
+ }
114
+ catch (GuzzleHttp\Exception\BadResponseException $e)
115
+ {
116
+ error_log($e->getResponse()->getContent());
117
+ var_dump($e->getResponse()->getContent());
118
+ throw($e);
119
+ }
120
+ catch (GuzzleHttp\Exception\ServerException $e)
121
+ {
122
+ error_log($e->getResponse()->getContent());
123
+ var_dump($e->getResponse()->getContent());
124
+ throw($e);
125
+ }
126
+ }
127
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/ClassicAvailabilityRequest.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
7
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
8
+
9
+ class ClassicAvailabilityRequest extends BaseRequest
10
+ {
11
+ /**
12
+ * (non-PHPdoc)
13
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
14
+ * @return \Nektria\Recs\MerchantApi\Responses\ClassicAvailabilityResponse
15
+ * @throws ApiClientException
16
+ */
17
+ protected function unsafe_execute(array $params)
18
+ {
19
+ if( ! $this->checkServiceType($params) )
20
+ return $this->thereIsNoAvailability();
21
+
22
+ $rq_params = $this->getRequestSettings();
23
+ $response = $this->client->classicAvailability($rq_params);
24
+ $wrapped_response = new ResponseBodyWrapper($response);
25
+ if( ! $wrapped_response->isSuccessfull())
26
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
27
+
28
+ $response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\ClassicAvailabilityResponse");
29
+ return $response_message;
30
+ }
31
+
32
+ /**
33
+ * Service type has to be here, and to be classic.
34
+ *
35
+ * @param array $params
36
+ * @throws ApiClientException if missing service_type parameter
37
+ * @return boolean true if we have availability for classic delivery
38
+ */
39
+ private function checkServiceType(array $params)
40
+ {
41
+ if(! array_key_exists("service_type", $params))
42
+ throw new ApiClientException("You need to specify the service type in Classic Availability Request. Service type is returned in ServiceCreationResponse.");
43
+
44
+ if($params["service_type"] != "classic") return false;
45
+
46
+ return true;
47
+ }
48
+
49
+ private function thereIsNoAvailability()
50
+ {
51
+ return new \Nektria\Recs\MerchantApi\Responses\ClassicAvailabilityResponse(false);
52
+ }
53
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/ClassicConfirmationRequest.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
7
+
8
+ class ClassicConfirmationRequest extends BaseRequest
9
+ {
10
+ /**
11
+ * (non-PHPdoc)
12
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
13
+ * @return \Nektria\Recs\MerchantApi\Responses\ClassicConfirmationResponse
14
+ * @throws ApiResponseException
15
+ */
16
+ protected function unsafe_execute(array $params)
17
+ {
18
+ $params = $this->mergeRequestSettings($params);
19
+
20
+ $response = $this->client->classicConfirmation($params);
21
+ $wrapped_response = new ResponseBodyWrapper($response);
22
+ if( ! $wrapped_response->isSuccessfull())
23
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
24
+
25
+ $response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\ClassicConfirmationResponse");
26
+ return $response_message;
27
+ }
28
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/CoverageRequest.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ /**
6
+ *
7
+ * @author mika
8
+ *
9
+ */
10
+ class CoverageRequest extends BaseRequest
11
+ {
12
+ /**
13
+ * (non-PHPdoc)
14
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
15
+ * @return \Nektria\Recs\MerchantApi\Responses\CoverageResponse
16
+ */
17
+ protected function unsafe_execute(array $params)
18
+ {
19
+ $response_message = new \Nektria\Recs\MerchantApi\Responses\CoverageResponse();
20
+ return $response_message;
21
+ }
22
+
23
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/KeepAliveRequest.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
7
+
8
+ /**
9
+ * We encapsulate the last mile and the transit requests,
10
+ * transit request is shot only when needed,
11
+ * and returned prices are combined results.
12
+ *
13
+ * @author mika
14
+ *
15
+ */
16
+ class KeepAliveRequest extends BaseRequest
17
+ {
18
+ /**
19
+ * (non-PHPdoc)
20
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
21
+ * @return \Nektria\Recs\MerchantApi\Responses\KeepAliveResponse
22
+ * @throws ApiResponseException
23
+ */
24
+ protected function unsafe_execute(array $dummy=array())
25
+ {
26
+ $params = $this->getRequestSettings();
27
+
28
+ $response = $this->client->keepAlive($params);
29
+ $wrapped_response = new ResponseBodyWrapper($response);
30
+ if( ! $wrapped_response->isSuccessfull())
31
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
32
+
33
+ $response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\NullResponse");
34
+ return $response_message;
35
+
36
+ }
37
+
38
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/LastMileAvailabilityRequest.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
7
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
8
+
9
+ /**
10
+ * We encapsulate the last mile and the transit requests,
11
+ * transit request is shot only when needed,
12
+ * and returned prices are combined results.
13
+ *
14
+ * @author mika
15
+ *
16
+ */
17
+ class LastMileAvailabilityRequest extends BaseRequest
18
+ {
19
+ /**
20
+ * Service type has to be here, and to be classic.
21
+ *
22
+ * @param array $params
23
+ * @throws ApiClientException if missing service_type parameter
24
+ * @return boolean true if we have availability for classic delivery
25
+ */
26
+ private function checkServiceType(array $params)
27
+ {
28
+ if(! array_key_exists("service_type", $params))
29
+ throw new ApiClientException("You need to specify the service type in LastMileAvailabilityRequest. Service type is returned in ServiceCreationResponse.");
30
+
31
+ if($params["service_type"] == "last-mile-with-transit") return true;
32
+ if($params["service_type"] == "last-mile-only") return true;
33
+
34
+ return false;
35
+ }
36
+
37
+ /**
38
+ * Is this a service with transit ?
39
+ * @param array $params
40
+ * @return boolean
41
+ */
42
+ private function checkTransit($params)
43
+ {
44
+ if($params["service_type"] == "last-mile-with-transit") return true;
45
+ if($params["service_type"] == "last-mile-only") return false;
46
+ }
47
+
48
+ private function thereIsNoAvailability()
49
+ {
50
+ return new \Nektria\Recs\MerchantApi\Responses\LastMileAvailabilityResponse(false);
51
+ }
52
+
53
+ /**
54
+ * Set up the logic to combine the two slots whenever this is needed
55
+ *
56
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
57
+ * @return \Nektria\Recs\MerchantApi\Responses\LastMileAvailabilityResponse
58
+ * @throws ApiResponseException
59
+ */
60
+ protected function unsafe_execute(array $params)
61
+ {
62
+ if( ! $this->checkServiceType($params) )
63
+ return $this->thereIsNoAvailability();
64
+
65
+ $params = $this->mergeRequestSettings($params);
66
+
67
+ $response = $this->client->lastMileAvailability($params);
68
+ $wrapped_response = new ResponseBodyWrapper($response);
69
+ if( ! $wrapped_response->isSuccessfull())
70
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
71
+
72
+ $response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\LastMileAvailabilityResponse");
73
+
74
+ return $response_message;
75
+ }
76
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/LastMileBestPriceRequest.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
7
+
8
+ /**
9
+ * Get assessment of best price for last mile service
10
+ * (before we get shopper address)
11
+ *
12
+ * @author mika
13
+ *
14
+ */
15
+ class LastMileBestPriceRequest extends BaseRequest
16
+ {
17
+ /**
18
+ * (non-PHPdoc)
19
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
20
+ * @return \Nektria\Recs\MerchantApi\Responses\LastMileBestPriceResponse
21
+ * @throws ApiResponseException
22
+ */
23
+ protected function unsafe_execute(array $params)
24
+ {
25
+ //$params = $this->mergeRequestSettings($params);
26
+
27
+ //$response = $this->client->lastMileValidation($params);
28
+ //$wrapped_response = new ResponseBodyWrapper($response);
29
+ //if( ! $wrapped_response->isSuccessfull())
30
+ // throw new ApiResponseException($response["httpStatus"], $wrapped_response);
31
+
32
+ //$response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\NullResponse");
33
+ //return $response_message;
34
+
35
+ return new \Nektria\Recs\MerchantApi\Responses\LastMileBestPriceResponse();
36
+ }
37
+
38
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/LastMileConfirmationRequest.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
7
+
8
+ /**
9
+ * We encapsulate the last mile and the transit requests,
10
+ * transit request is shot only when needed,
11
+ * and returned prices are combined results.
12
+ *
13
+ * @author mika
14
+ *
15
+ */
16
+ class LastMileConfirmationRequest extends BaseRequest
17
+ {
18
+ /**
19
+ * (non-PHPdoc)
20
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
21
+ * @return \Nektria\Recs\MerchantApi\Responses\LastMileConfirmationResponse
22
+ * @throws ApiResponseException
23
+ */
24
+ protected function unsafe_execute(array $params=array())
25
+ {
26
+ $params = $this->mergeRequestSettings($params);
27
+
28
+ $response = $this->client->lastMileConfirmation($params);
29
+ $wrapped_response = new ResponseBodyWrapper($response);
30
+ if( ! $wrapped_response->isSuccessfull())
31
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
32
+
33
+ $response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\LastMileConfirmationResponse");
34
+ return $response_message;
35
+ }
36
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/LastMileValidationRequest.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
7
+
8
+ /**
9
+ * We encapsulate the last mile and the transit requests,
10
+ * transit request is shot only when needed,
11
+ * and returned prices are combined results.
12
+ *
13
+ * @author mika
14
+ *
15
+ */
16
+ class LastMileValidationRequest extends BaseRequest
17
+ {
18
+ /**
19
+ * (non-PHPdoc)
20
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
21
+ * @return \Nektria\Recs\MerchantApi\Responses\LastMileValidationResponse
22
+ * @throws ApiResponseException
23
+ */
24
+ protected function unsafe_execute(array $params)
25
+ {
26
+ $params = $this->mergeRequestSettings($params);
27
+
28
+ $response = $this->client->lastMileValidation($params);
29
+ $wrapped_response = new ResponseBodyWrapper($response);
30
+ if( ! $wrapped_response->isSuccessfull())
31
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
32
+
33
+ $response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\NullResponse");
34
+ return $response_message;
35
+ }
36
+
37
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/RegistrationAccessRequest.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
7
+
8
+ /**
9
+ * Retrieve url to access merchant configuration parameters.
10
+ * @author mika
11
+ *
12
+ */
13
+ class RegistrationAccessRequest extends BaseRequest
14
+ {
15
+ /**
16
+ * Force empty API key, because Guzzle requires it (but our API does not)
17
+ */
18
+ public function __construct(array $settings=array())
19
+ {
20
+ $settings["APIKEY"] = "";
21
+ parent::__construct($settings);
22
+ }
23
+
24
+ /**
25
+ * (non-PHPdoc)
26
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
27
+ * @return \Nektria\Recs\MerchantApi\Responses\BackendAccessResponse
28
+ * @throws ApiResponseException
29
+ */
30
+ protected function unsafe_execute(array $params)
31
+ {
32
+ $params = $this->mergeRequestSettings($params);
33
+
34
+ $response = $this->client->registrationAccess($params);
35
+ $wrapped_response = new ResponseBodyWrapper($response);
36
+ if( ! $wrapped_response->isSuccessfull())
37
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
38
+
39
+ $response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\RegistrationAccessResponse");
40
+ return $response_message;
41
+
42
+ }
43
+
44
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/ServiceCreationRequest.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
6
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
7
+
8
+ class ServiceCreationRequest extends BaseRequest
9
+ {
10
+ /**
11
+ * (non-PHPdoc)
12
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
13
+ * @param array $params: array with following keys
14
+ * - shopper: shopper details as described in the docs
15
+ * - destination_address: shopper address as described in the docs
16
+ * - products: shopping basket products as described in the docs
17
+ *
18
+ * @return \Nektria\Recs\MerchantApi\Responses\ServiceCreationResponse
19
+ * @throws ApiResponseException
20
+ */
21
+ protected function unsafe_execute(array $params=array())
22
+ {
23
+ $params = array_merge($params, array("services" => ["classic", "last-mile"]));
24
+
25
+ $response = $this->client->serviceCreation($params);
26
+ $wrapped_response = new ResponseBodyWrapper($response);
27
+ if( ! $wrapped_response->isSuccessfull())
28
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
29
+
30
+ $response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\ServiceCreationResponse");
31
+ return $response_message;
32
+ }
33
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/ShowShippingRequest.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
7
+
8
+ /**
9
+ * We encapsulate the last mile and the transit requests,
10
+ * transit request is shot only when needed,
11
+ * and returned prices are combined results.
12
+ *
13
+ * @author mika
14
+ *
15
+ */
16
+ class ShowShippingRequest extends BaseRequest
17
+ {
18
+ /**
19
+ * (non-PHPdoc)
20
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
21
+ * @return \Nektria\Recs\MerchantApi\Responses\ShowShippingResponse
22
+ * @throws ApiResponseException
23
+ */
24
+ protected function unsafe_execute(array $params=array())
25
+ {
26
+ $params = $this->mergeRequestSettings($params);
27
+
28
+ $response = $this->client->showShipping($params);
29
+ $wrapped_response = new ResponseBodyWrapper($response);
30
+ if( ! $wrapped_response->isSuccessfull())
31
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
32
+
33
+ $response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\ShowShippingResponse");
34
+ return $response_message;
35
+ }
36
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/TestRequest.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
7
+ use Nektria\Recs\MerchantApi\Responses\NullResponse;
8
+
9
+ class TestRequest extends BaseRequest
10
+ {
11
+ protected function unsafe_execute(array $params=null)
12
+ {
13
+ $response = $this->client->test();
14
+ $wrapped_response = new ResponseBodyWrapper($response);
15
+
16
+ if (! $wrapped_response->isSuccessfull())
17
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
18
+
19
+ return new NullResponse();
20
+ }
21
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Requests/getAssetsRequest.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Requests;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ResponseBodyWrapper;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiResponseException;
7
+
8
+ /**
9
+ * We encapsulate the last mile and the transit requests,
10
+ * transit request is shot only when needed,
11
+ * and returned prices are combined results.
12
+ *
13
+ * @author mika
14
+ *
15
+ */
16
+ class getAssetsRequest extends BaseRequest
17
+ {
18
+ /**
19
+ * (non-PHPdoc)
20
+ * @see \Nektria\Recs\MerchantApiMessages\BaseRequest::execute()
21
+ * @return \Nektria\Recs\MerchantApi\Responses\getAssetsResponse
22
+ * @throws ApiResponseException
23
+ */
24
+ protected function unsafe_execute(array $params)
25
+ {
26
+ $params = $this->mergeRequestSettings($params);
27
+
28
+ $response = $this->client->getAssets($params);
29
+ $wrapped_response = new ResponseBodyWrapper($response);
30
+ if( ! $wrapped_response->isSuccessfull())
31
+ throw new ApiResponseException($response["httpStatus"], $wrapped_response);
32
+
33
+ $response_message = $wrapped_response->getContent("\\Nektria\\Recs\\MerchantApi\\Responses\\getAssetsResponse");
34
+ return $response_message;
35
+
36
+ }
37
+
38
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/BackendAccessResponse.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ use Nektria\Recs\Exceptions;
6
+
7
+ class BackendAccessResponse
8
+ {
9
+ private $uri;
10
+
11
+ /**
12
+ * Instantiate message variables
13
+ * @param string $content in json format or array format
14
+ * @throws ApiClientException
15
+ */
16
+ public function __construct($content)
17
+ {
18
+ if(is_string($content))
19
+ $a_content = json_decode($content, true);
20
+ else
21
+ $a_content = $content;
22
+
23
+ if(is_null($a_content))
24
+ throw new ApiClientException("Incorrect Json Format in BackendAccess message response");
25
+
26
+ if(! array_key_exists("uri", $a_content))
27
+ throw new ApiClientException("Uri field is compulsory in BackendAccess message response");
28
+
29
+ $this->uri = $a_content["uri"];
30
+ }
31
+
32
+ public function getBackendUrl(){ return $this->uri; }
33
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/BaseResponse.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
6
+
7
+ /**
8
+ * Temporary response message. It displays request class name and response class name.
9
+ *
10
+ * @author mika
11
+ *
12
+ */
13
+ class BaseResponse
14
+ {
15
+ protected function checkCompulsoryFields($list, $content)
16
+ {
17
+ if(is_null($content))
18
+ throw new ApiClientException("Incorrect Json Format in InAndOut message response");
19
+
20
+ foreach($list as $element)
21
+ if(! array_key_exists($element, $content))
22
+ throw new ApiClientException(ucfirst($element)." field is compulsory in ".get_class($this)." message response.");
23
+ }
24
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/ClassicAvailabilityResponse.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ use Nektria\Recs\MerchantApi\Price;
6
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
7
+
8
+ class ClassicAvailabilityResponse extends BaseResponse
9
+ {
10
+ private $available;
11
+ private $price;
12
+
13
+ /**
14
+ *
15
+ * @param array or false $content array with response
16
+ * false if request was not shot
17
+ */
18
+ public function __construct($content)
19
+ {
20
+ if($content === false)
21
+ {
22
+ $this->available = false;
23
+ return;
24
+ }
25
+ $this->available = true;
26
+
27
+ if(is_string($content))
28
+ $a_content = json_decode($content, true);
29
+ else
30
+ $a_content = $content;
31
+
32
+ if(is_null($a_content))
33
+ throw new ApiClientException("Incorrect Json Format in Confirmation Response message response");
34
+
35
+ $this->checkCompulsoryFields(["price", "currency_code"], $content);
36
+ $this->price = new Price($content["price"], $content["currency_code"]);
37
+ }
38
+
39
+ public function isAvailable()
40
+ {
41
+ return $this->available ? true : false;
42
+ }
43
+
44
+ /**
45
+ * @todo pick up real price from webservice
46
+ * @return Ambigous <number, NULL>
47
+ */
48
+ public function getPrice()
49
+ {
50
+ return $this->isAvailable() ? $this->price : null;
51
+ }
52
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/ClassicConfirmationResponse.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
5
+ use Nektria\Recs\MerchantApi\Price;
6
+
7
+ class ClassicConfirmationResponse extends BaseResponse
8
+ {
9
+ private $price;
10
+
11
+ public function getPrice(){ return $this->price; }
12
+
13
+ /**
14
+ * Instanciate message variables
15
+ * @param string $content in json format or array format
16
+ * @throws ApiClientException
17
+ */
18
+ public function __construct($content)
19
+ {
20
+ if(is_string($content))
21
+ $a_content = json_decode($content, true);
22
+ else
23
+ $a_content = $content;
24
+
25
+ if(is_null($a_content))
26
+ throw new ApiClientException("Incorrect Json Format in Confirmation Response message response");
27
+
28
+ $this->checkCompulsoryFields(["total_price", "currency_code"], $content);
29
+
30
+ $this->price = new Price($content["total_price"], $content["currency_code"]);
31
+ }
32
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/CoverageResponse.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ class CoverageResponse
6
+ {
7
+ /**
8
+ * @return array of country codes
9
+ */
10
+ public function getCoveredCountries()
11
+ {
12
+ return array("ES");
13
+ }
14
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/LastMileAvailabilityResponse.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ use Nektria\Recs\MerchantApi\Price;
6
+ use Nektria\Recs\MerchantApi\TimeWindowPrice;
7
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
8
+
9
+ class LastMileAvailabilityResponse
10
+ {
11
+ private $available;
12
+ private $best_price;
13
+ private $highest_price;
14
+ private $time_window_prices;
15
+
16
+ public function isAvailable(){ return $this->available ? true : false; }
17
+ public function getHighestPrice(){ return $this->highest_price; }
18
+ public function getBestPrice(){ return $this->best_price; }
19
+
20
+ private function addTimeWindowPrice(TimeWindowPrice $tw)
21
+ {
22
+ $this->time_window_prices[] = $tw;
23
+ }
24
+ /**
25
+ *
26
+ * @param array or false $content array with response
27
+ * false if request was not shot
28
+ */
29
+ public function __construct($content)
30
+ {
31
+ if($this->processUnavailable($content)) return;
32
+ $a_content = $this->formatAndCheck($content);
33
+ $this->checkCompulsoryFields(["best_price","highest_price", "currency_code","time_window_prices"], $a_content);
34
+
35
+ $currency_code = $a_content["currency_code"];
36
+ $this->best_price = new Price($a_content["best_price"], $currency_code);
37
+ $this->highest_price = new Price($a_content["highest_price"], $currency_code);
38
+
39
+ $this->time_window_prices = array();
40
+ foreach($a_content["time_window_prices"] as $twp)
41
+ $this->addTimeWindowPrice(new TimeWindowPrice($twp, $currency_code));
42
+ }
43
+
44
+
45
+ private function getTimeWindowPrices(){return $this->time_window_prices; }
46
+
47
+ /**
48
+ * if param is set to boolean value false, we have no availability whatsoever.
49
+ *
50
+ * @param mixed $content
51
+ * @return boolean
52
+ */
53
+ private function processUnavailable($content)
54
+ {
55
+ $unavailable = ($content === false) ? true : false;
56
+ $this->available = !$unavailable;
57
+ return $unavailable;
58
+ }
59
+
60
+ /**
61
+ *
62
+ * @param mixed $content
63
+ * @return array
64
+ * @throws ApiClientException if invalid json
65
+ */
66
+ protected function formatAndCheck($content)
67
+ {
68
+ if(is_string($content))
69
+ {
70
+ $a_content = json_decode($content, true);
71
+ if(json_last_error() != JSON_ERROR_NONE)
72
+ throw new ApiClientException("Incorrect Json Format in InAndOut message response");
73
+ }
74
+ else
75
+ $a_content = $content;
76
+
77
+ return $a_content;
78
+ }
79
+
80
+ protected function checkCompulsoryFields($compulsory_list, $message)
81
+ {
82
+ foreach($compulsory_list as $field)
83
+ if(! array_key_exists($field, $message))
84
+ throw new ApiClientException("$field field is compulsory in Last Mile Availability message response");
85
+ }
86
+
87
+ /**
88
+ * Get information about prices and calendar windows
89
+ * We return the original response plus additional information
90
+ * to format the widget, and which is made available in time_window_ranges
91
+ *
92
+ * @return string in json format
93
+ */
94
+ public function getPriceMatrix()
95
+ {
96
+ $result = array(
97
+ "best_price" => $this->getBestPrice()->getAmount(),
98
+ "highest_price" => $this->getHighestPrice()->getAmount(),
99
+ "currency_code" => "EUR",
100
+ "time_window_ranges" =>
101
+ array(
102
+ "min_hour" => $this->getMinHour(),
103
+ "max_hour" => $this->getMaxHour(),
104
+ "days" => $this->getDays()
105
+
106
+ ),
107
+ "time_window_prices" => $this->getTimeWindowPricesArray()
108
+ );
109
+
110
+ return json_encode($result);
111
+ }
112
+
113
+ private function getTimeWindowPricesArray()
114
+ {
115
+ $result = array();
116
+ foreach($this->getTimeWindowPrices() as $twp)
117
+ {
118
+ $element = array(
119
+ "start_time" => $twp->getStartTime()->format(\DateTime::ATOM),
120
+ "end_time" => $twp->getEndTime()->format(\DateTime::ATOM),
121
+ "price" => $twp->getPrice()->getAmount()
122
+ );
123
+ $result[] = $element;
124
+ }
125
+ return $result;
126
+ }
127
+
128
+ /**
129
+ * @return string hour in format H:i:s with leading 0
130
+ */
131
+ private function getMinHour()
132
+ {
133
+ $min_hour = 23;
134
+ foreach($this->getTimeWindowPrices() as $twp)
135
+ $min_hour = min($twp->getStartTime()->format("H"), $min_hour);
136
+ return $min_hour.":00:00";
137
+ }
138
+
139
+ /**
140
+ * @return string hour in format H:i:s with leading 0
141
+ */
142
+ private function getMaxHour()
143
+ {
144
+ $max_hour = 0;
145
+ foreach($this->getTimeWindowPrices() as $twp)
146
+ $max_hour = max($twp->getEndTime()->format("H"), $max_hour);
147
+ return $max_hour.":00:00";
148
+ }
149
+
150
+ /**
151
+ * @return string[] array of days informat Y-m-d, ordered chronologically
152
+ */
153
+ private function getDays()
154
+ {
155
+ $days = array();
156
+ foreach($this->getTimeWindowPrices() as $twp)
157
+ $days[$twp->getStartTime()->format("Y-m-d")] = null;
158
+
159
+ $days = array_keys($days);
160
+ sort($days);
161
+
162
+ return $days;
163
+ }
164
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/LastMileBestPriceResponse.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
6
+ use Nektria\Recs\MerchantApi\Price;
7
+ use Nektria\Recs\MerchantApi\TimeWindow;
8
+
9
+ class LastMileBestPriceResponse
10
+ {
11
+ //private $best_price;
12
+ //private $best_price_currency;
13
+
14
+ public function getBestPrice(){ return 12.49; }
15
+ public function getBestPriceCurrency(){ return "EUR"; }
16
+ public function getBestPriceCurrencySign(){ return "€"; }
17
+
18
+ /**
19
+ * Instanciate message variables
20
+ * @param string $content in json format or array format
21
+ * @throws ApiClientException
22
+ */
23
+ public function __construct($content=null)
24
+ {
25
+ //if(is_string($content))
26
+ // $a_content = json_decode($content, true);
27
+ //else
28
+ // $a_content = $content;
29
+
30
+ //if(is_null($a_content))
31
+ // throw new ApiClientException("Incorrect Json Format in InAndOut message response");
32
+
33
+ //$this->price = new Price($a_content["total_price"], $a_content["currency_code"]);
34
+ //$this->delivery_windows = array();
35
+ //foreach($a_content["delivery_windows"] as $a_window)
36
+ // $this->delivery_windows[] = new TimeWindow($a_window);
37
+ }
38
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/LastMileConfirmationResponse.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
6
+ use Nektria\Recs\MerchantApi\Price;
7
+ use Nektria\Recs\MerchantApi\TimeWindow;
8
+
9
+ class lastMileConfirmationResponse
10
+ {
11
+ private $price;
12
+ private $delivery_windows;
13
+
14
+ public function getFormattedPrice(){ return $this->price->getAmount()."€"; }
15
+ public function getDeliveryWindows(){ return $this->delivery_windows; }
16
+
17
+ /**
18
+ * Instanciate message variables
19
+ * @param string $content in json format or array format
20
+ * @throws ApiClientException
21
+ */
22
+ public function __construct($content)
23
+ {
24
+ if(is_string($content))
25
+ $a_content = json_decode($content, true);
26
+ else
27
+ $a_content = $content;
28
+
29
+ if(is_null($a_content))
30
+ throw new ApiClientException("Incorrect Json Format in InAndOut message response");
31
+
32
+ $this->price = new Price($a_content["total_price"], $a_content["currency_code"]);
33
+ $this->delivery_windows = array();
34
+ foreach($a_content["delivery_windows"] as $a_window)
35
+ $this->delivery_windows[] = new TimeWindow($a_window);
36
+ }
37
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/NullResponse.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ class NullResponse
6
+ {
7
+
8
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/RegistrationAccessResponse.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ use Nektria\Recs\Exceptions;
6
+
7
+ class RegistrationAccessResponse
8
+ {
9
+ private $uri;
10
+
11
+ /**
12
+ * Instantiate message variables
13
+ * @param string $content in json format or array format
14
+ * @throws ApiClientException
15
+ */
16
+ public function __construct($content)
17
+ {
18
+ if(is_string($content))
19
+ $a_content = json_decode($content, true);
20
+ else
21
+ $a_content = $content;
22
+
23
+ if(is_null($a_content))
24
+ throw new ApiClientException("Incorrect Json Format in RegistrationAccess message response");
25
+
26
+ if(! array_key_exists("uri", $a_content))
27
+ throw new ApiClientException("Uri field is compulsory in RegistrationAccess message response");
28
+
29
+ $this->uri = $a_content["uri"];
30
+ }
31
+
32
+ public function getRegistrationUrl(){ return $this->uri; }
33
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/ResponseBodyWrapper.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
6
+
7
+ /**
8
+ * Wrapper for all the messages
9
+ * @author mika
10
+ *
11
+ */
12
+ class ResponseBodyWrapper
13
+ {
14
+ protected $status;
15
+ private $content;
16
+ private $message;
17
+ private $code;
18
+
19
+ public function getStatus(){ return $this->status; }
20
+
21
+ public function hasMessage(){ return ! is_null($this->message); }
22
+ public function hasCode(){ return ! is_null($this->code); }
23
+ public function hasContent(){ return !is_null($this->content); }
24
+
25
+ public function getMessage(){ return $this->message; }
26
+ public function getCode(){ return $this->code;}
27
+
28
+
29
+ /**
30
+ * Instantiate wrapper variables
31
+ * @param string $body in json format
32
+ * @throws ApiClientException
33
+ */
34
+ public function __construct($body)
35
+ {
36
+ if(is_string($body))
37
+ $a_body = json_decode($body, true);
38
+ else
39
+ $a_body = $body;
40
+
41
+ if(is_null($a_body))
42
+ throw new ApiClientException("Incorrect Json Format in message response");
43
+
44
+ if(! array_key_exists("status", $a_body))
45
+ throw new ApiClientException("Status field is compulsory in message response");
46
+
47
+ //if(! array_key_exists("content", $a_content))
48
+ // throw new ApiClientException("Content field is compulsory in message response.");
49
+
50
+ $this->status = $a_body["status"];
51
+
52
+ if(array_key_exists("content", $a_body)) // should not be needed...
53
+ $this->content = $a_body["content"];
54
+
55
+ if(array_key_exists("message", $a_body))
56
+ $this->message = $a_body["message"];
57
+
58
+ if(array_key_exists("code", $a_body))
59
+ $this->code = $a_body["code"];
60
+ }
61
+
62
+ public function isSuccessfull(){ return $this->status == "success"; }
63
+
64
+ /**
65
+ * Getter for content, with option for on the fly creation of message object
66
+ *
67
+ * @param string $message_class the name of the class interpreting the content
68
+ * @return mixed
69
+ */
70
+ public function getContent($message_class=null)
71
+ {
72
+ return is_null($message_class) ?
73
+ $this->content :
74
+ new $message_class($this->content);
75
+ }
76
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/ServiceCreationResponse.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
6
+
7
+ class ServiceCreationResponse extends BaseResponse
8
+ {
9
+ private $service_number;
10
+ private $service_type;
11
+
12
+ /**
13
+ * Instanciate message variables
14
+ * @param string $content in json format or array format
15
+ * @throws ApiClientException
16
+ */
17
+ public function __construct($content)
18
+ {
19
+ $a_content = is_string($content) ? json_decode($content, true) : $content;
20
+ $compulsory = array("service_number", "last-mile", "classic");
21
+ $this->checkCompulsoryFields($compulsory, $a_content);
22
+
23
+ $this->service_number = $a_content["service_number"];
24
+ $this->service_type = $this->computeServiceType($a_content);
25
+ }
26
+
27
+ /**
28
+ * Find out what service we provide.
29
+ *
30
+ * @param array $content
31
+ * @return string
32
+ */
33
+ private function computeServiceType(array $content)
34
+ {
35
+ if($content["last-mile"]["availability"])
36
+ return "last-mile-with-transit";
37
+ else
38
+ return $content["classic"]["availability"] ?
39
+ "classic" :
40
+ "unavailable";
41
+ }
42
+
43
+ public function getServiceNumber()
44
+ {
45
+ return $this->service_number;
46
+ }
47
+
48
+ /**
49
+ * @return unavailable / classic / last-mile-only / last-mile-with-transit
50
+ */
51
+ public function getServiceType()
52
+ {
53
+ return $this->service_type;
54
+ }
55
+
56
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/ShowShippingResponse.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
6
+ use Nektria\Recs\MerchantApi\Price;
7
+ use Nektria\Recs\MerchantApi\Address;
8
+ use Nektria\Recs\MerchantApi\Product;
9
+ use Nektria\Recs\MerchantApi\TimeWindow;
10
+
11
+ class ShowShippingResponse
12
+ {
13
+ private $merchant_name;
14
+ private $service_type;
15
+
16
+ private $shipping_cost;
17
+ private $order_number;
18
+ private $order_date;
19
+
20
+ private $status;
21
+
22
+ private $delivery_windows;
23
+ private $shopper_address;
24
+ private $products;
25
+
26
+ public function getMerchantName(){ return $this->merchant_name; }
27
+ public function getServiceType(){ return $this->service_type; }
28
+ public function isLastMile(){ return $this->service_type == "last-mile"; }
29
+
30
+ public function getShippingCost(){ return $this->shipping_cost; }
31
+ public function getOrderNumber(){ return $this->order_number; }
32
+ public function getOrderDate(){ return $this->order_date; }
33
+
34
+ public function getStatus(){ return $this->status; }
35
+
36
+ public function getDeliveryWindows(){ return $this->delivery_windows; }
37
+ public function getShopperAddress(){ return $this->shopper_address; }
38
+
39
+ private function hasProducts(){ return ! is_null($this->products); }
40
+ public function getProducts(){ return $this->products; }
41
+
42
+ private function isLastMileDelivery(){ return $this->service_type == "last-mile"; }
43
+ private function hasDeliveryWindows(){ return ! is_null($this->delivery_windows);}
44
+ private function addDeliveryWindow($window)
45
+ {
46
+ if(! $this->hasDeliveryWindows()) $this->delivery_windows = array();
47
+ $this->delivery_windows[] = is_array($window) ? new TimeWindow($window) : $window;
48
+ }
49
+
50
+ private function addProduct($product)
51
+ {
52
+ if(! $this->hasProducts()) $this->products = array();
53
+ $this->products[] = is_array($product) ? new Product($product) : $product;
54
+ }
55
+
56
+ /**
57
+ * Instanciate message variables
58
+ * @param string $content in json format or array format
59
+ * @throws ApiClientException
60
+ */
61
+ public function __construct($content)
62
+ {
63
+ if(is_string($content))
64
+ $a_content = json_decode($content, true);
65
+ else
66
+ $a_content = $content;
67
+
68
+ if(is_null($a_content))
69
+ throw new ApiClientException("Incorrect Json Format in InAndOut message response");
70
+
71
+ $this->merchant_name = $a_content["merchant"];
72
+ $this->service_type = $a_content["delivery_type"];
73
+ $this->order_number = $a_content["number"];
74
+ $this->order_date = new \DateTime($a_content["date"]);
75
+
76
+ $this->status = $a_content["status"];
77
+
78
+ if(array_key_exists("shipping_cost", $a_content))
79
+ $this->shipping_cost = new Price($a_content["shipping_cost"], $a_content["currency_code"]);
80
+
81
+ if($this->isLastMileDelivery())
82
+ foreach($a_content["windows"] as $window)
83
+ $this->addDeliveryWindow($window);
84
+
85
+ $this->shopper_address = new Address($a_content["destination"]);
86
+
87
+ foreach($a_content["products"] as $product)
88
+ $this->addProduct($product);
89
+ }
90
+
91
+ public function asArray()
92
+ {
93
+ $result = array(
94
+ "merchant" => $this->getMerchantName(),
95
+ "service_type" => $this->getServiceType(),
96
+ "shipping_cost" => (string)$this->getShippingCost(),
97
+ "order_number" => $this->getOrderNumber(),
98
+ "order_date" => $this->getOrderDate()->format("Y-m-d"),
99
+ "status"=> $this->getStatus(),
100
+ "shopper_address" => $this->getShopperAddress()->asArray()
101
+ );
102
+
103
+ $result["products"] = array();
104
+ foreach($this->getProducts() as $product)
105
+ $result["products"][] = $product->asArray();
106
+
107
+ if($this->isLastMileDelivery())
108
+ {
109
+ $result["windows"] = array();
110
+ foreach($this->getDeliveryWindows() as $window)
111
+ $result["windows"][] = $window->asArray();
112
+ }
113
+
114
+ return $result;
115
+ }
116
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/TransitAvailabilityResponse.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ class TransitAvailabilityResponse extends InAndOut
6
+ {
7
+
8
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/TransitConfirmationResponse.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ class TransitConfirmationResponse extends InAndOut
6
+ {
7
+
8
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/Responses/getAssetsResponse.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi\Responses;
4
+
5
+ use Nektria\Recs\Exceptions;
6
+
7
+ class getAssetsResponse
8
+ {
9
+ private $css_url;
10
+ private $js_url;
11
+ private $html_url;
12
+
13
+ /**
14
+ * Instanciate message variables
15
+ * @param string $content in json format or array format
16
+ * @throws ApiClientException
17
+ */
18
+ public function __construct($content)
19
+ {
20
+ if(is_string($content))
21
+ $a_content = json_decode($content, true);
22
+ else
23
+ $a_content = $content;
24
+
25
+ if(is_null($a_content))
26
+ throw new ApiClientException("Incorrect Json Format in getAssets message response");
27
+
28
+ if(! array_key_exists("js", $a_content))
29
+ throw new ApiClientException("In field is compulsory in getAssets message response");
30
+
31
+ if(! array_key_exists("css", $a_content))
32
+ throw new ApiClientException("Out field is compulsory in getAssets message response.");
33
+
34
+ if(! array_key_exists("html", $a_content))
35
+ throw new ApiClientException("Out field is compulsory in getAssets message response.");
36
+
37
+ $this->js_url = $a_content["js"];
38
+ $this->css_url = $a_content["css"];
39
+ $this->html_url = $a_content["html"];
40
+ }
41
+
42
+ public function getCssUrl(){ return $this->css_url; }
43
+ public function getJsUrl(){ return $this->js_url; }
44
+ public function getHtmlUrl(){ return $this->html_url; }
45
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/ShowShippingHelper.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi;
4
+
5
+ use Nektria\Recs\MerchantApi\Responses\ShowShippingResponse;
6
+
7
+ /**
8
+ * Class ShowShippingHelper: ShowShippingResponse wrapper to display things
9
+ * @package Nektria\Recs\MerchantApi
10
+ */
11
+ class ShowShippingHelper
12
+ {
13
+ private $response;
14
+ private $locale;
15
+
16
+ public function __construct(ShowShippingResponse $response, $locale)
17
+ {
18
+ $this->response = $response;
19
+ $this->locale = $locale;
20
+ }
21
+
22
+
23
+ public function getResponse(){ return $this->response; }
24
+ public function isLastMile()
25
+ {
26
+ return $this->response->isLastMile();
27
+ }
28
+
29
+ /**
30
+ * Get string explaining status of the shipping resposne
31
+ * @return string human readable status
32
+ */
33
+ public function getStatus()
34
+ {
35
+ // if($this->locale != "ES_es") $this->warning !;
36
+
37
+ switch($this->response->getStatus())
38
+ {
39
+ case "pending": $wording = "Servicio previsto. Pendiente de asignación a operador logístico de RECS";break;
40
+ case "in-process": $wording = "Servicio asignado a operador logístico de RECS";break;
41
+ case "completed": $wording = "Entregado a consumidor";break;
42
+ case "cancelled": $wording = "Cancelado" ;break;
43
+ default: $wording = "Estado desconocido.";
44
+ }
45
+ return $wording;
46
+ }
47
+
48
+ public function getDeliveryWindows()
49
+ {
50
+ // if($this->locale != "ES_es") $this->warning !;
51
+ setlocale(LC_TIME, "ES_es");
52
+
53
+ $delivery_windows = array();
54
+ foreach($this->response->getDeliveryWindows() as $time_window)
55
+ {
56
+ $formatted_time = strftime("%A %e %B", $time_window->getStartTime()->getTimestamp());
57
+ $formatted_time .= " entre las ".$time_window->getStartTime()->format("H")."h";
58
+ $formatted_time .= " y las ".$time_window->getEndTime()->format("H")."h";
59
+ $delivery_windows[] = $formatted_time;
60
+ }
61
+ return $delivery_windows;
62
+ }
63
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/TimeWindow.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi;
4
+
5
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
6
+
7
+ class TimeWindow
8
+ {
9
+ private $start_time;
10
+ private $end_time;
11
+
12
+ /**
13
+ * @param <string> array of ISO8601 strings $time_window
14
+ * with keys "start_time" and "end_time"
15
+ * @throws ApiClientException
16
+ */
17
+ public function __construct($time_window)
18
+ {
19
+ if( ! array_key_exists("start_time", $time_window))
20
+ throw new ApiClientException("Incorrect format for new time window price (start_time).");
21
+
22
+ if( ! array_key_exists("end_time", $time_window))
23
+ throw new ApiClientException("Incorrect format for new time window price (end_time).");
24
+
25
+ $this->start_time = new \DateTime($time_window["start_time"]);
26
+ $this->end_time = new \DateTime($time_window["end_time"]);
27
+
28
+ if($this->start_time > $this->end_time)
29
+ throw new ApiClientException("Start time should be previous end time.");
30
+ }
31
+
32
+ public function asArray()
33
+ {
34
+ return array(
35
+ "start_time" => $this->getStartTime()->format(\DateTime::ATOM),
36
+ "end_time" => $this->getEndTime()->format(\DateTime::ATOM)
37
+ );
38
+ }
39
+
40
+ public function getStartTime(){ return $this->start_time; }
41
+ public function getEndTime(){ return $this->end_time; }
42
+
43
+ /**
44
+ * return list of days involved in this time window (usually one).
45
+ * @return DateTime[]
46
+ */
47
+ public function getDays()
48
+ {
49
+ $days = array();
50
+ if($this->start_time == $this->end_time) return $days;
51
+
52
+ $current_time = clone $this->start_time;
53
+ $current_time->setTime(0,0,0);
54
+ while($current_time < $this->end_time)
55
+ $days[] = $current_time;
56
+
57
+ return $days;
58
+ }
59
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/TimeWindowPrice.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Nektria\Recs\MerchantApi;
4
+
5
+ use Nektria\Recs\MerchantApi\Exceptions\ApiClientException;
6
+
7
+
8
+ /**
9
+ * Add price concept to a time window.
10
+ *
11
+ * @author mika
12
+ *
13
+ */
14
+ class TimeWindowPrice extends TimeWindow
15
+ {
16
+ private $price;
17
+
18
+ /**
19
+ * @param <string> array of ISO8601 strings $time_window
20
+ * with keys "start_time", "end_time" and "price"
21
+ * @param string $default_currency_code
22
+ * @throws RecsBookingException
23
+ */
24
+ public function __construct($time_window_price, $default_currency_code=null)
25
+ {
26
+ parent::__construct($time_window_price);
27
+
28
+ if( ! array_key_exists("price", $time_window_price))
29
+ throw new ApiClientException("Incorrect format for new time window price (price).");
30
+
31
+ if( ! array_key_exists("currency_code", $time_window_price))
32
+ if(is_null($default_currency_code))
33
+ throw new ApiClientException("Incorrect format for new time window price (currency_code).");
34
+
35
+ $currency_code = array_key_exists("currency_code", $time_window_price) ?
36
+ $time_window_price["currency_code"] :
37
+ $default_currency_code;
38
+ $this->price = new Price($time_window_price["price"], $currency_code);
39
+ }
40
+
41
+ public function getPrice(){ return $this->price; }
42
+ }
app/code/community/Nektria/ReCS/lib/Nektria/src/services/services.json ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "ReCS API",
3
+ "apiVersion": "0.8",
4
+ "description": "Responsive eCommerce Shipping API",
5
+ "operations": {
6
+ "test": {
7
+ "httpMethod": "GET",
8
+ "uri": "test",
9
+ "summary": "Test request is useful to verify the client authentication is correct",
10
+ "responseClass": "TestOutput"
11
+ },
12
+ "serviceCreation": {
13
+ "httpMethod": "POST",
14
+ "uri": "services",
15
+ "summary": "Service Creation - trying unsuccessfully to use responseClass \\Nektria\\Recs\\MerchantApiMessages\\ResponseBodyWrapper",
16
+ "responseClass": "GenericOutput",
17
+ "parameters":{
18
+ "services": {
19
+ "location": "json",
20
+ "type": "array",
21
+ "description": "Type of services requested (should be classic + last-mile)",
22
+ "required": true
23
+ },
24
+ "shopper": {
25
+ "location": "json",
26
+ "type": "array",
27
+ "description": "Shopper name and contact details",
28
+ "required": true
29
+ },
30
+ "destination_address": {
31
+ "location": "json",
32
+ "type": "array",
33
+ "description": "Shopper address",
34
+ "required": true
35
+ },
36
+ "products": {
37
+ "location": "json",
38
+ "type": "array",
39
+ "description": "List of products in the shopping basket",
40
+ "required": true
41
+ }
42
+ }
43
+ },
44
+ "lastMileAvailability": {
45
+ "httpMethod": "POST",
46
+ "uri": "services/{id}/last-mile",
47
+ "summary": "Get availability windows and prices for the last mile delivery service.",
48
+ "parameters": {
49
+ "id": {
50
+ "location": "uri",
51
+ "description": "ID of service request",
52
+ "required": true
53
+ }
54
+ },
55
+ "responseClass": "GenericOutput"
56
+ },
57
+ "lastMileValidation": {
58
+ "httpMethod": "PATCH",
59
+ "uri": "services/{id}/last-mile/validate",
60
+ "summary": "Choose delivery window for last mile and verify the price is correct.",
61
+ "parameters": {
62
+ "id": {
63
+ "location": "uri",
64
+ "description": "ID of service request",
65
+ "required": true
66
+ },
67
+ "validation_windows": {
68
+ "location": "json",
69
+ "type": "array",
70
+ "description": "Initially chosen delivery timeslots",
71
+ "required": true
72
+ },
73
+ "delivery_windows": {
74
+ "location": "json",
75
+ "type": "array",
76
+ "description": "Chosen delivery timeslots",
77
+ "required": true
78
+ },
79
+ "total_price": {
80
+ "location": "json",
81
+ "type": "number",
82
+ "description": "Total price of the delivery selection",
83
+ "required": true
84
+ },
85
+ "currency_code": {
86
+ "location": "json",
87
+ "type": "string",
88
+ "description": "Currency that is being used (should be EUR)",
89
+ "required": true
90
+ }
91
+ },
92
+ "responseClass": "GenericOutput"
93
+ },
94
+ "lastMileConfirmation": {
95
+ "httpMethod": "PATCH",
96
+ "uri": "services/{id}/last-mile/confirm",
97
+ "summary": "Confirm a last mile service",
98
+ "parameters": {
99
+ "id": {
100
+ "location": "uri",
101
+ "description": "ID of service request",
102
+ "required": true
103
+ },
104
+ "order_number": {
105
+ "location": "json",
106
+ "type": "string",
107
+ "description": "order number in eCommerce",
108
+ "required": false
109
+ }
110
+ },
111
+ "responseClass": "GenericOutput"
112
+ },
113
+ "classicAvailability": {
114
+ "httpMethod": "POST",
115
+ "uri": "services/{id}/classic",
116
+ "summary": "Get availability and prices for classic delivery service",
117
+ "parameters": {
118
+ "id": {
119
+ "location": "uri",
120
+ "description": "ID of service request",
121
+ "required": true
122
+ }
123
+ },
124
+ "responseClass": "GenericOutput"
125
+ },
126
+ "classicConfirmation": {
127
+ "httpMethod": "PATCH",
128
+ "uri": "services/{id}/classic/confirm",
129
+ "summary": "Confirm a classic service",
130
+ "parameters": {
131
+ "id": {
132
+ "location": "uri",
133
+ "description": "ID of service request",
134
+ "required": true
135
+ },
136
+ "order_number": {
137
+ "location": "json",
138
+ "type": "string",
139
+ "description": "order number in eCommerce",
140
+ "required": false
141
+ }
142
+ },
143
+ "responseClass": "GenericOutput"
144
+ },
145
+ "keepAlive": {
146
+ "httpMethod": "PATCH",
147
+ "uri": "services/{id}/keep-alive",
148
+ "summary": "Reset last mile request timeout so it does not expire",
149
+ "parameters": {
150
+ "id": {
151
+ "location": "uri",
152
+ "description": "ID of service request",
153
+ "required": true
154
+ }
155
+ },
156
+ "responseClass": "GenericOutput"
157
+ },
158
+ "getAssets": {
159
+ "httpMethod": "GET",
160
+ "uri": "services/{id}/assets",
161
+ "summary": "Retrieve locations of the assets for the widget",
162
+ "parameters": {
163
+ "id": {
164
+ "location": "uri",
165
+ "description": "ID of service request",
166
+ "required": true
167
+ },
168
+ "language": {
169
+ "location": "query",
170
+ "type": "string",
171
+ "description": "locale descriptor (5 letters)",
172
+ "required": false
173
+ },
174
+ "version": {
175
+ "location": "query",
176
+ "type": "string",
177
+ "description": "asset version number requested",
178
+ "required": false
179
+ }
180
+ },
181
+ "responseClass": "GenericOutput"
182
+ },
183
+ "showShipping": {
184
+ "httpMethod": "GET",
185
+ "uri": "services/{id}/shipping",
186
+ "summary": "Retrieve information about a shipping",
187
+ "parameters": {
188
+ "id": {
189
+ "location": "uri",
190
+ "description": "ID of service request",
191
+ "required": true
192
+ }
193
+ },
194
+ "responseClass": "GenericOutput"
195
+ },
196
+ "backendAccess": {
197
+ "httpMethod": "GET",
198
+ "uri": "configuration/backend-access",
199
+ "summary": "Get link to edit merchant's advanced settings",
200
+ "responseClass": "GenericOutput"
201
+ },
202
+ "registrationAccess": {
203
+ "httpMethod": "GET",
204
+ "uri": "configuration/registration-access",
205
+ "summary": "Get link to log in to your account or to create a new account",
206
+ "responseClass": "GenericOutput"
207
+ }
208
+ },
209
+ "models": {
210
+ "TestOutput": {
211
+ "type": "object",
212
+ "properties": {
213
+ "status": {
214
+ "location": "json",
215
+ "type": "string"
216
+ },
217
+ "httpStatus": {
218
+ "location": "statusCode",
219
+ "type": "string"
220
+ },
221
+ "message": {
222
+ "location": "json",
223
+ "type": "string"
224
+ },
225
+ "code": {
226
+ "location": "json",
227
+ "type": "string"
228
+ },
229
+ "content": {
230
+ "type": "null",
231
+ "location": "json"
232
+ }
233
+ }
234
+ },
235
+ "GenericOutput": {
236
+ "type": "object",
237
+ "properties": {
238
+ "httpStatus": {
239
+ "location": "statusCode",
240
+ "type": "string"
241
+ },
242
+ "status": {
243
+ "location": "json",
244
+ "type": "string"
245
+ },
246
+ "message": {
247
+ "location": "json",
248
+ "type": "string"
249
+ },
250
+ "code": {
251
+ "location": "json",
252
+ "type": "string"
253
+ },
254
+ "content": {
255
+ "type": "object",
256
+ "location": "json",
257
+ "additionalProperties": true
258
+ }
259
+ }
260
+ }
261
+ }
262
+ }
app/code/community/Nektria/ReCS/lib/Nektria/test.php ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Require the Composer autoloader.
4
+ require 'vendor/autoload.php';
5
+
6
+ function executeRequest($request_name)
7
+ {
8
+ switch($request_name)
9
+ {
10
+ case "test":
11
+ $tr = new Nektria\Recs\MerchantApi\Requests\TestRequest([
12
+ 'APIKEY' => 'dGVzdDp0ZXN0'
13
+ ]);
14
+ $response = $tr->execute();
15
+ break;
16
+ case "service-creation":
17
+ $response = executeServiceCreation();
18
+ break;
19
+ case "last-mile-availability":
20
+ $response = executeLastMileAvailability();
21
+ break;
22
+ case "last-mile-validation":
23
+ $response = executeLastMileValidation();
24
+ break;
25
+ case "last-mile-confirmation":
26
+ $lmcr = new Nektria\Recs\MerchantApi\Requests\LastMileConfirmationRequest([
27
+ 'APIKEY' => 'dGVzdDp0ZXN0',
28
+ 'id' => '1'
29
+ ]);
30
+
31
+ $response = $lmcr->execute();
32
+ break;
33
+ case "classic-availability":
34
+ $response = executeClassicAvailability();
35
+ break;
36
+ case "classic-confirmation":
37
+ $lmcr = new Nektria\Recs\MerchantApi\Requests\ClassicConfirmationRequest([
38
+ 'APIKEY' => 'dGVzdDp0ZXN0',
39
+ 'id' => '1'
40
+ ]);
41
+
42
+ $response = $lmcr->execute();
43
+ break;
44
+ case "keep-alive":
45
+ $kar = new Nektria\Recs\MerchantApi\Requests\KeepAliveRequest([
46
+ 'APIKEY' => 'dGVzdDp0ZXN0',
47
+ 'id' => '1'
48
+ ]);
49
+
50
+ $more_params = array("here" => "is", "some" => "more");
51
+ $response = $kar->execute($more_params);
52
+ break;
53
+ case "get-assets":
54
+ $gar = new Nektria\Recs\MerchantApi\Requests\getAssetsRequest([
55
+ 'APIKEY' => 'dGVzdDp0ZXN0',
56
+ 'id' => '1'
57
+ ]);
58
+
59
+ $more_params = array("here" => "is", "some" => "more");
60
+ $response = $gar->execute($more_params);
61
+ break;
62
+ default:
63
+ $response = "Incorrect parameter $request_name. This is not a know service.";
64
+ }
65
+
66
+ return $response;
67
+ }
68
+
69
+ $opt = getopt("r:");
70
+
71
+ if(array_key_exists("r", $opt))
72
+ {
73
+ var_dump(executeRequest($opt["r"]));
74
+ }
75
+ else
76
+ {
77
+ echo 'use: test.php [-r test-name]
78
+ with test name in
79
+ "test", "service-creation", "last-mile-availability",
80
+ "last-mile-validation", "last-mile-confirmation",
81
+ "classic-availability", "classic-confirmation",
82
+ "keep-alive", "get-assets"
83
+ ';
84
+ }
85
+
86
+
87
+
88
+ function executeServiceCreation()
89
+ {
90
+ $sr = new Nektria\Recs\MerchantApi\Requests\ServiceCreationRequest([
91
+ 'APIKEY' => 'dGVzdDp0ZXN0'
92
+ ]);
93
+
94
+ $params = array(
95
+ "order_number" => "abc",
96
+ "services" => ["last-mile", "classic"],
97
+ "shopper" => array(
98
+ "name" => "Roberto",
99
+ "surname" => "Rodríguez",
100
+ "email" => "roberto.rodriguez@gmail.com",
101
+ "phone" => "83486923409"
102
+ ),
103
+ "destination_address" => array(
104
+ "postal_code" => "08022",
105
+ "street_type" => "Pza.",
106
+ "street_name" => "Urquinaona",
107
+ "street_number" => "5",
108
+ "city" => "Barcelona",
109
+ "country_code" => "ES"
110
+ ),
111
+ "products" => array(
112
+
113
+ array(
114
+ "name" => "T-shirt Monashee",
115
+ "reference" => "PQR48-D",
116
+ "quantity" => 1,
117
+ "weight_kg" => 0.5,
118
+ "size" =>
119
+ array(
120
+ "height_cm" => 20,
121
+ "width_cm" => 10,
122
+ "depth_cm" =>10
123
+ )
124
+ ),
125
+ array(
126
+ "name" => "Jeans Lemon pie",
127
+ "reference" => "WDV48-D",
128
+ "quantity" => 2,
129
+ "weight_kg" => 0.5,
130
+ "size" =>
131
+ array(
132
+ "height_cm" => 20,
133
+ "width_cm" => 10,
134
+ "depth_cm" =>10
135
+ )
136
+ )
137
+ )
138
+ );
139
+
140
+ return $sr->execute($params);
141
+ }
142
+
143
+ function executeLastMileAvailability()
144
+ {
145
+ $lmar = new Nektria\Recs\MerchantApi\Requests\LastMileAvailabilityRequest([
146
+ 'APIKEY' => 'dGVzdDp0ZXN0',
147
+ 'id' => '1'
148
+ ]);
149
+
150
+ $more_params = array("service_type" => "last-mile-with-transit");
151
+ return $lmar->execute($more_params);
152
+
153
+ }
154
+
155
+ function executeLastMileValidation()
156
+ {
157
+ $lmvr = new Nektria\Recs\MerchantApi\Requests\LastMileValidationRequest([
158
+ 'APIKEY' => 'dGVzdDp0ZXN0',
159
+ 'id' => '1'
160
+ ]);
161
+
162
+ $params = array(
163
+ "delivery_windows" => [["start_time" => "2015-05-19T14:00:00+02:00", "end_time" => "2015-05-19T17:00:00+02:00"]],
164
+ "validation_windows" => [
165
+ ["start_time" => "2015-05-18T12:00:00+02:00", "end_time" => "2015-05-18T14:00:00+02:00"],
166
+ ["start_time" => "2015-05-18T16:00:00+02:00", "end_time" => "2015-05-18T18:00:00+02:00"]
167
+ ],
168
+ "total_price" => 16.3,
169
+ "currency_code" => "EUR"
170
+ );
171
+ try
172
+ {
173
+ return $lmvr->execute($params);
174
+ }
175
+ catch(GuzzleHttp\Command\Exception\CommandException $e)
176
+ {
177
+ var_dump($e->getResponse()->getBody()->getContents());
178
+ var_dump($e->getResponse()->getStatusCode());
179
+
180
+ }
181
+ catch(GuzzleHttp\Command\Exception\CommandClientException $e)
182
+ {
183
+ var_dump($e->getResponse()->getBody()->getContents());
184
+ var_dump($e->getResponse()->getStatusCode());
185
+ var_dump($e->getResponse()->getEffectiveUrl());
186
+ }
187
+ catch(GuzzleHttp\Command\Exception\CommandServerException $e)
188
+ {
189
+ var_dump($e->getResponse()->getBody()->getContents());
190
+ var_dump($e->getResponse()->getStatusCode());
191
+ var_dump($e->getResponse()->getEffectiveUrl());
192
+ }
193
+ catch(GuzzleHttp\Command\Exception\CommandException $e)
194
+ {
195
+ var_dump(get_class($e));
196
+ }
197
+ }
198
+
199
+ function executeClassicAvailability()
200
+ {
201
+ $car = new Nektria\Recs\MerchantApi\Requests\ClassicAvailabilityRequest([
202
+ 'APIKEY' => 'dGVzdDp0ZXN0',
203
+ 'id' => '1'
204
+ ]);
205
+
206
+ $more_params = array("service_type" => "classic");
207
+ return $car->execute($more_params);
208
+
209
+ }
210
+
app/code/community/Nektria/ReCS/sql/nektria_recs_setup/install-1.0.0.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Setup procedure for Nektria ReCS extension
4
+ */
5
+
6
+ $installer = $this;
7
+
8
+ $installer->startSetup();
9
+
10
+ $table = $installer->getConnection()
11
+ ->newTable( $installer->getTable('nektria_recs/lastmile') )
12
+ ->addColumn('lastmile_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
13
+ 'unsigned' => true,
14
+ 'identify' => true,
15
+ 'nullable' => false,
16
+ 'primary' => true
17
+ ), 'LastMile id')
18
+ ->addColumn('order_id', Varien_Db_Ddl_Table::TYPE_TEXT, 60, array(
19
+ 'nullable' => false
20
+ ), 'Order id')
21
+ ->addColumn('user_selection', Varien_Db_Ddl_Table::TYPE_TEXT, '2M', array(
22
+ 'nullable' => false
23
+ ), 'UserSelection')
24
+ ->addIndex( $installer->getIdxName(
25
+ $installer->getTable('nektria_recs/lastmile'),
26
+ array('order_id'),
27
+ Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX
28
+ ) ,
29
+ array('order_id'),
30
+ array( 'type' =>Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX)
31
+ )
32
+ ->setComment( 'User Selection from Nektria ReCS' );
33
+
34
+ $installer->getConnection()->createTable( $table );
35
+
36
+ $installer->endSetup();
app/code/community/Nektria/ReCS/sql/nektria_recs_setup/install-1.0.1.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Setup procedure for Nektria ReCS extension
4
+ */
5
+
6
+ $installer = $this;
7
+
8
+ $installer->startSetup();
9
+
10
+ if ($installer->getConnection()->isTableExists('nektria_recs/lastmile') != true) {
11
+ $table = $installer->getConnection()
12
+ ->newTable( $installer->getTable('nektria_recs/lastmile') )
13
+ ->addColumn('lastmile_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
14
+ 'unsigned' => true,
15
+ 'identify' => true,
16
+ 'nullable' => false,
17
+ 'primary' => true
18
+ ), 'LastMile id')
19
+ ->addColumn('order_id', Varien_Db_Ddl_Table::TYPE_TEXT, 60, array(
20
+ 'nullable' => false
21
+ ), 'Order id')
22
+ ->addColumn('user_selection', Varien_Db_Ddl_Table::TYPE_TEXT, '2M', array(
23
+ 'nullable' => false
24
+ ), 'UserSelection')
25
+ ->addIndex( $installer->getIdxName(
26
+ $installer->getTable('nektria_recs/lastmile'),
27
+ array('order_id'),
28
+ Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX
29
+ ) ,
30
+ array('order_id'),
31
+ array( 'type' =>Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX)
32
+ )
33
+ ->setComment( 'User Selection from Nektria ReCS' );
34
+
35
+ $installer->getConnection()->createTable( $table );
36
+ }
37
+
38
+ $table = $installer->getConnection()
39
+ ->changeColumn($installer->getTable('nektria_recs/lastmile'), 'lastmile_id', 'lastmile_id', array(
40
+ 'type' => Varien_Db_Ddl_Table::TYPE_INTEGER,
41
+ 'auto_increment' => true,
42
+ 'identity' => true
43
+ ));
44
+
45
+ $installer->endSetup();
app/design/adminhtml/default/default/layout/recs.xml ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <layout version="0.1.0">
2
+ <adminhtml_sales_order_view>
3
+ <reference name="order_tab_info">
4
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active"><template>recs/sales/order/view/info.phtml</template></action>
5
+ </reference>
6
+ </adminhtml_sales_order_view>
7
+
8
+ <adminhtml_sales_order_invoice_new>
9
+ <reference name="form">
10
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active"><template>recs/sales/order/invoice/create/form.phtml</template></action>
11
+ </reference>
12
+ </adminhtml_sales_order_invoice_new>
13
+
14
+ <adminhtml_sales_order_invoice_view>
15
+ <reference name="form">
16
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active"><template>recs/sales/order/invoice/view/form.phtml</template></action>
17
+ </reference>
18
+ </adminhtml_sales_order_invoice_view>
19
+
20
+ <adminhtml_sales_order_creditmemo_new>
21
+ <reference name="form">
22
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active"><template>recs/sales/order/creditmemo/create/form.phtml</template></action>
23
+ </reference>
24
+ </adminhtml_sales_order_creditmemo_new>
25
+
26
+ <adminhtml_sales_order_creditmemo_view>
27
+ <reference name="form">
28
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active"><template>recs/sales/order/creditmemo/view/form.phtml</template></action>
29
+ </reference>
30
+ </adminhtml_sales_order_creditmemo_view>
31
+
32
+ <adminhtml_sales_order_shipment_new>
33
+ <reference name="form">
34
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active"><template>recs/sales/order/shipment/create/form.phtml</template></action>
35
+ </reference>
36
+ </adminhtml_sales_order_shipment_new>
37
+
38
+ <adminhtml_sales_order_shipment_view>
39
+ <reference name="form">
40
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active"><template>recs/sales/order/shipment/view/form.phtml</template></action>
41
+ </reference>
42
+ </adminhtml_sales_order_shipment_view>
43
+ </layout>
app/design/adminhtml/default/default/template/recs/sales/order/creditmemo/create/form.phtml ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <form id="edit_form" method="post" action="<?php echo $this->getSaveUrl() ?>">
28
+ <?php echo $this->getBlockHtml('formkey')?>
29
+ <?php $_order = $this->getCreditmemo()->getOrder() ?>
30
+ <?php echo $this->getChildHtml('order_info') ?>
31
+
32
+ <?php if (!$_order->getIsVirtual()): ?>
33
+ <div class="box-left">
34
+ <?php else: ?>
35
+ <div class="box-right">
36
+ <?php endif; ?>
37
+ <!--Billing Address-->
38
+ <div class="entry-edit">
39
+ <div class="entry-edit-head">
40
+ <h4 class="icon-head head-payment-method"><?php echo Mage::helper('sales')->__('Payment Information') ?></h4>
41
+ </div>
42
+ <fieldset>
43
+ <div><?php echo $this->getChildHtml('order_payment') ?></div>
44
+ <div><?php echo Mage::helper('sales')->__('Order was placed using %s', $_order->getOrderCurrencyCode()) ?></div>
45
+ <?php /*if ($this->getCreditmemo()->canRefund()): ?>
46
+ <input type="checkbox" name="creditmemo[do_refund]" id="creditmemo_do_refund" value="1" checked/>
47
+ <label for="creditmemo_do_refund" class="normal"><?php echo Mage::helper('sales')->__('Refund Amount') ?></label>
48
+ <?php endif;*/ ?>
49
+ </fieldset>
50
+ </div>
51
+ </div>
52
+ <?php if (!$_order->getIsVirtual()): ?>
53
+ <div class="box-right">
54
+ <!--Shipping Address-->
55
+ <div class="entry-edit">
56
+ <div class="entry-edit-head">
57
+ <h4 class="icon-head head-shipping-method"><?php echo Mage::helper('sales')->__('Shipping Information') ?></h4>
58
+ </div>
59
+ <fieldset>
60
+ <strong><?php echo $this->escapeHtml($_order->getShippingDescription()) ?></strong>
61
+ <?php echo $this->helper('sales')->__('Total Shipping Charges'); ?>:
62
+
63
+ <?php if ($this->helper('tax')->displaySalesPriceInclTax($this->getSource()->getStoreId())): ?>
64
+ <?php $_excl = $this->displayShippingPriceInclTax($_order); ?>
65
+ <?php else: ?>
66
+ <?php $_excl = $this->displayPriceAttribute('shipping_amount', false, ' '); ?>
67
+ <?php endif; ?>
68
+ <?php $_incl = $this->displayShippingPriceInclTax($_order); ?>
69
+
70
+ <?php echo $_excl; ?>
71
+ <?php if ($this->helper('tax')->displaySalesBothPrices($this->getSource()->getStoreId()) && $_incl != $_excl): ?>
72
+ (<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
73
+ <?php endif; ?>
74
+
75
+ <?php if ($_order->getShippingMethod() == 'nektria_recs_lastmile'): ?>
76
+ <div><?php echo Mage::helper('nektria')->htmlAdminLastMileSelection($_order); ?></div>
77
+ <?php endif ?>
78
+ </fieldset>
79
+ </div>
80
+ </div>
81
+ <?php endif; ?>
82
+ <div class="clear"></div>
83
+
84
+ <div class="entry-edit">
85
+ <div class="entry-edit-head">
86
+ <h4 class="icon-head head-products"><?php echo Mage::helper('sales')->__('Items to Refund') ?></h4>
87
+ </div>
88
+ </div>
89
+ <div id="creditmemo_item_container">
90
+ <?php echo $this->getChildHtml('order_items') ?>
91
+ </div>
92
+ </form>
app/design/adminhtml/default/default/template/recs/sales/order/creditmemo/view/form.phtml ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php $_order = $this->getCreditmemo()->getOrder() ?>
28
+ <?php echo $this->getChildHtml('order_info') ?>
29
+ <?php if (!$_order->getIsVirtual()): ?>
30
+ <div class="box-left">
31
+ <?php else: ?>
32
+ <div class="box-right">
33
+ <?php endif; ?>
34
+ <!--Billing Address-->
35
+ <div class="entry-edit">
36
+ <div class="entry-edit-head">
37
+ <h4 class="icon-head head-payment-method"><?php echo $this->helper('sales')->__('Payment Information') ?></h4>
38
+ </div>
39
+ <fieldset>
40
+ <div><?php echo $this->getChildHtml('order_payment') ?></div>
41
+ <div><?php echo Mage::helper('sales')->__('Order was placed using %s', $_order->getOrderCurrencyCode()) ?></div>
42
+ </fieldset>
43
+ </div>
44
+ </div>
45
+ <?php if (!$_order->getIsVirtual()): ?>
46
+ <div class="box-right">
47
+ <!--Shipping Address-->
48
+ <div class="entry-edit">
49
+ <div class="entry-edit-head">
50
+ <h4 class="icon-head head-shipping-method"><?php echo $this->helper('sales')->__('Shipping Information') ?></h4>
51
+ </div>
52
+ <fieldset>
53
+ <strong><?php echo $this->escapeHtml($_order->getShippingDescription()) ?></strong>
54
+ <?php echo $this->helper('sales')->__('Total Shipping Charges'); ?>:
55
+
56
+ <?php if ($this->helper('tax')->displayShippingPriceIncludingTax()): ?>
57
+ <?php $_excl = $this->displayShippingPriceInclTax($_order); ?>
58
+ <?php else: ?>
59
+ <?php $_excl = $this->displayPriceAttribute('shipping_amount', false, ' '); ?>
60
+ <?php endif; ?>
61
+ <?php $_incl = $this->displayShippingPriceInclTax($_order); ?>
62
+
63
+ <?php echo $_excl; ?>
64
+ <?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
65
+ (<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
66
+ <?php endif; ?>
67
+
68
+ <?php if ($_order->getShippingMethod() == 'nektria_recs_lastmile'): ?>
69
+ <div><?php echo Mage::helper('nektria')->htmlAdminLastMileSelection($_order); ?></div>
70
+ <?php endif ?>
71
+ </fieldset>
72
+ </div>
73
+ </div>
74
+ <?php endif; ?>
75
+ <div class="clear"></div>
76
+ <?php $_items = $this->getCreditmemo()->getAllItems() ?>
77
+ <div class="entry-edit">
78
+ <div class="entry-edit-head">
79
+ <h4 class="icon-head head-products"><?php echo $this->helper('sales')->__('Items Refunded') ?></h4>
80
+ </div>
81
+ </div>
82
+ <?php if (count($_items)): ?>
83
+ <div id="creditmemo_items_container">
84
+ <?php echo $this->getChildHtml('creditmemo_items') ?>
85
+ </div>
86
+ <?php else: ?>
87
+ <div class="entry-edit">
88
+ <fieldset><center><?php echo $this->helper('sales')->__('No Items') ?></center></fieldset>
89
+ </div>
90
+ <?php endif; ?>
91
+ <br />
92
+ <div class="box-left entry-edit">
93
+ <div class="entry-edit-head"><h4><?php echo $this->__('Credit Memo History') ?></h4></div>
94
+ <fieldset><?php echo $this->getChildHtml('order_comments') ?></fieldset>
95
+ </div>
96
+
97
+ <div class="box-right entry-edit" id="history_form">
98
+ <div class="entry-edit-head"><h4><?php echo $this->__('Credit Memo Totals') ?></h4></div>
99
+ <div class="order-totals"><?php echo $this->getChildHtml('creditmemo_totals') ?></div>
100
+ </div>
101
+ <div class="clear"></div>
app/design/adminhtml/default/default/template/recs/sales/order/invoice/create/form.phtml ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <form id="edit_form" method="post" action="<?php echo $this->getSaveUrl() ?>">
28
+ <?php echo $this->getBlockHtml('formkey')?>
29
+ <?php $_order = $this->getInvoice()->getOrder() ?>
30
+ <?php echo $this->getChildHtml('order_info') ?>
31
+ <?php if (!$_order->getIsVirtual()): ?>
32
+ <div class="box-left">
33
+ <?php else: ?>
34
+ <div class="box-right">
35
+ <?php endif; ?>
36
+
37
+ <div class="entry-edit">
38
+ <div class="entry-edit-head">
39
+ <h4 class="icon-head head-payment-method"><?php echo Mage::helper('sales')->__('Payment Information') ?></h4>
40
+ </div>
41
+ <fieldset>
42
+ <div><?php echo $this->getChildHtml('order_payment') ?></div>
43
+ <div><?php echo Mage::helper('sales')->__('Order was placed using %s', $_order->getOrderCurrencyCode()) ?></div>
44
+ </fieldset>
45
+ </div>
46
+ </div>
47
+ <?php if (!$_order->getIsVirtual()): ?>
48
+ <div class="box-right">
49
+ <!--Shipping Address-->
50
+ <div class="entry-edit">
51
+ <div class="entry-edit-head">
52
+ <h4 class="icon-head head-shipping-method"><?php echo Mage::helper('sales')->__('Shipping Information') ?></h4>
53
+ </div>
54
+ <fieldset>
55
+ <div>
56
+ <strong><?php echo $this->escapeHtml($_order->getShippingDescription()) ?></strong>
57
+ <?php echo $this->helper('sales')->__('Total Shipping Charges'); ?>:
58
+
59
+ <?php if ($this->helper('tax')->displayShippingPriceIncludingTax()): ?>
60
+ <?php $_excl = $this->displayShippingPriceInclTax($_order); ?>
61
+ <?php else: ?>
62
+ <?php $_excl = $this->displayPriceAttribute('shipping_amount', false, ' '); ?>
63
+ <?php endif; ?>
64
+ <?php $_incl = $this->displayShippingPriceInclTax($_order); ?>
65
+
66
+ <?php echo $_excl; ?>
67
+ <?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
68
+ (<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
69
+ <?php endif; ?>
70
+ </div>
71
+ <?php if ($_order->getShippingMethod() == 'nektria_recs_lastmile'): ?>
72
+ <div><?php echo Mage::helper('nektria')->htmlAdminLastMileSelection($_order); ?></div>
73
+ <?php endif ?>
74
+
75
+ <?php if ($this->canCreateShipment() && $this->canShipPartiallyItem()): ?>
76
+ <p class="nm">
77
+ <label for="invoice_do_shipment" class="normal"><?php echo Mage::helper('sales')->__('Create Shipment') ?></label>
78
+ <input type="checkbox" name="invoice[do_shipment]" id="invoice_do_shipment" value="1" <?php echo $this->hasInvoiceShipmentTypeMismatch()?' disabled="disabled"':'' ?> />
79
+ </p>
80
+ <?php if ($this->hasInvoiceShipmentTypeMismatch()): ?>
81
+ <small><?php echo $this->__('Some items in this order have different invoice and shipment types. You can create shipment only after the invoice is created.') ?></small>
82
+ <?php endif; ?>
83
+ <?php endif; ?>
84
+ <div id="tracking" style="display:none;"><?php echo $this->getChildHtml('tracking',false) ?></div>
85
+ </fieldset>
86
+ </div>
87
+ </div>
88
+ <?php endif; ?>
89
+ <div class="clear"></div>
90
+
91
+ <div class="entry-edit">
92
+ <div class="entry-edit-head">
93
+ <?php
94
+ $_itemsGridLabel = $this->getForcedShipmentCreate()?'Items to Invoice and Ship':'Items to Invoice';
95
+ ?>
96
+ <h4 class="icon-head head-products"><?php echo Mage::helper('sales')->__('%s', $_itemsGridLabel) ?></h4>
97
+ </div>
98
+ </div>
99
+ <div id="invoice_item_container">
100
+ <?php echo $this->getChildHtml('order_items') ?>
101
+ </div>
102
+ </form>
103
+ <script type="text/javascript">
104
+ //<![CDATA[
105
+ var createShipment = $('invoice_do_shipment');
106
+ createShipment.observe('click', function(e){
107
+ if (createShipment.checked) {
108
+ document.getElementById('tracking').style.display = 'block';
109
+ } else {
110
+ document.getElementById('tracking').style.display = 'none'
111
+ }
112
+ })
113
+
114
+ /*forced creating of shipment*/
115
+ var forcedShipmentCreate = <?php echo $this->getForcedShipmentCreate() ?>;
116
+ var shipmentElement = $('invoice_do_shipment');
117
+ if (forcedShipmentCreate && shipmentElement) {
118
+ shipmentElement.checked = true;
119
+ shipmentElement.disabled = true;
120
+ document.getElementById('tracking').style.display = 'block';
121
+ }
122
+ //]]>
123
+ </script>
app/design/adminhtml/default/default/template/recs/sales/order/invoice/view/form.phtml ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php $_invoice = $this->getInvoice() ?>
28
+ <?php $_order = $_invoice->getOrder() ?>
29
+ <?php echo $this->getChildHtml('order_info') ?>
30
+ <?php if (!$_order->getIsVirtual()): ?>
31
+ <div class="box-left">
32
+ <?php else: ?>
33
+ <div class="box-right">
34
+ <?php endif; ?>
35
+ <!--Billing Address-->
36
+ <div class="entry-edit">
37
+ <div class="entry-edit-head">
38
+ <h4 class="icon-head head-payment-method"><?php echo $this->helper('sales')->__('Payment Information') ?></h4>
39
+ </div>
40
+ <fieldset>
41
+ <div><?php echo $this->getChildHtml('order_payment') ?></div>
42
+ <div><?php echo Mage::helper('sales')->__('Order was placed using %s', $_order->getOrderCurrencyCode()) ?></div>
43
+ </fieldset>
44
+ </div>
45
+ </div>
46
+ <?php if (!$_order->getIsVirtual()): ?>
47
+ <div class="box-right">
48
+ <!--Shipping Address-->
49
+ <div class="entry-edit">
50
+ <div class="entry-edit-head">
51
+ <h4 class="icon-head head-shipping-method"><?php echo $this->helper('sales')->__('Shipping Information') ?></h4>
52
+ </div>
53
+ <fieldset>
54
+ <strong><?php echo $this->escapeHtml($_order->getShippingDescription()) ?></strong>
55
+ <?php echo $this->helper('sales')->__('Total Shipping Charges'); ?>:
56
+
57
+ <?php if ($this->helper('tax')->displayShippingPriceIncludingTax()): ?>
58
+ <?php $_excl = $this->displayShippingPriceInclTax($_order); ?>
59
+ <?php else: ?>
60
+ <?php $_excl = $this->displayPriceAttribute('shipping_amount', false, ' '); ?>
61
+ <?php endif; ?>
62
+ <?php $_incl = $this->displayShippingPriceInclTax($_order); ?>
63
+
64
+ <?php echo $_excl; ?>
65
+ <?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
66
+ (<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
67
+ <?php endif; ?>
68
+ <?php if ($_order->getShippingMethod() == 'nektria_recs_lastmile'): ?>
69
+ <div><?php echo Mage::helper('nektria')->htmlAdminLastMileSelection($_order); ?></div>
70
+ <?php endif ?>
71
+
72
+ <div><?php echo $this->getChildHtml('shipment_tracking') ?></div>
73
+ </fieldset>
74
+ </div>
75
+ <?php endif; ?>
76
+ </div>
77
+ <div class="clear"></div>
78
+
79
+ <div class="entry-edit">
80
+ <div class="entry-edit-head">
81
+ <h4 class="icon-head head-products"><?php echo $this->helper('sales')->__('Items Invoiced') ?></h4>
82
+ </div>
83
+ <div id="invoice_item_container">
84
+ <?php echo $this->getChildHtml('invoice_items') ?>
85
+ </div>
86
+ </div>
87
+
88
+ <div class="box-left entry-edit">
89
+ <div class="entry-edit-head"><h4><?php echo $this->__('Invoice History') ?></h4></div>
90
+ <fieldset><?php echo $this->getChildHtml('order_comments') ?></fieldset>
91
+ </div>
92
+
93
+ <div class="box-right entry-edit" id="history_form">
94
+ <div class="entry-edit-head"><h4><?php echo $this->__('Invoice Totals') ?></h4></div>
95
+ <div class="order-totals"><?php echo $this->getChildHtml('invoice_totals') ?></div>
96
+ </div>
97
+ <div class="clear"></div>
app/design/adminhtml/default/default/template/recs/sales/order/shipment/create/form.phtml ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <form id="edit_form" method="post" action="<?php echo $this->getSaveUrl() ?>">
28
+ <?php echo $this->getBlockHtml('formkey')?>
29
+ <?php $_order = $this->getShipment()->getOrder() ?>
30
+ <?php echo $this->getChildHtml('order_info') ?>
31
+
32
+
33
+ <div class="box-left">
34
+ <!--Billing Address-->
35
+ <div class="entry-edit">
36
+ <div class="entry-edit-head">
37
+ <h4 class="icon-head head-payment-method"><?php echo Mage::helper('sales')->__('Payment Information') ?></h4>
38
+ </div>
39
+ <fieldset>
40
+ <div><?php echo $this->getPaymentHtml() ?></div>
41
+ <div><?php echo Mage::helper('sales')->__('The order was placed using %s', $_order->getOrderCurrencyCode()) ?></div>
42
+ </fieldset>
43
+ </div>
44
+ </div>
45
+ <div class="box-right">
46
+ <!--Shipping Address-->
47
+ <div class="entry-edit">
48
+ <div class="entry-edit-head">
49
+ <h4 class="icon-head head-shipping-method"><?php echo Mage::helper('sales')->__('Shipping Information') ?></h4>
50
+ </div>
51
+ <fieldset>
52
+ <div>
53
+ <strong><?php echo $this->escapeHtml($_order->getShippingDescription()) ?></strong>
54
+ <?php echo $this->helper('sales')->__('Total Shipping Charges'); ?>:
55
+
56
+ <?php if ($this->helper('tax')->displayShippingPriceIncludingTax()): ?>
57
+ <?php $_excl = $this->displayShippingPriceInclTax($_order); ?>
58
+ <?php else: ?>
59
+ <?php $_excl = $this->displayPriceAttribute('shipping_amount', false, ' '); ?>
60
+ <?php endif; ?>
61
+ <?php $_incl = $this->displayShippingPriceInclTax($_order); ?>
62
+
63
+ <?php echo $_excl; ?>
64
+ <?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
65
+ (<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
66
+ <?php endif; ?>
67
+ </div>
68
+ <?php if ($_order->getShippingMethod() == 'nektria_recs_lastmile'): ?>
69
+ <div><?php echo Mage::helper('nektria')->htmlAdminLastMileSelection($_order); ?></div>
70
+ <?php endif ?>
71
+ <div><?php echo $this->getChildHtml('shipment_tracking') ?></div>
72
+ </fieldset>
73
+ </div>
74
+ </div>
75
+ <div class="clear"></div>
76
+
77
+ <div class="entry-edit">
78
+ <div class="entry-edit-head">
79
+ <h4 class="icon-head head-products"><?php echo Mage::helper('sales')->__('Items to Ship') ?></h4>
80
+ </div>
81
+ </div>
82
+ <div id="ship_items_container">
83
+ <?php echo $this->getItemsHtml() ?>
84
+ </div>
85
+ </form>
86
+ <?php echo $this->getChildHtml('shipment_packaging') ?>
87
+ <script type="text/javascript">
88
+ //<![CDATA[
89
+ document.observe("dom:loaded", function() {
90
+ setTimeout(function(){
91
+ packaging.setConfirmPackagingCallback(function(){
92
+ packaging.setParamsCreateLabelRequest($('edit_form').serialize(true));
93
+ packaging.sendCreateLabelRequest();
94
+ });
95
+ packaging.setLabelCreatedCallback(function(response){
96
+ setLocation("<?php echo $this->getUrl(
97
+ '*/sales_order/view',
98
+ array('order_id' => $this->getShipment()->getOrderId())
99
+ ); ?>");
100
+ });
101
+ packaging.setCancelCallback(function() {
102
+ packaging.cleanPackages();
103
+ $('create_shipping_label').checked = false;
104
+ toggleCreateLabelCheckbox();
105
+ });
106
+ packaging.setItemQtyCallback(function(itemId){
107
+ var item = $$('[name="shipment[items]['+itemId+']"]')[0];
108
+ if (item && !isNaN(item.value)) {
109
+ return item.value;
110
+ }
111
+ });
112
+ }, 500);
113
+ });
114
+
115
+ editForm = new varienForm('edit_form');
116
+ //]]>
117
+ </script>
app/design/adminhtml/default/default/template/recs/sales/order/shipment/view/form.phtml ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php $_order = $this->getShipment()->getOrder() ?>
28
+ <?php echo $this->getChildHtml('order_info') ?>
29
+
30
+ <div class="box-left">
31
+ <!--Billing Address-->
32
+ <div class="entry-edit">
33
+ <div class="entry-edit-head">
34
+ <h4 class="icon-head head-payment-method"><?php echo $this->helper('sales')->__('Payment Information') ?></h4>
35
+ </div>
36
+ <fieldset>
37
+ <div><?php echo $this->getChildHtml('order_payment') ?></div>
38
+ <div><?php echo Mage::helper('sales')->__('Order was placed using %s', $_order->getOrderCurrencyCode()) ?></div>
39
+ </fieldset>
40
+ </div>
41
+ </div>
42
+ <div class="box-right">
43
+ <!--Shipping Address-->
44
+ <div class="entry-edit">
45
+ <div class="entry-edit-head">
46
+ <h4 class="icon-head head-shipping-method"><?php echo $this->helper('sales')->__('Shipping and Tracking Information') ?></h4>
47
+ </div>
48
+ <fieldset>
49
+ <div>
50
+ <?php if($this->getShipment()->getTracksCollection()->count()): ?>
51
+ <a href="#" id="linkId" onclick="popWin('<?php echo $this->helper('shipping')->getTrackingPopupUrlBySalesModel($this->getShipment()) ?>','trackshipment','width=800,height=600,resizable=yes,scrollbars=yes')" title="<?php echo $this->__('Track this shipment') ?>"><?php echo $this->__('Track this shipment') ?></a>
52
+ <br/>
53
+ <?php endif; ?>
54
+ <strong><?php echo $this->escapeHtml($_order->getShippingDescription()) ?></strong>
55
+ <?php echo $this->helper('sales')->__('Total Shipping Charges'); ?>:
56
+
57
+ <?php if ($this->helper('tax')->displayShippingPriceIncludingTax()): ?>
58
+ <?php $_excl = $this->displayShippingPriceInclTax($_order); ?>
59
+ <?php else: ?>
60
+ <?php $_excl = $this->displayPriceAttribute('shipping_amount', false, ' '); ?>
61
+ <?php endif; ?>
62
+ <?php $_incl = $this->displayShippingPriceInclTax($_order); ?>
63
+
64
+ <?php echo $_excl; ?>
65
+ <?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
66
+ (<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
67
+ <?php endif; ?>
68
+ <?php if ($_order->getShippingMethod() == 'nektria_recs_lastmile'): ?>
69
+ <div><?php echo Mage::helper('nektria')->htmlAdminLastMileSelection($_order); ?></div>
70
+ <?php endif ?>
71
+ </div>
72
+
73
+
74
+ <?php if ($this->canCreateShippingLabel()): ?>
75
+ <div style="text-align: center; margin: 10px 0;">
76
+ <?php echo $this->getCreateLabelButton()?>
77
+ <?php if ($this->getShipment()->getShippingLabel()): ?>
78
+ <?php echo $this->getPrintLabelButton() ?>
79
+ <?php endif ?>
80
+ <?php if ($this->getShipment()->getPackages()): ?>
81
+ <?php echo $this->getShowPackagesButton() ?>
82
+ <?php endif ?>
83
+ </div>
84
+ <?php endif ?>
85
+ <div><?php echo $this->getChildHtml('shipment_tracking') ?></div>
86
+ </fieldset>
87
+ <?php echo $this->getChildHtml('shipment_packaging') ?>
88
+ <script type="text/javascript">
89
+ //<![CDATA[
90
+ document.observe("dom:loaded", function() {
91
+ setTimeout(function(){
92
+ packaging.setConfirmPackagingCallback(function(){
93
+ packaging.sendCreateLabelRequest();
94
+ });
95
+ packaging.setLabelCreatedCallback(function(response){
96
+ setLocation("<?php echo $this->getUrl(
97
+ '*/sales_order_shipment/view',
98
+ array('shipment_id' => $this->getShipment()->getId())
99
+ ); ?>");
100
+ });
101
+ }, 500);
102
+ });
103
+ //]]>
104
+ </script>
105
+ </div>
106
+ </div>
107
+ <div class="clear"></div>
108
+
109
+ <div class="entry-edit">
110
+ <div class="entry-edit-head">
111
+ <h4 class="icon-head head-products"><?php echo $this->helper('sales')->__('Items Shipped') ?></h4>
112
+ </div>
113
+ </div>
114
+
115
+ <?php echo $this->getChildHtml('shipment_items') ?>
116
+ <?php echo $this->getChildHtml('shipment_packed') ?>
117
+
118
+ <div class="box-left entry-edit">
119
+ <div class="entry-edit-head"><h4><?php echo $this->__('Shipment History') ?></h4></div>
120
+ <fieldset><?php echo $this->getChildHtml('order_comments') ?></fieldset>
121
+ </div>
122
+ <div class="clear"></div>
app/design/adminhtml/default/default/template/recs/sales/order/view/info.phtml ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php /** @var $this Mage_Adminhtml_Block_Sales_Order_View_Tab_Info */ ?>
28
+ <?php $_order = $this->getOrder() ?>
29
+
30
+ <div>
31
+ <div id="order-messages">
32
+ <?php echo $this->getChildHtml('order_messages') ?>
33
+ </div>
34
+ <?php echo $this->getChildHtml('order_info') ?>
35
+ <input type="hidden" name="order_id" value="<?php echo $_order->getId() ?>"/>
36
+ <?php if ($_order->getIsVirtual()): ?>
37
+ <div class="box-right">
38
+ <?php else: ?>
39
+ <div class="box-left">
40
+ <?php endif; ?>
41
+ <!--Payment Method-->
42
+ <div class="entry-edit">
43
+ <div class="entry-edit-head">
44
+ <h4 class="icon-head head-payment-method"><?php echo Mage::helper('sales')->__('Payment Information') ?></h4>
45
+ </div>
46
+ <fieldset>
47
+ <?php echo $this->getPaymentHtml() ?>
48
+ <div><?php echo Mage::helper('sales')->__('Order was placed using %s', $_order->getOrderCurrencyCode()) ?></div>
49
+ </fieldset>
50
+ </div>
51
+ </div>
52
+ <?php if (!$_order->getIsVirtual()): ?>
53
+ <div class="box-right">
54
+ <!--Shipping Method-->
55
+ <div class="entry-edit">
56
+ <div class="entry-edit-head">
57
+ <h4 class="icon-head head-shipping-method"><?php echo Mage::helper('sales')->__('Shipping &amp; Handling Information') ?></h4>
58
+ </div>
59
+ <fieldset>
60
+ <?php if ($_order->getTracksCollection()->count()) : ?>
61
+ <a href="#" id="linkId" onclick="popWin('<?php echo $this->helper('shipping')->getTrackingPopupUrlBySalesModel($_order) ?>','trackorder','width=800,height=600,resizable=yes,scrollbars=yes')" title="<?php echo $this->__('Track Order') ?>"><?php echo $this->__('Track Order') ?></a>
62
+ <br/>
63
+ <?php endif; ?>
64
+ <?php if ($_order->getShippingDescription()): ?>
65
+ <strong><?php echo $this->escapeHtml($_order->getShippingDescription()) ?></strong>
66
+
67
+ <?php if ($this->helper('tax')->displayShippingPriceIncludingTax()): ?>
68
+ <?php $_excl = $this->displayShippingPriceInclTax($_order); ?>
69
+ <?php else: ?>
70
+ <?php $_excl = $this->displayPriceAttribute('shipping_amount', false, ' '); ?>
71
+ <?php endif; ?>
72
+ <?php $_incl = $this->displayShippingPriceInclTax($_order); ?>
73
+
74
+ <?php echo $_excl; ?>
75
+ <?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
76
+ (<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
77
+ <?php endif; ?>
78
+ <?php if ($_order->getShippingMethod() == 'nektria_recs_lastmile'): ?>
79
+ <div><?php echo Mage::helper('nektria')->htmlAdminLastMileSelection($_order); ?></div>
80
+ <?php endif ?>
81
+ <?php else: ?>
82
+ <?php echo $this->helper('sales')->__('No shipping information available'); ?>
83
+ <?php endif; ?>
84
+ </fieldset>
85
+ </div>
86
+ </div>
87
+ <?php endif; ?>
88
+ <div class="clear"></div>
89
+ <?php echo $this->getGiftOptionsHtml() ?>
90
+ <div class="clear"></div>
91
+ <div class="entry-edit">
92
+ <div class="entry-edit-head">
93
+ <h4 class="icon-head head-products"><?php echo Mage::helper('sales')->__('Items Ordered') ?></h4>
94
+ </div>
95
+ </div>
96
+ <?php echo $this->getItemsHtml() ?>
97
+ <div class="clear"></div>
98
+
99
+ <div class="box-left">
100
+ <div class="entry-edit">
101
+ <div class="entry-edit-head">
102
+ <h4><?php echo Mage::helper('sales')->__('Comments History') ?></h4>
103
+ </div>
104
+ <fieldset><?php echo $this->getChildHtml('order_history') ?></fieldset>
105
+ </div>
106
+ </div>
107
+ <div class="box-right entry-edit">
108
+ <div class="entry-edit-head"><h4><?php echo Mage::helper('sales')->__('Order Totals') ?></h4></div>
109
+ <div class="order-totals"><?php echo $this->getChildHtml('order_totals') ?></div>
110
+ </div>
111
+ <div class="clear"></div>
112
+ </div>
113
+
114
+ <?php echo $this->getChildHtml('popup_window');?>
115
+ <script type="text/javascript">
116
+ //<![CDATA[
117
+ /**
118
+ * Retrieve gift options tooltip content
119
+ */
120
+ function getGiftOptionsTooltipContent(itemId) {
121
+ var contentLines = [];
122
+ var headerLine = null;
123
+ var contentLine = null;
124
+
125
+ $$('#gift_options_data_' + itemId + ' .gift-options-tooltip-content').each(function (element) {
126
+ if (element.down(0)) {
127
+ headerLine = element.down(0).innerHTML;
128
+ contentLine = element.down(0).next().innerHTML;
129
+ if (contentLine.length > 30) {
130
+ contentLine = contentLine.slice(0,30) + '...';
131
+ }
132
+ contentLines.push(headerLine + ' ' + contentLine);
133
+ }
134
+ });
135
+ return contentLines.join('<br/>');
136
+ }
137
+ giftOptionsTooltip.setTooltipContentLoaderFunction(getGiftOptionsTooltipContent);
138
+ //]]>
139
+ </script>
app/design/adminhtml/default/default/template/recs/sales/order/view/lastmile.phtml ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //this block view receives as param "order" object called from Nektria Helper
3
+ $_order = $this->getOrder();
4
+
5
+ $userSelection = Mage::getModel('nektria_recs/lastmile')->load($_order->getIncrementId(),'order_id');
6
+ $json = $userSelection->getUserSelection();
7
+
8
+ if ($json){
9
+ try{
10
+ $selectedTime = Mage::helper('core')->jsonDecode($json);
11
+ }catch(Exception $e){
12
+ $selectedTime = array();
13
+ }
14
+ }
15
+ ?>
16
+
17
+ <?php if ($json): ?>
18
+ <style type="text/css">
19
+ .nektria_user_selection ul li{
20
+ list-style: none;
21
+ }
22
+ .nektria_user_selection{
23
+ margin-top: 10px;
24
+ font-size: 0.95em;
25
+ }
26
+ </style>
27
+ <div class="nektria_user_selection">
28
+ <?php echo $this->__('Selected delivery'); ?><br />
29
+ <ul>
30
+ <?php foreach ($selectedTime['validation_windows'] as $selectedDate): ?>
31
+ <li><?php
32
+ echo $this->__('from').
33
+ ': '.Mage::getModel('core/date')->date('H:i', strtotime($selectedDate['start_time'])).
34
+ ' '.Mage::helper('nektria')->_('to').
35
+ ': '.Mage::getModel('core/date')->date('H:i', strtotime($selectedDate['end_time'])).
36
+ ' '.Mage::helper('nektria')->_('for').
37
+ ': '.Mage::getModel('core/date')->date('d/m/y', strtotime($selectedDate['end_time']));
38
+ ?></li>
39
+ <?php endforeach ?>
40
+ </ul>
41
+ </div>
42
+ <?php endif; ?>
app/design/frontend/base/default/layout/recs.xml ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout version="0.1.0">
3
+ <default>
4
+ </default>
5
+
6
+ <!-- Main template for collectCarrier -->
7
+ <checkout_onepage_shippingmethod>
8
+ <reference name="root">
9
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active">
10
+ <template>recs/shipping_method/available.phtml</template>
11
+ </action>
12
+ </reference>
13
+ </checkout_onepage_shippingmethod>
14
+
15
+ <!-- Below templates only works for right ajax panel in OnePage Checkout -->
16
+ <checkout_onepage_index>
17
+ <reference name="shippingmethod.progress">
18
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active">
19
+ <template>recs/progress/shipping_method.phtml</template>
20
+ </action>
21
+ </reference>
22
+
23
+ <reference name='checkout.onepage.shipping_method.available'>
24
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active">
25
+ <template>recs/shipping_method/available.phtml</template>
26
+ </action>
27
+ </reference>
28
+ </checkout_onepage_index>
29
+
30
+ <gomage_checkout_onepage_index>
31
+ <reference name='checkout.onepage.shipping_method.available'>
32
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active">
33
+ <template>recs/shipping_method/available.phtml</template>
34
+ </action>
35
+ </reference>
36
+ </gomage_checkout_onepage_index>
37
+
38
+ <gomage_checkout_onepage_methods>
39
+ <reference name='checkout.onepage.shipping_method.available'>
40
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active">
41
+ <template>recs/shipping_method/available.phtml</template>
42
+ </action>
43
+ </reference>
44
+ </gomage_checkout_onepage_methods>
45
+
46
+
47
+ <checkout_onepage_progress>
48
+ <reference name="shippingmethod.progress">
49
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active">
50
+ <template>recs/progress/shipping_method.phtml</template>
51
+ </action>
52
+ </reference>
53
+ </checkout_onepage_progress>
54
+
55
+ <checkout_onepage_progress_shipping_method>
56
+ <reference name="root">
57
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active">
58
+ <template>recs/progress/shipping_method.phtml</template>
59
+ </action>
60
+ </reference>
61
+ </checkout_onepage_progress_shipping_method>
62
+
63
+ <checkout_onepage_review>
64
+ <reference name="checkout.onepage.review.info.totals">
65
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active">
66
+ <template>recs/totals/onepage.phtml</template>
67
+ </action>
68
+ </reference>
69
+ </checkout_onepage_review>
70
+
71
+ <gomage_checkout_onepage_index>
72
+ <reference name="checkout.onepage.review.info.totals">
73
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active">
74
+ <template>recs/totals/gomage.phtml</template>
75
+ </action>
76
+ </reference>
77
+ </gomage_checkout_onepage_index>
78
+
79
+ <gomage_checkout_onepage_review>
80
+ <reference name="checkout.onepage.review.info.totals">
81
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active">
82
+ <template>recs/totals/gomage.phtml</template>
83
+ </action>
84
+ </reference>
85
+ </gomage_checkout_onepage_review>
86
+
87
+ <checkout_onepage_success>
88
+ <reference name="order_totals">
89
+ <action method="setTemplate" ifconfig="carriers/nektria_recs/active">
90
+ <template>recs/totals/success.phtml</template>
91
+ </action>
92
+ </reference>
93
+ </checkout_onepage_success>
94
+ </layout>
app/design/frontend/base/default/template/recs/email/lastmile.phtml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $json = Mage::getSingleton('checkout/session')->getNektriaUserSelection(FALSE);
3
+
4
+ if ($json){
5
+ try{
6
+ $selectedTime = Mage::helper('core')->jsonDecode($json);
7
+ }catch(Exception $e){
8
+ $selectedTime = array();
9
+ }
10
+ }
11
+ ?>
12
+
13
+ <?php if ($json): ?>
14
+ <style type="text/css">
15
+ .nektria_user_selection ul li{
16
+ list-style: none;
17
+ }
18
+ .nektria_user_selection{
19
+ margin-top: 10px;
20
+ font-size: 0.95em;
21
+ }
22
+ </style>
23
+ <div class="nektria_user_selection">
24
+ <?php echo $this->__('Selected delivery'); ?><br />
25
+ <ul>
26
+ <?php foreach ($selectedTime['validation_windows'] as $selectedDate): ?>
27
+ <li><?php
28
+ echo $this->__('from').
29
+ ': '.Mage::getModel('core/date')->date('h:i', strtotime($selectedDate['start_time'])).
30
+ ' '.Mage::helper('nektria')->_('to').
31
+ ': '.Mage::getModel('core/date')->date('h:i', strtotime($selectedDate['end_time'])).
32
+ ' '.Mage::helper('nektria')->_('for').
33
+ ': '.Mage::getModel('core/date')->date('d/m/y', strtotime($selectedDate['end_time']));
34
+ ?></li>
35
+ <?php endforeach ?>
36
+ </ul>
37
+ </div>
38
+ <?php endif; ?>
app/design/frontend/base/default/template/recs/progress/shipping_method.phtml ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magento.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magento.com for more information.
20
+ *
21
+ * @category design
22
+ * @package base_default
23
+ * @copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+
28
+ <?php if ($this->getCheckout()->getStepData('shipping_method', 'complete')): ?>
29
+ <dt class="complete">
30
+ <?php echo $this->__('Shipping Method') ?> <span class="changelink"><span class="separator">|</span> <a
31
+ href="#shipping_method"
32
+ onclick="checkout.changeSection('opc-shipping_method'); return false;"><?php echo $this->__('Change') ?></a></span>
33
+ </dt>
34
+ <dd class="complete">
35
+ <?php if ($this->getShippingMethod()): ?>
36
+ <?php echo $this->getShippingDescription() ?>
37
+
38
+ <?php if (! Mage::helper('nektria')->getLastMileSelected() ): ?>
39
+
40
+ <?php $_excl = $this->getShippingPriceExclTax(); ?>
41
+ <?php $_incl = $this->getShippingPriceInclTax(); ?>
42
+ <?php if ($this->helper('tax')->displayShippingPriceIncludingTax()): ?>
43
+ <?php echo $_incl; ?>
44
+ <?php else: ?>
45
+ <?php echo $_excl; ?>
46
+ <?php endif; ?>
47
+ <?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
48
+ (<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
49
+ <?php endif; ?>
50
+
51
+ <?php else: ?>
52
+
53
+ <?php echo Mage::helper('nektria')->getLastMileSelectedPrice() ?>
54
+
55
+ <?php endif; ?>
56
+ <?php else: ?>
57
+ <?php echo $this->__('Shipping method has not been selected yet') ?>
58
+ <?php endif; ?>
59
+ </dd>
60
+ <?php else: ?>
61
+ <dt>
62
+ <?php echo $this->__('Shipping Method') ?>
63
+ </dt>
64
+ <?php endif; ?>
app/design/frontend/base/default/template/recs/shipping_method/available.phtml ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package base_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php /** @var $this Mage_Checkout_Block_Onepage_Shipping_Method_Available */ ?>
28
+ <?php $_shippingRateGroups = $this->getShippingRates(); ?>
29
+ <?php if (!$_shippingRateGroups): ?>
30
+ <p><?php echo $this->__('Sorry, no quotes are available for this order at this time.') ?></p>
31
+ <?php else: ?>
32
+ <dl class="sp-methods">
33
+ <?php $shippingCodePrice = array(); ?>
34
+ <?php $_sole = count($_shippingRateGroups) == 1; foreach ($_shippingRateGroups as $code => $_rates): ?>
35
+ <?php if ( $this->getCarrierName($code) !== 'nektria_recs' ) : ?>
36
+ <dt><?php echo $this->escapeHtml($this->getCarrierName($code)) ?></dt>
37
+ <?php endif; ?>
38
+ <dd>
39
+ <ul>
40
+ <?php $_sole = $_sole && count($_rates) == 1; foreach ($_rates as $_rate): ?>
41
+ <?php $shippingCodePrice[] = "'".$_rate->getCode()."':".(float)$_rate->getPrice(); ?>
42
+ <li>
43
+ <?php if ($_rate->getErrorMessage()): ?>
44
+ <ul class="messages"><li class="error-msg"><ul><li><?php echo $this->escapeHtml($_rate->getErrorMessage()) ?></li></ul></li></ul>
45
+
46
+ <!-- En caso de que el método lastmile esté disponible -->
47
+ <?php elseif ($_rate->getMethod() == "lastmile") : ?>
48
+ <script type="text/javascript">
49
+ if(typeof(jQuery)== "undefined"){
50
+ var script = document.createElement("script");
51
+ script.src = "https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js";
52
+ script.onload = function(){ jQuery.noConflict(); }
53
+ document.getElementsByTagName('head')[0].appendChild(script);
54
+ }
55
+ </script>
56
+ <?php
57
+ //Cargamos el código javascript, html y css para el widget de Nektria
58
+ $html_code = Mage::getSingleton('checkout/session')->getNektriaHtml();
59
+ Mage::getSingleton('checkout/session')->unsNektriaHtml();
60
+ $js_code = Mage::getSingleton('checkout/session')->getNektriaJs();
61
+ Mage::getSingleton('checkout/session')->unsNektriaJs();
62
+ $css_code = Mage::getSingleton('checkout/session')->getNektriaCss();
63
+ Mage::getSingleton('checkout/session')->unsNektriaCss();
64
+ ?>
65
+
66
+ <script type="text/javascript">
67
+
68
+ var nektriaUserSelection = false;
69
+ var gomage_lightCheckout = false;
70
+
71
+ function nektria_selection_callback(userSelection, totalPrice){
72
+ window.nektriaStringUserSelection = userSelection;
73
+ jQuery("#nektria_selection").val(userSelection);
74
+ nektria_data = JSON.parse(userSelection);
75
+ //Update the selected price in the label with currency symbol and decimal separator
76
+ element_replaced = jQuery(".price",jQuery("#s_method_nektria_recs_lastmile").parent().next());
77
+ replacing_strings = element_replaced.html().match(/(\d+([\.|,])\d+)(\s|&nbsp;)(.*)/);
78
+ if (replacing_strings){
79
+ element_replaced.html( nektria_data.total_price.replace('.',replacing_strings[2]) + "&nbsp;" + replacing_strings[4] );
80
+ }
81
+ //confirm selection to continue submit
82
+ nektriaUserSelection = true;
83
+
84
+ jQuery("#s_method_nektria_recs_lastmile").prop("checked",true).removeAttr("disabled");
85
+ jQuery("#s_method_nektria_recs_lastmile").click();
86
+ if (!gomage_lightCheckout){
87
+ shippingMethod.save();
88
+ }
89
+ }
90
+
91
+ <?php if(Mage::getSingleton('checkout/session')->getPriceMatrix()): ?>
92
+
93
+ var jsfile = document.createElement("script");
94
+
95
+ jsfile.setAttribute("type", "text/javascript");
96
+ jsfile.setAttribute("src", "<?php echo $js_code; ?>");
97
+
98
+ jsfile.onload = function() {
99
+ jQuery("#nektriaTimeWindowBT").on("click change", function(){
100
+ nektria_recs.showTimeWindowArea();
101
+ jQuery("#s_method_nektria_recs_lastmile").prop("checked",false).attr("disabled","disabled");
102
+ jQuery("#co-shipping-method-form input.radio, #gcheckout-shipping-method-available input.radio[name='shipping_method']").prop("checked",false);
103
+ });
104
+
105
+ jQuery("#co-shipping-method-form input.radio").not("#s_method_nektria_recs_lastmile").on("click change" ,function(){
106
+ nektria_recs.hideTimeWindowArea();
107
+ jQuery("#nektriaTimeWindowBT").prop("checked", false);
108
+ jQuery("#s_method_nektria_recs_lastmile").prop("checked",false).attr("disabled","disabled");
109
+ });
110
+
111
+ jQuery("#s_method_nektria_recs_lastmile").attr("disabled","disabled");
112
+
113
+ nektria_recs.initTimeWindowPrices(<?php echo Mage::getSingleton('checkout/session')->getPriceMatrix(); ?>, nektria_selection_callback);
114
+ if (window.showTimeWindowArea){
115
+ nektria_recs.showTimeWindowArea();
116
+ }
117
+
118
+ if (window.nektriaStringUserSelection){
119
+ nektria_recs.updateSelectedWindows( window.nektriaStringUserSelection );
120
+ }
121
+ };
122
+
123
+ document.getElementsByTagName("head")[0].appendChild(jsfile);
124
+
125
+ var cssfile = document.createElement("link");
126
+
127
+ cssfile.setAttribute("rel", "stylesheet");
128
+ cssfile.setAttribute("type", "text/css");
129
+ cssfile.setAttribute("href", "<?php echo $css_code; ?>");
130
+
131
+ document.getElementsByTagName("head")[0].appendChild(cssfile);
132
+ <?php endif; ?>
133
+ </script>
134
+
135
+ <?php if(Mage::helper('nektria')->getGomageLightCheckoutEnabled()): ?>
136
+ <style>
137
+ /*
138
+ .glc-step.address{
139
+ width: 32% !important;
140
+ }
141
+ .glc-step.methods{
142
+ width: 67% !important;
143
+ }
144
+ #nektriaTimeWindowBT{
145
+ padding: 2px 5px;
146
+ }
147
+ */
148
+ #recs-timewindow-area.recs-hidden{
149
+ background-color: transparent;
150
+ }
151
+
152
+ </style>
153
+ <script type="text/javascript">gomage_lightCheckout = true; </script>
154
+ <?php else: ?>
155
+ <style type="text/css">
156
+ #nektriaLabel{
157
+ margin-left: 30px;
158
+ }
159
+ </style>
160
+ <script type="text/javascript">
161
+ var element = jQuery( "#shipping_method-progress-opcheckout" );
162
+ if (typeof(element.live)!= "undefined"){
163
+ element.live( "DOMNodeInserted DOMNodeRemoved", function( event ) {});
164
+ }else{
165
+ element.on( "DOMNodeInserted DOMNodeRemoved", function( event ) {});
166
+ }
167
+
168
+ </script>
169
+ <?php endif; ?>
170
+
171
+ <input type="hidden" name="nektria_selection" id="nektria_selection" value='<?php if( Mage::helper('nektria')->getLastSelection() ) : ?><?php echo Mage::helper('nektria')->getLastSelection(); ?><?php else: ?>{}<?php endif; ?>' />
172
+ <input id="nektriaTimeWindowBT" type="radio" value="" class="radio" <?php if(Mage::helper('nektria')->getLastMileSelected()): ?>checked<?php endif; ?> />
173
+ <?php if ($_sole) : ?>
174
+
175
+ <span class="no-display"><input name="shipping_method" type="radio" value="<?php echo $_rate->getCode() ?>" id="s_method_<?php echo $_rate->getCode() ?>" disabled="disabled" <?php if(Mage::helper('nektria')->getLastMileSelected()): ?>checked<?php endif; ?> /></span>
176
+ <script type="text/javascript"> window.showTimeWindowArea = true; </script>
177
+
178
+ <?php else: ?>
179
+ <span class="no-display"><input name="shipping_method" type="radio" value="<?php echo $_rate->getCode() ?>" id="s_method_<?php echo $_rate->getCode() ?>"<?php if($_rate->getCode()===$this->getAddressShippingMethod()) echo ' disabled="disabled" ' ?> class="radio" <?php if(Mage::helper('nektria')->getLastMileSelected()): ?>checked<?php endif; ?> /></span>
180
+ <?php endif; ?>
181
+
182
+ <label for="nektriaTimeWindowBT" id="nektriaLabel"><?php echo $this->escapeHtml($_rate->getMethodTitle()) ?>
183
+ <?php $_excl = $this->getShippingPrice($_rate->getPrice(), $this->helper('tax')->displayShippingPriceIncludingTax()); ?>
184
+ <?php $_incl = $this->getShippingPrice($_rate->getPrice(), true); ?>
185
+ <?php echo $_excl; ?>
186
+
187
+ <?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
188
+ (<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
189
+ <?php endif; ?>
190
+
191
+ </label>
192
+
193
+ <?php if (Mage::getSingleton('checkout/session')->getPriceMatrix()) {
194
+ $ctx = stream_context_create(array(
195
+ 'http'=>
196
+ array(
197
+ 'timeout' => 1, //1 seconds
198
+ ),
199
+ 'https'=>
200
+ array(
201
+ 'timeout' => 2, //2 seconds in production
202
+ ),
203
+ ));
204
+ echo file_get_contents($html_code, FALSE, $ctx);
205
+ }
206
+ ?>
207
+
208
+
209
+ <?php elseif ($_rate->getMethod() == "classic") : ?>
210
+ <?php if ($_sole) : ?>
211
+ <!--<span class="no-display">--><span><input name="shipping_method" type="radio" value="<?php echo $_rate->getCode() ?>" id="s_method_<?php echo $_rate->getCode() ?>" checked="checked" /></span>
212
+ <?php else: ?>
213
+ <input name="shipping_method" type="radio" value="<?php echo $_rate->getCode() ?>" id="s_method_<?php echo $_rate->getCode() ?>"<?php if($_rate->getCode()===$this->getAddressShippingMethod()) echo ' checked="checked"' ?> class="radio" />
214
+ <?php endif; ?>
215
+ <label for="s_method_<?php echo $_rate->getCode() ?>"><?php echo $this->escapeHtml($_rate->getMethodTitle()) ?>
216
+ <?php $_excl = $this->getShippingPrice($_rate->getPrice(), $this->helper('tax')->displayShippingPriceIncludingTax()); ?>
217
+ <?php $_incl = $this->getShippingPrice($_rate->getPrice(), true); ?>
218
+ <?php echo $_excl; ?>
219
+ <?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
220
+ (<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
221
+ <?php endif; ?>
222
+ </label>
223
+
224
+
225
+ <?php else: ?>
226
+ <?php if ($_sole) : ?>
227
+ <!--<span class="no-display">--><span><input name="shipping_method" type="radio" value="<?php echo $_rate->getCode() ?>" id="s_method_<?php echo $_rate->getCode() ?>" checked="checked" /></span>
228
+ <?php else: ?>
229
+ <input name="shipping_method" type="radio" value="<?php echo $_rate->getCode() ?>" id="s_method_<?php echo $_rate->getCode() ?>"<?php if($_rate->getCode()===$this->getAddressShippingMethod()) echo ' checked="checked"' ?> class="radio" />
230
+
231
+ <?php if ($_rate->getCode() === $this->getAddressShippingMethod()): ?>
232
+ <script type="text/javascript">
233
+ //<![CDATA[
234
+ lastPrice = <?php echo (float)$_rate->getPrice(); ?>;
235
+ //]]>
236
+ </script>
237
+ <?php endif; ?>
238
+
239
+ <?php endif; ?>
240
+ <label for="s_method_<?php echo $_rate->getCode() ?>"><?php echo $this->escapeHtml($_rate->getMethodTitle()) ?>
241
+ <?php $_excl = $this->getShippingPrice($_rate->getPrice(), $this->helper('tax')->displayShippingPriceIncludingTax()); ?>
242
+ <?php $_incl = $this->getShippingPrice($_rate->getPrice(), true); ?>
243
+ <?php echo $_excl; ?>
244
+ <?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
245
+ (<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
246
+ <?php endif; ?>
247
+ </label>
248
+ <?php endif ?>
249
+ </li>
250
+ <?php endforeach; ?>
251
+ </ul>
252
+ </dd>
253
+ <?php endforeach; ?>
254
+ </dl>
255
+
256
+ <script type="text/javascript">
257
+ //<![CDATA[
258
+ <?php if (!empty($shippingCodePrice)): ?>
259
+ var shippingCodePrice = {<?php echo implode(',',$shippingCodePrice); ?>};
260
+ <?php endif; ?>
261
+
262
+ $$('input[type="radio"][name="shipping_method"]').each(function(el){
263
+ Event.observe(el, 'click', function(){
264
+ if (el.checked == true) {
265
+ var getShippingCode = el.getValue();
266
+ <?php if (!empty($shippingCodePrice)): ?>
267
+ var newPrice = shippingCodePrice[getShippingCode];
268
+ if (!lastPrice) {
269
+ lastPrice = newPrice;
270
+ quoteBaseGrandTotal += newPrice;
271
+ }
272
+ if (newPrice != lastPrice) {
273
+ quoteBaseGrandTotal += (newPrice-lastPrice);
274
+ lastPrice = newPrice;
275
+ }
276
+ <?php endif; ?>
277
+ checkQuoteBaseGrandTotal = quoteBaseGrandTotal;
278
+ return false;
279
+ }
280
+ });
281
+ });
282
+ //]]>
283
+ </script>
284
+ <style type="text/css">
285
+ #gcheckout-shipping-method-available dt{
286
+ margin-top: 10px;
287
+ }
288
+ #recs-timewindow-area{
289
+ position: relative;
290
+ z-index: 30;
291
+ }
292
+ </style>
293
+ <?php endif; ?>
app/design/frontend/base/default/template/recs/totals/gomage.phtml ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * GoMage LightCheckout Extension
4
+ *
5
+ * @category Extension
6
+ * @copyright Copyright (c) 2010-2014 GoMage (http://www.gomage.com)
7
+ * @author GoMage
8
+ * @license http://www.gomage.com/license-agreement/ Single domain license
9
+ * @terms of use http://www.gomage.com/terms-of-use
10
+ * @version Release: 5.8
11
+ * @since Class available since Release 1.0
12
+ */
13
+ ?>
14
+ <?php if ($this->getTotals()): ?>
15
+ <tfoot>
16
+ <?php if(Mage::helper('gomage_checkout')->getConfigData('general/allow_remove')>0):?>
17
+ <?php $_colspan = $this->helper('tax')->displayCartBothPrices() ? 6 : 4; ?>
18
+ <?php else:?>
19
+ <?php $_colspan = $this->helper('tax')->displayCartBothPrices() ? 5 : 3; ?>
20
+ <?php endif;?>
21
+ <?php
22
+ if (Mage::helper('gomage_checkout')->getConfigData('gift_wrapping/enable')>0){
23
+ $_colspan++;
24
+ }
25
+ if (Mage::helper('gomage_checkout')->getConfigData('address_fields/thumbnails')>0){
26
+ $_colspan++;
27
+ }
28
+ ?>
29
+ <?php
30
+ if (Mage::helper('nektria')->getLastMileSelected()){
31
+ //Display User Selection
32
+ $methods = Mage::helper('nektria')->getReCSMethods();
33
+ $resumeTotal = $this->renderTotals(null, $_colspan);
34
+ $pattern = '('.$methods['lastmile'].')';
35
+
36
+ $outputSelection = $outputSelection = Mage::helper('nektria')->htmlLastMileSelection();
37
+ $resumeTotal = str_replace($pattern, $pattern.$outputSelection, $resumeTotal);
38
+ echo $resumeTotal;
39
+
40
+ }else{
41
+ echo $this->renderTotals(null, $_colspan);
42
+ }
43
+ ?>
44
+ <?php echo $this->renderTotals('footer', $_colspan); ?>
45
+ <?php if ($this->needDisplayBaseGrandtotal()):?>
46
+ <tr>
47
+ <td class="a-right" colspan="<?php echo $_colspan; ?>">
48
+ <small><?php echo $this->helper('sales')->__('Your credit card will be charged for') ?></small>
49
+ </td>
50
+ <td class="a-right">
51
+ <small><?php echo $this->displayBaseGrandtotal() ?></small>
52
+ </td>
53
+ </tr>
54
+ <?php endif?>
55
+ </tfoot>
56
+ <?php endif; ?>
57
+ <script type="text/javascript">
58
+ //<![CDATA[
59
+ var quoteBaseGrandTotal = <?php echo Mage::getSingleton('checkout/session')->getQuote()->getBaseGrandTotal(); ?>;
60
+ var checkQuoteBaseGrandTotal = <?php echo Mage::getSingleton('checkout/session')->getQuote()->getBaseGrandTotal(); ?>;
61
+ //]]>
62
+ </script>
app/design/frontend/base/default/template/recs/totals/lastmile.phtml ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $json = Mage::getSingleton('checkout/session')->getNektriaUserSelection(FALSE);
3
+ if (!$json){
4
+ $order_id = Mage::getSingleton('checkout/session')->getLastRealOrderId();
5
+ $userSelection = Mage::getModel('nektria_recs/lastmile')->load($order_id,'order_id');
6
+ $json = $userSelection->getUserSelection();
7
+ }
8
+
9
+ if ($json){
10
+ try{
11
+ $selectedTime = Mage::helper('core')->jsonDecode($json);
12
+ }catch(Exception $e){
13
+ $selectedTime = array();
14
+ }
15
+ }
16
+ ?>
17
+
18
+ <?php if ($json): ?>
19
+ <style type="text/css">
20
+ .nektria_user_selection ul li{
21
+ list-style: none;
22
+ }
23
+ .nektria_user_selection{
24
+ margin-top: 10px;
25
+ font-size: 0.95em;
26
+ }
27
+ </style>
28
+ <div class="nektria_user_selection">
29
+ <?php echo $this->__('Selected delivery'); ?><br />
30
+ <ul>
31
+ <?php foreach ($selectedTime['validation_windows'] as $selectedDate): ?>
32
+ <li><?php
33
+ echo $this->__('from').
34
+ ': '.Mage::getModel('core/date')->date('h:i', strtotime($selectedDate['start_time'])).
35
+ ' '.Mage::helper('nektria')->_('to').
36
+ ': '.Mage::getModel('core/date')->date('h:i', strtotime($selectedDate['end_time'])).
37
+ ' '.Mage::helper('nektria')->_('for').
38
+ ': '.Mage::getModel('core/date')->date('d/m/y', strtotime($selectedDate['end_time']));
39
+ ?></li>
40
+ <?php endforeach ?>
41
+ </ul>
42
+ </div>
43
+ <?php endif; ?>
app/design/frontend/base/default/template/recs/totals/onepage.phtml ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package base_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+
27
+ /**
28
+ * @see Mage_Checkout_Block_Cart_Totals
29
+ */
30
+ ?>
31
+ <?php if ($this->getTotals()): ?>
32
+ <tfoot>
33
+ <?php $_colspan = $this->helper('tax')->displayCartBothPrices() ? 5 : 3; ?>
34
+ <?php
35
+ if (Mage::helper('nektria')->getLastMileSelected()){
36
+ //Display User Selection
37
+ $methods = Mage::helper('nektria')->getReCSMethods();
38
+ $resumeTotal = $this->renderTotals(null, $_colspan);
39
+ $pattern = '('.$methods['lastmile'].')';
40
+
41
+ $outputSelection = Mage::helper('nektria')->htmlLastMileSelection();
42
+
43
+ $resumeTotal = str_replace($pattern, $pattern.$outputSelection, $resumeTotal);
44
+ echo $resumeTotal;
45
+
46
+ }else{
47
+ echo $this->renderTotals(null, $_colspan);
48
+ }
49
+ ?>
50
+ <?php echo $this->renderTotals('footer', $_colspan); ?>
51
+ <?php if ($this->needDisplayBaseGrandtotal()):?>
52
+ <tr>
53
+ <td class="a-right" colspan="<?php echo $_colspan; ?>">
54
+ <small><?php echo $this->helper('sales')->__('Your credit card will be charged for') ?></small>
55
+ </td>
56
+ <td class="a-right">
57
+ <small><?php echo $this->displayBaseGrandtotal() ?></small>
58
+ </td>
59
+ </tr>
60
+ <?php endif?>
61
+ </tfoot>
62
+ <?php endif; ?>
app/design/frontend/base/default/template/recs/totals/success.phtml ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package base_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ /**
27
+ * @var $this Mage_Sales_Block_Order_Totals
28
+ * @see Mage_Sales_Block_Order_Totals
29
+ */
30
+ ?>
31
+ <?php foreach ($this->getTotals() as $_code => $_total): ?>
32
+ <?php if ($_total->getBlockName()): ?>
33
+ <?php echo $this->getChildHtml($_total->getBlockName(), false); ?>
34
+ <?php else:?>
35
+ <tr class="<?php echo $_code?>">
36
+ <td <?php echo $this->getLabelProperties()?>>
37
+ <?php if ($_total->getStrong()):?>
38
+ <strong><?php echo $this->escapeHtml($_total->getLabel());?></strong>
39
+ <?php else:?>
40
+ <?php if ($_code == 'shipping'): ?>
41
+ <?php
42
+ echo $this->escapeHtml($_total->getLabel()).Mage::helper('nektria')->htmlLastMileSelection();
43
+ ?>
44
+ <?php else: ?>
45
+ <?php echo $this->escapeHtml($_total->getLabel());?>
46
+ <?php endif; ?>
47
+ <?php endif?>
48
+ </td>
49
+ <td <?php echo $this->getValueProperties()?>>
50
+ <?php if ($_total->getStrong()):?>
51
+ <strong><?php echo $this->formatValue($_total) ?></strong>
52
+ <?php else:?>
53
+ <?php echo $this->formatValue($_total) ?>
54
+ <?php endif?>
55
+ </td>
56
+ </tr>
57
+ <?php endif?>
58
+ <?php endforeach?>
app/etc/modules/Nektria_ReCS.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8" standalone="no"?>
2
+ <config>
3
+ <modules>
4
+ <Nektria_ReCS>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Mage_Shipping />
9
+ </depends>
10
+ </Nektria_ReCS>
11
+ </modules>
12
+ </config>
app/locale/es_ES/Nektria_Translations.csv ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "Select day and time you want to receive your order","Selecciona día y hora de recepción"
2
+ "Please specify day and time you want to receive your order before you continue","Por favor, seleccione el día y hora de recepción antes de continuar"
3
+ "Custom title","Nombre personalizado"
4
+ "Sort Order","Posición"
5
+ "Countries for which to apply the shipping method","Países en los que el envío es aplicable"
6
+ "Specific Countries for which to apply the shipping method","Países específicos en los que el envío es aplicable"
7
+ "Shipping method choices have timed out, please select your delivery windows again","Las selecciones del método de envío han caducado, por favor vuelva a seleccionar sus franjas horarias"
8
+ "Disable LastMile for these payment methods","Deshabilitar ReCS: elige día y hora para estos métodos de pago"
9
+ "Last Mile shipping method is not compatible with the selected payment method","El método de envío Last Mile no es compatible con el método de pago seleccionado"
10
+ "An error has ocurred during Last Mile Shipping Method validation. Please change your selection","Ha ocurrido un error al validar el método de envío ReCS: elige día y hora, por favor cambie su selección"
11
+ "Selected delivery","Selección de recepción"
12
+ "for","el"
13
+ "from","de"
14
+ "Sign up and get your API Key","Registrate y obten tu API Key"
15
+ "Nektria ReCS backend configuration","Panel de configuración de Nektria ReCS"
16
+ "Nektria Signup","Registro"
17
+ "Nektria Configuration","Configuración"
package.xml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Nektria_ReCS</name>
4
+ <version>1.0.1</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://www.opensource.org/licenses/lgpl-license.php">LGPL</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Let your customers choose the day and time they will receive their order.</summary>
10
+ <description>With a subscription to our service, you will be able to offer to your customers the option to choose the day and time they want to receive their order. Nektria will manage completely the delivery of your products so you can focus on what you do the best: selling.&#xD;
11
+ &#xD;
12
+ RECShipping will integrate seemlessly with your existing shipping options offering an additional, more convenient alternative in the big cities that are covered by our service. Then, you can choose to use or not our standard delivery service to reach every area of the Spanish mainland territory.&#xD;
13
+ &#xD;
14
+ Choose the theme that best fits your shop !&#xD;
15
+ &#xD;
16
+ more information on our website: http://www.recshipping.com/&#xD;
17
+ &#xD;
18
+ Note: Our extension is compatible with the LightCheckout module!</description>
19
+ <notes>First stable release</notes>
20
+ <authors><author><name>Digio Soluciones Digitales</name><user>digio</user><email>jose@digio.es</email></author><author><name>Mikael Baron</name><user>mikael_baron</user><email>mikael@nektria.com</email></author></authors>
21
+ <date>2015-12-01</date>
22
+ <time>15:58:20</time>
23
+ <contents><target name="magecommunity"><dir name="Nektria"><dir name="ReCS"><dir name="Block"><file name="Config.php" hash="ac30816bde1549eb169087b7435a1a53"/><file name="Registration.php" hash="4c9eb2181f12e347b9ccef1de5ce758b"/></dir><dir name="Helper"><file name="Data.php" hash="b0fb1c7bca8953529f0c636c99412f5d"/></dir><dir name="Model"><file name="Carrier.php" hash="60a9690fe4244503ac80d09702afb21c"/><file name="Lastmile.php" hash="58800f6a1d6494cddf6c4a09712cb5b8"/><file name="Observer.php" hash="a42b40f1c09d00b94cc5e3d2edc4bd2e"/><file name="Paymentmethods.php" hash="e74903910fb8b1d973914c5d007b0559"/><dir name="Resource"><dir name="Lastmile"><file name="Collection.php" hash="b3c178ac9e474b229dc92dda487496d1"/></dir><file name="Lastmile.php" hash="5deaf65f0a8701e63e291893e6414d83"/></dir><dir name="Sales"><file name="Order.php" hash="784b6ace35afbfb1c250ec4bdabb1b29"/></dir></dir><dir name="etc"><file name="config.xml" hash="e21733f24072893b6658d6d32996cbfd"/><file name="system.xml" hash="9702f5244ad837033a7d0748c429c0ae"/></dir><dir name="lib"><dir name="Nektria"><file name="CHANGELOG.md" hash="7bf4880e5268caaca3f49ec95e118a23"/><file name="LICENSE.md" hash="f2c581eab0338cfc8dff951987bad127"/><file name="README.md" hash="c5a8cf173d61c84068ce49a0b8a33e49"/><file name="composer.json" hash="0fd28f55d1f6935970434efb5049a064"/><file name="composer.lock" hash="b498933e56fac022e8023802a164a002"/><dir name="src"><file name="Address.php" hash="a06450f90a49e90b84689ed386110848"/><file name="Client.php" hash="a552803172ec4566e3caf6016754d12a"/><file name="Description.php" hash="5262a31bcaa75fb606bc931a3f7c8ed4"/><dir name="Exceptions"><file name="ApiClientException.php" hash="4a372b94fe96d57f00585964aa5de9ad"/><file name="ApiResponseException.php" hash="5766a0c8da908027f33fbbea5e54ca05"/></dir><file name="Price.php" hash="07907b8c071ff9e7c2db59759518a4f3"/><file name="Product.php" hash="383a4b33ad6667efc4d44f46340e60a2"/><dir name="Requests"><file name="BackendAccessRequest.php" hash="9a9f7b944a141baf6ae1726375d55315"/><file name="BaseRequest.php" hash="f1c87c94f470ea00a5cb7c63a6525428"/><file name="ClassicAvailabilityRequest.php" hash="eeaff0374c838bcfb2e7bd1a7bc86647"/><file name="ClassicConfirmationRequest.php" hash="e6fa133a76cfcdc4224a54cf0c533c63"/><file name="CoverageRequest.php" hash="a0cc3ce428554f65e30338a53729cb38"/><file name="KeepAliveRequest.php" hash="1dc5fa4916275f2c964c8951224235be"/><file name="LastMileAvailabilityRequest.php" hash="fa5ae9b6444d50a190841ff29992de1c"/><file name="LastMileBestPriceRequest.php" hash="bab9292d870e951a528ce47ebe9c8b28"/><file name="LastMileConfirmationRequest.php" hash="ed2c9ab713c659c1966d8bcd81aeafeb"/><file name="LastMileValidationRequest.php" hash="21cf5790f64052028eaca1077bfb0bcc"/><file name="RegistrationAccessRequest.php" hash="5b11c5abe7e65866327589e07d5b7447"/><file name="ServiceCreationRequest.php" hash="d37240018b197f6a320a12b4194835a3"/><file name="ShowShippingRequest.php" hash="a45ce1bbeb9f42d4665ef1c029f26b82"/><file name="TestRequest.php" hash="5b4cb97c8d5975fe6367bfec96113926"/><file name="getAssetsRequest.php" hash="58aa8a75c2ea53eb1eebde566a7610c0"/></dir><dir name="Responses"><file name="BackendAccessResponse.php" hash="8c5b38813d387780b972c91207c31736"/><file name="BaseResponse.php" hash="33f3797e9c9e91b3a2a615ca85247977"/><file name="ClassicAvailabilityResponse.php" hash="773653c362001788e16ce128a90f2558"/><file name="ClassicConfirmationResponse.php" hash="5d9ed11dae8cb75e3c9960fb744736be"/><file name="CoverageResponse.php" hash="6ac1a2599bcba0005b9e80174e690cde"/><file name="LastMileAvailabilityResponse.php" hash="13e6615241f6c2a78d910af3b29b0f7f"/><file name="LastMileBestPriceResponse.php" hash="03ffb34b080c5d7485d60cb5156fe435"/><file name="LastMileConfirmationResponse.php" hash="71739279f5e9082e473546f5708351c8"/><file name="NullResponse.php" hash="93c8006a8cf5e0b9d11282d1eb82f245"/><file name="RegistrationAccessResponse.php" hash="0cb5636b0960b8957a5af6902beb4781"/><file name="ResponseBodyWrapper.php" hash="9f6a0a35632303e846d7454b7b54b1a5"/><file name="ServiceCreationResponse.php" hash="f561c6c6897fb703d7965f6bbed8eb64"/><file name="ShowShippingResponse.php" hash="99baba4daec77cf260eb0e995639b726"/><file name="TransitAvailabilityResponse.php" hash="f6ee6023dba18b3dc5b86061b6d979ea"/><file name="TransitConfirmationResponse.php" hash="a6fe1cc1326d8f372b2e980b5a6ca2a4"/><file name="getAssetsResponse.php" hash="0c3d9b0c8497d41d7f170d7fb948443f"/></dir><file name="ShowShippingHelper.php" hash="5fd55ecebae8fdeea739ffd0a1cdde7b"/><file name="TimeWindow.php" hash="eee34cc65df56cea229cc06ff2ce0103"/><file name="TimeWindowPrice.php" hash="31a6698f74f341b6780956ba951b2731"/><dir name="services"><file name="services.json" hash="db9b2f1d18ceebf127a5a5946379dcfb"/></dir></dir><file name="test.php" hash="75ef983b0e4af1e502de8900f533f6c0"/><dir name="vendor"><file name="autoload.php" hash="0925eae8ac293490e5fc975679e8d09a"/><dir name="composer"><file name="ClassLoader.php" hash="9c1e7fe1a9eb1693e07ee4420ca5361e"/><file name="LICENSE" hash="084a034acbad39464e3df608c6dc064f"/><file name="autoload_classmap.php" hash="8645d3a4e3ad87e7cf4d88a46717aab4"/><file name="autoload_files.php" hash="2e85332f49b950e0803a44b0b32e2e45"/><file name="autoload_namespaces.php" hash="6283a0a4a3a2d2c8973dcea23edd07f4"/><file name="autoload_psr4.php" hash="158231c55af504a4879bf5e66885ecc5"/><file name="autoload_real.php" hash="2cc2523fead4b3011773884563248734"/><file name="installed.json" hash="7182f34454afa1edd2b24a956f708c35"/></dir><dir name="guzzlehttp"><dir name="command"><file name="LICENSE" hash="582d7d97bab524143526a38575956e46"/><file name="composer.json" hash="6a4db1d61cf703bb376e300f2b8ff450"/><dir name="src"><file name="AbstractClient.php" hash="f9842d8b970876368f3c4cd44aab11b0"/><file name="Command.php" hash="47e1e4fe507c1e85fa02e75b635cfb7c"/><file name="CommandInterface.php" hash="3dae8f8358cc93fbe29de5b714cd704a"/><file name="CommandToRequestIterator.php" hash="e48d64affa57a6fd3eb0b5f6aa0d5434"/><file name="CommandTransaction.php" hash="ab514b3ff0099b1e463d35aead687611"/><file name="CommandUtils.php" hash="787e835f4660e46ab26445506f8c4ed0"/><dir name="Event"><file name="CommandEvent.php" hash="6c7fc87858a8584f5aebededd10c243f"/><file name="InitEvent.php" hash="108505d45ed7012583cfb543b777b1f2"/><file name="PreparedEvent.php" hash="aac473c4e68ade95452387d7069ddc36"/><file name="ProcessEvent.php" hash="4e50fd5e3861fe4a595e98b0ec3f16e4"/></dir><dir name="Exception"><file name="CommandClientException.php" hash="24e95664f5fa914d6ebf1a689de34c95"/><file name="CommandException.php" hash="48b60048c83f240c3babf0b27470b6b2"/><file name="CommandServerException.php" hash="588645616a623dfdf2c5e65e04c408aa"/></dir><file name="ServiceClientInterface.php" hash="eafcecbcaf8f1dce5b8cbe52b7321a1c"/><dir name="Subscriber"><file name="Debug.php" hash="2a7bc810a41587cfdc4f4a38c4e71029"/><file name="ResultMock.php" hash="e1d45561599e46b12918ad6732cf3e0e"/></dir></dir></dir><dir name="guzzle"><file name="CHANGELOG.md" hash="acc188c927e6bf09d6f9d018ca24d1e8"/><file name="LICENSE" hash="f9ddfabead2127b089fa60b1cf462ad7"/><file name="Makefile" hash="317955136cb3575149363d0b7174dbe5"/><file name="README.md" hash="d1df21412e1e3a6dd1d2d5b796db9be7"/><file name="UPGRADING.md" hash="8d0d9048e11ed2b5e79b1ad86db91d48"/><dir name="build"><file name="packager.php" hash="ab4669be9765aecb479f77c67b98b276"/></dir><file name="composer.json" hash="67f18c5c530a0534f1164fb1ff040444"/><dir name="docs"><file name="Makefile" hash="12a604d6e6b876e11714735cdc6403f1"/><dir name="_static"><file name="guzzle-icon.png" hash="18e05d325a1a51de498fc4a32b15ca48"/><file name="logo.png" hash="f87c876737dd9b36664e6055196c1341"/></dir><dir name="_templates"><file name="nav_links.html" hash="fb4639874978e92069d3d58405369a40"/></dir><file name="clients.rst" hash="f49ec91ff685e740a00dc295297a2660"/><file name="conf.py" hash="24f0dcb8445fe1e4f2c05aa782f9385e"/><file name="events.rst" hash="c1615c7cd00adb02cdebe755b7bb1b18"/><file name="faq.rst" hash="94e3a8cefa5068ebea9223b2ab9cb194"/><file name="handlers.rst" hash="e92fd255c14344536d326b19fcd6ae70"/><file name="http-messages.rst" hash="37e5a669761894e39e32f6cc6da9ede3"/><file name="index.rst" hash="ebb9c7abc88df5051c5eb2419fbb740a"/><file name="overview.rst" hash="0b8656757de9b8f5b0b4f3c6179755db"/><file name="quickstart.rst" hash="c8777d83b78d55453bf8c2ae22a9beb4"/><file name="requirements.txt" hash="444d2df1b594a091c02af61aa48e3ad9"/><file name="streams.rst" hash="c074299618766206fdf8273e89c36fe3"/><file name="testing.rst" hash="435bfaab2b1d85cc3f0e9895fb49ccb7"/></dir><file name="phpunit.xml.dist" hash="b9ae0ee5ca5b26ef09506f77bc93f8be"/><dir name="src"><file name="BatchResults.php" hash="9601ffcd97c39a60ccb6d14bb008bbb3"/><file name="Client.php" hash="637bba764765ed5e7684f35532c0a4ed"/><file name="ClientInterface.php" hash="b5137b3a2e3d26ce9be986dfd13499e6"/><file name="Collection.php" hash="431f847865c9621f926b35f91a85dd2c"/><dir name="Cookie"><file name="CookieJar.php" hash="2981ed1414b29b66426eece64865c3ab"/><file name="CookieJarInterface.php" hash="51fd9da76a30957b484296f452c1da42"/><file name="FileCookieJar.php" hash="4aa9c86927b79cf2d978253e0410fb78"/><file name="SessionCookieJar.php" hash="b6c5adee6743072b733a8f3dba43761b"/><file name="SetCookie.php" hash="00db8c8eb2182fddf8afadaaaff20460"/></dir><dir name="Event"><file name="AbstractEvent.php" hash="ce6fb61cd25791ac865d4e84cd9759fd"/><file name="AbstractRequestEvent.php" hash="b18f06f7d9c95a0cc3ef99fdbf4dc203"/><file name="AbstractRetryableEvent.php" hash="2d170945ffa71a89f384ec58078e0c19"/><file name="AbstractTransferEvent.php" hash="89813f179d9cd109a17bebc28494d773"/><file name="BeforeEvent.php" hash="f2cd9a9ac1070b718540129f5909402e"/><file name="CompleteEvent.php" hash="a2b9b8e1e58f198601c22a7f2708b2c1"/><file name="Emitter.php" hash="ad466ad06deedb7331ce7cbd7764f8d9"/><file name="EmitterInterface.php" hash="50d4ccf2a59c4d70b6134873f6934c6e"/><file name="EndEvent.php" hash="1f076fa17483b2dd92098023e78069b6"/><file name="ErrorEvent.php" hash="9d0eaa82626bccaffac0a5f978c13fd8"/><file name="EventInterface.php" hash="2cf7086b80fad54dd9fb1bd66bd3af95"/><file name="HasEmitterInterface.php" hash="aca299bf20f91968a149cb89e117ddc9"/><file name="HasEmitterTrait.php" hash="fceb27761c90d7704cfc2e7ab31651b0"/><file name="ListenerAttacherTrait.php" hash="e71a23d493f4af08228d061dab2ee118"/><file name="ProgressEvent.php" hash="92e78daf64260f604add6dc7ae6b1c4c"/><file name="RequestEvents.php" hash="21dcaf3d461607486b356042032ac74d"/><file name="SubscriberInterface.php" hash="399edbac1d85763544dc54c597194345"/></dir><dir name="Exception"><file name="BadResponseException.php" hash="5d502016856c146aa47d0bbed5106ee1"/><file name="ClientException.php" hash="d1c7f54a71cb105131c0c22b20619bcb"/><file name="ConnectException.php" hash="9ff38d10d12832a15172c72c086143a4"/><file name="CouldNotRewindStreamException.php" hash="d73abf147478558ed008bbffe9985780"/><file name="ParseException.php" hash="4cc7b783e1a68628a7a85f2ad163e775"/><file name="RequestException.php" hash="583ee428fc5aed66ee3b68d05acd967d"/><file name="ServerException.php" hash="36ecb7a8e416e9633b10e677fa5a639e"/><file name="StateException.php" hash="7ed449728b670500dcbde0fad3d2c0c8"/><file name="TooManyRedirectsException.php" hash="9952c5877077fad22bed15fbe04a1ca7"/><file name="TransferException.php" hash="42ffaf70cff001e7b0cfc42ce2e8f8dd"/><file name="XmlParseException.php" hash="77d95d8fa4fb670b348f9c0318a6e107"/></dir><file name="HasDataTrait.php" hash="fb294d4af626e5dd9cf4dec0a146ba0b"/><dir name="Message"><file name="AbstractMessage.php" hash="305754413e6ce7869b6d5c1d711d531b"/><file name="AppliesHeadersInterface.php" hash="8e21471c8384c82f9953a5f35a8c1aad"/><file name="FutureResponse.php" hash="f272567b867f4ac209dd6c92eaf19056"/><file name="MessageFactory.php" hash="a325ba562846468a6267fda2031c7cec"/><file name="MessageFactoryInterface.php" hash="72c981182dc3381da7e1d764745fb50f"/><file name="MessageInterface.php" hash="396bfc61fe4cebb62fa47524c772b513"/><file name="MessageParser.php" hash="a73a7ad08d219ccbd98679a31328d249"/><file name="Request.php" hash="69893f14e5f063861b7a9229cde5d741"/><file name="RequestInterface.php" hash="375992a94f5e9926801bff04d9a97c33"/><file name="Response.php" hash="a5fafa750b85c8bfc94c8ecf22d33fef"/><file name="ResponseInterface.php" hash="650349ea50ba9118c92e34fa95ff7e27"/></dir><file name="Mimetypes.php" hash="98c49c56940197e757af27bb7e13a89b"/><file name="Pool.php" hash="324bd717b59e8aab19b6047b5715e04f"/><dir name="Post"><file name="MultipartBody.php" hash="f33a49bd4efe5ea4685365600bd383d7"/><file name="PostBody.php" hash="bb0f2cf36086a5ab8c83907468472d7f"/><file name="PostBodyInterface.php" hash="6b2f4ea74647a3b5c122366b50fd4931"/><file name="PostFile.php" hash="855721b2dd955fab148b96f609d66349"/><file name="PostFileInterface.php" hash="125d790f2656efe2005a46d98bbf9ccd"/></dir><file name="Query.php" hash="87ec30bde4145bb5086b0f905a37acc7"/><file name="QueryParser.php" hash="e756aae39877cf8137a7d61731a96c5b"/><file name="RequestFsm.php" hash="53643f146ac4a8af437f985b56537cf3"/><file name="RingBridge.php" hash="f5a096b469ac183996a00ccbe59d2ff1"/><dir name="Subscriber"><file name="Cookie.php" hash="9da9bde856192c9588ba7288508fe57c"/><file name="History.php" hash="0b69411a23222125a63b1168e872e7d1"/><file name="HttpError.php" hash="54881525a1132d20b9c94d2263c74c3c"/><file name="Mock.php" hash="7e03e626b83424724aae8e3a6aaaac4a"/><file name="Prepare.php" hash="ea2f4fad216b1050c6bc69c6c9de28a6"/><file name="Redirect.php" hash="5937a24086742fe1d71f70632cf74626"/></dir><file name="ToArrayInterface.php" hash="d6f685d05271786954881729ea03acdf"/><file name="Transaction.php" hash="4b09f99ae5c89731dd0ded5c7e270fce"/><file name="UriTemplate.php" hash="d1eb1c8d5d8e952ec5ebc5ec229ebd8b"/><file name="Url.php" hash="5aedbcee0366876653ff7740928d0b7b"/><file name="Utils.php" hash="7bfdfed1cfceac8fb74825e2e7d58ca2"/></dir><dir name="tests"><file name="BatchResultsTest.php" hash="2bece7f1aab2b56c7d0a95044d364455"/><file name="ClientTest.php" hash="3bfe6825efd15d6d92d08914b5d3e9ec"/><file name="CollectionTest.php" hash="a12026f2f56133a78abc670cdbc41ef8"/><dir name="Cookie"><file name="CookieJarTest.php" hash="0b4f9c735a6777d87ca27a88adba5ade"/><file name="FileCookieJarTest.php" hash="a53871768dfbdd5fdd1c810bbbc97081"/><file name="SessionCookieJarTest.php" hash="e6b75dee2a71c1cf330b3dfaa8510234"/><file name="SetCookieTest.php" hash="9e89006d954368173e74dac68a2188fd"/></dir><dir name="Event"><file name="AbstractEventTest.php" hash="d6c4101eb6d4f9785710bb75faeb0b21"/><file name="AbstractRequestEventTest.php" hash="7d7e5da804db3051bd646058fdcec31b"/><file name="AbstractRetryableEventTest.php" hash="bc0811545d15c9749b03c954bc22dc4b"/><file name="AbstractTransferEventTest.php" hash="f7933c0b89a3697373fd3e926d1b29cc"/><file name="BeforeEventTest.php" hash="e1e03516a4eafbd9c0399ed07092dbeb"/><file name="EmitterTest.php" hash="ad7982eab84ad5ce11f1f8bd04a01cc6"/><file name="ErrorEventTest.php" hash="b6274e50ba68c65f4951780215ef9b5e"/><file name="HasEmitterTraitTest.php" hash="2d1716214cdf9d89e433706292754293"/><file name="ListenerAttacherTraitTest.php" hash="61f0139442059871254ce2e921b7b13b"/><file name="ProgressEventTest.php" hash="6c9bcc84308a5093dc2d90c02d0a00d1"/><file name="RequestEventsTest.php" hash="16a17dc96688fd52d8ebadb3743561a3"/></dir><dir name="Exception"><file name="ParseExceptionTest.php" hash="9ae68634df9b8bd4da10db3ae3c98240"/><file name="RequestExceptionTest.php" hash="02c354306343fc46aa523d6c22b6a363"/><file name="XmlParseExceptionTest.php" hash="0fa1390ebeb36ded883e0e9f67131710"/></dir><file name="IntegrationTest.php" hash="77ecb08442b3edaf4a17dbc3b5eb6645"/><dir name="Message"><file name="AbstractMessageTest.php" hash="4d28bffec70b45a77d5ca8e5c60f7013"/><file name="FutureResponseTest.php" hash="4ec0c219593360e97d539b98982875a9"/><file name="MessageFactoryTest.php" hash="4a4da3a4dcaea6e470f0db5f36aef037"/><file name="MessageParserTest.php" hash="61023f113eafb82e1c519d4e007df5c0"/><file name="RequestTest.php" hash="a213727539122149ba0ef29f43dd5ab1"/><file name="ResponseTest.php" hash="b2eee9848eb5753370156db659fea334"/></dir><file name="MimetypesTest.php" hash="b97bc6a576e373a0f9ea663c67994606"/><file name="PoolTest.php" hash="1c36bb95c48e06a8676869fe3a00efb9"/><dir name="Post"><file name="MultipartBodyTest.php" hash="2f5b276dc55f4e6acc353f15da893090"/><file name="PostBodyTest.php" hash="bd99b38841137550692b0f7758a91e5c"/><file name="PostFileTest.php" hash="61126cad841a60e81eb44a455c3a2468"/></dir><file name="QueryParserTest.php" hash="263e1bfbd5a62751d31b37b1f7b6a366"/><file name="QueryTest.php" hash="22f2d92e4861f452ff44c885ad606cc6"/><file name="RequestFsmTest.php" hash="a1e93b846366335645bdbb527ba5307b"/><file name="RingBridgeTest.php" hash="96b4a0305c26b445fd2a60b866893847"/><file name="Server.php" hash="5f48ad0972b3bebb9fc45b65c6495e49"/><dir name="Subscriber"><file name="CookieTest.php" hash="3d6f6925dcadba10ede56d56b920eac4"/><file name="HistoryTest.php" hash="7ad048226fb91b77be6a191fd7f4c4b6"/><file name="HttpErrorTest.php" hash="f7ef34e0b5cf44bc4274097ff1d3c7df"/><file name="MockTest.php" hash="bac3eebae3a935597e1721b06aea4164"/><file name="PrepareTest.php" hash="9e17a67eec520969e0f3ab550708735a"/><file name="RedirectTest.php" hash="c1d1e3980709198e3b1cb17bf8867046"/></dir><file name="TransactionTest.php" hash="880f3a2f0941a608b15de98231ad5e63"/><file name="UriTemplateTest.php" hash="896b5959837d4094ce45d3d4f1a0efc4"/><file name="UrlTest.php" hash="023ba3e99932d6427cfefea2a28825e6"/><file name="UtilsTest.php" hash="39002d5af09b85b2ec765e6e4698f94e"/><file name="bootstrap.php" hash="2485c354ba16ebdece68b7036a68d90a"/><file name="perf.php" hash="1f2e05c29dea96304aa4ff3f07480801"/></dir><file name=".editorconfig" hash="7e66193b631a146c4a293759de00bf55"/><file name=".gitignore" hash="98d0c9e025ddeaea0512712bf442e39f"/><file name=".travis.yml" hash="fc89cdb2bffb45541e0ab0eaa564b136"/></dir><dir name="guzzle-services"><file name="LICENSE" hash="f9ddfabead2127b089fa60b1cf462ad7"/><file name="Makefile" hash="f3364726c6c548160b4af524d7749226"/><file name="README.rst" hash="a5eb708dee2d36276d12ee97a2d855e1"/><file name="composer.json" hash="4dc80269f09ee9e68ca470fd22b75140"/><file name="phpunit.xml.dist" hash="0a0f7e08978d788bfe53c30fb8fea79a"/><dir name="src"><file name="Description.php" hash="18701338f73aab046e9dd1cc01c8464c"/><file name="DescriptionInterface.php" hash="5bf2e170c1713ca461527d92c4d11bcd"/><file name="GuzzleClient.php" hash="61c2e61eea4c23ac89fa5aa4b7000c76"/><file name="Operation.php" hash="b4414480b481e1fc112719ab7ceda602"/><file name="Parameter.php" hash="8679cca4a8a6eb02367c9f3791e14f39"/><dir name="RequestLocation"><file name="AbstractLocation.php" hash="b79e5e0ed31b444b6ff4db9c91010c9c"/><file name="BodyLocation.php" hash="bf342b2ec4e883b71cd17bc78d58d3db"/><file name="HeaderLocation.php" hash="6b08999b75d9685f11a478f2dc597137"/><file name="JsonLocation.php" hash="2d2b7f4e4406d3a2d300267d97d07037"/><file name="PostFieldLocation.php" hash="d3cddfd75a9d764f731a42ece5114ae0"/><file name="PostFileLocation.php" hash="cefdb773df7a8526adc5c9d3b2dd8b87"/><file name="QueryLocation.php" hash="e498fa726d6a31c1de051ad7cf0440d0"/><file name="RequestLocationInterface.php" hash="256addedd3129e536592959b5d15cec4"/><file name="XmlLocation.php" hash="e25fc2ae8b2f18a7e5cb74a15f6c4b78"/></dir><dir name="ResponseLocation"><file name="AbstractLocation.php" hash="7bf6c0ce0939cbad8e5a910c0c038c82"/><file name="BodyLocation.php" hash="cc1e61e02c3ec22e3a88bfdf1190a9a1"/><file name="HeaderLocation.php" hash="60e2afc6d54f6e7a287ae563cc8b5672"/><file name="JsonLocation.php" hash="401676e23362dd09f9f0dc6bcdcb22ea"/><file name="ReasonPhraseLocation.php" hash="e0e0614f7b150da17d0d599bfed7081a"/><file name="ResponseLocationInterface.php" hash="5c29ed2e157580f7576e59780f6e0e76"/><file name="StatusCodeLocation.php" hash="113889d6e28a5ef2e7a40818c3044b4b"/><file name="XmlLocation.php" hash="8589906cc9f5b3719166b5e7d77a51d3"/></dir><file name="SchemaFormatter.php" hash="cf5eb3ada11ce4ddad9971b7acd033a6"/><file name="SchemaValidator.php" hash="6c0f364d6b2d9d5b07cbc6e4d7350a6a"/><file name="Serializer.php" hash="3db6574d8e55ba6680cad7c9c0869786"/><dir name="Subscriber"><file name="ProcessResponse.php" hash="33ab7f4f0491dc8ed30f45b272d4f7a4"/><file name="ValidateInput.php" hash="22700d95812e1526e0ab070927de3c89"/></dir></dir><dir name="tests"><file name="DescriptionTest.php" hash="071edbc19de928c6647457ecb84a1d5c"/><file name="GuzzleClientTest.php" hash="283e621f79108b56a7801f3a64553fa8"/><file name="OperationTest.php" hash="37498b3bc3148f57c8b36cab08cc10d8"/><file name="ParameterTest.php" hash="c05f957913771df2fe88caa0c522c554"/><dir name="RequestLocation"><file name="BodyLocationTest.php" hash="48f98fef7f77deb609133eed3ff3915b"/><file name="HeaderLocationTest.php" hash="db169df2970e05556ab394141135025f"/><file name="JsonLocationTest.php" hash="202768cb03debf540bfe6c72d41ecf4c"/><file name="PostFieldLocationTest.php" hash="4f8fd5fa5a4a76e75f26345407b36309"/><file name="PostFileLocationTest.php" hash="7e632a6453f8224135cacb32a44128fa"/><file name="QueryLocationTest.php" hash="27a56d4d5a2350055123931ffa285696"/><file name="XmlLocationTest.php" hash="0f462e9e04d97c5ede2741740775fcc0"/></dir><dir name="ResponseLocation"><file name="BodyLocationTest.php" hash="79252c9ad9b4e50d51e12044e5f23e4a"/><file name="HeaderLocationTest.php" hash="958fd9ed78860b2299188c1cb636e081"/><file name="JsonLocationTest.php" hash="96c2d8042aeff4cbea9a78e1207bf8d7"/><file name="ReasonPhraseLocationTest.php" hash="542c13fa76ad9d3bf5a599de943c48d4"/><file name="StatusCodeLocationTest.php" hash="6d3a1070a4e41aa094a9279dd3493e76"/><file name="XmlLocationTest.php" hash="64813fceb6aa37497a774d2b9028ef5d"/></dir><file name="SchemaFormatterTest.php" hash="622c275fb473edfb92094e4929718195"/><file name="SchemaValidatorTest.php" hash="e875b51dbc49c18883d4431efbd9bb8a"/><file name="SerializerTest.php" hash="8ccac616b1ac162e4bfe70553318fd6f"/><dir name="Subscriber"><file name="ProcessResponseTest.php" hash="1dd8cdc678cae379bb83cc0b68f5d297"/><file name="ValidateInputTest.php" hash="88a77941ddd4020f8c545a23faf55b24"/></dir></dir><file name=".gitignore" hash="42681fa01a89f4be449cbee88066955c"/><file name=".travis.yml" hash="277b298f9d9212ade8c84fddf8d87561"/></dir><dir name="log-subscriber"><file name="LICENSE" hash="f9ddfabead2127b089fa60b1cf462ad7"/><file name="README.rst" hash="54c951dcdf7412ecb5a0c0cfe0f54d8e"/><file name="composer.json" hash="3b6b8e6f4120cec4148faecdca206153"/><file name="phpunit.xml.dist" hash="0a0f7e08978d788bfe53c30fb8fea79a"/><dir name="src"><file name="Formatter.php" hash="c5b9539c49d77dcab9ff952547bbe780"/><file name="LogSubscriber.php" hash="39b79bee16d09324cac27f5ffc686929"/><file name="SimpleLogger.php" hash="9d9e9d52c4b1a82df5f82a2386af75b4"/></dir><dir name="tests"><file name="FormatterTest.php" hash="3e9e0f1fb090a58d8b1227e81a3dcd20"/><file name="LogSubscriberTest.php" hash="2ccde676513a6cc22ade7eb44d1fb7c4"/><file name="SimpleLoggerTest.php" hash="8b3e0340b59a223a698eae26af24b3bd"/></dir><file name=".gitignore" hash="af19642b4a44a0330a47893c52d33a78"/><file name=".travis.yml" hash="e52939624b9ea1eff7db5a0737954162"/></dir><dir name="ringphp"><file name="CHANGELOG.md" hash="799347e9b288e0be8ea32f1a1abf8267"/><file name="LICENSE" hash="f9ddfabead2127b089fa60b1cf462ad7"/><file name="Makefile" hash="a17b9a1407c7959a90868c31f61e71f4"/><file name="README.rst" hash="e7a3f00179cfb4b0feee9f88b85e9fe9"/><file name="composer.json" hash="68665e93d1453df2865ed80265fff1ba"/><dir name="docs"><file name="Makefile" hash="777df5c7fafb2d6bfcb3c802e84adc3a"/><file name="client_handlers.rst" hash="6ca3e9e513f571032762133d8a162471"/><file name="client_middleware.rst" hash="681214a7d675a62a5ef3b86acfe37a20"/><file name="conf.py" hash="9f2affce54bd7d8c9a9007b59fc763e0"/><file name="futures.rst" hash="34a204df5751b48199926211066729eb"/><file name="index.rst" hash="a3671abf15c984498720c8899bb08394"/><file name="requirements.txt" hash="baa676171a96a28c1393d91384b1b7ef"/><file name="spec.rst" hash="a01eb587edb3e5114007cad16d235e02"/><file name="testing.rst" hash="6413148aac13954f10afe9f49312710d"/></dir><file name="phpunit.xml.dist" hash="a08ade01ef087db50589d228bb9eb420"/><dir name="src"><dir name="Client"><file name="ClientUtils.php" hash="0287d3512ac65d1f8e278e219274c847"/><file name="CurlFactory.php" hash="f909fb13038da4267441077c7b794500"/><file name="CurlHandler.php" hash="85e6686ed0f84679fc7e4f851c268b63"/><file name="CurlMultiHandler.php" hash="fc5c927d9981a88d28ec6071c437bfbf"/><file name="Middleware.php" hash="10b4e00d41ae53ab744c3df441813175"/><file name="MockHandler.php" hash="d9b3b00bd2e611076fb26f6706c6210c"/><file name="StreamHandler.php" hash="f7d46f8fe620052a8d45b454c42cedc0"/></dir><file name="Core.php" hash="f658655aef2402084df1ae4f1fe426aa"/><dir name="Exception"><file name="CancelledException.php" hash="b520e10d3139675532606f2a0334cca7"/><file name="CancelledFutureAccessException.php" hash="fa44e44ab519317596c0790a65d7bf38"/><file name="ConnectException.php" hash="de603e26f57a49cd5e4eab10e1686f15"/><file name="RingException.php" hash="965eeeb09364f0e0da13d094eefb4be3"/></dir><dir name="Future"><file name="BaseFutureTrait.php" hash="718e41c2d5cef401149c20ca371ad424"/><file name="CompletedFutureArray.php" hash="2ac2ca1892020c4608f2435fd0ebccd5"/><file name="CompletedFutureValue.php" hash="3c6ebdc379ed9af49fc185dd3d37c210"/><file name="FutureArray.php" hash="7f9b892d14899e73e491389c48301d4a"/><file name="FutureArrayInterface.php" hash="4871442a53bd711d89ac9823ee0d8df9"/><file name="FutureInterface.php" hash="eb26d9d532221a1425a8fac2aad96a9e"/><file name="FutureValue.php" hash="be5e06025b123a0d8a9acb8198c2f936"/><file name="MagicFutureTrait.php" hash="94f71a67eebbeaf6f85f778b73ae931d"/></dir></dir><dir name="tests"><dir name="Client"><file name="CurlFactoryTest.php" hash="acaa0fec3dcbc3128b80e020340ac669"/><file name="CurlHandlerTest.php" hash="21ec6983ba2f120240b61e9ab428198d"/><file name="CurlMultiHandlerTest.php" hash="06596c64487027c651f33b797e12a2f6"/><file name="MiddlewareTest.php" hash="100c93dbc7a3053493a42e3e42a244a5"/><file name="MockHandlerTest.php" hash="38eee76c7a84144938ad6704f87d805e"/><file name="Server.php" hash="fa6f211ad34231d3db7bd09a65e20669"/><file name="StreamHandlerTest.php" hash="29e30c9dbdd9728b000494d651e135cb"/><file name="server.js" hash="88d159b78be1b7fa9212209d4d38aef3"/></dir><file name="CoreTest.php" hash="5f7dca3a73b8831f4465fe8dab669118"/><dir name="Future"><file name="CompletedFutureArrayTest.php" hash="700f902ea1cce7e9001d01568ed581d8"/><file name="CompletedFutureValueTest.php" hash="f0f0fbd1dd1c4ac7c200cac5254f6cf8"/><file name="FutureArrayTest.php" hash="faa49dcfb801b774d54ee6c086011614"/><file name="FutureValueTest.php" hash="e7c40a1fd52bb1a58aaad00c8705b37f"/></dir><file name="bootstrap.php" hash="2b4a9ef0805593b41fc90c937437c53d"/></dir><file name=".gitignore" hash="2eb59fa71b9af27e9490e3f48045826d"/><file name=".travis.yml" hash="efa3829190500a4d0da1a423497a5cbe"/></dir><dir name="streams"><file name="CHANGELOG.rst" hash="4752dfe3eab49192fde530a2c2cdb4fe"/><file name="LICENSE" hash="f9ddfabead2127b089fa60b1cf462ad7"/><file name="Makefile" hash="648bf3b1ee188fe82ff842fbf8703ce6"/><file name="README.rst" hash="3e6fd1afbf41950f151ec71a248852ea"/><file name="composer.json" hash="b1a7224ca7d3dc8822599053a986ecb7"/><file name="phpunit.xml.dist" hash="2c20ff733adcdbfc654d37cd863c62a1"/><dir name="src"><file name="AppendStream.php" hash="6058885102fd00fb17b3ba541631bd07"/><file name="AsyncReadStream.php" hash="357a76d042d9f3e7aec1062f6e3a80d2"/><file name="BufferStream.php" hash="87ddb692697c7708e20e1145e7a63911"/><file name="CachingStream.php" hash="6fe89b215a313c235b9239e52378180b"/><file name="DroppingStream.php" hash="44a9450100c8a5f85f3b95563417ccf5"/><dir name="Exception"><file name="CannotAttachException.php" hash="ab4352ccfc2468697a1a86945bbdd1c8"/><file name="SeekException.php" hash="68575bcb6ba2622232ffe7e65450b165"/></dir><file name="FnStream.php" hash="d4bf7cd1da1124cf8c5a561cecdc5059"/><file name="GuzzleStreamWrapper.php" hash="048a82bcb138568e0bbbceaf5f886716"/><file name="InflateStream.php" hash="788a139a27c18d6bd886159e8ef8c10e"/><file name="LazyOpenStream.php" hash="2424456087e77c0cdf3ba02de4f15e9c"/><file name="LimitStream.php" hash="e2a9332833d878494ed30fb3d9f2b8a3"/><file name="MetadataStreamInterface.php" hash="802f0231c068d9f085f3c8653bb926d1"/><file name="NoSeekStream.php" hash="a35f7ea68c23cab4d246f7a2a0edcbe9"/><file name="NullStream.php" hash="a0b4395fc529242d414dd578c4c6f980"/><file name="PumpStream.php" hash="bb422e1161cc1ccf89951fea853f135a"/><file name="Stream.php" hash="f6efbdb369652e6351c8e837febe1795"/><file name="StreamDecoratorTrait.php" hash="775c6b0b12cec849cd1be3bab364006a"/><file name="StreamInterface.php" hash="4ed5919e395f7e4c568e600c800f378d"/><file name="Utils.php" hash="5ee03fd3c0c37082efab7dc213c9f455"/></dir><dir name="tests"><file name="AppendStreamTest.php" hash="7c1d5b1fd981a895240c532a3388cadd"/><file name="AsyncReadStreamTest.php" hash="3cf24da24619f99afd5361953a87a0c9"/><file name="BufferStreamTest.php" hash="e1dff59b71a28ca18f2bf64d88160f8e"/><file name="CachingStreamTest.php" hash="8857ec65fa6e1733a835d1bdecadf0df"/><file name="DroppingStreamTest.php" hash="cb27027850b6b6b87764e716f18568fc"/><dir name="Exception"><file name="SeekExceptionTest.php" hash="2396902960ff0282591d51fd5d40c2df"/></dir><file name="FnStreamTest.php" hash="10285ef01d4cdde83ee80b6132f05a30"/><file name="GuzzleStreamWrapperTest.php" hash="c3f6afb7e215827d5c02cc7ccb4a1848"/><file name="InflateStreamTest.php" hash="b34cbead206f2c39af9735299732b0c5"/><file name="LazyOpenStreamTest.php" hash="794d1631cdf4970a0e69d6ec18290b8a"/><file name="LimitStreamTest.php" hash="66aa7cda081a9d98b8520f942d8f959c"/><file name="NoSeekStreamTest.php" hash="23e203dceb9d70b248d9c3ff5a7aa19b"/><file name="NullStreamTest.php" hash="667a01a596537fe1743ccc237e29cb61"/><file name="PumpStreamTest.php" hash="4cfac47d1911e456bb024913883d675e"/><file name="StreamDecoratorTraitTest.php" hash="0a5247c33b45fd37eb6d4582fd33560e"/><file name="StreamTest.php" hash="a9651186306c293533de2c7d9575f23b"/><file name="UtilsTest.php" hash="f137bb850134805b09794ce79423d9ad"/></dir><file name=".gitignore" hash="af19642b4a44a0330a47893c52d33a78"/><file name=".travis.yml" hash="2559fbe72dc387ede606879bedf4a420"/></dir></dir><dir name="psr"><dir name="log"><file name="LICENSE" hash="1a74629072fd794937be394ab689327e"/><dir name="Psr"><dir name="Log"><file name="AbstractLogger.php" hash="a57c1be541193b72d09307bb0dfb9ed2"/><file name="InvalidArgumentException.php" hash="7d2f0bd1583524d739fff12f0507de65"/><file name="LogLevel.php" hash="19ab55cc711ed2f3ab2ec72e7f0600cb"/><file name="LoggerAwareInterface.php" hash="3ba5ffac8108e1da7657b1fad8651900"/><file name="LoggerAwareTrait.php" hash="5b3adf6c4f09c61d7488b0f9ac2c696a"/><file name="LoggerInterface.php" hash="023885df6a26d8137d5a13da51f066d2"/><file name="LoggerTrait.php" hash="1cb8db6d0b81cf85f81b6c7c09db7a9a"/><file name="NullLogger.php" hash="e71559fea0239b7441d221f8c7beae5b"/><dir name="Test"><file name="LoggerInterfaceTest.php" hash="867f36a94c35322470458f4eba246458"/></dir></dir></dir><file name="README.md" hash="144a71a4e1f9c67ac79751acc37614c4"/><file name="composer.json" hash="de1539d2aa7830d13a968d33d1039f1a"/><file name=".gitignore" hash="e8a346051f935e6cb104e1dc40998a91"/></dir></dir><dir name="react"><dir name="promise"><file name="CHANGELOG.md" hash="2b1f02283ecd949264f900170ea8b3fc"/><file name="LICENSE" hash="e46a0a186cdc556ce7574113f2653180"/><file name="README.md" hash="bbcb0875dc0201cdfe6573443d2bea14"/><file name="composer.json" hash="0ca73967404075ef80fc494b370ddefc"/><file name="phpunit.xml.dist" hash="7d9482f8cd074b464c0f57496e727d5e"/><dir name="src"><file name="CancellablePromiseInterface.php" hash="1d8feeea39ac3cd66f2c041f0f6589f0"/><file name="Deferred.php" hash="a922b6f8f9d7f8525ddc2c5704eb1377"/><file name="ExtendedPromiseInterface.php" hash="1a287908208d527bbbe6e3128af84d26"/><file name="FulfilledPromise.php" hash="773d525b931f7ceb4e1cfa1fec923462"/><file name="LazyPromise.php" hash="a34e5f6bbc510757cb2d41ca41b846e5"/><file name="Promise.php" hash="f7ff3401d5f36e6e4bd613c859fd8d76"/><file name="PromiseInterface.php" hash="488da4a38d218ba8fb3eaea05dd1c264"/><file name="PromisorInterface.php" hash="d7bf061df9395a7cf5fd082805e42c7a"/><file name="RejectedPromise.php" hash="55b2be16604c09ed1add52d1c49dc56c"/><file name="UnhandledRejectionException.php" hash="b814c8ef9bd08d1d41782104aa6ef8f9"/><file name="functions.php" hash="ce714c7d1e64104fa43c043555078a8f"/><file name="functions_include.php" hash="4da7302e4ed0862c6fa885a3c66bcd01"/></dir><dir name="tests"><file name="DeferredTest.php" hash="5fb76a8bd96a79598d69afb9bcc8c1e1"/><file name="FulfilledPromiseTest.php" hash="20e21c11b19ec8b46a47fc072e7a9e0c"/><file name="FunctionAllTest.php" hash="c2ee53ecc37d95fc55c57912477c215a"/><file name="FunctionAnyTest.php" hash="23565b2dfd5969a213862a7f061b2e03"/><file name="FunctionCheckTypehintTest.php" hash="b48395c507606f68d32150ddfc28ae0d"/><file name="FunctionMapTest.php" hash="287d180adefce847aa222bdb05025eb9"/><file name="FunctionRaceTest.php" hash="3d9edf2ca2f2253496c8cf0ecba7c5d6"/><file name="FunctionReduceTest.php" hash="1b9bc983e9900e29f187475072d10cd9"/><file name="FunctionRejectTest.php" hash="4209c5e6b051b3c065b4a8e1e32949dd"/><file name="FunctionResolveTest.php" hash="4836614d978e9b75b8857ed92e837468"/><file name="FunctionSomeTest.php" hash="78c1ad99506be879d910617d744274c0"/><file name="LazyPromiseTest.php" hash="f3f8f1e47ebf5097d726086c785a7b20"/><dir name="PromiseAdapter"><file name="CallbackPromiseAdapter.php" hash="3429d665b2a9dd4a9d3606af69db5c17"/><file name="PromiseAdapterInterface.php" hash="a02b0b5e52a71149688f7bef8894fcda"/></dir><dir name="PromiseTest"><file name="CancelTestTrait.php" hash="eab33b77dca722a733911b1e94ffb16c"/><file name="FullTestTrait.php" hash="e82099e47b8fe984b7f5ff832c811b9b"/><file name="NotifyTestTrait.php" hash="314ba252939f84fd2885064409d4247d"/><file name="PromiseFulfilledTestTrait.php" hash="d83a22d7b2792a2e067447533ef80598"/><file name="PromisePendingTestTrait.php" hash="ca94a285a8ac4b0f402f9915025997a9"/><file name="PromiseRejectedTestTrait.php" hash="286f6bd7327a649c553096b4cb899642"/><file name="PromiseSettledTestTrait.php" hash="2b4de2fa354193aa5d577d2996713eb0"/><file name="RejectTestTrait.php" hash="11d13fb0d33113764df7ad81981e3ff5"/><file name="ResolveTestTrait.php" hash="e8786f5b09a518feb6cb991ec28093df"/></dir><file name="PromiseTest.php" hash="7bbbd1f2acb6e6187b42751a093fb057"/><file name="RejectedPromiseTest.php" hash="e72e7e3d7bc3e7779ea1b8383604a263"/><dir name="Stub"><file name="CallableStub.php" hash="aa2c5ca5528276a340c013c950c3c792"/></dir><file name="TestCase.php" hash="4c1e0a05effe1354008b82a9c903b5b9"/><file name="bootstrap.php" hash="ac271c71e8caa31202d61356508b7c32"/></dir><file name=".gitignore" hash="dbc957e3a33427be6ecce1f274683ed4"/><file name=".travis.yml" hash="ae054f04b30abca8bfdb9f0726d02c2d"/></dir></dir></dir><file name=".editorconfig" hash="992eebd87865ed8081f2f65e2049cd7b"/><file name=".git" hash="ffafd865dc05f7a97a328e8da0a4f0c1"/><file name=".gitignore" hash="54e699d77045a737ccc746b8cc227162"/></dir><file name="Nektria.php" hash="302be7f98de0754c0ee0f6c326f756ee"/></dir><dir name="sql"><dir name="nektria_recs_setup"><file name="install-1.0.0.php" hash="8b9f2a7289187a054aa867aab397b24a"/><file name="install-1.0.1.php" hash="3685fc27ea718cbc5ca8e8269f6b078d"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="recs"><dir name="email"><file name="lastmile.phtml" hash="45fee0e197b2aaa2f4a8ea2ea3c499b6"/></dir><dir name="progress"><file name="shipping_method.phtml" hash="835b3cad28fce0565efb56b7be052d47"/></dir><dir name="shipping_method"><file name="available.phtml" hash="218798342af79311471e673665566fcf"/></dir><dir name="totals"><file name="gomage.phtml" hash="0f7c34bcf53e50868f368945df74ebc3"/><file name="lastmile.phtml" hash="ebd821972959dbea1260ba2760cd127f"/><file name="onepage.phtml" hash="ef089e02099d64ddb8634a4fb53b8398"/><file name="success.phtml" hash="d41fb8bc248a8516cc51825b0c4b8d4f"/></dir></dir></dir><dir name="layout"><file name="recs.xml" hash="c671b7f667b38d62564d435493ca031c"/></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="recs"><dir name="sales"><dir name="order"><dir name="creditmemo"><dir name="create"><file name="form.phtml" hash="dab64339a84f4ff7f5d85b5fd8ee46ea"/></dir><dir name="view"><file name="form.phtml" hash="93b8200fecb0e2b5226b2763ac5d97db"/></dir></dir><dir name="invoice"><dir name="create"><file name="form.phtml" hash="40ded721298719c36a0eba62db5cc3b3"/></dir><dir name="view"><file name="form.phtml" hash="c57e9f594cac34fd7a465eefe3671d22"/></dir></dir><dir name="shipment"><dir name="create"><file name="form.phtml" hash="e05472213fdc397e09311bdc3e0b856d"/></dir><dir name="view"><file name="form.phtml" hash="5a4ba9ac376a5e753e61808b33ac7902"/></dir></dir><dir name="view"><file name="info.phtml" hash="ba408dd6e2ebec0a3ec7f4af115b7631"/><file name="lastmile.phtml" hash="6694b381456a14886fdcb75bcbb69274"/></dir></dir></dir></dir></dir><dir name="layout"><file name="recs.xml" hash="2ee79c0a8a9435bf9fe36467d2990a30"/></dir></dir></dir></dir></target><target name="magelocale"><dir name="es_ES"><file name="Nektria_Translations.csv" hash="9b6a41274182d11e716f0618ddc9e44e"/></dir></target><target name="mageetc"><dir name="modules"><file name="Nektria_ReCS.xml" hash="9003ab46f73920faa5daf6b7f8c5288e"/></dir></target></contents>
24
+ <compatible/>
25
+ <dependencies><required><php><min>5.4.0</min><max>6.5.0</max></php><extension><name>curl</name><min></min><max></max></extension></required></dependencies>
26
+ </package>