PageRenderTime 37ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/sale/ru/delivery/pecom/location.php

https://gitlab.com/alexprowars/bitrix
PHP | 298 lines | 219 code | 49 blank | 30 comment | 38 complexity | a276d468c3a900a7ce2e351aa60282d1 MD5 | raw file
  1. <?
  2. namespace Bitrix\Sale\Delivery\Pecom;
  3. use Bitrix\Main\Error;
  4. use Bitrix\Main\Loader;
  5. use Bitrix\Sale\Result;
  6. use Bitrix\Main\Text\Encoding;
  7. use Bitrix\Sale\Location\Comparator;
  8. use Bitrix\Main\ArgumentNullException;
  9. use Bitrix\Sale\Location\ExternalTable;
  10. use Bitrix\Sale\Location\LocationTable;
  11. use Bitrix\Sale\Delivery\ExternalLocationMap;
  12. Loader::registerAutoLoadClasses(
  13. 'sale',
  14. array(
  15. 'Bitrix\\Sale\\Delivery\\Pecom\\Replacement' => 'ru/delivery/pecom/replacement.php'
  16. )
  17. );
  18. /**
  19. * Class Location
  20. * @package Bitrix\Sale\Delivery\Pecom
  21. */
  22. class Location extends ExternalLocationMap
  23. {
  24. const EXTERNAL_SERVICE_CODE = 'PECOM';
  25. const CSV_FILE_PATH = '/bitrix/modules/sale/ru/delivery/pecom/location.csv';
  26. public static function compare($startKey = 0, $timeout = 0, $updateExist = false)
  27. {
  28. set_time_limit(0);
  29. $result = new Result();
  30. $srvId = self::getExternalServiceId();
  31. if(intval($srvId) <= 0)
  32. return $result;
  33. self::fillNormalizedTable();
  34. $res = static::getAllLocations();
  35. if($res->isSuccess())
  36. {
  37. $locations = $res->getData();
  38. if(is_array($locations) && !empty($locations))
  39. {
  40. $lastKey = static::mapByNames($locations, $srvId, $startKey, $timeout, $updateExist);
  41. $result->addData(array(
  42. 'LAST_KEY' => $lastKey
  43. ));
  44. }
  45. }
  46. else
  47. {
  48. $result->addErrors($res->getErrors());
  49. }
  50. return $result;
  51. }
  52. /**
  53. * @param array $locations
  54. * @param int $srvId
  55. * @param int $startKey
  56. * @param int $timeout
  57. * @param bool $updateExist
  58. * @return int Last processed id.
  59. * @throws ArgumentNullException
  60. * @throws \Bitrix\Main\ArgumentException
  61. */
  62. protected static function mapByNames($locations, $srvId, $startKey = 0, $timeout = 0, $updateExist = false)
  63. {
  64. if(empty($locations))
  65. throw new ArgumentNullException('locations');
  66. $startTime = mktime(true);
  67. $imported = 0;
  68. $xmlIdExist = array();
  69. $locationIdExist = array();
  70. if(!$updateExist)
  71. {
  72. $res = ExternalTable::getList(array(
  73. 'filter' => array(
  74. '=SERVICE_ID' => $srvId
  75. )
  76. ));
  77. while($map = $res->fetch())
  78. {
  79. $xmlIdExist[] = $map['XML_ID'];
  80. $locationIdExist[] = $map['LOCATION_ID'];
  81. }
  82. }
  83. $key = 0;
  84. foreach($locations as $key => $location)
  85. {
  86. $xmlId = $location[self::CITY_XML_ID_IDX];
  87. if($startKey <= 0 || $key >= $startKey)
  88. {
  89. if(!in_array($xmlId, $xmlIdExist))
  90. {
  91. $cityName = $location[static::CITY_NAME_IDX];
  92. $districtName = self::extractDistrict($cityName);
  93. $locationId = static::getLocationIdByNames($cityName, '', $districtName, $location[static::REGION_NAME_IDX], '', true);
  94. if(!$locationId)
  95. $locationId = static::getLocationIdByNames($cityName, '', $districtName,$location[static::REGION_NAME_IDX], '', false);
  96. if(intval($locationId) > 0 && !in_array($locationId, $locationIdExist))
  97. {
  98. $res = self::setExternalLocation($srvId, $locationId, $xmlId, $updateExist);
  99. if($res)
  100. $imported++;
  101. }
  102. }
  103. }
  104. unset($locations[$key]);
  105. if($timeout > 0 && (mktime(true)-$startTime) >= $timeout)
  106. return intval($key);
  107. }
  108. return intval($key) > 0 ? intval($key) : 0;
  109. }
  110. protected static function setMap(array $cities)
  111. {
  112. self::mapByNames($cities, static::getExternalServiceId());
  113. return new Result();
  114. }
  115. /**
  116. * @return Result
  117. */
  118. protected static function getAllLocations()
  119. {
  120. $result = new Result();
  121. $http = new \Bitrix\Main\Web\HttpClient(array(
  122. "version" => "1.1",
  123. "socketTimeout" => 30,
  124. "streamTimeout" => 30,
  125. "redirect" => true,
  126. "redirectMax" => 5,
  127. "disableSslVerification" => true
  128. ));
  129. $jsnData = $http->get("https://www.pecom.ru/ru/calc/towns.php");
  130. $errors = $http->getError();
  131. if (!$jsnData && !empty($errors))
  132. {
  133. foreach($errors as $errorCode => $errMes)
  134. $result->addError(new Error($errMes, $errorCode));
  135. return $result;
  136. }
  137. $data = json_decode($jsnData, true);
  138. if(is_array($data))
  139. {
  140. // City MOSKVA Region MOSKVA
  141. $cityRegionSame = array();
  142. //City name contains (temeryazevskiy r-n)
  143. $precised = array();
  144. $emptyRegions = array();
  145. $other = array();
  146. if(mb_strtolower(SITE_CHARSET) != 'utf-8')
  147. $data = Encoding::convertEncoding($data, 'UTF-8', SITE_CHARSET, $em);
  148. $regions = self::getParents(array_keys($data));
  149. foreach($data as $regionCity => $city)
  150. {
  151. $regionCity = ToUpper($regionCity);
  152. $regionName = !empty($regions[$regionCity]['REGION']) ? $regions[$regionCity]['REGION'] : '';
  153. if($regionName == '')
  154. {
  155. foreach(Replacement::getRegionExceptions() as $cName => $rName)
  156. {
  157. if($regionCity == $cName)
  158. {
  159. $regionName = $rName;
  160. break;
  161. }
  162. }
  163. }
  164. foreach($city as $cityId => $cityName)
  165. {
  166. $cityName = ToUpper($cityName);
  167. $location = array($cityName, $regionName, $cityId);
  168. if(mb_strpos($cityName, '(') !== false && mb_strpos($cityName, ')') !== false)
  169. $precised[] = $location;
  170. elseif($cityName == $regionCity)
  171. $cityRegionSame[] = $location;
  172. elseif($regionCity == '' || $regionCity == '-' || $regionCity == '--')
  173. $emptyRegions = $location;
  174. else
  175. $other[] = $location;
  176. }
  177. }
  178. $result->addData(
  179. array_merge(
  180. $precised,
  181. $other,
  182. $cityRegionSame,
  183. $emptyRegions
  184. )
  185. );
  186. }
  187. else
  188. {
  189. $result->addError(new Error("Can decode pecom cities data!"));
  190. }
  191. return $result;
  192. }
  193. /**
  194. * Find regions by city names.
  195. * @param array $cityNames
  196. * @return array
  197. * @throws \Bitrix\Main\ArgumentException
  198. */
  199. protected static function getParents(array $cityNames)
  200. {
  201. if(empty($cityNames))
  202. return array();
  203. $result = array();
  204. foreach($cityNames as $key => $name)
  205. $cityNames[$key] = ToUpper($name);
  206. $res = LocationTable::getList(array(
  207. 'filter' => array(
  208. '=NAME.NAME_UPPER' => $cityNames,
  209. '=NAME.LANGUAGE_ID' => LANGUAGE_ID,
  210. '=PARENTS.NAME.LANGUAGE_ID' => LANGUAGE_ID
  211. ),
  212. 'select' => array(
  213. 'NAME_UPPER' => 'NAME.NAME_UPPER',
  214. 'PARENTS_TYPE_CODE' => 'PARENTS.TYPE.CODE' ,
  215. 'PARENTS_NAME_UPPER' => 'PARENTS.NAME.NAME_UPPER'
  216. )
  217. ));
  218. while($loc = $res->fetch())
  219. {
  220. if(!isset($result[$loc['NAME_UPPER']]))
  221. $result[$loc['NAME_UPPER']] = array();
  222. $result[$loc['NAME_UPPER']][$loc['PARENTS_TYPE_CODE']] = $loc['PARENTS_NAME_UPPER'];
  223. }
  224. return $result;
  225. }
  226. /**
  227. * SOKOLOVSKOE (GULKELIVICHSKIY R-N) => GULKELIVICHSKIY R-N
  228. * @param $cityName
  229. * @return string
  230. */
  231. protected static function extractDistrict(&$cityName)
  232. {
  233. $result = '';
  234. $matches = array();
  235. if(preg_match('/(.*)\s*\((.*)\)/i'.BX_UTF_PCRE_MODIFIER, $cityName, $matches))
  236. {
  237. if(!empty($matches[2]))
  238. {
  239. $result = trim($matches[2]);
  240. $mark = Replacement::getDistrictMark();
  241. if(!preg_match('/('.$mark.'){1}/i'.BX_UTF_PCRE_MODIFIER, $result))
  242. $result = '';
  243. if(!empty($matches[1]))
  244. $cityName = trim($matches[1]);
  245. }
  246. }
  247. return $result;
  248. }
  249. }