План обмена 1С 8.3: узлы, регистрация изменений, код

Дата: 21.09.2026 10:32:50
Обмен данными
Интеграции
Программирование 1С
Доработка 1С
Комментарий:
0
Платформа:
8.3
Конфигурация:
Любая
Формы:
Любые

План обмена 1С — объект конфигурации, который помнит, какие данные изменились и какому узлу их ещё нужно отправить. На нём построены РИБ, синхронизация в типовых конфигурациях и самописные обмены. Выбор способа обмена разобран в обзоре способов обмена данными 1С, здесь — только план обмена данными: узлы, состав, регистрация изменений, сообщения обмена, квитирование и РИБ.

Код — для платформы 8.3, имена условные: план обмена Магазины с реквизитом узла Склад, справочник Номенклатура, документ ПеремещениеТоваров. Процедуры обмена лежат в общем модуле с флажком «Сервер».

Что такое план обмена 1С: узлы и ЭтотУзел

План обмена устроен как справочник: его элементы — узлы, участники обмена (центральная база, магазин, сайт). У узла есть код, наименование, свои реквизиты и стандартные НомерОтправленного и НомерПринятого. Один узел платформа создаёт сама — ЭтотУзел, он обозначает текущую базу. Его возвращает ПланыОбмена.Магазины.ЭтотУзел(), удалить его нельзя.

Как создать план обмена с нуля:

  1. Конфигуратор: «Общие» → «Планы обмена» → «Добавить», имя Магазины.
  2. Реквизиты узла добавить как у справочника, например Склад.
  3. Командой «Состав» отметить объекты и задать каждому авторегистрацию.
  4. Обновить конфигурацию базы данных и задать коды узлов процедурами ниже.

Код ЭтотУзел — подпись отправителя в заголовке сообщения: база-получатель ищет у себя узел с таким кодом. Поэтому коды настраивают крест-накрест:

БазаКод ЭтотУзелУзел-корреспондент
Центральный офисЦОМ01 — магазин
МагазинМ01ЦО — центральный офис
// Общий модуль ОбменМагазины, флажок «Сервер». Имена условные: план обмена
// Магазины с реквизитом узла Склад. В ЦО: НастроитьЭтотУзел("ЦО", "Центральный офис")
// и УзелКорреспондента("М01", "Магазин 1", Склад); в базе магазина — зеркально.

// Код этого узла попадает в заголовок каждого сообщения как код отправителя.
Процедура НастроитьЭтотУзел(Код, Наименование) Экспорт

	УзелОбъект = ПланыОбмена.Магазины.ЭтотУзел().ПолучитьОбъект();
	Если УзелОбъект.Код = Код И УзелОбъект.Наименование = Наименование Тогда
		Возврат;
	КонецЕсли;
	УзелОбъект.Код = Код;
	УзелОбъект.Наименование = Наименование;
	УзелОбъект.Записать();

КонецПроцедуры

// Возвращает узел другой базы, при первом вызове создаёт его.
Функция УзелКорреспондента(Код, Наименование, Склад = Неопределено) Экспорт

	Узел = ПланыОбмена.Магазины.НайтиПоКоду(Код);
	Если Узел = ПланыОбмена.Магазины.ЭтотУзел() Тогда
		ВызватьИсключение СтрШаблон("Код %1 уже занят узлом этой базы", Код);
	ИначеЕсли ЗначениеЗаполнено(Узел) Тогда
		Возврат Узел;
	КонецЕсли;

	УзелОбъект = ПланыОбмена.Магазины.СоздатьУзел();
	УзелОбъект.Код = Код;
	УзелОбъект.Наименование = Наименование;
	Если Склад <> Неопределено Тогда
		УзелОбъект.Склад = Склад;
	КонецЕсли;
	УзелОбъект.Записать();
	Возврат УзелОбъект.Ссылка;

КонецФункции

