@zeniai/client-epic-state 5.1.37-betaRD3 → 5.1.38
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.
- package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.js +2 -0
- package/lib/esm/entity/snackbar/snackbarTypes.js +2 -0
- package/lib/esm/index.js +3 -2
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.js +5 -3
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +2 -3
- package/lib/esm/view/expenseAutomationView/helpers/mapStatementUpdateLocalDataToRequestBody.js +32 -0
- package/lib/esm/view/expenseAutomationView/payload/reconciliationPayload.js +1 -0
- package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +163 -21
- package/lib/esm/view/expenseAutomationView/selectors/reconciliationViewSelector.js +30 -26
- package/lib/esm/view/expenseAutomationView/selectors/statementParseViewSelector.js +295 -0
- package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +5 -24
- package/lib/index.d.ts +4 -3
- package/lib/index.js +44 -38
- package/lib/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.js +4 -2
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +2 -3
- package/lib/view/expenseAutomationView/helpers/mapStatementUpdateLocalDataToRequestBody.d.ts +2 -0
- package/lib/view/expenseAutomationView/helpers/mapStatementUpdateLocalDataToRequestBody.js +36 -0
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/payload/reconciliationPayload.js +1 -0
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.d.ts +14 -1
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +165 -23
- package/lib/view/expenseAutomationView/selectorTypes/reconciliationViewSelectorTypes.d.ts +10 -2
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.js +30 -26
- package/lib/view/expenseAutomationView/selectors/statementParseViewSelector.d.ts +25 -0
- package/lib/view/expenseAutomationView/selectors/statementParseViewSelector.js +313 -0
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +5 -24
- package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +52 -2
- package/package.json +1 -1
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyStatementParseFormChange = exports.toStatementUpdateLocalDataFromFormView = exports.getStatementParseFormView = exports.mergeStatementParseDeletedTransactionIds = exports.areStatementParseBalancesConsistent = exports.resolveStatementParseBalanceFields = exports.shouldRecalculateStatementParseBalances = exports.isStatementParseManualBalanceField = exports.isStatementParseTransactionFieldChange = exports.getDateFilteredDeletedTransactionIds = exports.getStatementTransactionPeriodById = exports.getParsedStatementDataForView = exports.filterStatementTransactionsByPeriod = exports.isStatementTransactionInPeriod = exports.getEffectiveStatementPeriod = void 0;
|
|
4
|
+
const zeniDayJS_1 = require("../../../zeniDayJS");
|
|
5
|
+
const getEffectiveStatementPeriod = (parsedMeta, localMeta) => ({
|
|
6
|
+
statementStartDate: localMeta?.statementStartDate != null && localMeta.statementStartDate !== ''
|
|
7
|
+
? localMeta.statementStartDate
|
|
8
|
+
: parsedMeta.statementStartDate,
|
|
9
|
+
statementEndDate: localMeta?.statementEndDate != null && localMeta.statementEndDate !== ''
|
|
10
|
+
? localMeta.statementEndDate
|
|
11
|
+
: parsedMeta.statementEndDate,
|
|
12
|
+
});
|
|
13
|
+
exports.getEffectiveStatementPeriod = getEffectiveStatementPeriod;
|
|
14
|
+
const isStatementTransactionInPeriod = (transactionDate, statementStartDate, statementEndDate) => {
|
|
15
|
+
if (statementStartDate === '' ||
|
|
16
|
+
statementEndDate === '' ||
|
|
17
|
+
transactionDate === '') {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
const txn = (0, zeniDayJS_1.date)(transactionDate).startOf('day');
|
|
21
|
+
const start = (0, zeniDayJS_1.date)(statementStartDate).startOf('day');
|
|
22
|
+
const end = (0, zeniDayJS_1.date)(statementEndDate).startOf('day');
|
|
23
|
+
return txn.isSameOrAfter(start, 'day') && txn.isSameOrBefore(end, 'day');
|
|
24
|
+
};
|
|
25
|
+
exports.isStatementTransactionInPeriod = isStatementTransactionInPeriod;
|
|
26
|
+
const filterStatementTransactionsByPeriod = (transactions, statementPeriod) => {
|
|
27
|
+
const { statementStartDate, statementEndDate } = statementPeriod;
|
|
28
|
+
if (statementStartDate === '' || statementEndDate === '') {
|
|
29
|
+
return transactions;
|
|
30
|
+
}
|
|
31
|
+
return transactions.filter((transaction) => (0, exports.isStatementTransactionInPeriod)(transaction.transactionDate, statementStartDate, statementEndDate));
|
|
32
|
+
};
|
|
33
|
+
exports.filterStatementTransactionsByPeriod = filterStatementTransactionsByPeriod;
|
|
34
|
+
const getParsedStatementDataForView = (parsedStatementData, statementUpdateLocalData) => {
|
|
35
|
+
if (parsedStatementData == null) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const statementUpload = parsedStatementData.statementUpload;
|
|
39
|
+
if (statementUpload == null) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const parsedMeta = statementUpload.statementMeta;
|
|
43
|
+
const localMeta = statementUpdateLocalData?.statementMeta;
|
|
44
|
+
const effectiveMeta = localMeta ?? parsedMeta;
|
|
45
|
+
const statementPeriod = (0, exports.getEffectiveStatementPeriod)(parsedMeta, localMeta);
|
|
46
|
+
return {
|
|
47
|
+
statementUpload: {
|
|
48
|
+
...statementUpload,
|
|
49
|
+
statementMeta: effectiveMeta,
|
|
50
|
+
statementTransactions: (0, exports.filterStatementTransactionsByPeriod)(statementUpload.statementTransactions, statementPeriod),
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
exports.getParsedStatementDataForView = getParsedStatementDataForView;
|
|
55
|
+
const getStatementTransactionPeriodById = (allParsedTransactions, parsedMeta, localMeta) => {
|
|
56
|
+
const statementPeriod = (0, exports.getEffectiveStatementPeriod)(parsedMeta, localMeta);
|
|
57
|
+
return Object.fromEntries(allParsedTransactions
|
|
58
|
+
.filter((transaction) => transaction.statementTransactionId !== '')
|
|
59
|
+
.map((transaction) => [
|
|
60
|
+
transaction.statementTransactionId,
|
|
61
|
+
(0, exports.isStatementTransactionInPeriod)(transaction.transactionDate, statementPeriod.statementStartDate, statementPeriod.statementEndDate),
|
|
62
|
+
]));
|
|
63
|
+
};
|
|
64
|
+
exports.getStatementTransactionPeriodById = getStatementTransactionPeriodById;
|
|
65
|
+
const getDateFilteredDeletedTransactionIds = (allParsedTransactions, statementPeriod) => {
|
|
66
|
+
if (statementPeriod.statementStartDate === '' ||
|
|
67
|
+
statementPeriod.statementEndDate === '') {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
return allParsedTransactions
|
|
71
|
+
.filter((transaction) => transaction.statementTransactionId !== '' &&
|
|
72
|
+
!(0, exports.isStatementTransactionInPeriod)(transaction.transactionDate, statementPeriod.statementStartDate, statementPeriod.statementEndDate))
|
|
73
|
+
.map((transaction) => transaction.statementTransactionId);
|
|
74
|
+
};
|
|
75
|
+
exports.getDateFilteredDeletedTransactionIds = getDateFilteredDeletedTransactionIds;
|
|
76
|
+
const roundCurrency = (value) => Math.round(value * 100) / 100;
|
|
77
|
+
const toApiDateString = (value) => {
|
|
78
|
+
if (value == null || value === '') {
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
return (0, zeniDayJS_1.date)(value).format('YYYY-MM-DD');
|
|
82
|
+
};
|
|
83
|
+
const computeStatementTransactionTotals = (transactions) => {
|
|
84
|
+
const totalDeposits = roundCurrency(transactions
|
|
85
|
+
.filter((txn) => txn.transactionDirection === 'credit')
|
|
86
|
+
.reduce((sum, txn) => sum + Math.abs(txn.amount ?? 0), 0));
|
|
87
|
+
const totalPayments = roundCurrency(transactions
|
|
88
|
+
.filter((txn) => txn.transactionDirection === 'debit')
|
|
89
|
+
.reduce((sum, txn) => sum + Math.abs(txn.amount ?? 0), 0));
|
|
90
|
+
return { totalDeposits, totalPayments };
|
|
91
|
+
};
|
|
92
|
+
const computeStatementClosingBalance = (openingBalance, totalDeposits, totalPayments) => roundCurrency(openingBalance + totalDeposits - totalPayments);
|
|
93
|
+
const filterFormTransactionsInPeriod = (transactions, statementStartDate, statementEndDate) => {
|
|
94
|
+
if (statementStartDate === '' || statementEndDate === '') {
|
|
95
|
+
return transactions;
|
|
96
|
+
}
|
|
97
|
+
const periodStart = (0, zeniDayJS_1.date)(statementStartDate).startOf('day');
|
|
98
|
+
const periodEnd = (0, zeniDayJS_1.date)(statementEndDate).startOf('day');
|
|
99
|
+
return transactions.filter((txn) => {
|
|
100
|
+
if (txn.transactionDate === '') {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
const txnDate = (0, zeniDayJS_1.date)(txn.transactionDate).startOf('day');
|
|
104
|
+
return (txnDate.isSameOrAfter(periodStart, 'day') &&
|
|
105
|
+
txnDate.isSameOrBefore(periodEnd, 'day'));
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
const isStatementParseTransactionFieldChange = (changedField) => changedField === 'transactions' ||
|
|
109
|
+
changedField?.startsWith('transactions.') === true;
|
|
110
|
+
exports.isStatementParseTransactionFieldChange = isStatementParseTransactionFieldChange;
|
|
111
|
+
const isStatementParseBalanceAffectingTransactionFieldChange = (changedField) => {
|
|
112
|
+
if (changedField === 'transactions') {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
if (changedField?.startsWith('transactions.') !== true) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return !changedField.endsWith('.transactionMemo');
|
|
119
|
+
};
|
|
120
|
+
const isStatementParseManualBalanceField = (field) => field === 'totalDeposits' ||
|
|
121
|
+
field === 'totalPayments' ||
|
|
122
|
+
field === 'closingBalance';
|
|
123
|
+
exports.isStatementParseManualBalanceField = isStatementParseManualBalanceField;
|
|
124
|
+
const shouldRecalculateStatementParseBalances = (changedField) => isStatementParseBalanceAffectingTransactionFieldChange(changedField) ||
|
|
125
|
+
changedField === 'statementStartDate' ||
|
|
126
|
+
changedField === 'statementEndDate';
|
|
127
|
+
exports.shouldRecalculateStatementParseBalances = shouldRecalculateStatementParseBalances;
|
|
128
|
+
const resolveStatementParseBalanceFields = (formView, changedField) => {
|
|
129
|
+
const inPeriodTransactions = filterFormTransactionsInPeriod(formView.transactions, formView.statementStartDate, formView.statementEndDate);
|
|
130
|
+
const { totalDeposits, totalPayments } = computeStatementTransactionTotals(inPeriodTransactions);
|
|
131
|
+
if (!(0, exports.shouldRecalculateStatementParseBalances)(changedField)) {
|
|
132
|
+
return {
|
|
133
|
+
openingBalance: formView.openingBalance,
|
|
134
|
+
closingBalance: formView.closingBalance,
|
|
135
|
+
totalDeposits: formView.totalDeposits,
|
|
136
|
+
totalPayments: formView.totalPayments,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
openingBalance: formView.openingBalance,
|
|
141
|
+
totalDeposits,
|
|
142
|
+
totalPayments,
|
|
143
|
+
closingBalance: computeStatementClosingBalance(formView.openingBalance, totalDeposits, totalPayments),
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
exports.resolveStatementParseBalanceFields = resolveStatementParseBalanceFields;
|
|
147
|
+
const areStatementParseBalancesConsistent = (formView) => {
|
|
148
|
+
const { totalDeposits, totalPayments } = computeStatementTransactionTotals(filterFormTransactionsInPeriod(formView.transactions, formView.statementStartDate, formView.statementEndDate));
|
|
149
|
+
return (roundCurrency(formView.closingBalance) ===
|
|
150
|
+
computeStatementClosingBalance(formView.openingBalance, totalDeposits, totalPayments));
|
|
151
|
+
};
|
|
152
|
+
exports.areStatementParseBalancesConsistent = areStatementParseBalancesConsistent;
|
|
153
|
+
const mapParsedTransactionToFormRow = (transaction, index) => ({
|
|
154
|
+
id: transaction.statementTransactionId || `parsed-${index}`,
|
|
155
|
+
transactionDate: toApiDateString(transaction.transactionDate),
|
|
156
|
+
transactionMemo: transaction.transactionMemo,
|
|
157
|
+
amount: transaction.amount,
|
|
158
|
+
transactionDirection: transaction.transactionDirection,
|
|
159
|
+
statementTransactionId: transaction.statementTransactionId,
|
|
160
|
+
});
|
|
161
|
+
const mapLocalTransactionToFormRow = (transaction, id) => ({
|
|
162
|
+
id,
|
|
163
|
+
transactionDate: toApiDateString(transaction.transactionDate),
|
|
164
|
+
transactionMemo: transaction.transactionMemo,
|
|
165
|
+
amount: transaction.amount,
|
|
166
|
+
transactionDirection: transaction.transactionDirection,
|
|
167
|
+
statementTransactionId: transaction.statementTransactionId,
|
|
168
|
+
});
|
|
169
|
+
const buildStatementParseFormTransactions = (originalTransactions, localData) => {
|
|
170
|
+
const deletedIdSet = new Set(localData.statementTransactions?.deletedIds ?? []);
|
|
171
|
+
const updatedById = new Map((localData.statementTransactions?.updated ?? [])
|
|
172
|
+
.filter((transaction) => transaction.statementTransactionId != null)
|
|
173
|
+
.map((transaction) => [
|
|
174
|
+
transaction.statementTransactionId,
|
|
175
|
+
transaction,
|
|
176
|
+
]));
|
|
177
|
+
const persistedTransactions = originalTransactions
|
|
178
|
+
.filter((transaction) => !deletedIdSet.has(transaction.statementTransactionId))
|
|
179
|
+
.map((transaction, index) => {
|
|
180
|
+
const updated = updatedById.get(transaction.statementTransactionId);
|
|
181
|
+
return updated != null
|
|
182
|
+
? mapLocalTransactionToFormRow(updated, transaction.statementTransactionId)
|
|
183
|
+
: mapParsedTransactionToFormRow(transaction, index);
|
|
184
|
+
});
|
|
185
|
+
const addedTransactions = (localData.statementTransactions?.added ?? []).map((transaction, index) => mapLocalTransactionToFormRow(transaction, `added-${index}`));
|
|
186
|
+
return [...persistedTransactions, ...addedTransactions];
|
|
187
|
+
};
|
|
188
|
+
const mergeStatementParseDeletedTransactionIds = (originalTransactions, statementPeriod, currentTransactionIds) => {
|
|
189
|
+
const dateFilteredDeletedIds = (0, exports.getDateFilteredDeletedTransactionIds)(originalTransactions, statementPeriod);
|
|
190
|
+
const dateFilteredDeletedIdSet = new Set(dateFilteredDeletedIds);
|
|
191
|
+
const userDeletedIds = originalTransactions
|
|
192
|
+
.filter((transaction) => transaction.statementTransactionId !== '' &&
|
|
193
|
+
!currentTransactionIds.has(transaction.statementTransactionId) &&
|
|
194
|
+
!dateFilteredDeletedIdSet.has(transaction.statementTransactionId))
|
|
195
|
+
.map((transaction) => transaction.statementTransactionId);
|
|
196
|
+
return [...new Set([...userDeletedIds, ...dateFilteredDeletedIds])];
|
|
197
|
+
};
|
|
198
|
+
exports.mergeStatementParseDeletedTransactionIds = mergeStatementParseDeletedTransactionIds;
|
|
199
|
+
const resolveStatementMetaDates = (parsedStatementMeta, localMeta) => ({
|
|
200
|
+
statementStartDate: localMeta?.statementStartDate != null && localMeta.statementStartDate !== ''
|
|
201
|
+
? localMeta.statementStartDate
|
|
202
|
+
: (parsedStatementMeta?.statementStartDate ?? ''),
|
|
203
|
+
statementEndDate: localMeta?.statementEndDate != null && localMeta.statementEndDate !== ''
|
|
204
|
+
? localMeta.statementEndDate
|
|
205
|
+
: (parsedStatementMeta?.statementEndDate ?? ''),
|
|
206
|
+
});
|
|
207
|
+
const getStatementParseFormView = ({ parsedStatementMeta, originalTransactions, statementUpdateLocalData, }) => {
|
|
208
|
+
const transactions = statementUpdateLocalData != null
|
|
209
|
+
? buildStatementParseFormTransactions(originalTransactions, statementUpdateLocalData)
|
|
210
|
+
: originalTransactions.map(mapParsedTransactionToFormRow);
|
|
211
|
+
const localMeta = statementUpdateLocalData?.statementMeta;
|
|
212
|
+
const { statementStartDate, statementEndDate } = resolveStatementMetaDates(parsedStatementMeta, localMeta);
|
|
213
|
+
const { totalDeposits, totalPayments } = computeStatementTransactionTotals(filterFormTransactionsInPeriod(transactions, statementStartDate, statementEndDate));
|
|
214
|
+
const openingBalance = localMeta?.openingBalance ?? parsedStatementMeta?.openingBalance ?? 0;
|
|
215
|
+
const computedClosingBalance = computeStatementClosingBalance(openingBalance, totalDeposits, totalPayments);
|
|
216
|
+
return {
|
|
217
|
+
statementStartDate,
|
|
218
|
+
statementEndDate,
|
|
219
|
+
openingBalance,
|
|
220
|
+
closingBalance: localMeta?.closingBalance ?? computedClosingBalance,
|
|
221
|
+
totalDeposits: localMeta?.totalDeposits ?? totalDeposits,
|
|
222
|
+
totalPayments: localMeta?.totalPayments ?? totalPayments,
|
|
223
|
+
transactions: filterFormTransactionsInPeriod(transactions, statementStartDate, statementEndDate),
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
exports.getStatementParseFormView = getStatementParseFormView;
|
|
227
|
+
const toStatementUpdateLocalDataFromFormView = ({ formView, parsedStatementMeta, originalTransactions, changedField, }) => {
|
|
228
|
+
const balanceFields = (0, exports.resolveStatementParseBalanceFields)(formView, changedField);
|
|
229
|
+
const currentTransactionIds = new Set(formView.transactions
|
|
230
|
+
.map((transaction) => transaction.statementTransactionId)
|
|
231
|
+
.filter((id) => id != null && id !== ''));
|
|
232
|
+
const added = [];
|
|
233
|
+
const updated = [];
|
|
234
|
+
formView.transactions.forEach((transaction) => {
|
|
235
|
+
const transactionDate = toApiDateString(transaction.transactionDate);
|
|
236
|
+
if (transaction.statementTransactionId == null) {
|
|
237
|
+
if (transaction.transactionDirection != null) {
|
|
238
|
+
added.push({
|
|
239
|
+
amount: transaction.amount,
|
|
240
|
+
transactionDate,
|
|
241
|
+
transactionDirection: transaction.transactionDirection,
|
|
242
|
+
transactionMemo: transaction.transactionMemo,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const original = originalTransactions.find((candidate) => candidate.statementTransactionId === transaction.statementTransactionId);
|
|
248
|
+
if (original != null &&
|
|
249
|
+
(original.amount !== transaction.amount ||
|
|
250
|
+
toApiDateString(original.transactionDate) !== transactionDate ||
|
|
251
|
+
original.transactionMemo !== transaction.transactionMemo)) {
|
|
252
|
+
updated.push({
|
|
253
|
+
amount: transaction.amount,
|
|
254
|
+
transactionDate,
|
|
255
|
+
transactionDirection: transaction.transactionDirection,
|
|
256
|
+
transactionMemo: transaction.transactionMemo,
|
|
257
|
+
statementTransactionId: transaction.statementTransactionId,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
const statementPeriod = {
|
|
262
|
+
statementStartDate: toApiDateString(formView.statementStartDate),
|
|
263
|
+
statementEndDate: toApiDateString(formView.statementEndDate),
|
|
264
|
+
};
|
|
265
|
+
const deletedIds = (0, exports.mergeStatementParseDeletedTransactionIds)(originalTransactions, statementPeriod, currentTransactionIds);
|
|
266
|
+
const deletedIdSet = new Set(deletedIds);
|
|
267
|
+
const inPeriodAdded = filterFormTransactionsInPeriod(added, statementPeriod.statementStartDate, statementPeriod.statementEndDate);
|
|
268
|
+
const inPeriodUpdated = updated.filter((transaction) => transaction.statementTransactionId != null &&
|
|
269
|
+
!deletedIdSet.has(transaction.statementTransactionId));
|
|
270
|
+
return {
|
|
271
|
+
statementMeta: {
|
|
272
|
+
closingBalance: balanceFields.closingBalance,
|
|
273
|
+
openingBalance: balanceFields.openingBalance,
|
|
274
|
+
statementDataStatus: parsedStatementMeta?.statementDataStatus ?? {
|
|
275
|
+
code: '',
|
|
276
|
+
label: '',
|
|
277
|
+
},
|
|
278
|
+
statementEndDate: statementPeriod.statementEndDate,
|
|
279
|
+
statementStartDate: statementPeriod.statementStartDate,
|
|
280
|
+
statementStatus: parsedStatementMeta?.statementStatus ?? {
|
|
281
|
+
code: '',
|
|
282
|
+
label: '',
|
|
283
|
+
},
|
|
284
|
+
statementUploadId: parsedStatementMeta?.statementUploadId ?? '',
|
|
285
|
+
totalDeposits: balanceFields.totalDeposits,
|
|
286
|
+
totalPayments: balanceFields.totalPayments,
|
|
287
|
+
},
|
|
288
|
+
statementTransactions: {
|
|
289
|
+
added: inPeriodAdded,
|
|
290
|
+
deletedIds,
|
|
291
|
+
updated: inPeriodUpdated,
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
};
|
|
295
|
+
exports.toStatementUpdateLocalDataFromFormView = toStatementUpdateLocalDataFromFormView;
|
|
296
|
+
const applyStatementParseFormChange = ({ formView, changedField, parsedStatementMeta, originalTransactions, }) => {
|
|
297
|
+
const balanceFields = (0, exports.resolveStatementParseBalanceFields)(formView, changedField);
|
|
298
|
+
const shouldRecalculate = (0, exports.shouldRecalculateStatementParseBalances)(changedField);
|
|
299
|
+
const mergedFormView = shouldRecalculate
|
|
300
|
+
? { ...formView, ...balanceFields }
|
|
301
|
+
: formView;
|
|
302
|
+
return {
|
|
303
|
+
didRecalculateBalances: shouldRecalculate,
|
|
304
|
+
formView: mergedFormView,
|
|
305
|
+
localData: (0, exports.toStatementUpdateLocalDataFromFormView)({
|
|
306
|
+
formView: mergedFormView,
|
|
307
|
+
parsedStatementMeta,
|
|
308
|
+
originalTransactions,
|
|
309
|
+
changedField,
|
|
310
|
+
}),
|
|
311
|
+
};
|
|
312
|
+
};
|
|
313
|
+
exports.applyStatementParseFormChange = applyStatementParseFormChange;
|
|
@@ -198,28 +198,15 @@ function getExpenseAutomationTransactionView(state) {
|
|
|
198
198
|
};
|
|
199
199
|
// Parent-tab badge counts. Sourced from `parent_tab_total_count` in the
|
|
200
200
|
// listing response and used exclusively by the navbar / tab strip badges.
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
const autoCatTabView = expenseAutomationTransactionsViewState.transactionCategorizationView
|
|
204
|
-
.autoCategorized;
|
|
205
|
-
const reviewTabView = expenseAutomationTransactionsViewState.transactionCategorizationView.review;
|
|
206
|
-
const autoCatSubTabCache = expenseAutomationTransactionsViewState.autoCategorizedSubTabCache;
|
|
207
|
-
const autoCatFilterActive = autoCatTabView.uiState.searchString !== '' ||
|
|
208
|
-
autoCatTabView.filters.categories.length > 0;
|
|
209
|
-
const reviewFilterActive = reviewTabView.uiState.searchString !== '' ||
|
|
210
|
-
reviewTabView.filters.categories.length > 0;
|
|
201
|
+
// Independent of which Completed sub-tab is active so the badge stays
|
|
202
|
+
// stable across sub-tab switches.
|
|
211
203
|
const parentTotalCountByTab = expenseAutomationTransactionsViewState.parentTotalCountByTab;
|
|
212
204
|
const parentTabTotalCountByTab = {
|
|
213
205
|
review: monthYearPeriodId != null
|
|
214
|
-
?
|
|
215
|
-
? totalCountByReview[monthYearPeriodId]
|
|
216
|
-
: (parentTotalCountByTab.review[monthYearPeriodId] ?? 0)
|
|
206
|
+
? (parentTotalCountByTab.review[monthYearPeriodId] ?? 0)
|
|
217
207
|
: 0,
|
|
218
208
|
autoCategorized: monthYearPeriodId != null
|
|
219
|
-
?
|
|
220
|
-
? (autoCatSubTabCache['all']?.totalCount[monthYearPeriodId] ??
|
|
221
|
-
totalCountByAutoCat[monthYearPeriodId])
|
|
222
|
-
: (parentTotalCountByTab.autoCategorized[monthYearPeriodId] ?? 0)
|
|
209
|
+
? (parentTotalCountByTab.autoCategorized[monthYearPeriodId] ?? 0)
|
|
223
210
|
: 0,
|
|
224
211
|
};
|
|
225
212
|
const fetchStateByTab = {
|
|
@@ -262,13 +249,7 @@ function getExpenseAutomationTransactionView(state) {
|
|
|
262
249
|
isAccountingProjectsEnabled,
|
|
263
250
|
projectList,
|
|
264
251
|
transactionLocalData: filteredTransactionLocalData,
|
|
265
|
-
|
|
266
|
-
// misleading — the server has more pages but the filter already reduces
|
|
267
|
-
// what's visible. Masking pageToken here prevents the skeleton "loading"
|
|
268
|
-
// row from appearing when the user is looking at a filtered result set.
|
|
269
|
-
uiState: filters.categories.length > 0
|
|
270
|
-
? { ...uiState, pageToken: null }
|
|
271
|
-
: uiState,
|
|
252
|
+
uiState,
|
|
272
253
|
refreshStatus,
|
|
273
254
|
saveStatus,
|
|
274
255
|
markAsNotMiscategorizedStatus,
|
|
@@ -232,7 +232,6 @@ export interface ReconciliationViewState extends FetchStateAndError {
|
|
|
232
232
|
reconTabsState: ReconciliationTabsState;
|
|
233
233
|
refreshStatus: FetchStateAndError;
|
|
234
234
|
selectedTab: ReconciliationViewTabType;
|
|
235
|
-
statementProcessingFailed: boolean;
|
|
236
235
|
statementUploadChosen: boolean;
|
|
237
236
|
selectedAccountId?: ID;
|
|
238
237
|
selectedDrawerAccountId?: ID;
|
|
@@ -259,12 +258,53 @@ export interface StatementTransactionsUpdate {
|
|
|
259
258
|
deletedIds: string[];
|
|
260
259
|
updated: StatementTransactionForUpdate[];
|
|
261
260
|
}
|
|
261
|
+
export type StatementParseManualBalanceField = 'totalDeposits' | 'totalPayments' | 'closingBalance';
|
|
262
|
+
export interface StatementParseFormTransaction {
|
|
263
|
+
amount: number;
|
|
264
|
+
id: string;
|
|
265
|
+
transactionDate: string;
|
|
266
|
+
transactionDirection: 'debit' | 'credit';
|
|
267
|
+
transactionMemo: string;
|
|
268
|
+
statementTransactionId?: string;
|
|
269
|
+
}
|
|
270
|
+
export interface StatementParseFormView {
|
|
271
|
+
closingBalance: number;
|
|
272
|
+
openingBalance: number;
|
|
273
|
+
statementEndDate: string;
|
|
274
|
+
statementStartDate: string;
|
|
275
|
+
totalDeposits: number;
|
|
276
|
+
totalPayments: number;
|
|
277
|
+
transactions: StatementParseFormTransaction[];
|
|
278
|
+
}
|
|
279
|
+
export interface GetStatementParseFormViewInput {
|
|
280
|
+
originalTransactions: StatementTransaction[];
|
|
281
|
+
parsedStatementMeta: StatementMeta | undefined;
|
|
282
|
+
statementUpdateLocalData: StatementUpdateLocalData | undefined;
|
|
283
|
+
}
|
|
284
|
+
export interface ToStatementUpdateLocalDataFromFormViewInput {
|
|
285
|
+
formView: StatementParseFormView;
|
|
286
|
+
originalTransactions: StatementTransaction[];
|
|
287
|
+
parsedStatementMeta: StatementMeta | undefined;
|
|
288
|
+
changedField?: string;
|
|
289
|
+
}
|
|
290
|
+
export interface ApplyStatementParseFormChangeInput {
|
|
291
|
+
formView: StatementParseFormView;
|
|
292
|
+
originalTransactions: StatementTransaction[];
|
|
293
|
+
parsedStatementMeta: StatementMeta | undefined;
|
|
294
|
+
changedField?: string;
|
|
295
|
+
}
|
|
296
|
+
export interface ApplyStatementParseFormChangeResult {
|
|
297
|
+
didRecalculateBalances: boolean;
|
|
298
|
+
formView: StatementParseFormView;
|
|
299
|
+
localData: StatementUpdateLocalData;
|
|
300
|
+
}
|
|
262
301
|
export interface StatementUpdateLocalData {
|
|
263
302
|
statementMeta: StatementMeta;
|
|
264
303
|
statementTransactions: StatementTransactionsUpdate;
|
|
265
304
|
}
|
|
266
305
|
export interface StatementUpdateLocalDataPayload {
|
|
267
306
|
statement_meta: {
|
|
307
|
+
closing_balance: number;
|
|
268
308
|
opening_balance: number;
|
|
269
309
|
statement_end_date: string;
|
|
270
310
|
statement_start_date: string;
|
|
@@ -299,15 +339,25 @@ export interface AccountReconciliationDataWithTransactionFetchState {
|
|
|
299
339
|
reparseStatementStatus: FetchStateAndError;
|
|
300
340
|
statementDateConflict: StatementDateConflict | null;
|
|
301
341
|
statementDeleteStatus: FetchStateAndError;
|
|
302
|
-
/**
|
|
342
|
+
/** True while statement upload/parse/reparse is in flight (local + entity signals). */
|
|
303
343
|
statementParseInProgress: boolean;
|
|
304
344
|
/** Client-driven fetch state for the parseStatement epic (In-Progress/Completed/Error). */
|
|
305
345
|
statementParseStatus: FetchStateAndError;
|
|
346
|
+
/** Step progress saved when user continues parsing in background. */
|
|
347
|
+
statementProcessingBackgroundCompletedSteps: number;
|
|
348
|
+
/** User dismissed StatementProcessingPage via Continue in Background. */
|
|
349
|
+
statementProcessingDismissedToBackground: boolean;
|
|
350
|
+
/** True when statement upload/parse failed for this account (drives drawer error popup). */
|
|
351
|
+
statementProcessingFailed: boolean;
|
|
306
352
|
statementUpdateStatus: FetchStateAndError;
|
|
307
353
|
statementUploadStatus: FetchStateAndError;
|
|
308
354
|
transactionFetchState: FetchStateAndError;
|
|
309
355
|
accountDetectionReason?: string;
|
|
310
356
|
parsedStatementData?: ParsedStatementData;
|
|
311
357
|
reconciliationId?: ID;
|
|
358
|
+
/** Wall-clock start used to recompute UI step progress after backgrounding. */
|
|
359
|
+
statementProcessingStartedAtMs?: number;
|
|
360
|
+
/** Locked countdown duration (seconds) paired with startedAtMs. */
|
|
361
|
+
statementProcessingTotalDurationSeconds?: number;
|
|
312
362
|
}
|
|
313
363
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeniai/client-epic-state",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.38",
|
|
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",
|