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