@zeniai/client-epic-state 5.1.29 → 5.1.30

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 (80) hide show
  1. package/README.md +3 -1
  2. package/lib/entity/genericEntity/entity.d.ts +1 -1
  3. package/lib/entity/jeSchedules/jeSchedulesPayload.js +2 -2
  4. package/lib/entity/jeSchedules/jeSchedulesSelector.d.ts +1 -1
  5. package/lib/entity/jeSchedules/jeSchedulesSelector.js +4 -4
  6. package/lib/entity/jeSchedules/jeSchedulesState.d.ts +1 -1
  7. package/lib/entity/vendor/vendorPayload.d.ts +3 -1
  8. package/lib/entity/vendor/vendorPayload.js +3 -1
  9. package/lib/epic.d.ts +2 -1
  10. package/lib/epic.js +2 -1
  11. package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +2 -2
  12. package/lib/esm/entity/jeSchedules/jeSchedulesSelector.js +4 -4
  13. package/lib/esm/entity/vendor/vendorPayload.js +3 -1
  14. package/lib/esm/epic.js +2 -1
  15. package/lib/esm/index.js +4 -4
  16. package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +29 -3
  17. package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +11 -0
  18. package/lib/esm/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -2
  19. package/lib/esm/view/aiCfoView/epics/fetchSkillsEpic.js +34 -0
  20. package/lib/esm/view/aiCfoView/epics/submitQuestionEpic.js +7 -1
  21. package/lib/esm/view/commonVendorView/transactionVendorView/epics/saveTransactionVendorEpic.js +5 -3
  22. package/lib/esm/view/createTransferEntry/epics/createTransferEntryEpic.js +5 -1
  23. package/lib/esm/view/expenseAutomationView/payload/jeSchedulesPayload.js +4 -1
  24. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +1 -1
  25. package/lib/esm/view/onboardingView/cockpitView/epic/initializeOnboardingCustomerViewUpdateDataEpic.js +4 -16
  26. package/lib/esm/view/onboardingView/cockpitView/onboardingCockpitViewPayload.js +2 -2
  27. package/lib/esm/view/referralView/epics/sendReferralInviteEpic.js +9 -1
  28. package/lib/esm/view/referralView/referralReducer.js +3 -2
  29. package/lib/esm/view/scheduleView/scheduleAccruedDetailView/epics/deleteScheduleAccruedDetailEpic.js +1 -1
  30. package/lib/esm/view/scheduleView/scheduleAccruedDetailView/epics/fetchRecommendedTransactionRowIndexEpic.js +11 -5
  31. package/lib/esm/view/scheduleView/scheduleAccruedDetailView/scheduleAccruedDetailPayload.js +4 -1
  32. package/lib/esm/view/scheduleView/scheduleDetailView/epics/createNewSchedulesEpic.js +1 -1
  33. package/lib/esm/view/scheduleView/scheduleDetailView/epics/deleteScheduleDetailEpic.js +1 -1
  34. package/lib/esm/view/scheduleView/scheduleDetailView/epics/markAsCompleteScheduleDetailEpic.js +1 -1
  35. package/lib/esm/view/scheduleView/scheduleDetailView/epics/saveScheduleDetailsEpic.js +1 -1
  36. package/lib/esm/view/scheduleView/scheduleDetailView/scheduleDetailPayload.js +12 -3
  37. package/lib/esm/view/scheduleView/scheduleListView/scheduleListSelector.js +8 -7
  38. package/lib/esm/view/spendManagement/billPay/billDetailView/epics/fetchBillDetailEpic.js +8 -3
  39. package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +5 -1
  40. package/lib/esm/view/trendWithTransactions/fetchTrendForEntityEpic.js +3 -1
  41. package/lib/esm/view/vendorFiling1099/vendorFiling1099List/vendorFiling1099ListReducer.js +4 -3
  42. package/lib/esm/view/vendorList/vendorListReducer.js +4 -3
  43. package/lib/esm/view/vendorReviewView/vendorFirstReviewView/vendorFirstReviewViewReducer.js +11 -3
  44. package/lib/index.d.ts +6 -6
  45. package/lib/index.js +11 -6
  46. package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +14 -0
  47. package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +8 -4
  48. package/lib/view/aiCfoView/aiCfoViewReducer.js +30 -4
  49. package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +2 -1
  50. package/lib/view/aiCfoView/aiCfoViewSelector.js +12 -0
  51. package/lib/view/aiCfoView/aiCfoViewState.d.ts +15 -0
  52. package/lib/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -2
  53. package/lib/view/aiCfoView/epics/fetchSkillsEpic.d.ts +8 -0
  54. package/lib/view/aiCfoView/epics/fetchSkillsEpic.js +38 -0
  55. package/lib/view/aiCfoView/epics/submitQuestionEpic.js +7 -1
  56. package/lib/view/commonVendorView/transactionVendorView/epics/saveTransactionVendorEpic.js +5 -3
  57. package/lib/view/createTransferEntry/epics/createTransferEntryEpic.js +5 -1
  58. package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.js +4 -1
  59. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +1 -1
  60. package/lib/view/onboardingView/cockpitView/epic/initializeOnboardingCustomerViewUpdateDataEpic.js +3 -15
  61. package/lib/view/onboardingView/cockpitView/onboardingCockpitViewPayload.js +2 -2
  62. package/lib/view/referralView/epics/sendReferralInviteEpic.js +9 -1
  63. package/lib/view/referralView/referralReducer.d.ts +1 -0
  64. package/lib/view/referralView/referralReducer.js +4 -3
  65. package/lib/view/scheduleView/scheduleAccruedDetailView/epics/deleteScheduleAccruedDetailEpic.js +1 -1
  66. package/lib/view/scheduleView/scheduleAccruedDetailView/epics/fetchRecommendedTransactionRowIndexEpic.js +11 -5
  67. package/lib/view/scheduleView/scheduleAccruedDetailView/scheduleAccruedDetailPayload.js +4 -1
  68. package/lib/view/scheduleView/scheduleDetailView/epics/createNewSchedulesEpic.js +1 -1
  69. package/lib/view/scheduleView/scheduleDetailView/epics/deleteScheduleDetailEpic.js +1 -1
  70. package/lib/view/scheduleView/scheduleDetailView/epics/markAsCompleteScheduleDetailEpic.js +1 -1
  71. package/lib/view/scheduleView/scheduleDetailView/epics/saveScheduleDetailsEpic.js +1 -1
  72. package/lib/view/scheduleView/scheduleDetailView/scheduleDetailPayload.js +12 -3
  73. package/lib/view/scheduleView/scheduleListView/scheduleListSelector.js +8 -7
  74. package/lib/view/spendManagement/billPay/billDetailView/epics/fetchBillDetailEpic.js +8 -3
  75. package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +5 -1
  76. package/lib/view/trendWithTransactions/fetchTrendForEntityEpic.js +3 -1
  77. package/lib/view/vendorFiling1099/vendorFiling1099List/vendorFiling1099ListReducer.js +4 -3
  78. package/lib/view/vendorList/vendorListReducer.js +4 -3
  79. package/lib/view/vendorReviewView/vendorFirstReviewView/vendorFirstReviewViewReducer.js +11 -3
  80. package/package.json +5 -2
