@zeniai/client-epic-state 5.2.35-beta2MM → 5.2.35-beta4MM

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 (38) hide show
  1. package/lib/entity/actualMatching/actualMatchingPayload.d.ts +6 -1
  2. package/lib/entity/actualMatching/actualMatchingPayload.js +8 -13
  3. package/lib/entity/actualMatching/actualMatchingReducer.d.ts +3 -2
  4. package/lib/entity/actualMatching/actualMatchingReducer.js +3 -3
  5. package/lib/entity/actualMatching/actualMatchingState.d.ts +3 -2
  6. package/lib/esm/entity/actualMatching/actualMatchingPayload.js +9 -14
  7. package/lib/esm/entity/actualMatching/actualMatchingReducer.js +3 -3
  8. package/lib/esm/index.js +2 -2
  9. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +2 -2
  10. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +3 -2
  11. package/lib/esm/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +21 -24
  12. package/lib/esm/view/expenseAutomationView/epics/actualMatching/refreshActualMatchingList.js +16 -0
  13. package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +6 -9
  14. package/lib/esm/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +15 -28
  15. package/lib/esm/view/expenseAutomationView/payload/actualMatchingPayload.js +9 -9
  16. package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +34 -16
  17. package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +65 -21
  18. package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +3 -0
  19. package/lib/index.d.ts +3 -2
  20. package/lib/index.js +49 -48
  21. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +1 -1
  22. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.d.ts +1 -1
  23. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +3 -2
  24. package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +17 -20
  25. package/lib/view/expenseAutomationView/epics/actualMatching/refreshActualMatchingList.d.ts +3 -0
  26. package/lib/view/expenseAutomationView/epics/actualMatching/refreshActualMatchingList.js +19 -0
  27. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +5 -8
  28. package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +13 -26
  29. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +2 -2
  30. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +9 -9
  31. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +19 -16
  32. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +33 -15
  33. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +0 -1
  34. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +6 -1
  35. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +66 -21
  36. package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +5 -1
  37. package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +4 -0
  38. package/package.json +1 -1
@@ -2,6 +2,10 @@ import { ID } from '../../commonStateTypes/common';
2
2
  import { JEOneTimeAccrualPayload } from '../jeSchedules/jeSchedulesPayload';
3
3
  import { ActualMatchingMatch } from './actualMatchingState';
4
4
  import { ActualMatchingMatchId } from './actualMatchingTypes';
