Напишите нам в WhatsApp
+7(906) 943-40-17
Сохраните этот номер в контактах и вы сможете написать нам в WhatsApp.
Или оставьте номер и мы сами напишем вам в WhatsApp
Условиями о персональных данных
Кнопка закрыть
Спасибо!
Спасибо, что оставили заявку.
Мы обработаем вашу заявку и обязательно позвоним!
Кнопка закрыть
Форма заявки
Оставьте ваши контакты,
мы обязательно с вами свяжемся
Ваше имя
Номер телефона (Перезвоним Вам)
Комментарий
Отправляя форму вы соглашаетесь с политикой конфиденциальности
пн-вс с 9:00 до 21:00
Почта: hello@redbe.ru
Уже есть сайт?
Сделаем бесплатный аудит с точки зрения маркетинга и SEO

Интеграция сайта на MODX с 1С подробное руководство и примеры

Интеграция сайта на MODX с 1С подробное руководство и примеры

Введение

Связать сайт на MODx с 1С можно несколькоми способами, но самый простой через модуль mSync. Это компонент для MODX (Revolution + miniShop2), предназначенный для синхронизации товаров, торговых предложений и заказов между сайтом и системой 1C или аналогичными сервисами, такими как Класс365 и МойСклад, посредством протокола CommerceML.

Возможности mSync

  • Импорт товаров и торговых предложений: поддержка CommerceML, возможность загрузки данных от 1C.
  • Экспорт заказов на сайт: передача заказов из CMS на сторону 1C.
  • Логирование: файлы логов для каждого процесса — полное и сокращённое; удобно для диагностики.
  • Плагины / События: множество событий (mSyncOnPrepareCategory, mSyncOnBeforeImportProduct, mSyncOnProductOffers и др.), позволяющих гибко дорабатывать обмен.
  • Ручная загрузка файлов: можно загружать import.xml и/или offers.xml независимо.
  • Поддержка кастомных свойств: легко интегрировать собственные свойства товаров, включая множественные.
  • Совместимость: требует miniShop2 и PHP ≥ 5.3.0 с модулями SimpleXML, XMLReader и XMLWriter.

Протокол обмена: 1C ⇄ сайт

Интеграция осуществляется через протокол CommerceML 2 и HTTP-запросы:

1. Синхронизация каталога (type=catalog)

  1. checkauth — начинается сеанс; возвращаются строки: success, имя Cookie, его значение.
  2. init — сайт сообщает, поддерживает ли zip (zip=yes/no) и максимальный размер файла (file_limit=…).
  3. file — передача файла (или его части) import.xml/offers.xml через POST.
  4. import — сайт импортирует файл, возвращает success или failure.

2. Синхронизация заказов (type=sale)

  1. checkauth;
  2. file — загрузка файла с заказами;
  3. success — подтверждение записи заказа.

Примерная схема интеграции (сценарий)

Подготовка

  1. Устанавливаем компонент mSync в MODX (miniShop2). Убедитесь, что PHP и XML-модули доступны.
  2. Передаем данные для синхронизации с сайтом 1С-никам

  3. Настраиваем соответствия свойств 1C → TV или с опциями товаров, это делается через интерфейс модуля.

  4. Производим настройки модуля в системных настройках

Обмен каталога (1C → сайт)

  • 1C делает checkauth → получает Cookie.
  • Затем init → получает zip и file_limit.
  • Отправляет файл (file) — import.xml и/или offers.xml.
  • Запрашивает import — сайт обрабатывает.

Обмен заказами (сайт → 1C)

  • 1C инициирует checkauth.
  • Загружает файл с заказами.
  • Подтверждение success.

Практические советы и примеры

  • Ручная инициация: можно остановить или перезапустить синхронизацию в панели mSync.

  • Логирование: изучайте логи при failure.
  • Оптимизация: делайте обмен только изменённых данных; используйте file_limit и zip.
  • Отладка: при замедлении проверяйте нагрузку сервера и настройки 1C.
  • Тестирование: начните с тестовой версии 1C.

Пример конфигурации

// В MODX → miniShop2
// Настройки mSync:
- Связать UUID 1C с полем Ид.
- Настроить свойства: TV, множественные атрибуты.
- Включить логирование — полный режим.

1C: Предприятие:
- Настроить узел обмена: URL вида
  http://site.ru/1c_exchange.php?type=catalog&mode=...
