diff --git a/MoySkladICMLParser.php b/MoySkladICMLParser.php index 83559e5..14e780e 100644 --- a/MoySkladICMLParser.php +++ b/MoySkladICMLParser.php @@ -87,29 +87,29 @@ class MoySkladICMLParser */ public function generateICML() { - $assortiment = $this->parseAssortiment(); $countAssortiment = count($assortiment); if ($countAssortiment > 0) { $categories = $this->parserFolder(); + } + + $countCategories = count($categories); + + if ($countCategories > 0) { $assortiment = $this->deleteProduct($categories, $assortiment); - } else { - $categories = array(); } $icml = $this->ICMLCreate($categories, $assortiment); - $countCategories = count($categories); - + if ($countCategories > 0 && $countAssortiment > 0) { $icml->asXML($this->getFilePath()); } - } /** * @param string $url - * @return JSON + * @return string */ protected function requestJson($url) { @@ -147,11 +147,11 @@ class MoySkladICMLParser $result = json_decode($responseBody, true); if ($statusCode >= 400) { - throw new Exception( - $this->getError($result) . + throw new Exception( + $this->getError($result) . " [errno = $errno, error = $error]", $statusCode - ); + ); } return $result; @@ -164,6 +164,7 @@ class MoySkladICMLParser */ protected function parserFolder() { + $categories = []; $offset = 0; $end = null; $ignoreCategories = $this->getIgnoreProductGroupsInfo(); @@ -175,7 +176,7 @@ class MoySkladICMLParser } while (true) { - + try { $response = $this->requestJson(self::BASE_URL . self::FOLDER_LIST_URL . '?expand=productFolder&limit=100&offset=' . $offset); } catch (Exception $e) { @@ -349,17 +350,17 @@ class MoySkladICMLParser ), ); if (isset($this->options['customFields'])) { - if (!empty($assortiment['product']['attributes'])) { - $products[$assortiment['id']]['customFields'] = $this->getCustomFields($assortiment['product']['attributes']); - } elseif (!empty($assortiment['attributes'])){ + if (!empty($assortiment['attributes'])) { $products[$assortiment['id']]['customFields'] = $this->getCustomFields($assortiment['attributes']); + } elseif (!empty($assortiment['product']['attributes'])){ + $products[$assortiment['id']]['customFields'] = $this->getCustomFields($assortiment['product']['attributes']); } } - if (!empty($assortiment['product']['barcodes'])){ - $products[$assortiment['id']]['barcodes'] = $assortiment['product']['barcodes']; - } elseif (!empty($assortiment['barcodes'])){ + if (!empty($assortiment['barcodes'])){ $products[$assortiment['id']]['barcodes'] = $assortiment['barcodes']; + } elseif (!empty($assortiment['product']['barcodes'])){ + $products[$assortiment['id']]['barcodes'] = $assortiment['product']['barcodes']; } if (isset($this->options['loadPurchasePrice']) && $this->options['loadPurchasePrice'] === true) { @@ -367,8 +368,9 @@ class MoySkladICMLParser $products[$assortiment['id']]['purchasePrice'] = (((float)$assortiment['buyPrice']['value']) / 100); } elseif (isset($assortiment['product']['buyPrice']['value'])) { $products[$assortiment['id']]['purchasePrice'] = (((float)$assortiment['product']['buyPrice']['value']) / 100); - } - $products[$assortiment['id']]['purchasePrice'] = 0; + } else { + $products[$assortiment['id']]['purchasePrice'] = 0; + } } if (isset($assortiment['salePrices'][0]['value']) && $assortiment['salePrices'][0]['value'] != 0) { @@ -530,6 +532,7 @@ class MoySkladICMLParser if (!empty($product['customFields']['dimensions'])){ $this->icmlAdd($offerXml, 'dimensions', $product['customFields']['dimensions']); } + if (!empty($product['customFields']['param'])){ foreach($product['customFields']['param'] as $param){ @@ -580,7 +583,7 @@ class MoySkladICMLParser } if ($product['vendor']) { - $this->icmlAdd($offerXml, 'vendor', $product['vendor']); + $this->icmlAdd($offerXml, 'vendor', $product['vendor']); } if (isset($product['image']['imageUrl']) && @@ -685,7 +688,14 @@ class MoySkladICMLParser } if (file_exists($root . $imgDirrectory . '/' . $image['name']) === false) { - $content = $this->requestJson($image['imageUrl']); + + try { + $content = $this->requestJson($image['imageUrl']); + } catch (Exception $e) { + echo $e->getMessage(); + + return false; + } if ($content) { file_put_contents($root . $imgDirrectory . '/' . $image['name'], $content); @@ -819,7 +829,7 @@ class MoySkladICMLParser } } - if (isset($this->options['customFields']['dimensions'])) { + if (isset($this->options['customFields']['paramTag'])) { if ($this->options['customFields']['paramTag']) { foreach ($this->options['customFields']['paramTag'] as $paramTag){ $paramTag = explode('#',$paramTag); @@ -827,7 +837,7 @@ class MoySkladICMLParser foreach($attributes as $attribute) { if ($attribute['id'] == $paramTag[1]) { - $result['param'][] = array('code' => $paramTag[0],'name' => $attribute['name'], 'value'=> $attribute['value']); + $result['param'][] = array('code' => $paramTag[0],'name' => $attribute['name'], 'value'=> htmlspecialchars($attribute['value'])); } } } diff --git a/README.md b/README.md index fe85dbe..e1be487 100644 --- a/README.md +++ b/README.md @@ -59,9 +59,7 @@ e) При необходимости включения в генерацию а * `file` - Имя файла с итоговым icml без пути (по умолчанию: shopname.catalog.xml) * `directory` - Директория для итогового icml файла (по умолчанию: текущая директория) -* `'archivedGoods'` - опция для включения в генерацию архивных товаров и торговых предложений (принимает значения `true` или `false`) -* `'purchasePrice'` - флаг для управление генерацией закупочной цены. Если данная опция установлена в `false` то генерация закупочной цены из сервиса Мой Склад производиться не будет. - При активной интеграции RetailCRM -> Мой Склад данная опция должна быть `false`. +* `archivedGoods` - опция для включения в генерацию архивных товаров и торговых предложений (принимает значения `true` или `false`) * `ignoreCategories` - массив с ключами: * `ids` - Массив c `id` групп товаров, которые должны быть проигнорированы * `externalCode` - Массив c `внешними кодами` групп товаров, которые должны быть проигнорированы @@ -72,14 +70,37 @@ e) При необходимости включения в генерацию а * `tagWeight` - передача веса в теге `weight` вместо `param`. Единица измерения - килограмм. Формат: положительное число с точностью 0.001 (или 0.000001, в зависимости от настройки RetailCRM "Точность веса": граммы или миллиграммы соответственно), разделитель целой и дробной части - точка. Указывается в свойствах товара сервиса Мой Склад. -* `'loadPurchasePrice'` - установка данной опции со значением `true` включает в генерацию закупочные цены. По умолчанию закупочные цены для товаров не генерируются. +* `loadPurchasePrice` - установка данной опции со значением `true` включает в генерацию закупочные цены. По умолчанию закупочные цены для товаров не генерируются. *`customFields` - массив для указания для генерации габаритов (dimensions) и дополнительных параметров товаров. Включает в себя следующие опции: - * `dimensions` - массив с одним или тремя значениями, содержащий id пользовательских полей товара в МС. При указании 3 полей должен соблюдаться порядок 'Длина,Ширина,Высота'. Если -для генерации планируется использовать одно поле, то нужно использовать дополнительный параметр `separate` в котором вы должны указать какой разделитель используется в поле между -значениями на стороне МС. + * `dimensions` - массив с одним или тремя значениями, содержащий id пользовательских полей товара в МС. При указании 3 полей должен соблюдаться порядок 'Длина,Ширина,Высота'. +Пример заполнения: + + `'dimensions' => + [ + '00000000-0000-0000-0000-000000000000', + '00000000-0000-0000-0000-000000000000', + '00000000-0000-0000-0000-000000000000' + ]` + +Если для генерации планируется использовать одно поле, то нужно использовать дополнительный параметр `separate` в котором вы должны указать какой разделитель используется в поле между +значениями на стороне МС. Пример заполнения: + ` + 'separate' => '/', + 'dimensions' => + [ + '00000000-0000-0000-0000-000000000000' + ] +` + * `paramTag` - массив со значениями,складывающимися из кода, который должен использоваться для генерации данного дополнительного параметра и id пользовательского поля товара. Заполняется с разделетелем "#" следующим образом: -'{произвольный_код_латиницей}#{id_пользовательского_свойства_товара}'. -Id пользовательских свойств товара можно получить, совершив GET-запрос к api МС по адресу `https://online.moysklad.ru/api/remap/1.1//entity/product/metadata`, используя для запроса ваш логин и пароль, используемый для генерации каталога. + + `'paramTag'=> + [ + 'somecode1#00000000-0000-0000-0000-000000000000', + 'somecode2#00000000-0000-0000-0000-000000000000' + ]` + +Id пользовательских свойств товара можно получить, совершив GET-запрос к api МС по адресу `https://online.moysklad.ru/api/remap/1.1/entity/product/metadata`, используя для запроса ваш логин и пароль, используемый для генерации каталога. Необходимые id будут указаны внутри индекса "attributes". Все доступные опции не обязательны для использования