1
0
mirror of synced 2024-11-24 22:16:06 +03:00
This commit is contained in:
cyradin 2015-09-07 18:09:12 +03:00
commit df7a781e27
7 changed files with 314 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.idea
vendor
config/config.php
composer.lock
composer.json

2
.htaccess Normal file
View File

@ -0,0 +1,2 @@
Order Deny, Allow
Deny From All

155
classes/ApiHelper.php Normal file
View File

@ -0,0 +1,155 @@
<?php
require_once(__DIR__ . "/../vendor/autoload.php");
require(__DIR__ . "/Parser.php");
class ApiHelper {
protected $config;
protected $crmClient;
protected $parser;
public function __construct($config) {
$this->config = $config;
$this->crmClient = new \RetailCrm\ApiClient(
$this->config['retailcrm_url'],
$this->config['retailcrm_apikey']
);
$this->parser = new Parser($config);
}
public function processXMLOrders() {
$url = $this->config['tiu_xml_url'];
$xml = simplexml_load_file($url);
if (! $xml instanceof SimpleXMLElement) {
$this->writeLog("ApiHelper::processXmlOrders: cannot get XML from $url");
return false;
}
$orders = array();
foreach($xml as $xmlOrder) {
$order = $this->parser->parseXMLNewOrder($xmlOrder);
if ($order) {
$customerId = $this->checkCustomers($order);
if ($customerId === false) {
echo "upload failed" . PHP_EOL;
return false;
} elseif ($customerId !== 0) {
$order['customerId'] = $customerId;
}
$orders[$order['number']] = $order;
}
}
$orders = $this->filterOrders($orders);
if ($this->uploadOrders($orders)) {
$a = sizeof($orders);
echo "uploaded $a orders" . PHP_EOL;
return true;
} else {
echo "upload failed" . PHP_EOL;
return false;
}
}
protected function uploadOrders($orders) {
if ($orders === false)
return false;
if (sizeof($orders)) {
$orders = array_chunk($orders, $this->config['retailcrm_order_chunk_size']);
foreach ($orders as $chunk) {
try {
$result = $this->crmClient->ordersUpload($chunk);
} catch (\RetailCrm\Exception\CurlException $e) {
$this->writeLog(
'\Retailcrm\ApiClient::ordersUpload: ' . $e,
'error'
);
return false;
}
if (! $result->isSuccessful()) {
$this->writeLog(
'\Retailcrm\ApiClient::ordersUpload: ' . $result['errorMsg'] . (isset($result['errors']) ? ': ' . json_encode($result['errors']) : '')
);
}
time_nanosleep(0, 200000000);
}
}
return true;
}
protected function checkCustomers($order) {
$customerId = 0;
if ($order['email'] != '')
$filter = array('email' => $order['email']);
if ($order['phone'] != '')
$filter = array('name' => $order['phone']);
if (isset($filter)) {
try {
$customers = $this->crmClient->customersList($filter);
} catch (\RetailCrm\Exception\CurlException $e) {
$this->writeLog(
'\Retailcrm\ApiClient::customersList: ' . $e,
'error'
);
return false;
}
if (isset($customers['customers']) && sizeof($customers['customers'] && isset($customers['customers'][0]['externalId']))) {
$customerId = $customers['customers'][0]['externalId'];
}
time_nanosleep(0, 200000000);
}
return $customerId;
}
protected function writeLog($text, $type = null) {
if (! file_exists(__DIR__ ."/../logs"))
mkdir(__DIR__ ."/../logs");
$date = date('Y-m-d H:i:s');
file_put_contents(__DIR__ . "/../logs/error.log", "[$date]$text" . PHP_EOL, FILE_APPEND);
if ($type == 'error') {
$this->sendAlertEmail($text);
}
}
protected function sendAlertEmail($text) {
mail($this->config['support_email'], $this->config['support_email_subject'], $text);
}
protected function filterOrders($toUpload) {
$numbers = array_keys($toUpload);
if (date_create_from_format('Y-m-d H:i:s', $this->config['filter_date'])) {
foreach ($toUpload as $i => $order) {
if ($order['createdAt'] < $this->config['filter_date']) {
unset($toUpload[$i]);
}
}
}
$ordersListPage = 0;
do {
$ordersListPage++;
try {
$orders = $this->crmClient->ordersList(array(
'numbers' => $numbers
), $ordersListPage, 100);
} catch (\RetailCrm\Exception\CurlException $e) {
$text = '\Retailcrm\ApiClient::ordersList: ' . $e;
$this->writeLog($text, 'error');
return false;
}
if (isset($orders['orders']) && sizeof($orders['orders'])) {
foreach ($orders['orders'] as $order) {
if (isset($toUpload[$order['number']]))
unset($toUpload[$order['number']]);
}
}
time_nanosleep(0, 200000000);
} while ($ordersListPage < $orders['pagination']['totalPageCount']);
return $toUpload;
}
}

83
classes/Parser.php Normal file
View File