- Передавать import.xml → файл каталога.
- Передавать offers.xml → предложения (цена, остатки).

Сценарий обмена:
1. checkauth → init → file (=> import.xml) → import
2. checkauth → file (=> orders.xml) → success

Выявление ошибок:
- читать логи.
- Разбить файлы при превышении file_limit.
- Проверить кодировку XML (UTF-8).

Сравнение потоков обмена

Направление Как инициируется Протокол / формат Примечания
1C → сайт (каталог) 1C HTTP + CommerceML 2 Checkauth → init → file → import
1C ← сайт (заказы) 1C HTTP + CommerceML 2 Checkauth → file → success
Управление mSync сайт MODX-интерфейс Ручной запуск, логирование
Проблемы нагрузка, XML, большой импорт - Разделяйте файлы, оптимизируйте настройки

Логирование данных с 1С

Для простоты и понимания что именно приходит к нам на сайт по каждому товары рекомундую создать TV поле и складывать туда JSON

Разбор структуры файлов CommerceML синхронизации 1С

Для ознакомления можно скачать файлы примеры синхронизации, разобрать их и понять как именно 1С передает данные сайту

import.xml
offers.xml

Разбор структуры файлов CommerceML

1) import.xml — каталог и описание товаров :contentReference[oaicite:0]{index=0}

Назначение: описывает структуру каталога, категории, свойства и полные карточки товаров.

  • <Классификатор> — метаданные каталога:
    • <Группы> — древовидные категории (включая вложенные группы).
    • <Свойства> — список характеристик (например, «Размер», «Цвет») и их варианты значений.
  • <Каталог СодержитТолькоИзменения="..."> — набор товарных позиций:
    • <Товар> — карточка товара:
      • <Ид>, <Артикул>, <Наименование> — идентификаторы и базовые реквизиты.
      • <Группы> — привязка к категории(ям) из классификатора.
      • <Описание>, <Изготовитель>, <Штрихкод> — дополнительные сведения.
      • <ХарактеристикиТовара> — произвольные характеристики (пример: «Страна: Россия»).
      • <ЗначенияРеквизитов> — реквизиты вроде «Полное наименование», «Вес» и др.
      • <ЗначенияСвойств> — значения свойств из <Свойства> классификатора (по ссылкам <Ид> свойств).
      • <Картинка> — относительный путь к изображению (например, 1.jpg).

2) offers.xml — цены и остатки :contentReference[oaicite:1]{index=1}

Назначение: содержит коммерческие предложения, то есть цены и доступные количества для уже описанных в import.xml товаров.

  • <ПакетПредложений>:
    • <ТипыЦен> — перечень типов цен (например, «Цена продажи», валюта, настройки НДС).
    • <Предложения> — список предложений по товарам:
      • <Предложение>:
        • <Ид> — GUID товара (совпадает с <Ид> из import.xml).
        • <Артикул>, <Наименование> — справочная информация.
        • <Цены><Цена>:
          • <ИдТипаЦены> — ссылка на тип цены из <ТипыЦен>.
          • <ЦенаЗаЕдиницу> — числовое значение цены.
          • <Валюта> — код валюты (например, 643 для RUB).
          • <Единица>, <Коэффициент> — единица измерения и коэффициент пересчёта.
        • <Количество> — остаток на складе.

Как файлы связаны между собой

  • Ключ связи: элемент <Ид> товара. Он идентичен в import.xml и offers.xml (по нему система находит цены/остатки для конкретной карточки). :contentReference[oaicite:2]{index=2}:contentReference[oaicite:3]{index=3}
  • Логика обновлений: описания и структура (категории, свойства) редактируются реже, поэтому они живут в import.xml, а оперативные данные (цены/остатки) — в offers.xml.

Мини-пример связки

import.xml → <Товар><Ид>46a248db-ae57-4027-b2b9-a135822f33ad</Ид>...</Товар>  
offers.xml → <Предложение><Ид>46a248db-ae57-4027-b2b9-a135822f33ad</Ид>...</Предложение>  

Плагины и события

Для продвинутых пользователей и сложных 1С систем часто требуется доработка на уровене плагина

Примеры плагина для события mSyncOnProductOffers

Где подключать: создайте плагин в MODX → Elements → Plugins, включите событие mSyncOnProductOffers, вставьте код из примеров ниже.

1) Базовый каркас плагина: проверки и входные данные

