Інтеграція 1С-Бітрікс із PIM-системою Salsify

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Інтеграція 1С-Бітрікс із PIM-системою Salsify
Середня
~1-2 тижні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Інтеграція 1С-Бітрікс із PIM-системою Salsify

Salsify — американська SaaS PIM-платформа, орієнтована на великої електронної комерції та мультиканальні продажи. Використовується переважно брендами та дистрибюторами, які керують тисячами SKU із синдикацією на маркетплейси (Amazon, Walmart, Target). Якщо на Бітрікс перенесено західний бренд або партнерство передбачає використання Salsify як джерела даних — інтеграція будується через REST API Salsify.

Salsify API: основні ендпоінти

Salsify надає REST API із аутентифікацією за токеном:

Base URL: https://app.salsify.com/api/v1/orgs/{org_id}/
Authorization: Bearer {api_key}

Ключові ендпоінти:

GET products                    — список продуктів з атрибутами
GET products/{product_id}       — конкретний продукт
GET products?filter[updated_at][gte]={timestamp}  — змінені з дати
GET property_groups             — групи атрибутів (аналог розділів властивостей)
GET assets?filter[product_id]={id}  — медіафайли продукту
GET digital_assets/{id}/download    — завантажити файл

Salsify використовує плоску структуру атрибутів: кожний атрибут — пара «імя» : «значення», де імя може бути довільним UUID або рядком. Перед маппінгом отримайте довідник атрибутів:

GET properties — повертає всі атрибути організації з ID, name, data_type

Клієнт Salsify

class SalsifyClient
{
    private string $baseUrl;
    private string $apiKey;

    public function __construct(string $orgId, string $apiKey)
    {
        $this->baseUrl = "https://app.salsify.com/api/v1/orgs/{$orgId}/";
        $this->apiKey  = $apiKey;
    }

    private function request(string $endpoint, array $params = []): array
    {
        $http = new \Bitrix\Main\Web\HttpClient();
        $http->setHeader('Authorization', 'Bearer ' . $this->apiKey);
        $http->setHeader('Content-Type', 'application/json');

        $url = $this->baseUrl . $endpoint;
        if ($params) {
            $url .= '?' . http_build_query($params);
        }

        $response = $http->get($url);
        return json_decode($response, true) ?? [];
    }

    public function getProducts(int $page = 1, int $perPage = 100, ?string $updatedAfter = null): array
    {
        $params = ['page' => $page, 'per_page' => $perPage];
        if ($updatedAfter) {
            $params['filter[updated_at][gte]'] = $updatedAfter;
        }
        return $this->request('products', $params);
    }

    public function getProperties(): array
    {
        return $this->request('properties');
    }

    public function downloadAsset(string $assetId): string
    {
        $http = new \Bitrix\Main\Web\HttpClient();
        $http->setHeader('Authorization', 'Bearer ' . $this->apiKey);
        return $http->get($this->baseUrl . 'digital_assets/' . $assetId . '/download');
    }
}

Маппінг атрибутів Salsify

Атрибути Salsify ідентифікуються за salsify:id (UUID) або за name. Конфігурація маппінгу:

// /local/config/salsify-mapping.php
// 'salsify_property_id_or_name' => ['target' => 'bitrix_field', 'type' => 'field|prop']
return [
    'Product Name'              => ['target' => 'NAME',          'type' => 'field'],
    'Long Description'          => ['target' => 'DETAIL_TEXT',   'type' => 'field'],
    'Short Description'         => ['target' => 'PREVIEW_TEXT',  'type' => 'field'],
    'Brand'                     => ['target' => 'BRAND',         'type' => 'prop'],
    'Net Weight (kg)'           => ['target' => 'WEIGHT',        'type' => 'prop'],
    'Color'                     => ['target' => 'COLOR',         'type' => 'prop'],
    'Country of Origin'         => ['target' => 'COUNTRY_ORIGIN','type' => 'prop'],
    'GTIN'                      => ['target' => 'CML2_BAR_CODE', 'type' => 'prop'],
    'Manufacturer SKU'          => ['target' => 'CML2_ARTICLE',  'type' => 'prop'],
];

