@zeniai/client-epic-state 5.2.79-betaGS3 → 5.2.79-betaGS4

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.
Files changed (27) hide show
  1. package/lib/entity/jeSchedules/jeSchedulesTypes.js +4 -1
  2. package/lib/esm/entity/jeSchedules/jeSchedulesTypes.js +4 -1
  3. package/lib/esm/index.js +3 -3
  4. package/lib/esm/reducer.js +1 -1
  5. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/compensation/createCompensationAccrualEpic.js +50 -37
  6. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -3
  7. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +1 -1
  8. package/lib/esm/view/expenseAutomationView/payload/compensationPayload.js +15 -0
  9. package/lib/esm/view/expenseAutomationView/reducers/compensationViewReducer.js +1 -2
  10. package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +1 -1
  11. package/lib/esm/view/expenseAutomationView/selectors/compensationViewSelector.js +5 -1
  12. package/lib/index.d.ts +3 -3
  13. package/lib/index.js +4 -4
  14. package/lib/reducer.js +1 -1
  15. package/lib/rootStateTypes.d.ts +1 -1
  16. package/lib/view/expenseAutomationView/epics/jeSchedule/compensation/createCompensationAccrualEpic.d.ts +2 -2
  17. package/lib/view/expenseAutomationView/epics/jeSchedule/compensation/createCompensationAccrualEpic.js +48 -35
  18. package/lib/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -3
  19. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +1 -1
  20. package/lib/view/expenseAutomationView/payload/compensationPayload.d.ts +12 -0
  21. package/lib/view/expenseAutomationView/payload/compensationPayload.js +15 -0
  22. package/lib/view/expenseAutomationView/reducers/compensationViewReducer.js +1 -2
  23. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +1 -1
  24. package/lib/view/expenseAutomationView/selectorTypes/compensationViewSelectorTypes.d.ts +1 -0
  25. package/lib/view/expenseAutomationView/selectors/compensationViewSelector.js +5 -1
  26. package/lib/view/expenseAutomationView/types/compensationViewState.d.ts +14 -0
  27. package/package.json +1 -1
@@ -81,7 +81,10 @@ const toOneTimeAccrualReversalTriggerType = (v) => (0, stringToUnion_1.stringToU
81
81
  exports.toOneTimeAccrualReversalTriggerType = toOneTimeAccrualReversalTriggerType;
82
82
  // Discriminates a vendor (bill-driven) accrual from a payroll compensation accrual. Absent on
83
83
  // older vendor documents, so the mapper leaves it undefined rather than defaulting.
84
- const ONE_TIME_ACCRUAL_TYPE = ['vendor_accrual', 'compensation_accrual'];
84
+ const ONE_TIME_ACCRUAL_TYPE = [
85
+ 'vendor_accrual',
86
+ 'compensation_accrual',
87
+ ];
85
88
  const toOneTimeAccrualType = (v) => (0, stringToUnion_1.stringToUnion)(v, ONE_TIME_ACCRUAL_TYPE);
86
89
  exports.toOneTimeAccrualType = toOneTimeAccrualType;
87
90
  exports.PAY_CADENCES = [
@@ -68,7 +68,10 @@ const ONE_TIME_ACCRUAL_REVERSAL_TRIGGER = [
68
68
  export const toOneTimeAccrualReversalTriggerType = (v) => stringToUnionStrict(v ?? '', ONE_TIME_ACCRUAL_REVERSAL_TRIGGER);
69
69
  // Discriminates a vendor (bill-driven) accrual from a payroll compensation accrual. Absent on
70
70
  // older vendor documents, so the mapper leaves it undefined rather than defaulting.
71
- const ONE_TIME_ACCRUAL_TYPE = ['vendor_accrual', 'compensation_accrual'];
71
+ const ONE_TIME_ACCRUAL_TYPE = [
72
+ 'vendor_accrual',
73
+ 'compensation_accrual',
74
+ ];
72
75
  export const toOneTimeAccrualType = (v) => stringToUnion(v, ONE_TIME_ACCRUAL_TYPE);
73
76
  export const PAY_CADENCES = [
74
77
  'weekly',
package/lib/esm/index.js CHANGED
@@ -60,7 +60,7 @@ import { getForecast } from './entity/forecast/forecastSelector';
60
60
  import { toEntityType, } from './entity/genericEntity/entity';
61
61
  import { updateEntities } from './entity/genericEntity/entityReducer';
62
62
  import { getEntityByEntityIDs } from './entity/genericEntity/entitySelector';
63
- 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, DAY_COUNT_POLICIES, PAY_CADENCES, PAYROLL_CYCLE_SOURCES, getJEScheduleTransactionKey, toDayCountPolicyType, toPayCadenceType, toPayrollCycleSourceType, toScheduleTypesType, toScheduleTypesTypeStrict, } from './entity/jeSchedules/jeSchedulesTypes';
63
+ 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, DAY_COUNT_POLICIES, PAYROLL_CYCLE_SOURCES, PAY_CADENCES, getJEScheduleTransactionKey, toDayCountPolicyType, toPayCadenceType, toPayrollCycleSourceType, toScheduleTypesType, toScheduleTypesTypeStrict, } from './entity/jeSchedules/jeSchedulesTypes';
64
64
  import { ALL_MONTH_END_CLOSE_CHECKS_FREQUENCY, } from './entity/monthEndCloseChecks/monthEndCloseChecksState';
65
65
  import { updateCommentsNotifications, updateCommentsNotificationsStatuses, } from './entity/notification/notificationReducer';
66
66
  import { toNotificationModeStrict, } from './entity/notification/types/notificationTypes';
@@ -195,7 +195,6 @@ import { clearJeScheduleLocalData as clearExpenseAutomationJEScheduleLocalData,
195
195
  import { acknowledgeBulkUploadConfirmMatchComplete, bulkUploadAutomatchingTimedOut, bulkUploadReceipts, bulkUploadReceiptsFailure, bulkUploadReceiptsSuccess, clearBulkUpload, clearBulkUploadBatchDetailsForScopeChange, clearManualSearchResults, clearMissingReceiptsTabNavigation, confirmBulkUploadMatch, confirmBulkUploadMatchFailure, confirmBulkUploadMatchSuccess, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsFailure, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatches, fetchBulkUploadBatchesFailure, fetchBulkUploadBatchesSuccess, fetchCompletedTransactions, fetchCompletedTransactionsFailure, fetchCompletedTransactionsSuccess, fetchMissingReceipts as fetchExpenseAutomationMissingReceipts, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, markBatchDetailRefreshAttempted, markMissingReceiptAsDone as markExpenseAutomationMissingReceiptAsDone, pusherBatchStatusUpdate, refreshBatchDetailsForBatchId, requestMissingReceiptsTabNavigation, restoreBulkUploadAutomatchingOnMount, restoreBulkUploadMatchingState, searchTransactionsForManualMatch, searchTransactionsForManualMatchFailure, searchTransactionsForManualMatchSuccess, setBulkUploadCompletedSubTab, setBulkUploadResultsTab, setBulkUploadSortConfig, setBulkUploadUploadedFileCount, storeBatchDetails, updateBulkUploadProgress, updateMissingReceiptUploadState as updateExpenseAutomationMissingReceiptUploadState, updateMissingReceiptsUIState as updateExpenseAutomationMissingReceiptsUIState, uploadMissingReceiptSuccess as uploadExpenseAutomationMissingReceiptSuccess, } from './view/expenseAutomationView/reducers/missingReceiptsViewReducer';
196
196
  import { clearStatementDateConflict, confirmStatementMapping, deleteAccountStatement, deleteCombinedStatement, excludeAccountFromReconciliation, fetchReconciliation as fetchReconciliationView, includeAccountInReconciliation, parseCombinedStatement, parseStatement, parseStatementFailure, parseStatementSuccess, reparseStatement, reparseStatementFailure, reparseStatementSuccess, resetReparseStatementStatus, saveReconciliationDetail as saveExpenseAutomationReconciliationDetail, saveReconciliationReview as saveExpenseAutomationReconciliationReview, setConnectionInProgressForAccount as setConnectionInProgressForAccountReconciliation, setStatementParseInProgress, setStatementProcessingDismissedToBackground, submitCombinedStatementUpdate, submitStatementUpdate, updateAccountReconciliationLocalData as updateExpenseAutomationAccountReconciliationLocalData, updateSelectedAccountId as updateExpenseAutomationAccountReconciliationSelectedAccountId, updateSelectedTab as updateExpenseAutomationAccountReconciliationSelectedTab, updateReconListScrollPosition as updateExpenseAutomationReconListScrollPosition, updateReviewTabSortState as updateExpenseAutomationReconReviewTabListSortState, updateReviewTabLocalData as updateExpenseAutomationReconReviewTabLocalData, updateReconcileTabListScrollState as updateExpenseAutomationReconcileTabListScrollState, updateReconcileTabListSortState as updateExpenseAutomationReconcileTabListSortState, updateReconcileTabLocalData as updateExpenseAutomationReconcileTabLocalData, updateSelectedDrawerAccountId as updateExpenseAutomationSelectedDrawerAccountId, updateNodeCollapseState, updateParsedStatementData, updateStatementProcessingBackgroundCompletedSteps, updateStatementProcessingFailed, updateStatementUpdateLocalData, updateStatementUploadChosen, uploadAccountStatement, } from './view/expenseAutomationView/reducers/reconciliationViewReducer';
197
197
  import { backgroundRefetchReviewTab, clearExpenseAutomationTransactionsView, fetchTransactionCategorization, fetchTransactionCategorizationFailure, fetchTransactionCategorizationView, initializeTransactionCategorizationViewLocalData, markCategoryClassRecommendationsFailureForCategorization, markTransactionAsNotMiscategorized, removeTransactionFromAllTabs, saveTransactionCategorization, saveTransactionCategorizationLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, setEntityRecommendationForLineIdsForCategorization, syncTransactionCategorizationFromDetailSave, updateCurrentSelectedTransactionCategorizationTab, updateSelectedCheckboxTransactionIds, updateSelectedCustomerForTransaction, updateSelectedTransactionId, updateSelectedVendorForTransaction, updateTransactionCategorization, updateTransactionCategorizationCompletedSubTab, updateTransactionCategorizationSaveStatus, updateTransactionCategorizationUIState, updateTransactionCategorizationUploadReceiptState, updateTransactionFilters, updateTransactionGroup, uploadTransactionCategorizationReceiptSuccess, } from './view/expenseAutomationView/reducers/transactionsViewReducer';
198
- import { NEW_PAYROLL_CYCLE_ID, } from './view/expenseAutomationView/types/compensationViewState';
199
198
  import { getExpenseAutomationFluxAnalysisView } from './view/expenseAutomationView/selectors/fluxAnalysisViewSelector';
200
199
  import { getNewAccrualAccountsView as getJeNewAccrualAccountsView, getNewScheduleSearchTransactionsView as getJeNewScheduleSearchTransactionsView, getNewScheduleView as getJeNewScheduleView, } from './view/expenseAutomationView/selectors/jeNewScheduleViewSelector';
201
200
  import { getExpenseAutomationReconciliationView, getLedgerAccountIdsWithStatementOverrideWarning, getLedgerAccountsForCombinedStatementMapping, getReparseStatementStatusByAccountId, getUnavailableLedgerAccountIds, isAccountReconReport, } from './view/expenseAutomationView/selectors/reconciliationViewSelector';
@@ -203,8 +202,9 @@ import { getExpenseAutomationTransactionView, getLastTransferEntryReplacement, }
203
202
  import { applyTransactionFilters } from './view/expenseAutomationView/transactionFilterHelpers';
204
203
  import { TRANSACTION_FILTER_CATEGORIES, } from './view/expenseAutomationView/transactionFilterTypes';
205
204
  import { ALL_ACTUAL_MATCHING_IGNORE_REASONS, MATCH_ACCRUAL_SEARCH_LIMIT, MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, actualMatchingTransactionLineKey, toActualMatchingIgnoreReasonType, toActualMatchingSortKey as toExpenseAutomationActualMatchingSortKey, toActualMatchingStatusFilter as toExpenseAutomationActualMatchingStatusFilter, toMatchAndReverseResultStatus, toUndoReversalResultStatus, } from './view/expenseAutomationView/types/actualMatchingViewState';
205
+ import { NEW_PAYROLL_CYCLE_ID, } from './view/expenseAutomationView/types/compensationViewState';
206
206
  import { DEFAULT_COMPLETED_SUB_TAB, toCompletedSubTab, } from './view/expenseAutomationView/types/completedSubTab';
207
- import { ALL_JE_PAGE_TABS, CHROME_ONLY_JE_PAGE_TABS, COMPENSATION_PAGE_TAB, toJEScheduleSortKey as toExpenseAutomationJEScheduleSortKey, toJEPageTab, isChromeOnlyJePageTab, } from './view/expenseAutomationView/types/jeSchedulesViewState';
207
+ import { ALL_JE_PAGE_TABS, CHROME_ONLY_JE_PAGE_TABS, COMPENSATION_PAGE_TAB, isChromeOnlyJePageTab, toJEScheduleSortKey as toExpenseAutomationJEScheduleSortKey, toJEPageTab, } from './view/expenseAutomationView/types/jeSchedulesViewState';
208
208
  import { BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toMatchSource, toMissingReceiptsTab, } from './view/expenseAutomationView/types/missingReceiptsViewState';
209
209
  import { toMissingReceiptsSortKey as toExpenseAutomationMissingReceiptsSortKey, } from './view/expenseAutomationView/types/missingReceiptsViewState';
210
210
  import { toReconciliationTabsType, } from './view/expenseAutomationView/types/reconciliationViewState';
@@ -38,10 +38,10 @@ import invoicingCoupon, { initialState as initialInvoicingCouponState, } from '.
38
38
  import invoicingCreditNote, { initialState as initialInvoicingCreditNoteState, } from './entity/invoicing/creditNote/creditNoteReducer';
39
39
  import invoicingDunningCase, { initialState as initialInvoicingDunningCaseState, } from './entity/invoicing/dunningCase/dunningCaseReducer';
40
40
  import invoicingInvoice, { initialState as initialInvoicingInvoiceState, } from './entity/invoicing/invoice/invoiceReducer';
41
+ import invoicingCatalog, { initialState as initialInvoicingCatalogState, } from './entity/invoicing/invoicingCatalog/invoicingCatalogReducer';
41
42
  import invoicingCustomer, { initialState as initialInvoicingCustomerState, } from './entity/invoicing/invoicingCustomer/invoicingCustomerReducer';
42
43
  import invoicingSubscription, { initialState as initialInvoicingSubscriptionState, } from './entity/invoicing/invoicingSubscription/invoicingSubscriptionReducer';
43
44
  import invoicingTransaction, { initialState as initialInvoicingTransactionState, } from './entity/invoicing/invoicingTransaction/invoicingTransactionReducer';
44
- import invoicingCatalog, { initialState as initialInvoicingCatalogState, } from './entity/invoicing/invoicingCatalog/invoicingCatalogReducer';
45
45
  import jeSchedules, { initialState as initialJESchedulesState, } from './entity/jeSchedules/jeSchedulesReducer';
46
46
  import merchant, { initialState as initialMerchantState, } from './entity/merchant/merchantReducer';
47
47
  import monthEndCloseChecks, { initialState as initialMonthEndCloseChecksState, } from './entity/monthEndCloseChecks/monthEndCloseChecksReducer';
@@ -6,8 +6,9 @@ import { openSnackbar } from '../../../../../entity/snackbar/snackbarReducer';
6
6
  import { getCurrentTenant } from '../../../../../entity/tenant/tenantSelector';
7
7
  import { createZeniAPIStatus, isSuccessResponse, } from '../../../../../responsePayload';
8
8
  import { clearAll } from '../../../../../rootActions';
9
- import { prepareCreateCompensationAccrualPayload } from '../../../payload/compensationPayload';
10
- import { closeCompensationDrawer, createCompensationAccrual, createCompensationAccrualFailure, createCompensationAccrualSuccess, fetchCompensationAccruals, upsertPayrollCycle, } from '../../../reducers/compensationViewReducer';
9
+ import { prepareCreateCompensationAccrualPayload, preparePayrollCyclePayload, } from '../../../payload/compensationPayload';
10
+ import { closeCompensationDrawer, createCompensationAccrual, createCompensationAccrualFailure, createCompensationAccrualSuccess, fetchCompensationAccruals, upsertPayrollCycleSuccess, } from '../../../reducers/compensationViewReducer';
11
+ import { NEW_PAYROLL_CYCLE_ID } from '../../../types/compensationViewState';
11
12
  export const createCompensationAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(createCompensationAccrual.match), mergeMap((action) => {
12
13
  const state = state$.value;
13
14
  const { localData } = action.payload;
@@ -19,14 +20,28 @@ export const createCompensationAccrualEpic = (actions$, state$, zeniAPI) => acti
19
20
  };
20
21
  // convertToPeriod destructures; an unset period would throw and kill the subscription.
21
22
  const selectedMonthYear = state.expenseAutomationViewState.selectedPeriodByTenantId[getCurrentTenant(state).tenantId];
22
- const selectedPeriod = selectedMonthYear != null ? convertToPeriod(selectedMonthYear) : undefined;
23
- const periodStart = selectedPeriod != null ? toAbsoluteDay(selectedPeriod.start) : undefined;
23
+ const selectedPeriod = selectedMonthYear != null
24
+ ? convertToPeriod(selectedMonthYear)
25
+ : undefined;
26
+ const periodStart = selectedPeriod != null
27
+ ? toAbsoluteDay(selectedPeriod.start)
28
+ : undefined;
24
29
  const periodEnd = selectedPeriod != null ? toAbsoluteDay(selectedPeriod.end) : undefined;
25
- return zeniAPI
26
- .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals`, payload)
30
+ const failure = (message, status) => [
31
+ createCompensationAccrualFailure({ status }),
32
+ openSnackbar({
33
+ messageSection: 'create_schedule',
34
+ messageText: 'failed',
35
+ type: 'error',
36
+ variables: [{ variableName: '_api-error_', variableValue: message }],
37
+ }),
38
+ ];
39
+ const postStub = (body, leading) => zeniAPI
40
+ .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals`, body)
27
41
  .pipe(mergeMap((response) => {
28
42
  if (isSuccessResponse(response) && response.data != null) {
29
43
  const successActions = [
44
+ ...leading,
30
45
  updateJEOneTimeAccruals([response.data.accrual]),
31
46
  createCompensationAccrualSuccess(),
32
47
  closeCompensationDrawer(),
@@ -42,9 +57,6 @@ export const createCompensationAccrualEpic = (actions$, state$, zeniAPI) => acti
42
57
  ],
43
58
  }),
44
59
  ];
45
- if (localData.repeatMonthly && localData.cycle != null) {
46
- successActions.push(upsertPayrollCycle(localData.cycle));
47
- }
48
60
  // The period slot is rebuilt per fetch; refetch rather than guess the key list.
49
61
  if (periodStart != null && periodEnd != null) {
50
62
  successActions.push(fetchCompensationAccruals({ start: periodStart, end: periodEnd }, true));
@@ -52,33 +64,34 @@ export const createCompensationAccrualEpic = (actions$, state$, zeniAPI) => acti
52
64
  return from(successActions);
53
65
  }
54
66
  return from([
55
- createCompensationAccrualFailure({ status: response.status }),
56
- openSnackbar({
57
- messageSection: 'create_schedule',
58
- messageText: 'failed',
59
- type: 'error',
60
- variables: [
61
- {
62
- variableName: '_api-error_',
63
- variableValue: response.status.message,
64
- },
65
- ],
66
- }),
67
+ ...leading,
68
+ ...failure(response.status.message, response.status),
67
69
  ]);
68
- }), catchError((error) => from([
69
- createCompensationAccrualFailure({
70
- status: createZeniAPIStatus('Unexpected Error', `Create Compensation Accrual REST API call errored out ${JSON.stringify(error)}`),
71
- }),
72
- openSnackbar({
73
- messageSection: 'create_schedule',
74
- messageText: 'failed',
75
- type: 'error',
76
- variables: [
77
- {
78
- variableName: '_api-error_',
79
- variableValue: JSON.stringify(error),
80
- },
81
- ],
82
- }),
83
- ])), takeUntil(actions$.pipe(filter(clearAll.match))));
70
+ }));
71
+ // Repeat monthly: create the pay cycle FIRST and post the stub under the id the server
72
+ // mints, so Cron 2's "already have a stub for this pay group + month" check sees it.
73
+ // Posting first under a browser id would leave the stub orphaned from its cycle and the
74
+ // agent would draft the same month again.
75
+ const request$ = localData.repeatMonthly && localData.cycle != null
76
+ ? zeniAPI
77
+ .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/payroll-cycles`, { ...preparePayrollCyclePayload(localData.cycle) })
78
+ .pipe(mergeMap((cycleResponse) => {
79
+ if (!isSuccessResponse(cycleResponse) ||
80
+ cycleResponse.data == null) {
81
+ return from(failure(cycleResponse.status.message, cycleResponse.status));
82
+ }
83
+ const cycle = cycleResponse.data.payroll_cycle;
84
+ return postStub({
85
+ ...payload,
86
+ pay_group_id: cycle.pay_group_id,
87
+ source: 'manual',
88
+ }, [
89
+ upsertPayrollCycleSuccess({
90
+ cycle,
91
+ requestedPayGroupId: NEW_PAYROLL_CYCLE_ID,
92
+ }),
93
+ ]);
94
+ }))
95
+ : postStub(payload, []);
96
+ return request$.pipe(catchError((error) => from(failure(JSON.stringify(error), createZeniAPIStatus('Unexpected Error', `Create Compensation Accrual REST API call errored out ${JSON.stringify(error)}`)))), takeUntil(actions$.pipe(filter(clearAll.match))));
84
97
  }));
@@ -41,8 +41,7 @@ export const prefetchOtherJeSchedulesTabEpic = (actions$, state$) => actions$.pi
41
41
  // GET /actual-matching is not Statsig-gated; CES has no Statsig. The screen
42
42
  // passes is_accrual_enabled so disabled tenants do not pay for a list they
43
43
  // cannot open. Visible AM is fetchJeSchedulesPageEpic's job.
44
- if (isAccrualEnabled === true &&
45
- selectedPageTab !== 'actual_matching') {
44
+ if (isAccrualEnabled === true && selectedPageTab !== 'actual_matching') {
46
45
  const periodId = toMonthYearPeriodId({
47
46
  month: period.start.month,
48
47
  year: period.start.year,
@@ -55,7 +54,8 @@ export const prefetchOtherJeSchedulesTabEpic = (actions$, state$) => actions$.pi
55
54
  }
56
55
  }
57
56
  // Same gate shape for Compensation; the slot check is per requested month.
58
- if (isCompensationEnabled === true && selectedPageTab !== 'compensation') {
57
+ if (isCompensationEnabled === true &&
58
+ selectedPageTab !== 'compensation') {
59
59
  const periodId = toMonthYearPeriodId({
60
60
  month: period.start.month,
61
61
  year: period.start.year,
@@ -15,7 +15,7 @@ export const switchJESchedulesTabEpic = (actions$, state$) => actions$.pipe(filt
15
15
  if (selectedPeriod == null || nextTab == null) {
16
16
  return EMPTY;
17
17
  }
18
- const { fetchState, refreshStatus, jeScheduleTransactionKeysByPeriodAndTab } = state.expenseAutomationJESchedulesViewState;
18
+ const { fetchState, refreshStatus, jeScheduleTransactionKeysByPeriodAndTab, } = state.expenseAutomationJESchedulesViewState;
19
19
  // Review/Existing share `/1.0/schedules` but not a cache slot. A Review
20
20
  // prefetch must not skip Existing when Existing has no keys yet — AM→Existing
21
21
  // would sit on a skeleton with no request. Skip only when this tab is warm.
@@ -49,6 +49,15 @@ export function toPayrollCycle(payload) {
49
49
  employees: payload.employees ?? undefined,
50
50
  syncedAt: payload.synced_at != null ? date(payload.synced_at) : undefined,
51
51
  accountMapping: toPayrollCycleAccountMapping(payload.account_mapping),
52
+ runs: (payload.runs ?? []).map((run) => ({
53
+ providerRunId: run.provider_run_id ?? undefined,
54
+ periodStart: run.period_start ?? undefined,
55
+ periodEnd: run.period_end ?? undefined,
56
+ checkDate: run.check_date ?? undefined,
57
+ total: run.total,
58
+ lines: (run.lines ?? []).map(toPayrollCycleLine),
59
+ })),
60
+ upcomingPayDates: payload.upcoming_pay_dates ?? [],
52
61
  };
53
62
  }
54
63
  function toPayrollCycleAccountMappingPayload(mapping) {
@@ -110,6 +119,12 @@ function toLineRequestPayloads(lines) {
110
119
  account_id: line.accountId,
111
120
  amount: line.amount,
112
121
  ...(line.accountName != null ? { account_name: line.accountName } : {}),
122
+ ...(line.accountingClassId != null
123
+ ? { accounting_class_id: line.accountingClassId }
124
+ : {}),
125
+ ...(line.accountingClassName != null
126
+ ? { accounting_class_name: line.accountingClassName }
127
+ : {}),
113
128
  ...(line.dailyRate != null ? { daily_rate: line.dailyRate } : {}),
114
129
  }));
115
130
  }
@@ -150,8 +150,7 @@ const expenseAutomationCompensationView = createSlice({
150
150
  };
151
151
  },
152
152
  upsertPayrollCycleFailure(draft, action) {
153
- draft.cycleMutationStatusByPayGroupId[action.payload.requestedPayGroupId] =
154
- { fetchState: 'Error', error: action.payload.status };
153
+ draft.cycleMutationStatusByPayGroupId[action.payload.requestedPayGroupId] = { fetchState: 'Error', error: action.payload.status };
155
154
  },
156
155
  deletePayrollCycle: {
157
156
  prepare(payGroupId) {
@@ -5,9 +5,9 @@ import { mapAccountBasePayloadToAccountBase, mapAccountMetadataPayloadToAccountM
5
5
  import { generateJEOneTimeAccrualKey } from '../../../entity/jeSchedules/jeScheduleHelper';
6
6
  import { getJEScheduleKey, getJEScheduleTransactionDetailKeyPayload, } from '../../../entity/jeSchedules/jeSchedulesPayload';
7
7
  import { clearAll } from '../../../rootActions';
8
- import { promoteCompensationAccrual } from './compensationViewReducer';
9
8
  import { mapAccountTypeRecommendationPayloadToAccountRecommendationByType, } from '../../accountMappingView/accountTypeRecommendation/accountTypeRecommendationPayload';
10
9
  import { MIN_NEW_SCHEDULE_SEARCH_LENGTH, getJESchedulePeriodTabKey, } from '../types/jeSchedulesViewState';
10
+ import { promoteCompensationAccrual } from './compensationViewReducer';
11
11
  function removeKeyFromEveryTabSlot(keysByPeriodAndTab, keyToRemove) {
12
12
  for (const periodTabKey of Object.keys(keysByPeriodAndTab)) {
13
13
  keysByPeriodAndTab[periodTabKey] = keysByPeriodAndTab[periodTabKey].filter((jeScheduleKey) => jeScheduleKey !== keyToRemove);
@@ -59,6 +59,8 @@ export function getExpenseAutomationCompensationView(state) {
59
59
  .map((accrual) => toCompensationRow(accrual, cyclesByPayGroupId[accrual.compensation.payGroupId]));
60
60
  const autoPosted = allRows.filter((row) => row.accrualStatus === 'posted');
61
61
  const pendingReview = allRows.filter((row) => row.accrualStatus === 'draft' && !row.isIgnored);
62
+ // Ignored drafts stay visible (design: "Skipped" group) so a dismissal can be seen and undone.
63
+ const skipped = allRows.filter((row) => row.accrualStatus === 'draft' && row.isIgnored);
62
64
  const stubbedPayGroupIds = new Set(allRows.map((row) => row.compensation.payGroupId));
63
65
  const cyclesWithoutStub = cycles.filter((cycle) => !cycle.isDeleted && !stubbedPayGroupIds.has(cycle.payGroupId));
64
66
  // `fetchState` is a flat slice field that survives a period switch. Until this month's keys
@@ -77,11 +79,13 @@ export function getExpenseAutomationCompensationView(state) {
77
79
  cyclesFetchState,
78
80
  autoPosted,
79
81
  pendingReview,
82
+ skipped,
80
83
  cyclesWithoutStub,
81
84
  kpiSummary: buildCompensationKpiSummary(autoPosted, pendingReview),
82
85
  uiState,
83
86
  createStatus,
84
- actionStatusById: state.expenseAutomationJESchedulesViewState.oneTimeAccrualActionStatusById,
87
+ actionStatusById: state.expenseAutomationJESchedulesViewState
88
+ .oneTimeAccrualActionStatusById,
85
89
  cycleMutationStatusByPayGroupId,
86
90
  };
87
91
  }
package/lib/index.d.ts CHANGED
@@ -109,7 +109,7 @@ 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
111
  import { CompensationAccrualDetails, CompensationAccrualLine, JEOneTimeAccrualAiSuggestion, JEOneTimeAccrualBillingPattern, JEOneTimeAccrualCleared, JEOneTimeAccrualMatchSuggestion, JEOneTimeAccrualMonthlyTotal, JEOneTimeAccrualProfileSnapshot, JEScheduleAISummaries, JEScheduleFieldRecommendation, JEScheduleSummary, OneTimeAccrualEdits } from './entity/jeSchedules/jeSchedulesState';
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, DAY_COUNT_POLICIES, DayCountPolicyType, JEOneTimeAccrualKey, JEScheduleIgnoreReasonType, JEScheduleKey, JEScheduleRevertReasonType, JEScheduleTransactionKey, JournalEntryErrorCodeType, OneTimeAccrualIgnoreReasonType, OneTimeAccrualRevertReasonType, OneTimeAccrualType, PAY_CADENCES, PAYROLL_CYCLE_SOURCES, PayCadenceType, PayrollCycleSourceType, ScheduleJournalEntryStatusCodeType, ScheduleStatusCodeType, ScheduleTransactionID, ScheduleTypes, getJEScheduleTransactionKey, toDayCountPolicyType, toPayCadenceType, toPayrollCycleSourceType, toScheduleTypesType, toScheduleTypesTypeStrict } from './entity/jeSchedules/jeSchedulesTypes';
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, DAY_COUNT_POLICIES, DayCountPolicyType, JEOneTimeAccrualKey, JEScheduleIgnoreReasonType, JEScheduleKey, JEScheduleRevertReasonType, JEScheduleTransactionKey, JournalEntryErrorCodeType, OneTimeAccrualIgnoreReasonType, OneTimeAccrualRevertReasonType, OneTimeAccrualType, PAYROLL_CYCLE_SOURCES, PAY_CADENCES, PayCadenceType, PayrollCycleSourceType, ScheduleJournalEntryStatusCodeType, ScheduleStatusCodeType, ScheduleTransactionID, ScheduleTypes, getJEScheduleTransactionKey, toDayCountPolicyType, toPayCadenceType, toPayrollCycleSourceType, 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';
115
115
  import { updateCommentsNotifications, updateCommentsNotificationsStatuses } from './entity/notification/notificationReducer';
@@ -319,7 +319,6 @@ import { clearStatementDateConflict, confirmStatementMapping, deleteAccountState
319
319
  import { backgroundRefetchReviewTab, clearExpenseAutomationTransactionsView, fetchTransactionCategorization, fetchTransactionCategorizationFailure, fetchTransactionCategorizationView, initializeTransactionCategorizationViewLocalData, markCategoryClassRecommendationsFailureForCategorization, markTransactionAsNotMiscategorized, removeTransactionFromAllTabs, saveTransactionCategorization, saveTransactionCategorizationLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, setEntityRecommendationForLineIdsForCategorization, syncTransactionCategorizationFromDetailSave, updateCurrentSelectedTransactionCategorizationTab, updateSelectedCheckboxTransactionIds, updateSelectedCustomerForTransaction, updateSelectedTransactionId, updateSelectedVendorForTransaction, updateTransactionCategorization, updateTransactionCategorizationCompletedSubTab, updateTransactionCategorizationSaveStatus, updateTransactionCategorizationUIState, updateTransactionCategorizationUploadReceiptState, updateTransactionFilters, updateTransactionGroup, uploadTransactionCategorizationReceiptSuccess } from './view/expenseAutomationView/reducers/transactionsViewReducer';
320
320
  import { ActualMatchingGroupedAccrual, ActualMatchingJournalEntryIds, ActualMatchingKpiSummary, ActualMatchingLeftoverAccrual, ActualMatchingMatchModalView, ActualMatchingMatchView, ActualMatchingRow, ActualMatchingRowKind, ExpenseAutomationActualMatchingViewSelector } from './view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes';
321
321
  import { CompensationKpiSummary, CompensationRow, ExpenseAutomationCompensationViewSelector } from './view/expenseAutomationView/selectorTypes/compensationViewSelectorTypes';
322
- import { CompensationDrawerState, CompensationViewUIState as ExpenseAutomationCompensationViewUIState, NEW_PAYROLL_CYCLE_ID, NewCompensationAccrualLine, NewCompensationAccrualLocalData, PayrollCycle, PayrollCycleAccountMapping, PayrollCycleAccountMappingEntry, PayrollCycleInput, PayrollCycleLine, PromoteCompensationAccrualLocalData } from './view/expenseAutomationView/types/compensationViewState';
323
322
  import { ExpenseAutomationStepDetails, ExpenseAutomationViewSelector } from './view/expenseAutomationView/selectorTypes/expenseAutomationViewSelectorTypes';
324
323
  import { ExpenseAutomationFluxAnalysisViewSelector, FluxAnalysisOperatingExpenseView, FluxAnalysisVendorView, FluxAnalysisViewSectionReport, FluxVendorAccountsAndClassesView } from './view/expenseAutomationView/selectorTypes/fluxAnalysisViewSelectorTypes';
325
324
  import { JEAccountSettingsView } from './view/expenseAutomationView/selectorTypes/jeAccountSettingsViewSelectorTypes';
@@ -338,9 +337,10 @@ import { getExpenseAutomationTransactionView, getLastTransferEntryReplacement }
338
337
  import { applyTransactionFilters } from './view/expenseAutomationView/transactionFilterHelpers';
339
338
  import { TRANSACTION_FILTER_CATEGORIES, TransactionFilterAmountMatchingOperator, TransactionFilterCategory, TransactionFilterCategoryDropdownOption, TransactionFilterCategoryField, TransactionFilterEntityType, TransactionFilters } from './view/expenseAutomationView/transactionFilterTypes';
340
339
  import { ALL_ACTUAL_MATCHING_IGNORE_REASONS, ActualMatchingIgnoreReasonType, ActualMatchingTransactionSearchResult, ActualMatchingSortKey as ExpenseAutomationActualMatchingSortKey, ActualMatchingStatusFilter as ExpenseAutomationActualMatchingStatusFilter, ActualMatchingViewUIState as ExpenseAutomationActualMatchingViewUIState, IgnoreActualMatchingSuggestionParams, MATCH_ACCRUAL_SEARCH_LIMIT, MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, MatchAndReverseAccrualsParams, MatchAndReverseResult, MatchAndReverseResultStatus, UndoReversalAccrualsParams, UndoReversalResult, UndoReversalResultStatus, actualMatchingTransactionLineKey, toActualMatchingIgnoreReasonType, toActualMatchingSortKey as toExpenseAutomationActualMatchingSortKey, toActualMatchingStatusFilter as toExpenseAutomationActualMatchingStatusFilter, toMatchAndReverseResultStatus, toUndoReversalResultStatus } from './view/expenseAutomationView/types/actualMatchingViewState';
340
+ import { CompensationDrawerState, CompensationViewUIState as ExpenseAutomationCompensationViewUIState, NEW_PAYROLL_CYCLE_ID, NewCompensationAccrualLine, NewCompensationAccrualLocalData, PayrollCycle, PayrollCycleAccountMapping, PayrollCycleAccountMappingEntry, PayrollCycleInput, PayrollCycleLine, PromoteCompensationAccrualLocalData } from './view/expenseAutomationView/types/compensationViewState';
341
341
  import { CompletedSubTab, DEFAULT_COMPLETED_SUB_TAB, toCompletedSubTab } from './view/expenseAutomationView/types/completedSubTab';
342
342
  import { FluxAnalysisActionType, FluxAnalysisReviewStatus, FluxAnalysisSectionType, FluxAnalysisSortKey, FluxAnalysisViewUIState, FluxBalancesByMonth } from './view/expenseAutomationView/types/fluxAnalysisViewState';
343
- import { ALL_JE_PAGE_TABS, CHROME_ONLY_JE_PAGE_TABS, COMPENSATION_PAGE_TAB, AccountSettingsLocalData, JEScheduleSortKey as ExpenseAutomationJEScheduleSortKey, JESchedulesViewUIState as ExpenseAutomationJESchedulesViewUIState, JEPageTab, JEScheduleLocalData, NewJeDetailLocalData, NewJeScheduleState, NewOneTimeAccrualLocalData, NewScheduleLocalData, NewScheduleLocalDataFixedAssets, SearchTransactionsState, toJEScheduleSortKey as toExpenseAutomationJEScheduleSortKey, toJEPageTab, isChromeOnlyJePageTab } from './view/expenseAutomationView/types/jeSchedulesViewState';
343
+ import { ALL_JE_PAGE_TABS, AccountSettingsLocalData, CHROME_ONLY_JE_PAGE_TABS, COMPENSATION_PAGE_TAB, JEScheduleSortKey as ExpenseAutomationJEScheduleSortKey, JESchedulesViewUIState as ExpenseAutomationJESchedulesViewUIState, JEPageTab, JEScheduleLocalData, NewJeDetailLocalData, NewJeScheduleState, NewOneTimeAccrualLocalData, NewScheduleLocalData, NewScheduleLocalDataFixedAssets, SearchTransactionsState, isChromeOnlyJePageTab, toJEScheduleSortKey as toExpenseAutomationJEScheduleSortKey, toJEPageTab } from './view/expenseAutomationView/types/jeSchedulesViewState';
344
344
  import { BATCH_FILE_STATUSES, BatchDetails, BatchFile, BatchFileStatus, BatchListItem, BatchStatus, BatchStatusValue, BatchSummary, BulkUploadPhase, BulkUploadResultsTab, BulkUploadSortKey, BulkUploadState, CandidateRef, MatchCandidate, MatchSource, MissingReceiptsTab, isUnmatchedTabFileStatus, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toMatchSource, toMissingReceiptsTab } from './view/expenseAutomationView/types/missingReceiptsViewState';
345
345
  import { MissingReceiptsSortKey as ExpenseAutomationMissingReceiptsSortKey, MissingReceiptsViewState as ExpenseAutomationMissingReceiptsViewState, MissingReceiptsViewUIState as ExpenseAutomationMissingReceiptsViewUIState, toMissingReceiptsSortKey as toExpenseAutomationMissingReceiptsSortKey } from './view/expenseAutomationView/types/missingReceiptsViewState';
346
346
  import { AccountReconciliationLocalData, CombinedStatementAccount, ExcludeAccountFromReconciliationPayload, ReconciliationViewTabType as ExpenseAutomationReconciliationViewTab, ParsedStatementData, ReconReconcileSortKey, ReconReviewSortKey, ReconciliationReconcileTabLocalData, ReconciliationReviewTabLocalData, SaveReconcileDetailActionPayload as SaveExpenseAutomationReconciliationActionType, StatementAccountScope, StatementDateConflict, StatementMeta, StatementTransaction, StatementTransactionForUpdate, StatementTransactionsUpdate, StatementUpdateLocalData, toReconciliationTabsType } from './view/expenseAutomationView/types/reconciliationViewState';
package/lib/index.js CHANGED
@@ -303,8 +303,8 @@ Object.defineProperty(exports, "ALL_ONE_TIME_ACCRUAL_IGNORE_REASONS", { enumerab
303
303
  Object.defineProperty(exports, "ALL_ONE_TIME_ACCRUAL_REVERT_REASONS", { enumerable: true, get: function () { return jeSchedulesTypes_1.ALL_ONE_TIME_ACCRUAL_REVERT_REASONS; } });
304
304
  Object.defineProperty(exports, "ALL_SCHEDULES_TYPES", { enumerable: true, get: function () { return jeSchedulesTypes_1.ALL_SCHEDULES_TYPES; } });
305
305
  Object.defineProperty(exports, "DAY_COUNT_POLICIES", { enumerable: true, get: function () { return jeSchedulesTypes_1.DAY_COUNT_POLICIES; } });
306
- Object.defineProperty(exports, "PAY_CADENCES", { enumerable: true, get: function () { return jeSchedulesTypes_1.PAY_CADENCES; } });
307
306
  Object.defineProperty(exports, "PAYROLL_CYCLE_SOURCES", { enumerable: true, get: function () { return jeSchedulesTypes_1.PAYROLL_CYCLE_SOURCES; } });
307
+ Object.defineProperty(exports, "PAY_CADENCES", { enumerable: true, get: function () { return jeSchedulesTypes_1.PAY_CADENCES; } });
308
308
  Object.defineProperty(exports, "getJEScheduleTransactionKey", { enumerable: true, get: function () { return jeSchedulesTypes_1.getJEScheduleTransactionKey; } });
309
309
  Object.defineProperty(exports, "toDayCountPolicyType", { enumerable: true, get: function () { return jeSchedulesTypes_1.toDayCountPolicyType; } });
310
310
  Object.defineProperty(exports, "toPayCadenceType", { enumerable: true, get: function () { return jeSchedulesTypes_1.toPayCadenceType; } });
@@ -1056,8 +1056,6 @@ Object.defineProperty(exports, "updateTransactionCategorizationUploadReceiptStat
1056
1056
  Object.defineProperty(exports, "updateTransactionFilters", { enumerable: true, get: function () { return transactionsViewReducer_1.updateTransactionFilters; } });
1057
1057
  Object.defineProperty(exports, "updateTransactionGroup", { enumerable: true, get: function () { return transactionsViewReducer_1.updateTransactionGroup; } });
1058
1058
  Object.defineProperty(exports, "uploadTransactionCategorizationReceiptSuccess", { enumerable: true, get: function () { return transactionsViewReducer_1.uploadTransactionCategorizationReceiptSuccess; } });
1059
- const compensationViewState_1 = require("./view/expenseAutomationView/types/compensationViewState");
1060
- Object.defineProperty(exports, "NEW_PAYROLL_CYCLE_ID", { enumerable: true, get: function () { return compensationViewState_1.NEW_PAYROLL_CYCLE_ID; } });
1061
1059
  const fluxAnalysisViewSelector_1 = require("./view/expenseAutomationView/selectors/fluxAnalysisViewSelector");
1062
1060
  Object.defineProperty(exports, "getExpenseAutomationFluxAnalysisView", { enumerable: true, get: function () { return fluxAnalysisViewSelector_1.getExpenseAutomationFluxAnalysisView; } });
1063
1061
  const jeNewScheduleViewSelector_1 = require("./view/expenseAutomationView/selectors/jeNewScheduleViewSelector");
@@ -1089,6 +1087,8 @@ Object.defineProperty(exports, "toExpenseAutomationActualMatchingSortKey", { enu
1089
1087
  Object.defineProperty(exports, "toExpenseAutomationActualMatchingStatusFilter", { enumerable: true, get: function () { return actualMatchingViewState_1.toActualMatchingStatusFilter; } });
1090
1088
  Object.defineProperty(exports, "toMatchAndReverseResultStatus", { enumerable: true, get: function () { return actualMatchingViewState_1.toMatchAndReverseResultStatus; } });
1091
1089
  Object.defineProperty(exports, "toUndoReversalResultStatus", { enumerable: true, get: function () { return actualMatchingViewState_1.toUndoReversalResultStatus; } });
1090
+ const compensationViewState_1 = require("./view/expenseAutomationView/types/compensationViewState");
1091
+ Object.defineProperty(exports, "NEW_PAYROLL_CYCLE_ID", { enumerable: true, get: function () { return compensationViewState_1.NEW_PAYROLL_CYCLE_ID; } });
1092
1092
  const completedSubTab_1 = require("./view/expenseAutomationView/types/completedSubTab");
1093
1093
  Object.defineProperty(exports, "DEFAULT_COMPLETED_SUB_TAB", { enumerable: true, get: function () { return completedSubTab_1.DEFAULT_COMPLETED_SUB_TAB; } });
1094
1094
  Object.defineProperty(exports, "toCompletedSubTab", { enumerable: true, get: function () { return completedSubTab_1.toCompletedSubTab; } });
@@ -1096,9 +1096,9 @@ const jeSchedulesViewState_1 = require("./view/expenseAutomationView/types/jeSch
1096
1096
  Object.defineProperty(exports, "ALL_JE_PAGE_TABS", { enumerable: true, get: function () { return jeSchedulesViewState_1.ALL_JE_PAGE_TABS; } });
1097
1097
  Object.defineProperty(exports, "CHROME_ONLY_JE_PAGE_TABS", { enumerable: true, get: function () { return jeSchedulesViewState_1.CHROME_ONLY_JE_PAGE_TABS; } });
1098
1098
  Object.defineProperty(exports, "COMPENSATION_PAGE_TAB", { enumerable: true, get: function () { return jeSchedulesViewState_1.COMPENSATION_PAGE_TAB; } });
1099
+ Object.defineProperty(exports, "isChromeOnlyJePageTab", { enumerable: true, get: function () { return jeSchedulesViewState_1.isChromeOnlyJePageTab; } });
1099
1100
  Object.defineProperty(exports, "toExpenseAutomationJEScheduleSortKey", { enumerable: true, get: function () { return jeSchedulesViewState_1.toJEScheduleSortKey; } });
1100
1101
  Object.defineProperty(exports, "toJEPageTab", { enumerable: true, get: function () { return jeSchedulesViewState_1.toJEPageTab; } });
1101
- Object.defineProperty(exports, "isChromeOnlyJePageTab", { enumerable: true, get: function () { return jeSchedulesViewState_1.isChromeOnlyJePageTab; } });
1102
1102
  const missingReceiptsViewState_1 = require("./view/expenseAutomationView/types/missingReceiptsViewState");
1103
1103
  Object.defineProperty(exports, "BATCH_FILE_STATUSES", { enumerable: true, get: function () { return missingReceiptsViewState_1.BATCH_FILE_STATUSES; } });
1104
1104
  Object.defineProperty(exports, "isUnmatchedTabFileStatus", { enumerable: true, get: function () { return missingReceiptsViewState_1.isUnmatchedTabFileStatus; } });
package/lib/reducer.js CHANGED
@@ -77,10 +77,10 @@ const couponReducer_1 = __importStar(require("./entity/invoicing/coupon/couponRe
77
77
  const creditNoteReducer_1 = __importStar(require("./entity/invoicing/creditNote/creditNoteReducer"));
78
78
  const dunningCaseReducer_1 = __importStar(require("./entity/invoicing/dunningCase/dunningCaseReducer"));
79
79
  const invoiceReducer_1 = __importStar(require("./entity/invoicing/invoice/invoiceReducer"));
80
+ const invoicingCatalogReducer_1 = __importStar(require("./entity/invoicing/invoicingCatalog/invoicingCatalogReducer"));
80
81
  const invoicingCustomerReducer_1 = __importStar(require("./entity/invoicing/invoicingCustomer/invoicingCustomerReducer"));
81
82
  const invoicingSubscriptionReducer_1 = __importStar(require("./entity/invoicing/invoicingSubscription/invoicingSubscriptionReducer"));
82
83
  const invoicingTransactionReducer_1 = __importStar(require("./entity/invoicing/invoicingTransaction/invoicingTransactionReducer"));
83
- const invoicingCatalogReducer_1 = __importStar(require("./entity/invoicing/invoicingCatalog/invoicingCatalogReducer"));
84
84
  const jeSchedulesReducer_1 = __importStar(require("./entity/jeSchedules/jeSchedulesReducer"));
85
85
  const merchantReducer_1 = __importStar(require("./entity/merchant/merchantReducer"));
86
86
  const monthEndCloseChecksReducer_1 = __importStar(require("./entity/monthEndCloseChecks/monthEndCloseChecksReducer"));
@@ -37,10 +37,10 @@ import { InvoicingCouponState } from './entity/invoicing/coupon/couponState';
37
37
  import { InvoicingCreditNoteState } from './entity/invoicing/creditNote/creditNoteState';
38
38
  import { InvoicingDunningCaseState } from './entity/invoicing/dunningCase/dunningCaseState';
39
39
  import { InvoiceState as InvoicingInvoiceState } from './entity/invoicing/invoice/invoiceState';
40
+ import { InvoicingCatalogState } from './entity/invoicing/invoicingCatalog/invoicingCatalogState';
40
41
  import { InvoicingCustomerState } from './entity/invoicing/invoicingCustomer/invoicingCustomerState';
41
42
  import { InvoicingSubscriptionState } from './entity/invoicing/invoicingSubscription/invoicingSubscriptionState';
42
43
  import { InvoicingTransactionState } from './entity/invoicing/invoicingTransaction/invoicingTransactionState';
43
- import { InvoicingCatalogState } from './entity/invoicing/invoicingCatalog/invoicingCatalogState';
44
44
  import { JESchedulesState } from './entity/jeSchedules/jeSchedulesState';
45
45
  import { MerchantState } from './entity/merchant/merchant';
46
46
  import { MonthEndCloseChecksState } from './entity/monthEndCloseChecks/monthEndCloseChecksState';
@@ -5,6 +5,6 @@ import { openSnackbar } from '../../../../../entity/snackbar/snackbarReducer';
5
5
  import { clearAll } from '../../../../../rootActions';
6
6
  import { RootState } from '../../../../../rootStateTypes';
7
7
  import { ZeniAPI } from '../../../../../zeniAPI';
8
- import { closeCompensationDrawer, createCompensationAccrual, createCompensationAccrualFailure, createCompensationAccrualSuccess, fetchCompensationAccruals, upsertPayrollCycle } from '../../../reducers/compensationViewReducer';
9
- export type ActionType = ReturnType<typeof clearAll> | ReturnType<typeof closeCompensationDrawer> | ReturnType<typeof createCompensationAccrual> | ReturnType<typeof createCompensationAccrualFailure> | ReturnType<typeof createCompensationAccrualSuccess> | ReturnType<typeof fetchCompensationAccruals> | ReturnType<typeof openSnackbar> | ReturnType<typeof updateJEOneTimeAccruals> | ReturnType<typeof upsertPayrollCycle>;
8
+ import { closeCompensationDrawer, createCompensationAccrual, createCompensationAccrualFailure, createCompensationAccrualSuccess, fetchCompensationAccruals, upsertPayrollCycleSuccess } from '../../../reducers/compensationViewReducer';
9
+ export type ActionType = ReturnType<typeof clearAll> | ReturnType<typeof closeCompensationDrawer> | ReturnType<typeof createCompensationAccrual> | ReturnType<typeof createCompensationAccrualFailure> | ReturnType<typeof createCompensationAccrualSuccess> | ReturnType<typeof fetchCompensationAccruals> | ReturnType<typeof openSnackbar> | ReturnType<typeof updateJEOneTimeAccruals> | ReturnType<typeof upsertPayrollCycleSuccess>;
10
10
  export declare const createCompensationAccrualEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
@@ -11,6 +11,7 @@ const responsePayload_1 = require("../../../../../responsePayload");
11
11
  const rootActions_1 = require("../../../../../rootActions");
12
12
  const compensationPayload_1 = require("../../../payload/compensationPayload");
13
13
  const compensationViewReducer_1 = require("../../../reducers/compensationViewReducer");
14
+ const compensationViewState_1 = require("../../../types/compensationViewState");
14
15
  const createCompensationAccrualEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(compensationViewReducer_1.createCompensationAccrual.match), (0, operators_1.mergeMap)((action) => {
15
16
  const state = state$.value;
16
17
  const { localData } = action.payload;
@@ -22,14 +23,28 @@ const createCompensationAccrualEpic = (actions$, state$, zeniAPI) => actions$.pi
22
23
  };
23
24
  // convertToPeriod destructures; an unset period would throw and kill the subscription.
24
25
  const selectedMonthYear = state.expenseAutomationViewState.selectedPeriodByTenantId[(0, tenantSelector_1.getCurrentTenant)(state).tenantId];
25
- const selectedPeriod = selectedMonthYear != null ? (0, timePeriod_1.convertToPeriod)(selectedMonthYear) : undefined;
26
- const periodStart = selectedPeriod != null ? (0, timePeriod_1.toAbsoluteDay)(selectedPeriod.start) : undefined;
26
+ const selectedPeriod = selectedMonthYear != null
27
+ ? (0, timePeriod_1.convertToPeriod)(selectedMonthYear)
28
+ : undefined;
29
+ const periodStart = selectedPeriod != null
30
+ ? (0, timePeriod_1.toAbsoluteDay)(selectedPeriod.start)
31
+ : undefined;
27
32
  const periodEnd = selectedPeriod != null ? (0, timePeriod_1.toAbsoluteDay)(selectedPeriod.end) : undefined;
28
- return zeniAPI
29
- .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals`, payload)
33
+ const failure = (message, status) => [
34
+ (0, compensationViewReducer_1.createCompensationAccrualFailure)({ status }),
35
+ (0, snackbarReducer_1.openSnackbar)({
36
+ messageSection: 'create_schedule',
37
+ messageText: 'failed',
38
+ type: 'error',
39
+ variables: [{ variableName: '_api-error_', variableValue: message }],
40
+ }),
41
+ ];
42
+ const postStub = (body, leading) => zeniAPI
43
+ .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals`, body)
30
44
  .pipe((0, operators_1.mergeMap)((response) => {
31
45
  if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
32
46
  const successActions = [
47
+ ...leading,
33
48
  (0, jeSchedulesReducer_1.updateJEOneTimeAccruals)([response.data.accrual]),
34
49
  (0, compensationViewReducer_1.createCompensationAccrualSuccess)(),
35
50
  (0, compensationViewReducer_1.closeCompensationDrawer)(),
@@ -45,9 +60,6 @@ const createCompensationAccrualEpic = (actions$, state$, zeniAPI) => actions$.pi
45
60
  ],
46
61
  }),
47
62
  ];
48
- if (localData.repeatMonthly && localData.cycle != null) {
49
- successActions.push((0, compensationViewReducer_1.upsertPayrollCycle)(localData.cycle));
50
- }
51
63
  // The period slot is rebuilt per fetch; refetch rather than guess the key list.
52
64
  if (periodStart != null && periodEnd != null) {
53
65
  successActions.push((0, compensationViewReducer_1.fetchCompensationAccruals)({ start: periodStart, end: periodEnd }, true));
@@ -55,34 +67,35 @@ const createCompensationAccrualEpic = (actions$, state$, zeniAPI) => actions$.pi
55
67
  return (0, rxjs_1.from)(successActions);
56
68
  }
57
69
  return (0, rxjs_1.from)([
58
- (0, compensationViewReducer_1.createCompensationAccrualFailure)({ status: response.status }),
59
- (0, snackbarReducer_1.openSnackbar)({
60
- messageSection: 'create_schedule',
61
- messageText: 'failed',
62
- type: 'error',
63
- variables: [
64
- {
65
- variableName: '_api-error_',
66
- variableValue: response.status.message,
67
- },
68
- ],
69
- }),
70
+ ...leading,
71
+ ...failure(response.status.message, response.status),
70
72
  ]);
71
- }), (0, operators_1.catchError)((error) => (0, rxjs_1.from)([
72
- (0, compensationViewReducer_1.createCompensationAccrualFailure)({
73
- status: (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', `Create Compensation Accrual REST API call errored out ${JSON.stringify(error)}`),
74
- }),
75
- (0, snackbarReducer_1.openSnackbar)({
76
- messageSection: 'create_schedule',
77
- messageText: 'failed',
78
- type: 'error',
79
- variables: [
80
- {
81
- variableName: '_api-error_',
82
- variableValue: JSON.stringify(error),
83
- },
84
- ],
85
- }),
86
- ])), (0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match))));
73
+ }));
74
+ // Repeat monthly: create the pay cycle FIRST and post the stub under the id the server
75
+ // mints, so Cron 2's "already have a stub for this pay group + month" check sees it.
76
+ // Posting first under a browser id would leave the stub orphaned from its cycle and the
77
+ // agent would draft the same month again.
78
+ const request$ = localData.repeatMonthly && localData.cycle != null
79
+ ? zeniAPI
80
+ .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/payroll-cycles`, { ...(0, compensationPayload_1.preparePayrollCyclePayload)(localData.cycle) })
81
+ .pipe((0, operators_1.mergeMap)((cycleResponse) => {
82
+ if (!(0, responsePayload_1.isSuccessResponse)(cycleResponse) ||
83
+ cycleResponse.data == null) {
84
+ return (0, rxjs_1.from)(failure(cycleResponse.status.message, cycleResponse.status));
85
+ }
86
+ const cycle = cycleResponse.data.payroll_cycle;
87
+ return postStub({
88
+ ...payload,
89
+ pay_group_id: cycle.pay_group_id,
90
+ source: 'manual',
91
+ }, [
92
+ (0, compensationViewReducer_1.upsertPayrollCycleSuccess)({
93
+ cycle,
94
+ requestedPayGroupId: compensationViewState_1.NEW_PAYROLL_CYCLE_ID,
95
+ }),
96
+ ]);
97
+ }))
98
+ : postStub(payload, []);
99
+ return request$.pipe((0, operators_1.catchError)((error) => (0, rxjs_1.from)(failure(JSON.stringify(error), (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', `Create Compensation Accrual REST API call errored out ${JSON.stringify(error)}`)))), (0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match))));
87
100
  }));
88
101
  exports.createCompensationAccrualEpic = createCompensationAccrualEpic;
@@ -44,8 +44,7 @@ const prefetchOtherJeSchedulesTabEpic = (actions$, state$) => actions$.pipe((0,
44
44
  // GET /actual-matching is not Statsig-gated; CES has no Statsig. The screen
45
45
  // passes is_accrual_enabled so disabled tenants do not pay for a list they
46
46
  // cannot open. Visible AM is fetchJeSchedulesPageEpic's job.
47
- if (isAccrualEnabled === true &&
48
- selectedPageTab !== 'actual_matching') {
47
+ if (isAccrualEnabled === true && selectedPageTab !== 'actual_matching') {
49
48
  const periodId = (0, timePeriod_1.toMonthYearPeriodId)({
50
49
  month: period.start.month,
51
50
  year: period.start.year,
@@ -58,7 +57,8 @@ const prefetchOtherJeSchedulesTabEpic = (actions$, state$) => actions$.pipe((0,
58
57
  }
59
58
  }
60
59
  // Same gate shape for Compensation; the slot check is per requested month.
61
- if (isCompensationEnabled === true && selectedPageTab !== 'compensation') {
60
+ if (isCompensationEnabled === true &&
61
+ selectedPageTab !== 'compensation') {
62
62
  const periodId = (0, timePeriod_1.toMonthYearPeriodId)({
63
63
  month: period.start.month,
64
64
  year: period.start.year,
@@ -18,7 +18,7 @@ const switchJESchedulesTabEpic = (actions$, state$) => actions$.pipe((0, operato
18
18
  if (selectedPeriod == null || nextTab == null) {
19
19
  return rxjs_1.EMPTY;
20
20
  }
21
- const { fetchState, refreshStatus, jeScheduleTransactionKeysByPeriodAndTab } = state.expenseAutomationJESchedulesViewState;
21
+ const { fetchState, refreshStatus, jeScheduleTransactionKeysByPeriodAndTab, } = state.expenseAutomationJESchedulesViewState;
22
22
  // Review/Existing share `/1.0/schedules` but not a cache slot. A Review
23
23
  // prefetch must not skip Existing when Existing has no keys yet — AM→Existing
24
24
  // would sit on a skeleton with no request. Skip only when this tab is warm.
@@ -36,7 +36,17 @@ export interface PayrollCyclePayload {
36
36
  last_period_end?: string | null;
37
37
  last_period_start?: string | null;
38
38
  next_pay_date?: string | null;
39
+ runs?: PayrollRunPayload[] | null;
39
40
  synced_at?: string | null;
41
+ upcoming_pay_dates?: string[] | null;
42
+ }
43
+ export interface PayrollRunPayload {
44
+ lines: PayrollCycleLinePayload[];
45
+ total: number;
46
+ check_date?: string | null;
47
+ period_end?: string | null;
48
+ period_start?: string | null;
49
+ provider_run_id?: string | null;
40
50
  }
41
51
  export type PayrollCyclesListResponse = ZeniAPIResponse<{
42
52
  payroll_cycles: PayrollCyclePayload[];
@@ -66,6 +76,8 @@ export interface PayrollCycleRequestPayload {
66
76
  export declare function preparePayrollCyclePayload(input: PayrollCycleInput): PayrollCycleRequestPayload;
67
77
  export type CompensationAccrualLineRequestPayload = Pick<CompensationAccrualLinePayload, 'account_id' | 'amount'> & {
68
78
  account_name?: string;
79
+ accounting_class_id?: ID;
80
+ accounting_class_name?: string;
69
81
  daily_rate?: number;
70
82
  };
71
83
  export interface CreateCompensationAccrualPayload {
@@ -56,6 +56,15 @@ function toPayrollCycle(payload) {
56
56
  employees: payload.employees ?? undefined,
57
57
  syncedAt: payload.synced_at != null ? (0, zeniDayJS_1.date)(payload.synced_at) : undefined,
58
58
  accountMapping: toPayrollCycleAccountMapping(payload.account_mapping),
59
+ runs: (payload.runs ?? []).map((run) => ({
60
+ providerRunId: run.provider_run_id ?? undefined,
61
+ periodStart: run.period_start ?? undefined,
62
+ periodEnd: run.period_end ?? undefined,
63
+ checkDate: run.check_date ?? undefined,
64
+ total: run.total,
65
+ lines: (run.lines ?? []).map(toPayrollCycleLine),
66
+ })),
67
+ upcomingPayDates: payload.upcoming_pay_dates ?? [],
59
68
  };
60
69
  }
61
70
  function toPayrollCycleAccountMappingPayload(mapping) {
@@ -117,6 +126,12 @@ function toLineRequestPayloads(lines) {
117
126
  account_id: line.accountId,
118
127
  amount: line.amount,
119
128
  ...(line.accountName != null ? { account_name: line.accountName } : {}),
129
+ ...(line.accountingClassId != null
130
+ ? { accounting_class_id: line.accountingClassId }
131
+ : {}),
132
+ ...(line.accountingClassName != null
133
+ ? { accounting_class_name: line.accountingClassName }
134
+ : {}),
120
135
  ...(line.dailyRate != null ? { daily_rate: line.dailyRate } : {}),
121
136
  }));
122
137
  }
@@ -154,8 +154,7 @@ const expenseAutomationCompensationView = (0, toolkit_1.createSlice)({
154
154
  };
155
155
  },
156
156
  upsertPayrollCycleFailure(draft, action) {
157
- draft.cycleMutationStatusByPayGroupId[action.payload.requestedPayGroupId] =
158
- { fetchState: 'Error', error: action.payload.status };
157
+ draft.cycleMutationStatusByPayGroupId[action.payload.requestedPayGroupId] = { fetchState: 'Error', error: action.payload.status };
159
158
  },
160
159
  deletePayrollCycle: {
161
160
  prepare(payGroupId) {
@@ -10,9 +10,9 @@ const accountPayload_1 = require("../../../entity/account/accountPayload");
10
10
  const jeScheduleHelper_1 = require("../../../entity/jeSchedules/jeScheduleHelper");
11
11
  const jeSchedulesPayload_1 = require("../../../entity/jeSchedules/jeSchedulesPayload");
12
12
  const rootActions_1 = require("../../../rootActions");
13
- const compensationViewReducer_1 = require("./compensationViewReducer");
14
13
  const accountTypeRecommendationPayload_1 = require("../../accountMappingView/accountTypeRecommendation/accountTypeRecommendationPayload");
15
14
  const jeSchedulesViewState_1 = require("../types/jeSchedulesViewState");
15
+ const compensationViewReducer_1 = require("./compensationViewReducer");
16
16
  function removeKeyFromEveryTabSlot(keysByPeriodAndTab, keyToRemove) {
17
17
  for (const periodTabKey of Object.keys(keysByPeriodAndTab)) {
18
18
  keysByPeriodAndTab[periodTabKey] = keysByPeriodAndTab[periodTabKey].filter((jeScheduleKey) => jeScheduleKey !== keyToRemove);
@@ -37,5 +37,6 @@ export interface ExpenseAutomationCompensationViewSelector extends SelectorView
37
37
  kpiSummary: CompensationKpiSummary;
38
38
  pendingReview: CompensationRow[];
39
39
  refreshStatus: FetchStateAndError;
40
+ skipped: CompensationRow[];
40
41
  uiState: CompensationViewUIState;
41
42
  }
@@ -64,6 +64,8 @@ function getExpenseAutomationCompensationView(state) {
64
64
  .map((accrual) => toCompensationRow(accrual, cyclesByPayGroupId[accrual.compensation.payGroupId]));
65
65
  const autoPosted = allRows.filter((row) => row.accrualStatus === 'posted');
66
66
  const pendingReview = allRows.filter((row) => row.accrualStatus === 'draft' && !row.isIgnored);
67
+ // Ignored drafts stay visible (design: "Skipped" group) so a dismissal can be seen and undone.
68
+ const skipped = allRows.filter((row) => row.accrualStatus === 'draft' && row.isIgnored);
67
69
  const stubbedPayGroupIds = new Set(allRows.map((row) => row.compensation.payGroupId));
68
70
  const cyclesWithoutStub = cycles.filter((cycle) => !cycle.isDeleted && !stubbedPayGroupIds.has(cycle.payGroupId));
69
71
  // `fetchState` is a flat slice field that survives a period switch. Until this month's keys
@@ -82,11 +84,13 @@ function getExpenseAutomationCompensationView(state) {
82
84
  cyclesFetchState,
83
85
  autoPosted,
84
86
  pendingReview,
87
+ skipped,
85
88
  cyclesWithoutStub,
86
89
  kpiSummary: buildCompensationKpiSummary(autoPosted, pendingReview),
87
90
  uiState,
88
91
  createStatus,
89
- actionStatusById: state.expenseAutomationJESchedulesViewState.oneTimeAccrualActionStatusById,
92
+ actionStatusById: state.expenseAutomationJESchedulesViewState
93
+ .oneTimeAccrualActionStatusById,
90
94
  cycleMutationStatusByPayGroupId,
91
95
  };
92
96
  }
@@ -29,7 +29,11 @@ export interface PayrollCycle {
29
29
  payGroupId: ID;
30
30
  payGroupName: string;
31
31
  provider: string;
32
+ /** Processed runs newest first (synced rows); the run PAID by a month end is what covers it. */
33
+ runs: PayrollRun[];
32
34
  source: PayrollCycleSourceType;
35
+ /** Scheduled pay dates after the latest processed run, ascending. */
36
+ upcomingPayDates: string[];
33
37
  accountMapping?: PayrollCycleAccountMapping;
34
38
  employees?: number;
35
39
  lastPayDate?: string;
@@ -38,6 +42,14 @@ export interface PayrollCycle {
38
42
  nextPayDate?: string;
39
43
  syncedAt?: ZeniDate;
40
44
  }
45
+ export interface PayrollRun {
46
+ lines: PayrollCycleLine[];
47
+ total: number;
48
+ checkDate?: string;
49
+ periodEnd?: string;
50
+ periodStart?: string;
51
+ providerRunId?: string;
52
+ }
41
53
  /** Create (no `payGroupId`) or edit (with `payGroupId`) body for a pay group. */
42
54
  export interface PayrollCycleInput {
43
55
  accountMapping?: PayrollCycleAccountMapping;
@@ -55,6 +67,8 @@ export declare const NEW_PAYROLL_CYCLE_ID: ID;
55
67
  export interface NewCompensationAccrualLine {
56
68
  accountId: ID;
57
69
  amount: number;
70
+ accountingClassId?: ID;
71
+ accountingClassName?: string;
58
72
  accountName?: string;
59
73
  dailyRate?: number;
60
74
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.2.79-betaGS3",
3
+ "version": "5.2.79-betaGS4",
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",