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

Почему покупатель кладёт в корзину одну коробку, а платит как за штуку: разбор связки MEASURE, MEASURE_RATIO и коэффициента из 1С.

Дмитрий Мещеряков
Дмитрий Мещеряков
📅 26 октября 2026 г.📖 7 мин чтения

Товар продаётся коробками по двенадцать штук. В карточке — 120 рублей. Покупатель нажимает «в корзину», получает двенадцать штук и сумму 1440. Менеджер говорит, что коробка стоит 1200, и просит «убрать наценку».

Наценки нет. Есть три числа — цена, единица измерения и кратность, — которые приехали из 1С по разным маршрутам и не сошлись. Разбираться в этой связке приходится редко, зато каждый раз в режиме «клиенты платят не ту сумму».

Что такое кратность и единица измерения

Кратность — это шаг, которым покупатель меняет количество товара в корзине: при кратности 12 товар добавляется по двенадцать единиц, и кнопки «плюс» и «минус» двигают количество на двенадцать. Единица измерения — это то, в чём товар считается: штуки, метры, килограммы, литры. В Битриксе она хранится ссылкой на справочник, где у каждой единицы есть код по классификатору ОКЕИ: 796 — штука, 006 — метр, 166 — килограмм.

Два поля отвечают на два разных вопроса — «какими порциями продаём» и «в чём считаем», — и путаница между ними даёт большинство ошибок в этой области.

Эти вопросы независимы. Товар может измеряться в штуках и продаваться коробками по двенадцать: единица — штука, кратность — 12.

ТоварЕдиницаКратностьЧто видит покупатель
Смесительшт1Кнопки меняют количество по 1
Плиткам²1,44Количество кратно площади одной коробки
Саморезышт100Добавляется упаковками по 100
Кабельм1Любое число метров
💡 Совет

Цена всегда хранится за базовую единицу. Это главное, что нужно запомнить: кратность не меняет цену, она меняет количество. Товар с ценой 120 за штуку и кратностью 12 даёт в корзине 12 штук за 1440 — и это правильное поведение Битрикса, а не ошибка. Если бизнес считает, что коробка стоит 1200, значит, в 1С цена задана за упаковку, и чинить надо выгрузку.

Как это приезжает из 1С

Здесь и кроется корень проблемы: значения приезжают двумя независимыми путями, и Битрикс не сверяет их между собой.

Базовая единица — в товаре, в import.xml:

xml
<Товар>
  <Ид>f4e2c1a9-...</Ид>
  <Наименование>Саморез универсальный 3.5×25</Наименование>
  <БазоваяЕдиница Код="796" НаименованиеПолное="Штука">шт</БазоваяЕдиница>
</Товар>

Единица и коэффициент цены — в предложении, в offers.xml:

xml
<Предложение>
  <Ид>f4e2c1a9-...</Ид>
  <Цены>
    <Цена>
      <ИдТипаЦены>b2d4...</ИдТипаЦены>
      <ЦенаЗаЕдиницу>1.20</ЦенаЗаЕдиницу>
      <Валюта>RUB</Валюта>
      <Единица>шт</Единица>
      <Коэффициент>100</Коэффициент>
    </Цена>
  </Цены>
  <Количество>4800</Количество>
</Предложение>

Прочитаем эту выгрузку буквально: саморез стоит 1,20 рубля за штуку, продаётся упаковками по 100, на складе 4800 штук. Всё согласовано.

А теперь типичная поломка: в 1С менеджер поставил цену 120 — за упаковку, «так удобнее». Коэффициент остался 100. Битрикс честно посчитает 100 × 120 = 12 000 рублей за упаковку самореза.

⚠️ Важно

Битрикс не проверяет согласованность цены и коэффициента, и не может её проверить. Из чисел «цена 120, коэффициент 100» невозможно вывести, что имелось в виду. Обе трактовки арифметически корректны, разница в сто раз, и обнаруживается она только тогда, когда кто-то посмотрит на итог в корзине. Никакой настройки, которая бы это ловила, не существует — контроль возможен только на стороне 1С или отдельной проверкой на сайте.

Что лежит в базе

Проверка занимает один запрос через D7-ORM:

php
<?php
use Bitrix\Catalog\ProductTable;
use Bitrix\Catalog\MeasureTable;
use Bitrix\Main\Loader;

Loader::includeModule('catalog');

// Справочник единиц измерения: что вообще заведено
$measures = MeasureTable::getList([
    'select' => ['ID', 'CODE', 'MEASURE_TITLE', 'SYMBOL_RUS', 'IS_DEFAULT'],
])->fetchAll();

foreach ($measures as $m) {
    printf(
        "%3d  ОКЕИ %-5s %-16s %s\n",
        $m['ID'],
        $m['CODE'],
        $m['MEASURE_TITLE'],
        $m['IS_DEFAULT'] === 'Y' ? '(по умолчанию)' : ''
    );
}
php
<?php
// Товары с подозрительной кратностью — то, что стоит смотреть после каждого обмена
$rows = ProductTable::getList([
    'select' => ['ID', 'QUANTITY', 'MEASURE', 'MEASURE_RATIO'],
    'filter' => [
        'LOGIC' => 'OR',
        ['=MEASURE_RATIO' => 0],
        ['=MEASURE_RATIO' => null],
        ['>MEASURE_RATIO' => 1000],
    ],
    'limit' => 50,
])->fetchAll();

