При сопровождении и кастомизации типовых конфигураций «1С:Предприятие 8», в частности «Бухгалтерии предприятия 3.0», разработчики часто сталкиваются с ситуацией, когда после очередного обновления системы затертыми оказываются уникальные доработки. Одной из типичных проблем является потеря статуса предопределенного элемента у добавленного ранее вида субконто. В метаданных (конфигурации) этот элемент исчезает, но в самой информационной базе (таблице данных) он остается как обычный, созданный пользователем («непредопределенный») элемент Плана видов характеристик (ПВХ) ВидыСубконтоТиповые.
С точки зрения обычного пользователя (бухгалтера) работа продолжается в штатном режиме: субконто отображается в документах, ручных операциях и бухгалтерских отчетах (например, в оборотно-сальдовой ведомости). Однако при попытке программного заполнения этого субконто в модулях проведения документов разработчик сталкивается с критической ошибкой выполнения кода:
Поле объекта не обнаружено (МойВидСубконто)
В этой статье мы подробно разберем, почему возникает эта ошибка, рассмотрим несколько способов программного заполнения непредопределенных субконто и изучим механизм восстановления связи элементов базы данных с метаданными конфигурации без потери накопленной истории проводок.
Проанализируем архитектуру регистра бухгалтерии в платформе «1С:Предприятие 8.3». Коллекция субконто (свойства СубконтоДт и СубконтоКт у строк движений) представляет собой специализированный объект платформы. Платформа обеспечивает удобный («быстрый») доступ к элементам этой коллекции по имени только в том случае, если вид субконто является предопределенным в конфигураторе.
Когда вид субконто описан в конфигураторе как предопределенный элемент ПВХ ВидыСубконтоТиповые (например, с именем МойВидСубконто), платформа динамически добавляет соответствующее свойство в объект коллекции. Мы можем написать интуитивно понятный код:
НоваяСтрока.СубконтоДт.МойВидСубконто = Ссылка;
Как только элемент теряет статус предопределенного (например, затирается обновлением и превращается в обычный элемент справочника/ПВХ), платформа больше не сопоставляет имя метаданных с динамическим свойством коллекции. Свойство МойВидСубконто исчезает, и при попытке обращения к нему система генерирует исключение Поле объекта не обнаружено.
Рассмотрим, как решить эту проблему программно, если субконто должно остаться пользовательским (непредопределенным), а также разберем алгоритм полного восстановления структуры данных.
Поскольку коллекция субконто по своей внутренней структуре аналогична объекту Соответствие, ключами в ней выступают не текстовые имена, а непосредственные ссылки на элементы плана видов характеристик ВидыСубконтоТиповые. Это означает, что мы можем обойти обращение по имени метаданных, обратившись к свойству через квадратные скобки и передав туда ссылку на нужный элемент.
Рассмотрим пример реализации такого подхода по шагам:
// 1. Находим нужный вид субконто по наименованию или коду в базе данных
ВидСубк = ПланыВидовХарактеристик.ВидыСубконтоТиповые.НайтиПоНаименованию("Мой вид субконто");
// 2. Обязательно проверяем, найден ли элемент в информационной базе
Если ЗначениеЗаполнено(ВидСубк) Тогда
// 3. Заполняем субконто напрямую по ссылке-ключу
НоваяСтрока.СубконтоДт[ВидСубк] = Ссылка;
КонецЕсли;
Важное предупреждение: Поиск элемента по наименованию с помощью метода НайтиПоНаименованию() в промышленном коде считается плохой практикой разработки. Если бухгалтер или администратор случайно изменит название субконто в режиме «Предприятие» (например, исправит опечатку или добавит лишний пробел), код перестанет находить элемент, и субконто перестанет заполняться. Поэтому, если вы выбираете данный путь, рекомендуется искать элемент по уникальному и неизменяемому реквизиту (например, по коду НайтиПоКоду()), предварительно запретив пользователям его редактирование.
В типовой конфигурации «Бухгалтерия предприятия 3.0», разработанной на базе Библиотеки Стандартных Подсистем (БСП), реализован обширный инструментарий для работы с учетными механизмами. Для безопасного заполнения аналитики на счетах предусмотрена готовая функция общего модуля БухгалтерскийУчет.
Проанализируем правильное использование этой функции в коде проведения документа:
// Находим ссылку на наш вид субконто (например, по коду или иным стабильным признакам)
ВидСубк = ПланыВидовХарактеристик.ВидыСубконтоТиповые.НайтиПоКоду("00001");
Если ЗначениеЗаполнено(ВидСубк) Тогда
// Безопасное заполнение субконто средствами БСП
БухгалтерскийУчет.УстановитьСубконто(НоваяСтрока.СчетДт, НоваяСтрока.СубконтоДт, ВидСубк, Ссылка);
КонецЕсли;
Использование метода БухгалтерскийУчет.УстановитьСубконто() обладает неоспоримыми преимуществами:
Если в вашем программном коде во множестве мест уже используется прямое обращение вида СубконтоДт.МойВидСубконто, переписывать везде логику может быть слишком трудозатратно и рискованно. Лучшим решением будет восстановление связи («склеивание») существующего пользовательского элемента в базе данных с конфигурацией, то есть возвращение ему статуса предопределенного элемента.
В платформе «1С:Предприятие 8.3» связь элементов базы данных с метаданными конфигуратора определяется специальным системным реквизитом ИмяПредопределенныхДанных. Разберем по шагам алгоритм восстановления этой связи:
ВидыСубконтоТиповые и добавьте новый предопределенный элемент с тем же именем, которое использовалось в коде (например, МойВидСубконто). Сохраните и обновите конфигурацию базы данных.
// Шаг А. Находим созданный платформой пустой предопределенный дубль и отвязываем его
ДубльСсылка = ПланыВидовХарактеристик.ВидыСубконтоТиповые.МойВидСубконто;
Если ЗначениеЗаполнено(ДубльСсылка) Тогда
ДубльОбъект = ДубльСсылка.ПолучитьОбъект();
// Очищаем имя предопределенных данных, делая элемент обычным
ДубльОбъект.ИмяПредопределенныхДанных = "";
ДубльОбъект.Записать();
// Теперь дубль можно безопасно пометить на удаление, чтобы он не путал бухгалтеров
ДубльОбъект.УстановитьПометкуУдаления(Истина);
КонецЕсли;
// Шаг Б. Находим наш старый заполненный элемент (например, по наименованию)
СтарыйЭлементСсылка = ПланыВидовХарактеристик.ВидыСубконтоТиповые.НайтиПоНаименованию("Мой вид субконто");
Если ЗначениеЗаполнено(СтарыйЭлементСсылка) Тогда
СтарыйОбъект = СтарыйЭлементСсылка.ПолучитьОбъект();
// Привязываем старый элемент к предопределенному имени из метаданных конфигурации
СтарыйОбъект.ИмяПредопределенныхДанных = "МойВидСубконто";
СтарыйОбъект.Записать();
Сообщить("Связь успешно восстановлена! Элемент снова стал предопределенным.");
КонецЕсли;
После успешного выполнения данного скрипта старый вид субконто вернет себе иконку предопределенного элемента (значок с желтой точкой). Все существующие проводки в регистре бухгалтерии останутся в целости и сохранности (так как внутренний уникальный идентификатор UUID элемента ПВХ не менялся), а старый программный код вида НоваяСтрока.СубконтоДт.МойВидСубконто = Ссылка; снова заработает без ошибок.
Проанализируем возможные побочные эффекты, которые могут возникнуть при проведении подобных манипуляций в рабочей базе данных:
ВидыСубконтоТиповые не стоит режим автоматического затирания пользовательских предопределенных элементов. Настройте правила обновления корректно, сохранив ваши доработки.