Как рассчитать стоимость доставки по весу из табличной части документа в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Шаг 1. Получение общего веса из табличной части

Если вес указывается для каждой отдельной строки документа, перед определением итогового тарифа необходимо сложить значения по всей колонке. Для этого во встроенном языке 1С предназначен метод Итог().

Метод применяется напрямую к объекту табличной части и принимает в качестве параметра строковое имя колонки, по которой нужно получить сумму:


// Пример для модуля формы
Объект.ОбщийВес = Объект.ВидОтправления.Итог("Вес");

Обратите внимание на важные особенности работы с методом Итог():

  1. Тип данных реквизита: Колонка табличной части (в примере Вес) обязательно должна иметь числовой тип данных. Если тип реквизита составной или строковый, метод не сможет корректно выполнить суммирование.
  2. Контекст исполнения: Обращение вида Объект.ИмяТабличнойЧасти используется в модулях управляемых форм. Если расчет выполняется на стороне сервера в модуле объекта (например, в процедуре ОбработкаПроведения), обращение к табличной части происходит напрямую по имени реквизита или через ключевое слово ЭтотОбъект:

// Пример для модуля объекта
ОбщийВес = ЭтотОбъект.ВидОтправления.Итог("Вес");

Шаг 2. Корректное составление условий для диапазонов чисел

Проанализируем распространенную логическую ошибку при проверке вхождения числа в диапазон. Запись вида Объект.ОбщийВес > 1 <= 5 или ОбщийВес 1 5 10 <= 30 является синтаксически и логически некорректной.

Во встроенном языке 1С составные математические неравенства вычисляются последовательно слева направо. Выражение ОбщийВес > 1 сначала возвращает булево значение (Истина или Ложь). Далее платформа пытается сравнить полученное булево значение со следующим числом, неявно приводя Истина к 1, а Ложь к 0. В результате условие 1 <= 5 или 0 <= 5 всегда возвращает Истина, нарушая всю логику работы алгоритма.

Для правильной проверки диапазона необходимо явно разделять условия логическим оператором И:


Если ОбщийВес > 1 И ОбщийВес <= 5 Тогда
    Сумма = 50;
КонецЕсли;

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


Если ОбщийВес <= 1 Тогда
    Сумма = 25;
ИначеЕсли ОбщийВес <= 5 Тогда
    Сумма = 50;
ИначеЕсли ОбщийВес <= 30 Тогда
    Сумма = 189;
Иначе
    // Обработка веса свыше 30 кг
    Сумма = 250;
КонецЕсли;

Шаг 3. Отказ от сравнения по строковому наименованию

В исходном коде часто встречается условие проверки реквизитов по их названию: Объект.ЗонаДоставки.Наименование = "Междугородняя". Проверка по строкам считается плохой практикой в 1С по следующим причинам:

  1. Пользователь может изменить наименование элемента справочника в режиме предприятия (добавить пробел, исправить опечатку), после чего расчет перестанет работать.
  2. Сравнение строк чувствительно к регистру и символам в разных раскладках клавиатуры.

Для надежной фиксации условий используйте один из следующих подходов:

  1. Перечисления: Для фиксированных списков (например, скорость доставки: «Обычная», «Экспресс») используйте объект метаданных Перечисление. Сравнение выполняется через ссылку: Объект.СкоростьДоставки = Перечисления.СкоростиДоставки.Обычная.
  2. Предопределенные элементы: Для справочников создавайте предопределенные элементы и обращайтесь к ним по имени: Объект.ЗонаДоставки = Справочники.ЗоныДоставки.Междугородняя.

Итоговый пример функции расчета стоимости

Соберем все правила воедино и посмотрим на корректный пример реализации функции расчета стоимости:


Функция РассчитатьСтоимостьДоставки(ДокументОбъект) Экспорт

    // 1. Получаем суммарный вес по табличной части
    ОбщийВес = ДокументОбъект.ВидОтправления.Итог("Вес");
    
    // 2. Инициализируем базовое значение суммы
    Стоимость = 0;

    // 3. Проверяем параметры доставки и рассчитываем тариф
    Если ДокументОбъект.ЗонаДоставки = Справочники.ЗоныДоставки.Междугородняя 
        И ДокументОбъект.СкоростьДоставки = Перечисления.СкоростиДоставки.Обычная Тогда
        
        Если ОбщийВес <= 1 Тогда
            Стоимость = 25;
        ИначеЕсли ОбщийВес > 1 И ОбщийВес <= 5 Тогда
            Стоимость = 50;
        ИначеЕсли ОбщийВес > 5 И ОбщийВес <= 30 Тогда
            Стоимость = 189;
        Иначе
            Стоимость = 300;
        КонецЕсли;
        
    КонецЕсли;

    Возврат Стоимость;

КонецФункции

Архитектурная рекомендация: хранение тарифов в регистре сведений

Если шкала тарифов часто меняется, жестко прописывать числовые значения в коде через Если ... ИначеЕсли не рекомендуется. Оптимальным решением будет создание непериодического или периодического регистра сведений (например, ТарифыДоставки) со следующей структурой:

  1. Измерения: ЗонаДоставки (Справочник), СкоростьДоставки (Перечисление), ПорогВеса (Число).
  2. Ресурсы: Стоимость (Число).

В таком случае поиск цены под конкретный вес выполняется через простой запрос с условием ГДЕ ПорогВеса >= &ВесОтправления УПОРЯДОЧИТЬ ПО ПорогВеса ВОЗР и выборкой первой записи (ВЫБРАТЬ ПЕРВЫЕ 1). Это позволит пользователям гибко настраивать сетку тарифов в режиме «1С:Предприятие» без доработки конфигурации.

← На главную