| Current Path : /var/www/homesaver/www/bitrix/modules/dellindev.delivery/classes/general/ |
| Current File : /var/www/homesaver/www/bitrix/modules/dellindev.delivery/classes/general/DellinAPI.php |
<?php
use \Bitrix\Main\Web\Uri;
use \Bitrix\Main\Web\HttpClient;
// �������� ������ ����.
IncludeModuleLangFile(__FILE__);
/**
* Class DellinAPI
* ����� ����������� �� ������ ��������� ��������.
*/
class DellinAPI
{
/**
* URL API �� ������ ��������� ���������.
* @var string
*/
protected static $calculator_url = 'https://api.dellin.ru/v1/public/calculator.json';
/**
* URL API �� ������ ����������� ������.
* @var string
*/
protected static $city_search_url = 'https://www.dellin.ru/api/cities/search.json';
/**
* Id ����� ��������
* @var array
*/
protected static $packing_types_id = array(
'hard' => '0x838FC70BAEB49B564426B45B1D216C15',
'additional' => '0x9A7F11408F4957D7494570820FCF4549',
'bubble' => '0xA8B42AC5EC921A4D43C0B702C3F1C109',
'bag' => '0xAD22189D098FB9B84EEC0043196370D6',
'pallet' => '0xBAA65B894F477A964D70A4D97EC280BE'
);
/**
* ������ �������� � ������ ����� api ����� �����.
* @param $query
* @return mixed
*/
protected static function SearchCity($query)
{
// ��������� ������ �������.
$uri = new Uri(self::$city_search_url);
if (LANG_CHARSET == 'windows-1251') {
$query = iconv('windows-1251', 'utf8', $query);
}
$uri->addParams(array('q' => $query));
// ������������� http ������.
$http = new HttpClient();
$response = json_decode($http->get($uri->getUri()));
if (LANG_CHARSET == 'windows-1251') {
foreach ($response as &$city) {
foreach ($city as &$city_field) {
if (is_string($city_field)) {
$city_field = iconv('utf8', 'windows-1251', $city_field);
}
}
}
}
return $response;
}
/**
* ��������� ��������� ����� �� �������.
* @param array $city_list
* @param string $bx_city_name
* @param string $bx_region_name
* @return mixed
*/
protected static function SelectCityByRegion($city_list, $bx_city_name, $bx_region_name = '')
{
$dl_city = $city_list[0];
if (LANG_CHARSET == 'windows-1251') {
$bx_region_name = iconv('windows-1251', 'utf-8', $bx_region_name);
}
$short_region_name = str_replace('������', '���.', $bx_region_name);
if (LANG_CHARSET == 'windows-1251') {
$bx_region_name = iconv('utf-8', 'windows-1251', $bx_region_name);
$short_region_name = iconv('utf-8', 'windows-1251', $short_region_name);
}
foreach ($city_list as $item) {
$item_city_name = (string)$item->city;
$item_region_name = (string)$item->regionString;
if (
$item_city_name == $bx_city_name && (
$item_region_name == $short_region_name ||
$item_region_name == $bx_region_name
)
) {
$dl_city = $item;
break;
}
}
return $dl_city;
}
/**
* ������� ���� ��� �� ������� ������.
* ��� �������, ��� �������� ����� � �������� ��.
* @param integer $bx_location_to_id
* @return string
*/
public static function GetCityKLADRCode($bx_location_to_id)
{
$kladr_code = '';
$cache = new CPHPCache();
$life_time = 24*60*60;
$cache_id = 'DELLIN_LOCATION_KLADR_CODE|' . $bx_location_to_id;
if ($cache->InitCache($life_time, $cache_id)) {
$cache_data = $cache->GetVars();
$kladr_code = $cache_data['VALUE'];
} else {
$db_vars = CSaleLocation::GetList(false, array("CODE" => $bx_location_to_id, "LID" => "ru"));
$bx_location = $db_vars->Fetch();
$dl_locations = empty($bx_location) ? array() : self::SearchCity($bx_location['CITY_NAME']);
if (count($dl_locations) > 0) {
$bx_region = $bx_location['REGION_NAME'] ? $bx_location['REGION_NAME'] : '';
$dl_city = self::SelectCityByRegion($dl_locations, $bx_location['CITY_NAME'], $bx_region);
$kladr_code = (string)$dl_city->code;
$cache->StartDataCache($life_time, $cache_id);
$cache->EndDataCache(array('VALUE' => $kladr_code));
}
}
return $kladr_code;
}
/**
* ���������� ���-�� ������ ����.
* @param array $arOrder
* @param array $arConfig
* @return int
*/
protected static function GetNumbersOfCargoPlaces($arOrder, $arConfig)
{
$numbers_of_places = 1;
switch ($arConfig['LOADING_GROUPING_OF_GOODS']['VALUE']) {
// ���� ������ ��� �����, ��� 1 ����������.
case 'ONE_CARGO_SPACE':
break;
// ���� ���������� ����� ��� ������, ��� �������� ����������.
case 'SEPARATED_CARGO_SPACE':
$numbers_of_places = count($arOrder['ITEMS']);
break;
// ���� ����� ������ ������ - �������� ����������.
case 'SINGLE_ITEM_SINGLE_SPACE':
$numbers_of_places = 0;
foreach ($arOrder['ITEMS'] as $item) {
$numbers_of_places += $item['QUANTITY'];
}
break;
}
return $numbers_of_places;
}
/**
* ������������ ����� � ���������.
* @param float $bx_goods_weight_in_gram
* @return bool|float|int
*/
protected static function ConvertWeightFromGramToKilogram($bx_goods_weight_in_gram)
{
$weight_in_kg = CSaleMeasure::Convert((float)$bx_goods_weight_in_gram, "G", "KG");
return $weight_in_kg > 0 ? $weight_in_kg : 0.01;
}
/**
* ������������ ��������� ��������� � �� ����� ��������� ����.
* @param float $bx_goods_volume_in_mm
* @return bool|float|int
*/
protected static function ConvertVolumeFromCubicMillimeterToCubicMeter($bx_goods_volume_in_mm)
{
$volume_in_meter = $bx_goods_volume_in_mm / (1000 * 1000 * 1000);
return $volume_in_meter > 0 ? $volume_in_meter : 0.01;
}
/**
* �������� �� ��������
* @param float $weight
* @return bool
*/
protected static function IsOversizedWeight($weight)
{
return $weight > 100;
}
/**
* ������� ������ � ����������� ����, �������� �� ���������
* @param float $bx_compare_weight
* @param null|float $bx_set_weight
* @return array
*/
protected static function GetWeightArray($bx_compare_weight, $bx_set_weight = null) {
$compare_weight = self::ConvertWeightFromGramToKilogram($bx_compare_weight);
$total_weight = is_null($bx_set_weight) ? $compare_weight : self::ConvertWeightFromGramToKilogram($bx_set_weight);
if (self::IsOversizedWeight($compare_weight)) {
return array('sized' => $total_weight, 'oversized' => $total_weight);
}
return array('sized' => $total_weight);
}
/**
* ��������� �������� "sizedWeight" � "oversizedWeight" �� ������� ����������� �����
* @param array $arOrder
* @param array $arConfig
* @return array
*/
protected static function CalculateWeight($arOrder, $arConfig)
{
$arWeight = array();
switch ($arConfig['LOADING_GROUPING_OF_GOODS']['VALUE']) {
// ���� ������ ��� �����, ��� 1 ����������.
case 'ONE_CARGO_SPACE':
$arWeight = self::GetWeightArray($arOrder['WEIGHT']);
break;
// ���� ���������� ����� ��� ������, ��� �������� ����������.
case 'SEPARATED_CARGO_SPACE':
$max_item_weight = 0;
$sum_item_weight = 0;
foreach ($arOrder['ITEMS'] as $item) {
$item_weight = $item['WEIGHT'] * $item['QUANTITY'];
$sum_item_weight += $item_weight;
if ($item_weight > $max_item_weight) {
$max_item_weight = $item_weight;
}
}
$arWeight = self::GetWeightArray($max_item_weight, $sum_item_weight);
break;
// ���� ����� ������ ������ - �������� ����������.
case 'SINGLE_ITEM_SINGLE_SPACE':
$max_item_weight = 0;
$sum_item_weight = 0;
foreach ($arOrder['ITEMS'] as $item) {
$sum_item_weight += $item['WEIGHT'] * $item['QUANTITY'];
if ($item['WEIGHT'] > $max_item_weight) {
$max_item_weight = $item['WEIGHT'];
}
}
$arWeight = self::GetWeightArray($max_item_weight, $sum_item_weight);
break;
}
return $arWeight;
}
/**
* ��������� ����������� ����, �� ��� ��������.
* @param int $bx_length
* @param int $bx_width
* @param int $bx_height
* @return bool
*/
protected static function IsOversized($bx_length, $bx_width, $bx_height)
{
return $bx_length >= 3000 || $bx_width >= 3000 || $bx_height >= 3000;
}
/**
* ��������� ����������� ����, �� ��� �����.
* @param int $bx_volume
* @return bool
*/
protected static function IsOversizedVolume($bx_volume)
{
return $bx_volume >= 27000000000;
}
/**
* ������� ������ ������ �����
* @param int $sized_volume
* @param null|int $oversized_volume
* @return array
*/
protected static function GetVolumeArray($sized_volume, $oversized_volume = null)
{
$arVolume = array();
$arVolume['sized'] = $sized_volume;
if (!is_null($oversized_volume)) {
$arVolume['oversized'] = $oversized_volume;
}
return $arVolume;
}
/**
* ������� ������ ������ ����� � ��������� �������������� ��� ��������.
* @param array $bx_size_list
* @param int $sized_volume
* @param null|int $oversized_volume
* @return array
*/
protected static function GetVolumeArrayBySize($bx_size_list, $sized_volume, $oversized_volume = null)
{
if (self::IsOversized($bx_size_list['length'], $bx_size_list['width'], $bx_size_list['height'])) {
return self::GetVolumeArray($sized_volume, $oversized_volume);
}
return self::GetVolumeArray($sized_volume);
}
/**
* ������� ������ ������ ����� � ��������� �������������� ��� �����.
* @param int $bx_volume
* @param int $sized_volume
* @param null|float|int $oversized_volume
* @return array
*/
protected static function GetVolumeArrayByVolume($bx_volume, $sized_volume, $oversized_volume = null)
{
if (self::IsOversizedVolume($bx_volume)) {
return self::GetVolumeArray($sized_volume, $oversized_volume);
}
return self::GetVolumeArray($sized_volume);
}
/**
* ��������� �������� "sizedVolume" � "oversizedVolume" �� ������� ����������� �����
* @param array $arOrder
* @param array $arConfig
* @return array
*/
protected static function CalculateVolume($arOrder, $arConfig) {
$arVolume = array();
$totalVolume = 0;
$totalOversizedVolume = 0;
foreach ($arOrder['ITEMS'] as $item) {
$bx_item_length = $item['DIMENSIONS']['LENGTH'];
$bx_item_width = $item['DIMENSIONS']['WIDTH'];
$bx_item_height = $item['DIMENSIONS']['HEIGHT'];
$totalVolume += $item['QUANTITY'] * $bx_item_length * $bx_item_width * $bx_item_height;
}
$totalVolume = self::ConvertVolumeFromCubicMillimeterToCubicMeter($totalVolume);
switch ($arConfig['LOADING_GROUPING_OF_GOODS']['VALUE']) {
// ���� ������ ��� �����, ��� 1 ����������.
case 'ONE_CARGO_SPACE':
$bx_item_max_size = array('length' => 0, 'width' => 0, 'height' => 0);
foreach ($arOrder['ITEMS'] as $item) {
$bx_item_length = $item['DIMENSIONS']['LENGTH'];
$bx_item_width = $item['DIMENSIONS']['WIDTH'];
$bx_item_height = $item['DIMENSIONS']['HEIGHT'];
if ($bx_item_length > $bx_item_max_size['length']) {
$bx_item_max_size['length'] = $bx_item_length;
}
if ($bx_item_width > $bx_item_max_size['width']) {
$bx_item_max_size['width'] = $bx_item_width;
}
if ($bx_item_height > $bx_item_max_size['height']) {
$bx_item_max_size['height'] = $bx_item_height;
}
}
$arVolume = self::GetVolumeArrayBySize($bx_item_max_size, $totalVolume, $totalVolume);
break;
// ���� ���������� ����� ��� ������, ��� �������� ����������.
case 'SEPARATED_CARGO_SPACE':
foreach ($arOrder['ITEMS'] as $item) {
$bx_item_length = $item['DIMENSIONS']['LENGTH'];
$bx_item_width = $item['DIMENSIONS']['WIDTH'];
$bx_item_height = $item['DIMENSIONS']['HEIGHT'];
$bx_item_volume = $item['QUANTITY'] * $bx_item_length * $bx_item_width * $bx_item_height;
if (self::IsOversizedVolume($bx_item_volume)) {
$totalOversizedVolume += $bx_item_volume;
}
}
$arVolume = self::GetVolumeArrayByVolume(
$totalOversizedVolume,
$totalVolume,
self::ConvertVolumeFromCubicMillimeterToCubicMeter($totalOversizedVolume)
);
break;
// ���� ����� ������ ������ - �������� ����������.
case 'SINGLE_ITEM_SINGLE_SPACE':
foreach ($arOrder['ITEMS'] as $item) {
$bx_item_length = $item['DIMENSIONS']['LENGTH'];
$bx_item_width = $item['DIMENSIONS']['WIDTH'];
$bx_item_height = $item['DIMENSIONS']['HEIGHT'];
$bx_item_volume = $bx_item_length * $bx_item_width * $bx_item_height;
if (self::IsOversizedVolume($bx_item_volume)) {
$totalOversizedVolume += $bx_item_volume;
}
}
$arVolume = self::GetVolumeArrayByVolume(
$totalOversizedVolume,
$totalVolume,
self::ConvertVolumeFromCubicMillimeterToCubicMeter($totalOversizedVolume)
);
break;
}
return $arVolume;
}
/**
* ������� ������ �� ��� "{arrival-derival}Services"
* @param array $bx_fields
* @return array
*/
protected static function GetAdditionalServices($bx_fields)
{
$value_list = array();
foreach ($bx_fields as $item) {
if ($item['VALUE'] == 'NULL') {
continue;
}
$value_list[] = $item['VALUE'];
}
return $value_list;
}
/**
* ������� ������ �� id ����� ��������.
* @param array $bx_fields
* @return array
*/
protected static function GetSelectedPackingTypesId($bx_fields)
{
$value_list = array();
foreach ($bx_fields as $key => $item) {
if ($item['VALUE'] == 'N') {
continue;
}
$value_list[] = self::$packing_types_id[$key];
}
return $value_list;
}
/**
* ������� ��������� � �������� �� ��������� �������� ����� � ����������� ������.
* @param array $arOrder
* @param array $arConfig
* @return array
*/
public static function GetDeliveryData($arOrder, $arConfig)
{
// ������� ���� ��� ����������� ������, �� �������� ����� �������� ����.
$delivery_from_kladr_code = (string)$arConfig['KLADR_CODE_DELIVERY_FROM']['VALUE'];
// ������� ���� ��� ����������� ������, � ������ ����� �������� ����.
$delivery_to_kladr_code = self::GetCityKLADRCode($arOrder['LOCATION_TO']);
// ������� ���-�� ������ ����.
$dl_api_numbers_of_cargo_places = self::GetNumbersOfCargoPlaces($arOrder, $arConfig);
// ������� ���.
$dl_api_weight = self::CalculateWeight($arOrder, $arConfig);
// ������� ����.
$dl_api_volume = self::CalculateVolume($arOrder, $arConfig);
// ��������� ����� �� ��������.
// ����� ������ ���������� ����� ����� ���:
// http://dev.dellin.ru/api/public/calculator/
$dl_api_data = array(
// �� API (���������� ����).
// string
'appKey' => (string)$arConfig['API_KEY']['VALUE'],
// ��� ���� ������ �������� (���������� ����).
// string
'derivalPoint' => $delivery_from_kladr_code,
// ��������� �������� ����� �� ������.
// boolean
'derivalDoor' => $arConfig['IS_GOODS_LOADING']['VALUE'] == 'Y',
// ������� ������������ ������ �� �������� ����� �� ������ - ������ ��������
// array
"derivalServices" => array(),
// ��� ���� ������ ������ (���������� ����).
// string
'arrivalPoint' => $delivery_to_kladr_code,
// ��������� �������� ����� �� ������.
// boolean
'arrivalDoor' => $arConfig['IS_GOODS_UNLOADING']['VALUE'] == 'Y',
// ������� ������������ ������ �� �������� ����� �� ������ - ������ ��������
// array
"arrivalServices" => array(),
// ���� ��� ����� � �������� ����� (��������� ����).
// string
'sizedVolume' => $dl_api_volume['sized'],
// ���� ��� ����� � ���������� (��������� ����).
// string
'sizedWeight' => $dl_api_weight['sized'],
// �������� �������� ����� � ����. ��� ��������� - ���� �� ��������, ��� ������� 0 - �������� ��� ��������� ���������,
// ��� ������� ������ ���� 0 - �������� �� �������� �����.
// float | integer
'statedValue' => $arConfig['IS_INSURANCE_GOODS_WITH_DECLARED_PRICE']['VALUE'] == 'Y' ? (float)$arOrder['PRICE'] : 0,
// �������� ���� � ��������?
// array
'packages' => self::GetSelectedPackingTypesId(array(
'hard' => $arConfig['PACKING_FOR_GOODS_HARD'],
'additional' => $arConfig['PACKING_FOR_GOODS_ADDITIONAL'],
'bubble' => $arConfig['PACKING_FOR_GOODS_BUBBLE'],
'bag' => $arConfig['PACKING_FOR_GOODS_BAG'],
'pallet' => $arConfig['PACKING_FOR_GOODS_PALLET']
)),
// ��������� ����, ��-������� ����� ����������� �� ������ �����.
// integer
'quantity' => $dl_api_numbers_of_cargo_places
);
// ���� ��� �������� ��� ���������, �� ������� ��� ��������.
if ($dl_api_volume['oversized'] || $dl_api_weight['oversized']) {
$dl_api_data['oversizedVolume'] = $dl_api_volume['sized'];
$dl_api_data['oversizedWeight'] = $dl_api_weight['sized'];
}
// �������� ������������ ������, ���� ������� ������, ��� ��������� �������� ������
if ($dl_api_data['derivalDoor']) {
$dl_api_data['derivalServices'] = self::GetAdditionalServices(array(
$arConfig['LOADING_TYPE'],
$arConfig['LOADING_TRANSPORT_REQUIREMENTS'],
$arConfig['LOADING_ADDITIONAL_EQUIPMENT']
));
}
// �������� ������������ ������, ���� ������� ������, ��� ��������� ��������� ������
if ($dl_api_data['arrivalDoor']) {
$dl_api_data['arrivalServices'] = self::GetAdditionalServices(array(
$arConfig['UNLOADING_TYPE'],
$arConfig['UNLOADING_TRANSPORT_REQUIREMENTS'],
$arConfig['UNLOADING_ADDITIONAL_EQUIPMENT']
));
}
return $dl_api_data;
}
/**
* �������� ��� �� ���������.
* @param array $data
* @param array $arOrder
* @param array $arConfig
* @return bool
*/
protected static function IsDataValid($data, $arOrder, $arConfig)
{
return
(
$arOrder['PRICE'] > 0
) && (
$data["appKey"] !== ''
) && (
$data["derivalPoint"] !== '' &&
$data["arrivalPoint"] !== ''
) && !(
$arConfig["INTERCITY_HIDE"]["VALUE"] == "Y" &&
$data["derivalPoint"] == $data["arrivalPoint"]
);
}
/**
* ��������� ������ �����.
* @param $errors
* @return string
*/
protected static function GetResponseErrors($errors)
{
$errors_srt = '';
if (is_string($errors)) {
$errors_srt = $errors;
} elseif (count($errors) > 0) {
// ��� ��� ������� �� ������ � object(stdClass),
// �� ��� ������� ���������.
$error_list = array();
foreach ($errors as $key => $val) {
$error_list[] = $key . ' - ' . $val;
}
$errors_srt = implode('; ', $error_list);
}
return $errors_srt;
}
/**
* ����� ������� ���������.
* @param object $response
* @param array $arConfig
* @return bool|float
*/
protected static function CalculatePrice($response, $arConfig)
{
$total_price = false;
$is_small_goods_price = $arConfig['IS_SMALL_GOODS_PRICE']['VALUE'] == 'Y';
$is_try_small_goods_price_calculate = $arConfig['TRY_SMALL_GOODS_PRICE_CALCULATE']['VALUE'] == 'Y';
if ($response->price > 0 || ($is_small_goods_price && $response->small->price > 0)) {
// �������� ��������
$total_price = $response->price;
if ($is_small_goods_price) {
if ($response->small->price > 0) {
$total_price = $response->small->price + $response->small->insurance + $response->small->notify->price;
} elseif (!$is_try_small_goods_price_calculate) {
$total_price = false;
}
}
}
return $total_price;
}
/**
* ����� ��������� ��������.
* @param array $arOrder
* @param array $arConfig
* @return array|bool
*/
public static function Calculate($arOrder, $arConfig)
{
$result = array('STATUS' => 'ERROR', 'BODY' => GetMessage('DELLIN_CALCULATE_ERROR'));
$data = self::GetDeliveryData($arOrder, $arConfig);
if (self::IsDataValid($data, $arOrder, $arConfig)) {
$cache = new CPHPCache();
$life_time = 10*60;
$cache_id = 'DELLIN_CALCULATE|' . serialize($data) . '&' . serialize($arConfig);
if ($cache->InitCache($life_time, $cache_id)) {
$cache_data = $cache->GetVars();
$result = $cache_data['VALUE'];
} else {
$http_client = new HttpClient();
$http_client->setHeader('Content-Type', 'application/json', true);
try {
$json = json_encode($data);
if (LANG_CHARSET == 'windows-1251') {
$json = iconv('windows-1251', 'utf8', $json);
}
$response = json_decode($http_client->post(self::$calculator_url, $json));
$result_body = '';
if (isset($response->errors)) {
$result_body = self::GetResponseErrors($response->errors);
if (LANG_CHARSET == 'windows-1251') {
$result_body = iconv('utf8', 'windows-1251', $result_body);
}
} elseif ($price = self::CalculatePrice($response, $arConfig)) {
$result['STATUS'] = 'OK';
$time = $response->time->nominative;
if (LANG_CHARSET == 'windows-1251') {
$time = iconv('utf8', 'windows-1251', $time);
}
$result_body = array($price, $time);
}
$result['BODY'] = $result_body;
} catch (Exception $e) {
$result['BODY'] = GetMessage('DELLIN_CONNECTION_ERROR');
}
$cache->StartDataCache($life_time, $cache_id);
$cache->EndDataCache(array('VALUE' => $result));
}
}
return $result;
}
}