@exhang

Скидка на чек, алгоритм разбиения?

Здравствуйте, есть у нас 54ФЗ, и есть чек вида:
Позиция    Кол-во   Цена  Сумма
Позиция1     3.8        98       372.4
Позиция2      1         4.5      4.5
Позиция3      6         88.2    529.2
Позиция4      1         180     180
Сумма чека: 1086.1


Как сделать скидку 86.1, что бы скидка была применена ко всем позициями (скидка на чек), при условии что в цене и сумме числа не могут быть больше 2ух знаков после запятой, так же можно разделять позиции на 2 части (позиция1 кол-во 1 цена n, сумма n, позиция1 кол-во 2.8 цена n, сумма n).
Может быть кто-то реализовывал такой алгоритм? Проблема в том что позиции всегда разные, цены, кол-во, а условие в 2 зн после запятой остается.
  • Вопрос задан
  • 554 просмотра
Решения вопроса 1
wataru
@wataru Куратор тега Алгоритмы
Разработчик на С++, экс-олимпиадник.
Во-первых, раз округления до второй цифры после запятой, умножте во время вычисления все суммы на 100 и считайте все копейках. Тогда округления будут до целых чисел - так проще.

Во-вторых, чтобы лучше смотрелось с начала примените процентную скидку ко всем ценам, округляя вверх.

Т.е. в вашем примере скидка должна быть 86.1/1086.1. В позиции1 цена будет 9800*(1-86.1/1086.1) = 9023.11 ~ 9024.

Для этого можно сделать
item.price = item.price - floor(item.price * discount / total )


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

Дальше можно брать позиции в каком-то порядке и убавлять их цену на 1 копейку. Если чек удешивился недостаточно - то продолжаем цикл. Если удешевили больше чем надо, то текущую позицию разбиваем на 2 позиции: одну с ценой на 1 копейку меньше, но с количеством, сколько осталось скинуть, вторую с изначальной ценой и остаточным количеством. Если чек удешевился как раз, то выходим из цикла. Это работает даже если количества дробные.

Что-то вроде:
leftover = ... # сколько осталось скинуть с чека
foreach item in items:
  if leftover == 0: break
  if item.count > leftover:
    new_item = item
    new_item.count = item.count - leftover
    item.count = leftover
    item.price -= 1
    items.add(new_item)
    break
  else:
    item.price -= 1
    leftover -= item.count


Есть, правда, один крайний случай. Что делать, если все товары стоят по 0.01 изначально? Можно ли скидывать товар до 0? Если можно, то этот алгоритм работает. Если нет, то такой чек вообще никак нельзя урезать.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
insighter
@insighter
-First time? - Huh? (C#, React, JS)
задачка несложная, решал
скидку раскидываете по строкам чека (например, пропорционально сумме строки),
получаете сумму строки чека со скидкой, потом вычисляете цену заново (разделив сумму со скидкой на кол-во),
обязательно округляете цену до копеек (всегда в меньшую сторону!!),

проводите все эти строки по фискальнику (вычисленная цена со скидкой * кол-во)
ну и в конце фокус, при введении 54ФЗ у фискальников пропала возможность делать уценки на чек - цену надо указывать с учетом скидки, но копеечные уценки делать можно, => делаете уценку на чек на кол-во копеек которые образовались из-за округление цены в меньшую сторону
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы