В многопользовательской среде 1С:Предприятия 7.7 разработчики и администраторы нередко сталкиваются с ситуацией, когда при одновременной работе пользователей проведение документов аварийно прерывается сообщениями «Невозможно рассчитать итоги после ТА» или длительными блокировками системной таблицы 1SSYSTEM. На первый взгляд кажется, что платформа разделяет проведение документа и сдвиг точки актуальности (ТА) на две разные операции, между которыми возникает временной зазор. Разберем механику работы платформы, выясним истинные причины коллизий и рассмотрим проверенные способы их устранения.
Проанализируем базовый принцип: в платформе 1С 7.7 проведение документа в реальном времени и перемещение точки актуальности неделимы и всегда выполняются внутри одной транзакции. Никакого промежуточного состояния, когда документ уже провелся, а ТА еще не сдвинулась, на уровне ядра базы данных физически не существует. При проведении документа на ТА платформа блокирует монопольно единственную запись в таблице 1SSYSTEM, записывает движения регистров, обновляет реквизиты ТА (дату, время и внутренний ID документа) и фиксирует транзакцию.
Почему же возникает ошибка невозможности расчета итогов? Механизм ВременныйРасчет() в регистрах оперативного учета умеет рассчитывать остатки только на позиции, которые находятся строго до или на момент ТА. Если платформа пытается рассчитать временные итоги на точку, расположенную в будущем относительно текущей ТА, транзакция немедленно падает с системным отказом.
Выясним, откуда берутся документы, опережающие точку актуальности, из-за которых блокируется нормальная работа пользователей:
23:59:59 для документов инвентаризации, списания или перемещения), ТА моментально перемещается в конец текущей даты. После этого любые оперативные документы, создаваемые в течение дня, попадают в прошлое относительно ТА.1SSYSTEM.Рассмотрим типовую ошибку в процедуре ОбработкаПроведения(). Часто разработчики пишут условие для получения временных остатков только через метод ИтогиАктуальны():
Если ИтогиАктуальны() = 0 Тогда
Регистры.ВременныйРасчет(1);
РассчитатьРегистрыНа(ТекущийДокумент());
КонецЕсли;
Посмотрим на проблему такого подхода: если документ по какой-то причине проводится позже ТА, функция ИтогиАктуальны() вернет значение 0. Программа зайдет в условие и попытается выполнить метод РассчитатьРегистрыНа() на момент позже ТА, что вызовет фатальное падение. Чтобы этого избежать, добавим дополнительную проверку через встроенную функцию СравнитьТА():
// СравнитьТА() возвращает:
// -1 : документ раньше ТА
// 0 : документ на ТА
// 1 : документ позже ТА
Если (ИтогиАктуальны() = 0) И (СравнитьТА() = -1) Тогда
Регистры.ВременныйРасчет(1);
РассчитатьРегистрыНа(ТекущийДокумент());
КонецЕсли;
Такой блок кода гарантирует, что расчет остатков будет выполняться исключительно тогда, когда документ находится строго в прошлом относительно текущей точки актуальности.
Разберем параметры позиционирования оперативных документов в конфигурации:
ПроводитьПослеТА(). Разберем синтаксис:
// В модуле формы документа, например, в процедуре ПриОткрытии():
// 1 - проводить документ в реальном потоке времени (время ставится после ТА)
ПроводитьПослеТА(1, 1);
Иногда администраторы пытаются решить проблему установкой точки актуальности вручную на конец месяца или на первое число следующего месяца. Разберем последствия этого шага:
ВременныйРасчет().Для надежной работы системы при параллельной нагрузке применим следующие шаги:
NOLOCK через класс ODBCRecordset. Это позволит считывать актуальные остатки без наложения блокировок и без механизма временного расчета.