Как программно создавать бухгалтерские операции последним числом каждого месяца при расчете процентов

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет Финансы и профессиональные услуги
← На главную

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

Разберем ситуацию: пользователь выбирает период (например, с февраля по апрель), система рассчитывает проценты за каждый день пользования денежными средствами, но итоговые проводки должны «лечь» на 28 февраля, 31 марта и 30 апреля соответственно. Рассмотрим, как это реализовать в конфигураторе 1С.

Анализ исходной проблемы

Проанализируем типичную ошибку начинающего разработчика. Часто в коде создание документа выносится за пределы цикла обхода данных запроса. В результате, сколько бы месяцев ни охватывал расчет, создается один единственный документ датой конца общего периода, куда «сваливаются» все начисления. Для решения задачи нам необходимо изменить структуру алгоритма: перенастроить запрос для получения данных в разрезе месяцев и перенести логику создания объектов ДокументОбъект.ОперацияБух внутрь цикла.

Шаг 1. Подготовка запроса с группировкой по месяцам

Для того чтобы система «понимала», к какому месяцу относится та или иная сумма остатка или оборота, воспользуемся функцией языка запросов КОНЕЦПЕРИОДА. Это позволит нам получить готовую дату для установки реквизита Дата документа и периода проводки.

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


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

Использование КОНЕЦПЕРИОДА(..., МЕСЯЦ) в полях выбора и в итогах позволяет нам организовать обход результата запроса сначала по месяцам, затем по контрагентам. Это ключевой момент для правильной датировки документов.

Шаг 2. Организация циклов и создание документов

Выясним причину, по которой документы могут создаваться некорректно. Если мы используем ОбходРезультатаЗапроса.ПоГруппировкам, нам нужно на каждом уровне иерархии принимать решение о создании нового объекта. Посмотрим на правильную структуру вложенных циклов:


ВыборкаМесяц = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "КонецМесяцаРасчета");

Пока ВыборкаМесяц.Следующий() Цикл
    
    // Для каждого месяца создаем отдельную операцию
    Если СоздатьОперацию Тогда
        НоваяОперация = Документы.ОперацияБух.СоздатьДокумент();
        НоваяОперация.Дата = ВыборкаМесяц.КонецМесяцаРасчета;
        НоваяОперация.Организация = Организация;
        НоваяОперация.Содержание = "Начисление процентов за " + Формат(ВыборкаМесяц.КонецМесяцаРасчета, "ДФ='ММММ гггг'");
        НоваяОперация.УстановитьНовыйНомер();
    КонецЕсли;

    ВыборкаКонтрагент = ВыборкаМесяц.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Контрагент");
    Пока ВыборкаКонтрагент.Следующий() Цикл
        
        ВыборкаДетали = ВыборкаКонтрагент.Выбрать();
        Пока ВыборкаДетали.Следующий() Цикл
            // Здесь выполняем расчет суммы процентов (алгоритм расчета зависит от условий договора)
            СуммаПроцентов = РассчитатьПроценты(ВыборкаДетали.ОстатокДолга, ...);
            
            Если СуммаПроцентов <> 0 Тогда
                // Добавляем проводку в текущий документ месяца
                Проводка = НоваяОперация.Движения.Хозрасчетный.Добавить();
                Проводка.Период = ВыборкаМесяц.КонецМесяцаРасчета;
                Проводка.Организация = Организация;
                Проводка.Активность = Истина;
                
                // Заполнение счетов и субконто
                Проводка.СчетДт = ПланыСчетов.Хозрасчетный.ПрочиеРасчетыСРазнымиДебиторамиИКредиторами;
                Проводка.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты] = ВыборкаДетали.Контрагент;
                Проводка.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры] = ВыборкаДетали.Договор;
                
                Проводка.СчетКт = ПланыСчетов.Хозрасчетный.ПрочиеДоходы;
                Проводка.Сумма = СуммаПроцентов;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;

    // Записываем документ после того, как добавили все проводки за этот месяц
    Если СоздатьОперацию Тогда
        НоваяОперация.Записать();
        НоваяОперация.Движения.Хозрасчетный.Записать();
    КонецЕсли;
    
КонецЦикла;

Важные технические нюансы

Рассмотрим подробнее несколько критических моментов, которые часто упускают при разработке подобных обработок:

  1. Соответствие даты документа и периода проводки. В документе «Операция (бухгалтерский учет)» свойство Дата самого документа и свойство Период в строках набора записей регистра бухгалтерии должны совпадать (или хотя бы находиться в пределах одного периода). Если вы установите дату документа 30 апреля, а проводку сделаете 28 февраля, это может вызвать проблемы при формировании отчетности и анализе движений.
  2. Налоговый учет (НУ). Если ваша организация применяет общую систему налогообложения (ОСНО), не забудьте заполнить соответствующие ресурсы НУ. В 1С:Бухгалтерии это СуммаНУДт и СуммаНУКт. Обычно для прочих доходов они равны сумме бухгалтерского учета. Без их заполнения возникнут разрывы в налоговых декларациях.
  3. Расчет базы (количества дней). Проанализируем ситуацию с расчетом количества дней в году. Использование функции ДеньГода(КонецГода(Дата)) корректно, однако помните, что расчет процентов за февраль високосного года должен учитывать 29 дней в знаменателе формулы, если это предусмотрено учетной политикой или договором.
  4. Проверка на дубли. Перед созданием документов программно, рекомендуется выполнить проверку: не были ли начислены проценты за этот месяц ранее? Простейший способ — поиск документа по комментарию или по содержанию проводок за указанный период.

Оптимизация работы с объектами

Создание объектов в цикле — ресурсоемкая задача. Если количество контрагентов и месяцев велико, разберем способ ускорения работы. Вместо непосредственного создания документов в основном цикле обхода запроса, можно сначала собрать все данные в ТаблицуЗначений, сгруппировать их, и только затем запустить процедуру записи в транзакции. Это значительно сократит время блокировки таблиц базы данных.

Также важно помнить о методе УстановитьНовыйНомер(). Если его не вызвать, документы могут записаться с пустым номером, что нарушит нумерацию в системе. При установке даты документа всегда используйте функцию КонецМесяца() для кода на стороне сервера 1С, чтобы время документа было 23:59:59 — это стандарт для регламентных операций.

Таким образом, мы выяснили, что для решения задачи необходимо синхронизировать три составляющие: группировку в запросе по месяцам, создание экземпляра документа на каждую итерацию этой группировки и установку корректного периода для каждой проводки внутри документа.

← На главную