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