// Узлы для регламентного обмена: все, кроме этого и помеченных на удаление.
Функция УзлыОбмена() Экспорт

	Запрос = Новый Запрос;
	Запрос.Текст =
		"ВЫБРАТЬ
		|	Магазины.Ссылка КАК Узел
		|ИЗ
		|	ПланОбмена.Магазины КАК Магазины
		|ГДЕ
		|	Магазины.Ссылка <> &ЭтотУзел
		|	И НЕ Магазины.ПометкаУдаления";
	Запрос.УстановитьПараметр("ЭтотУзел", ПланыОбмена.Магазины.ЭтотУзел());
	Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Узел");

КонецФункции

СоздатьУзел() работает как СоздатьЭлемент() у справочника: объект живёт в памяти до Записать(). Проверка на ЭтотУзел не даёт завести корреспондента с кодом своей базы — иначе ошибка всплывёт только при первой загрузке. С версии 8.3.9 у ссылки на узел есть и свойство ЭтотУзел (Булево).

Состав плана обмена и авторегистрация

В состав включают объекты, изменения которых надо отслеживать: справочники, документы, регистры, константы. У каждого — признак Авторегистрация. При «Разрешить» каждая запись или удаление объекта регистрирует изменение для всех узлов плана, кроме ЭтотУзел и узла из ОбменДанными.Отправитель, — даже если данные не менялись. При «Запретить» очередь наполняет только код.

Регистрируется факт, а не версия: узел, ключ данных и номер сообщения. Записи лежат в таблицах изменений, по одной на объект для всех планов обмена. В запросе это Справочник.Номенклатура.Изменения с полями Узел, НомерСообщения, Ссылка.

До вызова ПередЗаписью платформа заполняет набор ОбменДанными.Получатели узлами, для которых будет регистрация. Его можно сократить или дополнить — так делают отбор по складу или организации.

// Модуль объекта документа ПеремещениеТоваров. Документ входит в состав плана
// обмена Магазины с авторегистрацией «Разрешить». Перед вызовом ПередЗаписью
// платформа заполняет ОбменДанными.Получатели узлами, которым уйдёт изменение.

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

	// Фильтр работает и при загрузке: документ, полученный ЦО от одного
	// магазина, не должен разойтись по остальным магазинам.
	ОставитьНужныхПолучателей();

	Если ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;

	// Здесь обычная логика документа: заполнение, проверки, пересчёт сумм.

КонецПроцедуры

// Убирает магазины, склады которых не участвуют в перемещении.
// Узел ЦО (Склад не заполнен) и узлы других планов обмена не трогаем.
Процедура ОставитьНужныхПолучателей()

	Лишние = Новый Массив;
	Для Каждого Узел Из ОбменДанными.Получатели Цикл
		Если ТипЗнч(Узел) <> Тип("ПланОбменаСсылка.Магазины") Тогда
			Продолжить;
		КонецЕсли;
		СкладУзла = Узел.Склад;
		Если ЗначениеЗаполнено(СкладУзла)
			И СкладУзла <> СкладОтправитель
			И СкладУзла <> СкладПолучатель Тогда
			Лишние.Добавить(Узел);
		КонецЕсли;
	КонецЦикла;

	Для Каждого Узел Из Лишние Цикл
		ОбменДанными.Получатели.Удалить(Узел);
	КонецЦикла;

КонецПроцедуры
  • Фильтр стоит до проверки ОбменДанными.Загрузка: при загрузке авторегистрация тоже работает, и без фильтра документ одного магазина ушёл бы через ЦО во все остальные.
  • Узлы удаляются после обхода — коллекцию не меняют внутри цикла по ней.
  • Для объекта с «Запретить» работает обратный приём: ОбменДанными.Получатели.Добавить(Узел).
  • Если в документе сменили склад, прежний магазин останется со старой версией — оставляйте в наборе и его узел.

Регистрация изменений программно

ПланыОбмена.ЗарегистрироватьИзменения(Узлы, Данные) ставит данные в очередь узла или массива узлов, ПланыОбмена.УдалитьРегистрациюИзменений снимает. Что передают вторым параметром:

