403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/grain.iiko/lib/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/grain.iiko/lib/dishes.php
<?php

namespace Grain\Iiko;

use \Bitrix\Main\Localization\Loc;	
use \Bitrix\Main\Config\Option;
use \Grain\Iiko\Rest;
use \Grain\Iiko\Tools;
use \Grain\Iiko\Modifier;
use \Grain\Iiko\ModifierListTable;
use \Grain\Iiko\ModifierImageTable;
use \Grain\Iiko\ServiceListTable;
use \Bitrix\Main\Loader;
use \Bitrix\Iblock\PropertyTable;
use \Bitrix\Iblock\PropertyEnumerationTable;
use \Bitrix\Iblock\IblockTable;
use \Bitrix\Iblock\SectionTable;
use \Bitrix\Main\Web\Json;	

Loc::loadMessages(__FILE__);

class Dishes
{	
	public static function sync() 
	{
		if(
			($restaurantsIblockId=intval($restaurantsIblockId=Option::get('grain.iiko','restaurants_iblock_id')))<=0
			|| !(Loader::includeModule('grain.iikomulti') || !!($apiLogin = Option::get('grain.iiko','api_login')))
			|| !Loader::includeModule('iblock')
		)
			return '\\'.__METHOD__.'();';
		
		$measures = static::getMeasures();
		
		$result = \Bitrix\Iblock\ElementTable::getList(array(
			'filter' => array('IBLOCK_ID'=>$restaurantsIblockId),
			'select' => array('NAME','ID','XML_ID'),
		));
		while($restaurant = $result->fetch())
		{
			$syncDishes = Option::get('grain.iiko','sync_dishes_'.$restaurant['ID'])=='Y';
			$syncSectionsType = Option::get('grain.iiko','sync_dishes_sections_type_'.$restaurant['ID']);
			$syncSections = (Option::get('grain.iiko','sync_dishes_sections_'.$restaurant['ID'])=='Y') && in_array($syncSectionsType,array('group','category'));
			$syncTags = Option::get('grain.iiko','sync_dishes_tags_'.$restaurant['ID'])=='Y';

			if(!$syncDishes && !$syncSections)
				continue;

			$removeAction = Option::get('grain.iiko','sync_dishes_remove_action_'.$restaurant['ID']);
			$doNotChangeCode = Option::get('grain.iiko','sync_dishes_do_not_change_code_'.$restaurant['ID'])=='Y';
			$doNotChangeSort = Option::get('grain.iiko','sync_dishes_do_not_change_sort_'.$restaurant['ID'])=='Y';
			$doNotChangePictures = Option::get('grain.iiko','sync_dishes_do_not_change_pictures_'.$restaurant['ID'])=='Y';
			$doNotChangeDescription = Option::get('grain.iiko','sync_dishes_do_not_change_description_'.$restaurant['ID'])=='Y';
			$doNotChangeWeight = Option::get('grain.iiko','sync_dishes_do_not_change_weight_'.$restaurant['ID'])=='Y';
			$blockedSectionNames = array();
			foreach(preg_split("/\r{0,1}\n/",Option::get('grain.iiko','sync_dishes_blocked_section_names_'.$restaurant['ID'])) as $name)
				if(strlen($name)>0)
					$blockedSectionNames[] = $name;
			$useStopList = Option::get('grain.iiko','sync_dishes_use_stop_list_'.$restaurant['ID'])=='Y';
			$stopListTerminalGroups = array();
			foreach(explode(',',Option::get('grain.iiko','sync_dishes_stop_list_terminal_groups_'.$restaurant['ID'])) as $terminalGroupId)
				if(strlen($terminalGroupId)>0)
					$stopListTerminalGroups[] = $terminalGroupId;

			$stat = array(
				'modified' => 0,
				'added' => 0,
				'deleted' => 0,
				'deactivated' => 0,
				'activated' => 0,
				'modifiedSections' => 0,
				'addedSections' => 0,
				'deletedSections' => 0,
				'deactivatedSections' => 0,
				'activatedSections' => 0,
			);
			
			if(intval($dishesIblockId=Option::get('grain.iiko','dishes_iblock_id_'.$restaurant['ID']))<=0)
				continue;

			$dishes = \Grain\Iiko\Rest::getDishes($restaurant['ID']);

			if($dishes['error'])			
			{
				\CEventLog::Add(Array(
					"SEVERITY" => "CUSTOM",
					"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
					"MODULE_ID" => "grain.iiko",
					"ITEM_ID" => $restaurant['ID'],
					"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_ERROR",array(
						'#NAME#' => $restaurant['NAME'],
						'#ERROR#' => $dishes['error'],
					)),
				));
				continue;
			}

			$stopList = array();
			if($useStopList && count($stopListTerminalGroups)>0) 
			{
				$stopListResult = \Grain\Iiko\Rest::getStopList($restaurant['ID']);
				if(
					!array_key_exists('error', $stopListResult) 
					&& isset($stopListResult['result']['terminalGroupStopLists'][0]['items'])
				) {
					foreach($stopListResult['result']['terminalGroupStopLists'][0]['items'] as $terminalGroupStopList)
					{
						if(isset($terminalGroupStopList['items'])) foreach($terminalGroupStopList['items'] as $stopListItem)
						{
							if(!array_key_exists($stopListItem['productId'], $stopList))
								$stopList[$stopListItem['productId']] = array(
									'inStopListOnAllTerminalGroups' => true,
									'totalQuantity' => 0.0,
									'minimalQuantity' => 1000000.0,
									'items' => array(),
								);
							if(!array_key_exists($terminalGroupStopList['terminalGroupId'], $stopList[$stopListItem['productId']]['items']))
								$stopList[$stopListItem['productId']]['items'][$terminalGroupStopList['terminalGroupId']] = array();
							$stopList[$stopListItem['productId']]['items'][$terminalGroupStopList['terminalGroupId']] = $stopListItem;
							$stopList[$stopListItem['productId']]['totalQuantity'] += floatval($stopListItem['balance']);
							if($stopList[$stopListItem['productId']]['minimalQuantity']>floatval($stopListItem['balance']))
								$stopList[$stopListItem['productId']]['minimalQuantity'] = floatval($stopListItem['balance']);
						}
					}
				}
				foreach($stopList as &$productStopList)
				{
					foreach($stopListTerminalGroups as $terminalGroupId)
					{
						if(!array_key_exists($terminalGroupId, $productStopList['items']))
							$productStopList['inStopListOnAllTerminalGroups'] = false;
					}
				}
				unset($productStopList);
			}

			$event = new \Bitrix\Main\Event("grain.iiko", "OnBeforeDishesSync", array(
				'RESTAURANT' => $restaurant,
				'DISHES_IBLOCK_ID' => $dishesIblockId,
				'DISHES' => $dishes,
				'STOP_LIST' => $stopList,
			));
			$event->send();								
			foreach ($event->getResults() as $eventResult)
			{
				if($eventResult->getType() == \Bitrix\Main\EventResult::ERROR)
					continue;
				if(is_array($eventResultData=$eventResult->getParameters()))
				{
					if(isset($eventResultData['RESTAURANT']))
						$restaurant = $eventResultData['RESTAURANT'];
					if(isset($eventResultData['DISHES_IBLOCK_ID']))
						$dishesIblockId = $eventResultData['DISHES_IBLOCK_ID'];
					if(isset($eventResultData['DISHES']))
						$dishes = $eventResultData['DISHES'];
					if(isset($eventResultData['STOP_LIST']))
						$stopList = $eventResultData['STOP_LIST'];
				}
			}
				
			$priceGroupId = 0;
			if(Loader::includeModule('catalog'))
				$priceGroupId = Option::get('grain.iiko','dishes_price_group_'.$restaurant['ID']);
			$currency = Option::get('grain.iiko','dishes_currency_'.$restaurant['ID']);
			
			$groupsById = array();
			if(is_array($dishes['result']['groups']))
			{
				$c=0;
				while(count($groupsById)<count($dishes['result']['groups']) && $c<=10)
				{
					foreach($dishes['result']['groups'] as $group)
					{
						if(array_key_exists($group['id'], $groupsById))
							continue;
						if(strlen(strval($group['parentGroup']))>0 && !array_key_exists($group['parentGroup'], $groupsById))
							continue;
						$groupsById[$group['id']] = $group;
					}
					$c++;
				}
			}			
			
			if($syncSections)
			{
				$sectionIds = array();
				$allSectionXmlIdList = array();
				
				if($syncSectionsType=='group')
				{
					foreach($groupsById as $group)
					{
						if(in_array($group['name'], $blockedSectionNames))
							continue;
						$image = false;
						if($group['imageLinks'] && $group['imageLinks'][0])
							$image = $group['imageLinks'][0];
						$allSectionXmlIdList[] = $group['id'];
						$resultSection = SectionTable::getList(array(
							'filter' => array(
								'IBLOCK_ID'  => $dishesIblockId,
								'=XML_ID' => $group['id'],								
							),
							'limit' => 1,
							'select' => array('ID','ACTIVE','PICTURE'),
						));
						if($section = $resultSection->fetch())
						{
							$bs = new \CIBlockSection;
							$updateSectionFields = array(
							    'NAME' => $group['name'],
							);
							if(!$doNotChangeCode)
								$updateSectionFields['CODE'] = Tools::getCode($group['name'],$dishesIblockId,'section',$section['ID']);
							if(!$doNotChangeSort)
								$updateSectionFields['SORT'] = $group['order'];
							if(array_key_exists('parentGroup',$group))
								$updateSectionFields['IBLOCK_SECTION_ID'] = isset($sectionIds[$group['parentGroup']])?$sectionIds[$group['parentGroup']]:false;
							if($removeAction=='deactivate' && $section['ACTIVE']=='N')
								$updateSectionFields['ACTIVE'] = 'Y';
							if($image && !$doNotChangePictures)
							{
								$currentPicture = \CFile::GetFileArray($section['PICTURE']);
								if(!$currentPicture || $currentPicture['ORIGINAL_NAME']!=pathinfo($image,PATHINFO_BASENAME))
								{
									$updateSectionFields['PICTURE'] = \CFile::MakeFileArray($image);
								}
							}
							elseif($section['PICTURE'] && !$doNotChangePictures)
							{
								$updateSectionFields['PICTURE'] = array('del'=>'Y');
							}
							$resultSectionUpdate = $bs->update($section['ID'],$updateSectionFields,true,true,true);
							if ($resultSectionUpdate)
							{
								$stat['modifiedSections']++;
								if($removeAction=='deactivate' && $section['ACTIVE']=='N')
									$stat['activatedSections']++;
								$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterSyncSectionAsGroupUpdate", array(
									'RESTAURANT' => $restaurant,
									'FIELDS' => $updateSectionFields,
									'ID' => $section['ID'],
									'GROUP' => $group,
								));
								$event->send();
							} 
							else
							{
								\CEventLog::Add(Array(
									"SEVERITY" => "CUSTOM",
									"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
									"MODULE_ID" => "grain.iiko",
									"ITEM_ID" => $dishesIblockId,
									"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_ERROR_SECTION_UPDATE",array(
										'#CATEGORYID#' => $section['ID'].", ".$group['id'],
										'#ERROR#' => $bs->LAST_ERROR,
									)),
								));
							}							
							$sectionIds[$group['id']] = $section['ID'];
						}
						else
						{
							$bs = new \CIBlockSection;
							$newSectionFields = array(
							    'IBLOCK_ID'  => $dishesIblockId,
							    'XML_ID' => $group['id'],
							    'SORT' => $group['order'],
							    'NAME' => $group['name'],
							    'CODE' => Tools::getCode($group['name'],$dishesIblockId,'section'),
							);
							if($group['parentGroup'])
								$newSectionFields['IBLOCK_SECTION_ID'] = $sectionIds[$group['parentGroup']];
							if($image)
								$newSectionFields['PICTURE'] = \CFile::MakeFileArray($image);
							$newSectionId = $bs->add($newSectionFields,true,true,true);
							if ($newSectionId)
							{
								$sectionIds[$group['id']] = $newSectionId;
								$stat['addedSections']++;
								$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterSyncSectionAsGroupAdd", array(
									'RESTAURANT' => $restaurant,
									'FIELDS' => $newSectionFields,
									'ID' => $newSectionId,
									'GROUP' => $group,
								));
								$event->send();
							}
							else
							{
								\CEventLog::Add(Array(
									"SEVERITY" => "CUSTOM",
									"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
									"MODULE_ID" => "grain.iiko",
									"ITEM_ID" => $dishesIblockId,
									"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_ERROR_SECTION_ADD",array(
										'#CATEGORYID#' => $group['id'],
										'#ERROR#' => $bs->LAST_ERROR,
									)),
								));
							}
						}

					}					
				}
				elseif($syncSectionsType=='category' && is_array($dishes['result']['productCategories']))
				{
					foreach($dishes['result']['productCategories'] as $productCategory)
					{
						if(in_array($productCategory['name'], $blockedSectionNames) || $productCategory['isDeleted'])
							continue;
						$allSectionXmlIdList[] = $productCategory['id'];
						$resultSection = SectionTable::getList(array(
							'filter' => array(
								'IBLOCK_ID'  => $dishesIblockId,
								'=XML_ID' => $productCategory['id'],								
							),
							'limit' => 1,
							'select' => array('ID','ACTIVE'),
						));
						if($section = $resultSection->fetch())
						{
							$bs = new \CIBlockSection;
							$updateSectionFields = array(
							    'NAME' => $productCategory['name'],
							);
							if(!$doNotChangeCode)
								$updateSectionFields['CODE'] = Tools::getCode($productCategory['name'],$dishesIblockId,'section',$section['ID']);
							if($removeAction=='deactivate' && $section['ACTIVE']=='N')
								$updateSectionFields['ACTIVE'] = 'Y';
								
							$resultSectionUpdate = $bs->update($section['ID'],$updateSectionFields);
							if ($resultSectionUpdate)
							{
								$stat['modifiedSections']++;
								if($removeAction=='deactivate' && $section['ACTIVE']=='N')
									$stat['activatedSections']++;
								$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterSyncSectionAsCategoryUpdate", array(
									'RESTAURANT' => $restaurant,
									'FIELDS' => $updateSectionFields,
									'ID' => $section['ID'],
									'CATEGORY' => $category,
								));
								$event->send();
							} 
							else
							{
								\CEventLog::Add(Array(
									"SEVERITY" => "CUSTOM",
									"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
									"MODULE_ID" => "grain.iiko",
									"ITEM_ID" => $dishesIblockId,
									"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_ERROR_SECTION_UPDATE",array(
										'#CATEGORYID#' => $section['ID'].", ".$productCategory['id'],
										'#ERROR#' => $bs->LAST_ERROR,
									)),
								));
							}							
							$sectionIds[$productCategory['id']] =  $section['ID'];
						}
						else
						{
							$bs = new \CIBlockSection;
							$newSectionFields = array(
							    'IBLOCK_ID'  => $dishesIblockId,
							    'XML_ID' => $productCategory['id'],
							    'NAME' => $productCategory['name'],
							    'CODE' =>  Tools::getCode($productCategory['name'],$dishesIblockId,'section'),
							);
							$newSectionId = $bs->add($newSectionFields);
							if ($newSectionId)
							{
								$sectionIds[$productCategory['id']] =  $newSectionId;
								$stat['addedSections']++;
								$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterSyncSectionAsCategoryAdd", array(
									'RESTAURANT' => $restaurant,
									'FIELDS' => $newSectionFields,
									'ID' => $newSectionId,
									'CATEGORY' => $category,
								));
								$event->send();
							}
							else
							{
								\CEventLog::Add(Array(
									"SEVERITY" => "CUSTOM",
									"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
									"MODULE_ID" => "grain.iiko",
									"ITEM_ID" => $dishesIblockId,
									"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_ERROR_SECTION_ADD",array(
										'#CATEGORYID#' => $productCategory['id'],
										'#ERROR#' => $bs->LAST_ERROR,
									)),
								));
							}
						}
						
					}
				}
			}
			
			if($syncDishes)
			{
				self::checkAndCreateProperties($dishesIblockId);
				
				$categoryEnumId = array();
				$rsProperty = PropertyTable::getList(array(
					'filter' => array(
						'IBLOCK_ID'=>$dishesIblockId,
						'=CODE'=>'productcategory',
					),
					'select' => array(
						'ID',
						'CODE',
					),
					'limit' => 1,
				));
				if($property=$rsProperty->fetch())
				{
					$rsEnum = PropertyEnumerationTable::getList(array(
						'filter' => array('PROPERTY_ID'=>$property['ID']),
					));
					while($enum=$rsEnum->fetch())
					{
						$categoryEnumId[$enum['XML_ID']] = $enum['ID'];
					}
					$productCategoryTemp = array();
					foreach($dishes['result']['productCategories'] as $productCategory)
					{
						if($productCategory['isDeleted'])
							continue;
						$productCategoryTemp[] = 'grain-iiko-'.$restaurant['ID'].'-'.$productCategory['id'];
						if(!array_key_exists('grain-iiko-'.$restaurant['ID'].'-'.$productCategory['id'],$categoryEnumId))
						{
							$enumAddResult = PropertyEnumerationTable::add(array(
								'PROPERTY_ID' => $property['ID'],
								'XML_ID' => 'grain-iiko-'.$restaurant['ID'].'-'.$productCategory['id'],
								'VALUE' => $productCategory['name'],
								'SORT' => 500,
							));							
							if($enumAddResult->isSuccess())
							{
								$categoryEnumId['grain-iiko-'.$restaurant['ID'].'-'.$productCategory['id']] = $enumAddResult->getId();
							}
						}
					}
					foreach($categoryEnumId as $xmlId=>$enumId)
					{
						if(in_array($xmlId, $productCategoryTemp))
							continue;
						PropertyEnumerationTable::delete(array('ID'=>$enumId,'PROPERTY_ID' => $property['ID']));
					}
				}
				
				if($syncTags)
				{
					$tagEnumId = array();
					$allTagsEnumId = array();
					$tagsProperty = null;	
					
					$rsProperty = PropertyTable::getList(array(
						'filter' => array(
							'IBLOCK_ID'=>$dishesIblockId,
							'=CODE'=>'tags',
						),
						'select' => array(
							'ID',
							'CODE',
						),
						'limit' => 1,
					));
					if($tagsProperty=$rsProperty->fetch())
					{	
						$rsEnum = PropertyEnumerationTable::getList(array(
							'filter' => array('PROPERTY_ID'=>$tagsProperty['ID']),
						));
						while($enum=$rsEnum->fetch())
						{
							$tagEnumId[$enum['XML_ID']] = $enum['ID'];
						}
					}
				}

				if(is_array($dishes['result']['products']))
				{
					$sizeData = array();
					if(is_array($dishes['result']['sizes']))
						foreach($dishes['result']['sizes'] as $size)
							$sizeData[$size['id']] = $size;
					$modifierData = array();
					$addModifiersAsInactive = Option::get('grain.iiko','add_modifiers_as_inactive')=='Y';
					$modifierIdWithNotEmptyImages = array();
					foreach($dishes['result']['products'] as $product)
					{
						if($product['type']!='Modifier' || !$product['imageLinks'])
							continue;
						$modifierIdWithNotEmptyImages[] = $product['id'];
					}
					foreach($dishes['result']['products'] as $product)
					{
						if($product['type']!='Modifier')
							continue;
						$productData = $product;
						$price = 0.0;
						if(is_array($product['sizePrices']))
						{
							foreach($product['sizePrices'] as $size)
							{
								$price = $size['price']['currentPrice'];
								break;
							}
						}
						$productData['price'] = $price;
						if(array_key_exists('sizePrices', $productData))
							unset($productData['sizePrices']);
						$modifierData[$product['id']] = $productData;
						// Save modifier to modifier list
						$parentGroupId = 0;
						if($product['groupId'])
						{
							$groupChain=array();
							$i=0;
							$iikoGroupId = $product['groupId'];
							while(!!$iikoGroupId && $i++<10)
							{
								if(!$group=$groupsById[$iikoGroupId])
									break; 	
								array_unshift($groupChain,$group);
								$iikoGroupId = $group['parentGroup'];
							}
							$parentGroupId = 0;
							foreach($groupChain as $group)
							{
								$resultGroupList = ModifierListGroupTable::getList(array(
									'filter' => array(
										'ORGANIZATION_ID' => $restaurant['XML_ID'],
										'GROUP_ID' => $group['id'],
									),
									'select' => array('ID','NAME'),
									'limit' => 1,
								));
								if($modifierListGroup=$resultGroupList->fetch())
								{
									$groupUpdateFields = array(
										'NAME' => $group['name'],
										'SORT' => $group['order'],
										'DELETED' => $group['isDeleted']?'Y':'N',
									);
									if($parentGroupId)
										$groupUpdateFields['PARENT_GROUP_ID'] = $parentGroupId;
									$resultUpdate = ModifierListGroupTable::update($modifierListGroup['ID'],$groupUpdateFields);
									$parentGroupId = $modifierListGroup['ID'];
								}
								else
								{
									$groupAddFields = array(
										'ORGANIZATION_ID' => $restaurant['XML_ID'],
										'GROUP_ID' => $group['id'],
										'NAME' => $group['name'],
										'SORT' => $group['order'],
										'ACTIVE' => $addModifiersAsInactive?'N':'Y',
										'DELETED' => $group['isDeleted']?'Y':'N',
									);
									if($parentGroupId)
										$groupAddFields['PARENT_GROUP_ID'] = $parentGroupId;
									$resultAdd = ModifierListGroupTable::add($groupAddFields);
									if ($resultAdd->isSuccess())
										$parentGroupId = $resultAdd->getId();
								}
							}
						}
						$resultModifierList = ModifierListTable::getList(array(
							'filter' => array(
								'ORGANIZATION_ID' => $restaurant['XML_ID'],
								'MODIFIER_ID' => $product['id'],
							),
							'select' => array('ID','NAME'),
							'limit' => 1,
						));
						if($modifierListItem=$resultModifierList->fetch())
						{
							$modifierUpdateFields = array(
								'NAME' => $product['name'],
								'SORT' => $product['order'],
								'DELETED' => $product['isDeleted']?'Y':'N',
							);
							if($parentGroupId)
								$modifierUpdateFields['GROUP_ID'] = $parentGroupId;
							$resultUpdate = ModifierListTable::update($modifierListItem['ID'],$modifierUpdateFields);
							if(!(!$product['imageLinks'] && in_array($product['id'], $modifierIdWithNotEmptyImages)))
								ModifierImageTable::saveImages($modifierListItem['ID'],$product['imageLinks']);
						}
						else
						{
							$modifierAddFields = array(
								'ORGANIZATION_ID' => $restaurant['XML_ID'],
								'MODIFIER_ID' => $product['id'],
								'NAME' => $product['name'],
								'SORT' => $product['order'],
								'ACTIVE' => $addModifiersAsInactive?'N':'Y',
								'DELETED' => $product['isDeleted']?'Y':'N',
							);
							if($parentGroupId)
								$modifierAddFields['GROUP_ID'] = $parentGroupId;
							$resultAdd = ModifierListTable::add($modifierAddFields);
							if($resultAdd->isSuccess() && !(!$product['imageLinks'] && in_array($product['id'], $modifierIdWithNotEmptyImages)))
								ModifierImageTable::saveImages($resultAdd->getId(),$product['imageLinks']);
						}						
						// /Save modifier to modifier list
					}
					$allServiceXmlIdList = array();
					foreach($dishes['result']['products'] as $product)
					{
						if($product['type']!='Service')
							continue;
						$price = 0.0;
						if(is_array($product['sizePrices']))
						{
							foreach($product['sizePrices'] as $size)
							{
								$price = $size['price']['currentPrice'];
								break;
							}
						}
						$allServiceXmlIdList[] = $product['id'];
						// Save service to service list
						$resultServiceList = ServiceListTable::getList(array(
							'filter' => array(
								'ORGANIZATION_ID' => $restaurant['XML_ID'],
								'SERVICE_ID' => $product['id'],
							),
							'select' => array('ID','NAME'),
							'limit' => 1,
						));
						if($serviceListItem=$resultServiceList->fetch())
						{
							$serviceUpdateFields = array(
								'NAME' => $product['name'],
								'CODE' => $product['code'],
								'ORDER_ITEM_TYPE' => $product['orderItemType'],
								'PRICE' => floatval($price),
								'NAME' => $product['name'],
								'DESCRIPTION' => strval($product['description']),
								'ADDITIONAL_INFO' => strval($product['additionalInfo']),
								'SORT' => intval($product['order']),
								'DELETED' => $product['isDeleted']?'Y':'N',
							);
							$resultUpdate = ServiceListTable::update($serviceListItem['ID'],$serviceUpdateFields);
						}
						else
						{
							$serviceAddFields = array(
								'ORGANIZATION_ID' => $restaurant['XML_ID'],
								'SERVICE_ID' => $product['id'],
								'NAME' => $product['name'],
								'CODE' => $product['code'],
								'ORDER_ITEM_TYPE' => $product['orderItemType'],
								'PRICE' => floatval($price),
								'NAME' => $product['name'],
								'DESCRIPTION' => strval($product['description']),
								'ADDITIONAL_INFO' => strval($product['additionalInfo']),
								'SORT' => intval($product['order']),
								'DELETED' => $product['isDeleted']?'Y':'N',
							);
							$resultAdd = ServiceListTable::add($serviceAddFields);							
						}
						// /Save service to service list
					}
					$resultServiceList = ServiceListTable::getList(array(
						'filter' => array(
							'ORGANIZATION_ID' => $restaurant['XML_ID'],
						),
						'select' => array('SERVICE_ID','ID'),
					));
					while($serviceListItem=$resultServiceList->fetch())
					{
						if(in_array($serviceListItem['SERVICE_ID'],$allServiceXmlIdList))
							continue;
						ServiceListTable::delete($serviceListItem['ID']);
					}
					$allProductXmlIdList = array();
					foreach($dishes['result']['products'] as $product)
					{
						if($product['type']=='Modifier' || $product['type']=='Service' || $product['isDeleted'])
							continue;
						$xmlId = $product['id'];
						$image = false;
						if($product['imageLinks'] && $product['imageLinks'][0])
							$image = $product['imageLinks'][0];
						$iblockSectionId=false;
						if($syncSections)
						{
							if($syncSectionsType=='group' && $product['parentGroup'] && $sectionIds[$product['parentGroup']])
								$iblockSectionId = $sectionIds[$product['parentGroup']];
							elseif($syncSectionsType=='category' && $product['productCategoryId'] && $sectionIds[$product['productCategoryId']])
								$iblockSectionId = $sectionIds[$product['productCategoryId']];
						}
						if(!isset($allProductXmlIdList[intval($iblockSectionId)]))
							$allProductXmlIdList[intval($iblockSectionId)] = array();
						$allProductXmlIdList[intval($iblockSectionId)][] = $xmlId;
						$dishesFilter = array("IBLOCK_ID"=>$dishesIblockId,"=XML_ID"=>$xmlId);
						if($syncSections)
							$dishesFilter['IBLOCK_SECTION_ID'] = $iblockSectionId;						
						$rsElements = \CIBlockElement::GetList(
							array(),
							$dishesFilter,
							false,
							array("nTopCount"=>1),
							array("ID","ACTIVE","XML_ID","IBLOCK_ID","NAME","DETAIL_PICTURE","PROPERTY_*")
						);
						$isNewProduct = true;
						if($obElement=$rsElements->GetNextElement()) 
						{
							$isNewProduct = false;
							$arElement = $obElement->GetFields();
							$arElement['PROPERTIES'] = $obElement->GetProperties();
							$elementId = $arElement['ID'];
							
							$el = new \CIBlockElement;
							$updateDishFields = array(
								'NAME' => $product['name'],
							);
							if(!$doNotChangeDescription)
								$updateDishFields['PREVIEW_TEXT'] = $product['description'];							
							if(!$doNotChangeCode)
								$updateDishFields['CODE'] = Tools::getCode($product['name'],$dishesIblockId,'element',$arElement['ID']);
							if(!$doNotChangeSort)
								$updateDishFields['SORT'] = $product['order'];
							if($image && !$doNotChangePictures)
							{
								$currentPicture = \CFile::GetFileArray($arElement['DETAIL_PICTURE']);
								if(!$currentPicture || $currentPicture['ORIGINAL_NAME']!=pathinfo($image,PATHINFO_BASENAME))
								{
									$updateDishFields['DETAIL_PICTURE'] = \CFile::MakeFileArray($image);
								}
							}
							elseif($arElement['DETAIL_PICTURE'] && !$doNotChangePictures)
							{
								$updateDishFields['DETAIL_PICTURE'] = array('del'=>'Y');
							}
							if($removeAction=='deactivate' && $arElement['ACTIVE']=='N')
								$updateDishFields['ACTIVE'] = 'Y';
							if($el->Update($elementId,$updateDishFields,false,true,true))
							{
								$stat['modified']++;
								if($removeAction=='deactivate' && $arElement['ACTIVE']=='N')
									$stat['activated']++;
								$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterSyncElementAsProductUpdate", array(
									'RESTAURANT' => $restaurant,
									'FIELDS' => $updateDishFields,
									'ID' => $elementId,
									'PRODUCT' => $product,
								));
								$event->send();
							} 
							else
							{
								\CEventLog::Add(Array(
									"SEVERITY" => "CUSTOM",
									"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
									"MODULE_ID" => "grain.iiko",
									"ITEM_ID" => $elementId,
									"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_ERROR_UPDATE",array(
										'#DISHID#' => $elementId.', '.$xmlId,
										'#ERROR#' => $el->LAST_ERROR,
									)),
								));
							}
						}
						else
						{
							$el = new \CIBlockElement;
							$newDishFields = array(
								'ACTIVE' => Option::get('grain.iiko','sync_dishes_inactive')=='Y'?'N':'Y',
								'NAME' => $product['name'],
								'XML_ID' => $xmlId,
								'IBLOCK_ID' => $dishesIblockId,
								'SORT' => $product['order'],
								'CODE' => Tools::getCode($product['name'],$dishesIblockId,'element'),
								'PREVIEW_TEXT' => $product['description'],
							);
							if($image)
								$newDishFields['DETAIL_PICTURE'] = \CFile::MakeFileArray($image);
							if($syncSections && $iblockSectionId)
								$newDishFields['IBLOCK_SECTION_ID'] = $iblockSectionId;
							if($elementId=$el->Add($newDishFields,false,true,true))
							{
								$stat['added']++;
								$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterSyncElementAsProductAdd", array(
									'RESTAURANT' => $restaurant,
									'FIELDS' => $newDishFields,
									'ID' => $elementId,
									'PRODUCT' => $product,
								));
								$event->send();								
							}
							else
							{
								\CEventLog::Add(Array(
									"SEVERITY" => "CUSTOM",
									"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
									"MODULE_ID" => "grain.iiko",
									"ITEM_ID" => $xmlId,
									"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_ERROR_ADD",array(
										'#DISHID#' => $xmlId,
										'#ERROR#' => $el->LAST_ERROR,
									)),
								));
								continue;
							}
						}
						
						$sizes = array();
						$n=0;
						$price = 0.0;
						if(is_array($product['sizePrices']))
						{
							$sizePrices = $product['sizePrices'];
							// sort and make default first if no default size
							if(count($sizePrices)>1)
							{
								usort($sizePrices,function($a,$b) use ($sizeData) {
									if(
										!isset($a['sizeId']) 
										|| !isset($sizeData[$a['sizeId']]['priority']) 
										|| !isset($b['sizeId']) 
										|| !isset($sizeData[$b['sizeId']]['priority'])
										|| $sizeData[$a['sizeId']]['priority'] == $sizeData[$b['sizeId']]['priority']
									)
										return 0;
									return intval($sizeData[$a['sizeId']]['priority'])>intval($sizeData[$b['sizeId']]['priority']);
								});
								$defaultSizeId = false;
								foreach($sizePrices as $sz)
								{
									if(!$sz['sizeId'] || !$sizeData[$sz['sizeId']] || !$sizeData[$sz['sizeId']]['isDefault'])
										continue;
									$defaultSizeId = $sz['sizeId'];
									break;
								}
								if($defaultSizeId===false)
								{
									foreach($sizePrices as $ksz=>$sz)
									{
										if(!$sz['sizeId'] || !$sizeData[$sz['sizeId']])
											break;
										$defaultSizeId = $sz['sizeId'];
										break;
									}
								}
							}
							// /sort and make default first if no default size
							foreach($sizePrices as $sz)
							{
								if(count($sizePrices)==1)
								{
									$price = $sz['price']['currentPrice'];
								}
								elseif(!!$sz['sizeId'] && !!$sizeData[$sz['sizeId']])
								{
									if($sz['sizeId']==$defaultSizeId)
										$price = $sz['price']['currentPrice'];
									$size = $sz;
									$size['s'] = $sizeData[$sz['sizeId']];
									$sizeJson = Json::encode($size);
									$sizes['n'.($n++)] = $sizeJson;
								}
							}
						}
						if(Loader::includeModule('catalog'))
						{
							static::savePrice($priceGroupId,$price,$elementId,$currency);
							$productUpdateFields = array();
							if($measures['DEFAULT']>0)
								$productUpdateFields['MEASURE'] = $measures['DEFAULT'];
							if(!empty($product['measureUnit']) && isset($measures['MAP'][$product['measureUnit']]))
							{
								$measure = $measures['MAP'][$product['measureUnit']];
								$productUpdateFields['MEASURE'] = $measure['ID'];
							}
							if(
								$useStopList
								&& isset($stopList[$product['id']]) 
								&& $stopList[$product['id']]['inStopListOnAllTerminalGroups']
							) {
								$quantity = $stopList[$product['id']]['minimalQuantity'];
								$productUpdateFields['QUANTITY'] = $quantity;
								$productUpdateFields['QUANTITY_TRACE'] = 'Y';
								$productUpdateFields['CAN_BUY_ZERO'] = 'N';
								$productUpdateFields['NEGATIVE_AMOUNT_TRACE'] = 'Y';
								$productUpdateFields['AVAILABLE'] = $quantity>0?'Y':'N';
							}
							else
							{
								$productUpdateFields['QUANTITY'] = '0';
								$productUpdateFields['QUANTITY_TRACE'] = 'N';
								$productUpdateFields['CAN_BUY_ZERO'] = 'Y';
								$productUpdateFields['NEGATIVE_AMOUNT_TRACE'] = 'Y';
								$productUpdateFields['AVAILABLE'] = 'Y';
							}								
							if($productUpdateFields)
								\Bitrix\Catalog\ProductTable::update($elementId,$productUpdateFields);
							$measureRatio = 1;
							if($measure['SYMBOL_LETTER_INTL']=='KGM')
								$measureRatio = 0.02;
							elseif($measure['SYMBOL_LETTER_INTL']=='GRM')
								$measureRatio = 20;
							$currentMeasureRatio = \Bitrix\Catalog\MeasureRatioTable::getList(array(
								'select' => array('ID', 'PRODUCT_ID'),
								'filter' => array('=PRODUCT_ID' => $elementId, '=IS_DEFAULT' => 'Y'),
							))->fetch();
							if(!empty($currentMeasureRatio))
							{
								\Bitrix\Catalog\MeasureRatioTable::update(intval($currentMeasureRatio['ID']), array(
									'RATIO' => $measureRatio,
								));
							}
							else
							{
								\Bitrix\Catalog\MeasureRatioTable::add(array(
									'PRODUCT_ID' => $elementId, 
									'RATIO' => $measureRatio, 
									'IS_DEFAULT' => 'Y',
								));
							}
						}
						else
						{
							\CIBlockElement::SetPropertyValueCode($elementId, 'price', $price);
						}
						$modifiers = array();
						$n=0;
						if($product['modifiers'])
						{
							foreach($product['modifiers'] as $mod)
							{
								if(!$modifierData[$mod['id']])
									continue;
								$modifier = $mod;
								$modifier['m'] = $modifierData[$mod['id']];
								$modifierJson = Json::encode($modifier);
								$modifiers['n'.($n++)] = $modifierJson;
							}
						}	 
						if($product['groupModifiers'])
						{
							foreach($product['groupModifiers'] as $group)
							{
								foreach($group['childModifiers'] as $mod)
								{									
									if(!$modifierData[$mod['id']])
										continue;
									/*
									if(!$group['childModifiersHaveMinMaxRestrictions'])
									{
										$mod['maxAmount'] = $group['maxAmount'];
										$mod['minAmount'] = $group['minAmount'];
									}
									*/
									$modifier = $mod;
									$modifier['groupId'] = $group['id'];
									$modifier['groupName'] = $groupsById[$group['id']]['name'];								
									$modifier['groupRequired'] = $group['required'];								
									$modifier['groupMinAmount'] = $group['minAmount'];								
									$modifier['groupMaxAmount'] = $group['maxAmount'];								
									$modifier['m'] = $modifierData[$mod['id']];
									$modifierJson = Json::encode($modifier);
									$modifiers['n'.($n++)] = $modifierJson;
								}
							}
						}

						// in order to not count value_id, but if something changes, we need to update all values to save sorting
						$sizesChanged = false;
						if(!$arElement || !$arElement['PROPERTIES']['sizes']['~VALUE'] || count($sizes)!=count($arElement['PROPERTIES']['sizes']['~VALUE']))
						{
							$sizesChanged = true;
						}
						else
						{
							$sizesCheck = array_values($sizes);
							foreach($arElement['PROPERTIES']['sizes']['~VALUE'] as $key=>$sizeJson)
							{
								if($sizesCheck[$key]!=$sizeJson)
								{
									$sizesChanged = true;
									break;
								}
							}
						}

						if($sizesChanged)	
							\CIBlockElement::SetPropertyValueCode($elementId, 'sizes', $sizes);
						
						// in order to not count value_id, but if something changes, we need to update all values to save sorting
						$modifiersChanged = false;
						if(!$arElement || !$arElement['PROPERTIES']['modifiers']['~VALUE'] || count($modifiers)!=count($arElement['PROPERTIES']['modifiers']['~VALUE']))
						{
							$modifiersChanged = true;
						}
						else
						{
							$modifiersCheck = array_values($modifiers);
							foreach($arElement['PROPERTIES']['modifiers']['~VALUE'] as $key=>$modifierJson)
							{
								if($modifiersCheck[$key]!=$modifierJson)
								{
									$modifiersChanged = true;
									break;
								}
							}
						}
						
						if($modifiersChanged)	
							\CIBlockElement::SetPropertyValueCode($elementId, 'modifiers', $modifiers);
						
						\CIBlockElement::SetPropertyValueCode($elementId, 'productcategory', $categoryEnumId['grain-iiko-'.$restaurant['ID'].'-'.$product['productCategoryId']]);

						if($syncTags && is_array($tagsProperty))
						{ 
							$tagsUpdate = array();
							if(is_array($product['tags']))
							{
								foreach($product['tags'] as $tag)
								{
									$tag = trim($tag);
									if(strlen($tag)<=0)
										continue;
									$code = \CUtil::translit($tag, LANGUAGE_ID, array(
										"max_len" => 100,
										"change_case" => 'L',
										"replace_space" => '-',
										"replace_other" => '-',
										"delete_repeat_replace" => true,
									));
									if(array_key_exists($code,$tagEnumId))
									{
										$tagsUpdate[] = $tagEnumId[$code];
										$allTagsEnumId[] = $tagEnumId[$code];
									}
									else
									{
										$enumAddResult = PropertyEnumerationTable::add(array(
											'PROPERTY_ID' => $tagsProperty['ID'],
											'XML_ID' => $code,
											'VALUE' => $tag,
											'SORT' => 500,
										));							
										if($enumAddResult->isSuccess())
										{
											$tagsUpdate[] = $enumAddResult->getId();
											$allTagsEnumId[] = $enumAddResult->getId();
											$tagEnumId[$code] = $enumAddResult->getId();
										}
									}
								}
							}
							\CIBlockElement::SetPropertyValueCode($elementId, 'tags', $tagsUpdate);
						}
						 
						$propToProduct = array(
							'carbohydrateamount' => 'carbohydratesAmount',
							'carbohydratefullamount' => 'carbohydratesFullAmount',
							'donotprintincheque' => 'doNotPrintInCheque',
							'energyamount' => 'energyAmount',
							'energyfullamount' => 'energyFullAmount',
							'fatamount' => 'fatAmount',
							'fatfullamount' => 'fatFullAmount',
							'fiberamount' => 'fiberAmount', // biz
							'fiberfullamount' => 'fiberFullAmount', // biz
							'proteinsamount' => 'proteinsAmount',
							'proteinsfullamount' => 'proteinsFullAmount',
							'measureunit' => 'measureUnit',
							'type' => 'type',
							'isincludedinmenu' => 'isIncludedInMenu',
							'code' => 'code',
						);
						if($isNewProduct || !$doNotChangeWeight)
							$propToProduct['weight'] = 'weight';
						foreach($propToProduct as $propCode=>$productKey)
							\CIBlockElement::SetPropertyValueCode($elementId, $propCode, ($arElement && $arElement['PROPERTIES'][$propCode]['PROPERTY_VALUE_ID'])?array($arElement['PROPERTIES'][$propCode]['PROPERTY_VALUE_ID']=>array('VALUE'=>$product[$productKey])):$product[$productKey]);
						if($isNewProduct || !$doNotChangeWeight)
							\Bitrix\Catalog\ProductTable::update($elementId,array('WEIGHT'=>floatval($product['weight'])*1000));
						$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterSyncElementAsProductPropertyUpdate", array(
							'RESTAURANT' => $restaurant,
							'PROP_TO_PRODUCT' => $propToProduct,
							'ID' => $elementId,
							'PRODUCT' => $product,
						));
						$event->send();
					}					
					if($removeAction=='delete' || $removeAction=='deactivate')
					{
						$resultProductDeleteList = \Bitrix\Iblock\ElementTable::getList(array(
							'filter' => array('IBLOCK_ID'=>$dishesIblockId),
							'select' => array('ID','XML_ID','IBLOCK_SECTION_ID'),
						));
						while($productToDelete = $resultProductDeleteList->fetch())
						{
							if(
								isset($allProductXmlIdList[intval($productToDelete['IBLOCK_SECTION_ID'])]) 
								&& in_array($productToDelete['XML_ID'],$allProductXmlIdList[intval($productToDelete['IBLOCK_SECTION_ID'])])
							)
								continue;
							if($removeAction=='delete')
							{
								$resultProductDelete = \CIBlockElement::delete($productToDelete['ID']);
								if($resultProductDelete)
								{
									$stat['deleted']++;
									$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterSyncElementAsProductDelete", array(
										'RESTAURANT' => $restaurant,
										'ID' => $productToDelete['ID'],
									));
									$event->send();
								}
								else
								{
									\CEventLog::Add(Array(
										"SEVERITY" => "CUSTOM",
										"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
										"MODULE_ID" => "grain.iiko",
										"ITEM_ID" => $dishesIblockId,
										"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_ERROR_DELETE",array(
											'#DISHID#' => $productToDelete['id'],
											'#ERROR#' => $bs->LAST_ERROR,
										)),
									));
								}
							}
							elseif($removeAction=='deactivate')
							{
								$bs = new \CIBlockElement;
								$resultProductDeactivate = $bs->update($productToDelete['ID'],array('ACTIVE'=>'N'));
								if($resultProductDeactivate)
								{
									$stat['deactivated']++;
									$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterSyncElementAsProductDeactivate", array(
										'RESTAURANT' => $restaurant,
										'ID' => $productToDelete['ID'],
									));
									$event->send();
								}
								else
								{
									\CEventLog::Add(Array(
										"SEVERITY" => "CUSTOM",
										"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
										"MODULE_ID" => "grain.iiko",
										"ITEM_ID" => $dishesIblockId,
										"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_ERROR_DEACTIVATE",array(
											'#DISHID#' => $productToDelete['id'],
											'#ERROR#' => $bs->LAST_ERROR,
										)),
									));
								}
							}
						}
					}
				}
			}
			
			if($syncSections)
			{
				if($removeAction=='delete' || $removeAction=='deactivate')
				{
					$resultSectionDeleteList = \Bitrix\Iblock\SectionTable::getList(array(
						'filter' => array('IBLOCK_ID'=>$dishesIblockId),
						'select' => array('ID','XML_ID'),
					));
					
					while($sectionToDelete = $resultSectionDeleteList->fetch())
					{
						if(in_array($sectionToDelete['XML_ID'],$allSectionXmlIdList))
							continue;
						if($removeAction=='delete')
						{
							$resultSectionDelete = \CIBlockSection::delete($sectionToDelete['ID']);
							if($resultSectionDelete)
							{
								$stat['deletedSections']++;
								$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterSyncSectionDelete", array(
									'RESTAURANT' => $restaurant,
									'ID' => $sectionToDelete['ID'],
								));
								$event->send();
							}
							else
							{
								\CEventLog::Add(Array(
									"SEVERITY" => "CUSTOM",
									"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
									"MODULE_ID" => "grain.iiko",
									"ITEM_ID" => $dishesIblockId,
									"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_ERROR_SECTION_DELETE",array(
										'#CATEGORYID#' => $sectionToDelete['id'],
										'#ERROR#' => "",
									)),
								));
							}
						}
						elseif($removeAction=='deactivate')
						{
							$bs = new \CIBlockSection;
							$resultSectionDeactivate = $bs->update($sectionToDelete['ID'],array('ACTIVE'=>'N'));
							if($resultSectionDeactivate)
							{
								$stat['deactivatedSections']++;
								$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterSyncSectionDeactivate", array(
									'RESTAURANT' => $restaurant,
									'ID' => $sectionToDelete['ID'],
								));
								$event->send();
							}
							else
							{
								\CEventLog::Add(Array(
									"SEVERITY" => "CUSTOM",
									"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
									"MODULE_ID" => "grain.iiko",
									"ITEM_ID" => $dishesIblockId,
									"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_ERROR_SECTION_DEACTIVATE",array(
										'#CATEGORYID#' => $sectionToDelete['id'],
										'#ERROR#' => $bs->LAST_ERROR,
									)),
								));
							}
						}
					}
				}
			}
			
			if($syncTags && is_array($tagsProperty) && $removeAction=='delete')
			{ 
				foreach($tagEnumId as $enumId)
				{
					if(in_array($enumId,$allTagsEnumId))
						continue;
					PropertyEnumerationTable::delete(array('ID'=>$enumId,'PROPERTY_ID' => $tagsProperty['ID']));
				}
			}
				
			\CEventLog::Add(Array(
				"SEVERITY" => "CUSTOM",
				"AUDIT_TYPE_ID" => "GRAIN_IIKO_DISHES_SYNC",
				"MODULE_ID" => "grain.iiko",
				"ITEM_ID" => $dishesIblockId,
				"DESCRIPTION" => Loc::getMessage("GRAIN_IIKO_DISHES_SYNC_SUCCESS",array(
					'#NAME#' => $restaurant['NAME'],
					'#ADDED#' => $stat['added'],
					'#MODIFIED#' => $stat['modified'],
					'#DELETED#' => $stat['deleted'],
					'#DEACTIVATED#' => $stat['deactivated'],
					'#ACTIVATED#' => $stat['activated'],
					'#ADDED_SECTIONS#' => $stat['addedSections'],
					'#MODIFIED_SECTIONS#' => $stat['modifiedSections'],
					'#DELETED_SECTIONS#' => $stat['deletedSections'],
					'#DEACTIVATED_SECTIONS#' => $stat['deactivatedSections'],
					'#ACTIVATED_SECTIONS#' => $stat['activatedSections'],
				)),
			));
			
			$event = new \Bitrix\Main\Event("grain.iiko", "OnAfterDishesSync", array(
				'RESTAURANT' => $restaurant,
				'DISHES_IBLOCK_ID' => $dishesIblockId,
				'STAT' => $stat,
				'DISHES' => $dishes,
				'SECTION_ID' => $sectionIds,
				'CATEGORY_ENUM_ID' => $categoryEnumId,
				'STOP_LIST' => $stopList,
			));
			$event->send();								
		}

		return '\\'.__METHOD__.'();';
	}

	public static function getMeasures()
	{
		$measures = array(
			'DEFAULT' => 0,
			'MAP' => array(),
		);
		if(!Loader::includeModule('catalog'))
			return $measures;
		$rsMeasure = \Bitrix\Catalog\MeasureTable::getList(array(
			'select' => array('ID', 'CODE', 'MEASURE_TITLE','SYMBOL','IS_DEFAULT','SYMBOL_LETTER_INTL'),
		));
		while($measure=$rsMeasure->fetch())
		{
			if (empty($measure['MEASURE_TITLE']))
			{
				$measure['MEASURE_TITLE'] = \CCatalogMeasureClassifier::getMeasureTitle($measure['CODE'], 'MEASURE_TITLE');
			}
			if (empty($measure['SYMBOL']))
			{
				$measure['SYMBOL'] = \CCatalogMeasureClassifier::getMeasureTitle($measure['CODE'], 'SYMBOL_RUS');
			}
			if(!empty($measure['SYMBOL']))
				$measures['MAP'][$measure['SYMBOL']] = $measure;
			if($measure['IS_DEFAULT']=='Y')
				$measures['DEFAULT']=$measure['ID'];
		}
		return $measures;
	}

	public static function checkAndCreateProperties($dishesIblockId)
	{
		$rsIblock = IblockTable::getList(array(
			'filter' => array(
				'=ID'=>$dishesIblockId,
				'ACTIVE'=>'Y',
			),
			'select' => array(
				'ID',
				'CODE',
			),
			'limit' => 1,
		));
		
		if(!($iblock=$rsIblock->fetch()))
			return false;
		
		$propertyList = array(
			array(
				'CODE' => 'code',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'carbohydrateamount',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'carbohydratefullamount',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'donotprintincheque',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'energyamount',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'energyfullamount',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'fatamount',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'fatfullamount',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array( // biz
				'CODE' => 'fiberamount',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array( // biz
				'CODE' => 'fiberfullamount',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array( 
				'CODE' => 'proteinsamount',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array( 
				'CODE' => 'proteinsfullamount',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'measureunit',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'type',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'weight',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'isincludedinmenu',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'COL_COUNT'=>'60',
			),
			array(
				'CODE' => 'tags',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_LIST,
				'MULTIPLE'=>'Y',
				'ROW_COUNT' => 1,
			),
			array(
				'CODE' => 'productcategory',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_LIST,
				'ROW_COUNT' => 1,
			),
			array(
				'CODE' => 'modifiers',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'MULTIPLE'=>'Y',
				'USER_TYPE'=>'grain_iiko_modifier',
			),
			array(
				'CODE' => 'sizes',
				'PROPERTY_TYPE'=>PropertyTable::TYPE_STRING,
				'MULTIPLE'=>'Y',
				'USER_TYPE'=>'grain_iiko_modifier',
			),
		);
		if(!Loader::includeModule('catalog'))
			$propertyList[] = array(
				'CODE' => 'price',
				'PROPERTY_TYPE' => PropertyTable::TYPE_NUMBER
			);
		
		$event = new \Bitrix\Main\Event("grain.iiko", "OnSyncProductPropertyList", array(
			'PROPERTY_LIST' => $propertyList,
		));
		$event->send();
		foreach ($event->getResults() as $eventResult)
		{
			if($eventResult->getType() == \Bitrix\Main\EventResult::ERROR)
				continue;
			if($eventResult->getParameters())
				$propertyList = $eventResult->getParameters();
		}
		$sort = 100;		
		foreach($propertyList as $propertyData)
		{
			$rsProperty = PropertyTable::getList(array(
				'filter' => array(
					'IBLOCK_ID'=>$dishesIblockId,
					'=CODE'=>$propertyData['CODE'],
				),
				'select' => array(
					'ID',
					'CODE',
				),
				'limit' => 1,
			));
			if(!$property=$rsProperty->fetch())
			{
				$newPropertyFields = array_merge($propertyData,array(
					'IBLOCK_ID' => $dishesIblockId,
					'NAME' => $propertyData['NAME']?$propertyData['NAME']:Loc::getMessage('GRAIN_IIKO_DISHES_SYNC_PROP_'.strtoupper($propertyData['CODE'])),
					'ACTIVE' => 'Y',
					'SORT' => $sort,
				));
				PropertyTable::add($newPropertyFields);
			}
			$sort+=10;			
		}
		
		return true;
	}


	public static function savePrice($catalogGroupId,$price,$productId,$currency='RUB')
	{		
		if(!$catalogGroupId || !$productId || !$currency)
			return array(Loc::getMessage('GRAIN_IIKO_DISHES_SYNC_ERROR_WRONG_PARAMETERS'));

		$price = floatval($price);

		$rsP = \Bitrix\Catalog\PriceTable::getList(array(
			'filter' => array('CATALOG_GROUP_ID'=>$catalogGroupId,'PRODUCT_ID'=>$productId),
		));
	
		$newProduct = array(
			'ID' => $productId,
			'QUANTITY' => '0',
			'QUANTITY_TRACE' => 'N',
			'CAN_BUY_ZERO' => 'Y',
			'NEGATIVE_AMOUNT_TRACE' => 'Y',
			'AVAILABLE' => 'Y',			
		);
	
		if($arP=$rsP->fetch())
		{
			$arProduct = \Bitrix\Catalog\ProductTable::getById($productId)->fetch();			
			if(!$arProduct)
				\Bitrix\Catalog\ProductTable::add($newProduct);
			$result = \Bitrix\Catalog\PriceTable::update($arP['ID'],array(
				'PRICE'=>$price,
				'PRICE_SCALE'=>$price,
				'CURRENCY'=>$currency,
			));
		}
		else
		{
			$arProduct = \Bitrix\Catalog\ProductTable::getById($productId)->fetch();
			if(!$arProduct)
				\Bitrix\Catalog\ProductTable::add($newProduct);
			$result = \Bitrix\Catalog\PriceTable::add(array(
				'CATALOG_GROUP_ID'=>$catalogGroupId,
				'PRODUCT_ID'=>$productId,
				'PRICE'=>$price,
				'PRICE_SCALE'=>$price,
				'CURRENCY'=>$currency,
			));			
		}
		
		if($result && $result->isSuccess()) 
		{
			return true;
		}
		elseif($result)
		{
			return $result->getErrorMessages();
		}
		else
		{
			return true;
		}
	}
	
	public static function resetAgent() 
	{
		\CAgent::RemoveAgent('\\Grain\\Iiko\\Dishes::sync();', "grain.iiko");
		\CAgent::AddAgent('\\Grain\\Iiko\\Dishes::sync();', "grain.iiko", "N", 3600);
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit