How dues are calculated¶
The bot computes a brother's owed amount per semester from four inputs:
member_due_cents = if assigned to a room → room.price_cents × share_fraction
else → semester.due_amount_cents
paid_cents = sum of active payments for that brother in that semester
deducted_cents = sum of active deductions for that brother in that semester
credited_cents = paid_cents + deducted_cents
owed_cents = max(member_due_cents - credited_cents, 0)
overpaid_cents = max(credited_cents - member_due_cents, 0)
"Active" means undone_at is null. Undoing a payment or deduction immediately removes it from totals.
All amounts are stored as integer cents in Mongo. Dollar conversion happens only at the human edges (Discord input/output, XLSX cells).
Worked examples¶
Assume /set_semester 400. Brothers A, B, C, D are onboarded.
Example 1 — non-resident, paid in full¶
Brother A doesn't live in the house. Pays $400 cash on Sep 5.
| Field | Value |
|---|---|
| Room | (none) |
member_due_cents |
40000 ($400) |
paid_cents |
40000 ($400) |
deducted_cents |
0 |
owed_cents |
0 |
Status: Paid up.
Example 2 — sole occupant of a $2000 room¶
Brother B is alone in Room 1 (/set_room "Room 1" 2000, /assign_room "Room 1" @b).
| Field | Value |
|---|---|
| Room | Room 1, share 1.0 |
member_due_cents |
200000 ($2000) — covers the flat $400 + $1600 of rent |
paid_cents |
50000 ($500 paid so far) |
owed_cents |
150000 ($1500) |
Note: B doesn't owe $400 + $2000. The room price already includes the dues. They owe $2000 total, period.
Example 3 — two brothers sharing a $2000 room¶
C and D share Room 2 (/set_room "Room 2" 2000, then /assign_room "Room 2" @c and /assign_room "Room 2" @d).
After the second /assign_room, the bot auto-rebalances both occupants to equal shares.
| Brother | Room | Share | Their due | Notes |
|---|---|---|---|---|
| C | Room 2 | 0.5 | $1000 | half of $2000 |
| D | Room 2 | 0.5 | $1000 | half of $2000 |
If C pays $400 and buys $200 of supplies (/deduct_dues @c 200 memo:"furniture"):
| Field | C's value |
|---|---|
member_due_cents |
100000 ($1000) |
paid_cents |
40000 ($400) |
deducted_cents |
20000 ($200) |
credited_cents |
60000 ($600) |
owed_cents |
40000 ($400) |
Example 4 — unequal split¶
D wants the bigger half of Room 2; C is fine paying less. Treasurer overrides:
| Brother | Share | Due |
|---|---|---|
| C | 0.4 | $800 |
| D | 0.6 | $1200 |
Sum still equals the full room price. The bot doesn't enforce that occupants of one room sum to 1.0 — you might have a 3rd brother joining mid-semester and want to leave room.
Example 5 — overpaid¶
Brother A from Example 1 keeps paying. After total $500 paid:
| Field | Value |
|---|---|
member_due_cents |
40000 |
paid_cents |
50000 |
owed_cents |
0 (clamped, can't be negative) |
overpaid_cents |
10000 ($100) |
Shown in /my_dues as a separate "Overpaid" field. Common for brothers who pay early for the next semester.
Edge cases¶
- Brother becomes a resident mid-semester —
/assign_roomflips theirmember_due_centsto room-based. Past payments still apply against the new (higher) total. They suddenly owe more than they paid. - Brother moves out mid-semester —
/unassign_roomflips them back to the flat$400. If they already overpaid the room amount, they're now massively overpaid against the flat amount. We don't auto-refund — that's a treasurer judgment call. - No active semester (summer gap) —
/log_paymentand/deduct_duesreject with "No active semester. Re-run after Fall starts." - Semester record exists but
due_amount_cents=0— happens if/set_semesterwas never run. All brothers show "owed: 0" with no error. Set the amount to fix.