Как корректно обрабатывать и хранить неметрические единицы измерения и высокоточные малые количества в спецификациях 1С?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Управленческий учет Промышленность, строительство и АПК
← На главную

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

Подход 1: Конвертация в более крупные базовые единицы или изменение масштаба

Первый и наиболее очевидный способ избежать проблем с высокой точностью десятичных дробей – это конвертировать значения в более крупные базовые единицы, если это возможно без потери смысла. Например, вместо хранения 0,000005 кг, мы можем конвертировать это значение в граммы: 0,000005 кг = 0,005 грамм. Это уменьшает количество знаков после запятой, делая число более удобным для обработки и хранения в 1С. Однако, как мы видим, даже после конвертации в граммы число может оставаться дробным и требовать дальнейшего внимания к точности.

Другой вариант, который иногда применяется в спецификациях, – это изменение масштаба спецификации. Например, вместо того, чтобы указывать пропорции на 1 изделие, мы могли бы создать спецификацию на 1000 изделий. Это позволяет нам умножить все мелкие количества на 1000, тем самым либо полностью избавившись от дробной части, либо значительно уменьшив количество знаков после запятой. Допустим, если на 1 изделие требуется 0,000005 кг компонента, то на 1000 изделий потребуется 0,005 кг или 5 грамм. В этом случае мы бы работали с более крупными и менее дробными числами.

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

Подход 2: Использование чисел с фиксированной запятой и настройка точности в 1С

В 1С:Предприятии для работы с числовыми значениями используется тип данных "Число", который представляет собой десятичные числа с фиксированной запятой (fixed-point decimal numbers). Это важное отличие от чисел с плавающей запятой, которое помогает избежать многих проблем с накоплением ошибок точности. Тип "Число" позволяет нам гибко настраивать параметры хранения:

  1. Общая длина числа (длина): Максимальное количество цифр, которое может содержать число (его целая и дробная часть вместе). В 1С это значение может достигать 38 цифр.
  2. Точность (количество знаков после запятой): Максимальное количество цифр, которые могут располагаться после десятичной запятой. Обычно, для большинства задач, используется до 10 знаков после запятой, хотя системно может быть и больше.

Мы можем настроить эти параметры для каждого числового реквизита в конфигураторе 1С. Для этого нам нужно открыть конфигуратор, перейти к нужному объекту (документу, справочнику, регистру) и выбрать реквизит. В его свойствах мы найдем тип данных Число, где сможем установить желаемые значения Длина и Точность. Например, если нам нужно хранить значения типа 0,000005 кг, где до запятой всегда 0, а после 6 знаков, мы можем установить Длина = 7 и Точность = 6 (1 цифра для целой части, 6 для дробной). Если целая часть может быть больше нуля, но мы знаем ее максимальную длину, например, 999 кг, то для 999,000005 кг нам потребуется Длина = 3 + 1 + 6 = 10 (3 для целой части, 1 для запятой, 6 для дробной) и Точность = 6.

Важно понимать: Хотя 1С:Предприятие внутренне оперирует числами с высокой точностью (до 38 значащих цифр в целом), фактическое хранение в базе данных может быть ограничено, и обычно рекомендуются настройки в пределах 10-15 знаков после запятой для дробной части, чтобы не перегружать СУБД и обеспечить адекватную производительность. Если требуется исключительная точность, превышающая стандартные возможности числового типа, мы можем рассмотреть следующие методы:

  1. Хранение множителей:

    Мы можем хранить число, умноженное на большой коэффициент (например, на 1 миллион или 1 миллиард), чтобы полностью избавиться от дробной части или значительно уменьшить количество знаков после запятой, при этом сохраняя абсолютную точность. Это позволяет нам работать с целыми числами, избегая любых проблем с точностью дробной части.

    Например, если у нас есть 0,000005 кг, мы можем умножить его на 1 000 000, получив 5. Тогда в реквизите Количество мы будем хранить 5, а в отдельном реквизите или предопределенной единице измерения будем знать, что это 5 * 10-6 кг (или 5 микрограмм). При отображении или использовании в расчетах нам потребуется выполнять обратное деление на этот коэффициент.

    Пример кода при работе с таким полем:

    
    // Допустим, в базе хранится 5 (единиц, где 1 единица = 1 микрограмм)
    // И нужно получить значение в килограммах
    КоличествоВКилограммах = КоличествоХранимаяВЕдиницах * 0.000001; 
            
    // Или наоборот, при записи:
    ИсходноеКоличествоВКилограммах = 0.000005;
    Коэффициент = 1000000;
    КоличествоДляХранения = ИсходноеКоличествоВКилограммах * Коэффициент; // Получим 5
    

    Этот метод требует аккуратности при каждом обращении к данным, но гарантирует точность на уровне целых чисел.

  2. Раздельное хранение целой и дробной части:

    В некоторых случаях мы можем хранить целую и дробную часть числа в двух отдельных числовых реквизитах. Например, один реквизит для целой части (КоличествоЦелое) и другой для дробной (КоличествоДробное), причем дробная часть может быть умножена на соответствующий коэффициент, чтобы стать целым числом. Например, для 0,000005 кг мы можем хранить КоличествоЦелое = 0 и КоличествоДробное = 5, подразумевая, что КоличествоДробное относится к единицам 10-6 кг.

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

  3. Хранение как строки:

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

    Однако этот способ наименее эффективен для математических операций. При необходимости вычислений нам придется каждый раз конвертировать строку в числовой формат (например, с помощью функции Число()) и обратно, что может быть ресурсоемким и замедлять работу системы, особенно при больших объемах данных. Мы бы использовали этот подход только в крайних случаях, когда другие варианты исчерпаны, и требуемая точность недостижима стандартными числовыми типами.

