@accounter/server 0.0.9-alpha-20251211132246-b18259e59cbca0d25dd94d8260a61b55a2f3b458 → 0.0.9-alpha-20251211161610-5ba6aa4ba27b2cc52460d8b17757dad51478bc4a

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 (22) hide show
  1. package/CHANGELOG.md +5 -5
  2. package/dist/green-invoice-graphql/src/mesh-artifacts/index.d.ts +1 -1
  3. package/dist/server/src/modules/charges/helpers/common.helper.js +19 -13
  4. package/dist/server/src/modules/charges/helpers/common.helper.js.map +1 -1
  5. package/dist/server/src/modules/charges/resolvers/charge-suggestions/charge-suggestions.resolver.js +561 -545
  6. package/dist/server/src/modules/charges/resolvers/charge-suggestions/charge-suggestions.resolver.js.map +1 -1
  7. package/dist/server/src/modules/charges/resolvers/charges.resolver.js +179 -140
  8. package/dist/server/src/modules/charges/resolvers/charges.resolver.js.map +1 -1
  9. package/dist/server/src/modules/charges/resolvers/common.js +45 -26
  10. package/dist/server/src/modules/charges/resolvers/common.js.map +1 -1
  11. package/dist/server/src/modules/charges/resolvers/financial-charges.resolver.js +31 -25
  12. package/dist/server/src/modules/charges/resolvers/financial-charges.resolver.js.map +1 -1
  13. package/dist/server/src/shared/errors.d.ts +1 -0
  14. package/dist/server/src/shared/errors.js +7 -0
  15. package/dist/server/src/shared/errors.js.map +1 -1
  16. package/package.json +1 -1
  17. package/src/modules/charges/helpers/common.helper.ts +24 -19
  18. package/src/modules/charges/resolvers/charge-suggestions/charge-suggestions.resolver.ts +588 -574
  19. package/src/modules/charges/resolvers/charges.resolver.ts +192 -157
  20. package/src/modules/charges/resolvers/common.ts +48 -31
  21. package/src/modules/charges/resolvers/financial-charges.resolver.ts +31 -27
  22. package/src/shared/errors.ts +8 -0
@@ -8,6 +8,7 @@ import type {
8
8
  } from '../../../../__generated__/types.js';
9
9
  import { UUID_REGEX } from '../../../../shared/constants.js';
10
10
  import { ChargeTypeEnum } from '../../../../shared/enums.js';
11
+ import { errorSimplifier } from '../../../../shared/errors.js';
11
12
  import { suggestionDataSchema } from '../../../financial-entities/helpers/business-suggestion-data-schema.helper.js';
12
13
  import { BusinessesProvider } from '../../../financial-entities/providers/businesses.provider.js';
13
14
  import { ChargeTagsProvider } from '../../../tags/providers/charge-tags.provider.js';
@@ -27,37 +28,104 @@ const missingInfoSuggestions: Resolver<
27
28
  ResolversParentTypes['Charge'],
28
29
  GraphQLModules.Context
