В практике работы с распределенными информационными базами (РИБ) часто возникает ситуация, когда центральный узел является основным местом ведения учета, а периферийный используется для подготовки отчетности. По умолчанию в платформе 1С реализован принцип «Главный узел всегда прав». Это означает, что при возникновении коллизий (когда один и тот же документ изменен в обеих базах) данные из центральной базы затирают изменения в подчиненной. Рассмотрим, как обойти это ограничение и обеспечить сохранность правок главного бухгалтера в периферийном узле.
Разберем ситуацию: бухгалтер вносит исправления в документы в периферийной базе перед сдачей отчетности. При очередной синхронизации из центральной базы прилетают те же самые документы (возможно, в них изменили только комментарий или незначительный реквизит), и платформа автоматически перезаписывает объект данными из центра. В итоге все «ручные» правки бухгалтера теряются. Нам необходимо изменить логику работы так, чтобы подчиненный узел имел приоритет или игнорировал загрузку определенных данных.
Прежде чем приступать к программированию, проанализируем типовой функционал 1С:Бухгалтерии 3.0, построенной на Библиотеке стандартных подсистем (БСП). В программе существует механизм Даты запрета загрузки данных. Это самый простой и безопасный способ защитить закрытые периоды.
Выясним, как это работает: в настройках синхронизации данных можно установить дату, ранее которой изменения из других узлов приниматься не будут. Если бухгалтер правит документы прошлого квартала, установка даты запрета загрузки на конец этого квартала полностью заблокирует любые изменения «сверху» для этих документов.
Важный нюанс: этот метод работает только для прошлых периодов. Если правки идут в «открытом» текущем периоде, этот способ не подойдет, и нам придется использовать программные методы.
Рассмотрим более гибкий вариант — создание подписки на событие ПередЗаписью. Этот метод позволяет точечно контролировать процесс записи объекта при обмене. Наша задача — определить, что объект записывается в процессе обмена данными, и проверить, нужно ли его защищать от перезаписи.
Для реализации этого метода выполним следующие шаги:
РучнаяКорректировкаГБ).ПередЗаписью для необходимых типов документов.Проанализируем пример кода для обработчика подписки:
Процедура ПередЗаписьюДокументаДляЗащиты(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
// Проверяем, что запись происходит в процессе загрузки обмена
Если Источник.ОбменДанными.Загрузка Тогда
// Пытаемся найти признак ручной корректировки в текущей базе
// Нужно прочитать состояние объекта непосредственно из базы данных
СсылкаНаОбъект = Источник.Ссылка;
Если Не СсылкаНаОбъект.Пустая() Тогда
// Здесь логика проверки: если в базе у документа уже стоит флаг "РучнаяКорректировка"
// то мы можем либо отменить запись, либо проигнорировать изменения
РучнаяПравка = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНаОбъект, "РучнаяКорректировкаГБ");
Если РучнаяПравка = Истина Тогда
// Отменяем загрузку изменений из центрального узла
Источник.ОбменДанными.Получатели.АвтоЗаполнение = Ложь;
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Использование параметра Отказ = Истина внутри загрузки обмена требует осторожности, так как это может прервать чтение всего сообщения обмена в некоторых старых версиях платформы. В современных конфигурациях на БСП лучше использовать механизм правил обработки данных.
Посмотрим на возможности платформы на уровне Плана обмена. В модуле Плана обмена существуют специализированные обработчики коллизий. Мы можем использовать событие ПриПриемеДанныхОтГлавного.
Разберем алгоритм работы в этом обработчике:
Игнорировать или Отказ.Пример реализации в модуле плана обмена:
Процедура ПриПриемеДанныхОтГлавного(ЭлементДанных, ПолучениеДанных, Отказ)
// Проверяем тип данных, так как через РИБ могут идти и константы, и справочники
Если ТипЗнч(ЭлементДанных) = Тип("ДокументОбъект.РеализацияТоваровУслуг") Тогда
// Находим текущую версию документа в базе
ДокВБазе = ЭлементДанных.Ссылка.ПолучитьОбъект();
Если ДокВБазе <> Неопределено Тогда
// Если документ в базе имеет признак "Не затирать", блокируем загрузку
Если ДокВБазе.ДополнительныеСвойства.Свойство("ЗаблокированоДляОбмена") Тогда
ПолучениеДанных = ПолучениеДанныхДанныхОбмена.Игнорировать;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Современный и «чистый» способ решения задачи — использование расширения конфигурации в сочетании со штатным механизмом Версионирования объектов. Это позволит не снимать базу с поддержки и не добавлять лишние реквизиты.
Проанализируем ситуацию: если в базе включено версионирование, мы всегда можем узнать, кто последним редактировал объект. Выясним логику работы расширения:
ВерсииОбъектов.Важно понимать, что нарушение целостности РИБ («рассинхрон» данных) несет определенные риски. Проанализируем, с чем мы можем столкнуться:
Для реализации задачи «РИБ для Главбуха» в 1С:Бухгалтерии 3.0 мы рекомендуем следующий порядок действий:
Во-первых, максимально используйте Дату запрета загрузки для всех закрытых периодов. Это снимет 80% проблем без написания кода.
Во-вторых, если требуется защита в открытом периоде, создайте Расширение, в котором через &Вместо или &Перед обработайте запись объектов. Использование расширения позволит вам безболезненно обновлять центральную базу, а все «костыли» по защите данных останутся локально в базе бухгалтера.
В-третьих, обязательно проинформируйте пользователя (ГБ), что при таком режиме работы ответственность за соответствие аналитики (субконто, контрагенты) лежит на нем, так как автоматическое обновление этих связей будет ограничено.