@zeniai/client-epic-state 5.1.45 → 5.1.46
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/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.js +3 -0
- package/lib/entity/task/taskPayload.d.ts +3 -1
- package/lib/entity/task/taskPayload.js +24 -2
- package/lib/entity/task/taskReducer.d.ts +8 -1
- package/lib/entity/task/taskReducer.js +29 -4
- package/lib/entity/task/taskState.d.ts +2 -0
- package/lib/entity/tenant/epic/saveExternalConnectionEpic.d.ts +2 -1
- package/lib/entity/tenant/epic/saveExternalConnectionEpic.js +17 -0
- package/lib/epic.d.ts +6 -3
- package/lib/epic.js +6 -3
- package/lib/esm/entity/snackbar/snackbarTypes.js +3 -0
- package/lib/esm/entity/task/taskPayload.js +24 -2
- package/lib/esm/entity/task/taskReducer.js +28 -3
- package/lib/esm/entity/tenant/epic/saveExternalConnectionEpic.js +17 -0
- package/lib/esm/epic.js +6 -3
- package/lib/esm/index.js +8 -8
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +31 -1
- package/lib/esm/view/aiCfoView/epics/fetchSkillsEpic.js +33 -8
- package/lib/esm/view/aiCfoView/epics/submitFeedbackEpic.js +39 -0
- package/lib/esm/view/companyTaskManagerView/epics/fetchCompanyTaskManagerViewEpic.js +3 -0
- package/lib/esm/view/companyTaskManagerView/epics/fetchTaskManagerMetricsEpic.js +7 -1
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +7 -0
- package/lib/esm/view/taskManager/taskDetailView/epics/createSubTaskEpic.js +96 -0
- package/lib/esm/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.js +53 -0
- package/lib/esm/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +1 -0
- package/lib/esm/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +70 -9
- package/lib/esm/view/taskManager/taskDetailView/taskDetailReducer.js +56 -2
- package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +35 -9
- package/lib/esm/view/taskManager/taskListView/epics/fetchTaskListEpic.js +3 -1
- package/lib/esm/view/taskManager/taskListView/taskList.js +1 -0
- package/lib/esm/view/taskManager/taskListView/taskListReducer.js +310 -18
- package/lib/esm/view/taskManager/taskListView/taskListSelector.js +1 -0
- package/lib/esm/view/taskManager/taskListView/taskListViewHelpers.js +58 -0
- package/lib/esm/view/transactionDetail/epics/saveTransactionHelper.js +22 -0
- package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +75 -3
- package/lib/esm/view/transactionDetail/journalEntryLinesViewModel.js +58 -0
- package/lib/esm/view/transactionDetail/transactionDetailLocalDataHelper.js +10 -8
- package/lib/esm/view/transactionDetail/transactionDetailReducer.js +66 -1
- package/lib/index.d.ts +12 -11
- package/lib/index.js +37 -28
- package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +10 -0
- package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +7 -2
- package/lib/view/aiCfoView/aiCfoViewReducer.js +32 -2
- package/lib/view/aiCfoView/aiCfoViewState.d.ts +5 -1
- package/lib/view/aiCfoView/epics/fetchSkillsEpic.js +33 -8
- package/lib/view/aiCfoView/epics/submitFeedbackEpic.d.ts +13 -0
- package/lib/view/aiCfoView/epics/submitFeedbackEpic.js +43 -0
- package/lib/view/companyTaskManagerView/epics/fetchCompanyTaskManagerViewEpic.js +3 -0
- package/lib/view/companyTaskManagerView/epics/fetchTaskManagerMetricsEpic.js +7 -1
- package/lib/view/companyView/types/cockpitTypes.d.ts +3 -0
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +7 -0
- package/lib/view/taskManager/taskDetailView/epics/createSubTaskEpic.d.ts +9 -0
- package/lib/view/taskManager/taskDetailView/epics/createSubTaskEpic.js +100 -0
- package/lib/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.d.ts +8 -0
- package/lib/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.js +57 -0
- package/lib/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +1 -0
- package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.d.ts +2 -2
- package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +69 -8
- package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +15 -0
- package/lib/view/taskManager/taskDetailView/taskDetailReducer.d.ts +14 -2
- package/lib/view/taskManager/taskDetailView/taskDetailReducer.js +57 -3
- package/lib/view/taskManager/taskDetailView/taskDetailSelector.d.ts +3 -1
- package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +33 -7
- package/lib/view/taskManager/taskListView/epics/fetchTaskListEpic.js +3 -1
- package/lib/view/taskManager/taskListView/taskList.d.ts +1 -1
- package/lib/view/taskManager/taskListView/taskList.js +1 -0
- package/lib/view/taskManager/taskListView/taskListPayload.d.ts +4 -0
- package/lib/view/taskManager/taskListView/taskListReducer.d.ts +6 -2
- package/lib/view/taskManager/taskListView/taskListReducer.js +311 -19
- package/lib/view/taskManager/taskListView/taskListSelector.js +1 -0
- package/lib/view/taskManager/taskListView/taskListViewHelpers.d.ts +11 -0
- package/lib/view/taskManager/taskListView/taskListViewHelpers.js +60 -1
- package/lib/view/transactionDetail/epics/saveTransactionHelper.js +22 -0
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.d.ts +5 -1
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +77 -4
- package/lib/view/transactionDetail/journalEntryLinesViewModel.d.ts +27 -0
- package/lib/view/transactionDetail/journalEntryLinesViewModel.js +61 -1
- package/lib/view/transactionDetail/transactionDetailLocalDataHelper.js +10 -8
- package/lib/view/transactionDetail/transactionDetailReducer.d.ts +11 -2
- package/lib/view/transactionDetail/transactionDetailReducer.js +67 -2
- package/lib/view/transactionDetail/transactionDetailState.d.ts +8 -1
- package/lib/view/transactionDetail/transactionDetailTypes.d.ts +2 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getTaskUpdates = exports.getDueDateValueFromDueDateGroupId = void 0;
|
|
3
|
+
exports.sortSubtasks = exports.getTaskUpdates = exports.getDueDateValueFromDueDateGroupId = void 0;
|
|
4
4
|
const zeniDayJS_1 = require("../../../zeniDayJS");
|
|
5
5
|
const taskDetailSelector_1 = require("../taskDetailView/taskDetailSelector");
|
|
6
6
|
const taskList_1 = require("./taskList");
|
|
@@ -53,3 +53,62 @@ const getTaskUpdates = (groupByKey, groupId) => {
|
|
|
53
53
|
};
|
|
54
54
|
};
|
|
55
55
|
exports.getTaskUpdates = getTaskUpdates;
|
|
56
|
+
/**
|
|
57
|
+
* Sort a subtask list by one of the sortable columns. Pure — no state
|
|
58
|
+
* dependency. `statusOrder` is derived from `allTaskStatus` so any new
|
|
59
|
+
* status added upstream slots in by its enum position instead of
|
|
60
|
+
* falling into a catch-all bucket.
|
|
61
|
+
*/
|
|
62
|
+
const sortSubtasks = (subtasks, sortKey, sortOrder, userList, tagList) => {
|
|
63
|
+
if (sortKey == null) {
|
|
64
|
+
return subtasks;
|
|
65
|
+
}
|
|
66
|
+
const statusOrder = taskDetailSelector_1.allTaskStatus.reduce((acc, status, index) => {
|
|
67
|
+
acc[status.code] = index;
|
|
68
|
+
return acc;
|
|
69
|
+
}, {});
|
|
70
|
+
const unknownStatusRank = taskDetailSelector_1.allTaskStatus.length;
|
|
71
|
+
const cmpStr = (a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' });
|
|
72
|
+
const keyFn = (task) => {
|
|
73
|
+
if (sortKey === 'name') {
|
|
74
|
+
return task.name ?? '';
|
|
75
|
+
}
|
|
76
|
+
if (sortKey === 'status') {
|
|
77
|
+
return statusOrder[task.status.code] ?? unknownStatusRank;
|
|
78
|
+
}
|
|
79
|
+
if (sortKey === 'assignee') {
|
|
80
|
+
const firstId = task.assignees?.[0];
|
|
81
|
+
if (firstId == null) {
|
|
82
|
+
return '';
|
|
83
|
+
}
|
|
84
|
+
const user = userList.find((candidate) => candidate.userId === firstId);
|
|
85
|
+
return user
|
|
86
|
+
? `${user.firstName ?? ''} ${user.lastName ?? ''}`.trim()
|
|
87
|
+
: '';
|
|
88
|
+
}
|
|
89
|
+
if (sortKey === 'tag') {
|
|
90
|
+
const firstTagId = task.tagIds?.[0];
|
|
91
|
+
if (firstTagId == null) {
|
|
92
|
+
return '';
|
|
93
|
+
}
|
|
94
|
+
const tag = tagList.find((candidate) => candidate.tagId === firstTagId);
|
|
95
|
+
return tag?.name ?? '';
|
|
96
|
+
}
|
|
97
|
+
return '';
|
|
98
|
+
};
|
|
99
|
+
const copy = [...subtasks];
|
|
100
|
+
copy.sort((a, b) => {
|
|
101
|
+
const av = keyFn(a);
|
|
102
|
+
const bv = keyFn(b);
|
|
103
|
+
let cmp;
|
|
104
|
+
if (typeof av === 'number' && typeof bv === 'number') {
|
|
105
|
+
cmp = av - bv;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
cmp = cmpStr(String(av), String(bv));
|
|
109
|
+
}
|
|
110
|
+
return sortOrder === 'asc' ? cmp : -cmp;
|
|
111
|
+
});
|
|
112
|
+
return copy;
|
|
113
|
+
};
|
|
114
|
+
exports.sortSubtasks = sortSubtasks;
|
|
@@ -48,7 +48,15 @@ const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLoc
|
|
|
48
48
|
let lastUpdatedCategory;
|
|
49
49
|
let lastUpdatedClass;
|
|
50
50
|
// single recommendation to just pick the last recommendation in the list of lines
|
|
51
|
+
const existingLineIds = new Set(transaction.lines?.map((l) => l.id) ?? []);
|
|
52
|
+
const deletedLineIds = new Set((transactionDetailLocalData.deletedLineIds ?? []).filter((id) => existingLineIds.has(id)));
|
|
53
|
+
// Collect new lines — in lineItemById but not yet in transaction.lines.
|
|
54
|
+
const addedLines = Object.values(transactionDetailLocalData.lineItemById).filter((item) => !existingLineIds.has(item.id));
|
|
51
55
|
transaction.lines?.forEach((line) => {
|
|
56
|
+
// Skip lines the user deleted in edit mode.
|
|
57
|
+
if (deletedLineIds.has(line.id)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
52
60
|
const lineItem = transactionDetailLocalData.lineItemById[line.id];
|
|
53
61
|
if (line.type === 'transaction_with_account_and_class_line' ||
|
|
54
62
|
line.type === 'transaction_with_product_or_service_line' ||
|
|
@@ -59,6 +67,7 @@ const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLoc
|
|
|
59
67
|
const entityDetails = getEntityDetails(selectedEntity, lineItem, transactionDetailLocalData.vendorUpdates, transactionDetailLocalData.customerUpdates);
|
|
60
68
|
updatesByLineId[line.id] = {
|
|
61
69
|
lineDescription: lineItem.lineDescription,
|
|
70
|
+
amount: lineItem.amount,
|
|
62
71
|
class: lineItem.class,
|
|
63
72
|
account: lineItem.account,
|
|
64
73
|
// Project is at the transaction level for invoice/credit_memo; omit from lines.
|
|
@@ -80,6 +89,17 @@ const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLoc
|
|
|
80
89
|
currentSelectedEntityLine.type === 'vendor'
|
|
81
90
|
? lineItem.vendor
|
|
82
91
|
: undefined,
|
|
92
|
+
// Carry the JE debit/credit side so a split edit that flips an
|
|
93
|
+
// existing line's posting side persists through the line patch.
|
|
94
|
+
...(line.type === 'journal_entry_transaction_line'
|
|
95
|
+
? {
|
|
96
|
+
postingType: lineItem.postingType,
|
|
97
|
+
postingTypeName: lineItem.postingType != null
|
|
98
|
+
? lineItem.postingType.charAt(0).toUpperCase() +
|
|
99
|
+
lineItem.postingType.slice(1)
|
|
100
|
+
: lineItem.postingTypeName,
|
|
101
|
+
}
|
|
102
|
+
: {}),
|
|
83
103
|
};
|
|
84
104
|
}
|
|
85
105
|
let hasCategoryChanged = false;
|
|
@@ -166,6 +186,8 @@ const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLoc
|
|
|
166
186
|
and all the line items are NOT uncategorized*/
|
|
167
187
|
markAsMiscatUpdates: isTransactionMisCategorized,
|
|
168
188
|
anyBulkUpdates: isBulkUpdate,
|
|
189
|
+
addedLines: addedLines.length > 0 ? addedLines : undefined,
|
|
190
|
+
deletedLineIds: deletedLineIds.size > 0 ? [...deletedLineIds] : undefined,
|
|
169
191
|
};
|
|
170
192
|
};
|
|
171
193
|
exports.toTransactionUpdatesFromTransactionDetailLocalData = toTransactionUpdatesFromTransactionDetailLocalData;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
|
+
import { ID } from '../../../commonStateTypes/common';
|
|
2
3
|
import { COTTransactionTracking } from '../../../commonStateTypes/recommendationBase';
|
|
3
4
|
import { CustomerBase } from '../../../entity/customer/customerState';
|
|
4
5
|
import { Entity } from '../../../entity/genericEntity/entity';
|
|
5
6
|
import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
6
7
|
import { TransactionPayload } from '../../../entity/transaction/payloadTypes/transactionPayload';
|
|
8
|
+
import { Line } from '../../../entity/transaction/stateTypes/transactionLine';
|
|
7
9
|
import { updateTransaction, updateTransactions } from '../../../entity/transaction/transactionReducer';
|
|
8
10
|
import { SupportedTransaction } from '../../../entity/transaction/transactionState';
|
|
9
11
|
import { updateVendors } from '../../../entity/vendor/vendorReducer';
|
|
@@ -13,6 +15,8 @@ import { ZeniAPI } from '../../../zeniAPI';
|
|
|
13
15
|
import { syncTransactionCategorizationFromDetailSave } from '../../expenseAutomationView/reducers/transactionsViewReducer';
|
|
14
16
|
import { initializeTransactionDetailLocalData, markTransactionAsNotMiscategorized, updateStatusConsolidatedSaveTransactionDetail, updateTransactionDetail, updateTransactionDetailSaveStatus, updateTransactionStateIfUpdateActionNotAllowed } from '../transactionDetailReducer';
|
|
15
17
|
import { TransactionUpdates } from '../transactionDetailState';
|
|
18
|
+
import { TransactionDetailLineItemData } from '../transactionDetailTypes';
|
|
16
19
|
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>;
|
|
17
20
|
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>;
|
|
21
|
+
export declare const toTransactionUpdatePayload: (updates: TransactionUpdates, detail: SupportedTransaction, cotTransactionTracking: COTTransactionTracking, isAccountingProjectsEnabled: boolean, vendorUpdates?: VendorBase, customerUpdates?: CustomerBase, tranSelectedEntity?: Entity, deletedLineIds?: ID[], addedLines?: TransactionDetailLineItemData[]) => Partial<TransactionPayload>;
|
|
22
|
+
export declare const toNewTransactionLine: (item: TransactionDetailLineItemData) => Line;
|
|
@@ -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.toTransactionUpdatePayload = exports.updateTransactionDetailEpic = void 0;
|
|
6
|
+
exports.toNewTransactionLine = 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");
|
|
@@ -64,7 +64,9 @@ const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
64
64
|
if (response.data.vendors != null) {
|
|
65
65
|
actions.push((0, vendorReducer_1.updateVendors)(response.data.vendors, 'merge'));
|
|
66
66
|
}
|
|
67
|
-
|
|
67
|
+
// 'replace' so deleted lines are removed from Redux; 'merge' would
|
|
68
|
+
// keep any line absent from the server response (deletion bug).
|
|
69
|
+
actions.push((0, transactionReducer_1.updateTransaction)(transactionDetailKeyForResponse, response.data.transaction, 'replace'));
|
|
68
70
|
actions.push((0, transactionDetailReducer_1.initializeTransactionDetailLocalData)({
|
|
69
71
|
transactionId: transactionIdResp,
|
|
70
72
|
vendorId: response.data.vendors?.[0]?.vendor_id,
|
|
@@ -166,7 +168,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
166
168
|
};
|
|
167
169
|
}
|
|
168
170
|
if (detail != null) {
|
|
169
|
-
const transUpdates = (0, exports.toTransactionUpdatePayload)(saveUpdates.updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, currentSelectedEntity);
|
|
171
|
+
const transUpdates = (0, exports.toTransactionUpdatePayload)(saveUpdates.updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, currentSelectedEntity, saveUpdates.deletedLineIds, saveUpdates.addedLines);
|
|
170
172
|
const entityUpdates = toEntityUpdatePayload(saveUpdates.entityRelatedUpdates);
|
|
171
173
|
return {
|
|
172
174
|
entity_related_updates: entityUpdates,
|
|
@@ -176,7 +178,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
176
178
|
}
|
|
177
179
|
return undefined;
|
|
178
180
|
}
|
|
179
|
-
const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, tranSelectedEntity) => {
|
|
181
|
+
const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, tranSelectedEntity, deletedLineIds, addedLines) => {
|
|
180
182
|
const transaction = Object.assign({}, detail);
|
|
181
183
|
transaction.memo = updates.memo ?? '';
|
|
182
184
|
// Unlike `memo` (always reset to '' when absent), `documentId` falls back to
|
|
@@ -185,6 +187,11 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isA
|
|
|
185
187
|
// either the unchanged current value or undefined, and we must not send an
|
|
186
188
|
// empty `document_id` that the server would treat as clearing the number.
|
|
187
189
|
transaction.documentId = updates.documentId ?? transaction.documentId;
|
|
190
|
+
// Remove lines deleted by the user in edit mode before patching or serializing.
|
|
191
|
+
if (deletedLineIds != null && deletedLineIds.length > 0) {
|
|
192
|
+
const deletedSet = new Set(deletedLineIds);
|
|
193
|
+
transaction.lines = transaction.lines?.filter((line) => !deletedSet.has(line.id));
|
|
194
|
+
}
|
|
188
195
|
const recommendationUpdates = {};
|
|
189
196
|
for (const key in updates.updatesByLineId) {
|
|
190
197
|
const lineUpdates = updates.updatesByLineId[key];
|
|
@@ -192,6 +199,9 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isA
|
|
|
192
199
|
if (line.id === key) {
|
|
193
200
|
const lineTobeUpdated = Object.assign({}, line);
|
|
194
201
|
lineTobeUpdated.lineDescription = lineUpdates.lineDescription ?? '';
|
|
202
|
+
if (lineUpdates.amount != null) {
|
|
203
|
+
lineTobeUpdated.amount = lineUpdates.amount;
|
|
204
|
+
}
|
|
195
205
|
if (lineUpdates.class != null) {
|
|
196
206
|
lineTobeUpdated.class = lineUpdates.class;
|
|
197
207
|
}
|
|
@@ -213,6 +223,16 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isA
|
|
|
213
223
|
else {
|
|
214
224
|
lineTobeUpdated.vendor = undefined;
|
|
215
225
|
}
|
|
226
|
+
// Persist a debit↔credit flip on an existing JE line. `lineTobeUpdated`
|
|
227
|
+
// is typed as the account-and-class shape, but for a JE the runtime
|
|
228
|
+
// object is a JournalEntryTransactionLine, so cast to set the side.
|
|
229
|
+
if (lineUpdates.postingType != null) {
|
|
230
|
+
const journalEntryLine = lineTobeUpdated;
|
|
231
|
+
journalEntryLine.postingType = lineUpdates.postingType;
|
|
232
|
+
if (lineUpdates.postingTypeName != null) {
|
|
233
|
+
journalEntryLine.postingTypeName = lineUpdates.postingTypeName;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
216
236
|
if (lineUpdates.recommendation != null) {
|
|
217
237
|
recommendationUpdates[line.id] = lineUpdates.recommendation;
|
|
218
238
|
}
|
|
@@ -232,6 +252,12 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isA
|
|
|
232
252
|
});
|
|
233
253
|
transaction.lines = newLineMap;
|
|
234
254
|
}
|
|
255
|
+
// Append lines added by the user in edit mode. Sending id='' tells the
|
|
256
|
+
// backend to create a new QBO line rather than updating an existing one.
|
|
257
|
+
if (addedLines != null && addedLines.length > 0) {
|
|
258
|
+
const newLines = addedLines.map(exports.toNewTransactionLine);
|
|
259
|
+
transaction.lines = [...(transaction.lines ?? []), ...newLines];
|
|
260
|
+
}
|
|
235
261
|
transaction.recommendations = recommendationUpdates;
|
|
236
262
|
// Convert transaction to payload first
|
|
237
263
|
let basePayload;
|
|
@@ -307,6 +333,53 @@ const checkIfVendorOrCustomerMissingForAnyLineItem = (transactionPayload) => {
|
|
|
307
333
|
}
|
|
308
334
|
return isAnyVendorOrCustomerMissing;
|
|
309
335
|
};
|
|
336
|
+
// Converts a locally-created line item (from edit mode) into the wire shape
|
|
337
|
+
// expected by the categorize endpoint. Sending id='' signals the backend to
|
|
338
|
+
// create a new QBO line rather than update an existing one.
|
|
339
|
+
//
|
|
340
|
+
// Type-dispatched so each transaction family contributes its own new-line
|
|
341
|
+
// shape: journal entries carry debit/credit `postingType`, expenses carry
|
|
342
|
+
// `billable`. Phase 3 types extend this by adding a branch rather than forking
|
|
343
|
+
// the function.
|
|
344
|
+
const EMPTY_ACCOUNT = {
|
|
345
|
+
accountDescription: '',
|
|
346
|
+
accountId: '',
|
|
347
|
+
accountName: '',
|
|
348
|
+
labels: [],
|
|
349
|
+
};
|
|
350
|
+
const toNewTransactionLine = (item) => {
|
|
351
|
+
if (item.type === 'journal_entry_transaction_line') {
|
|
352
|
+
const journalEntryLine = {
|
|
353
|
+
...item,
|
|
354
|
+
id: '',
|
|
355
|
+
type: 'journal_entry_transaction_line',
|
|
356
|
+
platformLineDetailType: item.platformLineDetailType ?? 'journal_entry_line_detail',
|
|
357
|
+
account: item.account ?? EMPTY_ACCOUNT,
|
|
358
|
+
billable: item.billable ?? 'not_billable',
|
|
359
|
+
isCategoryMiscategorized: false,
|
|
360
|
+
isClassMiscategorized: false,
|
|
361
|
+
lineTransactionType: item.lineTransactionType ?? 'journal_entry',
|
|
362
|
+
postingType: item.postingType ?? 'debit',
|
|
363
|
+
postingTypeName: item.postingTypeName != null && item.postingTypeName !== ''
|
|
364
|
+
? item.postingTypeName
|
|
365
|
+
: (item.postingType ?? 'debit').charAt(0).toUpperCase() +
|
|
366
|
+
(item.postingType ?? 'debit').slice(1),
|
|
367
|
+
};
|
|
368
|
+
return journalEntryLine;
|
|
369
|
+
}
|
|
370
|
+
const accountAndClassLine = {
|
|
371
|
+
...item,
|
|
372
|
+
id: '',
|
|
373
|
+
type: 'transaction_with_account_and_class_line',
|
|
374
|
+
platformLineDetailType: item.platformLineDetailType ?? 'account_based_expense_line_detail',
|
|
375
|
+
account: item.account ?? EMPTY_ACCOUNT,
|
|
376
|
+
billable: item.billable ?? 'not_billable',
|
|
377
|
+
isCategoryMiscategorized: false,
|
|
378
|
+
isClassMiscategorized: false,
|
|
379
|
+
};
|
|
380
|
+
return accountAndClassLine;
|
|
381
|
+
};
|
|
382
|
+
exports.toNewTransactionLine = toNewTransactionLine;
|
|
310
383
|
const toEntityUpdatePayload = (entityUpdates) => {
|
|
311
384
|
const entityUpdatesPayload = [];
|
|
312
385
|
let entityKey;
|
|
@@ -64,6 +64,33 @@ export declare const journalEntryTotalsByPostingSide: (lines: ReadonlyArray<Pick
|
|
|
64
64
|
creditTotal?: Amount;
|
|
65
65
|
debitTotal?: Amount;
|
|
66
66
|
};
|
|
67
|
+
type PostingBearer = Pick<JournalEntryTransactionLine, 'amount' | 'postingType'>;
|
|
68
|
+
export interface JournalEntrySplitReconciliation {
|
|
69
|
+
creditTotal: number;
|
|
70
|
+
debitTotal: number;
|
|
71
|
+
/** Total debits == total credits == original transaction total. */
|
|
72
|
+
isBalanced: boolean;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Sums debit and credit sides (big.js-exact) and reports whether the split is
|
|
76
|
+
* balanced: total debits equal total credits AND equal the original
|
|
77
|
+
* transaction total. The original total of a valid JE equals its total debits,
|
|
78
|
+
* so it is passed in by the caller (`transaction.amount.amount`).
|
|
79
|
+
*/
|
|
80
|
+
export declare const journalEntrySplitReconciliation: (lines: ReadonlyArray<PostingBearer>, originalTotal: number) => JournalEntrySplitReconciliation;
|
|
81
|
+
export type JournalEntrySplitErrorKey = 'lineNeedsDebitOrCredit' | 'totalsMustEqual';
|
|
82
|
+
export interface JournalEntrySplitValidation {
|
|
83
|
+
ok: boolean;
|
|
84
|
+
errorKey?: JournalEntrySplitErrorKey;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Save-time validation for a JE split (Figma `4165:33028` / `4165:45379`):
|
|
88
|
+
* 1. every line needs a non-zero debit or credit, and
|
|
89
|
+
* 2. total debits == total credits == original total.
|
|
90
|
+
* Returns the first failing rule's `errorKey` (maps to a strings entry). Does
|
|
91
|
+
* NOT require category/class to be chosen — balance is the only gate.
|
|
92
|
+
*/
|
|
93
|
+
export declare const validateJournalEntrySplit: (lines: ReadonlyArray<PostingBearer>, originalTotal: number) => JournalEntrySplitValidation;
|
|
67
94
|
/**
|
|
68
95
|
* Drops `linked_transaction_line` entries — equivalent to legacy
|
|
69
96
|
* `filterOutLinkedTransactionLine` in `transactionDetail.helpers.ts`.
|
|
@@ -3,7 +3,8 @@ 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.sortJournalEntryLines = exports.filterJournalEntryLinesExcludingLinked = exports.journalEntryTotalsByPostingSide = exports.sumJournalEntryAmounts = exports.journalEntryDefaultSortConfig = exports.toJournalEntrySortKey = exports.JOURNAL_ENTRY_SORT_KEYS = void 0;
|
|
6
|
+
exports.sortJournalEntryLines = exports.filterJournalEntryLinesExcludingLinked = exports.validateJournalEntrySplit = exports.journalEntrySplitReconciliation = exports.journalEntryTotalsByPostingSide = exports.sumJournalEntryAmounts = exports.journalEntryDefaultSortConfig = exports.toJournalEntrySortKey = exports.JOURNAL_ENTRY_SORT_KEYS = void 0;
|
|
7
|
+
const big_js_1 = __importDefault(require("big.js"));
|
|
7
8
|
const orderBy_1 = __importDefault(require("lodash/orderBy"));
|
|
8
9
|
const stringToUnion_1 = require("../../commonStateTypes/stringToUnion");
|
|
9
10
|
const transactionLine_1 = require("../../entity/transaction/stateTypes/transactionLine");
|
|
@@ -110,6 +111,65 @@ const journalEntryTotalsByPostingSide = (lines) => {
|
|
|
110
111
|
};
|
|
111
112
|
exports.journalEntryTotalsByPostingSide = journalEntryTotalsByPostingSide;
|
|
112
113
|
// ---------------------------------------------------------------------------
|
|
114
|
+
// Split reconciliation & validation (Phase 2 — JE split)
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// Half-cent tolerance for the balance equality checks, matching the expense
|
|
117
|
+
// reconciliation row's epsilon. Sums use big.js so repeated decimal addition
|
|
118
|
+
// doesn't drift before the comparison.
|
|
119
|
+
const JOURNAL_ENTRY_BALANCE_EPSILON = 0.005;
|
|
120
|
+
/**
|
|
121
|
+
* Sums debit and credit sides (big.js-exact) and reports whether the split is
|
|
122
|
+
* balanced: total debits equal total credits AND equal the original
|
|
123
|
+
* transaction total. The original total of a valid JE equals its total debits,
|
|
124
|
+
* so it is passed in by the caller (`transaction.amount.amount`).
|
|
125
|
+
*/
|
|
126
|
+
const journalEntrySplitReconciliation = (lines, originalTotal) => {
|
|
127
|
+
let debit = new big_js_1.default(0);
|
|
128
|
+
let credit = new big_js_1.default(0);
|
|
129
|
+
for (const line of lines) {
|
|
130
|
+
const amount = new big_js_1.default(line.amount?.amount ?? 0);
|
|
131
|
+
if (line.postingType === 'debit') {
|
|
132
|
+
debit = debit.plus(amount);
|
|
133
|
+
}
|
|
134
|
+
else if (line.postingType === 'credit') {
|
|
135
|
+
credit = credit.plus(amount);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const balancedToEachOther = debit
|
|
139
|
+
.minus(credit)
|
|
140
|
+
.abs()
|
|
141
|
+
.lt(JOURNAL_ENTRY_BALANCE_EPSILON);
|
|
142
|
+
const balancedToOriginal = debit
|
|
143
|
+
.minus(originalTotal)
|
|
144
|
+
.abs()
|
|
145
|
+
.lt(JOURNAL_ENTRY_BALANCE_EPSILON);
|
|
146
|
+
return {
|
|
147
|
+
debitTotal: debit.toNumber(),
|
|
148
|
+
creditTotal: credit.toNumber(),
|
|
149
|
+
isBalanced: balancedToEachOther && balancedToOriginal,
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
exports.journalEntrySplitReconciliation = journalEntrySplitReconciliation;
|
|
153
|
+
/**
|
|
154
|
+
* Save-time validation for a JE split (Figma `4165:33028` / `4165:45379`):
|
|
155
|
+
* 1. every line needs a non-zero debit or credit, and
|
|
156
|
+
* 2. total debits == total credits == original total.
|
|
157
|
+
* Returns the first failing rule's `errorKey` (maps to a strings entry). Does
|
|
158
|
+
* NOT require category/class to be chosen — balance is the only gate.
|
|
159
|
+
*/
|
|
160
|
+
const validateJournalEntrySplit = (lines, originalTotal) => {
|
|
161
|
+
const everyLineHasSide = lines.every((line) => (line.postingType === 'debit' || line.postingType === 'credit') &&
|
|
162
|
+
Math.abs(line.amount?.amount ?? 0) > JOURNAL_ENTRY_BALANCE_EPSILON);
|
|
163
|
+
if (!everyLineHasSide) {
|
|
164
|
+
return { ok: false, errorKey: 'lineNeedsDebitOrCredit' };
|
|
165
|
+
}
|
|
166
|
+
if (!(0, exports.journalEntrySplitReconciliation)(lines, originalTotal).isBalanced) {
|
|
167
|
+
return { ok: false, errorKey: 'totalsMustEqual' };
|
|
168
|
+
}
|
|
169
|
+
return { ok: true };
|
|
170
|
+
};
|
|
171
|
+
exports.validateJournalEntrySplit = validateJournalEntrySplit;
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
113
173
|
// Filter
|
|
114
174
|
// ---------------------------------------------------------------------------
|
|
115
175
|
/**
|
|
@@ -834,14 +834,16 @@ const getChangedLineItemCountFromLocalData = (transaction, transactionLocalData)
|
|
|
834
834
|
line.type === 'transaction_with_product_or_service_line' ||
|
|
835
835
|
line.type === 'journal_entry_transaction_line') {
|
|
836
836
|
const accountLineLocal = transactionLocalData.lineItemById[lineId];
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
accountLineLocal.account?.
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
837
|
+
if (accountLineLocal != null) {
|
|
838
|
+
const accountLine = line;
|
|
839
|
+
hasCategoryChanged =
|
|
840
|
+
accountLineLocal.account?.qboId !== accountLine.account.qboId &&
|
|
841
|
+
accountLineLocal.account?.accountId !== accountLine.account.accountId;
|
|
842
|
+
hasClassChanged =
|
|
843
|
+
(accountLineLocal.class?.qboId != null ||
|
|
844
|
+
accountLine.class?.qboId != null) &&
|
|
845
|
+
accountLineLocal.class?.qboId !== accountLine.class?.qboId;
|
|
846
|
+
}
|
|
845
847
|
}
|
|
846
848
|
hasDescriptionChanged =
|
|
847
849
|
transactionLocalData.lineItemById[lineId] != null
|
|
@@ -8,7 +8,7 @@ import { SupportedTransaction, SupportedTransactionPayload } from '../../entity/
|
|
|
8
8
|
import { ZeniAPIStatus } from '../../responsePayload';
|
|
9
9
|
import { UncategorizedAccounts } from '../accountList/accountListSelector';
|
|
10
10
|
import { TransactionDetailState, TransactionSaveUpdates } from './transactionDetailState';
|
|
11
|
-
import { TransactionDetailLocalData, TransactionVendorUpdates } from './transactionDetailTypes';
|
|
11
|
+
import { TransactionDetailLineItemData, TransactionDetailLocalData, TransactionVendorUpdates } from './transactionDetailTypes';
|
|
12
12
|
export declare const initialState: TransactionDetailState;
|
|
13
13
|
export declare const downloadAccountingProviderAttachment: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[attachmentId: string], {
|
|
14
14
|
attachmentId: string;
|
|
@@ -166,6 +166,15 @@ export declare const downloadAccountingProviderAttachment: import("@reduxjs/tool
|
|
|
166
166
|
transactionId: TransactionID;
|
|
167
167
|
transaction: SupportedTransaction;
|
|
168
168
|
isEnabled: boolean;
|
|
169
|
-
}, "transactionDetail/setIsVendorUpdateAllChecked", never, never
|
|
169
|
+
}, "transactionDetail/setIsVendorUpdateAllChecked", never, never>, addSplitLine: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, newLine: TransactionDetailLineItemData], {
|
|
170
|
+
transactionId: TransactionID;
|
|
171
|
+
newLine: TransactionDetailLineItemData;
|
|
172
|
+
}, "transactionDetail/addSplitLine", never, never>, deleteSplitLine: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, lineId: string], {
|
|
173
|
+
transactionId: TransactionID;
|
|
174
|
+
lineId: string;
|
|
175
|
+
}, "transactionDetail/deleteSplitLine", never, never>, toggleSplitEditMode: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, editMode: boolean], {
|
|
176
|
+
transactionId: TransactionID;
|
|
177
|
+
editMode: boolean;
|
|
178
|
+
}, "transactionDetail/toggleSplitEditMode", never, never>;
|
|
170
179
|
declare const _default: import("redux").Reducer<TransactionDetailState>;
|
|
171
180
|
export default _default;
|
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
var _a;
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.setIsVendorUpdateAllChecked = exports.updateVendorBulkRecommendationsFetchStatus = exports.updateLatestSelectedEntity = exports.resetAllLineItemsToVendor = exports.updateVendorToAllLineItems = exports.updateLocalDataWithTransactionsUpdateWithVendorCheckbox = exports.resetSelectedCustomer = exports.resetVendor = exports.updateSelectedCustomer = exports.updateSelectedVendor = exports.removeEntityRecommendationForLineIdForTransactionDetail = exports.markCategoryClassRecommendationsFailureForTransactionDetail = exports.markCategoryClassRecommendationsCompletedForTransactionDetail = exports.markCategoryClassRecommendationsInProgressForTransactionDetail = exports.setEntityRecommendationForLineIdsForTransactionDetail = exports.setAllLineItemsLocalDataIsUpdateAllChecked = exports.setAllLineItemsToCategoryClassInLocalData = exports.resetLineItemsCategoryClassInLocalData = exports.clearTransactionDetailLocalData = exports.saveTransactionDetailLocalData = exports.initializeTransactionDetailLocalData = exports.saveTransactionDetail = exports.updateTransactionStateIfUpdateActionNotAllowed = exports.updateStatusConsolidatedSaveTransactionDetail = exports.updateStatusForTransactionNotMiscategorizedUpdate = exports.deleteTransactionAttachmentSuccess = exports.deleteTransactionAttachmentFailure = exports.deleteTransactionAttachment = exports.markTransactionAsNotMiscategorized = exports.clearTransactionDetailSaveStatus = exports.updateTransactionDetailSaveStatus = exports.updateTransactionDetail = exports.uploadMissingAttachmentSuccess = exports.clearTransactionDetail = exports.removeTransactionDetail = exports.updateTransactionDetailFetchState = exports.fetchTransactionDetail = exports.downloadAccountingProviderAttachmentFailure = exports.downloadAccountingProviderAttachmentSuccess = exports.downloadAccountingProviderAttachment = exports.initialState = void 0;
|
|
7
|
+
exports.toggleSplitEditMode = exports.deleteSplitLine = exports.addSplitLine = exports.setIsVendorUpdateAllChecked = exports.updateVendorBulkRecommendationsFetchStatus = exports.updateLatestSelectedEntity = exports.resetAllLineItemsToVendor = exports.updateVendorToAllLineItems = exports.updateLocalDataWithTransactionsUpdateWithVendorCheckbox = exports.resetSelectedCustomer = exports.resetVendor = exports.updateSelectedCustomer = exports.updateSelectedVendor = exports.removeEntityRecommendationForLineIdForTransactionDetail = exports.markCategoryClassRecommendationsFailureForTransactionDetail = exports.markCategoryClassRecommendationsCompletedForTransactionDetail = exports.markCategoryClassRecommendationsInProgressForTransactionDetail = exports.setEntityRecommendationForLineIdsForTransactionDetail = exports.setAllLineItemsLocalDataIsUpdateAllChecked = exports.setAllLineItemsToCategoryClassInLocalData = exports.resetLineItemsCategoryClassInLocalData = exports.clearTransactionDetailLocalData = exports.saveTransactionDetailLocalData = exports.initializeTransactionDetailLocalData = exports.saveTransactionDetail = exports.updateTransactionStateIfUpdateActionNotAllowed = exports.updateStatusConsolidatedSaveTransactionDetail = exports.updateStatusForTransactionNotMiscategorizedUpdate = exports.deleteTransactionAttachmentSuccess = exports.deleteTransactionAttachmentFailure = exports.deleteTransactionAttachment = exports.markTransactionAsNotMiscategorized = exports.clearTransactionDetailSaveStatus = exports.updateTransactionDetailSaveStatus = exports.updateTransactionDetail = exports.uploadMissingAttachmentSuccess = exports.clearTransactionDetail = exports.removeTransactionDetail = exports.updateTransactionDetailFetchState = exports.fetchTransactionDetail = exports.downloadAccountingProviderAttachmentFailure = exports.downloadAccountingProviderAttachmentSuccess = exports.downloadAccountingProviderAttachment = exports.initialState = void 0;
|
|
8
8
|
const toolkit_1 = require("@reduxjs/toolkit");
|
|
9
9
|
const get_1 = __importDefault(require("lodash/get"));
|
|
10
10
|
const entity_1 = require("../../entity/genericEntity/entity");
|
|
@@ -670,6 +670,71 @@ const transactionDetail = (0, toolkit_1.createSlice)({
|
|
|
670
670
|
};
|
|
671
671
|
},
|
|
672
672
|
},
|
|
673
|
+
// Split transaction — Phase 1 (expense)
|
|
674
|
+
addSplitLine: {
|
|
675
|
+
reducer(draft, action) {
|
|
676
|
+
const key = (0, transactionDetailState_1.getTransactionDetailKey)(action.payload.transactionId);
|
|
677
|
+
const detail = (0, get_1.default)(draft.transactionDetailById, key, undefined);
|
|
678
|
+
if (detail != null) {
|
|
679
|
+
draft.transactionDetailById[key] = {
|
|
680
|
+
...detail,
|
|
681
|
+
transactionDetailLocalData: {
|
|
682
|
+
...detail.transactionDetailLocalData,
|
|
683
|
+
lineItemById: {
|
|
684
|
+
...detail.transactionDetailLocalData.lineItemById,
|
|
685
|
+
[action.payload.newLine.id]: action.payload.newLine,
|
|
686
|
+
},
|
|
687
|
+
},
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
prepare(transactionId, newLine) {
|
|
692
|
+
return { payload: { transactionId, newLine } };
|
|
693
|
+
},
|
|
694
|
+
},
|
|
695
|
+
deleteSplitLine: {
|
|
696
|
+
reducer(draft, action) {
|
|
697
|
+
const key = (0, transactionDetailState_1.getTransactionDetailKey)(action.payload.transactionId);
|
|
698
|
+
const detail = (0, get_1.default)(draft.transactionDetailById, key, undefined);
|
|
699
|
+
if (detail == null) {
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
const { lineItemById, deletedLineIds = [] } = detail.transactionDetailLocalData;
|
|
703
|
+
const updated = { ...lineItemById };
|
|
704
|
+
delete updated[action.payload.lineId];
|
|
705
|
+
draft.transactionDetailById[key] = {
|
|
706
|
+
...detail,
|
|
707
|
+
transactionDetailLocalData: {
|
|
708
|
+
...detail.transactionDetailLocalData,
|
|
709
|
+
lineItemById: updated,
|
|
710
|
+
deletedLineIds: [...deletedLineIds, action.payload.lineId],
|
|
711
|
+
},
|
|
712
|
+
};
|
|
713
|
+
},
|
|
714
|
+
prepare(transactionId, lineId) {
|
|
715
|
+
return { payload: { transactionId, lineId } };
|
|
716
|
+
},
|
|
717
|
+
},
|
|
718
|
+
toggleSplitEditMode: {
|
|
719
|
+
reducer(draft, action) {
|
|
720
|
+
const key = (0, transactionDetailState_1.getTransactionDetailKey)(action.payload.transactionId);
|
|
721
|
+
const detail = (0, get_1.default)(draft.transactionDetailById, key, undefined);
|
|
722
|
+
if (detail != null) {
|
|
723
|
+
draft.transactionDetailById[key] = {
|
|
724
|
+
...detail,
|
|
725
|
+
transactionDetailLocalData: {
|
|
726
|
+
...detail.transactionDetailLocalData,
|
|
727
|
+
editMode: action.payload.editMode,
|
|
728
|
+
// Clear delete tracking when exiting edit mode without saving.
|
|
729
|
+
...(!action.payload.editMode && { deletedLineIds: [] }),
|
|
730
|
+
},
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
},
|
|
734
|
+
prepare(transactionId, editMode) {
|
|
735
|
+
return { payload: { transactionId, editMode } };
|
|
736
|
+
},
|
|
737
|
+
},
|
|
673
738
|
clearRecommendedVendorsList(draft) {
|
|
674
739
|
Object.assign(draft, exports.initialState);
|
|
675
740
|
},
|
|
@@ -778,7 +843,7 @@ const transactionDetail = (0, toolkit_1.createSlice)({
|
|
|
778
843
|
},
|
|
779
844
|
},
|
|
780
845
|
});
|
|
781
|
-
_a = transactionDetail.actions, exports.downloadAccountingProviderAttachment = _a.downloadAccountingProviderAttachment, exports.downloadAccountingProviderAttachmentSuccess = _a.downloadAccountingProviderAttachmentSuccess, exports.downloadAccountingProviderAttachmentFailure = _a.downloadAccountingProviderAttachmentFailure, exports.fetchTransactionDetail = _a.fetchTransactionDetail, exports.updateTransactionDetailFetchState = _a.updateTransactionDetailFetchState, exports.removeTransactionDetail = _a.removeTransactionDetail, exports.clearTransactionDetail = _a.clearTransactionDetail, exports.uploadMissingAttachmentSuccess = _a.uploadMissingAttachmentSuccess, exports.updateTransactionDetail = _a.updateTransactionDetail, exports.updateTransactionDetailSaveStatus = _a.updateTransactionDetailSaveStatus, exports.clearTransactionDetailSaveStatus = _a.clearTransactionDetailSaveStatus, exports.markTransactionAsNotMiscategorized = _a.markTransactionAsNotMiscategorized, exports.deleteTransactionAttachment = _a.deleteTransactionAttachment, exports.deleteTransactionAttachmentFailure = _a.deleteTransactionAttachmentFailure, exports.deleteTransactionAttachmentSuccess = _a.deleteTransactionAttachmentSuccess, exports.updateStatusForTransactionNotMiscategorizedUpdate = _a.updateStatusForTransactionNotMiscategorizedUpdate, exports.updateStatusConsolidatedSaveTransactionDetail = _a.updateStatusConsolidatedSaveTransactionDetail, exports.updateTransactionStateIfUpdateActionNotAllowed = _a.updateTransactionStateIfUpdateActionNotAllowed, exports.saveTransactionDetail = _a.saveTransactionDetail, exports.initializeTransactionDetailLocalData = _a.initializeTransactionDetailLocalData, exports.saveTransactionDetailLocalData = _a.saveTransactionDetailLocalData, exports.clearTransactionDetailLocalData = _a.clearTransactionDetailLocalData, exports.resetLineItemsCategoryClassInLocalData = _a.resetLineItemsCategoryClassInLocalData, exports.setAllLineItemsToCategoryClassInLocalData = _a.setAllLineItemsToCategoryClassInLocalData, exports.setAllLineItemsLocalDataIsUpdateAllChecked = _a.setAllLineItemsLocalDataIsUpdateAllChecked, exports.setEntityRecommendationForLineIdsForTransactionDetail = _a.setEntityRecommendationForLineIdsForTransactionDetail, exports.markCategoryClassRecommendationsInProgressForTransactionDetail = _a.markCategoryClassRecommendationsInProgressForTransactionDetail, exports.markCategoryClassRecommendationsCompletedForTransactionDetail = _a.markCategoryClassRecommendationsCompletedForTransactionDetail, exports.markCategoryClassRecommendationsFailureForTransactionDetail = _a.markCategoryClassRecommendationsFailureForTransactionDetail, exports.removeEntityRecommendationForLineIdForTransactionDetail = _a.removeEntityRecommendationForLineIdForTransactionDetail, exports.updateSelectedVendor = _a.updateSelectedVendor, exports.updateSelectedCustomer = _a.updateSelectedCustomer, exports.resetVendor = _a.resetVendor, exports.resetSelectedCustomer = _a.resetSelectedCustomer, exports.updateLocalDataWithTransactionsUpdateWithVendorCheckbox = _a.updateLocalDataWithTransactionsUpdateWithVendorCheckbox, exports.updateVendorToAllLineItems = _a.updateVendorToAllLineItems, exports.resetAllLineItemsToVendor = _a.resetAllLineItemsToVendor, exports.updateLatestSelectedEntity = _a.updateLatestSelectedEntity, exports.updateVendorBulkRecommendationsFetchStatus = _a.updateVendorBulkRecommendationsFetchStatus, exports.setIsVendorUpdateAllChecked = _a.setIsVendorUpdateAllChecked;
|
|
846
|
+
_a = transactionDetail.actions, exports.downloadAccountingProviderAttachment = _a.downloadAccountingProviderAttachment, exports.downloadAccountingProviderAttachmentSuccess = _a.downloadAccountingProviderAttachmentSuccess, exports.downloadAccountingProviderAttachmentFailure = _a.downloadAccountingProviderAttachmentFailure, exports.fetchTransactionDetail = _a.fetchTransactionDetail, exports.updateTransactionDetailFetchState = _a.updateTransactionDetailFetchState, exports.removeTransactionDetail = _a.removeTransactionDetail, exports.clearTransactionDetail = _a.clearTransactionDetail, exports.uploadMissingAttachmentSuccess = _a.uploadMissingAttachmentSuccess, exports.updateTransactionDetail = _a.updateTransactionDetail, exports.updateTransactionDetailSaveStatus = _a.updateTransactionDetailSaveStatus, exports.clearTransactionDetailSaveStatus = _a.clearTransactionDetailSaveStatus, exports.markTransactionAsNotMiscategorized = _a.markTransactionAsNotMiscategorized, exports.deleteTransactionAttachment = _a.deleteTransactionAttachment, exports.deleteTransactionAttachmentFailure = _a.deleteTransactionAttachmentFailure, exports.deleteTransactionAttachmentSuccess = _a.deleteTransactionAttachmentSuccess, exports.updateStatusForTransactionNotMiscategorizedUpdate = _a.updateStatusForTransactionNotMiscategorizedUpdate, exports.updateStatusConsolidatedSaveTransactionDetail = _a.updateStatusConsolidatedSaveTransactionDetail, exports.updateTransactionStateIfUpdateActionNotAllowed = _a.updateTransactionStateIfUpdateActionNotAllowed, exports.saveTransactionDetail = _a.saveTransactionDetail, exports.initializeTransactionDetailLocalData = _a.initializeTransactionDetailLocalData, exports.saveTransactionDetailLocalData = _a.saveTransactionDetailLocalData, exports.clearTransactionDetailLocalData = _a.clearTransactionDetailLocalData, exports.resetLineItemsCategoryClassInLocalData = _a.resetLineItemsCategoryClassInLocalData, exports.setAllLineItemsToCategoryClassInLocalData = _a.setAllLineItemsToCategoryClassInLocalData, exports.setAllLineItemsLocalDataIsUpdateAllChecked = _a.setAllLineItemsLocalDataIsUpdateAllChecked, exports.setEntityRecommendationForLineIdsForTransactionDetail = _a.setEntityRecommendationForLineIdsForTransactionDetail, exports.markCategoryClassRecommendationsInProgressForTransactionDetail = _a.markCategoryClassRecommendationsInProgressForTransactionDetail, exports.markCategoryClassRecommendationsCompletedForTransactionDetail = _a.markCategoryClassRecommendationsCompletedForTransactionDetail, exports.markCategoryClassRecommendationsFailureForTransactionDetail = _a.markCategoryClassRecommendationsFailureForTransactionDetail, exports.removeEntityRecommendationForLineIdForTransactionDetail = _a.removeEntityRecommendationForLineIdForTransactionDetail, exports.updateSelectedVendor = _a.updateSelectedVendor, exports.updateSelectedCustomer = _a.updateSelectedCustomer, exports.resetVendor = _a.resetVendor, exports.resetSelectedCustomer = _a.resetSelectedCustomer, exports.updateLocalDataWithTransactionsUpdateWithVendorCheckbox = _a.updateLocalDataWithTransactionsUpdateWithVendorCheckbox, exports.updateVendorToAllLineItems = _a.updateVendorToAllLineItems, exports.resetAllLineItemsToVendor = _a.resetAllLineItemsToVendor, exports.updateLatestSelectedEntity = _a.updateLatestSelectedEntity, exports.updateVendorBulkRecommendationsFetchStatus = _a.updateVendorBulkRecommendationsFetchStatus, exports.setIsVendorUpdateAllChecked = _a.setIsVendorUpdateAllChecked, exports.addSplitLine = _a.addSplitLine, exports.deleteSplitLine = _a.deleteSplitLine, exports.toggleSplitEditMode = _a.toggleSplitEditMode;
|
|
782
847
|
exports.default = transactionDetail.reducer;
|
|
783
848
|
function getUpdatedEntityLocalData(detail, updates, entity, resetRecommendations, type) {
|
|
784
849
|
const key = type === 'customer' ? 'customerUpdates' : 'vendorUpdates';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FetchState, FetchStateAndError, FetchedState, ID } from '../../commonStateTypes/common';
|
|
2
|
+
import { Amount } from '../../commonStateTypes/amount';
|
|
2
3
|
import { Recommendation } from '../../commonStateTypes/recommendationBase';
|
|
3
4
|
import { AccountBase } from '../../entity/account/accountState';
|
|
4
5
|
import { ClassBase } from '../../entity/class/classState';
|
|
@@ -6,9 +7,10 @@ import { CustomerBase } from '../../entity/customer/customerState';
|
|
|
6
7
|
import { EntityType } from '../../entity/genericEntity/entity';
|
|
7
8
|
import { ProjectBase } from '../../entity/project/projectState';
|
|
8
9
|
import { Transaction, TransactionID } from '../../entity/transaction/stateTypes/transaction';
|
|
10
|
+
import { TransactionCategory } from '../../entity/transaction/stateTypes/transactionType';
|
|
9
11
|
import { VendorBase } from '../../entity/vendor/vendorState';
|
|
10
12
|
import { EntityRecommendationKey } from '../recommendation/recommendationState';
|
|
11
|
-
import { TransactionDetailLocalData } from './transactionDetailTypes';
|
|
13
|
+
import { TransactionDetailLineItemData, TransactionDetailLocalData } from './transactionDetailTypes';
|
|
12
14
|
export declare const getTransactionDetailKey: (transactionId: TransactionID) => `${string}_bill` | `${string}_expense` | `${string}_check` | `${string}_refund` | `${string}_invoice` | `${string}_payment` | `${string}_credit_memo` | `${string}_sales_receipt` | `${string}_delayed_credit` | `${string}_delayed_charge` | `${string}_bill_payment` | `${string}_bill_payment_check` | `${string}_bill_payment_credit_card` | `${string}_vendor_credit` | `${string}_credit_card_credit` | `${string}_transfer` | `${string}_credit_card_payment` | `${string}_deposit` | `${string}_journal_entry`;
|
|
13
15
|
export type TransactionDetailKey = ReturnType<typeof getTransactionDetailKey>;
|
|
14
16
|
export declare const getZeniTransactionDetailKey: (transactionId: TransactionID) => `${string}_bill` | `${string}_expense` | `${string}_check` | `${string}_refund` | `${string}_invoice` | `${string}_payment` | `${string}_credit_memo` | `${string}_sales_receipt` | `${string}_delayed_credit` | `${string}_delayed_charge` | `${string}_bill_payment` | `${string}_bill_payment_check` | `${string}_bill_payment_credit_card` | `${string}_vendor_credit` | `${string}_credit_card_credit` | `${string}_transfer` | `${string}_credit_card_payment` | `${string}_deposit` | `${string}_journal_entry`;
|
|
@@ -50,9 +52,12 @@ export interface TransactionDetailState {
|
|
|
50
52
|
}
|
|
51
53
|
export interface TransactionLineUpdates {
|
|
52
54
|
account?: AccountBase;
|
|
55
|
+
amount?: Amount;
|
|
53
56
|
class?: ClassBase;
|
|
54
57
|
customer?: CustomerBase;
|
|
55
58
|
lineDescription?: string;
|
|
59
|
+
postingType?: TransactionCategory;
|
|
60
|
+
postingTypeName?: string;
|
|
56
61
|
project?: ProjectBase;
|
|
57
62
|
recommendation?: Recommendation[];
|
|
58
63
|
vendor?: VendorBase;
|
|
@@ -78,5 +83,7 @@ export interface TransactionSaveUpdates {
|
|
|
78
83
|
entityRelatedUpdates: Record<EntityRecommendationKey, EntityRelatedRecommendationUpdates>;
|
|
79
84
|
markAsMiscatUpdates: boolean;
|
|
80
85
|
updates: TransactionUpdates;
|
|
86
|
+
addedLines?: TransactionDetailLineItemData[];
|
|
87
|
+
deletedLineIds?: ID[];
|
|
81
88
|
}
|
|
82
89
|
export {};
|
|
@@ -50,7 +50,9 @@ export interface TransactionDetailLocalData {
|
|
|
50
50
|
qboId: ID;
|
|
51
51
|
};
|
|
52
52
|
customerUpdates?: TransactionVendorUpdates;
|
|
53
|
+
deletedLineIds?: ID[];
|
|
53
54
|
documentId?: string;
|
|
55
|
+
editMode?: boolean;
|
|
54
56
|
latestSelectedEntityOnLineItem?: Entity;
|
|
55
57
|
latestUpdatedLineWithEntity?: ID;
|
|
56
58
|
memo?: string;
|
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.46",
|
|
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",
|