@zeniai/client-epic-state 5.1.24 → 5.1.25-betaRD2
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/README.md +2 -1
- package/lib/entity/transaction/payloadTypes/transactionPayload.d.ts +1 -0
- package/lib/entity/transaction/payloadTypes/transactionPayload.js +5 -0
- package/lib/entity/transaction/stateTypes/transaction.d.ts +1 -0
- package/lib/epic.d.ts +2 -1
- package/lib/epic.js +2 -1
- package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +5 -0
- package/lib/esm/epic.js +2 -1
- package/lib/esm/index.js +2 -2
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +29 -3
- package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +11 -0
- package/lib/esm/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -2
- package/lib/esm/view/aiCfoView/epics/fetchSkillsEpic.js +34 -0
- package/lib/esm/view/aiCfoView/epics/submitQuestionEpic.js +7 -1
- package/lib/esm/view/transactionDetail/epics/saveTransactionDetailEpic.js +3 -1
- package/lib/esm/view/transactionDetail/epics/saveTransactionHelper.js +11 -2
- package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +28 -4
- package/lib/esm/view/transactionDetail/transactionDetailLocalDataHelper.js +17 -0
- package/lib/index.d.ts +4 -4
- package/lib/index.js +9 -5
- package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +14 -0
- package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +8 -4
- package/lib/view/aiCfoView/aiCfoViewReducer.js +30 -4
- package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +2 -1
- package/lib/view/aiCfoView/aiCfoViewSelector.js +12 -0
- package/lib/view/aiCfoView/aiCfoViewState.d.ts +15 -0
- package/lib/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -2
- package/lib/view/aiCfoView/epics/fetchSkillsEpic.d.ts +8 -0
- package/lib/view/aiCfoView/epics/fetchSkillsEpic.js +38 -0
- package/lib/view/aiCfoView/epics/submitQuestionEpic.js +7 -1
- package/lib/view/transactionDetail/epics/saveTransactionDetailEpic.js +3 -1
- package/lib/view/transactionDetail/epics/saveTransactionHelper.d.ts +1 -1
- package/lib/view/transactionDetail/epics/saveTransactionHelper.js +11 -2
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.d.ts +8 -0
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +30 -5
- package/lib/view/transactionDetail/transactionDetailLocalDataHelper.js +17 -0
- package/lib/view/transactionDetail/transactionDetailState.d.ts +1 -0
- package/lib/view/transactionDetail/transactionDetailTypes.d.ts +1 -0
- package/package.json +4 -2
|
@@ -69,7 +69,7 @@ function waitForChannelSubscription(pusherInstance, channelName, timeoutMs = 500
|
|
|
69
69
|
}));
|
|
70
70
|
}
|
|
71
71
|
const createSessionAndSubmitEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(aiCfoViewReducer_1.createSessionAndSubmit.match), (0, operators_1.switchMap)((action) => {
|
|
72
|
-
const { agentId, userId, questionAnswerId, questionId, createdAt, question, files, pageContext, } = action.payload;
|
|
72
|
+
const { agentId, userId, questionAnswerId, questionId, createdAt, question, files, pageContext, macroId, } = action.payload;
|
|
73
73
|
const payload = {
|
|
74
74
|
agent_id: agentId,
|
|
75
75
|
...(pageContext != null && { page_context: pageContext }),
|
|
@@ -116,7 +116,7 @@ const createSessionAndSubmitEpic = (actions$, _state$, zeniAPI) => actions$.pipe
|
|
|
116
116
|
// This allows fetchChatHistory to run after the question is submitted
|
|
117
117
|
(0, rxjs_1.of)((0, aiCfoViewReducer_1.createSessionAndSubmitSuccess)(),
|
|
118
118
|
// Submit the question after handlers are bound
|
|
119
|
-
(0, aiCfoViewReducer_1.submitQuestion)(sessionId, questionAnswerId, userId, questionId, createdAt, question, files),
|
|
119
|
+
(0, aiCfoViewReducer_1.submitQuestion)(sessionId, questionAnswerId, userId, questionId, createdAt, question, files, macroId),
|
|
120
120
|
// Add question payload optimistically after submitQuestion (matches original order)
|
|
121
121
|
// This is idempotent - won't create duplicates if called multiple times
|
|
122
122
|
// submitQuestionEpic will find the question already exists and only update the response
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { RootState } from '../../../reducer';
|
|
4
|
+
import { ZeniAPI } from '../../../zeniAPI';
|
|
5
|
+
import { fetchSkills, fetchSkillsFailure, fetchSkillsSuccess } from '../aiCfoViewReducer';
|
|
6
|
+
export type ActionType = ReturnType<typeof fetchSkills> | ReturnType<typeof fetchSkillsSuccess> | ReturnType<typeof fetchSkillsFailure>;
|
|
7
|
+
/** GET {aiCfoMicroServiceBaseUrl}/1.0/skills — chat-visible skills for the `/` menu. */
|
|
8
|
+
export declare const fetchSkillsEpic: (actions$: ActionsObservable<ActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchSkillsEpic = void 0;
|
|
4
|
+
const rxjs_1 = require("rxjs");
|
|
5
|
+
const operators_1 = require("rxjs/operators");
|
|
6
|
+
const responsePayload_1 = require("../../../responsePayload");
|
|
7
|
+
const aiCfoViewReducer_1 = require("../aiCfoViewReducer");
|
|
8
|
+
const toSkill = (s) => ({
|
|
9
|
+
macroId: s.macro_id,
|
|
10
|
+
name: s.name,
|
|
11
|
+
displayName: s.display_name,
|
|
12
|
+
description: s.description,
|
|
13
|
+
semver: s.semver,
|
|
14
|
+
parameterHints: s.parameter_hints,
|
|
15
|
+
hasScripts: s.has_scripts,
|
|
16
|
+
});
|
|
17
|
+
/** GET {aiCfoMicroServiceBaseUrl}/1.0/skills — chat-visible skills for the `/` menu. */
|
|
18
|
+
const fetchSkillsEpic = (actions$,
|
|
19
|
+
// state$ intentionally unused: the `/` menu dispatches this once per slash-entry
|
|
20
|
+
// (the composer dedupes), so we always re-fetch the (small, singleton) list.
|
|
21
|
+
_state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(aiCfoViewReducer_1.fetchSkills.match),
|
|
22
|
+
// switchMap: a singleton list endpoint with no key — cancel any in-flight
|
|
23
|
+
// fetch so the latest dispatch wins (no racing writes to `skills`).
|
|
24
|
+
(0, operators_1.switchMap)(() => {
|
|
25
|
+
// aiCfoMicroServiceBaseUrl already targets the chat service (it serves the
|
|
26
|
+
// /1.0/agents/{id} submit route too); /1.0/skills lives on the same service.
|
|
27
|
+
const url = `${zeniAPI.apiEndPoints.aiCfoMicroServiceBaseUrl}/1.0/skills`;
|
|
28
|
+
return zeniAPI.getJSON(url).pipe((0, operators_1.mergeMap)((response) => {
|
|
29
|
+
if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
|
|
30
|
+
// Guard the array: a malformed 2xx body without `skills` must not crash .map.
|
|
31
|
+
return (0, rxjs_1.of)((0, aiCfoViewReducer_1.fetchSkillsSuccess)({
|
|
32
|
+
skills: (response.data.skills ?? []).map(toSkill),
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
return (0, rxjs_1.of)((0, aiCfoViewReducer_1.fetchSkillsFailure)(response.status));
|
|
36
|
+
}), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, aiCfoViewReducer_1.fetchSkillsFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Fetch skills REST API call failed', error instanceof Error ? { message: error.message } : undefined)))));
|
|
37
|
+
}));
|
|
38
|
+
exports.fetchSkillsEpic = fetchSkillsEpic;
|
|
@@ -7,7 +7,7 @@ const aiCfoReducer_1 = require("../../../entity/aiCfo/aiCfoReducer");
|
|
|
7
7
|
const responsePayload_1 = require("../../../responsePayload");
|
|
8
8
|
const aiCfoViewReducer_1 = require("../aiCfoViewReducer");
|
|
9
9
|
const submitQuestionEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(aiCfoViewReducer_1.submitQuestion.match), (0, operators_1.mergeMap)((action) => {
|
|
10
|
-
const { questionAnswerId, userId, sessionId, questionId, createdAt, question, files, } = action.payload;
|
|
10
|
+
const { questionAnswerId, userId, sessionId, questionId, createdAt, question, files, macroId, } = action.payload;
|
|
11
11
|
const { aiCfoViewState } = state$.value;
|
|
12
12
|
const { uiState } = aiCfoViewState;
|
|
13
13
|
const agentId = uiState.agentId;
|
|
@@ -20,15 +20,21 @@ const submitQuestionEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, oper
|
|
|
20
20
|
const formData = new FormData();
|
|
21
21
|
formData.append('chat_session_id', sessionId);
|
|
22
22
|
formData.append('message', question);
|
|
23
|
+
if (macroId != null) {
|
|
24
|
+
formData.append('macro_id', macroId);
|
|
25
|
+
}
|
|
23
26
|
for (const file of files) {
|
|
24
27
|
formData.append('files', file, file.name);
|
|
25
28
|
}
|
|
26
29
|
apiCall = zeniAPI.postFormData(endpoint, formData);
|
|
27
30
|
}
|
|
28
31
|
else {
|
|
32
|
+
// `message` is the display token (e.g. "/flux"); `macro_id` tells the chat
|
|
33
|
+
// service to expand the skill's instructions as the actual agent prompt.
|
|
29
34
|
apiCall = zeniAPI.postAndGetJSON(endpoint, {
|
|
30
35
|
chat_session_id: sessionId,
|
|
31
36
|
message: question,
|
|
37
|
+
...(macroId != null && { macro_id: macroId }),
|
|
32
38
|
});
|
|
33
39
|
}
|
|
34
40
|
return apiCall.pipe((0, operators_1.mergeMap)((response) => {
|
|
@@ -8,6 +8,7 @@ const get_1 = __importDefault(require("lodash/get"));
|
|
|
8
8
|
const rxjs_1 = require("rxjs");
|
|
9
9
|
const operators_1 = require("rxjs/operators");
|
|
10
10
|
const transactionSelector_1 = require("../../../entity/transaction/transactionSelector");
|
|
11
|
+
const tenantSelector_1 = require("../../../entity/tenant/tenantSelector");
|
|
11
12
|
const transactionDetailReducer_1 = require("../transactionDetailReducer");
|
|
12
13
|
const transactionDetailState_1 = require("../transactionDetailState");
|
|
13
14
|
const saveTransactionHelper_1 = require("./saveTransactionHelper");
|
|
@@ -16,12 +17,13 @@ const saveTransactionDetailEpic = (actions$, state$) => actions$.pipe((0, operat
|
|
|
16
17
|
const fetchActions = [];
|
|
17
18
|
const transactionDetailState = state$.value.transactionDetailState;
|
|
18
19
|
const transactionState = state$.value.transactionState;
|
|
20
|
+
const isAccountingProjectsEnabled = (0, tenantSelector_1.getIsAccountingProjectsEnabled)(state$.value);
|
|
19
21
|
const key = (0, transactionDetailState_1.getTransactionDetailKey)(transactionId);
|
|
20
22
|
const detail = (0, get_1.default)(transactionDetailState.transactionDetailById, key, undefined);
|
|
21
23
|
const transaction = (0, transactionSelector_1.getSupportedTransactionById)(transactionState, key);
|
|
22
24
|
if (detail != null && transaction != null) {
|
|
23
25
|
const localData = detail.transactionDetailLocalData;
|
|
24
|
-
const transactionSaveUpdates = (0, saveTransactionHelper_1.toTransactionUpdatesFromTransactionDetailLocalData)(localData, transaction, isExpenseAutomationEnabled);
|
|
26
|
+
const transactionSaveUpdates = (0, saveTransactionHelper_1.toTransactionUpdatesFromTransactionDetailLocalData)(localData, transaction, isExpenseAutomationEnabled, isAccountingProjectsEnabled);
|
|
25
27
|
fetchActions.push((0, transactionDetailReducer_1.updateTransactionDetail)(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, cotTransactionTracking, isUncategorizedExpenseCategoryEnabled));
|
|
26
28
|
return (0, rxjs_1.from)(fetchActions);
|
|
27
29
|
}
|
|
@@ -21,7 +21,7 @@ import { TransactionDetailLocalData } from '../transactionDetailTypes';
|
|
|
21
21
|
* 4. Only difference between this and Miscategorized will be that we will
|
|
22
22
|
* additionally fire “Mark as not miscat” for every point above.
|
|
23
23
|
*/
|
|
24
|
-
export declare const toTransactionUpdatesFromTransactionDetailLocalData: (transactionDetailLocalData: TransactionDetailLocalData, transaction: SupportedTransaction, isExpenseAutomationEnabled: boolean) => TransactionSaveUpdates;
|
|
24
|
+
export declare const toTransactionUpdatesFromTransactionDetailLocalData: (transactionDetailLocalData: TransactionDetailLocalData, transaction: SupportedTransaction, isExpenseAutomationEnabled: boolean, isAccountingProjectsEnabled?: boolean) => TransactionSaveUpdates;
|
|
25
25
|
export declare const toRecommendedAccountBase: (amountValue: number, accountBase?: AccountBase, recommendationBase?: RecommendationBase) => RecommendedAccountBase | undefined;
|
|
26
26
|
export declare const toRecommendedClassBase: (amountValue: number, classBase?: ClassBase, recommendationBase?: RecommendationBase) => RecommendedClassBase | undefined;
|
|
27
27
|
export declare const isTransactionMiscategorized: (transaction: SupportedTransaction, isExpenseAutomationEnabled: boolean) => boolean;
|
|
@@ -24,7 +24,7 @@ const transactionDetailLocalDataHelper_1 = require("../transactionDetailLocalDat
|
|
|
24
24
|
* 4. Only difference between this and Miscategorized will be that we will
|
|
25
25
|
* additionally fire “Mark as not miscat” for every point above.
|
|
26
26
|
*/
|
|
27
|
-
const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLocalData, transaction, isExpenseAutomationEnabled) => {
|
|
27
|
+
const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLocalData, transaction, isExpenseAutomationEnabled, isAccountingProjectsEnabled = false) => {
|
|
28
28
|
const updates = {
|
|
29
29
|
updatesByLineId: {},
|
|
30
30
|
};
|
|
@@ -33,6 +33,12 @@ const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLoc
|
|
|
33
33
|
const isTransactionMisCategorized = (0, exports.isTransactionMiscategorized)(transaction, isExpenseAutomationEnabled);
|
|
34
34
|
updates.memo = transactionDetailLocalData.memo;
|
|
35
35
|
updates.documentId = transactionDetailLocalData.documentId;
|
|
36
|
+
// Project is at the transaction level only for invoice and credit_memo,
|
|
37
|
+
// and only when the projects feature is enabled for this tenant.
|
|
38
|
+
if (isAccountingProjectsEnabled &&
|
|
39
|
+
(transaction.type === 'invoice' || transaction.type === 'credit_memo')) {
|
|
40
|
+
updates.project = transactionDetailLocalData.project;
|
|
41
|
+
}
|
|
36
42
|
const selectedEntity = transactionDetailLocalData.selectedEntity;
|
|
37
43
|
const updatedEntityId = transactionDetailLocalData.updatePreviousTransactionsWithUpdatedVendor ===
|
|
38
44
|
true
|
|
@@ -55,7 +61,10 @@ const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLoc
|
|
|
55
61
|
lineDescription: lineItem.lineDescription,
|
|
56
62
|
class: lineItem.class,
|
|
57
63
|
account: lineItem.account,
|
|
58
|
-
|
|
64
|
+
// Project is at the transaction level for invoice/credit_memo; omit from lines.
|
|
65
|
+
...(transaction.type !== 'invoice' && transaction.type !== 'credit_memo'
|
|
66
|
+
? { project: lineItem.project }
|
|
67
|
+
: {}),
|
|
59
68
|
recommendation: (0, transactionHelper_1.convertCOTRecommendationsToRegular)(lineItem.recommendationsWithCOT),
|
|
60
69
|
};
|
|
61
70
|
if (line.type === 'journal_entry_transaction_line' ||
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
|
+
import { COTTransactionTracking } from '../../../commonStateTypes/recommendationBase';
|
|
3
|
+
import { CustomerBase } from '../../../entity/customer/customerState';
|
|
4
|
+
import { Entity } from '../../../entity/genericEntity/entity';
|
|
2
5
|
import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
6
|
+
import { TransactionPayload } from '../../../entity/transaction/payloadTypes/transactionPayload';
|
|
3
7
|
import { updateTransaction, updateTransactions } from '../../../entity/transaction/transactionReducer';
|
|
8
|
+
import { SupportedTransaction } from '../../../entity/transaction/transactionState';
|
|
4
9
|
import { updateVendors } from '../../../entity/vendor/vendorReducer';
|
|
10
|
+
import { VendorBase } from '../../../entity/vendor/vendorState';
|
|
5
11
|
import { RootState } from '../../../reducer';
|
|
6
12
|
import { ZeniAPI } from '../../../zeniAPI';
|
|
7
13
|
import { syncTransactionCategorizationFromDetailSave } from '../../expenseAutomationView/reducers/transactionsViewReducer';
|
|
8
14
|
import { initializeTransactionDetailLocalData, markTransactionAsNotMiscategorized, updateStatusConsolidatedSaveTransactionDetail, updateTransactionDetail, updateTransactionDetailSaveStatus, updateTransactionStateIfUpdateActionNotAllowed } from '../transactionDetailReducer';
|
|
15
|
+
import { TransactionUpdates } from '../transactionDetailState';
|
|
9
16
|
export type ActionType = ReturnType<typeof updateTransactionDetail> | ReturnType<typeof updateTransaction> | ReturnType<typeof updateTransactions> | ReturnType<typeof updateTransactionStateIfUpdateActionNotAllowed> | ReturnType<typeof openSnackbar> | ReturnType<typeof updateTransactionDetailSaveStatus> | ReturnType<typeof updateStatusConsolidatedSaveTransactionDetail> | ReturnType<typeof initializeTransactionDetailLocalData> | ReturnType<typeof updateVendors> | ReturnType<typeof markTransactionAsNotMiscategorized> | ReturnType<typeof syncTransactionCategorizationFromDetailSave>;
|
|
10
17
|
export declare const updateTransactionDetailEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => import("rxjs").Observable<ActionType>;
|
|
18
|
+
export declare const toTransactionUpdatePayload: (updates: TransactionUpdates, detail: SupportedTransaction, cotTransactionTracking: COTTransactionTracking, isAccountingProjectsEnabled: boolean, vendorUpdates?: VendorBase, customerUpdates?: CustomerBase, tranSelectedEntity?: Entity) => Partial<TransactionPayload>;
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.updateTransactionDetailEpic = void 0;
|
|
6
|
+
exports.toTransactionUpdatePayload = exports.updateTransactionDetailEpic = void 0;
|
|
7
7
|
const get_1 = __importDefault(require("lodash/get"));
|
|
8
8
|
const rxjs_1 = require("rxjs");
|
|
9
9
|
const operators_1 = require("rxjs/operators");
|
|
@@ -25,6 +25,7 @@ const transactionSelector_1 = require("../../../entity/transaction/transactionSe
|
|
|
25
25
|
const vendorReducer_1 = require("../../../entity/vendor/vendorReducer");
|
|
26
26
|
const vendorSelector_1 = require("../../../entity/vendor/vendorSelector");
|
|
27
27
|
const responsePayload_1 = require("../../../responsePayload");
|
|
28
|
+
const tenantSelector_1 = require("../../../entity/tenant/tenantSelector");
|
|
28
29
|
const accountListSelector_1 = require("../../accountList/accountListSelector");
|
|
29
30
|
const transactionCategorizationLocalDataHelper_1 = require("../../expenseAutomationView/helpers/transactionCategorizationLocalDataHelper");
|
|
30
31
|
const transactionsViewReducer_1 = require("../../expenseAutomationView/reducers/transactionsViewReducer");
|
|
@@ -33,9 +34,10 @@ const transactionDetailState_1 = require("../transactionDetailState");
|
|
|
33
34
|
const saveTransactionHelper_1 = require("./saveTransactionHelper");
|
|
34
35
|
const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(transactionDetailReducer_1.updateTransactionDetail.match), (0, operators_1.mergeMap)((action) => {
|
|
35
36
|
const { transactionState, vendorState, transactionDetailState } = state$.value;
|
|
37
|
+
const isAccountingProjectsEnabled = (0, tenantSelector_1.getIsAccountingProjectsEnabled)(state$.value);
|
|
36
38
|
const { cotTransactionTracking, transactionId, transactionSaveUpdates, isUncategorizedExpenseCategoryEnabled, } = action.payload;
|
|
37
39
|
return zeniAPI
|
|
38
|
-
.putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${action.payload.transactionId.id}/categorize`, preparePayload(transactionState, vendorState, transactionDetailState, transactionId, transactionSaveUpdates, cotTransactionTracking))
|
|
40
|
+
.putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${action.payload.transactionId.id}/categorize`, preparePayload(transactionState, vendorState, transactionDetailState, transactionId, transactionSaveUpdates, cotTransactionTracking, isAccountingProjectsEnabled))
|
|
39
41
|
.pipe((0, operators_1.mergeMap)((response) => {
|
|
40
42
|
if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
|
|
41
43
|
const transactionIdResp = (0, transactionIDPayload_1.toTransactionID)(response.data.transaction);
|
|
@@ -130,7 +132,7 @@ const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
130
132
|
}), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, transactionDetailReducer_1.updateTransactionDetailSaveStatus)(action.payload.transactionId, 'Error', (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', `REST API call errored out ${error}`)))));
|
|
131
133
|
}));
|
|
132
134
|
exports.updateTransactionDetailEpic = updateTransactionDetailEpic;
|
|
133
|
-
function preparePayload(transactionState, vendorState, transactionDetailState, transactionId, saveUpdates, cotTransactionTracking) {
|
|
135
|
+
function preparePayload(transactionState, vendorState, transactionDetailState, transactionId, saveUpdates, cotTransactionTracking, isAccountingProjectsEnabled) {
|
|
134
136
|
const transactionDetailKey = (0, transactionDetailState_1.getTransactionDetailKey)(transactionId);
|
|
135
137
|
const detail = (0, transactionSelector_1.getSupportedTransactionById)(transactionState, transactionDetailKey);
|
|
136
138
|
const tranDetail = (0, get_1.default)(transactionDetailState.transactionDetailById, transactionDetailKey, undefined);
|
|
@@ -162,7 +164,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
162
164
|
};
|
|
163
165
|
}
|
|
164
166
|
if (detail != null) {
|
|
165
|
-
const transUpdates = toTransactionUpdatePayload(saveUpdates.updates, detail, cotTransactionTracking, vendorUpdates, customerUpdates, currentSelectedEntity);
|
|
167
|
+
const transUpdates = (0, exports.toTransactionUpdatePayload)(saveUpdates.updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, currentSelectedEntity);
|
|
166
168
|
const entityUpdates = toEntityUpdatePayload(saveUpdates.entityRelatedUpdates);
|
|
167
169
|
return {
|
|
168
170
|
entity_related_updates: entityUpdates,
|
|
@@ -172,7 +174,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
172
174
|
}
|
|
173
175
|
return undefined;
|
|
174
176
|
}
|
|
175
|
-
const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, vendorUpdates, customerUpdates, tranSelectedEntity) => {
|
|
177
|
+
const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, tranSelectedEntity) => {
|
|
176
178
|
const transaction = Object.assign({}, detail);
|
|
177
179
|
transaction.memo = updates.memo ?? '';
|
|
178
180
|
// Unlike `memo` (always reset to '' when absent), `documentId` falls back to
|
|
@@ -233,6 +235,28 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, ven
|
|
|
233
235
|
let basePayload;
|
|
234
236
|
if ((0, customerTransaction_1.isCustomerTransaction)(transaction)) {
|
|
235
237
|
basePayload = (0, customerTransactionPayload_1.toCustomerTransactionPayload)(transaction);
|
|
238
|
+
// For invoice/credit_memo only, project lives at the transaction level.
|
|
239
|
+
// Guard behind the projects feature flag to avoid touching the field when
|
|
240
|
+
// projects are disabled for this tenant. Clear-project (null injection) is
|
|
241
|
+
// intentionally out of scope for this change — the null write-back path will
|
|
242
|
+
// be added in a follow-up once the backend contract is confirmed.
|
|
243
|
+
if (isAccountingProjectsEnabled &&
|
|
244
|
+
(transaction.type === 'invoice' || transaction.type === 'credit_memo') &&
|
|
245
|
+
updates.project != null) {
|
|
246
|
+
basePayload = {
|
|
247
|
+
...basePayload,
|
|
248
|
+
accounting_project_id: updates.project.projectId,
|
|
249
|
+
// Only spread integration_id when we have a concrete value; omitting it
|
|
250
|
+
// avoids accidentally nulling out the server-side value when the load
|
|
251
|
+
// path didn't surface the field (e.g. list-shaped data or pre-deploy store).
|
|
252
|
+
...(updates.project.accountingProviderProjectId != null
|
|
253
|
+
? {
|
|
254
|
+
accounting_project_integration_id: updates.project.accountingProviderProjectId,
|
|
255
|
+
}
|
|
256
|
+
: {}),
|
|
257
|
+
accounting_project_name: updates.project.projectName,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
236
260
|
}
|
|
237
261
|
else if ((0, vendorTransaction_1.isVendorTransaction)(transaction)) {
|
|
238
262
|
if (tranSelectedEntity != null && tranSelectedEntity.type === 'customer') {
|
|
@@ -251,6 +275,7 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, ven
|
|
|
251
275
|
// Inject COT flags into the payload
|
|
252
276
|
return (0, transactionPayload_1.injectCOTFlagsIntoTransactionPayload)(basePayload, transaction);
|
|
253
277
|
};
|
|
278
|
+
exports.toTransactionUpdatePayload = toTransactionUpdatePayload;
|
|
254
279
|
const checkIfClassMissingForAnyLineItem = (transactionPayload) => {
|
|
255
280
|
let isAnyClassMissing = false;
|
|
256
281
|
if (transactionPayload.lines != null) {
|
|
@@ -15,6 +15,17 @@ const toTransactionDetailLocalData = (transaction, defaultVendorId, uncategorize
|
|
|
15
15
|
const vendorId = defaultVendorId ?? transaction.vendor?.id;
|
|
16
16
|
transactionLocal.memo = transaction.memo;
|
|
17
17
|
transactionLocal.documentId = transaction.documentId;
|
|
18
|
+
// Project is at the transaction level only for invoice and credit_memo.
|
|
19
|
+
if ((transaction.type === 'invoice' || transaction.type === 'credit_memo') &&
|
|
20
|
+
transaction.projectId != null) {
|
|
21
|
+
transactionLocal.project = {
|
|
22
|
+
projectId: transaction.projectId,
|
|
23
|
+
projectName: transaction.projectName ?? '',
|
|
24
|
+
...(transaction.accountingProviderProjectId != null
|
|
25
|
+
? { accountingProviderProjectId: transaction.accountingProviderProjectId }
|
|
26
|
+
: {}),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
18
29
|
transactionLocal.vendorUpdates =
|
|
19
30
|
(0, vendorTransaction_1.isVendorTransaction)(transaction) && vendorId != null
|
|
20
31
|
? {
|
|
@@ -429,6 +440,7 @@ const toUpdateLineItemsOriginalCategoryClass = (transaction, transactionDetailLo
|
|
|
429
440
|
...transactionDetailState_1.initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
430
441
|
memo: transactionDetailLocalData.memo,
|
|
431
442
|
documentId: transactionDetailLocalData.documentId,
|
|
443
|
+
project: transactionDetailLocalData.project,
|
|
432
444
|
lineItemById: newLineItems,
|
|
433
445
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
434
446
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
@@ -534,6 +546,7 @@ const toSetAllLineItemsToCategoryClass = (transaction, transactionDetailLocalDat
|
|
|
534
546
|
...transactionDetailState_1.initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
535
547
|
memo: transactionDetailLocalData.memo,
|
|
536
548
|
documentId: transactionDetailLocalData.documentId,
|
|
549
|
+
project: transactionDetailLocalData.project,
|
|
537
550
|
lineItemById: newLineItems,
|
|
538
551
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
539
552
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
@@ -580,6 +593,7 @@ const toSetAllLineItemsLocalDataIsUpdateAllChecked = (transaction, transactionDe
|
|
|
580
593
|
...transactionDetailState_1.initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
581
594
|
memo: transactionDetailLocalData.memo,
|
|
582
595
|
documentId: transactionDetailLocalData.documentId,
|
|
596
|
+
project: transactionDetailLocalData.project,
|
|
583
597
|
lineItemById: newLineItems,
|
|
584
598
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
585
599
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
@@ -738,6 +752,7 @@ const setEntityRecommendationForLineIdInLocalData = (transaction, transactionDet
|
|
|
738
752
|
...transactionDetailState_1.initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
739
753
|
memo: transactionDetailLocalData.memo,
|
|
740
754
|
documentId: transactionDetailLocalData.documentId,
|
|
755
|
+
project: transactionDetailLocalData.project,
|
|
741
756
|
lineItemById: newLineItems,
|
|
742
757
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
743
758
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
@@ -792,6 +807,7 @@ const removeEntityRecommendationForLineIdInLocalData = (transaction, transaction
|
|
|
792
807
|
...transactionDetailState_1.initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
793
808
|
memo: transactionDetailLocalData.memo,
|
|
794
809
|
documentId: transactionDetailLocalData.documentId,
|
|
810
|
+
project: transactionDetailLocalData.project,
|
|
795
811
|
lineItemById: newLineItems,
|
|
796
812
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
797
813
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
@@ -1015,6 +1031,7 @@ const toUpdateLineItemsToOriginalVendor = (transaction, transactionDetailLocalDa
|
|
|
1015
1031
|
...transactionDetailState_1.initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
1016
1032
|
memo: transactionDetailLocalData.memo,
|
|
1017
1033
|
documentId: transactionDetailLocalData.documentId,
|
|
1034
|
+
project: transactionDetailLocalData.project,
|
|
1018
1035
|
lineItemById: newLineItems,
|
|
1019
1036
|
isVendorUpdateAllChecked: false,
|
|
1020
1037
|
latestUpdatedLineWithEntity: transactionDetailLocalData.latestUpdatedLineWithEntity,
|
|
@@ -54,6 +54,7 @@ export interface TransactionDetailLocalData {
|
|
|
54
54
|
latestSelectedEntityOnLineItem?: Entity;
|
|
55
55
|
latestUpdatedLineWithEntity?: ID;
|
|
56
56
|
memo?: string;
|
|
57
|
+
project?: ProjectBase;
|
|
57
58
|
selectedEntity?: Entity;
|
|
58
59
|
updatePreviousTransactionsWithUpdatedVendor?: boolean;
|
|
59
60
|
vendorDetails?: {
|
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.25-betaRD2",
|
|
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",
|
|
@@ -79,6 +79,7 @@
|
|
|
79
79
|
"ts-prune": "^0.10.3",
|
|
80
80
|
"ts-unused-exports": "^11.0.1",
|
|
81
81
|
"typescript": "^5.7.3",
|
|
82
|
+
"vite": "^7.3.5",
|
|
82
83
|
"vitest": "^4.1.8"
|
|
83
84
|
},
|
|
84
85
|
"dependencies": {
|
|
@@ -129,7 +130,8 @@
|
|
|
129
130
|
"postversion": "git push && git push --tags",
|
|
130
131
|
"check-dependencies": "node ./scripts/check_dependencies.js",
|
|
131
132
|
"clean-overrides": "node ./scripts/clean_overrides.js",
|
|
132
|
-
"create-release-branch": "chmod +x ./scripts/
|
|
133
|
+
"create-or-update-release-branch": "chmod +x ./scripts/create_or_update_release_branch.sh && ./scripts/create_or_update_release_branch.sh",
|
|
134
|
+
"bump-versions-master": "chmod +x ./scripts/bump_versions_master.sh && ./scripts/bump_versions_master.sh",
|
|
133
135
|
"bump-update-web-app-cockpit-beta": "chmod +x ./scripts/bump_and_update_web_app_ui_beta.sh && ./scripts/bump_and_update_web_app_ui_beta.sh",
|
|
134
136
|
"send-release-notes": "chmod +x ./scripts/send_release_notes.sh && ./scripts/send_release_notes.sh",
|
|
135
137
|
"update-slack-group-topic": "chmod +x ./scripts/update-slack-group-topic.sh && ./scripts/update-slack-group-topic.sh",
|