Из-за временных ограничений на территории РФ наблюдаются проблемы с оплатой. Если платёж не проходит, оставьте запрос в службу поддержки.Служба поддержки работает 24/7 — мы всегда на связи по вопросам хостинга и серверов.Открыт прием заявок на аренду выделенных серверов и размещение оборудования в дата-центре.Напоминаем: рекомендуем включить резервное копирование для дополнительной защиты данных.Доступна новая линейка VPS/VDS с NVMe-дисками и увеличенной производительностью.Технические работы на части серверов завершены. Все сервисы работают в штатном режиме.
Статья5 мин чтенияПросмотры0

Куда деть копейку при распределении скидки между товарами

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

Комментарии 0

Денис сравнивает три стопки монет и остаток: распределение скидки между строками заказа
В этой статье

У магазина скидка 100 рублей, у трёх строк заказа — по 33,33 рубля скидки. Сумма строк даёт 99,99. Потерялась одна копейка, хотя каждый результат округлён вполне разумно. Если получатель заново распределит скидку другим способом, обмен начнёт спорить с сохранённым заказом.

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

Сначала согласуйте единицу и момент округления

Внутри системы сумма может храниться целым числом минимальных единиц либо десятичным числом с заданной точностью. На границе API она может передаваться строкой с десятичной точкой. Тип, валюта и масштаб — часть контракта. Число 100 без этих условий недостаточно: оно может означать сто рублей или сто копеек.

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

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

Одна копейка на трёх строках

Возьмём учебный заказ: три разные строки, в каждой один товар стоимостью 200 рублей. Общая сумма до скидки — 600 рублей. Согласованная скидка на товары — 100 рублей; доставки, налоговых вычислений и других поправок в этой модели нет. Скидка распределяется пропорционально исходной стоимости, поэтому точные доли равны.

Перейдём к копейкам. Всего нужно распределить 10 000. Целая часть каждой доли составляет 3 333 копейки. После трёх назначений распределены 9 999 копеек, остаётся одна. Её можно отдать строке, выбранной заранее описанным правилом. Например, среди строк с равной дробной частью выигрывает наименьший устойчивый идентификатор строки.

Тогда скидки составят 33,34; 33,33; 33,33 рубля. Итоговые суммы строк — 166,66; 166,67; 166,67 рубля. Их сумма ровно 500 рублей, а скидка ровно 100. Другой заранее согласованный способ может выбрать другую строку; существенны сохранение общей суммы и воспроизводимость.

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

Скидка 100 рублей распределена как 33,34, 33,33 и 33,33; итоговые суммы трёх строк дают ровно 500 рублей
Учебный заказ: три строки по 200 рублей. Одна оставшаяся копейка назначается по заранее согласованному правилу.

Перестановка товаров не должна менять прошлый результат

Правило «добавим разницу последней строке» зависит от того, кто оказался последним. Сайт сортирует строки по добавлению, учётная система — по артикулу, доставка — по упаковке. На каждой стороне одна и та же копейка может переходить к другому товару. Общий итог будет сходиться, а построчная сверка — нет.

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

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

Возврат проверяет расчёт строже оплаты

Для учебного заказа покупатель возвращает строку с итогом 166,66 рубля. Если процесс предусматривает возврат её сохранённой оплаченной стоимости, пересчёт по нынешним трём равным долям даст уже другой ответ. Исходные суммы нужны именно потому, что состояние заказа и правила акции могли измениться.

При частичном возврате нескольких единиц одной строки возникает новый уровень распределения: сумма строки должна согласованно делиться между возвращаемыми и оставшимися единицами. В нашем примере по одной единице в строке, поэтому этот вопрос намеренно не решён. Также отдельно согласуют доставку, налоговые и кассовые документы; арифметический пример не устанавливает их правила.

При перестановке строк А, Б и В сохраняются утверждённые суммы 166,66, 166,67 и 166,67 рубля
Связь с устойчивым идентификатором сохраняет историю расчёта. Возврат сохранённой стоимости применим, если это предусмотрено процессом.

Для приёмки достаточно начать с конкретных инвариантов: сумма распределённых скидок равна утверждённой скидке; сумма итогов строк соответствует согласованному итогу товаров; повтор того же расчёта не меняет распределение; перестановка входных строк не меняет результат, если порядок не является условием договора.

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

Обсуждение 0

Делись опытом и задавай вопросы. Комментарии без ссылок появляются после проверки редактором.

Пока никто не написал. Начни обсуждение.