@zeniai/client-epic-state 5.3.19 → 5.3.21-beta0KB
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.
- package/lib/commonStateTypes/coaBalance/coaBalance.d.ts +9 -0
- package/lib/commonStateTypes/coaBalance/coaBalance.js +11 -0
- package/lib/entity/genericEntity/customerWithSubCustomersId.d.ts +7 -0
- package/lib/entity/genericEntity/customerWithSubCustomersId.js +17 -0
- package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.js +1 -0
- package/lib/entity/tenant/epic/fetchAllTenantsEpic.js +6 -4
- package/lib/entity/tenant/tenantPayload.d.ts +6 -0
- package/lib/entity/tenant/tenantPayload.js +5 -0
- package/lib/entity/tenant/tenantReducer.d.ts +6 -2
- package/lib/entity/tenant/tenantReducer.js +32 -5
- package/lib/entity/tenant/tenantSelector.d.ts +2 -1
- package/lib/entity/tenant/tenantSelector.js +4 -1
- package/lib/entity/tenant/tenantState.d.ts +10 -0
- package/lib/entity/tenant/tenantState.js +5 -0
- package/lib/epic.d.ts +2 -1
- package/lib/epic.js +3 -0
- package/lib/esm/commonStateTypes/coaBalance/coaBalance.js +10 -0
- package/lib/esm/entity/genericEntity/customerWithSubCustomersId.js +12 -0
- package/lib/esm/entity/snackbar/snackbarTypes.js +1 -0
- package/lib/esm/entity/tenant/epic/fetchAllTenantsEpic.js +6 -4
- package/lib/esm/entity/tenant/tenantPayload.js +4 -1
- package/lib/esm/entity/tenant/tenantReducer.js +31 -4
- package/lib/esm/entity/tenant/tenantSelector.js +2 -0
- package/lib/esm/entity/tenant/tenantState.js +4 -1
- package/lib/esm/epic.js +4 -1
- package/lib/esm/index.js +7 -6
- package/lib/esm/view/balanceSheet/balanceSheetForTimeframeEpic.js +9 -4
- package/lib/esm/view/balanceSheet/balanceSheetReducer.js +2 -0
- package/lib/esm/view/cashFlow/cashFlowForTimeframeEpic.js +11 -5
- package/lib/esm/view/cashFlow/cashFlowReducer.js +2 -0
- package/lib/esm/view/companyView/companyViewReducer.js +26 -1
- package/lib/esm/view/companyView/epic/companyPassport/updateCustomersTabSettingEpic.js +47 -0
- package/lib/esm/view/companyView/selector/companyPassportViewSelector.js +2 -0
- package/lib/esm/view/companyView/types/companyPassport/companyPassportViewState.js +4 -0
- package/lib/esm/view/customerSummaryView/customerSummaryViewReducer.js +39 -6
- package/lib/esm/view/customerSummaryView/customerSummaryViewSelector.js +41 -11
- package/lib/esm/view/customerSummaryView/epic/fetchCustomerSummaryListEpic.js +6 -1
- package/lib/esm/view/financeStatement/financeStatementSelector.js +18 -0
- package/lib/esm/view/profitAndLoss/profitAndLossForTimeframeEpic.js +9 -4
- package/lib/esm/view/profitAndLoss/profitAndLossReducer.js +5 -1
- package/lib/esm/view/spendManagement/reimbursement/editRemiView/editRemiViewReducer.js +23 -3
- package/lib/esm/view/spendManagement/reimbursement/editRemiView/epics/fetchRemiAndInitializeLocalStoreEpic.js +17 -4
- package/lib/esm/view/spendManagement/reimbursement/remiDetailView/epics/fetchRemiDetailEpic.js +1 -1
- package/lib/esm/view/transactionDetail/createTransaction/epics/createTransactionEpic.js +1 -5
- package/lib/esm/view/transactionList/fetchTransactionListByEntityEpic.js +11 -2
- package/lib/esm/view/transactionList/filterTransactionsByTimePeriod.js +18 -0
- package/lib/esm/view/transactionList/transactionListByAccountSelector.js +2 -1
- package/lib/esm/view/transactionList/transactionListByCategoryTypeSelector.js +2 -1
- package/lib/esm/view/transactionList/transactionListByClassSelector.js +2 -1
- package/lib/esm/view/transactionList/transactionListByProjectSelector.js +2 -1
- package/lib/esm/view/transactionList/transactionListReducer.js +24 -15
- package/lib/esm/view/trend/fetchIncomeTrendEpic.js +6 -2
- package/lib/index.d.ts +9 -8
- package/lib/index.js +53 -46
- package/lib/view/balanceSheet/balanceSheetForTimeframeEpic.js +8 -3
- package/lib/view/balanceSheet/balanceSheetReducer.js +2 -0
- package/lib/view/balanceSheet/balanceSheetState.d.ts +2 -0
- package/lib/view/cashFlow/cashFlowForTimeframeEpic.js +10 -4
- package/lib/view/cashFlow/cashFlowReducer.js +2 -0
- package/lib/view/cashFlow/cashFlowState.d.ts +2 -0
- package/lib/view/companyView/companyViewReducer.d.ts +8 -1
- package/lib/view/companyView/companyViewReducer.js +28 -3
- package/lib/view/companyView/epic/companyPassport/updateCustomersTabSettingEpic.d.ts +11 -0
- package/lib/view/companyView/epic/companyPassport/updateCustomersTabSettingEpic.js +51 -0
- package/lib/view/companyView/selector/companyPassportViewSelector.d.ts +1 -0
- package/lib/view/companyView/selector/companyPassportViewSelector.js +4 -1
- package/lib/view/companyView/types/companyPassport/companyPassportViewState.d.ts +1 -0
- package/lib/view/companyView/types/companyPassport/companyPassportViewState.js +4 -0
- package/lib/view/customerSummaryView/customerSummaryViewPayload.d.ts +20 -1
- package/lib/view/customerSummaryView/customerSummaryViewReducer.d.ts +3 -1
- package/lib/view/customerSummaryView/customerSummaryViewReducer.js +42 -6
- package/lib/view/customerSummaryView/customerSummaryViewSelector.d.ts +13 -1
- package/lib/view/customerSummaryView/customerSummaryViewSelector.js +45 -12
- package/lib/view/customerSummaryView/customerSummaryViewState.d.ts +24 -10
- package/lib/view/customerSummaryView/epic/fetchCustomerSummaryListEpic.js +6 -1
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/financeStatement/financeStatementSelector.d.ts +8 -0
- package/lib/view/financeStatement/financeStatementSelector.js +18 -0
- package/lib/view/profitAndLoss/profitAndLossForTimeframeEpic.js +8 -3
- package/lib/view/profitAndLoss/profitAndLossReducer.js +5 -1
- package/lib/view/profitAndLoss/profitAndLossState.d.ts +2 -1
- package/lib/view/spendManagement/reimbursement/editRemiView/editRemiViewReducer.d.ts +7 -2
- package/lib/view/spendManagement/reimbursement/editRemiView/editRemiViewReducer.js +24 -4
- package/lib/view/spendManagement/reimbursement/editRemiView/epics/fetchRemiAndInitializeLocalStoreEpic.d.ts +7 -4
- package/lib/view/spendManagement/reimbursement/editRemiView/epics/fetchRemiAndInitializeLocalStoreEpic.js +15 -1
- package/lib/view/spendManagement/reimbursement/remiDetailView/epics/fetchRemiDetailEpic.js +1 -1
- package/lib/view/transactionDetail/createTransaction/epics/createTransactionEpic.js +1 -5
- package/lib/view/transactionList/fetchTransactionListByEntityEpic.js +11 -2
- package/lib/view/transactionList/filterTransactionsByTimePeriod.d.ts +15 -0
- package/lib/view/transactionList/filterTransactionsByTimePeriod.js +22 -0
- package/lib/view/transactionList/transactionListByAccountSelector.js +2 -1
- package/lib/view/transactionList/transactionListByCategoryTypeSelector.js +2 -1
- package/lib/view/transactionList/transactionListByClassSelector.js +2 -1
- package/lib/view/transactionList/transactionListByProjectSelector.js +2 -1
- package/lib/view/transactionList/transactionListReducer.d.ts +3 -1
- package/lib/view/transactionList/transactionListReducer.js +24 -15
- package/lib/view/trend/fetchIncomeTrendEpic.js +6 -2
- package/package.json +1 -1
|
@@ -116,12 +116,26 @@ const tenant = createSlice({
|
|
|
116
116
|
tenantSummariesById[payload.tenant_id] =
|
|
117
117
|
mapTenantSummaryPayloadToTenantSummary(payload);
|
|
118
118
|
});
|
|
119
|
-
draft.tenantSummariesById = tenantSummariesById;
|
|
120
119
|
draft.tenantIds = Object.keys(tenantSummariesById);
|
|
121
|
-
// A tenant missing from the list is no longer accessible to the user
|
|
120
|
+
// A tenant missing from the list is no longer accessible to the user,
|
|
121
|
+
// except the open one: the list hides companies by status, and the
|
|
122
|
+
// selected tenant's record was loaded for it on its own. Its summary
|
|
123
|
+
// stays too (outside `tenantIds`, so not in the switcher), so its ids
|
|
124
|
+
// are still known while its record loads.
|
|
125
|
+
const { currentTenantId } = draft;
|
|
126
|
+
const currentTenantSummary = currentTenantId != null
|
|
127
|
+
? draft.tenantSummariesById[currentTenantId]
|
|
128
|
+
: undefined;
|
|
129
|
+
if (currentTenantId != null &&
|
|
130
|
+
currentTenantSummary != null &&
|
|
131
|
+
tenantSummariesById[currentTenantId] == null) {
|
|
132
|
+
tenantSummariesById[currentTenantId] = currentTenantSummary;
|
|
133
|
+
}
|
|
134
|
+
draft.tenantSummariesById = tenantSummariesById;
|
|
122
135
|
const accessibleTenantsById = {};
|
|
123
136
|
Object.values(draft.tenantsById).forEach((tenant) => {
|
|
124
|
-
if (tenantSummariesById[tenant.tenantId] != null
|
|
137
|
+
if (tenantSummariesById[tenant.tenantId] != null ||
|
|
138
|
+
tenant.tenantId === draft.currentTenantId) {
|
|
125
139
|
accessibleTenantsById[tenant.tenantId] = tenant;
|
|
126
140
|
}
|
|
127
141
|
});
|
|
@@ -174,6 +188,13 @@ const tenant = createSlice({
|
|
|
174
188
|
enabled;
|
|
175
189
|
}
|
|
176
190
|
},
|
|
191
|
+
updateTenantCustomersTabSetting(draft, action) {
|
|
192
|
+
const { tenantId, setting, enabled } = action.payload;
|
|
193
|
+
const tenant = draft.tenantsById[tenantId];
|
|
194
|
+
if (tenant != null) {
|
|
195
|
+
tenant.customersTabSettings[setting] = enabled;
|
|
196
|
+
}
|
|
197
|
+
},
|
|
177
198
|
// Optimistic per-key merge of the product-family flags after a cockpit
|
|
178
199
|
// "enable services" write succeeds. Only the provided keys are applied so
|
|
179
200
|
// other product settings are preserved.
|
|
@@ -953,7 +974,7 @@ const tenant = createSlice({
|
|
|
953
974
|
});
|
|
954
975
|
},
|
|
955
976
|
});
|
|
956
|
-
export const { updateTenants, fetchAllTenants, updateTenantSummariesSuccess, seedTenantSummary, updateTenantsFailure, fetchActiveTenant, updateTenantSuccess, updateTenantFailure, updateCurrentTenant, fetchExcludedResources, updateExcludedResourcesSuccess, updateExcludedResourcesFailure, doSignIn, doMagicLinkSignIn, magicLinkSignInSuccess, magicLinkSignInFailure, sendEmailMagicLinkToUser, sendEmailMagicLinkToUserSuccess, sendEmailMagicLinkToUserFailure, updateSignInState, doSignOut, signOutSuccess, sendSessionHeartbeat, sessionHeartbeatSuccess, sessionHeartbeatFailure, updateLoggedInUser, fetchExternalConnections, saveExternalConnection, saveExternalConnectionSuccess, saveExternalConnectionFailure, fetchExternalConnectionsFailure, fetchExternalConnectionsSuccess, saveAPIKeyConnection, saveAPIKeyConnectionSuccess, saveAPIKeyConnectionFailure, saveOAuthConnection, saveOAuthConnectionSuccess, saveOAuthConnectionFailure, saveConnectorCredentials, saveConnectorCredentialsSuccess, saveConnectorCredentialsFailure, initEmailConnectOAuth, initEmailConnectOAuthSuccess, initEmailConnectOAuthFailure, deleteConnection, deleteConnectionSuccess, deleteConnectionFailure, fetchSubscriptionSummaryForTenant, updateSubscriptionSummaryForTenantSuccess, updateSubscriptionSummaryForTenantFailure, updateOnboardingTenants, removeOnboardingTenant, updateTenantReimbursementInfo, updateReferViewedForLoggedInUser, resetSignInState, trigger2FA, updateTenantAccountingClassesEnabled, updateTenantAccountingProjectsEnabled, updateTenantAutoReviewIncomeWithoutCustomer, updateTenantProductSettings, updateTenantCapitalizationOnboardingDismissed, updateTenantCapitalizationAccountOverride, updateTenantMasterTOSInfo, verifyDeviceWithTwoFA, verifyDeviceWithTwoFASuccess, verifyDeviceWithTwoFAFailure, updateTreasuryVideoViewedForLoggedInUser, updateTreasuryPromoRemindMeLaterClickedForLoggedInUser, updateTreasuryPromoIntroClosedByOutsideClickForLoggedInUser, resendVerifyDeviceOTP, resendVerifyDeviceOTPSuccess, resendVerifyDeviceOTPFailure, } = tenant.actions;
|
|
977
|
+
export const { updateTenants, fetchAllTenants, updateTenantSummariesSuccess, seedTenantSummary, updateTenantsFailure, fetchActiveTenant, updateTenantSuccess, updateTenantFailure, updateCurrentTenant, fetchExcludedResources, updateExcludedResourcesSuccess, updateExcludedResourcesFailure, doSignIn, doMagicLinkSignIn, magicLinkSignInSuccess, magicLinkSignInFailure, sendEmailMagicLinkToUser, sendEmailMagicLinkToUserSuccess, sendEmailMagicLinkToUserFailure, updateSignInState, doSignOut, signOutSuccess, sendSessionHeartbeat, sessionHeartbeatSuccess, sessionHeartbeatFailure, updateLoggedInUser, fetchExternalConnections, saveExternalConnection, saveExternalConnectionSuccess, saveExternalConnectionFailure, fetchExternalConnectionsFailure, fetchExternalConnectionsSuccess, saveAPIKeyConnection, saveAPIKeyConnectionSuccess, saveAPIKeyConnectionFailure, saveOAuthConnection, saveOAuthConnectionSuccess, saveOAuthConnectionFailure, saveConnectorCredentials, saveConnectorCredentialsSuccess, saveConnectorCredentialsFailure, initEmailConnectOAuth, initEmailConnectOAuthSuccess, initEmailConnectOAuthFailure, deleteConnection, deleteConnectionSuccess, deleteConnectionFailure, fetchSubscriptionSummaryForTenant, updateSubscriptionSummaryForTenantSuccess, updateSubscriptionSummaryForTenantFailure, updateOnboardingTenants, removeOnboardingTenant, updateTenantReimbursementInfo, updateReferViewedForLoggedInUser, resetSignInState, trigger2FA, updateTenantAccountingClassesEnabled, updateTenantAccountingProjectsEnabled, updateTenantAutoReviewIncomeWithoutCustomer, updateTenantCustomersTabSetting, updateTenantProductSettings, updateTenantCapitalizationOnboardingDismissed, updateTenantCapitalizationAccountOverride, updateTenantMasterTOSInfo, verifyDeviceWithTwoFA, verifyDeviceWithTwoFASuccess, verifyDeviceWithTwoFAFailure, updateTreasuryVideoViewedForLoggedInUser, updateTreasuryPromoRemindMeLaterClickedForLoggedInUser, updateTreasuryPromoIntroClosedByOutsideClickForLoggedInUser, resendVerifyDeviceOTP, resendVerifyDeviceOTPSuccess, resendVerifyDeviceOTPFailure, } = tenant.actions;
|
|
957
978
|
export default tenant.reducer;
|
|
958
979
|
/**
|
|
959
980
|
* Applies treasury promo user fields from the tenants API user block when present.
|
|
@@ -1012,6 +1033,12 @@ function mapTenantPayloadToTenant(payload, userTenantPayload) {
|
|
|
1012
1033
|
isAccountingProjectsEnabled: payload.is_accounting_projects_enabled ?? false,
|
|
1013
1034
|
isAutoReviewIncomeWithoutCustomerEnabled: payload.accounting_config?.customers
|
|
1014
1035
|
?.auto_review_income_without_customer ?? false,
|
|
1036
|
+
customersTabSettings: {
|
|
1037
|
+
includeSubCustomersInTotals: payload.accounting_config?.customers?.include_sub_customers_in_totals ??
|
|
1038
|
+
false,
|
|
1039
|
+
listTopLevelCustomersOnly: payload.accounting_config?.customers?.list_top_level_customers_only ??
|
|
1040
|
+
false,
|
|
1041
|
+
},
|
|
1015
1042
|
bookCloseDate: payload.book_close_date != null
|
|
1016
1043
|
? date(payload.book_close_date)
|
|
1017
1044
|
: undefined,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createSelector } from '@reduxjs/toolkit';
|
|
2
|
+
import recordGet from 'lodash/get';
|
|
2
3
|
import orderBy from 'lodash/orderBy';
|
|
3
4
|
import { getCompanyByCompanyId } from '../company/companySelector';
|
|
4
5
|
export function getTenant(tenantState, companyState, tenantId) {
|
|
@@ -318,6 +319,7 @@ export const getIsAutoReviewIncomeWithoutCustomerEnabled = (state) => {
|
|
|
318
319
|
return (tenantsById[currentTenantId]?.isAutoReviewIncomeWithoutCustomerEnabled ??
|
|
319
320
|
false);
|
|
320
321
|
};
|
|
322
|
+
export const getTenantCustomersTabSettings = (tenantState, tenantId) => recordGet(tenantState.tenantsById, [tenantId, 'customersTabSettings'], undefined);
|
|
321
323
|
export const isTenantBookkeepingEnabled = (tenant) => {
|
|
322
324
|
// if the tenants API takes time, tenant can be non null with productSettings as null
|
|
323
325
|
return tenant != null && tenant.productSettings != null
|
package/lib/esm/epic.js
CHANGED
|
@@ -161,6 +161,7 @@ import { updateCapitalizationAccountThresholdEpic, } from './view/companyView/ep
|
|
|
161
161
|
import { updateCompanyDetailsEpic, } from './view/companyView/epic/companyPassport/updateCompanyDetailsEpic';
|
|
162
162
|
import { updateCompanyOfficerEpic, } from './view/companyView/epic/companyPassport/updateCompanyOfficerEpic';
|
|
163
163
|
import { updateCompanyPassportLocalStoreDataEpic, } from './view/companyView/epic/companyPassport/updateCompanyPassportLocalStoreDataEpic';
|
|
164
|
+
import { updateCustomersTabSettingEpic, } from './view/companyView/epic/companyPassport/updateCustomersTabSettingEpic';
|
|
164
165
|
import { updatePrimaryContactEpic, } from './view/companyView/epic/companyPassport/updatePrimaryContactEpic';
|
|
165
166
|
import { fetchAllCockpitViewsEpic, } from './view/companyView/epic/fetchAllCockpitViewsEpic';
|
|
166
167
|
import { fetchCompanyManagementViewEpic, } from './view/companyView/epic/fetchCompanyManagementViewEpic';
|
|
@@ -636,7 +637,7 @@ import { saveRealTimeApprovalEpic, } from './view/spendManagement/realTimeApprov
|
|
|
636
637
|
import { fetchCurrencyConversionValueEpic, } from './view/spendManagement/reimbursement/editRemiView/epics/fetchCurrencyConversionValueEpic';
|
|
637
638
|
import { fetchEditRemiDetailPageEpic, } from './view/spendManagement/reimbursement/editRemiView/epics/fetchEditRemiDetailPageEpic';
|
|
638
639
|
import { fetchRecommendationsAndUpdateMerchantRecommendationsEpic, waitForMerchantRecommendationFetchThenUpdateRecommendationInMerchantEpic, } from './view/spendManagement/reimbursement/editRemiView/epics/fetchRecommendationsAndUpdateMerchantRecommendationsEpic';
|
|
639
|
-
import { fetchRemiAndInitializeLocalStoreEpic, } from './view/spendManagement/reimbursement/editRemiView/epics/fetchRemiAndInitializeLocalStoreEpic';
|
|
640
|
+
import { fetchRemiAndInitializeLocalStoreEpic, waitForRemiDetailThenInitializeLocalStoreEpic, } from './view/spendManagement/reimbursement/editRemiView/epics/fetchRemiAndInitializeLocalStoreEpic';
|
|
640
641
|
import { initializeRemiToLocalStoreEpic, } from './view/spendManagement/reimbursement/editRemiView/epics/initializeRemiToLocalStoreEpic';
|
|
641
642
|
import { parseReceiptsToRemiEpic, } from './view/spendManagement/reimbursement/editRemiView/epics/parseReceiptsToRemiEpic';
|
|
642
643
|
import { saveRemiDetailEpic, } from './view/spendManagement/reimbursement/editRemiView/epics/saveRemiDetailEpic';
|
|
@@ -1517,6 +1518,7 @@ const ALL_EPICS = [
|
|
|
1517
1518
|
updateCompanyProductServicesEpic,
|
|
1518
1519
|
updateCompanyQboRealmIdEpic,
|
|
1519
1520
|
updateCompanyTaskManagerViewFiltersEpic,
|
|
1521
|
+
updateCustomersTabSettingEpic,
|
|
1520
1522
|
updateDashboardLayoutEpic,
|
|
1521
1523
|
updateDebitCardPinAttemptEpic,
|
|
1522
1524
|
updateDepositAccountEpic,
|
|
@@ -1576,6 +1578,7 @@ const ALL_EPICS = [
|
|
|
1576
1578
|
waitForForecastListThenFetchOpExWithForecastEpic,
|
|
1577
1579
|
waitForForecastListThenFetchRevenueWithForecastEpic,
|
|
1578
1580
|
waitForMerchantRecommendationFetchThenUpdateRecommendationInMerchantEpic,
|
|
1581
|
+
waitForRemiDetailThenInitializeLocalStoreEpic,
|
|
1579
1582
|
waitForVendorByIdThenSaveBillUpdatetoLocalStoreEpic,
|
|
1580
1583
|
waitForVendorByNameThenParsetoLocalStoreEpic,
|
|
1581
1584
|
waitForVendorByNameThenUpdateBillDetailEpic,
|
package/lib/esm/index.js
CHANGED
|
@@ -73,7 +73,7 @@ import { getSnackbar } from './entity/snackbar/snackbarSelector';
|
|
|
73
73
|
import { ALL_WEEK_DAYS, toDayOfWeek, toPriorityCodeType, toTaskStatusCodeType, } from './entity/task/taskState';
|
|
74
74
|
import { getTaskGroupById } from './entity/taskGroup/taskGroupSelector';
|
|
75
75
|
import { deleteConnection, doMagicLinkSignIn, doSignIn, doSignOut, fetchActiveTenant, fetchAllTenants, fetchExcludedResources as fetchExcludedResourcesForTenant, fetchExternalConnections as fetchExternalConnectionsForTenant, fetchSubscriptionSummaryForTenant, initEmailConnectOAuth, resendVerifyDeviceOTP, resetSignInState, saveAPIKeyConnection, saveConnectorCredentials, saveExternalConnection as saveExternalConnectionForTenant, saveOAuthConnection, seedTenantSummary, sendEmailMagicLinkToUser, sendSessionHeartbeat, toExternalIntegrationType, updateCurrentTenant, updateSignInState, verifyDeviceWithTwoFA, } from './entity/tenant/tenantReducer';
|
|
76
|
-
import { DEFAULT_RECEIPTS_EMAIL, getCurrentTenant, getCurrentTenantId, getCurrentTenantIds, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getIsAutoReviewIncomeWithoutCustomerEnabled, getReceiptsEmail, getTenantBaseById, getTenantBaseViewForTenantId, getTenantBaseViewForTenantView, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, isCurrentTenantLoaded, isOtherProductsEnabledForTenant, isTenantBankingOnly, isTenantBookkeepingEnabled, isTenantCardsOnly, isTenantLoaded, isTenantUsingZeniCOA, isZeniDomainTenant, toTenantCoreDetailsView, } from './entity/tenant/tenantSelector';
|
|
76
|
+
import { DEFAULT_RECEIPTS_EMAIL, getCurrentTenant, getCurrentTenantId, getCurrentTenantIds, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getIsAutoReviewIncomeWithoutCustomerEnabled, getReceiptsEmail, getTenantBaseById, getTenantBaseViewForTenantId, getTenantBaseViewForTenantView, getTenantCustomersTabSettings, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, isCurrentTenantLoaded, isOtherProductsEnabledForTenant, isTenantBankingOnly, isTenantBookkeepingEnabled, isTenantCardsOnly, isTenantLoaded, isTenantUsingZeniCOA, isZeniDomainTenant, toTenantCoreDetailsView, } from './entity/tenant/tenantSelector';
|
|
77
77
|
import { toExternalSupportedTool } from './entity/tenant/tenantTypes';
|
|
78
78
|
import { pushToastNotification } from './entity/toastNotification/toastNotificationReducer';
|
|
79
79
|
import { getLastNotificationTime, getNotifications, } from './entity/toastNotification/toastNotificationSelector';
|
|
@@ -169,11 +169,11 @@ import { fetchCompanyMonthEndReportHistoricData, fetchCompanyMonthEndReportHisto
|
|
|
169
169
|
import { getCompanyMonthEndReportHistoricData, getCompanyMonthEndReportSelectorView, } from './view/companyMonthEndReportView/companyMonthEndReportViewSelector';
|
|
170
170
|
import { fetchCockpitContext, fetchCompanyTaskManagerView, fetchTaskManagerMetrics, updateCompanyTaskManagerViewFilters, } from './view/companyTaskManagerView/companyTaskManagerViewReducer';
|
|
171
171
|
import { getCompanyTaskManagerView, } from './view/companyTaskManagerView/companyTaskManagerViewSelector';
|
|
172
|
-
import { clearQboProjectsReconnectRequest, companyManagementSaveUpdates, companyPassportClearDataInLocalStore, companyPassportSaveDataInLocalStore, deleteCompanyOfficerInLocalStore, disableAccountingProjects, dismissCapitalizationOnboarding, enableAccountingProjects, fetchAllCockpitViews, fetchCompanyManagementView, fetchCompanyPassportView, fetchCompanyPortfolioView, fetchManagementView, fetchOnboardingView, fetchParentSubsidiaryManagementView, fetchPortfolioView, fetchSubscriptionView, fetchZeniUsers, resumeEnableAccountingProjects, saveCompanyPassportDetails, saveIndustryAndIncDateInCompanyPassportLocalStore, updateAccountingClassesEnabled, updateAutoReviewIncomeWithoutCustomer, updateCapitalizationAccountThreshold, updateCompanyDownloadState, updateCompanyManagementUIState, updateCompanyPassportLocalStoreData, updateCompanyPortfolioUIState, updateCompanyProductServices, updateCompanyQboRealmId, } from './view/companyView/companyViewReducer';
|
|
172
|
+
import { clearQboProjectsReconnectRequest, companyManagementSaveUpdates, companyPassportClearDataInLocalStore, companyPassportSaveDataInLocalStore, deleteCompanyOfficerInLocalStore, disableAccountingProjects, dismissCapitalizationOnboarding, enableAccountingProjects, fetchAllCockpitViews, fetchCompanyManagementView, fetchCompanyPassportView, fetchCompanyPortfolioView, fetchManagementView, fetchOnboardingView, fetchParentSubsidiaryManagementView, fetchPortfolioView, fetchSubscriptionView, fetchZeniUsers, resumeEnableAccountingProjects, saveCompanyPassportDetails, saveIndustryAndIncDateInCompanyPassportLocalStore, updateAccountingClassesEnabled, updateAutoReviewIncomeWithoutCustomer, updateCapitalizationAccountThreshold, updateCompanyDownloadState, updateCompanyManagementUIState, updateCompanyPassportLocalStoreData, updateCompanyPortfolioUIState, updateCompanyProductServices, updateCompanyQboRealmId, updateCustomersTabSetting, } from './view/companyView/companyViewReducer';
|
|
173
173
|
import { canSendMonthEndEmailReport, shouldEnableCalendarPickerForLastReportSent, } from './view/companyView/helpers/cockpitHelpers';
|
|
174
174
|
import { getParentSubsidiaryManagementView } from './view/companyView/parentSubsidiaryView/parentSubsidiaryViewSelector';
|
|
175
175
|
import { getAddonListZeniSku, getCompanyManagementView, getCompanyProductServicesUpdateStatus, getCompanyQboRealmIdUpdateStatus, getPlanListZeniSku, } from './view/companyView/selector/companyManagementViewSelector';
|
|
176
|
-
import { getCompanyPassportLocalStoreData, getCompanyPassportView, isCompanyPassportDataToBeSaved, } from './view/companyView/selector/companyPassportViewSelector';
|
|
176
|
+
import { getCompanyPassportLocalStoreData, getCompanyPassportView, getIsCustomersTabSettingsUpdateInProgress, isCompanyPassportDataToBeSaved, } from './view/companyView/selector/companyPassportViewSelector';
|
|
177
177
|
import { getCompanyPortfolioView, isInfiniteRunway, } from './view/companyView/selector/companyPortfolioViewSelector';
|
|
178
178
|
import { getAllCockpitTabsFilterView, } from './view/companyView/selector/getAllCockpitTabsFilterView';
|
|
179
179
|
import { ALL_COCKPIT_TABS_FILE_TYPES, ALL_COCKPIT_TABS_IDS, toCockpitTabsFileTypeStrict, toCockpitTabsIDStrict, } from './view/companyView/types/cockpitTabsID';
|
|
@@ -509,7 +509,7 @@ export { toTimeframeTick, mapTimePeriodtoTimeframeTick, toTimePeriod, toAbsolute
|
|
|
509
509
|
export { toVendorSpendTrendFilterTabsTypeStrict, } from './entity/vendorExpense/vendorSpendTrendFilterTabType';
|
|
510
510
|
export { getNumberOfPeriods };
|
|
511
511
|
export { SCHEDULE_DAYS_OF_MONTH, toScheduleDaysOfMonth, toMonth, toMonthStrict, toQuarter, toQuarterStrict, };
|
|
512
|
-
export { getTenantBaseById, getCurrentTenant, getCurrentTenantId, getCurrentTenantIds, isCurrentTenantLoaded, isTenantLoaded, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getIsAutoReviewIncomeWithoutCustomerEnabled, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, toTenantCoreDetailsView, getTenantBaseViewForTenantView, getTenantBaseViewForTenantId, isZeniDomainTenant, isTenantUsingZeniCOA, fetchActiveTenant, fetchAllTenants, seedTenantSummary, updateCurrentTenant, clearAll, doMagicLinkSignIn, verifyDeviceWithTwoFA, resendVerifyDeviceOTP, sendEmailMagicLinkToUser, doSignIn, updateSignInState, doSignOut, sendSessionHeartbeat, resetSignInState, fetchExcludedResourcesForTenant, fetchExternalConnectionsForTenant, saveExternalConnectionForTenant, deleteConnection, saveAPIKeyConnection, saveConnectorCredentials, saveOAuthConnection, initEmailConnectOAuth, toExternalIntegrationType, toExternalSupportedTool, fetchSubscriptionSummaryForTenant, isTenantBankingOnly, isTenantCardsOnly, isTenantBookkeepingEnabled, isOtherProductsEnabledForTenant, DEFAULT_RECEIPTS_EMAIL, getReceiptsEmail, };
|
|
512
|
+
export { getTenantBaseById, getCurrentTenant, getCurrentTenantId, getCurrentTenantIds, isCurrentTenantLoaded, isTenantLoaded, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getIsAutoReviewIncomeWithoutCustomerEnabled, getTenantCustomersTabSettings, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, toTenantCoreDetailsView, getTenantBaseViewForTenantView, getTenantBaseViewForTenantId, isZeniDomainTenant, isTenantUsingZeniCOA, fetchActiveTenant, fetchAllTenants, seedTenantSummary, updateCurrentTenant, clearAll, doMagicLinkSignIn, verifyDeviceWithTwoFA, resendVerifyDeviceOTP, sendEmailMagicLinkToUser, doSignIn, updateSignInState, doSignOut, sendSessionHeartbeat, resetSignInState, fetchExcludedResourcesForTenant, fetchExternalConnectionsForTenant, saveExternalConnectionForTenant, deleteConnection, saveAPIKeyConnection, saveConnectorCredentials, saveOAuthConnection, initEmailConnectOAuth, toExternalIntegrationType, toExternalSupportedTool, fetchSubscriptionSummaryForTenant, isTenantBankingOnly, isTenantCardsOnly, isTenantBookkeepingEnabled, isOtherProductsEnabledForTenant, DEFAULT_RECEIPTS_EMAIL, getReceiptsEmail, };
|
|
513
513
|
export { toAccountType, toAccountGroupType, getAccountGroupKey, getAllAccounts, getTransactionFilterAccountOptions, };
|
|
514
514
|
export { getAllClasses, getClassById, getClassFilterOptions, } from './entity/class/classSelector';
|
|
515
515
|
export { getForecast };
|
|
@@ -599,7 +599,7 @@ export { newAddressInLocalStore, getAddress, getNewAddress, getAllNewAddresses,
|
|
|
599
599
|
export { toManagementSortKeyType, toOnboardingSortKeyType, toPortfolioSortKeyType, toHealthSortKeyType, toTaskManagerSortKeyType, updateCompanyTaskManagerViewFilters, };
|
|
600
600
|
export { ALL_COCKPIT_TABS_FILE_TYPES, ALL_COCKPIT_TABS_IDS, toCockpitTabsIDStrict, toCockpitTabsFileTypeStrict, };
|
|
601
601
|
export { isAllowedValueWithCode, isAllowedValueWithID, };
|
|
602
|
-
export { fetchCompanyPassportView, getCompanyPassportView, getCompanyPassportLocalStoreData, isCompanyPassportDataToBeSaved, companyPassportSaveDataInLocalStore, saveIndustryAndIncDateInCompanyPassportLocalStore, deleteCompanyOfficerInLocalStore, companyPassportClearDataInLocalStore, updateCompanyPassportLocalStoreData, saveCompanyPassportDetails, updateAccountingClassesEnabled, updateAutoReviewIncomeWithoutCustomer, enableAccountingProjects, resumeEnableAccountingProjects, disableAccountingProjects, clearQboProjectsReconnectRequest, updateCompanyProductServices, getCompanyProductServicesUpdateStatus, updateCompanyQboRealmId, getCompanyQboRealmIdUpdateStatus, updateCapitalizationAccountThreshold, dismissCapitalizationOnboarding, };
|
|
602
|
+
export { fetchCompanyPassportView, getCompanyPassportView, getCompanyPassportLocalStoreData, getIsCustomersTabSettingsUpdateInProgress, isCompanyPassportDataToBeSaved, companyPassportSaveDataInLocalStore, saveIndustryAndIncDateInCompanyPassportLocalStore, deleteCompanyOfficerInLocalStore, companyPassportClearDataInLocalStore, updateCompanyPassportLocalStoreData, saveCompanyPassportDetails, updateAccountingClassesEnabled, updateAutoReviewIncomeWithoutCustomer, updateCustomersTabSetting, enableAccountingProjects, resumeEnableAccountingProjects, disableAccountingProjects, clearQboProjectsReconnectRequest, updateCompanyProductServices, getCompanyProductServicesUpdateStatus, updateCompanyQboRealmId, getCompanyQboRealmIdUpdateStatus, updateCapitalizationAccountThreshold, dismissCapitalizationOnboarding, };
|
|
603
603
|
export { toCompanyPassportLocalData, };
|
|
604
604
|
export { COMPANY_ONBOARDING_INDUSTRY_TYPE_CODES, COMPANY_ONBOARDING_SUB_INDUSTRY_CODES_BY_INDUSTRY, COMPANY_PURPOSE_OF_ACCOUNT_CODES, COMPANY_SOURCE_OF_FUNDS_CODES, COMPANY_TRANSACTION_VOLUME_CODES, COMPANY_US_NEXUS_TYPE_CODES, getCompanyOnboardingSubIndustryCodesForIndustry, };
|
|
605
605
|
export { getUncategorizedAccounts, getNestedAccountListHierarchy, };
|
|
@@ -876,5 +876,6 @@ export { getInvoicingOnboardingGateView } from './view/invoicing/invoicingConfig
|
|
|
876
876
|
export { getExpenseAutomationJEOneTimeAccrualDetailView, getJEScheduleRowType, isAccruedScheduleRow, isAiAccountantSchedule, isExistingTabRow, isOneTimeAccrualRow, isRenderableOneTimeAccrual, isPendingReviewRow, } from './view/expenseAutomationView/selectors/jeSchedulesViewSelector';
|
|
877
877
|
export { getActualMatchingAmount, getActualMatchingReversalDate, getActualMatchingMatchModalConfirmStatus, getCloseMatchAfterIgnoreMatchId, getCloseMatchAfterUndo, getCloseMatchAfterUndoMatchId, parseActualMatchingMatchId, getExpenseAutomationActualMatchingMatchView, getExpenseAutomationActualMatchingView, isAutoReversedAccrual, isManuallyReversedAccrual, isPendingReviewAccrual, } from './view/expenseAutomationView/selectors/actualMatchingViewSelector';
|
|
878
878
|
export { fetchCustomerSummaryDetail, fetchCustomerSummaryList, resetCustomerSummaryDetailUiState, saveCustomerSummaryDetail, updateCustomerAllTransactionsTabData, updateCustomerDetailSelectedTab, updateCustomerSummaryRevenueSelection, updateCustomerSummaryScrollYOffset, updateCustomerSummarySortUiState, updateCustomerTrendFilter, } from './view/customerSummaryView/customerSummaryViewReducer';
|
|
879
|
-
export { getCustomerSummaryAllTransactionsTabData, getCustomerSummaryDetail, getCustomerSummaryList, getCustomerSummarySelectedTabType, getCustomerSummaryTrendFilter, isCustomersTabVisible, } from './view/customerSummaryView/customerSummaryViewSelector';
|
|
879
|
+
export { getCustomerSummaryAllTransactionsTabData, getCustomerSummaryDetail, getCustomerSummaryList, getCustomerSummarySelectedTabType, getCustomerSummaryTrendFilter, getCustomersTabSettings, isCustomersTabVisible, } from './view/customerSummaryView/customerSummaryViewSelector';
|
|
880
880
|
export { CUSTOMER_REVENUE_KEYS } from './view/customerSummaryView/customerSummaryViewState';
|
|
881
|
+
export { fromCustomerEntityId, toCustomerWithSubCustomersId, } from './entity/genericEntity/customerWithSubCustomersId';
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { from, of } from 'rxjs';
|
|
2
|
-
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
2
|
+
import { catchError, filter, groupBy, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
3
|
import { updateCalculatedSectionAccountsView, updateSectionAccountsView, } from '../../entity/sectionAccountsView/sectionAccountsViewReducer';
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
|
|
5
5
|
import { ALL_ASSETS_SECTIONS, ALL_CURRENT_ASSETS_SECTIONS, ALL_CURRENT_LIABILITIES_SECTIONS, ALL_LIABILITIES_SECTIONS, toSectionId, } from './balanceSheetPayload';
|
|
6
6
|
import { fetchBalanceSheetForTimeframe, updateBalanceSheetForTimeframe, updateBalanceSheetForTimeframeFailure, } from './balanceSheetReducer';
|
|
7
7
|
export const reportIdUniqueKey = () => 'balance_sheet';
|
|
8
|
-
export const fetchBalanceSheetForTimeframeEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchBalanceSheetForTimeframe.match),
|
|
8
|
+
export const fetchBalanceSheetForTimeframeEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchBalanceSheetForTimeframe.match),
|
|
9
|
+
// One stream per timeframe: a newer request for the same timeframe (e.g. a
|
|
10
|
+
// custom-date-range change, or a dated fetch right after a default one)
|
|
11
|
+
// cancels the older in-flight request so a stale response can't land last.
|
|
12
|
+
groupBy((action) => action.payload.timeframe), mergeMap((group$) => group$.pipe(switchMap((action) => {
|
|
9
13
|
const getTimeSeriesGroup = (timeframe) => {
|
|
10
14
|
switch (timeframe) {
|
|
11
15
|
case 'month':
|
|
@@ -20,7 +24,8 @@ export const fetchBalanceSheetForTimeframeEpic = (actions$, _, zeniAPI) => actio
|
|
|
20
24
|
is_full_response: action.payload.fetchFullReport,
|
|
21
25
|
time_series_groups: [getTimeSeriesGroup(action.payload.timeframe)],
|
|
22
26
|
};
|
|
23
|
-
if (action.payload.startDate != null &&
|
|
27
|
+
if (action.payload.startDate != null &&
|
|
28
|
+
action.payload.endDate != null) {
|
|
24
29
|
queryValue.custom_start_date = action.payload.startDate;
|
|
25
30
|
queryValue.custom_end_date = action.payload.endDate;
|
|
26
31
|
}
|
|
@@ -73,4 +78,4 @@ export const fetchBalanceSheetForTimeframeEpic = (actions$, _, zeniAPI) => actio
|
|
|
73
78
|
}
|
|
74
79
|
}), catchError((error) => of(updateBalanceSheetForTimeframeFailure(createZeniAPIStatus('Unexpected Error', 'Balance Sheet REST API call errored out' +
|
|
75
80
|
JSON.stringify(error)), action.payload.timeframe))));
|
|
76
|
-
}));
|
|
81
|
+
}))));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
2
|
import { mapReportPayloadV2ToReportV2 } from '../../commonPayloadTypes/v2/viewAndReportPayloadv2';
|
|
3
|
+
import { withFetchedCustomDateRange } from '../../commonStateTypes/coaBalance/coaBalance';
|
|
3
4
|
import { clearAll } from '../../rootActions';
|
|
4
5
|
export const initialState = {
|
|
5
6
|
bookCloseDate: undefined,
|
|
@@ -62,6 +63,7 @@ const balanceSheet = createSlice({
|
|
|
62
63
|
fetchState: 'In-Progress',
|
|
63
64
|
error: undefined,
|
|
64
65
|
};
|
|
66
|
+
draft.customDateRangeByTimeframe = withFetchedCustomDateRange(draft.customDateRangeByTimeframe, timeframe, action.payload.startDate, action.payload.endDate);
|
|
65
67
|
},
|
|
66
68
|
},
|
|
67
69
|
updateBalanceSheetForTimeframe(draft, action) {
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { from, of } from 'rxjs';
|
|
2
|
-
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
2
|
+
import { catchError, filter, groupBy, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
3
|
import { updateCalculatedSectionAccountsView, updateSectionAccountsView, } from '../../entity/sectionAccountsView/sectionAccountsViewReducer';
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
|
|
5
5
|
import { toCashFlowReportViewID, } from './cashFlowPayload';
|
|
6
6
|
import { fetchCashFlowForTimeframe, updateCashFlowForTimeframe, updateCashFlowForTimeframeFailure, } from './cashFlowReducer';
|
|
7
7
|
export const reportIdUniqueKey = () => 'cash_flow';
|
|
8
|
-
export const fetchCashFlowForTimeframeEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchCashFlowForTimeframe.match),
|
|
8
|
+
export const fetchCashFlowForTimeframeEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchCashFlowForTimeframe.match),
|
|
9
|
+
// One stream per timeframe: a newer request for the same timeframe (e.g. a
|
|
10
|
+
// custom-date-range change, or a dated fetch right after a default one)
|
|
11
|
+
// cancels the older in-flight request so a stale response can't land last.
|
|
12
|
+
groupBy((action) => action.payload.timeframe), mergeMap((group$) => group$.pipe(switchMap((action) => {
|
|
9
13
|
const getTimeSeriesGroup = (timeframe) => {
|
|
10
14
|
switch (timeframe) {
|
|
11
15
|
case 'month':
|
|
@@ -20,7 +24,8 @@ export const fetchCashFlowForTimeframeEpic = (actions$, _, zeniAPI) => actions$.
|
|
|
20
24
|
is_full_response: action.payload.fetchFullReport,
|
|
21
25
|
time_series_groups: [getTimeSeriesGroup(action.payload.timeframe)],
|
|
22
26
|
};
|
|
23
|
-
if (action.payload.startDate != null &&
|
|
27
|
+
if (action.payload.startDate != null &&
|
|
28
|
+
action.payload.endDate != null) {
|
|
24
29
|
queryValue.custom_start_date = action.payload.startDate;
|
|
25
30
|
queryValue.custom_end_date = action.payload.endDate;
|
|
26
31
|
}
|
|
@@ -48,5 +53,6 @@ export const fetchCashFlowForTimeframeEpic = (actions$, _, zeniAPI) => actions$.
|
|
|
48
53
|
else {
|
|
49
54
|
return of(updateCashFlowForTimeframeFailure(response.status, action.payload.timeframe));
|
|
50
55
|
}
|
|
51
|
-
}), catchError((error) => of(updateCashFlowForTimeframeFailure(createZeniAPIStatus('Unexpected Error', 'Cash Flow REST API call errored out' +
|
|
52
|
-
|
|
56
|
+
}), catchError((error) => of(updateCashFlowForTimeframeFailure(createZeniAPIStatus('Unexpected Error', 'Cash Flow REST API call errored out' +
|
|
57
|
+
JSON.stringify(error)), action.payload.timeframe))));
|
|
58
|
+
}))));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
2
|
import { mapReportPayloadV2ToReportV2 } from '../../commonPayloadTypes/v2/viewAndReportPayloadv2';
|
|
3
|
+
import { withFetchedCustomDateRange } from '../../commonStateTypes/coaBalance/coaBalance';
|
|
3
4
|
import { clearAll } from '../../rootActions';
|
|
4
5
|
export const initialState = {
|
|
5
6
|
fetchState: {
|
|
@@ -54,6 +55,7 @@ const cashFlow = createSlice({
|
|
|
54
55
|
fetchState: 'In-Progress',
|
|
55
56
|
error: undefined,
|
|
56
57
|
};
|
|
58
|
+
draft.customDateRangeByTimeframe = withFetchedCustomDateRange(draft.customDateRangeByTimeframe, timeframe, action.payload.startDate, action.payload.endDate);
|
|
57
59
|
},
|
|
58
60
|
},
|
|
59
61
|
updateCashFlowForTimeframe(draft, action) {
|
|
@@ -335,6 +335,31 @@ const companyView = createSlice({
|
|
|
335
335
|
error: action.payload.status,
|
|
336
336
|
};
|
|
337
337
|
},
|
|
338
|
+
updateCustomersTabSetting: {
|
|
339
|
+
reducer(draft,
|
|
340
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
341
|
+
_action) {
|
|
342
|
+
draft.passportView.customersTabSettingsUpdateStatus = {
|
|
343
|
+
fetchState: 'In-Progress',
|
|
344
|
+
error: undefined,
|
|
345
|
+
};
|
|
346
|
+
},
|
|
347
|
+
prepare(companyId, setting, enabled, tenantId) {
|
|
348
|
+
return { payload: { companyId, enabled, setting, tenantId } };
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
updateCustomersTabSettingSuccess(draft) {
|
|
352
|
+
draft.passportView.customersTabSettingsUpdateStatus = {
|
|
353
|
+
fetchState: 'Completed',
|
|
354
|
+
error: undefined,
|
|
355
|
+
};
|
|
356
|
+
},
|
|
357
|
+
updateCustomersTabSettingFailure(draft, action) {
|
|
358
|
+
draft.passportView.customersTabSettingsUpdateStatus = {
|
|
359
|
+
fetchState: 'Error',
|
|
360
|
+
error: action.payload.status,
|
|
361
|
+
};
|
|
362
|
+
},
|
|
338
363
|
enableAccountingProjects: {
|
|
339
364
|
reducer(draft,
|
|
340
365
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -779,5 +804,5 @@ const companyView = createSlice({
|
|
|
779
804
|
});
|
|
780
805
|
},
|
|
781
806
|
});
|
|
782
|
-
export const { fetchCompanyPassportView, fetchAllCockpitViews, fetchOnboardingView, fetchManagementView, fetchSubscriptionView, fetchPortfolioView, fetchCompanyManagementView, companyManagementSaveUpdates, companyManagementSavePendingUpdates, companyManagementDiscardUpdates, companyManagementSaveUpdatesSuccess, companyManagementSaveUpdatesFailure, updateCompanyViewOnSuccess, updateCompanyViewOnFailure, fetchCompanyPortfolioView, fetchZeniUsers, updateZeniUsersOnSuccess, updateZeniUsersOnFailure, updateCompanyPortfolioUIState, updateCompanyManagementUIState, companyPassportSaveDataInLocalStore, deleteCompanyOfficerInLocalStore, companyPassportClearDataInLocalStore, companyPassportUpdateCompanyDetails, companyPassportUpdateCompanyDetailsSuccess, companyPassportUpdateCompanyDetailsFailure, updateAccountingClassesEnabled, updateAccountingClassesEnabledSuccess, updateAccountingClassesEnabledFailure, updateAutoReviewIncomeWithoutCustomer, updateAutoReviewIncomeWithoutCustomerSuccess, updateAutoReviewIncomeWithoutCustomerFailure, updateCompanyProductServices, updateCompanyProductServicesSuccess, updateCompanyProductServicesFailure, updateCompanyQboRealmId, updateCompanyQboRealmIdSuccess, updateCompanyQboRealmIdFailure, enableAccountingProjects, resumeEnableAccountingProjects, disableAccountingProjects, updateAccountingProjectsEnabledSuccess, updateAccountingProjectsEnabledFailure, requestQboProjectsReconnect, clearQboProjectsReconnectRequest, updateCapitalizationAccountThreshold, updateCapitalizationAccountThresholdSuccess, updateCapitalizationAccountThresholdFailure, dismissCapitalizationOnboarding, companyPassportUpdatePrimaryContact, companyPassportUpdatePrimaryContactSuccess, companyPassportUpdatePrimaryContactFailure, companyPassportUpdateCompanyOfficer, companyPassportUpdateCompanyOfficerSuccess, companyPassportUpdateCompanyOfficerFailure, companyPassportCreateCompanyOfficers, companyPassportCreateCompanyOfficersSuccess, companyPassportCreateCompanyOfficersFailure, updateCompanyPassportLocalStoreData, saveIndustryAndIncDateInCompanyPassportLocalStore, saveCompanyPassportDetails, fetchParentSubsidiaryManagementView, updateParentSubsidiaryView, updateParentSubsidiaryViewOnFailure, updateCompanyDownloadState, fetchCompanyMetaData, updateCompanyMetaDataOnSuccess, updateCompanyMetaDataOnFailure, updateMetaDataOnSendMonthEndReport, } = companyView.actions;
|
|
807
|
+
export const { fetchCompanyPassportView, fetchAllCockpitViews, fetchOnboardingView, fetchManagementView, fetchSubscriptionView, fetchPortfolioView, fetchCompanyManagementView, companyManagementSaveUpdates, companyManagementSavePendingUpdates, companyManagementDiscardUpdates, companyManagementSaveUpdatesSuccess, companyManagementSaveUpdatesFailure, updateCompanyViewOnSuccess, updateCompanyViewOnFailure, fetchCompanyPortfolioView, fetchZeniUsers, updateZeniUsersOnSuccess, updateZeniUsersOnFailure, updateCompanyPortfolioUIState, updateCompanyManagementUIState, companyPassportSaveDataInLocalStore, deleteCompanyOfficerInLocalStore, companyPassportClearDataInLocalStore, companyPassportUpdateCompanyDetails, companyPassportUpdateCompanyDetailsSuccess, companyPassportUpdateCompanyDetailsFailure, updateAccountingClassesEnabled, updateAccountingClassesEnabledSuccess, updateAccountingClassesEnabledFailure, updateAutoReviewIncomeWithoutCustomer, updateAutoReviewIncomeWithoutCustomerSuccess, updateAutoReviewIncomeWithoutCustomerFailure, updateCustomersTabSetting, updateCustomersTabSettingSuccess, updateCustomersTabSettingFailure, updateCompanyProductServices, updateCompanyProductServicesSuccess, updateCompanyProductServicesFailure, updateCompanyQboRealmId, updateCompanyQboRealmIdSuccess, updateCompanyQboRealmIdFailure, enableAccountingProjects, resumeEnableAccountingProjects, disableAccountingProjects, updateAccountingProjectsEnabledSuccess, updateAccountingProjectsEnabledFailure, requestQboProjectsReconnect, clearQboProjectsReconnectRequest, updateCapitalizationAccountThreshold, updateCapitalizationAccountThresholdSuccess, updateCapitalizationAccountThresholdFailure, dismissCapitalizationOnboarding, companyPassportUpdatePrimaryContact, companyPassportUpdatePrimaryContactSuccess, companyPassportUpdatePrimaryContactFailure, companyPassportUpdateCompanyOfficer, companyPassportUpdateCompanyOfficerSuccess, companyPassportUpdateCompanyOfficerFailure, companyPassportCreateCompanyOfficers, companyPassportCreateCompanyOfficersSuccess, companyPassportCreateCompanyOfficersFailure, updateCompanyPassportLocalStoreData, saveIndustryAndIncDateInCompanyPassportLocalStore, saveCompanyPassportDetails, fetchParentSubsidiaryManagementView, updateParentSubsidiaryView, updateParentSubsidiaryViewOnFailure, updateCompanyDownloadState, fetchCompanyMetaData, updateCompanyMetaDataOnSuccess, updateCompanyMetaDataOnFailure, updateMetaDataOnSendMonthEndReport, } = companyView.actions;
|
|
783
808
|
export default companyView.reducer;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { from } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { updateCompanies } from '../../../../entity/company/companyReducer';
|
|
4
|
+
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
5
|
+
import { CUSTOMERS_TAB_SETTING_API_KEYS } from '../../../../entity/tenant/tenantPayload';
|
|
6
|
+
import { updateTenantCustomersTabSetting } from '../../../../entity/tenant/tenantReducer';
|
|
7
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
8
|
+
import { updateCustomersTabSetting, updateCustomersTabSettingFailure, updateCustomersTabSettingSuccess, } from '../../companyViewReducer';
|
|
9
|
+
const failureActions = (status) => [
|
|
10
|
+
updateCustomersTabSettingFailure({ status }),
|
|
11
|
+
openSnackbar({
|
|
12
|
+
messageSection: 'customers_tab_settings_update',
|
|
13
|
+
messageText: 'failed',
|
|
14
|
+
type: 'error',
|
|
15
|
+
}),
|
|
16
|
+
];
|
|
17
|
+
/** Settings › Accounting › Customers: save one Customers tab setting (accounting_config is deep-merged). */
|
|
18
|
+
export const updateCustomersTabSettingEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(updateCustomersTabSetting.match),
|
|
19
|
+
// The two settings are separate keys: a quick second toggle mustn't cancel the first save
|
|
20
|
+
mergeMap((action) => {
|
|
21
|
+
const { companyId, enabled, setting, tenantId } = action.payload;
|
|
22
|
+
return zeniAPI
|
|
23
|
+
.putAndGetJSON(`${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/companies/${companyId}`, {
|
|
24
|
+
accounting_config: {
|
|
25
|
+
customers: { [CUSTOMERS_TAB_SETTING_API_KEYS[setting]]: enabled },
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
.pipe(mergeMap((response) => {
|
|
29
|
+
const companies = response.data?.companies ?? [];
|
|
30
|
+
if (!isSuccessResponse(response) || companies.length === 0) {
|
|
31
|
+
return from(failureActions(response.status));
|
|
32
|
+
}
|
|
33
|
+
return from([
|
|
34
|
+
updateCompanies({ payload: companies, schema: {} }),
|
|
35
|
+
updateTenantCustomersTabSetting({ enabled, setting, tenantId }),
|
|
36
|
+
updateCustomersTabSettingSuccess(),
|
|
37
|
+
openSnackbar({
|
|
38
|
+
messageSection: 'customers_tab_settings_update',
|
|
39
|
+
messageText: 'success',
|
|
40
|
+
type: 'success',
|
|
41
|
+
}),
|
|
42
|
+
]);
|
|
43
|
+
}), catchError((error) => from(failureActions(createZeniAPIStatus('Unexpected Error', 'Update Customers tab setting errored out: ' +
|
|
44
|
+
(error instanceof Error
|
|
45
|
+
? error.message
|
|
46
|
+
: JSON.stringify(error)))))));
|
|
47
|
+
}));
|
|
@@ -153,3 +153,5 @@ export const isCompanyPassportDataToBeSaved = (companyLocalStoreData, companyVie
|
|
|
153
153
|
.reduce((isDetailsUpdated, isCurDetailsUpdated) => isDetailsUpdated || isCurDetailsUpdated, false);
|
|
154
154
|
return isCompanyDataUpdated;
|
|
155
155
|
};
|
|
156
|
+
export const getIsCustomersTabSettingsUpdateInProgress = (state) => state.companyViewState.passportView.customersTabSettingsUpdateStatus
|
|
157
|
+
.fetchState === 'In-Progress';
|
|
@@ -17,6 +17,10 @@ export const initialCompanyPassportView = {
|
|
|
17
17
|
fetchState: 'Not-Started',
|
|
18
18
|
error: undefined,
|
|
19
19
|
},
|
|
20
|
+
customersTabSettingsUpdateStatus: {
|
|
21
|
+
fetchState: 'Not-Started',
|
|
22
|
+
error: undefined,
|
|
23
|
+
},
|
|
20
24
|
needsQboProjectsReconnect: false,
|
|
21
25
|
companyDetails: {
|
|
22
26
|
localData: undefined,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
+
import isEqual from 'lodash/isEqual';
|
|
3
|
+
import { updateTenantCustomersTabSetting } from '../../entity/tenant/tenantReducer';
|
|
2
4
|
import { clearAll } from '../../rootActions';
|
|
3
5
|
import { CUSTOMER_REVENUE_KEYS, } from './customerSummaryViewState';
|
|
4
6
|
export const initialState = {
|
|
@@ -20,6 +22,9 @@ export const initialState = {
|
|
|
20
22
|
detailCustomerId: undefined,
|
|
21
23
|
error: undefined,
|
|
22
24
|
};
|
|
25
|
+
const toReference = (payload) => payload != null
|
|
26
|
+
? { id: payload.customer_id, name: payload.customer_name ?? '' }
|
|
27
|
+
: undefined;
|
|
23
28
|
export const toCustomerSummary = (payload) => ({
|
|
24
29
|
id: payload.customer_id,
|
|
25
30
|
qboId: payload.qbo_id ?? undefined,
|
|
@@ -28,6 +33,22 @@ export const toCustomerSummary = (payload) => ({
|
|
|
28
33
|
currencyCode: payload.currency_code ?? undefined,
|
|
29
34
|
currencySymbol: payload.currency_symbol ?? undefined,
|
|
30
35
|
revenue: Object.fromEntries(CUSTOMER_REVENUE_KEYS.map((key) => [key, payload[key] ?? 0])),
|
|
36
|
+
hasChildren: payload.has_children === true,
|
|
37
|
+
isProject: payload.is_project === true,
|
|
38
|
+
isSubCustomer: payload.is_sub_customer === true,
|
|
39
|
+
parentId: payload.parent_customer_id ?? undefined,
|
|
40
|
+
parentPath: (payload.parent_path ?? []).flatMap((parent) => toReference(parent) ?? []),
|
|
41
|
+
familyTree: payload.family_tree?.map(toCustomerSummary),
|
|
42
|
+
// Only the details response carries them
|
|
43
|
+
totals: payload.total_balance != null
|
|
44
|
+
? {
|
|
45
|
+
balance: payload.total_balance,
|
|
46
|
+
revenue: Object.fromEntries(CUSTOMER_REVENUE_KEYS.map((key) => [
|
|
47
|
+
key,
|
|
48
|
+
payload[`total_${key}`] ?? 0,
|
|
49
|
+
])),
|
|
50
|
+
}
|
|
51
|
+
: undefined,
|
|
31
52
|
account: payload.account?.account_id != null
|
|
32
53
|
? {
|
|
33
54
|
id: payload.account.account_id,
|
|
@@ -73,11 +94,16 @@ const customerSummaryView = createSlice({
|
|
|
73
94
|
},
|
|
74
95
|
},
|
|
75
96
|
updateCustomerSummaryList: {
|
|
76
|
-
prepare(response, keepExistingListItems) {
|
|
77
|
-
return { payload: { keepExistingListItems, response } };
|
|
97
|
+
prepare(response, keepExistingListItems, settings) {
|
|
98
|
+
return { payload: { keepExistingListItems, response, settings } };
|
|
78
99
|
},
|
|
79
100
|
reducer(draft, action) {
|
|
80
|
-
const { response, keepExistingListItems } = action.payload;
|
|
101
|
+
const { response, keepExistingListItems, settings } = action.payload;
|
|
102
|
+
// A next page fetched under other settings than the listed rows: drop it, the list refetches
|
|
103
|
+
if (keepExistingListItems && !isEqual(draft.listSettings, settings)) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
draft.listSettings = settings;
|
|
81
107
|
const customers = (response.data?.customers ?? []).map(toCustomerSummary);
|
|
82
108
|
const existingIds = new Set(draft.customers.map(({ id }) => id));
|
|
83
109
|
draft.customers = keepExistingListItems
|
|
@@ -126,12 +152,13 @@ const customerSummaryView = createSlice({
|
|
|
126
152
|
detail.customer = toCustomerSummary(action.payload.customer);
|
|
127
153
|
detail.fetchState = 'Completed';
|
|
128
154
|
// Keep the list row in sync after an edit.
|
|
155
|
+
const { account, accountingClass } = detail.customer;
|
|
129
156
|
const index = draft.customers.findIndex(({ id }) => id === action.payload.customerId);
|
|
130
157
|
if (index >= 0) {
|
|
131
158
|
draft.customers[index] = {
|
|
132
159
|
...draft.customers[index],
|
|
133
|
-
account
|
|
134
|
-
accountingClass
|
|
160
|
+
account,
|
|
161
|
+
accountingClass,
|
|
135
162
|
};
|
|
136
163
|
}
|
|
137
164
|
},
|
|
@@ -188,8 +215,14 @@ const customerSummaryView = createSlice({
|
|
|
188
215
|
},
|
|
189
216
|
},
|
|
190
217
|
extraReducers: (builder) => {
|
|
191
|
-
builder
|
|
218
|
+
builder
|
|
219
|
+
.addCase(clearAll, (draft) => {
|
|
192
220
|
Object.assign(draft, initialState);
|
|
221
|
+
})
|
|
222
|
+
// Totals on / off switch the detail page's All transactions tab to another entity: restart its window.
|
|
223
|
+
// (The list refetches through `getCustomerSummaryList`; the details carry both figures.)
|
|
224
|
+
.addCase(updateTenantCustomersTabSetting, (draft) => {
|
|
225
|
+
draft.allTransactionsTabData = undefined;
|
|
193
226
|
});
|
|
194
227
|
},
|
|
195
228
|
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { createSelector } from '@reduxjs/toolkit';
|
|
2
|
-
import
|
|
2
|
+
import isEqual from 'lodash/isEqual';
|
|
3
|
+
import { toCustomerWithSubCustomersId } from '../../entity/genericEntity/customerWithSubCustomersId';
|
|
4
|
+
import { getIsAccountingClassesEnabled, getTenantCustomersTabSettings, } from '../../entity/tenant/tenantSelector';
|
|
5
|
+
import { DEFAULT_CUSTOMERS_TAB_SETTINGS, } from '../../entity/tenant/tenantState';
|
|
3
6
|
import { getNestedAccountListHierarchy } from '../accountList/accountListSelector';
|
|
4
7
|
import { getNestedClassListHierarchy } from '../classList/classListSelector';
|
|
5
8
|
const isLoadingFetchState = (fetchState) => fetchState === 'Not-Started' || fetchState === 'In-Progress';
|
|
@@ -7,16 +10,43 @@ const NOT_STARTED_DETAIL = {
|
|
|
7
10
|
fetchState: 'Not-Started',
|
|
8
11
|
saveState: 'Not-Started',
|
|
9
12
|
};
|
|
10
|
-
export const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
export const getCustomersTabSettings = (state) => {
|
|
14
|
+
const { currentTenantId } = state.tenantState;
|
|
15
|
+
return ((currentTenantId != null
|
|
16
|
+
? getTenantCustomersTabSettings(state.tenantState, currentTenantId)
|
|
17
|
+
: undefined) ?? DEFAULT_CUSTOMERS_TAB_SETTINGS);
|
|
18
|
+
};
|
|
19
|
+
/** Rows fetched under other Customers tab settings (however those changed) read as not fetched yet. */
|
|
20
|
+
export const getCustomerSummaryList = createSelector((state) => state.customerSummaryViewState, getCustomersTabSettings, (view, settings) => view.listSettings == null || isEqual(view.listSettings, settings)
|
|
21
|
+
? view
|
|
22
|
+
: {
|
|
23
|
+
...view,
|
|
24
|
+
customers: [],
|
|
25
|
+
error: undefined,
|
|
26
|
+
fetchState: 'Not-Started',
|
|
27
|
+
totalCount: 0,
|
|
28
|
+
uiState: { ...view.uiState, pageToken: null, scrollYOffset: 0 },
|
|
29
|
+
});
|
|
30
|
+
export const getCustomerSummaryDetail = createSelector((state, customerId) => state.customerSummaryViewState.detailById[customerId], (state) => state.accountListState, (state) => state.classListState, getIsAccountingClassesEnabled, (state) => getCustomersTabSettings(state).includeSubCustomersInTotals, (_state, customerId) => customerId, (detail, accountListState, classListState, isAccountingClassesEnabled, includeSubCustomersInTotals, customerId) => {
|
|
31
|
+
const customer = detail?.customer;
|
|
32
|
+
// Rolled up from the start (in parallel with the details); own figures if the details turn out to have no totals
|
|
33
|
+
const includesSubCustomers = includeSubCustomersInTotals &&
|
|
34
|
+
(customer == null || customer.totals != null);
|
|
35
|
+
return {
|
|
36
|
+
...(detail ?? NOT_STARTED_DETAIL),
|
|
37
|
+
accountsHierarchyList: getNestedAccountListHierarchy(accountListState, 'accountList'),
|
|
38
|
+
classHierarchyList: getNestedClassListHierarchy(classListState),
|
|
39
|
+
isAccountingClassesEnabled,
|
|
40
|
+
isReferenceDataLoading: isLoadingFetchState(accountListState.byReportId.accountList.fetchState) ||
|
|
41
|
+
(isAccountingClassesEnabled &&
|
|
42
|
+
isLoadingFetchState(classListState.fetchState)),
|
|
43
|
+
includesSubCustomers,
|
|
44
|
+
figures: includesSubCustomers ? customer?.totals : customer,
|
|
45
|
+
trendEntityId: includesSubCustomers
|
|
46
|
+
? toCustomerWithSubCustomersId(customerId)
|
|
47
|
+
: customerId,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
20
50
|
export const getCustomerSummarySelectedTabType = (state) => state.customerSummaryViewState.selectedTabType;
|
|
21
51
|
export const getCustomerSummaryAllTransactionsTabData = (state) => state.customerSummaryViewState.allTransactionsTabData;
|
|
22
52
|
export const getCustomerSummaryTrendFilter = (state) => state.customerSummaryViewState.trendFilter;
|
|
@@ -2,21 +2,26 @@ import { of } from 'rxjs';
|
|
|
2
2
|
import { catchError, exhaustMap, filter, map, startWith, switchMap, } from 'rxjs/operators';
|
|
3
3
|
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
4
4
|
import { fetchCustomerSummaryList, updateCustomerSummaryList, updateCustomerSummaryListFailure, } from '../customerSummaryViewReducer';
|
|
5
|
+
import { getCustomersTabSettings } from '../customerSummaryViewSelector';
|
|
5
6
|
export const fetchCustomerSummaryListEpic = (actions$, state$, zeniAPI) => {
|
|
6
7
|
const fetch$ = actions$.pipe(filter(fetchCustomerSummaryList.match));
|
|
7
8
|
const fetchPage = (action) => {
|
|
8
9
|
const { keepExistingListItems, pageToken, searchString } = action.payload;
|
|
9
10
|
const { uiState } = state$.value.customerSummaryViewState;
|
|
11
|
+
const settings = getCustomersTabSettings(state$.value);
|
|
10
12
|
const query = {
|
|
11
13
|
page_token: pageToken,
|
|
12
14
|
sort_by: uiState.sortKey,
|
|
13
15
|
sort_order: uiState.sortOrder === 'ascending' ? 'asc' : 'desc',
|
|
14
16
|
search_text: searchString,
|
|
17
|
+
// Top-level only: a search also finds a customer by its sub-customers' and projects' names
|
|
18
|
+
top_level_only: settings.listTopLevelCustomersOnly,
|
|
19
|
+
include_sub_customers: settings.includeSubCustomersInTotals,
|
|
15
20
|
};
|
|
16
21
|
return zeniAPI
|
|
17
22
|
.getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/customers/summary?query=${encodeURIComponent(JSON.stringify(query))}`)
|
|
18
23
|
.pipe(map((response) => isSuccessResponse(response)
|
|
19
|
-
? updateCustomerSummaryList(response, keepExistingListItems)
|
|
24
|
+
? updateCustomerSummaryList(response, keepExistingListItems, settings)
|
|
20
25
|
: updateCustomerSummaryListFailure(response.status)), catchError((error) => of(updateCustomerSummaryListFailure(createZeniAPIStatus('Unexpected Error', 'Fetch customer summary list REST API call errored out' +
|
|
21
26
|
JSON.stringify(error))))));
|
|
22
27
|
};
|