5
+ export interface DisplayCurrencyFallback {
6
+ currencyCode: string;
7
+ currencySymbol: string;
8
+ }
5
9
  export interface ActualMatchingMatchPayload {
6
10
  accrued_amount: number;
7
11
  actual_amount: number;
@@ -12,6 +16,7 @@ export interface ActualMatchingMatchPayload {
12
16
  transaction_type: string;
13
17
  currency_code?: string | null;
14
18
  currency_symbol?: string | null;
19
+ leftovers?: JEOneTimeAccrualPayload[];
15
20
  match_shape?: string | null;
16
21
  match_tier?: string | null;
17
22
  transaction_date?: string | null;
@@ -22,4 +27,4 @@ export interface ActualMatchingListResponsePayload {
22
27
  matches: ActualMatchingMatchPayload[];
23
28
  total: number;
24
29
  }
25
- export declare function toActualMatchingMatch(payload: ActualMatchingMatchPayload): ActualMatchingMatch;
30
+ export declare function toActualMatchingMatch(payload: ActualMatchingMatchPayload, fallbackCurrency?: DisplayCurrencyFallback): ActualMatchingMatch;
@@ -4,29 +4,23 @@ exports.toActualMatchingMatch = toActualMatchingMatch;
4
4
  const amount_1 = require("../../commonStateTypes/amount");
5
5
  const stringToUnion_1 = require("../../commonStateTypes/stringToUnion");
6
6
  const jeSchedulesPayload_1 = require("../jeSchedules/jeSchedulesPayload");
7
- const USD_CURRENCY_CODE = 'USD';
8
- const USD_CURRENCY_SYMBOL = '$';
9
7
  const MATCH_KINDS = [
10
8
  'auto_reversed',
11
9
  'pending_review',
12
10
  'manually_reversed',
13
11
  ];
14
12
  function toMatchKind(raw) {
15
- const kind = (0, stringToUnion_1.stringToUnionStrict)(raw, MATCH_KINDS);
16
- if (kind == null) {
17
- console.error(`Unknown ActualMatchingMatchKind: ${raw}`);
18
- return 'auto_reversed';
19
- }
20
- return kind;
13
+ return (0, stringToUnion_1.stringToUnion)(raw, MATCH_KINDS);
21
14
  }
22
- function toActualMatchingMatch(payload) {
15
+ function toActualMatchingMatch(payload, fallbackCurrency) {
23
16
  const currencyCode = payload.currency_code != null && payload.currency_code !== ''
24
17
  ? payload.currency_code
25
- : USD_CURRENCY_CODE;
18
+ : fallbackCurrency?.currencyCode ?? '';
26
19
  const currencySymbol = payload.currency_symbol != null && payload.currency_symbol !== ''
27
20
  ? payload.currency_symbol
28
- : currencyCode === USD_CURRENCY_CODE
29
- ? USD_CURRENCY_SYMBOL
21
+ : fallbackCurrency != null &&
22
+ currencyCode === fallbackCurrency.currencyCode
23
+ ? fallbackCurrency.currencySymbol
30
24
  : currencyCode;
31
25
  return {
32
26
  matchId: payload.match_id,
@@ -34,12 +28,13 @@ function toActualMatchingMatch(payload) {
34
28
  transactionIntegrationId: payload.transaction_integration_id,
35
29
  transactionDate: payload.transaction_date ?? undefined,
36
30
  vendorId: payload.vendor_id ?? undefined,
37
- vendorName: payload.vendor_name ?? '',
31
+ vendorName: payload.vendor_name ?? undefined,
38
32
  kind: toMatchKind(payload.kind),
39
33
  matchTier: payload.match_tier ?? undefined,
40
34
  matchShape: payload.match_shape ?? undefined,
41
35
  accruedAmount: (0, amount_1.toAmount)(payload.accrued_amount, currencyCode, currencySymbol),
42
36
  actualAmount: (0, amount_1.toAmount)(payload.actual_amount, currencyCode, currencySymbol),
43
37
  members: payload.members.map(jeSchedulesPayload_1.toJEOneTimeAccrual),
38
+ leftovers: (payload.leftovers ?? []).map(jeSchedulesPayload_1.toJEOneTimeAccrual),
44
39
  };
45
40
  }
@@ -1,8 +1,9 @@
1
- import { ActualMatchingMatchPayload } from './actualMatchingPayload';
1
+ import { ActualMatchingMatchPayload, DisplayCurrencyFallback } from './actualMatchingPayload';
2
2
  import { ActualMatchingState } from './actualMatchingState';
3
3
  export declare const initialState: ActualMatchingState;
4
- export declare const updateActualMatchingMatches: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[matches: ActualMatchingMatchPayload[]], {
4
+ export declare const updateActualMatchingMatches: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[matches: ActualMatchingMatchPayload[], fallbackCurrency?: DisplayCurrencyFallback | undefined], {
5
5
  matches: ActualMatchingMatchPayload[];
6
+ fallbackCurrency: DisplayCurrencyFallback | undefined;
6
7
  }, "actualMatching/updateActualMatchingMatches", never, never>;
7
8
  declare const _default: import("redux").Reducer<ActualMatchingState>;
8
9
  export default _default;
@@ -12,12 +12,12 @@ const actualMatching = (0, toolkit_1.createSlice)({
12
12
  initialState: exports.initialState,
13
13
  reducers: {
14
14
  updateActualMatchingMatches: {
15
- prepare(matches) {
16
- return { payload: { matches } };
15
+ prepare(matches, fallbackCurrency) {
16
+ return { payload: { matches, fallbackCurrency } };
17
17
  },
18
18
  reducer(draft, action) {
19
19
  action.payload.matches.forEach((payload) => {
20
- const match = (0, actualMatchingPayload_1.toActualMatchingMatch)(payload);
20
+ const match = (0, actualMatchingPayload_1.toActualMatchingMatch)(payload, action.payload.fallbackCurrency);
21
21
  draft.byMatchId[match.matchId] = match;
22
22
  });
23
23
  },
@@ -9,13 +9,14 @@ export interface ActualMatchingMatch {
9
9
  kind: ActualMatchingMatchKind;
10
10
  matchId: ActualMatchingMatchId;
11
11
  members: JEOneTimeAccrualState[];
12
- transactionIntegrationId: string;
12
+ transactionIntegrationId: ID;
13
13
  transactionType: string;
14
- vendorName: string;
14
+ leftovers?: JEOneTimeAccrualState[];
15
15
  matchShape?: string;
16
16
  matchTier?: string;
17
17
  transactionDate?: string;
18
18
  vendorId?: ID;
19
+ vendorName?: string;
19
20
  }
20
21
  export interface ActualMatchingState {
21
22
  byMatchId: Record<ActualMatchingMatchId, ActualMatchingMatch>;
@@ -1,29 +1,23 @@
1
1
  import { toAmount } from '../../commonStateTypes/amount';
2
- import { stringToUnionStrict } from '../../commonStateTypes/stringToUnion';
2
+ import { stringToUnion } from '../../commonStateTypes/stringToUnion';
3
3
  import { toJEOneTimeAccrual, } from '../jeSchedules/jeSchedulesPayload';
4
- const USD_CURRENCY_CODE = 'USD';
5
- const USD_CURRENCY_SYMBOL = '$';
6
4
  const MATCH_KINDS = [
7
5
  'auto_reversed',
8
6
  'pending_review',
9
7
  'manually_reversed',
10
8
  ];
11
9
  function toMatchKind(raw) {
12
- const kind = stringToUnionStrict(raw, MATCH_KINDS);
13
- if (kind == null) {
14
- console.error(`Unknown ActualMatchingMatchKind: ${raw}`);
15
- return 'auto_reversed';
16
- }
17
- return kind;
10
+ return stringToUnion(raw, MATCH_KINDS);
18
11
  }
19
- export function toActualMatchingMatch(payload) {
12
+ export function toActualMatchingMatch(payload, fallbackCurrency) {
20
13
  const currencyCode = payload.currency_code != null && payload.currency_code !== ''
21
14
  ? payload.currency_code
22
- : USD_CURRENCY_CODE;
15
+ : fallbackCurrency?.currencyCode ?? '';
23
16
  const currencySymbol = payload.currency_symbol != null && payload.currency_symbol !== ''
24
17
  ? payload.currency_symbol
25
- : currencyCode === USD_CURRENCY_CODE
26
- ? USD_CURRENCY_SYMBOL
18
+ : fallbackCurrency != null &&
19
+ currencyCode === fallbackCurrency.currencyCode
20
+ ? fallbackCurrency.currencySymbol
27
21
  : currencyCode;
28
22
  return {
29
23
  matchId: payload.match_id,
@@ -31,12 +25,13 @@ export function toActualMatchingMatch(payload) {
31
25
  transactionIntegrationId: payload.transaction_integration_id,
32
26
  transactionDate: payload.transaction_date ?? undefined,
33
27
  vendorId: payload.vendor_id ?? undefined,
34
- vendorName: payload.vendor_name ?? '',
28
+ vendorName: payload.vendor_name ?? undefined,
35
29
  kind: toMatchKind(payload.kind),
36
30
  matchTier: payload.match_tier ?? undefined,
37
31
  matchShape: payload.match_shape ?? undefined,
38
32
  accruedAmount: toAmount(payload.accrued_amount, currencyCode, currencySymbol),
39
33
  actualAmount: toAmount(payload.actual_amount, currencyCode, currencySymbol),
40
34
  members: payload.members.map(toJEOneTimeAccrual),
35
+ leftovers: (payload.leftovers ?? []).map(toJEOneTimeAccrual),
41
36
  };
42
37
  }
@@ -9,12 +9,12 @@ const actualMatching = createSlice({
9
9
  initialState,
10
10
  reducers: {
11
11
  updateActualMatchingMatches: {
12
- prepare(matches) {
13
- return { payload: { matches } };
12
+ prepare(matches, fallbackCurrency) {
13
+ return { payload: { matches, fallbackCurrency } };
14
14
  },
15
15
  reducer(draft, action) {
16
16
  action.payload.matches.forEach((payload) => {
17
- const match = toActualMatchingMatch(payload);
17
+ const match = toActualMatchingMatch(payload, action.payload.fallbackCurrency);
18
18
  draft.byMatchId[match.matchId] = match;
19
19
  });
20
20
  },
package/lib/esm/index.js CHANGED
@@ -200,7 +200,7 @@ import { getExpenseAutomationReconciliationView, getLedgerAccountIdsWithStatemen
200
200
  import { getExpenseAutomationTransactionView, getLastTransferEntryReplacement, } from './view/expenseAutomationView/selectors/transactionCategorizationSelector';
201
201
  import { applyTransactionFilters } from './view/expenseAutomationView/transactionFilterHelpers';
202
202
  import { TRANSACTION_FILTER_CATEGORIES, } from './view/expenseAutomationView/transactionFilterTypes';
203
- import { MATCH_ACCRUAL_SEARCH_LIMIT, MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, toActualMatchingSortKey as toExpenseAutomationActualMatchingSortKey, toMatchAndReverseResultStatus, toUndoReversalResultStatus, } from './view/expenseAutomationView/types/actualMatchingViewState';
203
+ import { MATCH_ACCRUAL_SEARCH_LIMIT, MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, actualMatchingTransactionLineKey, toActualMatchingSortKey as toExpenseAutomationActualMatchingSortKey, toMatchAndReverseResultStatus, toUndoReversalResultStatus, } from './view/expenseAutomationView/types/actualMatchingViewState';
204
204
  import { DEFAULT_COMPLETED_SUB_TAB, toCompletedSubTab, } from './view/expenseAutomationView/types/completedSubTab';
205
205
  import { ALL_JE_PAGE_TABS, toJEScheduleSortKey as toExpenseAutomationJEScheduleSortKey, toJEPageTab, } from './view/expenseAutomationView/types/jeSchedulesViewState';
206
206
  import { BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toMatchSource, toMissingReceiptsTab, } from './view/expenseAutomationView/types/missingReceiptsViewState';
@@ -491,7 +491,7 @@ export { stringToUnion, stringToUnionStrict };
491
491
  export { fetchMonthEndCloseChecks, fetchMonthClosePerformanceTrend, getMonthEndCloseChecksViewByTenantId, ALL_MONTH_END_CLOSE_CHECKS_FREQUENCY, };
492
492
  export {
493
493
  // Bulk Upload Types
494
- BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, DEFAULT_COMPLETED_SUB_TAB, DEFAULT_TRANSACTION_GROUP, TRANSACTION_GROUPS, toTransactionGroup, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, ALL_JE_PAGE_TABS, MATCH_ACCRUAL_SEARCH_LIMIT, MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, toExpenseAutomationJEScheduleSortKey, toExpenseAutomationActualMatchingSortKey, toJEPageTab, toMatchAndReverseResultStatus, toUndoReversalResultStatus, toggleJECreatedGroupCollapsed, toggleJEPendingGroupCollapsed, updateJEScheduleTypeFilter, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, toExpenseAutomationViewTypeStrict, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, updateTransactionGroup, fetchExpenseAutomationMissingReceipts,
494
+ BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, DEFAULT_COMPLETED_SUB_TAB, DEFAULT_TRANSACTION_GROUP, TRANSACTION_GROUPS, toTransactionGroup, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, actualMatchingTransactionLineKey, ALL_JE_PAGE_TABS, MATCH_ACCRUAL_SEARCH_LIMIT, MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, toExpenseAutomationJEScheduleSortKey, toExpenseAutomationActualMatchingSortKey, toJEPageTab, toMatchAndReverseResultStatus, toUndoReversalResultStatus, toggleJECreatedGroupCollapsed, toggleJEPendingGroupCollapsed, updateJEScheduleTypeFilter, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, toExpenseAutomationViewTypeStrict, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, updateTransactionGroup, fetchExpenseAutomationMissingReceipts,
495
495
  // Bulk Upload Actions
496
496
  bulkUploadReceipts, bulkUploadAutomatchingTimedOut, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, restoreBulkUploadAutomatchingOnMount, restoreBulkUploadMatchingState, updateBulkUploadProgress, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, clearBulkUploadBatchDetailsForScopeChange, markBatchDetailRefreshAttempted, refreshBatchDetailsForBatchId, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, setBulkUploadUploadedFileCount, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete, fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, fetchFluxAnalysisView, clearExpenseAutomationFluxAnalysisView, updateOperatingExpensesIdsForReview as updateFluxOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview as updateFluxAnalysisSelectedSectionIdsForReview, reviewFluxAnalysisView, updateExpenseAutomationMissingReceiptUploadState, updateExpenseAutomationMissingReceiptsUIState, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, getExpenseAutomationFluxAnalysisView, updateCurrentSelectedView, updateCurrentSelectedPeriod, getExpenseAutomationTransactionView, getLastTransferEntryReplacement, updateFluxAnalysisViewUIState, updateFluxAnalysisViewPageMetaData, MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, excludeAccountFromReconciliation, includeAccountInReconciliation, saveExpenseAutomationReconciliationDetail, updateExpenseAutomationReconcileTabListScrollState, updateExpenseAutomationReconReviewTabListSortState, updateExpenseAutomationReconcileTabListSortState, updateExpenseAutomationReconcileTabLocalData, updateExpenseAutomationAccountReconciliationSelectedTab, updateExpenseAutomationAccountReconciliationSelectedAccountId, getExpenseAutomationReconciliationView, getLedgerAccountIdsWithStatementOverrideWarning, getLedgerAccountsForCombinedStatementMapping, getReparseStatementStatusByAccountId, getUnavailableLedgerAccountIds, fetchReconciliationView, uploadAccountStatementIntoDocumentAI, updateExpenseAutomationReconListScrollPosition, setConnectionInProgressForAccountReconciliation, getAccountReconByAccountIdAndSelectedPeriod, toReconciliationTabsType, isAccountReconReport, updateExpenseAutomationReconReviewTabLocalData, updateExpenseAutomationSelectedDrawerAccountId, updateStatementProcessingFailed, saveExpenseAutomationReconciliationReview, updateExpenseAutomationAccountReconciliationLocalData, toReconciliationAccountSource, deleteAccountStatement, deleteCombinedStatement, uploadAccountStatement, parseCombinedStatement, parseStatement, parseStatementSuccess, parseStatementFailure, reparseStatement, reparseStatementSuccess, reparseStatementFailure, resetReparseStatementStatus, updateParsedStatementData, updateNodeCollapseState, updateStatementUploadChosen, submitCombinedStatementUpdate, submitStatementUpdate, clearStatementDateConflict, confirmStatementMapping, updateStatementUpdateLocalData, isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType, isReviewTransactionCreditCardPaymentType, isReviewTransactionDepositType, isReviewTransactionExpenseType, isReviewTransactionCreditCardCreditType, setStatementParseInProgress, setStatementProcessingDismissedToBackground, updateStatementProcessingBackgroundCompletedSteps, };
497
497
  export { computeNewScheduleJeDetails, createOneTimeAccrual, createOneTimeAccrualFailure, createOneTimeAccrualSuccess, fetchOneTimeAccrual, getJeNewAccrualAccountsView, ignoreOneTimeAccrual, promoteOneTimeAccrual, revertJeSchedule, revertOneTimeAccrual, getJeNewScheduleSearchTransactionsView, getJeNewScheduleView, };
@@ -5,7 +5,7 @@ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePay
5
5
  import { clearAll } from '../../../../rootActions';
6
6
  import { toServiceMonthFromPeriod, } from '../../payload/actualMatchingPayload';
7
7
  import { fetchActualMatching, fetchActualMatchingFailure, fetchActualMatchingSuccess, } from '../../reducers/actualMatchingViewReducer';
8
- import { getSelectedMonthYearForCurrentTenant } from '../../selectors/actualMatchingViewSelector';
8
+ import { getSelectedMonthYearForCurrentTenant, getTenantDisplayCurrency, } from '../../selectors/actualMatchingViewSelector';
9
9
  export const fetchActualMatchingEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchActualMatching.match), switchMap((action) => {
10
10
  const state = state$.value;
11
11
  const { period, refreshViewInBackground } = action.payload;
@@ -21,7 +21,7 @@ export const fetchActualMatchingEpic = (actions$, state$, zeniAPI) => actions$.p
21
21
  const matches = response.data.matches;
22
22
  const updateActions = [];
23
23
  if (matches.length > 0) {
24
- updateActions.push(updateActualMatchingMatches(matches));
24
+ updateActions.push(updateActualMatchingMatches(matches, getTenantDisplayCurrency(state)));
25
25
  }
26
26
  updateActions.push(fetchActualMatchingSuccess({
27
27
  matchIds: matches.map((match) => match.match_id),
@@ -4,14 +4,15 @@ import { updateActualMatchingMatches } from '../../../../entity/actualMatching/a
4
4
  import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
5
5
  import { clearAll } from '../../../../rootActions';
6
6
  import { fetchActualMatchingMatch, fetchActualMatchingMatchFailure, fetchActualMatchingMatchSuccess, } from '../../reducers/actualMatchingViewReducer';
7
- export const fetchActualMatchingMatchEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchActualMatchingMatch.match), mergeMap((action) => {
7
+ import { getTenantDisplayCurrency } from '../../selectors/actualMatchingViewSelector';
8
+ export const fetchActualMatchingMatchEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchActualMatchingMatch.match), mergeMap((action) => {
8
9
  const { matchId, refreshViewInBackground } = action.payload;
9
10
  return zeniAPI
10
11
  .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/actual-matching/${encodeURIComponent(matchId)}`)
11
12
  .pipe(mergeMap((response) => {
12
13
  if (isSuccessResponse(response) && response.data != null) {
13
14
  return from([
14
- updateActualMatchingMatches([response.data]),
15
+ updateActualMatchingMatches([response.data], getTenantDisplayCurrency(state$.value)),
15
16
  fetchActualMatchingMatchSuccess({
16
17
  matchId,
17
18
  refreshViewInBackground,
@@ -1,25 +1,13 @@
1
1
  import { from, of } from 'rxjs';
2
- import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
3
- import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/timePeriod';
4
- import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
2
+ import { catchError, exhaustMap, filter, mergeMap, takeUntil } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../../responsePayload';
5
4
  import { clearAll } from '../../../../rootActions';
6
- import { toMatchAndReverseResult, } from '../../payload/actualMatchingPayload';
7
- import { clearMatchNewModal, fetchActualMatching, matchAndReverseAccruals, matchAndReverseAccrualsFailure, matchAndReverseAccrualsSuccess, } from '../../reducers/actualMatchingViewReducer';
8
- import { getSelectedMonthYearForCurrentTenant } from '../../selectors/actualMatchingViewSelector';
9
- function refreshActualMatchingList(state) {
10
- const selectedMonthYear = getSelectedMonthYearForCurrentTenant(state);
11
- if (selectedMonthYear == null) {
12
- return [];
13
- }
14
- const period = convertToPeriod(selectedMonthYear);
15
- const start = toAbsoluteDay(period.start);
16
- const end = toAbsoluteDay(period.end);
17
- if (start == null || end == null) {
18
- return [];
19
- }
20
- return [fetchActualMatching({ start, end }, true)];
21
- }
22
- export const matchAndReverseAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(matchAndReverseAccruals.match), mergeMap((action) => {
5
+ import { toMatchAndReverseResult } from '../../payload/actualMatchingPayload';
6
+ import { clearMatchNewModal, matchAndReverseAccruals, matchAndReverseAccrualsFailure, matchAndReverseAccrualsSuccess } from '../../reducers/actualMatchingViewReducer';
7
+ import { refreshActualMatchingList } from './refreshActualMatchingList';
8
+ export const matchAndReverseAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(matchAndReverseAccruals.match),
9
+ // Posts reversing JEs; drop duplicate clicks while a request is in flight.
10
+ exhaustMap((action) => {
23
11
  const { transactionId, transactionIntegrationId, transactionType, lineId, accrualIds, transactionSyncToken, } = action.payload;
24
12
  const body = {
25
13
  transaction_id: transactionId,
@@ -34,12 +22,21 @@ export const matchAndReverseAccrualsEpic = (actions$, state$, zeniAPI) => action
34
22
  .pipe(mergeMap((response) => {
35
23
  if (isSuccessResponse(response) && response.data != null) {
36
24
  const results = response.data.results.map(toMatchAndReverseResult);
25
+ const openedFromMatchId = state$.value.expenseAutomationActualMatchingViewState.matchModal
26
+ .openedFromMatchId;
27
+ const matchId = openedFromMatchId ??
28
+ `${transactionType}:${transactionIntegrationId}`;
37
29
  const successActions = [
38
- matchAndReverseAccrualsSuccess({ results }),
30
+ matchAndReverseAccrualsSuccess({ matchId, results }),
39
31
  ];
40
- const anyReversed = results.some((result) => result.status === 'reversed');
41
- if (anyReversed) {
42
- successActions.push(...refreshActualMatchingList(state$.value), clearMatchNewModal());
32
+ const occupancyChanged = results.some((result) => result.status === 'reversed' || result.status === 'noop');
33
+ const allComplete = results.length > 0 &&
34
+ results.every((result) => result.status === 'reversed' || result.status === 'noop');
35
+ if (occupancyChanged) {
36
+ successActions.push(...refreshActualMatchingList(state$.value));
37
+ }
38
+ if (allComplete) {
39
+ successActions.push(clearMatchNewModal());
43
40
  }
44
41
  return from(successActions);
45
42
  }
@@ -0,0 +1,16 @@
1
+ import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/timePeriod';
2
+ import { fetchActualMatching } from '../../reducers/actualMatchingViewReducer';
3
+ import { getSelectedMonthYearForCurrentTenant } from '../../selectors/actualMatchingViewSelector';
4
+ export function refreshActualMatchingList(state) {
5
+ const selectedMonthYear = getSelectedMonthYearForCurrentTenant(state);
6
+ if (selectedMonthYear == null) {
7
+ return [];
8
+ }
9
+ const period = convertToPeriod(selectedMonthYear);
10
+ const start = toAbsoluteDay(period.start);
11
+ const end = toAbsoluteDay(period.end);
12
+ if (start == null || end == null) {
13
+ return [];
14
+ }
15
+ return [fetchActualMatching({ start, end }, true)];
16
+ }
@@ -5,15 +5,15 @@ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePay
5
5
  import { clearAll } from '../../../../rootActions';
6
6
  import { toActualMatchingTransactionSearchResult, } from '../../payload/actualMatchingPayload';
7
7
  import { openMatchNewModal, searchMatchAccruals, searchMatchTransactions, searchMatchTransactionsFailure, searchMatchTransactionsSuccess, } from '../../reducers/actualMatchingViewReducer';
8
- import { parseActualMatchingMatchId } from '../../selectors/actualMatchingViewSelector';
8
+ import { getTenantDisplayCurrency, parseActualMatchingMatchId, } from '../../selectors/actualMatchingViewSelector';
9
9
  import { MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, } from '../../types/actualMatchingViewState';
10
10
  export const searchMatchTransactionsEpic = (actions$, state$, zeniAPI) => {
11
11
  const openModal$ = actions$.pipe(filter(openMatchNewModal.match), mergeMap((action) => {
12
12
  const matchId = action.payload.matchId;
13
13
  if (matchId == null || matchId === '') {
14
14
  return from([
15
- searchMatchTransactions({ query: '' }),
16
- searchMatchAccruals({ query: '' }),
15
+ searchMatchTransactions(''),
16
+ searchMatchAccruals(''),
17
17
  ]);
18
18
  }
19
19
  const match = getActualMatchingMatchById(state$.value.actualMatchingState, matchId);
@@ -26,11 +26,7 @@ export const searchMatchTransactionsEpic = (actions$, state$, zeniAPI) => {
26
26
  ? match.transactionIntegrationId
27
27
  : parsed?.transactionIntegrationId;
28
28
  return from([
29
- searchMatchTransactions({
30
- query: '',
31
- transactionType,
32
- transactionIntegrationId,
33
- }),
29
+ searchMatchTransactions('', undefined, transactionType, transactionIntegrationId),
34
30
  ]);
35
31
  }));
36
32
  const searchActions$ = actions$.pipe(filter(searchMatchTransactions.match));
@@ -55,7 +51,8 @@ export const searchMatchTransactionsEpic = (actions$, state$, zeniAPI) => {
55
51
  if (isSuccessResponse(response) && response.data != null) {
56
52
  const { transactions, next_page_token } = response.data;
57
53
  const append = pageToken != null;
58
- const results = transactions.map(toActualMatchingTransactionSearchResult);
54
+ const fallbackCurrency = getTenantDisplayCurrency(state$.value);
55
+ const results = transactions.map((transaction) => toActualMatchingTransactionSearchResult(transaction, fallbackCurrency));
59
56
  return of(searchMatchTransactionsSuccess({
60
57
  append,
61
58
  nextPageToken: next_page_token ?? null,
@@ -1,33 +1,16 @@
1
1
  import { from, of } from 'rxjs';
2
- import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
3
- import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/timePeriod';
2
+ import { catchError, exhaustMap, filter, mergeMap, takeUntil, } from 'rxjs/operators';
4
3
  import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
5
4
  import { clearAll } from '../../../../rootActions';
6
5
  import { toUndoReversalResult, } from '../../payload/actualMatchingPayload';
7
- import { fetchActualMatching, fetchActualMatchingMatch, undoReversalAccruals, undoReversalAccrualsFailure, undoReversalAccrualsSuccess, } from '../../reducers/actualMatchingViewReducer';
8
- import { getSelectedMonthYearForCurrentTenant } from '../../selectors/actualMatchingViewSelector';
9
- function refreshActualMatchingList(state) {
10
- const selectedMonthYear = getSelectedMonthYearForCurrentTenant(state);
11
- if (selectedMonthYear == null) {
12
- return [];
13
- }
14
- const period = convertToPeriod(selectedMonthYear);
15
- const start = toAbsoluteDay(period.start);
16
- const end = toAbsoluteDay(period.end);
17
- if (start == null || end == null) {
18
- return [];
19
- }
20
- return [fetchActualMatching({ start, end }, true)];
21
- }
22
- function refreshOpenMatchDetails(state) {
23
- const detailState = state.expenseAutomationActualMatchingViewState.detailFetchStateByMatchId;
24
- return Object.keys(detailState)
25
- .filter((matchId) => detailState[matchId]?.fetchState !== 'Not-Started')
26
- .map((matchId) => fetchActualMatchingMatch(matchId, true));
27
- }
28
- export const undoReversalAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(undoReversalAccruals.match), mergeMap((action) => {
6
+ import { fetchActualMatchingMatch, undoReversalAccruals, undoReversalAccrualsFailure, undoReversalAccrualsSuccess, } from '../../reducers/actualMatchingViewReducer';
7
+ import { refreshActualMatchingList } from './refreshActualMatchingList';
8
+ export const undoReversalAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(undoReversalAccruals.match),
9
+ // Posts QBO deletes; drop duplicate clicks while a request is in flight.
10
+ exhaustMap((action) => {
11
+ const { accrualIds, matchId } = action.payload;
29
12
  const body = {
30
- accrual_ids: action.payload.accrualIds,
13
+ accrual_ids: accrualIds,
31
14
  };
32
15
  return zeniAPI
33
16
  .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/undo-reversal`, body)
@@ -35,16 +18,20 @@ export const undoReversalAccrualsEpic = (actions$, state$, zeniAPI) => actions$.
35
18
  if (isSuccessResponse(response) && response.data != null) {
36
19
  const results = response.data.results.map(toUndoReversalResult);
37
20
  const successActions = [
38
- undoReversalAccrualsSuccess({ results }),
21
+ undoReversalAccrualsSuccess(matchId, results),
39
22
  ];
40
23
  const anyUndone = results.some((result) => result.status === 'undone');
41
24
  if (anyUndone) {
42
- successActions.push(...refreshActualMatchingList(state$.value), ...refreshOpenMatchDetails(state$.value));
25
+ successActions.push(...refreshActualMatchingList(state$.value), fetchActualMatchingMatch(matchId, true));
43
26
  }
44
27
  return from(successActions);
45
28
  }
46
- return of(undoReversalAccrualsFailure({ status: response.status }));
29
+ return of(undoReversalAccrualsFailure({
30
+ matchId,
31
+ status: response.status,
32
+ }));
47
33
  }), catchError((error) => of(undoReversalAccrualsFailure({
34
+ matchId,
48
35
  status: createZeniAPIStatus('Unexpected Error', 'Undo reversal accruals REST API call errored out' +
49
36
  JSON.stringify(error)),
50
37
  }))), takeUntil(actions$.pipe(filter(clearAll.match))));
@@ -3,8 +3,6 @@ import { toMatchAndReverseResultStatus, toUndoReversalResultStatus, } from '../t
3
3
  export function toServiceMonthFromPeriod(period) {
4
4
  return toString(period.start).slice(0, 7);
5
5
  }
6
- const DEFAULT_CURRENCY_CODE = 'USD';
7
- const DEFAULT_CURRENCY_SYMBOL = '$';
8
6
  function resolveMatchSearchAmount(payload) {
9
7
  const raw = payload.total_amount ?? payload.amount;
10
8
  if (typeof raw === 'number' && Number.isFinite(raw)) {
@@ -18,18 +16,20 @@ function resolveMatchSearchAmount(payload) {
18
16
  }
19
17
  return 0;
20
18
  }
21
- function resolveMatchSearchCurrencySymbol(payload, currencyCode) {
19
+ function resolveMatchSearchCurrencySymbol(payload, currencyCode, fallbackCurrency) {
22
20
  if (payload.currency_symbol != null && payload.currency_symbol !== '') {
23
21
  return payload.currency_symbol;
24
22
  }
25
- return currencyCode === DEFAULT_CURRENCY_CODE
26
- ? DEFAULT_CURRENCY_SYMBOL
27
- : currencyCode;
23
+ if (fallbackCurrency != null &&
24
+ currencyCode === fallbackCurrency.currencyCode) {
25
+ return fallbackCurrency.currencySymbol;
26
+ }
27
+ return currencyCode;
28
28
  }
29
- export function toActualMatchingTransactionSearchResult(payload) {
29
+ export function toActualMatchingTransactionSearchResult(payload, fallbackCurrency) {
30
30
  const currencyCode = payload.currency_code != null && payload.currency_code !== ''
31
31
  ? payload.currency_code
32
- : DEFAULT_CURRENCY_CODE;
32
+ : fallbackCurrency?.currencyCode ?? '';
33
33
  return {
34
34
  transactionId: payload.transaction_id,
35
35
  transactionIntegrationId: payload.transaction_integration_id,
@@ -45,7 +45,7 @@ export function toActualMatchingTransactionSearchResult(payload) {
45
45
  accountingClassId: payload.accounting_class_id ?? undefined,
46
46
  accountingClassName: payload.accounting_class_name ?? undefined,
47
47
  currencyCode,
48
- currencySymbol: resolveMatchSearchCurrencySymbol(payload, currencyCode),
48
+ currencySymbol: resolveMatchSearchCurrencySymbol(payload, currencyCode, fallbackCurrency),
49
49
  transactionMemo: payload.transaction_memo ?? undefined,
50
50
  transactionDescription: payload.transaction_description ?? undefined,
51
51
  transactionTypeName: payload.transaction_type_name ?? undefined,
@@ -1,7 +1,8 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
- import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
2
+ import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
3
3
  import { generateJEOneTimeAccrualKey } from '../../../entity/jeSchedules/jeScheduleHelper';
4
4
  import { clearAll } from '../../../rootActions';
5
+ import { actualMatchingTransactionLineKey } from '../types/actualMatchingViewState';
5
6
  export const initialTransactionSearchState = {
6
7
  query: '',
7
8
  results: [],
@@ -43,7 +44,9 @@ export const initialState = {
43
44
  scrollPosition: { scrollTop: 0, scrollLeft: undefined },
44
45
  },
45
46
  matchModal: initialMatchModalState,
46
- undoReversalStatus: { fetchState: 'Not-Started', error: undefined },
47
+ undoReversalStatusByMatchId: {},
48
+ lastUndoResultsByMatchId: {},
49
+ lastMatchResultsByMatchId: {},
47
50
  hasValidState() {
48
51
  return this.fetchState == 'Completed';
49
52
  },
@@ -224,7 +227,7 @@ const expenseAutomationActualMatchingView = createSlice({
224
227
  draft.matchModal.transactionSearch.error = undefined;
225
228
  }
226
229
  },
227
- prepare({ query, pageToken, transactionType, transactionIntegrationId, }) {
230
+ prepare(query, pageToken, transactionType, transactionIntegrationId) {
228
231
  return {
229
232
  payload: {
230
233
  query,
@@ -243,7 +246,7 @@ const expenseAutomationActualMatchingView = createSlice({
243
246
  ...results,
244
247
  ];
245
248
  const byKey = new Map(merged.map((result) => [
246
- `${result.transactionId}:${result.lineId}`,
249
+ actualMatchingTransactionLineKey(result.transactionType, result.transactionIntegrationId, result.lineId),
247
250
  result,
248
251
  ]));
249
252
  draft.matchModal.transactionSearch.results = Array.from(byKey.values());
@@ -281,7 +284,7 @@ const expenseAutomationActualMatchingView = createSlice({
281
284
  draft.matchModal.accrualSearch.error = undefined;
282
285
  }
283
286
  },
284
- prepare({ query, pageToken }) {
287
+ prepare(query, pageToken) {
285
288
  return { payload: { query, pageToken: pageToken ?? undefined } };
286
289
  },
287
290
  },
@@ -312,8 +315,17 @@ const expenseAutomationActualMatchingView = createSlice({
312
315
  error: undefined,
313
316
  };
314
317
  },
315
- prepare(params) {
316
- return { payload: params };
318
+ prepare(transactionId, transactionIntegrationId, transactionType, lineId, transactionSyncToken, accrualIds) {
319
+ return {
320
+ payload: {
321
+ transactionId,
322
+ transactionIntegrationId,
323
+ transactionType,
324
+ lineId,
325
+ transactionSyncToken,
326
+ accrualIds,
327
+ },
328
+ };
317
329
  },
318
330
  },
319
331
  matchAndReverseAccrualsSuccess(draft, action) {
@@ -322,6 +334,10 @@ const expenseAutomationActualMatchingView = createSlice({
322
334
  error: undefined,
323
335
  };
324
336
  draft.matchModal.lastBatchResults = action.payload.results;
337
+ if (action.payload.matchId != null) {
338
+ draft.lastMatchResultsByMatchId[action.payload.matchId] =
339
+ action.payload.results;
340
+ }
325
341
  },
326
342
  matchAndReverseAccrualsFailure(draft, action) {
327
343
  draft.matchModal.confirmStatus = {
@@ -330,29 +346,31 @@ const expenseAutomationActualMatchingView = createSlice({
330
346
  };
331
347
  },
332
348
  undoReversalAccruals: {
333
- reducer(draft) {
334
- draft.undoReversalStatus = {
349
+ reducer(draft, action) {
350
+ draft.undoReversalStatusByMatchId[action.payload.matchId] = {
335
351
  fetchState: 'In-Progress',
336
352
  error: undefined,
337
353
  };
338
354
  },
339
- prepare(params) {
340
- return { payload: params };
355
+ prepare(matchId, accrualIds) {
356
+ return { payload: { matchId, accrualIds } };
341
357
  },
342
358
  },
343
359
  undoReversalAccrualsSuccess: {
344
- reducer(draft) {
345
- draft.undoReversalStatus = {
360
+ reducer(draft, action) {
361
+ const { matchId, results } = action.payload;
362
+ draft.undoReversalStatusByMatchId[matchId] = {
346
363
  fetchState: 'Completed',
347
364
  error: undefined,
348
365
  };
366
+ draft.lastUndoResultsByMatchId[matchId] = results;
349
367
  },
350
- prepare(payload) {
351
- return { payload };
368
+ prepare(matchId, results) {
369
+ return { payload: { matchId, results } };
352
370
  },
353
371
  },
354
372
  undoReversalAccrualsFailure(draft, action) {
355
- draft.undoReversalStatus = {
373
+ draft.undoReversalStatusByMatchId[action.payload.matchId] = {
356
374
  fetchState: 'Error',
357
375
  error: action.payload.status,
358
376
  };