@zeeshan60/event-processor 1.0.48 → 1.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/ActivityEventHandler.d.ts.map +1 -1
  2. package/dist/ActivityEventHandler.js +3 -7
  3. package/dist/ActivityEventHandler.js.map +1 -1
  4. package/dist/EventProcessorSDK.d.ts +8 -0
  5. package/dist/EventProcessorSDK.d.ts.map +1 -1
  6. package/dist/EventProcessorSDK.js +24 -2
  7. package/dist/EventProcessorSDK.js.map +1 -1
  8. package/dist/GroupEventHandler.d.ts +6 -11
  9. package/dist/GroupEventHandler.d.ts.map +1 -1
  10. package/dist/GroupEventHandler.js +42 -359
  11. package/dist/GroupEventHandler.js.map +1 -1
  12. package/dist/GroupEvents.d.ts +10 -28
  13. package/dist/GroupEvents.d.ts.map +1 -1
  14. package/dist/GroupEvents.js +11 -55
  15. package/dist/GroupEvents.js.map +1 -1
  16. package/dist/GroupTransactionEventHandler.d.ts +6 -12
  17. package/dist/GroupTransactionEventHandler.d.ts.map +1 -1
  18. package/dist/GroupTransactionEventHandler.js +46 -39
  19. package/dist/GroupTransactionEventHandler.js.map +1 -1
  20. package/dist/GroupTransactionEvents.d.ts +29 -157
  21. package/dist/GroupTransactionEvents.d.ts.map +1 -1
  22. package/dist/GroupTransactionEvents.js +25 -307
  23. package/dist/GroupTransactionEvents.js.map +1 -1
  24. package/dist/TransactionEvents.d.ts.map +1 -1
  25. package/dist/TransactionEvents.js.map +1 -1
  26. package/dist/UserEvents.d.ts.map +1 -1
  27. package/dist/UserEvents.js +1 -0
  28. package/dist/UserEvents.js.map +1 -1
  29. package/dist/__tests__/test-helpers/IMFriendModelStore.d.ts +2 -0
  30. package/dist/__tests__/test-helpers/IMFriendModelStore.d.ts.map +1 -1
  31. package/dist/__tests__/test-helpers/IMFriendModelStore.js +20 -0
  32. package/dist/__tests__/test-helpers/IMFriendModelStore.js.map +1 -1
  33. package/dist/__tests__/test-helpers/IMGroupModelStore.d.ts +1 -0
  34. package/dist/__tests__/test-helpers/IMGroupModelStore.d.ts.map +1 -1
  35. package/dist/__tests__/test-helpers/IMGroupModelStore.js +9 -0
  36. package/dist/__tests__/test-helpers/IMGroupModelStore.js.map +1 -1
  37. package/dist/__tests__/test-helpers/IMGroupTransactionModelStore.d.ts +1 -0
  38. package/dist/__tests__/test-helpers/IMGroupTransactionModelStore.d.ts.map +1 -1
  39. package/dist/__tests__/test-helpers/IMGroupTransactionModelStore.js +11 -0
  40. package/dist/__tests__/test-helpers/IMGroupTransactionModelStore.js.map +1 -1
  41. package/dist/__tests__/test-helpers/IMUserModelStore.d.ts +1 -0
  42. package/dist/__tests__/test-helpers/IMUserModelStore.d.ts.map +1 -1
  43. package/dist/__tests__/test-helpers/IMUserModelStore.js +10 -0
  44. package/dist/__tests__/test-helpers/IMUserModelStore.js.map +1 -1
  45. package/dist/client/controllers/ExpenseAccountController.d.ts +2 -1
  46. package/dist/client/controllers/ExpenseAccountController.d.ts.map +1 -1
  47. package/dist/client/controllers/ExpenseAccountController.js +43 -51
  48. package/dist/client/controllers/ExpenseAccountController.js.map +1 -1
  49. package/dist/client/controllers/ExpenseController.d.ts.map +1 -1
  50. package/dist/client/controllers/ExpenseController.js +11 -0
  51. package/dist/client/controllers/ExpenseController.js.map +1 -1
  52. package/dist/client/controllers/FriendController.d.ts.map +1 -1
  53. package/dist/client/controllers/FriendController.js +14 -0
  54. package/dist/client/controllers/FriendController.js.map +1 -1
  55. package/dist/client/controllers/GroupController.d.ts +21 -0
  56. package/dist/client/controllers/GroupController.d.ts.map +1 -0
  57. package/dist/client/controllers/GroupController.js +262 -0
  58. package/dist/client/controllers/GroupController.js.map +1 -0
  59. package/dist/client/controllers/GroupTransactionController.d.ts +23 -0
  60. package/dist/client/controllers/GroupTransactionController.d.ts.map +1 -0
  61. package/dist/client/controllers/GroupTransactionController.js +172 -0
  62. package/dist/client/controllers/GroupTransactionController.js.map +1 -0
  63. package/dist/client/controllers/TransactionController.d.ts.map +1 -1
  64. package/dist/client/controllers/TransactionController.js +14 -2
  65. package/dist/client/controllers/TransactionController.js.map +1 -1
  66. package/dist/client/controllers/UserController.d.ts.map +1 -1
  67. package/dist/client/controllers/UserController.js +15 -1
  68. package/dist/client/controllers/UserController.js.map +1 -1
  69. package/dist/common/EventTypes.d.ts +2 -9
  70. package/dist/common/EventTypes.d.ts.map +1 -1
  71. package/dist/common/EventTypes.js +2 -9
  72. package/dist/common/EventTypes.js.map +1 -1
  73. package/dist/contracts/groups/index.d.ts +13 -1
  74. package/dist/contracts/groups/index.d.ts.map +1 -1
  75. package/dist/converters/GroupConverters.d.ts +4 -10
  76. package/dist/converters/GroupConverters.d.ts.map +1 -1
  77. package/dist/converters/GroupConverters.js +5 -28
  78. package/dist/converters/GroupConverters.js.map +1 -1
  79. package/dist/converters/GroupTransactionConverters.d.ts +4 -40
  80. package/dist/converters/GroupTransactionConverters.d.ts.map +1 -1
  81. package/dist/converters/GroupTransactionConverters.js +33 -154
  82. package/dist/converters/GroupTransactionConverters.js.map +1 -1
  83. package/dist/converters/eventConverter.d.ts.map +1 -1
  84. package/dist/converters/eventConverter.js +4 -18
  85. package/dist/converters/eventConverter.js.map +1 -1
  86. package/dist/index.d.ts +4 -2
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +6 -1
  89. package/dist/index.js.map +1 -1
  90. package/dist/store/FriendModelStore.d.ts +2 -0
  91. package/dist/store/FriendModelStore.d.ts.map +1 -1
  92. package/dist/store/GroupModelStore.d.ts +1 -0
  93. package/dist/store/GroupModelStore.d.ts.map +1 -1
  94. package/dist/store/GroupTransactionModelStore.d.ts +1 -0
  95. package/dist/store/GroupTransactionModelStore.d.ts.map +1 -1
  96. package/dist/store/UserModelStore.d.ts +1 -0
  97. package/dist/store/UserModelStore.d.ts.map +1 -1
  98. package/dist/utils/ActivityUtil.d.ts +3 -0
  99. package/dist/utils/ActivityUtil.d.ts.map +1 -0
  100. package/dist/utils/ActivityUtil.js +15 -0
  101. package/dist/utils/ActivityUtil.js.map +1 -0
  102. package/dist/utils/BalanceUtil.d.ts +1 -0
  103. package/dist/utils/BalanceUtil.d.ts.map +1 -1
  104. package/dist/utils/BalanceUtil.js +40 -0
  105. package/dist/utils/BalanceUtil.js.map +1 -1
  106. package/dist/utils/GroupUtil.d.ts +29 -0
  107. package/dist/utils/GroupUtil.d.ts.map +1 -0
  108. package/dist/utils/GroupUtil.js +762 -0
  109. package/dist/utils/GroupUtil.js.map +1 -0
  110. package/package.json +3 -1
