@zeniai/client-epic-state 5.1.25 → 5.1.27
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 +1 -0
- 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/esm/entity/transaction/payloadTypes/transactionPayload.js +5 -0
- 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 +31 -4
- package/lib/esm/view/transactionDetail/transactionDetailLocalDataHelper.js +17 -0
- 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 +33 -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 +2 -1
package/README.md
CHANGED
|
@@ -91,6 +91,7 @@ Testing types with `tsc` and Vitest is an experimental feature. Breaking changes
|
|
|
91
91
|
- `pnpm clean-resolutions` — Cleans up resolutions using a custom script.
|
|
92
92
|
- `pnpm create-or-update-release-branch` — Runs the release branch creation/update script.
|
|
93
93
|
- `pnpm bump-versions-master` — Bumps versions and publishes all client repos on master end-to-end (per-repo PR + auto-merge + publish; v2 bumps only, no deploy).
|
|
94
|
+
- `pnpm bump-versions-beta` — Selectable upstream→downstream beta publish chain (CES / analytics / web-components / app-ui / cockpit) tagged `beta<initials>`. v2 step is a local-only dep repointing (no commit, no publish). Single-popup config.
|
|
94
95
|
- `pnpm bump-update-web-app-cockpit-beta` — Runs the cockpit beta update script.
|
|
95
96
|
- `pnpm send-release-notes` — Sends release notes using a custom script.
|
|
96
97
|
- `pnpm update-slack-group-topic` — Updates the Slack group topic using a custom script.
|
|
@@ -19,6 +19,7 @@ export interface TransactionPayload extends TransactionIDPayload, AccountBasePay
|
|
|
19
19
|
/** Transactions list API: preferred debit integration id for transfer flows */
|
|
20
20
|
account_integration_id?: string | null;
|
|
21
21
|
accounting_project_id?: string | null;
|
|
22
|
+
accounting_project_integration_id?: string | null;
|
|
22
23
|
accounting_project_name?: string | null;
|
|
23
24
|
amount?: number;
|
|
24
25
|
attachments?: AttachmentPayload[];
|
|
@@ -105,6 +105,11 @@ const toTransaction = (payload) => {
|
|
|
105
105
|
payload.accounting_project_id !== ''
|
|
106
106
|
? { projectId: payload.accounting_project_id }
|
|
107
107
|
: {}),
|
|
108
|
+
...(payload.accounting_project_integration_id != null
|
|
109
|
+
? {
|
|
110
|
+
accountingProviderProjectId: payload.accounting_project_integration_id,
|
|
111
|
+
}
|
|
112
|
+
: {}),
|
|
108
113
|
...(payload.accounting_project_name != null &&
|
|
109
114
|
payload.accounting_project_name !== ''
|
|
110
115
|
? { projectName: payload.accounting_project_name }
|
|
@@ -25,6 +25,7 @@ export interface Transaction extends BaseTransaction {
|
|
|
25
25
|
createTime: ZeniDate;
|
|
26
26
|
description: string;
|
|
27
27
|
isUpdatingTransaction: boolean;
|
|
28
|
+
accountingProviderProjectId?: ID;
|
|
28
29
|
accountIntegrationId?: string;
|
|
29
30
|
attachments?: Attachment[];
|
|
30
31
|
bookCloseDate?: ZeniDate;
|
|
@@ -101,6 +101,11 @@ export const toTransaction = (payload) => {
|
|
|
101
101
|
payload.accounting_project_id !== ''
|
|
102
102
|
? { projectId: payload.accounting_project_id }
|
|
103
103
|
: {}),
|
|
104
|
+
...(payload.accounting_project_integration_id != null
|
|
105
|
+
? {
|
|
106
|
+
accountingProviderProjectId: payload.accounting_project_integration_id,
|
|
107
|
+
}
|
|
108
|
+
: {}),
|
|
104
109
|
...(payload.accounting_project_name != null &&
|
|
105
110
|
payload.accounting_project_name !== ''
|
|
106
111
|
? { projectName: payload.accounting_project_name }
|
|
@@ -2,6 +2,7 @@ import recordGet from 'lodash/get';
|
|
|
2
2
|
import { from } from 'rxjs';
|
|
3
3
|
import { filter, mergeMap } from 'rxjs/operators';
|
|
4
4
|
import { getSupportedTransactionById } from '../../../entity/transaction/transactionSelector';
|
|
5
|
+
import { getIsAccountingProjectsEnabled } from '../../../entity/tenant/tenantSelector';
|
|
5
6
|
import { saveTransactionDetail, updateTransactionDetail, } from '../transactionDetailReducer';
|
|
6
7
|
import { getTransactionDetailKey } from '../transactionDetailState';
|
|
7
8
|
import { toTransactionUpdatesFromTransactionDetailLocalData } from './saveTransactionHelper';
|
|
@@ -10,12 +11,13 @@ export const saveTransactionDetailEpic = (actions$, state$) => actions$.pipe(fil
|
|
|
10
11
|
const fetchActions = [];
|
|
11
12
|
const transactionDetailState = state$.value.transactionDetailState;
|
|
12
13
|
const transactionState = state$.value.transactionState;
|
|
14
|
+
const isAccountingProjectsEnabled = getIsAccountingProjectsEnabled(state$.value);
|
|
13
15
|
const key = getTransactionDetailKey(transactionId);
|
|
14
16
|
const detail = recordGet(transactionDetailState.transactionDetailById, key, undefined);
|
|
15
17
|
const transaction = getSupportedTransactionById(transactionState, key);
|
|
16
18
|
if (detail != null && transaction != null) {
|
|
17
19
|
const localData = detail.transactionDetailLocalData;
|
|
18
|
-
const transactionSaveUpdates = toTransactionUpdatesFromTransactionDetailLocalData(localData, transaction, isExpenseAutomationEnabled);
|
|
20
|
+
const transactionSaveUpdates = toTransactionUpdatesFromTransactionDetailLocalData(localData, transaction, isExpenseAutomationEnabled, isAccountingProjectsEnabled);
|
|
19
21
|
fetchActions.push(updateTransactionDetail(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, cotTransactionTracking, isUncategorizedExpenseCategoryEnabled));
|
|
20
22
|
return from(fetchActions);
|
|
21
23
|
}
|
|
@@ -21,7 +21,7 @@ import { isAccountUncategorized } from '../transactionDetailLocalDataHelper';
|
|
|
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 const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLocalData, transaction, isExpenseAutomationEnabled) => {
|
|
24
|
+
export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLocalData, transaction, isExpenseAutomationEnabled, isAccountingProjectsEnabled = false) => {
|
|
25
25
|
const updates = {
|
|
26
26
|
updatesByLineId: {},
|
|
27
27
|
};
|
|
@@ -30,6 +30,12 @@ export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDe
|
|
|
30
30
|
const isTransactionMisCategorized = isTransactionMiscategorized(transaction, isExpenseAutomationEnabled);
|
|
31
31
|
updates.memo = transactionDetailLocalData.memo;
|
|
32
32
|
updates.documentId = transactionDetailLocalData.documentId;
|
|
33
|
+
// Project is at the transaction level only for invoice and credit_memo,
|
|
34
|
+
// and only when the projects feature is enabled for this tenant.
|
|
35
|
+
if (isAccountingProjectsEnabled &&
|
|
36
|
+
(transaction.type === 'invoice' || transaction.type === 'credit_memo')) {
|
|
37
|
+
updates.project = transactionDetailLocalData.project;
|
|
38
|
+
}
|
|
33
39
|
const selectedEntity = transactionDetailLocalData.selectedEntity;
|
|
34
40
|
const updatedEntityId = transactionDetailLocalData.updatePreviousTransactionsWithUpdatedVendor ===
|
|
35
41
|
true
|
|
@@ -52,7 +58,10 @@ export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDe
|
|
|
52
58
|
lineDescription: lineItem.lineDescription,
|
|
53
59
|
class: lineItem.class,
|
|
54
60
|
account: lineItem.account,
|
|
55
|
-
|
|
61
|
+
// Project is at the transaction level for invoice/credit_memo; omit from lines.
|
|
62
|
+
...(transaction.type !== 'invoice' && transaction.type !== 'credit_memo'
|
|
63
|
+
? { project: lineItem.project }
|
|
64
|
+
: {}),
|
|
56
65
|
recommendation: convertCOTRecommendationsToRegular(lineItem.recommendationsWithCOT),
|
|
57
66
|
};
|
|
58
67
|
if (line.type === 'journal_entry_transaction_line' ||
|
|
@@ -19,6 +19,7 @@ import { getSupportedTransactionById } from '../../../entity/transaction/transac
|
|
|
19
19
|
import { updateVendors } from '../../../entity/vendor/vendorReducer';
|
|
20
20
|
import { getVendorByVendorId } from '../../../entity/vendor/vendorSelector';
|
|
21
21
|
import { createZeniAPIStatus, isActionNotAllowed, isSuccessResponse, } from '../../../responsePayload';
|
|
22
|
+
import { getIsAccountingProjectsEnabled } from '../../../entity/tenant/tenantSelector';
|
|
22
23
|
import { getUncategorizedAccounts } from '../../accountList/accountListSelector';
|
|
23
24
|
import { getPendingReviewLineIdsFromTransaction } from '../../expenseAutomationView/helpers/transactionCategorizationLocalDataHelper';
|
|
24
25
|
import { syncTransactionCategorizationFromDetailSave } from '../../expenseAutomationView/reducers/transactionsViewReducer';
|
|
@@ -27,9 +28,10 @@ import { getTransactionDetailKey, } from '../transactionDetailState';
|
|
|
27
28
|
import { isTransactionUncategorized } from './saveTransactionHelper';
|
|
28
29
|
export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(updateTransactionDetail.match), mergeMap((action) => {
|
|
29
30
|
const { transactionState, vendorState, transactionDetailState } = state$.value;
|
|
31
|
+
const isAccountingProjectsEnabled = getIsAccountingProjectsEnabled(state$.value);
|
|
30
32
|
const { cotTransactionTracking, transactionId, transactionSaveUpdates, isUncategorizedExpenseCategoryEnabled, } = action.payload;
|
|
31
33
|
return zeniAPI
|
|
32
|
-
.putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${action.payload.transactionId.id}/categorize`, preparePayload(transactionState, vendorState, transactionDetailState, transactionId, transactionSaveUpdates, cotTransactionTracking))
|
|
34
|
+
.putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${action.payload.transactionId.id}/categorize`, preparePayload(transactionState, vendorState, transactionDetailState, transactionId, transactionSaveUpdates, cotTransactionTracking, isAccountingProjectsEnabled))
|
|
33
35
|
.pipe(mergeMap((response) => {
|
|
34
36
|
if (isSuccessResponse(response) && response.data != null) {
|
|
35
37
|
const transactionIdResp = toTransactionID(response.data.transaction);
|
|
@@ -123,7 +125,7 @@ export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => action
|
|
|
123
125
|
}
|
|
124
126
|
}), catchError((error) => of(updateTransactionDetailSaveStatus(action.payload.transactionId, 'Error', createZeniAPIStatus('Unexpected Error', `REST API call errored out ${error}`)))));
|
|
125
127
|
}));
|
|
126
|
-
function preparePayload(transactionState, vendorState, transactionDetailState, transactionId, saveUpdates, cotTransactionTracking) {
|
|
128
|
+
function preparePayload(transactionState, vendorState, transactionDetailState, transactionId, saveUpdates, cotTransactionTracking, isAccountingProjectsEnabled) {
|
|
127
129
|
const transactionDetailKey = getTransactionDetailKey(transactionId);
|
|
128
130
|
const detail = getSupportedTransactionById(transactionState, transactionDetailKey);
|
|
129
131
|
const tranDetail = recordGet(transactionDetailState.transactionDetailById, transactionDetailKey, undefined);
|
|
@@ -155,7 +157,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
155
157
|
};
|
|
156
158
|
}
|
|
157
159
|
if (detail != null) {
|
|
158
|
-
const transUpdates = toTransactionUpdatePayload(saveUpdates.updates, detail, cotTransactionTracking, vendorUpdates, customerUpdates, currentSelectedEntity);
|
|
160
|
+
const transUpdates = toTransactionUpdatePayload(saveUpdates.updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, currentSelectedEntity);
|
|
159
161
|
const entityUpdates = toEntityUpdatePayload(saveUpdates.entityRelatedUpdates);
|
|
160
162
|
return {
|
|
161
163
|
entity_related_updates: entityUpdates,
|
|
@@ -165,7 +167,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
165
167
|
}
|
|
166
168
|
return undefined;
|
|
167
169
|
}
|
|
168
|
-
const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, vendorUpdates, customerUpdates, tranSelectedEntity) => {
|
|
170
|
+
export const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, tranSelectedEntity) => {
|
|
169
171
|
const transaction = Object.assign({}, detail);
|
|
170
172
|
transaction.memo = updates.memo ?? '';
|
|
171
173
|
// Unlike `memo` (always reset to '' when absent), `documentId` falls back to
|
|
@@ -226,6 +228,31 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, ven
|
|
|
226
228
|
let basePayload;
|
|
227
229
|
if (isCustomerTransaction(transaction)) {
|
|
228
230
|
basePayload = toCustomerTransactionPayload(transaction);
|
|
231
|
+
// For invoice/credit_memo only, project lives at the transaction level.
|
|
232
|
+
// Guard behind the projects feature flag to avoid touching the field when
|
|
233
|
+
// projects are disabled for this tenant. Clear-project (null injection) is
|
|
234
|
+
// intentionally out of scope for this change — the null write-back path will
|
|
235
|
+
// be added in a follow-up once the backend contract is confirmed.
|
|
236
|
+
if (isAccountingProjectsEnabled &&
|
|
237
|
+
(transaction.type === 'invoice' || transaction.type === 'credit_memo') &&
|
|
238
|
+
updates.project != null) {
|
|
239
|
+
basePayload = {
|
|
240
|
+
...basePayload,
|
|
241
|
+
accounting_project_id: updates.project.projectId,
|
|
242
|
+
// Only spread integration_id / name when we have a concrete value; omitting
|
|
243
|
+
// them avoids accidentally nulling/blanking out the server-side value when
|
|
244
|
+
// the load path didn't surface the field (e.g. list-shaped data or pre-deploy
|
|
245
|
+
// store where the API returned projectId but not the name/integration_id).
|
|
246
|
+
...(updates.project.accountingProviderProjectId != null
|
|
247
|
+
? {
|
|
248
|
+
accounting_project_integration_id: updates.project.accountingProviderProjectId,
|
|
249
|
+
}
|
|
250
|
+
: {}),
|
|
251
|
+
...(updates.project.projectName
|
|
252
|
+
? { accounting_project_name: updates.project.projectName }
|
|
253
|
+
: {}),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
229
256
|
}
|
|
230
257
|
else if (isVendorTransaction(transaction)) {
|
|
231
258
|
if (tranSelectedEntity != null && tranSelectedEntity.type === 'customer') {
|
|
@@ -12,6 +12,17 @@ export const toTransactionDetailLocalData = (transaction, defaultVendorId, uncat
|
|
|
12
12
|
const vendorId = defaultVendorId ?? transaction.vendor?.id;
|
|
13
13
|
transactionLocal.memo = transaction.memo;
|
|
14
14
|
transactionLocal.documentId = transaction.documentId;
|
|
15
|
+
// Project is at the transaction level only for invoice and credit_memo.
|
|
16
|
+
if ((transaction.type === 'invoice' || transaction.type === 'credit_memo') &&
|
|
17
|
+
transaction.projectId != null) {
|
|
18
|
+
transactionLocal.project = {
|
|
19
|
+
projectId: transaction.projectId,
|
|
20
|
+
projectName: transaction.projectName ?? '',
|
|
21
|
+
...(transaction.accountingProviderProjectId != null
|
|
22
|
+
? { accountingProviderProjectId: transaction.accountingProviderProjectId }
|
|
23
|
+
: {}),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
15
26
|
transactionLocal.vendorUpdates =
|
|
16
27
|
isVendorTransaction(transaction) && vendorId != null
|
|
17
28
|
? {
|
|
@@ -423,6 +434,7 @@ export const toUpdateLineItemsOriginalCategoryClass = (transaction, transactionD
|
|
|
423
434
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
424
435
|
memo: transactionDetailLocalData.memo,
|
|
425
436
|
documentId: transactionDetailLocalData.documentId,
|
|
437
|
+
project: transactionDetailLocalData.project,
|
|
426
438
|
lineItemById: newLineItems,
|
|
427
439
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
428
440
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
@@ -527,6 +539,7 @@ export const toSetAllLineItemsToCategoryClass = (transaction, transactionDetailL
|
|
|
527
539
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
528
540
|
memo: transactionDetailLocalData.memo,
|
|
529
541
|
documentId: transactionDetailLocalData.documentId,
|
|
542
|
+
project: transactionDetailLocalData.project,
|
|
530
543
|
lineItemById: newLineItems,
|
|
531
544
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
532
545
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
@@ -572,6 +585,7 @@ export const toSetAllLineItemsLocalDataIsUpdateAllChecked = (transaction, transa
|
|
|
572
585
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
573
586
|
memo: transactionDetailLocalData.memo,
|
|
574
587
|
documentId: transactionDetailLocalData.documentId,
|
|
588
|
+
project: transactionDetailLocalData.project,
|
|
575
589
|
lineItemById: newLineItems,
|
|
576
590
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
577
591
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
@@ -729,6 +743,7 @@ export const setEntityRecommendationForLineIdInLocalData = (transaction, transac
|
|
|
729
743
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
730
744
|
memo: transactionDetailLocalData.memo,
|
|
731
745
|
documentId: transactionDetailLocalData.documentId,
|
|
746
|
+
project: transactionDetailLocalData.project,
|
|
732
747
|
lineItemById: newLineItems,
|
|
733
748
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
734
749
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
@@ -782,6 +797,7 @@ export const removeEntityRecommendationForLineIdInLocalData = (transaction, tran
|
|
|
782
797
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
783
798
|
memo: transactionDetailLocalData.memo,
|
|
784
799
|
documentId: transactionDetailLocalData.documentId,
|
|
800
|
+
project: transactionDetailLocalData.project,
|
|
785
801
|
lineItemById: newLineItems,
|
|
786
802
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
787
803
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
@@ -1002,6 +1018,7 @@ export const toUpdateLineItemsToOriginalVendor = (transaction, transactionDetail
|
|
|
1002
1018
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
1003
1019
|
memo: transactionDetailLocalData.memo,
|
|
1004
1020
|
documentId: transactionDetailLocalData.documentId,
|
|
1021
|
+
project: transactionDetailLocalData.project,
|
|
1005
1022
|
lineItemById: newLineItems,
|
|
1006
1023
|
isVendorUpdateAllChecked: false,
|
|
1007
1024
|
latestUpdatedLineWithEntity: transactionDetailLocalData.latestUpdatedLineWithEntity,
|
|
@@ -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,31 @@ 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 / name when we have a concrete value; omitting
|
|
250
|
+
// them avoids accidentally nulling/blanking out the server-side value when
|
|
251
|
+
// the load path didn't surface the field (e.g. list-shaped data or pre-deploy
|
|
252
|
+
// store where the API returned projectId but not the name/integration_id).
|
|
253
|
+
...(updates.project.accountingProviderProjectId != null
|
|
254
|
+
? {
|
|
255
|
+
accounting_project_integration_id: updates.project.accountingProviderProjectId,
|
|
256
|
+
}
|
|
257
|
+
: {}),
|
|
258
|
+
...(updates.project.projectName
|
|
259
|
+
? { accounting_project_name: updates.project.projectName }
|
|
260
|
+
: {}),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
236
263
|
}
|
|
237
264
|
else if ((0, vendorTransaction_1.isVendorTransaction)(transaction)) {
|
|
238
265
|
if (tranSelectedEntity != null && tranSelectedEntity.type === 'customer') {
|
|
@@ -251,6 +278,7 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, ven
|
|
|
251
278
|
// Inject COT flags into the payload
|
|
252
279
|
return (0, transactionPayload_1.injectCOTFlagsIntoTransactionPayload)(basePayload, transaction);
|
|
253
280
|
};
|
|
281
|
+
exports.toTransactionUpdatePayload = toTransactionUpdatePayload;
|
|
254
282
|
const checkIfClassMissingForAnyLineItem = (transactionPayload) => {
|
|
255
283
|
let isAnyClassMissing = false;
|
|
256
284
|
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.27",
|
|
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",
|
|
@@ -132,6 +132,7 @@
|
|
|
132
132
|
"clean-overrides": "node ./scripts/clean_overrides.js",
|
|
133
133
|
"create-or-update-release-branch": "chmod +x ./scripts/create_or_update_release_branch.sh && ./scripts/create_or_update_release_branch.sh",
|
|
134
134
|
"bump-versions-master": "chmod +x ./scripts/bump_versions_master.sh && ./scripts/bump_versions_master.sh",
|
|
135
|
+
"bump-versions-beta": "chmod +x ./scripts/bump_versions_beta.sh && ./scripts/bump_versions_beta.sh",
|
|
135
136
|
"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",
|
|
136
137
|
"send-release-notes": "chmod +x ./scripts/send_release_notes.sh && ./scripts/send_release_notes.sh",
|
|
137
138
|
"update-slack-group-topic": "chmod +x ./scripts/update-slack-group-topic.sh && ./scripts/update-slack-group-topic.sh",
|