Мы рассмотрим распространенную ситуацию, когда при программном заполнении документа "Инвентаризация ОС" в 1С, несмотря на установку флага фактического наличия, сумма по факту остается нулевой. Разберем, почему это происходит, и как правильно реализовать заполнение этого поля в вашей обработке.
Когда вы создаете документ "Инвентаризация ОС" программно и заполняете его табличную часть, присваивая значение Истина реквизиту НаличиеФактическое, вы можете обнаружить, что поле СтоимостьФактическая остается равным нулю. При этом, если в уже созданном документе вручную снять и снова поставить эту галочку, сумма появляется корректно. Такая ситуация часто вводит в заблуждение, поскольку кажется, что достаточно установить одно значение, чтобы зависимое поле рассчиталось автоматически.
Давайте проанализируем исходный код обработки, который привел к данной проблеме:
Процедура ЗаписатьДанныеНаСервере
НовыйДок = Документы.ИнвентаризацияОС.СоздатьДокумент;
НовыйДок.Дата = ТекущаяДата;
НовыйДок.Организация = Справочники.Организации.НайтиПоНаименованию("ВОДОКАНАЛ-МЫТИЩИ АО");
Для Каждого СтрокаДанных Из Объект.ДанныеДляРегистров Цикл
НайденнаяНоменклатура = Справочники.ОсновныеСредства.НайтиПоКоду(СтрокаДанных.Инв);
Если ЗначениеЗаполнено(НайденнаяНоменклатура) Тогда
НоваяСтрока = НовыйДок.ОС.Добавить;
НоваяСтрока.ОсновноеСредство = НайденнаяНоменклатура;
НоваяСтрока.СтоимостьПоДаннымУчета = Число(СтрокаДанных.Сумма);
// НовыйДок.Записать(РежимЗАписиДокумента.Запись); // Лишняя запись внутри цикла
НоваяСтрока.НаличиеПоДаннымУчета = Истина;
НоваяСтрока.НаличиеФактическое = Истина;
Иначе
Сообщить ("Номенклатура не обнаружена!!!" + СтрокаДанных);
КонецЕсли;
КонецЦикла;
НовыйДок.Записать;
Сообщить("Запись, создана" + НовыйДок.Ссылка);
КонецПроцедуры
Как мы видим из кода, автор обработки действительно устанавливает НоваяСтрока.НаличиеФактическое = Истина;. Однако поле СтоимостьФактическая нигде явно не заполняется. Именно в этом и кроется корень проблемы.
В типовых конфигурациях 1С многие поля документов, особенно в табличных частях, имеют зависимые расчеты. Эти расчеты обычно реализованы в обработчиках событий элементов формы. Например, при изменении значения в поле НаличиеФактическое на форме документа, срабатывает процедура, которая и заполняет СтоимостьФактическая.
Когда мы работаем с объектом документа программно (например, через НовыйДок = Документы.ИнвентаризацияОС.СоздатьДокумент;), мы оперируем непосредственно с данными в базе данных, а не с элементами формы. Соответственно, обработчики событий формы, которые срабатывают при интерактивном взаимодействии пользователя с интерфейсом, не вызываются автоматически при программном изменении реквизитов объекта.
Для решения этой проблемы нам необходимо "подсмотреть" логику заполнения поля СтоимостьФактическая в типовом документе и воспроизвести ее в нашей обработке. Обычно такую логику можно найти в модуле формы документа или в модуле объекта, в обработчиках событий полей табличной части.
Давайте посмотрим на код обработчика события, который был найден в документе "Инвентаризация ОС" для поля НаличиеФактическое:
Процедура ОСНаличиеФактическоеПриИзменении(Элемент)
ТекущаяСтрокаТЧ = Элементы.ОС.ТекущиеДанные;
Если ТекущаяСтрокаТЧ.НаличиеФактическое Тогда
ТекущаяСтрокаТЧ.СтоимостьФактическая = ТекущаяСтрокаТЧ.СтоимостьПоРезультатамИнвентаризации;
Иначе
ТекущаяСтрокаТЧ.СтоимостьФактическая = 0;
КонецЕсли;
РассчитатьВычисляемыеПоляПоСтроке(ТекущаяСтрокаТЧ);
КонецПроцедуры
Из этого кода становится очевидно:
НаличиеФактическое установлено в Истина, то СтоимостьФактическая присваивается значение из поля СтоимостьПоРезультатамИнвентаризации.СтоимостьФактическая устанавливается в 0.РассчитатьВычисляемыеПоляПоСтроке(ТекущаяСтрокаТЧ), которая, вероятно, выполняет дополнительные расчеты, такие как определение отклонений.Теперь нам нужно внедрить эту логику в нашу обработку.
Разберем, как мы можем модифицировать исходный код нашей обработки, чтобы корректно заполнять СтоимостьФактическая.
Мы добавим строку, которая будет присваивать СтоимостьФактическая значение, соответствующее фактическому наличию. В типовой логике используется поле СтоимостьПоРезультатамИнвентаризации. Это поле может быть заполнено вручную пользователем или же автоматически при заполнении документа "по данным учета", где оно часто приравнивается к СтоимостьПоДаннымУчета. В вашем случае, если вы не используете отдельное поле СтоимостьПоРезультатамИнвентаризации в своей структуре СтрокаДанных, то можно использовать СтоимостьПоДаннымУчета для СтоимостьФактическая, что является распространенной практикой при отсутствии расхождений. Если по условиям задачи фактическая стоимость может отличаться от учетной, вы должны получить это значение из ваших исходных данных (СтрокаДанных) или рассчитать его.
В исходном коде присутствовала строка НовыйДок.Записать(РежимЗАписиДокумента.Запись); внутри цикла. Это некорректно и неэффективно. Документ должен быть записан один раз после того, как все его табличные части полностью заполнены. Множественные записи в цикле могут привести к проблемам с блокировками, производительностью и некорректному поведению документа, особенно если есть обработчики ПриЗаписи или ПередЗаписью.
Хотя процедура РассчитатьВычисляемыеПоляПоСтроке вызывается в интерактивном обработчике, обычно при программном создании документа такие вспомогательные расчеты, которые влияют только на форму или производные поля, не являются обязательными. Документ сам по себе корректно запишет данные. Если же эта процедура выполняет какие-либо критически важные расчеты, которые влияют на движения или являются основой для дальнейших действий с документом, и их результат хранится в реквизитах объекта (а не только формы), то ее логику также нужно было бы воспроизвести. В данном случае, судя по названию, она скорее всего обновляет отклонения и другие показатели, которые могут быть рассчитаны и при чтении документа.
Вот как будет выглядеть доработанный код:
Процедура ЗаписатьДанныеНаСервере
НовыйДок = Документы.ИнвентаризацияОС.СоздатьДокумент;
НовыйДок.Дата = ТекущаяДата;
НовыйДок.Организация = Справочники.Организации.НайтиПоНаименованию("ВОДОКАНАЛ-МЫТИЩИ АО");
Для Каждого СтрокаДанных Из Объект.ДанныеДляРегистров Цикл
НайденнаяНоменклатура = Справочники.ОсновныеСредства.НайтиПоКоду(СтрокаДанных.Инв);
Если ЗначениеЗаполнено(НайденнаяНоменклатура) Тогда
НоваяСтрока = НовыйДок.ОС.Добавить;
НоваяСтрока.ОсновноеСредство = НайденнаяНоменклатура;
НоваяСтрока.СтоимостьПоДаннымУчета = Число(СтрокаДанных.Сумма);
НоваяСтрока.НаличиеПоДаннымУчета = Истина;
НоваяСтрока.НаличиеФактическое = Истина;
// !!! ВАЖНО: Явно заполняем СтоимостьФактическая
// Используем СтрокаДанных.Сумма как источник фактической стоимости
НоваяСтрока.СтоимостьФактическая = Число(СтрокаДанных.Сумма);
// Если в ваших данных есть отдельное поле для СтоимостьПоРезультатамИнвентаризации,
// сначала заполняем его, а затем присваиваем СтоимостьФактическая.
// Например:
// Если ЗначениеЗаполнено(СтрокаДанных.СуммаПоРезультатамИнвентаризации) Тогда
// НоваяСтрока.СтоимостьПоРезультатамИнвентаризации = Число(СтрокаДанных.СуммаПоРезультатамИнвентаризации);
// НоваяСтрока.СтоимостьФактическая = НоваяСтрока.СтоимостьПоРезультатамИнвентаризации;
// Иначе
// НоваяСтрока.СтоимостьПоРезультатамИнвентаризации = НоваяСтрока.СтоимостьПоДаннымУчета;
// НоваяСтрока.СтоимостьФактическая = НоваяСтрока.СтоимостьПоДаннымУчета;
// КонецЕсли;
Иначе
Сообщить ("Номенклатура не обнаружена!!!" + СтрокаДанных);
КонецЕсли;
КонецЦикла;
// Окончательная запись документа после полного заполнения всех данных
НовыйДок.Записать(РежимЗАписиДокумента.Проведение); // Можно использовать Проведение, если документ должен сразу проводить движения
Сообщить("Запись создана: " + НовыйДок.Ссылка);
КонецПроцедуры
В этом примере мы добавили строку НоваяСтрока.СтоимостьФактическая = Число(СтрокаДанных.Сумма);, которая явно присваивает фактическую стоимость. Мы также убрали лишнюю запись внутри цикла и перенесли ее в конец процедуры. Рекомендуется использовать РежимЗАписиДокумента.Проведение, если документ должен сразу сформировать проводки или движения регистров.
Важно понимать, что документ "Инвентаризация ОС" сам по себе не формирует проводки напрямую. Он служит основанием для создания других документов, которые уже будут генерировать бухгалтерские записи по результатам инвентаризации (например, "Списание ОС" для недостачи или "Принятие к учету ОС" для излишков).
При заполнении этого документа указываются местонахождение ОС и материально ответственное лицо (МОЛ). Табличная часть может быть заполнена не только вашей обработкой, но и типовыми средствами по данным бухгалтерского учета с помощью кнопки "Заполнить" на форме документа.
При работе с программным заполнением документов и их табличных частей в 1С всегда помните о следующих принципах:
НовыйДок). Это значит, что обработчики событий формы (ПриИзменении, ПередЗаписьюНаСервере формы и т.д.) не будут срабатывать.
НаличиеФактическое на СтоимостьФактическая), то логику этого влияния необходимо явно воспроизвести в вашем коде.
ЗаполнитьЗначенияСвойств: Если вы заполняете табличную часть из данных запроса или другой структуры, у которой имена полей совпадают с именами реквизитов табличной части, используйте метод ЗаполнитьЗначенияСвойств(Приемник, Источник). Это может упростить и ускорить процесс заполнения.
Следуя этим рекомендациям, вы сможете создавать и заполнять документы в 1С программно, избегая распространенных ошибок и обеспечивая корректность данных.