@zeniai/client-epic-state 4.20.3-betaML4 → 4.20.3-betaNB11

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 (87) hide show
  1. package/lib/commonStateTypes/viewAndReport/viewAndReport.d.ts +2 -2
  2. package/lib/commonStateTypes/viewAndReport/viewAndReport.js +1 -0
  3. package/lib/entity/account/accountPayload.d.ts +2 -0
  4. package/lib/entity/account/accountReducer.d.ts +5 -2
  5. package/lib/entity/account/accountReducer.js +7 -2
  6. package/lib/entity/account/accountState.d.ts +1 -1
  7. package/lib/entity/accountGroup/accountGroupState.d.ts +1 -1
  8. package/lib/entity/class/classReducer.d.ts +4 -4
  9. package/lib/entity/class/classState.d.ts +1 -1
  10. package/lib/entity/forecast/forecastState.d.ts +1 -1
  11. package/lib/entity/sectionAccountsView/sectionAccountsView.d.ts +1 -1
  12. package/lib/entity/sectionClassesViewV2/sectionClassesView.d.ts +1 -1
  13. package/lib/entity/sectionClassesViewV2/sectionClassesViewReducer.d.ts +2 -2
  14. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  15. package/lib/entity/snackbar/snackbarTypes.js +1 -0
  16. package/lib/entity/tenant/tenantReducer.d.ts +5 -2
  17. package/lib/entity/tenant/tenantReducer.js +8 -2
  18. package/lib/entity/transaction/payloadTypes/transactionPayload.d.ts +6 -0
  19. package/lib/entity/transaction/payloadTypes/transactionPayload.js +62 -0
  20. package/lib/entity/transaction/stateTypes/transaction.d.ts +6 -0
  21. package/lib/epic.d.ts +10 -7
  22. package/lib/epic.js +10 -7
  23. package/lib/esm/commonStateTypes/viewAndReport/viewAndReport.js +1 -0
  24. package/lib/esm/entity/account/accountReducer.js +6 -1
  25. package/lib/esm/entity/snackbar/snackbarTypes.js +1 -0
  26. package/lib/esm/entity/tenant/tenantReducer.js +7 -1
  27. package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +62 -0
  28. package/lib/esm/epic.js +10 -7
  29. package/lib/esm/index.js +7 -7
  30. package/lib/esm/view/companyView/companyViewReducer.js +26 -1
  31. package/lib/esm/view/companyView/epic/companyPassport/updateAccountingClassesEnabledEpic.js +61 -0
  32. package/lib/esm/view/companyView/types/companyPassport/companyPassportViewState.js +4 -0
  33. package/lib/esm/view/expenseAutomationView/epics/accountRecon/excludeAccountFromReconciliationEpic.js +44 -0
  34. package/lib/esm/view/expenseAutomationView/epics/accountRecon/fetchReconciliationViewEpic.js +4 -9
  35. package/lib/esm/view/expenseAutomationView/epics/accountRecon/includeAccountInReconciliationEpic.js +44 -0
  36. package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +5 -1
  37. package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +167 -3
  38. package/lib/esm/view/expenseAutomationView/selectorTypes/reconciliationViewSelectorTypes.js +1 -2
  39. package/lib/esm/view/expenseAutomationView/selectors/reconciliationViewSelector.js +114 -0
  40. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +10 -6
  41. package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +6 -0
  42. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +4 -2
  43. package/lib/esm/view/spendManagement/autotransferRules/epics/createAutoTransferRuleEpic.js +2 -1
  44. package/lib/esm/view/spendManagement/autotransferRules/epics/fetchAutoTransferReviewDetailEpic.js +1 -1
  45. package/lib/index.d.ts +7 -7
  46. package/lib/index.js +39 -32
  47. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  48. package/lib/view/auditReportView/auditReportViewState.d.ts +1 -1
  49. package/lib/view/billPayCard/billPayCardSelector.d.ts +1 -1
  50. package/lib/view/cardBalance/cardBalanceSelector.d.ts +1 -1
  51. package/lib/view/cashBalance/cashBalanceSelector.d.ts +1 -1
  52. package/lib/view/cashInCashOut/cashInCashOutSelector.d.ts +1 -1
  53. package/lib/view/cashPosition/cashPositionSelector.d.ts +1 -1
  54. package/lib/view/companyView/companyViewReducer.d.ts +6 -1
  55. package/lib/view/companyView/companyViewReducer.js +28 -2
  56. package/lib/view/companyView/epic/companyPassport/updateAccountingClassesEnabledEpic.d.ts +10 -0
  57. package/lib/view/companyView/epic/companyPassport/updateAccountingClassesEnabledEpic.js +65 -0
  58. package/lib/view/companyView/types/companyPassport/companyPassportViewState.d.ts +1 -0
  59. package/lib/view/companyView/types/companyPassport/companyPassportViewState.js +4 -0
  60. package/lib/view/dashboard/dashboardReducer.d.ts +2 -2
  61. package/lib/view/expenseAutomationView/epics/accountRecon/excludeAccountFromReconciliationEpic.d.ts +8 -0
  62. package/lib/view/expenseAutomationView/epics/accountRecon/excludeAccountFromReconciliationEpic.js +48 -0
  63. package/lib/view/expenseAutomationView/epics/accountRecon/fetchReconciliationViewEpic.js +4 -9
  64. package/lib/view/expenseAutomationView/epics/accountRecon/includeAccountInReconciliationEpic.d.ts +9 -0
  65. package/lib/view/expenseAutomationView/epics/accountRecon/includeAccountInReconciliationEpic.js +48 -0
  66. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  67. package/lib/view/expenseAutomationView/payload/reconciliationPayload.d.ts +45 -0
  68. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +5 -1
  69. package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.d.ts +18 -4
  70. package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +168 -4
  71. package/lib/view/expenseAutomationView/selectorTypes/reconciliationViewSelectorTypes.d.ts +7 -2
  72. package/lib/view/expenseAutomationView/selectorTypes/reconciliationViewSelectorTypes.js +2 -2
  73. package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.js +114 -0
  74. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +9 -5
  75. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +3 -0
  76. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +8 -1
  77. package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +14 -0
  78. package/lib/view/financeStatement/financeStatementReducer.d.ts +1 -1
  79. package/lib/view/globalMerchantView/globalMerchantViewReducer.d.ts +2 -2
  80. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +4 -2
  81. package/lib/view/reimbursementCard/reimbursementCardSelector.d.ts +1 -1
  82. package/lib/view/reportsResync/reportsResyncReducer.d.ts +2 -2
  83. package/lib/view/spendManagement/autotransferRules/epics/createAutoTransferRuleEpic.js +2 -1
  84. package/lib/view/spendManagement/autotransferRules/epics/fetchAutoTransferReviewDetailEpic.js +1 -1
  85. package/lib/view/tasksCard/tasksCardSelector.d.ts +1 -1
  86. package/lib/view/topEx/topExSelector.d.ts +1 -1
  87. package/package.json +1 -1