@@ -0,0 +1,762 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processGroupEventForPerspectives = processGroupEventForPerspectives;
4
+ exports.generateFriendEventsForMissingFriendships = generateFriendEventsForMissingFriendships;
5
+ exports.generateGroupPerspectiveEvents = generateGroupPerspectiveEvents;
6
+ exports.processGroupTransactionEventForPerspectives = processGroupTransactionEventForPerspectives;
7
+ exports.calculateDebtsForMember = calculateDebtsForMember;
8
+ exports.generatePerspectiveEvents = generatePerspectiveEvents;
9
+ exports.generateTransactionEventsForGroupTransactionModel = generateTransactionEventsForGroupTransactionModel;
10
+ exports.buildYouPaidSplitEquallyEvent = buildYouPaidSplitEquallyEvent;
11
+ exports.buildTheyPaidSplitEquallyEvent = buildTheyPaidSplitEquallyEvent;
12
+ exports.buildSpecificAmountsEvent = buildSpecificAmountsEvent;
13
+ exports.toGroupTransactionResponse = toGroupTransactionResponse;
14
+ const __1 = require("..");
15
+ const EventTypes_1 = require("../common/EventTypes");
16
+ const uuid_1 = require("uuid");
17
+ const splitTypeUtils_1 = require("./splitTypeUtils");
18
+ function processGroupEventForPerspectives(event, existingGroupModels, friendModelsByUserId, existingUsersInGroup) {
19
+ console.log(`[Debug] processGroupEventForPerspectives: eventType=${event.eventType}, userId=${event.userId}, streamId=${event.streamId}`);
20
+ console.log(`[Debug] processGroupEventForPerspectives: existingGroupModels.size=${existingGroupModels.size}, existingUsersInGroup.length=${existingUsersInGroup.length}`);
21
+ console.log(`[Debug] processGroupEventForPerspectives: existingGroupModels keys=${JSON.stringify([...existingGroupModels.keys()])}`);
22
+ const groupEventsToSave = [];
23
+ const friendEventsToSave = [];
24
+ const groupModelsToSave = [];
25
+ const friendModelsToSave = [];
26
+ const perspectiveEvents = generateGroupPerspectiveEvents(event, existingGroupModels);
27
+ console.log(`[Debug] processGroupEventForPerspectives: generated ${perspectiveEvents.length} perspective events`);
28
+ for (const perspectiveEvent of perspectiveEvents) {
29
+ const existingPerspective = existingGroupModels.get(perspectiveEvent.userId);
30
+ const perspectiveModel = perspectiveEvent.apply(existingPerspective);
31
+ groupModelsToSave.push(perspectiveModel);
32
+ groupEventsToSave.push(perspectiveEvent);
33
+ const friendModels = friendModelsByUserId[perspectiveModel.userId] ?? [];
34
+ const friendModelsByStreamId = new Map(friendModels.map((f) => [f.streamId, f]));
35
+ const friendEvents = generateFriendEventsForMissingFriendships(perspectiveModel, friendModels, existingUsersInGroup);
36
+ for (const friendEvent of friendEvents) {
37
+ const existingFriendModel = friendModelsByStreamId.get(friendEvent.streamId);
38
+ const friendModel = friendEvent.apply(existingFriendModel);
39
+ friendModelsToSave.push(friendModel);
40
+ friendEventsToSave.push(friendEvent);
41
+ }
42
+ }
43
+ console.log(`[Debug] processGroupEventForPerspectives: returning groupEventsToSave.length=${groupEventsToSave.length}, friendEventsToSave.length=${friendEventsToSave.length}`);
44
+ console.log(`[Debug] processGroupEventForPerspectives: returning groupModelsToSave.length=${groupModelsToSave.length}, friendModelsToSave.length=${friendModelsToSave.length}`);
45
+ return {
46
+ groupEventsToSave,
47
+ friendEventsToSave,
48
+ groupModelsToSave,
49
+ friendModelsToSave,
50
+ };
51
+ }
52
+ function generateFriendEventsForMissingFriendships(groupModel, friendModels, existingUsersInGroup) {
53
+ console.log(`[Debug] generateFriendEventsForMissingFriendships: groupModel.userId=${groupModel.userId}, groupModel.groupId=${groupModel.groupId}`);
54
+ console.log(`[Debug] generateFriendEventsForMissingFriendships: friendModels.length=${friendModels.length}, existingUsersInGroup.length=${existingUsersInGroup.length}`);
55
+ console.log(`[Debug] generateFriendEventsForMissingFriendships: groupModel.members=${JSON.stringify(groupModel.members)}`);
56
+ const events = [];
57
+ const memberIds = groupModel.members ?? [];
58
+ // Separate active and deleted friend models by friendId
59
+ const activeFriendIds = new Set();
60
+ const deletedFriendsByFriendId = new Map();
61
+ for (const friendModel of friendModels) {
62
+ if (!friendModel.friendId)
63
+ continue;
64
+ if (friendModel.deleted) {
65
+ deletedFriendsByFriendId.set(friendModel.friendId, friendModel);
66
+ }
67
+ else {
68
+ activeFriendIds.add(friendModel.friendId);
69
+ }
70
+ }
71
+ // Create a map of user data by userId for quick lookup
72
+ const userDataMap = new Map();
73
+ for (const user of existingUsersInGroup) {
74
+ userDataMap.set(user.userId, user);
75
+ }
76
+ // Generate friend events for members not already active friends (excluding current user)
77
+ for (const memberId of memberIds) {
78
+ if (memberId === groupModel.userId) {
79
+ continue;
80
+ }
81
+ if (activeFriendIds.has(memberId)) {
82
+ continue;
83
+ }
84
+ const userData = userDataMap.get(memberId);
85
+ if (!userData) {
86
+ console.warn(`[generateFriendEventsForMissingFriendships] User data not found for memberId: ${memberId}`);
87
+ continue;
88
+ }
89
+ const deletedFriend = deletedFriendsByFriendId.get(memberId);
90
+ if (deletedFriend) {
91
+ // Restore deleted friend with FriendUnDeleted
92
+ events.push(new __1.FriendUnDeleted({
93
+ eventId: (0, uuid_1.v4)(),
94
+ userId: groupModel.userId,
95
+ friendEmail: userData.email,
96
+ friendPhoneNumber: userData.phoneNumber,
97
+ friendDisplayName: userData.displayName,
98
+ photoUrl: userData.photoUrl,
99
+ createdAt: new Date(),
100
+ createdBy: groupModel.userId,
101
+ streamId: deletedFriend.streamId,
102
+ version: deletedFriend.version + 1,
103
+ systemGenerated: true,
104
+ }));
105
+ }
106
+ else {
107
+ // Create new friend with FriendCreated
108
+ events.push(new __1.FriendCreated({
109
+ eventId: (0, uuid_1.v4)(),
110
+ userId: groupModel.userId,
111
+ friendId: memberId,
112
+ friendEmail: userData.email,
113
+ friendPhoneNumber: userData.phoneNumber,
114
+ friendDisplayName: userData.displayName,
115
+ photoUrl: userData.photoUrl,
116
+ groupId: groupModel.groupId,
117
+ createdAt: new Date(),
118
+ createdBy: groupModel.userId,
119
+ streamId: (0, uuid_1.v4)(),
120
+ version: 1,
121
+ systemGenerated: true,
122
+ }));
123
+ }
124
+ }
125
+ console.log(`[Debug] generateFriendEventsForMissingFriendships: returning ${events.length} friend events`);
126
+ return events;
127
+ }
128
+ function generateGroupPerspectiveEvents(clientEvent, existingGroupModels) {
129
+ console.log(`[Debug] generateGroupPerspectiveEvents: eventType=${clientEvent.eventType}, userId=${clientEvent.userId}, streamId=${clientEvent.streamId}`);
130
+ console.log(`[Debug] generateGroupPerspectiveEvents: existingGroupModels provided=${!!existingGroupModels}, size=${existingGroupModels?.size ?? 0}`);
131
+ const events = [];
132
+ switch (clientEvent.eventType) {
133
+ case EventTypes_1.EventType.GROUP_CREATED: {
134
+ const event = clientEvent;
135
+ const otherMembers = (event.members ?? []).filter((id) => id !== event.userId);
136
+ console.log(`[Debug] generateGroupPerspectiveEvents GROUP_CREATED: members=${JSON.stringify(event.members)}, otherMembers=${JSON.stringify(otherMembers)}`);
137
+ for (const memberId of otherMembers) {
138
+ events.push(new __1.GroupCreated({
139
+ eventId: (0, uuid_1.v4)(),
140
+ userId: memberId,
141
+ groupId: event.groupId,
142
+ name: event.name,
143
+ description: event.description,
144
+ members: event.members,
145
+ createdAt: new Date(),
146
+ createdBy: event.createdBy,
147
+ streamId: (0, uuid_1.v4)(),
148
+ version: 1,
149
+ systemGenerated: true,
150
+ }));
151
+ }
152
+ break;
153
+ }
154
+ case EventTypes_1.EventType.GROUP_UPDATED: {
155
+ const event = clientEvent;
156
+ if (!existingGroupModels) {
157
+ console.warn(`[generateGroupPerspectiveEvents] existingGroupModels is required for GROUP_UPDATED but was not provided. streamId: ${event.streamId}`);
158
+ break;
159
+ }
160
+ for (const [userId, model] of existingGroupModels) {
161
+ if (model.streamId !== event.streamId) {
162
+ events.push(new __1.GroupUpdated({
163
+ eventId: (0, uuid_1.v4)(),
164
+ userId: userId,
165
+ name: event.name,
166
+ description: event.description,
167
+ createdAt: new Date(),
168
+ createdBy: event.createdBy,
169
+ streamId: model.streamId,
170
+ version: model.version + 1,
171
+ systemGenerated: true,
172
+ }));
173
+ }
174
+ }
175
+ break;
176
+ }
177
+ case EventTypes_1.EventType.GROUP_MEMBERS_ADDED: {
178
+ const event = clientEvent;
179
+ if (!existingGroupModels) {
180
+ console.warn(`[generateGroupPerspectiveEvents] existingGroupModels is required for GROUP_MEMBERS_ADDED but was not provided. streamId: ${event.streamId}`);
181
+ break;
182
+ }
183
+ const triggerModel = existingGroupModels.get(event.userId);
184
+ if (!triggerModel) {
185
+ console.warn(`[generateGroupPerspectiveEvents] triggerModel not found for GROUP_MEMBERS_ADDED. userId: ${event.userId}, streamId: ${event.streamId}`);
186
+ break;
187
+ }
188
+ // Include both existing and new members
189
+ const existingMembers = triggerModel.members ?? [];
190
+ const existingMembersSet = new Set(existingMembers);
191
+ const allMemberIds = [...new Set([...existingMembers, ...event.members])];
192
+ // GroupCreated for newly added members (skip if already in group)
193
+ for (const newMemberId of event.members) {
194
+ if (existingMembersSet.has(newMemberId)) {
195
+ continue;
196
+ }
197
+ events.push(new __1.GroupCreated({
198
+ eventId: (0, uuid_1.v4)(),
199
+ userId: newMemberId,
200
+ groupId: triggerModel.groupId,
201
+ name: triggerModel.name,
202
+ description: triggerModel.description,
203
+ members: allMemberIds,
204
+ createdAt: new Date(),
205
+ createdBy: event.createdBy,
206
+ streamId: (0, uuid_1.v4)(),
207
+ version: 1,
208
+ systemGenerated: true,
209
+ }));
210
+ }
211
+ // GroupMembersAdded for existing members (excluding trigger user and new members)
212
+ for (const [userId, model] of existingGroupModels) {
213
+ if (model.streamId !== event.streamId &&
214
+ !event.members.includes(userId)) {
215
+ events.push(new __1.GroupMembersAdded({
216
+ eventId: (0, uuid_1.v4)(),
217
+ userId: userId,
218
+ members: event.members,
219
+ createdAt: new Date(),
220
+ createdBy: event.createdBy,
221
+ streamId: model.streamId,
222
+ version: model.version + 1,
223
+ systemGenerated: true,
224
+ }));
225
+ }
226
+ }
227
+ break;
228
+ }
229
+ case EventTypes_1.EventType.GROUP_MEMBERS_REMOVED: {
230
+ const event = clientEvent;
231
+ if (!existingGroupModels) {
232
+ console.warn(`[generateGroupPerspectiveEvents] existingGroupModels is required for GROUP_MEMBERS_REMOVED but was not provided. streamId: ${event.streamId}`);
233
+ break;
234
+ }
235
+ // GroupDeleted for removed members
236
+ for (const removedMemberId of event.members) {
237
+ const removedModel = existingGroupModels.get(removedMemberId);
238
+ if (removedModel) {
239
+ events.push(new __1.GroupDeleted({
240
+ eventId: (0, uuid_1.v4)(),
241
+ userId: removedMemberId,
242
+ createdAt: new Date(),
243
+ createdBy: event.createdBy,
244
+ streamId: removedModel.streamId,
245
+ version: removedModel.version + 1,
246
+ systemGenerated: true,
247
+ }));
248
+ }
249
+ }
250
+ // GroupMembersRemoved for remaining members (excluding trigger user and removed members)
251
+ for (const [userId, model] of existingGroupModels) {
252
+ if (model.streamId !== event.streamId &&
253
+ !event.members.includes(userId)) {
254
+ events.push(new __1.GroupMembersRemoved({
255
+ eventId: (0, uuid_1.v4)(),
256
+ userId: userId,
257
+ members: event.members,
258
+ createdAt: new Date(),
259
+ createdBy: event.createdBy,
260
+ streamId: model.streamId,
261
+ version: model.version + 1,
262
+ systemGenerated: true,
263
+ }));
264
+ }
265
+ }
266
+ break;
267
+ }
268
+ case EventTypes_1.EventType.GROUP_DELETED: {
269
+ const event = clientEvent;
270
+ if (!existingGroupModels) {
271
+ console.warn(`[generateGroupPerspectiveEvents] existingGroupModels is required for GROUP_DELETED but was not provided. streamId: ${event.streamId}`);
272
+ break;
273
+ }
274
+ for (const [userId, model] of existingGroupModels) {
275
+ if (model.streamId !== event.streamId) {
276
+ events.push(new __1.GroupDeleted({
277
+ eventId: (0, uuid_1.v4)(),
278
+ userId: userId,
279
+ createdAt: new Date(),
280
+ createdBy: event.createdBy,
281
+ streamId: model.streamId,
282
+ version: model.version + 1,
283
+ systemGenerated: true,
284
+ }));
285
+ }
286
+ }
287
+ break;
288
+ }
289
+ }
290
+ console.log(`[Debug] generateGroupPerspectiveEvents: returning ${events.length} events`);
291
+ return events;
292
+ }
293
+ function processGroupTransactionEventForPerspectives(event, updatedModel, existingPerspectiveModels, existingTransactionModels) {
294
+ console.log(`[Debug] processGroupTransactionEventForPerspectives: eventType=${event.eventType}, userId=${event.userId}, streamId=${event.streamId}`);
295
+ console.log(`[Debug] processGroupTransactionEventForPerspectives: existingPerspectiveModels.size=${existingPerspectiveModels.size}, existingTransactionModels.length=${existingTransactionModels.length}`);
296
+ const groupTransactionEventsToSave = [];
297
+ const groupTransactionModelsToSave = [];
298
+ const transactionModelsToSave = [];
299
+ const perspectiveEvents = generatePerspectiveEvents(event, updatedModel, existingPerspectiveModels);
300
+ console.log(`[Debug] processGroupTransactionEventForPerspectives: generated ${perspectiveEvents.length} perspective events`);
301
+ for (const perspectiveEvent of perspectiveEvents) {
302
+ const existingPerspective = existingPerspectiveModels.get(perspectiveEvent.userId);
303
+ const perspectiveModel = perspectiveEvent.apply(existingPerspective);
304
+ groupTransactionModelsToSave.push(perspectiveModel);
305
+ groupTransactionEventsToSave.push(perspectiveEvent);
306
+ }
307
+ const transactionEvents = generateTransactionEventsForGroupTransactionModel(existingTransactionModels, updatedModel);
308
+ for (const transactionEvent of transactionEvents) {
309
+ const existingTx = existingTransactionModels.find((tx) => tx.streamId === transactionEvent.streamId);
310
+ const transactionModel = transactionEvent.apply(existingTx);
311
+ transactionModelsToSave.push(transactionModel);
312
+ }
313
+ console.log(`[Debug] processGroupTransactionEventForPerspectives: returning groupTransactionEventsToSave.length=${groupTransactionEventsToSave.length}, transactionEvents.length=${transactionEvents.length}`);
314
+ return {
315
+ groupTransactionEventsToSave,
316
+ groupTransactionModelsToSave,
317
+ transactionEventsToSave: transactionEvents,
318
+ transactionModelsToSave,
319
+ };
320
+ }
321
+ function calculateDebtsForMember(originalTransaction, memberId) {
322
+ const members = originalTransaction.members;
323
+ const whoYouOwe = [];
324
+ const whoOweYou = [];
325
+ const balances = members.map((m) => ({
326
+ memberId: m.memberId,
327
+ balance: m.paid - m.owed,
328
+ }));
329
+ const creditors = balances
330
+ .filter((b) => b.balance > 0)
331
+ .map((b) => ({ ...b, remaining: b.balance }));
332
+ const debtors = balances
333
+ .filter((b) => b.balance < 0)
334
+ .map((b) => ({ ...b, remaining: -b.balance }));
335
+ for (const debtor of debtors) {
336
+ for (const creditor of creditors) {
337
+ if (debtor.remaining <= 0 || creditor.remaining <= 0)
338
+ continue;
339
+ const amount = Math.min(debtor.remaining, creditor.remaining);
340
+ debtor.remaining -= amount;
341
+ creditor.remaining -= amount;
342
+ if (debtor.memberId === memberId) {
343
+ whoYouOwe.push({ memberId: creditor.memberId, amount });
344
+ }
345
+ if (creditor.memberId === memberId) {
346
+ whoOweYou.push({ memberId: debtor.memberId, amount });
347
+ }
348
+ }
349
+ }
350
+ return { whoYouOwe, whoOweYou };
351
+ }
352
+ function generatePerspectiveEvents(clientEvent, updatedModel, existingPerspectiveModels) {
353
+ console.log(`[Debug] generatePerspectiveEvents: eventType=${clientEvent.eventType}, userId=${clientEvent.userId}`);
354
+ console.log(`[Debug] generatePerspectiveEvents: existingPerspectiveModels provided=${!!existingPerspectiveModels}, size=${existingPerspectiveModels?.size ?? 0}`);
355
+ const perspectiveEvents = [];
356
+ const eventType = clientEvent.eventType;
357
+ const memberIds = updatedModel.originalTransaction.members.map((m) => m.memberId);
358
+ console.log(`[Debug] generatePerspectiveEvents: memberIds=${JSON.stringify(memberIds)}`);
359
+ for (const memberId of memberIds) {
360
+ if (memberId === clientEvent.userId) {
361
+ console.log(`[Debug] generatePerspectiveEvents: skipping clientEvent.userId=${clientEvent.userId}`);
362
+ continue;
363
+ }
364
+ const existingModel = existingPerspectiveModels?.get(memberId);
365
+ const streamId = existingModel?.streamId ?? (0, uuid_1.v4)();
366
+ const version = existingModel ? existingModel.version + 1 : 1;
367
+ if (eventType === EventTypes_1.EventType.GROUP_TRANSACTION_CREATED) {
368
+ const createdEvent = clientEvent;
369
+ let perspectiveSplitType = createdEvent.splitType;
370
+ if (perspectiveSplitType !== __1.SplitTypeEnum.SpecificAmounts) {
371
+ perspectiveSplitType = (0, splitTypeUtils_1.reverseSplitType)(perspectiveSplitType);
372
+ }
373
+ const { whoYouOwe, whoOweYou } = calculateDebtsForMember(createdEvent.originalTransaction, memberId);
374
+ perspectiveEvents.push(new __1.GroupTransactionCreated({
375
+ eventId: (0, uuid_1.v4)(),
376
+ userId: memberId,
377
+ groupId: createdEvent.groupId,
378
+ transactionId: createdEvent.transactionId,
379
+ description: createdEvent.description,
380
+ notes: createdEvent.notes,
381
+ totalAmount: createdEvent.totalAmount,
382
+ currency: createdEvent.currency,
383
+ splitType: perspectiveSplitType,
384
+ transactionDate: createdEvent.transactionDate,
385
+ originalTransaction: createdEvent.originalTransaction,
386
+ whoYouOwe,
387
+ whoOweYou,
388
+ createdAt: createdEvent.createdAt,
389
+ createdBy: createdEvent.createdBy,
390
+ streamId,
391
+ version,
392
+ systemGenerated: true,
393
+ }));
394
+ }
395
+ else if (eventType === EventTypes_1.EventType.GROUP_TRANSACTION_UPDATED) {
396
+ const updatedEvent = clientEvent;
397
+ let perspectiveSplitType = updatedEvent.splitType;
398
+ if (perspectiveSplitType !== undefined &&
399
+ perspectiveSplitType !== __1.SplitTypeEnum.SpecificAmounts) {
400
+ perspectiveSplitType = (0, splitTypeUtils_1.reverseSplitType)(perspectiveSplitType);
401
+ }
402
+ let whoYouOwe = updatedEvent.whoYouOwe;
403
+ let whoOweYou = updatedEvent.whoOweYou;
404
+ if (updatedEvent.originalTransaction) {
405
+ const debts = calculateDebtsForMember(updatedEvent.originalTransaction, memberId);
406
+ whoYouOwe = debts.whoYouOwe;
407
+ whoOweYou = debts.whoOweYou;
408
+ }
409
+ perspectiveEvents.push(new __1.GroupTransactionUpdated({
410
+ eventId: (0, uuid_1.v4)(),
411
+ userId: memberId,
412
+ description: updatedEvent.description,
413
+ notes: updatedEvent.notes,
414
+ totalAmount: updatedEvent.totalAmount,
415
+ currency: updatedEvent.currency,
416
+ splitType: perspectiveSplitType,
417
+ transactionDate: updatedEvent.transactionDate,
418
+ originalTransaction: updatedEvent.originalTransaction,
419
+ whoYouOwe,
420
+ whoOweYou,
421
+ createdAt: updatedEvent.createdAt,
422
+ createdBy: updatedEvent.createdBy,
423
+ streamId,
424
+ version,
425
+ systemGenerated: true,
426
+ }));
427
+ }
428
+ else if (eventType === EventTypes_1.EventType.GROUP_TRANSACTION_DELETED) {
429
+ const deletedEvent = clientEvent;
430
+ perspectiveEvents.push(new __1.GroupTransactionDeleted({
431
+ eventId: (0, uuid_1.v4)(),
432
+ userId: memberId,
433
+ createdAt: new Date(),
434
+ createdBy: deletedEvent.createdBy,
435
+ streamId,
436
+ version,
437
+ systemGenerated: true,
438
+ }));
439
+ }
440
+ }
441
+ console.log(`[Debug] generatePerspectiveEvents: returning ${perspectiveEvents.length} perspective events`);
442
+ return perspectiveEvents;
443
+ }
444
+ function generateTransactionEventsForGroupTransactionModel(existingGroupTransactions, updatedModel) {
445
+ console.log(`[Debug] generateTransactionEventsForGroupTransactionModel: updatedModel.userId=${updatedModel.userId}, transactionId=${updatedModel.transactionId}`);
446
+ console.log(`[Debug] generateTransactionEventsForGroupTransactionModel: existingGroupTransactions.length=${existingGroupTransactions.length}`);
447
+ console.log(`[Debug] generateTransactionEventsForGroupTransactionModel: whoYouOwe=${JSON.stringify(updatedModel.whoYouOwe)}, whoOweYou=${JSON.stringify(updatedModel.whoOweYou)}`);
448
+ const events = [];
449
+ const now = new Date();
450
+ const processedRecipientIds = new Set();
451
+ const existingByRecipient = new Map();
452
+ for (const tx of existingGroupTransactions) {
453
+ existingByRecipient.set(tx.recipientUserId, tx);
454
+ }
455
+ for (const debt of updatedModel.whoYouOwe) {
456
+ processedRecipientIds.add(debt.memberId);
457
+ const existing = existingByRecipient.get(debt.memberId);
458
+ if (existing) {
459
+ events.push(new __1.TransactionUpdated({
460
+ eventId: (0, uuid_1.v4)(),
461
+ userId: updatedModel.userId,
462
+ description: updatedModel.description ?? "",
463
+ currency: updatedModel.currency,
464
+ splitType: __1.SplitTypeEnum.SpecificAmounts,
465
+ totalAmount: updatedModel.totalAmount,
466
+ amount: debt.amount,
467
+ isOwed: true,
468
+ transactionDate: updatedModel.transactionDate,
469
+ createdAt: now,
470
+ createdBy: updatedModel.updatedBy,
471
+ streamId: existing.streamId,
472
+ version: existing.version + 1,
473
+ systemGenerated: true,
474
+ }));
475
+ }
476
+ else {
477
+ events.push(new __1.TransactionCreated({
478
+ eventId: (0, uuid_1.v4)(),
479
+ userId: updatedModel.userId,
480
+ recipientUserId: debt.memberId,
481
+ logicalTransactionId: updatedModel.transactionId,
482
+ description: updatedModel.description ?? "",
483
+ currency: updatedModel.currency,
484
+ splitType: __1.SplitTypeEnum.SpecificAmounts,
485
+ totalAmount: updatedModel.totalAmount,
486
+ amount: debt.amount,
487
+ isOwed: true,
488
+ transactionDate: updatedModel.transactionDate,
489
+ groupId: updatedModel.groupId,
490
+ groupTransactionId: updatedModel.transactionId,
491
+ createdAt: now,
492
+ createdBy: updatedModel.updatedBy,
493
+ streamId: (0, uuid_1.v4)(),
494
+ version: 1,
495
+ systemGenerated: true,
496
+ }));
497
+ }
498
+ }
499
+ for (const credit of updatedModel.whoOweYou) {
500
+ processedRecipientIds.add(credit.memberId);
501
+ const existing = existingByRecipient.get(credit.memberId);
502
+ if (existing) {
503
+ events.push(new __1.TransactionUpdated({
504
+ eventId: (0, uuid_1.v4)(),
505
+ userId: updatedModel.userId,
506
+ description: updatedModel.description ?? "",
507
+ currency: updatedModel.currency,
508
+ splitType: __1.SplitTypeEnum.SpecificAmounts,
509
+ totalAmount: updatedModel.totalAmount,
510
+ amount: credit.amount,
511
+ isOwed: false,
512
+ transactionDate: updatedModel.transactionDate,
513
+ createdAt: now,
514
+ createdBy: updatedModel.updatedBy,
515
+ streamId: existing.streamId,
516
+ version: existing.version + 1,
517
+ systemGenerated: true,
518
+ }));
519
+ }
520
+ else {
521
+ events.push(new __1.TransactionCreated({
522
+ eventId: (0, uuid_1.v4)(),
523
+ userId: updatedModel.userId,
524
+ recipientUserId: credit.memberId,
525
+ logicalTransactionId: updatedModel.transactionId,
526
+ description: updatedModel.description ?? "",
527
+ currency: updatedModel.currency,
528
+ splitType: __1.SplitTypeEnum.SpecificAmounts,
529
+ totalAmount: updatedModel.totalAmount,
530
+ amount: credit.amount,
531
+ isOwed: false,
532
+ transactionDate: updatedModel.transactionDate,
533
+ groupId: updatedModel.groupId,
534
+ groupTransactionId: updatedModel.transactionId,
535
+ createdAt: now,
536
+ createdBy: updatedModel.updatedBy,
537
+ streamId: (0, uuid_1.v4)(),
538
+ version: 1,
539
+ systemGenerated: true,
540
+ }));
541
+ }
542
+ }
543
+ for (const existing of existingGroupTransactions) {
544
+ if (!processedRecipientIds.has(existing.recipientUserId)) {
545
+ events.push(new __1.TransactionDeleted({
546
+ eventId: (0, uuid_1.v4)(),
547
+ userId: updatedModel.userId,
548
+ streamId: existing.streamId,
549
+ version: existing.version + 1,
550
+ createdAt: now,
551
+ createdBy: updatedModel.updatedBy,
552
+ systemGenerated: true,
553
+ }));
554
+ }
555
+ }
556
+ console.log(`[Debug] generateTransactionEventsForGroupTransactionModel: returning ${events.length} transaction events`);
557
+ return events;
558
+ }
559
+ function buildYouPaidSplitEquallyEvent(userId, groupId, request, existingModel) {
560
+ const transactionDate = new Date(request.transactionDate);
561
+ const allMemberIds = [userId, ...request.memberIds];
562
+ const memberCount = allMemberIds.length;
563
+ const amountPerMember = request.totalAmount / memberCount;
564
+ const members = allMemberIds.map((memberId) => ({
565
+ memberId,
566
+ paid: memberId === userId ? request.totalAmount : 0,
567
+ owed: amountPerMember,
568
+ }));
569
+ const originalTransaction = { members };
570
+ const { whoYouOwe, whoOweYou } = calculateDebtsForMember(originalTransaction, userId);
571
+ const commonFields = {
572
+ eventId: (0, uuid_1.v4)(),
573
+ userId,
574
+ description: request.description.trim(),
575
+ totalAmount: request.totalAmount,
576
+ currency: request.currency,
577
+ splitType: __1.SplitTypeEnum.YouPaidSplitEqually,
578
+ transactionDate,
579
+ originalTransaction,
580
+ whoYouOwe,
581
+ whoOweYou,
582
+ createdAt: new Date(),
583
+ createdBy: userId,
584
+ systemGenerated: false,
585
+ };
586
+ if (existingModel) {
587
+ return new __1.GroupTransactionUpdated({
588
+ ...commonFields,
589
+ streamId: existingModel.streamId,
590
+ version: existingModel.version + 1,
591
+ });
592
+ }
593
+ return new __1.GroupTransactionCreated({
594
+ ...commonFields,
595
+ groupId,
596
+ transactionId: request.transactionId ?? (0, uuid_1.v4)(),
597
+ streamId: (0, uuid_1.v4)(),
598
+ version: 1,
599
+ });
600
+ }
601
+ function buildTheyPaidSplitEquallyEvent(userId, groupId, request, existingModel) {
602
+ const transactionDate = new Date(request.transactionDate);
603
+ const allMemberIds = [
604
+ request.paidByMemberId,
605
+ ...request.memberIds.filter((id) => id !== request.paidByMemberId),
606
+ ];
607
+ if (!allMemberIds.includes(userId)) {
608
+ allMemberIds.push(userId);
609
+ }
610
+ const memberCount = allMemberIds.length;
611
+ const amountPerMember = request.totalAmount / memberCount;
612
+ const members = allMemberIds.map((memberId) => ({
613
+ memberId,
614
+ paid: memberId === request.paidByMemberId ? request.totalAmount : 0,
615
+ owed: amountPerMember,
616
+ }));
617
+ const originalTransaction = { members };
618
+ const { whoYouOwe, whoOweYou } = calculateDebtsForMember(originalTransaction, userId);
619
+ const commonFields = {
620
+ eventId: (0, uuid_1.v4)(),
621
+ userId,
622
+ description: request.description.trim(),
623
+ totalAmount: request.totalAmount,
624
+ currency: request.currency,
625
+ splitType: __1.SplitTypeEnum.TheyPaidSplitEqually,
626
+ transactionDate,
627
+ originalTransaction,
628
+ whoYouOwe,
629
+ whoOweYou,
630
+ createdAt: new Date(),
631
+ createdBy: userId,
632
+ systemGenerated: false,
633
+ };
634
+ if (existingModel) {
635
+ return new __1.GroupTransactionUpdated({
636
+ ...commonFields,
637
+ streamId: existingModel.streamId,
638
+ version: existingModel.version + 1,
639
+ });
640
+ }
641
+ return new __1.GroupTransactionCreated({
642
+ ...commonFields,
643
+ groupId,
644
+ transactionId: request.transactionId ?? (0, uuid_1.v4)(),
645
+ streamId: (0, uuid_1.v4)(),
646
+ version: 1,
647
+ });
648
+ }
649
+ function buildSpecificAmountsEvent(userId, groupId, request, existingModel) {
650
+ const transactionDate = new Date(request.transactionDate);
651
+ const members = request.memberAmounts.map((ma) => ({
652
+ memberId: ma.memberId,
653
+ paid: ma.amountPaid,
654
+ owed: ma.amountSpent,
655
+ }));
656
+ const originalTransaction = { members };
657
+ const { whoYouOwe, whoOweYou } = calculateDebtsForMember(originalTransaction, userId);
658
+ const commonFields = {
659
+ eventId: (0, uuid_1.v4)(),
660
+ userId,
661
+ description: request.description.trim(),
662
+ totalAmount: request.totalAmount,
663
+ currency: request.currency,
664
+ splitType: __1.SplitTypeEnum.SpecificAmounts,
665
+ transactionDate,
666
+ originalTransaction,
667
+ whoYouOwe,
668
+ whoOweYou,
669
+ createdAt: new Date(),
670
+ createdBy: userId,
671
+ systemGenerated: false,
672
+ };
673
+ if (existingModel) {
674
+ return new __1.GroupTransactionUpdated({
675
+ ...commonFields,
676
+ streamId: existingModel.streamId,
677
+ version: existingModel.version + 1,
678
+ });
679
+ }
680
+ return new __1.GroupTransactionCreated({
681
+ ...commonFields,
682
+ groupId,
683
+ transactionId: request.transactionId ?? (0, uuid_1.v4)(),
684
+ streamId: (0, uuid_1.v4)(),
685
+ version: 1,
686
+ });
687
+ }
688
+ function convertCurrency(amount, fromCurrency, toCurrency, rates) {
689
+ if (fromCurrency === toCurrency) {
690
+ return amount;
691
+ }
692
+ const fromRate = rates[fromCurrency] ?? 1;
693
+ const toRate = rates[toCurrency] ?? 1;
694
+ return (amount / fromRate) * toRate;
695
+ }
696
+ function toGroupTransactionResponse(model, toCurrency, rates) {
697
+ const whoOweYouConverted = model.whoOweYou.map((m) => ({
698
+ memberId: m.memberId,
699
+ amount: m.amount,
700
+ amountInDefaultCurrency: convertCurrency(m.amount, model.currency, toCurrency, rates),
701
+ }));
702
+ const whoYouOweConverted = model.whoYouOwe.map((m) => ({
703
+ memberId: m.memberId,
704
+ amount: m.amount,
705
+ amountInDefaultCurrency: convertCurrency(m.amount, model.currency, toCurrency, rates),
706
+ }));
707
+ const totalOwedToYou = model.whoOweYou.reduce((sum, m) => sum + m.amount, 0);
708
+ const totalYouOwe = model.whoYouOwe.reduce((sum, m) => sum + m.amount, 0);
709
+ const netAmount = totalOwedToYou - totalYouOwe;
710
+ const whoOweWho = {
711
+ amount: Math.abs(netAmount),
712
+ isOwed: netAmount > 0,
713
+ amountInDefaultCurrency: convertCurrency(Math.abs(netAmount), model.currency, toCurrency, rates),
714
+ defaultCurrency: toCurrency,
715
+ whoOweYou: whoOweYouConverted,
716
+ whoYouOwe: whoYouOweConverted,
717
+ };
718
+ return {
719
+ id: model.transactionId,
720
+ date: model.transactionDate.toISOString(),
721
+ description: model.description,
722
+ notes: model.notes,
723
+ totalAmount: model.totalAmount,
724
+ currency: model.currency,
725
+ splitType: model.splitType,
726
+ whoOweWho,
727
+ originalTransaction: mapOriginalTransaction(model),
728
+ deleted: model.deleted,
729
+ createdAt: model.createdAt.toISOString(),
730
+ createdBy: model.createdBy,
731
+ };
732
+ }
733
+ function mapOriginalTransaction(model) {
734
+ if (model.splitType === __1.SplitTypeEnum.YouPaidSplitEqually) {
735
+ return {
736
+ type: "YouPaidSplitEqually",
737
+ memberIds: model.originalTransaction.members.map((m) => m.memberId),
738
+ whoPaidWhoResponse: () => [],
739
+ };
740
+ }
741
+ else if (model.splitType === __1.SplitTypeEnum.TheyPaidSplitEqually) {
742
+ const payer = model.originalTransaction.members.find((m) => m.paid > 0 && m.paid === model.totalAmount);
743
+ return {
744
+ type: "TheyPaidSplitEqually",
745
+ memberWhoPaid: payer?.memberId ?? "",
746
+ memberIds: model.originalTransaction.members.map((m) => m.memberId),
747
+ whoPaidWhoResponse: () => [],
748
+ };
749
+ }
750
+ else {
751
+ return {
752
+ type: "SpecificAmounts",
753
+ members: model.originalTransaction.members.map((m) => ({
754
+ memberId: m.memberId,
755
+ amountPaid: m.paid,
756
+ amountSpent: m.owed,
757
+ })),
758
+ whoPaidWhoResponse: () => [],
759
+ };
760
+ }
761
+ }
762
+ //# sourceMappingURL=GroupUtil.js.map