File size: 2,657 Bytes
d904dd8
 
 
 
 
 
 
 
 
 
 
 
 
 
589c7cd
 
 
 
d904dd8
589c7cd
d904dd8
589c7cd
d904dd8
 
 
589c7cd
 
 
 
d904dd8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589c7cd
 
d904dd8
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
This module is used to calculate the split of the bill among people.

Author: Sarath Rajan S
Date: 26-01-2026
"""

def splitCalculator(receipt_data: dict, matched_items: list, final_amount_paid: float = None):
    """
    Calculates the split of the bill.
    1. Calculate Raw Individual Total
    2. Ratio = Individual Total / Raw Receipt Total
    3. Final Split = Ratio * Final Amount Paid
    """
    # The denominator for ratios should be the sum of all individual item costs being split.
    # This ensures that even if tax/service charge are not itemized, 
    # the total split will still add up to final_amount_paid proportionally.
    subtotal = sum(float(item.get("price", 0)) * int(item.get("quantity", 1)) for item in matched_items)
    
    # If final_amount_paid is not provided or zero, assume no discount/tax (subtotal is the total)
    if final_amount_paid is None or final_amount_paid <= 0:
        final_amount_paid = subtotal
        
    person_data = {} # {name: {"items": [], "raw_sum": 0}}
    
    # Avoid division by zero
    if subtotal == 0:
        return []
    
    for item in matched_items:
        iname = item.get("name", "Unknown")
        iprice = float(item.get("price", 0))
        iqty = int(item.get("quantity", 1))
        item_total = iprice * iqty
        people = item.get("people", [])
        
        if not people:
            people = ["Unassigned"]
            
        share = item_total / len(people)
        
        for person in people:
            if person not in person_data:
                person_data[person] = {"items": [], "raw_sum": 0}
            
            # Since items are now exploded in the matching phase, iqty is usually 1 here
            item_display = f"{iname} @ ${iprice}"
            if iqty > 1:
                item_display = f"{iname} (x{iqty}) @ ${iprice}"
                
            person_data[person]["items"].append(item_display)
            person_data[person]["raw_sum"] += share
            
    table_data = []
    for person, data in person_data.items():
        # Step: Ratio of person raw total vs subtotal
        ratio = data["raw_sum"] / subtotal if subtotal > 0 else 0
        
        # Step: Apply final amount paid based on that ratio
        final_cost = ratio * final_amount_paid
        
        table_data.append({
            "Person": person,
            "Items Consumed": "\n".join(data["items"]), # Multi-line string for "nested" look
            "Raw Share ($)": round(data["raw_sum"], 2),
            "Ratio (%)": f"{round(ratio * 100, 1)}%",
            "Final Split ($)": round(final_cost, 2)
        })
        
    return table_data