package/lib/esm/index.js CHANGED
@@ -244,7 +244,7 @@ import { getProfitAndLossProjectView } from './view/profitAndLossProjectView/pro
244
244
  import { fetchProjectList } from './view/projectList/projectListReducer';
245
245
  import { getProjectList, } from './view/projectList/projectListSelector';
246
246
  import { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName, } from './view/recommendation/recommendationReducer';
247
- import { clearReferrals, fetchReferrals, fetchRewardsPlan, resendReferralInvite, saveReferralFormDataInLocalStore, sendReferralInvite, updateReferViewed, updateReferralListSortUiState, } from './view/referralView/referralReducer';
247
+ import { DEFAULT_REFERRER_AMOUNT, clearReferrals, fetchReferrals, fetchRewardsPlan, resendReferralInvite, saveReferralFormDataInLocalStore, sendReferralInvite, updateReferViewed, updateReferralListSortUiState, } from './view/referralView/referralReducer';
248
248
  import { getInviteFormView, getReferralListView, getRewardsPlanCard, } from './view/referralView/referralSelector';
249
249
  import { AmountStatusTypes, StatusTypes, toReferralListViewSortKeyType, } from './view/referralView/referralState';
250
250
  import { fetchReimbursementCard } from './view/reimbursementCard/reimbursementCardReducer';
