Direct Settlement

This commit is contained in:
2026-09-30 22:51:10 +02:00
parent 642b3b9c68
commit 6800fc6c41
7 changed files with 51 additions and 5 deletions
@@ -48,8 +48,10 @@ import net.helcel.cowspent.model.Transaction
import net.helcel.cowspent.model.UserItem import net.helcel.cowspent.model.UserItem
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
import net.helcel.cowspent.util.SupportUtil import net.helcel.cowspent.util.SupportUtil
import net.helcel.cowspent.util.SupportUtil.SETTLE_DIRECT
import net.helcel.cowspent.util.SupportUtil.SETTLE_OPTIMAL import net.helcel.cowspent.util.SupportUtil.SETTLE_OPTIMAL
import net.helcel.cowspent.util.SupportUtil.settleBills import net.helcel.cowspent.util.SupportUtil.settleBills
import net.helcel.cowspent.util.SupportUtil.settleBillsDirect
@Composable @Composable
fun ProjectSettlementDialogContent( fun ProjectSettlementDialogContent(
@@ -60,10 +62,12 @@ fun ProjectSettlementDialogContent(
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {
val centerNoneStr = stringResource(R.string.center_none) val centerNoneStr = stringResource(R.string.center_none)
val centerDirectStr = stringResource(R.string.center_none_direct)
val memberList = remember(proj.id) { db.getMembersOfProject(proj.id, null) } val memberList = remember(proj.id) { db.getMembersOfProject(proj.id, null) }
val userList = remember(memberList, centerNoneStr) { val userList = remember(memberList, centerNoneStr, centerDirectStr) {
buildList { buildList {
add(UserItem(SETTLE_OPTIMAL, centerNoneStr)) add(UserItem(SETTLE_OPTIMAL, centerNoneStr))
add(UserItem(SETTLE_DIRECT, centerDirectStr))
addAll(memberList.map { UserItem(it.id, it.name) }) addAll(memberList.map { UserItem(it.id, it.name) })
} }
} }
@@ -91,8 +95,12 @@ fun ProjectSettlementDialogContent(
} }
val transactions = remember(selectedMemberId, membersBalance, membersSortedByName) { val transactions = remember(selectedMemberId, membersBalance, membersSortedByName) {
if (selectedMemberId == SETTLE_DIRECT) {
settleBillsDirect(membersSortedByName, db.getBillsOfProject(proj.id))
} else {
settleBills(membersSortedByName, membersBalance, selectedMemberId) settleBills(membersSortedByName, membersBalance, selectedMemberId)
} }
}
ProjectSettlementUI( ProjectSettlementUI(
transactions = transactions, transactions = transactions,
@@ -167,6 +167,39 @@ object SupportUtil {
} }
const val SETTLE_OPTIMAL: Long = 0 const val SETTLE_OPTIMAL: Long = 0
const val SETTLE_DIRECT: Long = -1
@JvmStatic
fun settleBillsDirect(members: List<DBMember>, bills: List<DBBill>): List<Transaction> {
val membersWeight = members.associate { it.id to it.weight }
// owed[debtor][creditor] = total the debtor owes the creditor over all bills
val owed = HashMap<Long, HashMap<Long, Double>>()
for (b in bills) {
if (b.state == DBBill.STATE_DELETED) continue
val nbOwerShares = b.billOwers.sumOf { membersWeight[it.memberId] ?: 0.0 }
if (nbOwerShares <= 0.0) continue
for (bo in b.billOwers) {
if (bo.memberId == b.payerId) continue
val share = b.amount / nbOwerShares * (membersWeight[bo.memberId] ?: 0.0)
val row = owed.getOrPut(bo.memberId) { HashMap() }
row[b.payerId] = (row[b.payerId] ?: 0.0) + share
}
}
val results: MutableList<Transaction> = ArrayList()
for (debtor in members) {
for (creditor in members) {
if (debtor.id == creditor.id) continue
val net = (owed[debtor.id]?.get(creditor.id) ?: 0.0) -
(owed[creditor.id]?.get(debtor.id) ?: 0.0)
if (round2(net) > 0.0) {
results.add(Transaction(debtor.id, creditor.id, round2(net)))
}
}
}
return results
}
@JvmStatic @JvmStatic
fun settleBills( fun settleBills(
@@ -209,6 +209,7 @@
<!-- Settlement --> <!-- Settlement -->
<string name="center_none">Keine (optimal)</string> <string name="center_none">Keine (optimal)</string>
<string name="center_none_direct">Keine (direkt)</string>
<string name="settle_who">Wer zahlt</string> <string name="settle_who">Wer zahlt</string>
<string name="settle_to_whom">An wen</string> <string name="settle_to_whom">An wen</string>
<string name="settle_how_much">Betrag</string> <string name="settle_how_much">Betrag</string>
@@ -210,6 +210,7 @@
<!-- Settlement --> <!-- Settlement -->
<string name="center_none">Ninguno (óptimo)</string> <string name="center_none">Ninguno (óptimo)</string>
<string name="center_none_direct">Ninguno (directo)</string>
<string name="settle_who">Quién paga</string> <string name="settle_who">Quién paga</string>
<string name="settle_to_whom">A quién</string> <string name="settle_to_whom">A quién</string>
<string name="settle_how_much">Importe</string> <string name="settle_how_much">Importe</string>
@@ -213,6 +213,7 @@
<!-- Settlement --> <!-- Settlement -->
<string name="center_none">Aucun (optimal)</string> <string name="center_none">Aucun (optimal)</string>
<string name="center_none_direct">Aucun (direct)</string>
<string name="settle_who">Qui paie</string> <string name="settle_who">Qui paie</string>
<string name="settle_to_whom">À qui</string> <string name="settle_to_whom">À qui</string>
<string name="settle_how_much">Montant</string> <string name="settle_how_much">Montant</string>
@@ -209,6 +209,7 @@
<!-- Settlement --> <!-- Settlement -->
<string name="center_none">Нет (оптимально)</string> <string name="center_none">Нет (оптимально)</string>
<string name="center_none_direct">Нет (напрямую)</string>
<string name="settle_who">Кто платит</string> <string name="settle_who">Кто платит</string>
<string name="settle_to_whom">Кому</string> <string name="settle_to_whom">Кому</string>
<string name="settle_how_much">Сумма</string> <string name="settle_how_much">Сумма</string>
+1
View File
@@ -247,6 +247,7 @@
<!-- Settlement --> <!-- Settlement -->
<string name="center_none">None (Optimal)</string> <string name="center_none">None (Optimal)</string>
<string name="center_none_direct">None (Direct)</string>
<string name="settle_who">Who pays</string> <string name="settle_who">Who pays</string>
<string name="settle_to_whom">To whom</string> <string name="settle_to_whom">To whom</string>
<string name="settle_how_much">Amount</string> <string name="settle_how_much">Amount</string>