Как правильно организовать цикл по количеству месяцев и рассчитать график платежей в 1С 7.7

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

Анализ типичных ошибок в коде

Разберем типичный фрагмент кода, в котором допущены сразу три распространенные ошибки при построении графика задолженности:

  1. Некорректное сложение дат: выражение ДатаДок + ДобавитьМесяц(ДатаДок, 1) ошибочно, так как функция ДобавитьМесяц() сама по себе возвращает полноценное значение типа Дата. Сложение двух дат в 1С 7.7 приводит к сложению их внутренних числовых представлений (юлианских дней), в результате чего получается дата из далекого будущего.
  2. Геометрическая прогрессия вместо шага: строка СуммаДолг = СуммаДолг + СуммаДолг удваивает значение на каждом шаге цикла вместо равномерного добавления ежемесячной доли.
  3. Неоптимальное использование цикла Пока: для фиксированного числа итераций (например, если количество месяцев задано числовым реквизитом на форме) цикл с предусловием усложняет код и может привести к бесконечному зацикливанию при ошибках в условиях выхода.

Решение 1. Использование фиксированного цикла «Для ... По»

Когда число повторений заранее известно и хранится в реквизите диалога Месяц (или мес), оптимальным решением является использование цикла Для со счетчиком. Проанализируем правильный вариант построения модуля формирования печатной формы:


Процедура СформироватьГрафик()
    // Проверяем корректность введенного количества месяцев
    Если (ПустоеЗначение(Месяц) = 1) Или (Месяц <= 0) Тогда
        Предупреждение("Укажите корректное количество месяцев!");
        Возврат;
    КонецЕсли;

    Таб = СоздатьОбъект("Таблица");
    Таб.ИсходнаяТаблица("Сформировать");

    ДатаДок = ТекущаяДата();
    НазваниеОрганизации = Константа.ЗаголовокДляСоглашения;

    Контрагент = Контр.Наименование;
    Паспорт = Контр.ПаспортныеДанные;
    АдресК = Контр.Адрес;
    Сумма = Контр.СуммаДолга;

    Таб.ВывестиСекцию("Шапка");

    // Рассчитываем базовый ежемесячный платеж
    СуммаМес = Окр(Сумма / Месяц, 2);
    Накоплено = 0;

    Для НомерМесяца = 1 По Месяц Цикл
        // Корректно смещаем дату на нужное число месяцев вперед
        ДатаМесяца = ДобавитьМесяц(ДатаДок, НомерМесяца);

        // В последнем месяце учитываем возможную погрешность округления копеек
        Если НомерМесяца = Месяц Тогда
            ТекущийПлатеж = Сумма - Накоплено;
        Иначе
            ТекущийПлатеж = СуммаМес;
            Накоплено = Накоплено + ТекущийПлатеж;
        КонецЕсли;

        Таб.ВывестиСекцию("Долг");
    КонецЦикла;

    Таб.ТолькоПросмотр(1);
    Таб.Показать("График платежей");
КонецПроцедуры

Решение 2. Использование цикла «Пока» с корректным шагом

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


СуммаМес = Окр(Сумма / Месяц, 2);
СуммаДолг = 0;
НомерШага = 1;

Пока СуммаДолг < Сумма Цикл
    ДатаМесяца = ДобавитьМесяц(ДатаДок, НомерШага);
    
    Если (СуммаДолг + СуммаМес) > Сумма Тогда
        ТекущийПлатеж = Сумма - СуммаДолг;
    Иначе
        ТекущийПлатеж = СуммаМес;
    КонецЕсли;
    
    СуммаДолг = СуммаДолг + ТекущийПлатеж;
    
    Таб.ВывестиСекцию("Долг");
    НомерШага = НомерШага + 1;
КонецЦикла;

Практические рекомендации по работе с датами и суммами в 1С 7.7

  1. Контроль деления на ноль: перед операцией деления Сумма / Месяц всегда делайте проверку значения реквизита. Если реквизит диалога пуст или равен нулю, 1С 7.7 аварийно завершит выполнение с системной ошибкой.
  2. Особенности функции ДобавитьМесяц: данная функция автоматически учитывает разное количество дней в месяцах и високосные годы. Смещение на 1 месяц от 31.01 корректно вернет 28.02 (или 29.02). Чтобы привязать платеж к строго первому или последнему числу, комбинируйте вызов с функциями НачМесяца() или КонМесяца().
  3. Отображение таблицы: после вывода секций методами Таб.ВывестиСекцию() печатная форма не отображается на экране сама. Обязательно вызывайте Таб.Показать(), а для запрета случайных правок пользователем используйте Таб.ТолькоПросмотр(1).
← На главную