@zeniai/client-epic-state 5.1.4 → 5.1.5-betaML1

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 (87) hide show
  1. package/lib/entity/company/companyPayload.d.ts +4 -0
  2. package/lib/entity/company/companyPayload.js +6 -0
  3. package/lib/entity/company/companyStateTypes.d.ts +7 -0
  4. package/lib/entity/paymentAccount/paymentAccountSelector.d.ts +1 -0
  5. package/lib/entity/paymentAccount/paymentAccountSelector.js +9 -0
  6. package/lib/entity/tenant/epic/deleteConnectionEpic.d.ts +1 -1
  7. package/lib/entity/tenant/epic/initEmailConnectOAuthEpic.d.ts +21 -0
  8. package/lib/entity/tenant/epic/initEmailConnectOAuthEpic.js +59 -0
  9. package/lib/entity/tenant/epic/saveAPIKeyConnectionEpic.d.ts +1 -1
  10. package/lib/entity/tenant/epic/saveConnectorCredentialsEpic.d.ts +3 -3
  11. package/lib/entity/tenant/epic/saveOAuthConnectionEpic.d.ts +1 -1
  12. package/lib/entity/tenant/tenantPayload.d.ts +1 -0
  13. package/lib/entity/tenant/tenantReducer.d.ts +38 -25
  14. package/lib/entity/tenant/tenantReducer.js +65 -5
  15. package/lib/entity/tenant/tenantState.d.ts +1 -0
  16. package/lib/entity/transaction/payloadTypes/transactionPayload.d.ts +2 -0
  17. package/lib/entity/transaction/payloadTypes/transactionPayload.js +1 -0
  18. package/lib/entity/transaction/stateTypes/transaction.d.ts +2 -0
  19. package/lib/epic.d.ts +6 -1
  20. package/lib/epic.js +7 -1
  21. package/lib/esm/entity/company/companyPayload.js +6 -0
  22. package/lib/esm/entity/paymentAccount/paymentAccountSelector.js +8 -0
  23. package/lib/esm/entity/tenant/epic/initEmailConnectOAuthEpic.js +55 -0
  24. package/lib/esm/entity/tenant/tenantReducer.js +63 -3
  25. package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +1 -0
  26. package/lib/esm/epic.js +7 -1
  27. package/lib/esm/index.js +11 -7
  28. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/backgroundRefetchReviewTabEpic.js +7 -1
  29. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +1 -1
  30. package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +1 -0
  31. package/lib/esm/view/fileView/epic/deleteFileEpic.js +2 -2
  32. package/lib/esm/view/fileView/epic/deleteFileListEpic.js +2 -2
  33. package/lib/esm/view/onboardingView/customerView/epic/aiAgentsActivation/fetchAiAgentsActivationStatusEpic.js +40 -0
  34. package/lib/esm/view/onboardingView/customerView/epic/customerDetails/acknowledgeOnboardingAiActivationViewedEpic.js +29 -0
  35. package/lib/esm/view/onboardingView/customerView/epic/customerDetails/acknowledgeOnboardingAiFinanceTeamEpic.js +40 -0
  36. package/lib/esm/view/onboardingView/customerView/epic/customerDetails/updateOnboardingCustomerViewEpic.js +24 -18
  37. package/lib/esm/view/onboardingView/customerView/epic/customerDetails/updateOnboardingCustomerViewLocalStoreDataEpic.js +29 -17
  38. package/lib/esm/view/onboardingView/customerView/onboardingCustomerViewReducer.js +223 -51
  39. package/lib/esm/view/onboardingView/customerView/onboardingCustomerViewSelector.js +24 -12
  40. package/lib/esm/view/onboardingView/customerView/onboardingCustomerViewState.js +37 -6
  41. package/lib/esm/view/spendManagement/commonSetup/epic/setup/parseUploadedKybDocumentEpic.js +58 -0
  42. package/lib/esm/view/spendManagement/commonSetup/epic/setup/parseUploadedKycDocumentEpic.js +77 -0
  43. package/lib/esm/view/spendManagement/commonSetup/kycKybAutofillActions.js +14 -0
  44. package/lib/esm/view/spendManagement/commonSetup/kycKybParseMapper.js +207 -0
  45. package/lib/esm/view/spendManagement/commonSetup/setupViewReducer.js +106 -52
  46. package/lib/esm/view/spendManagement/commonSetup/setupViewSelector.js +6 -1
  47. package/lib/esm/view/spendManagement/commonSetup/types/kycKybAutofill.js +41 -0
  48. package/lib/index.d.ts +14 -10
  49. package/lib/index.js +64 -35
  50. package/lib/view/expenseAutomationView/epics/transactionCategorization/backgroundRefetchReviewTabEpic.js +7 -1
  51. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +1 -1
  52. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +1 -0
  53. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +2 -0
  54. package/lib/view/fileView/epic/deleteFileEpic.js +1 -1
  55. package/lib/view/fileView/epic/deleteFileListEpic.js +1 -1
  56. package/lib/view/onboardingView/customerView/epic/aiAgentsActivation/fetchAiAgentsActivationStatusEpic.d.ts +7 -0
  57. package/lib/view/onboardingView/customerView/epic/aiAgentsActivation/fetchAiAgentsActivationStatusEpic.js +44 -0
  58. package/lib/view/onboardingView/customerView/epic/customerDetails/acknowledgeOnboardingAiActivationViewedEpic.d.ts +8 -0
  59. package/lib/view/onboardingView/customerView/epic/customerDetails/acknowledgeOnboardingAiActivationViewedEpic.js +33 -0
  60. package/lib/view/onboardingView/customerView/epic/customerDetails/acknowledgeOnboardingAiFinanceTeamEpic.d.ts +9 -0
  61. package/lib/view/onboardingView/customerView/epic/customerDetails/acknowledgeOnboardingAiFinanceTeamEpic.js +44 -0
  62. package/lib/view/onboardingView/customerView/epic/customerDetails/updateOnboardingCustomerViewEpic.js +24 -18
  63. package/lib/view/onboardingView/customerView/epic/customerDetails/updateOnboardingCustomerViewLocalStoreDataEpic.d.ts +2 -2
  64. package/lib/view/onboardingView/customerView/epic/customerDetails/updateOnboardingCustomerViewLocalStoreDataEpic.js +27 -15
  65. package/lib/view/onboardingView/customerView/onboardingCustomerViewPayload.d.ts +3 -0
  66. package/lib/view/onboardingView/customerView/onboardingCustomerViewReducer.d.ts +44 -5
  67. package/lib/view/onboardingView/customerView/onboardingCustomerViewReducer.js +225 -52
  68. package/lib/view/onboardingView/customerView/onboardingCustomerViewSelector.d.ts +6 -1
  69. package/lib/view/onboardingView/customerView/onboardingCustomerViewSelector.js +27 -12
  70. package/lib/view/onboardingView/customerView/onboardingCustomerViewState.d.ts +52 -8
  71. package/lib/view/onboardingView/customerView/onboardingCustomerViewState.js +39 -7
  72. package/lib/view/spendManagement/commonSetup/epic/setup/parseUploadedKybDocumentEpic.d.ts +28 -0
  73. package/lib/view/spendManagement/commonSetup/epic/setup/parseUploadedKybDocumentEpic.js +62 -0
  74. package/lib/view/spendManagement/commonSetup/epic/setup/parseUploadedKycDocumentEpic.d.ts +9 -0
  75. package/lib/view/spendManagement/commonSetup/epic/setup/parseUploadedKycDocumentEpic.js +81 -0
  76. package/lib/view/spendManagement/commonSetup/kycKybAutofillActions.d.ts +24 -0
  77. package/lib/view/spendManagement/commonSetup/kycKybAutofillActions.js +17 -0
  78. package/lib/view/spendManagement/commonSetup/kycKybParseMapper.d.ts +29 -0
  79. package/lib/view/spendManagement/commonSetup/kycKybParseMapper.js +215 -0
  80. package/lib/view/spendManagement/commonSetup/setupViewReducer.d.ts +28 -2
  81. package/lib/view/spendManagement/commonSetup/setupViewReducer.js +107 -53
  82. package/lib/view/spendManagement/commonSetup/setupViewSelector.d.ts +7 -2
  83. package/lib/view/spendManagement/commonSetup/setupViewSelector.js +6 -1
  84. package/lib/view/spendManagement/commonSetup/setupViewState.d.ts +19 -0
  85. package/lib/view/spendManagement/commonSetup/types/kycKybAutofill.d.ts +154 -0
  86. package/lib/view/spendManagement/commonSetup/types/kycKybAutofill.js +46 -0
  87. package/package.json +1 -1