29
30
  > = async (DbCharge, _, context, __) => {
30
- const { injector, adminContext } = context;
31
- const { poalimBusinessId, etherScanBusinessId, krakenBusinessId, etanaBusinessId } =
32
- adminContext.financialAccounts;
31
+ try {
32
+ const { injector, adminContext } = context;
33
+ const { poalimBusinessId, etherScanBusinessId, krakenBusinessId, etanaBusinessId } =
34
+ adminContext.financialAccounts;
33
35
 
34
- const [chargeType, tags] = await Promise.all([
35
- getChargeType(DbCharge, context),
36
- context.injector.get(ChargeTagsProvider).getTagsByChargeIDLoader.load(DbCharge.id),
37
- ]);
36
+ const [chargeType, tags] = await Promise.all([
37
+ getChargeType(DbCharge, context),
38
+ context.injector.get(ChargeTagsProvider).getTagsByChargeIDLoader.load(DbCharge.id),
39
+ ]);
38
40
 
39
- // if all required fields are filled, no need for suggestions
40
- if (!!tags.length && !!DbCharge.user_description?.trim()) {
41
- return null;
42
- }
41
+ // if all required fields are filled, no need for suggestions
42
+ if (!!tags.length && !!DbCharge.user_description?.trim()) {
43
+ return null;
44
+ }
43
45
 
44
- if (chargeType === ChargeTypeEnum.Conversion) {
45
- return missingConversionInfoSuggestions(DbCharge, _, context, __);
46
- }
46
+ if (chargeType === ChargeTypeEnum.Conversion) {
47
+ return missingConversionInfoSuggestions(DbCharge, _, context, __);
48
+ }
47
49
 
48
- const [formattedAmount, { allBusinessIds, mainBusinessId }] = await Promise.all([
49
- calculateTotalAmount(DbCharge.id, injector, adminContext.defaultLocalCurrency),
50
- getChargeBusinesses(DbCharge.id, injector),
51
- ]);
50
+ const [formattedAmount, { allBusinessIds, mainBusinessId }] = await Promise.all([
51
+ calculateTotalAmount(DbCharge.id, injector, adminContext.defaultLocalCurrency),
52
+ getChargeBusinesses(DbCharge.id, injector),
53
+ ]);
54
+
55
+ const chargeAmount = formattedAmount?.raw ?? 0;
56
+
57
+ // if charge has a businesses, use it's suggestion data
58
+ if (mainBusinessId) {
59
+ const business = await injector
60
+ .get(BusinessesProvider)
61
+ .getBusinessByIdLoader.load(mainBusinessId);
62
+ if (business?.suggestion_data) {
63
+ const {
64
+ data: suggestionData,
65
+ error,
66
+ success,
67
+ } = suggestionDataSchema.safeParse(business.suggestion_data);
68
+ if (!success) {
69
+ console.error('Failed to parse suggestion data for business', {
70
+ businessId: business.id,
71
+ error,
72
+ });
73
+ throw new GraphQLError('Failed to parse suggestion data for business');
74
+ }
52
75
 
53
- const chargeAmount = formattedAmount?.raw ?? 0;
76
+ return {
77
+ description: suggestionData.description,
78
+ tags: await Promise.all(
79
+ (suggestionData.tags ?? []).map(tag =>
80
+ UUID_REGEX.test(tag)
81
+ ? injector.get(TagsProvider).getTagByIDLoader.load(tag)
82
+ : injector.get(TagsProvider).getTagByNameLoader.load(tag),
83
+ ),
84
+ ).then(tags => tags.filter(Boolean) as IGetTagsByIDsResult[]),
85
+ };
86
+ }
87
+ }
88
+
89
+ if (allBusinessIds.length > 1) {
90
+ const isKrakenIncluded = krakenBusinessId && allBusinessIds.includes(krakenBusinessId);
91
+ const isEtherscanIncluded =
92
+ etherScanBusinessId && allBusinessIds.includes(etherScanBusinessId);
93
+ const isEtanaIncluded = etanaBusinessId && allBusinessIds.includes(etanaBusinessId);
94
+ const isPoalimIncluded = poalimBusinessId && allBusinessIds.includes(poalimBusinessId);
95
+
96
+ if (isKrakenIncluded && isEtherscanIncluded) {
97
+ return {
98
+ description: 'Etherscan to Kraken transfer',
99
+ tags: await injector
100
+ .get(TagsProvider)
101
+ .getTagByNameLoader.load('financial')
102
+ .then(res => (res ? [res] : [])),
103
+ };
104
+ }
105
+ if (isKrakenIncluded && isEtanaIncluded) {
106
+ return {
107
+ description: 'Kraken to Etana transfer',
108
+ tags: await injector
109
+ .get(TagsProvider)
110
+ .getTagByNameLoader.load('financial')
111
+ .then(res => (res ? [res] : [])),
112
+ };
113
+ }
114
+ if (isPoalimIncluded && isEtanaIncluded) {
115
+ return {
116
+ description: 'Etana to Poalim transfer',
117
+ tags: await injector
118
+ .get(TagsProvider)
119
+ .getTagByNameLoader.load('financial')
120
+ .then(res => (res ? [res] : [])),
121
+ };
122
+ }
123
+ }
54
124
 
55
- // if charge has a businesses, use it's suggestion data
56
- if (mainBusinessId) {
57
- const business = await injector
58
- .get(BusinessesProvider)
59
- .getBusinessByIdLoader.load(mainBusinessId);
60
- if (business?.suggestion_data) {
125
+ const allBusinesses = await injector.get(BusinessesProvider).getAllBusinesses();
126
+ const suggestions: Record<string, Suggestion> = {};
127
+ for (const business of allBusinesses) {
128
+ if (!business.suggestion_data) continue;
61
129
  const {
62
130
  data: suggestionData,
63
131
  error,
@@ -68,545 +136,483 @@ const missingInfoSuggestions: Resolver<
68
136
  businessId: business.id,
69
137
  error,
70
138
  });
71
- throw new GraphQLError('Failed to parse suggestion data for business');
139
+ continue;
72
140
  }
73
141
 
74
- return {
75
- description: suggestionData.description,
76
- tags: await Promise.all(
77
- (suggestionData.tags ?? []).map(tag =>
78
- UUID_REGEX.test(tag)
79
- ? injector.get(TagsProvider).getTagByIDLoader.load(tag)
80
- : injector.get(TagsProvider).getTagByNameLoader.load(tag),
81
- ),
82
- ).then(tags => tags.filter(Boolean) as IGetTagsByIDsResult[]),
83
- };
142
+ if (business.id in allBusinessIds) {
143
+ return {
144
+ description: suggestionData.description,
145
+ tags: await Promise.all(
146
+ (suggestionData.tags ?? []).map(tag =>
147
+ UUID_REGEX.test(tag)
148
+ ? injector.get(TagsProvider).getTagByIDLoader.load(tag)
149
+ : injector.get(TagsProvider).getTagByNameLoader.load(tag),
150
+ ),
151
+ ).then(tags => tags.filter(Boolean) as IGetTagsByIDsResult[]),
152
+ };
153
+ }
154
+
155
+ if (!suggestionData.phrases) continue;
156
+
157
+ for (const phrase of suggestionData.phrases) {
158
+ suggestions[phrase] = {
159
+ description: suggestionData.description,
160
+ tags: suggestionData.tags
161
+ ? await Promise.all(
162
+ suggestionData.tags.map(tag =>
163
+ UUID_REGEX.test(tag)
164
+ ? injector.get(TagsProvider).getTagByIDLoader.load(tag)
165
+ : injector.get(TagsProvider).getTagByNameLoader.load(tag),
166
+ ),
167
+ ).then(tags => tags.filter(Boolean) as IGetTagsByIDsResult[])
168
+ : [],
169
+ };
170
+ }
84
171
  }
85
- }
86
172
 
87
- if (allBusinessIds.length > 1) {
88
- const isKrakenIncluded = krakenBusinessId && allBusinessIds.includes(krakenBusinessId);
89
- const isEtherscanIncluded = etherScanBusinessId && allBusinessIds.includes(etherScanBusinessId);
90
- const isEtanaIncluded = etanaBusinessId && allBusinessIds.includes(etanaBusinessId);
91
- const isPoalimIncluded = poalimBusinessId && allBusinessIds.includes(poalimBusinessId);
173
+ const transactions = await injector
174
+ .get(TransactionsProvider)
175
+ .transactionsByChargeIDLoader.load(DbCharge.id);
176
+ const description = transactions.map(t => t.source_description).join(' ');
177
+
178
+ for (const [phrase, suggestion] of Object.entries(suggestions)) {
179
+ if (Array.isArray(phrase) && new RegExp(phrase.join('|')).test(description)) {
180
+ return suggestion;
181
+ }
182
+ if (description.includes(phrase)) {
183
+ return suggestion;
184
+ }
185
+ }
92
186
 
93
- if (isKrakenIncluded && isEtherscanIncluded) {
187
+ if (
188
+ description.includes('ע\' העברת מט"ח') ||
189
+ (description.includes('העברת מט"ח') && Math.abs(chargeAmount) < 400) ||
190
+ (description.includes('מטח') && Math.abs(chargeAmount) < 400) ||
191
+ description.includes('F.C.COM') ||
192
+ description.includes('ע.מפעולות-ישיר') ||
193
+ description.includes('ריבית חובה') ||
194
+ description.includes('FEE')
195
+ ) {
196
+ const sourceTransaction =
197
+ transactions.length === 0
198
+ ? 'Missing'
199
+ : transactions.length === 1
200
+ ? transactions[0].source_reference
201
+ : `['${transactions.map(t => t.source_reference).join("','")}']`;
94
202
  return {
95
- description: 'Etherscan to Kraken transfer',
96
203
  tags: await injector
97
204
  .get(TagsProvider)
98
205
  .getTagByNameLoader.load('financial')
99
206
  .then(res => (res ? [res] : [])),
207
+ description: `Fees for source transaction=${sourceTransaction}`,
208
+ };
209
+ }
210
+ if (description.includes('דותן שמחה') || description.includes('שמחה דותן')) {
211
+ const current = new Date();
212
+ current.setMonth(current.getMonth() - 1);
213
+ const previousMonth = current.toLocaleString('default', {
214
+ month: '2-digit',
215
+ });
216
+ return {
217
+ description: `${previousMonth}/2022 Salary`,
218
+ tags: await injector
219
+ .get(TagsProvider)
220
+ .getTagByNameLoader.load('business')
221
+ .then(res => (res ? [res] : [])),
222
+ };
223
+ }
224
+ if (description.includes('גולדשטין אורי')) {
225
+ const current = new Date();
226
+ current.setMonth(current.getMonth() - 1);
227
+ const previousMonth = current.toLocaleString('default', {
228
+ month: '2-digit',
229
+ });
230
+ return {
231
+ description: `${previousMonth}/2022 Salary`,
232
+ tags: await injector
233
+ .get(TagsProvider)
234
+ .getTagByNameLoader.load('business')
235
+ .then(res => (res ? [res] : [])),
236
+ };
237
+ }
238
+ if (description.includes('גרדוש')) {
239
+ const current = new Date();
240
+ current.setMonth(current.getMonth() - 1);
241
+ const previousMonth = current.toLocaleString('default', {
242
+ month: '2-digit',
243
+ });
244
+ return {
245
+ description: `${previousMonth}/2022 Salary`,
246
+ tags: await injector
247
+ .get(TagsProvider)
248
+ .getTagByNameLoader.load('business')
249
+ .then(res => (res ? [res] : [])),
250
+ };
251
+ }
252
+ if (description.includes('תובל')) {
253
+ const current = new Date();
254
+ current.setMonth(current.getMonth() - 1);
255
+ const previousMonth = current.toLocaleString('default', {
256
+ month: '2-digit',
257
+ });
258
+ return {
259
+ description: `${previousMonth}/2022 Salary`,
260
+ tags: await injector
261
+ .get(TagsProvider)
262
+ .getTagByNameLoader.load('business')
263
+ .then(res => (res ? [res] : [])),
264
+ };
265
+ }
266
+ if (description.includes('מנורה מבטחים פנס')) {
267
+ const current = new Date();
268
+ current.setMonth(current.getMonth() - 1);
269
+ const previousMonth = current.toLocaleString('default', {
270
+ month: '2-digit',
271
+ });
272
+ return {
273
+ description: `Pension ${previousMonth}/2022`,
274
+ tags: await injector
275
+ .get(TagsProvider)
276
+ .getTagByNameLoader.load('business')
277
+ .then(res => (res ? [res] : [])),
278
+ };
279
+ }
280
+ if (description.includes('פניקס אקסלנס')) {
281
+ const current = new Date();
282
+ current.setMonth(current.getMonth() - 1);
283
+ const previousMonth = current.toLocaleString('default', {
284
+ month: '2-digit',
285
+ });
286
+ return {
287
+ description: `Training Fund ${previousMonth}/2022`,
288
+ tags: await injector
289
+ .get(TagsProvider)
290
+ .getTagByNameLoader.load('business')
291
+ .then(res => (res ? [res] : [])),
292
+ };
293
+ }
294
+ if (description.includes('מיטב דש גמל ופנס')) {
295
+ const current = new Date();
296
+ current.setMonth(current.getMonth() - 1);
297
+ const previousMonth = current.toLocaleString('default', {
298
+ month: '2-digit',
299
+ });
300
+ return {
301
+ description: `Pension ${previousMonth}/2022`,
302
+ tags: await injector
303
+ .get(TagsProvider)
304
+ .getTagByNameLoader.load('business')
305
+ .then(res => (res ? [res] : [])),
306
+ };
307
+ }
308
+ if (description.includes('מגדל מקפת')) {
309
+ const current = new Date();
310
+ current.setMonth(current.getMonth() - 1);
311
+ const previousMonth = current.toLocaleString('default', {
312
+ month: '2-digit',
313
+ });
314
+ return {
315
+ description: `Pension ${previousMonth}/2022`,
316
+ tags: await injector
317
+ .get(TagsProvider)
318
+ .getTagByNameLoader.load('business')
319
+ .then(res => (res ? [res] : [])),
320
+ };
321
+ }
322
+ if (description.includes('מגדל השתלמות')) {
323
+ const current = new Date();
324
+ current.setMonth(current.getMonth() - 1);
325
+ const previousMonth = current.toLocaleString('default', {
326
+ month: '2-digit',
327
+ });
328
+ return {
329
+ description: `Training Fund ${previousMonth}/2022`,
330
+ tags: await injector
331
+ .get(TagsProvider)
332
+ .getTagByNameLoader.load('business')
333
+ .then(res => (res ? [res] : [])),
334
+ };
335
+ }
336
+ if (description.includes('ביטוח לאומי')) {
337
+ const current = new Date();
338
+ current.setMonth(current.getMonth() - 1);
339
+ const previousMonth = current.toLocaleString('default', {
340
+ month: '2-digit',
341
+ });
342
+ return {
343
+ description: `Social Security Deductions for Salaries ${previousMonth}/2022`,
344
+ tags: await injector
345
+ .get(TagsProvider)
346
+ .getTagByNameLoader.load('business')
347
+ .then(res => (res ? [res] : [])),
348
+ };
349
+ }
350
+ if (description.includes('LANCE GLOBAL')) {
351
+ const current = new Date();
352
+ current.setMonth(current.getMonth() - 1);
353
+ const previousMonth = current.toLocaleString('default', { month: 'long' });
354
+ return {
355
+ description: `The Guild Enterprise Support - ${previousMonth} 2022`,
356
+ tags: await injector
357
+ .get(TagsProvider)
358
+ .getTagByNameLoader.load('business')
359
+ .then(res => (res ? [res] : [])),
100
360
  };
101
361
  }
102
- if (isKrakenIncluded && isEtanaIncluded) {
362
+ if (
363
+ (description.includes('העברת מט"ח') &&
364
+ (description.includes('fbv') || description.includes('fv'))) ||
365
+ description.includes('kamil kisiela')
366
+ ) {
367
+ const current = new Date();
368
+ current.setMonth(current.getMonth() - 1);
369
+ const previousMonth = current.toLocaleString('default', {
370
+ month: '2-digit',
371
+ });
372
+ return {
373
+ description: `Software Development and Consulting ${previousMonth}/23`,
374
+ tags: await injector
375
+ .get(TagsProvider)
376
+ .getTagByNameLoader.load('business')
377
+ .then(res => (res ? [res] : [])),
378
+ };
379
+ }
380
+ if (description.includes('slava')) {
381
+ const current = new Date();
382
+ current.setMonth(current.getMonth() - 1);
383
+ const previousMonth = current.toLocaleString('default', { month: '2-digit' });
384
+ return {
385
+ description: `Web Development Services ${previousMonth}/23`,
386
+ tags: await injector
387
+ .get(TagsProvider)
388
+ .getTagByNameLoader.load('business')
389
+ .then(res => (res ? [res] : [])),
390
+ };
391
+ }
392
+ if (description.includes('COURIER PLUS INC')) {
393
+ const current = new Date();
394
+ current.setMonth(current.getMonth() - 1);
395
+ const previousMonth = current.toLocaleString('default', { month: 'long' });
396
+ return {
397
+ description: `GraphQL Hive Enterprise License - ${previousMonth} 2023`,
398
+ tags: await injector
399
+ .get(TagsProvider)
400
+ .getTagByNameLoader.load('business')
401
+ .then(res => (res ? [res] : [])),
402
+ };
403
+ }
404
+ if (description.includes('GOBRANDS')) {
405
+ const current = new Date();
406
+ current.setMonth(current.getMonth() - 1);
407
+ const previousMonth = current.toLocaleString('default', { month: 'long' });
408
+ return {
409
+ description: `GraphQL Hive Enterprise License - ${previousMonth} 2023`,
410
+ tags: await injector
411
+ .get(TagsProvider)
412
+ .getTagByNameLoader.load('business')
413
+ .then(res => (res ? [res] : [])),
414
+ };
415
+ }
416
+ if (description.includes('MEDIC FIRST AI')) {
417
+ const current = new Date();
418
+ current.setMonth(current.getMonth() - 1);
419
+ const previousMonth = current.toLocaleString('default', { month: 'long' });
420
+ return {
421
+ description: `GraphQL Hive Enterprise License - ${previousMonth} 2023`,
422
+ tags: await injector
423
+ .get(TagsProvider)
424
+ .getTagByNameLoader.load('business')
425
+ .then(res => (res ? [res] : [])),
426
+ };
427
+ }
428
+ if (description.includes('מס הכנסה')) {
429
+ const flag = description.includes('מס הכנסה ני');
430
+ const current = new Date();
431
+ current.setMonth(current.getMonth() - 1);
432
+ const previousMonth = current.toLocaleString('default', {
433
+ month: '2-digit',
434
+ });
435
+ return {
436
+ tags: await injector
437
+ .get(TagsProvider)
438
+ .getTagByNameLoader.load('business')
439
+ .then(res => (res ? [res] : [])),
440
+ description: flag
441
+ ? `Tax for employees for ${previousMonth}/2022`
442
+ : `Advance Tax for ${previousMonth}/2022`,
443
+ };
444
+ }
445
+ if (description.includes('המכס ומעמ-גביי תשלום') || description.includes('CUSTOM + V.A.T')) {
446
+ const current = new Date();
447
+ current.setMonth(current.getMonth() - 1);
448
+ const previousMonth = current.toLocaleString('default', {
449
+ month: '2-digit',
450
+ });
451
+ return {
452
+ description: `VAT for ${previousMonth}/2022`,
453
+ tags: await injector
454
+ .get(TagsProvider)
455
+ .getTagByNameLoader.load('business')
456
+ .then(res => (res ? [res] : [])),
457
+ };
458
+ }
459
+ if (description.includes('חניון')) {
460
+ return {
461
+ description: 'Parking',
462
+ tags: await injector
463
+ .get(TagsProvider)
464
+ .getTagByNameLoader.load('transportation')
465
+ .then(res => (res ? [res] : [])),
466
+ };
467
+ }
468
+ if (description.includes('deel')) {
469
+ return {
470
+ description: 'Laurin Salary',
471
+ tags: await injector
472
+ .get(TagsProvider)
473
+ .getTagByNameLoader.load('business')
474
+ .then(res => (res ? [res] : [])),
475
+ };
476
+ }
477
+ if (description.includes('GITHUB')) {
478
+ const suggested = {
479
+ description: 'GitHub Actions',
480
+ tags: await injector
481
+ .get(TagsProvider)
482
+ .getTagByNameLoader.load('business')
483
+ .then(res => (res ? [res] : [])),
484
+ };
485
+ if (chargeAmount <= -2000) {
486
+ suggested.description = 'Monthly Sponsor for Benjie, Code-Hex, hayes';
487
+ } else if (chargeAmount <= -1000) {
488
+ suggested.description = 'Monthly Sponsor for Andarist, warrenday';
489
+ } else {
490
+ suggested.description = 'GitHub Actions';
491
+ }
492
+ return suggested;
493
+ }
494
+ if (chargeAmount === -4329) {
495
+ return {
496
+ description: 'Office rent',
497
+ tags: await injector
498
+ .get(TagsProvider)
499
+ .getTagByNameLoader.load('business')
500
+ .then(res => (res ? [res] : [])),
501
+ };
502
+ }
503
+ if (description.includes('APPLE COM BILL/ITUNES.COM')) {
504
+ const flag = chargeAmount === -109.9;
505
+ return {
506
+ taxCategory: 'אתר',
507
+ beneficiaaries: [], // NOTE: used to be ' '
508
+ description: flag ? 'LinkedIn' : 'Apple Services',
509
+ tags: await injector
510
+ .get(TagsProvider)
511
+ .getTagByNameLoader.load(flag ? 'business' : 'computer')
512
+ .then(res => (res ? [res] : [])),
513
+ };
514
+ }
515
+ if (
516
+ description.includes('ע\' העברת מט"ח') ||
517
+ (description.includes('העברת מט"ח') && Math.abs(chargeAmount) < 400) ||
518
+ (description.includes('מטח') && Math.abs(chargeAmount) < 400) ||
519
+ description.includes('F.C.COM') ||
520
+ description.includes('ע.מפעולות-ישיר') ||
521
+ description.includes('ריבית חובה') ||
522
+ description.includes('FEE')
523
+ ) {
524
+ const description = transactions.length
525
+ ? `['${transactions.map(t => t.source_reference).join("','")}']`
526
+ : 'Missing';
527
+ //NOTE: multiple suggestions business
103
528
  return {
104
- description: 'Kraken to Etana transfer',
105
529
  tags: await injector
106
530
  .get(TagsProvider)
107
531
  .getTagByNameLoader.load('financial')
108
532
  .then(res => (res ? [res] : [])),
533
+ description,
109
534
  };
110
535
  }
111
- if (isPoalimIncluded && isEtanaIncluded) {
536
+ if (description.includes('ריבית זכות')) {
537
+ //NOTE: multiple suggestions business
112
538
  return {
113
- description: 'Etana to Poalim transfer',
539
+ description: 'Interest fees on Euro plus',
114
540
  tags: await injector
115
541
  .get(TagsProvider)
116
542
  .getTagByNameLoader.load('financial')
117
543
  .then(res => (res ? [res] : [])),
118
544
  };
119
545
  }
120
- }
121
-
122
- const allBusinesses = await injector.get(BusinessesProvider).getAllBusinesses();
123
- const suggestions: Record<string, Suggestion> = {};
124
- for (const business of allBusinesses) {
125
- if (!business.suggestion_data) continue;
126
- const {
127
- data: suggestionData,
128
- error,
129
- success,
130
- } = suggestionDataSchema.safeParse(business.suggestion_data);
131
- if (!success) {
132
- console.error('Failed to parse suggestion data for business', {
133
- businessId: business.id,
134
- error,
135
- });
136
- continue;
546
+ if (description.includes('פועלים- דמי כרטיס')) {
547
+ //NOTE: multiple suggestions business
548
+ return {
549
+ description: 'Bank creditcard fees',
550
+ tags: await injector
551
+ .get(TagsProvider)
552
+ .getTagByNameLoader.load('financial')
553
+ .then(res => (res ? [res] : [])),
554
+ };
137
555
  }
138
-
139
- if (business.id in allBusinessIds) {
556
+ if (description.includes('אריה קריסטל')) {
557
+ //NOTE: multiple suggestions business
140
558
  return {
141
- description: suggestionData.description,
142
- tags: await Promise.all(
143
- (suggestionData.tags ?? []).map(tag =>
144
- UUID_REGEX.test(tag)
145
- ? injector.get(TagsProvider).getTagByIDLoader.load(tag)
146
- : injector.get(TagsProvider).getTagByNameLoader.load(tag),
147
- ),
148
- ).then(tags => tags.filter(Boolean) as IGetTagsByIDsResult[]),
559
+ description: 'Water bill for 04-2022',
560
+ tags: await injector
561
+ .get(TagsProvider)
562
+ .getTagByNameLoader.load('house')
563
+ .then(res => (res ? [res] : [])),
149
564
  };
150
565
  }
151
-
152
- if (!suggestionData.phrases) continue;
153
-
154
- for (const phrase of suggestionData.phrases) {
155
- suggestions[phrase] = {
156
- description: suggestionData.description,
157
- tags: suggestionData.tags
158
- ? await Promise.all(
159
- suggestionData.tags.map(tag =>
160
- UUID_REGEX.test(tag)
161
- ? injector.get(TagsProvider).getTagByIDLoader.load(tag)
162
- : injector.get(TagsProvider).getTagByNameLoader.load(tag),
163
- ),
164
- ).then(tags => tags.filter(Boolean) as IGetTagsByIDsResult[])
165
- : [],
566
+ if (description.includes('aleksandra')) {
567
+ const current = new Date();
568
+ current.setMonth(current.getMonth() - 1);
569
+ const previousMonth = current.toLocaleString('default', { month: '2-digit' });
570
+ return {
571
+ description: `Software Consulting Fees (${previousMonth}/2023)`,
572
+ tags: await injector
573
+ .get(TagsProvider)
574
+ .getTagByNameLoader.load('business')
575
+ .then(res => (res ? [res] : [])),
166
576
  };
167
577
  }
168
- }
169
-
170
- const transactions = await injector
171
- .get(TransactionsProvider)
172
- .transactionsByChargeIDLoader.load(DbCharge.id);
173
- const description = transactions.map(t => t.source_description).join(' ');
174
-
175
- for (const [phrase, suggestion] of Object.entries(suggestions)) {
176
- if (Array.isArray(phrase) && new RegExp(phrase.join('|')).test(description)) {
177
- return suggestion;
578
+ if (description.includes('denelop')) {
579
+ const current = new Date();
580
+ current.setMonth(current.getMonth() - 1);
581
+ const previousMonth = current.toLocaleString('default', { month: '2-digit' });
582
+ return {
583
+ description: `Software Development and Consulting ${previousMonth}/2023`,
584
+ tags: await injector
585
+ .get(TagsProvider)
586
+ .getTagByNameLoader.load('business')
587
+ .then(res => (res ? [res] : [])),
588
+ };
178
589
  }
179
- if (description.includes(phrase)) {
180
- return suggestion;
590
+ if (chargeAmount === -12_000) {
591
+ const current = new Date();
592
+ current.setMonth(current.getMonth() - 1);
593
+ const previousMonth = current.toLocaleString('default', { month: '2-digit' });
594
+ return {
595
+ description: `${previousMonth}/2022`,
596
+ tags: await injector
597
+ .get(TagsProvider)
598
+ .getTagByNameLoader.load('business')
599
+ .then(res => (res ? [res] : [])),
600
+ };
601
+ }
602
+ if (chargeAmount === -600) {
603
+ return {
604
+ description: 'Matic Zavadlal - April 2021',
605
+ tags: await injector
606
+ .get(TagsProvider)
607
+ .getTagByNameLoader.load('business')
608
+ .then(res => (res ? [res] : [])),
609
+ };
181
610
  }
182
- }
183
611
 
184
- if (
185
- description.includes('ע\' העברת מט"ח') ||
186
- (description.includes('העברת מט"ח') && Math.abs(chargeAmount) < 400) ||
187
- (description.includes('מטח') && Math.abs(chargeAmount) < 400) ||
188
- description.includes('F.C.COM') ||
189
- description.includes('ע.מפעולות-ישיר') ||
190
- description.includes('ריבית חובה') ||
191
- description.includes('FEE')
192
- ) {
193
- const sourceTransaction =
194
- transactions.length === 0
195
- ? 'Missing'
196
- : transactions.length === 1
197
- ? transactions[0].source_reference
198
- : `['${transactions.map(t => t.source_reference).join("','")}']`;
199
- return {
200
- tags: await injector
201
- .get(TagsProvider)
202
- .getTagByNameLoader.load('financial')
203
- .then(res => (res ? [res] : [])),
204
- description: `Fees for source transaction=${sourceTransaction}`,
205
- };
206
- }
207
- if (description.includes('דותן שמחה') || description.includes('שמחה דותן')) {
208
- const current = new Date();
209
- current.setMonth(current.getMonth() - 1);
210
- const previousMonth = current.toLocaleString('default', {
211
- month: '2-digit',
212
- });
213
- return {
214
- description: `${previousMonth}/2022 Salary`,
215
- tags: await injector
216
- .get(TagsProvider)
217
- .getTagByNameLoader.load('business')
218
- .then(res => (res ? [res] : [])),
219
- };
220
- }
221
- if (description.includes('גולדשטין אורי')) {
222
- const current = new Date();
223
- current.setMonth(current.getMonth() - 1);
224
- const previousMonth = current.toLocaleString('default', {
225
- month: '2-digit',
226
- });
227
- return {
228
- description: `${previousMonth}/2022 Salary`,
229
- tags: await injector
230
- .get(TagsProvider)
231
- .getTagByNameLoader.load('business')
232
- .then(res => (res ? [res] : [])),
233
- };
234
- }
235
- if (description.includes('גרדוש')) {
236
- const current = new Date();
237
- current.setMonth(current.getMonth() - 1);
238
- const previousMonth = current.toLocaleString('default', {
239
- month: '2-digit',
240
- });
241
- return {
242
- description: `${previousMonth}/2022 Salary`,
243
- tags: await injector
244
- .get(TagsProvider)
245
- .getTagByNameLoader.load('business')
246
- .then(res => (res ? [res] : [])),
247
- };
248
- }
249
- if (description.includes('תובל')) {
250
- const current = new Date();
251
- current.setMonth(current.getMonth() - 1);
252
- const previousMonth = current.toLocaleString('default', {
253
- month: '2-digit',
254
- });
255
- return {
256
- description: `${previousMonth}/2022 Salary`,
257
- tags: await injector
258
- .get(TagsProvider)
259
- .getTagByNameLoader.load('business')
260
- .then(res => (res ? [res] : [])),
261
- };
262
- }
263
- if (description.includes('מנורה מבטחים פנס')) {
264
- const current = new Date();
265
- current.setMonth(current.getMonth() - 1);
266
- const previousMonth = current.toLocaleString('default', {
267
- month: '2-digit',
268
- });
269
- return {
270
- description: `Pension ${previousMonth}/2022`,
271
- tags: await injector
272
- .get(TagsProvider)
273
- .getTagByNameLoader.load('business')
274
- .then(res => (res ? [res] : [])),
275
- };
276
- }
277
- if (description.includes('פניקס אקסלנס')) {
278
- const current = new Date();
279
- current.setMonth(current.getMonth() - 1);
280
- const previousMonth = current.toLocaleString('default', {
281
- month: '2-digit',
282
- });
283
- return {
284
- description: `Training Fund ${previousMonth}/2022`,
285
- tags: await injector
286
- .get(TagsProvider)
287
- .getTagByNameLoader.load('business')
288
- .then(res => (res ? [res] : [])),
289
- };
290
- }
291
- if (description.includes('מיטב דש גמל ופנס')) {
292
- const current = new Date();
293
- current.setMonth(current.getMonth() - 1);
294
- const previousMonth = current.toLocaleString('default', {
295
- month: '2-digit',
296
- });
297
- return {
298
- description: `Pension ${previousMonth}/2022`,
299
- tags: await injector
300
- .get(TagsProvider)
301
- .getTagByNameLoader.load('business')
302
- .then(res => (res ? [res] : [])),
303
- };
304
- }
305
- if (description.includes('מגדל מקפת')) {
306
- const current = new Date();
307
- current.setMonth(current.getMonth() - 1);
308
- const previousMonth = current.toLocaleString('default', {
309
- month: '2-digit',
310
- });
311
- return {
312
- description: `Pension ${previousMonth}/2022`,
313
- tags: await injector
314
- .get(TagsProvider)
315
- .getTagByNameLoader.load('business')
316
- .then(res => (res ? [res] : [])),
317
- };
318
- }
319
- if (description.includes('מגדל השתלמות')) {
320
- const current = new Date();
321
- current.setMonth(current.getMonth() - 1);
322
- const previousMonth = current.toLocaleString('default', {
323
- month: '2-digit',
324
- });
325
- return {
326
- description: `Training Fund ${previousMonth}/2022`,
327
- tags: await injector
328
- .get(TagsProvider)
329
- .getTagByNameLoader.load('business')
330
- .then(res => (res ? [res] : [])),
331
- };
332
- }
333
- if (description.includes('ביטוח לאומי')) {
334
- const current = new Date();
335
- current.setMonth(current.getMonth() - 1);
336
- const previousMonth = current.toLocaleString('default', {
337
- month: '2-digit',
338
- });
339
- return {
340
- description: `Social Security Deductions for Salaries ${previousMonth}/2022`,
341
- tags: await injector
342
- .get(TagsProvider)
343
- .getTagByNameLoader.load('business')
344
- .then(res => (res ? [res] : [])),
345
- };
346
- }
347
- if (description.includes('LANCE GLOBAL')) {
348
- const current = new Date();
349
- current.setMonth(current.getMonth() - 1);
350
- const previousMonth = current.toLocaleString('default', { month: 'long' });
351
- return {
352
- description: `The Guild Enterprise Support - ${previousMonth} 2022`,
353
- tags: await injector
354
- .get(TagsProvider)
355
- .getTagByNameLoader.load('business')
356
- .then(res => (res ? [res] : [])),
357
- };
358
- }
359
- if (
360
- (description.includes('העברת מט"ח') &&
361
- (description.includes('fbv') || description.includes('fv'))) ||
362
- description.includes('kamil kisiela')
363
- ) {
364
- const current = new Date();
365
- current.setMonth(current.getMonth() - 1);
366
- const previousMonth = current.toLocaleString('default', {
367
- month: '2-digit',
368
- });
369
- return {
370
- description: `Software Development and Consulting ${previousMonth}/23`,
371
- tags: await injector
372
- .get(TagsProvider)
373
- .getTagByNameLoader.load('business')
374
- .then(res => (res ? [res] : [])),
375
- };
376
- }
377
- if (description.includes('slava')) {
378
- const current = new Date();
379
- current.setMonth(current.getMonth() - 1);
380
- const previousMonth = current.toLocaleString('default', { month: '2-digit' });
381
- return {
382
- description: `Web Development Services ${previousMonth}/23`,
383
- tags: await injector
384
- .get(TagsProvider)
385
- .getTagByNameLoader.load('business')
386
- .then(res => (res ? [res] : [])),
387
- };
388
- }
389
- if (description.includes('COURIER PLUS INC')) {
390
- const current = new Date();
391
- current.setMonth(current.getMonth() - 1);
392
- const previousMonth = current.toLocaleString('default', { month: 'long' });
393
- return {
394
- description: `GraphQL Hive Enterprise License - ${previousMonth} 2023`,
395
- tags: await injector
396
- .get(TagsProvider)
397
- .getTagByNameLoader.load('business')
398
- .then(res => (res ? [res] : [])),
399
- };
400
- }
401
- if (description.includes('GOBRANDS')) {
402
- const current = new Date();
403
- current.setMonth(current.getMonth() - 1);
404
- const previousMonth = current.toLocaleString('default', { month: 'long' });
405
- return {
406
- description: `GraphQL Hive Enterprise License - ${previousMonth} 2023`,
407
- tags: await injector
408
- .get(TagsProvider)
409
- .getTagByNameLoader.load('business')
410
- .then(res => (res ? [res] : [])),
411
- };
412
- }
413
- if (description.includes('MEDIC FIRST AI')) {
414
- const current = new Date();
415
- current.setMonth(current.getMonth() - 1);
416
- const previousMonth = current.toLocaleString('default', { month: 'long' });
417
- return {
418
- description: `GraphQL Hive Enterprise License - ${previousMonth} 2023`,
419
- tags: await injector
420
- .get(TagsProvider)
421
- .getTagByNameLoader.load('business')
422
- .then(res => (res ? [res] : [])),
423
- };
424
- }
425
- if (description.includes('מס הכנסה')) {
426
- const flag = description.includes('מס הכנסה ני');
427
- const current = new Date();
428
- current.setMonth(current.getMonth() - 1);
429
- const previousMonth = current.toLocaleString('default', {
430
- month: '2-digit',
431
- });
432
- return {
433
- tags: await injector
434
- .get(TagsProvider)
435
- .getTagByNameLoader.load('business')
436
- .then(res => (res ? [res] : [])),
437
- description: flag
438
- ? `Tax for employees for ${previousMonth}/2022`
439
- : `Advance Tax for ${previousMonth}/2022`,
440
- };
441
- }
442
- if (description.includes('המכס ומעמ-גביי תשלום') || description.includes('CUSTOM + V.A.T')) {
443
- const current = new Date();
444
- current.setMonth(current.getMonth() - 1);
445
- const previousMonth = current.toLocaleString('default', {
446
- month: '2-digit',
447
- });
448
- return {
449
- description: `VAT for ${previousMonth}/2022`,
450
- tags: await injector
451
- .get(TagsProvider)
452
- .getTagByNameLoader.load('business')
453
- .then(res => (res ? [res] : [])),
454
- };
455
- }
456
- if (description.includes('חניון')) {
457
- return {
458
- description: 'Parking',
459
- tags: await injector
460
- .get(TagsProvider)
461
- .getTagByNameLoader.load('transportation')
462
- .then(res => (res ? [res] : [])),
463
- };
464
- }
465
- if (description.includes('deel')) {
466
- return {
467
- description: 'Laurin Salary',
468
- tags: await injector
469
- .get(TagsProvider)
470
- .getTagByNameLoader.load('business')
471
- .then(res => (res ? [res] : [])),
472
- };
473
- }
474
- if (description.includes('GITHUB')) {
475
- const suggested = {
476
- description: 'GitHub Actions',
477
- tags: await injector
478
- .get(TagsProvider)
479
- .getTagByNameLoader.load('business')
480
- .then(res => (res ? [res] : [])),
481
- };
482
- if (chargeAmount <= -2000) {
483
- suggested.description = 'Monthly Sponsor for Benjie, Code-Hex, hayes';
484
- } else if (chargeAmount <= -1000) {
485
- suggested.description = 'Monthly Sponsor for Andarist, warrenday';
486
- } else {
487
- suggested.description = 'GitHub Actions';
488
- }
489
- return suggested;
490
- }
491
- if (chargeAmount === -4329) {
492
- return {
493
- description: 'Office rent',
494
- tags: await injector
495
- .get(TagsProvider)
496
- .getTagByNameLoader.load('business')
497
- .then(res => (res ? [res] : [])),
498
- };
499
- }
500
- if (description.includes('APPLE COM BILL/ITUNES.COM')) {
501
- const flag = chargeAmount === -109.9;
502
- return {
503
- taxCategory: 'אתר',
504
- beneficiaaries: [], // NOTE: used to be ' '
505
- description: flag ? 'LinkedIn' : 'Apple Services',
506
- tags: await injector
507
- .get(TagsProvider)
508
- .getTagByNameLoader.load(flag ? 'business' : 'computer')
509
- .then(res => (res ? [res] : [])),
510
- };
511
- }
512
- if (
513
- description.includes('ע\' העברת מט"ח') ||
514
- (description.includes('העברת מט"ח') && Math.abs(chargeAmount) < 400) ||
515
- (description.includes('מטח') && Math.abs(chargeAmount) < 400) ||
516
- description.includes('F.C.COM') ||
517
- description.includes('ע.מפעולות-ישיר') ||
518
- description.includes('ריבית חובה') ||
519
- description.includes('FEE')
520
- ) {
521
- const description = transactions.length
522
- ? `['${transactions.map(t => t.source_reference).join("','")}']`
523
- : 'Missing';
524
- //NOTE: multiple suggestions business
525
- return {
526
- tags: await injector
527
- .get(TagsProvider)
528
- .getTagByNameLoader.load('financial')
529
- .then(res => (res ? [res] : [])),
530
- description,
531
- };
532
- }
533
- if (description.includes('ריבית זכות')) {
534
- //NOTE: multiple suggestions business
535
- return {
536
- description: 'Interest fees on Euro plus',
537
- tags: await injector
538
- .get(TagsProvider)
539
- .getTagByNameLoader.load('financial')
540
- .then(res => (res ? [res] : [])),
541
- };
542
- }
543
- if (description.includes('פועלים- דמי כרטיס')) {
544
- //NOTE: multiple suggestions business
545
- return {
546
- description: 'Bank creditcard fees',
547
- tags: await injector
548
- .get(TagsProvider)
549
- .getTagByNameLoader.load('financial')
550
- .then(res => (res ? [res] : [])),
551
- };
552
- }
553
- if (description.includes('אריה קריסטל')) {
554
- //NOTE: multiple suggestions business
555
- return {
556
- description: 'Water bill for 04-2022',
557
- tags: await injector
558
- .get(TagsProvider)
559
- .getTagByNameLoader.load('house')
560
- .then(res => (res ? [res] : [])),
561
- };
562
- }
563
- if (description.includes('aleksandra')) {
564
- const current = new Date();
565
- current.setMonth(current.getMonth() - 1);
566
- const previousMonth = current.toLocaleString('default', { month: '2-digit' });
567
- return {
568
- description: `Software Consulting Fees (${previousMonth}/2023)`,
569
- tags: await injector
570
- .get(TagsProvider)
571
- .getTagByNameLoader.load('business')
572
- .then(res => (res ? [res] : [])),
573
- };
574
- }
575
- if (description.includes('denelop')) {
576
- const current = new Date();
577
- current.setMonth(current.getMonth() - 1);
578
- const previousMonth = current.toLocaleString('default', { month: '2-digit' });
579
- return {
580
- description: `Software Development and Consulting ${previousMonth}/2023`,
581
- tags: await injector
582
- .get(TagsProvider)
583
- .getTagByNameLoader.load('business')
584
- .then(res => (res ? [res] : [])),
585
- };
586
- }
587
- if (chargeAmount === -12_000) {
588
- const current = new Date();
589
- current.setMonth(current.getMonth() - 1);
590
- const previousMonth = current.toLocaleString('default', { month: '2-digit' });
591
- return {
592
- description: `${previousMonth}/2022`,
593
- tags: await injector
594
- .get(TagsProvider)
595
- .getTagByNameLoader.load('business')
596
- .then(res => (res ? [res] : [])),
597
- };
598
- }
599
- if (chargeAmount === -600) {
600
- return {
601
- description: 'Matic Zavadlal - April 2021',
602
- tags: await injector
603
- .get(TagsProvider)
604
- .getTagByNameLoader.load('business')
605
- .then(res => (res ? [res] : [])),
606
- };
612
+ return null;
613
+ } catch (error) {
614
+ throw errorSimplifier('Unexpected error fetching missing info suggestions', error);
607
615
  }
608
-
609
- return null;
610
616
  };
611
617
 
612
618
  const commonChargeFields: ChargesModule.ChargeResolvers = {
@@ -630,42 +636,46 @@ export const chargeSuggestionsResolvers: ChargesModule.Resolvers = {
630
636
  throw new GraphQLError('Charge ID is required');
631
637
  }
632
638
 
633
- const [mainCharge, { allBusinessIds, mainBusinessId }] = await Promise.all([
634
- injector
635
- .get(ChargesProvider)
636
- .getChargeByIdLoader.load(chargeId)
637
- .catch(e => {
638
- console.error('Error fetching charge', { chargeId, error: e });
639
- throw new GraphQLError('Error fetching charge');
640
- }),
641
- getChargeBusinesses(chargeId, injector),
642
- ]);
639
+ try {
640
+ const [mainCharge, { allBusinessIds, mainBusinessId }] = await Promise.all([
641
+ injector
642
+ .get(ChargesProvider)
643
+ .getChargeByIdLoader.load(chargeId)
644
+ .catch(e => {
645
+ console.error('Error fetching charge', { chargeId, error: e });
646
+ throw new GraphQLError('Error fetching charge');
647
+ }),
648
+ getChargeBusinesses(chargeId, injector),
649
+ ]);
643
650
 
644
- if (!mainCharge) {
645
- throw new GraphQLError(`Charge not found: ${chargeId}`);
646
- }
651
+ if (!mainCharge) {
652
+ throw new GraphQLError(`Charge not found: ${chargeId}`);
653
+ }
647
654
 
648
- const similarCharges = await injector
649
- .get(ChargesProvider)
650
- .getSimilarCharges({
651
- businessId: mainBusinessId,
652
- businessArray: allBusinessIds,
653
- withMissingTags,
654
- withMissingDescription,
655
- tagsDifferentThan: tagsDifferentThan ? [...tagsDifferentThan] : undefined,
656
- descriptionDifferentThan,
657
- ownerId: mainCharge.owner_id,
658
- })
659
- .catch(e => {
660
- console.error('Error fetching similar charges:', {
661
- chargeId,
655
+ const similarCharges = await injector
656
+ .get(ChargesProvider)
657
+ .getSimilarCharges({
662
658
  businessId: mainBusinessId,
663
659
  businessArray: allBusinessIds,
664
- error: e.message,
660
+ withMissingTags,
661
+ withMissingDescription,
662
+ tagsDifferentThan: tagsDifferentThan ? [...tagsDifferentThan] : undefined,
663
+ descriptionDifferentThan,
664
+ ownerId: mainCharge.owner_id,
665
+ })
666
+ .catch(e => {
667
+ console.error('Error fetching similar charges:', {
668
+ chargeId,
669
+ businessId: mainBusinessId,
670
+ businessArray: allBusinessIds,
671
+ error: e.message,
672
+ });
673
+ throw new GraphQLError('Error fetching similar charges');
665
674
  });
666
- throw new GraphQLError('Error fetching similar charges');
667
- });
668
- return similarCharges;
675
+ return similarCharges;
676
+ } catch (error) {
677
+ throw errorSimplifier('Unexpected error fetching similar charges', error);
678
+ }
669
679
  },
670
680
  similarChargesByBusiness: async (
671
681
  _,
@@ -676,25 +686,29 @@ export const chargeSuggestionsResolvers: ChargesModule.Resolvers = {
676
686
  throw new GraphQLError('Business ID is required');
677
687
  }
678
688
 
679
- const ownerId = ownerIdInput?.trim() || adminContext.defaultAdminBusinessId;
689
+ try {
690
+ const ownerId = ownerIdInput?.trim() || adminContext.defaultAdminBusinessId;
680
691
 
681
- const similarCharges = await injector
682
- .get(ChargesProvider)
683
- .getSimilarCharges({
684
- businessId,
685
- tagsDifferentThan: tagsDifferentThan ? [...tagsDifferentThan] : undefined,
686
- descriptionDifferentThan,
687
- ownerId,
688
- })
689
- .catch(e => {
690
- console.error('Error fetching similar charges:', {
692
+ const similarCharges = await injector
693
+ .get(ChargesProvider)
694
+ .getSimilarCharges({
691
695
  businessId,
696
+ tagsDifferentThan: tagsDifferentThan ? [...tagsDifferentThan] : undefined,
697
+ descriptionDifferentThan,
692
698
  ownerId,
693
- error: e.message,
699
+ })
700
+ .catch(e => {
701
+ console.error('Error fetching similar charges:', {
702
+ businessId,
703
+ ownerId,
704
+ error: e.message,
705
+ });
706
+ throw new GraphQLError('Error fetching similar charges by business');
694
707
  });
695
- throw new GraphQLError('Error fetching similar charges by business');
696
- });
697
- return similarCharges;
708
+ return similarCharges;
709
+ } catch (error) {
710
+ throw errorSimplifier('Unexpected error fetching similar charges by business', error);
711
+ }
698
712
  },
699
713
  },
700
714
  CommonCharge: commonChargeFields,