ДанныеЧто регистрируется
Объект метаданныхвсе данные этого объекта
Ссылка или объектодин элемент
Набор записейзаписи регистра по отбору набора
Массив ссылок или наборовто же списком, в одной транзакции
Не указановесь состав плана, только для одного узла

Объект должен входить в состав плана. УдалитьРегистрациюИзменений принимает ещё и число: удаляются записи узла с номером сообщения не больше него — это и есть квитирование.

// Общий модуль ОбменМагазины (продолжение).
// Узел подключили к работающей базе: авторегистрация ловит только изменения
// после его создания, поэтому стартовый набор данных регистрируем сами.
Процедура ЗарегистрироватьСтартовыеДанные(Узел) Экспорт

	// Справочник целиком: передаём объект метаданных.
	ПланыОбмена.ЗарегистрироватьИзменения(Узел, Метаданные.Справочники.Номенклатура);

	// Документы — только склада узла и за 30 дней. Массив ссылок
	// регистрируется одним вызовом в одной транзакции.
	Запрос = Новый Запрос;
	Запрос.Текст =
		"ВЫБРАТЬ
		|	Док.Ссылка КАК Ссылка
		|ИЗ
		|	Документ.ПеремещениеТоваров КАК Док
		|ГДЕ
		|	Док.Дата >= &Начало
		|	И (Док.СкладОтправитель = &Склад
		|			ИЛИ Док.СкладПолучатель = &Склад)";
	Запрос.УстановитьПараметр("Начало", НачалоДня(ТекущаяДатаСеанса()) - 30 * 86400);
	Запрос.УстановитьПараметр("Склад", Узел.Склад);
	Ссылки = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
	Если Ссылки.Количество() > 0 Тогда
		ПланыОбмена.ЗарегистрироватьИзменения(Узел, Ссылки);
	КонецЕсли;

КонецПроцедуры

// После перепроведения закрытого периода в очереди тысячи старых документов.
// Снимаем с отправки те, что ещё не выгружены и датированы раньше Граница.
Процедура СнятьСОтправкиСтарыеДокументы(Узел, Граница) Экспорт

	Запрос = Новый Запрос;
	Запрос.Текст =
		"ВЫБРАТЬ
		|	Изм.Ссылка КАК Ссылка
		|ИЗ
		|	Документ.ПеремещениеТоваров.Изменения КАК Изм
		|ГДЕ
		|	Изм.Узел = &Узел
		|	И Изм.НомерСообщения ЕСТЬ NULL
		|	И Изм.Ссылка.Дата < &Граница";
	Запрос.УстановитьПараметр("Узел", Узел);
	Запрос.УстановитьПараметр("Граница", Граница);
	Ссылки = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
	Если Ссылки.Количество() > 0 Тогда
		ПланыОбмена.УдалитьРегистрациюИзменений(Узел, Ссылки);
	КонецЕсли;

КонецПроцедуры

Первая процедура нужна при подключении узла к работающей базе: авторегистрация не знает о данных, созданных до него. Во второй условие НомерСообщения ЕСТЬ NULL оставляет только невыгруженное — выгруженное ждёт квитанции. Удаления остаются в очереди: у ссылки на удалённый документ Ссылка.Дата равна NULL.

Запись сообщения обмена: ВыбратьИзменения

Сообщение обмена — XML с заголовком (план обмена, коды отправителя и получателя, номер сообщения, номер последнего принятого) и телом с данными. Заголовок пишет ЗаписьСообщенияОбмена, тело — ваш код; строку из примера удобно отдавать через HTTP-сервис.