@@ -284,6 +284,31 @@ const companyView = createSlice({
284
284
  error: status,
285
285
  };
286
286
  },
287
+ updateAccountingClassesEnabled: {
288
+ reducer(draft,
289
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
290
+ _action) {
291
+ draft.passportView.accountingClassesUpdateStatus = {
292
+ fetchState: 'In-Progress',
293
+ error: undefined,
294
+ };
295
+ },
296
+ prepare(companyId, enabled) {
297
+ return { payload: { companyId, enabled } };
298
+ },
299
+ },
300
+ updateAccountingClassesEnabledSuccess(draft) {
301
+ draft.passportView.accountingClassesUpdateStatus = {
302
+ fetchState: 'Completed',
303
+ error: undefined,
304
+ };
305
+ },
306
+ updateAccountingClassesEnabledFailure(draft, action) {
307
+ draft.passportView.accountingClassesUpdateStatus = {
308
+ fetchState: 'Error',
309
+ error: action.payload.status,
310
+ };
311
+ },
287
312
  companyPassportUpdatePrimaryContact: {
288
313
  reducer(draft, action) {
289
314
  const { primaryContact } = action.payload;
@@ -557,5 +582,5 @@ const companyView = createSlice({
557
582
  },
558
583
  },
559
584
  });
560
- export const { fetchCompanyPassportView, fetchAllCockpitViews, fetchOnboardingView, fetchManagementView, fetchSubscriptionView, fetchPortfolioView, fetchCompanyManagementView, companyManagementSaveUpdates, companyManagementSavePendingUpdates, companyManagementDiscardUpdates, companyManagementSaveUpdatesSuccess, companyManagementSaveUpdatesFailure, updateCompanyViewOnSuccess, updateCompanyViewOnFailure, fetchCompanyPortfolioView, fetchZeniUsers, updateZeniUsersOnSuccess, updateZeniUsersOnFailure, clearCompanyView, updateCompanyPortfolioUIState, updateCompanyManagementUIState, companyPassportSaveDataInLocalStore, deleteCompanyOfficerInLocalStore, companyPassportClearDataInLocalStore, companyPassportUpdateCompanyDetails, companyPassportUpdateCompanyDetailsSuccess, companyPassportUpdateCompanyDetailsFailure, companyPassportUpdatePrimaryContact, companyPassportUpdatePrimaryContactSuccess, companyPassportUpdatePrimaryContactFailure, companyPassportUpdateCompanyOfficer, companyPassportUpdateCompanyOfficerSuccess, companyPassportUpdateCompanyOfficerFailure, companyPassportCreateCompanyOfficers, companyPassportCreateCompanyOfficersSuccess, companyPassportCreateCompanyOfficersFailure, updateCompanyPassportLocalStoreData, saveIndustryAndIncDateInCompanyPassportLocalStore, saveCompanyPassportDetails, fetchParentSubsidiaryManagementView, updateParentSubsidiaryView, updateParentSubsidiaryViewOnFailure, updateCompanyDownloadState, fetchCompanyMetaData, updateCompanyMetaDataOnSuccess, updateCompanyMetaDataOnFailure, updateMetaDataOnSendMonthEndReport, } = companyView.actions;
585
+ export const { fetchCompanyPassportView, fetchAllCockpitViews, fetchOnboardingView, fetchManagementView, fetchSubscriptionView, fetchPortfolioView, fetchCompanyManagementView, companyManagementSaveUpdates, companyManagementSavePendingUpdates, companyManagementDiscardUpdates, companyManagementSaveUpdatesSuccess, companyManagementSaveUpdatesFailure, updateCompanyViewOnSuccess, updateCompanyViewOnFailure, fetchCompanyPortfolioView, fetchZeniUsers, updateZeniUsersOnSuccess, updateZeniUsersOnFailure, clearCompanyView, updateCompanyPortfolioUIState, updateCompanyManagementUIState, companyPassportSaveDataInLocalStore, deleteCompanyOfficerInLocalStore, companyPassportClearDataInLocalStore, companyPassportUpdateCompanyDetails, companyPassportUpdateCompanyDetailsSuccess, companyPassportUpdateCompanyDetailsFailure, updateAccountingClassesEnabled, updateAccountingClassesEnabledSuccess, updateAccountingClassesEnabledFailure, companyPassportUpdatePrimaryContact, companyPassportUpdatePrimaryContactSuccess, companyPassportUpdatePrimaryContactFailure, companyPassportUpdateCompanyOfficer, companyPassportUpdateCompanyOfficerSuccess, companyPassportUpdateCompanyOfficerFailure, companyPassportCreateCompanyOfficers, companyPassportCreateCompanyOfficersSuccess, companyPassportCreateCompanyOfficersFailure, updateCompanyPassportLocalStoreData, saveIndustryAndIncDateInCompanyPassportLocalStore, saveCompanyPassportDetails, fetchParentSubsidiaryManagementView, updateParentSubsidiaryView, updateParentSubsidiaryViewOnFailure, updateCompanyDownloadState, fetchCompanyMetaData, updateCompanyMetaDataOnSuccess, updateCompanyMetaDataOnFailure, updateMetaDataOnSendMonthEndReport, } = companyView.actions;
561
586
  export default companyView.reducer;
