Интеграция сайта на MODX с 1С подробное руководство и примеры
.png)
Введение
Связать сайт на 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)
- checkauth — начинается сеанс; возвращаются строки:
success, имя Cookie, его значение. - init — сайт сообщает, поддерживает ли zip (
zip=yes/no) и максимальный размер файла (file_limit=…). - file — передача файла (или его части)
import.xml/offers.xmlчерез POST. - import — сайт импортирует файл, возвращает
successилиfailure.
2. Синхронизация заказов (type=sale)
- checkauth;
- file — загрузка файла с заказами;
- success — подтверждение записи заказа.
Примерная схема интеграции (сценарий)
Подготовка
- Устанавливаем компонент mSync в MODX (miniShop2). Убедитесь, что PHP и XML-модули доступны.
Передаем данные для синхронизации с сайтом 1С-никам

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


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


Обмен каталога (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С передает данные сайту
Разбор структуры файлов 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 есть кнопки для ручного запуска, а также возможность остановить или перезапустить текущий обмен.

Напишите нам в WhatsApp



