LinnLiveConnect - Version 1.1.48

Version Notes

update prices in bulk added

Download this release

Release Info

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


Code changes from version 1.1.47 to 1.1.48

app/code/local/LinnSystems/LinnLiveConnect/Model/Api/V2.php CHANGED
@@ -1,12 +1,12 @@
1
  <?php
2
  class Settings {
3
- const VERSION = 47;
4
  }
5
 
6
- class LinnSystems_LinnLiveConnect_Model_Api_V2{
7
 
8
 
9
- public function getProductStoreURL($version, $productId, $store = null, $identifierType = 'id'){
10
  $worker = Factory::createWorker($version);
11
  return $worker->getProductStoreURL($productId, $store, $identifierType);
12
  }
@@ -76,15 +76,23 @@ class LinnSystems_LinnLiveConnect_Model_Api_V2{
76
  $worker = Factory::createWorker($version);
77
  return $worker->updatePriceBulk($data, $store, $identifierType);
78
  }
79
-
80
  public function debugInfo()
81
  {
82
- $worker = Factory::createWorker(Settings::$VERSION);
83
  return $worker->debugInfo();
84
  }
 
 
 
 
 
 
 
 
85
  }
86
 
87
- class Factory{
88
 
89
  private static function _checkVersion($version)
90
  {
@@ -96,9 +104,9 @@ class Factory{
96
 
97
  public static function createWorker($version)
98
  {
99
- self::_checkVersion($version);
100
-
101
- if(Mage::GetEdition() == Mage::EDITION_COMMUNITY)
102
  {
103
  return new LinnLiveCommunity();
104
  }
@@ -111,82 +119,117 @@ class Factory{
111
  }
112
  }
113
 
114
- class LinnLiveMain extends Mage_Core_Model_Abstract{
115
 
116
 
117
  protected $_ignoredAttributes = array(
118
- 'created_at',
119
- 'updated_at',
120
- 'category_ids',
121
- 'required_options',
122
- 'old_id',
123
- 'url_key',
124
- 'url_path',
125
- 'has_options',
126
- 'image_label',
127
- 'small_image_label',
128
- 'thumbnail_label',
129
- 'image',
130
- 'small_image',
131
- 'thumbnail',
132
- 'options_container',
133
- 'entity_id',
134
- 'entity_type_id',
135
- 'attribute_set_id',
136
- 'type_id',
137
- 'sku',
138
- 'name',
139
- 'status',
140
- 'stock_item',
141
- 'description',
142
- );
143
 
144
  protected $_permittedAttributes = array (
145
- 'select',
146
- 'multiselect',
147
- 'text',
148
- 'textarea',
149
- 'date',
150
- 'price'
151
- );
152
-
153
- private function _prepareConfigurableData(
154
- & $store, & $productData, & $assignedProductsArray,
155
- & $attributesSetArray, $productsSet, $attributesSet)
156
- {
157
- $store = $this->_currentStoreCode($store);
158
 
159
- $this->_updateConfigurableQuantity($productData);
160
-
161
- $productData = $this->_fixAttributes($productData);
162
-
163
- if (!is_array($attributesSet))
164
- {
165
- $attributesSet = array($attributesSet);
166
- }
167
-
168
- $assignedProductsData = $this->_createProductsData($productsSet);
169
- $assignedProductsArray = $this->_objectToArray($assignedProductsData);
170
 
171
  $_newAttributeOptions = $this->_newConfigurableOptions($assignedProductsArray);
172
  if (count($_newAttributeOptions) > 0)
173
  {
174
- $_availableOptions = $this->_createOptions($_newAttributeOptions);
175
- $this->_checkAssignedProductsOptions($_availableOptions, $assignedProductsArray);
 
 
176
  }
177
 
178
- $attributesSetArray = $this->_objectToArray($attributesSet);
179
- $attributesSetArray = $this->_prepareAttributesData($attributesSetArray, $assignedProductsArray);
 
 
 
 
 
 
 
 
180
 
181
  foreach($attributesSetArray as $key=>$value)
182
  {
183
  $attributesSetArray[$key]["id"] = NULL;
184
  $attributesSetArray[$key]["position"] = NULL;
185
  $attributesSetArray[$key]["store_label"] = $value['frontend_label'];
186
- $attributesSetArray[$key]["use_default"] = 1;
 
 
 
 
 
 
 
 
 
 
187
  }
 
188
  }
189
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  private function _checkAssignedProductsOptions($availableOptions, & $assignedProductsArray)
191
  {
192
  foreach ($assignedProductsArray as $id => $productOptions)
@@ -332,20 +375,20 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
332
  private function _containsOption($attributeOption, $option)
333
  {
334
  foreach ($attributeOption as $inArrayOption)
335
- if ($inArrayOption['value_index'] == $option['value_index']) return true;
336
 
337
  return false;
338
  }
339
 
340
  private function _prepareAttributesData($attributesSetArray, $assignedProductsArray)
341
  {
 
342
  $_attributesOptions = array();
343
  foreach ($assignedProductsArray as $id => $productOptions)
344
  {
345
  foreach($productOptions as $option)
346
  {
347
- if (isset($_attributesOptions[$option['attribute_id']]) &&
348
- !$this->_containsOption($_attributesOptions[$option['attribute_id']], $option))
349
  {
350
  $_attributesOptions[$option['attribute_id']][] = $option;
351
  }
@@ -359,33 +402,39 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
359
 
360
  foreach($attributesSetArray as $key => $attribute)
361
  {
362
- if (isset($_attributesOptions[$attribute['attribute_id']]))
363
  $attributesSetArray[$key]['values'] = $_attributesOptions[$attribute['attribute_id']];
 
364
  }
365
 
366
  return $attributesSetArray;
367
  }
368
 
369
- private function _updateConfigurable($store, $productId, $productData, $assignedProducts, $assignedAttributes, $identifierType, $isUpdate=false, $reindex=true)
370
  {
371
  $magentoVer = $this->_getCurrentVersion();
372
  if ($magentoVer == 162)
373
  {
374
  $store = Mage::app()->getStore($store)->getId();
 
 
375
  }
376
 
377
  $product = Mage::helper('catalog/product')->getProduct($productId, $store, $identifierType);
 
 
378
 
379
- $product->setConfigurableProductsData($assignedProducts);
380
- if (!$isUpdate){
381
- $product->setConfigurableAttributesData($assignedAttributes);
382
  }
383
- $product->setCanSaveConfigurableAttributes(true);
 
384
 
385
  try {
386
  $result = $product->save();
387
  }
388
- catch (Exception $e){
389
  throw new Mage_Api_Exception('configurable_creating_error', $e->getMessage());
390
  }
391
 
@@ -456,12 +505,10 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
456
 
457
  private function _updateProperties($productData)
458
  {
459
-
460
- if (property_exists($productData, 'status')){
461
  $productData->status = ($productData->status == 1) ? Mage_Catalog_Model_Product_Status::STATUS_ENABLED : Mage_Catalog_Model_Product_Status::STATUS_DISABLED;
462
  }
463
-
464
-
465
  if (property_exists($productData, 'stock_data') && property_exists($productData->stock_data, 'qty')) {
466
  $productData->stock_data->qty = intval($productData->stock_data->qty);
467
  $productData->stock_data->is_in_stock = 1;
@@ -470,6 +517,7 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
470
  return $productData;
471
  }
472
 
 
473
  private function _objectToArray( $result )
474
  {
475
  $array = array();
@@ -538,8 +586,8 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
538
  }
539
 
540
  private function _currentStoreCode($store=null)
541
- {
542
- if ($store != null){
543
  return $store;
544
  }
545
  return $this->_getStore()->getCode();
@@ -547,12 +595,12 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
547
 
548
  private function _getProductBySku($sku)
549
  {
550
- if($sku){
551
  $product = Mage::getModel('catalog/product');
552
  $productId = $product->getIdBySku((string)$sku);
553
- if($productId){
554
  $product->load($productId);
555
- if($product->getId()){
556
  return $product;
557
  }
558
  }
@@ -568,7 +616,7 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
568
  $mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : '';
569
  $mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store';
570
 
571
- if ($storeCode != null){
572
  return Mage::getModel('core/store')->load( $storeCode, 'code');
573
  }
574
 
@@ -578,18 +626,19 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
578
  return Mage::getModel('core/store')->load( $mageRunCode, 'code');
579
  }
580
  } else {
581
- if ($mageRunType == 'website'){
582
  $websiteCode = empty($mageRunCode) ? '' : $mageRunCode;
583
- }else{
584
  $websiteCode = empty($mageRunType) ? '' : $mageRunType;
585
  }
586
-
587
  if (!empty($websiteCode))
588
  {
589
  $currentWebSite = Mage::getModel('core/website')->load( $websiteCode, 'code');
590
  $defaultStore = $currentWebSite->getDefaultStore();
591
- if (isset($defaultStore))
592
  return $defaultStore;
 
593
  }
594
  }
595
 
@@ -604,8 +653,7 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
604
 
605
  private function _productAttributeInfo($attribute_id, $attributeAPI)
606
  {
607
- $model = Mage::getResourceModel('catalog/eav_attribute')
608
- ->setEntityTypeId(Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId());
609
 
610
  $model->load($attribute_id);
611
 
@@ -622,22 +670,22 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
622
  }
623
 
624
  $result = array(
625
- 'attribute_id' => $model->getId(),
626
- 'attribute_code' => $model->getAttributeCode(),
627
- 'frontend_input' => $model->getFrontendInput(),
628
- 'default_value' => $model->getDefaultValue(),
629
- 'is_unique' => $model->getIsUnique(),
630
- 'is_required' => $model->getIsRequired(),
631
- 'apply_to' => $model->getApplyTo(),
632
- 'is_configurable' => $model->getIsConfigurable(),
633
- 'is_searchable' => $model->getIsSearchable(),
634
- 'is_visible_in_advanced_search' => $model->getIsVisibleInAdvancedSearch(),
635
- 'is_comparable' => $model->getIsComparable(),
636
- 'is_used_for_promo_rules' => $model->getIsUsedForPromoRules(),
637
- 'is_visible_on_front' => $model->getIsVisibleOnFront(),
638
- 'used_in_product_listing' => $model->getUsedInProductListing(),
639
- 'scope' => $scope,
640
- );
641
 
642
  // set options
643
  $options = $attributeAPI->options($model->getId());
@@ -671,7 +719,6 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
671
  return $productData;
672
  }
673
 
674
- $i=0;
675
  if (is_array($tmpAttr))
676
  {
677
  foreach ($tmpAttr as $option) {
@@ -720,43 +767,66 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
720
  return $productData;
721
  }
722
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
723
  /*
724
- * Helper for productList
725
- */
726
- private function _convertFiltersToArray($filters){
 
 
 
 
727
  $arrayParams = array(
728
- 'nin',
729
- 'in',
730
- );
731
 
732
  $preparedFilters = array();
733
-
734
  if (isset($filters->filter)) {
735
  $preparedFilters = $filters->filter;
736
- }
737
-
738
  if (isset($filters->complex_filter)) {
739
-
740
- foreach ($filters->complex_filter as $idx=>$data) {
741
- if(is_object($data->value)){
742
  //1.8
743
  $field = $data->key;
744
- $opts = $data->value;
745
-
746
- }else{
747
- //1.7
748
  $field = $idx;
749
- $opts = $data;
750
- }
751
-
752
- $value = (in_array($opts->key, $arrayParams)) ? explode(',', $opts->value) : $opts->value;
753
- $preparedFilters[$field][$opts->key] = $value;
754
  }
755
  }
756
  return $preparedFilters;
757
- }
758
 
759
- protected function _log($message){
760
  Mage::log(print_r($message, true), null, 'LinnLiveExt.log');
761
  }
762
 
@@ -770,10 +840,11 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
770
  if (!$set || !$sku) {
771
  throw new Mage_Api_Exception('data_invalid');
772
  }
773
-
774
- $this->_prepareConfigurableData($store, $productData, $assignedProductsArray,
775
- $attributesSetArray, $productsSet, $attributesSet);
776
-
 
777
  $defaultStore = $this->_getStore();
778
 
779
  if (property_exists($productData, 'websites') === false && isset($defaultStore) ) {
@@ -792,11 +863,13 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
792
  }
793
 
794
  $productData->categories = $productData->category_ids;
795
-
 
796
  $productAPI = new Mage_Catalog_Model_Product_Api_V2();
797
  $productId = $productAPI->create('configurable', $set, $sku, $productData, $store);
798
 
799
- $this->_updateConfigurable($store, $productId, $productData, $assignedProductsArray, $attributesSetArray, 'id', false, $reindex);
 
800
 
801
  return $productId;
802
  }
@@ -804,9 +877,12 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
804
  public function updateConfigurableProduct($productId, $reindex, $productData, $productsSet, $attributesSet, $store=null, $identifierType='id')
805
  {
806
 
807
-
808
- $this->_prepareConfigurableData($store, $productData, $assignedProductsArray,
809
- $attributesSetArray, $productsSet, $attributesSet);
 
 
 
810
 
811
  try {
812
  $storeId = Mage::app()->getStore($store)->getId();
@@ -823,6 +899,7 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
823
  }
824
 
825
  $_categoryIds = $_loadedProduct->getCategoryIds();
 
826
  if (property_exists($productData, 'category_ids'))
827
  {
828
 
@@ -840,12 +917,9 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
840
 
841
  $productData->category_ids = array_unique($productData->category_ids);
842
 
843
- if ( (property_exists($productData, 'removed_categories') === true)
844
- && (is_array($productData->removed_categories) === true)
845
- && (count($productData->removed_categories) > 0) )
846
  {
847
  $tmpCats = array();
848
-
849
  $productData->category_ids = array_diff($productData->category_ids, $productData->removed_categories);
850
  }
851
 
@@ -868,14 +942,51 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
868
 
869
  $productAPI->update($productId, $productData, $store, $identifierType);
870
 
871
- return $this->_updateConfigurable($store, $productId, $productData, $assignedProductsArray, $attributesSetArray, $identifierType, true, $reindex);
 
872
  }
873
 
874
  /*
875
  * Checks if this Magento server has valid Extension installed
876
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
877
  public function storesList()
878
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
879
  return ($this->_getCurrentVersion() >= 160);
880
  }
881
 
@@ -911,7 +1022,7 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
911
 
912
  if (in_array($websiteId, $currentWebsites) === true)
913
  {
914
- for($i = 0; $i < count($currentWebsites); $i++)
915
  {
916
  if ($currentWebsites[$i] != $websiteId)
917
  {
@@ -987,9 +1098,9 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
987
  return true;
988
  }
989
 
990
-
991
 
992
-
 
993
  /*
994
  * Implementation of catalogProductList because of bug in associativeArray.
995
  * Extended to filter by category id too.
@@ -998,7 +1109,7 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
998
  * 'type_id' instead of product type.
999
  */
1000
  public function productList($page, $perPage, $filters = null, $store = null)
1001
- {
1002
  //get store
1003
  try {
1004
  $storeId = Mage::app()->getStore( $this->_currentStoreCode($store) )->getId();
@@ -1006,30 +1117,28 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1006
  catch (Mage_Core_Model_Store_Exception $e) {
1007
  throw new Mage_Api_Exception('store_not_exists', null);
1008
  }
1009
-
1010
  //prepare and convert filters to array
1011
- $preparedFilters = $this->_convertFiltersToArray($filters);
1012
  if (empty($preparedFilters)) {
1013
  throw new Mage_Api_Exception('filters_invalid', 'Filters not found');
1014
  }
1015
-
1016
  //load collection
1017
  $collection = Mage::getModel('catalog/product')->getCollection()->addStoreFilter($storeId);
1018
-
1019
- //filter collection by category if exists
1020
  if (isset($preparedFilters['category']) && is_string($preparedFilters['category']))
1021
- {
1022
- $_category = Mage::getModel('catalog/category')->load(
1023
- intval($preparedFilters['category'])
1024
- );
1025
-
1026
- if($_category->getId()){
1027
  $collection = $collection->addCategoryFilter($_category);
1028
  }
1029
-
1030
  unset($preparedFilters['category']);
1031
  }
1032
-
1033
  //add prepared filters to collection
1034
  try {
1035
  foreach ($preparedFilters as $field => $value) {
@@ -1038,8 +1147,8 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1038
  }
1039
  catch (Mage_Core_Exception $e) {
1040
  throw new Mage_Api_Exception('filters_invalid', $e->getMessage());
1041
- }
1042
-
1043
 
1044
  if ($page == 1)
1045
  {
@@ -1050,19 +1159,19 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1050
  {
1051
  $count = 0;
1052
  $collection->setPageSize($perPage)->setCurPage($page);
1053
- }
1054
-
1055
  $result = array(
1056
- 'count'=>$count,
1057
- 'products'=>array()
1058
- );
1059
-
1060
  $_assignedIds = array();
1061
  $_fetchedIds = array();
1062
-
1063
  $i = 0;
1064
- foreach ($collection as $_product) {
1065
-
1066
  if ($i >= ($perPage * $page)) break;//TODO remove
1067
  $_loadedProduct = Mage::helper('catalog/product')->getProduct($_product->getId(), $storeId, 'id');
1068
 
@@ -1077,43 +1186,42 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1077
  $_fetchedIds[] = $_loadedProduct->getId();
1078
 
1079
  $result['products'][$i] = array(
1080
- 'product_id' => $_loadedProduct->getId(),
1081
- 'sku' => $_loadedProduct->getSku(),
1082
- 'name' => $_loadedProduct->GetName(),
1083
- 'set' => $_loadedProduct->getAttributeSetId(),
1084
- 'type' => $_loadedProduct->getTypeId(),
1085
- 'price' => $_loadedProduct->getPrice(),
1086
- 'status' => $_loadedProduct->getStatus(),
1087
- 'description' => $_description,
1088
- 'category_ids' => $_loadedProduct->getCategoryIds(),
1089
- 'website_ids' => $_loadedProduct->getWebsiteIds(),
1090
- 'assigned_ids' => array(),
1091
- 'conf_attrib_ids' => array(),
1092
- 'images' => $_productImages,
1093
- 'attributes' => $_productAttributes,
1094
- );
1095
-
1096
- if($_loadedProduct->getTypeId() == "configurable")
1097
  {
1098
  $_typeInstance = $_loadedProduct->getTypeInstance();
1099
  $result['products'][$i]['assigned_ids'] = $_typeInstance->getUsedProductIds();
1100
- foreach($_typeInstance->getConfigurableAttributes() as $attribute){
1101
  $_prices = array();
1102
  foreach($attribute->getPrices() as $price)
1103
  {
1104
  $_prices[] = array(
1105
- 'value_index' => $price['value_index'],
1106
- 'is_fixed' => !$price['is_percent'],
1107
- 'price_diff' => $price['pricing_value'],
1108
- 'label' => $price['label'],
1109
- );
1110
-
1111
  }
1112
 
1113
  $result['products'][$i]['conf_attrib_ids'][] = array(
1114
- 'code' => $attribute->getProductAttribute()->getAttributeCode(),
1115
- 'prices' => $_prices
1116
- );
1117
  }
1118
  $_assignedIds = array_merge($_assignedIds, $result['products'][$i]['assigned_ids']);
1119
  }
@@ -1138,21 +1246,21 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1138
  $_productAttributes = $this->_removeIgnoredAttributes($_allAttributes);
1139
 
1140
  $result['products'][] = array(
1141
- 'product_id' => $_loadedProduct->getId(),
1142
- 'sku' => $_loadedProduct->getSku(),
1143
- 'name' => $_loadedProduct->GetName(),
1144
- 'set' => $_loadedProduct->getAttributeSetId(),
1145
- 'type' => $_loadedProduct->getTypeId(),
1146
- 'price' => $_loadedProduct->getPrice(),
1147
- 'status' => $_loadedProduct->getStatus(),
1148
- 'description' => $_description,
1149
- 'category_ids' => $_loadedProduct->getCategoryIds(),
1150
- 'website_ids' => $_loadedProduct->getWebsiteIds(),
1151
- 'assigned_ids' => array(),
1152
- 'conf_attrib_ids' => array(),
1153
- 'images' => $_productImages,
1154
- 'attributes' => $this->_removeIgnoredAttributes($_loadedProduct->getData()),
1155
- );
1156
  }
1157
  }
1158
 
@@ -1161,7 +1269,7 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1161
 
1162
  public function productAttributeOptions($setId)
1163
  {
1164
-
1165
  $result = array();
1166
 
1167
  $setId = intval($setId);
@@ -1171,10 +1279,8 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1171
 
1172
  $items = $attributeAPI->items($setId);
1173
 
1174
- $attributes = Mage::getModel('catalog/product')->getResource()
1175
- ->loadAllAttributes();
1176
 
1177
- $i=0;
1178
  foreach ($items as $item) {
1179
  if (!isset($item['attribute_id']) || empty($item['attribute_id'])) continue;
1180
  $attributeId = intval($item['attribute_id']);
@@ -1182,8 +1288,7 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1182
 
1183
  $additionInfo = $this->_productAttributeInfo($attributeId, $attributeAPI);
1184
 
1185
- if (in_array($additionInfo['frontend_input'], $this->_permittedAttributes) &&
1186
- !in_array($additionInfo['attribute_code'], $this->_ignoredAttributes))
1187
  {
1188
 
1189
  $attribute = array(
@@ -1193,32 +1298,21 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1193
  'required' => $additionInfo['is_required'],
1194
  'scope' => $additionInfo['scope'],
1195
  'can_config' => 0
1196
- );
1197
-
1198
  if ( ($additionInfo['frontend_input'] == 'select') || ($additionInfo['frontend_input'] == 'multiselect') ) {
1199
- if (isset($additionInfo['options'])){
1200
 
1201
- if(sizeof($additionInfo['options']) && is_array($additionInfo['options'][0]['value'])){
1202
- continue;//ignore attributes with multidimensional options
1203
- }
1204
- $attribute['attribute_options'] = $additionInfo['options'];
1205
- }
1206
-
1207
- if (($additionInfo['scope'] == 'global') && ($additionInfo['is_configurable']))
1208
- {
1209
- if(sizeof($additionInfo['apply_to'])){
1210
- if(in_array('simple', $additionInfo['apply_to'])){
1211
- $attribute['can_config'] = 1;
1212
- }
1213
- }else{
1214
- $attribute['can_config'] = 1;
1215
  }
 
1216
  }
 
 
1217
  }
1218
-
1219
- $result[$i] = $attribute;
1220
-
1221
- $i++;
1222
  }
1223
  }
1224
 
@@ -1260,9 +1354,7 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1260
 
1261
  $productData->category_ids = array_unique($productData->category_ids);
1262
 
1263
- if ( (property_exists($productData, 'removed_categories') === true)
1264
- && (is_array($productData->removed_categories) === true)
1265
- && (count($productData->removed_categories) > 0) )
1266
  {
1267
  $tmpCats = array();
1268
 
@@ -1297,11 +1389,11 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1297
 
1298
  public function create($type, $set, $sku, $productData, $store = null)
1299
  {
1300
- $product = $this->_getProductBySku($sku);
1301
- if($product){
1302
  return $product->getId();
1303
  }
1304
-
1305
  $store = $this->_currentStoreCode($store);
1306
 
1307
  $defaultStore = $this->_getStore();
@@ -1311,10 +1403,10 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1311
  }
1312
 
1313
  if (property_exists($productData, 'category_ids') && !is_array($productData->category_ids)) {
1314
- if (is_string($productData->category_ids))
1315
  $productData->category_ids = array($productData->category_ids);
1316
- }
1317
- else if (property_exists($productData, 'category_ids') === false)
1318
  {
1319
  $productData->category_ids = array();
1320
  }
@@ -1335,14 +1427,14 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1335
  $verInfo = Mage::getVersionInfo();
1336
 
1337
  $result = array(
1338
- 'llc_ver' => Settings::$VERSION,
1339
  'magento_ver' => $verInfo
1340
  );
1341
 
1342
  return $result;
1343
  }
1344
-
1345
- public function getProductStoreURL($productId, $store = null, $identifierType = 'id'){
1346
 
1347
  $storeId = $this->getStoreCode($store);
1348
 
@@ -1355,14 +1447,14 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1355
 
1356
  return $_loadedProduct->getProductUrl();
1357
  }
1358
-
1359
- public function updatePriceBulk($data, $store, $identifierType){
1360
  $response = array();
1361
- for($i = 0; $i< sizeof($data); $i++){
1362
  $d = $data[$i];
1363
  $product = Mage::helper('catalog/product')->getProduct($d->sku, $store, $identifierType);
1364
- if($product && $product->getId()){
1365
- if($product->getPrice()!=$d->price){
1366
  $product->setPrice($d->price);
1367
  $product->save();
1368
  }
@@ -1373,7 +1465,7 @@ class LinnLiveMain extends Mage_Core_Model_Abstract{
1373
  }
1374
  }
1375
 
1376
- class LinnLiveEnterprise extends LinnLiveMain{
1377
 
1378
  public function productAttributeOptions($setId)
1379
  {
@@ -1384,11 +1476,7 @@ class LinnLiveEnterprise extends LinnLiveMain{
1384
 
1385
  $attributeAPI = Mage::getModel('catalog/product_attribute_api');
1386
 
1387
- $attributes = Mage::getModel('catalog/product')->getResource()
1388
- ->loadAllAttributes()
1389
- ->getSortedAttributes($setId);
1390
-
1391
- $i=0;
1392
 
1393
  foreach ($attributes as $attribute) {
1394
 
@@ -1414,11 +1502,10 @@ class LinnLiveEnterprise extends LinnLiveMain{
1414
  );
1415
 
1416
  if ( ($attribute->getFrontendInput() == 'select') || ($attribute->getFrontendInput() == 'multiselect') ) {
1417
- if (($scope == 'global') &&
1418
- $attribute->getIsConfigurable())
1419
  {
1420
  if (strpos($attribute->getApplyTo(), 'simple') !== false)
1421
- $result[$i]['can_config'] = 1;
1422
  }
1423
 
1424
  $options = $attributeAPI->options($attribute->getId());
@@ -1429,10 +1516,9 @@ class LinnLiveEnterprise extends LinnLiveMain{
1429
  }
1430
 
1431
  if (count($options) > 0) {
1432
- $result[$i]['attribute_options'] = $options;
1433
  }
1434
  }
1435
- $i++;
1436
  }
1437
  }
1438
 
@@ -1510,7 +1596,8 @@ class LinnLiveEnterprise extends LinnLiveMain{
1510
  }
1511
  }
1512
 
1513
- class LinnLiveCommunity extends LinnLiveMain{
1514
 
1515
  }
 
1516
  ?>
1
  <?php
2
  class Settings {
3
+ const VERSION = 48;
4
  }
5
 
6
+ class LinnSystems_LinnLiveConnect_Model_Api_V2 {
7
 
8
 
9
+ public function getProductStoreURL($version, $productId, $store = null, $identifierType = 'id') {
10
  $worker = Factory::createWorker($version);
11
  return $worker->getProductStoreURL($productId, $store, $identifierType);
12
  }
76
  $worker = Factory::createWorker($version);
77
  return $worker->updatePriceBulk($data, $store, $identifierType);
78
  }
79
+
80
  public function debugInfo()
81
  {
82
+ $worker = Factory::createWorker(Settings::VERSION);
83
  return $worker->debugInfo();
84
  }
85
+
86
+ public function getGeneralInfo()
87
+ {
88
+ $worker = Factory::createWorker(Settings::VERSION);
89
+ return $worker->getGeneralInfo();
90
+ }
91
+
92
+
93
  }
94
 
95
+ class Factory {
96
 
97
  private static function _checkVersion($version)
98
  {
104
 
105
  public static function createWorker($version)
106
  {
107
+ self::_checkVersion($version);
108
+
109
+ if (Mage::GetEdition() == Mage::EDITION_COMMUNITY)
110
  {
111
  return new LinnLiveCommunity();
112
  }
119
  }
120
  }
121
 
122
+ class LinnLiveMain extends Mage_Core_Model_Abstract {
123
 
124
 
125
  protected $_ignoredAttributes = array(
126
+ 'created_at',
127
+ 'updated_at',
128
+ 'category_ids',
129
+ 'required_options',
130
+ 'old_id',
131
+ 'url_key',
132
+ 'url_path',
133
+ 'has_options',
134
+ 'image_label',
135
+ 'small_image_label',
136
+ 'thumbnail_label',
137
+ 'image',
138
+ 'small_image',
139
+ 'thumbnail',
140
+ 'options_container',
141
+ 'entity_id',
142
+ 'entity_type_id',
143
+ 'attribute_set_id',
144
+ 'type_id',
145
+ 'sku',
146
+ 'name',
147
+ 'status',
148
+ 'stock_item',
149
+ 'description',
150
+ );
151
 
152
  protected $_permittedAttributes = array (
153
+ 'select',
154
+ 'multiselect',
155
+ 'text',
156
+ 'textarea',
157
+ 'date',
158
+ 'price'
159
+ );
 
 
 
 
 
 
160
 
161
+
162
+ private function _prepareConfigurableData($productsSet, $attributesSet, $isUpdate)
163
+ {
164
+ $assignedProductsArray = $this->_objectToArray(
165
+ $this->_createProductsData($productsSet)
166
+ );
 
 
 
 
 
167
 
168
  $_newAttributeOptions = $this->_newConfigurableOptions($assignedProductsArray);
169
  if (count($_newAttributeOptions) > 0)
170
  {
171
+ $this->_checkAssignedProductsOptions(
172
+ $this->_createOptions($_newAttributeOptions),
173
+ $assignedProductsArray
174
+ );
175
  }
176
 
177
+
178
+ if (!is_array($attributesSet))
179
+ {
180
+ $attributesSet = array($attributesSet);
181
+ }
182
+
183
+ $attributesSetArray = $this->_prepareAttributesData(
184
+ $this->_objectToArray($attributesSet),
185
+ $assignedProductsArray
186
+ );
187
 
188
  foreach($attributesSetArray as $key=>$value)
189
  {
190
  $attributesSetArray[$key]["id"] = NULL;
191
  $attributesSetArray[$key]["position"] = NULL;
192
  $attributesSetArray[$key]["store_label"] = $value['frontend_label'];
193
+ //$attributesSetArray[$key]["use_default"] = 0;
194
+
195
+ if($isUpdate==false){
196
+ //check if attribute exists and available
197
+ $checkAttribute = Mage::getModel('catalog/resource_eav_attribute')->loadByCode('catalog_product',$attributesSetArray[$key]["attribute_code"]);
198
+
199
+ if(!$checkAttribute->getId() || !$this->_isConfigurable($checkAttribute)){
200
+ throw new Mage_Api_Exception('invalid_variation_attribute', 'Invalid variation attribute ['.$checkAttribute['attribute_code'].']');
201
+ }
202
+ }
203
+
204
  }
205
+ return array($assignedProductsArray, $attributesSetArray);
206
  }
207
 
208
+
209
+ private function _isConfigurable($attribute){
210
+ $isConfigurable = 0;
211
+
212
+ if(isset($attribute['is_global']) && $attribute['is_global']){
213
+ $attribute['scope'] = 'global';
214
+ }
215
+
216
+ if (($attribute['scope'] == 'global') && ($attribute['is_configurable']))
217
+ {
218
+ if(is_array($attribute['apply_to']) && sizeof($attribute['apply_to'])){
219
+ if (in_array('simple', $attribute['apply_to'])) {
220
+ $isConfigurable = 1;
221
+ }
222
+ }elseif(is_string($attribute['apply_to']) && strlen($attribute['apply_to'])){
223
+ if(strpos($attribute['apply_to'],'simple')!==false){
224
+ $isConfigurable = 1;
225
+ }
226
+ }else{
227
+ $isConfigurable = 1;
228
+ }
229
+ }
230
+ return $isConfigurable;
231
+ }
232
+
233
  private function _checkAssignedProductsOptions($availableOptions, & $assignedProductsArray)
234
  {
235
  foreach ($assignedProductsArray as $id => $productOptions)
375
  private function _containsOption($attributeOption, $option)
376
  {
377
  foreach ($attributeOption as $inArrayOption)
378
+ if ($inArrayOption['value_index'] == $option['value_index']) return true;
379
 
380
  return false;
381
  }
382
 
383
  private function _prepareAttributesData($attributesSetArray, $assignedProductsArray)
384
  {
385
+
386
  $_attributesOptions = array();
387
  foreach ($assignedProductsArray as $id => $productOptions)
388
  {
389
  foreach($productOptions as $option)
390
  {
391
+ if (isset($_attributesOptions[$option['attribute_id']]) && !$this->_containsOption($_attributesOptions[$option['attribute_id']], $option))
 
392
  {
393
  $_attributesOptions[$option['attribute_id']][] = $option;
394
  }
402
 
403
  foreach($attributesSetArray as $key => $attribute)
404
  {
405
+ if (isset($_attributesOptions[$attribute['attribute_id']])){
406
  $attributesSetArray[$key]['values'] = $_attributesOptions[$attribute['attribute_id']];
407
+ }
408
  }
409
 
410
  return $attributesSetArray;
411
  }
412
 
413
+ private function _updateConfigurable($store, $productId, $assignedProducts, $assignedAttributes, $identifierType, $isUpdate=false, $reindex=true)
414
  {
415
  $magentoVer = $this->_getCurrentVersion();
416
  if ($magentoVer == 162)
417
  {
418
  $store = Mage::app()->getStore($store)->getId();
419
+ }else{
420
+ $store = NULL;
421
  }
422
 
423
  $product = Mage::helper('catalog/product')->getProduct($productId, $store, $identifierType);
424
+
425
+ $product->setConfigurableProductsData($assignedProducts);
426
 
427
+ if ($isUpdate == false) {
428
+ $product->setConfigurableAttributesData($assignedAttributes);
429
+ $product->setCanSaveConfigurableAttributes(true);
430
  }
431
+
432
+
433
 
434
  try {
435
  $result = $product->save();
436
  }
437
+ catch (Exception $e) {
438
  throw new Mage_Api_Exception('configurable_creating_error', $e->getMessage());
439
  }
440
 
505
 
506
  private function _updateProperties($productData)
507
  {
508
+ if (property_exists($productData, 'status')) {
 
509
  $productData->status = ($productData->status == 1) ? Mage_Catalog_Model_Product_Status::STATUS_ENABLED : Mage_Catalog_Model_Product_Status::STATUS_DISABLED;
510
  }
511
+
 
512
  if (property_exists($productData, 'stock_data') && property_exists($productData->stock_data, 'qty')) {
513
  $productData->stock_data->qty = intval($productData->stock_data->qty);
514
  $productData->stock_data->is_in_stock = 1;
517
  return $productData;
518
  }
519
 
520
+ //TODO: use helper func
521
  private function _objectToArray( $result )
522
  {
523
  $array = array();
586
  }
587
 
588
  private function _currentStoreCode($store=null)
589
+ {
590
+ if ($store != null) {
591
  return $store;
592
  }
593
  return $this->_getStore()->getCode();
595
 
596
  private function _getProductBySku($sku)
597
  {
598
+ if ($sku) {
599
  $product = Mage::getModel('catalog/product');
600
  $productId = $product->getIdBySku((string)$sku);
601
+ if ($productId) {
602
  $product->load($productId);
603
+ if ($product->getId()) {
604
  return $product;
605
  }
606
  }
616
  $mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : '';
617
  $mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store';
618
 
619
+ if ($storeCode != null) {
620
  return Mage::getModel('core/store')->load( $storeCode, 'code');
621
  }
622
 
626
  return Mage::getModel('core/store')->load( $mageRunCode, 'code');
627
  }
628
  } else {
629
+ if ($mageRunType == 'website') {
630
  $websiteCode = empty($mageRunCode) ? '' : $mageRunCode;
631
+ } else {
632
  $websiteCode = empty($mageRunType) ? '' : $mageRunType;
633
  }
634
+
635
  if (!empty($websiteCode))
636
  {
637
  $currentWebSite = Mage::getModel('core/website')->load( $websiteCode, 'code');
638
  $defaultStore = $currentWebSite->getDefaultStore();
639
+ if (isset($defaultStore)){
640
  return $defaultStore;
641
+ }
642
  }
643
  }
644
 
653
 
654
  private function _productAttributeInfo($attribute_id, $attributeAPI)
655
  {
656
+ $model = Mage::getResourceModel('catalog/eav_attribute')->setEntityTypeId(Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId());
 
657
 
658
  $model->load($attribute_id);
659
 
670
  }
671
 
672
  $result = array(
673
+ 'attribute_id' => $model->getId(),
674
+ 'attribute_code' => $model->getAttributeCode(),
675
+ 'frontend_input' => $model->getFrontendInput(),
676
+ 'default_value' => $model->getDefaultValue(),
677
+ 'is_unique' => $model->getIsUnique(),
678
+ 'is_required' => $model->getIsRequired(),
679
+ 'apply_to' => $model->getApplyTo(),
680
+ 'is_configurable' => $model->getIsConfigurable(),
681
+ 'is_searchable' => $model->getIsSearchable(),
682
+ 'is_visible_in_advanced_search' => $model->getIsVisibleInAdvancedSearch(),
683
+ 'is_comparable' => $model->getIsComparable(),
684
+ 'is_used_for_promo_rules' => $model->getIsUsedForPromoRules(),
685
+ 'is_visible_on_front' => $model->getIsVisibleOnFront(),
686
+ 'used_in_product_listing' => $model->getUsedInProductListing(),
687
+ 'scope' => $scope,
688
+ );
689
 
690
  // set options
691
  $options = $attributeAPI->options($model->getId());
719
  return $productData;
720
  }
721
 
 
722
  if (is_array($tmpAttr))
723
  {
724
  foreach ($tmpAttr as $option) {
767
  return $productData;
768
  }
769
 
770
+
771
+ protected function reindexSingleProduct($product){
772
+ $event = Mage::getSingleton('index/indexer')->logEvent( $product, $product->getResource()->getType(), Mage_Index_Model_Event::TYPE_SAVE, false);
773
+ Mage::getSingleton('index/indexer')->getProcessByCode('catalog_url')->setMode(Mage_Index_Model_Process::MODE_REAL_TIME)->processEvent($event);
774
+ }
775
+
776
+ protected function disableIndexing(){
777
+ $processes = Mage::getSingleton('index/indexer')->getProcessesCollection();
778
+ $processes->walk('setMode', array(Mage_Index_Model_Process::MODE_MANUAL));
779
+ $processes->walk('save');
780
+ }
781
+
782
+ protected function enableIndexing(){
783
+ $processes = Mage::getSingleton('index/indexer')->getProcessesCollection();
784
+ $processes->walk('reindexAll');
785
+ $processes->walk('setMode', array(Mage_Index_Model_Process::MODE_REAL_TIME));
786
+ $processes->walk('save');
787
+ }
788
+
789
  /*
790
+ * Helper for productList
791
+ $helper = Mage::helper('api');
792
+ $helper->v2AssociativeArrayUnpacker($data);
793
+ Mage::helper('api')->toArray($data);
794
+
795
+ */
796
+ private function _convertFiltersToArray($filters) {
797
  $arrayParams = array(
798
+ 'nin',
799
+ 'in',
800
+ );
801
 
802
  $preparedFilters = array();
803
+
804
  if (isset($filters->filter)) {
805
  $preparedFilters = $filters->filter;
806
+ }
807
+
808
  if (isset($filters->complex_filter)) {
809
+
810
+ foreach ($filters->complex_filter as $idx=>$data) {
811
+ if (is_object($data->value)) {
812
  //1.8
813
  $field = $data->key;
814
+ $opts = $data->value;
815
+
816
+ } else {
817
+ //1.7
818
  $field = $idx;
819
+ $opts = $data;
820
+ }
821
+
822
+ $value = (in_array($opts->key, $arrayParams)) ? explode(',', $opts->value) : $opts->value;
823
+ $preparedFilters[$field][$opts->key] = $value;
824
  }
825
  }
826
  return $preparedFilters;
827
+ }
828
 
829
+ protected function _log($message) {
830
  Mage::log(print_r($message, true), null, 'LinnLiveExt.log');
831
  }
832
 
840
  if (!$set || !$sku) {
841
  throw new Mage_Api_Exception('data_invalid');
842
  }
843
+
844
+ $this->_updateConfigurableQuantity($productData);
845
+ $productData = $this->_fixAttributes($productData);
846
+
847
+ $store = $this->_currentStoreCode($store);
848
  $defaultStore = $this->_getStore();
849
 
850
  if (property_exists($productData, 'websites') === false && isset($defaultStore) ) {
863
  }
864
 
865
  $productData->categories = $productData->category_ids;
866
+
867
+ //merge into 1?
868
  $productAPI = new Mage_Catalog_Model_Product_Api_V2();
869
  $productId = $productAPI->create('configurable', $set, $sku, $productData, $store);
870
 
871
+ list($assignedProductsArray, $attributesSetArray) = $this->_prepareConfigurableData($productsSet, $attributesSet, false);
872
+ $this->_updateConfigurable($store, $productId, $assignedProductsArray, $attributesSetArray, 'id', false, $reindex);
873
 
874
  return $productId;
875
  }
877
  public function updateConfigurableProduct($productId, $reindex, $productData, $productsSet, $attributesSet, $store=null, $identifierType='id')
878
  {
879
 
880
+ $this->_updateConfigurableQuantity($productData);
881
+ $productData = $this->_fixAttributes($productData);
882
+
883
+
884
+
885
+ $store = $this->_currentStoreCode($store);
886
 
887
  try {
888
  $storeId = Mage::app()->getStore($store)->getId();
899
  }
900
 
901
  $_categoryIds = $_loadedProduct->getCategoryIds();
902
+
903
  if (property_exists($productData, 'category_ids'))
904
  {
905
 
917
 
918
  $productData->category_ids = array_unique($productData->category_ids);
919
 
920
+ if ( (property_exists($productData, 'removed_categories') === true) && (is_array($productData->removed_categories) === true) && (count($productData->removed_categories) > 0) )
 
 
921
  {
922
  $tmpCats = array();
 
923
  $productData->category_ids = array_diff($productData->category_ids, $productData->removed_categories);
924
  }
925
 
942
 
943
  $productAPI->update($productId, $productData, $store, $identifierType);
944
 
945
+ list($assignedProductsArray, $attributesSetArray) = $this->_prepareConfigurableData($productsSet, $attributesSet, true);
946
+ return $this->_updateConfigurable($store, $productId, $assignedProductsArray, $attributesSetArray, $identifierType, true, $reindex);
947
  }
948
 
949
  /*
950
  * Checks if this Magento server has valid Extension installed
951
  */
952
+
953
+ //http://magento18.ixander.eu/api/v2_soap
954
+ public function getGeneralInfo(){
955
+ $config = Mage::getStoreConfig("api/config");
956
+ $verInfo = Mage::getVersionInfo();
957
+
958
+ $result = array(
959
+ 'llc_ver' => Settings::VERSION,
960
+ 'magento_ver' => $verInfo,
961
+ 'php_ver' => phpversion(),
962
+ 'api_config' => $config
963
+ );
964
+
965
+ return $result;
966
+ }
967
+
968
+
969
  public function storesList()
970
  {
971
+ $config = Mage::getStoreConfig("api/config");
972
+
973
+
974
+ //config/stores_admin/api/config
975
+ $verInfo = Mage::getVersionInfo();
976
+
977
+
978
+
979
+ $result = array(
980
+ 'llc_ver' => Settings::VERSION,
981
+ 'magento_ver' => trim("{$verInfo['major']}.{$verInfo['minor']}.{$verInfo['revision']}" . ($verInfo['patch'] != '' ? ".{$verInfo['patch']}" : ""). "-{$verInfo['stability']}{$verInfo['number']}", '.-'),
982
+ 'php_ver' => phpversion(),
983
+ 'api_config'=> $config
984
+ );
985
+ //['config']['stores_admin']['api']['config']
986
+ $this->_log($result);
987
+ return $result;
988
+
989
+
990
  return ($this->_getCurrentVersion() >= 160);
991
  }
992
 
1022
 
1023
  if (in_array($websiteId, $currentWebsites) === true)
1024
  {
1025
+ for ($i = 0; $i < count($currentWebsites); $i++)
1026
  {
1027
  if ($currentWebsites[$i] != $websiteId)
1028
  {
1098
  return true;
1099
  }
1100
 
 
1101
 
1102
+
1103
+
1104
  /*
1105
  * Implementation of catalogProductList because of bug in associativeArray.
1106
  * Extended to filter by category id too.
1109
  * 'type_id' instead of product type.
1110
  */
1111
  public function productList($page, $perPage, $filters = null, $store = null)
1112
+ {
1113
  //get store
1114
  try {
1115
  $storeId = Mage::app()->getStore( $this->_currentStoreCode($store) )->getId();
1117
  catch (Mage_Core_Model_Store_Exception $e) {
1118
  throw new Mage_Api_Exception('store_not_exists', null);
1119
  }
1120
+
1121
  //prepare and convert filters to array
1122
+ $preparedFilters = $this->_convertFiltersToArray($filters);
1123
  if (empty($preparedFilters)) {
1124
  throw new Mage_Api_Exception('filters_invalid', 'Filters not found');
1125
  }
1126
+
1127
  //load collection
1128
  $collection = Mage::getModel('catalog/product')->getCollection()->addStoreFilter($storeId);
1129
+
1130
+ //filter collection by category if exists
1131
  if (isset($preparedFilters['category']) && is_string($preparedFilters['category']))
1132
+ {
1133
+ $_category = Mage::getModel('catalog/category')->load( intval($preparedFilters['category']) );
1134
+
1135
+ if ($_category->getId()) {
 
 
1136
  $collection = $collection->addCategoryFilter($_category);
1137
  }
1138
+
1139
  unset($preparedFilters['category']);
1140
  }
1141
+
1142
  //add prepared filters to collection
1143
  try {
1144
  foreach ($preparedFilters as $field => $value) {
1147
  }
1148
  catch (Mage_Core_Exception $e) {
1149
  throw new Mage_Api_Exception('filters_invalid', $e->getMessage());
1150
+ }
1151
+
1152
 
1153
  if ($page == 1)
1154
  {
1159
  {
1160
  $count = 0;
1161
  $collection->setPageSize($perPage)->setCurPage($page);
1162
+ }
1163
+
1164
  $result = array(
1165
+ 'count'=>$count,
1166
+ 'products'=>array()
1167
+ );
1168
+
1169
  $_assignedIds = array();
1170
  $_fetchedIds = array();
1171
+
1172
  $i = 0;
1173
+ foreach ($collection as $_product) {
1174
+
1175
  if ($i >= ($perPage * $page)) break;//TODO remove
1176
  $_loadedProduct = Mage::helper('catalog/product')->getProduct($_product->getId(), $storeId, 'id');
1177
 
1186
  $_fetchedIds[] = $_loadedProduct->getId();
1187
 
1188
  $result['products'][$i] = array(
1189
+ 'product_id' => $_loadedProduct->getId(),
1190
+ 'sku' => $_loadedProduct->getSku(),
1191
+ 'name' => $_loadedProduct->GetName(),
1192
+ 'set' => $_loadedProduct->getAttributeSetId(),
1193
+ 'type' => $_loadedProduct->getTypeId(),
1194
+ 'price' => $_loadedProduct->getPrice(),
1195
+ 'status' => $_loadedProduct->getStatus(),
1196
+ 'description' => $_description,
1197
+ 'category_ids' => $_loadedProduct->getCategoryIds(),
1198
+ 'website_ids' => $_loadedProduct->getWebsiteIds(),
1199
+ 'assigned_ids' => array(),
1200
+ 'conf_attrib_ids' => array(),
1201
+ 'images' => $_productImages,
1202
+ 'attributes' => $_productAttributes,
1203
+ );
1204
+
1205
+ if ($_loadedProduct->getTypeId() == "configurable")
1206
  {
1207
  $_typeInstance = $_loadedProduct->getTypeInstance();
1208
  $result['products'][$i]['assigned_ids'] = $_typeInstance->getUsedProductIds();
1209
+ foreach($_typeInstance->getConfigurableAttributes() as $attribute) {
1210
  $_prices = array();
1211
  foreach($attribute->getPrices() as $price)
1212
  {
1213
  $_prices[] = array(
1214
+ 'value_index' => $price['value_index'],
1215
+ 'is_fixed' => !$price['is_percent'],
1216
+ 'price_diff' => $price['pricing_value'],
1217
+ 'label' => $price['label'],
1218
+ );
 
1219
  }
1220
 
1221
  $result['products'][$i]['conf_attrib_ids'][] = array(
1222
+ 'code' => $attribute->getProductAttribute()->getAttributeCode(),
1223
+ 'prices' => $_prices
1224
+ );
1225
  }
1226
  $_assignedIds = array_merge($_assignedIds, $result['products'][$i]['assigned_ids']);
1227
  }
1246
  $_productAttributes = $this->_removeIgnoredAttributes($_allAttributes);
1247
 
1248
  $result['products'][] = array(
1249
+ 'product_id' => $_loadedProduct->getId(),
1250
+ 'sku' => $_loadedProduct->getSku(),
1251
+ 'name' => $_loadedProduct->GetName(),
1252
+ 'set' => $_loadedProduct->getAttributeSetId(),
1253
+ 'type' => $_loadedProduct->getTypeId(),
1254
+ 'price' => $_loadedProduct->getPrice(),
1255
+ 'status' => $_loadedProduct->getStatus(),
1256
+ 'description' => $_description,
1257
+ 'category_ids' => $_loadedProduct->getCategoryIds(),
1258
+ 'website_ids' => $_loadedProduct->getWebsiteIds(),
1259
+ 'assigned_ids' => array(),
1260
+ 'conf_attrib_ids' => array(),
1261
+ 'images' => $_productImages,
1262
+ 'attributes' => $this->_removeIgnoredAttributes($_loadedProduct->getData()),
1263
+ );
1264
  }
1265
  }
1266
 
1269
 
1270
  public function productAttributeOptions($setId)
1271
  {
1272
+
1273
  $result = array();
1274
 
1275
  $setId = intval($setId);
1279
 
1280
  $items = $attributeAPI->items($setId);
1281
 
1282
+ $attributes = Mage::getModel('catalog/product')->getResource()->loadAllAttributes();
 
1283
 
 
1284
  foreach ($items as $item) {
1285
  if (!isset($item['attribute_id']) || empty($item['attribute_id'])) continue;
1286
  $attributeId = intval($item['attribute_id']);
1288
 
1289
  $additionInfo = $this->_productAttributeInfo($attributeId, $attributeAPI);
1290
 
1291
+ if (in_array($additionInfo['frontend_input'], $this->_permittedAttributes) && !in_array($additionInfo['attribute_code'], $this->_ignoredAttributes))
 
1292
  {
1293
 
1294
  $attribute = array(
1298
  'required' => $additionInfo['is_required'],
1299
  'scope' => $additionInfo['scope'],
1300
  'can_config' => 0
1301
+ );
1302
+
1303
  if ( ($additionInfo['frontend_input'] == 'select') || ($additionInfo['frontend_input'] == 'multiselect') ) {
1304
+ if (isset($additionInfo['options'])) {
1305
 
1306
+ if (sizeof($additionInfo['options']) && is_array($additionInfo['options'][0]['value'])) {
1307
+ continue;//ignore attributes with multidimensional options
 
 
 
 
 
 
 
 
 
 
 
 
1308
  }
1309
+ $attribute['attribute_options'] = $additionInfo['options'];
1310
  }
1311
+
1312
+ $attribute['can_config'] = $this->_isConfigurable($additionInfo);
1313
  }
1314
+
1315
+ $result[] = $attribute;
 
 
1316
  }
1317
  }
1318
 
1354
 
1355
  $productData->category_ids = array_unique($productData->category_ids);
1356
 
1357
+ if ( (property_exists($productData, 'removed_categories') === true) && (is_array($productData->removed_categories) === true) && (count($productData->removed_categories) > 0) )
 
 
1358
  {
1359
  $tmpCats = array();
1360
 
1389
 
1390
  public function create($type, $set, $sku, $productData, $store = null)
1391
  {
1392
+ $product = $this->_getProductBySku($sku);
1393
+ if ($product) {
1394
  return $product->getId();
1395
  }
1396
+
1397
  $store = $this->_currentStoreCode($store);
1398
 
1399
  $defaultStore = $this->_getStore();
1403
  }
1404
 
1405
  if (property_exists($productData, 'category_ids') && !is_array($productData->category_ids)) {
1406
+ if (is_string($productData->category_ids)){
1407
  $productData->category_ids = array($productData->category_ids);
1408
+ }
1409
+ }else if (property_exists($productData, 'category_ids') === false)
1410
  {
1411
  $productData->category_ids = array();
1412
  }
1427
  $verInfo = Mage::getVersionInfo();
1428
 
1429
  $result = array(
1430
+ 'llc_ver' => Settings::VERSION,
1431
  'magento_ver' => $verInfo
1432
  );
1433
 
1434
  return $result;
1435
  }
1436
+
1437
+ public function getProductStoreURL($productId, $store = null, $identifierType = 'id') {
1438
 
1439
  $storeId = $this->getStoreCode($store);
1440
 
1447
 
1448
  return $_loadedProduct->getProductUrl();
1449
  }
1450
+
1451
+ public function updatePriceBulk($data, $store, $identifierType) {
1452
  $response = array();
1453
+ for ($i = 0; $i< sizeof($data); $i++) {
1454
  $d = $data[$i];
1455
  $product = Mage::helper('catalog/product')->getProduct($d->sku, $store, $identifierType);
1456
+ if ($product && $product->getId()) {
1457
+ if ($product->getPrice()!=$d->price) {
1458
  $product->setPrice($d->price);
1459
  $product->save();
1460
  }
1465
  }
1466
  }
1467
 
1468
+ class LinnLiveEnterprise extends LinnLiveMain {
1469
 
1470
  public function productAttributeOptions($setId)
1471
  {
1476
 
1477
  $attributeAPI = Mage::getModel('catalog/product_attribute_api');
1478
 
1479
+ $attributes = Mage::getModel('catalog/product')->getResource()->loadAllAttributes()->getSortedAttributes($setId);
 
 
 
 
1480
 
1481
  foreach ($attributes as $attribute) {
1482
 
1502
  );
1503
 
1504
  if ( ($attribute->getFrontendInput() == 'select') || ($attribute->getFrontendInput() == 'multiselect') ) {
1505
+ if (($scope == 'global') && $attribute->getIsConfigurable())
 
1506
  {
1507
  if (strpos($attribute->getApplyTo(), 'simple') !== false)
1508
+ $result[]['can_config'] = 1;
1509
  }
1510
 
1511
  $options = $attributeAPI->options($attribute->getId());
1516
  }
1517
 
1518
  if (count($options) > 0) {
1519
+ $result[]['attribute_options'] = $options;
1520
  }
1521
  }
 
1522
  }
1523
  }
1524
 
1596
  }
1597
  }
1598
 
1599
+ class LinnLiveCommunity extends LinnLiveMain {
1600
 
1601
  }
1602
+
1603
  ?>
app/code/local/LinnSystems/LinnLiveConnect/etc/api.xml CHANGED
@@ -61,6 +61,10 @@
61
  <title>Update products in bulk</title>
62
  <acl>linnLive/updateBulk</acl>
63
  </updatePriceBulk>
 
 
 
 
64
  </methods>
65
 
66
  <faults module="linnLiveConnect">
@@ -120,7 +124,10 @@
120
  <code>112</code>
121
  <message>Version is not specified.</message>
122
  </version_not_specified>
123
-
 
 
 
124
  </faults>
125
  </linnLive>
126
  </resources>
@@ -173,6 +180,9 @@
173
  <updatePriceBulk translate="title" module="linnLiveConnect">
174
  <title>Update products in bulk</title>
175
  </updatePriceBulk>
 
 
 
176
  </linnLive>
177
  </resources>
178
  </acl>
61
  <title>Update products in bulk</title>
62
  <acl>linnLive/updateBulk</acl>
63
  </updatePriceBulk>
64
+ <getGeneralInfo translate="title" module="linnLiveConnect">
65
+ <title>Get general information</title>
66
+ <acl>linnLive/getGeneralInfo</acl>
67
+ </getGeneralInfo>
68
  </methods>
69
 
70
  <faults module="linnLiveConnect">
124
  <code>112</code>
125
  <message>Version is not specified.</message>
126
  </version_not_specified>
127
+ <invalid_variation_attribute>
128
+ <code>113</code>
129
+ <message>Invalid variation attribute.</message>
130
+ </invalid_variation_attribute>
131
  </faults>
132
  </linnLive>
133
  </resources>
180
  <updatePriceBulk translate="title" module="linnLiveConnect">
181
  <title>Update products in bulk</title>
182
  </updatePriceBulk>
183
+ <getGeneralInfo translate="title" module="linnLiveConnect">
184
+ <title>Get general info</title>
185
+ </getGeneralInfo>
186
  </linnLive>
187
  </resources>
188
  </acl>
app/code/local/LinnSystems/LinnLiveConnect/etc/config.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <modules>
4
  <LinnSystems_LinnLiveConnect>
5
- <version>1.1.45</version>
6
  </LinnSystems_LinnLiveConnect>
7
  </modules>
8
  <global>
2
  <config>
3
  <modules>
4
  <LinnSystems_LinnLiveConnect>
5
+ <version>1.1.48</version>
6
  </LinnSystems_LinnLiveConnect>
7
  </modules>
8
  <global>
app/code/local/LinnSystems/LinnLiveConnect/etc/wsi.xml CHANGED
@@ -8,6 +8,23 @@
8
  targetNamespace="urn:{{var wsdl.name}}">
9
  <wsdl:types>
10
  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  <!-- Update bulk-->
12
  <xsd:complexType name="linnLiveUpdatePriceBulkRequestDataArray">
13
  <xsd:sequence>
@@ -159,6 +176,7 @@
159
  <xsd:element minOccurs="1" name="value_index" type="xsd:string" />
160
  <xsd:element minOccurs="1" name="is_percent" type="xsd:boolean" />
161
  <xsd:element minOccurs="1" name="pricing_value" type="xsd:double" />
 
162
  </xsd:sequence>
163
  </xsd:complexType>
164
  <!-- Configurable product data sets end -->
@@ -456,6 +474,25 @@
456
  </xsd:complexType>
457
  </xsd:element>
458
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
  <xsd:element name="linnLiveGetProductStoreURLRequestParam">
460
  <xsd:complexType>
461
  <xsd:sequence>
@@ -604,6 +641,14 @@
604
  <wsdl:part name="parameters" element="typens:linnLiveGetStoreCodeResponseParam" />
605
  </wsdl:message>
606
 
 
 
 
 
 
 
 
 
607
  <wsdl:message name="linnLiveGetProductStoreURLRequest">
608
  <wsdl:part name="parameters" element="typens:linnLiveGetProductStoreURLRequestParam" />
609
  </wsdl:message>
@@ -655,7 +700,7 @@
655
  <wsdl:message name="catalogProductAttributeRemoveResponse">
656
  <wsdl:part name="parameters" element="typens:linnLiveAttributeRemoveResponseParam" />
657
  </wsdl:message>
658
- <!-- Stub parameters for catalogProductAttributeRemove end -->
659
 
660
 
661
 
@@ -712,6 +757,12 @@
712
  <wsdl:output message="typens:linnLiveGetProductStoreURLResponse" />
713
  </wsdl:operation>
714
 
 
 
 
 
 
 
715
  <wsdl:operation name="linnLiveUpdatePriceBulk">
716
  <wsdl:documentation>Update products in bulk</wsdl:documentation>
717
  <wsdl:input message="typens:linnLiveUpdatePriceBulkRequest" />
@@ -724,13 +775,13 @@
724
  <wsdl:output message="typens:linnLiveProductListResponse"></wsdl:output>
725
  </wsdl:operation>
726
 
727
- <!-- remove for 1.8 -->
728
  <wsdl:operation name="catalogProductAttributeRemove">
729
  <wsdl:documentation>Stub operation for catalogProductAttributeRemove</wsdl:documentation>
730
  <wsdl:input message="typens:catalogProductAttributeRemoveRequest" />
731
  <wsdl:output message="typens:catalogProductAttributeRemoveResponse" />
732
  </wsdl:operation>
733
- <!-- remove for 1.8 -->
734
 
735
  <wsdl:operation name="linnLiveInfo">
736
  <wsdl:documentation>Get information about current magento settings and installation</wsdl:documentation>
@@ -846,6 +897,17 @@
846
  </wsdl:output>
847
  </wsdl:operation>
848
 
 
 
 
 
 
 
 
 
 
 
 
849
  <wsdl:operation name="linnLiveUpdatePriceBulk">
850
  <soap:operation soapAction="" />
851
  <wsdl:input>
8
  targetNamespace="urn:{{var wsdl.name}}">
9
  <wsdl:types>
10
  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}">
11
+ <!-- Get general version-->
12
+ <xsd:complexType name="linnLiveGetGeneralInfoApiConfigResponseDataArray">
13
+ <xsd:sequence>
14
+ <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:linnLiveGetGeneralInfoApiConfigResponseDataEntity" />
15
+ </xsd:sequence>
16
+ </xsd:complexType>
17
+
18
+ <xsd:complexType name="linnLiveGetGeneralInfoApiConfigResponseDataEntity">
19
+ <xsd:sequence>
20
+ <xsd:element name="charset" type="xsd:string" minOccurs="1" />
21
+ <xsd:element name="session_timeout" type="xsd:string" minOccurs="1" />
22
+ <xsd:element name="compliance_wsi" type="xsd:string" minOccurs="1" />
23
+ <xsd:element name="wsdl_cache_enabled" type="xsd:string" minOccurs="1" />
24
+ </xsd:sequence>
25
+ </xsd:complexType>
26
+ <!-- End get general version-->
27
+
28
  <!-- Update bulk-->
29
  <xsd:complexType name="linnLiveUpdatePriceBulkRequestDataArray">
30
  <xsd:sequence>
176
  <xsd:element minOccurs="1" name="value_index" type="xsd:string" />
177
  <xsd:element minOccurs="1" name="is_percent" type="xsd:boolean" />
178
  <xsd:element minOccurs="1" name="pricing_value" type="xsd:double" />
179
+ <xsd:element minOccurs="1" name="use_default" type="xsd:boolean" />
180
  </xsd:sequence>
181
  </xsd:complexType>
182
  <!-- Configurable product data sets end -->
474
  </xsd:complexType>
475
  </xsd:element>
476
 
477
+ <xsd:element name="linnLiveGetGeneralInfoRequestParam">
478
+ <xsd:complexType>
479
+ <xsd:sequence>
480
+ <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" />
481
+ <xsd:element minOccurs="1" maxOccurs="1" name="version" type="xsd:int" />
482
+ </xsd:sequence>
483
+ </xsd:complexType>
484
+ </xsd:element>
485
+ <xsd:element name="linnLiveGetGeneralInfoResponseParam">
486
+ <xsd:complexType>
487
+ <xsd:sequence>
488
+ <xsd:element minOccurs="1" maxOccurs="1" name="llc_ver" type="xsd:string" />
489
+ <xsd:element minOccurs="1" maxOccurs="1" name="magento_ver" type="xsd:string" />
490
+ <xsd:element minOccurs="1" maxOccurs="1" name="php_ver" type="xsd:string" />
491
+ <xsd:element minOccurs="1" maxOccurs="1" name="api_config" type="typens:linnLiveGetGeneralInfoApiConfigResponseDataArray" />
492
+ </xsd:sequence>
493
+ </xsd:complexType>
494
+ </xsd:element>
495
+
496
  <xsd:element name="linnLiveGetProductStoreURLRequestParam">
497
  <xsd:complexType>
498
  <xsd:sequence>
641
  <wsdl:part name="parameters" element="typens:linnLiveGetStoreCodeResponseParam" />
642
  </wsdl:message>
643
 
644
+ <wsdl:message name="linnLiveGetGeneralInfoRequest">
645
+ <wsdl:part name="parameters" element="typens:linnLiveGetGeneralInfoRequestParam" />
646
+ </wsdl:message>
647
+ <wsdl:message name="linnLiveGetGeneralInfoResponse">
648
+ <wsdl:part name="parameters" element="typens:linnLiveGetGeneralInfoResponseParam" />
649
+ </wsdl:message>
650
+
651
+
652
  <wsdl:message name="linnLiveGetProductStoreURLRequest">
653
  <wsdl:part name="parameters" element="typens:linnLiveGetProductStoreURLRequestParam" />
654
  </wsdl:message>
700
  <wsdl:message name="catalogProductAttributeRemoveResponse">
701
  <wsdl:part name="parameters" element="typens:linnLiveAttributeRemoveResponseParam" />
702
  </wsdl:message>
703
+ <!-- Stub parameters for catalogProductAttributeRemove end -->
704
 
705
 
706
 
757
  <wsdl:output message="typens:linnLiveGetProductStoreURLResponse" />
758
  </wsdl:operation>
759
 
760
+ <wsdl:operation name="linnLiveGetGeneralInfo">
761
+ <wsdl:documentation>Get general information</wsdl:documentation>
762
+ <wsdl:input message="typens:linnLiveGetGeneralInfoRequest" />
763
+ <wsdl:output message="typens:linnLiveGetGeneralInfoResponse" />
764
+ </wsdl:operation>
765
+
766
  <wsdl:operation name="linnLiveUpdatePriceBulk">
767
  <wsdl:documentation>Update products in bulk</wsdl:documentation>
768
  <wsdl:input message="typens:linnLiveUpdatePriceBulkRequest" />
775
  <wsdl:output message="typens:linnLiveProductListResponse"></wsdl:output>
776
  </wsdl:operation>
777
 
778
+ <!-- remove for 1.8 -->
779
  <wsdl:operation name="catalogProductAttributeRemove">
780
  <wsdl:documentation>Stub operation for catalogProductAttributeRemove</wsdl:documentation>
781
  <wsdl:input message="typens:catalogProductAttributeRemoveRequest" />
782
  <wsdl:output message="typens:catalogProductAttributeRemoveResponse" />
783
  </wsdl:operation>
784
+ <!-- remove for 1.8 -->
785
 
786
  <wsdl:operation name="linnLiveInfo">
787
  <wsdl:documentation>Get information about current magento settings and installation</wsdl:documentation>
897
  </wsdl:output>
898
  </wsdl:operation>
899
 
900
+ <wsdl:operation name="linnLiveGetGeneralInfo">
901
+ <soap:operation soapAction="" />
902
+ <wsdl:input>
903
+ <soap:body use="literal" />
904
+ </wsdl:input>
905
+ <wsdl:output>
906
+ <soap:body use="literal" />
907
+ </wsdl:output>
908
+ </wsdl:operation>
909
+
910
+
911
  <wsdl:operation name="linnLiveUpdatePriceBulk">
912
  <soap:operation soapAction="" />
913
  <wsdl:input>
package.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>LinnLiveConnect</name>
4
- <version>1.1.47</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>update prices in bulk added</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-06-25</date>
15
- <time>08:48:09</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="6d34f49d0a9103d6d7d1349abb87759b"/></dir></dir><dir name="etc"><file name="api.xml" hash="75403bf71702d476312343f261337b0b"/><file name="config.xml" hash="717548edb063f515541a7d357242f272"/><file name="wsdl.xml" hash="2b450fd6a6332d20583aaa4fc52012b6"/><file name="wsi.xml" hash="1cf14a4c3fc1c1ab8e7fea32ac1adea9"/></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.48</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>update prices in bulk added</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-07-10</date>
15
+ <time>14:54:00</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="0d4c246963e5fc641b10338f3b8f8d38"/></dir></dir><dir name="etc"><file name="api.xml" hash="be095375b1cd4ebbe91185ae668f8f16"/><file name="config.xml" hash="1a7f272308abe6808c843320b5a74696"/><file name="wsdl.xml" hash="2b450fd6a6332d20583aaa4fc52012b6"/><file name="wsi.xml" hash="bf47087306e0e2067673017558f64417"/></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>