// Общий модуль ОбменМагазины (продолжение).
// Собирает сообщение для узла в строку XML: её можно вернуть из HTTP-сервиса,
// записать в файл или отправить почтой.
Функция СообщениеДляУзла(Узел) Экспорт

	ЗаписьXML = Новый ЗаписьXML;
	ЗаписьXML.УстановитьСтроку("UTF-8");
	ЗаписьXML.ЗаписатьОбъявлениеXML();

	ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
	ЗаписьСообщения.НачатьЗапись(ЗаписьXML, Узел); // номер = НомерОтправленного + 1
	Попытка
		Выборка = ПланыОбмена.ВыбратьИзменения(Узел, ЗаписьСообщения.НомерСообщения);
		Пока Выборка.Следующий() Цикл
			Данные = Выборка.Получить(); // объект, набор записей или УдалениеОбъекта
			Если ТипЗнч(Данные) = Тип("ДокументОбъект.ПеремещениеТоваров") Тогда
				// Объект только прочитан в память, в базу он не пишется:
				// внутренний комментарий ЦО магазину не передаём.
				Данные.Комментарий = "";
			КонецЕсли;
			ЗаписатьXML(ЗаписьXML, Данные);
		КонецЦикла;
		ЗаписьСообщения.ЗакончитьЗапись();
	Исключение
		ЗаписьСообщения.ПрерватьЗапись();
		ВызватьИсключение;
	КонецПопытки;

	Возврат ЗаписьXML.Закрыть();

КонецФункции
  • НачатьЗапись присваивает номер «НомерОтправленного + 1» и блокирует узел от параллельного обмена; получателем не может быть ЭтотУзел.
  • ВыбратьИзменения ничего не удаляет, а проставляет номер сообщения в записях регистрации. Удалит их квитанция из ответа.
  • Получить() возвращает объект, набор записей, менеджер значения константы или УдалениеОбъекта. Объект можно поправить в памяти перед сериализацией.
  • Без ЗакончитьЗапись сообщение не считается отправленным.
  • Третий параметр ВыбратьИзменения — фильтр для выгрузки частями. Записи вне фильтра сохраняют старый номер, и квитанция на новое сообщение удалит их, даже если старое потерялось.

Чтение сообщения: ОбменДанными.Загрузка и Отправитель

// Общий модуль ОбменМагазины (продолжение), выполняется в ЦО.
// Загружает сообщение магазина. Номенклатуру ведут только в ЦО: её изменения
// из магазина не принимаем и ставим к отправке версию ЦО.
Процедура ЗагрузитьСообщение(ТекстXML) Экспорт

	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.УстановитьСтроку(ТекстXML);

	ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
	// Проверка заголовка: план обмена, узлы, номер сообщения.
	ЧтениеСообщения.НачатьЧтение(ЧтениеXML, ДопустимыйНомерСообщения.Больший);
	Отправитель = ЧтениеСообщения.Отправитель;

	НачатьТранзакцию();
	Попытка
		// Квитанция: магазин получил наши сообщения до НомерПринятого включительно.
		ПланыОбмена.УдалитьРегистрациюИзменений(Отправитель, ЧтениеСообщения.НомерПринятого);

		Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
			Данные = ПрочитатьXML(ЧтениеXML);
			Если ЭтоНоменклатура(Данные) Тогда
				ПланыОбмена.ЗарегистрироватьИзменения(Отправитель, Данные.Ссылка);
				Продолжить;
			КонецЕсли;
			Данные.ОбменДанными.Отправитель = Отправитель; // не регистрировать обратно
			Данные.ОбменДанными.Загрузка = Истина;          // без бизнес-логики
			Данные.Записать();
		КонецЦикла;

		ЧтениеСообщения.ЗакончитьЧтение(); // запоминает НомерПринятого
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ЧтениеСообщения.ПрерватьЧтение();
		ВызватьИсключение;
	КонецПопытки;

	ЧтениеXML.Закрыть();

КонецПроцедуры

// Изменение или удаление элемента справочника Номенклатура.
Функция ЭтоНоменклатура(Данные)

	Если ТипЗнч(Данные) = Тип("УдалениеОбъекта") Тогда
		Возврат ТипЗнч(Данные.Ссылка) = Тип("СправочникСсылка.Номенклатура");
	КонецЕсли;
	Возврат ТипЗнч(Данные) = Тип("СправочникОбъект.Номенклатура");

