E
E
exhang2020-08-29 12:01:59
Algorithms
exhang, 2020-08-29 12:01:59

Check discount, partitioning algorithm?

Hello, we have 54FZ, and there is a check of the form:

Позиция    Кол-во   Цена  Сумма
Позиция1     3.8        98       372.4
Позиция2      1         4.5      4.5
Позиция3      6         88.2    529.2
Позиция4      1         180     180
Сумма чека: 1086.1


How to make a discount 86.1, so that the discount would be applied to all positions (discount on the check), provided that the price and the amount of the number cannot exceed 2 decimal places, you can also divide the positions into 2 parts (position 1 quantity 1 price n, amount n, position1 quantity 2.8 price n, amount n).
Maybe someone implemented such an algorithm? The problem is that the positions are always different, prices, quantity, and the condition of 2 digits after the decimal point remains.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
W
Wataru, 2020-08-29
@exhang

First, once rounding to the second decimal place, multiply all amounts by 100 during the calculation and count all kopecks. Then rounding will be to integers - it's easier.
Second, to make it look better from the start, apply a percentage discount to all prices, rounding up.
Those. in your example the discount should be 86.1/1086.1. In position 1, the price will be 9800*(1-86.1/1086.1) = 9023.11 ~ 9024.
To do this, you can do

item.price = item.price - floor(item.price * discount / total )

After all such operations, you will have to deduct from the check the number of kopecks that does not exceed the total number of all positions. It is easy to find how many of them to subtract - calculate the amount of the check with new prices and subtract from it how much should be at the end (100000 in your example).
Then you can take positions in some order and reduce their price by 1 kopeck. If the check is not depreciated enough, then we continue the cycle. If we have reduced the price more than necessary, then we divide the current position into 2 positions: one with a price of 1 kopeck less, but with the amount left to throw off, the second with the original price and the remaining quantity. If the check has become cheaper, then we exit the cycle. This works even if the quantities are fractional.
Something like:
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

There is, however, one extreme case. What if all products cost 0.01 initially? Is it possible to drop an item to 0? If possible, then this algorithm works. If not, then such a check cannot be cut at all.

@
@insighter, 2020-09-11
_

the problem is simple, solve
the discount, scatter it over the lines of the check (for example, in proportion to the amount of the line),
get the amount of the check line with a discount, then calculate the price again (dividing the discounted amount by the quantity),
be sure to round the price to kopecks (always down! !),
spend all these lines on the fiscal (calculated price with a discount * quantity)
and at the end of the trick, with the introduction of 54FZ, the fiscals lost the opportunity to make markdowns on the check - the price must be indicated taking into account the discount, but penny markdowns can be done, => make a markdown on the check for the number of kopecks that were formed due to price rounding down

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question