@@ -0,0 +1,61 @@
1
+ import { from } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { updateCompanies } from '../../../../entity/company/companyReducer';
4
+ import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
5
+ import { updateTenantAccountingClassesEnabled } from '../../../../entity/tenant/tenantReducer';
6
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
7
+ import { updateAccountingClassesEnabled, updateAccountingClassesEnabledFailure, updateAccountingClassesEnabledSuccess, } from '../../companyViewReducer';
8
+ export const updateAccountingClassesEnabledEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(updateAccountingClassesEnabled.match), switchMap((action) => {
9
+ const { companyId, enabled } = action.payload;
10
+ const tenantId = Object.values(state$.value.tenantState.tenantsById).find((t) => t.companyId === companyId)?.tenantId;
11
+ return zeniAPI
12
+ .putAndGetJSON(`${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/companies/${companyId}`, { is_accounting_classes_enabled: enabled })
13
+ .pipe(mergeMap((response) => {
14
+ const companies = response.data?.companies ?? [];
15
+ if (isSuccessResponse(response) && companies.length > 0) {
16
+ const actions = [
17
+ updateCompanies({
18
+ payload: companies,
19
+ schema: {},
20
+ }),
21
+ ];
22
+ if (tenantId != null) {
23
+ actions.push(updateTenantAccountingClassesEnabled({
24
+ enabled,
25
+ tenantId,
26
+ }));
27
+ }
28
+ actions.push(updateAccountingClassesEnabledSuccess());
29
+ actions.push(openSnackbar({
30
+ messageSection: 'accounting_classes_enabled_update',
31
+ messageText: 'success',
32
+ type: 'success',
33
+ }));
34
+ return from(actions);
35
+ }
36
+ else {
37
+ return from([
38
+ updateAccountingClassesEnabledFailure({
39
+ status: response.status,
40
+ }),
41
+ openSnackbar({
42
+ messageSection: 'accounting_classes_enabled_update',
43
+ messageText: 'failed',
44
+ type: 'error',
45
+ }),
46
+ ]);
47
+ }
48
+ }), catchError((error) => from([
49
+ updateAccountingClassesEnabledFailure({
50
+ status: createZeniAPIStatus('Unexpected error', 'Update Accounting Classes Enabled errored out' +
51
+ (error instanceof Error
52
+ ? error.message
53
+ : JSON.stringify(error))),
54
+ }),
55
+ openSnackbar({
56
+ messageSection: 'accounting_classes_enabled_update',
57
+ messageText: 'failed',
58
+ type: 'error',
59
+ }),
60
+ ])));
61
+ }));
@@ -1,6 +1,10 @@
1
1
  import { initialCommonState } from '../commonState';
