@zeniai/client-epic-state 5.1.45-betaDI3 → 5.1.45
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 +0 -3
- package/lib/entity/task/taskPayload.d.ts +1 -3
- package/lib/entity/task/taskPayload.js +2 -24
- package/lib/entity/task/taskReducer.d.ts +1 -8
- package/lib/entity/task/taskReducer.js +4 -29
- package/lib/entity/task/taskState.d.ts +0 -2
- package/lib/entity/tenant/epic/saveExternalConnectionEpic.d.ts +1 -2
- package/lib/entity/tenant/epic/saveExternalConnectionEpic.js +0 -17
- package/lib/epic.d.ts +3 -6
- package/lib/epic.js +3 -6
- package/lib/esm/entity/snackbar/snackbarTypes.js +0 -3
- package/lib/esm/entity/task/taskPayload.js +2 -24
- package/lib/esm/entity/task/taskReducer.js +3 -28
- package/lib/esm/entity/tenant/epic/saveExternalConnectionEpic.js +0 -17
- package/lib/esm/epic.js +3 -6
- package/lib/esm/index.js +8 -8
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +1 -31
- package/lib/esm/view/aiCfoView/epics/fetchSkillsEpic.js +8 -33
- package/lib/esm/view/companyTaskManagerView/epics/fetchCompanyTaskManagerViewEpic.js +0 -3
- package/lib/esm/view/companyTaskManagerView/epics/fetchTaskManagerMetricsEpic.js +1 -7
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +0 -7
- package/lib/esm/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +0 -1
- package/lib/esm/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +9 -70
- package/lib/esm/view/taskManager/taskDetailView/taskDetailReducer.js +2 -56
- package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +9 -35
- package/lib/esm/view/taskManager/taskListView/epics/fetchTaskListEpic.js +1 -3
- package/lib/esm/view/taskManager/taskListView/taskList.js +0 -1
- package/lib/esm/view/taskManager/taskListView/taskListReducer.js +18 -310
- package/lib/esm/view/taskManager/taskListView/taskListSelector.js +0 -1
- package/lib/esm/view/taskManager/taskListView/taskListViewHelpers.js +0 -58
- package/lib/esm/view/transactionDetail/epics/saveTransactionHelper.js +0 -22
- package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +3 -75
- package/lib/esm/view/transactionDetail/journalEntryLinesViewModel.js +0 -58
- package/lib/esm/view/transactionDetail/transactionDetailLocalDataHelper.js +8 -10
- package/lib/esm/view/transactionDetail/transactionDetailReducer.js +1 -66
- package/lib/index.d.ts +11 -12
- package/lib/index.js +28 -37
- package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +0 -10
- package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +2 -7
- package/lib/view/aiCfoView/aiCfoViewReducer.js +2 -32
- package/lib/view/aiCfoView/aiCfoViewState.d.ts +1 -5
- package/lib/view/aiCfoView/epics/fetchSkillsEpic.js +8 -33
- package/lib/view/companyTaskManagerView/epics/fetchCompanyTaskManagerViewEpic.js +0 -3
- package/lib/view/companyTaskManagerView/epics/fetchTaskManagerMetricsEpic.js +1 -7
- package/lib/view/companyView/types/cockpitTypes.d.ts +0 -3
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +0 -7
- package/lib/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +0 -1
- package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.d.ts +2 -2
- package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +8 -69
- package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +0 -15
- package/lib/view/taskManager/taskDetailView/taskDetailReducer.d.ts +2 -14
- package/lib/view/taskManager/taskDetailView/taskDetailReducer.js +3 -57
- package/lib/view/taskManager/taskDetailView/taskDetailSelector.d.ts +1 -3
- package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +7 -33
- package/lib/view/taskManager/taskListView/epics/fetchTaskListEpic.js +1 -3
- package/lib/view/taskManager/taskListView/taskList.d.ts +1 -1
- package/lib/view/taskManager/taskListView/taskList.js +0 -1
- package/lib/view/taskManager/taskListView/taskListPayload.d.ts +0 -4
- package/lib/view/taskManager/taskListView/taskListReducer.d.ts +2 -6
- package/lib/view/taskManager/taskListView/taskListReducer.js +19 -311
- package/lib/view/taskManager/taskListView/taskListSelector.js +0 -1
- package/lib/view/taskManager/taskListView/taskListViewHelpers.d.ts +0 -11
- package/lib/view/taskManager/taskListView/taskListViewHelpers.js +1 -60
- package/lib/view/transactionDetail/epics/saveTransactionHelper.js +0 -22
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.d.ts +1 -5
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +4 -77
- package/lib/view/transactionDetail/journalEntryLinesViewModel.d.ts +0 -27
- package/lib/view/transactionDetail/journalEntryLinesViewModel.js +1 -61
- package/lib/view/transactionDetail/transactionDetailLocalDataHelper.js +8 -10
- package/lib/view/transactionDetail/transactionDetailReducer.d.ts +2 -11
- package/lib/view/transactionDetail/transactionDetailReducer.js +2 -67
- package/lib/view/transactionDetail/transactionDetailState.d.ts +1 -8
- package/lib/view/transactionDetail/transactionDetailTypes.d.ts +0 -2
- package/package.json +1 -1
- package/lib/esm/view/aiCfoView/epics/submitFeedbackEpic.js +0 -39
- package/lib/esm/view/taskManager/taskDetailView/epics/createSubTaskEpic.js +0 -96
- package/lib/esm/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.js +0 -53
- package/lib/view/aiCfoView/epics/submitFeedbackEpic.d.ts +0 -13
- package/lib/view/aiCfoView/epics/submitFeedbackEpic.js +0 -43
- package/lib/view/taskManager/taskDetailView/epics/createSubTaskEpic.d.ts +0 -9
- package/lib/view/taskManager/taskDetailView/epics/createSubTaskEpic.js +0 -100
- package/lib/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.d.ts +0 -8
- package/lib/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.js +0 -57
|
@@ -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.
|
|
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");
|
|
@@ -64,9 +64,7 @@ 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
|
-
|
|
68
|
-
// keep any line absent from the server response (deletion bug).
|
|
69
|
-
actions.push((0, transactionReducer_1.updateTransaction)(transactionDetailKeyForResponse, response.data.transaction, 'replace'));
|
|
67
|
+
actions.push((0, transactionReducer_1.updateTransaction)(transactionDetailKeyForResponse, response.data.transaction));
|
|
70
68
|
actions.push((0, transactionDetailReducer_1.initializeTransactionDetailLocalData)({
|
|
71
69
|
transactionId: transactionIdResp,
|
|
72
70
|
vendorId: response.data.vendors?.[0]?.vendor_id,
|
|
@@ -168,7 +166,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
168
166
|
};
|
|
169
167
|
}
|
|
170
168
|
if (detail != null) {
|
|
171
|
-
const transUpdates = (0, exports.toTransactionUpdatePayload)(saveUpdates.updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, currentSelectedEntity
|
|
169
|
+
const transUpdates = (0, exports.toTransactionUpdatePayload)(saveUpdates.updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, currentSelectedEntity);
|
|
172
170
|
const entityUpdates = toEntityUpdatePayload(saveUpdates.entityRelatedUpdates);
|
|
173
171
|
return {
|
|
174
172
|
entity_related_updates: entityUpdates,
|
|
@@ -178,7 +176,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
178
176
|
}
|
|
179
177
|
return undefined;
|
|
180
178
|
}
|
|
181
|
-
const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, tranSelectedEntity
|
|
179
|
+
const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, tranSelectedEntity) => {
|
|
182
180
|
const transaction = Object.assign({}, detail);
|
|
183
181
|
transaction.memo = updates.memo ?? '';
|
|
184
182
|
// Unlike `memo` (always reset to '' when absent), `documentId` falls back to
|
|
@@ -187,11 +185,6 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isA
|
|
|
187
185
|
// either the unchanged current value or undefined, and we must not send an
|
|
188
186
|
// empty `document_id` that the server would treat as clearing the number.
|
|
189
187
|
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
|
-
}
|
|
195
188
|
const recommendationUpdates = {};
|
|
196
189
|
for (const key in updates.updatesByLineId) {
|
|
197
190
|
const lineUpdates = updates.updatesByLineId[key];
|
|
@@ -199,9 +192,6 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isA
|
|
|
199
192
|
if (line.id === key) {
|
|
200
193
|
const lineTobeUpdated = Object.assign({}, line);
|
|
201
194
|
lineTobeUpdated.lineDescription = lineUpdates.lineDescription ?? '';
|
|
202
|
-
if (lineUpdates.amount != null) {
|
|
203
|
-
lineTobeUpdated.amount = lineUpdates.amount;
|
|
204
|
-
}
|
|
205
195
|
if (lineUpdates.class != null) {
|
|
206
196
|
lineTobeUpdated.class = lineUpdates.class;
|
|
207
197
|
}
|
|
@@ -223,16 +213,6 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isA
|
|
|
223
213
|
else {
|
|
224
214
|
lineTobeUpdated.vendor = undefined;
|
|
225
215
|
}
|
|
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
|
-
}
|
|
236
216
|
if (lineUpdates.recommendation != null) {
|
|
237
217
|
recommendationUpdates[line.id] = lineUpdates.recommendation;
|
|
238
218
|
}
|
|
@@ -252,12 +232,6 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isA
|
|
|
252
232
|
});
|
|
253
233
|
transaction.lines = newLineMap;
|
|
254
234
|
}
|
|
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
|
-
}
|
|
261
235
|
transaction.recommendations = recommendationUpdates;
|
|
262
236
|
// Convert transaction to payload first
|
|
263
237
|
let basePayload;
|
|
@@ -333,53 +307,6 @@ const checkIfVendorOrCustomerMissingForAnyLineItem = (transactionPayload) => {
|
|
|
333
307
|
}
|
|
334
308
|
return isAnyVendorOrCustomerMissing;
|
|
335
309
|
};
|
|
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;
|
|
383
310
|
const toEntityUpdatePayload = (entityUpdates) => {
|
|
384
311
|
const entityUpdatesPayload = [];
|
|
385
312
|
let entityKey;
|
|
@@ -64,33 +64,6 @@ 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;
|
|
94
67
|
/**
|
|
95
68
|
* Drops `linked_transaction_line` entries — equivalent to legacy
|
|
96
69
|
* `filterOutLinkedTransactionLine` in `transactionDetail.helpers.ts`.
|
|
@@ -3,8 +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.sortJournalEntryLines = exports.filterJournalEntryLinesExcludingLinked = exports.
|
|
7
|
-
const big_js_1 = __importDefault(require("big.js"));
|
|
6
|
+
exports.sortJournalEntryLines = exports.filterJournalEntryLinesExcludingLinked = exports.journalEntryTotalsByPostingSide = exports.sumJournalEntryAmounts = exports.journalEntryDefaultSortConfig = exports.toJournalEntrySortKey = exports.JOURNAL_ENTRY_SORT_KEYS = void 0;
|
|
8
7
|
const orderBy_1 = __importDefault(require("lodash/orderBy"));
|
|
9
8
|
const stringToUnion_1 = require("../../commonStateTypes/stringToUnion");
|
|
10
9
|
const transactionLine_1 = require("../../entity/transaction/stateTypes/transactionLine");
|
|
@@ -111,65 +110,6 @@ const journalEntryTotalsByPostingSide = (lines) => {
|
|
|
111
110
|
};
|
|
112
111
|
exports.journalEntryTotalsByPostingSide = journalEntryTotalsByPostingSide;
|
|
113
112
|
// ---------------------------------------------------------------------------
|
|
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
|
-
// ---------------------------------------------------------------------------
|
|
173
113
|
// Filter
|
|
174
114
|
// ---------------------------------------------------------------------------
|
|
175
115
|
/**
|
|
@@ -834,16 +834,14 @@ 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
|
-
|
|
845
|
-
accountLineLocal.class?.qboId !== accountLine.class?.qboId;
|
|
846
|
-
}
|
|
837
|
+
const accountLine = line;
|
|
838
|
+
hasCategoryChanged =
|
|
839
|
+
accountLineLocal.account?.qboId !== accountLine.account.qboId &&
|
|
840
|
+
accountLineLocal.account?.accountId !== accountLine.account.accountId;
|
|
841
|
+
hasClassChanged =
|
|
842
|
+
(accountLineLocal.class?.qboId != null ||
|
|
843
|
+
accountLine.class?.qboId != null) &&
|
|
844
|
+
accountLineLocal.class?.qboId !== accountLine.class?.qboId;
|
|
847
845
|
}
|
|
848
846
|
hasDescriptionChanged =
|
|
849
847
|
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 {
|
|
11
|
+
import { 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,15 +166,6 @@ export declare const downloadAccountingProviderAttachment: import("@reduxjs/tool
|
|
|
166
166
|
transactionId: TransactionID;
|
|
167
167
|
transaction: SupportedTransaction;
|
|
168
168
|
isEnabled: boolean;
|
|
169
|
-
}, "transactionDetail/setIsVendorUpdateAllChecked", never, never
|
|
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>;
|
|
169
|
+
}, "transactionDetail/setIsVendorUpdateAllChecked", never, never>;
|
|
179
170
|
declare const _default: import("redux").Reducer<TransactionDetailState>;
|
|
180
171
|
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.
|
|
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;
|
|
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,71 +670,6 @@ 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
|
-
},
|
|
738
673
|
clearRecommendedVendorsList(draft) {
|
|
739
674
|
Object.assign(draft, exports.initialState);
|
|
740
675
|
},
|
|
@@ -843,7 +778,7 @@ const transactionDetail = (0, toolkit_1.createSlice)({
|
|
|
843
778
|
},
|
|
844
779
|
},
|
|
845
780
|
});
|
|
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
|
|
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;
|
|
847
782
|
exports.default = transactionDetail.reducer;
|
|
848
783
|
function getUpdatedEntityLocalData(detail, updates, entity, resetRecommendations, type) {
|
|
849
784
|
const key = type === 'customer' ? 'customerUpdates' : 'vendorUpdates';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { FetchState, FetchStateAndError, FetchedState, ID } from '../../commonStateTypes/common';
|
|
2
|
-
import { Amount } from '../../commonStateTypes/amount';
|
|
3
2
|
import { Recommendation } from '../../commonStateTypes/recommendationBase';
|
|
4
3
|
import { AccountBase } from '../../entity/account/accountState';
|
|
5
4
|
import { ClassBase } from '../../entity/class/classState';
|
|
@@ -7,10 +6,9 @@ import { CustomerBase } from '../../entity/customer/customerState';
|
|
|
7
6
|
import { EntityType } from '../../entity/genericEntity/entity';
|
|
8
7
|
import { ProjectBase } from '../../entity/project/projectState';
|
|
9
8
|
import { Transaction, TransactionID } from '../../entity/transaction/stateTypes/transaction';
|
|
10
|
-
import { TransactionCategory } from '../../entity/transaction/stateTypes/transactionType';
|
|
11
9
|
import { VendorBase } from '../../entity/vendor/vendorState';
|
|
12
10
|
import { EntityRecommendationKey } from '../recommendation/recommendationState';
|
|
13
|
-
import {
|
|
11
|
+
import { TransactionDetailLocalData } from './transactionDetailTypes';
|
|
14
12
|
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`;
|
|
15
13
|
export type TransactionDetailKey = ReturnType<typeof getTransactionDetailKey>;
|
|
16
14
|
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`;
|
|
@@ -52,12 +50,9 @@ export interface TransactionDetailState {
|
|
|
52
50
|
}
|
|
53
51
|
export interface TransactionLineUpdates {
|
|
54
52
|
account?: AccountBase;
|
|
55
|
-
amount?: Amount;
|
|
56
53
|
class?: ClassBase;
|
|
57
54
|
customer?: CustomerBase;
|
|
58
55
|
lineDescription?: string;
|
|
59
|
-
postingType?: TransactionCategory;
|
|
60
|
-
postingTypeName?: string;
|
|
61
56
|
project?: ProjectBase;
|
|
62
57
|
recommendation?: Recommendation[];
|
|
63
58
|
vendor?: VendorBase;
|
|
@@ -83,7 +78,5 @@ export interface TransactionSaveUpdates {
|
|
|
83
78
|
entityRelatedUpdates: Record<EntityRecommendationKey, EntityRelatedRecommendationUpdates>;
|
|
84
79
|
markAsMiscatUpdates: boolean;
|
|
85
80
|
updates: TransactionUpdates;
|
|
86
|
-
addedLines?: TransactionDetailLineItemData[];
|
|
87
|
-
deletedLineIds?: ID[];
|
|
88
81
|
}
|
|
89
82
|
export {};
|
|
@@ -50,9 +50,7 @@ export interface TransactionDetailLocalData {
|
|
|
50
50
|
qboId: ID;
|
|
51
51
|
};
|
|
52
52
|
customerUpdates?: TransactionVendorUpdates;
|
|
53
|
-
deletedLineIds?: ID[];
|
|
54
53
|
documentId?: string;
|
|
55
|
-
editMode?: boolean;
|
|
56
54
|
latestSelectedEntityOnLineItem?: Entity;
|
|
57
55
|
latestUpdatedLineWithEntity?: ID;
|
|
58
56
|
memo?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeniai/client-epic-state",
|
|
3
|
-
"version": "5.1.45
|
|
3
|
+
"version": "5.1.45",
|
|
4
4
|
"description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { of } from 'rxjs';
|
|
2
|
-
import { catchError, filter, groupBy, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
|
-
import { createZeniAPIStatus, isSuccessStatus, } from '../../../responsePayload';
|
|
4
|
-
import { submitFeedback, submitFeedbackFailure, submitFeedbackSuccess, } from '../aiCfoViewReducer';
|
|
5
|
-
/**
|
|
6
|
-
* Thin wiring for AI CFO answer feedback (👍/👎). Dispatch `submitFeedback(...)` (defined on the
|
|
7
|
-
* aiCfoView slice) to POST to the AI CFO micro-service `/1.0/feedback` endpoint, which emits the
|
|
8
|
-
* analytics event server-side and routes negatives to the review queue. The capture-prompt UI
|
|
9
|
-
* that dispatches this lands in a fast-follow PR.
|
|
10
|
-
*/
|
|
11
|
-
export const submitFeedbackEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(submitFeedback.match),
|
|
12
|
-
// Per-message dedup: group by chatMessageId so rapid repeat clicks on the SAME answer cancel
|
|
13
|
-
// the in-flight request (switchMap) — no duplicate POST / analytics / Slack row — while
|
|
14
|
-
// feedback on different answers still runs concurrently (separate groups under mergeMap).
|
|
15
|
-
groupBy((action) => action.payload.chatMessageId), mergeMap((perMessage$) => perMessage$.pipe(switchMap((action) => {
|
|
16
|
-
const { chatMessageId, chatSessionId, feedbackType, answerText, model, questionText, } = action.payload;
|
|
17
|
-
const body = {
|
|
18
|
-
chat_message_id: chatMessageId,
|
|
19
|
-
chat_session_id: chatSessionId,
|
|
20
|
-
feedback_type: feedbackType,
|
|
21
|
-
...(answerText != null && { answer_text: answerText }),
|
|
22
|
-
...(model != null && { model }),
|
|
23
|
-
...(questionText != null && { question_text: questionText }),
|
|
24
|
-
};
|
|
25
|
-
return zeniAPI
|
|
26
|
-
.postAndGetJSON(`${zeniAPI.apiEndPoints.aiCfoMicroServiceBaseUrl}/1.0/feedback`, body)
|
|
27
|
-
.pipe(
|
|
28
|
-
// Status-only success check (no `data`): /1.0/feedback returns a 2xx with status and no
|
|
29
|
-
// body, so isSuccessResponse (which requires response.data) would wrongly fail it.
|
|
30
|
-
mergeMap((response) => isSuccessStatus(response)
|
|
31
|
-
? of(submitFeedbackSuccess(chatMessageId))
|
|
32
|
-
: of(submitFeedbackFailure(chatMessageId, response.status))), catchError((error) => of(submitFeedbackFailure(chatMessageId, createZeniAPIStatus(
|
|
33
|
-
// message (detailed) first, then the short title — per createZeniAPIStatus(message, title).
|
|
34
|
-
// JSON.stringify(Error) drops the (non-enumerable) message — extract it explicitly.
|
|
35
|
-
'Feedback REST API call errored out: ' +
|
|
36
|
-
(error instanceof Error
|
|
37
|
-
? error.message
|
|
38
|
-
: String(error)), 'Unexpected Error')))));
|
|
39
|
-
}))));
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { from, of } from 'rxjs';
|
|
2
|
-
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
-
import { convertHHMMStrToMinutes } from '../../../../commonStateTypes/fiscalYearHelpers/formatMinutesToFromHHMM';
|
|
4
|
-
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
5
|
-
import { appendSubTaskId, updateTasks, } from '../../../../entity/task/taskReducer';
|
|
6
|
-
import { getTaskById } from '../../../../entity/task/taskSelector';
|
|
7
|
-
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
8
|
-
import { updateTaskListOnNewTaskCreationSuccess } from '../../taskListView/taskListReducer';
|
|
9
|
-
import { createSubTask, createSubTaskSuccessOrFailure, } from '../taskDetailReducer';
|
|
10
|
-
export const createSubTaskEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(createSubTask.match), mergeMap((action) => {
|
|
11
|
-
const state = state$.value;
|
|
12
|
-
const parentTask = getTaskById(state.taskState, action.payload.parentTaskId);
|
|
13
|
-
// Subtasks inherit every parent group membership, not just the first,
|
|
14
|
-
// so the subtask surfaces in all the same buckets as its parent.
|
|
15
|
-
const parentTaskGroupIds = parentTask?.taskGroupIds ?? [];
|
|
16
|
-
const parentTaskGroupId = parentTaskGroupIds[0];
|
|
17
|
-
const isTaskListFetched = state.taskListState.fetchState === 'Completed';
|
|
18
|
-
const payload = prepareSubTaskPayload(action.payload, parentTaskGroupIds);
|
|
19
|
-
return zeniAPI
|
|
20
|
-
.postAndGetJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks`, payload)
|
|
21
|
-
.pipe(mergeMap((response) => {
|
|
22
|
-
if (isSuccessResponse(response) &&
|
|
23
|
-
response.data != null &&
|
|
24
|
-
response.data.tasks.length > 0) {
|
|
25
|
-
const newTaskId = response.data.tasks[0].task_id;
|
|
26
|
-
const actions = [
|
|
27
|
-
updateTasks(response.data.tasks),
|
|
28
|
-
appendSubTaskId({
|
|
29
|
-
parentTaskId: action.payload.parentTaskId,
|
|
30
|
-
subTaskId: newTaskId,
|
|
31
|
-
}),
|
|
32
|
-
createSubTaskSuccessOrFailure({
|
|
33
|
-
fetchState: 'Completed',
|
|
34
|
-
newTaskId,
|
|
35
|
-
}),
|
|
36
|
-
openSnackbar({
|
|
37
|
-
messageSection: 'create_sub_task',
|
|
38
|
-
messageText: 'success',
|
|
39
|
-
type: 'success',
|
|
40
|
-
}),
|
|
41
|
-
];
|
|
42
|
-
// The task list is keyed on parent tasks (no parent_task_id)
|
|
43
|
-
// — subtasks belong to their parent's children list, not the
|
|
44
|
-
// top-level list. Pushing a subtask into the list would
|
|
45
|
-
// surface it as an orphan row at the top of the group.
|
|
46
|
-
// Only fire the list-update for actual parent tasks.
|
|
47
|
-
const createdTask = response.data.tasks[0];
|
|
48
|
-
const isSubtask = createdTask.parent_task_id != null &&
|
|
49
|
-
createdTask.parent_task_id !== '';
|
|
50
|
-
if (!isSubtask &&
|
|
51
|
-
isTaskListFetched === true &&
|
|
52
|
-
parentTaskGroupId != null) {
|
|
53
|
-
actions.push(updateTaskListOnNewTaskCreationSuccess({
|
|
54
|
-
taskGroupId: parentTaskGroupId,
|
|
55
|
-
task: createdTask,
|
|
56
|
-
}));
|
|
57
|
-
}
|
|
58
|
-
return from(actions);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
return of(createSubTaskSuccessOrFailure({
|
|
62
|
-
fetchState: 'Error',
|
|
63
|
-
error: response.status,
|
|
64
|
-
}), openSnackbar({
|
|
65
|
-
messageSection: 'create_sub_task',
|
|
66
|
-
messageText: 'failed',
|
|
67
|
-
type: 'error',
|
|
68
|
-
variables: [
|
|
69
|
-
{
|
|
70
|
-
variableName: '_api-error_',
|
|
71
|
-
variableValue: response.status.message,
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
}));
|
|
75
|
-
}
|
|
76
|
-
}), catchError((error) => of(createSubTaskSuccessOrFailure({
|
|
77
|
-
fetchState: 'Error',
|
|
78
|
-
error: createZeniAPIStatus('Unexpected Error', 'Create Sub Task REST API call errored out' +
|
|
79
|
-
JSON.stringify(error)),
|
|
80
|
-
}))));
|
|
81
|
-
}));
|
|
82
|
-
const prepareSubTaskPayload = (subTask, parentTaskGroupIds) => ({
|
|
83
|
-
name: subTask.name,
|
|
84
|
-
assignees: subTask.assignee,
|
|
85
|
-
description: subTask.description,
|
|
86
|
-
priority: subTask.priority,
|
|
87
|
-
status: subTask.status,
|
|
88
|
-
tags: subTask.tagIds,
|
|
89
|
-
time_spent: convertHHMMStrToMinutes(subTask.timeSpent),
|
|
90
|
-
group_assignees: subTask.groupAssignees,
|
|
91
|
-
parent_task_id: subTask.parentTaskId,
|
|
92
|
-
// Inherit every parent group, not just the first — see callsite for
|
|
93
|
-
// the two-scope rationale.
|
|
94
|
-
task_group_ids: parentTaskGroupIds,
|
|
95
|
-
due_date: subTask.dueDate?.format('YYYY-MM-DD') ?? null,
|
|
96
|
-
});
|