Как программно изменить проводки в регистре бухгалтерии с фильтром по конкретному клиенту или субконто?

Программист 1С v8.3 (Обычные формы) Бухгалтерский учет IT и автоматизация бизнеса
← На главную

Работа с регистрами бухгалтерии (РБ) в системе «1С:Предприятие» существенно отличается от работы с регистрами сведений или накопления. Основная сложность заключается в жесткой структуре отборов и необходимости соблюдения принципа двойной записи. В данной статье мы подробно разберем, как правильно модифицировать проводки, если нам нужно изменить данные только по определенному контрагенту (клиенту), и почему стандартный механизм отборов в наборе записей здесь не сработает напрямую.

Особенности работы с отборами в наборе записей регистра бухгалтерии

Проанализируем ситуацию, с которой сталкиваются многие начинающие разработчики. При попытке создать РегистрБухгалтерииНаборЗаписей и установить отбор по произвольному реквизиту (например, «Клиент» или «Субконто»), система выдает ошибку или просто не применяет фильтр. Выясним причину: в регистрах бухгалтерии, подчиненных регистратору, основным и зачастую единственным доступным полем для отбора в объекте НаборЗаписей является Регистратор. Платформа 1С оптимизирована таким образом, что записи регистра жестко привязаны к документу, который их породил.

Если нам необходимо изменить проводки по конкретному клиенту, мы не можем просто сказать системе: «Дай мне все записи регистра по Иванову». Мы должны действовать в два этапа:

  1. Найти все документы (регистраторы), которые делали движения по данному клиенту.
  2. Для каждого найденного документа создать набор записей, прочитать его, модифицировать нужные строки и записать обратно.

Шаг 1: Поиск документов-регистраторов через запрос

Рассмотрим, как правильно собрать список документов для последующей обработки. Для этого лучше всего использовать объект Запрос к виртуальной таблице регистра бухгалтерии ДвиженияССубконто. Это позволит нам сразу отфильтровать данные по нужному значению субконто (в нашем случае — Клиенту).

Посмотрим на пример кода для поиска регистраторов:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |   ХозрасчетныйДвиженияССубконто.Регистратор КАК Регистратор
    |ИЗ
    |   РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
    |       &НачалоПериода, 
    |       &КонецПериода, 
    |       Субконто1 = &Клиент) КАК ХозрасчетныйДвиженияССубконто";

Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("Клиент", ВыбранныйКлиентСсылка);

Выборка = Запрос.Выполнить().Выбрать();

Обратите внимание, что мы используем ВЫБРАТЬ РАЗЛИЧНЫЕ, так как один документ может порождать десятки проводок по одному и тому же клиенту, а нам нужна лишь ссылка на сам документ для установки отбора в наборе записей.

Шаг 2: Программное изменение проводок в цикле

После того как мы получили список регистраторов, проанализируем процесс изменения самих записей. Важно помнить, что метод Записать(Истина) полностью перезаписывает движения документа по конкретному регистру. Если вы забудете вызвать метод Прочитать(), вы рискуете стереть все существующие проводки документа, заменив их пустым набором.

Разберем по шагам правильный алгоритм внутри цикла обхода документов:

  1. Создаем набор записей регистра.
  2. Устанавливаем отбор по Регистратору (используя ссылку на документ).
  3. Вызываем Прочитать(), чтобы наполнить набор существующими данными.
  4. В цикле Для Каждого перебираем записи и меняем нужные ресурсы (например, количество или сумму).
  5. Вызываем Записать().

Посмотрим на пример реализации, который исправляет типичные ошибки начинающих:


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

Разбор типичных ошибок и важных нюансов

Проанализируем ситуацию, возникшую в обсуждении на форуме. Автор столкнулась с ошибкой «Объект не найден» при установке отбора. Выясним причину: вместо ссылки на конкретный документ в метод Установить() передавался менеджер объекта (Документы.ПриходнаяНакладная). Запомните: в отбор всегда должна передаваться конкретная ссылка (Ссылка), а не тип документа.

Еще один критический момент — использование правильного оператора цикла. Рассмотрим разницу между Если и Пока при работе с выборкой. Если вы напишете Если Выборка.Следующий() Тогда, программа обработает только один (первый) найденный документ и остановится. Для обработки всех документов необходимо использовать конструкцию Пока Выборка.Следующий() Цикл.

Также стоит затронуть вопрос балансовых ресурсов. В регистрах бухгалтерии ресурс Сумма обычно является балансовым. Это означает, что он записывается один раз для всей проводки (между дебетом и кредитом). В то же время Количество часто является небалансовым ресурсом, привязанным к конкретному счету (Дебету или Кредиту). При программном изменении количественных показателей всегда проверяйте, по какому именно счету (Дт или Кт) ведется количественный учет, чтобы не допустить рассинхронизации данных.

Практические советы по безопасности данных

Когда мы меняем движения документов «на лету» внешней обработкой, мы фактически действуем в обход стандартной бизнес-логики проведения. Рассмотрим, как минимизировать риски:

Подводя итог, можно сказать, что работа с проводками требует от разработчика понимания не только программного кода 1С, но и основ бухгалтерского учета. Комбинация запроса к виртуальным таблицам и аккуратной работы с объектом НаборЗаписей позволяет решать практически любые задачи по корректировке данных в учетных системах.

← На главную