Интернет-торговля развивается стремительными темпами, и одним из главных направлений её роста является интеграция различных платформ для улучшения удобства ведения бизнеса. В этой статье мы рассмотрим важную тему – интеграцию системы управления 1С-Битрикс с одним из крупнейших онлайн-ретейлеров России – Wildberries, с акцентом на выгрузку остатков.
Почему интеграция важна?
Wildberries является одной из ведущих площадок для онлайн-продаж, предоставляя доступ к огромной аудитории покупателей. Чтобы эффективно управлять бизнесом, необходимо легко и быстро обмениваться данными между вашим интернет-магазином и Wildberries. Именно здесь на помощь приходит 1С-Битрикс, одна из самых популярных систем управления сайтом в России.
Преимущества интеграции 1С-Битрикс с Wildberries:
- Автоматизация процессов: Интеграция позволяет автоматизировать обмен данными о товарах, заказах и остатках, что значительно сокращает временные затраты на ручную работу.
- Синхронизация данных: Обеспечивает точную и актуальную информацию о наличии товаров, ценах и статусах заказов.
- Увеличение продаж: Быстрая и точная обработка заказов и управление запасами способствует повышению уровня обслуживания клиентов, что может привести к увеличению объема продаж.
- Удобство управления: Все процессы управляются из одной системы, что облегчает контроль и анализ эффективности бизнеса.
Готовые плагины и ручная настройка
На рынке существует множество готовых решений для интеграции 1С-Битрикс и Wildberries. Эти плагины предоставляют простую и быструю настройку обмена данными, но иногда они могут быть недостаточно гибкими или не полностью соответствовать специфическим требованиям вашего бизнеса. Поэтому, в этой статье мы попробуем сделать все сами, шаг за шагом, с акцентом на выгрузку остатков.
Как происходит интеграция?
Шаг 1: Подготовка
Прежде чем начать процесс интеграции, необходимо убедиться, что у вас есть учетные записи в 1С-Битрикс и Wildberries. Кроме того, рекомендуется иметь базовые знания об обеих платформах, чтобы процесс настройки прошел гладко.
Шаг 2: Создание скрипта для выгрузки остатков
Основная цель скрипта
Наша основная цель – создать скрипт, который будет автоматически выгружать данные о текущих остатках товаров из 1С-Битрикс в Wildberries.
Структура скрипта
- Получение данных об остатках: Скрипт должен получать актуальные данные о остатках товаров из 1С-Битрикс.
- Форматирование данных: Данные должны быть отформатированы в соответствии с требованиями API Wildberries.
- Отправка данных в Wildberries: Скрипт должен отправлять данные об остатках в Wildberries через их API.
Шаг 3: Написание и настройка скрипта
1. Получение токена wildberries в личном кабинете. Для этого в личном кабинете продавца переходим в настройки.
Создаем новый ключ api.
Обязательно создаем для управления контентом и маркетплейсом.
2) в файле /local/php_interface/init.php cоздаем обработчик событий.
\Bitrix\Main\Loader::registerAutoLoadClasses(
null,
array(
"wildberriesApi" => "/bitrix/php_interface/class/wildberries.php",
)
);
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
"catalog",
"OnStoreProductUpdate",
array(
"wildberriesApi",
"OnStoreProductUpdateHandler"
),
);
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
"catalog",
"OnStoreProductAdd",
array(
"wildberriesApi",
"OnStoreProductUpdateHandler"
)
);
В файле /local/php_interface/class/wildberries.php пишем сам класс обработки.
class wildberriesApi
{
public $iblockId = 8; // id инфоблока каталога
public $token = "<токен WB>";
public $arElement = [];
public $warehouses = [];
public $articlePropCode = "CML2_ARTICLE"; // Свойство артикулаpublic $tableName = "b_wildberries_product_update"; // название таблицы sql
public $tableLimit = 1000; // количество товаров отправляемых за один шаг
public $storeCompare = [ // Сопоставления складов
<id склада сайта>=><id склада WB>,
];
public static function OnStoreProductUpdateHandler($ID, $arFields){
$class = new wildberriesApi();
$class->SetProductStore($arFields["PRODUCT_ID"],$arFields["STORE_ID"],$arFields["AMOUNT"]);
return true;
}
public function sendWB() { // проверить наличие таблицы в базе данных
$this->checkTableDB();
global $DB;
$rowIDs = [];
$arElements = [];
$results = $DB->Query("SELECT * FROM `".$this->tableName."` WHERE `STATUS`='NEW' LIMIT ".$this->tableLimit.";");
while ($row = $results->Fetch()){
$rowIDs[] = $row["ID"];
$arElements[$row["PRODUCT_ID"]]["STORES"][$row["STORE_ID"]] = $row;
}
if(!empty($arElements)){
$arSelect = Array("ID", "IBLOCK_ID", "NAME", "PROPERTY_*");
$arFilter = Array("ID" => array_keys($arElements));
$res = CIBlockElement::GetList(Array(), $arFilter, false, Array("nPageSize"=>$this->tableLimit), $arSelect);
while($ob = $res->GetNextElement()){
$arFields = $ob->GetFields();
if(!empty($arElements[$arFields["ID"]])){
$arFields["PROPS"] = $ob->GetProperties();
$arElements[$arFields["ID"]] = array_merge($arElements[$arFields["ID"]],$arFields);
}
}
foreach ($arElements as $id => $arData) {
if($arData["IBLOCK_ID"] != $this->iblockId){
$this->saveLog(["DELETE",$arData["ID"]]);
$DB->Query("DELETE FROM `".$this->tableName."` WHERE `PRODUCT_ID` = '".$arData["ID"]."';");
continue;
}
$this->saveLog(["START",$arData["ID"]]);
$DB->Query("UPDATE `".$this->tableName."` SET `STATUS` = 'START' WHERE `PRODUCT_ID` = '".$arData["ID"]."';");
if($this->UpdateStore($arData) == true){
$this->saveLog(["END",$arData["ID"]]);
$DB->Query("UPDATE `".$this->tableName."` SET `STATUS` = 'END' WHERE `PRODUCT_ID` = '".$arData["ID"]."';");
}else{
$this->saveLog(["NO_WB",$arData["ID"]]);
$DB->Query("UPDATE `".$this->tableName."` SET `STATUS` = 'NO_WB' WHERE `PRODUCT_ID` = '".$arData["ID"]."';");
}
}
}
}
public function checkTableDB() { // проверить наличие таблицы в базе данных
global $DB;
$results = $DB->Query("SHOW TABLES LIKE '".$this->tableName."';");
if (!($row = $results->Fetch())){
$DB->Query("CREATE TABLE `".$this->tableName."` ( `ID` INT(18) NOT NULL AUTO_INCREMENT , `PRODUCT_ID` INT(18) NOT NULL , `STORE_ID` INT(18) NOT NULL , `AMOUNT` INT(18) NOT NULL , `STATUS` VARCHAR(255) NOT NULL , PRIMARY KEY (`ID`)) ENGINE = InnoDB;");
}
}
public function SetProductStore($PRODUCT_ID, $STORE_ID, $AMOUNT) {
$this->checkTableDB();
global $DB;
$results = $DB->Query("SELECT * FROM `".$this->tableName."` WHERE `PRODUCT_ID`='".$PRODUCT_ID."' AND `STORE_ID`='".$STORE_ID."';");
if ($row = $results->Fetch()){
$DB->Query("UPDATE `".$this->tableName."` SET `AMOUNT` = '".$AMOUNT."', `STATUS` = 'NEW' WHERE `ID` = '".$row["ID"]."';");
}else{
$DB->Query("INSERT INTO `".$this->tableName."` (`PRODUCT_ID`, `STORE_ID`, `AMOUNT`, `STATUS`) VALUES ('".$PRODUCT_ID."', '".$STORE_ID."', '".$AMOUNT."', 'NEW');");
}
}
public function UpdateStore($arElement) {
global $DB;
$this->arElement = $arElement;
$vendorCode = $this->getProductArticle();
$this->arElement["WB_DATA"] = $this->getProductWildberries($vendorCode)["cards"];
if(empty($this->arElement["WB_DATA"])){
return false;
}
foreach ($this->arElement["STORES"] as $key => $value) {
if(!empty($this->storeCompare[$key])){
$value["sku"] = current(current(current($this->arElement["WB_DATA"])["sizes"])["skus"]);
if(!empty($value["sku"])){
$value["api"] = $this->SendRequest("/api/v3/stocks/".$this->storeCompare[$key],[
"stocks" => [
[
"sku" => $value["sku"],
"amount" => (float)$value["AMOUNT"]
]
]
], "PUT");
}
}
}
return true;
}
public function getProductStore($id) {
$arReturn = [];
$rsStoreProduct = \Bitrix\Catalog\StoreProductTable::getList(array(
'filter' => array('=PRODUCT_ID'=>$id,'STORE.ACTIVE'=>'Y'),
'select' => array('STORE_ID','AMOUNT','STORE_TITLE' => 'STORE.TITLE'),
));
while($arStoreProduct=$rsStoreProduct->fetch()){
$arReturn[$arStoreProduct["STORE_ID"]] = $arStoreProduct;
}
return $arReturn;
}
public function getProductWildberries($text) {
return $this->SendRequest("/content/v2/get/cards/list",[
"settings" => [
"filter" => [
"textSearch" => $text,
"allowedCategoriesOnly" => false,
"withPhoto" => -1
],
"cursor" => [
"limit" => 1
]
]
]);
}
public function getProductArticle() {
return is_array($this->arElement["PROPS"][$this->articlePropCode]["VALUE"])?current($this->arElement["PROPS"][$this->articlePropCode]["VALUE"]):$this->arElement["PROPS"][$this->articlePropCode]["VALUE"];
}
public function SendRequest($url,$data,$methodPost = "POST") {
$curl = curl_init();
if($methodPost == "POST"){
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://suppliers-api.wildberries.ru'.$url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => array(
'Authorization: Bearer '.$this->token,
'Content-Type: application/json'
),
));
}
if($methodPost == "GET"){
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://suppliers-api.wildberries.ru'.$url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_POSTFIELDS =>json_encode($data),
CURLOPT_HTTPHEADER => array(
'Authorization: Bearer '.$this->token,
'Content-Type: application/json'
),
));
}
if($methodPost == "PUT"){
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://suppliers-api.wildberries.ru'.$url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS =>json_encode($data),
CURLOPT_HTTPHEADER => array(
'Authorization: Bearer '.$this->token,
'Content-Type: application/json'
),
));
}
$response = curl_exec($curl);
curl_close($curl);
return json_decode($response , true);
}
public function saveLog($log){
file_put_contents($_SERVER["DOCUMENT_ROOT"]."/local/php_interface/class/wildberries.log" , var_export($log , true));
}
}
Обратите внимание на переменные которые описаны в начале класса. Туда нужно вставить ваши данные и склады. Скрипт отрабатывает в момент сохранения остатков товара.
В файле /local/php_interface/cron/sendWB.php пишем запуск по cron.
$_SERVER["DOCUMENT_ROOT"] = "путь до корня сайта";
$DOCUMENT_ROOT = $_SERVER["DOCUMENT_ROOT"];
define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS",true);
define("BX_CRONTAB", true);
define('BX_WITH_ON_AFTER_EPILOG', true);
define('BX_NO_ACCELERATOR_RESET', true);
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
CModule::IncludeModule('iblock');
set_time_limit(1630000);
ini_set('max_execution_time', 90000);
ini_set('memory_limit', '3048M');
(new wildberriesApi())->sendWB();
Интеграция 1С-Битрикс с Wildberries – это мощный инструмент, который помогает автоматизировать процессы, улучшить управление бизнесом и увеличить продажи. Следуя нашим рекомендациям и примерному коду, вы сможете настроить эту интеграцию быстро и без особых проблем, что позволит вам сосредоточиться на развитии вашего бизнеса и удовлетворении потребностей клиентов.
Поделитесь в комментариях своим опытом интеграции 1С-Битрикс с Wildberries и задавайте вопросы, если они у вас возникли! Мы всегда рады помочь.