@zeniai/client-epic-state 5.1.58 → 5.1.60

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 (62) hide show
  1. package/lib/entity/accountRecon/accountReconPayload.d.ts +1 -1
  2. package/lib/entity/accountRecon/accountReconReducer.js +15 -1
  3. package/lib/esm/entity/accountRecon/accountReconReducer.js +15 -1
  4. package/lib/esm/index.js +1 -2
  5. package/lib/esm/view/commonVendorView/transactionVendorView/epics/saveTransactionVendorEpic.js +0 -1
  6. package/lib/esm/view/commonVendorView/transactionVendorView/transactionVendorViewReducer.js +1 -2
  7. package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +3 -3
  8. package/lib/esm/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +2 -3
  9. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/backgroundRefetchReviewTabEpic.js +2 -2
  10. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +1 -1
  11. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +4 -4
  12. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/initializeTransactionCategorizationLocalDataEpic.js +2 -4
  13. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/markTransactionAsNotMiscategorizedEpic.js +2 -2
  14. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/saveTransactionCategorizationEpic.js +2 -2
  15. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/triggerReviewTabRefetchEpic.js +2 -2
  16. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/updateTransactionCategorizationEpic.js +2 -2
  17. package/lib/esm/view/expenseAutomationView/expenseAutomationViewReducer.js +3 -4
  18. package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +14 -25
  19. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +21 -32
  20. package/lib/esm/view/expenseAutomationView/selectors/statementParseViewSelector.js +0 -224
  21. package/lib/esm/view/onboardingView/customerView/onboardingCustomerViewSelector.js +2 -1
  22. package/lib/esm/view/recommendation/fetchEntityRecommendationsByTransactionIdEpic.js +2 -2
  23. package/lib/esm/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +2 -2
  24. package/lib/esm/view/recommendation/recommendationReducer.js +1 -2
  25. package/lib/esm/view/transactionDetail/epics/saveTransactionDetailEpic.js +2 -2
  26. package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +2 -2
  27. package/lib/esm/view/transactionDetail/transactionDetailReducer.js +1 -2
  28. package/lib/index.d.ts +2 -3
  29. package/lib/index.js +38 -42
  30. package/lib/view/commonVendorView/transactionVendorView/epics/saveTransactionVendorEpic.js +0 -1
  31. package/lib/view/commonVendorView/transactionVendorView/transactionVendorViewReducer.d.ts +1 -2
  32. package/lib/view/commonVendorView/transactionVendorView/transactionVendorViewReducer.js +1 -2
  33. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +3 -3
  34. package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +2 -3
  35. package/lib/view/expenseAutomationView/epics/transactionCategorization/backgroundRefetchReviewTabEpic.js +2 -2
  36. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +1 -1
  37. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +4 -4
  38. package/lib/view/expenseAutomationView/epics/transactionCategorization/initializeTransactionCategorizationLocalDataEpic.js +2 -4
  39. package/lib/view/expenseAutomationView/epics/transactionCategorization/markTransactionAsNotMiscategorizedEpic.js +2 -2
  40. package/lib/view/expenseAutomationView/epics/transactionCategorization/saveTransactionCategorizationEpic.js +2 -2
  41. package/lib/view/expenseAutomationView/epics/transactionCategorization/triggerReviewTabRefetchEpic.js +2 -2
  42. package/lib/view/expenseAutomationView/epics/transactionCategorization/updateTransactionCategorizationEpic.js +2 -2
  43. package/lib/view/expenseAutomationView/expenseAutomationViewReducer.d.ts +2 -5
  44. package/lib/view/expenseAutomationView/expenseAutomationViewReducer.js +3 -4
  45. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +5 -5
  46. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +14 -25
  47. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +10 -23
  48. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +21 -32
  49. package/lib/view/expenseAutomationView/selectors/statementParseViewSelector.d.ts +1 -15
  50. package/lib/view/expenseAutomationView/selectors/statementParseViewSelector.js +1 -233
  51. package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +7 -44
  52. package/lib/view/onboardingView/customerView/onboardingCustomerViewSelector.d.ts +1 -0
  53. package/lib/view/onboardingView/customerView/onboardingCustomerViewSelector.js +2 -1
  54. package/lib/view/recommendation/fetchEntityRecommendationsByTransactionIdEpic.js +2 -2
  55. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +2 -2
  56. package/lib/view/recommendation/recommendationReducer.d.ts +1 -3
  57. package/lib/view/recommendation/recommendationReducer.js +1 -2
  58. package/lib/view/transactionDetail/epics/saveTransactionDetailEpic.js +2 -2
  59. package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +2 -2
  60. package/lib/view/transactionDetail/transactionDetailReducer.d.ts +1 -3
  61. package/lib/view/transactionDetail/transactionDetailReducer.js +1 -2
  62. package/package.json +1 -1