КонецФункции
  • НачатьЧтение проверяет заголовок — план обмена, узлы, номер — и при расхождении вызывает исключение, поэтому стоит до транзакции.
  • УдалитьРегистрациюИзменений(Отправитель, НомерПринятого) — квитанция за наши сообщения.
  • ОбменДанными.Отправитель отключает регистрацию обратно отправителю; для остальных узлов авторегистрация работает с фильтром из модуля документа.
  • ОбменДанными.Загрузка = Истина — запись с минимумом проверок. ПередЗаписью, ПриЗаписи и подписки всё равно вызываются, поэтому в них первой строкой проверяют флаг.
  • Номенклатуру магазина не записываем, а ставим в очередь версию ЦО; если в ЦО позиции нет, магазин получит УдалениеОбъекта.
  • Документ, изменённый в обеих базах, достаётся последнему загруженному. Правило через ИзменениеЗарегистрировано — в обзорной статье.

Номера сообщений и квитирование

Цикл обмена между ЦО и магазином М01:

  1. ЦО формирует сообщение № 15 с НомерПринятого = 9 — последним, что ЦО принял от М01. Выбранные записи регистрации получают номер 15, НомерОтправленного узла М01 становится 15.
  2. М01 проверяет, что 15 больше его НомерПринятого от ЦО, удаляет свои регистрации для ЦО с номерами до 9 и запоминает НомерПринятого = 15.
  3. М01 отвечает сообщением № 10 с НомерПринятого = 15, и ЦО удаляет регистрации для М01 с номерами до 15.

Если сообщение № 15 потерялось, ВыбратьИзменения заберёт неподтверждённые записи в № 16 — переотправлять вручную ничего не нужно. Объект, изменённый после выгрузки, снова встаёт в очередь без номера, и квитанция за старое сообщение его не удалит.

Допустимый номер задаёт второй параметр НачатьЧтение:

  • ДопустимыйНомерСообщения.Больший — по умолчанию: номер больше последнего принятого, пропуски разрешены;
  • ДопустимыйНомерСообщения.Очередной — строго следующий номер;
  • ДопустимыйНомерСообщения.Любой — без проверки, для осознанной повторной загрузки.

Как посмотреть и почистить зарегистрированные изменения

Функция обходит состав плана и считает записи в таблицах изменений по узлу, процедура очищает очередь одного объекта.

