File size: 4,526 Bytes
e69be74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75a9c52
eba303d
75a9c52
 
 
 
e69be74
 
 
 
 
 
4a10a29
e69be74
 
4a10a29
e69be74
 
4a10a29
 
e69be74
 
 
4a10a29
e69be74
75a9c52
4a10a29
e69be74
 
 
 
 
 
eba303d
 
 
e69be74
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import math
import copy

from algorithm.product import Product


def calculate_dish_price_with_taxes(_products, taxes, grand_total):
    payment_total = round(grand_total - taxes, 2)
    grand_total = round(payment_total, 2) + round(taxes, 2)
    _product_with_taxes = copy.deepcopy(_products)
    for _product in _product_with_taxes:
        _product.price = round(((_product.price / payment_total) * grand_total), 5)
    return _product_with_taxes, grand_total


def round_up_two_decimals(_products_total):
    _product_with_taxes_rounded = copy.deepcopy(_products_total)
    for _product in _product_with_taxes_rounded:
        _product.price = math.ceil(_product.price * 100) / 100

    return _product_with_taxes_rounded


def first_algorithm(_products_total_rounded, receipt_subtotal):
    current_total = 0
    for _product in _products_total_rounded:
        current_total += _product.price

    current_total = round(current_total, 2)

    difference = current_total - receipt_subtotal

    corrections = copy.deepcopy(_products_total_rounded)

    for _product in corrections:
        _product.price = round((_product.price / current_total) * difference, 2)

    for i in range(len(_products_total_rounded)):
        _products_total_rounded[i].price = round(_products_total_rounded[i].price - corrections[i].price, 2)

    _final_total = 0
    for _product in _products_total_rounded:
        _final_total += _product.price

    return _products_total_rounded, _final_total


def fractional_part_rest(value):
    fraction_str = f"{value:.10f}".split('.')[1]
    rest_of_digits = fraction_str[2:]
    return float(rest_of_digits)


def second_algorithm(_products_total, receipt_total):
    _products_total_rounded = round_up_two_decimals(_products_total)

    current_total = 0
    for _product in _products_total_rounded:
        current_total += _product.price

    if current_total == receipt_total:
        return _products_total_rounded, receipt_total

    difference = current_total - receipt_total
    difference = round(difference, 2)

    fractional_parts = copy.deepcopy(_products_total)

    for _product in fractional_parts:
        _product.price = fractional_part_rest(_product.price) - math.ceil(_product.price)

    fractional_parts = sorted(fractional_parts, key=lambda p: p.price, reverse=False)

    for i in range(len(fractional_parts)):
        if difference <= 0:
            break
        _products_total_rounded[i].price -= 0.01
        difference -= 0.01

    _final_total = 0
    for _product in _products_total_rounded:
        _final_total += _product.price

    for _product in _products_total_rounded:
        _product.price = round(_product.price, 2)

    return _products_total_rounded, _final_total


def clean_and_convert_to_float(price):
    if price == "": return 0.0
    clean_price = ''.join(c for c in str(price) if c.isdigit() or c in ",.")
    return float(clean_price.replace(",", "."))


def calculate_tips_and_taxes(items_table, total_amount, tax, tips):
    products = []

    if items_table[0][0] == "No items":
        return products, 0

    if total_amount == "Not specified" or total_amount == "unknown" or total_amount is None:
        total_amount = "0.0"

    if tax == "Not specified" or tax == "unknown" or tax is None:
        tax = "0.0"

    if tips == "Not specified" or tips == "unknown" or tips is None:
        tips = "0.0"

    for item in items_table:
        price = item[5]
        if price == "Not specified" or price == "unknown":
            price = "0.0"
        item_value = clean_and_convert_to_float(price) if item[5] is not None else 0.0
        products.append(Product(item[0], item_value))

    sum_of_product_prices = 0
    for _product in products:
        sum_of_product_prices += _product.price

    sum_of_product_prices = round(float(sum_of_product_prices), 2)
    total_amount = round(clean_and_convert_to_float(total_amount), 2)
    tips = round(clean_and_convert_to_float(tips), 2)
    tax = round(tips + round(clean_and_convert_to_float(tax), 2), 2)
    if round(float(total_amount), 2) != round(float(sum_of_product_prices) + float(tax), 2):
        return products, sum_of_product_prices

    products_total, subtotal = calculate_dish_price_with_taxes(products, taxes=float(tax),
                                                               grand_total=float(total_amount))
    final_prices, final_total = second_algorithm(products_total, subtotal)

    final_total = round(final_total, 2)
    return final_prices, final_total