@zeniai/client-epic-state 5.2.11-betaRD2 → 5.2.11-betaRD4
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/jeSchedules/jeSchedulesPayload.d.ts +10 -0
- package/lib/entity/jeSchedules/jeSchedulesPayload.js +39 -0
- package/lib/entity/jeSchedules/jeSchedulesState.d.ts +15 -0
- package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +39 -0
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/newSchedule/createOneTimeAccrualEpic.js +7 -2
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/newSchedule/saveNewScheduleEpic.js +31 -5
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/oneTimeAccrualActionsEpic.js +33 -15
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/revertJeScheduleEpic.js +7 -2
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +6 -0
- package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +3 -0
- package/lib/index.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/createOneTimeAccrualEpic.d.ts +2 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/createOneTimeAccrualEpic.js +6 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/saveNewScheduleEpic.d.ts +4 -40
- package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/saveNewScheduleEpic.js +29 -3
- package/lib/view/expenseAutomationView/epics/jeSchedule/oneTimeAccrualActionsEpic.d.ts +2 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/oneTimeAccrualActionsEpic.js +32 -14
- package/lib/view/expenseAutomationView/epics/jeSchedule/revertJeScheduleEpic.d.ts +2 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/revertJeScheduleEpic.js +6 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +6 -0
- package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +3 -0
- package/package.json +1 -1
|
@@ -19,14 +19,24 @@ export interface JEScheduleAISummaryFieldPayload {
|
|
|
19
19
|
cot?: string[];
|
|
20
20
|
predicted_value?: number | string;
|
|
21
21
|
}
|
|
22
|
+
/** The whole-recommendation summary. Carries narrative only -- no predicted value, no confidence. */
|
|
23
|
+
export interface JEScheduleSummaryPayload {
|
|
24
|
+
cot?: string[];
|
|
25
|
+
reasoning?: string;
|
|
26
|
+
reasoning_long?: string;
|
|
27
|
+
}
|
|
22
28
|
export interface JEScheduleAISummariesPayload {
|
|
23
29
|
credit_account?: JEScheduleAISummaryFieldPayload;
|
|
24
30
|
credit_accounting_class?: JEScheduleAISummaryFieldPayload;
|
|
25
31
|
debit_account?: JEScheduleAISummaryFieldPayload;
|
|
26
32
|
debit_accounting_class?: JEScheduleAISummaryFieldPayload;
|
|
33
|
+
end_date?: JEScheduleAISummaryFieldPayload;
|
|
27
34
|
period?: JEScheduleAISummaryFieldPayload;
|
|
28
35
|
posting_date?: JEScheduleAISummaryFieldPayload;
|
|
36
|
+
posting_start_date?: JEScheduleAISummaryFieldPayload;
|
|
37
|
+
schedule_summary?: JEScheduleSummaryPayload;
|
|
29
38
|
schedule_type?: JEScheduleAISummaryFieldPayload;
|
|
39
|
+
starting_month?: JEScheduleAISummaryFieldPayload;
|
|
30
40
|
}
|
|
31
41
|
export interface JEScheduleRecommendationsPayload {
|
|
32
42
|
credit_account_confidence?: number;
|
|
@@ -215,6 +215,42 @@ function toJEScheduleAISummaries(payload) {
|
|
|
215
215
|
: undefined,
|
|
216
216
|
};
|
|
217
217
|
}
|
|
218
|
+
if (payload.starting_month != null) {
|
|
219
|
+
result.startingMonth = {
|
|
220
|
+
confidence: payload.starting_month.confidence,
|
|
221
|
+
reasoning: payload.starting_month.reasoning,
|
|
222
|
+
cot: Array.isArray(payload.starting_month.cot)
|
|
223
|
+
? payload.starting_month.cot
|
|
224
|
+
: undefined,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
if (payload.end_date != null) {
|
|
228
|
+
result.endDate = {
|
|
229
|
+
confidence: payload.end_date.confidence,
|
|
230
|
+
reasoning: payload.end_date.reasoning,
|
|
231
|
+
cot: Array.isArray(payload.end_date.cot)
|
|
232
|
+
? payload.end_date.cot
|
|
233
|
+
: undefined,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
if (payload.posting_start_date != null) {
|
|
237
|
+
result.postingStartDate = {
|
|
238
|
+
confidence: payload.posting_start_date.confidence,
|
|
239
|
+
reasoning: payload.posting_start_date.reasoning,
|
|
240
|
+
cot: Array.isArray(payload.posting_start_date.cot)
|
|
241
|
+
? payload.posting_start_date.cot
|
|
242
|
+
: undefined,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
if (payload.schedule_summary != null) {
|
|
246
|
+
result.scheduleSummary = {
|
|
247
|
+
reasoning: payload.schedule_summary.reasoning,
|
|
248
|
+
reasoningLong: payload.schedule_summary.reasoning_long,
|
|
249
|
+
cot: Array.isArray(payload.schedule_summary.cot)
|
|
250
|
+
? payload.schedule_summary.cot
|
|
251
|
+
: undefined,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
218
254
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
219
255
|
}
|
|
220
256
|
function toJEScheduleRecommendations(payload) {
|
|
@@ -329,6 +365,9 @@ function toJEAccruedScheduledTransaction(payload) {
|
|
|
329
365
|
endDate: payload.end_date != null ? (0, zeniDayJS_1.date)(payload.end_date) : undefined,
|
|
330
366
|
period: payload.period != null ? Number(payload.period) : undefined,
|
|
331
367
|
updatedByUserID: payload.updated_by.user_id,
|
|
368
|
+
// The accrued joiner resolves createdByUserID into the "Created by" cell. Without this the
|
|
369
|
+
// payload's created_by was dropped here and every accrued row rendered a hyphen.
|
|
370
|
+
createdByUserID: payload.created_by?.user_id ?? undefined,
|
|
332
371
|
balanceAsOfToday: payload.balance ?? undefined,
|
|
333
372
|
updatedAt: payload.updated_at != null ? (0, zeniDayJS_1.date)(payload.updated_at) : undefined,
|
|
334
373
|
jeCredit: {
|
|
@@ -19,14 +19,29 @@ export interface JEScheduleFieldRecommendation {
|
|
|
19
19
|
reasoning: string;
|
|
20
20
|
cot?: string[];
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* The agent's summary of the whole recommendation, as opposed to one field of it.
|
|
24
|
+
*
|
|
25
|
+
* No confidence: the producing side models this as narrative only, so anything showing a confidence
|
|
26
|
+
* alongside it has to read the schedule's own `confidenceScore`.
|
|
27
|
+
*/
|
|
28
|
+
export interface JEScheduleSummary {
|
|
29
|
+
cot?: string[];
|
|
30
|
+
reasoning?: string;
|
|
31
|
+
reasoningLong?: string;
|
|
32
|
+
}
|
|
22
33
|
export interface JEScheduleAISummaries {
|
|
23
34
|
creditAccount?: JEScheduleFieldRecommendation;
|
|
24
35
|
creditClass?: JEScheduleFieldRecommendation;
|
|
25
36
|
debitAccount?: JEScheduleFieldRecommendation;
|
|
26
37
|
debitClass?: JEScheduleFieldRecommendation;
|
|
38
|
+
endDate?: JEScheduleFieldRecommendation;
|
|
27
39
|
period?: JEScheduleFieldRecommendation;
|
|
28
40
|
postingDate?: JEScheduleFieldRecommendation;
|
|
41
|
+
postingStartDate?: JEScheduleFieldRecommendation;
|
|
42
|
+
scheduleSummary?: JEScheduleSummary;
|
|
29
43
|
scheduleType?: JEScheduleFieldRecommendation;
|
|
44
|
+
startingMonth?: JEScheduleFieldRecommendation;
|
|
30
45
|
}
|
|
31
46
|
export interface JEScheduleRecommendations {
|
|
32
47
|
creditAccountConfidence?: number;
|
|
@@ -204,6 +204,42 @@ function toJEScheduleAISummaries(payload) {
|
|
|
204
204
|
: undefined,
|
|
205
205
|
};
|
|
206
206
|
}
|
|
207
|
+
if (payload.starting_month != null) {
|
|
208
|
+
result.startingMonth = {
|
|
209
|
+
confidence: payload.starting_month.confidence,
|
|
210
|
+
reasoning: payload.starting_month.reasoning,
|
|
211
|
+
cot: Array.isArray(payload.starting_month.cot)
|
|
212
|
+
? payload.starting_month.cot
|
|
213
|
+
: undefined,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
if (payload.end_date != null) {
|
|
217
|
+
result.endDate = {
|
|
218
|
+
confidence: payload.end_date.confidence,
|
|
219
|
+
reasoning: payload.end_date.reasoning,
|
|
220
|
+
cot: Array.isArray(payload.end_date.cot)
|
|
221
|
+
? payload.end_date.cot
|
|
222
|
+
: undefined,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (payload.posting_start_date != null) {
|
|
226
|
+
result.postingStartDate = {
|
|
227
|
+
confidence: payload.posting_start_date.confidence,
|
|
228
|
+
reasoning: payload.posting_start_date.reasoning,
|
|
229
|
+
cot: Array.isArray(payload.posting_start_date.cot)
|
|
230
|
+
? payload.posting_start_date.cot
|
|
231
|
+
: undefined,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
if (payload.schedule_summary != null) {
|
|
235
|
+
result.scheduleSummary = {
|
|
236
|
+
reasoning: payload.schedule_summary.reasoning,
|
|
237
|
+
reasoningLong: payload.schedule_summary.reasoning_long,
|
|
238
|
+
cot: Array.isArray(payload.schedule_summary.cot)
|
|
239
|
+
? payload.schedule_summary.cot
|
|
240
|
+
: undefined,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
207
243
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
208
244
|
}
|
|
209
245
|
function toJEScheduleRecommendations(payload) {
|
|
@@ -318,6 +354,9 @@ export function toJEAccruedScheduledTransaction(payload) {
|
|
|
318
354
|
endDate: payload.end_date != null ? date(payload.end_date) : undefined,
|
|
319
355
|
period: payload.period != null ? Number(payload.period) : undefined,
|
|
320
356
|
updatedByUserID: payload.updated_by.user_id,
|
|
357
|
+
// The accrued joiner resolves createdByUserID into the "Created by" cell. Without this the
|
|
358
|
+
// payload's created_by was dropped here and every accrued row rendered a hyphen.
|
|
359
|
+
createdByUserID: payload.created_by?.user_id ?? undefined,
|
|
321
360
|
balanceAsOfToday: payload.balance ?? undefined,
|
|
322
361
|
updatedAt: payload.updated_at != null ? date(payload.updated_at) : undefined,
|
|
323
362
|
jeCredit: {
|
package/lib/esm/view/expenseAutomationView/epics/jeSchedule/newSchedule/createOneTimeAccrualEpic.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { from } from 'rxjs';
|
|
2
|
-
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
2
|
+
import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
|
|
3
3
|
import { convertToPeriod, toAbsoluteDay, } from '../../../../../commonStateTypes/timePeriod';
|
|
4
4
|
import { updateJEOneTimeAccruals } from '../../../../../entity/jeSchedules/jeSchedulesReducer';
|
|
5
5
|
import { openSnackbar } from '../../../../../entity/snackbar/snackbarReducer';
|
|
6
6
|
import { getCurrentTenant } from '../../../../../entity/tenant/tenantSelector';
|
|
7
|
+
import { clearAll } from '../../../../../rootActions';
|
|
7
8
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../../responsePayload';
|
|
8
9
|
import { prepareCreateOneTimeAccrualPayload, } from '../../../payload/jeSchedulesPayload';
|
|
9
10
|
import { createOneTimeAccrual, createOneTimeAccrualFailure, createOneTimeAccrualSuccess, fetchJeSchedules, } from '../../../reducers/jeSchedulesViewReducer';
|
|
@@ -95,5 +96,9 @@ export const createOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.
|
|
|
95
96
|
createOneTimeAccrualFailure({
|
|
96
97
|
status: createZeniAPIStatus('Unexpected Error', `Create One Time Accrual REST API call errored out ${JSON.stringify(error)}`),
|
|
97
98
|
}),
|
|
98
|
-
]))
|
|
99
|
+
])),
|
|
100
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
101
|
+
// Without this the old tenant's response is written back into the freshly
|
|
102
|
+
// cleared store and stays on screen under the new tenant.
|
|
103
|
+
takeUntil(actions$.pipe(filter(clearAll.match))));
|
|
99
104
|
}));
|
package/lib/esm/view/expenseAutomationView/epics/jeSchedule/newSchedule/saveNewScheduleEpic.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { from } from 'rxjs';
|
|
2
|
-
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
2
|
+
import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
|
|
3
|
+
import { convertToPeriod, toAbsoluteDay, } from '../../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { getCurrentTenant } from '../../../../../entity/tenant/tenantSelector';
|
|
5
|
+
import { clearAll } from '../../../../../rootActions';
|
|
3
6
|
import { updateJESchedules, updateJESchedulesDetails, } from '../../../../../entity/jeSchedules/jeSchedulesReducer';
|
|
4
7
|
import { getJEScheduleTransactionKey } from '../../../../../entity/jeSchedules/jeSchedulesTypes';
|
|
5
8
|
import { openSnackbar } from '../../../../../entity/snackbar/snackbarReducer';
|
|
6
9
|
import { getScheduleTransactionById } from '../../../../../entity/transaction/transactionSelector';
|
|
7
10
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../../responsePayload';
|
|
8
11
|
import { prepareNewSchedulePayload, } from '../../../helpers/newScheduleLocalDataHelper';
|
|
9
|
-
import { resetNewScheduleLocalData, saveNewSchedule, saveNewScheduleFailure, saveNewScheduleSuccess, } from '../../../reducers/jeSchedulesViewReducer';
|
|
12
|
+
import { fetchJeSchedules, resetNewScheduleLocalData, saveNewSchedule, saveNewScheduleFailure, saveNewScheduleSuccess, } from '../../../reducers/jeSchedulesViewReducer';
|
|
10
13
|
const FAILURE_REASON_MESSAGES = {
|
|
11
14
|
missing_third_party_id: 'This transaction is missing a QuickBooks reference and cannot be scheduled.',
|
|
12
15
|
missing_vendor: 'Select a vendor before saving this schedule.',
|
|
@@ -58,11 +61,21 @@ export const saveNewScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe(
|
|
|
58
61
|
je_schedule_type: scheduleType,
|
|
59
62
|
};
|
|
60
63
|
const payload = { ...result.payload };
|
|
64
|
+
// convertToPeriod destructures, so an unset period would throw here and take the epic
|
|
65
|
+
// subscription down for the whole session -- a missed refresh is the cheaper failure.
|
|
66
|
+
const selectedMonthYear = state.expenseAutomationViewState.selectedPeriodByTenantId[getCurrentTenant(state).tenantId];
|
|
67
|
+
const selectedPeriod = selectedMonthYear != null
|
|
68
|
+
? convertToPeriod(selectedMonthYear)
|
|
69
|
+
: undefined;
|
|
70
|
+
const periodStart = selectedPeriod != null
|
|
71
|
+
? toAbsoluteDay(selectedPeriod.start)
|
|
72
|
+
: undefined;
|
|
73
|
+
const periodEnd = selectedPeriod != null ? toAbsoluteDay(selectedPeriod.end) : undefined;
|
|
61
74
|
return zeniAPI
|
|
62
75
|
.postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/schedules?query=${encodeURIComponent(JSON.stringify(queryParam))}`, payload)
|
|
63
76
|
.pipe(mergeMap((response) => {
|
|
64
77
|
if (isSuccessResponse(response) && response.data != null) {
|
|
65
|
-
|
|
78
|
+
const successActions = [
|
|
66
79
|
updateJESchedules(response.data.je_schedules),
|
|
67
80
|
updateJESchedulesDetails(response.data.je_schedules, response.data.scheduled_journal_entries),
|
|
68
81
|
resetNewScheduleLocalData({ scheduleType }),
|
|
@@ -75,7 +88,16 @@ export const saveNewScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe(
|
|
|
75
88
|
{ variableName: '_vendor_name_', variableValue: vendorName },
|
|
76
89
|
],
|
|
77
90
|
}),
|
|
78
|
-
]
|
|
91
|
+
];
|
|
92
|
+
// Writing the entity is not enough: the list reads
|
|
93
|
+
// jeScheduleTransactionKeysByPeriodAndTab, which is rebuilt wholesale per fetch, so
|
|
94
|
+
// without this the new schedule stays invisible until some later fetch. The page
|
|
95
|
+
// only refetches when the save also changes tab, so saving from the tab the row
|
|
96
|
+
// lands on showed nothing. Same reasoning as createOneTimeAccrualEpic.
|
|
97
|
+
if (periodStart != null && periodEnd != null) {
|
|
98
|
+
successActions.push(fetchJeSchedules({ start: periodStart, end: periodEnd }, true));
|
|
99
|
+
}
|
|
100
|
+
return from(successActions);
|
|
79
101
|
}
|
|
80
102
|
return from([
|
|
81
103
|
saveNewScheduleFailure({ status: response.status }),
|
|
@@ -106,5 +128,9 @@ export const saveNewScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe(
|
|
|
106
128
|
saveNewScheduleFailure({
|
|
107
129
|
status: createZeniAPIStatus('Unexpected Error', `Save New Schedule REST API call errored out ${JSON.stringify(error)}`),
|
|
108
130
|
}),
|
|
109
|
-
]))
|
|
131
|
+
])),
|
|
132
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
133
|
+
// Without this the old tenant's response is written back into the freshly
|
|
134
|
+
// cleared store and stays on screen under the new tenant.
|
|
135
|
+
takeUntil(actions$.pipe(filter(clearAll.match))));
|
|
110
136
|
}));
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { from, merge } from 'rxjs';
|
|
2
|
-
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
2
|
+
import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
|
|
3
3
|
import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/timePeriod';
|
|
4
4
|
import { generateJEOneTimeAccrualKey } from '../../../../entity/jeSchedules/jeScheduleHelper';
|
|
5
5
|
import { updateJEOneTimeAccruals } from '../../../../entity/jeSchedules/jeSchedulesReducer';
|
|
6
6
|
import { getJEOneTimeAccrualByKey } from '../../../../entity/jeSchedules/jeSchedulesSelector';
|
|
7
7
|
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
8
8
|
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
9
|
+
import { clearAll } from '../../../../rootActions';
|
|
9
10
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
10
11
|
import { fetchJeSchedules, ignoreOneTimeAccrual, oneTimeAccrualActionFailure, oneTimeAccrualActionSuccess, promoteOneTimeAccrual, revertOneTimeAccrual, } from '../../reducers/jeSchedulesViewReducer';
|
|
11
12
|
/**
|
|
12
13
|
* The page the accrual came from, so a promoted or ignored row lands in the right bucket. Guarded
|
|
13
14
|
* because convertToPeriod destructures: an unset period would throw and take the epic subscription
|
|
14
15
|
* down for the session, and a missed refresh is the cheaper failure.
|
|
16
|
+
*
|
|
17
|
+
* Read state$.value at response time rather than the snapshot taken when the action was dispatched:
|
|
18
|
+
* if the user changes month while the request is in flight, the snapshot refreshes the month they
|
|
19
|
+
* have left and the month they are now looking at stays stale.
|
|
15
20
|
*/
|
|
16
21
|
function refreshCurrentPage(state) {
|
|
17
22
|
const selectedMonthYear = state.expenseAutomationViewState.selectedPeriodByTenantId[getCurrentTenant(state).tenantId];
|
|
@@ -26,14 +31,17 @@ function refreshCurrentPage(state) {
|
|
|
26
31
|
}
|
|
27
32
|
return [fetchJeSchedules({ start, end }, true)];
|
|
28
33
|
}
|
|
29
|
-
function failureActions(
|
|
34
|
+
function failureActions(
|
|
35
|
+
// Per action, not fixed: every failure used to read "Save schedule failed", so skipping or
|
|
36
|
+
// reverting an accrual reported an operation the user had not performed.
|
|
37
|
+
messageSection, accrualId, message, status) {
|
|
30
38
|
return [
|
|
31
39
|
oneTimeAccrualActionFailure({
|
|
32
40
|
accrualId,
|
|
33
41
|
status: status ?? createZeniAPIStatus('Unexpected Error', message),
|
|
34
42
|
}),
|
|
35
43
|
openSnackbar({
|
|
36
|
-
messageSection
|
|
44
|
+
messageSection,
|
|
37
45
|
messageText: 'failed',
|
|
38
46
|
type: 'error',
|
|
39
47
|
variables: [{ variableName: '_api-error_', variableValue: message }],
|
|
@@ -47,7 +55,7 @@ export const promoteOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$
|
|
|
47
55
|
if (accrual?.jeDebitAccountId == null ||
|
|
48
56
|
accrual.jeCreditAccountId == null) {
|
|
49
57
|
// Promote posts a journal entry, so it cannot proceed without both sides of it.
|
|
50
|
-
return from(failureActions(accrualId, 'This accrual is missing an expense or liability account.'));
|
|
58
|
+
return from(failureActions('save_schedule', accrualId, 'This accrual is missing an expense or liability account.'));
|
|
51
59
|
}
|
|
52
60
|
// vendor_id, vendor_name and service_month are deliberately absent: promote takes them from
|
|
53
61
|
// the stored draft and ignores them in the body, so sending them would imply a reassignment
|
|
@@ -76,14 +84,17 @@ export const promoteOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$
|
|
|
76
84
|
},
|
|
77
85
|
],
|
|
78
86
|
}),
|
|
79
|
-
...refreshCurrentPage(state),
|
|
87
|
+
...refreshCurrentPage(state$.value),
|
|
80
88
|
]);
|
|
81
89
|
}
|
|
82
|
-
return from(failureActions(accrualId, response.status.message, response.status));
|
|
83
|
-
}), catchError((error) => from(failureActions(accrualId, `Promote accrual REST API call errored out ${JSON.stringify(error)}`)))
|
|
90
|
+
return from(failureActions('save_schedule', accrualId, response.status.message, response.status));
|
|
91
|
+
}), catchError((error) => from(failureActions('save_schedule', accrualId, `Promote accrual REST API call errored out ${JSON.stringify(error)}`))),
|
|
92
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
93
|
+
// Without this the old tenant's response is written back into the freshly
|
|
94
|
+
// cleared store and stays on screen under the new tenant.
|
|
95
|
+
takeUntil(actions$.pipe(filter(clearAll.match))));
|
|
84
96
|
}));
|
|
85
97
|
export const ignoreOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(ignoreOneTimeAccrual.match), mergeMap((action) => {
|
|
86
|
-
const state = state$.value;
|
|
87
98
|
const { accrualId, reason, note } = action.payload;
|
|
88
99
|
// `scope` is deliberately never sent: the API returns 400 on it, which is why the design's
|
|
89
100
|
// "Apply to" selector cannot be built yet.
|
|
@@ -103,14 +114,17 @@ export const ignoreOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.
|
|
|
103
114
|
messageText: 'success',
|
|
104
115
|
type: 'success',
|
|
105
116
|
}),
|
|
106
|
-
...refreshCurrentPage(state),
|
|
117
|
+
...refreshCurrentPage(state$.value),
|
|
107
118
|
]);
|
|
108
119
|
}
|
|
109
|
-
return from(failureActions(accrualId, response.status.message, response.status));
|
|
110
|
-
}), catchError((error) => from(failureActions(accrualId, `Ignore accrual REST API call errored out ${JSON.stringify(error)}`)))
|
|
120
|
+
return from(failureActions('ignore_accrual', accrualId, response.status.message, response.status));
|
|
121
|
+
}), catchError((error) => from(failureActions('ignore_accrual', accrualId, `Ignore accrual REST API call errored out ${JSON.stringify(error)}`))),
|
|
122
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
123
|
+
// Without this the old tenant's response is written back into the freshly
|
|
124
|
+
// cleared store and stays on screen under the new tenant.
|
|
125
|
+
takeUntil(actions$.pipe(filter(clearAll.match))));
|
|
111
126
|
}));
|
|
112
127
|
export const revertOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(revertOneTimeAccrual.match), mergeMap((action) => {
|
|
113
|
-
const state = state$.value;
|
|
114
128
|
const { accrualId, reason, note } = action.payload;
|
|
115
129
|
// Deletes the accrual's journal entry in QBO and soft-deletes the row. `scope` is never sent:
|
|
116
130
|
// the endpoint 400s on it, exactly as ignore does.
|
|
@@ -130,10 +144,14 @@ export const revertOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.
|
|
|
130
144
|
messageText: 'success',
|
|
131
145
|
type: 'success',
|
|
132
146
|
}),
|
|
133
|
-
...refreshCurrentPage(state),
|
|
147
|
+
...refreshCurrentPage(state$.value),
|
|
134
148
|
]);
|
|
135
149
|
}
|
|
136
|
-
return from(failureActions(accrualId, response.status.message, response.status));
|
|
137
|
-
}), catchError((error) => from(failureActions(accrualId, `Revert accrual REST API call errored out ${JSON.stringify(error)}`)))
|
|
150
|
+
return from(failureActions('revert_accrual', accrualId, response.status.message, response.status));
|
|
151
|
+
}), catchError((error) => from(failureActions('revert_accrual', accrualId, `Revert accrual REST API call errored out ${JSON.stringify(error)}`))),
|
|
152
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
153
|
+
// Without this the old tenant's response is written back into the freshly
|
|
154
|
+
// cleared store and stays on screen under the new tenant.
|
|
155
|
+
takeUntil(actions$.pipe(filter(clearAll.match))));
|
|
138
156
|
}));
|
|
139
157
|
export const oneTimeAccrualActionsEpic = (actions$, state$, zeniAPI) => merge(promoteOneTimeAccrualEpic(actions$, state$, zeniAPI), ignoreOneTimeAccrualEpic(actions$, state$, zeniAPI), revertOneTimeAccrualEpic(actions$, state$, zeniAPI));
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { from } from 'rxjs';
|
|
2
|
-
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
2
|
+
import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
|
|
3
3
|
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
4
4
|
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
|
+
import { clearAll } from '../../../../rootActions';
|
|
5
6
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
6
7
|
import { fetchMonthEndCloseChecks } from '../../../monthEndCloseChecksView/monthEndCloseChecksViewReducer';
|
|
7
8
|
import { removeJeAccruedScheduleKey, removeJeScheduleTransactionKey, revertJeSchedule, revertJeScheduleFailure, revertJeScheduleSuccess, } from '../../reducers/jeSchedulesViewReducer';
|
|
@@ -102,5 +103,9 @@ export const revertJeScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
102
103
|
messageText: 'failed',
|
|
103
104
|
type: 'error',
|
|
104
105
|
}),
|
|
105
|
-
]))
|
|
106
|
+
])),
|
|
107
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
108
|
+
// Without this the old tenant's response is written back into the freshly
|
|
109
|
+
// cleared store and stays on screen under the new tenant.
|
|
110
|
+
takeUntil(actions$.pipe(filter(clearAll.match))));
|
|
106
111
|
}));
|
|
@@ -12,6 +12,12 @@ export const switchJESchedulesTabEpic = (actions$, state$) => actions$.pipe(filt
|
|
|
12
12
|
}
|
|
13
13
|
const currentTenant = getCurrentTenant(state);
|
|
14
14
|
const selectedPeriod = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant.tenantId];
|
|
15
|
+
// convertToPeriod destructures, so an unset period throws and takes this epic's subscription
|
|
16
|
+
// down for the rest of the session -- every later tab switch would then stop refreshing. A
|
|
17
|
+
// skipped refresh is the cheaper failure, as in refreshCurrentPage.
|
|
18
|
+
if (selectedPeriod == null) {
|
|
19
|
+
return EMPTY;
|
|
20
|
+
}
|
|
15
21
|
const period = convertToPeriod(selectedPeriod);
|
|
16
22
|
const timePeriodStart = toAbsoluteDay(period.start);
|
|
17
23
|
const timePeriodEnd = toAbsoluteDay(period.end);
|
|
@@ -172,6 +172,9 @@ const expenseAutomationJESchedulesView = createSlice({
|
|
|
172
172
|
draft.jeScheduleTransactionKeysByPeriodAndTab[periodTabKey] = [];
|
|
173
173
|
draft.jeScheduleAccruedKeysByPeriodAndTab[periodTabKey] = [];
|
|
174
174
|
draft.jeScheduleOneTimeAccrualKeysByPeriodAndTab[periodTabKey] = [];
|
|
175
|
+
// Cleared with the rest: leaving it behind kept the previous fetch's resolve rows on an
|
|
176
|
+
// otherwise empty errored tab, which reads as "these are all the schedules there are".
|
|
177
|
+
draft.failedJeScheduleTransactionKeysByPeriodAndTab[periodTabKey] = [];
|
|
175
178
|
}
|
|
176
179
|
},
|
|
177
180
|
retryJeSchedule(draft, action) {
|
package/lib/index.d.ts
CHANGED
|
@@ -108,7 +108,7 @@ import { TrendChangeType } from './entity/insights/insightPayload';
|
|
|
108
108
|
import { Insight } from './entity/insights/insightState';
|
|
109
109
|
import { InsightSummary } from './entity/insights/insightSummary';
|
|
110
110
|
import { JEAccruedSchedule, JEOneTimeAccrual, JEScheduledTransaction, ScheduledJournalEntry } from './entity/jeSchedules/jeSchedulesSelector';
|
|
111
|
-
import { JEOneTimeAccrualAiSuggestion, JEOneTimeAccrualBillingPattern, JEOneTimeAccrualMonthlyTotal, JEOneTimeAccrualProfileSnapshot, JEScheduleAISummaries, JEScheduleFieldRecommendation } from './entity/jeSchedules/jeSchedulesState';
|
|
111
|
+
import { JEOneTimeAccrualAiSuggestion, JEOneTimeAccrualBillingPattern, JEOneTimeAccrualMonthlyTotal, JEOneTimeAccrualProfileSnapshot, JEScheduleAISummaries, JEScheduleFieldRecommendation, JEScheduleSummary } from './entity/jeSchedules/jeSchedulesState';
|
|
112
112
|
import { ALL_JE_SCHEDULE_IGNORE_REASONS, ALL_JE_SCHEDULE_REVERT_REASONS, ALL_ONE_TIME_ACCRUAL_IGNORE_REASONS, ALL_ONE_TIME_ACCRUAL_REVERT_REASONS, ALL_SCHEDULES_TYPES, JEOneTimeAccrualKey, JEScheduleIgnoreReasonType, JEScheduleKey, JEScheduleRevertReasonType, JEScheduleTransactionKey, JournalEntryErrorCodeType, OneTimeAccrualIgnoreReasonType, OneTimeAccrualRevertReasonType, ScheduleJournalEntryStatusCodeType, ScheduleStatusCodeType, ScheduleTransactionID, ScheduleTypes, getJEScheduleTransactionKey, toScheduleTypesType, toScheduleTypesTypeStrict } from './entity/jeSchedules/jeSchedulesTypes';
|
|
113
113
|
import { Merchant } from './entity/merchant/merchant';
|
|
114
114
|
import { ALL_MONTH_END_CLOSE_CHECKS_FREQUENCY, MonthCloseCheckMetrics, MonthCloseCheckProgressJson, MonthEndAuditSummary, MonthEndCloseCheck, MonthEndCloseCheckFrequency } from './entity/monthEndCloseChecks/monthEndCloseChecksState';
|
|
@@ -940,7 +940,7 @@ export { fetchApAgingDetail, AgingReportInvoice, ApAgingDetail, getApAgingDetail
|
|
|
940
940
|
export { LinkBillExpenseKey };
|
|
941
941
|
export { clearExpenseAutomationJEScheduleLocalData, clearExpenseAutomationJESchedulesView, clearJeSearchTransactionsForNewSchedule, fetchExpenseAutomationJESchedulesPage, ignoreExpenseAutomationJESchedule, initializeJeAccountSettingsView, initializeJeNewSchedule, initializeJeScheduleLocalData, removeJeScheduleTransactionKey, resetJeNewScheduleLocalData, retryExpenseAutomationJESchedule, saveJeNewSchedule, saveJeNewScheduleFailure, saveJeNewScheduleSuccess, searchJeTransactionsForNewSchedule, searchJeTransactionsForNewScheduleFailure, searchJeTransactionsForNewScheduleSuccess, updateExpenseAutomationJESchedulesUIState, updateJeNewScheduleLocalData, updateJeScheduleLocalDataById, updateJeScheduleTransactionKeys, };
|
|
942
942
|
export { createNewSchedulesAccrued, deleteScheduleAccruedDetail, cancelScheduleAccruedJournalEntry, fetchScheduleAccruedDetails, fetchScheduleAccruedDetailsPage, resetJEAccruedLinkInLocalData, saveScheduleAccruedDetails, updateAmountsInScheduleAccruedDetail, updatedJEAccruedLinkWithRecommendedLocalData, updatedJELinkInLocalDataAccruedExpenses, fetchRecommendedTransactionRowIndex, clearSelectedJELinkRowIndex, updateLinkBillExpenseLocalData, updateScheduleAccruedDetailsLocalData, updateSelectedJEAccruedScheduleKey, resetSelectedJEAccruedScheduleKey, resetAccruedDetailNewScheduleState, };
|
|
943
|
-
export { JEScheduleKey, JEScheduleTransactionKey, ScheduleTransactionID, getJEScheduleTransactionKey, ALL_JE_SCHEDULE_IGNORE_REASONS, ALL_JE_SCHEDULE_REVERT_REASONS, ALL_ONE_TIME_ACCRUAL_IGNORE_REASONS, ALL_ONE_TIME_ACCRUAL_REVERT_REASONS, ALL_SCHEDULES_TYPES, JEScheduledTransaction, JEAccruedSchedule, JEOneTimeAccrual, JEOneTimeAccrualAiSuggestion, JEOneTimeAccrualBillingPattern, JEOneTimeAccrualMonthlyTotal, JEOneTimeAccrualProfileSnapshot, JEOneTimeAccrualKey, JEScheduleAISummaries, JEScheduleFieldRecommendation, ScheduleTypes, ScheduleJournalEntryStatusCodeType, ScheduleListReport, ScheduleAccruedListReport, getScheduleListReport, getAccruedScheduleListReport, ScheduleSubTabType, ScheduleListSortKey, fetchScheduleList, fetchAccruedScheduleList, fetchDownloadSchedules, fetchSchedulesAccount, updateScheduleListLocalData, getFetchStateForScheduleAccountList, toScheduleTypesType, toScheduleTypesTypeStrict, toScheduleListTabsFileTypeStrict, ScheduleListLocalData, ScheduleDetailsLocalDataFixedAssets, ScheduleDetailsLocalDataAccruedExpenses, ScheduleDetailsView, ScheduleAccruedDetailsView, LinkBillExpenseView, LinkBillExpenseLocalData, JEScheduleDetailsLocalData, ScheduleDetailsLocalData, toScheduleSubTabType, ScheduleStatusCodeType, JEScheduleIgnoreReasonType, JEScheduleRevertReasonType, JournalEntryErrorCodeType, OneTimeAccrualIgnoreReasonType, OneTimeAccrualRevertReasonType, ScheduleTransaction, updateScheduleListSubTab, updateScheduleListSearchText, updateScheduleListScrollState, updateScheduleListSortState, ScheduleDetailSortKey, ScheduledJournalEntry, updateSelectedJEScheduleKey, fetchScheduleDetails, getScheduleDetailsView, getAccruedScheduleDetailsView, fetchScheduleDetailsPage, saveScheduleDetails, deleteScheduleDetail, createNewSchedules, updateScheduleDetailsLocalData, JETransactionLink, updateScheduleListDownloadState, updateAccruedJEScheduleAccruedByListKey, DownloadJEScheduleTabOptions, updatedSelectedJELinkRowIndex, ScheduleListTabsFileType, getQBOUrlForLink, getThirdPartyIDFromQBOURL, updatedJELinkInLocalData, updateAmountsInScheduleDetail, ScheduleDetailUIState, resetJELinkInLocalData, JEScheduledTransactionWithBalance, JEScheduleWithBalance, JELinkType, updatedJELinkWithRecommendedLocalData, getFetchStateForScheduleListByType, getDefaultSelectedTimeframeForScheduleType, markAsCompleteScheduleDetail, resetMarkAsCompleteStatus, fetchVendorTabView, updateVendorTabViewTab, VendorTabViewTabType, getVendorTabView, VendorTabViewSelectorView, };
|
|
943
|
+
export { JEScheduleKey, JEScheduleTransactionKey, ScheduleTransactionID, getJEScheduleTransactionKey, ALL_JE_SCHEDULE_IGNORE_REASONS, ALL_JE_SCHEDULE_REVERT_REASONS, ALL_ONE_TIME_ACCRUAL_IGNORE_REASONS, ALL_ONE_TIME_ACCRUAL_REVERT_REASONS, ALL_SCHEDULES_TYPES, JEScheduledTransaction, JEAccruedSchedule, JEOneTimeAccrual, JEOneTimeAccrualAiSuggestion, JEOneTimeAccrualBillingPattern, JEOneTimeAccrualMonthlyTotal, JEOneTimeAccrualProfileSnapshot, JEOneTimeAccrualKey, JEScheduleAISummaries, JEScheduleFieldRecommendation, JEScheduleSummary, ScheduleTypes, ScheduleJournalEntryStatusCodeType, ScheduleListReport, ScheduleAccruedListReport, getScheduleListReport, getAccruedScheduleListReport, ScheduleSubTabType, ScheduleListSortKey, fetchScheduleList, fetchAccruedScheduleList, fetchDownloadSchedules, fetchSchedulesAccount, updateScheduleListLocalData, getFetchStateForScheduleAccountList, toScheduleTypesType, toScheduleTypesTypeStrict, toScheduleListTabsFileTypeStrict, ScheduleListLocalData, ScheduleDetailsLocalDataFixedAssets, ScheduleDetailsLocalDataAccruedExpenses, ScheduleDetailsView, ScheduleAccruedDetailsView, LinkBillExpenseView, LinkBillExpenseLocalData, JEScheduleDetailsLocalData, ScheduleDetailsLocalData, toScheduleSubTabType, ScheduleStatusCodeType, JEScheduleIgnoreReasonType, JEScheduleRevertReasonType, JournalEntryErrorCodeType, OneTimeAccrualIgnoreReasonType, OneTimeAccrualRevertReasonType, ScheduleTransaction, updateScheduleListSubTab, updateScheduleListSearchText, updateScheduleListScrollState, updateScheduleListSortState, ScheduleDetailSortKey, ScheduledJournalEntry, updateSelectedJEScheduleKey, fetchScheduleDetails, getScheduleDetailsView, getAccruedScheduleDetailsView, fetchScheduleDetailsPage, saveScheduleDetails, deleteScheduleDetail, createNewSchedules, updateScheduleDetailsLocalData, JETransactionLink, updateScheduleListDownloadState, updateAccruedJEScheduleAccruedByListKey, DownloadJEScheduleTabOptions, updatedSelectedJELinkRowIndex, ScheduleListTabsFileType, getQBOUrlForLink, getThirdPartyIDFromQBOURL, updatedJELinkInLocalData, updateAmountsInScheduleDetail, ScheduleDetailUIState, resetJELinkInLocalData, JEScheduledTransactionWithBalance, JEScheduleWithBalance, JELinkType, updatedJELinkWithRecommendedLocalData, getFetchStateForScheduleListByType, getDefaultSelectedTimeframeForScheduleType, markAsCompleteScheduleDetail, resetMarkAsCompleteStatus, fetchVendorTabView, updateVendorTabViewTab, VendorTabViewTabType, getVendorTabView, VendorTabViewSelectorView, };
|
|
944
944
|
export { GlobalMerchant, GlobalMerchantBase, TenantMerchant };
|
|
945
945
|
export { ReviewStatus, VendorTransactionAttachment, VendorTransactionAttachmentPayload, VendorFirstReviewViewSelectorView, VendorFirstReviewViewLocalData, VendorFirstReviewSelectorView, VendorFirstReviewSelectorAttachmentView, VendorFirstReviewViewUIState, VendorFirstReviewViewColumnKey, GlobalMerchantAutoCompleteView, VendorReviewRowCurrentSelection, toVendorFirstReviewViewColumnKeyType, RecommendedNonExistingGlobalMerchant, getGlobalMerchantAutoCompleteResults, VendorReviewRecommendationViewState, GlobalMerchantType, getVendorFirstReviewView, getVendorFirstReviewAttachmentView, fetchVendorFirstReviewView, fetchVendorFirstReviewAttachments, updateVendorFirstReviewViewScrollYOffset, resetVendorFirstReviewLocalData, updateVendorFirstReviewViewPageToken, clearRecentlySavedErroredVendorData, saveVendorFirstReviewView, updateVendorFirstReviewViewLocalData, updateVendorFirstReviewSortUiState, fetchGlobalMerchantAutoCompleteView, clearGlobalMerchantAutoCompleteResults, GlobalVendorReviewRowCurrentSelection, FirstReviewPageCurrentSelectionByColumn, updateReviewVendorDetailLocalData, saveVendorDetailsView, getVendorDetailSelectorView, FirstReviewVendorDetailSelectorView, VendorViewLocalData, };
|
|
946
946
|
export { fetchGlobalMerchantRecommendation, createGlobalMerchant, updateCreateGlobalMerchantLocalData, clearGlobalMerchantView, getGlobalMerchantView, GlobalMerchantViewSelectorView, GlobalMerchantViewState, NewGlobalMerchantData, NewGlobalMerchantCurrentSelection, };
|
package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/createOneTimeAccrualEpic.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
|
2
2
|
import { updateJEOneTimeAccruals } from '../../../../../entity/jeSchedules/jeSchedulesReducer';
|
|
3
3
|
import { openSnackbar } from '../../../../../entity/snackbar/snackbarReducer';
|
|
4
4
|
import { RootState } from '../../../../../reducer';
|
|
5
|
+
import { clearAll } from '../../../../../rootActions';
|
|
5
6
|
import { ZeniAPI } from '../../../../../zeniAPI';
|
|
6
7
|
import { createOneTimeAccrual, createOneTimeAccrualFailure, createOneTimeAccrualSuccess, fetchJeSchedules } from '../../../reducers/jeSchedulesViewReducer';
|
|
7
|
-
export type ActionType = ReturnType<typeof createOneTimeAccrual> | ReturnType<typeof createOneTimeAccrualSuccess> | ReturnType<typeof createOneTimeAccrualFailure> | ReturnType<typeof updateJEOneTimeAccruals> | ReturnType<typeof fetchJeSchedules> | ReturnType<typeof openSnackbar>;
|
|
8
|
+
export type ActionType = ReturnType<typeof clearAll> | ReturnType<typeof createOneTimeAccrual> | ReturnType<typeof createOneTimeAccrualSuccess> | ReturnType<typeof createOneTimeAccrualFailure> | ReturnType<typeof updateJEOneTimeAccruals> | ReturnType<typeof fetchJeSchedules> | ReturnType<typeof openSnackbar>;
|
|
8
9
|
export declare const createOneTimeAccrualEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => import("rxjs").Observable<ActionType>;
|
package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/createOneTimeAccrualEpic.js
CHANGED
|
@@ -7,6 +7,7 @@ const timePeriod_1 = require("../../../../../commonStateTypes/timePeriod");
|
|
|
7
7
|
const jeSchedulesReducer_1 = require("../../../../../entity/jeSchedules/jeSchedulesReducer");
|
|
8
8
|
const snackbarReducer_1 = require("../../../../../entity/snackbar/snackbarReducer");
|
|
9
9
|
const tenantSelector_1 = require("../../../../../entity/tenant/tenantSelector");
|
|
10
|
+
const rootActions_1 = require("../../../../../rootActions");
|
|
10
11
|
const responsePayload_1 = require("../../../../../responsePayload");
|
|
11
12
|
const jeSchedulesPayload_1 = require("../../../payload/jeSchedulesPayload");
|
|
12
13
|
const jeSchedulesViewReducer_1 = require("../../../reducers/jeSchedulesViewReducer");
|
|
@@ -98,6 +99,10 @@ const createOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe((0
|
|
|
98
99
|
(0, jeSchedulesViewReducer_1.createOneTimeAccrualFailure)({
|
|
99
100
|
status: (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', `Create One Time Accrual REST API call errored out ${JSON.stringify(error)}`),
|
|
100
101
|
}),
|
|
101
|
-
]))
|
|
102
|
+
])),
|
|
103
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
104
|
+
// Without this the old tenant's response is written back into the freshly
|
|
105
|
+
// cleared store and stays on screen under the new tenant.
|
|
106
|
+
(0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match))));
|
|
102
107
|
}));
|
|
103
108
|
exports.createOneTimeAccrualEpic = createOneTimeAccrualEpic;
|
package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/saveNewScheduleEpic.d.ts
CHANGED
|
@@ -1,45 +1,9 @@
|
|
|
1
1
|
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
|
+
import { clearAll } from '../../../../../rootActions';
|
|
2
3
|
import { updateJESchedules, updateJESchedulesDetails } from '../../../../../entity/jeSchedules/jeSchedulesReducer';
|
|
3
4
|
import { openSnackbar } from '../../../../../entity/snackbar/snackbarReducer';
|
|
4
5
|
import { RootState } from '../../../../../reducer';
|
|
5
6
|
import { ZeniAPI } from '../../../../../zeniAPI';
|
|
6
|
-
import { resetNewScheduleLocalData, saveNewSchedule, saveNewScheduleFailure, saveNewScheduleSuccess } from '../../../reducers/jeSchedulesViewReducer';
|
|
7
|
-
export type ActionType = ReturnType<typeof saveNewSchedule> | ReturnType<typeof saveNewScheduleSuccess> | ReturnType<typeof saveNewScheduleFailure> | ReturnType<typeof updateJESchedules> | ReturnType<typeof updateJESchedulesDetails> | ReturnType<typeof resetNewScheduleLocalData> | ReturnType<typeof openSnackbar>;
|
|
8
|
-
export declare const saveNewScheduleEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => import("rxjs").Observable<
|
|
9
|
-
payload: {
|
|
10
|
-
messageSection: import("../../../../..").SnackbarMessageSections;
|
|
11
|
-
messageText: import("../../../../..").SnackbarMessageSectionTexts;
|
|
12
|
-
type: import("../../../../..").SnackbarMessageType;
|
|
13
|
-
showStatusIcon?: boolean;
|
|
14
|
-
variables?: {
|
|
15
|
-
variableName: string;
|
|
16
|
-
variableValue: string;
|
|
17
|
-
}[];
|
|
18
|
-
};
|
|
19
|
-
type: "snackbar/openSnackbar";
|
|
20
|
-
} | {
|
|
21
|
-
payload: {
|
|
22
|
-
jeSchedulesTransactionsPayload: import("../../../../../entity/jeSchedules/jeSchedulesPayload").JEScheduledTransactionPayload[];
|
|
23
|
-
};
|
|
24
|
-
type: "jeSchedules/updateJESchedules";
|
|
25
|
-
} | {
|
|
26
|
-
payload: {
|
|
27
|
-
jeSchedulesPayload: import("../../../../../entity/jeSchedules/jeSchedulesPayload").JEScheduledTransactionPayload[];
|
|
28
|
-
scheduledJEntriesPayload: import("../../../../../entity/jeSchedules/jeSchedulesPayload").ScheduledJournalEntryPayload[] | undefined;
|
|
29
|
-
updateType: import("../../../../..").UpdateType;
|
|
30
|
-
};
|
|
31
|
-
type: "jeSchedules/updateJESchedulesDetails";
|
|
32
|
-
} | {
|
|
33
|
-
payload: {
|
|
34
|
-
scheduleType: "prepaid_expenses" | "fixed_assets";
|
|
35
|
-
};
|
|
36
|
-
type: "expenseAutomationJESchedulesView/resetNewScheduleLocalData";
|
|
37
|
-
} | {
|
|
38
|
-
payload: undefined;
|
|
39
|
-
type: "expenseAutomationJESchedulesView/saveNewScheduleSuccess";
|
|
40
|
-
} | {
|
|
41
|
-
payload: {
|
|
42
|
-
status: import("../../../../../zeniAPIStatus").ZeniAPIStatus;
|
|
43
|
-
};
|
|
44
|
-
type: "expenseAutomationJESchedulesView/saveNewScheduleFailure";
|
|
45
|
-
}>;
|
|
7
|
+
import { fetchJeSchedules, resetNewScheduleLocalData, saveNewSchedule, saveNewScheduleFailure, saveNewScheduleSuccess } from '../../../reducers/jeSchedulesViewReducer';
|
|
8
|
+
export type ActionType = ReturnType<typeof saveNewSchedule> | ReturnType<typeof saveNewScheduleSuccess> | ReturnType<typeof saveNewScheduleFailure> | ReturnType<typeof updateJESchedules> | ReturnType<typeof updateJESchedulesDetails> | ReturnType<typeof resetNewScheduleLocalData> | ReturnType<typeof fetchJeSchedules> | ReturnType<typeof clearAll> | ReturnType<typeof openSnackbar>;
|
|
9
|
+
export declare const saveNewScheduleEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => import("rxjs").Observable<ActionType>;
|
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.saveNewScheduleEpic = void 0;
|
|
4
4
|
const rxjs_1 = require("rxjs");
|
|
5
5
|
const operators_1 = require("rxjs/operators");
|
|
6
|
+
const timePeriod_1 = require("../../../../../commonStateTypes/timePeriod");
|
|
7
|
+
const tenantSelector_1 = require("../../../../../entity/tenant/tenantSelector");
|
|
8
|
+
const rootActions_1 = require("../../../../../rootActions");
|
|
6
9
|
const jeSchedulesReducer_1 = require("../../../../../entity/jeSchedules/jeSchedulesReducer");
|
|
7
10
|
const jeSchedulesTypes_1 = require("../../../../../entity/jeSchedules/jeSchedulesTypes");
|
|
8
11
|
const snackbarReducer_1 = require("../../../../../entity/snackbar/snackbarReducer");
|
|
@@ -61,11 +64,21 @@ const saveNewScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, ope
|
|
|
61
64
|
je_schedule_type: scheduleType,
|
|
62
65
|
};
|
|
63
66
|
const payload = { ...result.payload };
|
|
67
|
+
// convertToPeriod destructures, so an unset period would throw here and take the epic
|
|
68
|
+
// subscription down for the whole session -- a missed refresh is the cheaper failure.
|
|
69
|
+
const selectedMonthYear = state.expenseAutomationViewState.selectedPeriodByTenantId[(0, tenantSelector_1.getCurrentTenant)(state).tenantId];
|
|
70
|
+
const selectedPeriod = selectedMonthYear != null
|
|
71
|
+
? (0, timePeriod_1.convertToPeriod)(selectedMonthYear)
|
|
72
|
+
: undefined;
|
|
73
|
+
const periodStart = selectedPeriod != null
|
|
74
|
+
? (0, timePeriod_1.toAbsoluteDay)(selectedPeriod.start)
|
|
75
|
+
: undefined;
|
|
76
|
+
const periodEnd = selectedPeriod != null ? (0, timePeriod_1.toAbsoluteDay)(selectedPeriod.end) : undefined;
|
|
64
77
|
return zeniAPI
|
|
65
78
|
.postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/schedules?query=${encodeURIComponent(JSON.stringify(queryParam))}`, payload)
|
|
66
79
|
.pipe((0, operators_1.mergeMap)((response) => {
|
|
67
80
|
if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
|
|
68
|
-
|
|
81
|
+
const successActions = [
|
|
69
82
|
(0, jeSchedulesReducer_1.updateJESchedules)(response.data.je_schedules),
|
|
70
83
|
(0, jeSchedulesReducer_1.updateJESchedulesDetails)(response.data.je_schedules, response.data.scheduled_journal_entries),
|
|
71
84
|
(0, jeSchedulesViewReducer_1.resetNewScheduleLocalData)({ scheduleType }),
|
|
@@ -78,7 +91,16 @@ const saveNewScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, ope
|
|
|
78
91
|
{ variableName: '_vendor_name_', variableValue: vendorName },
|
|
79
92
|
],
|
|
80
93
|
}),
|
|
81
|
-
]
|
|
94
|
+
];
|
|
95
|
+
// Writing the entity is not enough: the list reads
|
|
96
|
+
// jeScheduleTransactionKeysByPeriodAndTab, which is rebuilt wholesale per fetch, so
|
|
97
|
+
// without this the new schedule stays invisible until some later fetch. The page
|
|
98
|
+
// only refetches when the save also changes tab, so saving from the tab the row
|
|
99
|
+
// lands on showed nothing. Same reasoning as createOneTimeAccrualEpic.
|
|
100
|
+
if (periodStart != null && periodEnd != null) {
|
|
101
|
+
successActions.push((0, jeSchedulesViewReducer_1.fetchJeSchedules)({ start: periodStart, end: periodEnd }, true));
|
|
102
|
+
}
|
|
103
|
+
return (0, rxjs_1.from)(successActions);
|
|
82
104
|
}
|
|
83
105
|
return (0, rxjs_1.from)([
|
|
84
106
|
(0, jeSchedulesViewReducer_1.saveNewScheduleFailure)({ status: response.status }),
|
|
@@ -109,6 +131,10 @@ const saveNewScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, ope
|
|
|
109
131
|
(0, jeSchedulesViewReducer_1.saveNewScheduleFailure)({
|
|
110
132
|
status: (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', `Save New Schedule REST API call errored out ${JSON.stringify(error)}`),
|
|
111
133
|
}),
|
|
112
|
-
]))
|
|
134
|
+
])),
|
|
135
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
136
|
+
// Without this the old tenant's response is written back into the freshly
|
|
137
|
+
// cleared store and stays on screen under the new tenant.
|
|
138
|
+
(0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match))));
|
|
113
139
|
}));
|
|
114
140
|
exports.saveNewScheduleEpic = saveNewScheduleEpic;
|
|
@@ -3,9 +3,10 @@ import { Observable } from 'rxjs';
|
|
|
3
3
|
import { updateJEOneTimeAccruals } from '../../../../entity/jeSchedules/jeSchedulesReducer';
|
|
4
4
|
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
5
5
|
import { RootState } from '../../../../reducer';
|
|
6
|
+
import { clearAll } from '../../../../rootActions';
|
|
6
7
|
import { ZeniAPI } from '../../../../zeniAPI';
|
|
7
8
|
import { fetchJeSchedules, ignoreOneTimeAccrual, oneTimeAccrualActionFailure, oneTimeAccrualActionSuccess, promoteOneTimeAccrual, revertOneTimeAccrual } from '../../reducers/jeSchedulesViewReducer';
|
|
8
|
-
export type ActionType = ReturnType<typeof promoteOneTimeAccrual> | ReturnType<typeof revertOneTimeAccrual> | ReturnType<typeof ignoreOneTimeAccrual> | ReturnType<typeof oneTimeAccrualActionSuccess> | ReturnType<typeof oneTimeAccrualActionFailure> | ReturnType<typeof updateJEOneTimeAccruals> | ReturnType<typeof fetchJeSchedules> | ReturnType<typeof openSnackbar>;
|
|
9
|
+
export type ActionType = ReturnType<typeof clearAll> | ReturnType<typeof promoteOneTimeAccrual> | ReturnType<typeof revertOneTimeAccrual> | ReturnType<typeof ignoreOneTimeAccrual> | ReturnType<typeof oneTimeAccrualActionSuccess> | ReturnType<typeof oneTimeAccrualActionFailure> | ReturnType<typeof updateJEOneTimeAccruals> | ReturnType<typeof fetchJeSchedules> | ReturnType<typeof openSnackbar>;
|
|
9
10
|
export declare const promoteOneTimeAccrualEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
|
|
10
11
|
export declare const ignoreOneTimeAccrualEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
|
|
11
12
|
export declare const revertOneTimeAccrualEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
|
|
@@ -9,12 +9,17 @@ const jeSchedulesReducer_1 = require("../../../../entity/jeSchedules/jeSchedules
|
|
|
9
9
|
const jeSchedulesSelector_1 = require("../../../../entity/jeSchedules/jeSchedulesSelector");
|
|
10
10
|
const snackbarReducer_1 = require("../../../../entity/snackbar/snackbarReducer");
|
|
11
11
|
const tenantSelector_1 = require("../../../../entity/tenant/tenantSelector");
|
|
12
|
+
const rootActions_1 = require("../../../../rootActions");
|
|
12
13
|
const responsePayload_1 = require("../../../../responsePayload");
|
|
13
14
|
const jeSchedulesViewReducer_1 = require("../../reducers/jeSchedulesViewReducer");
|
|
14
15
|
/**
|
|
15
16
|
* The page the accrual came from, so a promoted or ignored row lands in the right bucket. Guarded
|
|
16
17
|
* because convertToPeriod destructures: an unset period would throw and take the epic subscription
|
|
17
18
|
* down for the session, and a missed refresh is the cheaper failure.
|
|
19
|
+
*
|
|
20
|
+
* Read state$.value at response time rather than the snapshot taken when the action was dispatched:
|
|
21
|
+
* if the user changes month while the request is in flight, the snapshot refreshes the month they
|
|
22
|
+
* have left and the month they are now looking at stays stale.
|
|
18
23
|
*/
|
|
19
24
|
function refreshCurrentPage(state) {
|
|
20
25
|
const selectedMonthYear = state.expenseAutomationViewState.selectedPeriodByTenantId[(0, tenantSelector_1.getCurrentTenant)(state).tenantId];
|
|
@@ -29,14 +34,17 @@ function refreshCurrentPage(state) {
|
|
|
29
34
|
}
|
|
30
35
|
return [(0, jeSchedulesViewReducer_1.fetchJeSchedules)({ start, end }, true)];
|
|
31
36
|
}
|
|
32
|
-
function failureActions(
|
|
37
|
+
function failureActions(
|
|
38
|
+
// Per action, not fixed: every failure used to read "Save schedule failed", so skipping or
|
|
39
|
+
// reverting an accrual reported an operation the user had not performed.
|
|
40
|
+
messageSection, accrualId, message, status) {
|
|
33
41
|
return [
|
|
34
42
|
(0, jeSchedulesViewReducer_1.oneTimeAccrualActionFailure)({
|
|
35
43
|
accrualId,
|
|
36
44
|
status: status ?? (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', message),
|
|
37
45
|
}),
|
|
38
46
|
(0, snackbarReducer_1.openSnackbar)({
|
|
39
|
-
messageSection
|
|
47
|
+
messageSection,
|
|
40
48
|
messageText: 'failed',
|
|
41
49
|
type: 'error',
|
|
42
50
|
variables: [{ variableName: '_api-error_', variableValue: message }],
|
|
@@ -50,7 +58,7 @@ const promoteOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe((
|
|
|
50
58
|
if (accrual?.jeDebitAccountId == null ||
|
|
51
59
|
accrual.jeCreditAccountId == null) {
|
|
52
60
|
// Promote posts a journal entry, so it cannot proceed without both sides of it.
|
|
53
|
-
return (0, rxjs_1.from)(failureActions(accrualId, 'This accrual is missing an expense or liability account.'));
|
|
61
|
+
return (0, rxjs_1.from)(failureActions('save_schedule', accrualId, 'This accrual is missing an expense or liability account.'));
|
|
54
62
|
}
|
|
55
63
|
// vendor_id, vendor_name and service_month are deliberately absent: promote takes them from
|
|
56
64
|
// the stored draft and ignores them in the body, so sending them would imply a reassignment
|
|
@@ -79,15 +87,18 @@ const promoteOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe((
|
|
|
79
87
|
},
|
|
80
88
|
],
|
|
81
89
|
}),
|
|
82
|
-
...refreshCurrentPage(state),
|
|
90
|
+
...refreshCurrentPage(state$.value),
|
|
83
91
|
]);
|
|
84
92
|
}
|
|
85
|
-
return (0, rxjs_1.from)(failureActions(accrualId, response.status.message, response.status));
|
|
86
|
-
}), (0, operators_1.catchError)((error) => (0, rxjs_1.from)(failureActions(accrualId, `Promote accrual REST API call errored out ${JSON.stringify(error)}`)))
|
|
93
|
+
return (0, rxjs_1.from)(failureActions('save_schedule', accrualId, response.status.message, response.status));
|
|
94
|
+
}), (0, operators_1.catchError)((error) => (0, rxjs_1.from)(failureActions('save_schedule', accrualId, `Promote accrual REST API call errored out ${JSON.stringify(error)}`))),
|
|
95
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
96
|
+
// Without this the old tenant's response is written back into the freshly
|
|
97
|
+
// cleared store and stays on screen under the new tenant.
|
|
98
|
+
(0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match))));
|
|
87
99
|
}));
|
|
88
100
|
exports.promoteOneTimeAccrualEpic = promoteOneTimeAccrualEpic;
|
|
89
101
|
const ignoreOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(jeSchedulesViewReducer_1.ignoreOneTimeAccrual.match), (0, operators_1.mergeMap)((action) => {
|
|
90
|
-
const state = state$.value;
|
|
91
102
|
const { accrualId, reason, note } = action.payload;
|
|
92
103
|
// `scope` is deliberately never sent: the API returns 400 on it, which is why the design's
|
|
93
104
|
// "Apply to" selector cannot be built yet.
|
|
@@ -107,15 +118,18 @@ const ignoreOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe((0
|
|
|
107
118
|
messageText: 'success',
|
|
108
119
|
type: 'success',
|
|
109
120
|
}),
|
|
110
|
-
...refreshCurrentPage(state),
|
|
121
|
+
...refreshCurrentPage(state$.value),
|
|
111
122
|
]);
|
|
112
123
|
}
|
|
113
|
-
return (0, rxjs_1.from)(failureActions(accrualId, response.status.message, response.status));
|
|
114
|
-
}), (0, operators_1.catchError)((error) => (0, rxjs_1.from)(failureActions(accrualId, `Ignore accrual REST API call errored out ${JSON.stringify(error)}`)))
|
|
124
|
+
return (0, rxjs_1.from)(failureActions('ignore_accrual', accrualId, response.status.message, response.status));
|
|
125
|
+
}), (0, operators_1.catchError)((error) => (0, rxjs_1.from)(failureActions('ignore_accrual', accrualId, `Ignore accrual REST API call errored out ${JSON.stringify(error)}`))),
|
|
126
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
127
|
+
// Without this the old tenant's response is written back into the freshly
|
|
128
|
+
// cleared store and stays on screen under the new tenant.
|
|
129
|
+
(0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match))));
|
|
115
130
|
}));
|
|
116
131
|
exports.ignoreOneTimeAccrualEpic = ignoreOneTimeAccrualEpic;
|
|
117
132
|
const revertOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(jeSchedulesViewReducer_1.revertOneTimeAccrual.match), (0, operators_1.mergeMap)((action) => {
|
|
118
|
-
const state = state$.value;
|
|
119
133
|
const { accrualId, reason, note } = action.payload;
|
|
120
134
|
// Deletes the accrual's journal entry in QBO and soft-deletes the row. `scope` is never sent:
|
|
121
135
|
// the endpoint 400s on it, exactly as ignore does.
|
|
@@ -135,11 +149,15 @@ const revertOneTimeAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe((0
|
|
|
135
149
|
messageText: 'success',
|
|
136
150
|
type: 'success',
|
|
137
151
|
}),
|
|
138
|
-
...refreshCurrentPage(state),
|
|
152
|
+
...refreshCurrentPage(state$.value),
|
|
139
153
|
]);
|
|
140
154
|
}
|
|
141
|
-
return (0, rxjs_1.from)(failureActions(accrualId, response.status.message, response.status));
|
|
142
|
-
}), (0, operators_1.catchError)((error) => (0, rxjs_1.from)(failureActions(accrualId, `Revert accrual REST API call errored out ${JSON.stringify(error)}`)))
|
|
155
|
+
return (0, rxjs_1.from)(failureActions('revert_accrual', accrualId, response.status.message, response.status));
|
|
156
|
+
}), (0, operators_1.catchError)((error) => (0, rxjs_1.from)(failureActions('revert_accrual', accrualId, `Revert accrual REST API call errored out ${JSON.stringify(error)}`))),
|
|
157
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
158
|
+
// Without this the old tenant's response is written back into the freshly
|
|
159
|
+
// cleared store and stays on screen under the new tenant.
|
|
160
|
+
(0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match))));
|
|
143
161
|
}));
|
|
144
162
|
exports.revertOneTimeAccrualEpic = revertOneTimeAccrualEpic;
|
|
145
163
|
const oneTimeAccrualActionsEpic = (actions$, state$, zeniAPI) => (0, rxjs_1.merge)((0, exports.promoteOneTimeAccrualEpic)(actions$, state$, zeniAPI), (0, exports.ignoreOneTimeAccrualEpic)(actions$, state$, zeniAPI), (0, exports.revertOneTimeAccrualEpic)(actions$, state$, zeniAPI));
|
|
@@ -3,10 +3,11 @@ import { updateJESchedules, updateJESchedulesDetails } from '../../../../entity/
|
|
|
3
3
|
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
4
4
|
import { JEScheduleKey, JEScheduleTransactionKey } from '../../../../entity/jeSchedules/jeSchedulesTypes';
|
|
5
5
|
import { RootState } from '../../../../reducer';
|
|
6
|
+
import { clearAll } from '../../../../rootActions';
|
|
6
7
|
import { ZeniAPI } from '../../../../zeniAPI';
|
|
7
8
|
import { fetchMonthEndCloseChecks } from '../../../monthEndCloseChecksView/monthEndCloseChecksViewReducer';
|
|
8
9
|
import { removeJeAccruedScheduleKey, removeJeScheduleTransactionKey, revertJeSchedule, revertJeScheduleFailure, revertJeScheduleSuccess } from '../../reducers/jeSchedulesViewReducer';
|
|
9
|
-
export type ActionType = ReturnType<typeof fetchMonthEndCloseChecks> | ReturnType<typeof openSnackbar> | ReturnType<typeof removeJeAccruedScheduleKey> | ReturnType<typeof removeJeScheduleTransactionKey> | ReturnType<typeof revertJeSchedule> | ReturnType<typeof revertJeScheduleFailure> | ReturnType<typeof revertJeScheduleSuccess> | ReturnType<typeof updateJESchedules> | ReturnType<typeof updateJESchedulesDetails>;
|
|
10
|
+
export type ActionType = ReturnType<typeof clearAll> | ReturnType<typeof fetchMonthEndCloseChecks> | ReturnType<typeof openSnackbar> | ReturnType<typeof removeJeAccruedScheduleKey> | ReturnType<typeof removeJeScheduleTransactionKey> | ReturnType<typeof revertJeSchedule> | ReturnType<typeof revertJeScheduleFailure> | ReturnType<typeof revertJeScheduleSuccess> | ReturnType<typeof updateJESchedules> | ReturnType<typeof updateJESchedulesDetails>;
|
|
10
11
|
/**
|
|
11
12
|
* Undo a posted prepaid / fixed-asset / accrued schedule: deletes its posted QBO journal entry, then
|
|
12
13
|
* soft-deletes the scheduled entries and the schedule itself.
|
|
@@ -5,6 +5,7 @@ const rxjs_1 = require("rxjs");
|
|
|
5
5
|
const operators_1 = require("rxjs/operators");
|
|
6
6
|
const snackbarReducer_1 = require("../../../../entity/snackbar/snackbarReducer");
|
|
7
7
|
const tenantSelector_1 = require("../../../../entity/tenant/tenantSelector");
|
|
8
|
+
const rootActions_1 = require("../../../../rootActions");
|
|
8
9
|
const responsePayload_1 = require("../../../../responsePayload");
|
|
9
10
|
const monthEndCloseChecksViewReducer_1 = require("../../../monthEndCloseChecksView/monthEndCloseChecksViewReducer");
|
|
10
11
|
const jeSchedulesViewReducer_1 = require("../../reducers/jeSchedulesViewReducer");
|
|
@@ -105,6 +106,10 @@ const revertJeScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, op
|
|
|
105
106
|
messageText: 'failed',
|
|
106
107
|
type: 'error',
|
|
107
108
|
}),
|
|
108
|
-
]))
|
|
109
|
+
])),
|
|
110
|
+
// A tenant switch clears the store while this request is still in flight.
|
|
111
|
+
// Without this the old tenant's response is written back into the freshly
|
|
112
|
+
// cleared store and stays on screen under the new tenant.
|
|
113
|
+
(0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match))));
|
|
109
114
|
}));
|
|
110
115
|
exports.revertJeScheduleEpic = revertJeScheduleEpic;
|
|
@@ -15,6 +15,12 @@ const switchJESchedulesTabEpic = (actions$, state$) => actions$.pipe((0, operato
|
|
|
15
15
|
}
|
|
16
16
|
const currentTenant = (0, tenantSelector_1.getCurrentTenant)(state);
|
|
17
17
|
const selectedPeriod = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant.tenantId];
|
|
18
|
+
// convertToPeriod destructures, so an unset period throws and takes this epic's subscription
|
|
19
|
+
// down for the rest of the session -- every later tab switch would then stop refreshing. A
|
|
20
|
+
// skipped refresh is the cheaper failure, as in refreshCurrentPage.
|
|
21
|
+
if (selectedPeriod == null) {
|
|
22
|
+
return rxjs_1.EMPTY;
|
|
23
|
+
}
|
|
18
24
|
const period = (0, timePeriod_1.convertToPeriod)(selectedPeriod);
|
|
19
25
|
const timePeriodStart = (0, timePeriod_1.toAbsoluteDay)(period.start);
|
|
20
26
|
const timePeriodEnd = (0, timePeriod_1.toAbsoluteDay)(period.end);
|
|
@@ -178,6 +178,9 @@ const expenseAutomationJESchedulesView = (0, toolkit_1.createSlice)({
|
|
|
178
178
|
draft.jeScheduleTransactionKeysByPeriodAndTab[periodTabKey] = [];
|
|
179
179
|
draft.jeScheduleAccruedKeysByPeriodAndTab[periodTabKey] = [];
|
|
180
180
|
draft.jeScheduleOneTimeAccrualKeysByPeriodAndTab[periodTabKey] = [];
|
|
181
|
+
// Cleared with the rest: leaving it behind kept the previous fetch's resolve rows on an
|
|
182
|
+
// otherwise empty errored tab, which reads as "these are all the schedules there are".
|
|
183
|
+
draft.failedJeScheduleTransactionKeysByPeriodAndTab[periodTabKey] = [];
|
|
181
184
|
}
|
|
182
185
|
},
|
|
183
186
|
retryJeSchedule(draft, action) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeniai/client-epic-state",
|
|
3
|
-
"version": "5.2.11-
|
|
3
|
+
"version": "5.2.11-betaRD4",
|
|
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",
|