%PDF- %PDF-
| Direktori : /home/bitrix/www/bitrix/modules/sale/handlers/delivery/spsr/ |
| Current File : /home/bitrix/www/bitrix/modules/sale/handlers/delivery/spsr/location.php |
<?
namespace Sale\Handlers\Delivery\Spsr;
use Bitrix\Main\Error;
use Bitrix\Main\Loader;
use Bitrix\Sale\Result;
use Bitrix\Main\Localization\Loc;
use Bitrix\Sale\Location\Comparator\Mapper;
use Bitrix\Sale\Location\Comparator\TmpTable;
use Bitrix\Sale\Location\Comparator\MapResult;
Loc::loadMessages(__FILE__);
Loader::registerAutoLoadClasses(
'sale',
array(
'Sale\Handlers\Delivery\Spsr\Replacement' => 'handlers/delivery/spsr/replacement/ru/replacement.php'
)
);
final class Location extends Mapper
{
const EXTERNAL_SERVICE_CODE = 'SPSR';
const CSV_FILE_PATH = '/bitrix/modules/sale/handlers/delivery/spsr/location.csv';
protected $tmpTable = null;
protected $serviceId = 0;
public function __construct()
{
$this->serviceId = $this->getExternalServiceId();
$this->tmpTable = new TmpTable($this->serviceId);
}
protected function getLocationsRequest($cityName = '', $countryName = '')
{
set_time_limit(0);
$result = new Result();
$requestData = '
<root xmlns="http://spsr.ru/webapi/Info/GetCities/1.0">
<p:Params Name="WAGetCities" Ver="1.0" xmlns:p="http://spsr.ru/webapi/WA/1.0" />
<GetCities CityName="'.strtolower($cityName).'" CountryName="'.strtolower($countryName).'" />
</root>';
$request = new Request();
$res = $request->send($requestData);
if($res->isSuccess())
{
$data = $res->getData();
$xmlAnswer = new \SimpleXMLElement($data[0]);
$cities = array();
foreach($xmlAnswer->City->Cities as $city)
{
$cities[(string)$city['City_ID']."|".(string)$city['City_owner_ID']] = array(
'City_ID' => (string)$city['City_ID'],
'City_owner_ID' => (string)$city['City_owner_ID'],
'CityName' => self::utfDecode(
(string)$city['CityName']
),
'RegionName' => self::utfDecode(
(string)$city['RegionName']
)
);
}
if(!empty($cities))
{
$result->setData($cities);
}
}
else
{
$result->addErrors($res->getErrors());
}
return $result;
}
protected function mapByNames($startId = 0, $timeout = 0)
{
$startTime = mktime(true);
$result = new MapResult;
\Bitrix\Sale\Location\Comparator::setVariants(Replacement::getVariants());
$dbRes = $this->tmpTable->getUnmappedLocations($startId);
while($loc = $dbRes->fetch())
{
/**
* Extract city name and subregion name from
* Abramtsevo (Balashihinskiy)
* Abramtsevo (Dmitrovskiy, 141880)
* Aborino
*/
$matches = array();
preg_match('/([^(]*)(\(([^\,\s]*)(\s*\,\s*\d*){0,1}\)){0,1}/i', $loc['CityName'], $matches);
if(empty($matches[1]))
{
if($this->collectNotFound)
$result->addNotFound($loc['XML_ID'], $loc['CityName'].' : '.$loc['RegionName']);
continue;
}
$cityName = !empty($matches[1]) ? trim($matches[1]) : '';
$subRegionName = !empty($matches[3]) ? trim($matches[3]) : '';
$locId = 0;
if(strlen($cityName) > 0)
{
$locId = self::getLocationIdByNames($cityName, "", $subRegionName, $loc['RegionName'], "", true);
if(intval($locId) <= 0)
$locId = self::getLocationIdByNames($cityName, "", $subRegionName, $loc['RegionName'], "", false);
}
if(intval($locId) > 0)
{
$res = self::setExternalLocation2($this->serviceId, $locId, $loc['XML_ID'], false);
if($res->isSuccess())
{
if($this->collectMapped)
$result->addMapped($loc['XML_ID'], $loc['CityName'].', '.$loc['RegionName'], $locId);
$this->tmpTable->markMapped($locId, $loc['XML_ID']);
}
elseif($this->collectDuplicated)
{
foreach($res->getErrors() as $error)
{
if($error->getCode() == 'EXTERNAL_LOCATION_EXISTS')
{
$result->addDuplicated($loc['XML_ID'], $loc['CityName'].':'.$loc['RegionName'], $locId);
break;
}
}
}
}
else
{
if($this->collectNotFound)
$result->addNotFound($loc['XML_ID'], $loc['CityName'].':'.$loc['RegionName']);
}
$result->setLastProcessedId($loc['ID']);
if($timeout > 0 && (mktime(true)-$startTime) >= $timeout)
return $result;
}
return $result;
}
public static function install()
{
return new Result();
}
public function mapStepless()
{
set_time_limit(0);
$result = new Result();
$res = $this->getLocationsRequest('', Loc::getMessage('SALE_DLV_SRV_SPSR_RUSSIA'));
if(!$res->isSuccess())
return $res;
$locationsData = $res->getData();
$locationsCount = count($locationsData);
if($this->tmpTable->isExist())
$this->tmpTable->drop();
$this->tmpTable->create($locationsData);
$tmpImported = $this->tmpTable->saveData($locationsData);
unset($locationsData);
if($tmpImported <= 0)
{
$result->addError(new Error(Loc::getMessage('SALE_DLV_SRV_SPSR_TMP_TBL_ERROR')));
return $result;
}
$this->importFromCsv($_SERVER["DOCUMENT_ROOT"].self::CSV_FILE_PATH);
$this->fillNormalizedTable();
$this->tmpTable->markAllMapped();
$mapRes = $this->mapByNames();
$mapRes->setSupportedCount($locationsCount);
$this->tmpTable->drop();
$result->setData(array('MAP_RESULT' => $mapRes));
return $result;
}
public function map($stage, $step = '', $progress = 0, $timeout = 0)
{
$result = new Result();
set_time_limit(0);
switch($stage)
{
case 'start':
$res = self::getLocationsRequest('', Loc::getMessage('SALE_DLV_SRV_SPSR_RUSSIA'));
if(!$res->isSuccess())
return $res;
$data = $res->getData();
if($this->tmpTable->isExist())
$this->tmpTable->drop();
$this->tmpTable->create($data);
$tmpImported = $this->tmpTable->saveData($data);
if($tmpImported <= 0)
{
$result->addError(new Error(Loc::getMessage('SALE_DLV_SRV_SPSR_TMP_TBL_ERROR')));
return $result;
}
$_SESSION['SALE_HNDL_SPSR_DLV_TMP_MAX_ID'] = $this->tmpTable->getMaxId();
$res = \Bitrix\Sale\Location\LocationTable::getList(array(
'runtime' => array(new \Bitrix\Main\Entity\ExpressionField('MAX', 'MAX(ID)')),
'select' => array('MAX')
));
if($loc = $res->fetch())
$_SESSION['SALE_HNDL_SPSR_DLV_LOC_MAX_ID'] = $loc['MAX'];
else
$_SESSION['SALE_HNDL_SPSR_DLV_LOC_MAX_ID'] = 0;
$result->setData(array(
'STAGE' => 'import_from_csv',
'MESSAGE' => Loc::getMessage('SALE_DLV_SRV_SPSR_LOC_CSV'),
'PROGRESS' => $progress + 5
));
break;
case 'import_from_csv':
$this->importFromCsv($_SERVER["DOCUMENT_ROOT"].self::CSV_FILE_PATH);
$result->setData(array(
'STAGE' => 'fill_normalized_table',
'MESSAGE' => Loc::getMessage('SALE_DLV_SRV_SPSR_LOC_NORM'),
'PROGRESS' => $progress + 5
));
break;
case 'fill_normalized_table':
$lastId = self::fillNormalizedTable($step, $timeout);
$progress = $this->calculateProgress($lastId, $_SESSION['SALE_HNDL_SPSR_DLV_LOC_MAX_ID'], $progress, 11, 30);
if($lastId > 0 && $lastId < $_SESSION['SALE_HNDL_SPSR_DLV_LOC_MAX_ID'])
{
$result->setData(array(
'STAGE' => 'fill_normalized_table',
'STEP' => $lastId,
'MESSAGE' => Loc::getMessage('SALE_DLV_SRV_SPSR_LOC_NORM'),
'PROGRESS' => $progress
));
}
else
{
unset($_SESSION['SALE_HNDL_SPSR_DLV_LOC_MAX_ID']);
$result->setData(array(
'STAGE' => 'mark_unmapped',
'MESSAGE' => Loc::getMessage('SALE_DLV_SRV_SPSR_LOC_CHECK_MAPPED'),
'PROGRESS' => 30
));
}
break;
case 'mark_unmapped':
$this->tmpTable->markAllMapped();
$result->setData(array(
'STAGE' => 'map_by_names',
'MESSAGE' => Loc::getMessage('SALE_DLV_SRV_SPSR_LOC_MAP_BY_NAME'),
'PROGRESS' => $progress + 5
));
break;
case 'map_by_names':
$mapResult = $this->mapByNames($step, $timeout);
$lastProcessedId = $mapResult->getLastProcessedId();
if($lastProcessedId > 0 && $lastProcessedId < $_SESSION['SALE_HNDL_SPSR_DLV_TMP_MAX_ID'])
{
$progress = $this->calculateProgress($lastProcessedId, $_SESSION['SALE_HNDL_SPSR_DLV_TMP_MAX_ID'], $progress, 36, 100);
$result->setData(array(
'STAGE' => 'map_by_names',
'STEP' => $lastProcessedId,
'MESSAGE' => Loc::getMessage('SALE_DLV_SRV_SPSR_LOC_MAP_BY_NAME'),
'PROGRESS' => $progress,
'MAP_RESULT' => $mapResult
));
}
else
{
unset($_SESSION['SALE_HNDL_SPSR_DLV_TMP_MAX_ID']);
$this->tmpTable->drop();
$result->setData(array(
'STAGE' => 'finish',
'MESSAGE' => Loc::getMessage('SALE_DLV_SRV_SPSR_LOC_MAP_FINISHED'),
'PROGRESS' => 100,
'MAP_RESULT' => $mapResult
));
}
break;
default:
$result->addError(new Error(Loc::getMessage('SALE_DLV_SRV_SPSR_LOC_MAP_STAGE_ERROR')));
}
return $result;
}
protected function calculateProgress($id, $maxId, $progress, $minProgress, $maxProgress)
{
if($maxId <= 0)
{
$progress = $progress < $maxProgress ? ($progress + 1) : $progress;
}
elseif($id >= $maxId)
{
$progress = $maxProgress;
}
else
{
$progress = $minProgress + round(($maxProgress-$minProgress) * $id / $maxId);
if($progress >= $maxProgress && $id < $maxId)
$progress--;
}
return $progress;
}
}