<?php
if ($modx->event->name !== 'mSyncOnProductOffers') {
    return;
}

/** @var modResource $resource  Товар (msProduct) */
if (empty($resource) || !($resource instanceof modResource)) {
    $modx->log(modX::LOG_LEVEL_ERROR, '[mSync] Нет $resource в событии');
    return;
}

/** @var SimpleXMLElement $xml  Узел CommerceML <Предложение> */
if (empty($xml) || !($xml instanceof SimpleXMLElement)) {
    $modx->log(modX::LOG_LEVEL_ERROR, '[mSync] Нет $xml (Предложение)');
    return;
}

// Текущая цена товара из сайта (до пересчетов)
$currentPrice = (float)$resource->get('price');

// Свойства CommerceML, которые вы положили в TV / поле (пример: TV с ID=23)
$props = json_decode($resource->getTVValue(23), true) ?: [];

// Удобные хелперы
$asFloat = static function($val) {
    $val = is_string($val) ? str_replace(',', '.', $val) : $val;
    return (float)$val;
};

$round3 = static function($val) {
    return round((float)$val, 3);
};

2) Пересчет цены из цены за упаковку → цену за м²

Частый кейс для плитки: 1С передает цены за упаковку, а на сайте нужна цена за м².

<?php
// Из props ожидаем:
// "Площадь в упаковке, м2", "Количество в упаковке, шт"
$areaPerPack = $asFloat($props['Площадь в упаковке, м2'] ?? 0);
$packQty     = $asFloat($props['Количество в упаковке, шт'] ?? 0);

if ($areaPerPack > 0) {
    // Упаковок в 1 м² = 1 / Sупак
    // Цена за м² = (1 / Sупак) * price(за упаковку)
    $newPrice = $round3((1 / $areaPerPack) * $currentPrice);

    $resource->set('price', $newPrice);
    $resource->set('units', 'м2');
    $resource->save();

    $modx->log(modX::LOG_LEVEL_INFO, "[mSync] Пересчет цены на м²: {$newPrice}");
}

3) Пересчет остатков по складам под новую единицу измерения

Если остатки в 1С хранятся в упаковках, а на сайте показываем м² — пересчитаем по той же формуле.

<?php
$totalStockM2 = 0.0;

// Сопоставление складов 1С → поля ресурса на сайте
$warehouseMap = [
    'AAAAAAAA-1111-2222-3333-000000000001' => 'stock_warehouse_1',
    'AAAAAAAA-1111-2222-3333-000000000002' => 'stock_warehouse_2',
    // ...добавьте свои соответствия
];

if (isset($xml->Склад) && $areaPerPack > 0) {
    foreach ($xml->Склад as $warehouse) {
        $warehouseId = (string)$warehouse->attributes()->ИдСклада;
        $qtyPack     = $asFloat((string)$warehouse->attributes()->КоличествоНаСкладе);

        // Переводим из упаковок в м²
        $qtyM2 = $round3($qtyPack / (1 / $areaPerPack)); // эквивалентно $qtyPack * $areaPerPack
        $totalStockM2 += $qtyM2;

        if (isset($warehouseMap[$warehouseId])) {
            $resource->set($warehouseMap[$warehouseId], $qtyM2);
        }
    }

    $resource->set('stock_all', $totalStockM2);           // суммарный остаток в м²
    $resource->set('stock_filter', (string)$xml->Количество[0]); // «сырой» остаток из 1С для фильтра
    $resource->save();

    $modx->log(modX::LOG_LEVEL_INFO, "[mSync] Пересчитанные остатки, м²: {$totalStockM2}");
}

4) Категориальные правила пересчета

Иногда пересчет нужен только для части категорий. Получим категорию товара и применим правила выборочно.

<?php
// Родители (в т.ч. категория) — подстройте нужный уровень в массиве
$parents = array_reverse($modx->getParentIds($resource->get('id'), 10, ['context' => 'web']));
$categoryId = $parents[2] ?? null;

// Категории, где нужен пересчет на м²
$categoryRecalc = [111, 222, 333];

if ($categoryId && in_array($categoryId, $categoryRecalc, true) && $areaPerPack > 0) {
    $newPrice = $round3((1 / $areaPerPack) * $currentPrice);
    $resource->set('price', $newPrice);
    $resource->set('units', 'м2');
    $resource->save();
    $modx->log(modX::LOG_LEVEL_INFO, "[mSync] Категориальный пересчет цены: {$newPrice}");
}

