@zeniai/client-epic-state 5.2.0-beta0AK → 5.2.1
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/accountRecon/accountReconReducer.js +4 -0
- package/lib/entity/accountRecon/accountReconState.d.ts +4 -1
- package/lib/entity/accountRecon/accountReconState.js +1 -0
- package/lib/entity/invoicing/invoicingCustomer/invoicingCustomerPayload.d.ts +0 -16
- package/lib/entity/invoicing/invoicingCustomer/invoicingCustomerPayload.js +0 -20
- package/lib/entity/invoicing/invoicingCustomer/invoicingCustomerSelector.d.ts +1 -8
- package/lib/entity/invoicing/invoicingCustomer/invoicingCustomerSelector.js +0 -48
- package/lib/entity/invoicing/invoicingCustomer/invoicingCustomerState.d.ts +0 -24
- package/lib/entity/invoicing/invoicingSubscription/invoicingSubscriptionPayload.d.ts +0 -1
- package/lib/entity/invoicing/invoicingSubscription/invoicingSubscriptionPayload.js +0 -1
- package/lib/entity/invoicing/invoicingSubscription/invoicingSubscriptionState.d.ts +0 -1
- package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.js +1 -0
- package/lib/epic.d.ts +4 -1
- package/lib/epic.js +4 -1
- package/lib/esm/entity/accountRecon/accountReconReducer.js +4 -0
- package/lib/esm/entity/accountRecon/accountReconState.js +1 -0
- package/lib/esm/entity/invoicing/invoicingCustomer/invoicingCustomerPayload.js +0 -20
- package/lib/esm/entity/invoicing/invoicingCustomer/invoicingCustomerSelector.js +0 -47
- package/lib/esm/entity/invoicing/invoicingSubscription/invoicingSubscriptionPayload.js +0 -1
- package/lib/esm/entity/snackbar/snackbarTypes.js +1 -0
- package/lib/esm/epic.js +4 -1
- package/lib/esm/index.js +6 -6
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/confirmStatementMappingEpic.js +43 -0
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/deleteAccountStatementEpic.js +1 -2
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/parseCombinedStatementEpic.js +31 -0
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.js +15 -18
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/updateCombinedStatementInfoEpic.js +68 -0
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.js +10 -10
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/uploadAccountStatementDocumentAIHelper.js +12 -4
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/uploadAccountStatementEpic.js +8 -2
- package/lib/esm/view/expenseAutomationView/helpers/mapStatementUpdateLocalDataToRequestBody.js +20 -5
- package/lib/esm/view/expenseAutomationView/payload/reconciliationPayload.js +135 -0
- package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +120 -16
- package/lib/esm/view/expenseAutomationView/selectors/reconciliationViewSelector.js +38 -7
- package/lib/esm/view/expenseAutomationView/selectors/statementParseViewSelector.js +43 -10
- package/lib/esm/view/expenseAutomationView/types/reconciliationViewState.js +15 -1
- package/lib/esm/view/invoicing/createInvoice/createInvoiceSelector.js +0 -1
- package/lib/esm/view/invoicing/invoicingCustomerDetailView/invoicingCustomerDetailViewSelector.js +2 -4
- package/lib/index.d.ts +9 -9
- package/lib/index.js +51 -46
- package/lib/view/expenseAutomationView/epics/accountRecon/confirmStatementMappingEpic.d.ts +34 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/confirmStatementMappingEpic.js +47 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/deleteAccountStatementEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/accountRecon/deleteAccountStatementEpic.js +0 -1
- package/lib/view/expenseAutomationView/epics/accountRecon/parseCombinedStatementEpic.d.ts +26 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/parseCombinedStatementEpic.js +35 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.d.ts +21 -1
- package/lib/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.js +15 -18
- package/lib/view/expenseAutomationView/epics/accountRecon/updateCombinedStatementInfoEpic.d.ts +27 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/updateCombinedStatementInfoEpic.js +72 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.js +10 -10
- package/lib/view/expenseAutomationView/epics/accountRecon/uploadAccountStatementDocumentAIHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/epics/accountRecon/uploadAccountStatementDocumentAIHelper.js +12 -4
- package/lib/view/expenseAutomationView/epics/accountRecon/uploadAccountStatementEpic.js +7 -1
- package/lib/view/expenseAutomationView/helpers/mapStatementUpdateLocalDataToRequestBody.d.ts +1 -0
- package/lib/view/expenseAutomationView/helpers/mapStatementUpdateLocalDataToRequestBody.js +20 -4
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/payload/reconciliationPayload.d.ts +109 -4
- package/lib/view/expenseAutomationView/payload/reconciliationPayload.js +143 -0
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.d.ts +32 -4
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +122 -18
- package/lib/view/expenseAutomationView/selectorTypes/reconciliationViewSelectorTypes.d.ts +5 -1
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.d.ts +4 -1
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.js +40 -7
- package/lib/view/expenseAutomationView/selectors/statementParseViewSelector.d.ts +3 -2
- package/lib/view/expenseAutomationView/selectors/statementParseViewSelector.js +44 -10
- package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +74 -1
- package/lib/view/expenseAutomationView/types/reconciliationViewState.js +19 -1
- package/lib/view/invoicing/createInvoice/createInvoiceSelector.d.ts +1 -4
- package/lib/view/invoicing/createInvoice/createInvoiceSelector.js +0 -1
- package/lib/view/invoicing/invoicingCustomerDetailView/invoicingCustomerDetailViewSelector.d.ts +1 -2
- package/lib/view/invoicing/invoicingCustomerDetailView/invoicingCustomerDetailViewSelector.js +1 -3
- package/package.json +1 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { of } from 'rxjs';
|
|
2
|
+
import { catchError, exhaustMap, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
4
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
|
+
import { isConfirmStatementMappingConflictResponse, transformConfirmStatementMappingConflictToState, transformConfirmStatementMappingPayloadToState, } from '../../payload/reconciliationPayload';
|
|
6
|
+
import { confirmStatementMapping, confirmStatementMappingFailure, confirmStatementMappingSuccess, } from '../../reducers/reconciliationViewReducer';
|
|
7
|
+
const confirmStatementMappingErrorSnackbar = openSnackbar({
|
|
8
|
+
messageSection: 'confirm_statement_mapping',
|
|
9
|
+
messageText: 'failed',
|
|
10
|
+
type: 'error',
|
|
11
|
+
});
|
|
12
|
+
export const confirmStatementMappingEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(confirmStatementMapping.match), exhaustMap((action) => {
|
|
13
|
+
const { accountId, selectedPeriod, statementUploadId, accountMappings } = action.payload;
|
|
14
|
+
const confirmMappingApi$ = zeniAPI.postAndGetJSON(`${zeniAPI.apiEndPoints.reconciliationMicroServiceBaseUrl}/1.0/reconciliation/statements/${statementUploadId}/confirm-mapping`, {
|
|
15
|
+
account_mappings: accountMappings.map((mapping) => ({
|
|
16
|
+
ledger_identifier: mapping.ledgerIdentifier,
|
|
17
|
+
account_id: mapping.accountId,
|
|
18
|
+
})),
|
|
19
|
+
});
|
|
20
|
+
return confirmMappingApi$.pipe(mergeMap((response) => {
|
|
21
|
+
if (isSuccessResponse(response) === true && response.data != null) {
|
|
22
|
+
return of(confirmStatementMappingSuccess({
|
|
23
|
+
accountId,
|
|
24
|
+
selectedPeriod,
|
|
25
|
+
statementUploads: transformConfirmStatementMappingPayloadToState(response.data),
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
const mappingConflict = isConfirmStatementMappingConflictResponse(response)
|
|
29
|
+
? transformConfirmStatementMappingConflictToState(response)
|
|
30
|
+
: null;
|
|
31
|
+
return of(confirmStatementMappingFailure({
|
|
32
|
+
accountId,
|
|
33
|
+
selectedPeriod,
|
|
34
|
+
error: response.status,
|
|
35
|
+
mappingConflict,
|
|
36
|
+
}), confirmStatementMappingErrorSnackbar);
|
|
37
|
+
}), catchError((error) => of(confirmStatementMappingFailure({
|
|
38
|
+
accountId,
|
|
39
|
+
selectedPeriod,
|
|
40
|
+
error: createZeniAPIStatus('Unexpected Error', 'Confirm Statement Mapping REST API call errored out ' +
|
|
41
|
+
(error instanceof Error ? error.message : String(error))),
|
|
42
|
+
}), confirmStatementMappingErrorSnackbar)));
|
|
43
|
+
}));
|
|
@@ -4,7 +4,7 @@ import { updateAccountReconDeleteStatement } from '../../../../entity/accountRec
|
|
|
4
4
|
import { toAccountReconKey } from '../../../../entity/accountRecon/accountReconState';
|
|
5
5
|
import { removeFiles } from '../../../../entity/file/fileReducer';
|
|
6
6
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
7
|
-
import { deleteAccountStatement, deleteAccountStatementFailure, deleteAccountStatementSuccess,
|
|
7
|
+
import { deleteAccountStatement, deleteAccountStatementFailure, deleteAccountStatementSuccess, } from '../../reducers/reconciliationViewReducer';
|
|
8
8
|
export const deleteAccountStatementEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(deleteAccountStatement.match), switchMap((action) => {
|
|
9
9
|
const { accountId, selectedPeriod, statementUploadId, fileId } = action.payload;
|
|
10
10
|
const request = zeniAPI.deleteAndGetJSON(`${zeniAPI.apiEndPoints.reconciliationMicroServiceBaseUrl}/1.0/reconciliation/statements/${statementUploadId}`);
|
|
@@ -17,7 +17,6 @@ export const deleteAccountStatementEpic = (actions$, _state$, zeniAPI) => action
|
|
|
17
17
|
actions.push(updateAccountReconDeleteStatement(accountReconKey, response.data));
|
|
18
18
|
}
|
|
19
19
|
actions.push(deleteAccountStatementSuccess({ accountId, selectedPeriod }));
|
|
20
|
-
actions.push(fetchReconciliation(selectedPeriod, undefined, true, true));
|
|
21
20
|
return of(...actions);
|
|
22
21
|
}
|
|
23
22
|
else {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
4
|
+
import { transformCombinedStatementGroupPayloadToState, } from '../../payload/reconciliationPayload';
|
|
5
|
+
import { parseCombinedStatement, parseStatementFailure, parseStatementSuccess, updateParsedStatementData, } from '../../reducers/reconciliationViewReducer';
|
|
6
|
+
export const parseCombinedStatementEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(parseCombinedStatement.match), switchMap((action) => {
|
|
7
|
+
const { accountId, selectedPeriod, combinedStatementGroupId } = action.payload;
|
|
8
|
+
const parseUrl = `${zeniAPI.apiEndPoints.reconciliationMicroServiceBaseUrl}/2.0/statement-uploads/combined-statement-groups/${combinedStatementGroupId}`;
|
|
9
|
+
return zeniAPI.getJSON(parseUrl).pipe(mergeMap((response) => {
|
|
10
|
+
if (isSuccessResponse(response) === true && response.data != null) {
|
|
11
|
+
return from([
|
|
12
|
+
updateParsedStatementData({
|
|
13
|
+
accountId,
|
|
14
|
+
selectedPeriod,
|
|
15
|
+
parsedStatementData: transformCombinedStatementGroupPayloadToState(response.data),
|
|
16
|
+
}),
|
|
17
|
+
parseStatementSuccess({ accountId, selectedPeriod }),
|
|
18
|
+
]);
|
|
19
|
+
}
|
|
20
|
+
return of(parseStatementFailure({
|
|
21
|
+
accountId,
|
|
22
|
+
selectedPeriod,
|
|
23
|
+
error: response.status,
|
|
24
|
+
}));
|
|
25
|
+
}), catchError((error) => of(parseStatementFailure({
|
|
26
|
+
accountId,
|
|
27
|
+
selectedPeriod,
|
|
28
|
+
error: createZeniAPIStatus('Unexpected Error', 'Parse Combined Statement REST API call errored out ' +
|
|
29
|
+
(error instanceof Error ? error.message : String(error))),
|
|
30
|
+
}))));
|
|
31
|
+
}));
|
|
@@ -5,26 +5,23 @@ import { transformParseStatementPayloadToState, } from '../../payload/reconcilia
|
|
|
5
5
|
import { parseStatement, parseStatementFailure, parseStatementSuccess, updateParsedStatementData, } from '../../reducers/reconciliationViewReducer';
|
|
6
6
|
export const parseStatementEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(parseStatement.match), switchMap((action) => {
|
|
7
7
|
const { accountId, selectedPeriod, statementUploadId } = action.payload;
|
|
8
|
-
const
|
|
9
|
-
return
|
|
8
|
+
const parseUrl = `${zeniAPI.apiEndPoints.reconciliationMicroServiceBaseUrl}/2.0/statement-uploads/${statementUploadId}`;
|
|
9
|
+
return zeniAPI.getJSON(parseUrl).pipe(mergeMap((response) => {
|
|
10
10
|
if (isSuccessResponse(response) === true && response.data != null) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return from(actions);
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
return of(parseStatementFailure({
|
|
23
|
-
accountId,
|
|
24
|
-
selectedPeriod,
|
|
25
|
-
error: response.status,
|
|
26
|
-
}));
|
|
11
|
+
return from([
|
|
12
|
+
updateParsedStatementData({
|
|
13
|
+
accountId,
|
|
14
|
+
selectedPeriod,
|
|
15
|
+
parsedStatementData: transformParseStatementPayloadToState(response.data),
|
|
16
|
+
}),
|
|
17
|
+
parseStatementSuccess({ accountId, selectedPeriod }),
|
|
18
|
+
]);
|
|
27
19
|
}
|
|
20
|
+
return of(parseStatementFailure({
|
|
21
|
+
accountId,
|
|
22
|
+
selectedPeriod,
|
|
23
|
+
error: response.status,
|
|
24
|
+
}));
|
|
28
25
|
}), catchError((error) => of(parseStatementFailure({
|
|
29
26
|
accountId,
|
|
30
27
|
selectedPeriod,
|
package/lib/esm/view/expenseAutomationView/epics/accountRecon/updateCombinedStatementInfoEpic.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { toMonthYearPeriodId } from '../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
|
+
import { mapCombinedStatementUpdateLocalDataToRequestBody } from '../../helpers/mapStatementUpdateLocalDataToRequestBody';
|
|
6
|
+
import { getStatementUploadsFromParsedData } from '../../selectors/statementParseViewSelector';
|
|
7
|
+
import { isStatementDateConflictResponse, transformStatementDateConflictToState, transformUpdateStatementInfoPayloadToState, } from '../../payload/reconciliationPayload';
|
|
8
|
+
import { submitCombinedStatementUpdate, submitStatementUpdateFailure, submitStatementUpdateSuccess, updateParsedStatementData, } from '../../reducers/reconciliationViewReducer';
|
|
9
|
+
export const updateCombinedStatementInfoEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(submitCombinedStatementUpdate.match), switchMap((action) => {
|
|
10
|
+
const { accountId, selectedPeriod } = action.payload;
|
|
11
|
+
const accountRecon = state$.value.expenseAutomationReconciliationViewState
|
|
12
|
+
.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
13
|
+
const parsedStatementData = accountRecon?.parsedStatementData;
|
|
14
|
+
const localDataByUploadId = accountRecon?.localData?.statementUpdateLocalDataByUploadId;
|
|
15
|
+
const statementUploads = getStatementUploadsFromParsedData(parsedStatementData);
|
|
16
|
+
if (parsedStatementData == null ||
|
|
17
|
+
localDataByUploadId == null ||
|
|
18
|
+
statementUploads.length === 0 ||
|
|
19
|
+
statementUploads.some((statementUpload) => localDataByUploadId[statementUpload.statementMeta.statementUploadId] == null)) {
|
|
20
|
+
return of(submitStatementUpdateFailure({
|
|
21
|
+
accountId,
|
|
22
|
+
selectedPeriod,
|
|
23
|
+
error: createZeniAPIStatus('Missing Data', 'No statement update data found for combined accounts'),
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
const combinedStatementGroupId = accountRecon?.combinedStatementGroupId ??
|
|
27
|
+
parsedStatementData.statementUpload.statementMeta
|
|
28
|
+
.combinedStatementGroupId ??
|
|
29
|
+
parsedStatementData.statementUpload.combinedStatementDetails
|
|
30
|
+
?.combinedStatementGroupId;
|
|
31
|
+
if (combinedStatementGroupId == null || combinedStatementGroupId === '') {
|
|
32
|
+
return of(submitStatementUpdateFailure({
|
|
33
|
+
accountId,
|
|
34
|
+
selectedPeriod,
|
|
35
|
+
error: createZeniAPIStatus('Missing Data', 'No combined statement group id found for bulk update'),
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
const body = mapCombinedStatementUpdateLocalDataToRequestBody(localDataByUploadId, parsedStatementData);
|
|
39
|
+
const updateUrl = `${zeniAPI.apiEndPoints.reconciliationMicroServiceBaseUrl}/2.0/statement-uploads/combined-statement-groups/${combinedStatementGroupId}`;
|
|
40
|
+
return zeniAPI
|
|
41
|
+
.putAndGetJSON(updateUrl, body)
|
|
42
|
+
.pipe(mergeMap((response) => {
|
|
43
|
+
if (isSuccessResponse(response) === true && response.data != null) {
|
|
44
|
+
return of(updateParsedStatementData({
|
|
45
|
+
accountId,
|
|
46
|
+
selectedPeriod,
|
|
47
|
+
parsedStatementData: transformUpdateStatementInfoPayloadToState(response.data),
|
|
48
|
+
}), submitStatementUpdateSuccess({
|
|
49
|
+
accountId,
|
|
50
|
+
selectedPeriod,
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
const dateConflict = isStatementDateConflictResponse(response)
|
|
54
|
+
? transformStatementDateConflictToState(response)
|
|
55
|
+
: null;
|
|
56
|
+
return of(submitStatementUpdateFailure({
|
|
57
|
+
accountId,
|
|
58
|
+
selectedPeriod,
|
|
59
|
+
error: response.status,
|
|
60
|
+
dateConflict,
|
|
61
|
+
}));
|
|
62
|
+
}), catchError((error) => of(submitStatementUpdateFailure({
|
|
63
|
+
accountId,
|
|
64
|
+
selectedPeriod,
|
|
65
|
+
error: createZeniAPIStatus('Unexpected Error', 'Update Statement REST API call errored out ' +
|
|
66
|
+
(error instanceof Error ? error.message : String(error))),
|
|
67
|
+
}))));
|
|
68
|
+
}));
|
|
@@ -7,12 +7,11 @@ import { isStatementDateConflictResponse, transformStatementDateConflictToState,
|
|
|
7
7
|
import { submitStatementUpdate, submitStatementUpdateFailure, submitStatementUpdateSuccess, updateParsedStatementData, } from '../../reducers/reconciliationViewReducer';
|
|
8
8
|
export const updateStatementInfoEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(submitStatementUpdate.match), switchMap((action) => {
|
|
9
9
|
const { accountId, selectedPeriod, statementUploadId } = action.payload;
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const accountRecon = reconciliationView.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
13
|
-
const localData = accountRecon?.localData?.statementUpdateLocalData;
|
|
10
|
+
const accountRecon = state$.value.expenseAutomationReconciliationViewState
|
|
11
|
+
.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
14
12
|
const parsedStatementData = accountRecon?.parsedStatementData;
|
|
15
|
-
|
|
13
|
+
const localData = accountRecon?.localData?.statementUpdateLocalDataByUploadId?.[statementUploadId];
|
|
14
|
+
if (parsedStatementData == null || localData == null) {
|
|
16
15
|
return of(submitStatementUpdateFailure({
|
|
17
16
|
accountId,
|
|
18
17
|
selectedPeriod,
|
|
@@ -20,7 +19,7 @@ export const updateStatementInfoEpic = (actions$, state$, zeniAPI) => actions$.p
|
|
|
20
19
|
}));
|
|
21
20
|
}
|
|
22
21
|
const hasInvalidUpdates = localData.statementTransactions.updated.some((txn) => txn.statementTransactionId == null);
|
|
23
|
-
if (hasInvalidUpdates) {
|
|
22
|
+
if (hasInvalidUpdates === true) {
|
|
24
23
|
return of(submitStatementUpdateFailure({
|
|
25
24
|
accountId,
|
|
26
25
|
selectedPeriod,
|
|
@@ -28,14 +27,15 @@ export const updateStatementInfoEpic = (actions$, state$, zeniAPI) => actions$.p
|
|
|
28
27
|
}));
|
|
29
28
|
}
|
|
30
29
|
const body = mapStatementUpdateLocalDataToRequestBody(localData, parsedStatementData);
|
|
31
|
-
const
|
|
32
|
-
return
|
|
30
|
+
const updateUrl = `${zeniAPI.apiEndPoints.reconciliationMicroServiceBaseUrl}/2.0/statement-uploads/${statementUploadId}`;
|
|
31
|
+
return zeniAPI
|
|
32
|
+
.putAndGetJSON(updateUrl, body)
|
|
33
|
+
.pipe(mergeMap((response) => {
|
|
33
34
|
if (isSuccessResponse(response) === true && response.data != null) {
|
|
34
|
-
const parsedStatementData = transformUpdateStatementInfoPayloadToState(response.data);
|
|
35
35
|
return of(updateParsedStatementData({
|
|
36
36
|
accountId,
|
|
37
37
|
selectedPeriod,
|
|
38
|
-
parsedStatementData,
|
|
38
|
+
parsedStatementData: transformUpdateStatementInfoPayloadToState(response.data),
|
|
39
39
|
}), submitStatementUpdateSuccess({
|
|
40
40
|
accountId,
|
|
41
41
|
selectedPeriod,
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import fetch from 'cross-fetch';
|
|
2
2
|
import { zeniAPI } from '../../../../init';
|
|
3
|
-
|
|
3
|
+
function toStatementDocumentType(accountType, isCombinedStatement) {
|
|
4
|
+
if (isCombinedStatement === true) {
|
|
5
|
+
return accountType === 'credit_card'
|
|
6
|
+
? 'reconciliation_combined_card_statement_upload'
|
|
7
|
+
: 'reconciliation_combined_bank_statement_upload';
|
|
8
|
+
}
|
|
9
|
+
return accountType === 'credit_card'
|
|
10
|
+
? 'reconciliation_card_statement_upload'
|
|
11
|
+
: 'reconciliation_bank_statement_upload';
|
|
12
|
+
}
|
|
13
|
+
export default async function uploadAccountStatementIntoDocumentAI(accountType, fileBlob, authParams, isCombinedStatement = false) {
|
|
4
14
|
let statementUpload;
|
|
5
15
|
const urlEndPoint = `${zeniAPI.apiEndPoints.documentAIMicroServiceBaseUrl}/1.0/processors/statement`;
|
|
6
16
|
const data = new FormData();
|
|
7
17
|
data.append('attachment_file_0', fileBlob);
|
|
8
18
|
const attachment_json = JSON.stringify({
|
|
9
|
-
document_type: accountType
|
|
10
|
-
? 'reconciliation_card_statement_upload'
|
|
11
|
-
: 'reconciliation_bank_statement_upload',
|
|
19
|
+
document_type: toStatementDocumentType(accountType, isCombinedStatement),
|
|
12
20
|
purpose_id: 'reconciliation',
|
|
13
21
|
});
|
|
14
22
|
data.append('attachment_json_0', attachment_json);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { from, of } from 'rxjs';
|
|
2
2
|
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
-
import { convertToPeriod } from '../../../../commonStateTypes/timePeriod';
|
|
3
|
+
import { convertToPeriod, toMonthYearPeriodId, } from '../../../../commonStateTypes/timePeriod';
|
|
4
4
|
import { getAccountBase } from '../../../../entity/account/accountSelector';
|
|
5
5
|
import { updateAccountReconUploadStatement } from '../../../../entity/accountRecon/accountReconReducer';
|
|
6
6
|
import { toAccountReconKey } from '../../../../entity/accountRecon/accountReconState';
|
|
@@ -8,7 +8,7 @@ import { updateFiles } from '../../../../entity/file/fileReducer';
|
|
|
8
8
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
9
9
|
import { uploadAccountStatement, uploadAccountStatementFailure, uploadAccountStatementSuccess, } from '../../reducers/reconciliationViewReducer';
|
|
10
10
|
export const uploadAccountStatementEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(uploadAccountStatement.match), mergeMap((action) => {
|
|
11
|
-
const { accountId, selectedPeriod, payload } = action.payload;
|
|
11
|
+
const { accountId, selectedPeriod, payload, statementAccountScope } = action.payload;
|
|
12
12
|
const { start, end } = convertToPeriod(selectedPeriod, true);
|
|
13
13
|
const accountBase = getAccountBase(state$.value.accountState, accountId, 'account_reconciliation');
|
|
14
14
|
if (accountBase == null) {
|
|
@@ -19,6 +19,11 @@ export const uploadAccountStatementEpic = (actions$, state$, zeniAPI) => actions
|
|
|
19
19
|
}));
|
|
20
20
|
}
|
|
21
21
|
const statementType = accountBase.accountType == 'credit_card' ? 'card' : 'bank';
|
|
22
|
+
const localStatementAccountScope = state$.value.expenseAutomationReconciliationViewState
|
|
23
|
+
.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId]?.localData
|
|
24
|
+
?.statementAccountScope;
|
|
25
|
+
const resolvedStatementAccountScope = statementAccountScope ?? localStatementAccountScope ?? 'single_account';
|
|
26
|
+
const isCombinedStatement = resolvedStatementAccountScope === 'multi_account';
|
|
22
27
|
const requestPayload = {
|
|
23
28
|
account_id: accountId,
|
|
24
29
|
statement_start_date: start.toString(),
|
|
@@ -26,6 +31,7 @@ export const uploadAccountStatementEpic = (actions$, state$, zeniAPI) => actions
|
|
|
26
31
|
processor_run_id: payload.processor_run_id,
|
|
27
32
|
file_id: payload.files[0].file_id,
|
|
28
33
|
statement_type: statementType,
|
|
34
|
+
is_combined_statement: isCombinedStatement,
|
|
29
35
|
};
|
|
30
36
|
const uploadAccountStatementApi$ = zeniAPI.postAndGetJSON(`${zeniAPI.apiEndPoints.reconciliationMicroServiceBaseUrl}/1.0/reconciliation/statements`, requestPayload);
|
|
31
37
|
return uploadAccountStatementApi$.pipe(mergeMap((response) => {
|
package/lib/esm/view/expenseAutomationView/helpers/mapStatementUpdateLocalDataToRequestBody.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { toStatementUpdateRequestBody } from '../payload/reconciliationPayload';
|
|
2
|
-
import { getEffectiveStatementPeriod, mergeStatementParseDeletedTransactionIds, } from '../selectors/statementParseViewSelector';
|
|
3
|
-
const prepareStatementUpdateLocalData = (localData,
|
|
4
|
-
const { statementMeta, statementTransactions } =
|
|
1
|
+
import { toBulkStatementUpdateRequestBody, toStatementUpdateRequestBody, } from '../payload/reconciliationPayload';
|
|
2
|
+
import { getEffectiveStatementPeriod, getStatementUploadsFromParsedData, mergeStatementParseDeletedTransactionIds, } from '../selectors/statementParseViewSelector';
|
|
3
|
+
const prepareStatementUpdateLocalData = (localData, statementUpload) => {
|
|
4
|
+
const { statementMeta, statementTransactions } = statementUpload;
|
|
5
5
|
const statementPeriod = getEffectiveStatementPeriod(statementMeta, localData.statementMeta);
|
|
6
6
|
const localDeletedIds = localData.statementTransactions?.deletedIds ?? [];
|
|
7
7
|
const currentTransactionIds = new Set(statementTransactions
|
|
@@ -27,4 +27,19 @@ const prepareStatementUpdateLocalData = (localData, parsedStatementData) => {
|
|
|
27
27
|
},
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
|
-
export const mapStatementUpdateLocalDataToRequestBody = (localData, parsedStatementData) => toStatementUpdateRequestBody(prepareStatementUpdateLocalData(localData, parsedStatementData));
|
|
30
|
+
export const mapStatementUpdateLocalDataToRequestBody = (localData, parsedStatementData) => toStatementUpdateRequestBody(prepareStatementUpdateLocalData(localData, parsedStatementData.statementUpload));
|
|
31
|
+
export const mapCombinedStatementUpdateLocalDataToRequestBody = (localDataByUploadId, parsedStatementData) => {
|
|
32
|
+
const statementUploads = getStatementUploadsFromParsedData(parsedStatementData);
|
|
33
|
+
const updates = statementUploads.map((statementUpload) => {
|
|
34
|
+
const statementUploadId = statementUpload.statementMeta.statementUploadId;
|
|
35
|
+
const localData = localDataByUploadId[statementUploadId];
|
|
36
|
+
if (localData == null) {
|
|
37
|
+
throw new Error(`Missing statement update local data for upload ${statementUploadId}`);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
statementUploadId,
|
|
41
|
+
localData: prepareStatementUpdateLocalData(localData, statementUpload),
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
return toBulkStatementUpdateRequestBody(updates);
|
|
45
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { convertToPeriod, } from '../../../commonStateTypes/timePeriod';
|
|
2
2
|
import { toTransactionsToReviewPayload, } from '../../../entity/accountRecon/accountReconPayload';
|
|
3
3
|
import { toMatchedTransactionPayload, } from '../../../entity/transaction/payloadTypes/reconciliationTransactionPayloads';
|
|
4
|
+
import { toStatementBalanceSourceStrict, } from '../types/reconciliationViewState';
|
|
4
5
|
export function createSaveReconciliationPayloadBasedOnActionAndMethod(state, selectedPeriod, localData, accountReconciliationEntity, action, method) {
|
|
5
6
|
const { balance, initialClearedBalance } = accountReconciliationEntity;
|
|
6
7
|
const { expenseAutomationReconciliationViewState: { selectedAccountId, reconTabsState: { reconcile: { localData: { selectedTransactionIds }, }, }, }, } = state;
|
|
@@ -67,10 +68,60 @@ function createReviewTransactionPayload(accountReconciliationEntity) {
|
|
|
67
68
|
});
|
|
68
69
|
return reviewTransactionsPayload;
|
|
69
70
|
}
|
|
71
|
+
export function isParseStatementCombinedResponsePayload(payload) {
|
|
72
|
+
return ('statement_uploads' in payload &&
|
|
73
|
+
Array.isArray(payload.statement_uploads) &&
|
|
74
|
+
payload.statement_uploads.length > 0 &&
|
|
75
|
+
// Batch group GET nests each upload under statement_upload — exclude that shape.
|
|
76
|
+
'statement_upload' in (payload.statement_uploads[0] ?? {}) === false);
|
|
77
|
+
}
|
|
78
|
+
export function isUpdateStatementInfoCombinedResponsePayload(payload) {
|
|
79
|
+
return ('statement_uploads' in payload &&
|
|
80
|
+
Array.isArray(payload.statement_uploads) &&
|
|
81
|
+
payload.statement_uploads.length > 0);
|
|
82
|
+
}
|
|
70
83
|
export function isStatementDateConflictResponse(response) {
|
|
71
84
|
return response.status.code === 409 && response.error_code != null;
|
|
72
85
|
}
|
|
86
|
+
function transformConfirmedCombinedStatementUploadsToState(statementUploads) {
|
|
87
|
+
return (statementUploads ?? []).map((statementUpload) => ({
|
|
88
|
+
accountId: statementUpload.account_id,
|
|
89
|
+
isCombinedStatementAnchor: statementUpload.is_combined_statement_anchor,
|
|
90
|
+
ledgerIdentifiers: statementUpload.ledger_identifiers ?? [],
|
|
91
|
+
statementUploadId: statementUpload.statement_upload_id,
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
function transformCombinedStatementDetailsToState(details) {
|
|
95
|
+
if (details == null) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
combinedStatementGroupId: details.combined_statement_group_id,
|
|
100
|
+
isMappingConfirmed: details.is_mapping_confirmed,
|
|
101
|
+
accounts: (details.accounts ?? []).map((account) => ({
|
|
102
|
+
ledgerIdentifier: account.ledger_identifier,
|
|
103
|
+
accountName: account.account_name,
|
|
104
|
+
accountType: account.account_type,
|
|
105
|
+
maskedAccountNumber: account.masked_account_number,
|
|
106
|
+
openingBalance: account.opening_balance,
|
|
107
|
+
closingBalance: account.closing_balance,
|
|
108
|
+
transactionCount: account.transaction_count,
|
|
109
|
+
isUploadContext: account.is_upload_context,
|
|
110
|
+
existingStatementStatus: account.existing_statement_status ?? null,
|
|
111
|
+
suggestion: account.suggestion != null
|
|
112
|
+
? {
|
|
113
|
+
accountId: account.suggestion.account_id,
|
|
114
|
+
accountName: account.suggestion.account_name,
|
|
115
|
+
matchedBy: account.suggestion.matched_by,
|
|
116
|
+
matchConfidence: account.suggestion.match_confidence,
|
|
117
|
+
}
|
|
118
|
+
: null,
|
|
119
|
+
})),
|
|
120
|
+
statementUploads: transformConfirmedCombinedStatementUploadsToState(details.statement_uploads),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
73
123
|
function transformStatementUploadPayloadToState(statementUploadPayload) {
|
|
124
|
+
const balanceSource = toStatementBalanceSourceStrict(statementUploadPayload.statement_meta.balance_source);
|
|
74
125
|
return {
|
|
75
126
|
account: {
|
|
76
127
|
accountId: statementUploadPayload.account.account_id,
|
|
@@ -96,6 +147,13 @@ function transformStatementUploadPayloadToState(statementUploadPayload) {
|
|
|
96
147
|
statementUploadId: statementUploadPayload.statement_meta.statement_upload_id,
|
|
97
148
|
totalDeposits: statementUploadPayload.statement_meta.total_deposits,
|
|
98
149
|
totalPayments: statementUploadPayload.statement_meta.total_payments,
|
|
150
|
+
isCombinedStatement: statementUploadPayload.statement_meta.is_combined_statement ??
|
|
151
|
+
undefined,
|
|
152
|
+
isCombinedStatementAnchor: statementUploadPayload.statement_meta.is_combined_statement_anchor ??
|
|
153
|
+
undefined,
|
|
154
|
+
combinedStatementGroupId: statementUploadPayload.statement_meta.combined_statement_group_id ??
|
|
155
|
+
undefined,
|
|
156
|
+
...(balanceSource != null ? { balanceSource } : {}),
|
|
99
157
|
},
|
|
100
158
|
statementTransactions: (statementUploadPayload.statement_transactions ?? []).map((txn) => ({
|
|
101
159
|
amount: txn.amount,
|
|
@@ -117,6 +175,7 @@ function transformStatementUploadPayloadToState(statementUploadPayload) {
|
|
|
117
175
|
transactionMemo: txn.transaction_memo,
|
|
118
176
|
})),
|
|
119
177
|
aiSummary: transformAiSummaryPayloadToState(statementUploadPayload.ai_summary),
|
|
178
|
+
combinedStatementDetails: transformCombinedStatementDetailsToState(statementUploadPayload.combined_statement_details),
|
|
120
179
|
};
|
|
121
180
|
}
|
|
122
181
|
function transformPreviousReconciliationInfoToState(payload) {
|
|
@@ -177,11 +236,71 @@ export function transformStatementDateConflictToState(response) {
|
|
|
177
236
|
};
|
|
178
237
|
}
|
|
179
238
|
export function transformParseStatementPayloadToState(payload) {
|
|
239
|
+
if (isParseStatementCombinedResponsePayload(payload) === true) {
|
|
240
|
+
const statementUploads = payload.statement_uploads.map(transformStatementUploadPayloadToState);
|
|
241
|
+
const anchorUpload = statementUploads.find((upload) => upload.statementMeta.isCombinedStatementAnchor === true) ?? statementUploads[0];
|
|
242
|
+
return {
|
|
243
|
+
statementUpload: anchorUpload,
|
|
244
|
+
statementUploads,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
180
247
|
return {
|
|
181
248
|
statementUpload: transformStatementUploadPayloadToState(payload.statement_upload),
|
|
182
249
|
};
|
|
183
250
|
}
|
|
251
|
+
export function transformCombinedStatementGroupPayloadToState(payload) {
|
|
252
|
+
const groupId = payload.combined_statement_group_id;
|
|
253
|
+
const statementUploads = (payload.statement_uploads ?? []).map((entry) => {
|
|
254
|
+
const upload = transformStatementUploadPayloadToState(entry.statement_upload);
|
|
255
|
+
if ((upload.statementMeta.combinedStatementGroupId == null ||
|
|
256
|
+
upload.statementMeta.combinedStatementGroupId === '') &&
|
|
257
|
+
groupId !== '') {
|
|
258
|
+
return {
|
|
259
|
+
...upload,
|
|
260
|
+
statementMeta: {
|
|
261
|
+
...upload.statementMeta,
|
|
262
|
+
combinedStatementGroupId: groupId,
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
return upload;
|
|
267
|
+
});
|
|
268
|
+
if (statementUploads.length === 0) {
|
|
269
|
+
throw new Error('Combined statement response has no statement uploads');
|
|
270
|
+
}
|
|
271
|
+
const anchorUpload = statementUploads.find((upload) => upload.statementMeta.isCombinedStatementAnchor === true) ?? statementUploads[0];
|
|
272
|
+
return {
|
|
273
|
+
statementUpload: anchorUpload,
|
|
274
|
+
statementUploads,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
export function isConfirmStatementMappingConflictResponse(response) {
|
|
278
|
+
return response.status.code === 409;
|
|
279
|
+
}
|
|
280
|
+
export function transformConfirmStatementMappingPayloadToState(payload) {
|
|
281
|
+
return transformConfirmedCombinedStatementUploadsToState(payload.statement_uploads);
|
|
282
|
+
}
|
|
283
|
+
export function transformConfirmStatementMappingConflictToState(response) {
|
|
284
|
+
if (isConfirmStatementMappingConflictResponse(response) === false) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
collidingAccountId: response.colliding_account_id != null
|
|
289
|
+
? response.colliding_account_id
|
|
290
|
+
: undefined,
|
|
291
|
+
collidingLedgerIdentifiers: response.colliding_ledger_identifiers ?? [],
|
|
292
|
+
previousReconciliationInfo: transformPreviousReconciliationInfoToState(response.previous_reconciliation_info),
|
|
293
|
+
};
|
|
294
|
+
}
|
|
184
295
|
export function transformUpdateStatementInfoPayloadToState(payload) {
|
|
296
|
+
if (isUpdateStatementInfoCombinedResponsePayload(payload) === true) {
|
|
297
|
+
const statementUploads = payload.statement_uploads.map(transformStatementUploadPayloadToState);
|
|
298
|
+
const anchorUpload = statementUploads.find((upload) => upload.statementMeta.isCombinedStatementAnchor === true) ?? statementUploads[0];
|
|
299
|
+
return {
|
|
300
|
+
statementUpload: anchorUpload,
|
|
301
|
+
statementUploads,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
185
304
|
return {
|
|
186
305
|
statementUpload: transformStatementUploadPayloadToState(payload.statement_upload),
|
|
187
306
|
};
|
|
@@ -221,3 +340,19 @@ export function transformStatementUpdateStateToPayload(localData) {
|
|
|
221
340
|
export function toStatementUpdateRequestBody(localData) {
|
|
222
341
|
return transformStatementUpdateStateToPayload(localData);
|
|
223
342
|
}
|
|
343
|
+
export function transformBulkStatementUpdateStateToPayload(updates) {
|
|
344
|
+
return {
|
|
345
|
+
statement_uploads: updates.map(({ localData, statementUploadId }) => {
|
|
346
|
+
const body = transformStatementUpdateStateToPayload(localData);
|
|
347
|
+
return {
|
|
348
|
+
statement_upload_id: statementUploadId,
|
|
349
|
+
statement_meta: body.statement_meta,
|
|
350
|
+
statement_transactions: body.statement_transactions,
|
|
351
|
+
};
|
|
352
|
+
}),
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
/** Bulk PUT body for combined multi-account Confirm & Save. */
|
|
356
|
+
export function toBulkStatementUpdateRequestBody(updates) {
|
|
357
|
+
return transformBulkStatementUpdateStateToPayload(updates);
|
|
358
|
+
}
|