add tag weight and tripping purchasePrice (#32)
This commit is contained in:
parent
ce86a5b6d9
commit
d8b5ba6632
@ -51,7 +51,7 @@ class MoySkladICMLParser
|
|||||||
* @var string $pass - пароль МойСклад
|
* @var string $pass - пароль МойСклад
|
||||||
*/
|
*/
|
||||||
protected $pass;
|
protected $pass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string $shop - имя магазина
|
* @var string $shop - имя магазина
|
||||||
*/
|
*/
|
||||||
@ -87,14 +87,15 @@ class MoySkladICMLParser
|
|||||||
*/
|
*/
|
||||||
public function generateICML()
|
public function generateICML()
|
||||||
{
|
{
|
||||||
|
|
||||||
$assortiment = $this->parseAssortiment();
|
$assortiment = $this->parseAssortiment();
|
||||||
|
|
||||||
$categories = $this->parserFolder();
|
if (count($assortiment) > 0) {
|
||||||
|
$categories = $this->parserFolder();
|
||||||
if (isset($this->options['imgur']) && isset($this->options['imgur']['clientId'])) {
|
} else {
|
||||||
$assortiment = $this->uploadImage($assortiment);
|
$categories = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
$icml = $this->ICMLCreate($categories, $assortiment);
|
$icml = $this->ICMLCreate($categories, $assortiment);
|
||||||
|
|
||||||
if (count($categories) > 0 && count($assortiment) > 0) {
|
if (count($categories) > 0 && count($assortiment) > 0) {
|
||||||
@ -119,7 +120,7 @@ class MoySkladICMLParser
|
|||||||
curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($curlHandler, CURLOPT_TIMEOUT, self::TIMEOUT);
|
curl_setopt($curlHandler, CURLOPT_TIMEOUT, self::TIMEOUT);
|
||||||
curl_setopt($curlHandler, CURLOPT_CONNECTTIMEOUT, 60);
|
curl_setopt($curlHandler, CURLOPT_CONNECTTIMEOUT, 60);
|
||||||
|
|
||||||
if (strripos($url, 'download')) {
|
if (strripos($url, 'download')) {
|
||||||
curl_setopt($curlHandler, CURLOPT_FOLLOWLOCATION, 1);
|
curl_setopt($curlHandler, CURLOPT_FOLLOWLOCATION, 1);
|
||||||
}
|
}
|
||||||
@ -128,19 +129,27 @@ class MoySkladICMLParser
|
|||||||
'Content-Type: application/json'
|
'Content-Type: application/json'
|
||||||
));
|
));
|
||||||
|
|
||||||
$result = curl_exec($curlHandler);
|
|
||||||
|
|
||||||
|
|
||||||
|
$responseBody = curl_exec($curlHandler);
|
||||||
|
$statusCode = curl_getinfo($curlHandler, CURLINFO_HTTP_CODE);
|
||||||
|
$errno = curl_errno($curlHandler);
|
||||||
|
$error = curl_error($curlHandler);
|
||||||
|
|
||||||
curl_close($curlHandler);
|
curl_close($curlHandler);
|
||||||
|
|
||||||
if ($result === false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strripos($url, 'download')) {
|
if (strripos($url, 'download')) {
|
||||||
|
return $responseBody;
|
||||||
return $result;
|
}
|
||||||
|
$result = json_decode($responseBody, true);
|
||||||
|
|
||||||
|
if ($statusCode >= 400) {
|
||||||
|
throw new Exception(
|
||||||
|
$this->getError($result) .
|
||||||
|
" [errno = $errno, error = $error]",
|
||||||
|
$statusCode
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = json_decode($result,true);
|
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
@ -163,44 +172,52 @@ class MoySkladICMLParser
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
$response = $this->requestJson(self::BASE_URL . self::FOLDER_LIST_URL . '?expand=productFolder&limit=100&offset=' . $offset);
|
|
||||||
|
try {
|
||||||
|
$response = $this->requestJson(self::BASE_URL . self::FOLDER_LIST_URL . '?expand=productFolder&limit=100&offset=' . $offset);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e->getMessage();
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response['rows']) {
|
||||||
|
foreach ($response['rows'] as $folder) {
|
||||||
|
if (isset($ignoreCategories['ids']) && is_array($ignoreCategories['ids'])) {
|
||||||
|
|
||||||
foreach ($response['rows'] as $folder) {
|
if (in_array($folder['id'], $ignoreCategories['id'])) {
|
||||||
if (isset($ignoreCategories['ids']) && is_array($ignoreCategories['ids'])) {
|
|
||||||
|
|
||||||
if (in_array($folder['id'], $ignoreCategories['id'])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($folder['productFolder']['id'])) {
|
|
||||||
if (in_array($folder['productFolder']['id'],$ignoreCategories['ids'])) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($ignoreCategories['externalCode']) && is_array($ignoreCategories['externalCode'])) {
|
if (isset($folder['productFolder']['id'])) {
|
||||||
if (in_array($folder['externalCode'],$ignoreCategories['externalCode'])) {
|
if (in_array($folder['productFolder']['id'],$ignoreCategories['ids'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isset($folder['productFolder']['externalCode'])) {
|
|
||||||
if (in_array($folder['productFolder']['externalCode'],$ignoreCategories['externalCode'])) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if($folder['archived'] == false) {
|
if (isset($ignoreCategories['externalCode']) && is_array($ignoreCategories['externalCode'])) {
|
||||||
$categories[] =
|
if (in_array($folder['externalCode'],$ignoreCategories['externalCode'])) {
|
||||||
array(
|
continue;
|
||||||
'name' => $folder['name'],
|
}
|
||||||
'externalCode' => $folder['externalCode'],
|
if (isset($folder['productFolder']['externalCode'])) {
|
||||||
'parentId' => isset($folder['productFolder']) ?
|
if (in_array($folder['productFolder']['externalCode'],$ignoreCategories['externalCode'])) {
|
||||||
$folder['productFolder']['externalCode'] : '',
|
continue;
|
||||||
);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($folder['archived'] == false) {
|
||||||
|
$categories[] =
|
||||||
|
array(
|
||||||
|
'name' => $folder['name'],
|
||||||
|
'externalCode' => $folder['externalCode'],
|
||||||
|
'parentId' => isset($folder['productFolder']) ?
|
||||||
|
$folder['productFolder']['externalCode'] : '',
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($end)) {
|
if (is_null($end)) {
|
||||||
$end = $response['meta']['size'] - self::STEP;
|
$end = $response['meta']['size'] - self::STEP;
|
||||||
} else {
|
} else {
|
||||||
@ -239,9 +256,12 @@ class MoySkladICMLParser
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
try{
|
||||||
$response = $this->requestJson($url.'&offset='.$offset);
|
$response = $this->requestJson($url.'&offset='.$offset);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e->getMessage();
|
||||||
|
return array();
|
||||||
|
}
|
||||||
if ($response && $response['rows']) {
|
if ($response && $response['rows']) {
|
||||||
|
|
||||||
foreach ($response['rows'] as $assortiment) {
|
foreach ($response['rows'] as $assortiment) {
|
||||||
@ -432,7 +452,7 @@ class MoySkladICMLParser
|
|||||||
$xmlstr = '<yml_catalog date="'.$date->format('Y-m-d H:i:s').'"><shop><name>'.$this->shop.'</name></shop></yml_catalog>';
|
$xmlstr = '<yml_catalog date="'.$date->format('Y-m-d H:i:s').'"><shop><name>'.$this->shop.'</name></shop></yml_catalog>';
|
||||||
$xml = new SimpleXMLElement($xmlstr);
|
$xml = new SimpleXMLElement($xmlstr);
|
||||||
|
|
||||||
if (count($categories)) {
|
if (count($categories) > 0) {
|
||||||
$categoriesXml = $this->icmlAdd($xml->shop, 'categories', '');
|
$categoriesXml = $this->icmlAdd($xml->shop, 'categories', '');
|
||||||
foreach ($categories as $category) {
|
foreach ($categories as $category) {
|
||||||
$categoryXml = $this->icmlAdd($categoriesXml, 'category', htmlspecialchars($category['name']));
|
$categoryXml = $this->icmlAdd($categoriesXml, 'category', htmlspecialchars($category['name']));
|
||||||
@ -445,67 +465,77 @@ class MoySkladICMLParser
|
|||||||
}
|
}
|
||||||
|
|
||||||
$offersXml = $this->icmlAdd($xml->shop, 'offers', '');
|
$offersXml = $this->icmlAdd($xml->shop, 'offers', '');
|
||||||
|
if (count($products) > 0) {
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$offerXml = $offersXml->addChild('offer');
|
||||||
|
$offerXml->addAttribute('id', $product['id']);
|
||||||
|
$offerXml->addAttribute('productId', $product['productId']);
|
||||||
|
|
||||||
foreach ($products as $product) {
|
$this->icmlAdd($offerXml, 'xmlId', $product['xmlId']);
|
||||||
$offerXml = $offersXml->addChild('offer');
|
$this->icmlAdd($offerXml, 'price', number_format($product['price'], 2, '.', ''));
|
||||||
$offerXml->addAttribute('id', $product['id']);
|
|
||||||
$offerXml->addAttribute('productId', $product['productId']);
|
|
||||||
|
|
||||||
$this->icmlAdd($offerXml, 'xmlId', $product['xmlId']);
|
if (!isset($this->options['purchasePrice']) || $this->options['purchasePrice'] != false) {
|
||||||
$this->icmlAdd($offerXml, 'price', number_format($product['price'], 2, '.', ''));
|
$this->icmlAdd($offerXml, 'purchasePrice', number_format($product['purchasePrice'], 2, '.', ''));
|
||||||
$this->icmlAdd($offerXml, 'purchasePrice', number_format($product['purchasePrice'], 2, '.', ''));
|
}
|
||||||
$this->icmlAdd($offerXml, 'name', htmlspecialchars($product['name']));
|
|
||||||
$this->icmlAdd($offerXml, 'productName', htmlspecialchars($product['productName']));
|
$this->icmlAdd($offerXml, 'name', htmlspecialchars($product['name']));
|
||||||
$this->icmlAdd($offerXml, 'vatRate', $product['effectiveVat']);
|
$this->icmlAdd($offerXml, 'productName', htmlspecialchars($product['productName']));
|
||||||
|
$this->icmlAdd($offerXml, 'vatRate', $product['effectiveVat']);
|
||||||
|
|
||||||
|
if (!empty($product['url'])) {
|
||||||
|
$this->icmlAdd($offerXml, 'url', htmlspecialchars($product['url']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($product['unit'] != '') {
|
||||||
|
$unitXml = $offerXml->addChild('unit');
|
||||||
|
$unitXml->addAttribute('code', $product['unit']['code']);
|
||||||
|
$unitXml->addAttribute('name', $product['unit']['description']);
|
||||||
|
$unitXml->addAttribute('sym', $product['unit']['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($product['categoryId']) {
|
||||||
|
$this->icmlAdd($offerXml, 'categoryId', $product['categoryId']);
|
||||||
|
}else {
|
||||||
|
$this->icmlAdd($offerXml, 'categoryId', 'warehouseRoot');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($product['article']) {
|
||||||
|
$art = $this->icmlAdd($offerXml, 'param', $product['article']);
|
||||||
|
$art->addAttribute('code', 'article');
|
||||||
|
$art->addAttribute('name', 'Артикул');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($product['weight']) {
|
||||||
|
if (isset($this->options['tagWeight']) && $this->options['tagWeight'] === true) {
|
||||||
|
$wei = $this->icmlAdd($offerXml, 'weight', $product['weight']);
|
||||||
|
} else {
|
||||||
|
$wei = $this->icmlAdd($offerXml, 'param', $product['weight']);
|
||||||
|
$wei->addAttribute('code', 'weight');
|
||||||
|
$wei->addAttribute('name', 'Вес');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($product['code']) {
|
||||||
|
$cod = $this->icmlAdd($offerXml, 'param', $product['code']);
|
||||||
|
$cod->addAttribute('code', 'code');
|
||||||
|
$cod->addAttribute('name', 'Код');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($product['vendor']) {
|
||||||
|
$this->icmlAdd($offerXml, 'vendor', $product['vendor']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($product['image']['imageUrl']) &&
|
||||||
|
!empty($this->options['imageDownload']['pathToImage']) &&
|
||||||
|
!empty($this->options['imageDownload']['site']))
|
||||||
|
{
|
||||||
|
$this->icmlAdd($offerXml, 'picture', $this->saveImage($product['image']));
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($product['url'])) {
|
|
||||||
$this->icmlAdd($offerXml, 'url', htmlspecialchars($product['url']));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($product['unit'] != '') {
|
|
||||||
$unitXml = $offerXml->addChild('unit');
|
|
||||||
$unitXml->addAttribute('code', $product['unit']['code']);
|
|
||||||
$unitXml->addAttribute('name', $product['unit']['description']);
|
|
||||||
$unitXml->addAttribute('sym', $product['unit']['name']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($product['categoryId']) {
|
|
||||||
$this->icmlAdd($offerXml, 'categoryId', $product['categoryId']);
|
|
||||||
}else {
|
|
||||||
$this->icmlAdd($offerXml, 'categoryId', 'warehouseRoot');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($product['article']) {
|
|
||||||
$art = $this->icmlAdd($offerXml, 'param', $product['article']);
|
|
||||||
$art->addAttribute('code', 'article');
|
|
||||||
$art->addAttribute('name', 'Артикул');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($product['weight']) {
|
|
||||||
$wei = $this->icmlAdd($offerXml, 'param', $product['weight']);
|
|
||||||
$wei->addAttribute('code', 'weight');
|
|
||||||
$wei->addAttribute('name', 'Вес');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($product['code']) {
|
|
||||||
$cod = $this->icmlAdd($offerXml, 'param', $product['code']);
|
|
||||||
$cod->addAttribute('code', 'code');
|
|
||||||
$cod->addAttribute('name', 'Код');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($product['vendor']) {
|
|
||||||
$this->icmlAdd($offerXml, 'vendor', $product['vendor']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($product['image']['imageUrl']) &&
|
|
||||||
!empty($this->options['imageDownload']['pathToImage']) &&
|
|
||||||
!empty($this->options['imageDownload']['site']))
|
|
||||||
{
|
|
||||||
$this->icmlAdd($offerXml, 'picture', $this->saveImage($product['image']));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return $xml;
|
return $xml;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -593,7 +623,7 @@ class MoySkladICMLParser
|
|||||||
|
|
||||||
if (file_exists($root . $imgDirrectory . '/' . $image['name']) === false) {
|
if (file_exists($root . $imgDirrectory . '/' . $image['name']) === false) {
|
||||||
$content = $this->requestJson($image['imageUrl']);
|
$content = $this->requestJson($image['imageUrl']);
|
||||||
|
|
||||||
if ($content) {
|
if ($content) {
|
||||||
file_put_contents($root . $imgDirrectory . '/' . $image['name'], $content);
|
file_put_contents($root . $imgDirrectory . '/' . $image['name'], $content);
|
||||||
}
|
}
|
||||||
@ -633,4 +663,56 @@ class MoySkladICMLParser
|
|||||||
|
|
||||||
return $link;
|
return $link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get error.
|
||||||
|
*
|
||||||
|
* @param array
|
||||||
|
* @return string
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
private function getError($result)
|
||||||
|
{
|
||||||
|
$error = "";
|
||||||
|
|
||||||
|
if (!empty($result['errors'])) {
|
||||||
|
foreach ($result['errors'] as $err) {
|
||||||
|
if (!empty($err['parameter'])) {
|
||||||
|
$error .= "'" . $err['parameter']."': ".$err['error'];
|
||||||
|
} else {
|
||||||
|
$error .= $err['error'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($err);
|
||||||
|
|
||||||
|
return $error;
|
||||||
|
} else {
|
||||||
|
if (is_array($result)) {
|
||||||
|
foreach ($result as $value) {
|
||||||
|
if (!empty($value['errors'])) {
|
||||||
|
foreach ($value['errors'] as $err) {
|
||||||
|
if (!empty($err['parameter'])) {
|
||||||
|
$error .= "'" . $err['parameter']."': ".$err['error'];
|
||||||
|
} else {
|
||||||
|
$error .= $err['error'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($err);
|
||||||
|
$error .= " / ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($value);
|
||||||
|
|
||||||
|
if (!empty(trim($error, ' / '))) {
|
||||||
|
return trim($error, ' / ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Internal server error (" . json_encode($result) . ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,8 @@ e) При необходимости включения в генерацию а
|
|||||||
* `file` - Имя файла с итоговым icml без пути (по умолчанию: shopname.catalog.xml)
|
* `file` - Имя файла с итоговым icml без пути (по умолчанию: shopname.catalog.xml)
|
||||||
* `directory` - Директория для итогового icml файла (по умолчанию: текущая директория)
|
* `directory` - Директория для итогового icml файла (по умолчанию: текущая директория)
|
||||||
* `'archivedGoods'` - опция для включения в генерацию архивных товаров и торговых предложений (принимает значения `true` или `false`)
|
* `'archivedGoods'` - опция для включения в генерацию архивных товаров и торговых предложений (принимает значения `true` или `false`)
|
||||||
|
* `'purchasePrice'` - флаг для управление генерацией закупочной цены. Если данная опция установлена в `false` то генерация закупочной цены из сервиса Мой Склад производиться не будет.
|
||||||
|
При активной интеграции RetailCRM -> Мой Склад данная опция должна быть `false`.
|
||||||
* `ignoreCategories` - массив с ключами:
|
* `ignoreCategories` - массив с ключами:
|
||||||
* `ids` - Массив c `id` групп товаров, которые должны быть проигнорированы
|
* `ids` - Массив c `id` групп товаров, которые должны быть проигнорированы
|
||||||
* `externalCodes` - Массив c `внешними кодами` групп товаров, которые должны быть проигнорированы
|
* `externalCodes` - Массив c `внешними кодами` групп товаров, которые должны быть проигнорированы
|
||||||
@ -67,7 +69,9 @@ e) При необходимости включения в генерацию а
|
|||||||
* `imageDownload` - массив, содержащий информацию для загрузки изображений
|
* `imageDownload` - массив, содержащий информацию для загрузки изображений
|
||||||
* `site` - адрес сайта откуда будут отдаваться изображения в retailCRM
|
* `site` - адрес сайта откуда будут отдаваться изображения в retailCRM
|
||||||
* `pathToImage` - путь от корня сайта до дирректории где будут храниться изображения
|
* `pathToImage` - путь от корня сайта до дирректории где будут храниться изображения
|
||||||
|
* `tagWeight` - передача веса в теге `weight` вместо `param`. Единица измерения - килограмм.
|
||||||
|
Формат: положительное число с точностью 0.001 (или 0.000001, в зависимости от настройки RetailCRM "Точность веса": граммы или миллиграммы соответственно), разделитель целой и дробной части - точка.
|
||||||
|
Указывается в свойствах товара сервиса Мой Склад
|
||||||
Все доступные опции не обязательны для использования
|
Все доступные опции не обязательны для использования
|
||||||
|
|
||||||
## Добавление изображения
|
## Добавление изображения
|
||||||
|
@ -4,13 +4,15 @@ include __DIR__ . '/MoySkladICMLParser.php';
|
|||||||
|
|
||||||
// configure
|
// configure
|
||||||
$parser = new MoySkladICMLParser(
|
$parser = new MoySkladICMLParser(
|
||||||
'login@moysklad',
|
|
||||||
|
'admin2@kh',
|
||||||
|
'indoor',
|
||||||
|
'adminlogin',
|
||||||
'password',
|
'password',
|
||||||
'shopname',
|
'shopname',
|
||||||
array(
|
array(
|
||||||
'directory' => __DIR__,
|
'directory' => __DIR__,
|
||||||
'file' => 'test.xml',
|
'file' => 'test.xml',
|
||||||
'archivedGoods' => false,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user