@zeniai/client-epic-state 4.19.77-betaAK7 → 4.19.77-betaAS1

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 (36) hide show
  1. package/lib/entity/company/companyPayload.d.ts +1 -0
  2. package/lib/entity/company/companyPayload.js +1 -0
  3. package/lib/entity/company/companyStateTypes.d.ts +1 -0
  4. package/lib/esm/entity/company/companyPayload.js +1 -0
  5. package/lib/esm/view/companyView/epic/companyPassport/updateCompanyDetailsEpic.js +3 -0
  6. package/lib/esm/view/companyView/types/companyPassport/companyPassportLocalData.js +1 -0
  7. package/lib/esm/view/spendManagement/commonSetup/epic/setup/updateBusinessVerificationDetailsEpic.js +4 -1
  8. package/lib/esm/view/spendManagement/commonSetup/epic/setup/updateSetupViewLocalStoreDataEpic.js +2 -1
  9. package/lib/esm/view/spendManagement/commonSetup/setupViewSelector.js +2 -1
  10. package/lib/esm/view/transactionDetail/epics/initializeTransactionDetailLocalDataEpic.js +3 -1
  11. package/lib/esm/view/transactionDetail/epics/saveTransactionDetailEpic.js +2 -4
  12. package/lib/esm/view/transactionDetail/epics/transactionDetailEpic.js +8 -34
  13. package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +7 -12
  14. package/lib/esm/view/transactionDetail/epics/uploadMissingAttachmentSuccessEpic.js +3 -2
  15. package/lib/esm/view/transactionDetail/transactionDetailSelector.js +3 -5
  16. package/lib/esm/view/transactionDetail/transactionDetailState.js +2 -14
  17. package/lib/view/companyView/epic/companyPassport/updateCompanyDetailsEpic.js +3 -0
  18. package/lib/view/companyView/types/companyPassport/companyDetailsLocalData.d.ts +1 -0
  19. package/lib/view/companyView/types/companyPassport/companyPassportLocalData.js +1 -0
  20. package/lib/view/spendManagement/commonSetup/epic/setup/updateBusinessVerificationDetailsEpic.js +4 -1
  21. package/lib/view/spendManagement/commonSetup/epic/setup/updateSetupViewLocalStoreDataEpic.js +2 -1
  22. package/lib/view/spendManagement/commonSetup/setupViewSelector.d.ts +1 -0
  23. package/lib/view/spendManagement/commonSetup/setupViewSelector.js +2 -1
  24. package/lib/view/spendManagement/commonSetup/setupViewState.d.ts +1 -0
  25. package/lib/view/spendManagement/commonSetup/types/businessVerification.d.ts +1 -0
  26. package/lib/view/transactionDetail/epics/initializeTransactionDetailLocalDataEpic.js +3 -1
  27. package/lib/view/transactionDetail/epics/saveTransactionDetailEpic.js +2 -4
  28. package/lib/view/transactionDetail/epics/transactionDetailEpic.js +8 -34
  29. package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.d.ts +2 -2
  30. package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +6 -11
  31. package/lib/view/transactionDetail/epics/uploadMissingAttachmentSuccessEpic.js +3 -2
  32. package/lib/view/transactionDetail/transactionDetailSelector.js +3 -5
  33. package/lib/view/transactionDetail/transactionDetailState.d.ts +1 -1
  34. package/lib/view/transactionDetail/transactionDetailState.js +2 -14
  35. package/package.json +1 -1
  36. package/lib/tsconfig.typecheck.tsbuildinfo +0 -1
@@ -48,6 +48,7 @@ export interface CompanyIncInfoPayload {
48
48
  company_inc_state_code: string | null;
49
49
  company_inc_type: string | null;
50
50
  company_industry_sub_type?: string | null;
51
+ company_industry_type?: string | null;
51
52
  file_ids?: ID[] | null;
52
53
  }
