В практике автоматизации бухгалтерского учета часто возникает задача начисления процентов по выданным или полученным займам. Основная сложность здесь заключается не только в точности математического расчета, но и в корректном отражении данных в учете. Согласно правилам бухгалтерского учета, начисление должно производиться ежемесячно, а значит, документы «Операция (бухгалтерский учет)» и соответствующие проводки должны быть датированы последним числом каждого месяца, входящего в период расчета.
Разберем ситуацию: пользователь выбирает период (например, с февраля по апрель), система рассчитывает проценты за каждый день пользования денежными средствами, но итоговые проводки должны «лечь» на 28 февраля, 31 марта и 30 апреля соответственно. Рассмотрим, как это реализовать в конфигураторе 1С.
Проанализируем типичную ошибку начинающего разработчика. Часто в коде создание документа выносится за пределы цикла обхода данных запроса. В результате, сколько бы месяцев ни охватывал расчет, создается один единственный документ датой конца общего периода, куда «сваливаются» все начисления. Для решения задачи нам необходимо изменить структуру алгоритма: перенастроить запрос для получения данных в разрезе месяцев и перенести логику создания объектов ДокументОбъект.ОперацияБух внутрь цикла.
Для того чтобы система «понимала», к какому месяцу относится та или иная сумма остатка или оборота, воспользуемся функцией языка запросов КОНЕЦПЕРИОДА. Это позволит нам получить готовую дату для установки реквизита Дата документа и периода проводки.
Рассмотрим пример модифицированного запроса к виртуальной таблице ОстаткиИОбороты регистра бухгалтерии:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОстаткиИОбороты.Период КАК Период,
| ХозрасчетныйОстаткиИОбороты.Субконто1 КАК Контрагент,
| ХозрасчетныйОстаткиИОбороты.Субконто2 КАК Договор,
| ХозрасчетныйОстаткиИОбороты.СуммаНачальныйОстатокДт КАК ОстатокДолга,
| КОНЕЦПЕРИОДА(ХозрасчетныйОстаткиИОбороты.Период, МЕСЯЦ) КАК КонецМесяцаРасчета
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&Начало, &Конец, День, , Счет = &Счет, , Организация = &Организация) КАК ХозрасчетныйОстаткиИОбороты
|ИТОГИ
| СУММА(ОстатокДолга)
|ПО
| КонецМесяцаРасчета,
| Контрагент,
| Договор";
Использование КОНЕЦПЕРИОДА(..., МЕСЯЦ) в полях выбора и в итогах позволяет нам организовать обход результата запроса сначала по месяцам, затем по контрагентам. Это ключевой момент для правильной датировки документов.
Выясним причину, по которой документы могут создаваться некорректно. Если мы используем ОбходРезультатаЗапроса.ПоГруппировкам, нам нужно на каждом уровне иерархии принимать решение о создании нового объекта. Посмотрим на правильную структуру вложенных циклов:
ВыборкаМесяц = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "КонецМесяцаРасчета");
Пока ВыборкаМесяц.Следующий() Цикл
// Для каждого месяца создаем отдельную операцию
Если СоздатьОперацию Тогда
НоваяОперация = Документы.ОперацияБух.СоздатьДокумент();
НоваяОперация.Дата = ВыборкаМесяц.КонецМесяцаРасчета;
НоваяОперация.Организация = Организация;
НоваяОперация.Содержание = "Начисление процентов за " + Формат(ВыборкаМесяц.КонецМесяцаРасчета, "ДФ='ММММ гггг'");
НоваяОперация.УстановитьНовыйНомер();
КонецЕсли;
ВыборкаКонтрагент = ВыборкаМесяц.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Контрагент");
Пока ВыборкаКонтрагент.Следующий() Цикл
ВыборкаДетали = ВыборкаКонтрагент.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
// Здесь выполняем расчет суммы процентов (алгоритм расчета зависит от условий договора)
СуммаПроцентов = РассчитатьПроценты(ВыборкаДетали.ОстатокДолга, ...);
Если СуммаПроцентов <> 0 Тогда
// Добавляем проводку в текущий документ месяца
Проводка = НоваяОперация.Движения.Хозрасчетный.Добавить();
Проводка.Период = ВыборкаМесяц.КонецМесяцаРасчета;
Проводка.Организация = Организация;
Проводка.Активность = Истина;
// Заполнение счетов и субконто
Проводка.СчетДт = ПланыСчетов.Хозрасчетный.ПрочиеРасчетыСРазнымиДебиторамиИКредиторами;
Проводка.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты] = ВыборкаДетали.Контрагент;
Проводка.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры] = ВыборкаДетали.Договор;
Проводка.СчетКт = ПланыСчетов.Хозрасчетный.ПрочиеДоходы;
Проводка.Сумма = СуммаПроцентов;
КонецЕсли;
КонецЦикла;
КонецЦикла;
// Записываем документ после того, как добавили все проводки за этот месяц
Если СоздатьОперацию Тогда
НоваяОперация.Записать();
НоваяОперация.Движения.Хозрасчетный.Записать();
КонецЕсли;
КонецЦикла;
Рассмотрим подробнее несколько критических моментов, которые часто упускают при разработке подобных обработок:
Дата самого документа и свойство Период в строках набора записей регистра бухгалтерии должны совпадать (или хотя бы находиться в пределах одного периода). Если вы установите дату документа 30 апреля, а проводку сделаете 28 февраля, это может вызвать проблемы при формировании отчетности и анализе движений.СуммаНУДт и СуммаНУКт. Обычно для прочих доходов они равны сумме бухгалтерского учета. Без их заполнения возникнут разрывы в налоговых декларациях.ДеньГода(КонецГода(Дата)) корректно, однако помните, что расчет процентов за февраль високосного года должен учитывать 29 дней в знаменателе формулы, если это предусмотрено учетной политикой или договором.Создание объектов в цикле — ресурсоемкая задача. Если количество контрагентов и месяцев велико, разберем способ ускорения работы. Вместо непосредственного создания документов в основном цикле обхода запроса, можно сначала собрать все данные в ТаблицуЗначений, сгруппировать их, и только затем запустить процедуру записи в транзакции. Это значительно сократит время блокировки таблиц базы данных.
Также важно помнить о методе УстановитьНовыйНомер(). Если его не вызвать, документы могут записаться с пустым номером, что нарушит нумерацию в системе. При установке даты документа всегда используйте функцию КонецМесяца() для кода на стороне сервера 1С, чтобы время документа было 23:59:59 — это стандарт для регламентных операций.
Таким образом, мы выяснили, что для решения задачи необходимо синхронизировать три составляющие: группировку в запросе по месяцам, создание экземпляра документа на каждую итерацию этой группировки и установку корректного периода для каждой проводки внутри документа.