Подход 3: Реализация физических величин с двумя полями (значение и единица) и встроенные механизмы 1С

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

  1. Значение (число): Здесь хранится само численное значение.
  2. Единица измерения (ссылка на справочник): Ссылка на элемент справочника, который определяет, в каких единицах представлено данное значение.

Рассмотрим этот подход подробнее:

1. Создание справочника "Единицы измерения"

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

Пример структуры справочника ЕдиницыИзмерения:


// Справочник "ЕдиницыИзмерения"
// Реквизиты:
//     Наименование: Строка
//     КодОКЕИ: Строка (или ссылка на КлассификаторЕдиницИзмерения)
//     КоэффициентПересчетаКБазовой: Число (Длина 15, Точность 10)
//     БазоваяЕдиницаИзмерения: СправочникСсылка.ЕдиницыИзмерения
//     ТочностьПредставления: Число (Длина 2, Точность 0)
//
// Примеры элементов:
//     Наименование: "кг", КоэффициентПересчетаКБазовой: 1, БазоваяЕдиницаИзмерения: "кг"
//     Наименование: "г", КоэффициентПересчетаКБазовой: 0.001, БазоваяЕдиницаИзмерения: "кг"
//     Наименование: "шт", КоэффициентПересчетаКБазовой: 1, БазоваяЕдиницаИзмерения: "шт"
//     Наименование: "пары", КоэффициентПересчетаКБазовой: 2, БазоваяЕдиницаИзмерения: "шт"
//     Наименование: "бобины", КоэффициентПересчетаКБазовой: 1000, БазоваяЕдиницаИзмерения: "метр" (пример)

2. Использование полей "Значение" и "Единица" в спецификациях

В наших спецификациях (например, в табличной части документа или регистре сведений) мы будем хранить компоненты, используя эти два поля:

Когда нам нужно будет выполнить какие-либо расчеты (например, суммировать количество разных компонентов или пересчитать в другую единицу), мы всегда будем приводить все значения к их базовой единице измерения. Например, чтобы сложить 0,005 грамм и 0,000002 кг, мы сначала переведем оба значения в одну базовую единицу (например, килограммы):

  1. 0,005 грамм * (0,001 кг / 1 грамм) = 0,000005 кг.
  2. 0,000002 кг (уже в базовой единице).
  3. Сумма = 0,000005 кг + 0,000002 кг = 0,000007 кг.

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

Пример функции для конвертации количества в базовую единицу:


