Stockbase - Version 1.0.2

Version Notes

Release notes v1.0.2:

- Fixed configuration for Order event observer to be enabled/disabled
- Added dutch translation
- Image import combined request to 1 call each cron run
- Fix of patch 6788 admin routing for Status page

Download this release

Release Info

Developer Divide BV
Extension Stockbase
Version 1.0.2
Comparing to
See all releases


Code changes from version 0.2.0 to 1.0.2

app/code/local/Divide/Stockbase/Block/Config.php CHANGED
@@ -1,15 +1,15 @@
1
- <?php
2
-
3
- class Divide_Stockbase_Block_Config extends Mage_Adminhtml_Block_Template
4
- {
5
- /**
6
- * Config Block constructor
7
- * Constructs the page and loads the phtml-template
8
- * See app/design/default/default/layout & /template for these files.
9
- */
10
- public function __construct()
11
- {
12
- parent::__construct();
13
- $this->setTemplate('stockbase/config.phtml');
14
- }
15
- }
1
+ <?php
2
+
3
+ class Divide_Stockbase_Block_Config extends Mage_Adminhtml_Block_Template
4
+ {
5
+ /**
6
+ * Config Block constructor
7
+ * Constructs the page and loads the phtml-template
8
+ * See app/design/default/default/layout & /template for these files.
9
+ */
10
+ public function __construct()
11
+ {
12
+ parent::__construct();
13
+ $this->setTemplate('stockbase/config.phtml');
14
+ }
15
+ }
app/code/local/Divide/Stockbase/Helper/Data.php CHANGED
@@ -1,29 +1,29 @@
1
- <?php
2
-
3
- class Divide_Stockbase_Helper_Data extends Mage_Core_Helper_Abstract
4
- {
5
- /**
6
- * Returns array with all product eans from this shop. Uses
7
- * the configured field in Stockbase settings to retrieve the ean values.
8
- *
9
- * @return array
10
- */
11
- public function getAllEans()
12
- {
13
- $attribute = Mage::getStoreConfig('stockbase_options/login/stockbase_ean_field');
14
- $collection = Mage::getModel('catalog/product')->getCollection();
15
- $storeId = Mage::app()->getStore()->getStoreId();
16
-
17
- $eans = [];
18
- foreach ($collection as $product) {
19
- $value = Mage::getResourceModel('catalog/product')
20
- ->getAttributeRawValue($product->getId(), $attribute, $storeId);
21
-
22
- if ($value) {
23
- $eans[] = $value;
24
- }
25
- }
26
-
27
- return $eans;
28
- }
29
  }
1
+ <?php
2
+
3
+ class Divide_Stockbase_Helper_Data extends Mage_Core_Helper_Abstract
4
+ {
5
+ /**
6
+ * Returns array with all product eans from this shop. Uses
7
+ * the configured field in Stockbase settings to retrieve the ean values.
8
+ *
9
+ * @return array
10
+ */
11
+ public function getAllEans()
12
+ {
13
+ $attribute = Mage::getStoreConfig('stockbase_options/login/stockbase_ean_field');
14
+ $collection = Mage::getModel('catalog/product')->getCollection();
15
+ $storeId = Mage::app()->getStore()->getStoreId();
16
+
17
+ $eans = [];
18
+ foreach ($collection as $product) {
19
+ $value = Mage::getResourceModel('catalog/product')
20
+ ->getAttributeRawValue($product->getId(), $attribute, $storeId);
21
+
22
+ if ($value) {
23
+ $eans[] = $value;
24
+ }
25
+ }
26
+
27
+ return $eans;
28
+ }
29
  }
