From 63ce035106841c9778fd5c5987b36549b204e5f1 Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Thu, 7 Apr 2022 10:02:30 +0200 Subject: Add expense delegation, transfers --- src/db.js | 21 +++++++++---- src/index.js | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 105 insertions(+), 13 deletions(-) diff --git a/src/db.js b/src/db.js index f97e9f0..e16c827 100644 --- a/src/db.js +++ b/src/db.js @@ -29,13 +29,14 @@ const write = async (obj) => { switch (obj.type) { case 'introduction': case 'expense': + case 'transfer': roomHash = _getHash(obj.roomId) db.data.rooms[roomHash] ||= { events: [] } db.data.rooms[roomHash].events.push(obj) break default: - throw new Error('Invalid type for db.write()') + throw new Error(`Invalid type "${obj.type}" for db.write()`) break } @@ -118,22 +119,30 @@ const getBalance = async (roomId) => { data.rooms[roomHash].events.forEach((event) => { switch (event.type) { case 'introduction': - balance.userIds.push(event.userId) - balance[event.userId] = { + balance.userIds.push(event.data.userId) + balance[event.data.userId] = { totalSpent: 0, spentForUserId: {}, + sentToUserId: {}, } break case 'expense': - balance[event.userId].totalSpent += event.data.amount + balance[event.data.from].totalSpent += event.data.amount balance.userIds.forEach((userId) => { - balance[event.userId].spentForUserId[userId] ||= 0 - balance[event.userId].spentForUserId[userId] += + balance[event.data.from].spentForUserId[userId] ||= 0 + balance[event.data.from].spentForUserId[userId] += event.data.amount / balance.userIds.length }) break + case 'transfer': + balance[event.data.from].totalSpent += event.data.amount + balance[event.data.from].sentToUserId[event.data.to] ||= 0 + balance[event.data.from].sentToUserId[event.data.to] += + event.data.amount + break + default: break } diff --git a/src/index.js b/src/index.js index dd92f9d..ae7cfe0 100644 --- a/src/index.js +++ b/src/index.js @@ -82,6 +82,11 @@ matrixClient.on('Room.timeline', async (event, room, toStartOfTimeline) => { let users = await db.getUsers(room.roomId) + let from + let to + let amount + let description + switch (command) { case 'h': case 'help': @@ -100,6 +105,16 @@ matrixClient.on('Room.timeline', async (event, room, toStartOfTimeline) => { '!e 42 Saturday market: describe the expense', '!e 42 Saturday market: describe the expense' ) + sendMessage( + room.roomId, + '!e @zaphod 42: delegate the expense', + '!e @zaphod 42: delegate the expense' + ) + sendMessage( + room.roomId, + '!e 10 @trillian: transfor to a fellow user', + '!e 10 @trillian: transfor to a fellow user' + ) sendMessage( room.roomId, '!b: get the balance', @@ -235,13 +250,9 @@ matrixClient.on('Room.timeline', async (event, room, toStartOfTimeline) => { case 'e': case 'exp': case 'expense': - let from - let amount - let description - if (users.includes(args[0])) { // Use delegated sender - from = parseFloat(args[0]) + from = args[0] amount = parseFloat(args[1]) description = args .slice(2) @@ -295,6 +306,76 @@ matrixClient.on('Room.timeline', async (event, room, toStartOfTimeline) => { }) break + case 't': + case 'transfer': + if (users.includes(args[0])) { + // Use delegated sender + from = args[0] + amount = parseFloat(args[1]) + to = args[2] + description = args + .slice(3) + .filter((a) => { + console.log(a, a[0]) + return a[0] !== '?' + }) + .join(' ') + } else { + // Use event sender + from = event.getSender() + amount = parseFloat(args[0]) + to = args[1] + description = args + .slice(2) + .filter((a) => { + console.log(a, a[0]) + return a[0] !== '?' + }) + .join(' ') + } + + // Check amount + if (!amount) { + sendMessage( + room.roomId, + '❌ That expense is invalid, need !help ?' + ) + return + } + + // Check recipient + if (!users.includes(to)) { + sendMessage( + room.roomId, + `❌ I don't know any "${to}", please try !users` + ) + return + } + + db.write({ + type: 'transfer', + timestamp: event.getDate(), + roomId: room.roomId, + userId: event.getSender(), + data: { + from: from, + to: to, + amount: amount, + currency: 'EUR', + description: description, + }, + }) + .then(() => { + sendMessage(room.roomId, '👍 Transfer noted') + }) + .catch((e) => { + sendMessage( + room.roomId, + `❌ Whoops, something went wrong (${e})` + ) + }) + break + case 'b': case 'balance': if (users.length === 0) { @@ -318,12 +399,14 @@ matrixClient.on('Room.timeline', async (event, room, toStartOfTimeline) => { const diff = (balance[userId2].spentForUserId[userId1] || 0) - - (balance[userId1].spentForUserId[userId2] || 0) + (balance[userId1].spentForUserId[userId2] || 0) + + (balance[userId2].sentToUserId[userId1] || 0) - + (balance[userId1].sentToUserId[userId2] || 0) sendMessage( room.roomId, `${userId1} ${ - diff > 0 ? '→' : '←' + diff == 0 ? '=' : diff > 0 ? '→' : '←' } ${userId2}: ${Math.abs(diff).toFixed(2)}` ) } -- cgit v1.2.3