@@ -642,7 +642,7 @@ export { toNotificationModeStrict, updateCommentsNotifications, updateCommentsNo
642
642
  export { toNotificationSubTabTypeStrict, toNotificationTabTypeStrict, fetchNotificationView, fetchNotificationUnreadCount, fetchNotificationUnreadCountSuccess, updateNotificationViewAllNotificationsStatus, updateNotificationViewNotificationStatus, updateNotificationViewTabState, updateNotificationViewCurrentTabAndSubTab, updateNotificationViewSubTab, updateNotificationViewUIState, getNotificationView, getExternalNotificationsForSelectedSubTab, getNotificationsForSelectedSubTab, };
643
643
  export { clearFeatureNotificationView, fetchRegisteredInterests, notifyMeForFeature, getFeatureNotificationView, getRegisteredInterests, getRegisteredInterestsByFeature, isFeatureInterestRegistered, };
644
644
  export { pushToastNotification, getLastNotificationTime, getNotifications, };
645
- export { getReferralListView, getInviteFormView, toReferralListViewSortKeyType, StatusTypes, AmountStatusTypes, fetchReferrals, sendReferralInvite, clearReferrals, saveReferralFormDataInLocalStore, updateReferralListSortUiState, resendReferralInvite, fetchRewardsPlan, getRewardsPlanCard, updateReferViewed, };
645
+ export { getReferralListView, getInviteFormView, toReferralListViewSortKeyType, StatusTypes, AmountStatusTypes, DEFAULT_REFERRER_AMOUNT, fetchReferrals, sendReferralInvite, clearReferrals, saveReferralFormDataInLocalStore, updateReferralListSortUiState, resendReferralInvite, fetchRewardsPlan, getRewardsPlanCard, updateReferViewed, };
646
646
  export { ALL_WEEK_DAYS, SEMI_WEEKLY_REQUIRED_DAYS_COUNT, getMinAllowedEndDate, getRecurringEndDateFromCount, toDayOfWeek, toRecurringFrequency, };
647
647
  export { fetchCockpitContext, fetchCompanyTaskManagerView, fetchTaskManagerMetrics, getCompanyTaskManagerView, createTaskFromTaskGroupTemplate, };
648
648
  export { fetchInternationalVerificationForm, submitInternationalVerificationForm, updateVerificationFormLocalData, getIntlWireVerificationView, };
@@ -655,8 +655,8 @@ export { clearAllAiAccountantCustomers, updateAiAccountantCustomers, updateAiAcc
655
655
  export { getAiAccountantCustomers, getAiAccountantJobsByTenantId, } from './entity/aiAccountantCustomer/aiAccountantCustomerSelector';
656
656
  export { cancelAiAccountantOnboarding, clearAiAccountantView, fetchAiAccountantCustomers, fetchAiAccountantJobs, setSelectedTenantIdsForJobTrigger, triggerAiAccountantJob, updateAiAccountantUIState, } from './view/aiAccountantView/aiAccountantViewReducer';
657
657
  export { getAiAccountantCockpitView, } from './view/aiAccountantView/aiAccountantViewSelector';
658
- export { fetchChatSessionsForUser, createSession, submitQuestion, updateAiCfoViewScrollPosition, updateCurrentInput, updateCotCollapsedState, clearInput, setSession, clearAiCfoView, clearCurrentSessionId, clearDeleteChatSessionStatus, clearLastContextMessage, createSessionAndSubmit, stopSubmit, stopSubmitQuestion, fetchChatHistory, acceptMasterTOS, deleteChatSession, updateResponseState, fetchSuggestedQuestions, fetchSuggestedQuestionsSuccess, fetchSuggestedQuestionsFailure, applyAiCfoSidePanelHostPageTransition, clearAiCfoSidePanelHostPageContext, } from './view/aiCfoView/aiCfoViewReducer';
659
- export { getAiCfoView, getSuggestedQuestionsForPageContext, } from './view/aiCfoView/aiCfoViewSelector';
658
+ export { fetchChatSessionsForUser, createSession, submitQuestion, updateAiCfoViewScrollPosition, updateCurrentInput, updateCotCollapsedState, clearInput, setSession, clearAiCfoView, clearCurrentSessionId, clearDeleteChatSessionStatus, clearLastContextMessage, createSessionAndSubmit, stopSubmit, stopSubmitQuestion, fetchChatHistory, acceptMasterTOS, deleteChatSession, updateResponseState, fetchSuggestedQuestions, fetchSuggestedQuestionsSuccess, fetchSuggestedQuestionsFailure, fetchSkills, fetchSkillsSuccess, fetchSkillsFailure, applyAiCfoSidePanelHostPageTransition, clearAiCfoSidePanelHostPageContext, } from './view/aiCfoView/aiCfoViewReducer';
659
+ export { getAiCfoView, getSuggestedQuestionsForPageContext, getSkills, } from './view/aiCfoView/aiCfoViewSelector';
660
660
  export { setNewSession, setSessions, updateAiCfoAnswerCardPolicyWizardPlan, upsertAnswerPayload, upsertOrAddQuestionAnswerPayload, addQuestionPayload, clearSession, clearAiCfo, toAiCfoVisualization, appendSyntheticAiCfoAnswer, updateSyntheticAiCfoAnswer, removeSyntheticAiCfoAnswer, clearSyntheticAiCfoAnswers, } from './entity/aiCfo/aiCfoReducer';
661
661
  export { getAllQuestionAnswersForChatSession, getQuestionAnswerByIdForChatSession, getAllQuestionsForChatSession, getAiCfoSelectorView, getSyntheticAiCfoAnswersForChatSession, getSyntheticAiCfoAnswerByQuestionAnswerId, } from './entity/aiCfo/aiCfoSelector';
662
662
  export { ALL_AI_CFO_CHARTS_TYPES, ALL_AI_CFO_VISUALIZATION_TYPES, ALL_AI_CFO_ANSWER_STATE_TYPES, ALL_AI_CFO_ANSWER_RESPONSE_TYPES, ALL_INTERACTIVE_FORM_TYPES, toAiCfoVisualizationType, toAiCfoVisualizationTypeStrict, toAiCfoChartType, toAiCfoChartTypeStrict, toAiCfoAnswerStateType, toAiCfoAnswerStateTypeStrict, toAiCfoAnswerResponseType, toAiCfoAnswerResponseTypeStrict, toInteractiveFormType, toInteractiveFormTypeStrict, ALL_SYNTHETIC_AI_CFO_ANSWER_KINDS, toMessageSender, toMessageType, } from './entity/aiCfo/aiCfoState';
@@ -47,6 +47,7 @@ export const initialAiCfoViewState = {
47
47
  responseStateByChatSessionId: {},
48
48
  stopSubmitStateByChatSessionId: {},
49
49
  suggestedQuestionsByPageContext: {},
50
+ skills: { fetchState: 'Not-Started', error: undefined, skills: [] },
50
51
  };
51
52
  const aiCfoView = createSlice({
52
53
  name: 'aiCfoView',
@@ -62,7 +63,7 @@ const aiCfoView = createSlice({
62
63
  answer: { fetchState: 'In-Progress', error: undefined },
63
64
  };
64
65
  },
65
- prepare(sessionId, questionAnswerId, userId, questionId, createdAt, question, files) {
66
+ prepare(sessionId, questionAnswerId, userId, questionId, createdAt, question, files, macroId) {
66
67
  return {
67
68
  payload: {
68
69
  sessionId,
@@ -72,6 +73,7 @@ const aiCfoView = createSlice({
72
73
  createdAt,
73
74
  question,
74
75
  files,
76
+ macroId,
75
77
  },
76
78
  };
77
79
  },
@@ -222,7 +224,7 @@ const aiCfoView = createSlice({
222
224
  draft.createSessionAndSubmitState.fetchState = 'In-Progress';
223
225
  draft.createSessionAndSubmitState.error = undefined;
224
226
  },
225
- prepare(agentId, userId, questionAnswerId, questionId, createdAt, question, files, pageContext) {
227
+ prepare(agentId, userId, questionAnswerId, questionId, createdAt, question, files, pageContext, macroId) {
226
228
  return {
227
229
  payload: {
228
230
  agentId,
@@ -233,6 +235,7 @@ const aiCfoView = createSlice({
233
235
  question,
234
236
  files,
235
237
  pageContext,
238
+ macroId,
236
239
  },
237
240
  };
238
241
  },
@@ -445,6 +448,29 @@ const aiCfoView = createSlice({
445
448
  error,
446
449
  };
447
450
  },
451
+ fetchSkills(draft) {
452
+ // Optional-chain: persisted/rehydrated state from before this slice existed
453
+ // may have no `skills`, so don't assume draft.skills is set.
454
+ draft.skills = {
455
+ fetchState: 'In-Progress',
456
+ error: undefined,
457
+ skills: draft.skills?.skills ?? [],
458
+ };
459
+ },
460
+ fetchSkillsSuccess(draft, action) {
461
+ draft.skills = {
462
+ fetchState: 'Completed',
463
+ error: undefined,
464
+ skills: action.payload.skills,
465
+ };
466
+ },
467
+ fetchSkillsFailure(draft, action) {
468
+ draft.skills = {
469
+ fetchState: 'Error',
470
+ error: action.payload,
471
+ skills: draft.skills?.skills ?? [],
472
+ };
473
+ },
448
474
  clearAiCfoView(draft) {
449
475
  Object.assign(draft, initialAiCfoViewState);
450
476
  },
@@ -455,5 +481,5 @@ const aiCfoView = createSlice({
455
481
  },
456
482
  },
457
483
  });
458
- export const { submitQuestion, submitQuestionSuccess, submitQuestionFailure, updateResponseState, updateAiCfoViewScrollPosition, updateCurrentInput, clearInput, setSession, createSession, createSessionSuccess, createSessionFailure, createSessionAndSubmit, initializeNewSessionState, createSessionAndSubmitSuccess, createSessionAndSubmitFailure, fetchChatSessionsForUser, fetchChatSessionsForUserSuccess, fetchChatSessionsForUserFailure, fetchChatHistory, fetchChatHistorySuccess, fetchChatHistoryFailure, clearCurrentSessionId, clearLastContextMessage, stopSubmit, stopSubmitSuccess, stopSubmitFailure, stopSubmitQuestion, stopSubmitQuestionSuccess, stopSubmitQuestionFailure, acceptMasterTOS, acceptMasterTOSSuccess, acceptMasterTOSFailure, deleteChatSession, deleteChatSessionSuccess, deleteChatSessionFailure, clearDeleteChatSessionStatus, clearAiCfoView, updateCotCollapsedState, fetchSuggestedQuestions, fetchSuggestedQuestionsSuccess, fetchSuggestedQuestionsFailure, applyAiCfoSidePanelHostPageTransition, clearAiCfoSidePanelHostPageContext, } = aiCfoView.actions;
484
+ export const { submitQuestion, submitQuestionSuccess, submitQuestionFailure, updateResponseState, updateAiCfoViewScrollPosition, updateCurrentInput, clearInput, setSession, createSession, createSessionSuccess, createSessionFailure, createSessionAndSubmit, initializeNewSessionState, createSessionAndSubmitSuccess, createSessionAndSubmitFailure, fetchChatSessionsForUser, fetchChatSessionsForUserSuccess, fetchChatSessionsForUserFailure, fetchChatHistory, fetchChatHistorySuccess, fetchChatHistoryFailure, clearCurrentSessionId, clearLastContextMessage, stopSubmit, stopSubmitSuccess, stopSubmitFailure, stopSubmitQuestion, stopSubmitQuestionSuccess, stopSubmitQuestionFailure, acceptMasterTOS, acceptMasterTOSSuccess, acceptMasterTOSFailure, deleteChatSession, deleteChatSessionSuccess, deleteChatSessionFailure, clearDeleteChatSessionStatus, clearAiCfoView, updateCotCollapsedState, fetchSuggestedQuestions, fetchSuggestedQuestionsSuccess, fetchSuggestedQuestionsFailure, fetchSkills, fetchSkillsSuccess, fetchSkillsFailure, applyAiCfoSidePanelHostPageTransition, clearAiCfoSidePanelHostPageContext, } = aiCfoView.actions;
459
485
  export default aiCfoView.reducer;
@@ -22,3 +22,14 @@ export const getAiCfoView = (state) => {
22
22
  export function getSuggestedQuestionsForPageContext(state, pageContext) {
23
23
  return state.aiCfoViewState?.suggestedQuestionsByPageContext?.[pageContext];
24
24
  }
25
+ // Stable fallback so getSkills returns a referentially-stable object when skills
26
+ // state is absent — a fresh literal each call would defeat useSelector identity
27
+ // checks and cause needless re-renders.
28
+ const EMPTY_SKILLS_STATE = {
29
+ fetchState: 'Not-Started',
30
+ error: undefined,
31
+ skills: [],
32
+ };
33
+ export function getSkills(state) {
34
+ return state.aiCfoViewState?.skills ?? EMPTY_SKILLS_STATE;
35
+ }
@@ -66,7 +66,7 @@ function waitForChannelSubscription(pusherInstance, channelName, timeoutMs = 500
66
66
  }));
67
67
  }
68
68
  export const createSessionAndSubmitEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(createSessionAndSubmit.match), switchMap((action) => {
69
- const { agentId, userId, questionAnswerId, questionId, createdAt, question, files, pageContext, } = action.payload;
69
+ const { agentId, userId, questionAnswerId, questionId, createdAt, question, files, pageContext, macroId, } = action.payload;
70
70
  const payload = {
71
71
  agent_id: agentId,
72
72
  ...(pageContext != null && { page_context: pageContext }),
@@ -113,7 +113,7 @@ export const createSessionAndSubmitEpic = (actions$, _state$, zeniAPI) => action
113
113
  // This allows fetchChatHistory to run after the question is submitted
114
114
  of(createSessionAndSubmitSuccess(),
115
115
  // Submit the question after handlers are bound
116
- submitQuestion(sessionId, questionAnswerId, userId, questionId, createdAt, question, files),
116
+ submitQuestion(sessionId, questionAnswerId, userId, questionId, createdAt, question, files, macroId),
117
117
  // Add question payload optimistically after submitQuestion (matches original order)
118
118
  // This is idempotent - won't create duplicates if called multiple times
119
119
  // submitQuestionEpic will find the question already exists and only update the response
@@ -0,0 +1,34 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
4
+ import { fetchSkills, fetchSkillsFailure, fetchSkillsSuccess, } from '../aiCfoViewReducer';
5
+ const toSkill = (s) => ({
6
+ macroId: s.macro_id,
7
+ name: s.name,
8
+ displayName: s.display_name,
9
+ description: s.description,
10
+ semver: s.semver,
11
+ parameterHints: s.parameter_hints,
12
+ hasScripts: s.has_scripts,
13
+ });
14
+ /** GET {aiCfoMicroServiceBaseUrl}/1.0/skills — chat-visible skills for the `/` menu. */
15
+ export const fetchSkillsEpic = (actions$,
16
+ // state$ intentionally unused: the `/` menu dispatches this once per slash-entry
17
+ // (the composer dedupes), so we always re-fetch the (small, singleton) list.
18
+ _state$, zeniAPI) => actions$.pipe(filter(fetchSkills.match),
19
+ // switchMap: a singleton list endpoint with no key — cancel any in-flight
20
+ // fetch so the latest dispatch wins (no racing writes to `skills`).
21
+ switchMap(() => {
22
+ // aiCfoMicroServiceBaseUrl already targets the chat service (it serves the
23
+ // /1.0/agents/{id} submit route too); /1.0/skills lives on the same service.
24
+ const url = `${zeniAPI.apiEndPoints.aiCfoMicroServiceBaseUrl}/1.0/skills`;
25
+ return zeniAPI.getJSON(url).pipe(mergeMap((response) => {
26
+ if (isSuccessResponse(response) && response.data != null) {
27
+ // Guard the array: a malformed 2xx body without `skills` must not crash .map.
28
+ return of(fetchSkillsSuccess({
29
+ skills: (response.data.skills ?? []).map(toSkill),
30
+ }));
31
+ }
32
+ return of(fetchSkillsFailure(response.status));
33
+ }), catchError((error) => of(fetchSkillsFailure(createZeniAPIStatus('Unexpected Error', 'Fetch skills REST API call failed', error instanceof Error ? { message: error.message } : undefined)))));
34
+ }));
@@ -4,7 +4,7 @@ import { upsertOrAddQuestionAnswerPayload } from '../../../entity/aiCfo/aiCfoRed
4
4
  import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
5
5
  import { submitQuestion, submitQuestionFailure, submitQuestionSuccess, } from '../aiCfoViewReducer';
6
6
  export const submitQuestionEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(submitQuestion.match), mergeMap((action) => {
7
- const { questionAnswerId, userId, sessionId, questionId, createdAt, question, files, } = action.payload;
7
+ const { questionAnswerId, userId, sessionId, questionId, createdAt, question, files, macroId, } = action.payload;
8
8
  const { aiCfoViewState } = state$.value;
9
9
  const { uiState } = aiCfoViewState;
10
10
  const agentId = uiState.agentId;
@@ -17,15 +17,21 @@ export const submitQuestionEpic = (actions$, state$, zeniAPI) => actions$.pipe(f
17
17
  const formData = new FormData();
18
18
  formData.append('chat_session_id', sessionId);
19
19
  formData.append('message', question);
20
+ if (macroId != null) {
21
+ formData.append('macro_id', macroId);
22
+ }
20
23
  for (const file of files) {
21
24
  formData.append('files', file, file.name);
22
25
  }
23
26
  apiCall = zeniAPI.postFormData(endpoint, formData);
24
27
  }
25
28
  else {
29
+ // `message` is the display token (e.g. "/flux"); `macro_id` tells the chat
30
+ // service to expand the skill's instructions as the actual agent prompt.
26
31
  apiCall = zeniAPI.postAndGetJSON(endpoint, {
27
32
  chat_session_id: sessionId,
28
33
  message: question,
34
+ ...(macroId != null && { macro_id: macroId }),
29
35
  });
30
36
  }
31
37
  return apiCall.pipe(mergeMap((response) => {
@@ -70,7 +70,8 @@ export const saveTransactionVendorEpic = (actions$, state$, zeniAPI) => actions$
70
70
  name: response.data.vendors[0].vendor_name,
71
71
  id: response.data.vendors[0].qbo_id,
72
72
  type: 'vendor',
73
- zeniId: savedVendor.vendor_id ?? '',
73
+ // Zeni platform id (vendor_id field), not the resolved id used for local-data keys.
74
+ zeniId: savedVendor.vendor_id ?? undefined,
74
75
  qboId: response.data.vendors[0].qbo_id,
75
76
  logo: toZeniUrlWithoutBaseURL(response.data.vendors[0].logo?.url ?? ''),
76
77
  },
@@ -83,14 +84,15 @@ export const saveTransactionVendorEpic = (actions$, state$, zeniAPI) => actions$
83
84
  transactionId: action.payload.transactionId,
84
85
  vendorUpdates: {
85
86
  name: response.data.vendors[0].vendor_name,
86
- id: savedVendor.vendor_id ?? '',
87
+ id: savedVendor.vendor_id ?? undefined,
87
88
  qboId: response.data.vendors[0].qbo_id,
88
89
  },
89
90
  entity: {
90
91
  name: response.data.vendors[0].vendor_name,
91
92
  id: response.data.vendors[0].qbo_id,
92
93
  type: 'vendor',
93
- zeniId: savedVendor.vendor_id ?? '',
94
+ // Zeni platform id (vendor_id field), not the resolved id used for local-data keys.
95
+ zeniId: savedVendor.vendor_id ?? undefined,
94
96
  qboId: response.data.vendors[0].qbo_id,
95
97
  logo: toZeniUrlWithoutBaseURL(response.data.vendors[0].logo?.url ?? ''),
96
98
  },
@@ -3,6 +3,7 @@ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
3
  import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
4
4
  import { toTransactionID } from '../../../entity/transaction/payloadTypes/transactionIDPayload';
5
5
  import { removeTransaction, updateTransaction, } from '../../../entity/transaction/transactionReducer';
6
+ import { getVendorPayloadIdentifier } from '../../../entity/vendor/vendorPayload';
6
7
  import { isSuccessResponse } from '../../../responsePayload';
7
8
  import { removeTransactionFromAllTabs } from '../../expenseAutomationView/reducers/transactionsViewReducer';
8
9
  import { initializeTransactionDetailLocalData, removeTransactionDetail, } from '../../transactionDetail/transactionDetailReducer';
@@ -85,11 +86,14 @@ function handleSuccessWithoutTransactionBody(transactionId) {
85
86
  function handleSuccessWithTransactionBody(transactionPayload, vendorPayload, previousTransactionId, sourceTransactionId) {
86
87
  const newTransactionId = toTransactionID(transactionPayload);
87
88
  const replaced = !transactionIdsAreEqual(previousTransactionId, newTransactionId);
89
+ const firstVendor = vendorPayload?.[0];
88
90
  const immediate = [
89
91
  updateTransaction(getTransactionDetailKey(newTransactionId), transactionPayload),
90
92
  initializeTransactionDetailLocalData({
91
93
  transactionId: newTransactionId,
92
- vendorId: vendorPayload?.[0]?.vendor_id ?? undefined,
94
+ vendorId: firstVendor != null
95
+ ? getVendorPayloadIdentifier(firstVendor) ?? undefined
96
+ : undefined,
93
97
  }),
94
98
  ...buildSuccessSideEffects(sourceTransactionId),
95
99
  ];
@@ -3,7 +3,10 @@ import { mapScheduleTransactionToBaseScheduleTransactionPayload, mapVendorToVend
3
3
  export const prepareIgnoreSchedulePayload = (scheduleType, jeScheduleTransaction, state) => {
4
4
  const { vendorState } = state;
5
5
  const { vendor, currencyCode, currencySymbol, baseTransaction, status, balanceAsOfToday, period, startDate, endDate, jeCredit, jeDebit, } = jeScheduleTransaction;
6
- const vendorID = vendor.id;
6
+ const vendorID = vendor?.id;
7
+ if (vendorID == null) {
8
+ throw new Error('Vendor is required to build JE schedule payload');
9
+ }
7
10
  const vendorDetails = vendorState.vendorByID[vendorID];
8
11
  const jeSchedulePayload = {
9
12
  status: status,
@@ -15,7 +15,7 @@ import { getJEAccountSettingsView } from './jeAccountSettingsViewSelector';
15
15
  function getJEScheduleSortAccessor(sortKey) {
16
16
  switch (sortKey) {
17
17
  case 'vendor':
18
- return (s) => s.vendor.name?.toLowerCase();
18
+ return (s) => s.vendor?.name?.toLowerCase();
19
19
  case 'category':
20
20
  return (s) => s.jeDebit.account?.accountName?.toLowerCase();
21
21
  case 'class':
@@ -4,7 +4,7 @@ import { getAddressByAddressId } from '../../../../entity/address/addressSelecto
4
4
  import { getOnboardingCompanyByCompanyId } from '../../../../entity/company/companySelector';
5
5
  import { toAccountingConnectionCreationModeStrict } from '../../../../entity/company/companyStateTypes';
6
6
  import { getOnboardingCustomersByCompanyId } from '../../../../entity/onboardingCustomer/onboardingCustomerSelector';
7
- import { getOnboardingTenantByTenantId, isOtherProductsEnabledForTenant, isTenantBankingOnly, isTenantBookkeepingEnabled, isTenantCardsOnly, isTenantTreasuryEnabled, } from '../../../../entity/tenant/tenantSelector';
7
+ import { getOnboardingTenantByTenantId, isOtherProductsEnabledForTenant, isTenantBankingOnly, isTenantBookkeepingEnabled, isTenantCardsOnly, } from '../../../../entity/tenant/tenantSelector';
8
8
  import { getUserByUserId } from '../../../../entity/user/userSelector';
9
9
  import { newAddressInLocalStore, resetNewAddressesInLocalStore, } from '../../../addressView/addressViewReducer';
10
10
  import { clearOnboardingCustomerViewUpdateData, initializeOnboardingCustomerViewUpdateData, saveOnboardingCustomerDataInLocalStore, saveOnboardingCustomerViewUpdateData, updateCustomerLocalStoreInitStateOnFailure, } from '../onboardingCockpitViewReducer';
@@ -112,32 +112,20 @@ const getSelectedProducts = (isDebitCardFlagEnabled, tenant) => {
112
112
  const isBookkeepingEnabled = isTenantBookkeepingEnabled(tenant);
113
113
  const isOtherProductsEnabled = isOtherProductsEnabledForTenant(tenant);
114
114
  const isCardsEnabled = isTenantCardsOnly(tenant);
115
- const isTreasuryEnabled = isTenantTreasuryEnabled(tenant);
116
115
  if (isCardsEnabled && isBankingOnly) {
117
- const selectedProducts = ['zeni_cards', 'zeni_checking'];
118
- if (isTreasuryEnabled) {
119
- selectedProducts.push('zeni_treasury');
120
- }
121
- return selectedProducts;
116
+ return [];
122
117
  }
123
118
  else if (isBankingOnly) {
124
- const selectedProducts = ['zeni_checking'];
125
- if (isTreasuryEnabled) {
126
- selectedProducts.push('zeni_treasury');
127
- }
128
- return selectedProducts;
119
+ return [];
129
120
  }
130
121
  else if (isCardsEnabled) {
131
- return ['zeni_cards'];
122
+ return [];
132
123
  }
133
124
  else if (isBookkeepingEnabled) {
134
125
  return [
135
126
  'bookkeeping',
136
127
  'zeni_bill_pay',
137
- 'zeni_checking',
138
128
  'zeni_reimbursements',
139
- 'zeni_treasury',
140
- 'zeni_cards',
141
129
  ];
142
130
  }
143
131
  else if (isOtherProductsEnabled) {
@@ -48,9 +48,9 @@ export const toOnboardingCustomerPayload = (onboardingCustomer, sendInvite, comp
48
48
  const isTreasury = selectedProducts.includes('zeni_treasury');
49
49
  if (isBookkeeping) {
50
50
  onboardingCustomerPayload.is_book_keeping_enabled = true;
51
- onboardingCustomerPayload.is_banking_enabled = true;
51
+ onboardingCustomerPayload.is_banking_enabled = isChecking;
52
52
  onboardingCustomerPayload.is_spend_management_enabled = true;
53
- onboardingCustomerPayload.is_card_enabled = true;
53
+ onboardingCustomerPayload.is_card_enabled = isCards;
54
54
  onboardingCustomerPayload.is_treasury_enabled = isTreasury;
55
55
  }
56
56
  else if (isChecking && isCards) {
@@ -1,5 +1,6 @@
1
1
  import { of } from 'rxjs';
2
2
  import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
3
4
  import { createZeniAPIStatus, isSuccessStatus } from '../../../responsePayload';
4
5
  import { sendReferralInvite, sendReferralInviteFailure, sendReferralInviteSuccess, } from '../referralReducer';
5
6
  export const sendReferralInviteEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(sendReferralInvite.match), switchMap(() => {
@@ -13,7 +14,14 @@ export const sendReferralInviteEpic = (actions$, state$, zeniAPI) => actions$.pi
13
14
  .postAndGetJSON(`${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/company-referrals`, invitePayload)
14
15
  .pipe(mergeMap((response) => {
15
16
  if (isSuccessStatus(response)) {
16
- const actions = [sendReferralInviteSuccess()];
17
+ const actions = [
18
+ sendReferralInviteSuccess(),
19
+ openSnackbar({
20
+ messageSection: 'referral_invite_sent',
21
+ messageText: 'success',
22
+ type: 'success',
23
+ }),
24
+ ];
17
25
  return actions;
18
26
  }
19
27
  else {
@@ -4,6 +4,7 @@ import { date } from '../../zeniDayJS';
4
4
  import { toZeniUrl } from '../../zeniUrl';
5
5
  import { toReferralInvitation, } from './referralPayload';
6
6
  import { toSupportedRewardPlansType, } from './referralState';
7
+ export const DEFAULT_REFERRER_AMOUNT = 4000;
7
8
  export const initialState = {
8
9
  fetchState: 'Not-Started',
9
10
  error: undefined,
@@ -44,7 +45,7 @@ export const initialState = {
44
45
  },
45
46
  rewardsPlan: {
46
47
  referrerAmount: {
47
- amount: 0,
48
+ amount: DEFAULT_REFERRER_AMOUNT,
48
49
  currencyCode: 'USD',
49
50
  currencySymbol: '$',
50
51
  },
@@ -53,7 +54,7 @@ export const initialState = {
53
54
  currencyCode: 'USD',
54
55
  currencySymbol: '$',
55
56
  },
56
- planName: 'PLAN_1000',
57
+ planName: 'PLAN_4000',
57
58
  planId: 'dummy',
58
59
  referralLink: toZeniUrl(''),
59
60
  },
@@ -20,7 +20,7 @@ export const deleteScheduleAccruedDetailEpic = (actions$, state$, zeniAPI) => ac
20
20
  return from(actions);
21
21
  }
22
22
  const scheduleDetailId = jeScheduleState.jeScheduleId;
23
- const vendorName = jeScheduleState.vendor.name;
23
+ const vendorName = jeScheduleState.vendor?.name ?? '';
24
24
  const scheduleDetailsUpdated = state.scheduleAccruedDetailState.editScheduleStateByDetailId[scheduleDetailId];
25
25
  const payload = {
26
26
  ...prepareScheduleAccruedDetailPayload(state, scheduleDetailsUpdated, selectedJEScheduleKey, true),
@@ -3,14 +3,13 @@ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
3
  import { DEFAULT_DATE_FORMAT } from '../../../../commonStateTypes/fiscalYearHelpers/formatZeniDateFY';
4
4
  import { getJEAccruedScheduleByJEScheduleKey } from '../../../../entity/jeSchedules/jeSchedulesSelector';
5
5
  import { updateTransactions } from '../../../../entity/transaction/transactionReducer';
6
- import { getVendorByVendorId } from '../../../../entity/vendor/vendorSelector';
7
6
  import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
8
7
  import { dateNow } from '../../../../zeniDayJS';
9
8
  import { fetchRecommendedTransactionRowIndex, updateFetchedTransactionIds, updatedFetchRecommendationBillExpenseSuccessOrFailure, } from '../scheduleAccruedDetailReducer';
10
9
  export const fetchRecommendedTransactionRowIndexEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchRecommendedTransactionRowIndex.match), mergeMap((action) => {
11
10
  const state = state$.value;
12
11
  const { selectedJELinkRowIndex } = action.payload;
13
- const { scheduleAccruedDetailState, vendorState } = state;
12
+ const { scheduleAccruedDetailState } = state;
14
13
  const actions = [];
15
14
  const { selectedJEAccruedScheduleKey } = scheduleAccruedDetailState;
16
15
  if (selectedJEAccruedScheduleKey == null ||
@@ -27,14 +26,21 @@ export const fetchRecommendedTransactionRowIndexEpic = (actions$, state$, zeniAP
27
26
  const { amount, runningBalance: accruedBalance, expectedPostDate, } = selectedJournalEntry;
28
27
  const endDate = dateNow().endOf('month').format(DEFAULT_DATE_FORMAT);
29
28
  const { vendor } = jeScheduleState;
30
- const vendorId = vendor.id;
31
- const vendorEntity = getVendorByVendorId(vendorState, vendorId);
29
+ if (vendor?.id == null) {
30
+ return from([
31
+ updateFetchedTransactionIds([], (value) => value.transaction_id),
32
+ updatedFetchRecommendationBillExpenseSuccessOrFailure({
33
+ fetchState: 'Completed',
34
+ error: undefined,
35
+ }),
36
+ ]);
37
+ }
32
38
  const queryParam = {
33
39
  start_date: expectedPostDate.format(DEFAULT_DATE_FORMAT),
34
40
  end_date: endDate,
35
41
  amount: amount?.amount ?? 0,
36
42
  accrued_balance: accruedBalance?.amount ?? 0,
37
- vendor_id: vendorEntity?.id ?? '',
43
+ vendor_id: vendor.id,
38
44
  account_name: account?.accountName ?? '',
39
45
  class_name: accountingClass?.className ?? '',
40
46
  };
@@ -202,7 +202,10 @@ export const mapAccruedExpenseJEScheduleTransactionToPayload = (jeScheduleAccrue
202
202
  const lastJEScheduleDate = scheduleLength > 0
203
203
  ? scheduleDetailsLocalDataAccruedExpenses.jeScheduleDetails[scheduleLength - 1].postingDate.format(DEFAULT_DATE_FORMAT)
204
204
  : null;
205
- const vendorID = vendor.id;
205
+ const vendorID = vendor?.id;
206
+ if (vendorID == null) {
207
+ throw new Error('Vendor is required to build accrued schedule detail payload');
208
+ }
206
209
  const vendorDetails = vendorState.vendorByID[vendorID];
207
210
  const payload = {
208
211
  status: status,
@@ -12,7 +12,7 @@ export const createNewSchedulesEpic = (actions$, state$) => actions$.pipe(filter
12
12
  if (selectedJEScheduleKey != null) {
13
13
  const jeScheduleTransactionState = getJEScheduledTransactionByJEScheduleTransactionKey(selectedJEScheduleKey, state);
14
14
  const totalAmount = jeScheduleTransactionState.baseTransaction.amount;
15
- const vendorName = jeScheduleTransactionState.vendor.name;
15
+ const vendorName = jeScheduleTransactionState.vendor?.name ?? '';
16
16
  const currentLocalData = jeScheduleTransactionState.jeScheduleId != null
17
17
  ? scheduleDetailState.editScheduleStateByDetailId[scheduleType][jeScheduleTransactionState.jeScheduleId]
18
18
  : scheduleDetailState.newScheduleState[scheduleType];
@@ -16,7 +16,7 @@ export const deleteScheduleDetailEpic = (actions$, state$, zeniAPI) => actions$.
16
16
  return from(actions);
17
17
  }
18
18
  const jeScheduleTransactionState = getJEScheduledTransactionByJEScheduleTransactionKey(selectedJEScheduleKey, state);
19
- const vendorName = jeScheduleTransactionState.vendor.name;
19
+ const vendorName = jeScheduleTransactionState.vendor?.name ?? '';
20
20
  const scheduleDetailId = jeScheduleTransactionState.jeScheduleId ?? selectedJeScheduleDetailId;
21
21
  if (scheduleDetailId == null) {
22
22
  return from(actions);
@@ -12,7 +12,7 @@ export const markAsCompleteScheduleDetailEpic = (actions$, state$, zeniAPI) => a
12
12
  const actions = [];
13
13
  const jeScheduleTransactionState = getJEScheduledTransactionByJEScheduleTransactionKey(jeScheduleKey, state);
14
14
  const scheduleDetailId = jeScheduleTransactionState.jeScheduleId;
15
- const vendorName = jeScheduleTransactionState.vendor.name;
15
+ const vendorName = jeScheduleTransactionState.vendor?.name ?? '';
16
16
  const scheduleDetailsUpdated = scheduleDetailId != null
17
17
  ? state.scheduleDetailState.editScheduleStateByDetailId[scheduleType][scheduleDetailId]
18
18
  : state.scheduleDetailState.newScheduleState[scheduleType];
@@ -16,7 +16,7 @@ export const saveScheduleDetailsEpic = (actions$, state$, zeniAPI) => actions$.p
16
16
  return from(actions);
17
17
  }
18
18
  const jeScheduleTransactionState = getJEScheduledTransactionByJEScheduleTransactionKey(selectedJEScheduleKey, state);
19
- const vendorName = jeScheduleTransactionState.vendor.name;
19
+ const vendorName = jeScheduleTransactionState.vendor?.name ?? '';
20
20
  const scheduleDetailId = jeScheduleTransactionState.jeScheduleId ?? selectedJeScheduleDetailId;
21
21
  const scheduleDetailsUpdated = scheduleDetailId != null
22
22
  ? state.scheduleDetailState.editScheduleStateByDetailId[scheduleType][scheduleDetailId]
@@ -120,7 +120,10 @@ const mapJEScheduleTransactionToPayload = (jeScheduleTransactionState, vendorSta
120
120
  const lastJEScheduleDate = scheduleLength > 0
121
121
  ? scheduleDetailsLocalData.jeScheduleDetails[scheduleLength - 1].postingDate.format(DEFAULT_DATE_FORMAT)
122
122
  : null;
123
- const vendorID = vendor.id;
123
+ const vendorID = vendor?.id;
124
+ if (vendorID == null) {
125
+ throw new Error('Vendor is required to build schedule detail payload (mapJEScheduleTransactionToPayload)');
126
+ }
124
127
  const vendorDetails = vendorState.vendorByID[vendorID];
125
128
  const updatedVendor = {
126
129
  vendor_id: selectedVendor?.id ?? '',
@@ -195,7 +198,10 @@ const mapFixedAssetJEScheduleTransactionToPayload = (jeScheduleTransactionState,
195
198
  const lastJEScheduleDate = scheduleLength > 0
196
199
  ? scheduleDetailsLocalData.jeScheduleDetails[scheduleLength - 1].postingDate.format(DEFAULT_DATE_FORMAT)
197
200
  : null;
198
- const vendorID = vendor.id;
201
+ const vendorID = vendor?.id;
202
+ if (vendorID == null) {
203
+ throw new Error('Vendor is required to build schedule detail payload (mapFixedAssetJEScheduleTransactionToPayload)');
204
+ }
199
205
  const vendorDetails = vendorState.vendorByID[vendorID];
200
206
  const updatedVendor = {
201
207
  vendor_id: selectedVendor?.id ?? '',
@@ -273,7 +279,10 @@ export const mapAccruedExpenseJEScheduleTransactionToPayload = (jeScheduleTransa
273
279
  const lastJEScheduleDate = scheduleLength > 0
274
280
  ? scheduleDetailsLocalData.jeScheduleDetails[scheduleLength - 1].postingDate.format(DEFAULT_DATE_FORMAT)
275
281
  : null;
276
- const vendorID = vendor.id;
282
+ const vendorID = vendor?.id;
283
+ if (vendorID == null) {
284
+ throw new Error('Vendor is required to build schedule detail payload (mapAccruedExpenseJEScheduleTransactionToPayload)');
285
+ }
277
286
  const vendorDetails = vendorState.vendorByID[vendorID];
278
287
  const payload = {
279
288
  status: updatedStatus,
@@ -12,9 +12,9 @@ const sortedJETransactionsView = (jeTransactions, sortKey, sortOrder) => {
12
12
  case 'transactionDate':
13
13
  return jeTransaction.baseTransaction.date.valueOf();
14
14
  case 'vendor':
15
- return jeTransaction.vendor.name != null
15
+ return jeTransaction.vendor?.name != null
16
16
  ? jeTransaction.vendor.name.toLowerCase()
17
- : jeTransaction.vendor.name;
17
+ : jeTransaction.vendor?.name;
18
18
  case 'scheduleCategory':
19
19
  return jeTransaction.baseTransaction.account.accountName.toLowerCase();
20
20
  case 'expenseCategory':
@@ -75,9 +75,9 @@ const sortedJEAccruedSchedules = (jeAccruedSchedules, sortKey, sortOrder) => {
75
75
  case 'createTime':
76
76
  return jeAccruedSchedule.createTime.valueOf();
77
77
  case 'vendor':
78
- return jeAccruedSchedule.vendor.name != null
78
+ return jeAccruedSchedule.vendor?.name != null
79
79
  ? jeAccruedSchedule.vendor.name.toLowerCase()
80
- : jeAccruedSchedule.vendor.name;
80
+ : jeAccruedSchedule.vendor?.name;
81
81
  case 'expenseCategory':
82
82
  return jeAccruedSchedule.jeDebit.account != null
83
83
  ? jeAccruedSchedule.jeDebit.account.accountName.toLowerCase()
@@ -202,7 +202,7 @@ export const getScheduleListReport = (state, scheduleType) => {
202
202
  .trim()
203
203
  .toLowerCase();
204
204
  const sortedJETransactionView = sortedJETransactionsView(jeTransactionsView.filter((jeTransaction) => {
205
- return ((jeTransaction.vendor.name != null &&
205
+ return ((jeTransaction.vendor?.name != null &&
206
206
  jeTransaction.vendor.name
207
207
  .toLowerCase()
208
208
  .includes(loweredSearchText) === true) ||
@@ -322,8 +322,9 @@ export const getAccruedScheduleListReport = (state, scheduleType) => {
322
322
  .trim()
323
323
  .toLocaleLowerCase();
324
324
  const sortedJESchedules = sortedJEAccruedSchedules(jeScheduleAccrued.filter((jeSchedule) => {
325
- return (jeSchedule.vendor.name.toLowerCase().includes(loweredSearchText) ===
326
- true ||
325
+ return (jeSchedule.vendor?.name
326
+ ?.toLowerCase()
327
+ ?.includes(loweredSearchText) === true ||
327
328
  jeSchedule.memo.toLowerCase().includes(loweredSearchText) === true);
328
329
  }), sortKey, sortOrder);
329
330
  const totalBalances = getCalculatedAccruedScheduleTotal(sortedJESchedules);
@@ -14,6 +14,7 @@ import { updateEntityApprovalStatus } from '../../../../../entity/entityApproval
14
14
  import { updatePaymentAccounts } from '../../../../../entity/paymentAccount/paymentAccountReducer';
15
15
  import { updatePaymentInstruments } from '../../../../../entity/paymentInstrument/paymentInstrumentReducer';
16
16
  import { updateAllUsers } from '../../../../../entity/user/userReducer';
17
+ import { getVendorPayloadIdentifier } from '../../../../../entity/vendor/vendorPayload';
17
18
  import { updateVendors } from '../../../../../entity/vendor/vendorReducer';
18
19
  import { createZeniAPIStatus, isSuccessResponse, } from '../../../../../responsePayload';
19
20
  import { getFlattenedAddress } from '../../../../commonVendorView/commonVendorViewHelper';
@@ -98,12 +99,16 @@ export const fetchBillDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(
98
99
  }
99
100
  else {
100
101
  fetchActions.push(updateBillDetail({ billId, billDetail: response.data }));
101
- fetchActions.push(updateBillDetailFetchState(transcationId, 'Completed', undefined, vendorInResponse?.vendor_id ?? undefined));
102
102
  const transactionInResponse = response.data?.transaction;
103
+ const resolvedVendorId = vendorInResponse != null
104
+ ? getVendorPayloadIdentifier(vendorInResponse)
105
+ : null;
106
+ fetchActions.push(updateBillDetailFetchState(transcationId, 'Completed', undefined, resolvedVendorId ?? undefined));
103
107
  if (transactionInResponse != null &&
104
108
  transactionInResponse.total_amount != null &&
105
- vendorInResponse.vendor_id != null) {
106
- fetchActions.push(fetchDuplicateBill(vendorInResponse.vendor_name, vendorInResponse.vendor_id, transactionInResponse.total_amount, transactionInResponse.recipient_total_amount, transactionInResponse.document_id, billId));
109
+ resolvedVendorId != null &&
110
+ vendorInResponse != null) {
111
+ fetchActions.push(fetchDuplicateBill(vendorInResponse.vendor_name, resolvedVendorId, transactionInResponse.total_amount, transactionInResponse.recipient_total_amount, transactionInResponse.document_id, billId));
107
112
  }
108
113
  const billHasPaymentError = [
109
114
  'failed',