53
54
  export interface CompanyTaxInfoPayload {
@@ -76,6 +76,7 @@ const toCompanyIncInfo = (payload) => ({
76
76
  companyIncCountryCode: payload.company_inc_country_code ?? undefined,
77
77
  fileIds: payload.file_ids ?? [],
78
78
  companySubIndustry: payload.company_industry_sub_type ?? undefined,
79
+ companyIndustryType: payload.company_industry_type ?? undefined,
79
80
  });
80
81
  const toCompanyTaxInfo = (payload) => ({
81
82
  taxesFiledDate: payload.taxes_filed_date != null
@@ -61,6 +61,7 @@ export interface CompanyIncInfo {
61
61
  companyIncState?: string;
62
62
  companyIncStateCode?: string;
63
63
  companyIncType?: string;
64
+ companyIndustryType?: string;
64
65
  companySubIndustry?: string;
65
66
  }
66
67
  export interface CompanyTaxInfo {
@@ -73,6 +73,7 @@ const toCompanyIncInfo = (payload) => ({
73
73
  companyIncCountryCode: payload.company_inc_country_code ?? undefined,
74
74
  fileIds: payload.file_ids ?? [],
75
75
  companySubIndustry: payload.company_industry_sub_type ?? undefined,
76
+ companyIndustryType: payload.company_industry_type ?? undefined,
76
77
  });
77
78
  const toCompanyTaxInfo = (payload) => ({
78
79
  taxesFiledDate: payload.taxes_filed_date != null
@@ -12,6 +12,9 @@ export const updateCompanyDetailsEpic = (actions$, state$, zeniAPI) => actions$.
12
12
  ...toCompanyIncInfoUpdatableInfoPayload(companyDetails.incInfo),
13
13
  ...toCompanyTaxInfoUpdatableInfoPayload(companyDetails.taxDetails),
14
14
  ...toCompanyFileInfoPayload(companyDetails.incInfo, companyDetails.taxDetails),
15
+ ...(companyDetails.companyInfo.companyIndustryType != null && {
16
+ company_industry_type: companyDetails.companyInfo.companyIndustryType,
17
+ }),
15
18
  ...(companyDetails.companyInfo.companySubIndustry != null && {
16
19
  company_industry_sub_type: companyDetails.companyInfo.companySubIndustry,
17
20
  }),
@@ -10,6 +10,7 @@ export function toCompanyPassportLocalData(companyView, companyFiles) {
10
10
  website: companyInfo.companyUrl,
11
11
  meetingLink: companyInfo.meetingUrl,
12
12
  industry: companyQuestionaire.companyIndustry,
13
+ companyIndustryType: incInfo.companyIndustryType,
13
14
  companySubIndustry: incInfo.companySubIndustry,
14
15
  businessModel: companyQuestionaire.companyBusinessModel ?? '',
15
16
  phone: companyInfo.phone ?? '',
@@ -136,7 +136,7 @@ function toUsNexusTypeKey(value) {
136
136
  return US_NEXUS_LABEL_TO_KEY[value] ?? value;
137
137
  }
138
138
  export const toBusinessVerificationCompanyDataPayload = (companyLocalData, sendForVerification, companyAddressData, registeredAddressData, setupViewType) => {
139
- const { companyDescription, companyLegalName, companyIndustry, companySubIndustry, countriesOfOperations, companySourceOfFunds, companySourceOfFundsDescription, transactionVolume, transactionVolumeDescription, purposeOfAccount, purposeOfAccountDescription, regulatedStatus, regulatedStatusDescription, usNexus, usNexusTypes, website, incDate, taxIdOrEIN, phone, syncToken, fileIds, typeOfIncorporation, stateOfIncorporation, sourceOfFunds, } = companyLocalData;
139
+ const { companyDescription, companyLegalName, companyIndustry, companyIndustryType, companySubIndustry, countriesOfOperations, companySourceOfFunds, companySourceOfFundsDescription, transactionVolume, transactionVolumeDescription, purposeOfAccount, purposeOfAccountDescription, regulatedStatus, regulatedStatusDescription, usNexus, usNexusTypes, website, incDate, taxIdOrEIN, phone, syncToken, fileIds, typeOfIncorporation, stateOfIncorporation, sourceOfFunds, } = companyLocalData;
140
140
  const company = {
141
141
  is_ready_for_verification: sendForVerification,
142
142
  file_ids: fileIds,
@@ -194,6 +194,9 @@ export const toBusinessVerificationCompanyDataPayload = (companyLocalData, sendF
194
194
  company['company_industry'] = companyIndustry;
195
195
  }
196
196
  Object.assign(company, {
197
+ ...(companyIndustryType != null && {
198
+ company_industry_type: companyIndustryType,
199
+ }),
197
200
  ...(companySubIndustry != null && {
198
201
  company_industry_sub_type: companySubIndustry,
199
202
  }),
@@ -45,13 +45,14 @@ export function toSetupViewLocalData(company, users, userRoles, primaryContact)
45
45
  const { companyInfo, incInfo, taxInfo, questionaire, companyBillPayInfo } = company;
46
46
  const { companyId, companyDescription, companyLegalName, companyUrl, phone, syncToken, sourceOfFunds, companySourceOfFunds: incCompanySourceOfFunds, companySourceOfFundsDescription, countriesOfOperations, transactionVolume, transactionVolumeDescription, purposeOfAccount, purposeOfAccountDescription, regulatedStatus, regulatedStatusDescription, usNexus, usNexusTypes, } = companyInfo;
47
47
  const { usersSelectedForVerification: usersSelected } = companyBillPayInfo;
48
- const { fileIds, companyIncDate: incDate, companyIncType, companyIncState, companySubIndustry, } = incInfo;
48
+ const { fileIds, companyIncDate: incDate, companyIncType, companyIncState, companySubIndustry, companyIndustryType, } = incInfo;
49
49
  const { companyIndustry } = questionaire;
50
50
  const { taxId } = taxInfo;
51
51
  const companyDetails = {
52
52
  companyId,
53
53
  companyDescription,
54
54
  companyIndustry,
55
+ companyIndustryType,
55
56
  companyLegalName,
56
57
  companySubIndustry,
57
58
  companySourceOfFunds: incCompanySourceOfFunds,
@@ -109,7 +109,7 @@ export const getCompanyAndIdentityDetails = (state, companyId, companyAndIdentit
109
109
  if (companyDetails.localData != null) {
110
110
  const deleteFileStatusById = {};
111
111
  const updateFileStatusById = {};
112
- const { syncToken, companyDescription, companyLegalName, website, companyIndustry, companySubIndustry, companySourceOfFunds, companySourceOfFundsDescription, countriesOfOperations, phone, taxIdOrEIN, incDate, fileIds, typeOfIncorporation, sourceOfFunds, transactionVolume, transactionVolumeDescription, purposeOfAccount, purposeOfAccountDescription, regulatedStatus, regulatedStatusDescription, stateOfIncorporation, usNexus, usNexusTypes, } = companyDetails.localData;
112
+ const { syncToken, companyDescription, companyLegalName, website, companyIndustry, companyIndustryType, companySubIndustry, companySourceOfFunds, companySourceOfFundsDescription, countriesOfOperations, phone, taxIdOrEIN, incDate, fileIds, typeOfIncorporation, sourceOfFunds, transactionVolume, transactionVolumeDescription, purposeOfAccount, purposeOfAccountDescription, regulatedStatus, regulatedStatusDescription, stateOfIncorporation, usNexus, usNexusTypes, } = companyDetails.localData;
113
113
  fileIds.forEach((fileId) => {
114
114
  deleteFileStatusById[fileId] = getFileDeleteStatusById(state, fileId);
115
115
  });
@@ -123,6 +123,7 @@ export const getCompanyAndIdentityDetails = (state, companyId, companyAndIdentit
123
123
  companyDescription,
124
124
  companyLegalName,
125
125
  companyIndustry,
126
+ companyIndustryType,
126
127
  companySubIndustry,
127
128
  companySourceOfFunds,
128
129
  companySourceOfFundsDescription,
@@ -4,11 +4,13 @@ import { getSupportedTransactionById } from '../../../entity/transaction/transac
4
4
  import { getUncategorizedAccounts } from '../../accountList/accountListSelector';
5
5
  import { toTransactionDetailLocalData } from '../transactionDetailLocalDataHelper';
6
6
  import { clearTransactionDetailLocalData, initializeTransactionDetailLocalData, saveTransactionDetailLocalData, } from '../transactionDetailReducer';
7
+ import { getTransactionDetailKey } from '../transactionDetailState';
7
8
  export const initializeTransactionDetailLocalDataEpic = (actions$, state$) => actions$.pipe(filter(initializeTransactionDetailLocalData.match), mergeMap((action) => {
8
9
  const { transactionId, vendorId } = action.payload;
9
10
  const fetchActions = [];
10
11
  const transactionState = state$.value.transactionState;
11
- const detail = getSupportedTransactionById(transactionState, transactionId.id); // entity store uses full zeni ID as canonical key
12
+ const key = getTransactionDetailKey(transactionId);
13
+ const detail = getSupportedTransactionById(transactionState, key);
12
14
  if (detail != null) {
13
15
  const uncategorizedIncomeExpense = getUncategorizedAccounts(state$.value.accountState, state$.value.accountListState, 'accountList');
14
16
  const localData = toTransactionDetailLocalData(detail, vendorId, uncategorizedIncomeExpense);
@@ -11,10 +11,8 @@ export const saveTransactionDetailEpic = (actions$, state$) => actions$.pipe(fil
11
11
  const transactionDetailState = state$.value.transactionDetailState;
12
12
  const transactionState = state$.value.transactionState;
13
13
  const key = getTransactionDetailKey(transactionId);
14
- const detail = recordGet(transactionDetailState.transactionDetailById, key, // detail key is correct for transactionDetailState
15
- undefined);
16
- const transaction = getSupportedTransactionById(transactionState, transactionId.id // entity store uses full zeni ID as canonical key
17
- );
14
+ const detail = recordGet(transactionDetailState.transactionDetailById, key, undefined);
15
+ const transaction = getSupportedTransactionById(transactionState, key);
18
16
  if (detail != null && transaction != null) {
19
17
  const localData = detail.transactionDetailLocalData;
20
18
  const transactionSaveUpdates = toTransactionUpdatesFromTransactionDetailLocalData(localData, transaction, isExpenseAutomationEnabled);
@@ -21,7 +21,7 @@ export const fetchTransactionDetailEpic = (actions$, state$, zeniAPI) => actions
21
21
  const detailKey = getTransactionDetailKey(transactionId);
22
22
  const transactionActions = [];
23
23
  if (cacheOverride === true) {
24
- const transaction = getSupportedTransactionById(state$.value.transactionState, transactionId.id);
24
+ const transaction = getSupportedTransactionById(state$.value.transactionState, detailKey);
25
25
  transactionActions.push(...removeCompleteTransaction(transactionId, transaction));
26
26
  }
27
27
  const transactionDetail = recordGet(state$.value.transactionDetailState.transactionDetailById, detailKey, undefined);
@@ -40,27 +40,6 @@ export const fetchTransactionDetailEpic = (actions$, state$, zeniAPI) => actions
40
40
  transactionActions.push(fetchClassList());
41
41
  }
42
42
  transactionActions.push(updateTransactionDetailFetchState(transactionId, 'In-Progress'));
43
- // If the transaction already exists in the entity store (e.g. fetched by the
44
- // list page), initialize local data immediately so the UI can render whatever
45
- // data is available while the full detail fetch completes in parallel.
46
- //
47
- // The entity store canonical key is the full zeni ID (transactionId.id),
48
- // which is the same key used by all list-fetch epics.
49
- //
50
- // DEPENDENCY: The web-components TransactionDetailPage sets effectiveIsDisabled
51
- // to "disabled" while fetchState !== "Completed". This prevents any user edits
52
- // between this early init and the second init dispatched on API response (below).
53
- // If that guard is ever removed, user edits made against partial list data will
54
- // be silently overwritten when the full detail response arrives.
55
- if (cacheOverride !== true) {
56
- const existingTransaction = getSupportedTransactionById(state$.value.transactionState, transactionId.id);
57
- if (existingTransaction != null) {
58
- transactionActions.push(initializeTransactionDetailLocalData({
59
- transactionId,
60
- vendorId: existingTransaction.vendorId,
61
- }));
62
- }
63
- }
64
43
  const query = { transaction_type: transactionId.type };
65
44
  const getTransactionDetail$ = zeniAPI
66
45
  .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${transactionId.id}?query=${encodeURIComponent(JSON.stringify(query))}`)
@@ -68,7 +47,7 @@ export const fetchTransactionDetailEpic = (actions$, state$, zeniAPI) => actions
68
47
  if (isSuccessResponse(response) &&
69
48
  response.data?.transaction?.transaction_id != null) {
70
49
  const updateActions = [];
71
- const responseTransactionId = toTransactionID(response.data.transaction);
50
+ const transcationId = toTransactionID(response.data.transaction);
72
51
  const responseData = {
73
52
  ...response.data,
74
53
  vendors: response.data.vendors?.map((vendor) => ({
@@ -79,15 +58,13 @@ export const fetchTransactionDetailEpic = (actions$, state$, zeniAPI) => actions
79
58
  if (responseData.vendors.length > 0) {
80
59
  updateActions.push(updateVendors(responseData.vendors, 'merge'));
81
60
  }
82
- // Use the full zeni ID as the entity store key so it matches
83
- // how all list-fetch epics save transactions, avoiding
84
- // duplicate entries under different key formats.
85
- updateActions.push(updateTransaction(responseTransactionId.id, responseData.transaction));
61
+ const transactionDetailKeyForResponse = getTransactionDetailKey(transcationId);
62
+ updateActions.push(updateTransaction(transactionDetailKeyForResponse, responseData.transaction));
86
63
  updateActions.push(initializeTransactionDetailLocalData({
87
- transactionId: responseTransactionId,
64
+ transactionId: transcationId,
88
65
  vendorId: responseData.vendors[0]?.vendor_id,
89
66
  }));
90
- updateActions.push(updateTransactionDetailFetchState(responseTransactionId, 'Completed'));
67
+ updateActions.push(updateTransactionDetailFetchState(transcationId, 'Completed'));
91
68
  // IMPORTANT: Fetch linked transactions..
92
69
  updateActions.push(...getAllFetchLinkedTransactionDetailActions(responseData.transaction, state$.value));
93
70
  if (responseData.vendors.length > 0) {
@@ -122,15 +99,12 @@ function removeCompleteTransaction(transactionId, transaction) {
122
99
  const actions = [];
123
100
  actions.push(removeTransactionDetail(transactionId));
124
101
  if (transaction != null) {
125
- // Use transactionId.id (full zeni ID) — the canonical entity store key.
126
- // getTransactionDetailKey produces a different composite key used only by
127
- // transactionDetailState, not the entity store.
128
- actions.push(removeTransaction(transactionId.id));
102
+ actions.push(removeTransaction(getTransactionDetailKey(transactionId)));
129
103
  // remove all the linked transactions too..
130
104
  const linkedTransactions = getAllLinkedTransactions(transaction);
131
105
  linkedTransactions.forEach((linkedTransaction) => {
132
106
  actions.push(removeTransactionDetail(linkedTransaction));
133
- actions.push(removeTransaction(linkedTransaction.id));
107
+ actions.push(removeTransaction(getTransactionDetailKey(linkedTransaction)));
134
108
  });
135
109
  }
136
110
  return actions;
@@ -14,7 +14,7 @@ import { toJEAndDepositTransactionTypeStrict, toVendorTransactionTypeStrict, } f
14
14
  import { isVendorTransaction, } from '../../../entity/transaction/stateTypes/vendorTransaction';
15
15
  import toSupportedTransaction from '../../../entity/transaction/toSupportedTransaction';
16
16
  import { getTransactionWithCOT } from '../../../entity/transaction/transactionHelper';
17
- import { updateTransaction } from '../../../entity/transaction/transactionReducer';
17
+ import { updateTransaction, updateTransactions, } from '../../../entity/transaction/transactionReducer';
18
18
  import { getSupportedTransactionById } from '../../../entity/transaction/transactionSelector';
19
19
  import { updateVendors } from '../../../entity/vendor/vendorReducer';
20
20
  import { getVendorByVendorId } from '../../../entity/vendor/vendorSelector';
@@ -34,8 +34,7 @@ export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => action
34
34
  if (isSuccessResponse(response) && response.data != null) {
35
35
  const transactionIdResp = toTransactionID(response.data.transaction);
36
36
  const transactionDetailKeyForResponse = getTransactionDetailKey(transactionIdResp);
37
- const tranDetail = recordGet(transactionDetailState.transactionDetailById, transactionDetailKeyForResponse, // detail key is correct for transactionDetailState
38
- undefined);
37
+ const tranDetail = recordGet(transactionDetailState.transactionDetailById, transactionDetailKeyForResponse, undefined);
39
38
  const tranVendorUpdates = tranDetail?.transactionDetailLocalData.vendorUpdates;
40
39
  let vendorUpdates = undefined;
41
40
  if (tranVendorUpdates?.qboId != null) {
@@ -57,7 +56,7 @@ export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => action
57
56
  if (response.data.vendors != null) {
58
57
  actions.push(updateVendors(response.data.vendors, 'merge'));
59
58
  }
60
- actions.push(updateTransaction(transactionIdResp.id, response.data.transaction));
59
+ actions.push(updateTransaction(transactionDetailKeyForResponse, response.data.transaction));
61
60
  actions.push(initializeTransactionDetailLocalData({
62
61
  transactionId: transactionIdResp,
63
62
  vendorId: response.data.vendors?.[0]?.vendor_id,
@@ -106,12 +105,9 @@ export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => action
106
105
  }));
107
106
  }
108
107
  }
109
- // No separate updateTransactions call needed: updateTransaction above
110
- // writes under transactionIdResp.id (the full zeni ID). This is the same
111
- // key all list-fetch epics use, so list selectors will read fresh data.
112
- // ASSUMPTION: toTransactionID(response).id === the transaction_id value
113
- // that list-fetch epics pass to updateTransactions. If these ever diverge,
114
- // list rows will go stale after a detail save.
108
+ // Sync transaction categorization list state from detail save
109
+ // Updates list-keyed canonical entity so the list selector reads fresh data
110
+ actions.push(updateTransactions([response.data.transaction], (value) => value.transaction_id, 'merge'));
115
111
  const transactionWithCOT = getTransactionWithCOT(transaction);
116
112
  const pendingReviewLineIds = getPendingReviewLineIdsFromTransaction(transactionWithCOT);
117
113
  actions.push(syncTransactionCategorizationFromDetailSave(transactionIdResp, transactionWithCOT, pendingReviewLineIds, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled));
@@ -129,8 +125,7 @@ export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => action
129
125
  }));
130
126
  function preparePayload(transactionState, vendorState, transactionDetailState, transactionId, saveUpdates, cotTransactionTracking) {
131
127
  const transactionDetailKey = getTransactionDetailKey(transactionId);
132
- const detail = getSupportedTransactionById(transactionState, transactionId.id // entity store uses full zeni ID as canonical key
133
- );
128
+ const detail = getSupportedTransactionById(transactionState, transactionDetailKey);
134
129
  const tranDetail = recordGet(transactionDetailState.transactionDetailById, transactionDetailKey, undefined);
135
130
  const tranVendorUpdates = tranDetail?.transactionDetailLocalData.vendorUpdates;
136
131
  const tranCustomerUpdates = tranDetail?.transactionDetailLocalData.customerUpdates;
@@ -4,12 +4,13 @@ import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
4
4
  import { toTransactionID } from '../../../entity/transaction/payloadTypes/transactionIDPayload';
5
5
  import { updateTransaction } from '../../../entity/transaction/transactionReducer';
6
6
  import { uploadMissingAttachmentSuccess } from '../transactionDetailReducer';
7
+ import { getTransactionDetailKey } from '../transactionDetailState';
7
8
  export const uploadMissingAttachmentSuccessEpic = (actions$) => actions$.pipe(filter(uploadMissingAttachmentSuccess.match), switchMap((action) => {
8
9
  const transactionId = toTransactionID(action.payload.payload);
10
+ const transactionDetailKeyForResponse = getTransactionDetailKey(transactionId);
9
11
  return of(openSnackbar({
10
12
  messageSection: 'receipts_upload',
11
13
  messageText: 'success',
12
14
  type: 'success',
13
- }), updateTransaction(transactionId.id, // entity store uses full zeni ID as canonical key
14
- action.payload.payload));
15
+ }), updateTransaction(transactionDetailKeyForResponse, action.payload.payload));
15
16
  }));
@@ -16,8 +16,7 @@ export const getTransactionDetail = (state, transactionId, fetchLinkedTransactio
16
16
  fetchState: transactionDetail?.fetchState ?? 'Not-Started',
17
17
  error: transactionDetail?.error,
18
18
  };
19
- const transaction = getSupportedTransactionById(transactionState, transactionId.id // entity store uses full zeni ID as canonical key
20
- );
19
+ const transaction = getSupportedTransactionById(transactionState, detailKey);
21
20
  let linkedTransactions = [];
22
21
  if (transactionDetail?.fetchState === 'Completed' && transaction != null) {
23
22
  // IMPORTANT: filtering out unsupported linked transactions
@@ -37,9 +36,8 @@ export const getTransactionDetail = (state, transactionId, fetchLinkedTransactio
37
36
  linkedTransactionsFetchState.fetchState === 'Completed') {
38
37
  linkedTransactions = linkedTransactionDetails
39
38
  .map((linkedTranDetail) => {
40
- const linkedTranId = linkedTranDetail.transactionId; // eslint-disable-line @typescript-eslint/no-non-null-assertion
41
- return getSupportedTransactionById(transactionState, linkedTranId.id // entity store uses full zeni ID as canonical key
42
- );
39
+ const key = getTransactionDetailKey(linkedTranDetail.transactionId); // eslint-disable-line @typescript-eslint/no-non-null-assertion
40
+ return getSupportedTransactionById(transactionState, key);
43
41
  })
44
42
  .filter((value) => {
45
43
  if (value == null) {
@@ -1,18 +1,6 @@
1
- // TWO-KEY SYSTEM read before touching transaction lookups:
2
- //
3
- // 1. transactionDetailState.transactionDetailById → keyed by getTransactionDetailKey()
4
- // Format: "<qbo_id>_<type>" (strips the "tran_<uuid>:" prefix)
5
- // Used by: all transactionDetail epics/selectors for detail metadata (fetch state, local data, etc.)
6
- //
7
- // 2. transactionState.transactionById → keyed by transactionId.id (full zeni ID, e.g. "tran_<uuid>:<qbo_id>")
8
- // Used by: all list-fetch epics, getSupportedTransactionById, and all entity store reads/writes
9
- //
10
- // IMPORTANT: Never use getTransactionDetailKey() to look up or remove from transactionState.
11
- // Always use transactionId.id for the entity store.
12
- // Produces the transactionDetailState key: "<qbo_id>_<type>"
1
+ // This transaction key only extracts the third party ID and uses that
2
+ // for the ID
13
3
  export const getTransactionDetailKey = (transactionId) => `${getActualTransactionID(transactionId.id)}_${transactionId.type}`;
14
- // Produces the full-zeni-ID-based key: "<tran_uuid:qbo_id>_<type>"
15
- // Note: this key format is not used by the entity store (which uses transactionId.id directly).
16
4
  export const getZeniTransactionDetailKey = (transactionId) => `${transactionId.id}_${transactionId.type}`;
17
5
  export const getThirdPartyIdFromTransactionId = (transactionId) => {
18
6
  const zeniGeneratedId = transactionId.id;
@@ -15,6 +15,9 @@ const updateCompanyDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe((0
15
15
  ...(0, companyPassportViewPayload_1.toCompanyIncInfoUpdatableInfoPayload)(companyDetails.incInfo),
16
16
  ...(0, companyPassportViewPayload_1.toCompanyTaxInfoUpdatableInfoPayload)(companyDetails.taxDetails),
17
17
  ...(0, companyPassportViewPayload_1.toCompanyFileInfoPayload)(companyDetails.incInfo, companyDetails.taxDetails),
18
+ ...(companyDetails.companyInfo.companyIndustryType != null && {
19
+ company_industry_type: companyDetails.companyInfo.companyIndustryType,
20
+ }),
18
21
  ...(companyDetails.companyInfo.companySubIndustry != null && {
19
22
  company_industry_sub_type: companyDetails.companyInfo.companySubIndustry,
20
23
  }),
@@ -8,6 +8,7 @@ export interface CompanyInfoLocalData {
8
8
  firstMonthOfFY: Month;
9
9
  legalName: string;
10
10
  phone: string;
11
+ companyIndustryType?: string;
11
12
  companySourceOfFunds?: string;
12
13
  companySourceOfFundsDescription?: string;
13
14
  companySubIndustry?: string;
@@ -13,6 +13,7 @@ function toCompanyPassportLocalData(companyView, companyFiles) {
13
13
  website: companyInfo.companyUrl,
14
14
  meetingLink: companyInfo.meetingUrl,
15
15
  industry: companyQuestionaire.companyIndustry,
16
+ companyIndustryType: incInfo.companyIndustryType,
16
17
  companySubIndustry: incInfo.companySubIndustry,
17
18
  businessModel: companyQuestionaire.companyBusinessModel ?? '',
18
19
  phone: companyInfo.phone ?? '',
@@ -143,7 +143,7 @@ function toUsNexusTypeKey(value) {
143
143
  return US_NEXUS_LABEL_TO_KEY[value] ?? value;
144
144
  }
145
145
  const toBusinessVerificationCompanyDataPayload = (companyLocalData, sendForVerification, companyAddressData, registeredAddressData, setupViewType) => {
146
- const { companyDescription, companyLegalName, companyIndustry, companySubIndustry, countriesOfOperations, companySourceOfFunds, companySourceOfFundsDescription, transactionVolume, transactionVolumeDescription, purposeOfAccount, purposeOfAccountDescription, regulatedStatus, regulatedStatusDescription, usNexus, usNexusTypes, website, incDate, taxIdOrEIN, phone, syncToken, fileIds, typeOfIncorporation, stateOfIncorporation, sourceOfFunds, } = companyLocalData;
146
+ const { companyDescription, companyLegalName, companyIndustry, companyIndustryType, companySubIndustry, countriesOfOperations, companySourceOfFunds, companySourceOfFundsDescription, transactionVolume, transactionVolumeDescription, purposeOfAccount, purposeOfAccountDescription, regulatedStatus, regulatedStatusDescription, usNexus, usNexusTypes, website, incDate, taxIdOrEIN, phone, syncToken, fileIds, typeOfIncorporation, stateOfIncorporation, sourceOfFunds, } = companyLocalData;
147
147
  const company = {
148
148
  is_ready_for_verification: sendForVerification,
149
149
  file_ids: fileIds,
@@ -201,6 +201,9 @@ const toBusinessVerificationCompanyDataPayload = (companyLocalData, sendForVerif
201
201
  company['company_industry'] = companyIndustry;
202
202
  }
203
203
  Object.assign(company, {
204
+ ...(companyIndustryType != null && {
205
+ company_industry_type: companyIndustryType,
206
+ }),
204
207
  ...(companySubIndustry != null && {
205
208
  company_industry_sub_type: companySubIndustry,
206
209
  }),
@@ -53,13 +53,14 @@ function toSetupViewLocalData(company, users, userRoles, primaryContact) {
53
53
  const { companyInfo, incInfo, taxInfo, questionaire, companyBillPayInfo } = company;
54
54
  const { companyId, companyDescription, companyLegalName, companyUrl, phone, syncToken, sourceOfFunds, companySourceOfFunds: incCompanySourceOfFunds, companySourceOfFundsDescription, countriesOfOperations, transactionVolume, transactionVolumeDescription, purposeOfAccount, purposeOfAccountDescription, regulatedStatus, regulatedStatusDescription, usNexus, usNexusTypes, } = companyInfo;
55
55
  const { usersSelectedForVerification: usersSelected } = companyBillPayInfo;
56
- const { fileIds, companyIncDate: incDate, companyIncType, companyIncState, companySubIndustry, } = incInfo;
56
+ const { fileIds, companyIncDate: incDate, companyIncType, companyIncState, companySubIndustry, companyIndustryType, } = incInfo;
57
57
  const { companyIndustry } = questionaire;
58
58
  const { taxId } = taxInfo;
59
59
  const companyDetails = {
60
60
  companyId,
61
61
  companyDescription,
62
62
  companyIndustry,
63
+ companyIndustryType,
63
64
  companyLegalName,
64
65
  companySubIndustry,
65
66
  companySourceOfFunds: incCompanySourceOfFunds,
@@ -69,6 +69,7 @@ export interface CompanyDetails {
69
69
  addressStatus?: NewAddressData;
70
70
  companyDescription?: string;
71
71
  companyIndustry?: string;
72
+ companyIndustryType?: string;
72
73
  companyLegalName?: string;
73
74
  companySourceOfFunds?: string;
74
75
  companySourceOfFundsDescription?: string;
@@ -114,7 +114,7 @@ const getCompanyAndIdentityDetails = (state, companyId, companyAndIdentityDetail
114
114
  if (companyDetails.localData != null) {
115
115
  const deleteFileStatusById = {};
116
116
  const updateFileStatusById = {};
117
- const { syncToken, companyDescription, companyLegalName, website, companyIndustry, companySubIndustry, companySourceOfFunds, companySourceOfFundsDescription, countriesOfOperations, phone, taxIdOrEIN, incDate, fileIds, typeOfIncorporation, sourceOfFunds, transactionVolume, transactionVolumeDescription, purposeOfAccount, purposeOfAccountDescription, regulatedStatus, regulatedStatusDescription, stateOfIncorporation, usNexus, usNexusTypes, } = companyDetails.localData;
117
+ const { syncToken, companyDescription, companyLegalName, website, companyIndustry, companyIndustryType, companySubIndustry, companySourceOfFunds, companySourceOfFundsDescription, countriesOfOperations, phone, taxIdOrEIN, incDate, fileIds, typeOfIncorporation, sourceOfFunds, transactionVolume, transactionVolumeDescription, purposeOfAccount, purposeOfAccountDescription, regulatedStatus, regulatedStatusDescription, stateOfIncorporation, usNexus, usNexusTypes, } = companyDetails.localData;
118
118
  fileIds.forEach((fileId) => {
119
119
  deleteFileStatusById[fileId] = (0, fileViewSelector_1.getFileDeleteStatusById)(state, fileId);
120
120
  });
@@ -128,6 +128,7 @@ const getCompanyAndIdentityDetails = (state, companyId, companyAndIdentityDetail
128
128
  companyDescription,
129
129
  companyLegalName,
130
130
  companyIndustry,
131
+ companyIndustryType,
131
132
  companySubIndustry,
132
133
  companySourceOfFunds,
133
134
  companySourceOfFundsDescription,
@@ -16,6 +16,7 @@ export interface CompanyDetailsLocalData {
16
16
  fileIds: ID[];
17
17
  companyDescription?: string;
18
18
  companyIndustry?: string;
19
+ companyIndustryType?: string;
19
20
  companyLegalName?: string;
20
21
  companySourceOfFunds?: string;
21
22
  companySourceOfFundsDescription?: string;
@@ -66,6 +66,7 @@ export interface CompanyDetailsVerificationPayload {
66
66
  company_countries_of_operations?: string[];
67
67
  company_inc_state?: string | null;
68
68
  company_industry_sub_type?: string;
69
+ company_industry_type?: string;
69
70
  company_purpose_of_account?: string;
70
71
  company_purpose_of_account_desc?: string;
71
72
  company_regulated_states?: boolean;
@@ -7,11 +7,13 @@ const transactionSelector_1 = require("../../../entity/transaction/transactionSe
7
7
  const accountListSelector_1 = require("../../accountList/accountListSelector");
8
8
  const transactionDetailLocalDataHelper_1 = require("../transactionDetailLocalDataHelper");
9
9
  const transactionDetailReducer_1 = require("../transactionDetailReducer");
10
+ const transactionDetailState_1 = require("../transactionDetailState");
10
11
  const initializeTransactionDetailLocalDataEpic = (actions$, state$) => actions$.pipe((0, operators_1.filter)(transactionDetailReducer_1.initializeTransactionDetailLocalData.match), (0, operators_1.mergeMap)((action) => {
11
12
  const { transactionId, vendorId } = action.payload;
12
13
  const fetchActions = [];
13
14
  const transactionState = state$.value.transactionState;
14
- const detail = (0, transactionSelector_1.getSupportedTransactionById)(transactionState, transactionId.id); // entity store uses full zeni ID as canonical key
15
+ const key = (0, transactionDetailState_1.getTransactionDetailKey)(transactionId);
16
+ const detail = (0, transactionSelector_1.getSupportedTransactionById)(transactionState, key);
15
17
  if (detail != null) {
16
18
  const uncategorizedIncomeExpense = (0, accountListSelector_1.getUncategorizedAccounts)(state$.value.accountState, state$.value.accountListState, 'accountList');
17
19
  const localData = (0, transactionDetailLocalDataHelper_1.toTransactionDetailLocalData)(detail, vendorId, uncategorizedIncomeExpense);
@@ -17,10 +17,8 @@ const saveTransactionDetailEpic = (actions$, state$) => actions$.pipe((0, operat
17
17
  const transactionDetailState = state$.value.transactionDetailState;
18
18
  const transactionState = state$.value.transactionState;
19
19
  const key = (0, transactionDetailState_1.getTransactionDetailKey)(transactionId);
20
- const detail = (0, get_1.default)(transactionDetailState.transactionDetailById, key, // detail key is correct for transactionDetailState
21
- undefined);
22
- const transaction = (0, transactionSelector_1.getSupportedTransactionById)(transactionState, transactionId.id // entity store uses full zeni ID as canonical key
23
- );
20
+ const detail = (0, get_1.default)(transactionDetailState.transactionDetailById, key, undefined);
21
+ const transaction = (0, transactionSelector_1.getSupportedTransactionById)(transactionState, key);
24
22
  if (detail != null && transaction != null) {
25
23
  const localData = detail.transactionDetailLocalData;
26
24
  const transactionSaveUpdates = (0, saveTransactionHelper_1.toTransactionUpdatesFromTransactionDetailLocalData)(localData, transaction, isExpenseAutomationEnabled);
@@ -27,7 +27,7 @@ const fetchTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(
27
27
  const detailKey = (0, transactionDetailState_1.getTransactionDetailKey)(transactionId);
28
28
  const transactionActions = [];
29
29
  if (cacheOverride === true) {
30
- const transaction = (0, transactionSelector_1.getSupportedTransactionById)(state$.value.transactionState, transactionId.id);
30
+ const transaction = (0, transactionSelector_1.getSupportedTransactionById)(state$.value.transactionState, detailKey);
31
31
  transactionActions.push(...removeCompleteTransaction(transactionId, transaction));
32
32
  }
33
33
  const transactionDetail = (0, get_1.default)(state$.value.transactionDetailState.transactionDetailById, detailKey, undefined);
@@ -46,27 +46,6 @@ const fetchTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(
46
46
  transactionActions.push((0, classListReducer_1.fetchClassList)());
47
47
  }
48
48
  transactionActions.push((0, transactionDetailReducer_1.updateTransactionDetailFetchState)(transactionId, 'In-Progress'));
49
- // If the transaction already exists in the entity store (e.g. fetched by the
50
- // list page), initialize local data immediately so the UI can render whatever
51
- // data is available while the full detail fetch completes in parallel.
52
- //
53
- // The entity store canonical key is the full zeni ID (transactionId.id),
54
- // which is the same key used by all list-fetch epics.
55
- //
56
- // DEPENDENCY: The web-components TransactionDetailPage sets effectiveIsDisabled
57
- // to "disabled" while fetchState !== "Completed". This prevents any user edits
58
- // between this early init and the second init dispatched on API response (below).
59
- // If that guard is ever removed, user edits made against partial list data will
60
- // be silently overwritten when the full detail response arrives.
61
- if (cacheOverride !== true) {
62
- const existingTransaction = (0, transactionSelector_1.getSupportedTransactionById)(state$.value.transactionState, transactionId.id);
63
- if (existingTransaction != null) {
64
- transactionActions.push((0, transactionDetailReducer_1.initializeTransactionDetailLocalData)({
65
- transactionId,
66
- vendorId: existingTransaction.vendorId,
67
- }));
68
- }
69
- }
70
49
  const query = { transaction_type: transactionId.type };
71
50
  const getTransactionDetail$ = zeniAPI
72
51
  .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${transactionId.id}?query=${encodeURIComponent(JSON.stringify(query))}`)
@@ -74,7 +53,7 @@ const fetchTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(
74
53
  if ((0, responsePayload_1.isSuccessResponse)(response) &&
75
54
  response.data?.transaction?.transaction_id != null) {
76
55
  const updateActions = [];
77
- const responseTransactionId = (0, transactionIDPayload_1.toTransactionID)(response.data.transaction);
56
+ const transcationId = (0, transactionIDPayload_1.toTransactionID)(response.data.transaction);
78
57
  const responseData = {
79
58
  ...response.data,
80
59
  vendors: response.data.vendors?.map((vendor) => ({
@@ -85,15 +64,13 @@ const fetchTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(
85
64
  if (responseData.vendors.length > 0) {
86
65
  updateActions.push((0, vendorReducer_1.updateVendors)(responseData.vendors, 'merge'));
87
66
  }
88
- // Use the full zeni ID as the entity store key so it matches
89
- // how all list-fetch epics save transactions, avoiding
90
- // duplicate entries under different key formats.
91
- updateActions.push((0, transactionReducer_1.updateTransaction)(responseTransactionId.id, responseData.transaction));
67
+ const transactionDetailKeyForResponse = (0, transactionDetailState_1.getTransactionDetailKey)(transcationId);
68
+ updateActions.push((0, transactionReducer_1.updateTransaction)(transactionDetailKeyForResponse, responseData.transaction));
92
69
  updateActions.push((0, transactionDetailReducer_1.initializeTransactionDetailLocalData)({
93
- transactionId: responseTransactionId,
70
+ transactionId: transcationId,
94
71
  vendorId: responseData.vendors[0]?.vendor_id,
95
72
  }));
96
- updateActions.push((0, transactionDetailReducer_1.updateTransactionDetailFetchState)(responseTransactionId, 'Completed'));
73
+ updateActions.push((0, transactionDetailReducer_1.updateTransactionDetailFetchState)(transcationId, 'Completed'));
97
74
  // IMPORTANT: Fetch linked transactions..
98
75
  updateActions.push(...getAllFetchLinkedTransactionDetailActions(responseData.transaction, state$.value));
99
76
  if (responseData.vendors.length > 0) {
@@ -129,15 +106,12 @@ function removeCompleteTransaction(transactionId, transaction) {
129
106
  const actions = [];
130
107
  actions.push((0, transactionDetailReducer_1.removeTransactionDetail)(transactionId));
131
108
  if (transaction != null) {
132
- // Use transactionId.id (full zeni ID) — the canonical entity store key.
133
- // getTransactionDetailKey produces a different composite key used only by
134
- // transactionDetailState, not the entity store.
135
- actions.push((0, transactionReducer_1.removeTransaction)(transactionId.id));
109
+ actions.push((0, transactionReducer_1.removeTransaction)((0, transactionDetailState_1.getTransactionDetailKey)(transactionId)));
136
110
  // remove all the linked transactions too..
137
111
  const linkedTransactions = (0, transactionDetailState_1.getAllLinkedTransactions)(transaction);
138
112
  linkedTransactions.forEach((linkedTransaction) => {
139
113
  actions.push((0, transactionDetailReducer_1.removeTransactionDetail)(linkedTransaction));
140
- actions.push((0, transactionReducer_1.removeTransaction)(linkedTransaction.id));
114
+ actions.push((0, transactionReducer_1.removeTransaction)((0, transactionDetailState_1.getTransactionDetailKey)(linkedTransaction)));
141
115
  });
142
116
  }
143
117
  return actions;
@@ -1,10 +1,10 @@
1
1
  import { ActionsObservable, StateObservable } from 'redux-observable';
2
2
  import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
3
- import { updateTransaction } from '../../../entity/transaction/transactionReducer';
3
+ import { updateTransaction, updateTransactions } from '../../../entity/transaction/transactionReducer';
4
4
  import { updateVendors } from '../../../entity/vendor/vendorReducer';
5
5
  import { RootState } from '../../../reducer';
6
6
  import { ZeniAPI } from '../../../zeniAPI';
7
7
  import { syncTransactionCategorizationFromDetailSave } from '../../expenseAutomationView/reducers/transactionsViewReducer';
8
8
  import { initializeTransactionDetailLocalData, markTransactionAsNotMiscategorized, updateStatusConsolidatedSaveTransactionDetail, updateTransactionDetail, updateTransactionDetailSaveStatus, updateTransactionStateIfUpdateActionNotAllowed } from '../transactionDetailReducer';
9
- export type ActionType = ReturnType<typeof updateTransactionDetail> | ReturnType<typeof updateTransaction> | ReturnType<typeof updateTransactionStateIfUpdateActionNotAllowed> | ReturnType<typeof openSnackbar> | ReturnType<typeof updateTransactionDetailSaveStatus> | ReturnType<typeof updateStatusConsolidatedSaveTransactionDetail> | ReturnType<typeof initializeTransactionDetailLocalData> | ReturnType<typeof updateVendors> | ReturnType<typeof markTransactionAsNotMiscategorized> | ReturnType<typeof syncTransactionCategorizationFromDetailSave>;
9
+ export type ActionType = ReturnType<typeof updateTransactionDetail> | ReturnType<typeof updateTransaction> | ReturnType<typeof updateTransactions> | ReturnType<typeof updateTransactionStateIfUpdateActionNotAllowed> | ReturnType<typeof openSnackbar> | ReturnType<typeof updateTransactionDetailSaveStatus> | ReturnType<typeof updateStatusConsolidatedSaveTransactionDetail> | ReturnType<typeof initializeTransactionDetailLocalData> | ReturnType<typeof updateVendors> | ReturnType<typeof markTransactionAsNotMiscategorized> | ReturnType<typeof syncTransactionCategorizationFromDetailSave>;
10
10
  export declare const updateTransactionDetailEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => import("rxjs").Observable<ActionType>;