Функция ПолучитьКоличествоВБазовойЕдинице(Количество, ЕдиницаИзмеренияСсылка) Экспорт
    Если Количество = 0 Тогда
        Возврат 0;
    КонецЕсли;

    // Предполагаем, что у элемента справочника ЕдиницаИзмеренияСсылка
    // есть реквизит КоэффициентПересчетаКБазовой и БазоваяЕдиницаИзмерения
    // которые определяют правила пересчета.
    // Если БазоваяЕдиницаИзмерения - это сама ссылка, значит, она уже базовая.
    
    ПеременнаяЕдиница = ЕдиницаИзмеренияСсылка;
    Результат = Количество;
    
    // Цикл для пересчета через иерархию базовых единиц, если она есть
    Пока ПеременнаяЕдиница.БазоваяЕдиницаИзмерения <> ПеременнаяЕдиница И НЕ ПеременнаяЕдиница.БазоваяЕдиницаИзмерения.Пустая() Цикл
        Если ПеременнаяЕдиница.КоэффициентПересчетаКБазовой <> 0 Тогда
            Результат = Результат * ПеременнаяЕдиница.КоэффициентПересчетаКБазовой;
        Иначе
            // Ошибка: нулевой коэффициент пересчета
            Возврат Неопределено; 
        КонецЕсли;
        ПеременнаяЕдиница = ПеременнаяЕдиница.БазоваяЕдиницаИзмерения;
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

3. Встроенные механизмы 1С для учета единиц измерения

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

  1. Основная и дополнительные единицы измерения (в карточке номенклатуры):

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

    Например, если базовая единица для товара — "кг", мы можем создать дополнительную единицу "шт" и указать, что 1 "шт" = 0,010 "кг". Это позволяет приходовать товар в одних единицах (кг), продавать в других (шт) и видеть корректные остатки в отчетах. Все эти единицы должны быть занесены в стандартный справочник ЕдиницыИзмерения, который можно заполнить из Общероссийского классификатора единиц измерения (ОКЕИ).

    Пример настройки в карточке номенклатуры:

    
    // В форме элемента справочника "Номенклатура":
    //   ОсновнаяЕдиницаИзмерения: Ссылка на элемент справочника "ЕдиницыИзмерения" (например, "кг")
    //
    // Табличная часть "УпаковкиНоменклатуры" или аналогичная:
    //   ЕдиницаИзмерения: Ссылка на элемент справочника "ЕдиницыИзмерения" (например, "шт")
    //   КоэффициентПересчета: Число (например, 0.010, если 1 шт = 0.010 кг)
    
  2. Единицы измерения для отчетов:

    Некоторые конфигурации предоставляют возможность использования "единиц измерения для отчетов". Это позволяет нам анализировать остатки на складе и другие оперативные данные в различных разрезах, применяя коэффициенты к единице хранения. Например, если основная единица — килограммы, но для анализа иногда нужно видеть тонны, мы можем указать соответствующий коэффициент для единицы "тонна" и использовать ее в отчетах без фактического пересчета всех движений в базе данных.

Важное замечание: При использовании встроенных механизмов следует учитывать, что в некоторых конфигурациях (например, 1С:ERP) основной учет количеств ведется в единицах хранения. Упаковки и альтернативные единицы используются как способы представления количества, но все внутренние операции и остатки, как правило, опираются на базовую единицу хранения. Это означает, что если единица хранения - "кг", и мы имеем дело с 0,000005 кг, то именно это значение будет храниться как количество в этой единице.

Общие рекомендации и выводы

При решении задачи обработки высокоточных неметрических единиц в 1С мы рекомендуем следующий подход:

  1. Начните с настройки точности реквизитов:

    В большинстве случаев проблему "большого количества нулей после запятой" мы можем решить, увеличив точность соответствующего числового реквизита (например, Количество) в конфигураторе 1С. Убедитесь, что установленные значения Длина и Точность достаточны для ваших нужд.

  2. Используйте типовые механизмы для неметрических единиц:

    Для "шт", "пары", "бобины" и других неметрических единиц мы в первую очередь рассмотрим встроенные механизмы 1С: "Основная единица измерения", "Наборы упаковок" и "Дополнительные единицы измерения". Это наиболее простой и поддерживаемый способ. Важно корректно настроить коэффициенты пересчета к базовой единице хранения.

  3. Применяйте конвертацию в более крупные единицы:

    Если после настройки точности все равно остаются сложности (например, с представлением или вводом), мы можем рассмотреть конвертацию в более крупные базовые единицы (кг в г) или изменение масштаба спецификации, если это не противоречит бизнес-логике.

  4. Рассмотрите кастомную реализацию для максимальной гибкости:

    В самых сложных случаях, когда типовых механизмов или настройки точности недостаточно, и требуется очень гибкая система работы с единицами измерения и их пересчетом, мы можем реализовать систему с двумя полями: "Значение" + "Единица измерения", где "Единица измерения" будет ссылкой на наш собственный справочник с коэффициентами и правилами пересчета. Этот подход дает нам полный контроль над логикой.

  5. Будьте внимательны с данными при миграции:

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

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

← На главную