При доработке типовых или старых кастомных конфигураций «1С:Предприятие» (например, на базе решений «Зарплата и Управление Персоналом 2.5» или «Управление производственным предприятием 1.3») разработчики часто сталкиваются с необходимостью изменить логику распределения затрат. Одной из классических задач является распределение сумм начисленного отпуска по разным счетам бухгалтерского учета непосредственно из табличной части документа, в то время как ранее учет велся по единому счету из шапки.
В процессе реализации этой задачи часто возникает неприятная ошибка при проведении документа:
«Ошибка при выполнении обработчика - '{Документ.дНачислениеОтпускаРаботникамОрганизаций(1309)}: Поле объекта не обнаружено (СпособОтражения)'»
В этой статье мы подробно разберем, почему возникает данная ошибка, проанализируем поведение системы при обработке основных начислений и материальной помощи, а также рассмотрим несколько эффективных способов решения проблемы — от быстрого «обхода» до архитектурно правильного и безопасного кода.
---
Рассмотрим ситуацию детальнее. Бухгалтерия ставит задачу: распределять отпускные по разным счетам затрат. Для этого в табличную часть документа начисления добавляется реквизит СпособОтражения (ссылка на справочник способов отражения зарплаты в регламентированном учете). Программист успешно реализует эту логику в процедуре проведения.
Однако в документе, помимо основных дней отпуска, присутствует дополнительная опция — «Материальная помощь к отпуску», которая включается специальным флажком (галочкой) в шапке или на отдельной вкладке и рассчитывается фиксированной суммой. При проведении документа система совершает циклическую запись движений в регистр расчета ОсновныеНачисленияРаботниковОрганизаций.
Давайте проанализируем стандартную процедуру, отвечающую за формирование движений:
Процедура ДобавитьСтрокуОсновныхНачислений(ВыборкаПоШапкеДокумента, ВыборкаПоСтрокамДокумента, УчетнаяПолитикаПоПерсоналуОрганизации)
Движение = Движения.ОсновныеНачисленияРаботниковОрганизаций.Добавить();
// Заполнение стандартных реквизитов движения
Движение.ПериодРегистрации = ВыборкаПоШапкеДокумента.ПериодРегистрации;
Движение.ПериодДействияНачало = ВыборкаПоСтрокамДокумента.ДатаНачала;
Движение.ПериодДействияКонец = ВыборкаПоСтрокамДокумента.ДатаОкончания;
Движение.ВидРасчета = ВыборкаПоСтрокамДокумента.ВидРасчета;
// ... [пропущен код заполнения других измерений и ресурсов] ...
// Попытка определить способ отражения в бухучете
Если ЗначениеЗаполнено(ВыборкаПоСтрокамДокумента.СпособОтражения) Тогда
Движение.ОтражениеВУчете = ВыборкаПоСтрокамДокумента.СпособОтражения;
ИначеЕсли ЗначениеЗаполнено(СпособОтражения) И ОбщегоНазначения.ЗначениеНеЗаполнено(ВыборкаПоСтрокамДокумента.ВидРасчета.СпособОтраженияВБухучете) Тогда
Движение.ОтражениеВУчете = СпособОтражения;
КонецЕсли;
Движение.ДатаНачалаСобытия = ПолучитьДатуНачалаСобытия;
Движение.Авторасчет = Истина;
КонецПроцедуры
Выясним причину сбоя. Данная процедура является универсальной и вызывается в цикле проведения несколько раз:
СпособОтражения присутствует физически, и код отрабатывает без ошибок).ВыборкаПоСтрокамДокумента в виде структуры или отдельной строки, в которой физически отсутствует поле СпособОтражения.При попытке выполнить проверку Если ЗначениеЗаполнено(ВыборкаПоСтрокамДокумента.СпособОтражения) на четвертом шаге система выбрасывает исключение, так как у переданного объекта (структуры) нет такого свойства.
---
Самый быстрый способ обойти ошибку, к которому часто прибегают разработчики в условиях жестких временных рамок, — это найти место в модуле проведения, где формируется структура данных для начисления материальной помощи, и принудительно добавить туда пустое свойство-заглушку.
Для этого в код формирования параметров (где заполняется структура проведения для материальной помощи) необходимо добавить следующую строку:
СтруктураПроведения.Вставить("СпособОтражения", Неопределено);
Это решает проблему «в лоб»: теперь при вызове процедуры ДобавитьСтрокуОсновныхНачислений обращение к свойству ВыборкаПоСтрокамДокумента.СпособОтражения не вызовет ошибку, так как свойство существует, хотя и содержит значение Неопределено.
Минус этого подхода: При последующих обновлениях конфигурации или изменении логики расчета материальной помощи это точечное исправление легко затереть или пропустить, что вернет ошибку вновь.
---
Более профессиональным решением является доработка самой процедуры ДобавитьСтрокуОсновныхНачислений. Мы сделаем ее устойчивой к передаче объектов различной структуры, чтобы отсутствие поля СпособОтражения обрабатывалось платформой корректно и без падений.
Рассмотрим, как переписать блок определения способа отражения:
// Безопасное определение способа отражения в бухучете
СпособОтраженияСтроки = Неопределено;
Если ТипЗнч(ВыборкаПоСтрокамДокумента) = Тип("Структура") Тогда
// Если передана структура, используем безопасный метод Свойство()
ВыборкаПоСтрокамДокумента.Свойство("СпособОтражения", СпособОтраженияСтроки);
Иначе
// Если передана выборка из запроса или строка таблицы значений
Попытка
СпособОтраженияСтроки = ВыборкаПоСтрокамДокумента.СпособОтражения;
Исключение
// Поля нет в выборке, оставляем значение Неопределено
СпособОтраженияСтроки = Неопределено;
КонецПопытки;
КонецЕсли;
// Применяем полученное значение в алгоритме
Если ЗначениеЗаполнено(СпособОтраженияСтроки) Тогда
Движение.ОтражениеВУчете = СпособОтраженияСтроки;
ИначеЕсли ЗначениеЗаполнено(СпособОтражения) И ОбщегоНазначения.ЗначениеНеЗаполнено(ВыборкаПоСтрокамДокумента.ВидРасчета.СпособОтраженияВБухучете) Тогда
Движение.ОтражениеВУчете = СпособОтражения;
КонецЕсли;
Этот код гарантирует, что даже если структура параметров материальной помощи изменится или будет передана неполной, система не завершит работу аварийно. Переменная СпособОтраженияСтроки просто примет пустое значение.
---
Если данные по материальной помощи собираются в общую временную таблицу или выборку с помощью SQL-запроса в модуле проведения, правильнее всего будет добавить недостающее поле непосредственно в текст этого запроса.
В той ветке пакета запросов (или объединения), которая отвечает за выборку данных по материальной помощи, необходимо явно инициализировать пустое поле нужного типа:
ВЫБРАТЬ
СсылкаНаДокумент.Сотрудник КАК Сотрудник,
СсылкаНаДокумент.МатериальнаяПомощьСумма КАК Результат,
// Принудительно создаем пустое поле нужного типа справочника
ВЫРАЗИТЬ(НЕОПРЕДЕЛЕНО КАК Справочник.СпособыОтраженияЗарплатыВБухучете) КАК СпособОтражения
ИЗ
Документ.НачислениеОтпускаРаботникамОрганизаций КАК СсылкаНаДокумент
Это исключит возникновение ошибки на уровне чтения выборки данных, сохранив типизацию метаданных.
---
Просто «обойти» техническую ошибку недостаточно. Важно понимать экономический смысл хозяйственных операций. Попытка принудительно распределить материальную помощь по тем же счетам затрат, на которые относятся отпускные сотрудников, может привести к серьезным налоговым рискам.
Проанализируем требования законодательства к учету материальной помощи:
Важная рекомендация разработчику: Не копируйте способ отражения отпуска для материальной помощи автоматически. Для нее необходимо предусмотреть отдельную схему отражения. Лучше всего оставить реквизит ОтражениеВУчете для строки материальной помощи пустым (Неопределено).
---
Что произойдет, если в движении регистра расчета по материальной помощи поле СпособОтражения останется пустым? Система 1С не оставит эту запись без проводки. При формировании документа «Отражение зарплаты в регламентированном учете» запустится стандартный алгоритм поиска счетов по приоритетам (от наивысшего к наинизшему):
Таким образом, оставляя поле СпособОтражения пустым для строки матпомощи в регистре расчета, мы действуем абсолютно правильно. Система автоматически подставит верный счет (например, 91.02) из настроек самого вида расчета «Материальная помощь», даже если основные отпускные будут распределены по производственным счетам 20 или 26 согласно табличной части документа.