При разработке правил обмена в конфигурации Конвертация данных 2.0 программисты часто сталкиваются с ситуацией, когда при тестировании через обработку Универсальный обмен данными XML всё работает корректно, но при реальной эксплуатации через Синхронизацию данных (в фоновом режиме) часть кода просто игнорируется. Особенно это касается заполнения реквизитов табличных частей, таких как единицы измерения, счета учета и коэффициенты.
Рассмотрим подробно причины возникновения этой проблемы, разберем типичные ошибки в коде и определим эффективные методы отладки серверных механизмов обмена.
Первая и самая важная причина заключается в том, где выполняется код. Когда мы запускаем обмен вручную через обработку Универсальный обмен данными XML, код выполняется в клиентском контексте (или на сервере, но в рамках текущего сеанса пользователя). Мы видим ошибки в окне сообщений, и у нас есть доступ к локальным дискам.
Синхронизация данных в современных конфигурациях (на базе БСП) запускается как фоновое задание на сервере. Это влечет за собой несколько последствий:
USR1CV8). У этого пользователя может не быть прав на запись файлов в корень диска C:\ или D:\, поэтому попытки логгирования через ЗаписьТекста часто заканчиваются неудачей без видимых ошибок.Проанализируем ситуацию, когда мы изменили XML-файл правил на диске, но синхронизация продолжает работать по-старому. В механизме синхронизации правила часто кешируются. Они загружаются в информационную базу (в справочник или регистр сведений) один раз при настройке.
Если вы внесли изменения в обработчик ПослеЗагрузки, обязательно зайдите в настройки синхронизации данных и выберите пункт Загрузить правила из файла. В противном случае программа будет использовать старую версию кода, зашитую в базе, и ваши новые циклы просто не попадут в исполняемый алгоритм.
Посмотрим на пример кода, который часто вызывает сбои:
// ОШИБОЧНЫЙ КОД
для каждого стр из Объект.Товары Цикл
стр.НалоговоеНазначение.Код = "000033"; // ТАК ДЕЛАТЬ НЕЛЬЗЯ
КонецЦикла;
В 1С нельзя изменять свойства объектов через точку от ссылки. стр.НалоговоеНазначение — это ссылка. Попытка присвоить значение её коду напрямую (.Код = ...) приведет к ошибке времени выполнения. При ручном обмене вы увидите эту ошибку в логе, а при фоновой синхронизации выполнение обработчика может просто прерваться, и последующие строки кода (например, заполнение единиц и коэффициентов) не будут выполнены.
Правильный вариант заполнения реквизита в табличной части выглядит так:
НалоговоеНазначениеСсылка = Справочники.НалоговыеНазначенияАктивовИЗатрат.НайтиПоКоду("000033");
Если Не НалоговоеНазначениеСсылка.Пустая() Тогда
Для каждого Стр Из Объект.Товары Цикл
Стр.НалоговоеНазначение = НалоговоеНазначениеСсылка;
КонецЦикла;
КонецЕсли;
Постоянный вызов метода НайтиПоКоду внутри цикла или при загрузке каждого объекта сильно замедляет обмен. Разберем, как сделать это профессионально. Лучше всего найти нужные константы один раз Перед загрузкой данных и передать их в параметры конвертации.
В обработчике Перед загрузкой данных (узел Конвертация):
Параметры.Вставить("ОргГлавная", Справочники.Организации.НайтиПоКоду("00-000001"));
Параметры.Вставить("СчетТовары", ПланыСчетов.Хозрасчетный.ТоварыНаСкладе);
Теперь в обработчике ПослеЗагрузки правила ПоступлениеТоваровУслуг код станет чище и быстрее:
Если Объект.Организация = Параметры.ОргГлавная Тогда
Для каждого Стр Из Объект.Товары Цикл
Стр.СчетУчетаБУ = Параметры.СчетТовары;
// Заполняем единицу из номенклатуры
Стр.ЕдиницаИзмерения = Стр.Номенклатура.БазоваяЕдиницаИзмерения;
Стр.Коэффициент = 1;
КонецЦикла;
КонецЕсли;
Если цикл всё равно не срабатывает, нам нужно понять, заходит ли программа в него. Выясним причину с помощью надежного логгирования, которое работает на сервере.
1. Использование Журнала регистрации: это самый простой и надежный способ. Записи гарантированно сохранятся в базе.
ЗаписьЖурналаРегистрации("Обмен_Данными_ПослеЗагрузки",
УровеньЖурналаРегистрации.Информация,
Объект.Метаданные(),
Объект.Ссылка,
"Количество строк в ТЧ Товары: " + Объект.Товары.Количество());
2. Правильная запись в файл на сервере: если вам все же нужен текстовый файл, используйте временные папки, к которым у сервера точно есть доступ, или проверяйте существование файла перед записью.
ПутьКЛогу = "D:\Logs\exchange_log.txt"; // Убедитесь, что папка Logs создана и доступна серверу 1С
Текст = Новый ЗаписьТекста;
Текст.Открыть(ПутьКЛогу, КодировкаТекста.UTF8, , Истина); // Параметр Истина включает режим дозаписи
Текст.ЗаписатьСтроку("" + ТекущаяДата() + ": Обработка документа " + Объект.Номер);
Текст.Закрыть();
Проанализируем ситуацию: лог показывает, что Объект.Товары.Количество() равно 0. Почему так происходит, если в исходной базе товары были?
Товары может стоять галочка Не замещать существующие значения. В этом случае, если документ в приемнике уже существует, его табличная часть не будет обновлена при загрузке.Объект.ОбменДанными.Загрузка = Истина. Это отключает стандартные проверки в модуле объекта, но не должно мешать обработчику ПослеЗагрузки. Однако, если логика заполнения единиц завязана на события ПриИзменении в экранных формах, она никогда не сработает при обмене, так как формы не открываются. Весь код заполнения должен быть явно прописан в правилах.Важное примечание: Если вы заполняете ЕдиницаИзмерения, убедитесь, что тип значения совпадает. В некоторых конфигурациях БазоваяЕдиницаИзмерения в справочнике Номенклатура — это ссылка на один справочник, а ЕдиницаИзмерения в документе — на другой (например, классификатор единиц или подчиненный справочник). В этом случае простое присваивание не сработает, нужно искать соответствующую ссылку.