@@ -121,7 +121,7 @@ const expenseAutomationTransactionsView = createSlice({
121
121
  reducers: {
122
122
  fetchTransactionCategorizationView: {
123
123
  prepare(selectedTab, period, cacheOverride = false, keepExistingListItems = false, searchString, // when this is defined the output should go to search result IDs
124
- pageToken, refreshViewInBackground = false, resetListItems = false, isUncategorizedExpenseCategoryEnabled) {
124
+ pageToken, refreshViewInBackground = false, resetListItems = false) {
125
125
  return {
126
126
  payload: {
127
127
  selectedTab,
@@ -132,7 +132,6 @@ const expenseAutomationTransactionsView = createSlice({
132
132
  cacheOverride,
133
133
  refreshViewInBackground,
134
134
  resetListItems,
135
- isUncategorizedExpenseCategoryEnabled,
136
135
  },
137
136
  };
138
137
  },
@@ -200,7 +199,7 @@ const expenseAutomationTransactionsView = createSlice({
200
199
  }
201
200
  },
202
201
  prepare(selectedTab, period, cacheOverride = false, keepExistingListItems = false, searchString, // when this is defined the output should go to search result IDs
203
- pageToken, refreshViewInBackground = false, resetListItems, isUncategorizedExpenseCategoryEnabled) {
202
+ pageToken, refreshViewInBackground = false, resetListItems) {
204
203
  return {
205
204
  payload: {
206
205
  selectedTab,
@@ -211,13 +210,12 @@ const expenseAutomationTransactionsView = createSlice({
211
210
  cacheOverride,
212
211
  refreshViewInBackground,
213
212
  resetListItems,
214
- isUncategorizedExpenseCategoryEnabled,
215
213
  },
216
214
  };
217
215
  },
218
216
  },
219
217
  initializeTransactionCategorizationViewLocalData: {
220
- prepare(selectedTab, transactionIds, selectedPeriod, keepExistingListItems = false, pageToken, totalCount, lineItemsByTransactionIds, refreshViewInBackground = false, isUncategorizedExpenseCategoryEnabled) {
218
+ prepare(selectedTab, transactionIds, selectedPeriod, keepExistingListItems = false, pageToken, totalCount, lineItemsByTransactionIds, refreshViewInBackground = false) {
221
219
  return {
222
220
  payload: {
223
221
  selectedTab,
@@ -228,7 +226,6 @@ const expenseAutomationTransactionsView = createSlice({
228
226
  totalCount,
229
227
  lineItemsByTransactionIds,
230
228
  refreshViewInBackground,
231
- isUncategorizedExpenseCategoryEnabled,
232
229
  },
233
230
  };
234
231
  },
@@ -332,13 +329,12 @@ const expenseAutomationTransactionsView = createSlice({
332
329
  });
333
330
  },
334
331
  saveTransactionCategorization: {
335
- prepare(selectedTab, transactionIds, cotTrackingByTransactionId, isUncategorizedExpenseCategoryEnabled) {
332
+ prepare(selectedTab, transactionIds, cotTrackingByTransactionId) {
336
333
  return {
337
334
  payload: {
338
335
  selectedTab,
339
336
  transactionIds,
340
337
  cotTrackingByTransactionId,
341
- isUncategorizedExpenseCategoryEnabled,
342
338
  },
343
339
  };
344
340
  },
@@ -412,21 +408,20 @@ const expenseAutomationTransactionsView = createSlice({
412
408
  fetchState: 'In-Progress',
413
409
  };
414
410
  },
415
- prepare(selectedTab, transactionIds, transactionSaveUpdates, cotTrackingByTransactionId, isUncategorizedExpenseCategoryEnabled) {
411
+ prepare(selectedTab, transactionIds, transactionSaveUpdates, cotTrackingByTransactionId) {
416
412
  return {
417
413
  payload: {
418
414
  selectedTab,
419
415
  transactionIds,
420
416
  transactionSaveUpdates,
421
417
  cotTrackingByTransactionId,
422
- isUncategorizedExpenseCategoryEnabled,
423
418
  },
424
419
  };
425
420
  },
426
421
  },
427
422
  setAllItemsToCategoryClassInLocalDataForCategorization: {
428
423
  reducer(draft, action) {
429
- const { vendorId, customerId, selectedAccount, selectedClassBase, selectedProjectBase, transactions, transactionId, lineId, selectedTab, uncategorizedAccounts, isAccountingClassesEnabled, isUncategorizedExpenseCategoryEnabled, } = action.payload;
424
+ const { vendorId, customerId, selectedAccount, selectedClassBase, selectedProjectBase, transactions, transactionId, lineId, selectedTab, isAccountingClassesEnabled, } = action.payload;
430
425
  const transactionLocalData = recordGet(draft.transactionCategorizationView[selectedTab]
431
426
  .transactionReviewLocalDataById, transactionId, undefined);
432
427
  const existingAccount = transactionLocalData?.transactionReviewLocalData.lineItemById[lineId]
@@ -452,7 +447,7 @@ const expenseAutomationTransactionsView = createSlice({
452
447
  const selectedCheckBoxTransactionIds = draft.transactionCategorizationView[selectedTab]
453
448
  .selectedCheckBoxTransactionIds;
454
449
  if (selectedTransaction != null &&
455
- shouldAutoSelectAndAdd(selectedTransaction, newTransactionLocalData, selectedCheckBoxTransactionIds, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled)) {
450
+ shouldAutoSelectAndAdd(selectedTransaction, newTransactionLocalData, selectedCheckBoxTransactionIds, isAccountingClassesEnabled)) {
456
451
  draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
457
452
  ...selectedCheckBoxTransactionIds,
458
453
  transactionId,
@@ -475,7 +470,7 @@ const expenseAutomationTransactionsView = createSlice({
475
470
  : existingProjectId !== selectedProjectBase?.projectId
476
471
  ? 'project'
477
472
  : 'class';
478
- const { localData, similarTransactionUpdated } = toSetAllLineItemsToCategoryClass(draft.transactionCategorizationView[selectedTab], transaction, transactionId, lineId, transactionLocalData.transactionReviewLocalData, updatedItem, uncategorizedAccounts, selectedTab, vendorId, customerId, selectedAccount, selectedClassBase, selectedProjectBase, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled);
473
+ const { localData, similarTransactionUpdated } = toSetAllLineItemsToCategoryClass(draft.transactionCategorizationView[selectedTab], transaction, transactionId, lineId, transactionLocalData.transactionReviewLocalData, updatedItem, selectedTab, vendorId, customerId, selectedAccount, selectedClassBase, selectedProjectBase, isAccountingClassesEnabled);
479
474
  draft.transactionCategorizationView[selectedTab].transactionReviewLocalDataById[transaction.id] = {
480
475
  transactionId: transaction.id,
481
476
  transactionReviewLocalData: localData,
@@ -494,7 +489,7 @@ const expenseAutomationTransactionsView = createSlice({
494
489
  ...dirtyIds,
495
490
  ]);
496
491
  },
497
- prepare(selectedTab, transactionId, lineId, transactions, uncategorizedAccounts, vendorId, customerId, selectedAccount, selectedClassBase, lineEntity, recommendations, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled, selectedProjectBase) {
492
+ prepare(selectedTab, transactionId, lineId, transactions, uncategorizedAccounts, vendorId, customerId, selectedAccount, selectedClassBase, lineEntity, recommendations, isAccountingClassesEnabled, selectedProjectBase) {
498
493
  return {
499
494
  payload: {
500
495
  selectedTab,
@@ -510,13 +505,12 @@ const expenseAutomationTransactionsView = createSlice({
510
505
  recommendations,
511
506
  uncategorizedAccounts,
512
507
  isAccountingClassesEnabled,
513
- isUncategorizedExpenseCategoryEnabled,
514
508
  },
515
509
  };
516
510
  },
517
511
  },
518
512
  setEntityRecommendationForLineIdsForCategorization: {
519
- prepare(selectedTab, transactionId, transaction, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled) {
513
+ prepare(selectedTab, transactionId, transaction, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedAccounts, isAccountingClassesEnabled) {
520
514
  return {
521
515
  payload: {
522
516
  selectedTab,
@@ -528,16 +522,15 @@ const expenseAutomationTransactionsView = createSlice({
528
522
  recommendationWithCOTByLineId,
529
523
  uncategorizedAccounts,
530
524
  isAccountingClassesEnabled,
531
- isUncategorizedExpenseCategoryEnabled,
532
525
  },
533
526
  };
534
527
  },
535
528
  reducer(draft, action) {
536
- const { entity, transaction, transactionId, selectedTab, lineIds, uncategorizedAccounts, isAccountingClassesEnabled, isUncategorizedExpenseCategoryEnabled, } = action.payload;
529
+ const { entity, transaction, transactionId, selectedTab, lineIds, isAccountingClassesEnabled, } = action.payload;
537
530
  const transactionLocalData = recordGet(draft.transactionCategorizationView[selectedTab]
538
531
  .transactionReviewLocalDataById, transactionId.id, undefined);
539
532
  if (transactionLocalData != null) {
540
- const newLocalData = setEntityRecommendationForLineIdInLocalData(draft.transactionCategorizationView[selectedTab], transaction, transactionLocalData.transactionReviewLocalData, entity, lineIds, uncategorizedAccounts, action.payload.recommendationWithCOTByLineId, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled);
533
+ const newLocalData = setEntityRecommendationForLineIdInLocalData(draft.transactionCategorizationView[selectedTab], transaction, transactionLocalData.transactionReviewLocalData, entity, lineIds, action.payload.recommendationWithCOTByLineId, isAccountingClassesEnabled);
541
534
  // Release the per-line fetch flag for every line this fetch
542
535
  // covered. Done in-place on the freshly returned local data
543
536
  // (the helper produces a new mutable object), before we write
@@ -710,7 +703,7 @@ const expenseAutomationTransactionsView = createSlice({
710
703
  action.payload.status;
711
704
  },
712
705
  updateSelectedCustomerForTransaction(draft, action) {
713
- const { transactionId, lineId, updatedCustomer, selectedTransaction, selectedTab, uncategorizedAccounts, isAccountingClassesEnabled, isUncategorizedExpenseCategoryEnabled, } = action.payload;
706
+ const { transactionId, lineId, updatedCustomer, selectedTransaction, selectedTab, isAccountingClassesEnabled, } = action.payload;
714
707
  const transactionLocalData = recordGet(draft.transactionCategorizationView[selectedTab]
715
708
  .transactionReviewLocalDataById, transactionId, undefined);
716
709
  if (transactionLocalData != null) {
@@ -763,7 +756,7 @@ const expenseAutomationTransactionsView = createSlice({
763
756
  .selectedCheckBoxTransactionIds;
764
757
  if (newTransactionLocalData.customer != null &&
765
758
  newTransactionLocalData.customer.id != null &&
766
- shouldAutoSelectAndAdd(selectedTransaction, newTransactionLocalData, selectedCheckBoxTransactionIds, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled)) {
759
+ shouldAutoSelectAndAdd(selectedTransaction, newTransactionLocalData, selectedCheckBoxTransactionIds, isAccountingClassesEnabled)) {
767
760
  draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
768
761
  ...selectedCheckBoxTransactionIds,
769
762
  transactionId,
@@ -780,7 +773,7 @@ const expenseAutomationTransactionsView = createSlice({
780
773
  }
781
774
  },
782
775
  updateSelectedVendorForTransaction(draft, action) {
783
- const { transactionId, lineId, updatedVendor, selectedTransaction, selectedTab, uncategorizedAccounts, isAccountingClassesEnabled, isUncategorizedExpenseCategoryEnabled, } = action.payload;
776
+ const { transactionId, lineId, updatedVendor, selectedTransaction, selectedTab, isAccountingClassesEnabled, } = action.payload;
784
777
  const transactionLocalData = recordGet(draft.transactionCategorizationView[selectedTab]
785
778
  .transactionReviewLocalDataById, transactionId, undefined);
786
779
  if (transactionLocalData != null) {
@@ -837,7 +830,7 @@ const expenseAutomationTransactionsView = createSlice({
837
830
  .selectedCheckBoxTransactionIds;
838
831
  if (newTransactionLocalData.vendor != null &&
839
832
  newTransactionLocalData.vendor.id != null &&
840
- shouldAutoSelectAndAdd(selectedTransaction, newTransactionLocalData, selectedCheckBoxTransactionIds, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled)) {
833
+ shouldAutoSelectAndAdd(selectedTransaction, newTransactionLocalData, selectedCheckBoxTransactionIds, isAccountingClassesEnabled)) {
841
834
  draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
842
835
  ...selectedCheckBoxTransactionIds,
843
836
  transactionId,
@@ -885,12 +878,11 @@ const expenseAutomationTransactionsView = createSlice({
885
878
  error: undefined,
886
879
  };
887
880
  },
888
- prepare(selectedTab, transactionsInReview, isUncategorizedExpenseCategoryEnabled) {
881
+ prepare(selectedTab, transactionsInReview) {
889
882
  return {
890
883
  payload: {
891
884
  selectedTab,
892
885
  transactionsInReview,
893
- isUncategorizedExpenseCategoryEnabled,
894
886
  },
895
887
  };
896
888
  },
@@ -1000,19 +992,17 @@ const expenseAutomationTransactionsView = createSlice({
1000
992
  },
1001
993
  },
1002
994
  syncTransactionCategorizationFromDetailSave: {
1003
- prepare(transactionId, updatedTransaction, pendingReviewLineIds, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled) {
995
+ prepare(transactionId, updatedTransaction, pendingReviewLineIds) {
1004
996
  return {
1005
997
  payload: {
1006
998
  transactionId,
1007
999
  updatedTransaction,
1008
1000
  pendingReviewLineIds,
1009
- uncategorizedIncomeExpense,
1010
- isUncategorizedExpenseCategoryEnabled,
1011
1001
  },
1012
1002
  };
1013
1003
  },
1014
1004
  reducer(draft, action) {
1015
- const { transactionId, updatedTransaction, pendingReviewLineIds, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled, } = action.payload;
1005
+ const { transactionId, updatedTransaction, pendingReviewLineIds, } = action.payload;
1016
1006
  const txnId = transactionId.id;
1017
1007
  const reviewTabView = draft.transactionCategorizationView.review;
1018
1008
  const autoTabView = draft.transactionCategorizationView.autoCategorized;
@@ -1034,7 +1024,7 @@ const expenseAutomationTransactionsView = createSlice({
1034
1024
  }
1035
1025
  // Partially reviewed: rebuild review tab local data with pending review lines
1036
1026
  if (existsInReview) {
1037
- const newLocalData = toTransactionDetailLocalData(updatedTransaction, 'review', pendingReviewLineIds, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled);
1027
+ const newLocalData = toTransactionDetailLocalData(updatedTransaction, 'review', pendingReviewLineIds);
1038
1028
  reviewTabView.transactionReviewLocalDataById[txnId] = {
1039
1029
  transactionId: txnId,
1040
1030
  transactionReviewLocalData: {
@@ -1053,11 +1043,10 @@ const expenseAutomationTransactionsView = createSlice({
1053
1043
  },
1054
1044
  },
1055
1045
  backgroundRefetchReviewTab: {
1056
- prepare(period, isUncategorizedExpenseCategoryEnabled) {
1046
+ prepare(period) {
1057
1047
  return {
1058
1048
  payload: {
1059
1049
  period,
1060
- isUncategorizedExpenseCategoryEnabled,
1061
1050
  },
1062
1051
  };
1063
1052
  },
@@ -64,117 +64,6 @@ export const getDateFilteredDeletedTransactionIds = (allParsedTransactions, stat
64
64
  !isStatementTransactionInPeriod(transaction.transactionDate, statementPeriod.statementStartDate, statementPeriod.statementEndDate))
65
65
  .map((transaction) => transaction.statementTransactionId);
66
66
  };
67
- const roundCurrency = (value) => Math.round(value * 100) / 100;
68
- const toApiDateString = (value) => {
69
- if (value == null || value === '') {
70
- return '';
71
- }
72
- return date(value).format('YYYY-MM-DD');
73
- };
74
- const computeStatementTransactionTotals = (transactions) => {
75
- const totalDeposits = roundCurrency(transactions
76
- .filter((txn) => txn.transactionDirection === 'credit')
77
- .reduce((sum, txn) => sum + Math.abs(txn.amount ?? 0), 0));
78
- const totalPayments = roundCurrency(transactions
79
- .filter((txn) => txn.transactionDirection === 'debit')
80
- .reduce((sum, txn) => sum + Math.abs(txn.amount ?? 0), 0));
81
- return { totalDeposits, totalPayments };
82
- };
83
- const computeStatementClosingBalance = (openingBalance, totalDeposits, totalPayments, accountType) => roundCurrency(accountType === 'credit_card'
84
- ? openingBalance + totalPayments - totalDeposits
85
- : openingBalance + totalDeposits - totalPayments);
86
- const filterFormTransactionsInPeriod = (transactions, statementStartDate, statementEndDate) => {
87
- if (statementStartDate === '' || statementEndDate === '') {
88
- return transactions;
89
- }
90
- const periodStart = date(statementStartDate).startOf('day');
91
- const periodEnd = date(statementEndDate).startOf('day');
92
- return transactions.filter((txn) => {
93
- if (txn.transactionDate === '') {
94
- return true;
95
- }
96
- const txnDate = date(txn.transactionDate).startOf('day');
97
- return (txnDate.isSameOrAfter(periodStart, 'day') &&
98
- txnDate.isSameOrBefore(periodEnd, 'day'));
99
- });
100
- };
101
- export const isStatementParseTransactionFieldChange = (changedField) => changedField === 'transactions' ||
102
- changedField?.startsWith('transactions.') === true;
103
- const isStatementParseBalanceAffectingTransactionFieldChange = (changedField) => {
104
- if (changedField === 'transactions') {
105
- return true;
106
- }
107
- if (changedField?.startsWith('transactions.') !== true) {
108
- return false;
109
- }
110
- return !changedField.endsWith('.transactionMemo');
111
- };
112
- export const isStatementParseManualBalanceField = (field) => field === 'totalDeposits' ||
113
- field === 'totalPayments' ||
114
- field === 'closingBalance';
115
- export const shouldRecalculateStatementParseBalances = (changedField) => isStatementParseBalanceAffectingTransactionFieldChange(changedField) ||
116
- changedField === 'statementStartDate' ||
117
- changedField === 'statementEndDate';
118
- export const resolveStatementParseBalanceFields = (formView, changedField, accountType) => {
119
- const inPeriodTransactions = filterFormTransactionsInPeriod(formView.transactions, formView.statementStartDate, formView.statementEndDate);
120
- const { totalDeposits, totalPayments } = computeStatementTransactionTotals(inPeriodTransactions);
121
- if (!shouldRecalculateStatementParseBalances(changedField)) {
122
- return {
123
- openingBalance: formView.openingBalance,
124
- closingBalance: formView.closingBalance,
125
- totalDeposits: formView.totalDeposits,
126
- totalPayments: formView.totalPayments,
127
- };
128
- }
129
- return {
130
- openingBalance: formView.openingBalance,
131
- totalDeposits,
132
- totalPayments,
133
- closingBalance: computeStatementClosingBalance(formView.openingBalance, totalDeposits, totalPayments, accountType),
134
- };
135
- };
136
- export const areStatementParseBalancesConsistent = (formView, accountType) => {
137
- // Validate the four balance fields against each other (what the user sees),
138
- // not against recomputed transaction totals. Manual deposits/payments edits
139
- // are allowed as long as closing matches the account-type formula.
140
- return (roundCurrency(formView.closingBalance) ===
141
- computeStatementClosingBalance(formView.openingBalance, formView.totalDeposits, formView.totalPayments, accountType));
142
- };
143
- const mapParsedTransactionToFormRow = (transaction, index) => ({
144
- id: transaction.statementTransactionId || `parsed-${index}`,
145
- transactionDate: toApiDateString(transaction.transactionDate),
146
- transactionMemo: transaction.transactionMemo,
147
- amount: transaction.amount,
148
- transactionDirection: transaction.transactionDirection,
149
- statementTransactionId: transaction.statementTransactionId,
150
- });
151
- const mapLocalTransactionToFormRow = (transaction, id) => ({
152
- id,
153
- transactionDate: toApiDateString(transaction.transactionDate),
154
- transactionMemo: transaction.transactionMemo,
155
- amount: transaction.amount,
156
- transactionDirection: transaction.transactionDirection,
157
- statementTransactionId: transaction.statementTransactionId,
158
- });
159
- const buildStatementParseFormTransactions = (originalTransactions, localData) => {
160
- const deletedIdSet = new Set(localData.statementTransactions?.deletedIds ?? []);
161
- const updatedById = new Map((localData.statementTransactions?.updated ?? [])
162
- .filter((transaction) => transaction.statementTransactionId != null)
163
- .map((transaction) => [
164
- transaction.statementTransactionId,
165
- transaction,
166
- ]));
167
- const persistedTransactions = originalTransactions
168
- .filter((transaction) => !deletedIdSet.has(transaction.statementTransactionId))
169
- .map((transaction, index) => {
170
- const updated = updatedById.get(transaction.statementTransactionId);
171
- return updated != null
172
- ? mapLocalTransactionToFormRow(updated, transaction.statementTransactionId)
173
- : mapParsedTransactionToFormRow(transaction, index);
174
- });
175
- const addedTransactions = (localData.statementTransactions?.added ?? []).map((transaction, index) => mapLocalTransactionToFormRow(transaction, `added-${index}`));
176
- return [...persistedTransactions, ...addedTransactions];
177
- };
178
67
  export const mergeStatementParseDeletedTransactionIds = (originalTransactions, statementPeriod, currentTransactionIds) => {
179
68
  const dateFilteredDeletedIds = getDateFilteredDeletedTransactionIds(originalTransactions, statementPeriod);
180
69
  const dateFilteredDeletedIdSet = new Set(dateFilteredDeletedIds);
@@ -185,116 +74,3 @@ export const mergeStatementParseDeletedTransactionIds = (originalTransactions, s
185
74
  .map((transaction) => transaction.statementTransactionId);
186
75
  return [...new Set([...userDeletedIds, ...dateFilteredDeletedIds])];
187
76
  };
188
- const resolveStatementMetaDates = (parsedStatementMeta, localMeta) => ({
189
- statementStartDate: localMeta?.statementStartDate != null && localMeta.statementStartDate !== ''
190
- ? localMeta.statementStartDate
191
- : (parsedStatementMeta?.statementStartDate ?? ''),
192
- statementEndDate: localMeta?.statementEndDate != null && localMeta.statementEndDate !== ''
193
- ? localMeta.statementEndDate
194
- : (parsedStatementMeta?.statementEndDate ?? ''),
195
- });
196
- export const getStatementParseFormView = ({ accountType, parsedStatementMeta, originalTransactions, statementUpdateLocalData, }) => {
197
- const transactions = statementUpdateLocalData != null
198
- ? buildStatementParseFormTransactions(originalTransactions, statementUpdateLocalData)
199
- : originalTransactions.map(mapParsedTransactionToFormRow);
200
- const localMeta = statementUpdateLocalData?.statementMeta;
201
- const { statementStartDate, statementEndDate } = resolveStatementMetaDates(parsedStatementMeta, localMeta);
202
- const { totalDeposits, totalPayments } = computeStatementTransactionTotals(filterFormTransactionsInPeriod(transactions, statementStartDate, statementEndDate));
203
- const openingBalance = localMeta?.openingBalance ?? parsedStatementMeta?.openingBalance ?? 0;
204
- const computedClosingBalance = computeStatementClosingBalance(openingBalance, totalDeposits, totalPayments, accountType);
205
- return {
206
- statementStartDate,
207
- statementEndDate,
208
- openingBalance,
209
- closingBalance: localMeta?.closingBalance ?? computedClosingBalance,
210
- totalDeposits: localMeta?.totalDeposits ?? totalDeposits,
211
- totalPayments: localMeta?.totalPayments ?? totalPayments,
212
- transactions: filterFormTransactionsInPeriod(transactions, statementStartDate, statementEndDate),
213
- };
214
- };
215
- export const toStatementUpdateLocalDataFromFormView = ({ accountType, formView, parsedStatementMeta, originalTransactions, changedField, }) => {
216
- const balanceFields = resolveStatementParseBalanceFields(formView, changedField, accountType);
217
- const currentTransactionIds = new Set(formView.transactions
218
- .map((transaction) => transaction.statementTransactionId)
219
- .filter((id) => id != null && id !== ''));
220
- const added = [];
221
- const updated = [];
222
- formView.transactions.forEach((transaction) => {
223
- const transactionDate = toApiDateString(transaction.transactionDate);
224
- if (transaction.statementTransactionId == null) {
225
- if (transaction.transactionDirection != null) {
226
- added.push({
227
- amount: transaction.amount,
228
- transactionDate,
229
- transactionDirection: transaction.transactionDirection,
230
- transactionMemo: transaction.transactionMemo,
231
- });
232
- }
233
- return;
234
- }
235
- const original = originalTransactions.find((candidate) => candidate.statementTransactionId === transaction.statementTransactionId);
236
- if (original != null &&
237
- (original.amount !== transaction.amount ||
238
- toApiDateString(original.transactionDate) !== transactionDate ||
239
- original.transactionMemo !== transaction.transactionMemo)) {
240
- updated.push({
241
- amount: transaction.amount,
242
- transactionDate,
243
- transactionDirection: transaction.transactionDirection,
244
- transactionMemo: transaction.transactionMemo,
245
- statementTransactionId: transaction.statementTransactionId,
246
- });
247
- }
248
- });
249
- const statementPeriod = {
250
- statementStartDate: toApiDateString(formView.statementStartDate),
251
- statementEndDate: toApiDateString(formView.statementEndDate),
252
- };
253
- const deletedIds = mergeStatementParseDeletedTransactionIds(originalTransactions, statementPeriod, currentTransactionIds);
254
- const deletedIdSet = new Set(deletedIds);
255
- const inPeriodAdded = filterFormTransactionsInPeriod(added, statementPeriod.statementStartDate, statementPeriod.statementEndDate);
256
- const inPeriodUpdated = updated.filter((transaction) => transaction.statementTransactionId != null &&
257
- !deletedIdSet.has(transaction.statementTransactionId));
258
- return {
259
- statementMeta: {
260
- closingBalance: balanceFields.closingBalance,
261
- openingBalance: balanceFields.openingBalance,
262
- statementDataStatus: parsedStatementMeta?.statementDataStatus ?? {
263
- code: '',
264
- label: '',
265
- },
266
- statementEndDate: statementPeriod.statementEndDate,
267
- statementStartDate: statementPeriod.statementStartDate,
268
- statementStatus: parsedStatementMeta?.statementStatus ?? {
269
- code: '',
270
- label: '',
271
- },
272
- statementUploadId: parsedStatementMeta?.statementUploadId ?? '',
273
- totalDeposits: balanceFields.totalDeposits,
274
- totalPayments: balanceFields.totalPayments,
275
- },
276
- statementTransactions: {
277
- added: inPeriodAdded,
278
- deletedIds,
279
- updated: inPeriodUpdated,
280
- },
281
- };
282
- };
283
- export const applyStatementParseFormChange = ({ accountType, formView, changedField, parsedStatementMeta, originalTransactions, }) => {
284
- const balanceFields = resolveStatementParseBalanceFields(formView, changedField, accountType);
285
- const shouldRecalculate = shouldRecalculateStatementParseBalances(changedField);
286
- const mergedFormView = shouldRecalculate
287
- ? { ...formView, ...balanceFields }
288
- : formView;
289
- return {
290
- didRecalculateBalances: shouldRecalculate,
291
- formView: mergedFormView,
292
- localData: toStatementUpdateLocalDataFromFormView({
293
- accountType,
294
- formView: mergedFormView,
295
- parsedStatementMeta,
296
- originalTransactions,
297
- changedField,
298
- }),
299
- };
300
- };
@@ -11,7 +11,7 @@ import { getCompanyAndIdentityDetails, } from '../../spendManagement/commonSetup
11
11
  import { ALL_ONBOARDING_STEPS, ALL_ZENI_USER_BOOKKEEPING_ONBOARDING_STEPS, ALL_ZENI_USER_ONBOARDING_STEPS, REQUIRED_ONBOARDING_STEPS, ZENI_USER_REQUIRED_ONBOARDING_STEPS, emptyAiAgentsActivationSubview, toOnboardingStepType, } from './onboardingCustomerViewState';
12
12
  export function getOnboardingCustomerView(state, companyId) {
13
13
  const { fileState, paymentAccountState, onboardingCustomerViewState, userState, userRoleState, subscriptionPaymentAccountState, companyConfigState, cardPaymentViewState, countryListState, addressViewState, } = state;
14
- const { companyDetails, companyOfficerUpdateStatus, primaryContactDetails, subscriptionPaymentAccountIds, paymentAccountDetails, plaidConnectionDetails, parsingDocumentFileIds, updateStatus, saveStatus, currentStep, currentSubStep, uiState, fetchState, error, } = onboardingCustomerViewState;
14
+ const { companyDetails, companyOfficerUpdateStatus, primaryContactDetails, subscriptionPaymentAccountIds, paymentAccountDetails, plaidConnectionDetails, parsingDocumentFileIds, updateStatus, saveStatus, aiFinanceTeamAcknowledgementStatus, currentStep, currentSubStep, uiState, fetchState, error, } = onboardingCustomerViewState;
15
15
  const { paymentAccountIds } = paymentAccountDetails;
16
16
  let subscriptionPaymentAccount;
17
17
  let paymentAccount;
@@ -148,6 +148,7 @@ export function getOnboardingCustomerView(state, companyId) {
148
148
  fetchStatus,
149
149
  saveStatus,
150
150
  updateStatus,
151
+ aiFinanceTeamAcknowledgementStatus,
151
152
  qboConnected: onboardingInfo?.qboLinked.completed ?? false,
152
153
  isInterimEmailSent: onboardingInfo?.isInterimEmailSent ?? false,
153
154
  };
@@ -10,7 +10,7 @@ import { getActualTransactionID } from '../transactionDetail/transactionDetailSt
10
10
  import { getRecommendationByLineIdWithCOTFromRecommendationPayloadWithCOT, getRecommendationFromRecommendationPayload, } from './recommendationHelper';
11
11
  import { fetchEntityRecommendationsByTransactionId, updateRecommendationForEntity, updateRecommendationForEntityFailure, } from './recommendationReducer';
12
12
  export const fetchEntityRecommendationsByTransactionIdEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchEntityRecommendationsByTransactionId.match), switchMap((action) => {
13
- const { entity, amount, transactionDetails, isBulkFetch, isTransactionCategorizationFlow, isFetchCOT, isUncategorizedExpenseCategoryEnabled, } = action.payload;
13
+ const { entity, amount, transactionDetails, isBulkFetch, isTransactionCategorizationFlow, isFetchCOT, } = action.payload;
14
14
  const { expenseAutomationTransactionsViewState: { selectedTransactionCategorizationTab, }, } = state$.value;
15
15
  const query = {
16
16
  amount,
@@ -52,7 +52,7 @@ export const fetchEntityRecommendationsByTransactionIdEpic = (actions$, state$,
52
52
  if (recommendationWithCOTByLineId != null) {
53
53
  const uncategorizedIncomeExpense = getUncategorizedAccounts(state$.value.accountState, state$.value.accountListState, 'accountList');
54
54
  if (isTransactionCategorizationFlow === true) {
55
- actions.push(setEntityRecommendationForLineIdsForCategorization(selectedTransactionCategorizationTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled, getIsAccountingClassesEnabled(state$.value)));
55
+ actions.push(setEntityRecommendationForLineIdsForCategorization(selectedTransactionCategorizationTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, getIsAccountingClassesEnabled(state$.value)));
56
56
  }
57
57
  else {
58
58
  actions.push(setEntityRecommendationForLineIdsForTransactionDetail(transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense));
@@ -37,7 +37,7 @@ const toGroupKey = (flowType, transactionId, lineIds) => `${flowType}${SEPARATOR
37
37
  export const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchEntityRecommendationsForLineUpdate.match), groupBy((action) => toGroupKey(action.payload.flowType, action.payload.transactionDetails.transactionId.id, action.payload.transactionDetails.lineIds), undefined, (group$) => group$.pipe(debounce(() => timer(GROUP_INACTIVITY_TIMEOUT_MS)))), mergeMap((group$) => group$.pipe(switchMap((action) => {
38
38
  const payload = action.payload;
39
39
  const { transactionId, transaction, lineIds } = payload.transactionDetails;
40
- const { entity, amount, isFetchCOT, isUncategorizedExpenseCategoryEnabled, } = payload;
40
+ const { entity, amount, isFetchCOT, } = payload;
41
41
  // The vendor "Update all lines" popup on the detail page watches
42
42
  // its own transaction-level fetch status, separate from the
43
43
  // per-line statuses below — surface completion/failure there too
@@ -84,7 +84,7 @@ export const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, ze
84
84
  : getTransactionWithCOT(transaction);
85
85
  const uncategorizedIncomeExpense = getUncategorizedAccounts(state$.value.accountState, state$.value.accountListState, 'accountList');
86
86
  if (payload.flowType === 'categorization') {
87
- return of(setEntityRecommendationForLineIdsForCategorization(payload.selectedTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled, getIsAccountingClassesEnabled(state$.value)));
87
+ return of(setEntityRecommendationForLineIdsForCategorization(payload.selectedTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, getIsAccountingClassesEnabled(state$.value)));
88
88
  }
89
89
  return emitWithBulkStatus(setEntityRecommendationForLineIdsForTransactionDetail(transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense), isBulkDetailFetch
90
90
  ? updateVendorBulkRecommendationsFetchStatus(transactionId, 'Completed')
@@ -19,7 +19,7 @@ const recommendation = createSlice({
19
19
  };
20
20
  }
21
21
  },
22
- prepare(entity, amount, transactionDetails, isBulkFetch, isTransactionCategorizationFlow = false, isFetchCOT = false, isUncategorizedExpenseCategoryEnabled) {
22
+ prepare(entity, amount, transactionDetails, isBulkFetch, isTransactionCategorizationFlow = false, isFetchCOT = false) {
23
23
  return {
24
24
  payload: {
25
25
  entity,
@@ -28,7 +28,6 @@ const recommendation = createSlice({
28
28
  isBulkFetch,
29
29
  isTransactionCategorizationFlow,
30
30
  isFetchCOT,
31
- isUncategorizedExpenseCategoryEnabled,
32
31
  },
33
32
  };
34
33
  },
@@ -7,7 +7,7 @@ import { saveTransactionDetail, updateTransactionDetail, } from '../transactionD
7
7
  import { getTransactionDetailKey } from '../transactionDetailState';
8
8
  import { toTransactionUpdatesFromTransactionDetailLocalData } from './saveTransactionHelper';
9
9
  export const saveTransactionDetailEpic = (actions$, state$) => actions$.pipe(filter(saveTransactionDetail.match), mergeMap((action) => {
10
- const { transactionId, cotTransactionTracking, isExpenseAutomationEnabled, isUncategorizedExpenseCategoryEnabled, } = action.payload;
10
+ const { transactionId, cotTransactionTracking, isExpenseAutomationEnabled, } = action.payload;
11
11
  const fetchActions = [];
12
12
  const transactionDetailState = state$.value.transactionDetailState;
13
13
  const transactionState = state$.value.transactionState;
@@ -18,7 +18,7 @@ export const saveTransactionDetailEpic = (actions$, state$) => actions$.pipe(fil
18
18
  if (detail != null && transaction != null) {
19
19
  const localData = detail.transactionDetailLocalData;
20
20
  const transactionSaveUpdates = toTransactionUpdatesFromTransactionDetailLocalData(localData, transaction, isExpenseAutomationEnabled, isAccountingProjectsEnabled);
21
- fetchActions.push(updateTransactionDetail(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, cotTransactionTracking, isUncategorizedExpenseCategoryEnabled));
21
+ fetchActions.push(updateTransactionDetail(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, cotTransactionTracking));
22
22
  return from(fetchActions);
23
23
  }
24
24
  return from(fetchActions);
@@ -29,7 +29,7 @@ import { getTransactionDetailKey, } from '../transactionDetailState';
29
29
  export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(updateTransactionDetail.match), mergeMap((action) => {
30
30
  const { transactionState, vendorState, transactionDetailState } = state$.value;
31
31
  const isAccountingProjectsEnabled = getIsAccountingProjectsEnabled(state$.value);
32
- const { cotTransactionTracking, transactionId, transactionSaveUpdates, isUncategorizedExpenseCategoryEnabled, } = action.payload;
32
+ const { cotTransactionTracking, transactionId, transactionSaveUpdates, } = action.payload;
33
33
  return zeniAPI
34
34
  .putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${action.payload.transactionId.id}/categorize`, preparePayload(transactionState, vendorState, transactionDetailState, transactionId, transactionSaveUpdates, cotTransactionTracking, isAccountingProjectsEnabled))
35
35
  .pipe(mergeMap((response) => {
@@ -82,7 +82,7 @@ export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => action
82
82
  actions.push(updateTransactions([response.data.transaction], (value) => value.transaction_id, 'merge'));
83
83
  const transactionWithCOT = getTransactionWithCOT(transaction);
84
84
  const pendingReviewLineIds = getPendingReviewLineIdsFromTransaction(transactionWithCOT);
85
- actions.push(syncTransactionCategorizationFromDetailSave(transactionIdResp, transactionWithCOT, pendingReviewLineIds, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled));
85
+ actions.push(syncTransactionCategorizationFromDetailSave(transactionIdResp, transactionWithCOT, pendingReviewLineIds));
86
86
  return from(actions);
87
87
  }
88
88
  else if (isActionNotAllowed(response)) {
@@ -105,14 +105,13 @@ const transactionDetail = createSlice({
105
105
  };
106
106
  }
107
107
  },
108
- prepare(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, cotTransactionTracking, isUncategorizedExpenseCategoryEnabled) {
108
+ prepare(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, cotTransactionTracking) {
109
109
  return {
110
110
  payload: {
111
111
  transactionId,
112
112
  transactionSaveUpdates,
113
113
  isExpenseAutomationEnabled,
114
114
  cotTransactionTracking,
115
- isUncategorizedExpenseCategoryEnabled,
116
115
  },
117
116
  };
118
117
  },