mirror of
https://github.com/spliit-app/spliit.git
synced 2026-02-09 09:06:13 +01:00
Make recalculation stable across repayments in suggested reimbursements (#179)
* suggested reimbursements: make recalculation stable across repayments Previously, after a group participant executed a suggested reimbursement, rerunning getSuggestedReimbursements() could return a completely new list of suggestions. With this change, getSuggestedReimbursements() should now be stable: if it returns a graph with n edges, and then a repayment is made according to one of those edges, when called again, it should now return the same graph but with that one edge removed. The trick is that the main logic in getSuggestedReimbursements() does not rely on balancesArray being sorted based on .total values, only that the array gets partitioned into participants with credit first and then participants with debt last. After a repayment is made, re-sorting based on .total values would result in a new order hence new suggestions, but sorting based on usernames/participantIds should be unaffected. fixes https://github.com/spliit-app/spliit/issues/178 * Prettier --------- Co-authored-by: Sebastien Castiel <sebastien@castiel.me>
This commit is contained in:
@@ -82,13 +82,29 @@ export function getPublicBalances(reimbursements: Reimbursement[]): Balances {
|
||||
return balances
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparator that is stable across reimbursements.
|
||||
* This ensures that a participant executing a suggested reimbursement
|
||||
* does not result in completely new repayment suggestions.
|
||||
*/
|
||||
function compareBalancesForReimbursements(b1: any, b2: any): number {
|
||||
// positive balances come before negative balances
|
||||
if (b1.total > 0 && 0 > b2.total) {
|
||||
return -1
|
||||
} else if (b2.total > 0 && 0 > b1.total) {
|
||||
return 1
|
||||
}
|
||||
// if signs match, sort based on userid
|
||||
return b1.participantId < b2.participantId ? -1 : 1
|
||||
}
|
||||
|
||||
export function getSuggestedReimbursements(
|
||||
balances: Balances,
|
||||
): Reimbursement[] {
|
||||
const balancesArray = Object.entries(balances)
|
||||
.map(([participantId, { total }]) => ({ participantId, total }))
|
||||
.filter((b) => b.total !== 0)
|
||||
balancesArray.sort((b1, b2) => b2.total - b1.total)
|
||||
balancesArray.sort(compareBalancesForReimbursements)
|
||||
const reimbursements: Reimbursement[] = []
|
||||
while (balancesArray.length > 1) {
|
||||
const first = balancesArray[0]
|
||||
|
||||
Reference in New Issue
Block a user