Как в 1С 7.7 округлить цену со скидкой в меньшую сторону до 50 копеек и вывести в ценник?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

При подготовке печатных форм ценников часто возникает задача отобразить две цены: регулярную цену продажи и акционную цену с учетом скидки (например, 2% или 5%). Нередко маркетинг требует округлять цену со скидкой строго вниз с определенным шагом — например, до 50 копеек (чтобы в копейках оставалось только 00 или 50), а в самом макете ценника рубли и копейки должны располагаться в разных ячейках с разным размером шрифта.

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

Анализ проблемы и типичные ошибки

Попытки решить задачу «на скорую руку» часто приводят к нерабочему коду или некорректным ценам. Выясним причину основных проблем:

  1. Попытка вычислений прямо в ячейках таблицы. Вставка громоздких условий вида ?(((Число(ПечРубли)...) % 1) * 100 >= 50, "50", "00") прямо в свойства ячеек макета приводит к ошибкам округления, путанице с типами данных и невозможности отладки. Логику расчетов необходимо выносить в программный модуль.
  2. Особенности типовой функции глОкруглить. В типовых конфигурациях 1С 7.7 (в частности, в «Торговле и Склад 7.7») функция глОкруглить(Числ, ПорядокОкругления) жестко запрограммирована на округление вверх (к верхней границе диапазона). Использовать её для скидочной цены с округлением в меньшую сторону нельзя.
  3. Использование синтаксиса 1С 8. Конструкции вида РежимОкругления.Окр15как10 или РежимОкругления.Вниз отсутствуют в платформе 7.7. Встроенная функция Окр(Число, Разрядность, Способ) в «семерке» принимает третьим параметром только 0 или 1 и округляет только математически до степеней десяти (0.1, 0.01 и т.д.), но не умеет округлять до произвольного шага вроде 0.5.
  4. Ошибочное использование глФРМ в математических расчетах. Функция глФРМ() возвращает форматированную строку (с неразрывными пробелами и валютой). Передача её результата в операцию деления или функцию глОкруглить вызовет исключение «Операция деления не определена для строковых величин».

Математический алгоритм округления вниз с шагом 50 копеек

Рассмотрим, как правильно выполнить округление вниз (отсечение) с произвольным шагом. Общая формула округления к меньшему выглядит так:

Результат = Цел(ИсходноеЧисло / Шаг) * Шаг

Для шага 50 копеек (0.5 рубля) деление на 0.5 равносильно умножению на 2. Соответственно, алгоритм выглядит следующим образом:

ЦенаСоСкидкой = Цел(ИсходнаяЦена * 2) / 2

Посмотрим на практические примеры:

  1. 100.49 руб.: Цел(100.49 * 2) / 2 = Цел(200.98) / 2 = 200 / 2 = 100.00 руб.
  2. 100.50 руб.: Цел(100.50 * 2) / 2 = Цел(201.00) / 2 = 201 / 2 = 100.50 руб.
  3. 100.99 руб.: Цел(100.99 * 2) / 2 = Цел(201.98) / 2 = 201 / 2 = 100.50 руб.

Важное замечание о точности чисел с плавающей точкой: при расчете процента скидки (например, умножении на 0.98 при скидке 2%) в памяти может возникнуть погрешность представления вида 10.49999999999999. Если сразу применить функцию Цел(), число ошибочно округлится не до 50 копеек, а до нуля. Поэтому перед шаговым округлением промежуточную цену со скидкой обязательно нужно нормализовать до сотых с помощью стандартной функции Окр(..., 2).


// ВремЦена - исходная цена из документа (число)
ПромежуточнаяЦена = Окр(ВремЦена * 0.98, 2);
СкидкаЦена = Цел(ПромежуточнаяЦена * 2) / 2;

Разделение цены на рубли и копейки для макета

После получения точного числового значения скидочной цены разберем ее на две составляющие для раздельного вывода в печатную форму:


// Получаем целую часть (рубли)
СкидкаРубли = Цел(СкидкаЦена);

// Получаем копейки в виде двух символов ("00" или "50")
СкидкаКопейки = ?((СкидкаЦена - СкидкаРубли) > 0, "50", "00");

Реализация в коде модуля печати ценников

Проанализируем структуру типовой обработки печати ценников. В ней печать обычно выполняется через процедуру Печать(), которая в цикле вызывает процедуру формирования отдельной секции ДобавитьЦенник().

Если мы создадим локальные переменные внутри Печать(), они не будут видны в ячейках таблицы внутри ДобавитьЦенник(), что приведет к ошибке «Переменная не определена». Чтобы переменные были доступны секции макета, объявим их на уровне модуля через директиву Перем либо передадим параметрами.

Разберем рабочий вариант с объявлением переменных на уровне модуля:


// В самом начале модуля обработки (до процедур) объявляем переменные:
Перем ПечФирма;
Перем ПечРубли, ПечКопейки;
Перем СкидкаРубли, СкидкаКопейки; // Новые переменные для акционной цены

Теперь модифицируем цикл выборки строк в процедуре Печать():


Докум.ВыбратьСтроки();
Пока Докум.ПолучитьСтроку() = 1 Цикл
    Если ДокумВид = "ПереоценкаРозница" Тогда
        Если Докум.ЦенаСтарая = Докум.ЦенаНовая Тогда
            Продолжить;    
        КонецЕсли;
    КонецЕсли;
    
    ВремЦена = Докум.ПолучитьАтрибут(ИдРознЦена);    
    
    // 1. Формируем основную цену (без скидки)
    ПечРубли   = Цел(ВремЦена);
    ПечКопейки = Прав("00" + ((ВремЦена * 100) % 100), 2);
    
    // 2. Рассчитываем цену со скидкой 2% с округлением вниз до 50 коп.
    ЦенаСоСкидкой = Цел(Окр(ВремЦена * 0.98, 2) * 2) / 2;
    СкидкаРубли   = Цел(ЦенаСоСкидкой);
    СкидкаКопейки = ?((ЦенаСоСкидкой - СкидкаРубли) > 0, "50", "00");
    
    ПечРозн = глФРМ(ВремЦена);
    ПечНаименованиеТМЦ = СокрЛП(Докум.Номенклатура.ПолнНаименование);
    
    ДобавитьЦенник(Таб, Докум.Фирма, ПечНаименованиеТМЦ, Докум.Единица, ПечРозн, Столбик, Ряд, СокрЛП(Докум.Номенклатура.СтранаПроисхождения));
    глОживить(1);
КонецЦикла;

Настройка ячеек в табличном макете

Завершающий шаг — правильная привязка переменных к ячейкам макета ценника:

  1. Открываем визуальный редактор таблицы ценника (макет).
  2. Находим ячейки регулярной цены: в свойствах ячейки рублей указываем тип Выражение и пишем ПечРубли, в ячейке копеек — ПечКопейки.
  3. Находим ячейки цены со скидкой: удаляем из них старые длинные формулы.
  4. Для ячейки акционных рублей устанавливаем значение СкидкаРубли.
  5. Для ячейки акционных копеек устанавливаем значение СкидкаКопейки.

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

← На главную