Синхронізація

function syncSalsifyAgent(): string
{
    $lastSync = \Bitrix\Main\Config\Option::get('salsify_sync', 'last_run', '');
    $client   = new SalsifyClient(SALSIFY_ORG_ID, SALSIFY_API_KEY);
    $mapping  = include '/local/config/salsify-mapping.php';

    $page    = 1;
    $newSync = date('c');

    do {
        $response = $client->getProducts($page, 100, $lastSync ?: null);
        $products = $response['products'] ?? [];

        foreach ($products as $product) {
            importSalsifyProduct($product, $mapping, $client);
        }

        $page++;
        $meta = $response['meta'] ?? [];
    } while (($meta['current_page'] ?? 1) < ($meta['total_pages'] ?? 1));

    \Bitrix\Main\Config\Option::set('salsify_sync', 'last_run', $newSync);
    return __FUNCTION__ . '();';
}

function importSalsifyProduct(array $product, array $mapping, SalsifyClient $client): void
{
    $attributes = $product['attributes'] ?? [];
    $sku        = $product['salsify:id'];

    // Отримуємо значення атрибутів
    $getValue = static function (array $attrs, string $key): mixed {
        return $attrs[$key] ?? null;
    };

    $fields = ['IBLOCK_ID' => CATALOG_IBLOCK_ID, 'ACTIVE' => 'Y'];
    $props  = [];

    foreach ($mapping as $salsifyKey => $config) {
        $value = $getValue($attributes, $salsifyKey);
        if ($value === null) continue;

        // Масиви перетворюємо в рядок через розділювач
        if (is_array($value)) {
            $value = implode(', ', $value);
        }

        if ($config['type'] === 'field') {
            $fields[$config['target']] = $value;
        } else {
            $props[$config['target']] = $value;
        }
    }

    $existing = CIBlockElement::GetList(
        [], ['IBLOCK_ID' => CATALOG_IBLOCK_ID, 'PROPERTY_CML2_ARTICLE' => $sku]
    )->Fetch();

    $el = new CIBlockElement();

    if ($existing) {
        $productId = $existing['ID'];
        $el->Update($productId, $fields);
    } else {
        $productId = $el->Add($fields);
    }

    if ($productId) {
        CIBlockElement::SetPropertyValuesEx($productId, CATALOG_IBLOCK_ID, $props);

        // Медіафайли
        $primaryImage = $product['salsify:primary_image'] ?? null;
        if ($primaryImage) {
            importSalsifyAsset($productId, $primaryImage, $client);
        }
    }
}

Особливості Salsify

Складні значення атрибутів. Salsify повертає атрибути як масив, де кожний елемент може бути скалярним значенням, об'єктом або списком. Enum-атрибути повертають {"salsify:id": "...", "salsify:name": "Red"} — потрібно вилучати salsify:name.

Ціни. Salsify не є системою ціноутворення. Ціни, як правило, не синхронізуються з Salsify — вони надходять з 1С. Перевірте з клієнтом, чи є Salsify джерелом цін або лише контенту.

Медіафайли. Salsify зберігає медіафайли із CDN-посиланнями. Можна не завантажувати файли, а зберігати зовнішні URL у властивості EXTERNAL_IMAGE_URL та підтягувати на льоту через <img src="...">. Це економить місце на сервері Бітрікс.

Webhook. Salsify підтримує вебхуки при зміні продукту. Налаштовується в Salsify → Integrations → Webhooks. URL обробника отримує POST-запит з product_id, потім запитує актуальні дані через API.

Тривалість реалізації

Обсяг Склад Тривалість
До 5 000 SKU, базовий контент Клієнт + маппінг + агент 1–2 тижня
10 000–100 000 SKU + медіа + вебхуки + обробка складних атрибутів + оптимізація 3–4 тижня
Мультирегіональний каталог (різні ціни, контент по регіонам) + логіка каналів Salsify + мультисайт Бітрікс 5–7 тижнів