printf("Товаров с некорректной кратностью: %d\n", count($rows));
💡 Совет

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

Три сценария, которые ломаются

Цена за упаковку вместо цены за единицу

Разобран выше. Симптом — сумма в корзине кратно больше ожидаемой, ровно во столько раз, какова кратность.

Проверка на конкретном товаре:

bash
# Что приехало из 1С
grep -A 15 "f4e2c1a9" /home/site/www/upload/1c_catalog/offers.xml

Сверяем ЦенаЗаЕдиницу с ценой в базе и Коэффициент с MEASURE_RATIO. Совпало — вопрос к тому, что имелось в виду в 1С. Не совпало — вопрос к сопоставлению типов цен, разобранному в статье про цены из 1С.

Дробная кратность

Плитка продаётся коробками по 1,44 м². Кратность дробная, и на этом ломаются округления: покупатель набирает 10 коробок, получает 14,4 м², а витрина показывает 14 — или 14,40, или 14,4000 в зависимости от настроек вывода.

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

Кратность ноль

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

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

Как встроить проверку в обмен

Ручная сверка не масштабируется. Разумнее повесить контроль на завершение импорта — там, где положено делать всё тяжёлое, как разобрано в статье про производительность импорта:

php
<?php
use Bitrix\Catalog\ProductTable;
use Bitrix\Main\Loader;

/**
 * Проверка после обмена: ищем товары, у которых кратность выглядит
 * несогласованной с ценой. Пороги подбираются под свой ассортимент —
 * универсальных здесь нет.
 */
function auditMeasureRatio(int $iblockId): array
{
    Loader::includeModule('catalog');

    $suspicious = [];

    $rows = ProductTable::getList([
        'select' => ['ID', 'MEASURE_RATIO'],
        'filter' => [
            'LOGIC' => 'OR',
            ['=MEASURE_RATIO' => 0],
            ['=MEASURE_RATIO' => null],
        ],
    ]);

    while ($row = $rows->fetch()) {
        $suspicious[] = (int)$row['ID'];
    }

    return $suspicious;
}

Дальше список уходит письмом или в мессенджер. Смысл не в автоматическом исправлении — исправлять нужно в 1С, — а в том, чтобы узнать о проблеме раньше покупателя.

Что показывать покупателю

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

Работающий минимум:

  • подпись у поля количества: «упаковка 12 шт»;
  • цена за единицу и цена за упаковку рядом, а не одна вместо другой;
  • в корзине — и количество упаковок, и суммарное количество единиц.

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

Итоги

Единица измерения и кратность — разные поля, отвечающие на разные вопросы. «В чём считаем» и «какими порциями продаём». Их путают чаще всего.

Цена хранится за базовую единицу, всегда. Умножение на кратность — правильное поведение. Если бизнес ждёт другого, менять надо выгрузку в 1С.

Из 1С приезжают два независимых значения, и Битрикс не может проверить их согласованность: обе трактовки арифметически корректны.

Нулевая кратность — регулярно появляющийся мусор. Ищется одним запросом, проверять стоит после каждого обмена.

Дробная кратность работает, но требует контроля округлений во всех местах, где число превращается в деньги.

И наблюдение, которое экономит время в разговоре с бизнесом: жалоба «сайт считает неправильно» в этой области почти никогда не про сайт. Сайт считает ровно то, что ему передали. Разговор стоит начинать не с кода, а с вопроса «за что именно поставлена цена в 1С — за штуку или за упаковку», и в половине случаев на этом он и заканчивается.

Частые вопросы

Что такое кратность товара в Битриксе?

Это поле MEASURE_RATIO в карточке товара: шаг, которым покупатель меняет количество в корзине. Кратность 12 означает, что товар добавляется по 12 единиц и кнопки «плюс» и «минус» двигают количество на 12. Кратность не меняет цену — она остаётся ценой за базовую единицу измерения.

Чем кратность отличается от единицы измерения?

Единица измерения отвечает на вопрос «в чём считаем» — штуки, метры, килограммы, и хранится ссылкой на справочник с кодами ОКЕИ. Кратность отвечает на вопрос «какими порциями продаём». Товар может измеряться в штуках и продаваться коробками по 12: единица — штука, кратность — 12.

Почему цена в корзине не совпадает с ценой в карточке?

Чаще всего потому, что цена выгружается из 1С за упаковку, а Битрикс трактует её как цену за базовую единицу и умножает на кратность. В карточке видна цена за единицу, в корзине — умноженная на 12 или 24. Проверяется сверкой ЦеныЗаЕдиницу и Коэффициента в offers.xml с полями MEASURE_RATIO и ценой в базе.

Как единицы измерения приезжают из 1С?

Базовая единица товара идёт в import.xml и попадает в служебное свойство CML2_BASE_UNIT, а в блоке цены предложения отдельно приезжают Единица и Коэффициент. Это два независимых источника, и они не обязаны совпадать: в 1С товар может учитываться в штуках, а цена задаваться за упаковку. Битрикс не сверяет их между собой.

Что будет, если у товара кратность 0 или пустая?

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