@zeniai/client-epic-state 5.0.53-betaML4 → 5.0.54
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/tenant/epic/deleteConnectionEpic.d.ts +1 -1
- package/lib/entity/tenant/epic/saveAPIKeyConnectionEpic.d.ts +1 -1
- package/lib/entity/tenant/epic/saveConnectorCredentialsEpic.d.ts +21 -0
- package/lib/entity/tenant/epic/saveConnectorCredentialsEpic.js +42 -0
- package/lib/entity/tenant/epic/saveOAuthConnectionEpic.d.ts +1 -1
- package/lib/entity/tenant/tenantReducer.d.ts +64 -16
- package/lib/entity/tenant/tenantReducer.js +86 -7
- package/lib/entity/tenant/tenantState.d.ts +3 -1
- package/lib/epic.js +2 -2
- package/lib/esm/entity/tenant/epic/saveConnectorCredentialsEpic.js +38 -0
- package/lib/esm/entity/tenant/tenantReducer.js +84 -5
- package/lib/esm/epic.js +2 -2
- package/lib/esm/index.js +4 -4
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +27 -114
- package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +0 -6
- package/lib/esm/view/recommendation/recommendationReducer.js +1 -52
- package/lib/index.d.ts +5 -4
- package/lib/index.js +32 -33
- package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +27 -114
- package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +0 -1
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +0 -6
- package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +0 -1
- package/lib/view/recommendation/recommendationReducer.d.ts +1 -21
- package/lib/view/recommendation/recommendationReducer.js +2 -53
- package/package.json +1 -1
- package/lib/esm/view/recommendation/fetchEntityRecommendationsForCategorizationEpic.js +0 -83
- package/lib/view/recommendation/fetchEntityRecommendationsForCategorizationEpic.d.ts +0 -8
- package/lib/view/recommendation/fetchEntityRecommendationsForCategorizationEpic.js +0 -87
|
@@ -8,7 +8,6 @@ exports.uploadTransactionCategorizationReceiptSuccess = exports.updateTransactio
|
|
|
8
8
|
const toolkit_1 = require("@reduxjs/toolkit");
|
|
9
9
|
const get_1 = __importDefault(require("lodash/get"));
|
|
10
10
|
const uniq_1 = __importDefault(require("lodash/uniq"));
|
|
11
|
-
const recommendationReducer_1 = require("../../recommendation/recommendationReducer");
|
|
12
11
|
const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
|
|
13
12
|
const vendorTransaction_1 = require("../../../entity/transaction/stateTypes/vendorTransaction");
|
|
14
13
|
const transactionCategorizationLocalDataHelper_1 = require("../helpers/transactionCategorizationLocalDataHelper");
|
|
@@ -404,53 +403,10 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
404
403
|
const transactionLocalData = (0, get_1.default)(draft.transactionCategorizationView[selectedTab]
|
|
405
404
|
.transactionReviewLocalDataById, transactionId.id, undefined);
|
|
406
405
|
if (transactionLocalData != null) {
|
|
407
|
-
// Snapshot the pre-fetch selection. setEntityRecommendationForLineIdInLocalData
|
|
408
|
-
// mutates selectedCheckBoxTransactionIds internally (auto-add when
|
|
409
|
-
// all-filled, auto-remove otherwise) but does not enforce
|
|
410
|
-
// MAX_SELECTION_LIMIT. We restore from this snapshot below and let
|
|
411
|
-
// the reducer-level gate own the selection contract so the cap is
|
|
412
|
-
// honored and the gate mirrors the original auto-add gate from
|
|
413
|
-
// updateSelectedVendor/CustomerForTransaction.
|
|
414
|
-
const selectionBeforeFetch = [
|
|
415
|
-
...draft.transactionCategorizationView[selectedTab]
|
|
416
|
-
.selectedCheckBoxTransactionIds,
|
|
417
|
-
];
|
|
418
|
-
const newLocalData = (0, transactionCategorizationLocalDataHelper_1.setEntityRecommendationForLineIdInLocalData)(draft.transactionCategorizationView[selectedTab], transaction, transactionLocalData.transactionReviewLocalData, entity, lineIds, uncategorizedAccounts, action.payload.recommendationWithCOTByLineId, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled);
|
|
419
|
-
// Flip the per-line "fetching" flag to Completed for the lines this
|
|
420
|
-
// fetch covered. Reads as the success arm of the
|
|
421
|
-
// fetchEntityRecommendationsForCategorization → epic → reducer cycle.
|
|
422
|
-
lineIds.forEach((lineId) => {
|
|
423
|
-
const lineItem = newLocalData.lineItemById[lineId];
|
|
424
|
-
if (lineItem != null) {
|
|
425
|
-
newLocalData.lineItemById[lineId] = {
|
|
426
|
-
...lineItem,
|
|
427
|
-
categoryClassRecommendationsFetchState: {
|
|
428
|
-
fetchState: 'Completed',
|
|
429
|
-
error: undefined,
|
|
430
|
-
},
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
406
|
draft.transactionCategorizationView[selectedTab].transactionReviewLocalDataById[transaction.id] = {
|
|
435
407
|
transactionId: transaction.id,
|
|
436
|
-
transactionReviewLocalData:
|
|
408
|
+
transactionReviewLocalData: (0, transactionCategorizationLocalDataHelper_1.setEntityRecommendationForLineIdInLocalData)(draft.transactionCategorizationView[selectedTab], transaction, transactionLocalData.transactionReviewLocalData, entity, lineIds, uncategorizedAccounts, action.payload.recommendationWithCOTByLineId, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled),
|
|
437
409
|
};
|
|
438
|
-
// Auto-add the transaction to the bulk-save selection now that
|
|
439
|
-
// fresh recs have landed and all required fields are filled. This
|
|
440
|
-
// is the success-arm of the deferral noted in
|
|
441
|
-
// updateSelectedVendor/CustomerForTransaction: their auto-add was
|
|
442
|
-
// suppressed because pre-fetch category/class were stale; we run
|
|
443
|
-
// the same gate here against newLocalData so the checkbox flips
|
|
444
|
-
// on against fresh recs.
|
|
445
|
-
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = selectionBeforeFetch;
|
|
446
|
-
if ((0, transactionCategorizationLocalDataHelper_1.checkIfAllLineItemsAreCategoryClassFilled)(transaction, newLocalData, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled) === true &&
|
|
447
|
-
selectionBeforeFetch.length < transactionCategorizationLocalDataHelper_1.MAX_SELECTION_LIMIT &&
|
|
448
|
-
selectionBeforeFetch.includes(transaction.id) === false) {
|
|
449
|
-
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
|
|
450
|
-
...selectionBeforeFetch,
|
|
451
|
-
transaction.id,
|
|
452
|
-
];
|
|
453
|
-
}
|
|
454
410
|
// Mark transaction as dirty (autofill happened)
|
|
455
411
|
if (!draft.transactionCategorizationView[selectedTab].transactionIdsWithUnsavedData.includes(transaction.id)) {
|
|
456
412
|
draft.transactionCategorizationView[selectedTab].transactionIdsWithUnsavedData = [
|
|
@@ -504,13 +460,7 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
504
460
|
action.payload.status;
|
|
505
461
|
},
|
|
506
462
|
updateSelectedCustomerForTransaction(draft, action) {
|
|
507
|
-
const { transactionId, lineId, updatedCustomer, selectedTransaction, selectedTab,
|
|
508
|
-
// uncategorizedAccounts, isAccountingClassesEnabled, and
|
|
509
|
-
// isUncategorizedExpenseCategoryEnabled remain in the payload type for
|
|
510
|
-
// backward compatibility but are no longer read here — the post-fetch
|
|
511
|
-
// success reducer (setEntityRecommendationForLineIdsForCategorization)
|
|
512
|
-
// owns the all-fields-filled check that drives auto-selection.
|
|
513
|
-
} = action.payload;
|
|
463
|
+
const { transactionId, lineId, updatedCustomer, selectedTransaction, selectedTab, uncategorizedAccounts, isAccountingClassesEnabled, isUncategorizedExpenseCategoryEnabled, } = action.payload;
|
|
514
464
|
const transactionLocalData = (0, get_1.default)(draft.transactionCategorizationView[selectedTab]
|
|
515
465
|
.transactionReviewLocalDataById, transactionId, undefined);
|
|
516
466
|
if (transactionLocalData != null) {
|
|
@@ -559,13 +509,18 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
559
509
|
transactionReviewLocalData: newTransactionLocalData,
|
|
560
510
|
transactionId,
|
|
561
511
|
};
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
512
|
+
const selectedCheckBoxTransactionIds = draft.transactionCategorizationView[selectedTab]
|
|
513
|
+
.selectedCheckBoxTransactionIds;
|
|
514
|
+
if (newTransactionLocalData.customer != null &&
|
|
515
|
+
newTransactionLocalData.customer.id != null &&
|
|
516
|
+
(0, transactionCategorizationLocalDataHelper_1.checkIfAllLineItemsAreCategoryClassFilled)(selectedTransaction, newTransactionLocalData, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled) === true && // check if all line items are filled
|
|
517
|
+
selectedCheckBoxTransactionIds.length < transactionCategorizationLocalDataHelper_1.MAX_SELECTION_LIMIT &&
|
|
518
|
+
selectedCheckBoxTransactionIds.includes(transactionId) === false) {
|
|
519
|
+
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
|
|
520
|
+
...selectedCheckBoxTransactionIds,
|
|
521
|
+
transactionId,
|
|
522
|
+
];
|
|
523
|
+
}
|
|
569
524
|
// Mark transaction as dirty (customer updated)
|
|
570
525
|
if (!draft.transactionCategorizationView[selectedTab].transactionIdsWithUnsavedData.includes(transactionId)) {
|
|
571
526
|
draft.transactionCategorizationView[selectedTab].transactionIdsWithUnsavedData = [
|
|
@@ -577,11 +532,7 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
577
532
|
}
|
|
578
533
|
},
|
|
579
534
|
updateSelectedVendorForTransaction(draft, action) {
|
|
580
|
-
const { transactionId, lineId, updatedVendor, selectedTransaction, selectedTab,
|
|
581
|
-
// See updateSelectedCustomerForTransaction for why
|
|
582
|
-
// uncategorizedAccounts, isAccountingClassesEnabled, and
|
|
583
|
-
// isUncategorizedExpenseCategoryEnabled are no longer destructured.
|
|
584
|
-
} = action.payload;
|
|
535
|
+
const { transactionId, lineId, updatedVendor, selectedTransaction, selectedTab, uncategorizedAccounts, isAccountingClassesEnabled, isUncategorizedExpenseCategoryEnabled, } = action.payload;
|
|
585
536
|
const transactionLocalData = (0, get_1.default)(draft.transactionCategorizationView[selectedTab]
|
|
586
537
|
.transactionReviewLocalDataById, transactionId, undefined);
|
|
587
538
|
if (transactionLocalData != null) {
|
|
@@ -634,8 +585,18 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
634
585
|
},
|
|
635
586
|
transactionId,
|
|
636
587
|
};
|
|
637
|
-
|
|
638
|
-
|
|
588
|
+
const selectedCheckBoxTransactionIds = draft.transactionCategorizationView[selectedTab]
|
|
589
|
+
.selectedCheckBoxTransactionIds;
|
|
590
|
+
if (newTransactionLocalData.vendor != null &&
|
|
591
|
+
newTransactionLocalData.vendor.id != null &&
|
|
592
|
+
(0, transactionCategorizationLocalDataHelper_1.checkIfAllLineItemsAreCategoryClassFilled)(selectedTransaction, newTransactionLocalData, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, isAccountingClassesEnabled) === true && // check if all line items are filled
|
|
593
|
+
selectedCheckBoxTransactionIds.length < transactionCategorizationLocalDataHelper_1.MAX_SELECTION_LIMIT &&
|
|
594
|
+
selectedCheckBoxTransactionIds.includes(transactionId) === false) {
|
|
595
|
+
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds = [
|
|
596
|
+
...selectedCheckBoxTransactionIds,
|
|
597
|
+
transactionId,
|
|
598
|
+
];
|
|
599
|
+
}
|
|
639
600
|
// Mark transaction as dirty (vendor updated)
|
|
640
601
|
if (!draft.transactionCategorizationView[selectedTab].transactionIdsWithUnsavedData.includes(transactionId)) {
|
|
641
602
|
draft.transactionCategorizationView[selectedTab].transactionIdsWithUnsavedData = [
|
|
@@ -848,54 +809,6 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
848
809
|
},
|
|
849
810
|
},
|
|
850
811
|
},
|
|
851
|
-
extraReducers: (builder) => {
|
|
852
|
-
// Start arm of the categorization-only recommendations fetch. Marks every
|
|
853
|
-
// affected line's per-line flag as In-Progress. The epic uses
|
|
854
|
-
// groupBy(transactionId+lineIds) + switchMap, so concurrent fetches for
|
|
855
|
-
// distinct (transaction, lineIds-set) targets do not cancel each other —
|
|
856
|
-
// there's no need for a global cleanup sweep here.
|
|
857
|
-
builder.addCase(recommendationReducer_1.fetchEntityRecommendationsForCategorization, (draft, action) => {
|
|
858
|
-
const { selectedTab, transactionDetails } = action.payload;
|
|
859
|
-
const { transactionId, lineIds } = transactionDetails;
|
|
860
|
-
const transactionLocalData = (0, get_1.default)(draft.transactionCategorizationView[selectedTab]
|
|
861
|
-
.transactionReviewLocalDataById, transactionId.id, undefined);
|
|
862
|
-
if (transactionLocalData != null) {
|
|
863
|
-
lineIds.forEach((lineId) => {
|
|
864
|
-
const lineItem = transactionLocalData.transactionReviewLocalData.lineItemById[lineId];
|
|
865
|
-
if (lineItem != null) {
|
|
866
|
-
transactionLocalData.transactionReviewLocalData.lineItemById[lineId] = {
|
|
867
|
-
...lineItem,
|
|
868
|
-
categoryClassRecommendationsFetchState: {
|
|
869
|
-
fetchState: 'In-Progress',
|
|
870
|
-
error: undefined,
|
|
871
|
-
},
|
|
872
|
-
};
|
|
873
|
-
}
|
|
874
|
-
});
|
|
875
|
-
}
|
|
876
|
-
});
|
|
877
|
-
// Failure arm. Flips the affected lines' per-line flag to Error so the
|
|
878
|
-
// skeleton resolves and the queued checkbox re-evaluation drops the entry.
|
|
879
|
-
builder.addCase(recommendationReducer_1.setCategoryClassRecommendationsForCategorizationFailure, (draft, action) => {
|
|
880
|
-
const { selectedTab, transactionId, lineIds, error } = action.payload;
|
|
881
|
-
const transactionLocalData = (0, get_1.default)(draft.transactionCategorizationView[selectedTab]
|
|
882
|
-
.transactionReviewLocalDataById, transactionId.id, undefined);
|
|
883
|
-
if (transactionLocalData != null) {
|
|
884
|
-
lineIds.forEach((lineId) => {
|
|
885
|
-
const lineItem = transactionLocalData.transactionReviewLocalData.lineItemById[lineId];
|
|
886
|
-
if (lineItem != null) {
|
|
887
|
-
transactionLocalData.transactionReviewLocalData.lineItemById[lineId] = {
|
|
888
|
-
...lineItem,
|
|
889
|
-
categoryClassRecommendationsFetchState: {
|
|
890
|
-
fetchState: 'Error',
|
|
891
|
-
error,
|
|
892
|
-
},
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
});
|
|
898
|
-
},
|
|
899
812
|
});
|
|
900
813
|
_a = expenseAutomationTransactionsView.actions, exports.fetchTransactionCategorization = _a.fetchTransactionCategorization, exports.updateTransactionCategorizationUIState = _a.updateTransactionCategorizationUIState, exports.initializeTransactionCategorizationViewLocalData = _a.initializeTransactionCategorizationViewLocalData, exports.saveTransactionCategorizationLocalData = _a.saveTransactionCategorizationLocalData, exports.fetchTransactionCategorizationFailure = _a.fetchTransactionCategorizationFailure, exports.saveTransactionCategorization = _a.saveTransactionCategorization, exports.updateTransactionCategorization = _a.updateTransactionCategorization, exports.updateCurrentSelectedTransactionCategorizationTab = _a.updateCurrentSelectedTransactionCategorizationTab, exports.updateTransactionCategorizationSaveStatus = _a.updateTransactionCategorizationSaveStatus, exports.markTransactionAsNotMiscategorized = _a.markTransactionAsNotMiscategorized, exports.updateStatusForTransactionNotMiscategorizedUpdateForCategorization = _a.updateStatusForTransactionNotMiscategorizedUpdateForCategorization, exports.updateSelectedVendorForTransaction = _a.updateSelectedVendorForTransaction, exports.updateSelectedCustomerForTransaction = _a.updateSelectedCustomerForTransaction, exports.setAllItemsToCategoryClassInLocalDataForCategorization = _a.setAllItemsToCategoryClassInLocalDataForCategorization, exports.updateTotalCountForTransactionCategorization = _a.updateTotalCountForTransactionCategorization, exports.fetchTransactionCategorizationSuccess = _a.fetchTransactionCategorizationSuccess, exports.resetOtherTabsFetchState = _a.resetOtherTabsFetchState, exports.fetchTransactionCategorizationView = _a.fetchTransactionCategorizationView, exports.updateSelectedCheckboxTransactionIds = _a.updateSelectedCheckboxTransactionIds, exports.clearExpenseAutomationTransactionsViewPerTabView = _a.clearExpenseAutomationTransactionsViewPerTabView, exports.clearExpenseAutomationTransactionsView = _a.clearExpenseAutomationTransactionsView, exports.setEntityRecommendationForLineIdsForCategorization = _a.setEntityRecommendationForLineIdsForCategorization, exports.updateSelectedTransactionId = _a.updateSelectedTransactionId, exports.syncTransactionCategorizationFromDetailSave = _a.syncTransactionCategorizationFromDetailSave, exports.backgroundRefetchReviewTab = _a.backgroundRefetchReviewTab, exports.updateTransactionCategorizationUploadReceiptState = _a.updateTransactionCategorizationUploadReceiptState, exports.uploadTransactionCategorizationReceiptSuccess = _a.uploadTransactionCategorizationReceiptSuccess;
|
|
901
814
|
exports.default = expenseAutomationTransactionsView.reducer;
|
|
@@ -19,7 +19,6 @@ export interface ExpenseAutomationTransactionViewSelector extends SelectorView {
|
|
|
19
19
|
classList: ClassBase[];
|
|
20
20
|
completionStatus: CompletionStatusType;
|
|
21
21
|
fetchStateByTransactionTabs: Record<TransactionsTab, FetchStateAndError>;
|
|
22
|
-
hasInFlightCategoryClassRecommendations: boolean;
|
|
23
22
|
isAccountingProjectsEnabled: boolean;
|
|
24
23
|
markAsNotMiscategorizedStatus: FetchStateAndError;
|
|
25
24
|
projectList: ProjectListSelectorView;
|
|
@@ -48,11 +48,6 @@ function getExpenseAutomationTransactionView(state) {
|
|
|
48
48
|
return null;
|
|
49
49
|
})
|
|
50
50
|
.filter((transaction) => transaction != null);
|
|
51
|
-
// True if any visible line is currently fetching category/class
|
|
52
|
-
// recommendations because the user changed the payee. Used to disable Save
|
|
53
|
-
// and to defer manual checkbox selection.
|
|
54
|
-
const hasInFlightCategoryClassRecommendations = transactionLocalData.some((transaction) => Object.values(transaction.transactionReviewLocalData.lineItemById).some((lineItem) => lineItem.categoryClassRecommendationsFetchState?.fetchState ===
|
|
55
|
-
'In-Progress'));
|
|
56
51
|
const transactions = (0, transactionSelector_1.getSupportedTransactionsByIds)(transactionState, transactionIds);
|
|
57
52
|
const transactionsWithCOT = transactions.map((transaction) => (0, transactionHelper_1.getTransactionWithCOT)(transaction));
|
|
58
53
|
const monthEndFetchState = monthYearPeriodId != null
|
|
@@ -123,6 +118,5 @@ function getExpenseAutomationTransactionView(state) {
|
|
|
123
118
|
uploadReceiptStatusById,
|
|
124
119
|
selectedTransactionId,
|
|
125
120
|
selectedTransactionLineId,
|
|
126
|
-
hasInFlightCategoryClassRecommendations,
|
|
127
121
|
};
|
|
128
122
|
}
|
|
@@ -46,7 +46,6 @@ export interface TransactionCategorizationLineItemData extends TransactionLineBa
|
|
|
46
46
|
transactionId: ID;
|
|
47
47
|
account?: AccountBase;
|
|
48
48
|
categorizationStatus?: CategorizationStatusType;
|
|
49
|
-
categoryClassRecommendationsFetchState?: FetchStateAndError;
|
|
50
49
|
class?: ClassBase;
|
|
51
50
|
customer?: CustomerBase;
|
|
52
51
|
item?: ProductOrService;
|
|
@@ -22,27 +22,7 @@ export declare const fetchEntityRecommendationsByTransactionId: import("@reduxjs
|
|
|
22
22
|
isTransactionCategorizationFlow: any;
|
|
23
23
|
isFetchCOT: any;
|
|
24
24
|
isUncategorizedExpenseCategoryEnabled: boolean | undefined;
|
|
25
|
-
}, "recommendation/fetchEntityRecommendationsByTransactionId", never, never>,
|
|
26
|
-
lineIds: ID[];
|
|
27
|
-
transaction: SupportedTransaction;
|
|
28
|
-
transactionId: TransactionID;
|
|
29
|
-
}, selectedTab: "review" | "autoCategorized", isFetchCOT?: any, isUncategorizedExpenseCategoryEnabled?: boolean | undefined], {
|
|
30
|
-
entity: Entity;
|
|
31
|
-
amount: number;
|
|
32
|
-
transactionDetails: {
|
|
33
|
-
lineIds: ID[];
|
|
34
|
-
transaction: SupportedTransaction;
|
|
35
|
-
transactionId: TransactionID;
|
|
36
|
-
};
|
|
37
|
-
selectedTab: "review" | "autoCategorized";
|
|
38
|
-
isFetchCOT: any;
|
|
39
|
-
isUncategorizedExpenseCategoryEnabled: boolean | undefined;
|
|
40
|
-
}, "recommendation/fetchEntityRecommendationsForCategorization", never, never>, setCategoryClassRecommendationsForCategorizationFailure: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[selectedTab: "review" | "autoCategorized", transactionId: TransactionID, lineIds: string[], error: ZeniAPIStatus<Record<string, unknown>>], {
|
|
41
|
-
selectedTab: "review" | "autoCategorized";
|
|
42
|
-
transactionId: TransactionID;
|
|
43
|
-
lineIds: string[];
|
|
44
|
-
error: ZeniAPIStatus<Record<string, unknown>>;
|
|
45
|
-
}, "recommendation/setCategoryClassRecommendationsForCategorizationFailure", never, never>, fetchRecommendationByEntityName: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[entityName: string, entityType: EntityType], {
|
|
25
|
+
}, "recommendation/fetchEntityRecommendationsByTransactionId", never, never>, fetchRecommendationByEntityName: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[entityName: string, entityType: EntityType], {
|
|
46
26
|
entityName: string;
|
|
47
27
|
entityType: EntityType;
|
|
48
28
|
}, "recommendation/fetchRecommendationByEntityName", never, never>, fetchRecommendationByEntityId: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[entityId: string, entityType: EntityType], {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var _a;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.clearRecommendation = exports.indicateReadyToInitializeRecommendation = exports.updateRecommendationForEntityFailure = exports.updateRecommendationForEntity = exports.fetchRecommendationByEntityId = exports.fetchRecommendationByEntityName = exports.
|
|
4
|
+
exports.clearRecommendation = exports.indicateReadyToInitializeRecommendation = exports.updateRecommendationForEntityFailure = exports.updateRecommendationForEntity = exports.fetchRecommendationByEntityId = exports.fetchRecommendationByEntityName = exports.fetchEntityRecommendationsByTransactionId = exports.initialState = void 0;
|
|
5
5
|
const toolkit_1 = require("@reduxjs/toolkit");
|
|
6
6
|
const recommendationState_1 = require("./recommendationState");
|
|
7
7
|
exports.initialState = {
|
|
@@ -110,63 +110,12 @@ const recommendation = (0, toolkit_1.createSlice)({
|
|
|
110
110
|
};
|
|
111
111
|
},
|
|
112
112
|
},
|
|
113
|
-
// Categorization-list-only fetch action. Mirrors the
|
|
114
|
-
// fetchEntityRecommendationsByTransactionId payload but is observed by a
|
|
115
|
-
// separate epic (with groupBy + switchMap, keyed on
|
|
116
|
-
// transactionId+lineIds-set) so concurrent fetches for distinct targets do
|
|
117
|
-
// not cancel each other. Reducer hooks in transactionsViewReducer use this
|
|
118
|
-
// to drive the per-line categoryClassRecommendationsFetchState flag.
|
|
119
|
-
fetchEntityRecommendationsForCategorization: {
|
|
120
|
-
reducer(draft, action) {
|
|
121
|
-
const { entity } = action.payload;
|
|
122
|
-
const key = (0, recommendationState_1.getEntityRecommendationKey)(entity.type, entity.id);
|
|
123
|
-
const existingRecommendation = draft.recommendationByEntity[key];
|
|
124
|
-
if (existingRecommendation == null) {
|
|
125
|
-
draft.recommendationByEntity[key] = {
|
|
126
|
-
...recommendationState_1.initialEntityRecommendationState,
|
|
127
|
-
fetchState: 'In-Progress',
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
prepare(entity, amount, transactionDetails, selectedTab, isFetchCOT = false, isUncategorizedExpenseCategoryEnabled) {
|
|
132
|
-
return {
|
|
133
|
-
payload: {
|
|
134
|
-
entity,
|
|
135
|
-
amount,
|
|
136
|
-
transactionDetails,
|
|
137
|
-
selectedTab,
|
|
138
|
-
isFetchCOT,
|
|
139
|
-
isUncategorizedExpenseCategoryEnabled,
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
setCategoryClassRecommendationsForCategorizationFailure: {
|
|
145
|
-
reducer(
|
|
146
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
147
|
-
_draft,
|
|
148
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
149
|
-
_action) {
|
|
150
|
-
// The transactionsViewReducer handles the per-line flag flip; this
|
|
151
|
-
// reducer slice has no recommendation cache to update for the failure.
|
|
152
|
-
},
|
|
153
|
-
prepare(selectedTab, transactionId, lineIds, error) {
|
|
154
|
-
return {
|
|
155
|
-
payload: {
|
|
156
|
-
selectedTab,
|
|
157
|
-
transactionId,
|
|
158
|
-
lineIds,
|
|
159
|
-
error,
|
|
160
|
-
},
|
|
161
|
-
};
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
113
|
clearRecommendation(draft) {
|
|
165
114
|
Object.assign(draft, exports.initialState);
|
|
166
115
|
},
|
|
167
116
|
},
|
|
168
117
|
});
|
|
169
|
-
_a = recommendation.actions, exports.fetchEntityRecommendationsByTransactionId = _a.fetchEntityRecommendationsByTransactionId, exports.
|
|
118
|
+
_a = recommendation.actions, exports.fetchEntityRecommendationsByTransactionId = _a.fetchEntityRecommendationsByTransactionId, exports.fetchRecommendationByEntityName = _a.fetchRecommendationByEntityName, exports.fetchRecommendationByEntityId = _a.fetchRecommendationByEntityId, exports.updateRecommendationForEntity = _a.updateRecommendationForEntity, exports.updateRecommendationForEntityFailure = _a.updateRecommendationForEntityFailure, exports.indicateReadyToInitializeRecommendation = _a.indicateReadyToInitializeRecommendation, exports.clearRecommendation = _a.clearRecommendation;
|
|
170
119
|
exports.default = recommendation.reducer;
|
|
171
120
|
const doUpdateRecommendationForEntity = (draft, entityId, entityType, payload) => {
|
|
172
121
|
const key = (0, recommendationState_1.getEntityRecommendationKey)(entityType, entityId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeniai/client-epic-state",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.54",
|
|
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",
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { from, of } from 'rxjs';
|
|
2
|
-
import { catchError, filter, groupBy, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
|
-
import { getIsAccountingClassesEnabled } from '../../entity/tenant/tenantSelector';
|
|
4
|
-
import { getTransactionWithCOT, getTransactionWithCOTFromRecommendations, } from '../../entity/transaction/transactionHelper';
|
|
5
|
-
import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
|
|
6
|
-
import { setEntityRecommendationForLineIdsForCategorization } from '../../view/expenseAutomationView/reducers/transactionsViewReducer';
|
|
7
|
-
import { getUncategorizedAccounts } from '../accountList/accountListSelector';
|
|
8
|
-
import { getActualTransactionID } from '../transactionDetail/transactionDetailState';
|
|
9
|
-
import { getRecommendationByLineIdWithCOTFromRecommendationPayloadWithCOT, getRecommendationFromRecommendationPayload, } from './recommendationHelper';
|
|
10
|
-
import { fetchEntityRecommendationsForCategorization, setCategoryClassRecommendationsForCategorizationFailure, updateRecommendationForEntity, } from './recommendationReducer';
|
|
11
|
-
// Categorization-list-only recommendations fetch.
|
|
12
|
-
//
|
|
13
|
-
// Concurrency model: groupBy on (transactionId.id, sorted lineIds) → switchMap
|
|
14
|
-
// inside each group → mergeMap to flatten groups. This means:
|
|
15
|
-
// • Same target (same transaction + same lineIds-set) — newer fetch cancels
|
|
16
|
-
// the prior in-flight fetch. Avoids the same-line stale-response race.
|
|
17
|
-
// • Different targets — run fully in parallel. Avoids the silent
|
|
18
|
-
// "stuck spinner" cancellation that the global-switchMap epic suffers
|
|
19
|
-
// from when the user moves between rows or JE lines mid-flight.
|
|
20
|
-
//
|
|
21
|
-
// The transactionsViewReducer's per-line categoryClassRecommendationsFetchState
|
|
22
|
-
// flag is set to In-Progress when the action enters this epic (start arm in
|
|
23
|
-
// extraReducers), Completed via setEntityRecommendationForLineIdsForCategorization,
|
|
24
|
-
// or Error via setCategoryClassRecommendationsForCategorizationFailure.
|
|
25
|
-
export const fetchEntityRecommendationsForCategorizationEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchEntityRecommendationsForCategorization.match), groupBy((action) => {
|
|
26
|
-
const { transactionId, lineIds } = action.payload.transactionDetails;
|
|
27
|
-
return `${transactionId.id}|${[...lineIds].sort().join('|')}`;
|
|
28
|
-
}), mergeMap((group$) => group$.pipe(switchMap((action) => {
|
|
29
|
-
const { entity, amount, transactionDetails, isFetchCOT, selectedTab, isUncategorizedExpenseCategoryEnabled, } = action.payload;
|
|
30
|
-
const query = {
|
|
31
|
-
amount,
|
|
32
|
-
transaction_id: getActualTransactionID(transactionDetails.transactionId.id),
|
|
33
|
-
transaction_type: transactionDetails.transaction.type,
|
|
34
|
-
line_ids: transactionDetails.lineIds,
|
|
35
|
-
};
|
|
36
|
-
if (isFetchCOT === true) {
|
|
37
|
-
query.include_cot = true;
|
|
38
|
-
}
|
|
39
|
-
const entityQuery = {
|
|
40
|
-
entity_name: entity.name,
|
|
41
|
-
entity_type: entity.type,
|
|
42
|
-
};
|
|
43
|
-
const recommendationUrl = entity.qboId === entity.name // entity id null case
|
|
44
|
-
? `${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/recommendations?query=${encodeURIComponent(JSON.stringify(entityQuery))}`
|
|
45
|
-
: `${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/${toEntityTypeURL(entity.type)}/${entity.qboId}/recommendations?query=${encodeURIComponent(JSON.stringify(query))}`;
|
|
46
|
-
return zeniAPI
|
|
47
|
-
.getJSON(recommendationUrl)
|
|
48
|
-
.pipe(mergeMap((response) => {
|
|
49
|
-
if (isSuccessResponse(response) && response.data != null) {
|
|
50
|
-
const actions = [];
|
|
51
|
-
const { transactionId, transaction, lineIds } = transactionDetails;
|
|
52
|
-
const recommendationWithCOTByLineId = getRecommendationByLineIdWithCOTFromRecommendationPayloadWithCOT(response.data.recommendations, lineIds);
|
|
53
|
-
const recommendations = getRecommendationFromRecommendationPayload(response.data.recommendations);
|
|
54
|
-
const transactionWithCOT = isFetchCOT === true &&
|
|
55
|
-
recommendationWithCOTByLineId != null
|
|
56
|
-
? getTransactionWithCOTFromRecommendations(transaction, recommendationWithCOTByLineId)
|
|
57
|
-
: getTransactionWithCOT(transaction);
|
|
58
|
-
actions.push(updateRecommendationForEntity({
|
|
59
|
-
entityId: entity.id,
|
|
60
|
-
entityType: entity.type,
|
|
61
|
-
recommendations,
|
|
62
|
-
}));
|
|
63
|
-
if (recommendationWithCOTByLineId != null) {
|
|
64
|
-
const uncategorizedIncomeExpense = getUncategorizedAccounts(state$.value.accountState, state$.value.accountListState, 'accountList');
|
|
65
|
-
actions.push(setEntityRecommendationForLineIdsForCategorization(selectedTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled, getIsAccountingClassesEnabled(state$.value)));
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
// Successful HTTP but no per-line recommendations — still
|
|
69
|
-
// need to clear the In-Progress flag, otherwise the
|
|
70
|
-
// skeleton sticks. Treat as a "no recommendations" success
|
|
71
|
-
// by firing the failure action with a benign error so the
|
|
72
|
-
// line flag flips out of In-Progress.
|
|
73
|
-
actions.push(setCategoryClassRecommendationsForCategorizationFailure(selectedTab, transactionId, lineIds, createZeniAPIStatus('Unexpected Error', 'Recommendations response missing per-line data')));
|
|
74
|
-
}
|
|
75
|
-
return from(actions);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
return of(setCategoryClassRecommendationsForCategorizationFailure(selectedTab, transactionDetails.transactionId, transactionDetails.lineIds, response.status));
|
|
79
|
-
}
|
|
80
|
-
}), catchError((error) => of(setCategoryClassRecommendationsForCategorizationFailure(selectedTab, transactionDetails.transactionId, transactionDetails.lineIds, createZeniAPIStatus('Unexpected Error', 'Fetch recommendations for categorization REST API call errored out' +
|
|
81
|
-
JSON.stringify(error))))));
|
|
82
|
-
}))));
|
|
83
|
-
const toEntityTypeURL = (entityType) => `${entityType}s`;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
|
-
import { Observable } from 'rxjs';
|
|
3
|
-
import { RootState } from '../../reducer';
|
|
4
|
-
import { setEntityRecommendationForLineIdsForCategorization } from '../../view/expenseAutomationView/reducers/transactionsViewReducer';
|
|
5
|
-
import { ZeniAPI } from '../../zeniAPI';
|
|
6
|
-
import { fetchEntityRecommendationsForCategorization, setCategoryClassRecommendationsForCategorizationFailure, updateRecommendationForEntity } from './recommendationReducer';
|
|
7
|
-
export type ActionType = ReturnType<typeof updateRecommendationForEntity> | ReturnType<typeof fetchEntityRecommendationsForCategorization> | ReturnType<typeof setCategoryClassRecommendationsForCategorizationFailure> | ReturnType<typeof setEntityRecommendationForLineIdsForCategorization>;
|
|
8
|
-
export declare const fetchEntityRecommendationsForCategorizationEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fetchEntityRecommendationsForCategorizationEpic = void 0;
|
|
4
|
-
const rxjs_1 = require("rxjs");
|
|
5
|
-
const operators_1 = require("rxjs/operators");
|
|
6
|
-
const tenantSelector_1 = require("../../entity/tenant/tenantSelector");
|
|
7
|
-
const transactionHelper_1 = require("../../entity/transaction/transactionHelper");
|
|
8
|
-
const responsePayload_1 = require("../../responsePayload");
|
|
9
|
-
const transactionsViewReducer_1 = require("../../view/expenseAutomationView/reducers/transactionsViewReducer");
|
|
10
|
-
const accountListSelector_1 = require("../accountList/accountListSelector");
|
|
11
|
-
const transactionDetailState_1 = require("../transactionDetail/transactionDetailState");
|
|
12
|
-
const recommendationHelper_1 = require("./recommendationHelper");
|
|
13
|
-
const recommendationReducer_1 = require("./recommendationReducer");
|
|
14
|
-
// Categorization-list-only recommendations fetch.
|
|
15
|
-
//
|
|
16
|
-
// Concurrency model: groupBy on (transactionId.id, sorted lineIds) → switchMap
|
|
17
|
-
// inside each group → mergeMap to flatten groups. This means:
|
|
18
|
-
// • Same target (same transaction + same lineIds-set) — newer fetch cancels
|
|
19
|
-
// the prior in-flight fetch. Avoids the same-line stale-response race.
|
|
20
|
-
// • Different targets — run fully in parallel. Avoids the silent
|
|
21
|
-
// "stuck spinner" cancellation that the global-switchMap epic suffers
|
|
22
|
-
// from when the user moves between rows or JE lines mid-flight.
|
|
23
|
-
//
|
|
24
|
-
// The transactionsViewReducer's per-line categoryClassRecommendationsFetchState
|
|
25
|
-
// flag is set to In-Progress when the action enters this epic (start arm in
|
|
26
|
-
// extraReducers), Completed via setEntityRecommendationForLineIdsForCategorization,
|
|
27
|
-
// or Error via setCategoryClassRecommendationsForCategorizationFailure.
|
|
28
|
-
const fetchEntityRecommendationsForCategorizationEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(recommendationReducer_1.fetchEntityRecommendationsForCategorization.match), (0, operators_1.groupBy)((action) => {
|
|
29
|
-
const { transactionId, lineIds } = action.payload.transactionDetails;
|
|
30
|
-
return `${transactionId.id}|${[...lineIds].sort().join('|')}`;
|
|
31
|
-
}), (0, operators_1.mergeMap)((group$) => group$.pipe((0, operators_1.switchMap)((action) => {
|
|
32
|
-
const { entity, amount, transactionDetails, isFetchCOT, selectedTab, isUncategorizedExpenseCategoryEnabled, } = action.payload;
|
|
33
|
-
const query = {
|
|
34
|
-
amount,
|
|
35
|
-
transaction_id: (0, transactionDetailState_1.getActualTransactionID)(transactionDetails.transactionId.id),
|
|
36
|
-
transaction_type: transactionDetails.transaction.type,
|
|
37
|
-
line_ids: transactionDetails.lineIds,
|
|
38
|
-
};
|
|
39
|
-
if (isFetchCOT === true) {
|
|
40
|
-
query.include_cot = true;
|
|
41
|
-
}
|
|
42
|
-
const entityQuery = {
|
|
43
|
-
entity_name: entity.name,
|
|
44
|
-
entity_type: entity.type,
|
|
45
|
-
};
|
|
46
|
-
const recommendationUrl = entity.qboId === entity.name // entity id null case
|
|
47
|
-
? `${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/recommendations?query=${encodeURIComponent(JSON.stringify(entityQuery))}`
|
|
48
|
-
: `${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/${toEntityTypeURL(entity.type)}/${entity.qboId}/recommendations?query=${encodeURIComponent(JSON.stringify(query))}`;
|
|
49
|
-
return zeniAPI
|
|
50
|
-
.getJSON(recommendationUrl)
|
|
51
|
-
.pipe((0, operators_1.mergeMap)((response) => {
|
|
52
|
-
if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
|
|
53
|
-
const actions = [];
|
|
54
|
-
const { transactionId, transaction, lineIds } = transactionDetails;
|
|
55
|
-
const recommendationWithCOTByLineId = (0, recommendationHelper_1.getRecommendationByLineIdWithCOTFromRecommendationPayloadWithCOT)(response.data.recommendations, lineIds);
|
|
56
|
-
const recommendations = (0, recommendationHelper_1.getRecommendationFromRecommendationPayload)(response.data.recommendations);
|
|
57
|
-
const transactionWithCOT = isFetchCOT === true &&
|
|
58
|
-
recommendationWithCOTByLineId != null
|
|
59
|
-
? (0, transactionHelper_1.getTransactionWithCOTFromRecommendations)(transaction, recommendationWithCOTByLineId)
|
|
60
|
-
: (0, transactionHelper_1.getTransactionWithCOT)(transaction);
|
|
61
|
-
actions.push((0, recommendationReducer_1.updateRecommendationForEntity)({
|
|
62
|
-
entityId: entity.id,
|
|
63
|
-
entityType: entity.type,
|
|
64
|
-
recommendations,
|
|
65
|
-
}));
|
|
66
|
-
if (recommendationWithCOTByLineId != null) {
|
|
67
|
-
const uncategorizedIncomeExpense = (0, accountListSelector_1.getUncategorizedAccounts)(state$.value.accountState, state$.value.accountListState, 'accountList');
|
|
68
|
-
actions.push((0, transactionsViewReducer_1.setEntityRecommendationForLineIdsForCategorization)(selectedTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled, (0, tenantSelector_1.getIsAccountingClassesEnabled)(state$.value)));
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
// Successful HTTP but no per-line recommendations — still
|
|
72
|
-
// need to clear the In-Progress flag, otherwise the
|
|
73
|
-
// skeleton sticks. Treat as a "no recommendations" success
|
|
74
|
-
// by firing the failure action with a benign error so the
|
|
75
|
-
// line flag flips out of In-Progress.
|
|
76
|
-
actions.push((0, recommendationReducer_1.setCategoryClassRecommendationsForCategorizationFailure)(selectedTab, transactionId, lineIds, (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Recommendations response missing per-line data')));
|
|
77
|
-
}
|
|
78
|
-
return (0, rxjs_1.from)(actions);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
return (0, rxjs_1.of)((0, recommendationReducer_1.setCategoryClassRecommendationsForCategorizationFailure)(selectedTab, transactionDetails.transactionId, transactionDetails.lineIds, response.status));
|
|
82
|
-
}
|
|
83
|
-
}), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, recommendationReducer_1.setCategoryClassRecommendationsForCategorizationFailure)(selectedTab, transactionDetails.transactionId, transactionDetails.lineIds, (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Fetch recommendations for categorization REST API call errored out' +
|
|
84
|
-
JSON.stringify(error))))));
|
|
85
|
-
}))));
|
|
86
|
-
exports.fetchEntityRecommendationsForCategorizationEpic = fetchEntityRecommendationsForCategorizationEpic;
|
|
87
|
-
const toEntityTypeURL = (entityType) => `${entityType}s`;
|