5) Процентная скидка из свойства CommerceML

Если в выгрузке приходит «% Скидки» — применим её к цене, сохранив старую цену и отметив товар как акционный.

<?php
$discount = $asFloat($props['% Скидки'] ?? 0);

if ($discount > 0) {
    $basePrice = (float)$resource->get('price');
    $salePrice = round($basePrice * (1 - $discount / 100));

    $resource->set('old_price', $basePrice);
    $resource->set('price', $salePrice);

    // Флаг или мульти-опция для «спецпредложений»
    $opt = $resource->get('special_offers');
    $opt = is_array($opt) ? $opt : ($opt ? [$opt] : []);
    if (!in_array('Товар со скидкой', $opt, true)) {
        $opt[] = 'Товар со скидкой';
    }
    $resource->set('special_offers', $opt);

    $resource->save();
    $modx->log(modX::LOG_LEVEL_INFO, "[mSync] Скидка {$discount}%, новая цена: {$salePrice}");
} else {
    // Сбрасываем старую цену и убираем метку при отсутствии скидки
    $resource->set('old_price', 0);
    $opt = $resource->get('special_offers');
    $opt = is_array($opt) ? $opt : ($opt ? [$opt] : []);
    if (in_array('Товар со скидкой', $opt, true)) {
        $opt = array_values(array_diff($opt, ['Товар со скидкой']));
        $resource->set('special_offers', $opt);
    }
    $resource->save();
}

6) Переименование товара для витрины

Если в свойствах приходит «Наименование для интернет-магазина» — используем его для pagetitle/longtitle.

<?php
$shopTitle = trim((string)($props['Наименование для интернет-магазина'] ?? ''));
if ($shopTitle !== '') {
    $resource->set('pagetitle', $shopTitle);
    $resource->set('longtitle', $shopTitle);
    $resource->save();
    $modx->log(modX::LOG_LEVEL_INFO, "[mSync] Новое имя для витрины: {$shopTitle}");
}

7) Проставление флагов «Новинка» / «Акционный под заказ»

<?php
$flagPromoByOrder = (string)($props['Акционный товар под заказ'] ?? '');
$flagNew          = (string)($props['Новинка'] ?? '');

if ($flagPromoByOrder === 'Да') {
    $resource->set('action_product_to_order', 1);
}
if ($flagNew === 'Да') {
    $resource->set('new', 1);
}
$resource->save();

8) Полный, компактный пример плагина «под ключ»

<?php
if ($modx->event->name !== 'mSyncOnProductOffers') return;

if (empty($resource) || !($resource instanceof modResource)) return;
if (empty($xml) || !($xml instanceof SimpleXMLElement)) return;

$asFloat = static function($v){ return (float)str_replace(',', '.', (string)$v); };
$round3  = static function($v){ return round((float)$v, 3); };

$props = json_decode($resource->getTVValue(23), true) ?: [];

$currentPrice  = (float)$resource->get('price');
$areaPerPack   = $asFloat($props['Площадь в упаковке, м2'] ?? 0);
$packQty       = $asFloat($props['Количество в упаковке, шт'] ?? 0);

// Пересчет цены и остатков в м² при наличии площади
if ($areaPerPack > 0) {
    $priceM2 = $round3((1 / $areaPerPack) * $currentPrice);
    $resource->set('price', $priceM2);
    $resource->set('units', 'м2');

    $totalStockM2 = 0.0;
    $warehouseMap = [
        'AAAAAAAA-1111-2222-3333-000000000001' => 'stock_warehouse_1',
        'AAAAAAAA-1111-2222-3333-000000000002' => 'stock_warehouse_2',
    ];
    if (isset($xml->Склад)) {
        foreach ($xml->Склад as $w) {
            $wid   = (string)$w->attributes()->ИдСклада;
            $qPack = $asFloat((string)$w->attributes()->КоличествоНаСкладе);
            $qM2   = $round3($qPack * $areaPerPack);
            $totalStockM2 += $qM2;
            if (isset($warehouseMap[$wid])) {
                $resource->set($warehouseMap[$wid], $qM2);
            }
        }
        $resource->set('stock_all', $totalStockM2);
        $resource->set('stock_filter', (string)$xml->Количество[0]); // «как в 1С»
    }
    $resource->save();
} else {
    // Если считаем поштучно
    $resource->set('units', 'шт');
    if (isset($xml->Склад)) {
        foreach ($xml->Склад as $w) {
            // ... при необходимости мапьте склады в поля ресурса
        }
    }
    $resource->set('stock_all', (string)$xml->Количество[0]);
    $resource->set('stock_filter', (string)$xml->Количество[0]);
    $resource->save();
}

