@zeniai/client-epic-state 5.2.12 → 5.2.13-betaAK0
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/esm/index.js +5 -4
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/confirmStatementMappingEpic.js +23 -7
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/updateCombinedStatementInfoEpic.js +1 -1
- package/lib/esm/view/expenseAutomationView/payload/reconciliationPayload.js +1 -1
- package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +5 -0
- package/lib/esm/view/expenseAutomationView/selectors/reconciliationViewSelector.js +33 -2
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/catalogDetailEditPayload.js +24 -7
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +1 -1
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +6 -8
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogSubFamilyEpics.js +8 -2
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +15 -10
- package/lib/esm/view/invoicing/invoicingQboView/epics/fetchInvoicingAccountingPickersEpic.js +0 -1
- package/lib/esm/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +15 -36
- package/lib/index.d.ts +7 -5
- package/lib/index.js +49 -46
- package/lib/view/expenseAutomationView/epics/accountRecon/confirmStatementMappingEpic.js +23 -7
- package/lib/view/expenseAutomationView/epics/accountRecon/updateCombinedStatementInfoEpic.js +1 -1
- package/lib/view/expenseAutomationView/payload/reconciliationPayload.d.ts +8 -3
- package/lib/view/expenseAutomationView/payload/reconciliationPayload.js +1 -1
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +5 -0
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.d.ts +3 -1
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.js +34 -2
- package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +6 -0
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/catalogDetailEditPayload.d.ts +11 -2
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/catalogDetailEditPayload.js +24 -7
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.d.ts +7 -0
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +4 -3
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.d.ts +19 -4
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.d.ts +5 -4
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +5 -7
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogSubFamilyEpics.d.ts +1 -1
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogSubFamilyEpics.js +8 -2
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +14 -9
- package/lib/view/invoicing/invoicingQboView/epics/fetchInvoicingAccountingPickersEpic.js +0 -1
- package/lib/view/invoicing/invoicingQboView/invoicingQboViewSelector.d.ts +12 -13
- package/lib/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +16 -38
- package/package.json +1 -1
|
@@ -271,7 +271,7 @@ function transformConfirmStatementMappingConflictToState(response) {
|
|
|
271
271
|
}
|
|
272
272
|
function transformUpdateStatementInfoPayloadToState(payload) {
|
|
273
273
|
if (isUpdateStatementInfoCombinedResponsePayload(payload) === true) {
|
|
274
|
-
const statementUploads = payload.statement_uploads.map(transformStatementUploadPayloadToState);
|
|
274
|
+
const statementUploads = payload.statement_uploads.map((item) => transformStatementUploadPayloadToState(item.statement_upload));
|
|
275
275
|
const anchorUpload = statementUploads.find((upload) => upload.statementMeta.isCombinedStatementAnchor === true) ?? statementUploads[0];
|
|
276
276
|
return {
|
|
277
277
|
statementUpload: anchorUpload,
|
|
@@ -469,6 +469,7 @@ const expenseAutomationReconciliationView = (0, toolkit_1.createSlice)({
|
|
|
469
469
|
accountRecon.confirmStatementMappingConflict = null;
|
|
470
470
|
if (accountRecon.localData != null) {
|
|
471
471
|
accountRecon.localData.statementUpdateLocalDataByUploadId = undefined;
|
|
472
|
+
accountRecon.localData.combinedStatementAccountMappings = undefined;
|
|
472
473
|
}
|
|
473
474
|
if (statementAccountScope != null) {
|
|
474
475
|
accountRecon.localData = {
|
|
@@ -547,6 +548,7 @@ const expenseAutomationReconciliationView = (0, toolkit_1.createSlice)({
|
|
|
547
548
|
accountRecon.confirmStatementMappingConflict = null;
|
|
548
549
|
if (accountRecon.localData != null) {
|
|
549
550
|
accountRecon.localData.statementUpdateLocalDataByUploadId = undefined;
|
|
551
|
+
accountRecon.localData.combinedStatementAccountMappings = undefined;
|
|
550
552
|
accountRecon.localData.statementAccountScope = undefined;
|
|
551
553
|
}
|
|
552
554
|
}
|
|
@@ -777,6 +779,9 @@ const expenseAutomationReconciliationView = (0, toolkit_1.createSlice)({
|
|
|
777
779
|
};
|
|
778
780
|
accountRecon.confirmStatementMappingConflict = null;
|
|
779
781
|
accountRecon.confirmedCombinedStatementUploads = statementUploads;
|
|
782
|
+
if (accountRecon.localData != null) {
|
|
783
|
+
accountRecon.localData.combinedStatementAccountMappings = undefined;
|
|
784
|
+
}
|
|
780
785
|
const combinedStatementDetails = accountRecon.parsedStatementData?.statementUpload
|
|
781
786
|
.combinedStatementDetails;
|
|
782
787
|
if (combinedStatementDetails != null) {
|
|
@@ -5,6 +5,8 @@ import { RootState } from '../../../rootStateTypes';
|
|
|
5
5
|
import { AccountReconciliationByAccount, ExpenseAutomationReconciliationViewSelector } from '../selectorTypes/reconciliationViewSelectorTypes';
|
|
6
6
|
export declare const getExpenseAutomationReconciliationView: (state: RootState) => ExpenseAutomationReconciliationViewSelector;
|
|
7
7
|
export declare const getReparseStatementStatusByAccountId: (state: RootState, accountId: ID) => import("../../../commonStateTypes/common").FetchStateAndError;
|
|
8
|
-
export declare function getLedgerAccountsForCombinedStatementMapping(accountReconciliationsByAccountID: Record<ID, AccountReconciliationByAccount
|
|
8
|
+
export declare function getLedgerAccountsForCombinedStatementMapping(accountReconciliationsByAccountID: Record<ID, AccountReconciliationByAccount>, selectedAccountId: ID): AccountBase[];
|
|
9
9
|
export declare function getUnavailableLedgerAccountIds(accountReconciliationsByAccountID: Record<ID, AccountReconciliationByAccount>): ID[];
|
|
10
|
+
/** Selectable accounts that already have a statement — mapping will override that work. */
|
|
11
|
+
export declare function getLedgerAccountIdsWithStatementOverrideWarning(accountReconciliationsByAccountID: Record<ID, AccountReconciliationByAccount>, selectedAccountId?: ID): ID[];
|
|
10
12
|
export declare const isAccountReconReport: (reportId: ReportIDPlusForecastID) => boolean;
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.isAccountReconReport = exports.getReparseStatementStatusByAccountId = exports.getExpenseAutomationReconciliationView = void 0;
|
|
7
7
|
exports.getLedgerAccountsForCombinedStatementMapping = getLedgerAccountsForCombinedStatementMapping;
|
|
8
8
|
exports.getUnavailableLedgerAccountIds = getUnavailableLedgerAccountIds;
|
|
9
|
+
exports.getLedgerAccountIdsWithStatementOverrideWarning = getLedgerAccountIdsWithStatementOverrideWarning;
|
|
9
10
|
const toolkit_1 = require("@reduxjs/toolkit");
|
|
10
11
|
const big_js_1 = __importDefault(require("big.js"));
|
|
11
12
|
const keys_1 = __importDefault(require("lodash/keys"));
|
|
@@ -484,8 +485,18 @@ exports.getExpenseAutomationReconciliationView = (0, toolkit_1.createSelector)((
|
|
|
484
485
|
const getReparseStatementStatusByAccountId = (state, accountId) => (0, exports.getExpenseAutomationReconciliationView)(state)
|
|
485
486
|
.accountReconciliationsByAccountID[accountId]?.reparseStatementStatus;
|
|
486
487
|
exports.getReparseStatementStatusByAccountId = getReparseStatementStatusByAccountId;
|
|
487
|
-
function getLedgerAccountsForCombinedStatementMapping(accountReconciliationsByAccountID) {
|
|
488
|
-
|
|
488
|
+
function getLedgerAccountsForCombinedStatementMapping(accountReconciliationsByAccountID, selectedAccountId) {
|
|
489
|
+
const selectedAccountType = accountReconciliationsByAccountID[selectedAccountId]?.accountReconEntity
|
|
490
|
+
.account.accountType;
|
|
491
|
+
const shouldFilterByPaymentAccountType = selectedAccountType === 'bank' || selectedAccountType === 'credit_card';
|
|
492
|
+
return Object.values(accountReconciliationsByAccountID)
|
|
493
|
+
.map((accountReconciliation) => accountReconciliation.accountReconEntity.account)
|
|
494
|
+
.filter((account) => {
|
|
495
|
+
if (shouldFilterByPaymentAccountType !== true) {
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
498
|
+
return account.accountType === selectedAccountType;
|
|
499
|
+
});
|
|
489
500
|
}
|
|
490
501
|
const UNAVAILABLE_LEDGER_ACCOUNT_RECON_STATUSES = new Set(['in_progress', 'reconciled', 'reconciled_on_qbo']);
|
|
491
502
|
function getUnavailableLedgerAccountIds(accountReconciliationsByAccountID) {
|
|
@@ -497,6 +508,27 @@ function getUnavailableLedgerAccountIds(accountReconciliationsByAccountID) {
|
|
|
497
508
|
})
|
|
498
509
|
.map((accountReconciliation) => accountReconciliation.accountReconEntity.account.accountId);
|
|
499
510
|
}
|
|
511
|
+
/** Selectable accounts that already have a statement — mapping will override that work. */
|
|
512
|
+
function getLedgerAccountIdsWithStatementOverrideWarning(accountReconciliationsByAccountID, selectedAccountId) {
|
|
513
|
+
return Object.values(accountReconciliationsByAccountID)
|
|
514
|
+
.filter((accountReconciliation) => {
|
|
515
|
+
const entity = accountReconciliation.accountReconEntity;
|
|
516
|
+
const accountId = entity.account.accountId;
|
|
517
|
+
if (selectedAccountId != null && accountId === selectedAccountId) {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
const hasUploadedStatement = entity.statementStatus?.code === 'uploaded' ||
|
|
521
|
+
entity.statementMetaData?.file != null ||
|
|
522
|
+
accountReconciliation.statementParseInProgress === true;
|
|
523
|
+
if (hasUploadedStatement !== true) {
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
const statusCode = entity.reconciliationStatus?.code;
|
|
527
|
+
return (statusCode == null ||
|
|
528
|
+
UNAVAILABLE_LEDGER_ACCOUNT_RECON_STATUSES.has(statusCode) !== true);
|
|
529
|
+
})
|
|
530
|
+
.map((accountReconciliation) => accountReconciliation.accountReconEntity.account.accountId);
|
|
531
|
+
}
|
|
500
532
|
const isAccountReconReport = (reportId) => {
|
|
501
533
|
return reportId.endsWith('reconciliation');
|
|
502
534
|
};
|
|
@@ -358,8 +358,14 @@ export declare const toStatementAccountScope: (v: string) => "single_account" |
|
|
|
358
358
|
export type StatementAccountScope = ReturnType<typeof toStatementAccountScope>;
|
|
359
359
|
export declare const toStatementAccountScopeStrict: (v: string | null | undefined) => StatementAccountScope | undefined;
|
|
360
360
|
export declare const STATEMENT_ACCOUNT_SCOPES: readonly StatementAccountScope[];
|
|
361
|
+
export interface CombinedStatementAccountMappingDraft {
|
|
362
|
+
accountId: ID;
|
|
363
|
+
ledgerIdentifier: string;
|
|
364
|
+
}
|
|
361
365
|
export interface AccountReconciliationLocalData {
|
|
362
366
|
accountSource?: ReconciliationAccountSourceType;
|
|
367
|
+
/** Draft ledger mappings saved when continuing combined mapping in background. */
|
|
368
|
+
combinedStatementAccountMappings?: CombinedStatementAccountMappingDraft[];
|
|
363
369
|
statementAccountScope?: StatementAccountScope;
|
|
364
370
|
/** Confirm & Save drafts keyed by statementUploadId (single and combined). */
|
|
365
371
|
statementUpdateLocalDataByUploadId?: Record<string, StatementUpdateLocalData>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Amount } from '../../../commonStateTypes/amount';
|
|
2
2
|
import type { InvoicingPlan } from '../../../entity/invoicing/plan/planState';
|
|
3
3
|
import type { InvoicingProduct } from '../../../entity/invoicing/product/productState';
|
|
4
|
+
import { type InvoicingCatalogAccountingLookup } from './editInvoicingCatalogItemDetailViewPayload';
|
|
4
5
|
import type { InvoicingCatalogItemFormSubFamily, InvoicingCatalogItemFormTier } from './editInvoicingCatalogItemDetailViewState';
|
|
5
6
|
export type CatalogDetailSubFamilyEditValues = InvoicingCatalogItemFormSubFamily;
|
|
6
7
|
export interface CatalogDetailEditValues {
|
|
@@ -30,18 +31,26 @@ export interface CatalogDetailSavePayload {
|
|
|
30
31
|
}
|
|
31
32
|
/** Build default inline-edit form values from a loaded catalog item. */
|
|
32
33
|
export declare const planToCatalogDetailEditValues: (plan: InvoicingPlan) => CatalogDetailEditValues;
|
|
33
|
-
export declare const catalogDetailEditValuesToSavePayload: (values: CatalogDetailEditValues, itemType?: string, originalSubFamilies?: readonly InvoicingProduct[]) => CatalogDetailSavePayload;
|
|
34
|
+
export declare const catalogDetailEditValuesToSavePayload: (values: CatalogDetailEditValues, lookup: InvoicingCatalogAccountingLookup, itemType?: string, originalSubFamilies?: readonly InvoicingProduct[]) => CatalogDetailSavePayload;
|
|
34
35
|
export interface CreateSubFamilyFormValues {
|
|
36
|
+
/** The QuickBooks class id the price point posts to. */
|
|
37
|
+
accountingCategory: string;
|
|
38
|
+
/** The QuickBooks income account id the price point posts to. */
|
|
39
|
+
accountingCode: string;
|
|
35
40
|
billingCycles: string;
|
|
36
41
|
description: string;
|
|
37
42
|
freeQuantity: string;
|
|
38
43
|
invoiceNotes: string;
|
|
44
|
+
isTaxable: boolean;
|
|
39
45
|
name: string;
|
|
40
46
|
period: string;
|
|
41
47
|
periodUnit: string;
|
|
42
48
|
priceCode: string;
|
|
43
49
|
pricingModel: string;
|
|
44
50
|
prorationType: string;
|
|
51
|
+
showDescriptionInInvoices: boolean;
|
|
52
|
+
showDescriptionInQuotes: boolean;
|
|
53
|
+
sku: string;
|
|
45
54
|
trialEndAction: string;
|
|
46
55
|
trialPeriod: string;
|
|
47
56
|
trialPeriodUnit: string;
|
|
@@ -50,5 +59,5 @@ export interface CreateSubFamilyFormValues {
|
|
|
50
59
|
tiers?: InvoicingCatalogItemFormTier[];
|
|
51
60
|
}
|
|
52
61
|
/** Build POST /catalog/products body for Create sub-family. */
|
|
53
|
-
export declare const createSubFamilyFormToPayload: (itemId: string, itemType: string, values: CreateSubFamilyFormValues) => Record<string, unknown>;
|
|
62
|
+
export declare const createSubFamilyFormToPayload: (itemId: string, itemType: string, values: CreateSubFamilyFormValues, lookup: InvoicingCatalogAccountingLookup) => Record<string, unknown>;
|
|
54
63
|
export declare const productToCreateSubFamilyFormValues: (product?: InvoicingProduct) => CreateSubFamilyFormValues;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.productToCreateSubFamilyFormValues = exports.createSubFamilyFormToPayload = exports.catalogDetailEditValuesToSavePayload = exports.planToCatalogDetailEditValues = void 0;
|
|
4
|
+
const editInvoicingCatalogItemDetailViewPayload_1 = require("./editInvoicingCatalogItemDetailViewPayload");
|
|
4
5
|
const invoicingCatalogItemFormConfig_1 = require("./invoicingCatalogItemFormConfig");
|
|
5
6
|
const trimOrUndefined = (value) => value.trim() !== '' ? value.trim() : undefined;
|
|
6
7
|
const trimOrNull = (value) => value.trim() !== '' ? value.trim() : null;
|
|
@@ -39,7 +40,7 @@ const tierToPayload = (tier) => ({
|
|
|
39
40
|
pricing_type: tier.pricingType,
|
|
40
41
|
starting_unit: Number(tier.startingUnit) || 1,
|
|
41
42
|
});
|
|
42
|
-
const subFamilyToProductUpdate = (subFamily, itemType) => {
|
|
43
|
+
const subFamilyToProductUpdate = (subFamily, itemType, lookup) => {
|
|
43
44
|
const tiered = (0, invoicingCatalogItemFormConfig_1.isTieredCatalogPricingModel)(subFamily.pricingModel);
|
|
44
45
|
const data = {
|
|
45
46
|
billing_cycles: hasValue(subFamily.billingCycles)
|
|
@@ -66,9 +67,12 @@ const subFamilyToProductUpdate = (subFamily, itemType) => {
|
|
|
66
67
|
if (itemType === 'addon') {
|
|
67
68
|
data.proration_type = subFamily.prorationType;
|
|
68
69
|
}
|
|
70
|
+
// `null` rather than omitted when empty: an absent key on an update reads as
|
|
71
|
+
// "leave it alone", so a cleared account or class could never be saved.
|
|
72
|
+
data.accounting_detail = (0, editInvoicingCatalogItemDetailViewPayload_1.buildAccountingDetail)(subFamily, lookup) ?? null;
|
|
69
73
|
return { data, id: subFamily.id };
|
|
70
74
|
};
|
|
71
|
-
const catalogDetailEditValuesToSavePayload = (values, itemType = 'plan', originalSubFamilies) => {
|
|
75
|
+
const catalogDetailEditValuesToSavePayload = (values, lookup, itemType = 'plan', originalSubFamilies) => {
|
|
72
76
|
const planData = {
|
|
73
77
|
applicable_items: values.itemApplicability === 'restricted' ? values.applicableItems : [],
|
|
74
78
|
enabled_for_checkout: values.enabledForCheckout,
|
|
@@ -100,12 +104,12 @@ const catalogDetailEditValuesToSavePayload = (values, itemType = 'plan', origina
|
|
|
100
104
|
planData.unit = unit;
|
|
101
105
|
}
|
|
102
106
|
const productUpdates = values.subFamilies.flatMap((subFamily) => {
|
|
103
|
-
const update = subFamilyToProductUpdate(subFamily, itemType);
|
|
107
|
+
const update = subFamilyToProductUpdate(subFamily, itemType, lookup);
|
|
104
108
|
const original = originalSubFamilies?.find((product) => product.id === subFamily.id);
|
|
105
109
|
if (original == null) {
|
|
106
110
|
return [update];
|
|
107
111
|
}
|
|
108
|
-
const originalUpdate = subFamilyToProductUpdate(subFamilyToEditValues(original), itemType);
|
|
112
|
+
const originalUpdate = subFamilyToProductUpdate(subFamilyToEditValues(original), itemType, lookup);
|
|
109
113
|
const changedData = Object.fromEntries(Object.entries(update.data).filter(([key, value]) => JSON.stringify(value) !== JSON.stringify(originalUpdate.data[key])));
|
|
110
114
|
return Object.keys(changedData).length > 0
|
|
111
115
|
? [{ data: changedData, id: update.id }]
|
|
@@ -118,21 +122,28 @@ const catalogDetailEditValuesToSavePayload = (values, itemType = 'plan', origina
|
|
|
118
122
|
};
|
|
119
123
|
exports.catalogDetailEditValuesToSavePayload = catalogDetailEditValuesToSavePayload;
|
|
120
124
|
/** Build POST /catalog/products body for Create sub-family. */
|
|
121
|
-
const createSubFamilyFormToPayload = (itemId, itemType, values) => {
|
|
125
|
+
const createSubFamilyFormToPayload = (itemId, itemType, values, lookup) => {
|
|
122
126
|
const name = values.name.trim();
|
|
123
127
|
const priceCode = trimOrUndefined(values.priceCode) ?? toProductCode(name);
|
|
124
128
|
const tiered = (0, invoicingCatalogItemFormConfig_1.isTieredCatalogPricingModel)(values.pricingModel);
|
|
125
129
|
const payload = {
|
|
126
130
|
currency_code: 'USD',
|
|
127
131
|
free_quantity: Number(values.freeQuantity) || 0,
|
|
128
|
-
is_taxable:
|
|
132
|
+
is_taxable: values.isTaxable,
|
|
129
133
|
item_id: itemId,
|
|
130
134
|
name,
|
|
131
135
|
price: tiered ? 0 : (values.priceDollars?.amount ?? 0),
|
|
132
136
|
price_code: priceCode,
|
|
133
137
|
pricing_model: values.pricingModel || 'flat_fee',
|
|
134
|
-
show_description_in_invoices:
|
|
138
|
+
show_description_in_invoices: values.showDescriptionInInvoices,
|
|
139
|
+
show_description_in_quotes: values.showDescriptionInQuotes,
|
|
135
140
|
};
|
|
141
|
+
// The same accounting body the item payload sends, so a price point created
|
|
142
|
+
// from the dialog carries the account and class the form would have given it.
|
|
143
|
+
const accountingDetail = (0, editInvoicingCatalogItemDetailViewPayload_1.buildAccountingDetail)(values, lookup);
|
|
144
|
+
if (accountingDetail != null) {
|
|
145
|
+
payload.accounting_detail = accountingDetail;
|
|
146
|
+
}
|
|
136
147
|
if (tiered) {
|
|
137
148
|
payload.tiers = (values.tiers ?? []).map(tierToPayload);
|
|
138
149
|
}
|
|
@@ -163,10 +174,13 @@ const createSubFamilyFormToPayload = (itemId, itemType, values) => {
|
|
|
163
174
|
};
|
|
164
175
|
exports.createSubFamilyFormToPayload = createSubFamilyFormToPayload;
|
|
165
176
|
const productToCreateSubFamilyFormValues = (product) => ({
|
|
177
|
+
accountingCategory: product?.accountingDetail?.accountingCategory1 ?? '',
|
|
178
|
+
accountingCode: product?.accountingDetail?.accountingCode ?? '',
|
|
166
179
|
billingCycles: product?.billingCycles != null ? String(product.billingCycles) : '',
|
|
167
180
|
description: product?.description ?? '',
|
|
168
181
|
freeQuantity: product?.freeQuantity != null ? String(product.freeQuantity) : '0',
|
|
169
182
|
invoiceNotes: product?.invoiceNotes ?? '',
|
|
183
|
+
isTaxable: product?.isTaxable ?? true,
|
|
170
184
|
name: product?.name != null ? `${product.name} (copy)` : '',
|
|
171
185
|
period: product?.period != null ? String(product.period) : '1',
|
|
172
186
|
periodUnit: product?.periodUnit ?? 'month',
|
|
@@ -174,6 +188,9 @@ const productToCreateSubFamilyFormValues = (product) => ({
|
|
|
174
188
|
priceDollars: product?.price,
|
|
175
189
|
pricingModel: product?.pricingModel ?? 'flat_fee',
|
|
176
190
|
prorationType: product?.prorationType ?? 'site_default',
|
|
191
|
+
showDescriptionInInvoices: product?.showDescriptionInInvoices ?? true,
|
|
192
|
+
showDescriptionInQuotes: product?.showDescriptionInQuotes ?? false,
|
|
193
|
+
sku: product?.accountingDetail?.sku ?? '',
|
|
177
194
|
trialEndAction: product?.trialEndAction ?? 'site_default',
|
|
178
195
|
trialPeriod: product?.trialPeriod != null ? String(product.trialPeriod) : '',
|
|
179
196
|
trialPeriodUnit: product?.trialPeriodUnit ?? 'day',
|
|
@@ -13,6 +13,13 @@ export interface InvoicingCatalogAccountingLookup {
|
|
|
13
13
|
accountByQboId: (qboId: string) => AccountBase | undefined;
|
|
14
14
|
classByQboId: (qboId: string) => ClassBase | undefined;
|
|
15
15
|
}
|
|
16
|
+
/** The accounting fields any price-point form collects. */
|
|
17
|
+
export interface InvoicingCatalogAccountingFields {
|
|
18
|
+
accountingCategory: string;
|
|
19
|
+
accountingCode: string;
|
|
20
|
+
sku: string;
|
|
21
|
+
}
|
|
22
|
+
export declare const buildAccountingDetail: (subFamily: InvoicingCatalogAccountingFields, lookup: InvoicingCatalogAccountingLookup) => Record<string, unknown> | undefined;
|
|
16
23
|
/**
|
|
17
24
|
* Build the parent catalog-item request body from the form draft. Creates omit
|
|
18
25
|
* both parent and sub-family IDs; edits retain returned sub-family IDs.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.localDataToSaveInvoicingCatalogItemPayload = void 0;
|
|
3
|
+
exports.localDataToSaveInvoicingCatalogItemPayload = exports.buildAccountingDetail = void 0;
|
|
4
4
|
const accountPayload_1 = require("../../../entity/account/accountPayload");
|
|
5
5
|
const classPayload_1 = require("../../../entity/class/classPayload");
|
|
6
6
|
const invoicingCatalogItemFormConfig_1 = require("./invoicingCatalogItemFormConfig");
|
|
@@ -31,6 +31,7 @@ const buildAccountingDetail = (subFamily, lookup) => {
|
|
|
31
31
|
}
|
|
32
32
|
return Object.keys(detail).length > 0 ? detail : undefined;
|
|
33
33
|
};
|
|
34
|
+
exports.buildAccountingDetail = buildAccountingDetail;
|
|
34
35
|
const buildSubFamilyPayload = (localData, subFamily, clearEmptyValues, lookup) => {
|
|
35
36
|
const isAddon = localData.catalogType === 'addon';
|
|
36
37
|
const tiered = (0, invoicingCatalogItemFormConfig_1.isTieredCatalogPricingModel)(subFamily.pricingModel);
|
|
@@ -85,7 +86,7 @@ const buildSubFamilyPayload = (localData, subFamily, clearEmptyValues, lookup) =
|
|
|
85
86
|
starting_unit: Number(tier.startingUnit) || 1,
|
|
86
87
|
}));
|
|
87
88
|
}
|
|
88
|
-
const accountingDetail = buildAccountingDetail(subFamily, lookup);
|
|
89
|
+
const accountingDetail = (0, exports.buildAccountingDetail)(subFamily, lookup);
|
|
89
90
|
if (accountingDetail != null) {
|
|
90
91
|
payload.accounting_detail = accountingDetail;
|
|
91
92
|
}
|
|
@@ -142,7 +143,7 @@ const localDataToSaveInvoicingCatalogItemPayload = (localData, isCreate, lookup)
|
|
|
142
143
|
// would make a cleared mapping impossible to save — the same reason
|
|
143
144
|
// `description` and `invoice_notes` go through `trimOrNull`.
|
|
144
145
|
detail.accounting_detail =
|
|
145
|
-
buildAccountingDetail(subFamily, lookup) ?? null;
|
|
146
|
+
(0, exports.buildAccountingDetail)(subFamily, lookup) ?? null;
|
|
146
147
|
const id = trimOrUndefined(subFamily.id);
|
|
147
148
|
return id != null ? { ...detail, id } : detail;
|
|
148
149
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ID } from '../../../commonStateTypes/common';
|
|
2
|
+
import type { InvoicingProduct } from '../../../entity/invoicing/product/productState';
|
|
2
3
|
import { ZeniAPIStatus } from '../../../responsePayload';
|
|
3
4
|
import { InvoicingCatalogItemKind } from '../invoicingCatalogItemDetailView/invoicingCatalogItemDetailViewState';
|
|
4
|
-
import type {
|
|
5
|
+
import type { CatalogDetailEditValues, CreateSubFamilyFormValues } from './catalogDetailEditPayload';
|
|
5
6
|
import { EditInvoicingCatalogItemDetailViewState, InvoicingCatalogItemFormLocalData } from './editInvoicingCatalogItemDetailViewState';
|
|
6
7
|
/** Push the full form draft into CES (edit tree when `id` is present). */
|
|
7
8
|
export interface UpdateInvoicingCatalogItemFormDraftPayload {
|
|
@@ -18,14 +19,28 @@ export interface SubmitInvoicingCatalogItemFormPayload {
|
|
|
18
19
|
* `submitInvoicingCatalogItemForm` instead.
|
|
19
20
|
*/
|
|
20
21
|
export interface SaveInvoicingCatalogItemPayload {
|
|
21
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The detail page's edit form values. The epic builds the parent body and the
|
|
24
|
+
* per-price-point updates from them, so it can resolve a picked account or
|
|
25
|
+
* class to the record the request carries — a page cannot.
|
|
26
|
+
*/
|
|
27
|
+
editValues: CatalogDetailEditValues;
|
|
22
28
|
kind: InvoicingCatalogItemKind;
|
|
23
29
|
id?: ID;
|
|
24
|
-
|
|
30
|
+
/** The catalog item's type, for the price-point bodies. */
|
|
31
|
+
itemType?: string;
|
|
32
|
+
/** The saved price points, so only changed fields are sent. */
|
|
33
|
+
originalSubFamilies?: readonly InvoicingProduct[];
|
|
25
34
|
}
|
|
26
35
|
export interface CreateInvoicingCatalogSubFamilyPayload {
|
|
27
|
-
|
|
36
|
+
itemType: string;
|
|
28
37
|
parentItemId: ID;
|
|
38
|
+
/**
|
|
39
|
+
* The dialog's form values. The request body is built in the epic, which can
|
|
40
|
+
* resolve a picked account id to the record the payload carries — the page
|
|
41
|
+
* holds ids and never needs to know the wire shape.
|
|
42
|
+
*/
|
|
43
|
+
values: CreateSubFamilyFormValues;
|
|
29
44
|
}
|
|
30
45
|
export interface ArchiveInvoicingCatalogSubFamilyPayload {
|
|
31
46
|
parentItemId: ID;
|
|
@@ -48,12 +48,13 @@ export interface InvoicingCatalogItemFormView extends SelectorView {
|
|
|
48
48
|
pricingModelValues: readonly string[];
|
|
49
49
|
prorationValues: readonly string[];
|
|
50
50
|
/**
|
|
51
|
-
* Account and class trees for the price-point pickers,
|
|
52
|
-
*
|
|
53
|
-
* must not offer a mapping that cannot
|
|
51
|
+
* Account and class trees for the price-point pickers, straight from the
|
|
52
|
+
* shared accounting lists — the pickers drop the nodes they cannot submit.
|
|
53
|
+
* Empty until QBO is connected: the form must not offer a mapping that cannot
|
|
54
|
+
* be pushed.
|
|
54
55
|
*/
|
|
56
|
+
qboAccountHierarchy: NestedAccountHierarchyForReport[];
|
|
55
57
|
qboClassHierarchy: NestedClassHierarchyForReport[];
|
|
56
|
-
qboIncomeAccountHierarchy: NestedAccountHierarchyForReport[];
|
|
57
58
|
tierTypeValues: readonly string[];
|
|
58
59
|
trialEndActionOptions: InvoicingNamedOption[];
|
|
59
60
|
trialUnitOptions: InvoicingNamedOption[];
|
|
@@ -55,17 +55,15 @@ const getInvoicingCatalogItemFormView = (state, id) => {
|
|
|
55
55
|
const applicableItemOptions = id != null
|
|
56
56
|
? allApplicableItemOptions.filter((option) => option.id !== id)
|
|
57
57
|
: allApplicableItemOptions;
|
|
58
|
-
const
|
|
58
|
+
const qboView = (0, invoicingQboViewSelector_1.isInvoicingQboConnected)(state)
|
|
59
|
+
? (0, invoicingQboViewSelector_1.getInvoicingQboView)(state)
|
|
60
|
+
: undefined;
|
|
59
61
|
const { billingPeriodUnitOptions, catalogItemTypeOptions, catalogTierTypeOptionsByPricingModel, catalogTrialEndActionOptions, catalogTrialUnitOptions, } = (0, invoicingConfigViewSelector_1.getInvoicingConfigView)(state);
|
|
60
62
|
return {
|
|
61
63
|
fieldHelp: (0, invoicingConfigViewSelector_1.invoicingFieldHelpForGroup)(state, 'catalog'),
|
|
62
64
|
isQboPickerDataLoading: (0, invoicingQboViewSelector_1.isInvoicingAccountingPickerDataLoading)(state),
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
: [],
|
|
66
|
-
qboIncomeAccountHierarchy: isQboConnected
|
|
67
|
-
? (0, invoicingQboViewSelector_1.invoicingAccountHierarchyForTypes)(state, invoicingQboViewSelector_1.INVOICING_INCOME_ACCOUNT_TYPES)
|
|
68
|
-
: [],
|
|
65
|
+
qboAccountHierarchy: qboView?.nestedAccountHierarchy ?? [],
|
|
66
|
+
qboClassHierarchy: qboView?.nestedClassHierarchy ?? [],
|
|
69
67
|
applicabilityValues: invoicingCatalogItemFormConfig_1.INVOICING_CATALOG_APPLICABILITY_VALUES,
|
|
70
68
|
applicableItemOptions,
|
|
71
69
|
localData,
|
package/lib/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogSubFamilyEpics.d.ts
CHANGED
|
@@ -5,5 +5,5 @@ import { RootState } from '../../../rootStateTypes';
|
|
|
5
5
|
import { ZeniAPI } from '../../../zeniAPI';
|
|
6
6
|
import { archiveInvoicingCatalogSubFamily, createInvoicingCatalogSubFamily, submitInvoicingCatalogItemFormFailure, submitInvoicingCatalogItemFormSuccess } from './editInvoicingCatalogItemDetailViewReducer';
|
|
7
7
|
export type ActionType = ReturnType<typeof createInvoicingCatalogSubFamily> | ReturnType<typeof archiveInvoicingCatalogSubFamily> | ReturnType<typeof mergeInvoicingPlanSubFamily> | ReturnType<typeof submitInvoicingCatalogItemFormSuccess> | ReturnType<typeof submitInvoicingCatalogItemFormFailure>;
|
|
8
|
-
export declare const createInvoicingCatalogSubFamilyEpic: (actions$: ActionsObservable<ActionType>,
|
|
8
|
+
export declare const createInvoicingCatalogSubFamilyEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
|
|
9
9
|
export declare const archiveInvoicingCatalogSubFamilyEpic: (actions$: ActionsObservable<ActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
|
package/lib/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogSubFamilyEpics.js
CHANGED
|
@@ -5,6 +5,8 @@ const rxjs_1 = require("rxjs");
|
|
|
5
5
|
const operators_1 = require("rxjs/operators");
|
|
6
6
|
const planReducer_1 = require("../../../entity/invoicing/plan/planReducer");
|
|
7
7
|
const responsePayload_1 = require("../../../responsePayload");
|
|
8
|
+
const invoicingQboViewSelector_1 = require("../invoicingQboView/invoicingQboViewSelector");
|
|
9
|
+
const catalogDetailEditPayload_1 = require("./catalogDetailEditPayload");
|
|
8
10
|
const editInvoicingCatalogItemDetailViewReducer_1 = require("./editInvoicingCatalogItemDetailViewReducer");
|
|
9
11
|
const subFamilySuccessActions = (parentItemId, subFamilyPayload) => [
|
|
10
12
|
(0, planReducer_1.mergeInvoicingPlanSubFamily)(parentItemId, subFamilyPayload),
|
|
@@ -13,8 +15,12 @@ const subFamilySuccessActions = (parentItemId, subFamilyPayload) => [
|
|
|
13
15
|
kind: 'plan',
|
|
14
16
|
}),
|
|
15
17
|
];
|
|
16
|
-
const createInvoicingCatalogSubFamilyEpic = (actions$,
|
|
17
|
-
const {
|
|
18
|
+
const createInvoicingCatalogSubFamilyEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(editInvoicingCatalogItemDetailViewReducer_1.createInvoicingCatalogSubFamily.match), (0, operators_1.mergeMap)((action) => {
|
|
19
|
+
const { itemType, parentItemId, values } = action.payload;
|
|
20
|
+
const state = state$.value;
|
|
21
|
+
// Built here so the dialog can stay in picked ids: resolving one to the
|
|
22
|
+
// account record the payload carries needs the shared account list.
|
|
23
|
+
const data = (0, catalogDetailEditPayload_1.createSubFamilyFormToPayload)(parentItemId, itemType, values, (0, invoicingQboViewSelector_1.getInvoicingCatalogAccountingLookup)(state));
|
|
18
24
|
const baseUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0`;
|
|
19
25
|
return zeniAPI
|
|
20
26
|
.postAndGetJSON(`${baseUrl}/catalog/products`, data)
|
package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js
CHANGED
|
@@ -10,25 +10,30 @@ const snackbarReducer_1 = require("../../../entity/snackbar/snackbarReducer");
|
|
|
10
10
|
const responsePayload_1 = require("../../../responsePayload");
|
|
11
11
|
const invoicingCatalogListViewReducer_1 = require("../invoicingCatalogListView/invoicingCatalogListViewReducer");
|
|
12
12
|
const invoicingQboViewSelector_1 = require("../invoicingQboView/invoicingQboViewSelector");
|
|
13
|
+
const catalogDetailEditPayload_1 = require("./catalogDetailEditPayload");
|
|
13
14
|
const editInvoicingCatalogItemDetailViewPayload_1 = require("./editInvoicingCatalogItemDetailViewPayload");
|
|
14
15
|
const editInvoicingCatalogItemDetailViewReducer_1 = require("./editInvoicingCatalogItemDetailViewReducer");
|
|
15
16
|
const saveInvoicingCatalogItemEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)((action) => editInvoicingCatalogItemDetailViewReducer_1.submitInvoicingCatalogItemForm.match(action) ||
|
|
16
17
|
editInvoicingCatalogItemDetailViewReducer_1.saveInvoicingCatalogItem.match(action)), (0, operators_1.mergeMap)((action) => {
|
|
17
18
|
const { id } = action.payload;
|
|
18
|
-
|
|
19
|
+
const state = state$.value;
|
|
20
|
+
const accountingLookup = (0, invoicingQboViewSelector_1.getInvoicingCatalogAccountingLookup)(state);
|
|
21
|
+
// Both sources are form values, turned into request bodies here so the
|
|
22
|
+
// picked account and class become the records the service stores: the
|
|
23
|
+
// detail page's edit form, or the create/edit form's draft.
|
|
19
24
|
let data;
|
|
25
|
+
let editProductUpdates;
|
|
20
26
|
if (editInvoicingCatalogItemDetailViewReducer_1.saveInvoicingCatalogItem.match(action)) {
|
|
21
|
-
|
|
27
|
+
const { editValues, itemType, originalSubFamilies } = action.payload;
|
|
28
|
+
const savePayload = (0, catalogDetailEditPayload_1.catalogDetailEditValuesToSavePayload)(editValues, accountingLookup, itemType, originalSubFamilies);
|
|
29
|
+
data = savePayload.planData;
|
|
30
|
+
editProductUpdates = savePayload.productUpdates;
|
|
22
31
|
}
|
|
23
32
|
else {
|
|
24
|
-
const viewState = state
|
|
33
|
+
const viewState = state.editInvoicingCatalogItemDetailViewState;
|
|
25
34
|
const localData = (id != null ? viewState.editDraftById[id] : viewState.newItemDraft) ??
|
|
26
35
|
viewState.newItemDraft;
|
|
27
|
-
|
|
28
|
-
data = (0, editInvoicingCatalogItemDetailViewPayload_1.localDataToSaveInvoicingCatalogItemPayload)(localData, id == null, {
|
|
29
|
-
accountByQboId: (qboId) => (0, invoicingQboViewSelector_1.invoicingQboAccountByQboId)(state, qboId),
|
|
30
|
-
classByQboId: (qboId) => (0, invoicingQboViewSelector_1.invoicingQboClassByQboId)(state, qboId),
|
|
31
|
-
});
|
|
36
|
+
data = (0, editInvoicingCatalogItemDetailViewPayload_1.localDataToSaveInvoicingCatalogItemPayload)(localData, id == null, accountingLookup);
|
|
32
37
|
}
|
|
33
38
|
const baseUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0`;
|
|
34
39
|
const path = id != null
|
|
@@ -91,7 +96,7 @@ const saveInvoicingCatalogItemEpic = (actions$, state$, zeniAPI) => actions$.pip
|
|
|
91
96
|
return resultActions;
|
|
92
97
|
};
|
|
93
98
|
const productUpdates = editInvoicingCatalogItemDetailViewReducer_1.saveInvoicingCatalogItem.match(action)
|
|
94
|
-
? (
|
|
99
|
+
? (editProductUpdates ?? [])
|
|
95
100
|
: [];
|
|
96
101
|
if (productUpdates.length === 0) {
|
|
97
102
|
return completeSave([]);
|
|
@@ -21,7 +21,6 @@ const fetchInvoicingAccountingPickersEpic = (actions$, state$) => actions$.pipe(
|
|
|
21
21
|
accountList.fetchState !== 'In-Progress') {
|
|
22
22
|
// Same arguments the vendor and categorization screens pass, so this
|
|
23
23
|
// shares their cached list rather than replacing it with a narrower one.
|
|
24
|
-
// Invoicing narrows to income accounts when it builds its options.
|
|
25
24
|
actions.push((0, accountListReducer_1.fetchAccountList)(invoicingQboViewSelector_1.INVOICING_ACCOUNT_LIST_KEY, true));
|
|
26
25
|
}
|
|
27
26
|
const classList = state.classListState;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NestedAccountHierarchyForReport } from '../../../commonStateTypes/accountView/nestedAccountID';
|
|
2
2
|
import { NestedClassHierarchyForReport } from '../../../commonStateTypes/classesView/nestedClassID';
|
|
3
3
|
import { FetchStateAndError } from '../../../commonStateTypes/common';
|
|
4
|
-
import { AccountBase
|
|
4
|
+
import { AccountBase } from '../../../entity/account/accountState';
|
|
5
5
|
import { ClassBase } from '../../../entity/class/classState';
|
|
6
6
|
import { RootState } from '../../../rootStateTypes';
|
|
7
7
|
import { InvoicingQboConnection, InvoicingQboSyncHealth } from './invoicingQboViewPayload';
|
|
@@ -16,11 +16,6 @@ export declare const isInvoicingQboConnected: (state: RootState) => boolean;
|
|
|
16
16
|
export declare const isInvoicingAccountingPickerDataLoading: (state: RootState) => boolean;
|
|
17
17
|
/** The QBO connection fetch on its own, without building the bundled view. */
|
|
18
18
|
export declare const getInvoicingQboConnectionFetchState: (state: RootState) => FetchStateAndError;
|
|
19
|
-
/**
|
|
20
|
-
* Account types that can back invoicing revenue. Named here so screens ask for
|
|
21
|
-
* "income accounts" rather than repeating the accounting service's vocabulary.
|
|
22
|
-
*/
|
|
23
|
-
export declare const INVOICING_INCOME_ACCOUNT_TYPES: readonly AccountType[];
|
|
24
19
|
/**
|
|
25
20
|
* The account behind a picker value. The pickers submit the QuickBooks id, so
|
|
26
21
|
* that is what callers hold; the payload builders need the whole entity to send
|
|
@@ -29,6 +24,17 @@ export declare const INVOICING_INCOME_ACCOUNT_TYPES: readonly AccountType[];
|
|
|
29
24
|
export declare const invoicingQboAccountByQboId: (state: RootState, qboId: string | undefined) => AccountBase | undefined;
|
|
30
25
|
/** The class behind a picker value, for the same reason as the account above. */
|
|
31
26
|
export declare const invoicingQboClassByQboId: (state: RootState, qboId: string | undefined) => ClassBase | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The resolver every catalog and settings payload builder needs: a picked
|
|
29
|
+
* QuickBooks id turned back into the account or class record the request body
|
|
30
|
+
* carries. Memoized so callers get one stable object rather than a fresh pair of
|
|
31
|
+
* closures per store change, which in `mapStateToProps` would re-render on every
|
|
32
|
+
* unrelated action.
|
|
33
|
+
*/
|
|
34
|
+
export declare const getInvoicingCatalogAccountingLookup: (state: RootState) => {
|
|
35
|
+
accountByQboId: (qboId: string) => AccountBase | undefined;
|
|
36
|
+
classByQboId: (qboId: string) => ClassBase | undefined;
|
|
37
|
+
};
|
|
32
38
|
/** An account or class as the invoicing pickers render and submit it. */
|
|
33
39
|
export interface InvoicingAccountingOption {
|
|
34
40
|
id: string;
|
|
@@ -60,13 +66,6 @@ export interface InvoicingQboView {
|
|
|
60
66
|
* required would post a mapping QuickBooks rejects.
|
|
61
67
|
*/
|
|
62
68
|
export declare const invoicingAccountsForQboAccountTypes: (accounts: InvoicingAccountingOption[], accountTypes: string) => InvoicingAccountingOption[];
|
|
63
|
-
/**
|
|
64
|
-
* The account tree narrowed to the given account types. The tree itself carries
|
|
65
|
-
* no account type, so the flat account list supplies that and the matching
|
|
66
|
-
* `qboId`s are kept — which is why callers that only need "income accounts, as a
|
|
67
|
-
* tree" do not have to hold a second flat list to filter with.
|
|
68
|
-
*/
|
|
69
|
-
export declare const invoicingAccountHierarchyForTypes: (state: RootState, accountTypes: readonly AccountType[]) => NestedAccountHierarchyForReport[];
|
|
70
69
|
/**
|
|
71
70
|
* Single bundled view for the QBO integration settings screen — the
|
|
72
71
|
* connection, the account and class options, sync health, and the fetch/action
|