@ -0,0 +1,83 @@
<?php
class Parser {
const ENCODING = 'UTF-8';
protected $config;
public function __construct($config) {
$this->config = $config;
}
public function parseXMLNewOrder(SimpleXMLElement $xml) {
$order = $this->explodeFIO((string)$xml->name);
foreach($xml->attributes() as $key => $val) {
switch ($key) {
case 'id':
$val = (string)$val;
$order['number'] = $this->config['order_prefix'] . $val;
break;
case 'state':
$orderStatuses = array_flip($this->config['order_statuses']);
$order['status'] = $orderStatuses[(string)$val];
break;
}
}
$createdAt = \DateTime::createFromFormat('d.m.y H:i', (string)$xml->date);
$createdAt = $createdAt->format('Y-m-d H:i:s');
if (isset($this->config['date_from']) && $createdAt < $this->config['date_from'])
return false;
$order = array_merge($order, array(
'email' => (string)$xml->email,
'phone' => (string)$xml->phone,
'orderMethod' => $this->config['order_method'],
'createdAt' => $createdAt,
'paymentType' => $this->config['payment'][(string)$xml->paymentType],
'delivery' => array(
'address' => array(
'text' => (string)$xml->address
),
'code' => $this->config['delivery'][(string)$xml->deliveryType]
)
));
$items = array();
$xmlItems = $xml->items;
foreach($xmlItems as $xmlItem) {
$xmlItem = $xmlItem->item;
$items[] = array(
'productId' => (string)$xmlItem->external_id,
'productName' => (string)$xmlItem->name,
'quantity' => (string)$xmlItem->quantity,
'initialPrice' => (string)$xmlItem->price
);
}
$order['items'] = $items;
return $order;
}
public function explodeFIO($name) {
$name = explode(' ', $name, 3);
$firstName = $lastName = $patronymic = '';
switch (sizeof($name)) {
case 1:
$firstName = $name[0];
break;
case 2:
$firstName = $name[0];
$lastName = $name[1];
break;
case 3:
$firstName = $name[1];
$lastName = $name[0];
$patronymic = $name[2];
break;
}
return array(
'firstName' => $firstName,
'lastName' => $lastName,
'patronymic' => $patronymic
);
}
}

47
config/config-dist.php Normal file
View File

@ -0,0 +1,47 @@
<?php
$сonfig = array(
// ссылка вида https://my.tiu.ru/cabinet/export_orders/xml/1234567?hash_tag=472g8fzb1af38d35f2c521dc8a1e1208
// берется отсюда: https://my.tiu.ru/cabinet/order/export_orders
'tiu_xml_url' => '',
'retailcrm_url' => 'https://site.retailcrm.ru',
'retailcrm_apikey' => 'qwerty123',
'retailcrm_order_chunk_size' => 50,
// загружать заказы только с определенной даты (Y-m-d H:i:s)
'date_from' => '',
'order_prefix' => 'TIU', // приписывается к номеру заказа в CRM
'set_external_ids' => false, // задавать ли externalId заказам
'order_method' => 'tiu', // способ оформления заказа
// соответствие доставок tiu => CRM
// https://my.tiu.ru/cabinet/shop_settings/delivery_options
'delivery' => array(
'Транспортная компания' => 'courier',
'Доставка курьером' => 'courier',
'Самовывоз' => 'courier'
),
// соответствие оплат tiu => CRM
// https://my.tiu.ru/cabinet/shop_settings/payment_options
'payment' => array(
'Наличными' => 'cash',
'Оплата банковской картой' => 'bank-card',
'Безналичный расчет' => 'bank-transfer'
),
// статусы заказов CRM => tiu
// https://my.tiu.ru/cabinet/order_v2
// по умолчанию заданы 4 статуса:
// 'opened' - новый, 'accepted' - принят, 'declined' - отменен, 'closed' - выполнен
'order_statuses' => array(
'new' => 'opened',
'processing' => 'accepted',
'complete' => 'closed',
'cancel-other' => 'declined',
),
// почта для логов с ошибками
'support_email' => '',
'support_email_subject' => 'tiu fail'
);

0
logs/.gitkeep Normal file
View File

22
run.php Normal file
View File

@ -0,0 +1,22 @@
<?php
require(__DIR__ . "/classes/ApiHelper.php");
require(__DIR__ . "/config/config.php");
if (! file_exists(__DIR__ . "/logs"))
mkdir(__DIR__ . "/logs");
if (file_exists(__DIR__ . "/logs/cookie.txt"))
unlink(__DIR__ . "/logs/cookie.txt");
$lockFile = __DIR__ . "/run.lock";
if (file_exists($lockFile)) {
if ((int)file_get_contents($lockFile) > time()) {
echo "script is busy";
exit();
}
}
file_put_contents("run.lock", strtotime('+5 minutes'));
$apiHelper = new ApiHelper($сonfig);
if ($apiHelper->processXMLOrders())
unlink($lockFile);