app/code/local/Divide/Stockbase/Helper/HTTP.php CHANGED
@@ -1,425 +1,474 @@
1
- <?php
2
-
3
- class Divide_Stockbase_Helper_HTTP extends Mage_Core_Helper_Abstract
4
- {
5
-
6
- /**
7
- * Webservice ENDPOINTS, & ANSWERS
8
- * Live: https://iqservice.divide.nl/
9
- * Dev: http://server.divide.nl/divide.api/
10
- * Docs: http://server.divide.nl/divide.api/docs
11
- */
12
- const ENDPOINT_LOGIN = 'services/login';
13
- const ENDPOINT_AUTH = 'authenticate';
14
- const ENDPOINT_STOCKBASE_STOCK = 'stockbase/stock';
15
- const ENDPOINT_STOCKBASE_ORDER = 'stockbase/orderRequest';
16
- const ENDPOINT_STOCKBASE_IMAGES = 'stockbase/images';
17
- const ANSWER_INVALID_CREDENTIALS = 'LoginCredentialsNotValid';
18
- const ANSWER_EMPTY_CREDENTIALS = 'CredentialsEmpty';
19
- const ANSWER_SUCCESS = 'Success';
20
- const ANSWER_UNKNOWN = 'UnknownError';
21
- const ANSWER_TOKEN_EXPIRED = 'TokenExpired';
22
-
23
- protected $authToken;
24
- protected $authTokenExpiration;
25
- protected $refreshToken;
26
- protected $accessToken;
27
- protected $awnser;
28
- protected $client;
29
- protected $env;
30
-
31
- /**
32
- * Divide_Stockbase_Helper_HTTP constructor.
33
- */
34
- public function __construct()
35
- {
36
- // Set mage storeview to default admin
37
- Mage::app()->getStore()->setId(Mage_Core_Model_App::ADMIN_STORE_ID);
38
- // Using UTC standards
39
- $now = new DateTime('NOW', new DateTimeZone('UTC'));
40
- // Varien HTTP Client for making request
41
- $this->client = new Varien_Http_Client();
42
- // Varien File IO for write/read actions to filesystem
43
- $this->file = new Varien_Io_File();
44
-
45
- // Server configured to use (production or development)
46
- $this->env = Mage::getStoreConfig('stockbase_options/login/stockbase_enviroment');
47
- // Client uses the REST Interface, set to be application/json for all calls.
48
- $this->client->setHeaders('Content-Type', 'application/json');
49
- $this->accessToken = Mage::getStoreConfig('stockbase_options/token/access');
50
- $this->authToken = Mage::getStoreConfig('stockbase_options/token/auth');
51
- $this->authTokenExpiration = Mage::getStoreConfig('stockbase_options/token/auth_expiration_date');
52
- $this->accessTokenExpiration = Mage::getStoreConfig('stockbase_options/token/access_expiration_date');
53
- $this->refreshToken = Mage::getStoreConfig('stockbase_options/token/refresh');
54
- $this->username = Mage::getStoreConfig('stockbase_options/login/username');
55
- $this->password = Mage::getStoreConfig('stockbase_options/login/password');
56
-
57
- // Check at instantiation for legit & non-expired tokens, otherwise refresh.
58
- if (strtotime($this->authTokenExpiration) < $now->getTimestamp()) {
59
- $this->authenticate(true);
60
- }
61
- }
62
-
63
- /**
64
- * Authenticate with the authentication token
65
- * for access and refresh tokens. refresh parameter
66
- * forces to refresh tokens, otherwise accesstoken will
67
- * be used by default.
68
- *
69
- * @param bool $refresh
70
- * @return bool
71
- */
72
- public function authenticate($refresh = false)
73
- {
74
- $token = $refresh ? $this->refreshToken : $this->authToken;
75
- if ($token == null) {
76
- $this->login($this->username, $this->password);
77
- }
78
- $this->client->setUri($this->env . self::ENDPOINT_AUTH);
79
- $this->client->setHeaders('Authentication', $token);
80
- $result = json_decode($this->client->request('GET')->getBody());
81
-
82
- $response = $result->{'nl.divide.iq'};
83
-
84
- if ($response->answer == self::ANSWER_TOKEN_EXPIRED) {
85
- $this->login($this->username, $this->password);
86
- }
87
-
88
- if ($response->answer == self::ANSWER_SUCCESS) {
89
- if ($refresh) {
90
- Mage::getModel('core/config')->saveConfig('stockbase_options/token/refresh', $response->refresh_token);
91
- } else {
92
- Mage::getModel('core/config')
93
- ->saveConfig('stockbase_options/token/access', $response->access_token);
94
- Mage::getModel('core/config')
95
- ->saveConfig('stockbase_options/token/access_expiration_date', $response->expiration_date);
96
- }
97
-
98
- return true;
99
- }
100
-
101
- return false;
102
- }
103
-
104
- /**
105
- * Array with username & password for getting
106
- * the authentication token and expiration date
107
- *
108
- * @param $username
109
- * @param $password
110
- * @return bool
111
- */
112
- public function login($username, $password)
113
- {
114
- $this->client->setUri($this->env . self::ENDPOINT_LOGIN);
115
- $this->client->setHeaders('username', $username);
116
- $this->client->setHeaders('password', $password);
117
-
118
- $result = json_decode($this->client->request('POST')->getBody());
119
- $response = $result->{'nl.divide.iq'};
120
-
121
- if ($response->answer == self::ANSWER_SUCCESS) {
122
- Mage::getModel('core/config')
123
- ->saveConfig('stockbase_options/token/auth', $response->authentication_token);
124
- Mage::getModel('core/config')
125
- ->saveConfig('stockbase_options/token/auth_expiration_date', $response->expiration_date);
126
-
127
- return true;
128
- }
129
-
130
- return false;
131
- }
132
-
133
- /**
134
- * Sends order to Stockbase if ordered quantity
135
- * is not met by own stocklevels.
136
- *
137
- * @param Mage_Sales_Model_Order $mageOrder
138
- * @return bool
139
- */
140
- public function sendMageOrder(Mage_Sales_Model_Order $mageOrder)
141
- {
142
- // Configured orderPrefix for keeping ordernumbers unique for merchant.
143
- $orderPrefix = Mage::getStoreConfig('stockbase_options/login/order_prefix');
144
- // Configured EAN field from stockbase configuration
145
- $configuredEan = Mage::getStoreConfig('stockbase_options/login/stockbase_ean_field');
146
- $shippingAddress = $mageOrder->getShippingAddress();
147
- // Parsing street for seperation of street, number, and additional
148
- $parsedAddress = $this->splitStreet($shippingAddress->getStreet1());
149
- // StockbaseEANs from users Stockbase account
150
- $sbEans = $this->getAllEansFromStockbase();
151
- // Using UTC TimeZone as standard
152
- $now = new DateTime('now', new DateTimeZone('UTC'));
153
- // Used for collecting items from order to send
154
- $Orderlines = null;
155
-
156
- // If splitStreet fails, fallback to fullstreet.
157
- if (!$parsedAddress['street'] || !$parsedAddress['number']) {
158
- $parsedAddress['street'] = $shippingAddress->getStreetFull();
159
- $parsedAddress['number'] = '-';
160
- }
161
-
162
- // Parsing Address fields from the Magento Order
163
- $Address = [
164
- 'Street' => $parsedAddress['street'],
165
- 'StreetNumber' => (int) $parsedAddress['number'],
166
- 'StreetNumberAddition' => $parsedAddress['numberAddition'],
167
- 'ZipCode' => $shippingAddress->getPostcode(),
168
- 'City' => $shippingAddress->getCity(),
169
- 'CountryCode' => $shippingAddress->getCountryModel()->getIso3Code(),
170
- ];
171
-
172
- // Filling Person details
173
- $Person = [
174
- 'Gender' => $mageOrder->getCustomerGender() ? 'Female' : 'Male',
175
- 'Initials' => strtoupper($mageOrder->getCustomerFirstname()[0]),
176
- 'FirstName' => $mageOrder->getCustomerFirstname(),
177
- 'SurnamePrefix' => $mageOrder->getCustomerPrefix() ? : ' ',
178
- 'Surname' => $mageOrder->getCustomerLastname(),
179
- 'Company' => $mageOrder->getShippingAddress()->getCompany() ? : " ",
180
- ];
181
-
182
- // Put the person and Adres in OrderDelivery Array
183
- $OrderDelivery = [
184
- 'Person' => $Person,
185
- 'Address' => $Address,
186
- ];
187
-
188
- // Loop over ordered items and check if there is a shortage on own stock
189
- foreach ($mageOrder->getAllItems() as $key => $item) {
190
- // Get stockitem from the orderedProduct to check with.
191
- $stock = $item->getProduct()->getStockItem()->getQty();
192
-
193
- // If out of stock && known by Stockbase,
194
- // TypeCasting it into integer cuz Magento uses decimals for qty.
195
- if ($stock < (int) $item->getQtyOrdered()) {
196
- // Find the configured EAN for the product so we can identify it.
197
- $ean = $item->getProduct()->getData($configuredEan);
198
- // Now check if the ordered shortage exsists in your stockbase account.
199
- if (in_array($ean, $sbEans)) {
200
- // Finally fill up the orderlines to be send to stockbase.
201
- $Orderlines[] = [
202
- 'Number' => $key + 1, // orderLineNumber starting from 1
203
- 'EAN' => $ean,
204
- 'Amount' => (int) $item->getQtyOrdered(),
205
- ];
206
- }
207
- }
208
- }
209
-
210
- // Compose the OrderHeader with the filled up data
211
- $OrderHeader = [
212
- 'OrderNumber' => $orderPrefix . '#' . $mageOrder->getRealOrderId(),
213
- 'TimeStamp' => $now->format('Y-m-d h:i:s'),
214
- 'Attention' => $mageOrder->getCustomerNote() ? $mageOrder->getCustomerNote() : ' ',
215
- ];
216
-
217
- // Compose the OrderRequest in final form for Stockbase
218
- $OrderRequest = [
219
- 'OrderHeader' => $OrderHeader,
220
- 'OrderLines' => $Orderlines,
221
- 'OrderDelivery' => $OrderDelivery,
222
- ];
223
-
224
- // Only send the order if we have collected items to be ordered.
225
- if (count($Orderlines) > 1) {
226
- $posted = $this->post(self::ENDPOINT_STOCKBASE_ORDER, $OrderRequest)->{'nl.divide.iq'};
227
- }
228
-
229
- // If failure, we log request and response for debugging.
230
- if (!$posted->response->content->StatusCode == 1) {
231
- // We log errors to stockbase-failure.txt in the /var/log/ folder of Magento
232
- Mage::log(var_export($posted, true), false, 'stockbase-failure.txt');
233
-
234
- return false;
235
- }
236
-
237
- return true;
238
- }
239
-
240
- /**
241
- * Magento street comes with housenumber attached to it, this
242
- * method tries to seperate the Street, housnumber, and additions.
243
- *
244
- * @param type $street
245
- * @return type
246
- */
247
- protected function splitStreet($street)
248
- {
249
- $aMatch = [];
250
- $pattern = '#^([\w[:punct:] ]+) ([0-9]{1,5})([\w[:punct:]\-/]*)$#';
251
- $matchResult = preg_match($pattern, $street, $aMatch);
252
-
253
- $street = (isset($aMatch[1])) ? $aMatch[1] : '';
254
- $number = (isset($aMatch[2])) ? $aMatch[2] : '';
255
- $numberAddition = (isset($aMatch[3])) ? $aMatch[3] : '';
256
-
257
- return [
258
- 'street' => $street,
259
- 'number' => $number,
260
- 'numberAddition' => $numberAddition,
261
- ];
262
- }
263
-
264
- /**
265
- * Collect all EANS from user Stockbase account in a array.
266
- *
267
- * @return type
268
- */
269
- protected function getAllEansFromStockbase()
270
- {
271
- $stockbaseStock = $this->getStock();
272
- $eans = [];
273
-
274
- foreach ($stockbaseStock->Groups as $group) {
275
- foreach ($group->Items as $brand) {
276
- $eans[] = $brand->EAN;
277
- }
278
- }
279
-
280
- return $eans;
281
- }
282
-
283
- /**
284
- * Returns simpleXMLElement with Stock (beginning from group)
285
- * Debug param defaults to false, gives debug info about request if true.
286
- *
287
- * @param bool $debug
288
- * @return SimpleXMLElement
289
- */
290
- public function getStock($debug = false)
291
- {
292
- return $this->call(self::ENDPOINT_STOCKBASE_STOCK, $debug);
293
- }
294
-
295
- /**
296
- * Makes the final call (the request)to the
297
- * given webservice endpoint. Should only be
298
- * used internally by this class.
299
- *
300
- * @param $endpoint
301
- * @param bool $debug
302
- * @return $response (json_decoded body)
303
- */
304
- protected function call($endpoint, $debug = false)
305
- {
306
- if (!$this->hasAccessToken()) {
307
- $this->authenticate(true);
308
- }
309
-
310
- $this->client->setUri($this->env . $endpoint);
311
- $this->client->setHeaders('Authentication', $this->accessToken);
312
-
313
- $result = json_decode($this->client->request()->getBody());
314
-
315
- if ($result->{'nl.divide.iq'}->response->answer == self::ANSWER_SUCCESS) {
316
- if (!$debug) {
317
- return $result->{'nl.divide.iq'}->response->content;
318
- }
319
-
320
- return $result->{'nl.divide.iq'};
321
- }
322
- }
323
-
324
- /**
325
- * Check if accesstoken is set from magento's config.
326
- *
327
- * @return bool
328
- */
329
- protected function hasAccessToken()
330
- {
331
- return (bool)$this->accessToken;
332
- }
333
-
334
- /**
335
- * Post a payload to a endpoint. See
336
- * defined ENDPOINT constants in HTTP Helper.
337
- *
338
- * @param $endpoint
339
- * @param array $payload
340
- * @return mixed
341
- */
342
- protected function post($endpoint, $payload = [])
343
- {
344
- if (!$this->hasAccessToken()) {
345
- $this->authenticate(true);
346
- }
347
-
348
- $this->client->setUri($this->env . $endpoint);
349
- $this->client->setHeaders('Authentication', $this->accessToken);
350
- $result = $this->client->setRawData(json_encode($payload), "application/json;charset=UTF-8")->request('POST');
351
- $response = json_decode($result->getBody());
352
-
353
- if (!$response) {
354
- Mage::log(var_export($result->getBody(), true), false, 'stockbase-curl-failure.txt');
355
-
356
- return $result;
357
- }
358
-
359
- return $response;
360
- }
361
-
362
- /**
363
- * Will return image if available at stockbase for given EAN.
364
- *
365
- * @param string $ean
366
- */
367
- public function getImageForEan($ean)
368
- {
369
- $this->client->setUri($this->env . self::ENDPOINT_STOCKBASE_IMAGES . "?ean={$ean}");
370
- $this->client->setHeaders('Authentication', $this->accessToken);
371
- $this->client->setHeaders('ean', $ean);
372
- $result = json_decode($this->client->request()->getBody());
373
- $images = $result->{'nl.divide.iq'}->response->content->Items;
374
-
375
- return $images;
376
- }
377
-
378
- /**
379
- * Saves images array from stockbase for given $ean
380
- *
381
- * @param object $images
382
- * @param string $ean
383
- */
384
- public function saveImageForProduct($images, $ean)
385
- {
386
- $product = Mage::getModel('catalog/product')->loadByAttribute(
387
- Mage::getStoreConfig('stockbase_options/login/stockbase_ean_field'),
388
- $ean
389
- );
390
-
391
- $addedImages = [];
392
- if ($product) {
393
- foreach ($images as $image) {
394
- $imageUrl = $image->Url;
395
- $ext = substr(strrchr($imageUrl, "."), 1);
396
- $tempName = basename($imageUrl);
397
- $filePath = Mage::getBaseDir('media') . DS . 'import' . DS . $tempName;
398
-
399
- $client = new Varien_Http_Client($imageUrl);
400
- $client->setMethod(Varien_Http_Client::GET);
401
- $client->setHeaders('Authentication', Mage::getStoreConfig('stockbase_options/token/access'));
402
- $protectedImage = $client->request()->getBody();
403
-
404
- $io = new Varien_Io_File();
405
- $io->write($filePath, $protectedImage);
406
-
407
- if ($io->fileExists($filePath)) {
408
- if ($product->getMediaGallery() == null) {
409
- $product->setMediaGallery(['images' => [], 'values' => []]);
410
- }
411
- $product->addImageToMediaGallery(
412
- $filePath,
413
- ['image', 'small_image', 'thumbnail'],
414
- false,
415
- false
416
- );
417
- $addedImages[] = $filePath;
418
- }
419
- }
420
- $product->save();
421
-
422
- return $addedImages;
423
- }
424
- }
425
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Divide_Stockbase_Helper_HTTP extends Mage_Core_Helper_Abstract
4
+ {
5
+
6
+ /**
7
+ * Webservice ENDPOINTS, & ANSWERS
8
+ * Live: https://iqservice.divide.nl/
9
+ * Dev: http://server.divide.nl/divide.api/
10
+ * Docs: http://server.divide.nl/divide.api/docs
11
+ */
12
+ const ENDPOINT_LOGIN = 'services/login';
13
+ const ENDPOINT_AUTH = 'authenticate';
14
+ const ENDPOINT_STOCKBASE_STOCK = 'stockbase/stock';
15
+ const ENDPOINT_STOCKBASE_ORDER = 'stockbase/orderRequest';
16
+ const ENDPOINT_STOCKBASE_IMAGES = 'stockbase/images';
17
+ const ANSWER_INVALID_CREDENTIALS = 'LoginCredentialsNotValid';
18
+ const ANSWER_EMPTY_CREDENTIALS = 'CredentialsEmpty';
19
+ const ANSWER_SUCCESS = 'Success';
20
+ const ANSWER_UNKNOWN = 'UnknownError';
21
+ const ANSWER_TOKEN_EXPIRED = 'TokenExpired';
22
+
23
+ protected $authToken;
24
+ protected $authTokenExpiration;
25
+ protected $refreshToken;
26
+ protected $accessToken;
27
+ protected $awnser;
28
+ protected $client;
29
+ protected $env;
30
+
31
+ /**
32
+ * Divide_Stockbase_Helper_HTTP constructor.
33
+ */
34
+ public function __construct()
35
+ {
36
+ // Set mage storeview to default admin
37
+ Mage::app()->getStore()->setId(Mage_Core_Model_App::ADMIN_STORE_ID);
38
+ // Using UTC standards
39
+ $now = new DateTime('NOW', new DateTimeZone('UTC'));
40
+ // Varien HTTP Client for making request
41
+ $this->client = new Varien_Http_Client();
42
+ // Varien File IO for write/read actions to filesystem
43
+ $this->file = new Varien_Io_File();
44
+
45
+ // Server configured to use (production or development)
46
+ $this->env = Mage::getStoreConfig('stockbase_options/login/stockbase_enviroment');
47
+ // Client uses the REST Interface, set to be application/json for all calls.
48
+ $this->client->setHeaders('Content-Type', 'application/json');
49
+ $this->accessToken = Mage::getStoreConfig('stockbase_options/token/access');
50
+ $this->authToken = Mage::getStoreConfig('stockbase_options/token/auth');
51
+ $this->authTokenExpiration = Mage::getStoreConfig('stockbase_options/token/auth_expiration_date');
52
+ $this->accessTokenExpiration = Mage::getStoreConfig('stockbase_options/token/access_expiration_date');
53
+ $this->refreshToken = Mage::getStoreConfig('stockbase_options/token/refresh');
54
+ $this->username = Mage::getStoreConfig('stockbase_options/login/username');
55
+ $this->password = Mage::getStoreConfig('stockbase_options/login/password');
56
+
57
+ // Check at instantiation for legit & non-expired tokens, otherwise refresh.
58
+ if (strtotime($this->authTokenExpiration) < $now->getTimestamp()) {
59
+ $this->authenticate(true);
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Authenticate with the authentication token
65
+ * for access and refresh tokens. refresh parameter
66
+ * forces to refresh tokens, otherwise accesstoken will
67
+ * be used by default.
68
+ *
69
+ * @param bool $refresh
70
+ * @return bool
71
+ */
72
+ public function authenticate($refresh = false)
73
+ {
74
+ $authClient = new Zend_Http_Client($this->env . self::ENDPOINT_AUTH);
75
+ $token = null;
76
+
77
+ // if refresh true, use refresh, but if not set, use auth instead
78
+ if($refresh){
79
+ $token = Mage::getStoreConfig('stockbase_options/token/refresh');
80
+ }
81
+
82
+ // Possible that we dont have refresh token yet, then fallback on the auth token to present
83
+ if (!$token) {
84
+ $token = Mage::getStoreConfig('stockbase_options/token/auth');
85
+ }
86
+
87
+ // If we still dont have token, login first then.
88
+ if ($token == null) {
89
+ $token = $this->login();
90
+ }
91
+
92
+ $authClient->setHeaders([
93
+ 'Content-Type' => 'application/json',
94
+ 'Authentication' => $token
95
+ ]);
96
+
97
+ $result = json_decode($authClient->request('GET')->getBody());
98
+ $response = $result->{'nl.divide.iq'};
99
+
100
+ if ($response->answer == self::ANSWER_TOKEN_EXPIRED) {
101
+ $this->login($this->username, $this->password);
102
+ }
103
+
104
+ if ($response->answer == self::ANSWER_SUCCESS) {
105
+ if(isset($response->refresh_token)){
106
+ Mage::getModel('core/config')
107
+ ->saveConfig('stockbase_options/token/refresh', $response->refresh_token);
108
+ }
109
+ Mage::getModel('core/config')
110
+ ->saveConfig('stockbase_options/token/access', $response->access_token);
111
+ Mage::getModel('core/config')
112
+ ->saveConfig('stockbase_options/token/access_expiration_date', $response->expiration_date);
113
+
114
+
115
+ return true;
116
+ }
117
+
118
+ return false;
119
+ }
120
+
121
+ /**
122
+ * Array with username & password for getting
123
+ * the authentication token and expiration date
124
+ *
125
+ * @param $username
126
+ * @param $password
127
+ * @return bool
128
+ */
129
+ public function login($username = false, $password = false)
130
+ {
131
+ $loginClient = new Zend_Http_Client($this->env . self::ENDPOINT_LOGIN);
132
+
133
+ if ($username == false || $password == false) {
134
+ $username = Mage::getStoreConfig('stockbase_options/login/username');
135
+ $password = Mage::getStoreConfig('stockbase_options/login/password');
136
+ }
137
+
138
+ $loginClient->setHeaders([
139
+ 'Content-Type' => 'application/json',
140
+ 'Username' => $username,
141
+ 'Password' => $password
142
+ ]);
143
+
144
+ $result = json_decode($loginClient->request('GET')->getBody());
145
+ $response = $result->{'nl.divide.iq'};
146
+
147
+ if ($response->answer == self::ANSWER_SUCCESS) {
148
+ Mage::getModel('core/config')
149
+ ->saveConfig('stockbase_options/token/auth', $response->authentication_token);
150
+ Mage::getModel('core/config')
151
+ ->saveConfig('stockbase_options/token/auth_expiration_date', $response->expiration_date);
152
+
153
+ return $response->authentication_token;
154
+ }
155
+
156
+ return false;
157
+ }
158
+
159
+ /**
160
+ * Sends order to Stockbase if ordered quantity
161
+ * is not met by own stocklevels.
162
+ *
163
+ * @param Mage_Sales_Model_Order $mageOrder
164
+ * @return bool
165
+ */
166
+ public function sendMageOrder(Mage_Sales_Model_Order $mageOrder)
167
+ {
168
+ // Configured orderPrefix for keeping ordernumbers unique for merchant.
169
+ $orderPrefix = Mage::getStoreConfig('stockbase_options/login/order_prefix');
170
+ // Configured EAN field from stockbase configuration
171
+ $configuredEan = Mage::getStoreConfig('stockbase_options/login/stockbase_ean_field');
172
+ $shippingAddress = $mageOrder->getShippingAddress();
173
+ // Parsing street for seperation of street, number, and additional
174
+ $parsedAddress = $this->splitStreet($shippingAddress->getStreet1());
175
+ // StockbaseEANs from users Stockbase account
176
+ $sbEans = $this->getAllEansFromStockbase();
177
+ // Using UTC TimeZone as standard
178
+ $now = new DateTime('now', new DateTimeZone('UTC'));
179
+ // Used for collecting items from order to send
180
+ $Orderlines = null;
181
+
182
+ // If splitStreet fails, fallback to fullstreet.
183
+ if (!$parsedAddress['street'] || !$parsedAddress['number']) {
184
+ $parsedAddress['street'] = $shippingAddress->getStreetFull();
185
+ $parsedAddress['number'] = '-';
186
+ }
187
+
188
+ // Parsing Address fields from the Magento Order
189
+ $Address = [
190
+ 'Street' => $parsedAddress['street'],
191
+ 'StreetNumber' => (int) $parsedAddress['number'],
192
+ 'StreetNumberAddition' => $parsedAddress['numberAddition'],
193
+ 'ZipCode' => $shippingAddress->getPostcode(),
194
+ 'City' => $shippingAddress->getCity(),
195
+ 'CountryCode' => $shippingAddress->getCountryModel()->getIso3Code(),
196
+ ];
197
+
198
+ // Filling Person details
199
+ $Person = [
200
+ 'Gender' => $mageOrder->getCustomerGender() ? 'Female' : 'Male',
201
+ 'Initials' => strtoupper($mageOrder->getCustomerFirstname()[0]),
202
+ 'FirstName' => $mageOrder->getCustomerFirstname(),
203
+ 'SurnamePrefix' => $mageOrder->getCustomerPrefix() ? : ' ',
204
+ 'Surname' => $mageOrder->getCustomerLastname(),
205
+ 'Company' => $mageOrder->getShippingAddress()->getCompany() ? : " ",
206
+ ];
207
+
208
+ // Put the person and Adres in OrderDelivery Array
209
+ $OrderDelivery = [
210
+ 'Person' => $Person,
211
+ 'Address' => $Address,
212
+ ];
213
+
214
+ // Loop over ordered items and check if there is a shortage on own stock
215
+ foreach ($mageOrder->getAllItems() as $key => $item) {
216
+ // Get stockitem from the orderedProduct to check with.
217
+ $stock = $item->getProduct()->getStockItem()->getQty();
218
+
219
+ // If out of stock && known by Stockbase,
220
+ // TypeCasting it into integer cuz Magento uses decimals for qty.
221
+ if ($stock < (int) $item->getQtyOrdered()) {
222
+ // Find the configured EAN for the product so we can identify it.
223
+ $ean = $item->getProduct()->getData($configuredEan);
224
+ // Now check if the ordered shortage exsists in your stockbase account.
225
+ if (in_array($ean, $sbEans)) {
226
+ // Finally fill up the orderlines to be send to stockbase.
227
+ $Orderlines[] = [
228
+ 'Number' => $key + 1, // orderLineNumber starting from 1
229
+ 'EAN' => $ean,
230
+ 'Amount' => (int) $item->getQtyOrdered(),
231
+ ];
232
+ }
233
+ }
234
+ }
235
+
236
+ // Compose the OrderHeader with the filled up data
237
+ $OrderHeader = [
238
+ 'OrderNumber' => $orderPrefix . '#' . $mageOrder->getRealOrderId(),
239
+ 'TimeStamp' => $now->format('Y-m-d h:i:s'),
240
+ 'Attention' => $mageOrder->getCustomerNote() ? $mageOrder->getCustomerNote() : ' ',
241
+ ];
242
+
243
+ // Compose the OrderRequest in final form for Stockbase
244
+ $OrderRequest = [
245
+ 'OrderHeader' => $OrderHeader,
246
+ 'OrderLines' => $Orderlines,
247
+ 'OrderDelivery' => $OrderDelivery,
248
+ ];
249
+
250
+ // Only send the order if we have collected items to be ordered.
251
+ if (count($Orderlines) > 1) {
252
+ $posted = $this->post(self::ENDPOINT_STOCKBASE_ORDER, $OrderRequest)->{'nl.divide.iq'};
253
+ }
254
+
255
+ // If failure, we log request and response for debugging.
256
+ if (!$posted->response->content->StatusCode == 1) {
257
+ // We log errors to stockbase-failure.txt in the /var/log/ folder of Magento
258
+ Mage::log(var_export($posted, true), false, 'stockbase-failure.txt');
259
+
260
+ return false;
261
+ }
262
+
263
+ return true;
264
+ }
265
+
266
+ /**
267
+ * Magento street comes with housenumber attached to it, this
268
+ * method tries to seperate the Street, housnumber, and additions.
269
+ *
270
+ * @param type $street
271
+ * @return type
272
+ */
273
+ protected function splitStreet($street)
274
+ {
275
+ $aMatch = [];
276
+ $pattern = '#^([\w[:punct:] ]+) ([0-9]{1,5})([\w[:punct:]\-/]*)$#';
277
+ $matchResult = preg_match($pattern, $street, $aMatch);
278
+
279
+ $street = (isset($aMatch[1])) ? $aMatch[1] : '';
280
+ $number = (isset($aMatch[2])) ? $aMatch[2] : '';
281
+ $numberAddition = (isset($aMatch[3])) ? $aMatch[3] : '';
282
+
283
+ return [
284
+ 'street' => $street,
285
+ 'number' => $number,
286
+ 'numberAddition' => $numberAddition,
287
+ ];
288
+ }
289
+
290
+ /**
291
+ * Collect all EANS from user Stockbase account in a array.
292
+ *
293
+ * @return type
294
+ */
295
+ protected function getAllEansFromStockbase()
296
+ {
297
+ $stockbaseStock = $this->getStock();
298
+ $eans = [];
299
+
300
+ foreach ($stockbaseStock->Groups as $group) {
301
+ foreach ($group->Items as $brand) {
302
+ $eans[] = $brand->EAN;
303
+ }
304
+ }
305
+
306
+ return $eans;
307
+ }
308
+
309
+ /**
310
+ * Returns simpleXMLElement with Stock (beginning from group)
311
+ * Debug param defaults to false, gives debug info about request if true.
312
+ *
313
+ * @param bool $debug
314
+ * @return SimpleXMLElement
315
+ */
316
+ public function getStock($debug = false)
317
+ {
318
+ return $this->call(self::ENDPOINT_STOCKBASE_STOCK, $debug);
319
+ }
320
+
321
+ /**
322
+ * Makes the final call (the request)to the
323
+ * given webservice endpoint. Should only be
324
+ * used internally by this class.
325
+ *
326
+ * @param $endpoint
327
+ * @param bool $debug
328
+ * @return $response (json_decoded body)
329
+ */
330
+ protected function call($endpoint, $debug = false)
331
+ {
332
+ if (!$this->hasAccessToken()) {
333
+ $this->authenticate(true);
334
+ }
335
+
336
+ $this->client->setUri($this->env . $endpoint);
337
+ $this->client->setHeaders('Authentication', $this->accessToken);
338
+
339
+ $result = json_decode($this->client->request()->getBody());
340
+
341
+ if ($result->{'nl.divide.iq'}->response->answer == self::ANSWER_SUCCESS) {
342
+ if (!$debug) {
343
+ return $result->{'nl.divide.iq'}->response->content;
344
+ }
345
+
346
+ return $result->{'nl.divide.iq'};
347
+ }
348
+ }
349
+
350
+ /**
351
+ * Check if accesstoken is set from magento's config.
352
+ *
353
+ * @return bool
354
+ */
355
+ protected function hasAccessToken()
356
+ {
357
+ return (bool)$this->accessToken;
358
+ }
359
+
360
+ /**
361
+ * Post a payload to a endpoint. See
362
+ * defined ENDPOINT constants in HTTP Helper.
363
+ *
364
+ * @param $endpoint
365
+ * @param array $payload
366
+ * @return mixed
367
+ */
368
+ protected function post($endpoint, $payload = [])
369
+ {
370
+ if (!$this->hasAccessToken()) {
371
+ $this->authenticate(true);
372
+ }
373
+
374
+ $this->client->setUri($this->env . $endpoint);
375
+ $this->client->setHeaders('Authentication', $this->accessToken);
376
+ $result = $this->client->setRawData(json_encode($payload), "application/json;charset=UTF-8")->request('POST');
377
+ $response = json_decode($result->getBody());
378
+
379
+ if (!$response) {
380
+ Mage::log(var_export($result->getBody(), true), false, 'stockbase-curl-failure.txt');
381
+
382
+ return $result;
383
+ }
384
+
385
+ return $response;
386
+ }
387
+
388
+ /**
389
+ * Will return image if available at stockbase for given EAN.
390
+ *
391
+ * @param string|array $ean
392
+ */
393
+ public function getImageForEan($ean)
394
+ {
395
+ $collectionEan = [];
396
+
397
+ if (is_array($ean)) {
398
+ foreach ($ean as $singleEAN) {
399
+ $collectionEan[] = $singleEAN;
400
+ }
401
+ $collectionEan = implode(',', $collectionEan);
402
+ } else {
403
+ $collectionEan = $ean;
404
+ }
405
+
406
+ $imageClient = new Zend_Http_Client($this->env . self::ENDPOINT_STOCKBASE_IMAGES . '?ean='.$collectionEan);
407
+
408
+ $imageClient->setHeaders([
409
+ 'Content-Type' => 'application/json',
410
+ 'Authentication' => Mage::getStoreConfig('stockbase_options/token/access')
411
+ ]);
412
+
413
+ $result = json_decode($imageClient->request()->getBody())->{'nl.divide.iq'};
414
+
415
+ if($result->response->answer == self::ANSWER_SUCCESS){
416
+ return $result->response->content->Items;
417
+ }
418
+
419
+ return false;
420
+ }
421
+
422
+ /**
423
+ * Saves images array from stockbase for given $ean
424
+ *
425
+ * @param array $images
426
+ *
427
+ * @return bool
428
+ */
429
+ public function saveImageForProduct($images)
430
+ {
431
+ $productModel = Mage::getModel('catalog/product');
432
+ $eanField = Mage::getStoreConfig('stockbase_options/login/stockbase_ean_field');
433
+ $accessToken = Mage::getStoreConfig('stockbase_options/token/access');
434
+ $tempFolder = Mage::getBaseDir('media') . DS . 'tmp';
435
+ $io = new Varien_Io_File();
436
+ $addedProducts = [];
437
+
438
+ foreach ($images as $image) {
439
+ $product = $productModel->loadByAttribute($eanField, $image->EAN);
440
+ $io->checkAndCreateFolder($tempFolder);
441
+ $filePath = $tempFolder . DS . basename($image->Url);
442
+
443
+ // Continue looping, if we dont have product, we have nothing.
444
+ if(!$product){
445
+ continue;
446
+ }
447
+
448
+ $client = new Varien_Http_Client($image->Url);
449
+ $client->setMethod(Varien_Http_Client::GET);
450
+ $client->setHeaders('Authentication', $accessToken);
451
+ $protectedImage = $client->request()->getBody();
452
+
453
+ if($io->isWriteable($tempFolder)){
454
+ $io->write($filePath, $protectedImage);
455
+ }
456
+
457
+ // Verify written file exsist
458
+ if ($io->fileExists($filePath)) {
459
+ if ($product->getMediaGallery() == null) {
460
+ $product->setMediaGallery(['images' => [], 'values' => []]);
461
+ }
462
+ $product->addImageToMediaGallery(
463
+ $filePath,
464
+ ['image', 'small_image', 'thumbnail'],
465
+ false,
466
+ false
467
+ );
468
+ $product->save();
469
+ }
470
+ }
471
+
472
+ return true;
473
+ }
474
+ }
app/code/local/Divide/Stockbase/Model/Crons.php CHANGED
@@ -1,71 +1,71 @@
1
- <?php
2
-
3
- class Divide_Stockbase_Model_Crons
4
- {
5
- /**
6
- * Method to be called by cron in config.xml
7
- *
8
- * @return boolean
9
- */
10
- public function runNoos()
11
- {
12
- if (Mage::getStoreConfig('stockbase_options/login/stockbase_noos_active', Mage::app()->getStore())) {
13
- $http_helper = Mage::getSingleton('Divide_Stockbase_Helper_HTTP');
14
- $data_helper = Mage::getSingleton('Divide_Stockbase_Helper_Data');
15
- $productModel = Mage::getModel('catalog/product');
16
- $stockModel = Mage::getModel('cataloginventory/stock_item');
17
- $noosEnabled = Mage::getStoreConfig('stockbase_options/login/stockbase_noos_active');
18
- $fieldSet = Mage::getStoreConfig('stockbase_options/login/stockbase_ean_field');
19
- Mage::getModel('core/config')->saveConfig('stockbase_options/cron/last_noos', date('Y-m-d h:i:s'));
20
- $http_helper->authenticate(true);
21
- $skus = $data_helper->getAllEans();
22
- $stockbaseEans = [];
23
-
24
- foreach ($http_helper->getStock()->Groups as $group) {
25
- foreach ($group->Items as $brand) {
26
- if (in_array($brand->EAN, $skus)) {
27
- $stockItem = $stockModel->loadByProduct($productModel->loadByAttribute($fieldSet, $brand->EAN));
28
- if ($stockItem && $brand->NOOS && $brand->Amount >= 1 && $noosEnabled) {
29
- $stockItem
30
- ->setData('use_config_backorders', 0)
31
- ->setData('is_in_stock', 1)
32
- ->setData('backorders', 1);
33
- $stockItem->save();
34
- }
35
- }
36
- }
37
- }
38
- Mage::log('done running never out of stock');
39
-
40
- return true;
41
- }
42
- }
43
-
44
- /**
45
- * Sync images with stockbase if configured.
46
- *
47
- * @return void
48
- */
49
- public function runImageImport()
50
- {
51
- if (Mage::getStoreConfig('stockbase_options/login/stockbase_image_import', Mage::app()->getStore())) {
52
- $cron = Mage::getSingleton('Divide_Stockbase_Model_Crons');
53
- $data_helper = Mage::getSingleton('Divide_Stockbase_Helper_Data');
54
- $http_helper = Mage::getSingleton('Divide_Stockbase_Helper_HTTP');
55
- $skus = $data_helper->getAllEans();
56
- $processed = Mage::getStoreConfig('stockbase_options/images/processed') ? : [];
57
- $processedEanList = json_decode($processed);
58
- $max = 5;
59
-
60
- foreach ($skus as $sku) {
61
- if (!in_array($sku, $processedEanList) && $max != 0) {
62
- $images = $http_helper->getImageForEan($sku);
63
- $http_helper->saveImageForProduct($images, $sku);
64
- $processedEanList[] = $sku;
65
- Mage::getConfig()->saveConfig('stockbase_options/images/processed', json_encode($processedEanList));
66
- $max--;
67
- }
68
- }
69
- }
70
- }
71
- }
1
+ <?php
2
+
3
+ class Divide_Stockbase_Model_Crons
4
+ {
5
+ /**
6
+ * Method to be called by cron in config.xml
7
+ *
8
+ * @return boolean
9
+ */
10
+ public function runNoos()
11
+ {
12
+ if (Mage::getStoreConfig('stockbase_options/login/stockbase_noos_active', Mage::app()->getStore())) {
13
+ $http_helper = Mage::getSingleton('Divide_Stockbase_Helper_HTTP');
14
+ $data_helper = Mage::getSingleton('Divide_Stockbase_Helper_Data');
15
+ $productModel = Mage::getModel('catalog/product');
16
+ $stockModel = Mage::getModel('cataloginventory/stock_item');
17
+ $noosEnabled = Mage::getStoreConfig('stockbase_options/login/stockbase_noos_active');
18
+ $fieldSet = Mage::getStoreConfig('stockbase_options/login/stockbase_ean_field');
19
+ Mage::getModel('core/config')->saveConfig('stockbase_options/cron/last_noos', date('Y-m-d h:i:s'));
20
+ $http_helper->authenticate(true);
21
+ $skus = $data_helper->getAllEans();
22
+ $stockbaseEans = [];
23
+
24
+ foreach ($http_helper->getStock()->Groups as $group) {
25
+ foreach ($group->Items as $brand) {
26
+ if (in_array($brand->EAN, $skus)) {
27
+ $stockItem = $stockModel->loadByProduct($productModel->loadByAttribute($fieldSet, $brand->EAN));
28
+ if ($stockItem && $brand->NOOS && $brand->Amount >= 1 && $noosEnabled) {
29
+ $stockItem
30
+ ->setData('use_config_backorders', 0)
31
+ ->setData('is_in_stock', 1)
32
+ ->setData('backorders', 1);
33
+ $stockItem->save();
34
+ }
35
+ }
36
+ }
37
+ }
38
+ Mage::log('done running never out of stock');
39
+
40
+ return true;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Sync images with stockbase if configured.
46
+ *
47
+ * @return void
48
+ */
49
+ public function runImageImport()
50
+ {
51
+ if (Mage::getStoreConfig('stockbase_options/login/stockbase_image_import', Mage::app()->getStore())) {
52
+ $cron = Mage::getSingleton('Divide_Stockbase_Model_Crons');
53
+ $data_helper = Mage::getSingleton('Divide_Stockbase_Helper_Data');
54
+ $http_helper = Mage::getSingleton('Divide_Stockbase_Helper_HTTP');
55
+ $skus = $data_helper->getAllEans();
56
+ $processed = Mage::getStoreConfig('stockbase_options/images/processed') ? : [];
57
+ $processedEanList = json_decode($processed);
58
+ $max = 5;
59
+
60
+ foreach ($skus as $sku) {
61
+ if (!in_array($sku, $processedEanList) && $max != 0) {
62
+ $images = $http_helper->getImageForEan($sku);
63
+ $http_helper->saveImageForProduct($images, $sku);
64
+ $processedEanList[] = $sku;
65
+ Mage::getConfig()->saveConfig('stockbase_options/images/processed', json_encode($processedEanList));
66
+ $max--;
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
app/code/local/Divide/Stockbase/Model/Enviroment.php CHANGED
@@ -1,26 +1,26 @@
1
- <?php
2
-
3
- /**
4
- * Enviroment options selection for in admin panel.
5
- * Switching production/development server by setting it in the MageAdmin.
6
- */
7
- class Divide_Stockbase_Model_Enviroment
8
- {
9
- const DEVELOPMENT = 'http://server.divide.nl/divide.api/';
10
- const PRODUCTION = 'https://iqservice.divide.nl/';
11
-
12
- /**
13
- * Returns option array for server selection in admin configuration.
14
- *
15
- * @return array
16
- */
17
- public function toOptionArray()
18
- {
19
- $options = [
20
- ['value' => self::PRODUCTION, 'label'=>'Production'],
21
- ['value' => self::DEVELOPMENT, 'label'=>'Development']
22
- ];
23
-
24
- return $options;
25
- }
26
- }
1
+ <?php
2
+
3
+ /**
4
+ * Enviroment options selection for in admin panel.
5
+ * Switching production/development server by setting it in the MageAdmin.
6
+ */
7
+ class Divide_Stockbase_Model_Enviroment
8
+ {
9
+ const DEVELOPMENT = 'http://server.divide.nl/divide.api/';
10
+ const PRODUCTION = 'https://iqservice.divide.nl/';
11
+
12
+ /**
13
+ * Returns option array for server selection in admin configuration.
14
+ *
15
+ * @return array
16
+ */
17
+ public function toOptionArray()
18
+ {
19
+ $options = [
20
+ ['value' => self::PRODUCTION, 'label'=>'Production'],
21
+ ['value' => self::DEVELOPMENT, 'label'=>'Development']
22
+ ];
23
+
24
+ return $options;
25
+ }
26
+ }
app/code/local/Divide/Stockbase/Model/Observer.php CHANGED
@@ -1,64 +1,67 @@
1
- <?php
2
-
3
- class Divide_Stockbase_Model_Observer
4
- {
5
- /**
6
- * Event catch after sale has successfully been paid for. We check your
7
- * own stock levels against the ordered amount and if your stock has shortage
8
- * we order the products for you at stockbase. Please login to your Stockbase
9
- * account to see these orders.
10
- *
11
- * @param Varien_Event_Observer $observerObserver
12
- */
13
- public function afterPayment(Varien_Event_Observer $observer)
14
- {
15
- /**
16
- * @var $order Mage_Sales_Model_Order
17
- * @var $_product Mage_Sales_Model_Order_Item
18
- * @var $_stock Mage_CatalogInventory_Model_Stock_Item
19
- * @var $oStock Mage_CatalogInventory_Model_Stock_Item
20
- * @var $orderedItem Mage_Sales_Model_Order_Item
21
- * @var $shipment Mage_Sales_Model_Order_Shipment
22
- * @var $observer Varien_Event_Observer
23
- *
24
- * After invoicing and payment this method will be used to
25
- * check if your own stock will be enough to fulfill the requested amount.
26
- * If not, we will take the product and send a order to Stockbase for the
27
- * amount needed, and the order will be placed @Stockbase. This method
28
- * is using the sales_order_payment_pay event and will only be activated
29
- * after payment completes and the order is payed for by the customer.
30
- */
31
- $http = Mage::getSingleton('Divide_Stockbase_Helper_HTTP');
32
- $invoice = $observer->getInvoice();
33
- $order = $invoice->getOrder();
34
- $orderedProducts = $order->getAllItems();
35
-
36
- if ($order) {
37
- // Always rely on own stock first, so stockbase does not always get triggerd.
38
- $sendItToStockbase = false;
39
- foreach ($orderedProducts as $orderedProduct) {
40
- $baseQty = 0;
41
- $productId = $orderedProduct->getId();
42
- $baseQty = $orderedProduct->getQtyOrdered()
43
- - $orderedProduct->getQtyShipped()
44
- - $orderedProduct->getQtyRefunded()
45
- - $orderedProduct->getQtyCanceled();
46
- $finalQty[$orderedProduct->getId()] = $baseQty;
47
- $ownStockQty = $orderedProduct->getProduct()->getStockItem()->getQty();
48
-
49
- if ($ownStockQty <= 0 || $ownStockQty <= $baseQty) {
50
- $sendItToStockbase = true;
51
- }
52
- }
53
-
54
- if ($sendItToStockbase == true) {
55
- $send = $http->sendMageOrder($order);
56
-
57
- if ($send) {
58
- $order->addStatusHistoryComment('This order was send to stockbase.');
59
- $order->save();
60
- }
61
- }
62
- }
63
- }
64
- }
 
 
 
1
+ <?php
2
+
3
+ class Divide_Stockbase_Model_Observer
4
+ {
5
+ /**
6
+ * Event catch after sale has successfully been paid for. We check your
7
+ * own stock levels against the ordered amount and if your stock has shortage
8
+ * we order the products for you at stockbase. Please login to your Stockbase
9
+ * account to see these orders.
10
+ *
11
+ * @param Varien_Event_Observer $observerObserver
12
+ */
13
+ public function afterPayment(Varien_Event_Observer $observer)
14
+ {
15
+ /**
16
+ * @var $order Mage_Sales_Model_Order
17
+ * @var $_product Mage_Sales_Model_Order_Item
18
+ * @var $_stock Mage_CatalogInventory_Model_Stock_Item
19
+ * @var $oStock Mage_CatalogInventory_Model_Stock_Item
20
+ * @var $orderedItem Mage_Sales_Model_Order_Item
21
+ * @var $shipment Mage_Sales_Model_Order_Shipment
22
+ * @var $observer Varien_Event_Observer
23
+ *
24
+ * After invoicing and payment this method will be used to
25
+ * check if your own stock will be enough to fulfill the requested amount.
26
+ * If not, we will take the product and send a order to Stockbase for the
27
+ * amount needed, and the order will be placed @Stockbase. This method
28
+ * is using the sales_order_payment_pay event and will only be activated
29
+ * after payment completes and the order is payed for by the customer.
30
+ */
31
+ $http = Mage::getSingleton('Divide_Stockbase_Helper_HTTP');
32
+ $invoice = $observer->getInvoice();
33
+ $order = $invoice->getOrder();
34
+ $orderedProducts = $order->getAllItems();
35
+ $moduleEnabled = Mage::getStoreConfig('stockbase_options/login/stockbase_active');
36
+
37
+ if ($order && $moduleEnabled) {
38
+ // Always rely on own stock first, so stockbase does not always get triggerd.
39
+ $sendItToStockbase = false;
40
+ foreach ($orderedProducts as $orderedProduct) {
41
+ $baseQty = 0;
42
+ $productId = $orderedProduct->getId();
43
+ $baseQty = $orderedProduct->getQtyOrdered()
44
+ - $orderedProduct->getQtyShipped()
45
+ - $orderedProduct->getQtyRefunded()
46
+ - $orderedProduct->getQtyCanceled();
47
+ $finalQty[$productId] = $baseQty;
48
+ $ownStockQty = $orderedProduct->getProduct()->getStockItem()->getQty();
49
+
50
+ if ($ownStockQty <= 0 || $ownStockQty <= $baseQty) {
51
+ $sendItToStockbase = true;
52
+ }
53
+ }
54
+
55
+ // Only send if own stock is too low
56
+ if ($sendItToStockbase == true) {
57
+ $send = $http->sendMageOrder($order);
58
+
59
+ // Add status history to order to identify Stockbase orders
60
+ if ($send) {
61
+ $order->addStatusHistoryComment('This order was send to stockbase.');
62
+ $order->save();
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
app/code/local/Divide/Stockbase/Model/Options.php CHANGED
@@ -1,33 +1,33 @@
1
- <?php
2
-
3
- class Divide_Stockbase_Model_Options
4
- {
5
- /**
6
- * Return options for EAN selection from all the created
7
- * attributes in magento. When user adds new fields to productattributes
8
- * this will fetch them and display them to be used as custom EAN field.
9
- * We default to 'sku' field
10
- *
11
- * @return array
12
- */
13
- public function toOptionArray()
14
- {
15
- $productAttrs = Mage::getResourceModel('catalog/product_attribute_collection');
16
- $options = [];
17
-
18
- foreach ($productAttrs as $productAttr) {
19
- $code = $productAttr->getAttributeCode();
20
- $label = $productAttr->getFrontendLabel();
21
- if (!$label) {
22
- $label = $productAttr->getAttributeCode();
23
- }
24
-
25
- $options[] = [
26
- 'value' => $code,
27
- 'label' => $label
28
- ];
29
- }
30
-
31
- return $options;
32
- }
33
- }
1
+ <?php
2
+
3
+ class Divide_Stockbase_Model_Options
4
+ {
5
+ /**
6
+ * Return options for EAN selection from all the created
7
+ * attributes in magento. When user adds new fields to productattributes
8
+ * this will fetch them and display them to be used as custom EAN field.
9
+ * We default to 'sku' field
10
+ *
11
+ * @return array
12
+ */
13
+ public function toOptionArray()
14
+ {
15
+ $productAttrs = Mage::getResourceModel('catalog/product_attribute_collection');
16
+ $options = [];
17
+
18
+ foreach ($productAttrs as $productAttr) {
19
+ $code = $productAttr->getAttributeCode();
20
+ $label = $productAttr->getFrontendLabel();
21
+ if (!$label) {
22
+ $label = $productAttr->getAttributeCode();
23
+ }
24
+
25
+ $options[] = [
26
+ 'value' => $code,
27
+ 'label' => $label
28
+ ];
29
+ }
30
+
31
+ return $options;
32
+ }
33
+ }
app/code/local/Divide/Stockbase/controllers/Adminhtml/ConfigController.php CHANGED
@@ -1,67 +1,66 @@
1
- <?php
2
-
3
- class Divide_Stockbase_Adminhtml_ConfigController extends Mage_Adminhtml_Controller_Action
4
- {
5
-
6
- /**
7
- * indexAction for config page of Stockbase
8
- *
9
- * First loads a block and then adds the block with data to the layout.
10
- * Loads the given stockbase phtml template and fills it up
11
- * with the configured configuration found in the mage core config.
12
- *
13
- * @return void
14
- */
15
- public function indexAction()
16
- {
17
- // First start loading the default adminhtml layout
18
- $this->loadLayout();
19
-
20
- // Fetch array with key-value pair Stockbase configuration
21
- $configuration = $this->getCurrentConfigurationForStockbase();
22
-
23
- // Make the block with the retrieved configuration for rendering
24
- $configBlock = $this->getLayout()->createBlock('Mage_Core_Block_Template')
25
- ->setTemplate('stockbase/config.phtml')
26
- ->setStockbaseConfiguration($configuration);
27
-
28
- // Using the Mage_Core_Block_Template now get the
29
- // content Block and append it with our block.
30
- $this->getLayout()->getBlock('content')->append($configBlock);
31
-
32
- // Render the total Mage_Core_Block_Template with our given config.
33
- $this->renderLayout();
34
- }
35
-
36
- /**
37
- * Returns array with set configuration for stockbase.
38
- *
39
- * @return array
40
- */
41
- private function getCurrentConfigurationForStockbase()
42
- {
43
- $configuration = [];
44
- $processedImages = Mage::getStoreConfig('stockbase_options/images/processed') ?: [];
45
- $configuration['module_version'] = Mage::getConfig()->getModuleConfig("Divide_Stockbase")->version;
46
- $configuration['enabled_module'] = Mage::getStoreConfig('stockbase_options/login/stockbase_active');
47
- $configuration['enabled_noos'] = Mage::getStoreConfig('stockbase_options/login/stockbase_noos_active');
48
- $configuration['enabled_image'] = Mage::getStoreConfig('stockbase_options/login/stockbase_image_import');
49
- $configuration['processed_images'] = count(json_decode($processedImages));
50
- $configuration['order_prefix'] = Mage::getStoreConfig('stockbase_options/login/order_prefix');
51
- $configuration['username'] = Mage::getStoreConfig('stockbase_options/login/username');
52
- $configuration['enviroment'] = Mage::getStoreConfig('stockbase_options/login/stockbase_enviroment');
53
- $configuration['last_cron'] = Mage::getStoreConfig('stockbase_options/cron/last_noos');
54
-
55
- return $configuration;
56
- }
57
-
58
- /**
59
- * Mage ACL rules for adminhtml
60
- *
61
- * @return boolean
62
- */
63
- protected function _isAllowed()
64
- {
65
- return true;
66
- }
67
- }
1
+ <?php
2
+
3
+ class Divide_Stockbase_Adminhtml_ConfigController extends Mage_Adminhtml_Controller_Action
4
+ {
5
+ /**
6
+ * indexAction for config page of Stockbase
7
+ *
8
+ * First loads a block and then adds the block with data to the layout.
9
+ * Loads the given stockbase phtml template and fills it up
10
+ * with the configured configuration found in the mage core config.
11
+ *
12
+ * @return void
13
+ */
14
+ public function indexAction()
15
+ {
16
+ // First start loading the default adminhtml layout
17
+ $this->loadLayout();
18
+
19
+ // Fetch array with key-value pair Stockbase configuration
20
+ $configuration = $this->getCurrentConfigurationForStockbase();
21
+
22
+ // Make the block with the retrieved configuration for rendering
23
+ $configBlock = $this->getLayout()->createBlock('Mage_Core_Block_Template')
24
+ ->setTemplate('stockbase/config.phtml')
25
+ ->setStockbaseConfiguration($configuration);
26
+
27
+ // Using the Mage_Core_Block_Template now get the
28
+ // content Block and append it with our block.
29
+ $this->getLayout()->getBlock('content')->append($configBlock);
30
+
31
+ // Render the total Mage_Core_Block_Template with our given config.
32
+ $this->renderLayout();
33
+ }
34
+
35
+ /**
36
+ * Returns array with set configuration for stockbase.
37
+ *
38
+ * @return array
39
+ */
40
+ private function getCurrentConfigurationForStockbase()
41
+ {
42
+ $configuration = [];
43
+ $processedImages = Mage::getStoreConfig('stockbase_options/images/processed') ?: [];
44
+ $configuration['module_version'] = Mage::getConfig()->getModuleConfig("Divide_Stockbase")->version;
45
+ $configuration['enabled_module'] = Mage::getStoreConfig('stockbase_options/login/stockbase_active');
46
+ $configuration['enabled_noos'] = Mage::getStoreConfig('stockbase_options/login/stockbase_noos_active');
47
+ $configuration['enabled_image'] = Mage::getStoreConfig('stockbase_options/login/stockbase_image_import');
48
+ $configuration['processed_images'] = count(json_decode($processedImages));
49
+ $configuration['order_prefix'] = Mage::getStoreConfig('stockbase_options/login/order_prefix');
50
+ $configuration['username'] = Mage::getStoreConfig('stockbase_options/login/username');
51
+ $configuration['enviroment'] = Mage::getStoreConfig('stockbase_options/login/stockbase_enviroment');
52
+ $configuration['last_cron'] = Mage::getStoreConfig('stockbase_options/cron/last_noos');
53
+
54
+ return $configuration;
55
+ }
56
+
57
+ /**
58
+ * Mage ACL rules for adminhtml
59
+ *
60
+ * @return boolean
61
+ */
62
+ protected function _isAllowed()
63
+ {
64
+ return true;
65
+ }
66
+ }
 
app/code/local/Divide/Stockbase/etc/config.xml CHANGED
@@ -1,160 +1,149 @@
1
- <?xml version="1.0"?>
2
- <config>
3
-
4
- <modules>
5
- <Divide_Stockbase>
6
- <version>0.2.0</version>
7
- </Divide_Stockbase>
8
- </modules>
9
-
10
- <global>
11
- <helpers>
12
- <Divide_Stockbase>
13
- <class>Divide_Stockbase_Helper</class>
14
- </Divide_Stockbase>
15
- </helpers>
16
- <models>
17
- <stock>
18
- <class>Divide_Stockbase_Model</class>
19
- <resourceModel>stock_mysql4</resourceModel>
20
- </stock>
21
-
22
- <stock_mysql4>
23
- <class>Divide_Stockbase_Model_Mysql4</class>
24
- <entities>
25
- <stock>
26
- <table>stock</table>
27
- </stock>
28
- </entities>
29
- </stock_mysql4>
30
- </models>
31
- <resources>
32
- <stock_setup>
33
- <setup>
34
- <module>Divide_Stockbase</module>
35
- </setup>
36
- <connection>
37
- <use>core_setup</use>
38
- </connection>
39
- </stock_setup>
40
- <stock_write>
41
- <connection>
42
- <use>core_write</use>
43
- </connection>
44
- </stock_write>
45
- <stock_read>
46
- <connection>
47
- <use>core_read</use>
48
- </connection>
49
- </stock_read>
50
- </resources>
51
- <blocks>
52
- <stockbase>
53
- <class>Divide_Stockbase_Block</class>
54
- </stockbase>
55
- </blocks>
56
- <events>
57
-
58
- <sales_order_payment_pay>
59
- <observers>
60
- <Divide_Stockbase_Model_Observer>
61
- <type>singleton</type>
62
- <class>Divide_Stockbase_Model_Observer</class>
63
- <method>afterPayment</method>
64
- </Divide_Stockbase_Model_Observer>
65
- </observers>
66
- </sales_order_payment_pay>
67
- </events>
68
- </global>
69
-
70
- <admin>
71
- <routers>
72
- <stockbase>
73
- <use>admin</use>
74
- <args>
75
- <module>Divide_Stockbase</module>
76
- <frontName>stockbase</frontName>
77
- </args>
78
- </stockbase>
79
- </routers>
80
- <adminhtml>
81
- <args>
82
- <modules>
83
- <module before="Mage_Adminhtml">Stockbase_Adminhtml</module>
84
- </modules>
85
- </args>
86
- </adminhtml>
87
- </admin>
88
-
89
- <adminhtml>
90
- <menu>
91
- <stockbase module="Divide_Stockbase" translate="title">
92
- <title>Stockbase</title>
93
- <sort_order>200</sort_order>
94
- <children>
95
- <stock>
96
- <title>Module Status</title>
97
- <action>stockbase/adminhtml_config/index</action>
98
- </stock>
99
- </children>
100
- </stockbase>
101
- </menu>
102
- <acl>
103
- <resources>
104
- <admin>
105
- <children>
106
- <system>
107
- <children>
108
- <config>
109
- <children>
110
- <stockbase_options>
111
- <title>Stockbase Module Section</title>
112
- </stockbase_options>
113
- </children>
114
- </config>
115
- </children>
116
- </system>
117
- </children>
118
- </admin>
119
- </resources>
120
- </acl>
121
- <translate>
122
- <modules>
123
- <translations>
124
- <files>
125
- <default>Divide_Stockbase.csv</default>
126
- </files>
127
- </translations>
128
- </modules>
129
- </translate>
130
- <layout>
131
- <updates>
132
- <stockbase>
133
- <file>stockbase.xml</file>
134
- </stockbase>
135
- </updates>
136
- </layout>
137
- </adminhtml>
138
-
139
- <crontab>
140
- <jobs>
141
- <stockbase_noos_cron>
142
- <schedule>
143
- <cron_expr>0 * * * *</cron_expr>
144
- </schedule>
145
- <run>
146
- <model>stock/crons::runNoos</model>
147
- </run>
148
- </stockbase_noos_cron>
149
- <stockbase_image_cron>
150
- <schedule>
151
- <cron_expr>*/30 * * * *</cron_expr>
152
- </schedule>
153
- <run>
154
- <model>stock/crons::runImageImport</model>
155
- </run>
156
- </stockbase_image_cron>
157
- </jobs>
158
- </crontab>
159
-
160
- </config>
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Divide_Stockbase>
5
+ <version>1.0.0</version>
6
+ </Divide_Stockbase>
7
+ </modules>
8
+ <global>
9
+ <helpers>
10
+ <Divide_Stockbase>
11
+ <class>Divide_Stockbase_Helper</class>
12
+ </Divide_Stockbase>
13
+ </helpers>
14
+ <models>
15
+ <stock>
16
+ <class>Divide_Stockbase_Model</class>
17
+ <resourceModel>stock_mysql4</resourceModel>
18
+ </stock>
19
+ <stock_mysql4>
20
+ <class>Divide_Stockbase_Model_Mysql4</class>
21
+ <entities>
22
+ <stock>
23
+ <table>stock</table>
24
+ </stock>
25
+ </entities>
26
+ </stock_mysql4>
27
+ </models>
28
+ <resources>
29
+ <stock_setup>
30
+ <setup>
31
+ <module>Divide_Stockbase</module>
32
+ </setup>
33
+ <connection>
34
+ <use>core_setup</use>
35
+ </connection>
36
+ </stock_setup>
37
+ <stock_write>
38
+ <connection>
39
+ <use>core_write</use>
40
+ </connection>
41
+ </stock_write>
42
+ <stock_read>
43
+ <connection>
44
+ <use>core_read</use>
45
+ </connection>
46
+ </stock_read>
47
+ </resources>
48
+ <blocks>
49
+ <stockbase>
50
+ <class>Divide_Stockbase_Block</class>
51
+ </stockbase>
52
+ </blocks>
53
+ <events>
54
+ <sales_order_payment_pay>
55
+ <observers>
56
+ <Divide_Stockbase_Model_Observer>
57
+ <type>singleton</type>
58
+ <class>Divide_Stockbase_Model_Observer</class>
59
+ <method>afterPayment</method>
60
+ </Divide_Stockbase_Model_Observer>
61
+ </observers>
62
+ </sales_order_payment_pay>
63
+ </events>
64
+ </global>
65
+ <admin>
66
+ <routers>
67
+ <adminhtml>
68
+ <args>
69
+ <modules>
70
+ <Divide_Stockbase before="Mage_Adminhtml">Divide_Stockbase_Adminhtml</Divide_Stockbase>
71
+ </modules>
72
+ </args>
73
+ </adminhtml>
74
+ </routers>
75
+ </admin>
76
+ <adminhtml>
77
+ <menu>
78
+ <stockbase module="Divide_Stockbase" translate="title">
79
+ <title>Stockbase</title>
80
+ <sort_order>200</sort_order>
81
+ <children>
82
+ <stock>
83
+ <title>Module Status</title>
84
+ <action>adminhtml/config/index</action>
85
+ </stock>
86
+ <configuration>
87
+ <title>Configuration</title>
88
+ <action>adminhtml/system_config/edit/section/stockbase_options</action>
89
+ </configuration>
90
+ </children>
91
+ </stockbase>
92
+ </menu>
93
+ <acl>
94
+ <resources>
95
+ <admin>
96
+ <children>
97
+ <system>
98
+ <children>
99
+ <config>
100
+ <children>
101
+ <stockbase_options>
102
+ <title>Stockbase Module Section</title>
103
+ </stockbase_options>
104
+ </children>
105
+ </config>
106
+ </children>
107
+ </system>
108
+ </children>
109
+ </admin>
110
+ </resources>
111
+ </acl>
112
+ <translate>
113
+ <modules>
114
+ <translations>
115
+ <files>
116
+ <default>Divide_Stockbase.csv</default>
117
+ </files>
118
+ </translations>
119
+ </modules>
120
+ </translate>
121
+ <layout>
122
+ <updates>
123
+ <stockbase>
124
+ <file>stockbase.xml</file>
125
+ </stockbase>
126
+ </updates>
127
+ </layout>
128
+ </adminhtml>
129
+ <crontab>
130
+ <jobs>
131
+ <stockbase_noos_cron>
132
+ <schedule>
133
+ <cron_expr>0 * * * *</cron_expr>
134
+ </schedule>
135
+ <run>
136
+ <model>stock/crons::runNoos</model>
137
+ </run>
138
+ </stockbase_noos_cron>
139
+ <stockbase_image_cron>
140
+ <schedule>
141
+ <cron_expr>*/30 * * * *</cron_expr>
142
+ </schedule>
143
+ <run>
144
+ <model>stock/crons::runImageImport</model>
145
+ </run>
146
+ </stockbase_image_cron>
147
+ </jobs>
148
+ </crontab>
149
+ </config>
 
 
 
 
 
 
 
 
 
 
 
app/code/local/Divide/Stockbase/etc/system.xml CHANGED
@@ -1,13 +1,11 @@
1
  <?xml version="1.0"?>
2
  <config>
3
-
4
  <tabs>
5
  <stockbaseconfig translate="label" module="Divide_Stockbase">
6
  <label>Stockbase</label>
7
  <sort_order>160</sort_order>
8
  </stockbaseconfig>
9
  </tabs>
10
-
11
  <sections>
12
  <stockbase_options translate="label" module="Divide_Stockbase">
13
  <label>Settings</label>
@@ -111,5 +109,4 @@
111
  </groups>
112
  </stockbase_options>
113
  </sections>
114
-
115
  </config>
1
  <?xml version="1.0"?>
2
  <config>
 
3
  <tabs>
4
  <stockbaseconfig translate="label" module="Divide_Stockbase">
5
  <label>Stockbase</label>
6
  <sort_order>160</sort_order>
7
  </stockbaseconfig>
8
  </tabs>
 
9
  <sections>
10
  <stockbase_options translate="label" module="Divide_Stockbase">
11
  <label>Settings</label>
109
  </groups>
110
  </stockbase_options>
111
  </sections>
 
112
  </config>
app/etc/modules/Divide_Stockbase.xml CHANGED
@@ -4,7 +4,7 @@
4
  <Divide_Stockbase>
5
  <active>true</active>
6
  <codePool>local</codePool>
7
- <version>0.2.0</version>
8
  </Divide_Stockbase>
9
  </modules>
10
  </config>
4
  <Divide_Stockbase>
5
  <active>true</active>
6
  <codePool>local</codePool>
7
+ <version>1.0.0</version>
8
  </Divide_Stockbase>
9
  </modules>
10
  </config>
package.xml CHANGED
@@ -1,24 +1,34 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Stockbase</name>
4
- <version>0.2.0</version>
5
  <stability>stable</stability>
6
  <license uri="https://opensource.org/licenses/GPL-3.0">GPL-3.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>This module allows connecting your Stockbase account with your Magento webshop, allowing it to make use of the extra inventory offered by Stockbase.</summary>
10
  <description>This module requires you to have a Stockbase account with username and password. After installing the module you have to connect it to your Stockbase account using the configuration page in the Magento administration. After configuration you can make use of the following features:&#xD;
11
- &#xD;
12
- - Image import: The module will check your stock levels and make a match based on EAN. If there are any images found at Stockbase, they will automatically be downloaded to your webshop and added to the product.&#xD;
13
- &#xD;
14
- - Products that are never-out-of-stock: Enabling this feature will give your shop an extra warehouse with its own stock. The connected suppliers and brands in your Stockbase account will be checked when receiving an order with an out-of-stock product. If the out-of-stock product is available for order in Stockbase, the order will be forwarded to the Stockbase internal order handling service, and the product will be shipped to the customer on your behalf.&#xD;
15
  &#xD;
 
 
 
 
 
 
 
 
16
  </description>
17
- <notes>Stable release version 0.2.0</notes>
 
 
 
 
 
 
18
  <authors><author><name>Divide BV</name><user>Stockbase</user><email>support@stockbase.nl</email></author></authors>
19
- <date>2016-08-29</date>
20
- <time>09:29:22</time>
21
- <contents><target name="magelocal"><dir name="Divide"><dir name="Stockbase"><dir name="Block"><file name="Config.php" hash="1ffe8997341bb531575d1202dc38aa7e"/></dir><dir name="Helper"><file name="Data.php" hash="ca8e9ab91ed7a276fe314386f9363ccc"/><file name="HTTP.php" hash="2697599b58371210ac4159e66435f4c5"/></dir><dir name="Model"><file name="Crons.php" hash="109c7171302e00048f428636ff63bc47"/><file name="Enviroment.php" hash="1669ade12c8620b8d2325368df9a94b3"/><file name="Observer.php" hash="16997e04ff0481f6c195d7cfff159779"/><file name="Options.php" hash="01a21925356ad2114115ffda1d921a2e"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="ConfigController.php" hash="12957f4fd1fe0abd3b054743666ed5d6"/></dir></dir><dir name="etc"><file name="config.xml" hash="9d8401fab6f5e8f0e6e4a206a998b180"/><file name="system.xml" hash="bd64fac936007a3fd60b72dc600ef704"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Divide_Stockbase.xml" hash="6dda151a88f221db20bd30afe0a1fb54"/></dir></target></contents>
22
  <compatible/>
23
  <dependencies><required><php><min>5.4.0</min><max>6.0.0</max></php></required></dependencies>
24
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Stockbase</name>
4
+ <version>1.0.2</version>
5
  <stability>stable</stability>
6
  <license uri="https://opensource.org/licenses/GPL-3.0">GPL-3.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>This module allows connecting your Stockbase account with your Magento webshop, allowing it to make use of the extra inventory offered by Stockbase.</summary>
10
  <description>This module requires you to have a Stockbase account with username and password. After installing the module you have to connect it to your Stockbase account using the configuration page in the Magento administration. After configuration you can make use of the following features:&#xD;
 
 
 
 
11
  &#xD;
12
+ Products never-out-of-stock:&#xD;
13
+ The connected suppliers and brands in your Stockbase account will be checked when receiving an order with an out-of-stock product. The order will be forwarded to Stockbase when applicable&#xD;
14
+ &#xD;
15
+ Sending orders to stockbase&#xD;
16
+ When the products are out-of-stock, the order will be forwarded to Stockbase's order handling service. Your own stock is not sufficient enough to fullfill the order. Products on your webshop can continue to be ordered, even when they are out of stock. Stockbase will take the order and deliver the desired quantity.&#xD;
17
+ &#xD;
18
+ Product image import&#xD;
19
+ The module will compare your webshop's product inventory to your Stockbase account's inventory, based on EAN. If a match is found, the module will download any images from Stockbase to your webshop and add them to the product.&#xD;
20
  </description>
21
+ <notes>Release notes v1.0.2:&#xD;
22
+ &#xD;
23
+ - Fixed configuration for Order event observer to be enabled/disabled&#xD;
24
+ - Added dutch translation&#xD;
25
+ - Image import combined request to 1 call each cron run&#xD;
26
+ - Fix of patch 6788 admin routing for Status page&#xD;
27
+ </notes>
28
  <authors><author><name>Divide BV</name><user>Stockbase</user><email>support@stockbase.nl</email></author></authors>
29
+ <date>2016-09-22</date>
30
+ <time>13:22:02</time>
31
+ <contents><target name="magelocal"><dir name="Divide"><dir name="Stockbase"><dir name="Block"><file name="Config.php" hash="8e7dc3df9eed45c8900436888590e604"/></dir><dir name="Helper"><file name="Data.php" hash="604fdc3a6c55e38092b9273ba57e29b1"/><file name="HTTP.php" hash="32cbc78fc27516815f304a6a073685a0"/></dir><dir name="Model"><file name="Crons.php" hash="6aac78bf53dd319c879e3cc4e4f28076"/><file name="Enviroment.php" hash="03258d9afaa6121144260001f4ad518a"/><file name="Observer.php" hash="6d4aae3551083b731c4df1a3f1923f17"/><file name="Options.php" hash="ec70a8490684ddd27db168cae92d48eb"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="ConfigController.php" hash="b56e1a7f9c5e3438d40f0c86465d3cd2"/></dir></dir><dir name="etc"><file name="config.xml" hash="8af12f6835ad02a97a5622e9bcc95af7"/><file name="system.xml" hash="e115570eb8fcaef89c1a310289d3cb16"/></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="stockbase.xml" hash=""/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Divide_Stockbase.xml" hash="139d8286a7d19483736b5c6b3b854786"/></dir></target></contents>
32
  <compatible/>
33
  <dependencies><required><php><min>5.4.0</min><max>6.0.0</max></php></required></dependencies>
34
  </package>