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