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