При разработке или доработке конфигураций на базе 1С:Предприятие 8, особенно в таких сложных решениях, как «Бухгалтерия предприятия КОРП», программисты часто сталкиваются с необходимостью программной корректировки движений документов. Одной из наиболее «коварных» ошибок в этом процессе является сообщение: «Запись не верна! Вид субконто не доступен для данной записи!». Рассмотрим подробно, почему возникает эта ситуация, проанализируем внутренние механизмы работы регистра бухгалтерии и выясним, как правильно изменять аналитику в проводках.
Давайте выясним, что происходит «под капотом» платформы 1С при записи набора записей регистра бухгалтерии. В отличие от обычных регистров сведений или накопления, регистр бухгалтерии имеет жесткую связь между выбранным счетом (СчетДт или СчетКт) и коллекцией субконто. В Плане счетов для каждого счета определены конкретные Виды субконто (например, «Контрагенты», «Договоры», «Статьи затрат»).
Когда мы пытаемся записать проводку, система выполняет валидацию: она проверяет, чтобы в коллекции СубконтоДт (или СубконтоКт) присутствовали только те ключи (Виды субконто), которые разрешены для данного счета в метаданных. Ошибка «Вид субконто не доступен» означает, что в коллекции субконто вашей проводки остался «лишний» вид субконто, который не числится за новым счетом.
Проанализируем типичную ситуацию из практики. Допустим, мы меняем в проводке счет 91.02 «Прочие расходы» на счет 44.01 «Издержки обращения». У счета 91.02 основным видом субконто является «Прочие доходы и расходы», а у счета 44.01 — «Статьи затрат». Если мы просто присвоим новый счет и попытаемся записать проводку, в коллекции субконто останется ключ «Прочие доходы и расходы», который для счета 44.01 является недопустимым. Даже если значение этого субконто будет пустым (Неопределено), сам факт наличия этого ключа в наборе приведет к отказу в записи.
Рассмотрим пример кода, который часто приводит к ошибке. Многие разработчики пытаются «обнулить» старое субконто, записывая в него пустое значение, как в данном примере:
// ОШИБОЧНЫЙ ПУТЬ
Для Каждого Проводка Из Источник.Движения.Хозрасчетный Цикл
Если Проводка.СчетДт = ПланыСчетов.Хозрасчетный.ПрочиеРасходы Тогда
ВидСубконто = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.ПрочиеДоходыИРасходы;
// Попытка "очистить" через вставку Неопределено
Проводка.СубконтоДт.Вставить(ВидСубконто, Неопределено);
Проводка.СчетДт = ПланыСчетов.Хозрасчетный.ИздержкиОбращения;
БухгалтерскийУчет.УстановитьСубконто(Проводка.СчетДт, Проводка.СубконтоДт, 1, СтатьяЗатрат);
КонецЕсли;
КонецЦикла;
Почему этот код не работает? Метод Вставить() для коллекции Субконто не удаляет связь с видом субконто. Он лишь меняет значение для конкретного ключа. В итоге, после смены счета на 44.01, в проводке всё равно «висит» аналитика «Прочие доходы и расходы», хотя она там не предусмотрена. Система видит этот посторонний ключ и блокирует запись.
Чтобы избежать конфликтов с метаданными, мы должны следовать строгому алгоритму. Рассмотрим его по шагам:
СчетДт или СчетКт.Очистить().БухгалтерскийУчет.УстановитьСубконто) для заполнения субконто, соответствующих новому счету.Посмотрим на исправленный и гарантированно рабочий вариант кода:
// ПРАВИЛЬНЫЙ ПУТЬ
Для Каждого Проводка Из Источник.Движения.Хозрасчетный Цикл
Если Проводка.СчетДт = ПланыСчетов.Хозрасчетный.ПрочиеРасходы Тогда
// 1. Устанавливаем новый счет
Проводка.СчетДт = ПланыСчетов.Хозрасчетный.ИздержкиОбращения;
// 2. Полностью очищаем коллекцию субконто от старых "хвостов"
Проводка.СубконтоДт.Очистить();
// 3. Заполняем субконто заново согласно метаданным нового счета
// Используем типовую функцию, которая сама определит нужные виды субконто по их номеру (индексу)
БухгалтерскийУчет.УстановитьСубконто(Проводка.СчетДт, Проводка.СубконтоДт, "СтатьиЗатрат", СтатьяЗатратНДС);
ЕстьИзменения = Истина;
КонецЕсли;
КонецЦикла;
Если ЕстьИзменения Тогда
// Записываем набор движений, если мы находимся вне транзакции проведения или нам нужна немедленная фиксация
Источник.Движения.Хозрасчетный.Записать();
КонецЕсли;
В типовых решениях (БП 3.0, ERP, КА) часто применяется функция БухгалтерскийУчет.УстановитьСубконто(). Разберем подробнее, как она работает и почему предварительная очистка Проводка.СубконтоДт.Очистить() обязательна.
Функция УстановитьСубконто анализирует структуру счета. Если в параметрах функции передается имя субконто (строкой) или его номер, функция ищет соответствие в Плане счетов. Однако, если коллекция субконто в проводке уже содержит какие-то данные, функция может вести себя непредсказуемо или оставить старые данные нетронутыми, если они не пересекаются с новыми. Помните: Платформа 1С проверяет всю коллекцию при записи. Если там останется хоть один вид субконто, не принадлежащий счету, вы получите ошибку.
Рассмотрим еще несколько нюансов, которые помогут вам писать более стабильный код при работе с регистрами бухгалтерии:
УстановитьСубконто, вы передаете либо индекс (1, 2, 3), либо конкретный ВидСубконто. Очистка коллекции перед этими действиями гарантирует, что данные не «наложатся» друг на друга.СтатьяЗатратНДС) не является пустой и имеет правильный тип, соответствующий виду субконто на данном счету.ОбработкаПроведения, помните, что по умолчанию платформа сама запишет движения по завершении процедуры. Явный вызов Записать() нужен только в том случае, если вы программно меняете движения уже проведенного документа или если вам нужно использовать результат этих движений в коде ниже (например, для формирования проводок по другому регистру в этой же транзакции).ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные[Имя]. Если в базе случайно созданы дубликаты видов субконто с одинаковыми именами, вы можете получить не ту ссылку, которая привязана к счету. Лучше использовать обращение к предопределенным элементам.Подводя итог, можно сказать, что решение проблемы «Вид субконто не доступен» всегда заключается в полной очистке контекста аналитики перед внесением изменений. Как только мы очищаем коллекцию СубконтоДт или СубконтоКт, мы снимаем с проводки ограничения, наложенные старым счетом, и можем свободно наполнять её данными, соответствующими новой бухгалтерской логике.