LinnLiveConnect - Version 1.1.43

Version Notes

minor bug fixes

Download this release

Release Info

Developer Albert Andrejev
Extension LinnLiveConnect
Version 1.1.43
Comparing to
See all releases


Code changes from version 1.1.42 to 1.1.43

app/code/local/LinnSystems/LinnLiveConnect/Model/Api/V2.php CHANGED
@@ -1,17 +1,17 @@
1
  <?php
2
  class Settings {
3
- static $VERSION = 41;
4
  }
5
 
6
  class LinnSystems_LinnLiveConnect_Model_Api_V2{
7
 
8
- public function configurableProduct($version, $set, $sku, $reindex, $productData, $productsSet, $attributesSet, $store=null)
9
  {
10
  $worker = Factory::createWorker($version);
11
  return $worker->configurableProduct($set, $sku, $reindex, $productData, $productsSet, $attributesSet, $store);
12
  }
13
 
14
- public function updateConfigurableProduct($version, $productId, $reindex, $productData, $productsSet, $attributesSet, $store=null, $identifierType='id')
15
  {
16
  $worker = Factory::createWorker($version);
17
  return $worker->updateConfigurableProduct($productId, $reindex, $productData, $productsSet, $attributesSet, $store, $identifierType);
@@ -23,79 +23,76 @@ class LinnSystems_LinnLiveConnect_Model_Api_V2{
23
  return $worker->storesList();
24
  }
25
 
26
- public function getStoreCode($version, $store=null)
27
  {
28
  $worker = Factory::createWorker($version);
29
  return $worker->getStoreCode($store);
30
  }
31
 
32
- public function deleteAssigned($version, $productId, $store=null, $identifierType='id')
33
  {
34
  $worker = Factory::createWorker($version);
35
  return $worker->deleteAssigned($productId, $store, $identifierType);
36
  }
37
 
38
- public function assignImages($version, $productImages)
39
  {
40
  $worker = Factory::createWorker($version);
41
  return $worker->assignImages($productImages);
42
  }
43
 
44
- public function productList($version, $page, $perPage, $filters = null, $store = null)
45
  {
46
  $worker = Factory::createWorker($version);
47
  return $worker->productList($page, $perPage, $filters, $store);
48
  }
49
 
50
- public function productAttributeOptions($version, $setId)
51
  {
52
  $worker = Factory::createWorker($version);
53
  return $worker->productAttributeOptions($setId);
54
  }
55
 
56
- public function update($version, $productId, $productData, $store = null, $identifierType = 'id')
57
- {
58
  $worker = Factory::createWorker($version);
59
  return $worker->update($productId, $productData, $store, $identifierType);
60
- }
61
 
62
- public function create($version, $type, $set, $sku, $productData, $store = null)
63
- {
64
  $worker = Factory::createWorker($version);
65
  return $worker->create($type, $set, $sku, $productData, $store);
66
- }
67
 
68
- public function debugInfo()
69
- {
70
  $worker = Factory::createWorker(Settings::$VERSION);
71
  return $worker->debugInfo();
72
- }
73
  }
74
 
75
  class Factory{
76
 
77
- private function _checkVersion($version)
78
  {
79
  $version = intval($version);
80
 
81
- if ($version == 0)
82
- throw new Mage_Api_Exception('version_not_specified');
83
- if (Settings::$VERSION < $version )
84
- throw new Mage_Api_Exception('wrong_version');
85
  }
86
 
87
-
88
  public static function createWorker($version)
89
  {
90
- self::_checkVersion($version);
91
 
92
  if(Mage::GetEdition() == Mage::EDITION_COMMUNITY)
93
  {
94
- return new LinnLiveCommunity();
95
  }
96
- else if (Mage::GetEdition() == Mage::EDITION_ENTERPRISE)
97
  {
98
- return new LinnLiveEnterprise();
99
  }
100
  else
101
  {
@@ -108,433 +105,433 @@ class Factory{
108
  class LinnLiveMain extends Mage_Core_Model_Abstract{
109
 
110
 
111
- private $_ignoredAttributes = array(
112
- 'created_at',
113
- 'updated_at',
114
- 'category_ids',
115
- 'required_options',
116
- 'old_id',
117
- 'url_key',
118
- 'url_path',
119
- 'has_options',
120
- 'image_label',
121
- 'small_image_label',
122
- 'thumbnail_label',
123
- 'image',
124
- 'small_image',
125
- 'thumbnail',
126
- 'options_container',
127
- 'entity_id',
128
- 'entity_type_id',
129
- 'attribute_set_id',
130
- 'type_id',
131
- 'sku',
132
- 'name',
133
- 'status',
134
- 'stock_item',
135
- 'description',
136
- );
137
 
138
  private $_permittedAttributes = array (
139
- 'select',
140
  'multiselect',
141
  'text',
142
- 'textarea',
143
- 'date',
144
- 'price'
145
  );
146
 
147
  private function _prepareConfigurableData(
148
- & $store, & $productData, & $assignedProductsArray,
149
- & $attributesSetArray, $productsSet, $attributesSet)
150
- {
151
- $store = $this->_currentStoreCode($store);
152
-
153
- $this->_updateConfigurableQuantity($productData);
154
-
155
- $productData = $this->_fixAttributes($productData);
156
-
157
- if (!is_array($attributesSet))
158
- {
159
- $tmpSet = $attributesSet;
160
- $attributesSet = array();
161
- $attributesSet[] = $tmpSet;
162
- }
163
-
164
- $assignedProductsData = $this->_createProductsData($productsSet);
165
- $assignedProductsArray = $this->_objectToArray($assignedProductsData);
166
-
167
- $_newAttributeOptions = $this->_newConfigurableOptions($assignedProductsArray);
168
- if (count($_newAttributeOptions) > 0)
169
- {
170
- $_availableOptions = $this->_createOptions($_newAttributeOptions);
171
- $this->_checkAssignedProductsOptions($_availableOptions, $assignedProductsArray);
172
- }
173
-
174
- $attributesSetArray = $this->_objectToArray($attributesSet);
175
- $attributesSetArray = $this->_prepareAttributesData($attributesSetArray, $assignedProductsArray);
176
-
177
- foreach($attributesSetArray as $key=>$value)
178
- {
179
- $attributesSetArray[$key]["id"] = NULL;
180
- $attributesSetArray[$key]["position"] = NULL;
181
-
182
- }
183
-
184
- }
185
-
186
- private function _checkAssignedProductsOptions($availableOptions, & $assignedProductsArray)
187
- {
188
- foreach ($assignedProductsArray as $id => $productOptions)
189
- {
190
- foreach($productOptions as $index => $option)
191
- {
192
- if (isset($availableOptions[$option['attribute_id']][strtolower($option['label'])]))
193
- {
194
- $assignedProductsArray[$id][$index]['value_index'] = $availableOptions[$option['attribute_id']][strtolower($option['label'])];
195
- }
196
- }
197
- }
198
- }
199
-
200
- private function _createOptions($newOptions)
201
- {
202
- $installer = new Mage_Eav_Model_Entity_Setup('core_setup');
203
- $attributeApi = Mage::getModel('catalog/product_attribute_api');
204
- $helperCatalog = Mage::helper('catalog');
205
-
206
- $installer->startSetup();
207
-
208
- $attributesList = array();
209
-
210
- foreach($newOptions as $attribute_id=>$options)
211
- {
212
- $aOption = array();
213
- $aOption['attribute_id'] = $attribute_id;
214
- $attributesList[] = $attribute_id;
215
-
216
- $i=0;
217
- foreach($options as $option)
218
- {
219
- $optionTitle = $helperCatalog->stripTags($option);
220
-
221
- $aOption['value']['option'.$i][0] = $optionTitle;
222
- $i++;
223
- }
224
- $installer->addAttributeOption($aOption);
225
- }
226
- $installer->endSetup();
227
-
228
- Mage::app()->cleanCache(array(Mage_Core_Model_Translate::CACHE_TAG));
229
-
230
-
231
- $currentOptions = array();
232
- $attributeApi = Mage::getModel('catalog/product_attribute_api');
233
- foreach($attributesList as $attribute_id)
234
- {
235
- if (!isset($currentOptions[$attribute_id]))
236
- $currentOptions[$attribute_id] = array();
237
-
238
- $attributeOptions = $attributeApi->options($attribute_id);
239
-
240
- foreach ($attributeOptions as $opts)
241
- {
242
- $label = strtolower($opts['label']);
243
- $optionId = $opts['value'];
244
- if (!isset($currentOptions[$attribute_id][$label]))
245
- $currentOptions[$attribute_id][$label] = $optionId;
246
- else {
247
- $oldId = $currentOptions[$attribute_id][$label];
248
- if ($oldId > $optionId)
249
- {
250
- $attributeApi->removeOption($attribute_id, $oldId);
251
- $currentOptions[$attribute_id][$label] = $optionId;
252
- }
253
- else
254
- {
255
- $attributeApi->removeOption($attribute_id, $optionId);
256
- }
257
- }
258
- }
259
- }
260
-
261
- return $currentOptions;
262
- }
263
-
264
- private function _newConfigurableOptions($assignedProductsArray)
265
- {
266
- $_attributesOptions = array();
267
- foreach ($assignedProductsArray as $id => $productOptions)
268
- {
269
- foreach($productOptions as $option)
270
- {
271
- if (isset($option['value_index']) && $option['value_index'] == '-1')
272
- {
273
- if (isset($_attributesOptions[$option['attribute_id']]))
274
- {
275
- $_attributesOptions[$option['attribute_id']][] = $option['label'];
276
- }
277
- else
278
- {
279
- $_attributesOptions[$option['attribute_id']] = array($option['label']);
280
- }
281
- }
282
- }
283
- }
284
- return $_attributesOptions;
285
- }
286
-
287
- private function _newOptions($productData)
288
- {
289
- $_attributesOptions = array();
290
-
291
- if (property_exists($productData, 'additional_attributes')) {
292
- $_attributes = $productData->additional_attributes;
293
- if (is_array($_attributes)) {
294
- foreach($_attributes as $_attribute) {
295
- if (($_attribute->type == 'select' || $_attribute->type == 'multiselect') && $_attribute->value == "-1")
296
- {
297
- if (isset($_attributesOptions[$_attribute->attribute_id]))
298
- {
299
- $_attributesOptions[$_attribute->attribute_id][] = $_attribute->label;
300
- }
301
- else
302
- {
303
- $_attributesOptions[$_attribute->attribute_id] = array($_attribute->label);
304
- }
305
- }
306
- }
307
- }
308
- else
309
- {
310
- if (($_attributes->type == 'select' || $_attributes->type == 'multiselect') && $_attributes->value == "-1")
311
- {
312
- if (isset($_attributesOptions[$_attributes->attribute_id]))
313
- {
314
- $_attributesOptions[$_attributes->attribute_id][] = $_attributes->label;
315
- }
316
- else
317
- {
318
- $_attributesOptions[$_attributes->attribute_id] = array($_attributes->label);
319
- }
320
- }
321
- }
322
-
323
- }
324
-
325
- return $_attributesOptions;
326
- }
327
-
328
- private function _containsOption($attributeOption, $option)
329
- {
330
- foreach ($attributeOption as $inArrayOption)
331
- if ($inArrayOption['value_index'] == $option['value_index']) return true;
332
-
333
- return false;
334
- }
335
-
336
- private function _prepareAttributesData($attributesSetArray, $assignedProductsArray)
337
- {
338
- $_attributesOptions = array();
339
- foreach ($assignedProductsArray as $id => $productOptions)
340
- {
341
- foreach($productOptions as $option)
342
- {
343
- if (isset($_attributesOptions[$option['attribute_id']]) &&
344
- !$this->_containsOption($_attributesOptions[$option['attribute_id']], $option))
345
- {
346
- $_attributesOptions[$option['attribute_id']][] = $option;
347
- }
348
- else if (!isset($_attributesOptions[$option['attribute_id']]))
349
- {
350
- $_attributesOptions[$option['attribute_id']] = array();
351
- $_attributesOptions[$option['attribute_id']][] = $option;
352
- }
353
- }
354
- }
355
-
356
- foreach($attributesSetArray as $key => $attribute)
357
- {
358
- if (isset($_attributesOptions[$attribute['attribute_id']]))
359
- $attributesSetArray[$key]['values'] = $_attributesOptions[$attribute['attribute_id']];
360
- }
361
-
362
- return $attributesSetArray;
363
- }
364
-
365
- private function _updateConfigurable($store, $productId, $productData, $assignedProducts, $assignedAttributes, $identifierType, $isUpdate=false, $reindex=true)
366
- {
367
- $magentoVer = $this->_getCurrentVersion();
368
- if ($magentoVer == 162)
369
- {
370
- $store = Mage::app()->getStore($store)->getId();
371
- }
372
-
373
- $product = Mage::helper('catalog/product')->getProduct($productId, $store, $identifierType);
374
-
375
- $product->setConfigurableProductsData($assignedProducts);
376
- if (!$isUpdate)
377
- $product->setConfigurableAttributesData($assignedAttributes);
378
- $product->setCanSaveConfigurableAttributes(true);
379
-
380
- try {
381
- $result = $product->save();
382
- }
383
- catch (Exception $e){
384
- throw new Mage_Api_Exception('configurable_creating_error', $e->getMessage());
385
- }
386
-
387
- if ($reindex === true)
388
- {
389
- try {
390
- $indexer = Mage::getSingleton('index/indexer');
391
- $process = $indexer->getProcessByCode('catalog_product_price');
392
- $process->reindexEverything();
393
- }
394
  catch (Mage_Core_Exception $e) {
395
- throw new Mage_Api_Exception('configurable_creating_error', $e->getMessage());
396
- }
397
- }
398
-
399
- return $result;
400
- }
401
-
402
- private function _createProductsData($productData)
403
- {
404
- $assignedProductsData = array();
405
-
406
- if (is_array($productData))
407
- {
408
- foreach ($productData as $product)
409
- {
410
- $assignedProductsData[$product->product_id] = array();
411
- $this->_fillAssignedProductValues($product, $assignedProductsData);
412
- }
413
- }
414
- else
415
- {
416
- $assignedProductsData[$productData->product_id] = array();
417
- $this->_fillAssignedProductValues($product, $assignedProductsData);
418
- }
419
-
420
-
421
- return $assignedProductsData;
422
- }
423
-
424
- private function _fillAssignedProductValues(& $product, & $assignedProductsData)
425
- {
426
- if (is_array($product->values))
427
- {
428
- foreach ($product->values as $productValue)
429
- {
430
- $assignedProductsData[$product->product_id][] = $productValue;
431
- }
432
- }
433
- else
434
- {
435
- $assignedProductsData[$product->product_id][] = $product->values;
436
- }
437
- }
438
-
439
- private function _updateConfigurableQuantity( & $productData)
440
- {
441
- $this->_updateQuantity($productData);
442
-
443
- if (!property_exists($productData, 'stock_data'))
444
- {
445
- $productData->stock_data = new stdClass();
446
- }
447
 
448
  $productData->stock_data->manage_stock = 1;
449
  $productData->stock_data->is_in_stock = 1;
450
- }
451
 
452
- private function _updateQuantity( & $productData)
453
- {
454
- if (property_exists($productData, 'stock_data') && property_exists($productData->stock_data, 'qty')) {
455
- $productData->stock_data->qty = intval($productData->stock_data->qty);
456
  $productData->stock_data->is_in_stock = 1;
457
- $productData->stock_data->manage_stock = 1;
458
- }
459
- }
460
 
461
- private function _objectToArray( $result )
462
  {
463
  $array = array();
464
- foreach ($result as $key=>$value)
465
- {
466
- if (is_object($value) || is_array($value))
467
- {
468
- $array[$key]=$this->_objectToArray($value);
469
- }
470
- else
471
- {
472
- $array[$key]=$value;
473
- }
474
- }
475
- return $array;
476
  }
477
 
478
  private function _getCurrentVersion()
479
- {
480
- $verInfo = Mage::getVersionInfo();
481
-
482
- return intval($verInfo['major'].$verInfo['minor'].$verInfo['revision']);
483
- }
484
-
485
- private function _productImages($attributesList)
486
- {
487
- $_images = array();
488
-
489
- if (is_array($attributesList) && count($attributesList) > 0 && isset($attributesList['media_gallery']))
490
- {
491
- $small = empty($attributesList['small_image']) ? false : $attributesList['small_image'];
492
- $base = empty($attributesList['image']) ? false : $attributesList['image'];
493
- $thumb = empty($attributesList['thumbnail']) ? false : $attributesList['thumbnail'];
494
-
495
- foreach($attributesList['media_gallery']['images'] as $key=>$value)
496
- {
497
- $newImage = array();
498
- $newImage['file'] = $value['file'];
499
- $newImage['label'] = $value['label'];
500
- $newImage['disabled'] = $value['disabled'] ? true : false;
501
-
502
- $newImage['small_image'] = $small == $newImage['file'];
503
- $newImage['image'] = $base == $newImage['file'];
504
- $newImage['thumbnail'] = $thumb == $newImage['file'];
505
-
506
- $_images[] = $newImage;
507
- }
508
- }
509
-
510
- return $_images;
511
- }
512
-
513
- private function _removeIgnoredAttributes($attributesList)
514
- {
515
- $_preparedAttributes = array();
516
- if (is_array($attributesList) && count($attributesList) > 0)
517
- {
518
- foreach($attributesList as $key=>$value)
519
- {
520
- if (!in_array($key, $this->_ignoredAttributes) && !is_array($value))
521
- $_preparedAttributes[]= array('key' => $key, 'value' => $value);
522
- }
523
- }
524
-
525
- return $_preparedAttributes;
526
- }
527
-
528
- private function _currentStoreCode($store=null)
529
- {
530
- if ($store != null)
531
- return $store;
532
-
533
- return $this->_getStore()->getCode();
534
- }
535
-
536
- private function _getProductBySku($sku)
537
- {
538
  if($sku){
539
  $product = Mage::getModel('catalog/product');
540
  $productId = $product->getIdBySku((string)$sku);
@@ -546,58 +543,58 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
546
  }
547
  }
548
  }
549
-
550
- private function _getStore($storeCode=null)
551
- {
552
- if (Mage::app()->isSingleStoreMode()) {
553
  return Mage::app()->getWebsite(true)->getDefaultStore();
554
  }
555
 
556
- $mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : '';
557
- $mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store';
558
 
559
- if ($storeCode != null)
560
- return Mage::getModel('core/store')->load( $storeCode, 'code');
561
 
562
- if ($mageRunType == 'store') {
563
- if (!empty($mageRunCode))
564
- {
565
- return Mage::getModel('core/store')->load( $mageRunCode, 'code');
566
- }
567
- }
568
- else {
569
- if ($mageRunType == 'website')
570
- $websiteCode = empty($mageRunCode) ? '' : $mageRunCode;
571
- else
572
- $websiteCode = empty($mageRunType) ? '' : $mageRunType;
573
 
574
- if (!empty($websiteCode))
575
- {
576
- $currentWebSite = Mage::getModel('core/website')->load( $websiteCode, 'code');
577
- $defaultStore = $currentWebSite->getDefaultStore();
578
- if (isset($defaultStore))
579
- return $defaultStore;
580
- }
581
- }
582
 
583
 
584
- return Mage::app()->getWebsite(true)->getDefaultStore();//Mage::app()->getStore();
585
- }
586
 
587
- private function _getWebsiteId($store=null)
588
  {
589
- return array($this->_getStore($store)->getWebsiteId());
590
  }
591
 
592
- private function _productAttributeInfo($attribute_id, $attributeAPI)
593
- {
594
- $model = Mage::getResourceModel('catalog/eav_attribute')
595
  ->setEntityTypeId(Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId());
596
 
597
  $model->load($attribute_id);
598
 
599
  if (!$model->getId()) {
600
- throw new Mage_Api_Exception('attribute_not_exists');
601
  }
602
 
603
  if ($model->isScopeGlobal()) {
@@ -638,36 +635,36 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
638
  }
639
 
640
  return $result;
641
- }
642
-
643
- //Fix for buggy associativeArray implementation
644
- private function _fixAttributes($productData)
645
- {
646
- $_newAttributeOptions = $this->_newOptions($productData);
647
- $_availableOptions = array();
648
- if (count($_newAttributeOptions) > 0)
649
- {
650
- $_availableOptions = $this->_createOptions($_newAttributeOptions);
651
- }
652
-
653
- if (property_exists($productData, 'additional_attributes')) {
654
- $tmpAttr = $productData->additional_attributes;
655
- if (count($tmpAttr) == 0)
656
- {
657
- unset($productData->additional_attributes);
658
- return $productData;
659
- }
660
-
661
- $i=0;
662
- if (is_array($tmpAttr))
663
- {
664
- foreach ($tmpAttr as $option) {
665
- $code = $option->code;
666
  if ( ($option->type == 'multiselect') && (is_array($productData->$code) == false) )
667
  {
668
  $productData->$code = array();
669
  }
670
- if (isset($_availableOptions[$option->attribute_id][strtolower($option->label)]))
671
  {
672
  if ($option->type == 'multiselect')
673
  {
@@ -690,22 +687,22 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
690
  }
691
  }
692
 
693
- }
694
- }
695
- else
696
- {
697
- $code = $tmpAttr->code;
698
- if (isset($_availableOptions[$tmpAttr->attribute_id][strtolower($tmpAttr->label)]))
699
- $productData->$code = $_availableOptions[$tmpAttr->attribute_id][strtolower($tmpAttr->label)];
700
- else
701
- $productData->$code = $tmpAttr->value;
702
- }
703
  }
704
 
705
- unset($productData->additional_attributes);
706
 
707
- return $productData;
708
- }
709
 
710
 
711
 
@@ -714,75 +711,75 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
714
  * Public functions(API)
715
  *
716
  */
717
- public function configurableProduct($set, $sku, $reindex, $productData, $productsSet, $attributesSet, $store=null)
718
  {
719
- if (!$set || !$sku) {
720
- throw new Mage_Api_Exception('data_invalid');
721
  }
722
 
723
- $this->_prepareConfigurableData($store, $productData, $assignedProductsArray,
724
- $attributesSetArray, $productsSet, $attributesSet);
725
 
726
- $DefaultStore = $this->_getStore();
727
 
728
- if (property_exists($productData, 'websites') === false && isset($DefaultStore) ) {
729
- $productData->websites = array($DefaultStore->getWebsiteId());
730
- }
731
 
732
- if (property_exists($productData, 'category_ids') && !is_array($productData->category_ids))
733
- {
734
- if (is_string($productData->category_ids)) {
735
- $productData->category_ids = array($productData->category_ids);
736
- }
737
- }
738
- else if (property_exists($productData, 'category_ids') === false)
739
- {
740
- $productData->category_ids = array();
741
- }
742
 
743
- $productData->categories = $productData->category_ids;
744
 
745
- $productAPI = new Mage_Catalog_Model_Product_Api_V2();
746
- $productId = $productAPI->create('configurable', $set, $sku, $productData, $store);
747
 
748
- $this->_updateConfigurable($store, $productId, $productData, $assignedProductsArray, $attributesSetArray, 'id', false, $reindex);
749
 
750
- return $productId;
751
  }
752
 
753
- public function updateConfigurableProduct($productId, $reindex, $productData, $productsSet, $attributesSet, $store=null, $identifierType='id')
754
  {
755
 
756
 
757
- $this->_prepareConfigurableData($store, $productData, $assignedProductsArray,
758
- $attributesSetArray, $productsSet, $attributesSet);
759
 
760
- try {
761
  $storeId = Mage::app()->getStore($store)->getId();
762
  }
763
  catch (Mage_Core_Model_Store_Exception $e) {
764
- throw new Mage_Api_Exception('store_not_exists', null);
765
  }
766
  /*
767
- if ($identifierType == 'id')
768
- {
769
  $productId = intval($productId);
770
 
771
  if ($productId < 1) {
772
  throw new Mage_Api_Exception('product_not_exists', null);
773
  }
774
- }*/
775
 
776
- $_loadedProduct = Mage::helper('catalog/product')->getProduct($productId, $storeId, $identifierType);
777
 
778
- if (!$_loadedProduct->getId())
779
- {
780
  throw new Mage_Api_Exception('product_not_exists', null);
781
  }
782
 
783
- $_categoryIds = $_loadedProduct->getCategoryIds();
784
- if (property_exists($productData, 'category_ids'))
785
- {
786
 
787
  if (!is_array($productData->category_ids))
788
  {
@@ -791,43 +788,43 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
791
 
792
  $productData->category_ids = array_merge($_categoryIds, $productData->category_ids);
793
 
794
- }
795
- else
796
- {
797
- $productData->category_ids = $_categoryIds;
798
- }
799
 
800
- $productData->category_ids = array_unique($productData->category_ids);
801
 
802
- if ( (property_exists($productData, 'removed_categories') === true)
803
- && (is_array($productData->removed_categories) === true)
804
- && (count($productData->removed_categories) > 0) )
805
- {
806
- $tmpCats = array();
807
 
808
- $productData->category_ids = array_diff($productData->category_ids, $productData->removed_categories);
809
- }
810
 
811
- $productData->categories = $productData->category_ids;
812
 
813
- if (property_exists($productData, 'add_to_websites') && $productData->add_to_websites === true)
814
- {
815
- $currentWebsites = $_loadedProduct->getWebsiteIds();
816
- $websiteId = $this->_getWebsiteId();
817
- $websiteId = $websiteId[0];
818
 
819
- if (in_array($websiteId, $currentWebsites) === false)
820
- {
821
- $currentWebsites[] = $websiteId;
822
- $productData->websites = $currentWebsites;
823
- }
824
- }
825
 
826
- $productAPI = new Mage_Catalog_Model_Product_Api_V2();
827
 
828
- $productAPI->update($productId, $productData, $store, $identifierType);
829
 
830
- return $this->_updateConfigurable($store, $productId, $productData, $assignedProductsArray, $attributesSetArray, $identifierType, true, $reindex);
831
  }
832
 
833
  /*
@@ -835,72 +832,72 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
835
  */
836
  public function storesList()
837
  {
838
- return ($this->_getCurrentVersion() >= 160);
839
  }
840
 
841
- public function getStoreCode($store=null)
842
  {
843
  return $this->_currentStoreCode($store);
844
  }
845
 
846
- public function deleteAssigned($productId, $store=null, $identifierType='id')
847
  {
848
- $store = $this->_currentStoreCode($store);
849
 
850
- try {
851
  $storeId = Mage::app()->getStore($store)->getId();
852
  }
853
  catch (Mage_Core_Model_Store_Exception $e) {
854
- throw new Mage_Api_Exception('store_not_exists', null);
855
  }
856
 
857
- $_loadedProduct = Mage::helper('catalog/product')->getProduct($productId, $storeId, $identifierType);
858
 
859
- if (!$_loadedProduct->getId())
860
- {
861
  throw new Mage_Api_Exception('product_not_exists', null);
862
  }
863
 
864
 
865
- $currentWebsites = $_loadedProduct->getWebsiteIds();
866
- $websiteId = $this->_getWebsiteId($store);
867
- $websiteId = $websiteId[0];
868
 
869
- $newWebsiteIds = array();
870
 
871
- if (in_array($websiteId, $currentWebsites) === true)
872
- {
873
- for($i = 0; $i < count($currentWebsites); $i++)
874
- {
875
- if ($currentWebsites[$i] != $websiteId)
876
- {
877
- $newWebsiteIds[] = $currentWebsites[$i];
878
- }
879
- }
880
 
881
- $_loadedProduct->setWebsiteIds($newWebsiteIds);
882
 
883
- $_loadedProduct->save();
884
- }
885
 
886
- return true;
887
  }
888
 
889
 
890
- public function assignImages($productImages)
891
  {
892
- $store = $this->_currentStoreCode(null);
893
 
894
- foreach($productImages as $imageData)
895
- {
896
- $productId = intval($imageData->product_id);
897
- if ($productId < 1) {
898
- throw new Mage_Api_Exception('product_not_exists', null);
899
- }
900
 
901
- $product = Mage::helper('catalog/product')->getProduct($productId, $store, 'id');
902
 
903
- $images = $imageData->images;
904
 
905
  $baseImageExist = false;
906
  foreach($images as $image)
@@ -918,55 +915,55 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
918
 
919
  reset($images);
920
 
921
- foreach($images as $image)
922
- {
923
- $catalogProductDir = Mage::getBaseDir('media') . DS . 'catalog/product';
924
- $filePath = $catalogProductDir.$image->image_name;
925
 
926
- if (is_array($image->types) && count($image->types) > 0)
927
- {
928
- $imageTypes = $image->types;
929
- }
930
- else
931
- {
932
- $imageTypes = "";
933
- }
934
 
935
- try
936
- {
937
- $product->addImageToMediaGallery($filePath, $imageTypes, false, false);
938
- }
939
- catch (Exception $e) { }
940
 
941
- }
942
 
943
- $product->save();
944
- }
945
 
946
- return true;
947
  }
948
 
949
- /*
950
  * Implementation of catalogProductList because of bug in associativeArray.
951
  * Extended to filter by category id too.
952
  *
953
  * Use 'entity_id' for product_id,
954
  * 'type_id' instead of product type.
955
  */
956
- public function productList($page, $perPage, $filters = null, $store = null)
957
  {
958
  $arrayParams = array(
959
- 'nin',
960
- 'in',
961
- );
962
 
963
- $store = $this->_currentStoreCode($store);
964
 
965
- try {
966
  $storeId = Mage::app()->getStore($store)->getId();
967
  }
968
  catch (Mage_Core_Model_Store_Exception $e) {
969
- throw new Mage_Api_Exception('store_not_exists', null);
970
  }
971
 
972
  $preparedFilters = array();
@@ -976,47 +973,47 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
976
  }
977
  }
978
  if (isset($filters->complex_filter)) {
979
- foreach ($filters->complex_filter as $_key => $_filter) {
980
- $_op = $_filter->key;
981
  $_filterVal = $_filter->value->value;
982
  $_filterKey = $_filter->value->key;
983
 
984
- if (in_array($_op, $arrayParams)) {
985
- $values = explode(',', $_filterVal);
986
- }
987
- else {
988
- $values = $_filterVal;
989
- }
990
 
991
  $preparedFilters[$_op] = array(
992
  $_filterKey => $values
993
  );
994
- }
995
- }
996
 
997
- if (isset($preparedFilters['category']) &&
998
- is_string($preparedFilters['category']))
999
  {
1000
- $_categoryId = intval($preparedFilters['category']);
1001
- unset($preparedFilters['category']);
1002
- }
1003
- else {
1004
- $_categoryId = 0;
1005
- }
1006
 
1007
  if (!empty($preparedFilters)) {
1008
- if ($_categoryId > 0)
1009
- {
1010
  $_category = Mage::getModel('catalog/category')->load($_categoryId);
1011
- $collection = Mage::getModel('catalog/product')->getCollection()
1012
- ->addStoreFilter($storeId)
1013
- ->addCategoryFilter($_category);
1014
- }
1015
- else
1016
- {
1017
  $collection = Mage::getModel('catalog/product')->getCollection()
1018
- ->addStoreFilter($storeId);
1019
- }
 
 
 
 
 
 
1020
 
1021
  try {
1022
  foreach ($preparedFilters as $field => $value) {
@@ -1024,42 +1021,42 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1024
  }
1025
  }
1026
  catch (Mage_Core_Exception $e) {
1027
- throw new Mage_Api_Exception('filters_invalid', $e->getMessage());
1028
  }
1029
  }
1030
 
1031
- if ($page == 1)
1032
- {
1033
- $count = $collection->count();
1034
- }
1035
- else
1036
- {
1037
- $collection->setPageSize($perPage)
1038
- ->setCurPage($page);
1039
- $count = 0;
1040
- }
1041
 
1042
  $result = array();
1043
- $result['count'] = $count;
1044
- $result['products'] = array();
1045
 
1046
  $_assignedIds = array();
1047
- $_fetchedIds = array();
1048
 
1049
- $i = 0;
1050
  foreach ($collection as $_product) {
1051
- if ($i >= ($perPage * $page)) break;
1052
- $_loadedProduct = Mage::helper('catalog/product')->getProduct($_product->getId(), $storeId, 'id');
1053
 
1054
- $_allAttributes = $_loadedProduct->getData();
1055
 
1056
 
1057
- $_description = isset($_allAttributes['description']) ? $_allAttributes['description'] : '';
1058
 
1059
- $_productImages = $this->_productImages($_allAttributes);
1060
- $_productAttributes = $this->_removeIgnoredAttributes($_allAttributes);
1061
 
1062
- $_fetchedIds[] = $_loadedProduct->getId();
1063
 
1064
  $result['products'][$i] = array(
1065
  'product_id' => $_loadedProduct->getId(),
@@ -1077,138 +1074,138 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1077
  'images' => $_productImages,
1078
  'attributes' => $_productAttributes,
1079
  );
1080
- if($_loadedProduct->getTypeId() == "configurable")
1081
- {
1082
- $_typeInstance = $_loadedProduct->getTypeInstance();
1083
- $result['products'][$i]['assigned_ids'] = $_typeInstance->getUsedProductIds();
1084
- foreach($_typeInstance->getConfigurableAttributes() as $attribute){
1085
- $_prices = array();
1086
- foreach($attribute->getPrices() as $price)
1087
- {
1088
- $_prices[] = array(
1089
- 'value_index' => $price['value_index'],
1090
- 'is_fixed' => !$price['is_percent'],
1091
- 'price_diff' => $price['pricing_value'],
1092
- 'label' => $price['label'],
1093
- );
1094
-
1095
- }
1096
-
1097
- $result['products'][$i]['conf_attrib_ids'][] = array(
1098
- 'code' => $attribute->getProductAttribute()->getAttributeCode(),
1099
- 'prices' => $_prices
1100
- );
1101
- }
1102
- $_assignedIds = array_merge($_assignedIds, $result['products'][$i]['assigned_ids']);
1103
- }
1104
-
1105
- $i++;
1106
- }
1107
-
1108
- $_absentIds = array_diff($_assignedIds, $_fetchedIds);
1109
-
1110
- if (count($_absentIds) > 0)
1111
- {
1112
- $collection = Mage::getModel('catalog/product')->getCollection()->addIdFilter($_absentIds);
1113
-
1114
- foreach ($collection as $_product) {
1115
- $_loadedProduct = Mage::helper('catalog/product')->getProduct($_product->getId(), $storeId, 'id');
1116
-
1117
- $_allAttributes = $_product->getData();
1118
-
1119
- $_description = isset($_allAttributes['description']) ? $_allAttributes['description'] : '';
1120
-
1121
- $_productImages = $this->_productImages($_allAttributes);
1122
- $_productAttributes = $this->_removeIgnoredAttributes($_allAttributes);
1123
-
1124
- $result['products'][] = array(
1125
- 'product_id' => $_loadedProduct->getId(),
1126
- 'sku' => $_loadedProduct->getSku(),
1127
- 'name' => $_loadedProduct->GetName(),
1128
- 'set' => $_loadedProduct->getAttributeSetId(),
1129
- 'type' => $_loadedProduct->getTypeId(),
1130
- 'price' => $_loadedProduct->getPrice(),
1131
- 'status' => $_loadedProduct->getStatus(),
1132
- 'description' => $_description,
1133
- 'category_ids' => $_loadedProduct->getCategoryIds(),
1134
- 'website_ids' => $_loadedProduct->getWebsiteIds(),
1135
- 'assigned_ids' => array(),
1136
- 'conf_attrib_ids' => array(),
1137
- 'images' => $_productImages,
1138
- 'attributes' => $this->_removeIgnoredAttributes($_loadedProduct->getData()),
1139
  );
1140
- }
1141
- }
1142
 
1143
  return $result;
1144
  }
1145
 
1146
- public function productAttributeOptions($setId)
1147
  {
1148
- $result = array();
1149
 
1150
- $setId = intval($setId);
1151
- if ($setId <= 0) return $result;
1152
 
1153
  $attributeAPI = Mage::getModel('catalog/product_attribute_api');
1154
 
1155
- $items = $attributeAPI->items($setId);
1156
-
1157
- $attributes = Mage::getModel('catalog/product')->getResource()
1158
- ->loadAllAttributes();
1159
-
1160
- $i=0;
1161
- foreach ($items as $item) {
1162
- if (!isset($item['attribute_id']) || empty($item['attribute_id'])) continue;
1163
- $attributeId = intval($item['attribute_id']);
1164
- if ($attributeId <= 0) continue;
1165
-
1166
- $additionInfo = $this->_productAttributeInfo($attributeId, $attributeAPI);
1167
-
1168
- if (in_array($additionInfo['frontend_input'], $this->_permittedAttributes) &&
1169
- !in_array($additionInfo['attribute_code'], $this->_ignoredAttributes))
1170
- {
1171
- $result[$i] = array(
1172
- 'attribute_id' => $additionInfo['attribute_id'],
1173
- 'code' => $additionInfo['attribute_code'],
1174
- 'type' => $additionInfo['frontend_input'],
1175
- 'required' => $additionInfo['is_required'],
1176
- 'scope' => $additionInfo['scope'],
1177
- 'can_config' => 0
1178
- );
1179
-
1180
- if ( ($additionInfo['frontend_input'] == 'select') || ($additionInfo['frontend_input'] == 'multiselect') ) {
1181
- if (($additionInfo['scope'] == 'global') &&
1182
- ($additionInfo['is_configurable']))
1183
- {
1184
- foreach ($additionInfo['apply_to'] as $applyTo)
1185
- {
1186
- if ($applyTo == 'simple')
1187
- {
1188
- $result[$i]['can_config'] = 1;
1189
- break;
1190
- }
1191
- }
1192
-
1193
- }
1194
- if (isset($additionInfo['options']))
1195
- $result[$i]['attribute_options'] = $additionInfo['options'];
1196
- }
1197
- $i++;
1198
- }
1199
- }
1200
-
1201
- return $result;
1202
  }
1203
 
1204
- public function update($productId, $productData, $store = null, $identifierType = 'id')
1205
- {
1206
- $store = $this->_currentStoreCode($store);
1207
- try {
1208
  $storeId = Mage::app()->getStore($store)->getId();
1209
  }
1210
  catch (Mage_Core_Model_Store_Exception $e) {
1211
- throw new Mage_Api_Exception('store_not_exists', null);
1212
  }
1213
 
1214
  $_loadedProduct = Mage::helper('catalog/product')->getProduct($productId, $storeId, $identifierType);
@@ -1219,128 +1216,128 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1219
  }
1220
 
1221
 
1222
- $_categoryIds = $_loadedProduct->getCategoryIds();
1223
- if (property_exists($productData, 'category_ids'))
1224
- {
1225
  if (!is_array($productData->category_ids))
1226
  {
1227
  $productData->category_ids = array($productData->category_ids);
1228
  }
1229
 
1230
  $productData->category_ids = array_merge($_categoryIds, $productData->category_ids);
1231
- }
1232
- else
1233
- {
1234
- $productData->category_ids = $_categoryIds;
1235
- }
1236
 
1237
- $productData->category_ids = array_unique($productData->category_ids);
1238
 
1239
- if ( (property_exists($productData, 'removed_categories') === true)
1240
- && (is_array($productData->removed_categories) === true)
1241
- && (count($productData->removed_categories) > 0) )
1242
- {
1243
- $tmpCats = array();
1244
 
1245
- $productData->category_ids = array_diff($productData->category_ids, $productData->removed_categories);
1246
- }
1247
 
1248
- $productData->categories = $productData->category_ids;
1249
 
1250
- if (property_exists($productData, 'add_to_websites') && $productData->add_to_websites === true)
1251
- {
1252
- $currentWebsites = $_loadedProduct->getWebsiteIds();
1253
- $websiteId = $this->_getWebsiteId();
1254
- $websiteId = $websiteId[0];
1255
 
1256
- if (in_array($websiteId, $currentWebsites) === false)
1257
- {
1258
- $currentWebsites[] = $websiteId;
1259
- $productData->websites = $currentWebsites;
1260
- }
1261
- }
1262
 
1263
- $this->_updateQuantity($productData);
1264
 
1265
- $productData = $this->_fixAttributes($productData);
1266
 
1267
- $productAPI = new Mage_Catalog_Model_Product_Api_V2();
1268
 
1269
- $result = $productAPI->update($productId, $productData, $store, $identifierType);
1270
 
1271
- return $result;
1272
- }
1273
 
1274
- public function create($type, $set, $sku, $productData, $store = null)
1275
- {
1276
  $product = $this->_getProductBySku($sku);
1277
  if($product){
1278
  return $product->getId();
1279
  }
1280
 
1281
- $store = $this->_currentStoreCode($store);
1282
 
1283
- $DefaultStore = $this->_getStore();
1284
 
1285
- if (property_exists($productData, 'websites') === false && isset($DefaultStore)) {
1286
- $productData->websites = array($DefaultStore->getWebsiteId());
1287
- }
1288
 
1289
- if (property_exists($productData, 'category_ids') && !is_array($productData->category_ids)) {
1290
- if (is_string($productData->category_ids))
1291
- $productData->category_ids = array($productData->category_ids);
1292
- }
1293
- else if (property_exists($productData, 'category_ids') === false)
1294
- {
1295
- $productData->category_ids = array();
1296
- }
1297
 
1298
- $productData->categories = $productData->category_ids;
1299
 
1300
- $this->_updateQuantity($productData);
1301
 
1302
- $productData = $this->_fixAttributes($productData);
1303
 
1304
- $productAPI = new Mage_Catalog_Model_Product_Api_V2();
1305
 
1306
- return $productAPI->create($type, $set, $sku, $productData, $store);
1307
- }
1308
 
1309
- public function debugInfo()
1310
- {
1311
- $verInfo = Mage::getVersionInfo();
1312
 
1313
- $result = array(
1314
- 'llc_ver' => Settings::$VERSION,
1315
- 'magento_ver' => $verInfo
1316
- );
1317
 
1318
- return $result;
1319
- }
1320
  }
1321
 
1322
  class LinnLiveEnterprise extends LinnLiveMain{
1323
 
1324
- public function productAttributeOptions($setId)
1325
  {
1326
- $result = array();
1327
 
1328
- $setId = intval($setId);
1329
- if ($setId <= 0) return $result;
1330
 
1331
  $attributeAPI = Mage::getModel('catalog/product_attribute_api');
1332
 
1333
- $attributes = Mage::getModel('catalog/product')->getResource()
1334
- ->loadAllAttributes()
1335
- ->getSortedAttributes($setId);
1336
 
1337
- $i=0;
1338
 
1339
- foreach ($attributes as $attribute) {
1340
 
1341
  if ((!$attribute->getId() || $attribute->isInSet($setId))
1342
  && !in_array($attribute->getAttributeCode(), $this->_ignoredAttributes)
1343
- && in_array($attribute->getFrontendInput(), $this->_permittedAttributes)) {
1344
 
1345
  if (!$attribute->getId() || $attribute->isScopeGlobal()) {
1346
  $scope = 'global';
@@ -1359,64 +1356,64 @@ class LinnLiveEnterprise extends LinnLiveMain{
1359
  'can_config' => 0
1360
  );
1361
 
1362
- if ( ($attribute->getFrontendInput() == 'select') || ($attribute->getFrontendInput() == 'multiselect') ) {
1363
- if (($scope == 'global') &&
1364
- $attribute->getIsConfigurable())
1365
- {
1366
- if (strpos($attribute->getApplyTo(), 'simple') !== false)
1367
- $result[$i]['can_config'] = 1;
1368
- }
1369
-
1370
- $options = $attributeAPI->options($attribute->getId());
1371
-
1372
- // remove empty first element
1373
- if ($attribute->getFrontendInput() != 'boolean') {
1374
- array_shift($options);
1375
- }
1376
-
1377
- if (count($options) > 0) {
1378
- $result[$i]['attribute_options'] = $options;
1379
- }
1380
- }
1381
- $i++;
1382
  }
1383
  }
1384
 
1385
- return $result;
1386
  }
1387
 
1388
- //Fix for buggy associativeArray implementation
1389
- private function _fixAttributes($productData)
1390
- {
1391
- $_newAttributeOptions = $this->_newOptions($productData);
1392
- $_availableOptions = array();
1393
- if (count($_newAttributeOptions) > 0)
1394
- {
1395
- $_availableOptions = $this->_createOptions($_newAttributeOptions);
1396
- }
1397
-
1398
- if (property_exists($productData, 'additional_attributes')) {
1399
- $tmpAttr = $productData->additional_attributes;
1400
- if (count($tmpAttr) == 0)
1401
- {
1402
- unset($productData->additional_attributes);
1403
- return $productData;
1404
- }
1405
- $productData->additional_attributes = new stdClass();
1406
- $productData->additional_attributes->single_data = array();
1407
- $i=0;
1408
- if (is_array($tmpAttr))
1409
- {
1410
- foreach ($tmpAttr as $option) {
1411
- $productData->additional_attributes->single_data[$i] = new stdClass();
1412
- $productData->additional_attributes->single_data[$i]->key = $option->code;
1413
 
1414
  if ( ($option->type == 'multiselect') && (is_array($productData->additional_attributes->single_data[$i]->value) == false) )
1415
  {
1416
  $productData->additional_attributes->single_data[$i]->value = array();
1417
  }
1418
 
1419
- if (isset($_availableOptions[$option->attribute_id][strtolower($option->label)]))
1420
  {
1421
  if ($option->type == 'multiselect')
1422
  {
@@ -1427,7 +1424,7 @@ class LinnLiveEnterprise extends LinnLiveMain{
1427
  $productData->additional_attributes->single_data[$i]->value = $_availableOptions[$option->attribute_id][strtolower($option->label)];
1428
  }
1429
  }
1430
- else
1431
  {
1432
  if ($option->type == 'multiselect')
1433
  {
@@ -1438,22 +1435,22 @@ class LinnLiveEnterprise extends LinnLiveMain{
1438
  $productData->additional_attributes->single_data[$i]->value = $option->value;
1439
  }
1440
  }
1441
- $i++;
1442
- }
1443
- }
1444
- else
1445
- {
1446
- $productData->additional_attributes->single_data[0] = new stdClass();
1447
- $productData->additional_attributes->single_data[0]->key = $tmpAttr->code;
1448
- if (isset($_availableOptions[$tmpAttr->attribute_id][strtolower($tmpAttr->label)]))
1449
- $productData->additional_attributes->single_data[0]->value = $_availableOptions[$tmpAttr->attribute_id][strtolower($tmpAttr->label)];
1450
- else
1451
- $productData->additional_attributes->single_data[0]->value = $tmpAttr->value;
1452
- }
1453
- }
1454
-
1455
- return $productData;
1456
- }
1457
  }
1458
 
1459
  class LinnLiveCommunity extends LinnLiveMain{
1
  <?php
2
  class Settings {
3
+ const VERSION = 43;
4
  }
5
 
6
  class LinnSystems_LinnLiveConnect_Model_Api_V2{
7
 
8
+ public function configurableProduct($version, $set, $sku, $reindex, $productData, $productsSet, $attributesSet, $store=null)
9
  {
10
  $worker = Factory::createWorker($version);
11
  return $worker->configurableProduct($set, $sku, $reindex, $productData, $productsSet, $attributesSet, $store);
12
  }
13
 
14
+ public function updateConfigurableProduct($version, $productId, $reindex, $productData, $productsSet, $attributesSet, $store=null, $identifierType='id')
15
  {
16
  $worker = Factory::createWorker($version);
17
  return $worker->updateConfigurableProduct($productId, $reindex, $productData, $productsSet, $attributesSet, $store, $identifierType);
23
  return $worker->storesList();
24
  }
25
 
26
+ public function getStoreCode($version, $store=null)
27
  {
28
  $worker = Factory::createWorker($version);
29
  return $worker->getStoreCode($store);
30
  }
31
 
32
+ public function deleteAssigned($version, $productId, $store=null, $identifierType='id')
33
  {
34
  $worker = Factory::createWorker($version);
35
  return $worker->deleteAssigned($productId, $store, $identifierType);
36
  }
37
 
38
+ public function assignImages($version, $productImages)
39
  {
40
  $worker = Factory::createWorker($version);
41
  return $worker->assignImages($productImages);
42
  }
43
 
44
+ public function productList($version, $page, $perPage, $filters = null, $store = null)
45
  {
46
  $worker = Factory::createWorker($version);
47
  return $worker->productList($page, $perPage, $filters, $store);
48
  }
49
 
50
+ public function productAttributeOptions($version, $setId)
51
  {
52
  $worker = Factory::createWorker($version);
53
  return $worker->productAttributeOptions($setId);
54
  }
55
 
56
+ public function update($version, $productId, $productData, $store = null, $identifierType = 'id')
57
+ {
58
  $worker = Factory::createWorker($version);
59
  return $worker->update($productId, $productData, $store, $identifierType);
60
+ }
61
 
62
+ public function create($version, $type, $set, $sku, $productData, $store = null)
63
+ {
64
  $worker = Factory::createWorker($version);
65
  return $worker->create($type, $set, $sku, $productData, $store);
66
+ }
67
 
68
+ public function debugInfo()
69
+ {
70
  $worker = Factory::createWorker(Settings::$VERSION);
71
  return $worker->debugInfo();
72
+ }
73
  }
74
 
75
  class Factory{
76
 
77
+ private static function _checkVersion($version)
78
  {
79
  $version = intval($version);
80
 
81
+ if ($version == 0) throw new Mage_Api_Exception('version_not_specified');
82
+ if (Settings::VERSION < $version ) throw new Mage_Api_Exception('wrong_version');
 
 
83
  }
84
 
 
85
  public static function createWorker($version)
86
  {
87
+ self::_checkVersion($version);
88
 
89
  if(Mage::GetEdition() == Mage::EDITION_COMMUNITY)
90
  {
91
+ return new LinnLiveCommunity();
92
  }
93
+ else if (Mage::GetEdition() == Mage::EDITION_ENTERPRISE)
94
  {
95
+ return new LinnLiveEnterprise();
96
  }
97
  else
98
  {
105
  class LinnLiveMain extends Mage_Core_Model_Abstract{
106
 
107
 
108
+ private $_ignoredAttributes = array(
109
+ 'created_at',
110
+ 'updated_at',
111
+ 'category_ids',
112
+ 'required_options',
113
+ 'old_id',
114
+ 'url_key',
115
+ 'url_path',
116
+ 'has_options',
117
+ 'image_label',
118
+ 'small_image_label',
119
+ 'thumbnail_label',
120
+ 'image',
121
+ 'small_image',
122
+ 'thumbnail',
123
+ 'options_container',
124
+ 'entity_id',
125
+ 'entity_type_id',
126
+ 'attribute_set_id',
127
+ 'type_id',
128
+ 'sku',
129
+ 'name',
130
+ 'status',
131
+ 'stock_item',
132
+ 'description',
133
+ );
134
 
135
  private $_permittedAttributes = array (
136
+ 'select',
137
  'multiselect',
138
  'text',
139
+ 'textarea',
140
+ 'date',
141
+ 'price'
142
  );
143
 
144
  private function _prepareConfigurableData(
145
+ & $store, & $productData, & $assignedProductsArray,
146
+ & $attributesSetArray, $productsSet, $attributesSet)
147
+ {
148
+ $store = $this->_currentStoreCode($store);
149
+
150
+ $this->_updateConfigurableQuantity($productData);
151
+
152
+ $productData = $this->_fixAttributes($productData);
153
+
154
+ if (!is_array($attributesSet))
155
+ {
156
+ $tmpSet = $attributesSet;
157
+ $attributesSet = array();
158
+ $attributesSet[] = $tmpSet;
159
+ }
160
+
161
+ $assignedProductsData = $this->_createProductsData($productsSet);
162
+ $assignedProductsArray = $this->_objectToArray($assignedProductsData);
163
+
164
+ $_newAttributeOptions = $this->_newConfigurableOptions($assignedProductsArray);
165
+ if (count($_newAttributeOptions) > 0)
166
+ {
167
+ $_availableOptions = $this->_createOptions($_newAttributeOptions);
168
+ $this->_checkAssignedProductsOptions($_availableOptions, $assignedProductsArray);
169
+ }
170
+
171
+ $attributesSetArray = $this->_objectToArray($attributesSet);
172
+ $attributesSetArray = $this->_prepareAttributesData($attributesSetArray, $assignedProductsArray);
173
+
174
+ foreach($attributesSetArray as $key=>$value)
175
+ {
176
+ $attributesSetArray[$key]["id"] = NULL;
177
+ $attributesSetArray[$key]["position"] = NULL;
178
+
179
+ }
180
+
181
+ }
182
+
183
+ private function _checkAssignedProductsOptions($availableOptions, & $assignedProductsArray)
184
+ {
185
+ foreach ($assignedProductsArray as $id => $productOptions)
186
+ {
187
+ foreach($productOptions as $index => $option)
188
+ {
189
+ if (isset($availableOptions[$option['attribute_id']][strtolower($option['label'])]))
190
+ {
191
+ $assignedProductsArray[$id][$index]['value_index'] = $availableOptions[$option['attribute_id']][strtolower($option['label'])];
192
+ }
193
+ }
194
+ }
195
+ }
196
+
197
+ private function _createOptions($newOptions)
198
+ {
199
+ $installer = new Mage_Eav_Model_Entity_Setup('core_setup');
200
+ $attributeApi = Mage::getModel('catalog/product_attribute_api');
201
+ $helperCatalog = Mage::helper('catalog');
202
+
203
+ $installer->startSetup();
204
+
205
+ $attributesList = array();
206
+
207
+ foreach($newOptions as $attribute_id=>$options)
208
+ {
209
+ $aOption = array();
210
+ $aOption['attribute_id'] = $attribute_id;
211
+ $attributesList[] = $attribute_id;
212
+
213
+ $i=0;
214
+ foreach($options as $option)
215
+ {
216
+ $optionTitle = $helperCatalog->stripTags($option);
217
+
218
+ $aOption['value']['option'.$i][0] = $optionTitle;
219
+ $i++;
220
+ }
221
+ $installer->addAttributeOption($aOption);
222
+ }
223
+ $installer->endSetup();
224
+
225
+ Mage::app()->cleanCache(array(Mage_Core_Model_Translate::CACHE_TAG));
226
+
227
+
228
+ $currentOptions = array();
229
+ $attributeApi = Mage::getModel('catalog/product_attribute_api');
230
+ foreach($attributesList as $attribute_id)
231
+ {
232
+ if (!isset($currentOptions[$attribute_id]))
233
+ $currentOptions[$attribute_id] = array();
234
+
235
+ $attributeOptions = $attributeApi->options($attribute_id);
236
+
237
+ foreach ($attributeOptions as $opts)
238
+ {
239
+ $label = strtolower($opts['label']);
240
+ $optionId = $opts['value'];
241
+ if (!isset($currentOptions[$attribute_id][$label]))
242
+ $currentOptions[$attribute_id][$label] = $optionId;
243
+ else {
244
+ $oldId = $currentOptions[$attribute_id][$label];
245
+ if ($oldId > $optionId)
246
+ {
247
+ $attributeApi->removeOption($attribute_id, $oldId);
248
+ $currentOptions[$attribute_id][$label] = $optionId;
249
+ }
250
+ else
251
+ {
252
+ $attributeApi->removeOption($attribute_id, $optionId);
253
+ }
254
+ }
255
+ }
256
+ }
257
+
258
+ return $currentOptions;
259
+ }
260
+
261
+ private function _newConfigurableOptions($assignedProductsArray)
262
+ {
263
+ $_attributesOptions = array();
264
+ foreach ($assignedProductsArray as $id => $productOptions)
265
+ {
266
+ foreach($productOptions as $option)
267
+ {
268
+ if (isset($option['value_index']) && $option['value_index'] == '-1')
269
+ {
270
+ if (isset($_attributesOptions[$option['attribute_id']]))
271
+ {
272
+ $_attributesOptions[$option['attribute_id']][] = $option['label'];
273
+ }
274
+ else
275
+ {
276
+ $_attributesOptions[$option['attribute_id']] = array($option['label']);
277
+ }
278
+ }
279
+ }
280
+ }
281
+ return $_attributesOptions;
282
+ }
283
+
284
+ private function _newOptions($productData)
285
+ {
286
+ $_attributesOptions = array();
287
+
288
+ if (property_exists($productData, 'additional_attributes')) {
289
+ $_attributes = $productData->additional_attributes;
290
+ if (is_array($_attributes)) {
291
+ foreach($_attributes as $_attribute) {
292
+ if (($_attribute->type == 'select' || $_attribute->type == 'multiselect') && $_attribute->value == "-1")
293
+ {
294
+ if (isset($_attributesOptions[$_attribute->attribute_id]))
295
+ {
296
+ $_attributesOptions[$_attribute->attribute_id][] = $_attribute->label;
297
+ }
298
+ else
299
+ {
300
+ $_attributesOptions[$_attribute->attribute_id] = array($_attribute->label);
301
+ }
302
+ }
303
+ }
304
+ }
305
+ else
306
+ {
307
+ if (($_attributes->type == 'select' || $_attributes->type == 'multiselect') && $_attributes->value == "-1")
308
+ {
309
+ if (isset($_attributesOptions[$_attributes->attribute_id]))
310
+ {
311
+ $_attributesOptions[$_attributes->attribute_id][] = $_attributes->label;
312
+ }
313
+ else
314
+ {
315
+ $_attributesOptions[$_attributes->attribute_id] = array($_attributes->label);
316
+ }
317
+ }
318
+ }
319
+
320
+ }
321
+
322
+ return $_attributesOptions;
323
+ }
324
+
325
+ private function _containsOption($attributeOption, $option)
326
+ {
327
+ foreach ($attributeOption as $inArrayOption)
328
+ if ($inArrayOption['value_index'] == $option['value_index']) return true;
329
+
330
+ return false;
331
+ }
332
+
333
+ private function _prepareAttributesData($attributesSetArray, $assignedProductsArray)
334
+ {
335
+ $_attributesOptions = array();
336
+ foreach ($assignedProductsArray as $id => $productOptions)
337
+ {
338
+ foreach($productOptions as $option)
339
+ {
340
+ if (isset($_attributesOptions[$option['attribute_id']]) &&
341
+ !$this->_containsOption($_attributesOptions[$option['attribute_id']], $option))
342
+ {
343
+ $_attributesOptions[$option['attribute_id']][] = $option;
344
+ }
345
+ else if (!isset($_attributesOptions[$option['attribute_id']]))
346
+ {
347
+ $_attributesOptions[$option['attribute_id']] = array();
348
+ $_attributesOptions[$option['attribute_id']][] = $option;
349
+ }
350
+ }
351
+ }
352
+
353
+ foreach($attributesSetArray as $key => $attribute)
354
+ {
355
+ if (isset($_attributesOptions[$attribute['attribute_id']]))
356
+ $attributesSetArray[$key]['values'] = $_attributesOptions[$attribute['attribute_id']];
357
+ }
358
+
359
+ return $attributesSetArray;
360
+ }
361
+
362
+ private function _updateConfigurable($store, $productId, $productData, $assignedProducts, $assignedAttributes, $identifierType, $isUpdate=false, $reindex=true)
363
+ {
364
+ $magentoVer = $this->_getCurrentVersion();
365
+ if ($magentoVer == 162)
366
+ {
367
+ $store = Mage::app()->getStore($store)->getId();
368
+ }
369
+
370
+ $product = Mage::helper('catalog/product')->getProduct($productId, $store, $identifierType);
371
+
372
+ $product->setConfigurableProductsData($assignedProducts);
373
+ if (!$isUpdate)
374
+ $product->setConfigurableAttributesData($assignedAttributes);
375
+ $product->setCanSaveConfigurableAttributes(true);
376
+
377
+ try {
378
+ $result = $product->save();
379
+ }
380
+ catch (Exception $e){
381
+ throw new Mage_Api_Exception('configurable_creating_error', $e->getMessage());
382
+ }
383
+
384
+ if ($reindex === true)
385
+ {
386
+ try {
387
+ $indexer = Mage::getSingleton('index/indexer');
388
+ $process = $indexer->getProcessByCode('catalog_product_price');
389
+ $process->reindexEverything();
390
+ }
391
  catch (Mage_Core_Exception $e) {
392
+ throw new Mage_Api_Exception('configurable_creating_error', $e->getMessage());
393
+ }
394
+ }
395
+
396
+ return $result;
397
+ }
398
+
399
+ private function _createProductsData($productData)
400
+ {
401
+ $assignedProductsData = array();
402
+
403
+ if (is_array($productData))
404
+ {
405
+ foreach ($productData as $product)
406
+ {
407
+ $assignedProductsData[$product->product_id] = array();
408
+ $this->_fillAssignedProductValues($product, $assignedProductsData);
409
+ }
410
+ }
411
+ else
412
+ {
413
+ $assignedProductsData[$productData->product_id] = array();
414
+ $this->_fillAssignedProductValues($product, $assignedProductsData);
415
+ }
416
+
417
+
418
+ return $assignedProductsData;
419
+ }
420
+
421
+ private function _fillAssignedProductValues(& $product, & $assignedProductsData)
422
+ {
423
+ if (is_array($product->values))
424
+ {
425
+ foreach ($product->values as $productValue)
426
+ {
427
+ $assignedProductsData[$product->product_id][] = $productValue;
428
+ }
429
+ }
430
+ else
431
+ {
432
+ $assignedProductsData[$product->product_id][] = $product->values;
433
+ }
434
+ }
435
+
436
+ private function _updateConfigurableQuantity( & $productData)
437
+ {
438
+ $this->_updateQuantity($productData);
439
+
440
+ if (!property_exists($productData, 'stock_data'))
441
+ {
442
+ $productData->stock_data = new stdClass();
443
+ }
444
 
445
  $productData->stock_data->manage_stock = 1;
446
  $productData->stock_data->is_in_stock = 1;
447
+ }
448
 
449
+ private function _updateQuantity( & $productData)
450
+ {
451
+ if (property_exists($productData, 'stock_data') && property_exists($productData->stock_data, 'qty')) {
452
+ $productData->stock_data->qty = intval($productData->stock_data->qty);
453
  $productData->stock_data->is_in_stock = 1;
454
+ $productData->stock_data->manage_stock = 1;
455
+ }
456
+ }
457
 
458
+ private function _objectToArray( $result )
459
  {
460
  $array = array();
461
+ foreach ($result as $key=>$value)
462
+ {
463
+ if (is_object($value) || is_array($value))
464
+ {
465
+ $array[$key]=$this->_objectToArray($value);
466
+ }
467
+ else
468
+ {
469
+ $array[$key]=$value;
470
+ }
471
+ }
472
+ return $array;
473
  }
474
 
475
  private function _getCurrentVersion()
476
+ {
477
+ $verInfo = Mage::getVersionInfo();
478
+
479
+ return intval($verInfo['major'].$verInfo['minor'].$verInfo['revision']);
480
+ }
481
+
482
+ private function _productImages($attributesList)
483
+ {
484
+ $_images = array();
485
+
486
+ if (is_array($attributesList) && count($attributesList) > 0 && isset($attributesList['media_gallery']))
487
+ {
488
+ $small = empty($attributesList['small_image']) ? false : $attributesList['small_image'];
489
+ $base = empty($attributesList['image']) ? false : $attributesList['image'];
490
+ $thumb = empty($attributesList['thumbnail']) ? false : $attributesList['thumbnail'];
491
+
492
+ foreach($attributesList['media_gallery']['images'] as $key=>$value)
493
+ {
494
+ $newImage = array();
495
+ $newImage['file'] = $value['file'];
496
+ $newImage['label'] = $value['label'];
497
+ $newImage['disabled'] = $value['disabled'] ? true : false;
498
+
499
+ $newImage['small_image'] = $small == $newImage['file'];
500
+ $newImage['image'] = $base == $newImage['file'];
501
+ $newImage['thumbnail'] = $thumb == $newImage['file'];
502
+
503
+ $_images[] = $newImage;
504
+ }
505
+ }
506
+
507
+ return $_images;
508
+ }
509
+
510
+ private function _removeIgnoredAttributes($attributesList)
511
+ {
512
+ $_preparedAttributes = array();
513
+ if (is_array($attributesList) && count($attributesList) > 0)
514
+ {
515
+ foreach($attributesList as $key=>$value)
516
+ {
517
+ if (!in_array($key, $this->_ignoredAttributes) && !is_array($value))
518
+ $_preparedAttributes[]= array('key' => $key, 'value' => $value);
519
+ }
520
+ }
521
+
522
+ return $_preparedAttributes;
523
+ }
524
+
525
+ private function _currentStoreCode($store=null)
526
+ {
527
+ if ($store != null)
528
+ return $store;
529
+
530
+ return $this->_getStore()->getCode();
531
+ }
532
+
533
+ private function _getProductBySku($sku)
534
+ {
535
  if($sku){
536
  $product = Mage::getModel('catalog/product');
537
  $productId = $product->getIdBySku((string)$sku);
543
  }
544
  }
545
  }
546
+
547
+ private function _getStore($storeCode=null)
548
+ {
549
+ if (Mage::app()->isSingleStoreMode()) {
550
  return Mage::app()->getWebsite(true)->getDefaultStore();
551
  }
552
 
553
+ $mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : '';
554
+ $mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store';
555
 
556
+ if ($storeCode != null)
557
+ return Mage::getModel('core/store')->load( $storeCode, 'code');
558
 
559
+ if ($mageRunType == 'store') {
560
+ if (!empty($mageRunCode))
561
+ {
562
+ return Mage::getModel('core/store')->load( $mageRunCode, 'code');
563
+ }
564
+ }
565
+ else {
566
+ if ($mageRunType == 'website')
567
+ $websiteCode = empty($mageRunCode) ? '' : $mageRunCode;
568
+ else
569
+ $websiteCode = empty($mageRunType) ? '' : $mageRunType;
570
 
571
+ if (!empty($websiteCode))
572
+ {
573
+ $currentWebSite = Mage::getModel('core/website')->load( $websiteCode, 'code');
574
+ $defaultStore = $currentWebSite->getDefaultStore();
575
+ if (isset($defaultStore))
576
+ return $defaultStore;
577
+ }
578
+ }
579
 
580
 
581
+ return Mage::app()->getWebsite(true)->getDefaultStore();//Mage::app()->getStore();
582
+ }
583
 
584
+ private function _getWebsiteId($store=null)
585
  {
586
+ return array($this->_getStore($store)->getWebsiteId());
587
  }
588
 
589
+ private function _productAttributeInfo($attribute_id, $attributeAPI)
590
+ {
591
+ $model = Mage::getResourceModel('catalog/eav_attribute')
592
  ->setEntityTypeId(Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId());
593
 
594
  $model->load($attribute_id);
595
 
596
  if (!$model->getId()) {
597
+ throw new Mage_Api_Exception('attribute_not_exists');
598
  }
599
 
600
  if ($model->isScopeGlobal()) {
635
  }
636
 
637
  return $result;
638
+ }
639
+
640
+ //Fix for buggy associativeArray implementation
641
+ private function _fixAttributes($productData)
642
+ {
643
+ $_newAttributeOptions = $this->_newOptions($productData);
644
+ $_availableOptions = array();
645
+ if (count($_newAttributeOptions) > 0)
646
+ {
647
+ $_availableOptions = $this->_createOptions($_newAttributeOptions);
648
+ }
649
+
650
+ if (property_exists($productData, 'additional_attributes')) {
651
+ $tmpAttr = $productData->additional_attributes;
652
+ if (count($tmpAttr) == 0)
653
+ {
654
+ unset($productData->additional_attributes);
655
+ return $productData;
656
+ }
657
+
658
+ $i=0;
659
+ if (is_array($tmpAttr))
660
+ {
661
+ foreach ($tmpAttr as $option) {
662
+ $code = $option->code;
663
  if ( ($option->type == 'multiselect') && (is_array($productData->$code) == false) )
664
  {
665
  $productData->$code = array();
666
  }
667
+ if (isset($_availableOptions[$option->attribute_id][strtolower($option->label)]))
668
  {
669
  if ($option->type == 'multiselect')
670
  {
687
  }
688
  }
689
 
690
+ }
691
+ }
692
+ else
693
+ {
694
+ $code = $tmpAttr->code;
695
+ if (isset($_availableOptions[$tmpAttr->attribute_id][strtolower($tmpAttr->label)]))
696
+ $productData->$code = $_availableOptions[$tmpAttr->attribute_id][strtolower($tmpAttr->label)];
697
+ else
698
+ $productData->$code = $tmpAttr->value;
699
+ }
700
  }
701
 
702
+ unset($productData->additional_attributes);
703
 
704
+ return $productData;
705
+ }
706
 
707
 
708
 
711
  * Public functions(API)
712
  *
713
  */
714
+ public function configurableProduct($set, $sku, $reindex, $productData, $productsSet, $attributesSet, $store=null)
715
  {
716
+ if (!$set || !$sku) {
717
+ throw new Mage_Api_Exception('data_invalid');
718
  }
719
 
720
+ $this->_prepareConfigurableData($store, $productData, $assignedProductsArray,
721
+ $attributesSetArray, $productsSet, $attributesSet);
722
 
723
+ $DefaultStore = $this->_getStore();
724
 
725
+ if (property_exists($productData, 'websites') === false && isset($DefaultStore) ) {
726
+ $productData->websites = array($DefaultStore->getWebsiteId());
727
+ }
728
 
729
+ if (property_exists($productData, 'category_ids') && !is_array($productData->category_ids))
730
+ {
731
+ if (is_string($productData->category_ids)) {
732
+ $productData->category_ids = array($productData->category_ids);
733
+ }
734
+ }
735
+ else if (property_exists($productData, 'category_ids') === false)
736
+ {
737
+ $productData->category_ids = array();
738
+ }
739
 
740
+ $productData->categories = $productData->category_ids;
741
 
742
+ $productAPI = new Mage_Catalog_Model_Product_Api_V2();
743
+ $productId = $productAPI->create('configurable', $set, $sku, $productData, $store);
744
 
745
+ $this->_updateConfigurable($store, $productId, $productData, $assignedProductsArray, $attributesSetArray, 'id', false, $reindex);
746
 
747
+ return $productId;
748
  }
749
 
750
+ public function updateConfigurableProduct($productId, $reindex, $productData, $productsSet, $attributesSet, $store=null, $identifierType='id')
751
  {
752
 
753
 
754
+ $this->_prepareConfigurableData($store, $productData, $assignedProductsArray,
755
+ $attributesSetArray, $productsSet, $attributesSet);
756
 
757
+ try {
758
  $storeId = Mage::app()->getStore($store)->getId();
759
  }
760
  catch (Mage_Core_Model_Store_Exception $e) {
761
+ throw new Mage_Api_Exception('store_not_exists', null);
762
  }
763
  /*
764
+ if ($identifierType == 'id')
765
+ {
766
  $productId = intval($productId);
767
 
768
  if ($productId < 1) {
769
  throw new Mage_Api_Exception('product_not_exists', null);
770
  }
771
+ }*/
772
 
773
+ $_loadedProduct = Mage::helper('catalog/product')->getProduct($productId, $storeId, $identifierType);
774
 
775
+ if (!$_loadedProduct->getId())
776
+ {
777
  throw new Mage_Api_Exception('product_not_exists', null);
778
  }
779
 
780
+ $_categoryIds = $_loadedProduct->getCategoryIds();
781
+ if (property_exists($productData, 'category_ids'))
782
+ {
783
 
784
  if (!is_array($productData->category_ids))
785
  {
788
 
789
  $productData->category_ids = array_merge($_categoryIds, $productData->category_ids);
790
 
791
+ }
792
+ else
793
+ {
794
+ $productData->category_ids = $_categoryIds;
795
+ }
796
 
797
+ $productData->category_ids = array_unique($productData->category_ids);
798
 
799
+ if ( (property_exists($productData, 'removed_categories') === true)
800
+ && (is_array($productData->removed_categories) === true)
801
+ && (count($productData->removed_categories) > 0) )
802
+ {
803
+ $tmpCats = array();
804
 
805
+ $productData->category_ids = array_diff($productData->category_ids, $productData->removed_categories);
806
+ }
807
 
808
+ $productData->categories = $productData->category_ids;
809
 
810
+ if (property_exists($productData, 'add_to_websites') && $productData->add_to_websites === true)
811
+ {
812
+ $currentWebsites = $_loadedProduct->getWebsiteIds();
813
+ $websiteId = $this->_getWebsiteId();
814
+ $websiteId = $websiteId[0];
815
 
816
+ if (in_array($websiteId, $currentWebsites) === false)
817
+ {
818
+ $currentWebsites[] = $websiteId;
819
+ $productData->websites = $currentWebsites;
820
+ }
821
+ }
822
 
823
+ $productAPI = new Mage_Catalog_Model_Product_Api_V2();
824
 
825
+ $productAPI->update($productId, $productData, $store, $identifierType);
826
 
827
+ return $this->_updateConfigurable($store, $productId, $productData, $assignedProductsArray, $attributesSetArray, $identifierType, true, $reindex);
828
  }
829
 
830
  /*
832
  */
833
  public function storesList()
834
  {
835
+ return ($this->_getCurrentVersion() >= 160);
836
  }
837
 
838
+ public function getStoreCode($store=null)
839
  {
840
  return $this->_currentStoreCode($store);
841
  }
842
 
843
+ public function deleteAssigned($productId, $store=null, $identifierType='id')
844
  {
845
+ $store = $this->_currentStoreCode($store);
846
 
847
+ try {
848
  $storeId = Mage::app()->getStore($store)->getId();
849
  }
850
  catch (Mage_Core_Model_Store_Exception $e) {
851
+ throw new Mage_Api_Exception('store_not_exists', null);
852
  }
853
 
854
+ $_loadedProduct = Mage::helper('catalog/product')->getProduct($productId, $storeId, $identifierType);
855
 
856
+ if (!$_loadedProduct->getId())
857
+ {
858
  throw new Mage_Api_Exception('product_not_exists', null);
859
  }
860
 
861
 
862
+ $currentWebsites = $_loadedProduct->getWebsiteIds();
863
+ $websiteId = $this->_getWebsiteId($store);
864
+ $websiteId = $websiteId[0];
865
 
866
+ $newWebsiteIds = array();
867
 
868
+ if (in_array($websiteId, $currentWebsites) === true)
869
+ {
870
+ for($i = 0; $i < count($currentWebsites); $i++)
871
+ {
872
+ if ($currentWebsites[$i] != $websiteId)
873
+ {
874
+ $newWebsiteIds[] = $currentWebsites[$i];
875
+ }
876
+ }
877
 
878
+ $_loadedProduct->setWebsiteIds($newWebsiteIds);
879
 
880
+ $_loadedProduct->save();
881
+ }
882
 
883
+ return true;
884
  }
885
 
886
 
887
+ public function assignImages($productImages)
888
  {
889
+ $store = $this->_currentStoreCode(null);
890
 
891
+ foreach($productImages as $imageData)
892
+ {
893
+ $productId = intval($imageData->product_id);
894
+ if ($productId < 1) {
895
+ throw new Mage_Api_Exception('product_not_exists', null);
896
+ }
897
 
898
+ $product = Mage::helper('catalog/product')->getProduct($productId, $store, 'id');
899
 
900
+ $images = $imageData->images;
901
 
902
  $baseImageExist = false;
903
  foreach($images as $image)
915
 
916
  reset($images);
917
 
918
+ foreach($images as $image)
919
+ {
920
+ $catalogProductDir = Mage::getBaseDir('media') . DS . 'catalog/product';
921
+ $filePath = $catalogProductDir.$image->image_name;
922
 
923
+ if (is_array($image->types) && count($image->types) > 0)
924
+ {
925
+ $imageTypes = $image->types;
926
+ }
927
+ else
928
+ {
929
+ $imageTypes = "";
930
+ }
931
 
932
+ try
933
+ {
934
+ $product->addImageToMediaGallery($filePath, $imageTypes, false, false);
935
+ }
936
+ catch (Exception $e) { }
937
 
938
+ }
939
 
940
+ $product->save();
941
+ }
942
 
943
+ return true;
944
  }
945
 
946
+ /*
947
  * Implementation of catalogProductList because of bug in associativeArray.
948
  * Extended to filter by category id too.
949
  *
950
  * Use 'entity_id' for product_id,
951
  * 'type_id' instead of product type.
952
  */
953
+ public function productList($page, $perPage, $filters = null, $store = null)
954
  {
955
  $arrayParams = array(
956
+ 'nin',
957
+ 'in',
958
+ );
959
 
960
+ $store = $this->_currentStoreCode($store);
961
 
962
+ try {
963
  $storeId = Mage::app()->getStore($store)->getId();
964
  }
965
  catch (Mage_Core_Model_Store_Exception $e) {
966
+ throw new Mage_Api_Exception('store_not_exists', null);
967
  }
968
 
969
  $preparedFilters = array();
973
  }
974
  }
975
  if (isset($filters->complex_filter)) {
976
+ foreach ($filters->complex_filter as $_key => $_filter) {
977
+ $_op = $_filter->key;
978
  $_filterVal = $_filter->value->value;
979
  $_filterKey = $_filter->value->key;
980
 
981
+ if (in_array($_op, $arrayParams)) {
982
+ $values = explode(',', $_filterVal);
983
+ }
984
+ else {
985
+ $values = $_filterVal;
986
+ }
987
 
988
  $preparedFilters[$_op] = array(
989
  $_filterKey => $values
990
  );
991
+ }
992
+ }
993
 
994
+ if (isset($preparedFilters['category']) &&
995
+ is_string($preparedFilters['category']))
996
  {
997
+ $_categoryId = intval($preparedFilters['category']);
998
+ unset($preparedFilters['category']);
999
+ }
1000
+ else {
1001
+ $_categoryId = 0;
1002
+ }
1003
 
1004
  if (!empty($preparedFilters)) {
1005
+ if ($_categoryId > 0)
1006
+ {
1007
  $_category = Mage::getModel('catalog/category')->load($_categoryId);
 
 
 
 
 
 
1008
  $collection = Mage::getModel('catalog/product')->getCollection()
1009
+ ->addStoreFilter($storeId)
1010
+ ->addCategoryFilter($_category);
1011
+ }
1012
+ else
1013
+ {
1014
+ $collection = Mage::getModel('catalog/product')->getCollection()
1015
+ ->addStoreFilter($storeId);
1016
+ }
1017
 
1018
  try {
1019
  foreach ($preparedFilters as $field => $value) {
1021
  }
1022
  }
1023
  catch (Mage_Core_Exception $e) {
1024
+ throw new Mage_Api_Exception('filters_invalid', $e->getMessage());
1025
  }
1026
  }
1027
 
1028
+ if ($page == 1)
1029
+ {
1030
+ $count = $collection->count();
1031
+ }
1032
+ else
1033
+ {
1034
+ $collection->setPageSize($perPage)
1035
+ ->setCurPage($page);
1036
+ $count = 0;
1037
+ }
1038
 
1039
  $result = array();
1040
+ $result['count'] = $count;
1041
+ $result['products'] = array();
1042
 
1043
  $_assignedIds = array();
1044
+ $_fetchedIds = array();
1045
 
1046
+ $i = 0;
1047
  foreach ($collection as $_product) {
1048
+ if ($i >= ($perPage * $page)) break;
1049
+ $_loadedProduct = Mage::helper('catalog/product')->getProduct($_product->getId(), $storeId, 'id');
1050
 
1051
+ $_allAttributes = $_loadedProduct->getData();
1052
 
1053
 
1054
+ $_description = isset($_allAttributes['description']) ? $_allAttributes['description'] : '';
1055
 
1056
+ $_productImages = $this->_productImages($_allAttributes);
1057
+ $_productAttributes = $this->_removeIgnoredAttributes($_allAttributes);
1058
 
1059
+ $_fetchedIds[] = $_loadedProduct->getId();
1060
 
1061
  $result['products'][$i] = array(
1062
  'product_id' => $_loadedProduct->getId(),
1074
  'images' => $_productImages,
1075
  'attributes' => $_productAttributes,
1076
  );
1077
+ if($_loadedProduct->getTypeId() == "configurable")
1078
+ {
1079
+ $_typeInstance = $_loadedProduct->getTypeInstance();
1080
+ $result['products'][$i]['assigned_ids'] = $_typeInstance->getUsedProductIds();
1081
+ foreach($_typeInstance->getConfigurableAttributes() as $attribute){
1082
+ $_prices = array();
1083
+ foreach($attribute->getPrices() as $price)
1084
+ {
1085
+ $_prices[] = array(
1086
+ 'value_index' => $price['value_index'],
1087
+ 'is_fixed' => !$price['is_percent'],
1088
+ 'price_diff' => $price['pricing_value'],
1089
+ 'label' => $price['label'],
1090
+ );
1091
+
1092
+ }
1093
+
1094
+ $result['products'][$i]['conf_attrib_ids'][] = array(
1095
+ 'code' => $attribute->getProductAttribute()->getAttributeCode(),
1096
+ 'prices' => $_prices
1097
+ );
1098
+ }
1099
+ $_assignedIds = array_merge($_assignedIds, $result['products'][$i]['assigned_ids']);
1100
+ }
1101
+
1102
+ $i++;
1103
+ }
1104
+
1105
+ $_absentIds = array_diff($_assignedIds, $_fetchedIds);
1106
+
1107
+ if (count($_absentIds) > 0)
1108
+ {
1109
+ $collection = Mage::getModel('catalog/product')->getCollection()->addIdFilter($_absentIds);
1110
+
1111
+ foreach ($collection as $_product) {
1112
+ $_loadedProduct = Mage::helper('catalog/product')->getProduct($_product->getId(), $storeId, 'id');
1113
+
1114
+ $_allAttributes = $_product->getData();
1115
+
1116
+ $_description = isset($_allAttributes['description']) ? $_allAttributes['description'] : '';
1117
+
1118
+ $_productImages = $this->_productImages($_allAttributes);
1119
+ $_productAttributes = $this->_removeIgnoredAttributes($_allAttributes);
1120
+
1121
+ $result['products'][] = array(
1122
+ 'product_id' => $_loadedProduct->getId(),
1123
+ 'sku' => $_loadedProduct->getSku(),
1124
+ 'name' => $_loadedProduct->GetName(),
1125
+ 'set' => $_loadedProduct->getAttributeSetId(),
1126
+ 'type' => $_loadedProduct->getTypeId(),
1127
+ 'price' => $_loadedProduct->getPrice(),
1128
+ 'status' => $_loadedProduct->getStatus(),
1129
+ 'description' => $_description,
1130
+ 'category_ids' => $_loadedProduct->getCategoryIds(),
1131
+ 'website_ids' => $_loadedProduct->getWebsiteIds(),
1132
+ 'assigned_ids' => array(),
1133
+ 'conf_attrib_ids' => array(),
1134
+ 'images' => $_productImages,
1135
+ 'attributes' => $this->_removeIgnoredAttributes($_loadedProduct->getData()),
1136
  );
1137
+ }
1138
+ }
1139
 
1140
  return $result;
1141
  }
1142
 
1143
+ public function productAttributeOptions($setId)
1144
  {
1145
+ $result = array();
1146
 
1147
+ $setId = intval($setId);
1148
+ if ($setId <= 0) return $result;
1149
 
1150
  $attributeAPI = Mage::getModel('catalog/product_attribute_api');
1151
 
1152
+ $items = $attributeAPI->items($setId);
1153
+
1154
+ $attributes = Mage::getModel('catalog/product')->getResource()
1155
+ ->loadAllAttributes();
1156
+
1157
+ $i=0;
1158
+ foreach ($items as $item) {
1159
+ if (!isset($item['attribute_id']) || empty($item['attribute_id'])) continue;
1160
+ $attributeId = intval($item['attribute_id']);
1161
+ if ($attributeId <= 0) continue;
1162
+
1163
+ $additionInfo = $this->_productAttributeInfo($attributeId, $attributeAPI);
1164
+
1165
+ if (in_array($additionInfo['frontend_input'], $this->_permittedAttributes) &&
1166
+ !in_array($additionInfo['attribute_code'], $this->_ignoredAttributes))
1167
+ {
1168
+ $result[$i] = array(
1169
+ 'attribute_id' => $additionInfo['attribute_id'],
1170
+ 'code' => $additionInfo['attribute_code'],
1171
+ 'type' => $additionInfo['frontend_input'],
1172
+ 'required' => $additionInfo['is_required'],
1173
+ 'scope' => $additionInfo['scope'],
1174
+ 'can_config' => 0
1175
+ );
1176
+
1177
+ if ( ($additionInfo['frontend_input'] == 'select') || ($additionInfo['frontend_input'] == 'multiselect') ) {
1178
+ if (($additionInfo['scope'] == 'global') &&
1179
+ ($additionInfo['is_configurable']))
1180
+ {
1181
+ foreach ($additionInfo['apply_to'] as $applyTo)
1182
+ {
1183
+ if ($applyTo == 'simple')
1184
+ {
1185
+ $result[$i]['can_config'] = 1;
1186
+ break;
1187
+ }
1188
+ }
1189
+
1190
+ }
1191
+ if (isset($additionInfo['options']))
1192
+ $result[$i]['attribute_options'] = $additionInfo['options'];
1193
+ }
1194
+ $i++;
1195
+ }
1196
+ }
1197
+
1198
+ return $result;
1199
  }
1200
 
1201
+ public function update($productId, $productData, $store = null, $identifierType = 'id')
1202
+ {
1203
+ $store = $this->_currentStoreCode($store);
1204
+ try {
1205
  $storeId = Mage::app()->getStore($store)->getId();
1206
  }
1207
  catch (Mage_Core_Model_Store_Exception $e) {
1208
+ throw new Mage_Api_Exception('store_not_exists', null);
1209
  }
1210
 
1211
  $_loadedProduct = Mage::helper('catalog/product')->getProduct($productId, $storeId, $identifierType);
1216
  }
1217
 
1218
 
1219
+ $_categoryIds = $_loadedProduct->getCategoryIds();
1220
+ if (property_exists($productData, 'category_ids'))
1221
+ {
1222
  if (!is_array($productData->category_ids))
1223
  {
1224
  $productData->category_ids = array($productData->category_ids);
1225
  }
1226
 
1227
  $productData->category_ids = array_merge($_categoryIds, $productData->category_ids);
1228
+ }
1229
+ else
1230
+ {
1231
+ $productData->category_ids = $_categoryIds;
1232
+ }
1233
 
1234
+ $productData->category_ids = array_unique($productData->category_ids);
1235
 
1236
+ if ( (property_exists($productData, 'removed_categories') === true)
1237
+ && (is_array($productData->removed_categories) === true)
1238
+ && (count($productData->removed_categories) > 0) )
1239
+ {
1240
+ $tmpCats = array();
1241
 
1242
+ $productData->category_ids = array_diff($productData->category_ids, $productData->removed_categories);
1243
+ }
1244
 
1245
+ $productData->categories = $productData->category_ids;
1246
 
1247
+ if (property_exists($productData, 'add_to_websites') && $productData->add_to_websites === true)
1248
+ {
1249
+ $currentWebsites = $_loadedProduct->getWebsiteIds();
1250
+ $websiteId = $this->_getWebsiteId();
1251
+ $websiteId = $websiteId[0];
1252
 
1253
+ if (in_array($websiteId, $currentWebsites) === false)
1254
+ {
1255
+ $currentWebsites[] = $websiteId;
1256
+ $productData->websites = $currentWebsites;
1257
+ }
1258
+ }
1259
 
1260
+ $this->_updateQuantity($productData);
1261
 
1262
+ $productData = $this->_fixAttributes($productData);
1263
 
1264
+ $productAPI = new Mage_Catalog_Model_Product_Api_V2();
1265
 
1266
+ $result = $productAPI->update($productId, $productData, $store, $identifierType);
1267
 
1268
+ return $result;
1269
+ }
1270
 
1271
+ public function create($type, $set, $sku, $productData, $store = null)
1272
+ {
1273
  $product = $this->_getProductBySku($sku);
1274
  if($product){
1275
  return $product->getId();
1276
  }
1277
 
1278
+ $store = $this->_currentStoreCode($store);
1279
 
1280
+ $DefaultStore = $this->_getStore();
1281
 
1282
+ if (property_exists($productData, 'websites') === false && isset($DefaultStore)) {
1283
+ $productData->websites = array($DefaultStore->getWebsiteId());
1284
+ }
1285
 
1286
+ if (property_exists($productData, 'category_ids') && !is_array($productData->category_ids)) {
1287
+ if (is_string($productData->category_ids))
1288
+ $productData->category_ids = array($productData->category_ids);
1289
+ }
1290
+ else if (property_exists($productData, 'category_ids') === false)
1291
+ {
1292
+ $productData->category_ids = array();
1293
+ }
1294
 
1295
+ $productData->categories = $productData->category_ids;
1296
 
1297
+ $this->_updateQuantity($productData);
1298
 
1299
+ $productData = $this->_fixAttributes($productData);
1300
 
1301
+ $productAPI = new Mage_Catalog_Model_Product_Api_V2();
1302
 
1303
+ return $productAPI->create($type, $set, $sku, $productData, $store);
1304
+ }
1305
 
1306
+ public function debugInfo()
1307
+ {
1308
+ $verInfo = Mage::getVersionInfo();
1309
 
1310
+ $result = array(
1311
+ 'llc_ver' => Settings::$VERSION,
1312
+ 'magento_ver' => $verInfo
1313
+ );
1314
 
1315
+ return $result;
1316
+ }
1317
  }
1318
 
1319
  class LinnLiveEnterprise extends LinnLiveMain{
1320
 
1321
+ public function productAttributeOptions($setId)
1322
  {
1323
+ $result = array();
1324
 
1325
+ $setId = intval($setId);
1326
+ if ($setId <= 0) return $result;
1327
 
1328
  $attributeAPI = Mage::getModel('catalog/product_attribute_api');
1329
 
1330
+ $attributes = Mage::getModel('catalog/product')->getResource()
1331
+ ->loadAllAttributes()
1332
+ ->getSortedAttributes($setId);
1333
 
1334
+ $i=0;
1335
 
1336
+ foreach ($attributes as $attribute) {
1337
 
1338
  if ((!$attribute->getId() || $attribute->isInSet($setId))
1339
  && !in_array($attribute->getAttributeCode(), $this->_ignoredAttributes)
1340
+ && in_array($attribute->getFrontendInput(), $this->_permittedAttributes)) {
1341
 
1342
  if (!$attribute->getId() || $attribute->isScopeGlobal()) {
1343
  $scope = 'global';
1356
  'can_config' => 0
1357
  );
1358
 
1359
+ if ( ($attribute->getFrontendInput() == 'select') || ($attribute->getFrontendInput() == 'multiselect') ) {
1360
+ if (($scope == 'global') &&
1361
+ $attribute->getIsConfigurable())
1362
+ {
1363
+ if (strpos($attribute->getApplyTo(), 'simple') !== false)
1364
+ $result[$i]['can_config'] = 1;
1365
+ }
1366
+
1367
+ $options = $attributeAPI->options($attribute->getId());
1368
+
1369
+ // remove empty first element
1370
+ if ($attribute->getFrontendInput() != 'boolean') {
1371
+ array_shift($options);
1372
+ }
1373
+
1374
+ if (count($options) > 0) {
1375
+ $result[$i]['attribute_options'] = $options;
1376
+ }
1377
+ }
1378
+ $i++;
1379
  }
1380
  }
1381
 
1382
+ return $result;
1383
  }
1384
 
1385
+ //Fix for buggy associativeArray implementation
1386
+ private function _fixAttributes($productData)
1387
+ {
1388
+ $_newAttributeOptions = $this->_newOptions($productData);
1389
+ $_availableOptions = array();
1390
+ if (count($_newAttributeOptions) > 0)
1391
+ {
1392
+ $_availableOptions = $this->_createOptions($_newAttributeOptions);
1393
+ }
1394
+
1395
+ if (property_exists($productData, 'additional_attributes')) {
1396
+ $tmpAttr = $productData->additional_attributes;
1397
+ if (count($tmpAttr) == 0)
1398
+ {
1399
+ unset($productData->additional_attributes);
1400
+ return $productData;
1401
+ }
1402
+ $productData->additional_attributes = new stdClass();
1403
+ $productData->additional_attributes->single_data = array();
1404
+ $i=0;
1405
+ if (is_array($tmpAttr))
1406
+ {
1407
+ foreach ($tmpAttr as $option) {
1408
+ $productData->additional_attributes->single_data[$i] = new stdClass();
1409
+ $productData->additional_attributes->single_data[$i]->key = $option->code;
1410
 
1411
  if ( ($option->type == 'multiselect') && (is_array($productData->additional_attributes->single_data[$i]->value) == false) )
1412
  {
1413
  $productData->additional_attributes->single_data[$i]->value = array();
1414
  }
1415
 
1416
+ if (isset($_availableOptions[$option->attribute_id][strtolower($option->label)]))
1417
  {
1418
  if ($option->type == 'multiselect')
1419
  {
1424
  $productData->additional_attributes->single_data[$i]->value = $_availableOptions[$option->attribute_id][strtolower($option->label)];
1425
  }
1426
  }
1427
+ else
1428
  {
1429
  if ($option->type == 'multiselect')
1430
  {
1435
  $productData->additional_attributes->single_data[$i]->value = $option->value;
1436
  }
1437
  }
1438
+ $i++;
1439
+ }
1440
+ }
1441
+ else
1442
+ {
1443
+ $productData->additional_attributes->single_data[0] = new stdClass();
1444
+ $productData->additional_attributes->single_data[0]->key = $tmpAttr->code;
1445
+ if (isset($_availableOptions[$tmpAttr->attribute_id][strtolower($tmpAttr->label)]))
1446
+ $productData->additional_attributes->single_data[0]->value = $_availableOptions[$tmpAttr->attribute_id][strtolower($tmpAttr->label)];
1447
+ else
1448
+ $productData->additional_attributes->single_data[0]->value = $tmpAttr->value;
1449
+ }
1450
+ }
1451
+
1452
+ return $productData;
1453
+ }
1454
  }
1455
 
1456
  class LinnLiveCommunity extends LinnLiveMain{
app/code/local/LinnSystems/LinnLiveConnect/etc/api.xml CHANGED
@@ -103,10 +103,6 @@ and click on "Check for Upgrades", and upgrade you LinnLiveConnect extension to
103
  </unsupported_edition>
104
  <filters_invalid>
105
  <code>111</code>
106
- <message>Invalid filters.</message>
107
- </filters_invalid>
108
- <filters_invalid>
109
- <code>111</code>
110
  <message>Invalid filters.</message>
111
  </filters_invalid>
112
  <version_not_specified>
103
  </unsupported_edition>
104
  <filters_invalid>
105
  <code>111</code>
 
 
 
 
106
  <message>Invalid filters.</message>
107
  </filters_invalid>
108
  <version_not_specified>
package.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>LinnLiveConnect</name>
4
- <version>1.1.42</version>
5
  <stability>stable</stability>
6
  <license>GPL v2</license>
7
  <channel>community</channel>
@@ -11,9 +11,9 @@
11
  Contains some workarounds to avoid bugs in original Magento modules and additional functionality to operate Magento store remotely.</description>
12
  <notes>minor bug fixes</notes>
13
  <authors><author><name>Albert Andrejev</name><user>albert_andrejev</user><email>albert@linnsystems.com</email></author><author><name>Pavel Nikolajev</name><user>Pavel_LL2</user><email>pavel.nokolajev@linnsystems.com</email></author><author><name>Aleksandr Kornev</name><user>alex_LL2</user><email>alex.kornevs@linnsystems.com</email></author></authors>
14
- <date>2014-04-29</date>
15
- <time>08:15:26</time>
16
- <contents><target name="magelocal"><dir name="LinnSystems"><dir name="LinnLiveConnect"><dir name="Helper"><file name="Data.php" hash="5fe5216de67d4e69a0f418b0cd7780ee"/></dir><dir name="Model"><dir name="Api"><file name="V2.php" hash="92f252fdbe817193d1cdf7ba4a402191"/></dir></dir><dir name="etc"><file name="api.xml" hash="cfb207e1a27826802b0bbef69a4213a6"/><file name="config.xml" hash="9367dc40a0ce3d4078039f495ccd6527"/><file name="wsdl.xml" hash="fc21f2963c1253f5f40e5e8414312174"/><file name="wsi.xml" hash="ef000d5115f5988664f58df8b9139e5e"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="LinnSystems_LinnLiveConnect.xml" hash="19c48712cd0516815d6784592ada0881"/></dir></target></contents>
17
  <compatible/>
18
  <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
19
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>LinnLiveConnect</name>
4
+ <version>1.1.43</version>
5
  <stability>stable</stability>
6
  <license>GPL v2</license>
7
  <channel>community</channel>
11
  Contains some workarounds to avoid bugs in original Magento modules and additional functionality to operate Magento store remotely.</description>
12
  <notes>minor bug fixes</notes>
13
  <authors><author><name>Albert Andrejev</name><user>albert_andrejev</user><email>albert@linnsystems.com</email></author><author><name>Pavel Nikolajev</name><user>Pavel_LL2</user><email>pavel.nokolajev@linnsystems.com</email></author><author><name>Aleksandr Kornev</name><user>alex_LL2</user><email>alex.kornevs@linnsystems.com</email></author></authors>
14
+ <date>2014-05-02</date>
15
+ <time>06:20:48</time>
16
+ <contents><target name="magelocal"><dir name="LinnSystems"><dir name="LinnLiveConnect"><dir name="Helper"><file name="Data.php" hash="5fe5216de67d4e69a0f418b0cd7780ee"/></dir><dir name="Model"><dir name="Api"><file name="V2.php" hash="bd8166a2de00ebe1a01a09279e396bbd"/></dir></dir><dir name="etc"><file name="api.xml" hash="ae6bb50af6b605606819021ce4acd33d"/><file name="config.xml" hash="9367dc40a0ce3d4078039f495ccd6527"/><file name="wsdl.xml" hash="fc21f2963c1253f5f40e5e8414312174"/><file name="wsi.xml" hash="ef000d5115f5988664f58df8b9139e5e"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="LinnSystems_LinnLiveConnect.xml" hash="19c48712cd0516815d6784592ada0881"/></dir></target></contents>
17
  <compatible/>
18
  <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
19
  </package>