@zeniai/client-epic-state 5.1.49 → 5.1.50-beta3RR
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/aiCfo/aiCfoPayload.d.ts +1 -0
- package/lib/entity/aiCfo/aiCfoReducer.js +3 -1
- package/lib/entity/aiCfo/aiCfoState.d.ts +1 -0
- package/lib/esm/entity/aiCfo/aiCfoReducer.js +3 -1
- package/lib/esm/view/transactionDetail/epics/markTransactionAsNotMiscategorizedEpic.js +85 -39
- package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +25 -66
- package/lib/esm/view/transactionDetail/transactionDetailReducer.js +2 -1
- package/lib/view/transactionDetail/epics/markTransactionAsNotMiscategorizedEpic.js +84 -38
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +24 -65
- package/lib/view/transactionDetail/transactionDetailReducer.d.ts +2 -1
- package/lib/view/transactionDetail/transactionDetailReducer.js +2 -1
- package/package.json +1 -1
|
@@ -102,6 +102,7 @@ export interface AiCfoAnswerPayload {
|
|
|
102
102
|
artifact_host_url?: string | null;
|
|
103
103
|
artifact_title?: string | null;
|
|
104
104
|
follow_up_questions?: string[];
|
|
105
|
+
suggested_reply?: string | null;
|
|
105
106
|
table?: AiCfoVisualizationPayload | null;
|
|
106
107
|
}
|
|
107
108
|
export interface ChatSessionPayload {
|
|
@@ -112,6 +112,7 @@ function chatHistoryToQA(history) {
|
|
|
112
112
|
followUpQuestions: Array.isArray(parsedAgentMessage.follow_up_questions)
|
|
113
113
|
? parsedAgentMessage.follow_up_questions
|
|
114
114
|
: [],
|
|
115
|
+
suggestedReply: parsedAgentMessage.suggested_reply ?? undefined,
|
|
115
116
|
assumptions: parsedAgentMessage.assumptions ?? '',
|
|
116
117
|
insights: parsedAgentMessage.insights ?? '',
|
|
117
118
|
summarizedTitle: parsedAgentMessage.summarized_title ?? undefined,
|
|
@@ -351,7 +352,7 @@ const toAiCfoVisualizationData = (data) => {
|
|
|
351
352
|
};
|
|
352
353
|
};
|
|
353
354
|
const toResponseBlockType = (answer, userId) => {
|
|
354
|
-
const { metadata, state, type, text, visualization, table, follow_up_questions, assumptions, insights, summarized_title, artifact, artifact_title, artifact_host_url, } = answer;
|
|
355
|
+
const { metadata, state, type, text, visualization, table, follow_up_questions, suggested_reply, assumptions, insights, summarized_title, artifact, artifact_title, artifact_host_url, } = answer;
|
|
355
356
|
const { chat_session_id, message_id, timestamp, chain_of_thought_action_steps: chainOfThoughtActionSteps = [], } = metadata;
|
|
356
357
|
return {
|
|
357
358
|
messageId: message_id,
|
|
@@ -365,6 +366,7 @@ const toResponseBlockType = (answer, userId) => {
|
|
|
365
366
|
visualization: visualization != null ? (0, exports.toAiCfoVisualization)(visualization) : undefined,
|
|
366
367
|
table: table != null ? (0, exports.toAiCfoVisualization)(table) : undefined,
|
|
367
368
|
followUpQuestions: follow_up_questions ?? [],
|
|
369
|
+
suggestedReply: suggested_reply ?? undefined,
|
|
368
370
|
assumptions: assumptions ?? '',
|
|
369
371
|
insights: insights ?? '',
|
|
370
372
|
summarizedTitle: summarized_title ?? undefined,
|
|
@@ -108,6 +108,7 @@ function chatHistoryToQA(history) {
|
|
|
108
108
|
followUpQuestions: Array.isArray(parsedAgentMessage.follow_up_questions)
|
|
109
109
|
? parsedAgentMessage.follow_up_questions
|
|
110
110
|
: [],
|
|
111
|
+
suggestedReply: parsedAgentMessage.suggested_reply ?? undefined,
|
|
111
112
|
assumptions: parsedAgentMessage.assumptions ?? '',
|
|
112
113
|
insights: parsedAgentMessage.insights ?? '',
|
|
113
114
|
summarizedTitle: parsedAgentMessage.summarized_title ?? undefined,
|
|
@@ -346,7 +347,7 @@ const toAiCfoVisualizationData = (data) => {
|
|
|
346
347
|
};
|
|
347
348
|
};
|
|
348
349
|
const toResponseBlockType = (answer, userId) => {
|
|
349
|
-
const { metadata, state, type, text, visualization, table, follow_up_questions, assumptions, insights, summarized_title, artifact, artifact_title, artifact_host_url, } = answer;
|
|
350
|
+
const { metadata, state, type, text, visualization, table, follow_up_questions, suggested_reply, assumptions, insights, summarized_title, artifact, artifact_title, artifact_host_url, } = answer;
|
|
350
351
|
const { chat_session_id, message_id, timestamp, chain_of_thought_action_steps: chainOfThoughtActionSteps = [], } = metadata;
|
|
351
352
|
return {
|
|
352
353
|
messageId: message_id,
|
|
@@ -360,6 +361,7 @@ const toResponseBlockType = (answer, userId) => {
|
|
|
360
361
|
visualization: visualization != null ? toAiCfoVisualization(visualization) : undefined,
|
|
361
362
|
table: table != null ? toAiCfoVisualization(table) : undefined,
|
|
362
363
|
followUpQuestions: follow_up_questions ?? [],
|
|
364
|
+
suggestedReply: suggested_reply ?? undefined,
|
|
363
365
|
assumptions: assumptions ?? '',
|
|
364
366
|
insights: insights ?? '',
|
|
365
367
|
summarizedTitle: summarized_title ?? undefined,
|
|
@@ -4,11 +4,95 @@ import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
|
4
4
|
import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
5
5
|
import { getCurrentTenant } from '../../../entity/tenant/tenantSelector';
|
|
6
6
|
import { removeTransactionCategorization, updateTransactionIsMiscategorized, } from '../../../entity/transaction/transactionReducer';
|
|
7
|
-
import {
|
|
7
|
+
import { getSupportedTransactionById } from '../../../entity/transaction/transactionSelector';
|
|
8
|
+
import { createZeniAPIStatus, isSuccessResponse, isSuccessStatus, } from '../../../responsePayload';
|
|
8
9
|
import { updateStatusForTransactionNotMiscategorizedUpdateForCategorization, updateTotalCountForTransactionCategorization, } from '../../expenseAutomationView/reducers/transactionsViewReducer';
|
|
9
10
|
import { markTransactionAsNotMiscategorized, updateStatusConsolidatedSaveTransactionDetail, updateStatusForTransactionNotMiscategorizedUpdate, } from '../transactionDetailReducer';
|
|
10
11
|
import { getTransactionDetailKey } from '../transactionDetailState';
|
|
11
12
|
export const markTransactionAsNotMiscategorizedEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(markTransactionAsNotMiscategorized.match), mergeMap((action) => {
|
|
13
|
+
if (action.payload.isExpenseAutomationEnabled === true) {
|
|
14
|
+
const transactionKey = getTransactionDetailKey(action.payload.transactionId);
|
|
15
|
+
const transaction = getSupportedTransactionById(state$.value.transactionState, transactionKey);
|
|
16
|
+
const lineIds = (action.payload.lineIds?.length ?? 0) > 0
|
|
17
|
+
? action.payload.lineIds
|
|
18
|
+
: (transaction?.lines ?? []).map((line) => line.id);
|
|
19
|
+
return zeniAPI
|
|
20
|
+
.putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/expense-automation/mark-as-reviewed`, {
|
|
21
|
+
transactions_reviewed: [
|
|
22
|
+
{
|
|
23
|
+
transaction_id: action.payload.transactionId.id,
|
|
24
|
+
line_ids: lineIds,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
})
|
|
28
|
+
.pipe(mergeMap((response) => {
|
|
29
|
+
if (isSuccessResponse(response)) {
|
|
30
|
+
const actions = [];
|
|
31
|
+
actions.push(updateStatusForTransactionNotMiscategorizedUpdate(action.payload.transactionId, 'Completed', undefined));
|
|
32
|
+
const txnId = action.payload.transactionId.id;
|
|
33
|
+
const reviewedFailed = response.data?.transactions_reviewed_failed ?? [];
|
|
34
|
+
const isTransactionFailed = reviewedFailed.some((t) => t.transaction_id === txnId);
|
|
35
|
+
if (!isTransactionFailed) {
|
|
36
|
+
actions.push(updateTransactionIsMiscategorized(transactionKey, false));
|
|
37
|
+
const { expenseAutomationViewState, expenseAutomationTransactionsViewState, } = state$.value;
|
|
38
|
+
const { transactionCategorizationView, selectedTransactionCategorizationTab, } = expenseAutomationTransactionsViewState;
|
|
39
|
+
const currentTenant = getCurrentTenant(state$.value);
|
|
40
|
+
const { selectedPeriodByTenantId } = expenseAutomationViewState;
|
|
41
|
+
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
42
|
+
const autoTabLineItems = transactionCategorizationView.autoCategorized
|
|
43
|
+
.transactionReviewLocalDataById[txnId]
|
|
44
|
+
?.transactionReviewLocalData.tabSpecificLineItems
|
|
45
|
+
.autoCategorized ?? [];
|
|
46
|
+
const hasAutoLines = autoTabLineItems.length > 0;
|
|
47
|
+
const { uiState } = transactionCategorizationView[selectedTransactionCategorizationTab];
|
|
48
|
+
const removeIdsFromPeriod = selectedTransactionCategorizationTab === 'review'
|
|
49
|
+
? [txnId]
|
|
50
|
+
: hasAutoLines
|
|
51
|
+
? []
|
|
52
|
+
: [txnId];
|
|
53
|
+
actions.push(updateStatusForTransactionNotMiscategorizedUpdateForCategorization(selectedTransactionCategorizationTab, [txnId], removeIdsFromPeriod, selectedPeriod, 'Completed'));
|
|
54
|
+
if (!hasAutoLines) {
|
|
55
|
+
actions.push(removeTransactionCategorization({
|
|
56
|
+
transactionIds: [txnId],
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
if (removeIdsFromPeriod.length > 0) {
|
|
60
|
+
const totalCountByPeriod = uiState.totalCount[toMonthYearPeriodId(selectedPeriod)];
|
|
61
|
+
const updatedTotalCount = totalCountByPeriod === 0
|
|
62
|
+
? totalCountByPeriod
|
|
63
|
+
: totalCountByPeriod - 1;
|
|
64
|
+
actions.push(updateTotalCountForTransactionCategorization({
|
|
65
|
+
selectedPeriod,
|
|
66
|
+
selectedTab: selectedTransactionCategorizationTab,
|
|
67
|
+
totalCount: updatedTotalCount,
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
actions.push(updateStatusConsolidatedSaveTransactionDetail({
|
|
72
|
+
transactionId: action.payload.transactionId,
|
|
73
|
+
fetchState: 'Completed',
|
|
74
|
+
}));
|
|
75
|
+
if (action.payload.transactionSaveUpdates.anyBulkUpdates === true) {
|
|
76
|
+
actions.push(openSnackbar({
|
|
77
|
+
messageSection: 'transactionDetails_updatingPastTransactions',
|
|
78
|
+
messageText: 'success',
|
|
79
|
+
type: 'success',
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
actions.push(openSnackbar({
|
|
84
|
+
messageSection: 'transactionDetails_transactionUpdated',
|
|
85
|
+
messageText: 'success',
|
|
86
|
+
type: 'success',
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
return from(actions);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
return of(updateStatusForTransactionNotMiscategorizedUpdate(action.payload.transactionId, 'Error', response.status));
|
|
93
|
+
}
|
|
94
|
+
}), catchError((error) => of(updateStatusForTransactionNotMiscategorizedUpdate(action.payload.transactionId, 'Error', createZeniAPIStatus('Unexpected Error', `Transaction mark as reviewed REST API call errored out ${error}`)))));
|
|
95
|
+
}
|
|
12
96
|
return zeniAPI
|
|
13
97
|
.putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${action.payload.transactionId.id}/mark-miscategorized-as-correct`, preparePayload(action.payload.transactionId))
|
|
14
98
|
.pipe(mergeMap((response) => {
|
|
@@ -16,44 +100,7 @@ export const markTransactionAsNotMiscategorizedEpic = (actions$, state$, zeniAPI
|
|
|
16
100
|
const actions = [];
|
|
17
101
|
actions.push(updateStatusForTransactionNotMiscategorizedUpdate(action.payload.transactionId, 'Completed', undefined));
|
|
18
102
|
const transactionKey = getTransactionDetailKey(action.payload.transactionId);
|
|
19
|
-
// Mark this transaction as not miscategorized anymore
|
|
20
103
|
actions.push(updateTransactionIsMiscategorized(transactionKey, false));
|
|
21
|
-
if (action.payload.isExpenseAutomationEnabled === true) {
|
|
22
|
-
const { expenseAutomationViewState, expenseAutomationTransactionsViewState, } = state$.value;
|
|
23
|
-
const { transactionCategorizationView, selectedTransactionCategorizationTab, } = expenseAutomationTransactionsViewState;
|
|
24
|
-
const currentTenant = getCurrentTenant(state$.value);
|
|
25
|
-
const { selectedPeriodByTenantId } = expenseAutomationViewState;
|
|
26
|
-
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
27
|
-
const txnId = action.payload.transactionId.id;
|
|
28
|
-
const autoTabLineItems = transactionCategorizationView.autoCategorized
|
|
29
|
-
.transactionReviewLocalDataById[txnId]
|
|
30
|
-
?.transactionReviewLocalData.tabSpecificLineItems
|
|
31
|
-
.autoCategorized ?? [];
|
|
32
|
-
const hasAutoLines = autoTabLineItems.length > 0;
|
|
33
|
-
const { uiState } = transactionCategorizationView[selectedTransactionCategorizationTab];
|
|
34
|
-
const removeIdsFromPeriod = selectedTransactionCategorizationTab === 'review'
|
|
35
|
-
? [txnId]
|
|
36
|
-
: hasAutoLines
|
|
37
|
-
? []
|
|
38
|
-
: [txnId];
|
|
39
|
-
actions.push(updateStatusForTransactionNotMiscategorizedUpdateForCategorization(selectedTransactionCategorizationTab, [txnId], removeIdsFromPeriod, selectedPeriod, 'Completed'));
|
|
40
|
-
if (!hasAutoLines) {
|
|
41
|
-
actions.push(removeTransactionCategorization({
|
|
42
|
-
transactionIds: [txnId],
|
|
43
|
-
}));
|
|
44
|
-
}
|
|
45
|
-
if (removeIdsFromPeriod.length > 0) {
|
|
46
|
-
const totalCountByPeriod = uiState.totalCount[toMonthYearPeriodId(selectedPeriod)];
|
|
47
|
-
const updatedTotalCount = totalCountByPeriod === 0
|
|
48
|
-
? totalCountByPeriod
|
|
49
|
-
: totalCountByPeriod - 1;
|
|
50
|
-
actions.push(updateTotalCountForTransactionCategorization({
|
|
51
|
-
selectedPeriod,
|
|
52
|
-
selectedTab: selectedTransactionCategorizationTab,
|
|
53
|
-
totalCount: updatedTotalCount,
|
|
54
|
-
}));
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
104
|
actions.push(updateStatusConsolidatedSaveTransactionDetail({
|
|
58
105
|
transactionId: action.payload.transactionId,
|
|
59
106
|
fetchState: 'Completed',
|
|
@@ -66,7 +113,6 @@ export const markTransactionAsNotMiscategorizedEpic = (actions$, state$, zeniAPI
|
|
|
66
113
|
}));
|
|
67
114
|
}
|
|
68
115
|
else {
|
|
69
|
-
//Finally everything done for this transaction
|
|
70
116
|
actions.push(openSnackbar({
|
|
71
117
|
messageSection: 'transactionDetails_transactionUpdated',
|
|
72
118
|
messageText: 'success',
|
|
@@ -10,7 +10,6 @@ import { injectCOTFlagsIntoTransactionPayload, toTransactionPayload, } from '../
|
|
|
10
10
|
import { toVendorTransactionPayload, toVendorTransactionWithCustomerPayload, } from '../../../entity/transaction/payloadTypes/vendorTransactionPayload';
|
|
11
11
|
import { isCustomerTransaction, } from '../../../entity/transaction/stateTypes/customerTransaction';
|
|
12
12
|
import { isTransferTransaction, } from '../../../entity/transaction/stateTypes/otherTransaction';
|
|
13
|
-
import { toJEAndDepositTransactionTypeStrict, toVendorTransactionTypeStrict, } from '../../../entity/transaction/stateTypes/transactionType';
|
|
14
13
|
import { isVendorTransaction, } from '../../../entity/transaction/stateTypes/vendorTransaction';
|
|
15
14
|
import toSupportedTransaction from '../../../entity/transaction/toSupportedTransaction';
|
|
16
15
|
import { getTransactionWithCOT } from '../../../entity/transaction/transactionHelper';
|
|
@@ -20,12 +19,12 @@ import { updateVendors } from '../../../entity/vendor/vendorReducer';
|
|
|
20
19
|
import { getVendorByVendorId } from '../../../entity/vendor/vendorSelector';
|
|
21
20
|
import { createZeniAPIStatus, isActionNotAllowed, isSuccessResponse, } from '../../../responsePayload';
|
|
22
21
|
import { getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, } from '../../../entity/tenant/tenantSelector';
|
|
23
|
-
import { getUncategorizedAccounts } from '../../accountList/accountListSelector';
|
|
22
|
+
import { getUncategorizedAccounts, } from '../../accountList/accountListSelector';
|
|
24
23
|
import { getPendingReviewLineIdsFromTransaction } from '../../expenseAutomationView/helpers/transactionCategorizationLocalDataHelper';
|
|
25
24
|
import { syncTransactionCategorizationFromDetailSave } from '../../expenseAutomationView/reducers/transactionsViewReducer';
|
|
26
25
|
import { initializeTransactionDetailLocalData, markTransactionAsNotMiscategorized, updateStatusConsolidatedSaveTransactionDetail, updateTransactionDetail, updateTransactionDetailSaveStatus, updateTransactionStateIfUpdateActionNotAllowed, } from '../transactionDetailReducer';
|
|
27
26
|
import { getTransactionDetailKey, } from '../transactionDetailState';
|
|
28
|
-
import {
|
|
27
|
+
import { isAccountUncategorized } from '../transactionDetailLocalDataHelper';
|
|
29
28
|
export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(updateTransactionDetail.match), mergeMap((action) => {
|
|
30
29
|
const { transactionState, vendorState, transactionDetailState } = state$.value;
|
|
31
30
|
const isAccountingProjectsEnabled = getIsAccountingProjectsEnabled(state$.value);
|
|
@@ -36,24 +35,6 @@ export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => action
|
|
|
36
35
|
if (isSuccessResponse(response) && response.data != null) {
|
|
37
36
|
const transactionIdResp = toTransactionID(response.data.transaction);
|
|
38
37
|
const transactionDetailKeyForResponse = getTransactionDetailKey(transactionIdResp);
|
|
39
|
-
const tranDetail = recordGet(transactionDetailState.transactionDetailById, transactionDetailKeyForResponse, undefined);
|
|
40
|
-
const tranVendorUpdates = tranDetail?.transactionDetailLocalData.vendorUpdates;
|
|
41
|
-
let vendorUpdates = undefined;
|
|
42
|
-
if (tranVendorUpdates?.qboId != null) {
|
|
43
|
-
const vendor = getVendorByVendorId(vendorState, tranVendorUpdates.qboId);
|
|
44
|
-
if (vendor != null) {
|
|
45
|
-
vendorUpdates = {
|
|
46
|
-
id: vendor?.qboId,
|
|
47
|
-
name: vendor?.name,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
else if (tranVendorUpdates.name != null) {
|
|
51
|
-
vendorUpdates = {
|
|
52
|
-
id: tranVendorUpdates.qboId,
|
|
53
|
-
name: tranVendorUpdates.name,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
38
|
const actions = [];
|
|
58
39
|
if (response.data.vendors != null) {
|
|
59
40
|
actions.push(updateVendors(response.data.vendors, 'merge'));
|
|
@@ -66,30 +47,14 @@ export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => action
|
|
|
66
47
|
vendorId: response.data.vendors?.[0]?.vendor_id,
|
|
67
48
|
}));
|
|
68
49
|
actions.push(updateTransactionDetailSaveStatus(transactionIdResp, 'Completed'));
|
|
69
|
-
let callMarkTransactionAsNotMiscategorized = true;
|
|
70
|
-
// NOTE: If tran is vendorType OR JE OR Deposit transaction and there is no vendor chosen on this tranaction while saving,
|
|
71
|
-
// then we need to skip mark-miscategorized-as-correct api call
|
|
72
|
-
if (toVendorTransactionTypeStrict(response.data.transaction.transaction_type) != null ||
|
|
73
|
-
toJEAndDepositTransactionTypeStrict(response.data.transaction.transaction_type) != null) {
|
|
74
|
-
const isAccountingClassesEnabled = getIsAccountingClassesEnabled(state$.value);
|
|
75
|
-
const isAnyClassMissing = isAccountingClassesEnabled &&
|
|
76
|
-
checkIfClassMissingForAnyLineItem(response.data.transaction);
|
|
77
|
-
const isVendorOrCustomerMissingInAnyLine = toJEAndDepositTransactionTypeStrict(response.data.transaction.transaction_type) != null &&
|
|
78
|
-
checkIfVendorOrCustomerMissingForAnyLineItem(response.data.transaction);
|
|
79
|
-
if ((vendorUpdates?.id == null &&
|
|
80
|
-
isVendorOrCustomerMissingInAnyLine == true) ||
|
|
81
|
-
isAnyClassMissing == true) {
|
|
82
|
-
callMarkTransactionAsNotMiscategorized = false;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
50
|
const uncategorizedIncomeExpense = getUncategorizedAccounts(state$.value.accountState, state$.value.accountListState, 'accountList');
|
|
86
51
|
const transaction = toSupportedTransaction(response.data.transaction);
|
|
87
|
-
const
|
|
52
|
+
const isAccountingClassesEnabled = getIsAccountingClassesEnabled(state$.value);
|
|
53
|
+
const eligibleLineIds = getLineIdsEligibleForReview(transaction, uncategorizedIncomeExpense, isAccountingClassesEnabled);
|
|
88
54
|
if (action.payload.transactionSaveUpdates.markAsMiscatUpdates ===
|
|
89
55
|
true &&
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
actions.push(markTransactionAsNotMiscategorized(transactionIdResp, action.payload.transactionSaveUpdates, action.payload.isExpenseAutomationEnabled));
|
|
56
|
+
eligibleLineIds.length > 0) {
|
|
57
|
+
actions.push(markTransactionAsNotMiscategorized(transactionIdResp, action.payload.transactionSaveUpdates, action.payload.isExpenseAutomationEnabled, eligibleLineIds));
|
|
93
58
|
}
|
|
94
59
|
else {
|
|
95
60
|
actions.push(updateStatusConsolidatedSaveTransactionDetail({
|
|
@@ -299,31 +264,25 @@ export const toTransactionUpdatePayload = (updates, detail, cotTransactionTracki
|
|
|
299
264
|
// Inject COT flags into the payload
|
|
300
265
|
return injectCOTFlagsIntoTransactionPayload(basePayload, transaction);
|
|
301
266
|
};
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
?.customer == null) {
|
|
322
|
-
isAnyVendorOrCustomerMissing = true;
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
return isAnyVendorOrCustomerMissing;
|
|
267
|
+
const getLineIdsEligibleForReview = (transaction, uncategorizedIncomeExpense, isAccountingClassesEnabled) => {
|
|
268
|
+
return (transaction.lines ?? [])
|
|
269
|
+
.filter((line) => {
|
|
270
|
+
if (line.type !== 'transaction_with_account_and_class_line' &&
|
|
271
|
+
line.type !== 'journal_entry_transaction_line' &&
|
|
272
|
+
line.type !== 'transaction_with_product_or_service_line') {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
const typedLine = line;
|
|
276
|
+
const hasCategory = !isAccountUncategorized(uncategorizedIncomeExpense, typedLine.account.qboId);
|
|
277
|
+
const hasClass = !isAccountingClassesEnabled || typedLine.class != null;
|
|
278
|
+
const hasAmount = (typedLine.amount?.amount ?? 0) !== 0;
|
|
279
|
+
const hasEntity = line.type !== 'journal_entry_transaction_line' ||
|
|
280
|
+
typedLine.vendor != null ||
|
|
281
|
+
typedLine.customer != null;
|
|
282
|
+
return hasCategory && hasClass && hasAmount && hasEntity;
|
|
283
|
+
})
|
|
284
|
+
.map((line) => line.id)
|
|
285
|
+
.filter(Boolean);
|
|
327
286
|
};
|
|
328
287
|
// Converts a locally-created line item (from edit mode) into the wire shape
|
|
329
288
|
// expected by the categorize endpoint. Sending id='' signals the backend to
|
|
@@ -190,12 +190,13 @@ const transactionDetail = createSlice({
|
|
|
190
190
|
};
|
|
191
191
|
}
|
|
192
192
|
},
|
|
193
|
-
prepare(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled) {
|
|
193
|
+
prepare(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, lineIds) {
|
|
194
194
|
return {
|
|
195
195
|
payload: {
|
|
196
196
|
transactionId,
|
|
197
197
|
transactionSaveUpdates,
|
|
198
198
|
isExpenseAutomationEnabled,
|
|
199
|
+
lineIds,
|
|
199
200
|
},
|
|
200
201
|
};
|
|
201
202
|
},
|
|
@@ -7,11 +7,95 @@ const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
|
|
|
7
7
|
const snackbarReducer_1 = require("../../../entity/snackbar/snackbarReducer");
|
|
8
8
|
const tenantSelector_1 = require("../../../entity/tenant/tenantSelector");
|
|
9
9
|
const transactionReducer_1 = require("../../../entity/transaction/transactionReducer");
|
|
10
|
+
const transactionSelector_1 = require("../../../entity/transaction/transactionSelector");
|
|
10
11
|
const responsePayload_1 = require("../../../responsePayload");
|
|
11
12
|
const transactionsViewReducer_1 = require("../../expenseAutomationView/reducers/transactionsViewReducer");
|
|
12
13
|
const transactionDetailReducer_1 = require("../transactionDetailReducer");
|
|
13
14
|
const transactionDetailState_1 = require("../transactionDetailState");
|
|
14
15
|
const markTransactionAsNotMiscategorizedEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(transactionDetailReducer_1.markTransactionAsNotMiscategorized.match), (0, operators_1.mergeMap)((action) => {
|
|
16
|
+
if (action.payload.isExpenseAutomationEnabled === true) {
|
|
17
|
+
const transactionKey = (0, transactionDetailState_1.getTransactionDetailKey)(action.payload.transactionId);
|
|
18
|
+
const transaction = (0, transactionSelector_1.getSupportedTransactionById)(state$.value.transactionState, transactionKey);
|
|
19
|
+
const lineIds = (action.payload.lineIds?.length ?? 0) > 0
|
|
20
|
+
? action.payload.lineIds
|
|
21
|
+
: (transaction?.lines ?? []).map((line) => line.id);
|
|
22
|
+
return zeniAPI
|
|
23
|
+
.putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/expense-automation/mark-as-reviewed`, {
|
|
24
|
+
transactions_reviewed: [
|
|
25
|
+
{
|
|
26
|
+
transaction_id: action.payload.transactionId.id,
|
|
27
|
+
line_ids: lineIds,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
})
|
|
31
|
+
.pipe((0, operators_1.mergeMap)((response) => {
|
|
32
|
+
if ((0, responsePayload_1.isSuccessResponse)(response)) {
|
|
33
|
+
const actions = [];
|
|
34
|
+
actions.push((0, transactionDetailReducer_1.updateStatusForTransactionNotMiscategorizedUpdate)(action.payload.transactionId, 'Completed', undefined));
|
|
35
|
+
const txnId = action.payload.transactionId.id;
|
|
36
|
+
const reviewedFailed = response.data?.transactions_reviewed_failed ?? [];
|
|
37
|
+
const isTransactionFailed = reviewedFailed.some((t) => t.transaction_id === txnId);
|
|
38
|
+
if (!isTransactionFailed) {
|
|
39
|
+
actions.push((0, transactionReducer_1.updateTransactionIsMiscategorized)(transactionKey, false));
|
|
40
|
+
const { expenseAutomationViewState, expenseAutomationTransactionsViewState, } = state$.value;
|
|
41
|
+
const { transactionCategorizationView, selectedTransactionCategorizationTab, } = expenseAutomationTransactionsViewState;
|
|
42
|
+
const currentTenant = (0, tenantSelector_1.getCurrentTenant)(state$.value);
|
|
43
|
+
const { selectedPeriodByTenantId } = expenseAutomationViewState;
|
|
44
|
+
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
45
|
+
const autoTabLineItems = transactionCategorizationView.autoCategorized
|
|
46
|
+
.transactionReviewLocalDataById[txnId]
|
|
47
|
+
?.transactionReviewLocalData.tabSpecificLineItems
|
|
48
|
+
.autoCategorized ?? [];
|
|
49
|
+
const hasAutoLines = autoTabLineItems.length > 0;
|
|
50
|
+
const { uiState } = transactionCategorizationView[selectedTransactionCategorizationTab];
|
|
51
|
+
const removeIdsFromPeriod = selectedTransactionCategorizationTab === 'review'
|
|
52
|
+
? [txnId]
|
|
53
|
+
: hasAutoLines
|
|
54
|
+
? []
|
|
55
|
+
: [txnId];
|
|
56
|
+
actions.push((0, transactionsViewReducer_1.updateStatusForTransactionNotMiscategorizedUpdateForCategorization)(selectedTransactionCategorizationTab, [txnId], removeIdsFromPeriod, selectedPeriod, 'Completed'));
|
|
57
|
+
if (!hasAutoLines) {
|
|
58
|
+
actions.push((0, transactionReducer_1.removeTransactionCategorization)({
|
|
59
|
+
transactionIds: [txnId],
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
if (removeIdsFromPeriod.length > 0) {
|
|
63
|
+
const totalCountByPeriod = uiState.totalCount[(0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod)];
|
|
64
|
+
const updatedTotalCount = totalCountByPeriod === 0
|
|
65
|
+
? totalCountByPeriod
|
|
66
|
+
: totalCountByPeriod - 1;
|
|
67
|
+
actions.push((0, transactionsViewReducer_1.updateTotalCountForTransactionCategorization)({
|
|
68
|
+
selectedPeriod,
|
|
69
|
+
selectedTab: selectedTransactionCategorizationTab,
|
|
70
|
+
totalCount: updatedTotalCount,
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
actions.push((0, transactionDetailReducer_1.updateStatusConsolidatedSaveTransactionDetail)({
|
|
75
|
+
transactionId: action.payload.transactionId,
|
|
76
|
+
fetchState: 'Completed',
|
|
77
|
+
}));
|
|
78
|
+
if (action.payload.transactionSaveUpdates.anyBulkUpdates === true) {
|
|
79
|
+
actions.push((0, snackbarReducer_1.openSnackbar)({
|
|
80
|
+
messageSection: 'transactionDetails_updatingPastTransactions',
|
|
81
|
+
messageText: 'success',
|
|
82
|
+
type: 'success',
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
actions.push((0, snackbarReducer_1.openSnackbar)({
|
|
87
|
+
messageSection: 'transactionDetails_transactionUpdated',
|
|
88
|
+
messageText: 'success',
|
|
89
|
+
type: 'success',
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
return (0, rxjs_1.from)(actions);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
return (0, rxjs_1.of)((0, transactionDetailReducer_1.updateStatusForTransactionNotMiscategorizedUpdate)(action.payload.transactionId, 'Error', response.status));
|
|
96
|
+
}
|
|
97
|
+
}), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, transactionDetailReducer_1.updateStatusForTransactionNotMiscategorizedUpdate)(action.payload.transactionId, 'Error', (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', `Transaction mark as reviewed REST API call errored out ${error}`)))));
|
|
98
|
+
}
|
|
15
99
|
return zeniAPI
|
|
16
100
|
.putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${action.payload.transactionId.id}/mark-miscategorized-as-correct`, preparePayload(action.payload.transactionId))
|
|
17
101
|
.pipe((0, operators_1.mergeMap)((response) => {
|
|
@@ -19,44 +103,7 @@ const markTransactionAsNotMiscategorizedEpic = (actions$, state$, zeniAPI) => ac
|
|
|
19
103
|
const actions = [];
|
|
20
104
|
actions.push((0, transactionDetailReducer_1.updateStatusForTransactionNotMiscategorizedUpdate)(action.payload.transactionId, 'Completed', undefined));
|
|
21
105
|
const transactionKey = (0, transactionDetailState_1.getTransactionDetailKey)(action.payload.transactionId);
|
|
22
|
-
// Mark this transaction as not miscategorized anymore
|
|
23
106
|
actions.push((0, transactionReducer_1.updateTransactionIsMiscategorized)(transactionKey, false));
|
|
24
|
-
if (action.payload.isExpenseAutomationEnabled === true) {
|
|
25
|
-
const { expenseAutomationViewState, expenseAutomationTransactionsViewState, } = state$.value;
|
|
26
|
-
const { transactionCategorizationView, selectedTransactionCategorizationTab, } = expenseAutomationTransactionsViewState;
|
|
27
|
-
const currentTenant = (0, tenantSelector_1.getCurrentTenant)(state$.value);
|
|
28
|
-
const { selectedPeriodByTenantId } = expenseAutomationViewState;
|
|
29
|
-
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
30
|
-
const txnId = action.payload.transactionId.id;
|
|
31
|
-
const autoTabLineItems = transactionCategorizationView.autoCategorized
|
|
32
|
-
.transactionReviewLocalDataById[txnId]
|
|
33
|
-
?.transactionReviewLocalData.tabSpecificLineItems
|
|
34
|
-
.autoCategorized ?? [];
|
|
35
|
-
const hasAutoLines = autoTabLineItems.length > 0;
|
|
36
|
-
const { uiState } = transactionCategorizationView[selectedTransactionCategorizationTab];
|
|
37
|
-
const removeIdsFromPeriod = selectedTransactionCategorizationTab === 'review'
|
|
38
|
-
? [txnId]
|
|
39
|
-
: hasAutoLines
|
|
40
|
-
? []
|
|
41
|
-
: [txnId];
|
|
42
|
-
actions.push((0, transactionsViewReducer_1.updateStatusForTransactionNotMiscategorizedUpdateForCategorization)(selectedTransactionCategorizationTab, [txnId], removeIdsFromPeriod, selectedPeriod, 'Completed'));
|
|
43
|
-
if (!hasAutoLines) {
|
|
44
|
-
actions.push((0, transactionReducer_1.removeTransactionCategorization)({
|
|
45
|
-
transactionIds: [txnId],
|
|
46
|
-
}));
|
|
47
|
-
}
|
|
48
|
-
if (removeIdsFromPeriod.length > 0) {
|
|
49
|
-
const totalCountByPeriod = uiState.totalCount[(0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod)];
|
|
50
|
-
const updatedTotalCount = totalCountByPeriod === 0
|
|
51
|
-
? totalCountByPeriod
|
|
52
|
-
: totalCountByPeriod - 1;
|
|
53
|
-
actions.push((0, transactionsViewReducer_1.updateTotalCountForTransactionCategorization)({
|
|
54
|
-
selectedPeriod,
|
|
55
|
-
selectedTab: selectedTransactionCategorizationTab,
|
|
56
|
-
totalCount: updatedTotalCount,
|
|
57
|
-
}));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
107
|
actions.push((0, transactionDetailReducer_1.updateStatusConsolidatedSaveTransactionDetail)({
|
|
61
108
|
transactionId: action.payload.transactionId,
|
|
62
109
|
fetchState: 'Completed',
|
|
@@ -69,7 +116,6 @@ const markTransactionAsNotMiscategorizedEpic = (actions$, state$, zeniAPI) => ac
|
|
|
69
116
|
}));
|
|
70
117
|
}
|
|
71
118
|
else {
|
|
72
|
-
//Finally everything done for this transaction
|
|
73
119
|
actions.push((0, snackbarReducer_1.openSnackbar)({
|
|
74
120
|
messageSection: 'transactionDetails_transactionUpdated',
|
|
75
121
|
messageText: 'success',
|
|
@@ -16,7 +16,6 @@ const transactionPayload_1 = require("../../../entity/transaction/payloadTypes/t
|
|
|
16
16
|
const vendorTransactionPayload_1 = require("../../../entity/transaction/payloadTypes/vendorTransactionPayload");
|
|
17
17
|
const customerTransaction_1 = require("../../../entity/transaction/stateTypes/customerTransaction");
|
|
18
18
|
const otherTransaction_1 = require("../../../entity/transaction/stateTypes/otherTransaction");
|
|
19
|
-
const transactionType_1 = require("../../../entity/transaction/stateTypes/transactionType");
|
|
20
19
|
const vendorTransaction_1 = require("../../../entity/transaction/stateTypes/vendorTransaction");
|
|
21
20
|
const toSupportedTransaction_1 = __importDefault(require("../../../entity/transaction/toSupportedTransaction"));
|
|
22
21
|
const transactionHelper_1 = require("../../../entity/transaction/transactionHelper");
|
|
@@ -31,7 +30,7 @@ const transactionCategorizationLocalDataHelper_1 = require("../../expenseAutomat
|
|
|
31
30
|
const transactionsViewReducer_1 = require("../../expenseAutomationView/reducers/transactionsViewReducer");
|
|
32
31
|
const transactionDetailReducer_1 = require("../transactionDetailReducer");
|
|
33
32
|
const transactionDetailState_1 = require("../transactionDetailState");
|
|
34
|
-
const
|
|
33
|
+
const transactionDetailLocalDataHelper_1 = require("../transactionDetailLocalDataHelper");
|
|
35
34
|
const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(transactionDetailReducer_1.updateTransactionDetail.match), (0, operators_1.mergeMap)((action) => {
|
|
36
35
|
const { transactionState, vendorState, transactionDetailState } = state$.value;
|
|
37
36
|
const isAccountingProjectsEnabled = (0, tenantSelector_1.getIsAccountingProjectsEnabled)(state$.value);
|
|
@@ -42,24 +41,6 @@ const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
42
41
|
if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
|
|
43
42
|
const transactionIdResp = (0, transactionIDPayload_1.toTransactionID)(response.data.transaction);
|
|
44
43
|
const transactionDetailKeyForResponse = (0, transactionDetailState_1.getTransactionDetailKey)(transactionIdResp);
|
|
45
|
-
const tranDetail = (0, get_1.default)(transactionDetailState.transactionDetailById, transactionDetailKeyForResponse, undefined);
|
|
46
|
-
const tranVendorUpdates = tranDetail?.transactionDetailLocalData.vendorUpdates;
|
|
47
|
-
let vendorUpdates = undefined;
|
|
48
|
-
if (tranVendorUpdates?.qboId != null) {
|
|
49
|
-
const vendor = (0, vendorSelector_1.getVendorByVendorId)(vendorState, tranVendorUpdates.qboId);
|
|
50
|
-
if (vendor != null) {
|
|
51
|
-
vendorUpdates = {
|
|
52
|
-
id: vendor?.qboId,
|
|
53
|
-
name: vendor?.name,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
else if (tranVendorUpdates.name != null) {
|
|
57
|
-
vendorUpdates = {
|
|
58
|
-
id: tranVendorUpdates.qboId,
|
|
59
|
-
name: tranVendorUpdates.name,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
44
|
const actions = [];
|
|
64
45
|
if (response.data.vendors != null) {
|
|
65
46
|
actions.push((0, vendorReducer_1.updateVendors)(response.data.vendors, 'merge'));
|
|
@@ -72,30 +53,14 @@ const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
72
53
|
vendorId: response.data.vendors?.[0]?.vendor_id,
|
|
73
54
|
}));
|
|
74
55
|
actions.push((0, transactionDetailReducer_1.updateTransactionDetailSaveStatus)(transactionIdResp, 'Completed'));
|
|
75
|
-
let callMarkTransactionAsNotMiscategorized = true;
|
|
76
|
-
// NOTE: If tran is vendorType OR JE OR Deposit transaction and there is no vendor chosen on this tranaction while saving,
|
|
77
|
-
// then we need to skip mark-miscategorized-as-correct api call
|
|
78
|
-
if ((0, transactionType_1.toVendorTransactionTypeStrict)(response.data.transaction.transaction_type) != null ||
|
|
79
|
-
(0, transactionType_1.toJEAndDepositTransactionTypeStrict)(response.data.transaction.transaction_type) != null) {
|
|
80
|
-
const isAccountingClassesEnabled = (0, tenantSelector_1.getIsAccountingClassesEnabled)(state$.value);
|
|
81
|
-
const isAnyClassMissing = isAccountingClassesEnabled &&
|
|
82
|
-
checkIfClassMissingForAnyLineItem(response.data.transaction);
|
|
83
|
-
const isVendorOrCustomerMissingInAnyLine = (0, transactionType_1.toJEAndDepositTransactionTypeStrict)(response.data.transaction.transaction_type) != null &&
|
|
84
|
-
checkIfVendorOrCustomerMissingForAnyLineItem(response.data.transaction);
|
|
85
|
-
if ((vendorUpdates?.id == null &&
|
|
86
|
-
isVendorOrCustomerMissingInAnyLine == true) ||
|
|
87
|
-
isAnyClassMissing == true) {
|
|
88
|
-
callMarkTransactionAsNotMiscategorized = false;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
56
|
const uncategorizedIncomeExpense = (0, accountListSelector_1.getUncategorizedAccounts)(state$.value.accountState, state$.value.accountListState, 'accountList');
|
|
92
57
|
const transaction = (0, toSupportedTransaction_1.default)(response.data.transaction);
|
|
93
|
-
const
|
|
58
|
+
const isAccountingClassesEnabled = (0, tenantSelector_1.getIsAccountingClassesEnabled)(state$.value);
|
|
59
|
+
const eligibleLineIds = getLineIdsEligibleForReview(transaction, uncategorizedIncomeExpense, isAccountingClassesEnabled);
|
|
94
60
|
if (action.payload.transactionSaveUpdates.markAsMiscatUpdates ===
|
|
95
61
|
true &&
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
actions.push((0, transactionDetailReducer_1.markTransactionAsNotMiscategorized)(transactionIdResp, action.payload.transactionSaveUpdates, action.payload.isExpenseAutomationEnabled));
|
|
62
|
+
eligibleLineIds.length > 0) {
|
|
63
|
+
actions.push((0, transactionDetailReducer_1.markTransactionAsNotMiscategorized)(transactionIdResp, action.payload.transactionSaveUpdates, action.payload.isExpenseAutomationEnabled, eligibleLineIds));
|
|
99
64
|
}
|
|
100
65
|
else {
|
|
101
66
|
actions.push((0, transactionDetailReducer_1.updateStatusConsolidatedSaveTransactionDetail)({
|
|
@@ -307,31 +272,25 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isA
|
|
|
307
272
|
return (0, transactionPayload_1.injectCOTFlagsIntoTransactionPayload)(basePayload, transaction);
|
|
308
273
|
};
|
|
309
274
|
exports.toTransactionUpdatePayload = toTransactionUpdatePayload;
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
?.customer == null) {
|
|
330
|
-
isAnyVendorOrCustomerMissing = true;
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
return isAnyVendorOrCustomerMissing;
|
|
275
|
+
const getLineIdsEligibleForReview = (transaction, uncategorizedIncomeExpense, isAccountingClassesEnabled) => {
|
|
276
|
+
return (transaction.lines ?? [])
|
|
277
|
+
.filter((line) => {
|
|
278
|
+
if (line.type !== 'transaction_with_account_and_class_line' &&
|
|
279
|
+
line.type !== 'journal_entry_transaction_line' &&
|
|
280
|
+
line.type !== 'transaction_with_product_or_service_line') {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
const typedLine = line;
|
|
284
|
+
const hasCategory = !(0, transactionDetailLocalDataHelper_1.isAccountUncategorized)(uncategorizedIncomeExpense, typedLine.account.qboId);
|
|
285
|
+
const hasClass = !isAccountingClassesEnabled || typedLine.class != null;
|
|
286
|
+
const hasAmount = (typedLine.amount?.amount ?? 0) !== 0;
|
|
287
|
+
const hasEntity = line.type !== 'journal_entry_transaction_line' ||
|
|
288
|
+
typedLine.vendor != null ||
|
|
289
|
+
typedLine.customer != null;
|
|
290
|
+
return hasCategory && hasClass && hasAmount && hasEntity;
|
|
291
|
+
})
|
|
292
|
+
.map((line) => line.id)
|
|
293
|
+
.filter(Boolean);
|
|
335
294
|
};
|
|
336
295
|
// Converts a locally-created line item (from edit mode) into the wire shape
|
|
337
296
|
// expected by the categorize endpoint. Sending id='' signals the backend to
|
|
@@ -38,10 +38,11 @@ export declare const downloadAccountingProviderAttachment: import("@reduxjs/tool
|
|
|
38
38
|
error: ZeniAPIStatus<Record<string, unknown>> | undefined;
|
|
39
39
|
}, "transactionDetail/updateTransactionDetailSaveStatus", never, never>, clearTransactionDetailSaveStatus: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID], {
|
|
40
40
|
transactionId: TransactionID;
|
|
41
|
-
}, "transactionDetail/clearTransactionDetailSaveStatus", never, never>, markTransactionAsNotMiscategorized: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, transactionSaveUpdates: TransactionSaveUpdates, isExpenseAutomationEnabled: boolean], {
|
|
41
|
+
}, "transactionDetail/clearTransactionDetailSaveStatus", never, never>, markTransactionAsNotMiscategorized: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, transactionSaveUpdates: TransactionSaveUpdates, isExpenseAutomationEnabled: boolean, lineIds?: string[] | undefined], {
|
|
42
42
|
transactionId: TransactionID;
|
|
43
43
|
transactionSaveUpdates: TransactionSaveUpdates;
|
|
44
44
|
isExpenseAutomationEnabled: boolean;
|
|
45
|
+
lineIds: string[] | undefined;
|
|
45
46
|
}, "transactionDetail/markTransactionAsNotMiscategorized", never, never>, deleteTransactionAttachment: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[attachmentFileName: string, transactionId: TransactionID], {
|
|
46
47
|
attachmentFileName: string;
|
|
47
48
|
transactionId: TransactionID;
|
|
@@ -197,12 +197,13 @@ const transactionDetail = (0, toolkit_1.createSlice)({
|
|
|
197
197
|
};
|
|
198
198
|
}
|
|
199
199
|
},
|
|
200
|
-
prepare(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled) {
|
|
200
|
+
prepare(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, lineIds) {
|
|
201
201
|
return {
|
|
202
202
|
payload: {
|
|
203
203
|
transactionId,
|
|
204
204
|
transactionSaveUpdates,
|
|
205
205
|
isExpenseAutomationEnabled,
|
|
206
|
+
lineIds,
|
|
206
207
|
},
|
|
207
208
|
};
|
|
208
209
|
},
|
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.50-beta3RR",
|
|
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",
|