2
2
  export const initialCompanyPassportView = {
3
3
  ...initialCommonState,
4
+ accountingClassesUpdateStatus: {
5
+ fetchState: 'Not-Started',
6
+ error: undefined,
7
+ },
4
8
  companyDetails: {
5
9
  localData: undefined,
6
10
  updateStatus: {
@@ -0,0 +1,44 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { changeAccountKey } from '../../../../entity/account/accountReducer';
4
+ import { getAccountKey } from '../../../../entity/account/accountState';
5
+ import { getAccountReconByAccountIdAndSelectedPeriod } from '../../../../entity/accountRecon/accountReconSelector';
6
+ import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
7
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
8
+ import { excludeAccountFromReconciliation, excludeAccountFromReconciliationFailure, excludeAccountFromReconciliationSuccess, } from '../../reducers/reconciliationViewReducer';
9
+ export const excludeAccountFromReconciliationEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(excludeAccountFromReconciliation.match), mergeMap((action) => {
10
+ const { accountId } = action.payload;
11
+ const state = state$.value;
12
+ const currentTenant = getCurrentTenant(state);
13
+ const selectedPeriod = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant.tenantId];
14
+ const reconciliationData = getAccountReconByAccountIdAndSelectedPeriod(state, accountId, selectedPeriod);
15
+ const payload = {
16
+ account_id: accountId,
17
+ bank_balance: reconciliationData?.balance?.amount ?? null,
18
+ cleared_balance: reconciliationData?.clearedBalance?.amount ?? null,
19
+ variance: reconciliationData?.variance?.amount ?? null,
20
+ };
21
+ const apiUrl = `${zeniAPI.apiEndPoints.reconciliationMicroServiceBaseUrl}/1.0/reconciliation/excluded-accounts`;
22
+ return zeniAPI
23
+ .postAndGetJSON(apiUrl, payload)
24
+ .pipe(mergeMap((response) => {
25
+ if (isSuccessResponse(response)) {
26
+ const newAccountKey = getAccountKey('excluded_account_reconciliation', accountId);
27
+ const oldAccountKey = getAccountKey('account_reconciliation', accountId);
28
+ return of(excludeAccountFromReconciliationSuccess({
29
+ account: response.data?.excluded_account ?? undefined,
30
+ selectedPeriod,
31
+ }), changeAccountKey({
32
+ oldKey: oldAccountKey,
33
+ newKey: newAccountKey,
34
+ }));
35
+ }
36
+ else {
37
+ return of(excludeAccountFromReconciliationFailure({
38
+ error: response.status,
39
+ }));
40
+ }
41
+ }), catchError((error) => of(excludeAccountFromReconciliationFailure({
42
+ error: createZeniAPIStatus('Unexpected Error', `Exclude account from reconciliation REST API call errored out ${JSON.stringify(error)}`),
43
+ }))));
44
+ }));
@@ -53,22 +53,17 @@ export const fetchReconciliationViewEpic = (actions$, state$, zeniAPI) => action
53
53
  return zeniAPI.getJSON(apiUrl).pipe(mergeMap((response) => {
54
54
  if (isSuccessResponse(response) && response.data != null) {
55
55
  const updateActions = [];
56
- updateActions.push(updateAccounts(response.data.accounts, 'account_reconciliation'));
57
- updateActions.push(updateAllUsers({
56
+ const allTransactionsPerRecon = getAllReviewTransactionsFromReconcilePayload(response.data.reconciliation);
57
+ updateActions.push(updateAccounts(response.data.accounts, 'account_reconciliation'), updateAccounts(response.data.excluded_accounts ?? [], 'excluded_account_reconciliation'), updateAllUsers({
58
58
  users: response.data.users ?? [],
59
59
  updateType: 'merge',
60
- }));
61
- updateActions.push(updateFiles({ files: response.data.files ?? [] }));
62
- const allTransactionsPerRecon = getAllReviewTransactionsFromReconcilePayload(response.data.reconciliation);
63
- updateActions.push(updateMultipleReconcileTransactions(allTransactionsPerRecon, 'merge'));
64
- updateActions.push(updateAccountRecon(selectedPeriod, response.data.reconciliation));
60
+ }), updateFiles({ files: response.data.files ?? [] }), updateMultipleReconcileTransactions(allTransactionsPerRecon, 'merge'), updateAccountRecon(selectedPeriod, response.data.reconciliation));
65
61
  const reviewTabLocalData = prepareReviewTabLocalData(response.data.reconciliation[0]?.transactions?.review ?? []);
66
62
  if (accountId != null) {
67
63
  const selectedTransactionIds = getTransactionIdFromCheckedMatchedTransactionPayload(response.data.reconciliation[0].transactions.reconcile);
68
64
  updateActions.push(updateReconcileTabLocalData({
69
65
  selectedTransactionIds: selectedTransactionIds,
70
- }));
71
- updateActions.push(initializeReconciliationReviewTabLocalData(reviewTabLocalData));
66
+ }), initializeReconciliationReviewTabLocalData(reviewTabLocalData));
72
67
  }
73
68
  updateActions.push(fetchReconciliationSuccess(selectedPeriod, response.data, refreshViewInBackground, accountId));
74
69
  return from(updateActions);
@@ -0,0 +1,44 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { convertToPeriod } from '../../../../commonStateTypes/timePeriod';
4
+ import { changeAccountKey } from '../../../../entity/account/accountReducer';
5
+ import { getAccountKey } from '../../../../entity/account/accountState';
6
+ import { updateAccountRecon } from '../../../../entity/accountRecon/accountReconReducer';
7
+ import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
8
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
9
+ import { includeAccountInReconciliation, includeAccountInReconciliationFailure, includeAccountInReconciliationSuccess, } from '../../reducers/reconciliationViewReducer';
10
+ export const includeAccountInReconciliationEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(includeAccountInReconciliation.match), mergeMap((action) => {
11
+ const { accountId } = action.payload;
12
+ const state = state$.value;
13
+ const currentTenant = getCurrentTenant(state);
14
+ const selectedPeriod = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant.tenantId];
15
+ const period = convertToPeriod(selectedPeriod, true);
16
+ const query = JSON.stringify({
17
+ start_date: period.start,
18
+ end_date: period.end,
19
+ });
20
+ const apiUrl = `${zeniAPI.apiEndPoints.reconciliationMicroServiceBaseUrl}/1.0/reconciliation/excluded-accounts/${accountId}?query=${encodeURIComponent(query)}`;
21
+ return zeniAPI
22
+ .deleteAndGetJSON(apiUrl)
23
+ .pipe(mergeMap((response) => {
24
+ if (isSuccessResponse(response) && response.data != null) {
25
+ const reconciliation = response.data.reconciliation;
26
+ const oldAccountKey = getAccountKey('excluded_account_reconciliation', reconciliation.account_id);
27
+ const newAccountKey = getAccountKey('account_reconciliation', reconciliation.account_id);
28
+ return of(updateAccountRecon(selectedPeriod, [reconciliation]), includeAccountInReconciliationSuccess({
29
+ reconciliation,
30
+ selectedPeriod,
31
+ }), changeAccountKey({
32
+ oldKey: oldAccountKey,
33
+ newKey: newAccountKey,
34
+ }));
35
+ }
36
+ else {
37
+ return of(includeAccountInReconciliationFailure({
38
+ error: response.status,
39
+ }));
40
+ }
41
+ }), catchError((error) => of(includeAccountInReconciliationFailure({
42
+ error: createZeniAPIStatus('Unexpected Error', `Include account in reconciliation REST API call errored out ${JSON.stringify(error)}`),
43
+ }))));
44
+ }));
@@ -44,7 +44,8 @@ export const initialState = {
44
44
  uiState: {
45
45
  searchString: '',
46
46
  scrollPosition: { scrollTop: 0, scrollLeft: undefined },
47
- sortKey: 'startMonth',
47
+ selectedMainTab: 'pending_review',
48
+ sortKey: 'transactionDate',
48
49
  sortOrder: 'descending',
49
50
  totalCount: 0,
50
51
  limit: 10,
@@ -380,6 +381,9 @@ const expenseAutomationJESchedulesView = createSlice({
380
381
  if (action.payload.scrollPosition != null) {
381
382
  draft.uiState.scrollPosition = action.payload.scrollPosition;
382
383
  }
384
+ if (action.payload.selectedMainTab != null) {
385
+ draft.uiState.selectedMainTab = action.payload.selectedMainTab;
386
+ }
383
387
  },
384
388
  clearExpenseAutomationJESchedulesView(draft) {
385
389
  Object.assign(draft, initialState);
@@ -37,7 +37,15 @@ export const initialReconciliationTabsState = {
37
37
  },
38
38
  };
39
39
  export const initialActionFetchState = {
40
+ excludeAccountFetch: {
41
+ fetchState: 'Not-Started',
42
+ error: undefined,
43
+ },
40
44
  excludeFetchById: {},
45
+ includeAccountFetch: {
46
+ fetchState: 'Not-Started',
47
+ error: undefined,
48
+ },
41
49
  reconcileFetch: {
42
50
  fetchState: 'Not-Started',
43
51
  error: undefined,
@@ -51,6 +59,7 @@ export const initialActionFetchState = {
51
59
  export const initialState = {
52
60
  accountReconciliationRecordsBySelectedPeriod: {},
53
61
  accountConnectionStatusByAccountID: {},
62
+ excludedAccountExclusionInfo: {},
54
63
  fetchState: 'Not-Started',
55
64
  error: undefined,
56
65
  selectedTab: 'review',
@@ -60,10 +69,12 @@ export const initialState = {
60
69
  selectedAccountId: undefined,
61
70
  statementUploadChosen: false,
62
71
  reconListUIState: {
72
+ nodeCollapseState: {},
63
73
  scrollPosition: {
64
74
  scrollTop: 0,
65
75
  },
66
76
  },
77
+ excludedAccountIDs: [],
67
78
  };
68
79
  // Create slice with reducers
69
80
  const expenseAutomationReconciliationView = createSlice({
@@ -132,7 +143,7 @@ const expenseAutomationReconciliationView = createSlice({
132
143
  fetchReconciliationSuccess: {
133
144
  reducer(draft, action) {
134
145
  if (action.payload.accountId == null) {
135
- updateAllReconciliation(draft, action.payload.reconciliation.accounts, action.payload.selectedPeriod, action.payload.reconciliation.reconciliation, action.payload.refreshViewInBackground);
146
+ updateAllReconciliation(draft, action.payload.reconciliation.accounts, action.payload.selectedPeriod, action.payload.reconciliation.reconciliation, action.payload.refreshViewInBackground, action.payload.reconciliation.excluded_accounts ?? []);
136
147
  }
137
148
  else if (action.payload.reconciliation.reconciliation.length > 0 &&
138
149
  action.payload.reconciliation.accounts.length > 0) {
@@ -344,6 +355,10 @@ const expenseAutomationReconciliationView = createSlice({
344
355
  updateReconListScrollPosition: (draft, action) => {
345
356
  draft.reconListUIState.scrollPosition = action.payload.scrollPosition;
346
357
  },
358
+ updateNodeCollapseState: (draft, action) => {
359
+ draft.reconListUIState.nodeCollapseState[action.payload.nodeId] =
360
+ action.payload.collapsed;
361
+ },
347
362
  setConnectionInProgressForAccount: (draft, action) => {
348
363
  if (draft.accountConnectionStatusByAccountID[action.payload.accountId] ==
349
364
  null) {
@@ -421,6 +436,85 @@ const expenseAutomationReconciliationView = createSlice({
421
436
  ...localData,
422
437
  };
423
438
  },
439
+ excludeAccountFromReconciliation: {
440
+ reducer(draft) {
441
+ draft.actionFetchState.excludeAccountFetch = {
442
+ fetchState: 'In-Progress',
443
+ error: undefined,
444
+ };
445
+ },
446
+ prepare(payload) {
447
+ return { payload };
448
+ },
449
+ },
450
+ excludeAccountFromReconciliationSuccess: (draft, action) => {
451
+ draft.actionFetchState.excludeAccountFetch = {
452
+ fetchState: 'Completed',
453
+ error: undefined,
454
+ };
455
+ const { account, selectedPeriod } = action.payload;
456
+ if (account != null) {
457
+ if (!draft.excludedAccountIDs.includes(account.account_id)) {
458
+ draft.excludedAccountIDs.push(account.account_id);
459
+ }
460
+ updateExcludedAccountExclusionInfo(draft, account);
461
+ const monthYearPeriodId = toMonthYearPeriodId(selectedPeriod);
462
+ if (draft.accountReconciliationRecordsBySelectedPeriod[monthYearPeriodId]
463
+ ?.accountIDs != null) {
464
+ draft.accountReconciliationRecordsBySelectedPeriod[monthYearPeriodId].accountIDs = draft.accountReconciliationRecordsBySelectedPeriod[monthYearPeriodId].accountIDs.filter((id) => id !== account.account_id);
465
+ }
466
+ }
467
+ },
468
+ excludeAccountFromReconciliationFailure: (draft, action) => {
469
+ draft.actionFetchState.excludeAccountFetch = {
470
+ fetchState: 'Error',
471
+ error: action.payload.error,
472
+ };
473
+ },
474
+ includeAccountInReconciliation: {
475
+ reducer(draft) {
476
+ draft.actionFetchState.includeAccountFetch = {
477
+ fetchState: 'In-Progress',
478
+ error: undefined,
479
+ };
480
+ },
481
+ prepare(payload) {
482
+ return { payload };
483
+ },
484
+ },
485
+ includeAccountInReconciliationSuccess: (draft, action) => {
486
+ draft.actionFetchState.includeAccountFetch = {
487
+ fetchState: 'Completed',
488
+ error: undefined,
489
+ };
490
+ const { reconciliation, selectedPeriod } = action.payload;
491
+ if (reconciliation == null) {
492
+ return;
493
+ }
494
+ const accountId = reconciliation.account_id;
495
+ draft.excludedAccountIDs = draft.excludedAccountIDs.filter((id) => id !== accountId);
496
+ delete draft.excludedAccountExclusionInfo[accountId];
497
+ const monthYearPeriodId = toMonthYearPeriodId(selectedPeriod);
498
+ const accountReconciliationRecords = draft.accountReconciliationRecordsBySelectedPeriod[monthYearPeriodId];
499
+ if (accountReconciliationRecords != null) {
500
+ if (!accountReconciliationRecords.accountIDs.includes(accountId)) {
501
+ accountReconciliationRecords.accountIDs.push(accountId);
502
+ }
503
+ // put this in a function
504
+ updateReconciliationByAccountIDOnIncludeAccount(draft, accountId, reconciliation, monthYearPeriodId);
505
+ }
506
+ draft.accountConnectionStatusByAccountID[accountId] = {
507
+ status: toBankStatusCodeType(reconciliation.bank_status.code),
508
+ connectionInProgress: false,
509
+ paymentAccountId: undefined,
510
+ };
511
+ },
512
+ includeAccountInReconciliationFailure: (draft, action) => {
513
+ draft.actionFetchState.includeAccountFetch = {
514
+ fetchState: 'Error',
515
+ error: action.payload.error,
516
+ };
517
+ },
424
518
  updateStatementUploadChosen: (draft, action) => {
425
519
  draft.statementUploadChosen = action.payload.statementUploadChosen;
426
520
  },
@@ -430,10 +524,38 @@ const expenseAutomationReconciliationView = createSlice({
430
524
  },
431
525
  });
432
526
  // Export actions
433
- export const { fetchReconciliation, fetchReconciliationFailure, fetchReconciliationSuccess, saveReconciliationDetail, saveReconciliationDetailFailure, updateSelectedAccountId, setConnectionInProgressForAccount, setStatementParseInProgress, updateReconcileTabLocalData, updateReconcileTabListSortState, updateReconcileTabListScrollState, saveReconciliationDetailSuccess, updateSelectedTab, updateBalancesLocalData, initialiseLocalDataForSelectedAccountId, clearExpenseAutomationReconciliationView, updateSelectedDrawerAccountId, updateReviewTabSortState, initializeReconciliationReviewTabLocalData, updateReviewTabLocalData, saveReconciliationReview, updateSaveReconciliationReviewFetchStatus, updateReconListScrollPosition, updateAccountReconciliationLocalData, deleteAccountStatement, deleteAccountStatementSuccess, deleteAccountStatementFailure, uploadAccountStatement, uploadAccountStatementSuccess, uploadAccountStatementFailure, updateStatementUploadChosen, } = expenseAutomationReconciliationView.actions;
527
+ export const { fetchReconciliation, fetchReconciliationFailure, fetchReconciliationSuccess, saveReconciliationDetail, saveReconciliationDetailFailure, updateSelectedAccountId, setConnectionInProgressForAccount, setStatementParseInProgress, updateReconcileTabLocalData, updateReconcileTabListSortState, updateReconcileTabListScrollState, saveReconciliationDetailSuccess, updateSelectedTab, updateBalancesLocalData, initialiseLocalDataForSelectedAccountId, clearExpenseAutomationReconciliationView, updateSelectedDrawerAccountId, updateReviewTabSortState, initializeReconciliationReviewTabLocalData, updateReviewTabLocalData, saveReconciliationReview, updateSaveReconciliationReviewFetchStatus, updateReconListScrollPosition, updateAccountReconciliationLocalData, deleteAccountStatement, deleteAccountStatementSuccess, deleteAccountStatementFailure, excludeAccountFromReconciliation, excludeAccountFromReconciliationSuccess, excludeAccountFromReconciliationFailure, includeAccountInReconciliation, includeAccountInReconciliationSuccess, includeAccountInReconciliationFailure, uploadAccountStatement, uploadAccountStatementSuccess, uploadAccountStatementFailure, updateStatementUploadChosen, updateNodeCollapseState, } = expenseAutomationReconciliationView.actions;
434
528
  // Export reducer
435
529
  export default expenseAutomationReconciliationView.reducer;
436
- function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliationData, refreshViewInBackground) {
530
+ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliationData, refreshViewInBackground, excludedAccounts) {
531
+ draft.excludedAccountIDs = excludedAccounts.map((ea) => ea.account_id);
532
+ draft.excludedAccountExclusionInfo = {};
533
+ excludedAccounts.forEach((ea) => {
534
+ const { exclusion_info } = ea;
535
+ draft.excludedAccountExclusionInfo[ea.account_id] = {
536
+ bankBalance: exclusion_info.bank_balance != null
537
+ ? {
538
+ amount: exclusion_info.bank_balance,
539
+ currencyCode: ea.currency_code ?? 'USD',
540
+ currencySymbol: ea.currency_symbol ?? '$',
541
+ }
542
+ : undefined,
543
+ clearedBalance: exclusion_info.cleared_balance != null
544
+ ? {
545
+ amount: exclusion_info.cleared_balance,
546
+ currencyCode: ea.currency_code ?? 'USD',
547
+ currencySymbol: ea.currency_symbol ?? '$',
548
+ }
549
+ : undefined,
550
+ variance: exclusion_info.variance != null
551
+ ? {
552
+ amount: exclusion_info.variance,
553
+ currencyCode: ea.currency_code ?? 'USD',
554
+ currencySymbol: ea.currency_symbol ?? '$',
555
+ }
556
+ : undefined,
557
+ };
558
+ });
437
559
  draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)] = {
438
560
  accountIDs: [],
439
561
  reconciliationByAccountID: {},
@@ -471,6 +593,9 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
471
593
  ? toReconciliationAccountSource(account.reconciliation_source)
472
594
  : undefined,
473
595
  },
596
+ accountDetectionReason: account?.detection_info != null && account.detection_reason != null
597
+ ? account.detection_reason
598
+ : undefined,
474
599
  };
475
600
  accountReconciliationRecords.accountIDs.push(reconciliation.account_id);
476
601
  });
@@ -516,3 +641,42 @@ function updateReconciliationByAccountID(draft, accounts, selectedPeriod, accoun
516
641
  };
517
642
  }
518
643
  }
644
+ const updateExcludedAccountExclusionInfo = (draft, account) => {
645
+ draft.excludedAccountExclusionInfo[account.account_id] = {
646
+ bankBalance: account.bank_balance != null
647
+ ? {
648
+ amount: account.bank_balance,
649
+ currencyCode: account.currency_code ?? 'USD',
650
+ currencySymbol: account.currency_symbol ?? '$',
651
+ }
652
+ : undefined,
653
+ clearedBalance: account.cleared_balance != null
654
+ ? {
655
+ amount: account.cleared_balance,
656
+ currencyCode: account.currency_code ?? 'USD',
657
+ currencySymbol: account.currency_symbol ?? '$',
658
+ }
659
+ : undefined,
660
+ variance: account.variance != null
661
+ ? {
662
+ amount: account.variance,
663
+ currencyCode: account.currency_code ?? 'USD',
664
+ currencySymbol: account.currency_symbol ?? '$',
665
+ }
666
+ : undefined,
667
+ };
668
+ };
669
+ const updateReconciliationByAccountIDOnIncludeAccount = (draft, accountId, reconciliation, monthYearPeriodId) => {
670
+ draft.accountReconciliationRecordsBySelectedPeriod[monthYearPeriodId].reconciliationByAccountID[accountId] = {
671
+ accountId,
672
+ reconciliationId: reconciliation.reconciliation_id ?? undefined,
673
+ transactionFetchState: { fetchState: 'Not-Started', error: undefined },
674
+ refreshStatus: { fetchState: 'Not-Started', error: undefined },
675
+ statementDeleteStatus: { fetchState: 'Not-Started', error: undefined },
676
+ statementUploadStatus: { fetchState: 'Not-Started', error: undefined },
677
+ statementUpdateStatus: { fetchState: 'Not-Started', error: undefined },
678
+ statementParseInProgress: reconciliation.bank_status.code === 'parsing',
679
+ localData: {},
680
+ accountDetectionReason: undefined,
681
+ };
682
+ };
@@ -1,4 +1,3 @@
1
1
  import { stringToUnion } from '../../../commonStateTypes/stringToUnion';
2
2
  export const ALL_ACCOUNT_RECON_SECTION_IDS = ['assets', 'liabilities'];
3
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
4
- const toAccountReconSectionID = (v) => stringToUnion(v, ALL_ACCOUNT_RECON_SECTION_IDS);
3
+ export const toAccountReconSectionID = (v) => stringToUnion(v, ALL_ACCOUNT_RECON_SECTION_IDS);
@@ -9,6 +9,7 @@ import { getAccountsByType } from '../../../entity/account/accountSelector';
9
9
  import { getAccountReconByAccountIdAndSelectedPeriod } from '../../../entity/accountRecon/accountReconSelector';
10
10
  import { getCurrentTenant } from '../../../entity/tenant/tenantSelector';
11
11
  import { getVendorByVendorId } from '../../../entity/vendor/vendorSelector';
12
+ import { date } from '../../../zeniDayJS';
12
13
  import { getAccountList, getNestedAccountListHierarchy, } from '../../accountList/accountListSelector';
13
14
  import { getClassList, getNestedClassListHierarchy, } from '../../classList/classListSelector';
14
15
  import { initialActionFetchState, initialReconciliationTabsState, initialState, } from '../reducers/reconciliationViewReducer';
@@ -90,6 +91,30 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
90
91
  totalVariancePercentage: undefined,
91
92
  },
92
93
  },
94
+ excludedAccountReconciliationByAccountID: {},
95
+ excludedAccountReconciliationBySectionID: {
96
+ assets: {
97
+ sectionId: 'assets',
98
+ accountIDs: [],
99
+ totalBankBalance: undefined,
100
+ totalClearedBalance: undefined,
101
+ totalReconciledBalance: undefined,
102
+ totalVariance: undefined,
103
+ totalVariancePercentage: undefined,
104
+ },
105
+ liabilities: {
106
+ sectionId: 'liabilities',
107
+ accountIDs: [],
108
+ totalBankBalance: undefined,
109
+ totalClearedBalance: undefined,
110
+ totalReconciledBalance: undefined,
111
+ totalVariance: undefined,
112
+ totalVariancePercentage: undefined,
113
+ },
114
+ },
115
+ excludeAccountFetchState: reconciliationViewState.actionFetchState.excludeAccountFetch,
116
+ includeAccountFetchState: reconciliationViewState.actionFetchState.includeAccountFetch,
117
+ excludedAccountIDs: reconciliationViewState.excludedAccountIDs,
93
118
  };
94
119
  }
95
120
  const allAccountIDs = accountReconForMonthYearPeriod.accountIDs;
@@ -227,6 +252,8 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
227
252
  .transactionFetchState,
228
253
  accountListState.byReportId.accountList,
229
254
  ]),
255
+ accountDetectionReason: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
256
+ .accountDetectionReason,
230
257
  };
231
258
  });
232
259
  const accountReconciliationBySectionID = {
@@ -249,6 +276,88 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
249
276
  totalVariancePercentage: liabilityTotals.variancePercentage,
250
277
  },
251
278
  };
