@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
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getSelectedMonthYearForCurrentTenant = getSelectedMonthYearForCurrentTenant;
7
+ exports.getTenantDisplayCurrency = getTenantDisplayCurrency;
7
8
  exports.parseActualMatchingMatchId = parseActualMatchingMatchId;
8
9
  exports.isAutoReversedAccrual = isAutoReversedAccrual;
9
10
  exports.isManuallyReversedAccrual = isManuallyReversedAccrual;
@@ -21,6 +22,7 @@ const actualMatchingSelector_1 = require("../../../entity/actualMatching/actualM
21
22
  const jeScheduleHelper_1 = require("../../../entity/jeSchedules/jeScheduleHelper");
22
23
  const jeSchedulesSelector_1 = require("../../../entity/jeSchedules/jeSchedulesSelector");
23
24
  const tenantSelector_1 = require("../../../entity/tenant/tenantSelector");
25
+ const actualMatchingViewState_1 = require("../types/actualMatchingViewState");
24
26
  function getSelectedMonthYearForCurrentTenant(state) {
25
27
  const tenantId = (0, tenantSelector_1.getCurrentTenant)(state)?.tenantId;
26
28
  if (tenantId == null) {
@@ -28,6 +30,18 @@ function getSelectedMonthYearForCurrentTenant(state) {
28
30
  }
29
31
  return state.expenseAutomationViewState.selectedPeriodByTenantId[tenantId];
30
32
  }
33
+ function getTenantDisplayCurrency(state) {
34
+ const locale = (0, tenantSelector_1.getCurrentTenant)(state)?.company?.companyLocaleInfo;
35
+ if (locale?.currencyCode == null || locale.currencyCode === '') {
36
+ return undefined;
37
+ }
38
+ return {
39
+ currencyCode: locale.currencyCode,
40
+ currencySymbol: locale.currencySymbol != null && locale.currencySymbol !== ''
41
+ ? locale.currencySymbol
42
+ : locale.currencyCode,
43
+ };
44
+ }
31
45
  function toMatchModalAccrual(member) {
32
46
  if ('jeOneTimeAccrualKey' in member && member.jeOneTimeAccrualKey != null) {
33
47
  return member;
@@ -49,9 +63,9 @@ function uniqueMatchModalAccruals(pinned, searched) {
49
63
  }
50
64
  function uniqueTransactionSearchResults(pinned, searched) {
51
65
  const byKey = new Map();
52
- pinned.forEach((row) => byKey.set(`${row.transactionId}:${row.lineId}`, row));
66
+ pinned.forEach((row) => byKey.set((0, actualMatchingViewState_1.actualMatchingTransactionLineKey)(row.transactionType, row.transactionIntegrationId, row.lineId), row));
53
67
  searched.forEach((row) => {
54
- const key = `${row.transactionId}:${row.lineId}`;
68
+ const key = (0, actualMatchingViewState_1.actualMatchingTransactionLineKey)(row.transactionType, row.transactionIntegrationId, row.lineId);
55
69
  if (!byKey.has(key)) {
56
70
  byKey.set(key, row);
57
71
  }
@@ -133,7 +147,9 @@ function toActualMatchingRow(match) {
133
147
  groupedAccrualIds: match.members.map((member) => member.accrualId),
134
148
  groupedMembers: collectGroupedMembers(match.members),
135
149
  reversalDate: getActualMatchingReversalDate(first),
136
- vendorName: match.vendorName !== '' ? match.vendorName : first.vendorName,
150
+ vendorName: match.vendorName != null && match.vendorName !== ''
151
+ ? match.vendorName
152
+ : first.vendorName,
137
153
  estimatedAmount: match.accruedAmount,
138
154
  };
139
155
  }
@@ -142,10 +158,10 @@ function matchesSearch(row, searchString) {
142
158
  if (trimmed.length === 0) {
143
159
  return true;
144
160
  }
145
- if (row.vendorName.toLowerCase().includes(trimmed)) {
161
+ if ((row.vendorName ?? '').toLowerCase().includes(trimmed)) {
146
162
  return true;
147
163
  }
148
- if (row.memo.toLowerCase().includes(trimmed)) {
164
+ if ((row.memo ?? '').toLowerCase().includes(trimmed)) {
149
165
  return true;
150
166
  }
151
167
  return (row.groupedMembers ?? []).some((member) => (member.memo ?? '').toLowerCase().includes(trimmed));
@@ -153,7 +169,7 @@ function matchesSearch(row, searchString) {
153
169
  function getActualMatchingSortValue(row, sortKey) {
154
170
  switch (sortKey) {
155
171
  case 'vendor':
156
- return row.vendorName.toLowerCase();
172
+ return (row.vendorName ?? '').toLowerCase();
157
173
  case 'date':
158
174
  return row.reversalDate?.valueOf() ?? row.transactionDate;
159
175
  case 'amount':
@@ -197,8 +213,14 @@ function emptyKpiSummary() {
197
213
  variance: { percent: 0, averagePercentPerMatch: 0, netAmount: 0 },
198
214
  };
199
215
  }
200
- function sumRowAmounts(rows) {
201
- return rows.reduce((sum, row) => sum + getActualMatchingAmount(row), 0);
216
+ function sumRowAmounts(rows, displayCurrencyCode) {
217
+ return rows.reduce((sum, row) => {
218
+ if (displayCurrencyCode != null &&
219
+ row.accruedAmount.currencyCode !== displayCurrencyCode) {
220
+ return sum;
221
+ }
222
+ return sum + getActualMatchingAmount(row);
223
+ }, 0);
202
224
  }
203
225
  function uniqueVendorCount(rows) {
204
226
  const ids = new Set();
@@ -207,7 +229,7 @@ function uniqueVendorCount(rows) {
207
229
  ids.add(row.vendorId);
208
230
  return;
209
231
  }
210
- if (row.vendorName !== '') {
232
+ if (row.vendorName != null && row.vendorName !== '') {
211
233
  ids.add(row.vendorName);
212
234
  }
213
235
  });
@@ -219,19 +241,35 @@ function rowVariancePercent(row) {
219
241
  if (actual == null || accrued === 0) {
220
242
  return undefined;
221
243
  }
222
- return ((actual - accrued) / accrued) * 100;
244
+ return ((actual - accrued) / Math.abs(accrued)) * 100;
223
245
  }
224
- function buildActualMatchingKpiSummary(rows) {
246
+ function buildActualMatchingKpiSummary(rows, displayCurrencyCode) {
225
247
  if (rows.length === 0) {
226
248
  return emptyKpiSummary();
227
249
  }
228
250
  const autoReversed = rows.filter((row) => row.kind === 'auto_reversed');
229
251
  const pendingReview = rows.filter((row) => row.kind === 'pending_review');
230
252
  const receivedCount = rows.length;
231
- const rowsWithActual = rows.filter((row) => row.actualAmount?.amount != null);
253
+ const rowsWithActual = rows.filter((row) => {
254
+ if (row.actualAmount?.amount == null) {
255
+ return false;
256
+ }
257
+ if (displayCurrencyCode == null) {
258
+ return true;
259
+ }
260
+ const rowCurrency = row.accruedAmount?.currencyCode ?? row.estimatedAmount.currencyCode;
261
+ return rowCurrency === displayCurrencyCode;
262
+ });
232
263
  const accruedTotal = rowsWithActual.reduce((sum, row) => sum + (row.accruedAmount?.amount ?? row.estimatedAmount.amount), 0);
233
264
  const actualTotal = rowsWithActual.reduce((sum, row) => sum + (row.actualAmount?.amount ?? 0), 0);
234
265
  const variancePercents = rows
266
+ .filter((row) => {
267
+ if (displayCurrencyCode == null) {
268
+ return true;
269
+ }
270
+ const rowCurrency = row.accruedAmount?.currencyCode ?? row.estimatedAmount.currencyCode;
271
+ return rowCurrency === displayCurrencyCode;
272
+ })
235
273
  .map(rowVariancePercent)
236
274
  .filter((percent) => percent != null);
237
275
  return {
@@ -245,17 +283,17 @@ function buildActualMatchingKpiSummary(rows) {
245
283
  autoReversed: {
246
284
  count: autoReversed.length,
247
285
  percent: Math.round((autoReversed.length / receivedCount) * 100),
248
- clearedAmount: sumRowAmounts(autoReversed),
286
+ clearedAmount: sumRowAmounts(autoReversed, displayCurrencyCode),
249
287
  },
250
288
  pendingReview: {
251
289
  count: pendingReview.length,
252
- amount: sumRowAmounts(pendingReview),
290
+ amount: sumRowAmounts(pendingReview, displayCurrencyCode),
253
291
  estimatedMinutesToClear: pendingReview.length * ESTIMATED_MINUTES_PER_PENDING_MATCH,
254
292
  },
255
293
  variance: {
256
294
  percent: accruedTotal === 0
257
295
  ? 0
258
- : ((actualTotal - accruedTotal) / accruedTotal) * 100,
296
+ : ((actualTotal - accruedTotal) / Math.abs(accruedTotal)) * 100,
259
297
  averagePercentPerMatch: variancePercents.length === 0
260
298
  ? 0
261
299
  : variancePercents.reduce((sum, percent) => sum + percent, 0) /
@@ -270,12 +308,14 @@ function getExpenseAutomationActualMatchingMatchView(state, matchId) {
270
308
  match: (0, actualMatchingSelector_1.getActualMatchingMatchById)(state.actualMatchingState, matchId),
271
309
  detailFetchState: view.detailFetchStateByMatchId[matchId] ?? NOT_STARTED,
272
310
  refreshStatus: view.detailRefreshStatusByMatchId[matchId] ?? NOT_STARTED,
273
- undoReversalStatus: view.undoReversalStatus ?? NOT_STARTED,
311
+ undoReversalStatus: view.undoReversalStatusByMatchId[matchId] ?? NOT_STARTED,
312
+ lastUndoResults: view.lastUndoResultsByMatchId[matchId],
313
+ lastMatchResults: view.lastMatchResultsByMatchId?.[matchId],
274
314
  };
275
315
  }
276
316
  function getExpenseAutomationActualMatchingView(state) {
277
317
  const { expenseAutomationActualMatchingViewState } = state;
278
- const { matchIdsByPeriod, fetchState, error, refreshStatus, uiState, matchModal, undoReversalStatus, } = expenseAutomationActualMatchingViewState;
318
+ const { matchIdsByPeriod, fetchState, error, refreshStatus, uiState, matchModal, } = expenseAutomationActualMatchingViewState;
279
319
  const selectedPeriod = getSelectedMonthYearForCurrentTenant(state);
280
320
  const monthYearPeriodId = selectedPeriod != null ? (0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod) : undefined;
281
321
  const matchIds = monthYearPeriodId != null ? matchIdsByPeriod[monthYearPeriodId] : undefined;
@@ -287,19 +327,25 @@ function getExpenseAutomationActualMatchingView(state) {
287
327
  const rows = allRows.filter((row) => matchesSearch(row, uiState.searchString));
288
328
  const reversed = sortActualMatchingRows(rows.filter((row) => isReversedMatchKind(row.kind)), uiState);
289
329
  const pendingReview = sortActualMatchingRows(rows.filter((row) => row.kind === 'pending_review'), uiState);
290
- const kpiSummary = buildActualMatchingKpiSummary(allRows);
330
+ const kpiSummary = buildActualMatchingKpiSummary(allRows, getTenantDisplayCurrency(state)?.currencyCode);
291
331
  const searchedAccruals = matchModal.accrualSearch.results
292
332
  .map((key) => (0, jeSchedulesSelector_1.getJEOneTimeAccrualByKey)(key, state.jeSchedulesState))
293
333
  .filter((accrual) => accrual != null);
294
334
  const openedMatch = matchModal.openedFromMatchId != null
295
335
  ? (0, actualMatchingSelector_1.getActualMatchingMatchById)(state.actualMatchingState, matchModal.openedFromMatchId)
296
336
  : undefined;
297
- const pinnedAccruals = (openedMatch?.members ?? []).map(toMatchModalAccrual);
337
+ const pinnedAccruals = [
338
+ ...(openedMatch?.members ?? []),
339
+ ...(openedMatch?.leftovers ?? []),
340
+ ].map(toMatchModalAccrual);
298
341
  const firstSuggestion = openedMatch?.members[0]?.matchSuggestion;
299
342
  const prefill = openedMatch == null
300
343
  ? undefined
301
344
  : {
302
- selectedAccrualIds: openedMatch.members.map((member) => member.accrualId),
345
+ selectedAccrualIds: [
346
+ ...openedMatch.members.map((member) => member.accrualId),
347
+ ...(openedMatch.leftovers ?? []).map((leftover) => leftover.accrualId),
348
+ ],
303
349
  actualAmount: openedMatch.actualAmount.amount,
304
350
  matchedLineId: firstSuggestion?.matchedLineId,
305
351
  matchedTransactionId: firstSuggestion?.matchedTransactionId,
@@ -313,7 +359,6 @@ function getExpenseAutomationActualMatchingView(state) {
313
359
  uiState,
314
360
  refreshStatus,
315
361
  hasLoadedForSelectedPeriod: matchIds != null,
316
- undoReversalStatus,
317
362
  matchModal: {
318
363
  isOpen: matchModal.isOpen,
319
364
  openedFromMatchId: matchModal.openedFromMatchId,
@@ -66,6 +66,7 @@ export interface UndoReversalResult {
66
66
  }
67
67
  export interface UndoReversalAccrualsParams {
68
68
  accrualIds: ID[];
69
+ matchId: ActualMatchingMatchId;
69
70
  }
70
71
  export interface ActualMatchingTransactionSearchState extends FetchStateAndError {
71
72
  isLoadingMore: boolean;
@@ -88,12 +89,15 @@ export interface ActualMatchingMatchModalState {
88
89
  lastBatchResults?: MatchAndReverseResult[];
89
90
  openedFromMatchId?: ActualMatchingMatchId;
90
91
  }
92
+ export declare function actualMatchingTransactionLineKey(transactionType: string, transactionIntegrationId: string, lineId: string): string;
91
93
  export interface ActualMatchingViewState extends FetchedState {
92
94
  detailFetchStateByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
93
95
  detailRefreshStatusByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
96
+ lastMatchResultsByMatchId: Record<ActualMatchingMatchId, MatchAndReverseResult[]>;
97
+ lastUndoResultsByMatchId: Record<ActualMatchingMatchId, UndoReversalResult[]>;
94
98
  matchIdsByPeriod: Record<MonthYearPeriodId, ActualMatchingMatchId[]>;
95
99
  matchModal: ActualMatchingMatchModalState;
96
100
  refreshStatus: FetchStateAndError;
97
101
  uiState: ActualMatchingViewUIState;
98
- undoReversalStatus: FetchStateAndError;
102
+ undoReversalStatusByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
99
103
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toUndoReversalResultStatus = exports.toMatchAndReverseResultStatus = exports.MATCH_SEARCH_DEBOUNCE_MS = exports.MATCH_ACCRUAL_SEARCH_LIMIT = exports.MATCH_TRANSACTION_SEARCH_PAGE_SIZE = exports.toActualMatchingSortKey = void 0;
4
+ exports.actualMatchingTransactionLineKey = actualMatchingTransactionLineKey;
4
5
  const stringToUnion_1 = require("../../../commonStateTypes/stringToUnion");
5
6
  const ACTUAL_MATCHING_SORT_KEYS = [
6
7
  'vendor',
@@ -36,3 +37,6 @@ const UNDO_REVERSAL_RESULT_STATUSES = [
36
37
  ];
37
38
  const toUndoReversalResultStatus = (v) => (0, stringToUnion_1.stringToUnion)(v, UNDO_REVERSAL_RESULT_STATUSES);
38
39
  exports.toUndoReversalResultStatus = toUndoReversalResultStatus;
40
+ function actualMatchingTransactionLineKey(transactionType, transactionIntegrationId, lineId) {
41
+ return `${transactionType}:${transactionIntegrationId}:${lineId}`;
42
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.2.35-beta2MM",
3
+ "version": "5.2.35-beta4MM",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",