How to split an itemized bill when one dish wasn't shared
Split a $525 dinner equally and one person quietly pays $70 for a dish they never touched. The fix is one expense with two rules: name who ate the unshared line, and let tax follow consumption.
Split a $525 dinner equally and one person overpays $70. Two of the three ate the $200 seafood platter and the third did not, yet an equal split charges all three $175. Dimesum handles that bill as one expense: equal at the top, with the $200 line carried only by the two who ordered it.
Mostly-equal bills with one unshared line are the commonest thing a splitting app is asked to do, and Dimesum's first data model could not express one. The earlier design made ITEMIZED a split type, mutually exclusive with EQUAL, PERCENT and SHARES. A real restaurant bill is both at once.
Itemising is detail on an expense, not a different kind of split
An itemised expense in Dimesum is an ordinary expense that happens to carry its lines. The expense keeps everything expenses already have: a total, participants, a split type, one or several payers. To that it adds items, the lines of the bill, and adjustments, the tax, tip, fees and discounts printed underneath them.
Two levels then decide every cent. The expense's split type divides any line with nobody named on it. A line with assignees is carried by exactly those people, and by nobody else.
| Level | What it decides | Applies to |
|---|---|---|
| Expense split type | How a shared cost divides: equally, by percent, or by weighted shares | Every item with no assignees named |
| Item assignees | Who consumed this line, and in what proportion | That line only |
A $525 dinner where the person who ate least pays $105
Asha, Bhavna and Chetan eat dinner, split equally at the top. Shared plates come to $300. A seafood dish comes to $200, and only Asha and Bhavna ate it. Service is 5%, and Chetan paid the whole $525.
| Line | Amount | Asha | Bhavna | Chetan |
|---|---|---|---|---|
| Shared plates, no assignees | $300 | $100 | $100 | $100 |
| Seafood platter, Asha and Bhavna | $200 | $100 | $100 | $0 |
| Subtotal | $500 | $200 | $200 | $100 |
| Service 5%, by subtotal | $25 | $10 | $10 | $5 |
| Total | $525 | $210 | $210 | $105 |
Chetan paid $525 and owes $105, so he is owed $420: $210 from Asha and $210 from Bhavna. Who paid is orthogonal to who owes. The payer being the person who barely ate changes none of the shares, which is why Dimesum keeps payers at expense level and assignees at line level.
Tax follows what you ate, not how many of you there are
Chetan's share of the $25 service charge is $5, not $8.33. Every adjustment allocates in proportion to each person's item subtotal, so the 200:200:100 split of the food decides the split of the service charge as well. Allocating by headcount would quietly charge Chetan tax on a dish he never touched.
Someone who ordered nothing therefore pays no tax and receives no discount. The weights are the pre-adjustment subtotals rather than the running total, which also stops each adjustment's rounding from compounding into the next one's weights.
Adjustments apply in order, so a discount moves the GST base
A bill reading "$1,000, less 10%, plus 5% GST" charges GST on $900, and the GST line is $45. Reverse the two and GST is charged on $1,000, giving $50. Adjustments are an ordered list, and a percentage applies to the running total at its own position. Both orderings are real bills, so the list is ordered rather than a set.
Each adjustment carries its own position. An ordering that rested on insertion order, or on an id generator staying monotonic, would silently change what everyone owes after a database restore.
Three validations stand between a typo and the arithmetic. A pool states either a flat amount or a rate in basis points, never both, because storing both stores a number and its own derivation. A negative amount is refused, with an error naming DISCOUNT as the way to write a reduction. A rate above 100,000 basis points is refused as well, a cap set far above the 10,000 basis points that mean 100%, because a hundred percent off is a real discount.
| Kind | Effect on the running total | Why it is its own kind |
|---|---|---|
TAX | Adds | Wording only; identical to the calculation |
TIP | Adds | Wording only; identical to the calculation |
FEE | Adds | Wording only; identical to the calculation |
DISCOUNT | Subtracts | The only kind that changes the arithmetic, so the direction comes from the kind and never from a sign |
The total comes from the lines, and a typed total is only a checksum
An itemised total is derived: the sum of the items plus the sum of the adjustments. The lines already say what the bill costs, so a separately stated total would be a second source of truth that can disagree with the first. Somebody who mis-enters a bill fixes a line, which is where the mistake actually is, and the total follows. Correcting a bill that is already posted goes through an edit that restates its split, so the correction lands as a new version rather than as an overwrite.
A client may still send amount_minor, and Dimesum then treats it as a checksum rather than as the answer. Agreement means the client read the same bill. Disagreement stops the expense before any money moves.
An earlier version auto-added an "Other" line for whatever a stated total did not account for, and removed the line when the gap closed. That line worked, and it is gone. Deriving the total dissolved the problem the "Other" line existed to manage, which only arose because the total was stated twice.
Why EXACT and items are refused together
EXACT names each member's final amount. Items derive each member's amount. Both at once is over-determined: either they agree, in which case one is redundant, or they disagree, in which case the expense has two answers and no rule says which wins. Dimesum refuses the combination at the door rather than settling it with a precedence rule nobody would remember.
EQUAL, PERCENT and SHARES all combine with items, because each is a rule for dividing a shared cost rather than a set of final amounts.
Where a discount used to lose a cent
Every allocation uses the largest-remainder method, and each one conserves its own total exactly. Ties in that method used to go to the lowest member id, which handed the group's oldest member the extra cent on every equally split expense; the tie now rotates on a hash of the expense id. Shared lines are pooled and divided once rather than line by line, so the odd cent does not land on the same member for every line of the bill.
Our apportion function had a real defect here. Go's integer division truncates toward zero, so a negative total floored the wrong way and the leftover was never handed out: −$10.00 over weights of 100, 200 and 300 came back as −$9.99. A vanished cent would have made a correct discounted bill fail its own sum check, and the user would have been told their arithmetic was wrong. Negative totals are now apportioned by magnitude and negated back.
Enter the bill the way it is printed
Type the lines you can see, name the people who ate the ones that were not shared, and add the tax, tip, fee and discount in the order the receipt prints them. Dimesum derives the total, allocates each adjustment by what each person consumed, and leaves the payer out of it. Next time one dish costs twice what everyone else ordered, add it as its own line with two names on it.
Common questions
How do you split a restaurant bill when one person ordered something expensive?
Put that dish on its own line and name the people who ate it. In Dimesum the rest of the bill still divides by the expense's own rule, usually equally, while the named line is carried only by its assignees. Tax and service then allocate by each person's subtotal, so whoever skipped the dish pays less of both.
Should tax and tip be split equally or by what each person ordered?
By what each person ordered. Dimesum allocates every adjustment in proportion to each person's item subtotal rather than by headcount. In a $525 dinner where one person ate $100 of food, that person carries $5 of a $25 service charge instead of $8.33. Anyone who ordered nothing pays no tax at all.
Does the order of a discount and a tax change what the bill costs?
Yes. Adjustments apply in order against a running total, so a bill reading "$1,000, less 10%, plus 5% GST" charges the GST on $900 and the GST line is $45. Put the GST first and it is charged on $1,000, giving $50. With a flat $100 discount the totals differ as well, $945 against $950.
Why can't you use exact amounts on an itemised bill?
EXACT names each person's final amount and items derive it, so the two together give one expense two answers. Dimesum refuses the combination rather than picking a winner with a precedence rule nobody would remember. EQUAL, PERCENT and SHARES all work alongside items, because each is a rule for dividing shared lines rather than a set of final amounts.
Do you have to type the total of an itemised bill?
No. Dimesum derives an itemised total as the sum of the items plus the sum of the adjustments, because the lines already say what the bill costs. A total sent by a client is checked as a checksum, and a mismatch stops the expense before money moves. Correcting a wrong figure means correcting the line it came from.
Popular posts
- The append-only ledger that keeps split-expense balances exact6 min read
- Why editing a shared expense must restate the split5 min read
- Six money bugs in multi-currency expense splitting6 min read
- Settle up: how to clear group expenses in fewer transfers6 min read
- The rent split guide: divide rent with roommates fairly6 min read