279
+ const bankAccountIdSet = new Set(uniqueBankAccounts.map((a) => a.accountId));
280
+ const creditCardIdSet = new Set(uniqueCreditCards.map((a) => a.accountId));
281
+ const excludedAssetAccountIDs = [];
282
+ const excludedLiabilityAccountIDs = [];
283
+ reconciliationViewState.excludedAccountIDs.forEach((accountID) => {
284
+ const isAsset = bankAccountIdSet.has(accountID);
285
+ const isLiability = creditCardIdSet.has(accountID);
286
+ if (!isAsset && !isLiability) {
287
+ return;
288
+ }
289
+ if (isAsset) {
290
+ excludedAssetAccountIDs.push(accountID);
291
+ }
292
+ else {
293
+ excludedLiabilityAccountIDs.push(accountID);
294
+ }
295
+ });
296
+ const excludedAccountReconciliationBySectionID = {
297
+ assets: {
298
+ sectionId: 'assets',
299
+ accountIDs: excludedAssetAccountIDs,
300
+ },
301
+ liabilities: {
302
+ sectionId: 'liabilities',
303
+ accountIDs: excludedLiabilityAccountIDs,
304
+ },
305
+ };
306
+ const excludedAccountReconciliationByAccountID = {};
307
+ const accountsInState = Object.values(accountState.accountsByKey);
308
+ const accountsInStateMap = new Map(accountsInState.map((a) => [a.accountId, a]));
309
+ reconciliationViewState.excludedAccountIDs.forEach((excludedAccountID) => {
310
+ const account = accountsInStateMap.get(excludedAccountID);
311
+ const exclusionInfo = reconciliationViewState.excludedAccountExclusionInfo[excludedAccountID];
312
+ if (account != null) {
313
+ excludedAccountReconciliationByAccountID[excludedAccountID] = {
314
+ refreshStatus: { fetchState: 'Not-Started' },
315
+ statementUpdateStatus: { fetchState: 'Not-Started' },
316
+ statementUploadStatus: { fetchState: 'Not-Started' },
317
+ statementDeleteStatus: { fetchState: 'Not-Started' },
318
+ localData: {},
319
+ connectionInProgress: false,
320
+ statementParseInProgress: false,
321
+ accountConnectionStatus: 'not_connected',
322
+ transactionFetchState: { fetchState: 'Not-Started' },
323
+ accountReconEntity: {
324
+ account: {
325
+ accountId: account.accountId,
326
+ accountName: account.accountName,
327
+ accountType: account.accountType,
328
+ accountSubType: account.accountSubType,
329
+ accountDescription: account.accountDescription,
330
+ qboId: account.qboId,
331
+ coaId: account.coaId,
332
+ labels: account.labels,
333
+ },
334
+ currency: {
335
+ currencyCode: exclusionInfo?.bankBalance?.currencyCode ??
336
+ exclusionInfo?.clearedBalance?.currencyCode ??
337
+ 'USD',
338
+ currencySymbol: exclusionInfo?.bankBalance?.currencySymbol ??
339
+ exclusionInfo?.clearedBalance?.currencySymbol ??
340
+ '$',
341
+ },
342
+ startDate: date(new Date().toDateString()),
343
+ endDate: date(new Date().toDateString()),
344
+ statementStatus: { code: 'not_found', label: 'Not Found' },
345
+ transactionsToReconcile: [],
346
+ transactionsToReview: [],
347
+ balance: exclusionInfo?.bankBalance,
348
+ clearedBalance: exclusionInfo?.clearedBalance,
349
+ variance: exclusionInfo?.variance,
350
+ variancePercentage: exclusionInfo?.variance != null &&
351
+ exclusionInfo?.bankBalance != null &&
352
+ exclusionInfo?.bankBalance.amount !== 0
353
+ ? Math.abs((exclusionInfo.variance.amount /
354
+ exclusionInfo.bankBalance.amount) *
355
+ 100)
356
+ : undefined,
357
+ },
358
+ };
359
+ }
360
+ });
252
361
  const accountListNestedAccountHierarchy = getNestedAccountListHierarchy(accountListState, 'accountList');
253
362
  const classListNestedAccountHierarchy = getNestedClassListHierarchy(classListState);
254
363
  const accountsList = getAccountList(accountState, accountListState, 'accountList');
@@ -309,6 +418,11 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
309
418
  allClassList: allClasses,
310
419
  reviewTabSelectedVendorByTransactionId,
311
420
  reconListUIState: reconciliationViewState.reconListUIState,
421
+ excludedAccountReconciliationBySectionID,
422
+ excludedAccountReconciliationByAccountID,
423
+ excludeAccountFetchState: reconciliationViewState.actionFetchState.excludeAccountFetch,
424
+ includeAccountFetchState: reconciliationViewState.actionFetchState.includeAccountFetch,
425
+ excludedAccountIDs: reconciliationViewState.excludedAccountIDs,
312
426
  };
313
427
  });
314
428
  export const isAccountReconReport = (reportId) => {