// Скидка
$discount = $asFloat($props['% Скидки'] ?? 0);
if ($discount > 0) {
    $base = (float)$resource->get('price');
    $sale = round($base * (1 - $discount/100));
    $resource->set('old_price', $base);
    $resource->set('price', $sale);
    $opt = $resource->get('special_offers');
    $opt = is_array($opt) ? $opt : ($opt ? [$opt] : []);
    if (!in_array('Товар со скидкой', $opt, true)) $opt[] = 'Товар со скидкой';
    $resource->set('special_offers', $opt);
    $resource->save();
} else {
    $resource->set('old_price', 0);
    $opt = $resource->get('special_offers');
    $opt = is_array($opt) ? $opt : ($opt ? [$opt] : []);
    if (in_array('Товар со скидкой', $opt, true)) {
        $opt = array_values(array_diff($opt, ['Товар со скидкой']));
        $resource->set('special_offers', $opt);
    }
    $resource->save();
}

// Имя для витрины
$title = trim((string)($props['Наименование для интернет-магазина'] ?? ''));
if ($title !== '') {
    $resource->set('pagetitle', $title);
    $resource->set('longtitle', $title);
    $resource->save();
}

// Флаги
if (($props['Акционный товар под заказ'] ?? '') === 'Да') {
    $resource->set('action_product_to_order', 1);
}
if (($props['Новинка'] ?? '') === 'Да') {
    $resource->set('new', 1);
}
$resource->save();

9) Советы по адаптации

  • Замените ID TV (в примерах это 23) на свой.
  • Подставьте реальную карту складов ($warehouseMap) и поля ресурса.
  • Уточните логику категорий и уровень родителя ($parents[2]) под вашу структуру.
  • Всегда логируйте ключевые шаги: это сильно экономит время при отладке.

Заключение

Синхронизация через mSync — мощное и гибкое решение:

  • Поддерживает полный обмен (каталог, заказы).
  • Предоставляет логирование, события и настройку.
  • Работает по стандартному протоколу CommerceML.
  • Позволяет настраивать как ручной запуск, так и автоматическую интеграцию.

👉 Хотите сделать интеграцию своего интернет-магазина на MODX с 1С? Обратитесь за интеграцией сайта на MODx с 1С — сделаем магазин с miniShop2 с 1С или Commerce под ваши задачи.

Частые вопросы по интеграции сайта MODX с 1С

Нужно ли обязательно использовать miniShop2 для работы mSync?

Да, компонент mSync рассчитан именно на работу с miniShop2. Без него синхронизация каталога и заказов невозможна.

Какие версии PHP поддерживаются?

Требуется PHP версии 5.3 и выше, а также включённые модули SimpleXML, XMLReader и XMLWriter.

Можно ли загружать только цены и остатки без полного каталога?

Да, достаточно выгрузить из 1С только файл offers.xml. В этом случае будут обновлены цены и остатки без изменения структуры каталога.

Где искать ошибки при синхронизации?

Все действия фиксируются в логах компонента mSync. Можно включить как краткие, так и полные логи для отладки.

Как ускорить процесс обмена?

Используйте zip-сжатие файлов, разбивайте большие выгрузки по параметру file_limit, загружайте только изменённые данные.

Можно ли протестировать интеграцию без боевой базы 1С?

Да, mSync поддерживает работу с тестовыми или учебными версиями 1С. Это удобно для отладки.

Что делать, если при импорте возвращается ошибка "failure"?

Проверьте кодировку XML (UTF-8), структуру файла и корректность тегов. Подробности ищите в логах mSync.

Поддерживаются ли кастомные свойства товаров?

Да, можно синхронизировать дополнительные свойства и атрибуты. Они могут быть связаны с TV-полями или храниться в отдельной таблице.

Как экспортируются заказы из сайта в 1С?

При синхронизации типа sale сайт формирует XML-файл заказов, который 1С загружает и обрабатывает.

Можно ли запускать синхронизацию вручную?

Да, в панели управления mSync есть кнопки для ручного запуска, а также возможность остановить или перезапустить текущий обмен.