При настройке стандартной синхронизации данных между конфигурациями 1С:Бухгалтерия предприятия 3.0 (БП) и 1С:Управление нашей фирмой 1.6/3.0 (УНФ) пользователи часто сталкиваются с неприятным поведением системы. Документ ПлатежноеПоручение, созданный в БП, успешно мигрирует в УНФ, однако при его проведении или проверке заполнения программа выдает предупреждение: «Сумма документа не соответствует сумме разнесенных платежей в табличной части». При этом визуально на форме документа всё выглядит корректно: присутствует одна строка с заполненной суммой, которая в точности совпадает с суммой в шапке документа.
В этой статье мы подробно разберем причины возникновения данной коллизии, заглянем во внутреннюю архитектуру конфигурации УНФ и рассмотрим три практических способа решения этой проблемы без снятия типовых конфигураций с поддержки («с замка»).
Для того чтобы понять природу этой ошибки, нам необходимо проанализировать разницу между интерактивной работой пользователя в интерфейсе программы и фоновым программным созданием объектов при обмене данными.
Разработчики 1С в конфигурации УНФ применили механизм «эмуляции» табличной части на форме документа ПлатежноеПоручение для удобства пользователя. Рассмотрим подробнее, как это устроено:
РасшифровкаПлатежа. Именно в ней хранятся аналитика платежа (договор, статья ДДС, заказ) и конкретные суммы распределения.РасшифровкаПлатежа в базе данных абсолютно пуста, срабатывает программный код формы (например, в процедуре ПриСозданииНаСервере). Он визуально эмулирует одну строку, подставляя туда сумму из шапки документа и базовую аналитику. Пользователь уверен, что строка существует.ОбменДанными.Загрузка = Истина. Код интерактивных форм при этом не выполняется. Документ записывается в базу данных с заполненной шапкой, но с абсолютно пустой табличной частью РасшифровкаПлатежа.В дальнейшем при проведении документа или принудительной проверке заполнения срабатывает код в модуле объекта (в обработчике события ОбработкаПроверкиЗаполнения):
СуммаПлатежа = РасшифровкаПлатежа.Итог("СуммаПлатежа");
Если СуммаПлатежа <> СуммаДокумента Тогда
// Генерируется предупреждение о несоответствии сумм...
КонецЕсли;
Поскольку физически в табличной части ноль строк, метод Итог("СуммаПлатежа") возвращает 0. Программа сравнивает 0 с реальной суммой документа (например, 1800) и выдает предупреждение об ошибке, регистрируя его в журнале регистрации обмена.
Теперь, когда мы детально разобрали причину сбоя, перейдем к методам исправления этой ситуации.
Поскольку наши конфигурации находятся «на замке» и мы не хотим лишать их возможности автоматического обновления, идеальным инструментом для решения проблемы будет создание небольшого расширения в базе УНФ.
Мы перехватим событие ПередЗаписью документа ПлатежноеПоручение на уровне объектного модуля. Если запись инициирована процессом обмена данными, мы принудительно создадим строку в табличной части и заполним ее данными из шапки.
Выполним следующие шаги:
ФиксЗагрузкиПлатежныхПоручений) с назначением «Адаптация».ПлатежноеПоручение и заимствуем его модуль объекта.ПередЗаписью с аннотацией &Перед или &После.Рассмотрим пример кода, который необходимо поместить в модуль расширения:
&После("ПередЗаписью")
Процедура Расш_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Обрабатываем заполнение только в режиме загрузки данных обмена
Если ЭтотОбъект.ОбменДанными.Загрузка Тогда
// Если сумма в шапке есть, а табличная часть пуста - заполняем ее
Если ЭтотОбъект.СуммаДокумента > 0 И ЭтотОбъект.РасшифровкаПлатежа.Количество() = 0 Тогда
НоваяСтрока = ЭтотОбъект.РасшифровкаПлатежа.Добавить();
НоваяСтрока.СуммаПлатежа = ЭтотОбъект.СуммаДокумента;
// Пытаемся заполнить Договор из реквизитов шапки (в зависимости от версии УНФ)
Попытка
НоваяСтрока.Договор = ЭтотОбъект.ДоговорКонтрагента;
Исключение
// Если имя реквизита отличается, игнорируем или анализируем метаданные
КонецПопытки;
// Пытаемся заполнить Статью ДДС
Попытка
НоваяСтрока.Статья = ЭтотОбъект.СтатьяДвиженияДенежныхСредств;
Исключение
// Обработка исключения при отсутствии реквизита в шапке
КонецПопытки;
// Заполняем валюту расчетов из валюты документа
НоваяСтрока.ВалютаРасчетов = ЭтотОбъект.ВалютаДокумента;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот способ полностью решает проблему: при загрузке документа из БП табличная часть заполнится автоматически одной строкой с правильной суммой, встроенная проверка сопоставления сумм УНФ отработает без ошибок, и предупреждение в мониторе обмена больше не появится.
Если обмен настроен по современному протоколу EnterpriseData, логика обработки входящих XDTO-пакетов описывается в общем модуле менеджера обмена. Мы также можем модифицировать её с помощью расширения.
Рассмотрим, как переопределить обработку загрузки объектов программно:
МенеджерОбменаЧерезУниверсальныйФормат).ПлатежноеПоручение (обычно это обработчики загрузки XDTO-объектов).РасшифровкаПлатежа на этапе конвертации данных, до момента непосредственной записи объекта в базу.Преимущество этого метода в том, что данные готовятся еще на этапе разбора XML/XDTO-пакета, однако этот метод более трудоемок в реализации и требует детального знания внутренней структуры формата EnterpriseData конкретной версии.
Если в вашей базе уже накопилось большое количество документов с подобной ошибкой и вам требуется оперативно привести их в порядок, можно воспользоваться внешней обработкой, не меняя конфигурацию.
Давайте разберем по шагам логику внешней обработки, которая найдет все «проблемные» документы за указанный период времени и автоматически исправит их структуру:
Процедура ИсправитьПустыеРасшифровкиНаСервере(ДатаНачала, ДатаОкончания)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПлатежноеПоручение.Ссылка КАК Ссылка
|ИЗ
| Документ.ПлатежноеПоручение КАК ПлатежноеПоручение
|ГДЕ
| ПлатежноеПоручение.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
| И ПлатежноеПоручение.СуммаДокумента > 0
| И НЕ ПлатежноеПоручение.ПометкаУдаления";
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ДатаОкончания));
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
КоличествоИсправленных = 0;
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
ДокументОбъект = ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
// Проверяем физическое наличие строк в табличной части
Если ДокументОбъект.РасшифровкаПлатежа.Количество() = 0 Тогда
НС = ДокументОбъект.РасшифровкаПлатежа.Добавить();
НС.СуммаПлатежа = ДокументОбъект.СуммаДокумента;
// Заполнение аналитики
Попытка
НС.Договор = ДокументОбъект.ДоговорКонтрагента;
НС.Статья = ДокументОбъект.СтатьяДвиженияДенежныхСредств;
НС.ВалютаРасчетов = ДокументОбъект.ВалютаДокумента;
Исключение
// Запись информации об ошибке в Журнал Регистрации при необходимости
КонецПопытки;
// Отключаем лишние проверки при записи для ускорения процесса
ДокументОбъект.ОбменДанными.Загрузка = Истина;
Попытка
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
КоличествоИсправленных = КоличествоИсправленных + 1;
Исключение
ЗаписьЖурналаРегистрации("ИсправлениеПлатежныхПоручений",
УровеньЖурналаРегистрации.Ошибка, , ,
"Не удалось записать документ: " + ДокументОбъект.Ссылка + " Описание: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЦикла;
Сообщить(СтрШаблон("Обработка завершена. Успешно исправлено документов: %1", КоличествоИсправленных));
КонецПроцедуры
Этот код выбирает все платежные поручения за период, проверяет их табличные части на пустоту и программно их заполняет, устанавливая свойство ОбменДанными.Загрузка = Истина, чтобы избежать блокировок из-за других проверок контроля заполнения.
Мы выяснили, что ложные предупреждения при синхронизации БП и УНФ возникают из-за различия в логике экранных форм и физического хранения табличных частей в СУБД.
Для надежного решения этой проблемы рекомендуем применить Вариант 1 (Создание расширения конфигурации с обработчиком ПередЗаписью). Это позволит вам: