@zeniai/client-epic-state 5.1.66 → 5.1.67

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 (24) hide show
  1. package/lib/entity/approvalRule/approvalRuleState.d.ts +1 -0
  2. package/lib/entity/entityApprovalStatus/entityApprovalStatusPayload.d.ts +1 -0
  3. package/lib/entity/entityApprovalStatus/entityApprovalStatusPayload.js +1 -0
  4. package/lib/entity/entityApprovalStatus/entityApprovalStatusState.d.ts +1 -0
  5. package/lib/esm/entity/entityApprovalStatus/entityApprovalStatusPayload.js +1 -0
  6. package/lib/esm/view/spendManagement/billPay/billDetailView/billDetailViewSelector.js +76 -37
  7. package/lib/esm/view/spendManagement/billPay/billList/billListSelector.js +14 -17
  8. package/lib/esm/view/spendManagement/billPay/editBillView/editBillViewSelector.js +1 -3
  9. package/lib/esm/view/spendManagement/billPay/editBillView/epics/fetchEditBillDetailPageEpic.js +0 -14
  10. package/lib/esm/view/spendManagement/helpers.js +14 -0
  11. package/lib/esm/view/spendManagement/reimbursement/remiDetailView/remiDetailViewSelector.js +44 -19
  12. package/lib/esm/view/spendManagement/reimbursement/remiListView/remiListSelector.js +14 -17
  13. package/lib/view/spendManagement/billPay/billDetailView/billDetailViewSelector.d.ts +2 -0
  14. package/lib/view/spendManagement/billPay/billDetailView/billDetailViewSelector.js +75 -36
  15. package/lib/view/spendManagement/billPay/billList/billListSelector.js +13 -16
  16. package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.js +1 -3
  17. package/lib/view/spendManagement/billPay/editBillView/epics/fetchEditBillDetailPageEpic.d.ts +1 -2
  18. package/lib/view/spendManagement/billPay/editBillView/epics/fetchEditBillDetailPageEpic.js +0 -14
  19. package/lib/view/spendManagement/helpers.d.ts +5 -1
  20. package/lib/view/spendManagement/helpers.js +18 -1
  21. package/lib/view/spendManagement/reimbursement/remiDetailView/remiDetailViewSelector.d.ts +2 -0
  22. package/lib/view/spendManagement/reimbursement/remiDetailView/remiDetailViewSelector.js +43 -18
  23. package/lib/view/spendManagement/reimbursement/remiListView/remiListSelector.js +13 -16
  24. package/package.json +1 -1
@@ -109,5 +109,6 @@ export interface ApprovalRule {
109
109
  export interface Approvers {
110
110
  attributes: AttributeType[];
111
111
  users: User[];
112
+ displayPendingApproverAsAdmin?: boolean;
112
113
  }
113
114
  export {};
@@ -38,6 +38,7 @@ export interface EntityApprovalStatusPayload {
38
38
  approval_rule_id?: string | null;
39
39
  current_pending_step_index?: number;
40
40
  is_real_time_approval_enabled?: boolean;
41
+ sod_excluded_approver_user_id?: string | null;
41
42
  }
42
43
  /**
43
44
  * Helpers
@@ -24,6 +24,7 @@ const toEntityApprovalStatus = (payload) => ({
24
24
  currentPendingStepIndex: payload.current_pending_step_index,
25
25
  isAdminFallbackApprover: payload.is_admin_fallback_approver_for_missing_user,
26
26
  isRealTimeApprovalEnabled: payload.is_real_time_approval_enabled ?? false,
27
+ sodExcludedApproverUserId: payload.sod_excluded_approver_user_id ?? undefined,
27
28
  });
28
29
  exports.toEntityApprovalStatus = toEntityApprovalStatus;
29
30
  const toEntityApprovalByUser = (payload) => {
@@ -55,6 +55,7 @@ export interface EntityApprovalStatus {
55
55
  approvalLastUpdateTime?: ZeniDate;
56
56
  approvalRuleId?: ID;
57
57
  currentPendingStepIndex?: number;
58
+ sodExcludedApproverUserId?: ID;
58
59
  status?: EntityApprovalStatusCode;
59
60
  }
60
61
  export {};
@@ -21,6 +21,7 @@ export const toEntityApprovalStatus = (payload) => ({
21
21
  currentPendingStepIndex: payload.current_pending_step_index,
22
22
  isAdminFallbackApprover: payload.is_admin_fallback_approver_for_missing_user,
23
23
  isRealTimeApprovalEnabled: payload.is_real_time_approval_enabled ?? false,
24
+ sodExcludedApproverUserId: payload.sod_excluded_approver_user_id ?? undefined,
24
25
  });
25
26
  const toEntityApprovalByUser = (payload) => {
26
27
  const res = {};
@@ -13,7 +13,7 @@ import { getUserByUserId } from '../../../../entity/user/userSelector';
13
13
  import { getUserRoleByUserId } from '../../../../entity/userRole/userRoleSelector';
14
14
  import { getActivityHistory, } from '../../commonHistoryView/commonHistorySelector';
15
15
  import { getAllFundingAccounts, } from '../../commonSetup/setupViewSelector';
16
- import { getLatestApprovalDate, isAwaitingMarkAsPaid } from '../../helpers';
16
+ import { getLatestApprovalDate, isAwaitingMarkAsPaid, isSodAdminFallbackEligibleForStep, isSodExcludedViewerBlocked, } from '../../helpers';
17
17
  import { getActivityRealTimeApproval, } from '../../realTimeApprovalView/realTimeApprovalSelector';
18
18
  import { getEntityRealTimeApprovalDetailKey } from '../../realTimeApprovalView/realTimeApprovalState';
19
19
  import { getBillPaymentSubConfigCodeKey, getInternationalSubConfigCodeKey, getInternationalWireMethodCodeKey, } from '../billPayConfig/billPayConfigPayload';
@@ -57,7 +57,7 @@ export const getBillActivities = (state, billId, billStageCode) => {
57
57
  const approvalRules = getApprovalRulesByIds(approvalRuleState, billDetail.approvalRuleIds);
58
58
  const entityApprovalStatusByIds = getEntityApprovalStatusByIds(entityApprovalStatusState, billDetail.entityApprovalIds);
59
59
  billActivities = entityApprovalStatusByIds.map((entityApprovalStatus) => {
60
- const { approvalRuleId, entityType, createTime, updateTime, stepsApprovalStatus, areApprovalsSerialized, isAdminFallbackApprover, isRealTimeApprovalEnabled, currentPendingStepIndex, } = entityApprovalStatus;
60
+ const { approvalRuleId, entityType, createTime, updateTime, stepsApprovalStatus, areApprovalsSerialized, isAdminFallbackApprover, isRealTimeApprovalEnabled, currentPendingStepIndex, sodExcludedApproverUserId, } = entityApprovalStatus;
61
61
  const approvalRule = approvalRules.find((rule) => rule.approvalRuleId === approvalRuleId);
62
62
  return {
63
63
  approvalRuleId,
@@ -69,21 +69,22 @@ export const getBillActivities = (state, billId, billStageCode) => {
69
69
  isAdminFallbackApprover,
70
70
  isRealTimeApprovalEnabled,
71
71
  currentPendingStepIndex,
72
+ sodExcludedApproverUserId,
72
73
  entityApprovalId: entityApprovalStatus.entityApprovalId,
73
74
  stepsWithStatus: stepsApprovalStatus.map((step) => {
75
+ const actorsActivity = step.actorsActivity.map((activity) => ({
76
+ ...activity,
77
+ actor: getUserByUserId(userState, activity.userId),
78
+ }));
74
79
  return {
75
80
  ...step,
76
81
  actors: step.actors
77
82
  .map((actor) => getUserByUserId(userState, actor.userId))
78
83
  .filter((user) => user != null),
79
84
  nonUserActors: step.actors.filter((actor) => actor.userId == null && actor.type !== 'user'),
80
- actorsActivity: step.actorsActivity.map((activity) => {
81
- return {
82
- ...activity,
83
- actor: getUserByUserId(userState, activity.userId),
84
- };
85
- }),
85
+ actorsActivity,
86
86
  isOriginalApprovalStep: step.isOriginalApprovalStep,
87
+ displayPendingApproverAsAdmin: isSodAdminFallbackEligibleForStep(sodExcludedApproverUserId, isAdminFallbackApprover, actorsActivity),
87
88
  };
88
89
  }),
89
90
  };
@@ -248,7 +249,7 @@ export const checkApproveRejectBtnShow = (billActivities, isUserAdmin, signedInU
248
249
  let isMarkAsPaidBtnVisible = false;
249
250
  let rejectedId = -1;
250
251
  const stepsWithStatusData = billActivities[0].stepsWithStatus;
251
- const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, } = billActivities[0];
252
+ const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, sodExcludedApproverUserId, } = billActivities[0];
252
253
  for (const [index, stepWithStatus] of stepsWithStatusData.entries()) {
253
254
  if (stepWithStatus.action === 'require_approval') {
254
255
  for (const actorActivity of stepWithStatus.actorsActivity) {
@@ -289,23 +290,42 @@ export const checkApproveRejectBtnShow = (billActivities, isUserAdmin, signedInU
289
290
  break;
290
291
  }
291
292
  }
292
- for (const actorActivity of pendingStep.actorsActivity) {
293
- if (actorActivity.actor?.userId === signedInUser?.userId &&
294
- isAllActivitiesPending) {
295
- isApprovalorRejectBtnVisible = true;
296
- isMarkAsPaidBtnVisible = isLastApprovalStep;
293
+ const sodBlocked = isSodExcludedViewerBlocked(sodExcludedApproverUserId, signedInUser?.userId, pendingStep.actorsActivity);
294
+ if (isAllActivitiesPending) {
295
+ for (const actorActivity of pendingStep.actorsActivity) {
296
+ if (!sodBlocked &&
297
+ actorActivity.actor?.userId === signedInUser?.userId) {
298
+ isApprovalorRejectBtnVisible = true;
299
+ isMarkAsPaidBtnVisible = isLastApprovalStep;
300
+ break;
301
+ }
297
302
  }
298
- // admin will be fallback approver if vendor-owner/manager are not assigned any user id
299
- if (actorActivity.type === 'attribute' &&
300
- (actorActivity.subType === 'manager' ||
301
- actorActivity.subType === 'vendor_owner') &&
302
- actorActivity.userId === null &&
303
- isAdminFallbackApprover === true &&
304
- isUserAdmin === true) {
305
- isApprovalorRejectBtnVisible = true;
306
- isMarkAsPaidBtnVisible = isLastApprovalStep;
303
+ }
304
+ if (!isApprovalorRejectBtnVisible) {
305
+ for (const actorActivity of pendingStep.actorsActivity) {
306
+ // admin will be fallback approver if vendor-owner/manager are not assigned any user id
307
+ if (actorActivity.type === 'attribute' &&
308
+ (actorActivity.subType === 'manager' ||
309
+ actorActivity.subType === 'vendor_owner') &&
310
+ actorActivity.userId === null &&
311
+ isAdminFallbackApprover &&
312
+ isUserAdmin &&
313
+ signedInUser?.userId != null &&
314
+ signedInUser.userId !== sodExcludedApproverUserId) {
315
+ isApprovalorRejectBtnVisible = true;
316
+ isMarkAsPaidBtnVisible = isLastApprovalStep;
317
+ break;
318
+ }
307
319
  }
308
320
  }
321
+ if (!isApprovalorRejectBtnVisible &&
322
+ isUserAdmin &&
323
+ signedInUser?.userId != null &&
324
+ signedInUser.userId !== sodExcludedApproverUserId &&
325
+ pendingStep.displayPendingApproverAsAdmin) {
326
+ isApprovalorRejectBtnVisible = true;
327
+ isMarkAsPaidBtnVisible = isLastApprovalStep;
328
+ }
309
329
  }
310
330
  }
311
331
  }
@@ -319,23 +339,42 @@ export const checkApproveRejectBtnShow = (billActivities, isUserAdmin, signedInU
319
339
  break;
320
340
  }
321
341
  }
322
- for (const actorActivity of stepWithStatus.actorsActivity) {
323
- if (actorActivity.actor?.userId === signedInUser?.userId &&
324
- isAllActivitiesPending) {
325
- isApprovalorRejectBtnVisible = true;
326
- isMarkAsPaidBtnVisible = true;
342
+ const sodBlocked = isSodExcludedViewerBlocked(sodExcludedApproverUserId, signedInUser?.userId, stepWithStatus.actorsActivity);
343
+ if (isAllActivitiesPending) {
344
+ for (const actorActivity of stepWithStatus.actorsActivity) {
345
+ if (!sodBlocked &&
346
+ actorActivity.actor?.userId === signedInUser?.userId) {
347
+ isApprovalorRejectBtnVisible = true;
348
+ isMarkAsPaidBtnVisible = true;
349
+ break;
350
+ }
327
351
  }
328
- // admin will be fallback approver if vendor-owner/manager are not assigned any user id
329
- else if (actorActivity.type === 'attribute' &&
330
- (actorActivity.subType === 'manager' ||
331
- actorActivity.subType === 'vendor_owner') &&
332
- actorActivity.userId === null &&
333
- isAdminFallbackApprover === true &&
334
- isUserAdmin === true) {
335
- isApprovalorRejectBtnVisible = true;
336
- isMarkAsPaidBtnVisible = true;
352
+ }
353
+ if (!isApprovalorRejectBtnVisible) {
354
+ for (const actorActivity of stepWithStatus.actorsActivity) {
355
+ // admin will be fallback approver if vendor-owner/manager are not assigned any user id
356
+ if (actorActivity.type === 'attribute' &&
357
+ (actorActivity.subType === 'manager' ||
358
+ actorActivity.subType === 'vendor_owner') &&
359
+ actorActivity.userId === null &&
360
+ isAdminFallbackApprover &&
361
+ isUserAdmin &&
362
+ signedInUser?.userId != null &&
363
+ signedInUser.userId !== sodExcludedApproverUserId) {
364
+ isApprovalorRejectBtnVisible = true;
365
+ isMarkAsPaidBtnVisible = true;
366
+ break;
367
+ }
337
368
  }
338
369
  }
370
+ if (!isApprovalorRejectBtnVisible &&
371
+ isUserAdmin &&
372
+ signedInUser?.userId != null &&
373
+ signedInUser.userId !== sodExcludedApproverUserId &&
374
+ stepWithStatus.displayPendingApproverAsAdmin) {
375
+ isApprovalorRejectBtnVisible = true;
376
+ isMarkAsPaidBtnVisible = true;
377
+ }
339
378
  }
340
379
  if (isApprovalorRejectBtnVisible) {
341
380
  break;
@@ -4,7 +4,7 @@ import orderBy from 'lodash/orderBy';
4
4
  import { toAttributeTypeStrict, } from '../../../../entity/approvalRule/approvalRuleState';
5
5
  import { getUserByUserId } from '../../../../entity/user/userSelector';
6
6
  import { dateNow } from '../../../../zeniDayJS';
7
- import { isAwaitingMarkAsPaid, isBulkProcessing, } from '../../helpers';
7
+ import { isAwaitingMarkAsPaid, isBulkProcessing, isSodAdminFallbackEligibleForStep, } from '../../helpers';
8
8
  import { applyAdvancedFiltersOnList, isBillListDownloadable, } from '../../spendManagementFilterHelpers';
9
9
  import { getSelectedWithdrawFromAccount } from '../billDetailView/billDetailViewSelector';
10
10
  import { getBillPayConfigBotEmail } from '../billPayConfig/billPayConfigSelector';
@@ -290,7 +290,7 @@ export const getApproversOrRejectors = (billTransaction, entityApprovalStatusSta
290
290
  };
291
291
  if (billTransaction.entityApprovalId !== null) {
292
292
  const entityApprovalStatus = entityApprovalStatusState.entityApprovalStatusById[billTransaction.entityApprovalId];
293
- const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, } = entityApprovalStatus;
293
+ const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, sodExcludedApproverUserId, } = entityApprovalStatus;
294
294
  const isBillSerailized = areApprovalsSerialized === true &&
295
295
  currentPendingStepIndex != null &&
296
296
  currentPendingStepIndex > -1;
@@ -318,23 +318,20 @@ export const getApproversOrRejectors = (billTransaction, entityApprovalStatusSta
318
318
  if (isBillSerailized) {
319
319
  requireApprovalInfo = [stepsApprovalStatus[currentPendingStepIndex]];
320
320
  }
321
- const pendingActivitiesList = [];
322
321
  requireApprovalInfo.forEach((approvalStep) => {
323
- const pendingActivities = approvalStep.actorsActivity.filter((activity) => activity.activity === 'pending');
324
- //if isBillSerailized, we need to show all the approvers in currentPendingStepIndex
325
- if (isBillSerailized) {
326
- pendingActivitiesList.push(...pendingActivities);
322
+ if (approvers.displayPendingApproverAsAdmin) {
323
+ return;
327
324
  }
328
- else {
329
- //if not isBillSerailized, we need to show all the first approvers in each steps_approval_status
330
- const pendingActivity = pendingActivities[0];
331
- if (pendingActivity != null) {
332
- pendingActivitiesList.push(pendingActivity);
333
- }
325
+ const pendingActivities = approvalStep.actorsActivity.filter((activity) => activity.activity === 'pending');
326
+ const sodDisplayAsAdmin = isSodAdminFallbackEligibleForStep(sodExcludedApproverUserId, isAdminFallbackApprover, approvalStep.actorsActivity);
327
+ const activitiesToShow = isBillSerailized
328
+ ? pendingActivities
329
+ : pendingActivities.slice(0, 1);
330
+ if (sodDisplayAsAdmin) {
331
+ approvers.displayPendingApproverAsAdmin = true;
332
+ return;
334
333
  }
335
- });
336
- if (pendingActivitiesList.length > 0) {
337
- pendingActivitiesList.forEach((activity) => {
334
+ activitiesToShow.forEach((activity) => {
338
335
  const user = getUserByUserId(userState, activity.userId);
339
336
  if (user != null) {
340
337
  approvers.users.push(user);
@@ -346,7 +343,7 @@ export const getApproversOrRejectors = (billTransaction, entityApprovalStatusSta
346
343
  }
347
344
  }
348
345
  });
349
- }
346
+ });
350
347
  }
351
348
  }
352
349
  }
@@ -29,7 +29,7 @@ import { getDuplicateBills, } from '../billPayReview/billPayReviewSelector';
29
29
  import { getBillPaySetupApproverView } from '../billPaySetupApproverView/billPaySetupApproverViewSelector';
30
30
  import { getPreviousBills, } from '../previousBills/previousBillsSelector';
31
31
  export const getEditBillDetail = (state, isVendorRecommendationFeatureEnabled, isZeniAccountsEnabled, billId) => {
32
- const { accountListState, accountState, bankAccountState, billDetailViewState, paymentAccountListState, billTransactionState, billPayConfigState, classListState, classState, editBillDetailViewState, paymentAccountState, vendorState, tenantState, companyState, userState, commonHistoryState, contactState, paymentInstrumentState, recurringBillState, depositAccountListState, depositAccountState, billPaySetupApproverViewState, plaidAccountViewState, } = state;
32
+ const { accountListState, accountState, bankAccountState, billDetailViewState, paymentAccountListState, billTransactionState, billPayConfigState, classListState, classState, editBillDetailViewState, paymentAccountState, vendorState, tenantState, companyState, userState, commonHistoryState, contactState, paymentInstrumentState, recurringBillState, depositAccountListState, depositAccountState, plaidAccountViewState, } = state;
33
33
  const transaction = recordGet(billTransactionState.transactionById, billId ?? '', undefined);
34
34
  let recommendations = {};
35
35
  if (billId != null) {
@@ -177,7 +177,6 @@ export const getEditBillDetail = (state, isVendorRecommendationFeatureEnabled, i
177
177
  const fetchStateList = [
178
178
  sourceBillDetail.fetchStatus,
179
179
  accountListState.byReportId.billPayAccountList,
180
- billPaySetupApproverViewState,
181
180
  ];
182
181
  if (getIsAccountingClassesEnabled(state)) {
183
182
  fetchStateList.push(classListState);
@@ -198,7 +197,6 @@ export const getEditBillDetail = (state, isVendorRecommendationFeatureEnabled, i
198
197
  else {
199
198
  const newBillFetchStateList = [
200
199
  accountListState.byReportId.billPayAccountList,
201
- billPaySetupApproverViewState,
202
200
  ];
203
201
  if (getIsAccountingClassesEnabled(state)) {
204
202
  newBillFetchStateList.push(classListState);
@@ -8,7 +8,6 @@ import { fetchVendorTypeList } from '../../../../vendorTypeList/vendorTypeListRe
8
8
  import { fetchDepositAccountList } from '../../../zeniAccounts/depositAccountList/depositAccountListReducer';
9
9
  import { fetchPaymentAccountList } from '../../../zeniAccounts/paymentAccountList/paymentAccountListReducer';
10
10
  import { fetchBillPayConfig } from '../../billPayConfig/billPayConfigReducer';
11
- import { fetchBillPaySetupApproverView } from '../../billPaySetupApproverView/billPaySetupApproverViewReducer';
12
11
  import { fetchBillAndInitializeLocalStore, fetchEditBillDetailPage, updateShowAutofill, } from '../editBillViewReducer';
13
12
  export const fetchEditBillDetailPageEpic = (actions$, state$) => actions$.pipe(filter(fetchEditBillDetailPage.match), mergeMap((action) => {
14
13
  const { cacheOverride, billId, isShowDeletedBillsEnabled, hasZeniAssistAccess, isInternationalWireEnabled, } = action.payload;
@@ -38,10 +37,6 @@ export const fetchEditBillDetailPageEpic = (actions$, state$) => actions$.pipe(f
38
37
  else {
39
38
  billDetailActions.push(updateShowAutofill(true));
40
39
  }
41
- // Side-fetch from the edit-bill page bootstrap. The triggering
42
- // action doesn't carry the V3 flag, so we explicitly target v1
43
- // here; tenants on v3 re-fetch through their own screen connector.
44
- billDetailActions.push(fetchBillPaySetupApproverView(true, true, false));
45
40
  }
46
41
  else {
47
42
  if (state.ownerListState.fetchState !== 'In-Progress' &&
@@ -80,15 +75,6 @@ export const fetchEditBillDetailPageEpic = (actions$, state$) => actions$.pipe(f
80
75
  if (billId != null) {
81
76
  billDetailActions.push(fetchBillAndInitializeLocalStore(billId, false, isShowDeletedBillsEnabled, hasZeniAssistAccess));
82
77
  }
83
- const approvalViewFetchState = state.billPaySetupApproverViewState.fetchState;
84
- // While opening New Bill Refresh Approval Rules and Payment Accounts
85
- if (approvalViewFetchState !== 'In-Progress' &&
86
- approvalViewFetchState !== 'Completed') {
87
- // Side-fetch from the edit-bill page bootstrap. The triggering
88
- // action doesn't carry the V3 flag, so we explicitly target v1
89
- // here; tenants on v3 re-fetch through their own screen connector.
90
- billDetailActions.push(fetchBillPaySetupApproverView(true, true, false));
91
- }
92
78
  }
93
79
  return concat(from(billDetailActions));
94
80
  }));
@@ -5,6 +5,20 @@ import { endDate, isHoliday, startDate, } from '../../commonStateTypes/workingDa
5
5
  import { VERIFIED_PAYMENT_ACCOUNT_PROVIDER_VERIFICATION_STATUS } from '../../entity/paymentAccount/paymentAccountState';
6
6
  import { hasBillPayAccess, hasBillPayAdminLevelAccess, hasReimbursementAccess, hasReimbursementAdminLevelAccess, } from '../../entity/userRole/userRoleType';
7
7
  import { date as zeniDate } from '../../zeniDayJS';
8
+ const getUserActorId = (activity) => activity.actor?.userId ?? activity.userId;
9
+ export const isUserActorOnApprovalStep = (userId, stepActorsActivity) => stepActorsActivity.some((activity) => getUserActorId(activity) === userId);
10
+ export const isSodExcludedViewerBlocked = (sodExcludedApproverUserId, signedInUserId, stepActorsActivity = []) => sodExcludedApproverUserId != null &&
11
+ signedInUserId != null &&
12
+ signedInUserId === sodExcludedApproverUserId &&
13
+ isUserActorOnApprovalStep(sodExcludedApproverUserId, stepActorsActivity);
14
+ export const isSodAdminFallbackEligibleForStep = (sodExcludedApproverUserId, isAdminFallbackApprover, stepActorsActivity = []) => {
15
+ if (sodExcludedApproverUserId == null || !isAdminFallbackApprover) {
16
+ return false;
17
+ }
18
+ const pendingResolvedApprovers = stepActorsActivity.filter((activity) => activity.activity === 'pending' && getUserActorId(activity) != null);
19
+ return (pendingResolvedApprovers.length > 0 &&
20
+ pendingResolvedApprovers.every((activity) => getUserActorId(activity) === sodExcludedApproverUserId));
21
+ };
8
22
  export const getLatestApprovalDate = (allActivities) => {
9
23
  let allStepsWithStatus = [];
10
24
  let allApprovedActions = [];
@@ -7,7 +7,7 @@ import { getEntityApprovalStatusByIds } from '../../../../entity/entityApprovalS
7
7
  import { getUserByUserId } from '../../../../entity/user/userSelector';
8
8
  import { getUserRoleByUserId } from '../../../../entity/userRole/userRoleSelector';
9
9
  import { getActivityHistory, } from '../../commonHistoryView/commonHistorySelector';
10
- import { getLatestApprovalDate } from '../../helpers';
10
+ import { getLatestApprovalDate, isSodAdminFallbackEligibleForStep, isSodExcludedViewerBlocked, } from '../../helpers';
11
11
  import { getActivityRealTimeApproval, } from '../../realTimeApprovalView/realTimeApprovalSelector';
12
12
  import { getReimbursementConfigByKey } from '../reimbursementConfig/reimbursementConfigSelector';
13
13
  import { REIMBURSEMENT_PAYMENT_NUMBER_OF_DAYS } from '../reimbursementConfig/reimbursementConfigState';
@@ -144,7 +144,7 @@ export const getRemiActivities = (state, reimbursementId, billStageCode) => {
144
144
  const approvalRules = getApprovalRulesByIds(approvalRuleState, remiTransactionDetails.approvalRuleIds);
145
145
  const entityApprovalStatusByIds = getEntityApprovalStatusByIds(entityApprovalStatusState, remiTransactionDetails.entityApprovalIds);
146
146
  remiActivities = entityApprovalStatusByIds.map((entityApprovalStatus) => {
147
- const { approvalRuleId, entityType, createTime, updateTime, stepsApprovalStatus, areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, isRealTimeApprovalEnabled, } = entityApprovalStatus;
147
+ const { approvalRuleId, entityType, createTime, updateTime, stepsApprovalStatus, areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, isRealTimeApprovalEnabled, sodExcludedApproverUserId, } = entityApprovalStatus;
148
148
  const approvalRule = approvalRules.find((rule) => rule.approvalRuleId === approvalRuleId);
149
149
  return {
150
150
  approvalRuleId,
@@ -156,21 +156,22 @@ export const getRemiActivities = (state, reimbursementId, billStageCode) => {
156
156
  isAdminFallbackApprover,
157
157
  currentPendingStepIndex,
158
158
  isRealTimeApprovalEnabled,
159
+ sodExcludedApproverUserId,
159
160
  entityApprovalId: entityApprovalStatus.entityApprovalId,
160
161
  stepsWithStatus: stepsApprovalStatus.map((step) => {
162
+ const actorsActivity = step.actorsActivity.map((activity) => ({
163
+ ...activity,
164
+ actor: getUserByUserId(userState, activity.userId),
165
+ }));
161
166
  return {
162
167
  ...step,
163
168
  actors: step.actors
164
169
  .map((actor) => getUserByUserId(userState, actor.userId))
165
170
  .filter((user) => user != null),
166
171
  nonUserActors: step.actors.filter((actor) => actor.userId == null && actor.type !== 'user'),
167
- actorsActivity: step.actorsActivity.map((activity) => {
168
- return {
169
- ...activity,
170
- actor: getUserByUserId(userState, activity.userId),
171
- };
172
- }),
172
+ actorsActivity,
173
173
  isOriginalApprovalStep: step.isOriginalApprovalStep,
174
+ displayPendingApproverAsAdmin: isSodAdminFallbackEligibleForStep(sodExcludedApproverUserId, isAdminFallbackApprover, actorsActivity),
174
175
  };
175
176
  }),
176
177
  };
@@ -183,7 +184,7 @@ export const checkApproveRejectBtnShow = (remiActivities, isUserAdmin, signedInU
183
184
  let isApprovalorRejectBtnVisible = false;
184
185
  let rejectedId = -1;
185
186
  const stepsWithStatusData = remiActivities[0].stepsWithStatus;
186
- const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, } = remiActivities[0];
187
+ const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, sodExcludedApproverUserId, } = remiActivities[0];
187
188
  for (const [index, stepWithStatus] of stepsWithStatusData.entries()) {
188
189
  if (stepWithStatus.action === 'require_approval') {
189
190
  for (const actorActivity of stepWithStatus.actorsActivity) {
@@ -219,27 +220,39 @@ export const checkApproveRejectBtnShow = (remiActivities, isUserAdmin, signedInU
219
220
  break;
220
221
  }
221
222
  }
223
+ const sodBlocked = isSodExcludedViewerBlocked(sodExcludedApproverUserId, signedInUser?.userId, pendingStep.actorsActivity);
222
224
  for (const actorActivity of pendingStep.actorsActivity) {
223
- if (actorActivity.actor?.userId === signedInUser?.userId &&
225
+ if (!sodBlocked &&
226
+ actorActivity.actor?.userId === signedInUser?.userId &&
224
227
  isAllActivitiesPending) {
225
228
  isApprovalorRejectBtnVisible = true;
226
229
  }
227
230
  else if (actorActivity.subType === 'admin' &&
228
231
  isUserAdmin &&
229
- isAllActivitiesPending) {
232
+ isAllActivitiesPending &&
233
+ signedInUser?.userId != null &&
234
+ signedInUser.userId !== sodExcludedApproverUserId) {
230
235
  isApprovalorRejectBtnVisible = true;
231
236
  }
232
- // admin will be fallback approver if vendor-owner/manager are not assigned any user id
233
237
  else if (actorActivity.type === 'attribute' &&
234
238
  (actorActivity.subType === 'manager' ||
235
239
  actorActivity.subType === 'vendor_owner' ||
236
240
  actorActivity.subType === 'manager_of_manager') &&
237
241
  actorActivity.userId === null &&
238
- isAdminFallbackApprover === true &&
239
- isUserAdmin === true) {
242
+ isAdminFallbackApprover &&
243
+ isUserAdmin &&
244
+ signedInUser?.userId != null &&
245
+ signedInUser.userId !== sodExcludedApproverUserId) {
240
246
  isApprovalorRejectBtnVisible = true;
241
247
  }
242
248
  }
249
+ if (!isApprovalorRejectBtnVisible &&
250
+ isUserAdmin &&
251
+ signedInUser?.userId != null &&
252
+ signedInUser.userId !== sodExcludedApproverUserId &&
253
+ pendingStep.displayPendingApproverAsAdmin) {
254
+ isApprovalorRejectBtnVisible = true;
255
+ }
243
256
  }
244
257
  }
245
258
  }
@@ -253,27 +266,39 @@ export const checkApproveRejectBtnShow = (remiActivities, isUserAdmin, signedInU
253
266
  break;
254
267
  }
255
268
  }
269
+ const sodBlocked = isSodExcludedViewerBlocked(sodExcludedApproverUserId, signedInUser?.userId, stepWithStatus.actorsActivity);
256
270
  for (const actorActivity of stepWithStatus.actorsActivity) {
257
- if (actorActivity.actor?.userId === signedInUser?.userId &&
271
+ if (!sodBlocked &&
272
+ actorActivity.actor?.userId === signedInUser?.userId &&
258
273
  isAllActivitiesPending) {
259
274
  isApprovalorRejectBtnVisible = true;
260
275
  }
261
276
  else if (actorActivity.subType === 'admin' &&
262
277
  isUserAdmin &&
263
- isAllActivitiesPending) {
278
+ isAllActivitiesPending &&
279
+ signedInUser?.userId != null &&
280
+ signedInUser.userId !== sodExcludedApproverUserId) {
264
281
  isApprovalorRejectBtnVisible = true;
265
282
  }
266
- // admin will be fallback approver if vendor-owner/manager are not assigned any user id
267
283
  else if (actorActivity.type === 'attribute' &&
268
284
  (actorActivity.subType === 'manager' ||
269
285
  actorActivity.subType === 'vendor_owner' ||
270
286
  actorActivity.subType === 'manager_of_manager') &&
271
287
  actorActivity.userId === null &&
272
- isAdminFallbackApprover === true &&
273
- isUserAdmin === true) {
288
+ isAdminFallbackApprover &&
289
+ isUserAdmin &&
290
+ signedInUser?.userId != null &&
291
+ signedInUser.userId !== sodExcludedApproverUserId) {
274
292
  isApprovalorRejectBtnVisible = true;
275
293
  }
276
294
  }
295
+ if (!isApprovalorRejectBtnVisible &&
296
+ isUserAdmin &&
297
+ signedInUser?.userId != null &&
298
+ signedInUser.userId !== sodExcludedApproverUserId &&
299
+ stepWithStatus.displayPendingApproverAsAdmin) {
300
+ isApprovalorRejectBtnVisible = true;
301
+ }
277
302
  }
278
303
  if (isApprovalorRejectBtnVisible) {
279
304
  break;
@@ -7,7 +7,7 @@ import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
7
7
  import { getUserByUserId, getUsersByUserIds, } from '../../../../entity/user/userSelector';
8
8
  import { hasAdminLevelAccess, hasReimbursementUserAccess, } from '../../../../entity/userRole/userRoleType';
9
9
  import { dateNow } from '../../../../zeniDayJS';
10
- import { isBulkProcessing } from '../../helpers';
10
+ import { isBulkProcessing, isSodAdminFallbackEligibleForStep } from '../../helpers';
11
11
  import { getReimbursementConfigBotEmail } from '../../reimbursement/reimbursementConfig/reimbursementConfigSelector';
12
12
  import { applyAdvancedFiltersOnList, isRemiListDownloadable, } from '../../spendManagementFilterHelpers';
13
13
  import { ALL_REMI_TABS, getRemiListKey, } from './remiListState';
@@ -209,7 +209,7 @@ export const getApproversOrRejectors = (reimbursement, entityApprovalStatusState
209
209
  };
210
210
  if (reimbursement.entityApprovalId !== null) {
211
211
  const entityApprovalStatus = entityApprovalStatusState.entityApprovalStatusById[reimbursement.entityApprovalId];
212
- const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, } = entityApprovalStatus;
212
+ const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, sodExcludedApproverUserId, } = entityApprovalStatus;
213
213
  const isReimbursementSerailized = areApprovalsSerialized === true &&
214
214
  currentPendingStepIndex != null &&
215
215
  currentPendingStepIndex > -1;
@@ -237,23 +237,20 @@ export const getApproversOrRejectors = (reimbursement, entityApprovalStatusState
237
237
  if (isReimbursementSerailized) {
238
238
  requireApprovalInfo = [stepsApprovalStatus[currentPendingStepIndex]];
239
239
  }
240
- const pendingActivitiesList = [];
241
240
  requireApprovalInfo.forEach((approvalStep) => {
242
- const pendingActivities = approvalStep.actorsActivity.filter((activity) => activity.activity === 'pending');
243
- //if isReimbursementSerailized, we need to show all the approvers in currentPendingStepIndex
244
- if (isReimbursementSerailized) {
245
- pendingActivitiesList.push(...pendingActivities);
241
+ if (approvers.displayPendingApproverAsAdmin) {
242
+ return;
246
243
  }
247
- else {
248
- //if not isReimbursementSerailized, we need to show all the first approvers in each steps_approval_status
249
- const pendingActivity = pendingActivities[0];
250
- if (pendingActivity != null) {
251
- pendingActivitiesList.push(pendingActivity);
252
- }
244
+ const pendingActivities = approvalStep.actorsActivity.filter((activity) => activity.activity === 'pending');
245
+ const sodDisplayAsAdmin = isSodAdminFallbackEligibleForStep(sodExcludedApproverUserId, isAdminFallbackApprover, approvalStep.actorsActivity);
246
+ const activitiesToShow = isReimbursementSerailized
247
+ ? pendingActivities
248
+ : pendingActivities.slice(0, 1);
249
+ if (sodDisplayAsAdmin) {
250
+ approvers.displayPendingApproverAsAdmin = true;
251
+ return;
253
252
  }
254
- });
255
- if (pendingActivitiesList.length > 0) {
256
- pendingActivitiesList.forEach((activity) => {
253
+ activitiesToShow.forEach((activity) => {
257
254
  const user = getUserByUserId(userState, activity.userId);
258
255
  if (user != null) {
259
256
  approvers.users.push(user);
@@ -265,7 +262,7 @@ export const getApproversOrRejectors = (reimbursement, entityApprovalStatusState
265
262
  }
266
263
  }
267
264
  });
268
- }
265
+ });
269
266
  }
270
267
  }
271
268
  }
@@ -54,6 +54,7 @@ export interface BillDetailViewSelector extends SelectorView {
54
54
  export interface StepWithStatus extends StepWithUser {
55
55
  actorsActivity: ActorActivityWithUser[];
56
56
  isOriginalApprovalStep: boolean;
57
+ displayPendingApproverAsAdmin?: boolean;
57
58
  }
58
59
  export interface ActorActivityWithUser {
59
60
  activity: ActivityStatus;
@@ -77,6 +78,7 @@ export interface BillActivity {
77
78
  currentPendingStepIndex?: number;
78
79
  entityApprovalId?: ID;
79
80
  isAdminFallbackApprover?: boolean;
81
+ sodExcludedApproverUserId?: ID;
80
82
  }
81
83
  export declare const getBillActivities: (state: RootState, billId: ID, billStageCode?: BillStageCodeType) => BillActivity[];
82
84
  export declare const getBillDetailView: (state: RootState, billId: ID) => BillDetailViewSelector;
@@ -63,7 +63,7 @@ const getBillActivities = (state, billId, billStageCode) => {
63
63
  const approvalRules = (0, approvalRuleSelector_1.getApprovalRulesByIds)(approvalRuleState, billDetail.approvalRuleIds);
64
64
  const entityApprovalStatusByIds = (0, entityApprovalStatusSelector_1.getEntityApprovalStatusByIds)(entityApprovalStatusState, billDetail.entityApprovalIds);
65
65
  billActivities = entityApprovalStatusByIds.map((entityApprovalStatus) => {
66
- const { approvalRuleId, entityType, createTime, updateTime, stepsApprovalStatus, areApprovalsSerialized, isAdminFallbackApprover, isRealTimeApprovalEnabled, currentPendingStepIndex, } = entityApprovalStatus;
66
+ const { approvalRuleId, entityType, createTime, updateTime, stepsApprovalStatus, areApprovalsSerialized, isAdminFallbackApprover, isRealTimeApprovalEnabled, currentPendingStepIndex, sodExcludedApproverUserId, } = entityApprovalStatus;
67
67
  const approvalRule = approvalRules.find((rule) => rule.approvalRuleId === approvalRuleId);
68
68
  return {
69
69
  approvalRuleId,
@@ -75,21 +75,22 @@ const getBillActivities = (state, billId, billStageCode) => {
75
75
  isAdminFallbackApprover,
76
76
  isRealTimeApprovalEnabled,
77
77
  currentPendingStepIndex,
78
+ sodExcludedApproverUserId,
78
79
  entityApprovalId: entityApprovalStatus.entityApprovalId,
79
80
  stepsWithStatus: stepsApprovalStatus.map((step) => {
81
+ const actorsActivity = step.actorsActivity.map((activity) => ({
82
+ ...activity,
83
+ actor: (0, userSelector_1.getUserByUserId)(userState, activity.userId),
84
+ }));
80
85
  return {
81
86
  ...step,
82
87
  actors: step.actors
83
88
  .map((actor) => (0, userSelector_1.getUserByUserId)(userState, actor.userId))
84
89
  .filter((user) => user != null),
85
90
  nonUserActors: step.actors.filter((actor) => actor.userId == null && actor.type !== 'user'),
86
- actorsActivity: step.actorsActivity.map((activity) => {
87
- return {
88
- ...activity,
89
- actor: (0, userSelector_1.getUserByUserId)(userState, activity.userId),
90
- };
91
- }),
91
+ actorsActivity,
92
92
  isOriginalApprovalStep: step.isOriginalApprovalStep,
93
+ displayPendingApproverAsAdmin: (0, helpers_1.isSodAdminFallbackEligibleForStep)(sodExcludedApproverUserId, isAdminFallbackApprover, actorsActivity),
93
94
  };
94
95
  }),
95
96
  };
@@ -256,7 +257,7 @@ const checkApproveRejectBtnShow = (billActivities, isUserAdmin, signedInUser) =>
256
257
  let isMarkAsPaidBtnVisible = false;
257
258
  let rejectedId = -1;
258
259
  const stepsWithStatusData = billActivities[0].stepsWithStatus;
259
- const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, } = billActivities[0];
260
+ const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, sodExcludedApproverUserId, } = billActivities[0];
260
261
  for (const [index, stepWithStatus] of stepsWithStatusData.entries()) {
261
262
  if (stepWithStatus.action === 'require_approval') {
262
263
  for (const actorActivity of stepWithStatus.actorsActivity) {
@@ -297,23 +298,42 @@ const checkApproveRejectBtnShow = (billActivities, isUserAdmin, signedInUser) =>
297
298
  break;
298
299
  }
299
300
  }
300
- for (const actorActivity of pendingStep.actorsActivity) {
301
- if (actorActivity.actor?.userId === signedInUser?.userId &&
302
- isAllActivitiesPending) {
303
- isApprovalorRejectBtnVisible = true;
304
- isMarkAsPaidBtnVisible = isLastApprovalStep;
301
+ const sodBlocked = (0, helpers_1.isSodExcludedViewerBlocked)(sodExcludedApproverUserId, signedInUser?.userId, pendingStep.actorsActivity);
302
+ if (isAllActivitiesPending) {
303
+ for (const actorActivity of pendingStep.actorsActivity) {
304
+ if (!sodBlocked &&
305
+ actorActivity.actor?.userId === signedInUser?.userId) {
306
+ isApprovalorRejectBtnVisible = true;
307
+ isMarkAsPaidBtnVisible = isLastApprovalStep;
308
+ break;
309
+ }
305
310
  }
306
- // admin will be fallback approver if vendor-owner/manager are not assigned any user id
307
- if (actorActivity.type === 'attribute' &&
308
- (actorActivity.subType === 'manager' ||
309
- actorActivity.subType === 'vendor_owner') &&
310
- actorActivity.userId === null &&
311
- isAdminFallbackApprover === true &&
312
- isUserAdmin === true) {
313
- isApprovalorRejectBtnVisible = true;
314
- isMarkAsPaidBtnVisible = isLastApprovalStep;
311
+ }
312
+ if (!isApprovalorRejectBtnVisible) {
313
+ for (const actorActivity of pendingStep.actorsActivity) {
314
+ // admin will be fallback approver if vendor-owner/manager are not assigned any user id
315
+ if (actorActivity.type === 'attribute' &&
316
+ (actorActivity.subType === 'manager' ||
317
+ actorActivity.subType === 'vendor_owner') &&
318
+ actorActivity.userId === null &&
319
+ isAdminFallbackApprover &&
320
+ isUserAdmin &&
321
+ signedInUser?.userId != null &&
322
+ signedInUser.userId !== sodExcludedApproverUserId) {
323
+ isApprovalorRejectBtnVisible = true;
324
+ isMarkAsPaidBtnVisible = isLastApprovalStep;
325
+ break;
326
+ }
315
327
  }
316
328
  }
329
+ if (!isApprovalorRejectBtnVisible &&
330
+ isUserAdmin &&
331
+ signedInUser?.userId != null &&
332
+ signedInUser.userId !== sodExcludedApproverUserId &&
333
+ pendingStep.displayPendingApproverAsAdmin) {
334
+ isApprovalorRejectBtnVisible = true;
335
+ isMarkAsPaidBtnVisible = isLastApprovalStep;
336
+ }
317
337
  }
318
338
  }
319
339
  }
@@ -327,23 +347,42 @@ const checkApproveRejectBtnShow = (billActivities, isUserAdmin, signedInUser) =>
327
347
  break;
328
348
  }
329
349
  }
330
- for (const actorActivity of stepWithStatus.actorsActivity) {
331
- if (actorActivity.actor?.userId === signedInUser?.userId &&
332
- isAllActivitiesPending) {
333
- isApprovalorRejectBtnVisible = true;
334
- isMarkAsPaidBtnVisible = true;
350
+ const sodBlocked = (0, helpers_1.isSodExcludedViewerBlocked)(sodExcludedApproverUserId, signedInUser?.userId, stepWithStatus.actorsActivity);
351
+ if (isAllActivitiesPending) {
352
+ for (const actorActivity of stepWithStatus.actorsActivity) {
353
+ if (!sodBlocked &&
354
+ actorActivity.actor?.userId === signedInUser?.userId) {
355
+ isApprovalorRejectBtnVisible = true;
356
+ isMarkAsPaidBtnVisible = true;
357
+ break;
358
+ }
335
359
  }
336
- // admin will be fallback approver if vendor-owner/manager are not assigned any user id
337
- else if (actorActivity.type === 'attribute' &&
338
- (actorActivity.subType === 'manager' ||
339
- actorActivity.subType === 'vendor_owner') &&
340
- actorActivity.userId === null &&
341
- isAdminFallbackApprover === true &&
342
- isUserAdmin === true) {
343
- isApprovalorRejectBtnVisible = true;
344
- isMarkAsPaidBtnVisible = true;
360
+ }
361
+ if (!isApprovalorRejectBtnVisible) {
362
+ for (const actorActivity of stepWithStatus.actorsActivity) {
363
+ // admin will be fallback approver if vendor-owner/manager are not assigned any user id
364
+ if (actorActivity.type === 'attribute' &&
365
+ (actorActivity.subType === 'manager' ||
366
+ actorActivity.subType === 'vendor_owner') &&
367
+ actorActivity.userId === null &&
368
+ isAdminFallbackApprover &&
369
+ isUserAdmin &&
370
+ signedInUser?.userId != null &&
371
+ signedInUser.userId !== sodExcludedApproverUserId) {
372
+ isApprovalorRejectBtnVisible = true;
373
+ isMarkAsPaidBtnVisible = true;
374
+ break;
375
+ }
345
376
  }
346
377
  }
378
+ if (!isApprovalorRejectBtnVisible &&
379
+ isUserAdmin &&
380
+ signedInUser?.userId != null &&
381
+ signedInUser.userId !== sodExcludedApproverUserId &&
382
+ stepWithStatus.displayPendingApproverAsAdmin) {
383
+ isApprovalorRejectBtnVisible = true;
384
+ isMarkAsPaidBtnVisible = true;
385
+ }
347
386
  }
348
387
  if (isApprovalorRejectBtnVisible) {
349
388
  break;
@@ -297,7 +297,7 @@ const getApproversOrRejectors = (billTransaction, entityApprovalStatusState, use
297
297
  };
298
298
  if (billTransaction.entityApprovalId !== null) {
299
299
  const entityApprovalStatus = entityApprovalStatusState.entityApprovalStatusById[billTransaction.entityApprovalId];
300
- const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, } = entityApprovalStatus;
300
+ const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, sodExcludedApproverUserId, } = entityApprovalStatus;
301
301
  const isBillSerailized = areApprovalsSerialized === true &&
302
302
  currentPendingStepIndex != null &&
303
303
  currentPendingStepIndex > -1;
@@ -325,23 +325,20 @@ const getApproversOrRejectors = (billTransaction, entityApprovalStatusState, use
325
325
  if (isBillSerailized) {
326
326
  requireApprovalInfo = [stepsApprovalStatus[currentPendingStepIndex]];
327
327
  }
328
- const pendingActivitiesList = [];
329
328
  requireApprovalInfo.forEach((approvalStep) => {
330
- const pendingActivities = approvalStep.actorsActivity.filter((activity) => activity.activity === 'pending');
331
- //if isBillSerailized, we need to show all the approvers in currentPendingStepIndex
332
- if (isBillSerailized) {
333
- pendingActivitiesList.push(...pendingActivities);
329
+ if (approvers.displayPendingApproverAsAdmin) {
330
+ return;
334
331
  }
335
- else {
336
- //if not isBillSerailized, we need to show all the first approvers in each steps_approval_status
337
- const pendingActivity = pendingActivities[0];
338
- if (pendingActivity != null) {
339
- pendingActivitiesList.push(pendingActivity);
340
- }
332
+ const pendingActivities = approvalStep.actorsActivity.filter((activity) => activity.activity === 'pending');
333
+ const sodDisplayAsAdmin = (0, helpers_1.isSodAdminFallbackEligibleForStep)(sodExcludedApproverUserId, isAdminFallbackApprover, approvalStep.actorsActivity);
334
+ const activitiesToShow = isBillSerailized
335
+ ? pendingActivities
336
+ : pendingActivities.slice(0, 1);
337
+ if (sodDisplayAsAdmin) {
338
+ approvers.displayPendingApproverAsAdmin = true;
339
+ return;
341
340
  }
342
- });
343
- if (pendingActivitiesList.length > 0) {
344
- pendingActivitiesList.forEach((activity) => {
341
+ activitiesToShow.forEach((activity) => {
345
342
  const user = (0, userSelector_1.getUserByUserId)(userState, activity.userId);
346
343
  if (user != null) {
347
344
  approvers.users.push(user);
@@ -353,7 +350,7 @@ const getApproversOrRejectors = (billTransaction, entityApprovalStatusState, use
353
350
  }
354
351
  }
355
352
  });
356
- }
353
+ });
357
354
  }
358
355
  }
359
356
  }
@@ -38,7 +38,7 @@ const billPayReviewSelector_1 = require("../billPayReview/billPayReviewSelector"
38
38
  const billPaySetupApproverViewSelector_1 = require("../billPaySetupApproverView/billPaySetupApproverViewSelector");
39
39
  const previousBillsSelector_1 = require("../previousBills/previousBillsSelector");
40
40
  const getEditBillDetail = (state, isVendorRecommendationFeatureEnabled, isZeniAccountsEnabled, billId) => {
41
- const { accountListState, accountState, bankAccountState, billDetailViewState, paymentAccountListState, billTransactionState, billPayConfigState, classListState, classState, editBillDetailViewState, paymentAccountState, vendorState, tenantState, companyState, userState, commonHistoryState, contactState, paymentInstrumentState, recurringBillState, depositAccountListState, depositAccountState, billPaySetupApproverViewState, plaidAccountViewState, } = state;
41
+ const { accountListState, accountState, bankAccountState, billDetailViewState, paymentAccountListState, billTransactionState, billPayConfigState, classListState, classState, editBillDetailViewState, paymentAccountState, vendorState, tenantState, companyState, userState, commonHistoryState, contactState, paymentInstrumentState, recurringBillState, depositAccountListState, depositAccountState, plaidAccountViewState, } = state;
42
42
  const transaction = (0, get_1.default)(billTransactionState.transactionById, billId ?? '', undefined);
43
43
  let recommendations = {};
44
44
  if (billId != null) {
@@ -186,7 +186,6 @@ const getEditBillDetail = (state, isVendorRecommendationFeatureEnabled, isZeniAc
186
186
  const fetchStateList = [
187
187
  sourceBillDetail.fetchStatus,
188
188
  accountListState.byReportId.billPayAccountList,
189
- billPaySetupApproverViewState,
190
189
  ];
191
190
  if ((0, tenantSelector_1.getIsAccountingClassesEnabled)(state)) {
192
191
  fetchStateList.push(classListState);
@@ -207,7 +206,6 @@ const getEditBillDetail = (state, isVendorRecommendationFeatureEnabled, isZeniAc
207
206
  else {
208
207
  const newBillFetchStateList = [
209
208
  accountListState.byReportId.billPayAccountList,
210
- billPaySetupApproverViewState,
211
209
  ];
212
210
  if ((0, tenantSelector_1.getIsAccountingClassesEnabled)(state)) {
213
211
  newBillFetchStateList.push(classListState);
@@ -8,7 +8,6 @@ import { fetchVendorTypeList } from '../../../../vendorTypeList/vendorTypeListRe
8
8
  import { fetchDepositAccountList } from '../../../zeniAccounts/depositAccountList/depositAccountListReducer';
9
9
  import { fetchPaymentAccountList } from '../../../zeniAccounts/paymentAccountList/paymentAccountListReducer';
10
10
  import { fetchBillPayConfig } from '../../billPayConfig/billPayConfigReducer';
11
- import { fetchBillPaySetupApproverView } from '../../billPaySetupApproverView/billPaySetupApproverViewReducer';
12
11
  import { fetchBillAndInitializeLocalStore, fetchEditBillDetailPage, updateShowAutofill } from '../editBillViewReducer';
13
- export type ActionType = ReturnType<typeof fetchEditBillDetailPage> | ReturnType<typeof fetchClassList> | ReturnType<typeof fetchVendorTypeList> | ReturnType<typeof fetchAccountList> | ReturnType<typeof fetchPaymentAccountList> | ReturnType<typeof fetchDepositAccountList> | ReturnType<typeof fetchBillPayConfig> | ReturnType<typeof updateShowAutofill> | ReturnType<typeof fetchBillPaySetupApproverView> | ReturnType<typeof fetchOwnerList> | ReturnType<typeof fetchBillAndInitializeLocalStore>;
12
+ export type ActionType = ReturnType<typeof fetchEditBillDetailPage> | ReturnType<typeof fetchClassList> | ReturnType<typeof fetchVendorTypeList> | ReturnType<typeof fetchAccountList> | ReturnType<typeof fetchPaymentAccountList> | ReturnType<typeof fetchDepositAccountList> | ReturnType<typeof fetchBillPayConfig> | ReturnType<typeof updateShowAutofill> | ReturnType<typeof fetchOwnerList> | ReturnType<typeof fetchBillAndInitializeLocalStore>;
14
13
  export declare const fetchEditBillDetailPageEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>) => Observable<ActionType>;
@@ -11,7 +11,6 @@ const vendorTypeListReducer_1 = require("../../../../vendorTypeList/vendorTypeLi
11
11
  const depositAccountListReducer_1 = require("../../../zeniAccounts/depositAccountList/depositAccountListReducer");
12
12
  const paymentAccountListReducer_1 = require("../../../zeniAccounts/paymentAccountList/paymentAccountListReducer");
13
13
  const billPayConfigReducer_1 = require("../../billPayConfig/billPayConfigReducer");
14
- const billPaySetupApproverViewReducer_1 = require("../../billPaySetupApproverView/billPaySetupApproverViewReducer");
15
14
  const editBillViewReducer_1 = require("../editBillViewReducer");
16
15
  const fetchEditBillDetailPageEpic = (actions$, state$) => actions$.pipe((0, operators_1.filter)(editBillViewReducer_1.fetchEditBillDetailPage.match), (0, operators_1.mergeMap)((action) => {
17
16
  const { cacheOverride, billId, isShowDeletedBillsEnabled, hasZeniAssistAccess, isInternationalWireEnabled, } = action.payload;
@@ -41,10 +40,6 @@ const fetchEditBillDetailPageEpic = (actions$, state$) => actions$.pipe((0, oper
41
40
  else {
42
41
  billDetailActions.push((0, editBillViewReducer_1.updateShowAutofill)(true));
43
42
  }
44
- // Side-fetch from the edit-bill page bootstrap. The triggering
45
- // action doesn't carry the V3 flag, so we explicitly target v1
46
- // here; tenants on v3 re-fetch through their own screen connector.
47
- billDetailActions.push((0, billPaySetupApproverViewReducer_1.fetchBillPaySetupApproverView)(true, true, false));
48
43
  }
49
44
  else {
50
45
  if (state.ownerListState.fetchState !== 'In-Progress' &&
@@ -83,15 +78,6 @@ const fetchEditBillDetailPageEpic = (actions$, state$) => actions$.pipe((0, oper
83
78
  if (billId != null) {
84
79
  billDetailActions.push((0, editBillViewReducer_1.fetchBillAndInitializeLocalStore)(billId, false, isShowDeletedBillsEnabled, hasZeniAssistAccess));
85
80
  }
86
- const approvalViewFetchState = state.billPaySetupApproverViewState.fetchState;
87
- // While opening New Bill Refresh Approval Rules and Payment Accounts
88
- if (approvalViewFetchState !== 'In-Progress' &&
89
- approvalViewFetchState !== 'Completed') {
90
- // Side-fetch from the edit-bill page bootstrap. The triggering
91
- // action doesn't carry the V3 flag, so we explicitly target v1
92
- // here; tenants on v3 re-fetch through their own screen connector.
93
- billDetailActions.push((0, billPaySetupApproverViewReducer_1.fetchBillPaySetupApproverView)(true, true, false));
94
- }
95
81
  }
96
82
  return (0, rxjs_1.concat)((0, rxjs_1.from)(billDetailActions));
97
83
  }));
@@ -1,4 +1,5 @@
1
1
  import { Amount } from '../../commonStateTypes/amount';
2
+ import { ID } from '../../commonStateTypes/common';
2
3
  import { ReportIDPlusForecastID } from '../../commonStateTypes/viewAndReport/viewAndReport';
3
4
  import { BillPayInfo, BulkProcessingStateType } from '../../entity/billPay/billTransaction/billTransactionState';
4
5
  import { RecurringBillConfig } from '../../entity/billPay/recurringBills/recurringBillsState';
@@ -6,13 +7,16 @@ import { ReimbursementTypeCode } from '../../entity/reimbursement/reimbursementS
6
7
  import { CurrentTenant } from '../../entity/tenant/tenantSelector';
7
8
  import { RoleMap } from '../../entity/userRole/userRoleType';
8
9
  import { ZeniDate } from '../../zeniDayJS';
9
- import { BillActivity } from './billPay/billDetailView/billDetailViewSelector';
10
+ import { ActorActivityWithUser, BillActivity } from './billPay/billDetailView/billDetailViewSelector';
10
11
  import { BillTransactionView } from './billPay/billList/billListSelector';
11
12
  import { AccType, AccountTypeSubConfigCodeKeyType } from './billPay/billPayConfig/billPayConfigState';
12
13
  import { RecurringBillConfigLocalData, RecurringBillInstance } from './billPay/editBillView/editBillViewState';
13
14
  import { BusinessVerificationDetails, CompanyOfficersDetails } from './commonSetup/setupViewSelector';
14
15
  import { SetupViewType } from './commonSetup/setupViewState';
15
16
  import { RemiActivity } from './reimbursement/remiDetailView/remiDetailViewSelector';
17
+ export declare const isUserActorOnApprovalStep: (userId: ID, stepActorsActivity: ActorActivityWithUser[]) => boolean;
18
+ export declare const isSodExcludedViewerBlocked: (sodExcludedApproverUserId?: ID, signedInUserId?: ID, stepActorsActivity?: ActorActivityWithUser[]) => boolean;
19
+ export declare const isSodAdminFallbackEligibleForStep: (sodExcludedApproverUserId?: ID, isAdminFallbackApprover?: boolean, stepActorsActivity?: ActorActivityWithUser[]) => boolean;
16
20
  export declare const getLatestApprovalDate: (allActivities: BillActivity[] | RemiActivity[]) => ZeniDate | undefined;
17
21
  export declare function getSpendManagementEffectiveListPeriod(): import("../..").TimePeriod;
18
22
  export declare const getSelectedCompanyOfficer: (verificationDetails: BusinessVerificationDetails) => CompanyOfficersDetails | undefined;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.toSameDayAchDisablementConfig = exports.checkIfLowBalance = exports.getReportIDPlusForecastIDFromSetupViewType = exports.isAwaitingMarkAsPaid = exports.isPaymentMethodOutsideZeni = exports.toAccountsPromoConfig = exports.getBulkOperationSuffix = exports.getRemiListUniqueType = exports.getBillListUniqueType = exports.isBulkProcessing = exports.getActualPaymentDate = exports.accountTypeSubConfigCodeToAccType = exports.isRecurringConfigChanged = exports.updateRecurringBillDetails = exports.getPaymentDateFromVendorReceiveDate = exports.getSelectedCompanyOfficer = exports.getLatestApprovalDate = void 0;
6
+ exports.toSameDayAchDisablementConfig = exports.checkIfLowBalance = exports.getReportIDPlusForecastIDFromSetupViewType = exports.isAwaitingMarkAsPaid = exports.isPaymentMethodOutsideZeni = exports.toAccountsPromoConfig = exports.getBulkOperationSuffix = exports.getRemiListUniqueType = exports.getBillListUniqueType = exports.isBulkProcessing = exports.getActualPaymentDate = exports.accountTypeSubConfigCodeToAccType = exports.isRecurringConfigChanged = exports.updateRecurringBillDetails = exports.getPaymentDateFromVendorReceiveDate = exports.getSelectedCompanyOfficer = exports.getLatestApprovalDate = exports.isSodAdminFallbackEligibleForStep = exports.isSodExcludedViewerBlocked = exports.isUserActorOnApprovalStep = void 0;
7
7
  exports.getSpendManagementEffectiveListPeriod = getSpendManagementEffectiveListPeriod;
8
8
  exports.showReimbursementPromoPage = showReimbursementPromoPage;
9
9
  exports.showBillPayPromoPage = showBillPayPromoPage;
@@ -16,6 +16,23 @@ const workingDayHelper_1 = require("../../commonStateTypes/workingDayHelper");
16
16
  const paymentAccountState_1 = require("../../entity/paymentAccount/paymentAccountState");
17
17
  const userRoleType_1 = require("../../entity/userRole/userRoleType");
18
18
  const zeniDayJS_1 = require("../../zeniDayJS");
19
+ const getUserActorId = (activity) => activity.actor?.userId ?? activity.userId;
20
+ const isUserActorOnApprovalStep = (userId, stepActorsActivity) => stepActorsActivity.some((activity) => getUserActorId(activity) === userId);
21
+ exports.isUserActorOnApprovalStep = isUserActorOnApprovalStep;
22
+ const isSodExcludedViewerBlocked = (sodExcludedApproverUserId, signedInUserId, stepActorsActivity = []) => sodExcludedApproverUserId != null &&
23
+ signedInUserId != null &&
24
+ signedInUserId === sodExcludedApproverUserId &&
25
+ (0, exports.isUserActorOnApprovalStep)(sodExcludedApproverUserId, stepActorsActivity);
26
+ exports.isSodExcludedViewerBlocked = isSodExcludedViewerBlocked;
27
+ const isSodAdminFallbackEligibleForStep = (sodExcludedApproverUserId, isAdminFallbackApprover, stepActorsActivity = []) => {
28
+ if (sodExcludedApproverUserId == null || !isAdminFallbackApprover) {
29
+ return false;
30
+ }
31
+ const pendingResolvedApprovers = stepActorsActivity.filter((activity) => activity.activity === 'pending' && getUserActorId(activity) != null);
32
+ return (pendingResolvedApprovers.length > 0 &&
33
+ pendingResolvedApprovers.every((activity) => getUserActorId(activity) === sodExcludedApproverUserId));
34
+ };
35
+ exports.isSodAdminFallbackEligibleForStep = isSodAdminFallbackEligibleForStep;
19
36
  const getLatestApprovalDate = (allActivities) => {
20
37
  let allStepsWithStatus = [];
21
38
  let allApprovedActions = [];
@@ -43,6 +43,7 @@ export interface RemiDetails extends Reimbursement {
43
43
  export interface StepWithStatus extends StepWithUser {
44
44
  actorsActivity: ActorActivityWithUser[];
45
45
  isOriginalApprovalStep: boolean;
46
+ displayPendingApproverAsAdmin?: boolean;
46
47
  }
47
48
  export interface ActorActivityWithUser extends Actor {
48
49
  activity: ActivityStatus;
@@ -66,6 +67,7 @@ export interface RemiActivity {
66
67
  currentPendingStepIndex?: number;
67
68
  entityApprovalId?: ID;
68
69
  isAdminFallbackApprover?: boolean;
70
+ sodExcludedApproverUserId?: ID;
69
71
  }
70
72
  export declare const getRemiDetailView: (state: RootState, reimbursementId: ID) => RemiDetailViewSelector;
71
73
  export declare const getRemiActivities: (state: RootState, reimbursementId: ID, billStageCode?: BillStageCodeType) => RemiActivity[];
@@ -151,7 +151,7 @@ const getRemiActivities = (state, reimbursementId, billStageCode) => {
151
151
  const approvalRules = (0, approvalRuleSelector_1.getApprovalRulesByIds)(approvalRuleState, remiTransactionDetails.approvalRuleIds);
152
152
  const entityApprovalStatusByIds = (0, entityApprovalStatusSelector_1.getEntityApprovalStatusByIds)(entityApprovalStatusState, remiTransactionDetails.entityApprovalIds);
153
153
  remiActivities = entityApprovalStatusByIds.map((entityApprovalStatus) => {
154
- const { approvalRuleId, entityType, createTime, updateTime, stepsApprovalStatus, areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, isRealTimeApprovalEnabled, } = entityApprovalStatus;
154
+ const { approvalRuleId, entityType, createTime, updateTime, stepsApprovalStatus, areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, isRealTimeApprovalEnabled, sodExcludedApproverUserId, } = entityApprovalStatus;
155
155
  const approvalRule = approvalRules.find((rule) => rule.approvalRuleId === approvalRuleId);
156
156
  return {
157
157
  approvalRuleId,
@@ -163,21 +163,22 @@ const getRemiActivities = (state, reimbursementId, billStageCode) => {
163
163
  isAdminFallbackApprover,
164
164
  currentPendingStepIndex,
165
165
  isRealTimeApprovalEnabled,
166
+ sodExcludedApproverUserId,
166
167
  entityApprovalId: entityApprovalStatus.entityApprovalId,
167
168
  stepsWithStatus: stepsApprovalStatus.map((step) => {
169
+ const actorsActivity = step.actorsActivity.map((activity) => ({
170
+ ...activity,
171
+ actor: (0, userSelector_1.getUserByUserId)(userState, activity.userId),
172
+ }));
168
173
  return {
169
174
  ...step,
170
175
  actors: step.actors
171
176
  .map((actor) => (0, userSelector_1.getUserByUserId)(userState, actor.userId))
172
177
  .filter((user) => user != null),
173
178
  nonUserActors: step.actors.filter((actor) => actor.userId == null && actor.type !== 'user'),
174
- actorsActivity: step.actorsActivity.map((activity) => {
175
- return {
176
- ...activity,
177
- actor: (0, userSelector_1.getUserByUserId)(userState, activity.userId),
178
- };
179
- }),
179
+ actorsActivity,
180
180
  isOriginalApprovalStep: step.isOriginalApprovalStep,
181
+ displayPendingApproverAsAdmin: (0, helpers_1.isSodAdminFallbackEligibleForStep)(sodExcludedApproverUserId, isAdminFallbackApprover, actorsActivity),
181
182
  };
182
183
  }),
183
184
  };
@@ -191,7 +192,7 @@ const checkApproveRejectBtnShow = (remiActivities, isUserAdmin, signedInUser) =>
191
192
  let isApprovalorRejectBtnVisible = false;
192
193
  let rejectedId = -1;
193
194
  const stepsWithStatusData = remiActivities[0].stepsWithStatus;
194
- const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, } = remiActivities[0];
195
+ const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, sodExcludedApproverUserId, } = remiActivities[0];
195
196
  for (const [index, stepWithStatus] of stepsWithStatusData.entries()) {
196
197
  if (stepWithStatus.action === 'require_approval') {
197
198
  for (const actorActivity of stepWithStatus.actorsActivity) {
@@ -227,27 +228,39 @@ const checkApproveRejectBtnShow = (remiActivities, isUserAdmin, signedInUser) =>
227
228
  break;
228
229
  }
229
230
  }
231
+ const sodBlocked = (0, helpers_1.isSodExcludedViewerBlocked)(sodExcludedApproverUserId, signedInUser?.userId, pendingStep.actorsActivity);
230
232
  for (const actorActivity of pendingStep.actorsActivity) {
231
- if (actorActivity.actor?.userId === signedInUser?.userId &&
233
+ if (!sodBlocked &&
234
+ actorActivity.actor?.userId === signedInUser?.userId &&
232
235
  isAllActivitiesPending) {
233
236
  isApprovalorRejectBtnVisible = true;
234
237
  }
235
238
  else if (actorActivity.subType === 'admin' &&
236
239
  isUserAdmin &&
237
- isAllActivitiesPending) {
240
+ isAllActivitiesPending &&
241
+ signedInUser?.userId != null &&
242
+ signedInUser.userId !== sodExcludedApproverUserId) {
238
243
  isApprovalorRejectBtnVisible = true;
239
244
  }
240
- // admin will be fallback approver if vendor-owner/manager are not assigned any user id
241
245
  else if (actorActivity.type === 'attribute' &&
242
246
  (actorActivity.subType === 'manager' ||
243
247
  actorActivity.subType === 'vendor_owner' ||
244
248
  actorActivity.subType === 'manager_of_manager') &&
245
249
  actorActivity.userId === null &&
246
- isAdminFallbackApprover === true &&
247
- isUserAdmin === true) {
250
+ isAdminFallbackApprover &&
251
+ isUserAdmin &&
252
+ signedInUser?.userId != null &&
253
+ signedInUser.userId !== sodExcludedApproverUserId) {
248
254
  isApprovalorRejectBtnVisible = true;
249
255
  }
250
256
  }
257
+ if (!isApprovalorRejectBtnVisible &&
258
+ isUserAdmin &&
259
+ signedInUser?.userId != null &&
260
+ signedInUser.userId !== sodExcludedApproverUserId &&
261
+ pendingStep.displayPendingApproverAsAdmin) {
262
+ isApprovalorRejectBtnVisible = true;
263
+ }
251
264
  }
252
265
  }
253
266
  }
@@ -261,27 +274,39 @@ const checkApproveRejectBtnShow = (remiActivities, isUserAdmin, signedInUser) =>
261
274
  break;
262
275
  }
263
276
  }
277
+ const sodBlocked = (0, helpers_1.isSodExcludedViewerBlocked)(sodExcludedApproverUserId, signedInUser?.userId, stepWithStatus.actorsActivity);
264
278
  for (const actorActivity of stepWithStatus.actorsActivity) {
265
- if (actorActivity.actor?.userId === signedInUser?.userId &&
279
+ if (!sodBlocked &&
280
+ actorActivity.actor?.userId === signedInUser?.userId &&
266
281
  isAllActivitiesPending) {
267
282
  isApprovalorRejectBtnVisible = true;
268
283
  }
269
284
  else if (actorActivity.subType === 'admin' &&
270
285
  isUserAdmin &&
271
- isAllActivitiesPending) {
286
+ isAllActivitiesPending &&
287
+ signedInUser?.userId != null &&
288
+ signedInUser.userId !== sodExcludedApproverUserId) {
272
289
  isApprovalorRejectBtnVisible = true;
273
290
  }
274
- // admin will be fallback approver if vendor-owner/manager are not assigned any user id
275
291
  else if (actorActivity.type === 'attribute' &&
276
292
  (actorActivity.subType === 'manager' ||
277
293
  actorActivity.subType === 'vendor_owner' ||
278
294
  actorActivity.subType === 'manager_of_manager') &&
279
295
  actorActivity.userId === null &&
280
- isAdminFallbackApprover === true &&
281
- isUserAdmin === true) {
296
+ isAdminFallbackApprover &&
297
+ isUserAdmin &&
298
+ signedInUser?.userId != null &&
299
+ signedInUser.userId !== sodExcludedApproverUserId) {
282
300
  isApprovalorRejectBtnVisible = true;
283
301
  }
284
302
  }
303
+ if (!isApprovalorRejectBtnVisible &&
304
+ isUserAdmin &&
305
+ signedInUser?.userId != null &&
306
+ signedInUser.userId !== sodExcludedApproverUserId &&
307
+ stepWithStatus.displayPendingApproverAsAdmin) {
308
+ isApprovalorRejectBtnVisible = true;
309
+ }
285
310
  }
286
311
  if (isApprovalorRejectBtnVisible) {
287
312
  break;
@@ -216,7 +216,7 @@ const getApproversOrRejectors = (reimbursement, entityApprovalStatusState, userS
216
216
  };
217
217
  if (reimbursement.entityApprovalId !== null) {
218
218
  const entityApprovalStatus = entityApprovalStatusState.entityApprovalStatusById[reimbursement.entityApprovalId];
219
- const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, } = entityApprovalStatus;
219
+ const { areApprovalsSerialized, isAdminFallbackApprover, currentPendingStepIndex, sodExcludedApproverUserId, } = entityApprovalStatus;
220
220
  const isReimbursementSerailized = areApprovalsSerialized === true &&
221
221
  currentPendingStepIndex != null &&
222
222
  currentPendingStepIndex > -1;
@@ -244,23 +244,20 @@ const getApproversOrRejectors = (reimbursement, entityApprovalStatusState, userS
244
244
  if (isReimbursementSerailized) {
245
245
  requireApprovalInfo = [stepsApprovalStatus[currentPendingStepIndex]];
246
246
  }
247
- const pendingActivitiesList = [];
248
247
  requireApprovalInfo.forEach((approvalStep) => {
249
- const pendingActivities = approvalStep.actorsActivity.filter((activity) => activity.activity === 'pending');
250
- //if isReimbursementSerailized, we need to show all the approvers in currentPendingStepIndex
251
- if (isReimbursementSerailized) {
252
- pendingActivitiesList.push(...pendingActivities);
248
+ if (approvers.displayPendingApproverAsAdmin) {
249
+ return;
253
250
  }
254
- else {
255
- //if not isReimbursementSerailized, we need to show all the first approvers in each steps_approval_status
256
- const pendingActivity = pendingActivities[0];
257
- if (pendingActivity != null) {
258
- pendingActivitiesList.push(pendingActivity);
259
- }
251
+ const pendingActivities = approvalStep.actorsActivity.filter((activity) => activity.activity === 'pending');
252
+ const sodDisplayAsAdmin = (0, helpers_1.isSodAdminFallbackEligibleForStep)(sodExcludedApproverUserId, isAdminFallbackApprover, approvalStep.actorsActivity);
253
+ const activitiesToShow = isReimbursementSerailized
254
+ ? pendingActivities
255
+ : pendingActivities.slice(0, 1);
256
+ if (sodDisplayAsAdmin) {
257
+ approvers.displayPendingApproverAsAdmin = true;
258
+ return;
260
259
  }
261
- });
262
- if (pendingActivitiesList.length > 0) {
263
- pendingActivitiesList.forEach((activity) => {
260
+ activitiesToShow.forEach((activity) => {
264
261
  const user = (0, userSelector_1.getUserByUserId)(userState, activity.userId);
265
262
  if (user != null) {
266
263
  approvers.users.push(user);
@@ -272,7 +269,7 @@ const getApproversOrRejectors = (reimbursement, entityApprovalStatusState, userS
272
269
  }
273
270
  }
274
271
  });
275
- }
272
+ });
276
273
  }
277
274
  }
278
275
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.1.66",
3
+ "version": "5.1.67",
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",