В практической работе с конфигурациями на платформе 1С:Предприятие (особенно в комплексных исторических системах, таких как УПП 1.3 или КА 1.1) пользователи и администраторы периодически сталкиваются с необъяснимым на первый взгляд явлением. Документ, созданный на основании (например, корректировка заказа, реализация товаров или корректировка реализации), имеет время проведения раньше, чем сам документ-основание (например, заказ покупателя). На оси времени «потомок» оказывается в прошлом по отношению к своему «родителю».
Эта ситуация таит в себе серьезную опасность для корректности ведения учета: ломаются партионные цепочки, сдвигаются границы последовательностей, а при проведении подчиненных документов система может сообщать о нехватке остатков, так как с точки зрения базы данных «поступление» или «заказ» еще не произошли. В этой статье мы подробно разберем причины этой проблемы, проанализируем механизмы работы платформы и предложим готовые программные решения для предотвращения подобных коллизий.
Давайте проанализируем стандартную ситуацию по шагам, чтобы понять логику работы системы и пользователей:
ЗаказПокупателя. Допустим, это происходит утром в 08:31:00. Документ успешно записывается и проводится.РеализацияТоваровУслуг или КорректировкаРеализации. Система связывает этот документ с заказом через ссылку GUID. Подчиненный документ записывается со своим текущим временем — 12:04:00.ЗаказПокупателя (например, изменить количество, цену или просто перезаполнить какой-то реквизит). Менеджер нажимает кнопку «Провести».В результате этой цепочки действий в базе данных оказывается следующая картина:
ЗаказПокупателя имеет время 12:16:00;РеализацияТоваровУслуг имеет время 12:04:00.С точки зрения логики платформы 1С все корректно: документы связаны ссылочной связью. Но с точки зрения бизнес-логики и проведения по регистрам учета хронология нарушена. Получается, что отгрузка товара произошла раньше, чем сам заказ поступил в систему.
Для того чтобы доказать пользователям, что документ действительно был перепроведен позже, нам потребуется обратиться к Журналу регистрации (ЖР). Именно там хранится вся история изменения объектов.
При анализе Журнала регистрации обратите внимание на следующие моменты:
Заказ покупателя №001 от 19.02.2019 08:31:00), в то время как в колонке Дата/Время события ЖР будет зафиксировано время фактического проведения (например, 19.02.2019 12:16:48). Это неопровержимо доказывает факт смещения времени документа в результате повторных действий пользователя.Для регулярного мониторинга состояния базы данных и поиска нарушений хронологии мы можем разработать простой отчет или воспользоваться консолью запросов. Нам необходимо сопоставить даты документов в парах «родитель — потомок».
Рассмотрим пример запроса, который находит расходные накладные, проведенные раньше своих заказов-оснований:
ВЫБРАТЬ
Реализация.Ссылка КАК ПодчиненныйДокумент,
Реализация.Дата КАК ДатаПодчиненного,
Реализация.Сделка КАК ДокументОснование,
Реализация.Сделка.Дата КАК ДатаОснования,
Реализация.Ответственный КАК Ответственный
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Проведен = ИСТИНА
И Реализация.Сделка.Проведен = ИСТИНА
И Реализация.Дата < Реализация.Сделка.Дата
И Реализация.Дата МЕЖДУ &НачалоПериода И &КонецПериода
Этот запрос можно положить в основу регламентного отчета, который будет рассылаться администраторам или руководителям бэк-офиса в конце рабочего дня для оперативного исправления хронологии.
Для исключения подобных ситуаций мы можем применить несколько подходов: от административных мер до программного запрета изменения времени проведенных документов.
Самым надежным решением является внедрение программной проверки. Мы можем создать подписку на событие ПередЗаписью для интересующих нас документов-оснований (например, заказов покупателей, поступлений товаров и услуг). Задача проверки — определить, проводится ли документ оперативно, и есть ли у него уже введенные на основании документы. Если подчиненные документы найдены, мы должны заблокировать проведение и выдать пользователю предупреждение.
Разберем пример реализации такой процедуры в общем модуле:
Процедура ПроверитьХронологиюПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
// Проверяем только при реальном проведении
Если РежимЗаписи <> РежимЗаписиДокумента.Проведение Тогда
Возврат;
КонецЕсли;
// Нас интересует только изменение времени при оперативном проведении проведенного ранее документа
Если РежимПроведения = РежимПроведенияДокумента.Оперативный И Источник.Проведен Тогда
СсылкаНаДокумент = Источник.Ссылка;
// Инициализируем запрос для поиска подчиненных документов через критерий отбора
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| СвязанныеДокументы.Ссылка КАК Ссылка
|ИЗ
| КритерийОтбора.СвязанныеДокументы(&СсылкаНаДокумент) КАК СвязанныеДокументы
|ГДЕ
| СвязанныеДокументы.Ссылка.Проведен = ИСТИНА";
Запрос.УстановитьПараметр("СсылкаНаДокумент", СсылкаНаДокумент);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
// Найдена проведенная подчиненная структура. Сдвигать время вверх нельзя!
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Невозможно выполнить оперативное проведение документа, так как на его основании уже введены и проведены подчиненные документы!
|Пожалуйста, проведите документ неоперативно (без изменения времени) или временно отмените проведение подчиненных документов.";
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Чтобы не раздражать пользователей постоянными отказами в проведении, мы можем пойти другим путем: автоматически менять режим проведения на неоперативный, если документ уже был проведен ранее. При неоперативном проведении платформа не сдвигает время документа на текущую секунду сервера, а сохраняет его первоначальную дату и время проведения.
Для реализации этого механизма в модуле формы документа или в подписке на событие мы можем переопределить параметр РежимПроведения:
Процедура ПередЗаписьюДокументаДляСохраненияВремени(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
// Если документ уже был проведен ранее, принудительно переводим проведение в неоперативный режим
Если Источник.Проведен Тогда
РежимПроведения = РежимПроведенияДокумента.Неоперативный;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важное примечание: Перевод проведения в неоперативный режим сохранит хронологическую цепочку нетронутой, однако следует помнить, что неоперативное проведение не контролирует остатки на текущую секунду времени, а проводит документ «задним числом». В большинстве случаев для документов типа ЗаказПокупателя это абсолютно безопасно, так как заказы обычно не списывают остатки со склада напрямую (в отличие от расходных накладных).
Если внесение изменений в программный код конфигурации нежелательно, мы можем минимизировать риски административными методами:
КорректировкаЗаказаПокупателя). Это позволит сохранить исходный документ-основание в первозданном виде с его первоначальным временем проведения, а все изменения будут зафиксированы новыми документами текущей датой.Таким образом, мы детально разобрали неочевидное поведение платформы 1С при оперативном проведении документов, выяснили техническую подоплеку смещения времени документов-оснований и научились бороться с этой проблемой как методами расследования через Журнал регистрации, так и с помощью превентивного написания кода подписок на события. Использование этих рекомендаций позволит вам поддерживать безупречную хронологию учета в ваших информационных базах.