// Общий модуль ОбменМагазины (продолжение).
// Очередь узла по каждому объекту состава: сколько изменений ещё не выгружено
// и сколько выгружено, но не подтверждено квитанцией.
Функция ОчередьУзла(Узел) Экспорт

	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("Объект", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("Авторегистрация", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("НеВыгружено", Новый ОписаниеТипов("Число"));
	Результат.Колонки.Добавить("ЖдетКвитанции", Новый ОписаниеТипов("Число"));

	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Узел", Узел);

	Для Каждого ЭлементСостава Из Метаданные.ПланыОбмена.Магазины.Состав Цикл
		ПолноеИмя = ЭлементСостава.Метаданные.ПолноеИмя();
		Запрос.Текст =
			"ВЫБРАТЬ
			|	КОЛИЧЕСТВО(*) КАК Всего,
			|	КОЛИЧЕСТВО(Изм.НомерСообщения) КАК Выгружено
			|ИЗ
			|	" + ПолноеИмя + ".Изменения КАК Изм
			|ГДЕ
			|	Изм.Узел = &Узел";
		Выборка = Запрос.Выполнить().Выбрать();
		Если Не Выборка.Следующий() Или Выборка.Всего = 0 Тогда
			Продолжить;
		КонецЕсли;
		СтрокаОчереди = Результат.Добавить();
		СтрокаОчереди.Объект = ПолноеИмя;
		СтрокаОчереди.Авторегистрация =
			(ЭлементСостава.АвтоРегистрация = АвтоРегистрацияИзменений.Разрешить);
		СтрокаОчереди.НеВыгружено = Выборка.Всего - Выборка.Выгружено;
		СтрокаОчереди.ЖдетКвитанции = Выборка.Выгружено;
	КонецЦикла;

	Результат.Сортировать("НеВыгружено Убыв");
	Возврат Результат;

КонецФункции

// Снимает с отправки все изменения одного объекта состава,
// например "РегистрСведений.ЦеныМагазинов".
Процедура ОчиститьОчередьОбъекта(Узел, ПолноеИмя) Экспорт

	ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ПолноеИмя);
	Если ОбъектМетаданных = Неопределено
		Или Не Метаданные.ПланыОбмена.Магазины.Состав.Содержит(ОбъектМетаданных) Тогда
		ВызватьИсключение СтрШаблон("%1 не входит в состав плана обмена", ПолноеИмя);
	КонецЕсли;
	ПланыОбмена.УдалитьРегистрациюИзменений(Узел, ОбъектМетаданных);

КонецПроцедуры
  • КОЛИЧЕСТВО(Изм.НомерСообщения) не считает NULL, поэтому разность с КОЛИЧЕСТВО(*) — записи, ещё не попавшие в сообщения.
  • Большое «ЖдетКвитанции» при малом «НеВыгружено»: сообщения уходят, но ответы не приходят или не загружаются.
  • Всю очередь узла очищает ПланыОбмена.УдалитьРегистрациюИзменений(Узел). Делайте это, только если узел получит данные другим путём.

Распределённая информационная база (РИБ) кратко

С флажком «Распределенная информационная база» все узлы работают на одной конфигурации, а её изменения идут из главного узла в подчинённые вместе с данными. Сериализацию, запись данных и коллизии платформа берёт на себя (побеждает главный узел), поэтому вместо цикла с ЗаписатьXML вызывают ПланыОбмена.ЗаписатьИзменения и ПланыОбмена.ПрочитатьИзменения. Подчинённый узел создаёт ПланыОбмена.СоздатьНачальныйОбраз, а ПланыОбмена.ГлавныйУзел() возвращает главный узел или Неопределено в корневой базе.

// Общий модуль ОбменРИБ, флажок «Сервер». План обмена Филиалы (имя условное)
// с флажком «Распределенная информационная база». Данные и изменения
// конфигурации платформа сериализует сама: ЗаписатьXML и ПрочитатьXML не нужны.

Процедура ВыгрузитьДляУзла(Узел, ИмяФайла) Экспорт

	ЗаписьXML = Новый ЗаписьXML;
	ЗаписьXML.ОткрытьФайл(ИмяФайла);
	ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
	ЗаписьСообщения.НачатьЗапись(ЗаписьXML, Узел);
	Попытка
		ПланыОбмена.ЗаписатьИзменения(ЗаписьСообщения, 1000); // по 1000 в транзакции
		ЗаписьСообщения.ЗакончитьЗапись();
	Исключение
		ЗаписьСообщения.ПрерватьЗапись();
		ЗаписьXML.Закрыть();
		ВызватьИсключение;
	КонецПопытки;
	ЗаписьXML.Закрыть();

КонецПроцедуры

Процедура ЗагрузитьСообщение(ИмяФайла) Экспорт

	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.ОткрытьФайл(ИмяФайла);
	ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
	Попытка
		ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
		ПланыОбмена.ПрочитатьИзменения(ЧтениеСообщения, 1000);
		ЧтениеСообщения.ЗакончитьЧтение();
	Исключение
		// Отправитель заполнен, только пока чтение начато и не завершено.
		Если ЧтениеСообщения.Отправитель <> Неопределено Тогда
			ЧтениеСообщения.ПрерватьЧтение();
		КонецЕсли;
		ЧтениеXML.Закрыть();
		ВызватьИсключение;
	КонецПопытки;
	ЧтениеXML.Закрыть();

КонецПроцедуры

Второй параметр — сколько элементов обрабатывать в одной транзакции, 0 — все сразу. Если главный узел прислал изменения конфигурации, ПрочитатьИзменения в подчинённом узле остановится с ошибкой «Из главного узла распределенной информационной базы получены изменения конфигурации. Необходимо выполнить обновление конфигурации базы данных.» — обновите конфигурацию и повторите загрузку.

// Модуль объекта справочника Номенклатура в конфигурации с РИБ:
// справочник правят в главном узле, в подчинённых он только читается.
Процедура ПередЗаписью(Отказ)

	Если ОбменДанными.Загрузка Тогда
		Возврат; // элемент пришёл из главного узла через ПрочитатьИзменения
	КонецЕсли;

	Если ПланыОбмена.ГлавныйУзел() <> Неопределено Тогда
		ВызватьИсключение "Номенклатуру изменяют только в главном узле";
	КонецЕсли;

КонецПроцедуры

Данные из главного узла платформа пишет в режиме загрузки, поэтому проверка флага стоит первой — иначе подчинённый узел отверг бы изменения из центра.

Типичные ошибки

  • «Номер сообщения меньше или равен номеру ранее принятого сообщения». Тот же файл загружают повторно или база-отправитель восстановлена из копии и выдаёт старые номера. В РИБ текст другой: «Номер сообщения распределенной ИБ должен быть больше номера ранее принятого сообщения». Повторный файл пропускают. После восстановления поднимают НомерОтправленного у узла-получателя в восстановленной базе (у объекта узла номера доступны на запись) или один раз читают с ДопустимыйНомерСообщения.Любой.
  • «Данные не входят в состав плана обмена». Регистрацию вызвали для объекта вне состава или передали узел другого плана. Проверка: Метаданные.ПланыОбмена.Магазины.Состав.Содержит(...).
  • Первое сообщение не читается. Код ЭтотУзел пустой или не совпадает с кодом узла в базе-получателе: НачатьЧтение не находит узел из заголовка. Сверьте коды по таблице выше.
  • «Чтение сообщения обмена данными не начато» (или «Запись сообщения обмена данными не начата»). Метод вызван без успешного НачатьЧтение или НачатьЗапись.
  • Объекты ходят по кругу. Не заполнен ОбменДанными.Отправитель: принятый объект регистрируется обратно, и базы пересылают его друг другу каждый сеанс.
  • При загрузке срабатывает бизнес-логика. В обработчике или подписке нет проверки ОбменДанными.Загрузка: документы перенумеровываются, реквизиты перезаполняются, движения пишутся дважды.
  • Таблицы изменений разрастаются. Авторегистрация стоит у регистра, который регламентное задание перезаписывает каждую ночь, или копится очередь узла закрытого магазина. Ставьте «Запретить» и регистрируйте из кода, лишнюю очередь очищайте.

Частые вопросы

Нужен ли план обмена для выгрузки на сайт?

Да, как журнал изменений: план с одним узлом «Сайт». Выгрузка берёт ссылки из Справочник.Номенклатура.Изменения по этому узлу и после ответа сайта снимает регистрацию методом УдалитьРегистрациюИзменений. Если товары правят часто, выбирайте через ВыбратьИзменения и снимайте по номеру — правки во время выгрузки не потеряются.

Чем план обмена отличается от правил конвертации?

План обмена решает, что и кому отправить: узлы, очередь, номера. Как превратить объект одной конфигурации в объект другой, решают правила конвертации данных или формат EnterpriseData. ЗаписатьXML и ПрочитатьXML из примеров переносят объекты один к одному и годятся, только когда объекты обмена в обеих базах одинаковые.

Как загрузить принятое сообщение повторно?

Передать в НачатьЧтение второй параметр ДопустимыйНомерСообщения.Любой. Объекты перезапишутся, НомерПринятого не уменьшится.

Когда проще заказать

Если обмен теряет или дублирует данные, очередь узлов разрослась или нужны свои правила отбора и коллизий, быстрее поручить диагностику и доработку исполнителю: услуги по доработке 1С. Опишите базы, план обмена и симптомы в форме задания, оценка бесплатная.

По теме

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.


1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.