@@ -1,5 +1,7 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
2
  import { date } from '../../../zeniDayJS';
3
+ import { parseUploadedKybDocument, parseUploadedKybDocumentFailure, parseUploadedKycDocument, parseUploadedKycDocumentFailure, } from '../../spendManagement/commonSetup/kycKybAutofillActions';
4
+ import { emptyAiAgentsActivationSubview, } from './onboardingCustomerViewState';
3
5
  const initialStatus = {
4
6
  fetchState: 'Not-Started',
5
7
  error: undefined,
@@ -8,62 +10,33 @@ export const initialState = {
8
10
  updateStatus: initialStatus,
9
11
  saveStatus: initialStatus,
10
12
  dashboardLoadedStatus: initialStatus,
11
- currentStep: 'link_payment_account',
13
+ currentStep: 'setup_billing',
14
+ currentSubStep: 'default',
15
+ parsingDocumentFileIds: [],
12
16
  companyDetails: {
17
+ autoFilledFields: [],
13
18
  localData: undefined,
14
19
  },
15
- companyOfficerUpdateStatus: {
16
- Officer_1: {
20
+ companyOfficerUpdateStatus: (() => {
21
+ const emptyOfficerSlot = {
22
+ autoFilledFields: [],
17
23
  localData: undefined,
18
24
  sendOtpStatus: initialStatus,
19
25
  otpverificationStatus: initialStatus,
20
- },
21
- Officer_2: {
22
- localData: undefined,
23
- sendOtpStatus: initialStatus,
24
- otpverificationStatus: initialStatus,
25
- },
26
- Officer_3: {
27
- localData: undefined,
28
- sendOtpStatus: initialStatus,
29
- otpverificationStatus: initialStatus,
30
- },
31
- Officer_4: {
32
- localData: undefined,
33
- sendOtpStatus: initialStatus,
34
- otpverificationStatus: initialStatus,
35
- },
36
- Officer_5: {
37
- localData: undefined,
38
- sendOtpStatus: initialStatus,
39
- otpverificationStatus: initialStatus,
40
- },
41
- Officer_6: {
42
- localData: undefined,
43
- sendOtpStatus: initialStatus,
44
- otpverificationStatus: initialStatus,
45
- },
46
- Officer_7: {
47
- localData: undefined,
48
- sendOtpStatus: initialStatus,
49
- otpverificationStatus: initialStatus,
50
- },
51
- Officer_8: {
52
- localData: undefined,
53
- sendOtpStatus: initialStatus,
54
- otpverificationStatus: initialStatus,
55
- },
56
- Officer_9: {
57
- localData: undefined,
58
- sendOtpStatus: initialStatus,
59
- otpverificationStatus: initialStatus,
60
- },
61
- Officer_10: {
62
- localData: undefined,
63
- sendOtpStatus: initialStatus,
64
- otpverificationStatus: initialStatus,
65
- },
66
- },
26
+ };
27
+ return {
28
+ Officer_1: { ...emptyOfficerSlot },
29
+ Officer_2: { ...emptyOfficerSlot },
30
+ Officer_3: { ...emptyOfficerSlot },
31
+ Officer_4: { ...emptyOfficerSlot },
32
+ Officer_5: { ...emptyOfficerSlot },
33
+ Officer_6: { ...emptyOfficerSlot },
34
+ Officer_7: { ...emptyOfficerSlot },
35
+ Officer_8: { ...emptyOfficerSlot },
36
+ Officer_9: { ...emptyOfficerSlot },
37
+ Officer_10: { ...emptyOfficerSlot },
38
+ };
39
+ })(),
67
40
  primaryContactDetails: {},
68
41
  paymentAccountDetails: {
69
42
  fetchStatus: initialStatus,
@@ -91,6 +64,7 @@ export const initialState = {
91
64
  },
92
65
  fetchState: 'Not-Started',
93
66
  error: undefined,
67
+ aiAgentsActivation: { ...emptyAiAgentsActivationSubview },
94
68
  uiState: {
95
69
  isQBOPopupOpen: false,
96
70
  isCardPaymentPopupOpen: false,
@@ -143,6 +117,9 @@ const onboardingCustomerView = createSlice({
143
117
  updateCurrentStep(draft, action) {
144
118
  draft.currentStep = action.payload.step;
145
119
  },
120
+ updateCurrentSubStep(draft, action) {
121
+ draft.currentSubStep = action.payload.subStep;
122
+ },
146
123
  updateOnboardingCustomerViewAccountDetails: {
147
124
  prepare(paymentAccountIds, subscriptionPaymentAccountIds) {
148
125
  return { payload: { paymentAccountIds, subscriptionPaymentAccountIds } };
@@ -180,6 +157,126 @@ const onboardingCustomerView = createSlice({
180
157
  };
181
158
  },
182
159
  },
160
+ acknowledgeOnboardingAiFinanceTeam: {
161
+ reducer(draft) {
162
+ draft.aiFinanceTeamAcknowledgementStatus = {
163
+ fetchState: 'In-Progress',
164
+ error: undefined,
165
+ };
166
+ },
167
+ prepare(companyId) {
168
+ return {
169
+ payload: { companyId },
170
+ };
171
+ },
172
+ },
173
+ acknowledgeOnboardingAiFinanceTeamSuccess(draft) {
174
+ draft.aiFinanceTeamAcknowledgementStatus = {
175
+ fetchState: 'Completed',
176
+ error: undefined,
177
+ };
178
+ },
179
+ acknowledgeOnboardingAiFinanceTeamFailure: {
180
+ reducer(draft, action) {
181
+ draft.aiFinanceTeamAcknowledgementStatus = {
182
+ fetchState: 'Error',
183
+ error: action.payload,
184
+ };
185
+ },
186
+ prepare(error) {
187
+ return {
188
+ payload: error,
189
+ };
190
+ },
191
+ },
192
+ acknowledgeOnboardingAiActivationViewed: {
193
+ reducer(draft) {
194
+ draft.aiActivationViewedAcknowledgementStatus = {
195
+ fetchState: 'In-Progress',
196
+ error: undefined,
197
+ };
198
+ },
199
+ prepare(companyId) {
200
+ return {
201
+ payload: { companyId },
202
+ };
203
+ },
204
+ },
205
+ acknowledgeOnboardingAiActivationViewedSuccess(draft) {
206
+ draft.aiActivationViewedAcknowledgementStatus = {
207
+ fetchState: 'Completed',
208
+ error: undefined,
209
+ };
210
+ },
211
+ acknowledgeOnboardingAiActivationViewedFailure: {
212
+ reducer(draft, action) {
213
+ draft.aiActivationViewedAcknowledgementStatus = {
214
+ fetchState: 'Error',
215
+ error: action.payload,
216
+ };
217
+ },
218
+ prepare(error) {
219
+ return {
220
+ payload: error,
221
+ };
222
+ },
223
+ },
224
+ fetchAiAgentsActivationStatus(draft) {
225
+ draft.aiAgentsActivation.fetchStatus = {
226
+ fetchState: 'In-Progress',
227
+ error: undefined,
228
+ };
229
+ },
230
+ fetchAiAgentsActivationStatusSuccess: {
231
+ reducer(draft, action) {
232
+ draft.aiAgentsActivation.fetchStatus = {
233
+ fetchState: 'Completed',
234
+ error: undefined,
235
+ };
236
+ draft.aiAgentsActivation.phases = action.payload.phases;
237
+ draft.aiAgentsActivation.counts = action.payload.counts;
238
+ },
239
+ prepare(payload) {
240
+ return { payload };
241
+ },
242
+ },
243
+ fetchAiAgentsActivationStatusFailure: {
244
+ reducer(draft, action) {
245
+ draft.aiAgentsActivation.fetchStatus = {
246
+ fetchState: 'Error',
247
+ error: action.payload,
248
+ };
249
+ },
250
+ prepare(error) {
251
+ return { payload: error };
252
+ },
253
+ },
254
+ aiAgentsActivationCountsUpdated: {
255
+ reducer(draft, action) {
256
+ draft.aiAgentsActivation.counts = {
257
+ ...draft.aiAgentsActivation.counts,
258
+ ...action.payload,
259
+ };
260
+ },
261
+ prepare(payload) {
262
+ return { payload };
263
+ },
264
+ },
265
+ aiAgentsActivationPhaseChanged: {
266
+ reducer(draft, action) {
267
+ const target = draft.aiAgentsActivation.phases;
268
+ const index = target.findIndex((phase) => phase.key === action.payload.key);
269
+ if (index === -1) {
270
+ target.push(action.payload);
271
+ }
272
+ else {
273
+ target[index] = { ...target[index], ...action.payload };
274
+ }
275
+ },
276
+ prepare(payload) {
277
+ return { payload };
278
+ },
279
+ },
183
280
  updateOnboardingCustomerViewDashboardLoaded: {
184
281
  reducer(draft) {
185
282
  draft.dashboardLoadedStatus = {
@@ -592,7 +689,82 @@ const onboardingCustomerView = createSlice({
592
689
  clearOnboardingCustomerView(draft) {
593
690
  Object.assign(draft, initialState);
594
691
  },
692
+ /** Merge AI-parsed officer fields into the officer's onboarding localData. */
693
+ applyKycDocumentAutofillForOnboarding: {
694
+ reducer(draft, action) {
695
+ const { officerType, values, autoFilledFieldNames, fileId } = action.payload;
696
+ const slot = draft.companyOfficerUpdateStatus[officerType];
697
+ slot.localData = Object.assign({}, slot.localData, values);
698
+ slot.autoFilledFields = Array.from(new Set([...(slot.autoFilledFields ?? []), ...autoFilledFieldNames]));
699
+ draft.parsingDocumentFileIds = (draft.parsingDocumentFileIds ?? []).filter((id) => id !== fileId);
700
+ },
701
+ prepare(payload) {
702
+ return { payload };
703
+ },
704
+ },
705
+ /** Merge AI-parsed company fields into companyDetails onboarding localData. */
706
+ applyKybDocumentAutofillForOnboarding: {
707
+ reducer(draft, action) {
708
+ const { values, autoFilledFieldNames, fileId } = action.payload;
709
+ draft.companyDetails.localData = Object.assign({}, draft.companyDetails.localData, values);
710
+ const prev = draft.companyDetails.autoFilledFields ?? [];
711
+ draft.companyDetails.autoFilledFields = Array.from(new Set([...prev, ...autoFilledFieldNames]));
712
+ draft.parsingDocumentFileIds = (draft.parsingDocumentFileIds ?? []).filter((id) => id !== fileId);
713
+ },
714
+ prepare(payload) {
715
+ return { payload };
716
+ },
717
+ },
718
+ /** Wipe AI-autofill badges during onboarding. */
719
+ clearKycKybAutofillForOnboarding: {
720
+ reducer(draft, action) {
721
+ const { officerType } = action.payload;
722
+ if (officerType != null) {
723
+ draft.companyOfficerUpdateStatus[officerType].autoFilledFields = [];
724
+ }
725
+ else {
726
+ draft.companyDetails.autoFilledFields = [];
727
+ Object.keys(draft.companyOfficerUpdateStatus).forEach((key) => {
728
+ draft.companyOfficerUpdateStatus[key].autoFilledFields = [];
729
+ });
730
+ }
731
+ },
732
+ prepare(payload = {}) {
733
+ return { payload };
734
+ },
735
+ },
736
+ },
737
+ extraReducers: (builder) => {
738
+ const addParsingFileId = (draft, fileId) => {
739
+ draft.parsingDocumentFileIds = draft.parsingDocumentFileIds ?? [];
740
+ if (!draft.parsingDocumentFileIds.includes(fileId)) {
741
+ draft.parsingDocumentFileIds.push(fileId);
742
+ }
743
+ };
744
+ const removeParsingFileId = (draft, fileId) => {
745
+ draft.parsingDocumentFileIds = (draft.parsingDocumentFileIds ?? []).filter((id) => id !== fileId);
746
+ };
747
+ builder.addCase(parseUploadedKycDocument, (draft, action) => {
748
+ if (action.payload.target === 'onboarding') {
749
+ addParsingFileId(draft, action.payload.fileId);
750
+ }
751
+ });
752
+ builder.addCase(parseUploadedKybDocument, (draft, action) => {
753
+ if (action.payload.target === 'onboarding') {
754
+ addParsingFileId(draft, action.payload.fileId);
755
+ }
756
+ });
757
+ builder.addCase(parseUploadedKycDocumentFailure, (draft, action) => {
758
+ if (action.payload.target === 'onboarding') {
759
+ removeParsingFileId(draft, action.payload.fileId);
760
+ }
761
+ });
762
+ builder.addCase(parseUploadedKybDocumentFailure, (draft, action) => {
763
+ if (action.payload.target === 'onboarding') {
764
+ removeParsingFileId(draft, action.payload.fileId);
765
+ }
766
+ });
595
767
  },
596
768
  });
597
- export const { fetchOnboardingCustomerView, fetchOnboardingCustomerSetupView, fetchOnboardingCustomerSetupViewSuccess, fetchOnboardingCustomerSetupViewFailure, updateOnboardingCustomerViewCompleteStatus, updateOnboardingCustomerViewCompleteStatusSuccess, updateOnboardingCustomerViewCompleteStatusFailure, updateOnboardingCustomerViewDashboardLoaded, updateOnboardingCustomerViewDashboardLoadedSuccess, updateOnboardingCustomerViewDashboardLoadedFailure, updateOnboardingCustomerView, updateOnboardingCustomerViewSuccess, updateOnboardingCustomerViewFailure, updateOnboardingPaymentAccountStatus, updateOnboardingPaymentAccountStatusSuccess, updateOnboardingPaymentAccountStatusFailure, updateOnboardingPaymentAccountLoginStatus, updateOnboardingPaymentAccountLoginStatusSuccess, updateOnboardingPaymentAccountLoginStatusFailure, establishOnboardingPlaidConnection, establishOnboardingPlaidConnectionSuccess, establishOnboardingPlaidConnectionFailure, getOnboardingPlaidLinkToken, getOnboardingPlaidLinkTokenSuccess, getOnboardingPlaidLinkTokenFailure, updateCurrentStep, updateOnboardingCustomerViewAccountDetails, updateOnboardingCustomerViewLocalStoreData, saveOnboardingCustomerViewDataInLocalStore, saveOnboardingCompnayOfficerPhoneInLocalStore, updateOnboardingCustomerViewUIState, sendOnboardingOfficerOtp, sendOnboardingOfficerOtpSuccess, sendOnboardingOfficerOtpFailure, resendOnboardingOfficerOtp, verifyOnboardingOfficerOtp, verifyOnboardingOfficerOtpSuccess, verifyOnboardingOfficerOtpFailure, clearOnboardingCustomerViewDataInLocalStore, clearOnboardingCustomerView, } = onboardingCustomerView.actions;
769
+ export const { fetchOnboardingCustomerView, fetchOnboardingCustomerSetupView, fetchOnboardingCustomerSetupViewSuccess, fetchOnboardingCustomerSetupViewFailure, updateOnboardingCustomerViewCompleteStatus, updateOnboardingCustomerViewCompleteStatusSuccess, updateOnboardingCustomerViewCompleteStatusFailure, acknowledgeOnboardingAiFinanceTeam, acknowledgeOnboardingAiFinanceTeamSuccess, acknowledgeOnboardingAiFinanceTeamFailure, acknowledgeOnboardingAiActivationViewed, acknowledgeOnboardingAiActivationViewedSuccess, acknowledgeOnboardingAiActivationViewedFailure, fetchAiAgentsActivationStatus, fetchAiAgentsActivationStatusSuccess, fetchAiAgentsActivationStatusFailure, aiAgentsActivationCountsUpdated, aiAgentsActivationPhaseChanged, updateOnboardingCustomerViewDashboardLoaded, updateOnboardingCustomerViewDashboardLoadedSuccess, updateOnboardingCustomerViewDashboardLoadedFailure, updateOnboardingCustomerView, updateOnboardingCustomerViewSuccess, updateOnboardingCustomerViewFailure, updateOnboardingPaymentAccountStatus, updateOnboardingPaymentAccountStatusSuccess, updateOnboardingPaymentAccountStatusFailure, updateOnboardingPaymentAccountLoginStatus, updateOnboardingPaymentAccountLoginStatusSuccess, updateOnboardingPaymentAccountLoginStatusFailure, establishOnboardingPlaidConnection, establishOnboardingPlaidConnectionSuccess, establishOnboardingPlaidConnectionFailure, getOnboardingPlaidLinkToken, getOnboardingPlaidLinkTokenSuccess, getOnboardingPlaidLinkTokenFailure, updateCurrentStep, updateCurrentSubStep, updateOnboardingCustomerViewAccountDetails, updateOnboardingCustomerViewLocalStoreData, saveOnboardingCustomerViewDataInLocalStore, saveOnboardingCompnayOfficerPhoneInLocalStore, updateOnboardingCustomerViewUIState, sendOnboardingOfficerOtp, sendOnboardingOfficerOtpSuccess, sendOnboardingOfficerOtpFailure, resendOnboardingOfficerOtp, verifyOnboardingOfficerOtp, verifyOnboardingOfficerOtpSuccess, verifyOnboardingOfficerOtpFailure, clearOnboardingCustomerViewDataInLocalStore, clearOnboardingCustomerView, applyKycDocumentAutofillForOnboarding, applyKybDocumentAutofillForOnboarding, clearKycKybAutofillForOnboarding, } = onboardingCustomerView.actions;
598
770
  export default onboardingCustomerView.reducer;
@@ -8,10 +8,10 @@ import { getUserRoleByUserIds } from '../../../entity/userRole/userRoleSelector'
8
8
  import { getCompanyConfig } from '../../companyConfigView/companyConfigSelector';
9
9
  import { getCompanyView } from '../../companyView/selectorHelpers/getCompanyView';
10
10
  import { getCompanyAndIdentityDetails, } from '../../spendManagement/commonSetup/setupViewSelector';
11
- import { ALL_ONBOARDING_STEPS, ALL_ZENI_USER_ONBOARDING_STEPS, REQUIRED_ONBOARDING_STEPS, ZENI_USER_REQUIRED_ONBOARDING_STEPS, toOnboardingStepType, } from './onboardingCustomerViewState';
11
+ import { ALL_ONBOARDING_STEPS, ALL_ZENI_USER_ONBOARDING_STEPS, REQUIRED_ONBOARDING_STEPS, ZENI_USER_REQUIRED_ONBOARDING_STEPS, emptyAiAgentsActivationSubview, toOnboardingStepType, } from './onboardingCustomerViewState';
12
12
  export function getOnboardingCustomerView(state, companyId) {
13
13
  const { fileState, paymentAccountState, onboardingCustomerViewState, userState, userRoleState, subscriptionPaymentAccountState, companyConfigState, cardPaymentViewState, countryListState, addressViewState, } = state;
14
- const { companyDetails, companyOfficerUpdateStatus, primaryContactDetails, subscriptionPaymentAccountIds, paymentAccountDetails, plaidConnectionDetails, updateStatus, saveStatus, currentStep, uiState, fetchState, error, } = onboardingCustomerViewState;
14
+ const { companyDetails, companyOfficerUpdateStatus, primaryContactDetails, subscriptionPaymentAccountIds, paymentAccountDetails, plaidConnectionDetails, parsingDocumentFileIds, updateStatus, saveStatus, currentStep, currentSubStep, uiState, fetchState, error, } = onboardingCustomerViewState;
15
15
  const { paymentAccountIds } = paymentAccountDetails;
16
16
  let subscriptionPaymentAccount;
17
17
  let paymentAccount;
@@ -54,6 +54,7 @@ export function getOnboardingCustomerView(state, companyId) {
54
54
  companyDetails,
55
55
  companyOfficerUpdateStatus,
56
56
  primaryContactDetails,
57
+ parsingDocumentFileIds,
57
58
  });
58
59
  const companyAddress = addressViewState.newAddressState?.company_address;
59
60
  if (companyAddress == null &&
@@ -73,7 +74,7 @@ export function getOnboardingCustomerView(state, companyId) {
73
74
  cardPaymentViewState.cardPaymentsIds.length > 0) &&
74
75
  companyView?.company.company.companyOnboardingInfo
75
76
  .subscriptionBillingAddressId != null) {
76
- completedSteps.push('link_payment_account');
77
+ completedSteps.push('setup_billing');
77
78
  }
78
79
  const isPaymentVerified = (paymentAccount?.providerVerificationStatus?.code?.includes('verified') ===
79
80
  true &&
@@ -84,24 +85,25 @@ export function getOnboardingCustomerView(state, companyId) {
84
85
  .subscriptionBillingAddressId != null;
85
86
  if ((isPaymentVerified || hasSubscriptionBillingAddress) &&
86
87
  !(isPaymentVerified && hasSubscriptionBillingAddress)) {
87
- halfCompletedSteps.push('link_payment_account');
88
+ halfCompletedSteps.push('setup_billing');
88
89
  }
89
90
  const isValidConnection = externalConnections?.accounting[0]?.isValid ?? false;
90
91
  if (isValidConnection) {
91
- completedSteps.push('qbo_connection');
92
+ completedSteps.push('connect_ledger');
92
93
  }
93
- if (companyDetails.localData != null &&
94
+ const isCompanyDetailsDone = companyDetails.localData != null &&
94
95
  primaryContactDetails.localData != null &&
95
- isCompanyDetailsCompleted(fileState, companyView, primaryContact)) {
96
- completedSteps.push('company_details');
97
- }
96
+ isCompanyDetailsCompleted(fileState, companyView, primaryContact);
98
97
  const officerIndex = companyOfficers.length > 0
99
98
  ? Object.values(companyOfficerLocalData).findIndex((officer) => officer?.isSelectedForVerification === true)
100
99
  : 0;
101
100
  const selectedOfficerType = `Officer_${officerIndex < 0 ? 1 : officerIndex + 1}`;
102
- if (companyOfficerLocalData[selectedOfficerType] != null &&
103
- isOfficerDetailsCompleted(companyOfficers, companyOfficerRoles, companyOfficerLocalData[selectedOfficerType], fileState)) {
104
- completedSteps.push('company_officer');
101
+ const isOfficerDone = companyOfficerLocalData[selectedOfficerType] != null &&
102
+ isOfficerDetailsCompleted(companyOfficers, companyOfficerRoles, companyOfficerLocalData[selectedOfficerType], fileState);
103
+ // The verification step (single sidebar step) is only "complete" once both
104
+ // the company-officer and company-details sub-steps are fully filled in.
105
+ if (isCompanyDetailsDone && isOfficerDone) {
106
+ completedSteps.push('verification');
105
107
  }
106
108
  const { allStepsData, requiredStepsData } = onboardingStepsData(isValidConnection, currentTenant?.productSettings ?? [], accountingConnectionCreationMode);
107
109
  const allRequiredStepsCompleted = requiredStepsData.every((step) => {
@@ -119,6 +121,7 @@ export function getOnboardingCustomerView(state, companyId) {
119
121
  return {
120
122
  companyDetailsLocalData,
121
123
  companyOfficerLocalData,
124
+ parsingDocumentFileIds,
122
125
  subscriptionBillingAddress: subscriptionBillingAddress?.addressToCreate,
123
126
  companyView,
124
127
  allNationalityCountries,
@@ -127,6 +130,7 @@ export function getOnboardingCustomerView(state, companyId) {
127
130
  officer: isOfficerDetailsSavePending(companyOfficers, companyOfficerRoles, fileState, companyOfficerLocalData[selectedOfficerType]),
128
131
  },
129
132
  currentStep,
133
+ currentSubStep,
130
134
  completedSteps,
131
135
  halfCompletedSteps,
132
136
  allRequiredStepsCompleted,
@@ -323,3 +327,11 @@ export const getProductSettingsString = (productSettings) => {
323
327
  .map((key) => productKeyMap[key])
324
328
  .join(',');
325
329
  };
330
+ const fromActivationView = (state) =>
331
+ // Fall back to the empty subview so state hydrated from an older persisted
332
+ // version (before aiAgentsActivation existed) doesn't crash on .phases/.counts.
333
+ state.onboardingCustomerViewState.aiAgentsActivation ??
334
+ emptyAiAgentsActivationSubview;
335
+ export const getAiAgentsActivationSubview = (state) => fromActivationView(state);
336
+ export const getAiAgentsActivationPhases = (state) => fromActivationView(state).phases;
337
+ export const getAiAgentsActivationCounts = (state) => fromActivationView(state).counts;
@@ -1,17 +1,18 @@
1
1
  import { stringToUnion } from '../../../commonStateTypes/stringToUnion';
2
- export const ZENI_USER_REQUIRED_ONBOARDING_STEPS = [
3
- 'link_payment_account',
4
- ];
2
+ // Onboarding steps are the 4 top-level surfaces. Officer + details verification
3
+ // live as sub-steps under `verification` (state machine in CustomerOnboardingPage).
4
+ // The optional data-source step is its own surface; the legacy connect-data-source
5
+ // sub-step under the old `qbo_connection` no longer exists.
6
+ export const ZENI_USER_REQUIRED_ONBOARDING_STEPS = ['setup_billing'];
5
7
  export const CUSTOMER_REQUIRED_ONBOARDING_STEPS_WITH_QBO = [
6
- 'qbo_connection',
8
+ 'connect_ledger',
7
9
  ];
8
10
  export const REQUIRED_ONBOARDING_STEPS = [
9
11
  ...ZENI_USER_REQUIRED_ONBOARDING_STEPS,
10
12
  ...CUSTOMER_REQUIRED_ONBOARDING_STEPS_WITH_QBO,
11
13
  ];
12
14
  export const ALL_ZENI_USER_ONBOARDING_STEPS_WITHOUT_ACCOUNT = [
13
- 'company_officer',
14
- 'company_details',
15
+ 'verification',
15
16
  ];
16
17
  export const ALL_ZENI_USER_ONBOARDING_STEPS = [
17
18
  ...ZENI_USER_REQUIRED_ONBOARDING_STEPS,
@@ -19,10 +20,40 @@ export const ALL_ZENI_USER_ONBOARDING_STEPS = [
19
20
  ];
20
21
  export const ALL_CUSTOMER_ONBOARDING_STEPS_WITH_QBO = [
21
22
  ...CUSTOMER_REQUIRED_ONBOARDING_STEPS_WITH_QBO,
23
+ 'connect_data_source',
22
24
  ...ALL_ZENI_USER_ONBOARDING_STEPS_WITHOUT_ACCOUNT,
23
25
  ];
24
26
  export const ALL_ONBOARDING_STEPS = [
25
27
  ...REQUIRED_ONBOARDING_STEPS,
28
+ 'connect_data_source',
26
29
  ...ALL_ZENI_USER_ONBOARDING_STEPS_WITHOUT_ACCOUNT,
27
30
  ];
28
31
  export const toOnboardingStepType = (v) => stringToUnion(v, ALL_ONBOARDING_STEPS);
32
+ // Per-step sub-state. Lives in Redux so the save epic can tell, for example,
33
+ // an officer-form save from a company-details save while both share
34
+ // currentStep = 'verification'.
35
+ // - 'default' generic landing sub-state.
36
+ // - 'ai-activating' connect_ledger interstitial during AI activation.
37
+ // - 'unlock-stack' verification landing — VerifyUnlockFinancialStackPage.
38
+ // - 'company_officer' verification → officer form.
39
+ // - 'company_details' verification → company details form.
40
+ export const ALL_ONBOARDING_SUB_STEPS = [
41
+ 'default',
42
+ 'ai-activating',
43
+ 'unlock-stack',
44
+ 'company_officer',
45
+ 'company_details',
46
+ ];
47
+ export const toOnboardingSubStepType = (v) => stringToUnion(v, ALL_ONBOARDING_SUB_STEPS);
48
+ export const emptyAiAgentsActivationCounts = {
49
+ customerCount: 0,
50
+ glAccountCount: 0,
51
+ targetTransactionCount: 0,
52
+ transactionCount: 0,
53
+ vendorCount: 0,
54
+ };
55
+ export const emptyAiAgentsActivationSubview = {
56
+ counts: emptyAiAgentsActivationCounts,
57
+ fetchStatus: { fetchState: 'Not-Started', error: undefined },
58
+ phases: [],
59
+ };
@@ -0,0 +1,58 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { isSuccessResponse } from '../../../../../responsePayload';
4
+ import { applyKybDocumentAutofillForOnboarding } from '../../../../onboardingView/customerView/onboardingCustomerViewReducer';
5
+ import { parseUploadedKybDocument, parseUploadedKybDocumentFailure, } from '../../kycKybAutofillActions';
6
+ import { mapCoiToCompanyDetails, mapTaxEinToCompanyDetails, } from '../../kycKybParseMapper';
7
+ import { applyKybDocumentAutofillForSetup } from '../../setupViewReducer';
8
+ const PROCESS_DOCUMENT_SYNC_PATH = '/1.0/documents/process/sync';
9
+ export const parseUploadedKybDocumentEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(parseUploadedKybDocument.match), mergeMap((action) => {
10
+ const { target, companyId, fileId, documentType } = action.payload;
11
+ const url = `${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}${PROCESS_DOCUMENT_SYNC_PATH}`;
12
+ const requestPayload = {
13
+ provided_document_type: documentType,
14
+ files: [{ file_id: fileId }],
15
+ processing_priority: 10,
16
+ metadata: { source: 'kyc_kyb_autofill' },
17
+ };
18
+ const failureAction = parseUploadedKybDocumentFailure({ target, fileId });
19
+ return zeniAPI
20
+ .postAndGetJSON(url, requestPayload)
21
+ .pipe(mergeMap((response) => {
22
+ if (!isSuccessResponse(response) || response.data == null) {
23
+ return of(failureAction);
24
+ }
25
+ // Sync API returns a batch envelope: `data.files[0].extracted_data`
26
+ // is the parser payload; `data` itself is the request-level wrapper.
27
+ const extracted = response.data.files?.[0]?.extracted_data;
28
+ if (extracted == null) {
29
+ return of(failureAction);
30
+ }
31
+ let result;
32
+ switch (documentType) {
33
+ case 'certificate_of_incorporation':
34
+ result = mapCoiToCompanyDetails(extracted);
35
+ break;
36
+ case 'tax_ein':
37
+ result = mapTaxEinToCompanyDetails(extracted);
38
+ break;
39
+ }
40
+ if (result.autoFilledFieldNames.length === 0) {
41
+ return of(failureAction);
42
+ }
43
+ const applyAction = target === 'setup'
44
+ ? applyKybDocumentAutofillForSetup({
45
+ companyId,
46
+ fileId,
47
+ values: result.values,
48
+ autoFilledFieldNames: result.autoFilledFieldNames,
49
+ })
50
+ : applyKybDocumentAutofillForOnboarding({
51
+ companyId,
52
+ fileId,
53
+ values: result.values,
54
+ autoFilledFieldNames: result.autoFilledFieldNames,
55
+ });
56
+ return of(applyAction);
57
+ }), catchError(() => of(failureAction)));
58
+ }));
@@ -0,0 +1,77 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { isSuccessResponse } from '../../../../../responsePayload';
4
+ import { newAddressInLocalStore } from '../../../../addressView/addressViewReducer';
5
+ import { applyKycDocumentAutofillForOnboarding } from '../../../../onboardingView/customerView/onboardingCustomerViewReducer';
6
+ import { parseUploadedKycDocument, parseUploadedKycDocumentFailure, } from '../../kycKybAutofillActions';
7
+ import { mapDrivingLicenseToOfficer, mapPassportToOfficer, mapSsnCardToOfficer, } from '../../kycKybParseMapper';
8
+ import { applyKycDocumentAutofillForSetup } from '../../setupViewReducer';
9
+ const PROCESS_DOCUMENT_SYNC_PATH = '/1.0/documents/process/sync';
10
+ export const parseUploadedKycDocumentEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(parseUploadedKycDocument.match), mergeMap((action) => {
11
+ const { target, companyId, officerType, fileId, documentType } = action.payload;
12
+ const url = `${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}${PROCESS_DOCUMENT_SYNC_PATH}`;
13
+ const requestPayload = {
14
+ provided_document_type: documentType,
15
+ files: [{ file_id: fileId }],
16
+ processing_priority: 10,
17
+ metadata: { source: 'kyc_kyb_autofill' },
18
+ };
19
+ const failureAction = parseUploadedKycDocumentFailure({ target, fileId });
20
+ return zeniAPI
21
+ .postAndGetJSON(url, requestPayload)
22
+ .pipe(mergeMap((response) => {
23
+ if (!isSuccessResponse(response) || response.data == null) {
24
+ return of(failureAction);
25
+ }
26
+ // Sync API returns a batch envelope: `data.files[0].extracted_data`
27
+ // is the parser payload; `data` itself is the request-level wrapper
28
+ // ({request_id, status, files, metadata, ...}). Drill in before
29
+ // dispatching to the mapper.
30
+ const extracted = response.data.files?.[0]?.extracted_data;
31
+ if (extracted == null) {
32
+ return of(failureAction);
33
+ }
34
+ let result;
35
+ switch (documentType) {
36
+ case 'passport':
37
+ result = mapPassportToOfficer(extracted);
38
+ break;
39
+ case 'driving_license':
40
+ result = mapDrivingLicenseToOfficer(extracted);
41
+ break;
42
+ case 'social_security_card':
43
+ result = mapSsnCardToOfficer(extracted);
44
+ break;
45
+ }
46
+ if (result.autoFilledFieldNames.length === 0) {
47
+ return of(failureAction);
48
+ }
49
+ const applyAction = target === 'setup'
50
+ ? applyKycDocumentAutofillForSetup({
51
+ companyId,
52
+ officerType,
53
+ fileId,
54
+ values: result.values,
55
+ autoFilledFieldNames: result.autoFilledFieldNames,
56
+ })
57
+ : applyKycDocumentAutofillForOnboarding({
58
+ companyId,
59
+ officerType,
60
+ fileId,
61
+ values: result.values,
62
+ autoFilledFieldNames: result.autoFilledFieldNames,
63
+ });
64
+ const actions = [applyAction];
65
+ // Driving licenses also carry the home address, which lives in the
66
+ // addressView slice (keyed `officer_<n>_address`). Seed it so the
67
+ // section's address field + ✦ badge pick it up.
68
+ if (result.address != null) {
69
+ const addressType = `${officerType.toLowerCase()}_address`;
70
+ actions.push(newAddressInLocalStore({
71
+ addressType,
72
+ addressToCreate: result.address,
73
+ }));
74
+ }
75
+ return from(actions);
76
+ }), catchError(() => of(failureAction)));
77
+ }));
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Trigger actions for the KYC / KYB autofill epics.
3
+ *
4
+ * These actions don't mutate state — the epic listens for them, calls
5
+ * document-communication-agent's sync endpoint, and dispatches the appropriate
6
+ * `applyKyc/KybDocumentAutofillFor{Setup,Onboarding}` against the matching
7
+ * slice. Co-located with the rest of the commonSetup module because the entire
8
+ * autofill flow is auxiliary to the setup view; there is no separate state.
9
+ */
10
+ import { createAction } from '@reduxjs/toolkit';
11
+ export const parseUploadedKycDocument = createAction('commonSetup/parseUploadedKycDocument');
12
+ export const parseUploadedKybDocument = createAction('commonSetup/parseUploadedKybDocument');
13
+ export const parseUploadedKycDocumentFailure = createAction('commonSetup/parseUploadedKycDocumentFailure');
14
+ export const parseUploadedKybDocumentFailure = createAction('commonSetup/parseUploadedKybDocumentFailure');