При реализации механизмов обмена данными между конфигурациями «1С:Бухгалтерия предприятия 3.0» и «Бухгалтерия предприятия 2.0» разработчики часто сталкиваются с задачей оптимизации объема передаваемой информации. Одним из популярных решений является группировка проводок: когда множество документов из базы-источника (БП 3.0) превращаются в одну сводную ОперацияБух в базе-приемнике (БП 2.0) за конкретный день. Однако такая схема порождает серьезную проблему: если пользователь в базе-источнике изменит дату документа (например, перенесет его с 01.02.23 на 31.01.23), стандартный план обмена зарегистрирует изменение самого объекта, но не «подскажет» системе, что в приемнике нужно пересчитать (или очистить) данные за старую дату. Рассмотрим, как решить эту задачу различными техническими способами.
Разберем, почему стандартный механизм регистрации изменений здесь оказывается недостаточно эффективным. План обмена фиксирует ссылку на измененный объект. При выгрузке система видит документ, берет его новую дату и отправляет данные в приемник. В базе-приемнике создается или обновляется ОперацияБух за новую дату. Но запись, которая была включена в сводную операцию за старую дату, остается там «навсегда», так как система приемника не получила команды на удаление или пересчет данных за прошлый период. Нам необходимо реализовать алгоритм, который позволит базе-источнику «запоминать» состояние документа до его записи.
Проанализируем самый доступный способ — использование модуля объекта или подписки на событие ПередЗаписью. В этот момент у нас есть доступ к текущим (еще не записанным) данным в переменной ЭтотОбъект и к данным, которые все еще хранятся в базе данных, через ЭтотОбъект.Ссылка. Это позволяет нам сравнить ключевые реквизиты, влияющие на группировку.
Выполним следующие шаги:
ПередЗаписью для необходимых документов.Рассмотрим пример кода для реализации такой проверки:
Процедура ПередЗаписьюДокументаДляОбмена(Источник, Отказ, РежимЗаписи, РежимПроведения)
Если Источник.ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Получаем старую дату напрямую из базы данных через ссылку
СтараяДата = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Источник.Ссылка, "Дата");
НоваяДата = Источник.Дата;
Если ЗначениеЗаполнено(СтараяДата) И НачалоДня(СтараяДата) <> НачалоДня(НоваяДата) Тогда
// Здесь необходимо инициировать механизм, который заставит приемник
// пересчитать данные за СтараяДата.
// Например, добавить запись в специально созданный регистр сведений "ОчередьПересчета".
РегистрироватьПересчетПериода(СтараяДата, Источник.Организация);
КонецЕсли;
КонецПроцедуры
Выясним, как сделать систему более отказоустойчивой, если мы не хотим перегружать обработчики проведения. Мы можем создать вспомогательный регистр сведений ИсторияВыгрузкиОбъектов. В нем будут храниться измерения Объект и ресурсы ДатаПоследнейВыгрузки, ХешСуммаДанных.
При каждой успешной выгрузке мы записываем в этот регистр текущую дату документа. При следующей итерации обмена система анализирует:
ДатаПоследнейВыгрузки в регистре — значит, документ «переехал» в другой период.ИсторияВыгрузкиОбъектов обновляются.Проанализируем подход, при котором мы отказываемся от регистрации самих документов в плане обмена в пользу регистрации «Дней, требующих синхронизации». Это наиболее логичный метод при сводном учете.
Посмотрим, как это работает по шагам:
ОчередьВыгрузкиПоДням с измерениями Дата и Организация.ОперацияБух в приемнике, которая полностью замещает старую.Пример кода для регистрации сразу двух дат:
Если НачалоДня(Источник.Дата) <> НачалоДня(Источник.Ссылка.Дата) Тогда
МенеджерЗаписи = РегистрыСведений.ОчередьВыгрузкиПоДням.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Дата = Источник.Ссылка.Дата;
МенеджерЗаписи.Организация = Источник.Организация;
МенеджерЗаписи.Записать();
КонецЕсли;
МенеджерЗаписи = РегистрыСведений.ОчередьВыгрузкиПоДням.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Дата = Источник.Дата;
МенеджерЗаписи.Организация = Источник.Организация;
МенеджерЗаписи.Записать();
Разберем, как базе-приемнику понять, какую именно операцию нужно править или удалять. Чтобы связь не терялась, в БП 2.0 в документе ОперацияБух следует использовать уникальный идентификатор группировки.
Рекомендуем формировать его программно в виде строки: "СВОД_" + Формат(Дата, "ДФ=yyyyMMdd") + "_" + ИдентификаторОрганизации. При загрузке данных за определенный день система первым делом ищет документ по этому ключу. Если в пакете данных за этот день пусто (все документы перенесены на другие даты), система найдет существующую операцию по ключу и обнулит в ней проводки или пометит на удаление.
В некоторых случаях, когда объем данных не критичен, а логика изменений слишком сложна (например, меняется не только дата, но и организация или другие аналитики группировки), проще применить метод «Граничных дат».
Мы собираем все изменившиеся документы за сеанс обмена, определяем минимальную и максимальную дату среди них. Затем за весь полученный интервал (например, с 20 по 25 число) мы полностью переформировываем данные в приемнике. Это гарантирует отсутствие «фантомных» проводок, оставшихся от удаленных или перенесенных документов, хотя и создает повышенную нагрузку на канал связи.
Выбор конкретного метода зависит от требований к оперативности и нагрузке:
ПередЗаписью) с принудительной регистрацией «пустого» изменения для старой даты.ОбменДанными.Загрузка, чтобы избежать зацикливания регистрации при двустороннем обмене.