@zeniai/client-epic-state 5.2.10-betaAK1 → 5.2.10-betaAK2

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.
@@ -107,7 +107,6 @@ export interface InvoicingQboAccountMappingsPayload {
107
107
  default_income_account_id?: string | null;
108
108
  deposit_account?: Partial<AccountBasePayload> | null;
109
109
  deposit_account_id?: string | null;
110
- deposit_account_overrides?: Record<string, string> | null;
111
110
  discounts_account?: Partial<AccountBasePayload> | null;
112
111
  discounts_account_id?: string | null;
113
112
  rounding_account?: Partial<AccountBasePayload> | null;
@@ -131,7 +130,20 @@ export declare const firstSelectableInvoicingId: (candidates: readonly (string |
131
130
  * Read one account-mapping dropdown value by its config `code` (the codes in
132
131
  * `qbo_account_mapping_kind_options` match the `account_mappings` field names).
133
132
  */
134
- export declare function getInvoicingQboAccountMappingId(accountMappings: InvoicingQboAccountMappingsPayload | undefined, code: string): string | undefined;
133
+ export declare function getInvoicingQboAccountMappingId(accountMappings: InvoicingQboAccountMappingsPayload | undefined, code: InvoicingQboAccountMappingCode): string | undefined;
134
+ /**
135
+ * Return a copy of the account mappings with the dropdown slot named by
136
+ * `code` set to `accountId`. Unknown codes leave the mappings unchanged.
137
+ */
138
+ /** Every account-mapping slot the page can set, in the order it renders them. */
139
+ export declare const INVOICING_QBO_ACCOUNT_MAPPING_CODES: readonly ["deposit_account_id", "default_income_account_id", "discounts_account_id", "rounding_account_id", "write_off_account_id"];
140
+ export type InvoicingQboAccountMappingCode = (typeof INVOICING_QBO_ACCOUNT_MAPPING_CODES)[number];
141
+ /**
142
+ * Narrows a mapping code that arrived from the config API. Anything the client
143
+ * has no slot for returns undefined rather than being cast through: a code we
144
+ * cannot place is a mapping we cannot read or write.
145
+ */
146
+ export declare const toInvoicingQboAccountMappingCode: (code: string) => InvoicingQboAccountMappingCode | undefined;
135
147
  /**
136
148
  * Expand each mapping from the id the picker submitted to the whole account, the
137
149
  * shape the service stores. Written at the request boundary rather than in the
@@ -139,7 +151,7 @@ export declare function getInvoicingQboAccountMappingId(accountMappings: Invoici
139
151
  * is left out — a mapping the service cannot expand is worse than none.
140
152
  */
141
153
  export declare const withInvoicingQboMappedAccounts: (accountMappings: InvoicingQboAccountMappingsPayload | undefined, accountByQboId: (qboId: string) => AccountBase | undefined) => InvoicingQboAccountMappingsPayload | undefined;
142
- export declare function withInvoicingQboAccountMappingId(accountMappings: InvoicingQboAccountMappingsPayload | undefined, code: string, accountId: string): InvoicingQboAccountMappingsPayload;
154
+ export declare function withInvoicingQboAccountMappingId(accountMappings: InvoicingQboAccountMappingsPayload | undefined, code: InvoicingQboAccountMappingCode, accountId: string): InvoicingQboAccountMappingsPayload;
143
155
  export interface InvoicingQboSettingsPayload {
144
156
  account_mappings?: InvoicingQboAccountMappingsPayload | null;
145
157
  auto_create_items?: boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ALL_INVOICING_FIELD_HELP_GROUPS = exports.withInvoicingQboMappedAccounts = exports.firstSelectableInvoicingId = exports.INVOICING_QBO_CUSTOMER_MATCHING_MODES = exports.INVOICING_DISCOUNT_LIFECYCLE_ACTIONS = exports.INVOICING_CATALOG_PRODUCT_LIFECYCLE_ACTIONS = exports.INVOICING_CATALOG_ITEM_LIFECYCLE_ACTIONS = exports.INVOICING_SUBSCRIPTION_LIFECYCLE_ACTIONS = exports.INVOICING_DUNNING_ACTIONS = void 0;
3
+ exports.ALL_INVOICING_FIELD_HELP_GROUPS = exports.withInvoicingQboMappedAccounts = exports.toInvoicingQboAccountMappingCode = exports.INVOICING_QBO_ACCOUNT_MAPPING_CODES = exports.firstSelectableInvoicingId = exports.INVOICING_QBO_CUSTOMER_MATCHING_MODES = exports.INVOICING_DISCOUNT_LIFECYCLE_ACTIONS = exports.INVOICING_CATALOG_PRODUCT_LIFECYCLE_ACTIONS = exports.INVOICING_CATALOG_ITEM_LIFECYCLE_ACTIONS = exports.INVOICING_SUBSCRIPTION_LIFECYCLE_ACTIONS = exports.INVOICING_DUNNING_ACTIONS = void 0;
4
4
  exports.toInvoicingDunningAction = toInvoicingDunningAction;
5
5
  exports.toInvoicingSubscriptionLifecycleAction = toInvoicingSubscriptionLifecycleAction;
6
6
  exports.toInvoicingSubscriptionLifecycleActionOption = toInvoicingSubscriptionLifecycleActionOption;
@@ -200,6 +200,21 @@ function getInvoicingQboAccountMappingId(accountMappings, code) {
200
200
  * Return a copy of the account mappings with the dropdown slot named by
201
201
  * `code` set to `accountId`. Unknown codes leave the mappings unchanged.
202
202
  */
203
+ /** Every account-mapping slot the page can set, in the order it renders them. */
204
+ exports.INVOICING_QBO_ACCOUNT_MAPPING_CODES = [
205
+ 'deposit_account_id',
206
+ 'default_income_account_id',
207
+ 'discounts_account_id',
208
+ 'rounding_account_id',
209
+ 'write_off_account_id',
210
+ ];
211
+ /**
212
+ * Narrows a mapping code that arrived from the config API. Anything the client
213
+ * has no slot for returns undefined rather than being cast through: a code we
214
+ * cannot place is a mapping we cannot read or write.
215
+ */
216
+ const toInvoicingQboAccountMappingCode = (code) => exports.INVOICING_QBO_ACCOUNT_MAPPING_CODES.find((knownCode) => knownCode === code);
217
+ exports.toInvoicingQboAccountMappingCode = toInvoicingQboAccountMappingCode;
203
218
  /** The object key holding the mapped account for each `*_account_id` code. */
204
219
  const INVOICING_QBO_MAPPED_ACCOUNT_KEY = {
205
220
  default_income_account_id: 'default_income_account',
@@ -219,7 +234,8 @@ const withInvoicingQboMappedAccounts = (accountMappings, accountByQboId) => {
219
234
  return undefined;
220
235
  }
221
236
  const expanded = { ...accountMappings };
222
- Object.entries(INVOICING_QBO_MAPPED_ACCOUNT_KEY).forEach(([code, objectKey]) => {
237
+ exports.INVOICING_QBO_ACCOUNT_MAPPING_CODES.forEach((code) => {
238
+ const objectKey = INVOICING_QBO_MAPPED_ACCOUNT_KEY[code];
223
239
  const accountId = getInvoicingQboAccountMappingId(accountMappings, code);
224
240
  if (accountId == null) {
225
241
  return;
package/lib/epic.js CHANGED
@@ -317,6 +317,7 @@ const connectInvoicingStripeEpic_1 = require("./view/invoicing/settingsView/epic
317
317
  const disconnectInvoicingStripeEpic_1 = require("./view/invoicing/settingsView/epics/disconnectInvoicingStripeEpic");
318
318
  const fetchInvoicingSettingsEpic_1 = require("./view/invoicing/settingsView/epics/fetchInvoicingSettingsEpic");
319
319
  const saveInvoicingSettingsEpic_1 = require("./view/invoicing/settingsView/epics/saveInvoicingSettingsEpic");
320
+ const submitInvoicingQboSettingsEpic_1 = require("./view/invoicing/settingsView/epics/submitInvoicingQboSettingsEpic");
320
321
  const invoicingBrandingFormEpics_1 = require("./view/invoicing/settingsView/invoicingBrandingFormEpics");
321
322
  const subscriptionActionEpic_1 = require("./view/invoicing/subscriptionAction/subscriptionActionEpic");
322
323
  const fetchMonthClosePerformanceTrendEpic_1 = require("./view/monthEndCloseChecksView/epics/fetchMonthClosePerformanceTrendEpic");
@@ -1363,6 +1364,7 @@ const ALL_EPICS = [
1363
1364
  submitFeedbackEpic_1.submitFeedbackEpic,
1364
1365
  submitIntlVerificationEpic_1.submitIntlVerificationEpic,
1365
1366
  invoicingBrandingFormEpics_1.submitInvoicingBrandingFormEpic,
1367
+ submitInvoicingQboSettingsEpic_1.submitInvoicingQboSettingsEpic,
1366
1368
  submitQuestionEpic_1.submitQuestionEpic,
1367
1369
  syncInvoicingSubscriptionCouponsEpic_1.syncInvoicingSubscriptionCouponsEpic,
1368
1370
  syncTabsAfterAutomatchEpic_1.syncTabsAfterAutomatchEpic,
@@ -174,6 +174,20 @@ export function getInvoicingQboAccountMappingId(accountMappings, code) {
174
174
  * Return a copy of the account mappings with the dropdown slot named by
175
175
  * `code` set to `accountId`. Unknown codes leave the mappings unchanged.
176
176
  */
177
+ /** Every account-mapping slot the page can set, in the order it renders them. */
178
+ export const INVOICING_QBO_ACCOUNT_MAPPING_CODES = [
179
+ 'deposit_account_id',
180
+ 'default_income_account_id',
181
+ 'discounts_account_id',
182
+ 'rounding_account_id',
183
+ 'write_off_account_id',
184
+ ];
185
+ /**
186
+ * Narrows a mapping code that arrived from the config API. Anything the client
187
+ * has no slot for returns undefined rather than being cast through: a code we
188
+ * cannot place is a mapping we cannot read or write.
189
+ */
190
+ export const toInvoicingQboAccountMappingCode = (code) => INVOICING_QBO_ACCOUNT_MAPPING_CODES.find((knownCode) => knownCode === code);
177
191
  /** The object key holding the mapped account for each `*_account_id` code. */
178
192
  const INVOICING_QBO_MAPPED_ACCOUNT_KEY = {
179
193
  default_income_account_id: 'default_income_account',
@@ -193,7 +207,8 @@ export const withInvoicingQboMappedAccounts = (accountMappings, accountByQboId)
193
207
  return undefined;
194
208
  }
195
209
  const expanded = { ...accountMappings };
196
- Object.entries(INVOICING_QBO_MAPPED_ACCOUNT_KEY).forEach(([code, objectKey]) => {
210
+ INVOICING_QBO_ACCOUNT_MAPPING_CODES.forEach((code) => {
211
+ const objectKey = INVOICING_QBO_MAPPED_ACCOUNT_KEY[code];
197
212
  const accountId = getInvoicingQboAccountMappingId(accountMappings, code);
198
213
  if (accountId == null) {
199
214
  return;
package/lib/esm/epic.js CHANGED
@@ -314,6 +314,7 @@ import { connectInvoicingStripeEpic } from './view/invoicing/settingsView/epics/
314
314
  import { disconnectInvoicingStripeEpic } from './view/invoicing/settingsView/epics/disconnectInvoicingStripeEpic';
315
315
  import { fetchInvoicingSettingsEpic } from './view/invoicing/settingsView/epics/fetchInvoicingSettingsEpic';
316
316
  import { saveInvoicingSettingsEpic } from './view/invoicing/settingsView/epics/saveInvoicingSettingsEpic';
317
+ import { submitInvoicingQboSettingsEpic } from './view/invoicing/settingsView/epics/submitInvoicingQboSettingsEpic';
317
318
  import { initializeInvoicingBrandingAddressEpic, submitInvoicingBrandingFormEpic, } from './view/invoicing/settingsView/invoicingBrandingFormEpics';
318
319
  import { runInvoicingSubscriptionActionEpic, } from './view/invoicing/subscriptionAction/subscriptionActionEpic';
319
320
  import { fetchMonthClosePerformanceTrendEpic, } from './view/monthEndCloseChecksView/epics/fetchMonthClosePerformanceTrendEpic';
@@ -1360,6 +1361,7 @@ const ALL_EPICS = [
1360
1361
  submitFeedbackEpic,
1361
1362
  submitIntlVerificationEpic,
1362
1363
  submitInvoicingBrandingFormEpic,
1364
+ submitInvoicingQboSettingsEpic,
1363
1365
  submitQuestionEpic,
1364
1366
  syncInvoicingSubscriptionCouponsEpic,
1365
1367
  syncTabsAfterAutomatchEpic,
package/lib/esm/index.js CHANGED
@@ -849,8 +849,10 @@ export { getInvoicingCatalogItemDetail } from './view/invoicing/invoicingCatalog
849
849
  export { getInvoicingPlanById } from './entity/invoicing/plan/planSelector';
850
850
  export { getInvoicingProductById } from './entity/invoicing/product/productSelector';
851
851
  // ── Invoicing: settings ───────────────────────────────────────────────────────
852
- export { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, resetInvoicingBrandingFormDraft, resetInvoicingQboSettingsDraft, resetSaveInvoicingSettings, saveInvoicingSettings, submitInvoicingBrandingForm, updateInvoicingBrandingFormDraft, updateInvoicingQboSettingsDraft, updateInvoicingSettings, } from './view/invoicing/settingsView/settingsViewReducer';
852
+ export { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, resetInvoicingBrandingFormDraft, resetInvoicingQboSettingsDraft, resetSaveInvoicingSettings, saveInvoicingSettings, submitInvoicingBrandingForm, submitInvoicingQboSettings, updateInvoicingBrandingFormDraft, updateInvoicingQboSettingsDraft, updateInvoicingSettings, } from './view/invoicing/settingsView/settingsViewReducer';
853
853
  export { getInvoicingBrandingFormView, getInvoicingQboSettingsFormView, getInvoicingSettings, getInvoicingSettingsFetchState, getInvoicingSettingsHubView, getInvoicingSettingsView, } from './view/invoicing/settingsView/settingsViewSelector';
854
+ export { INVOICING_QBO_ACCOUNT_MAPPING_CODES, toInvoicingQboAccountMappingCode, } from './entity/invoicing/invoicingCommonPayload';
855
+ export { entityToInvoicingQboSettingsLocalData, initialInvoicingQboSettingsLocalData, invoicingQboSettingsLocalDataToPayload, } from './view/invoicing/settingsView/invoicingQboSettingsFormConfig';
854
856
  export { INVOICING_BUSINESS_ADDRESS_TYPE, entityToInvoicingBrandingFormLocalData, initialInvoicingBrandingFormLocalData, } from './view/invoicing/settingsView/invoicingBrandingFormConfig';
855
857
  export { isStripeConnectedFromSettings } from './view/invoicing/settingsView/invoicingSettingsHelpers';
856
858
  // ── Invoicing: QBO integration ────────────────────────────────────────────────
@@ -0,0 +1,22 @@
1
+ import { EMPTY, of } from 'rxjs';
2
+ import { filter, mergeMap, withLatestFrom } from 'rxjs/operators';
3
+ import { invoicingQboSettingsLocalDataToPayload } from '../invoicingQboSettingsFormConfig';
4
+ import { saveInvoicingSettings, submitInvoicingQboSettings, } from '../settingsViewReducer';
5
+ /**
6
+ * Saves the QBO local data. The screen fires this without a payload — the local
7
+ * data is already in the store, so sending it back through the action would make
8
+ * the page the carrier for state it does not own. Converting to the request body
9
+ * happens here too, keeping the wire shape out of the screen.
10
+ */
11
+ export const submitInvoicingQboSettingsEpic = (actions$, state$) => actions$.pipe(filter(submitInvoicingQboSettings.match), withLatestFrom(state$), mergeMap(([, state]) => {
12
+ const { qboDraft } = state.invoicingSettingsViewState;
13
+ // No local data means the settings response has not landed, so there is
14
+ // nothing the user could have edited yet.
15
+ if (qboDraft == null) {
16
+ return EMPTY;
17
+ }
18
+ return of(saveInvoicingSettings({
19
+ settings: { qbo: invoicingQboSettingsLocalDataToPayload(qboDraft) },
20
+ snackbarSection: 'invoicing_qbo_settings_save',
21
+ }));
22
+ }));
@@ -0,0 +1,52 @@
1
+ import { INVOICING_QBO_ACCOUNT_MAPPING_CODES, getInvoicingQboAccountMappingId, withInvoicingQboAccountMappingId, } from '../../../entity/invoicing/invoicingCommonPayload';
2
+ export const initialInvoicingQboSettingsLocalData = {
3
+ accountIdByMappingCode: {},
4
+ autoCreateItems: false,
5
+ closedPeriodVoidAsCreditMemo: false,
6
+ customerMatching: '',
7
+ isSyncEnabled: false,
8
+ syncStartDate: '',
9
+ trackingCategoriesEnabled: false,
10
+ };
11
+ /** The settings response as the page edits it. */
12
+ export const entityToInvoicingQboSettingsLocalData = (qbo) => {
13
+ const accountIdByMappingCode = {};
14
+ INVOICING_QBO_ACCOUNT_MAPPING_CODES.forEach((code) => {
15
+ const accountId = getInvoicingQboAccountMappingId(qbo?.account_mappings ?? undefined, code);
16
+ if (accountId != null) {
17
+ accountIdByMappingCode[code] = accountId;
18
+ }
19
+ });
20
+ return {
21
+ accountIdByMappingCode,
22
+ autoCreateItems: qbo?.auto_create_items === true,
23
+ closedPeriodVoidAsCreditMemo: qbo?.closed_period_void_as_credit_memo === true,
24
+ customerMatching: qbo?.customer_matching ?? '',
25
+ isSyncEnabled: qbo?.enabled === true,
26
+ syncStartDate: qbo?.sync_start_date ?? '',
27
+ trackingCategoriesEnabled: qbo?.tracking_categories_enabled === true,
28
+ };
29
+ };
30
+ /**
31
+ * The local data as the request body. Only the mappings the page holds are sent;
32
+ * an empty id means the slot was never set, so it is left out rather than sent
33
+ * blank.
34
+ */
35
+ export const invoicingQboSettingsLocalDataToPayload = (localData) => {
36
+ let accountMappings = {};
37
+ INVOICING_QBO_ACCOUNT_MAPPING_CODES.forEach((code) => {
38
+ const accountId = localData.accountIdByMappingCode[code] ?? '';
39
+ if (accountId !== '') {
40
+ accountMappings = withInvoicingQboAccountMappingId(accountMappings, code, accountId);
41
+ }
42
+ });
43
+ return {
44
+ account_mappings: accountMappings,
45
+ auto_create_items: localData.autoCreateItems,
46
+ closed_period_void_as_credit_memo: localData.closedPeriodVoidAsCreditMemo,
47
+ customer_matching: localData.customerMatching,
48
+ enabled: localData.isSyncEnabled,
49
+ sync_start_date: localData.syncStartDate !== '' ? localData.syncStartDate : null,
50
+ tracking_categories_enabled: localData.trackingCategoriesEnabled,
51
+ };
52
+ };
@@ -1,5 +1,6 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
2
  import { clearAll } from '../../../rootActions';
3
+ import { entityToInvoicingQboSettingsLocalData, } from './invoicingQboSettingsFormConfig';
3
4
  export const initialState = {
4
5
  fetchState: 'Not-Started',
5
6
  error: undefined,
@@ -22,6 +23,11 @@ const settingsView = createSlice({
22
23
  draft.settings = action.payload;
23
24
  draft.fetchState = 'Completed';
24
25
  draft.error = undefined;
26
+ // Seed the QBO page's local data from the response. An edit already in
27
+ // progress wins: a refetch behind the user must not discard it.
28
+ if (draft.qboDraft == null) {
29
+ draft.qboDraft = entityToInvoicingQboSettingsLocalData(action.payload.qbo);
30
+ }
25
31
  },
26
32
  updateInvoicingSettingsFailure(draft, action) {
27
33
  draft.fetchState = 'Error';
@@ -36,9 +42,9 @@ const settingsView = createSlice({
36
42
  saveInvoicingSettingsSuccess(draft, action) {
37
43
  draft.settings = action.payload;
38
44
  draft.saveFetchState = { fetchState: 'Completed', error: undefined };
39
- // The server is authoritative again, so the draft steps aside rather than
40
- // shadowing what was just persisted.
41
- draft.qboDraft = undefined;
45
+ // Re-seeded from what was just persisted, so the page keeps working off
46
+ // local data while showing the server's version of it.
47
+ draft.qboDraft = entityToInvoicingQboSettingsLocalData(action.payload.qbo);
42
48
  },
43
49
  saveInvoicingSettingsFailure(draft, action) {
44
50
  draft.saveFetchState = { fetchState: 'Error', error: action.payload };
@@ -60,6 +66,11 @@ const settingsView = createSlice({
60
66
  updateInvoicingQboSettingsDraft(draft, action) {
61
67
  draft.qboDraft = action.payload.localData;
62
68
  },
69
+ // Trigger only — handled by submitInvoicingQboSettingsEpic, which reads the
70
+ // local data and converts it to the request body.
71
+ submitInvoicingQboSettings(draft) {
72
+ draft.saveFetchState = { fetchState: 'In-Progress', error: undefined };
73
+ },
63
74
  resetInvoicingQboSettingsDraft(draft) {
64
75
  draft.qboDraft = undefined;
65
76
  },
@@ -94,5 +105,5 @@ const settingsView = createSlice({
94
105
  });
95
106
  },
96
107
  });
97
- export const { fetchInvoicingSettings, updateInvoicingSettings, updateInvoicingSettingsFailure, saveInvoicingSettings, saveInvoicingSettingsSuccess, saveInvoicingSettingsFailure, resetSaveInvoicingSettings, updateInvoicingBrandingFormDraft, submitInvoicingBrandingForm, resetInvoicingBrandingFormDraft, updateInvoicingQboSettingsDraft, resetInvoicingQboSettingsDraft, connectInvoicingStripe, disconnectInvoicingStripe, updateInvoicingStripeConnection, invoicingStripeConnectionFailure, } = settingsView.actions;
108
+ export const { fetchInvoicingSettings, updateInvoicingSettings, updateInvoicingSettingsFailure, saveInvoicingSettings, saveInvoicingSettingsSuccess, saveInvoicingSettingsFailure, resetSaveInvoicingSettings, updateInvoicingBrandingFormDraft, submitInvoicingBrandingForm, resetInvoicingBrandingFormDraft, updateInvoicingQboSettingsDraft, submitInvoicingQboSettings, resetInvoicingQboSettingsDraft, connectInvoicingStripe, disconnectInvoicingStripe, updateInvoicingStripeConnection, invoicingStripeConnectionFailure, } = settingsView.actions;
98
109
  export default settingsView.reducer;
@@ -1,8 +1,9 @@
1
- import { getInvoicingQboAccountMappingId, } from '../../../entity/invoicing/invoicingCommonPayload';
1
+ import { getInvoicingQboAccountMappingId, toInvoicingQboAccountMappingCode, } from '../../../entity/invoicing/invoicingCommonPayload';
2
2
  import { getFormattedAddress } from '../../addressView/addressViewSelector';
3
3
  import { getInvoicingConfigView } from '../invoicingConfigView/invoicingConfigViewSelector';
4
4
  import { getInvoicingQboView, isInvoicingAccountingPickerDataLoading, } from '../invoicingQboView/invoicingQboViewSelector';
5
5
  import { INVOICING_BUSINESS_ADDRESS_TYPE, entityToInvoicingBrandingFormLocalData, } from './invoicingBrandingFormConfig';
6
+ import { initialInvoicingQboSettingsLocalData, } from './invoicingQboSettingsFormConfig';
6
7
  /**
7
8
  * Shared primitive: the raw invoicing settings. Consumed internally by other
8
9
  * CES selectors (create-invoice, customer-detail, overview) and by non-settings
@@ -51,7 +52,12 @@ export function deriveInvoicingEnablePrerequisites(settings, isQboConnected, qbo
51
52
  // configured would let `every` pass vacuously and unlock the button early.
52
53
  const isQboConfigured = isQboConnected &&
53
54
  qboAccountMappingKindOptions.length > 0 &&
54
- qboAccountMappingKindOptions.every((option) => getInvoicingQboAccountMappingId(accountMappings, option.code) != null);
55
+ qboAccountMappingKindOptions.every((option) => {
56
+ // A kind the client has no slot for cannot count as configured.
57
+ const code = toInvoicingQboAccountMappingCode(option.code);
58
+ return (code != null &&
59
+ getInvoicingQboAccountMappingId(accountMappings, code) != null);
60
+ });
55
61
  return {
56
62
  canEnable: isStripeConnected && isQboConfigured,
57
63
  isQboConfigured,
@@ -119,7 +125,9 @@ export const getInvoicingQboSettingsFormView = (state) => {
119
125
  fetchState === 'In-Progress' ||
120
126
  isInvoicingAccountingPickerDataLoading(state),
121
127
  isSyncEnabledSaved: settings?.qbo?.enabled === true,
122
- localData: qboDraft ?? settings?.qbo ?? {},
128
+ // Seeded in the reducer when the settings response lands, so this is a plain
129
+ // read rather than a second place that decides what the page starts from.
130
+ localData: qboDraft ?? initialInvoicingQboSettingsLocalData,
123
131
  nestedAccountHierarchy: qboView.nestedAccountHierarchy,
124
132
  retryFetchStateByTaskId: qboView.retryFetchStateByTaskId,
125
133
  saveState: saveFetchState.fetchState === 'Not-Started' && error != null
package/lib/index.d.ts CHANGED
@@ -1235,10 +1235,14 @@ export { getInvoicingCatalogItemDetail } from './view/invoicing/invoicingCatalog
1235
1235
  export { getInvoicingPlanById } from './entity/invoicing/plan/planSelector';
1236
1236
  export { getInvoicingProductById } from './entity/invoicing/product/productSelector';
1237
1237
  export type { InvoicingCatalogItemDetailView } from './view/invoicing/invoicingCatalogItemDetailView/invoicingCatalogItemDetailViewSelector';
1238
- export { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, resetInvoicingBrandingFormDraft, resetInvoicingQboSettingsDraft, resetSaveInvoicingSettings, saveInvoicingSettings, submitInvoicingBrandingForm, updateInvoicingBrandingFormDraft, updateInvoicingQboSettingsDraft, updateInvoicingSettings, } from './view/invoicing/settingsView/settingsViewReducer';
1238
+ export { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, resetInvoicingBrandingFormDraft, resetInvoicingQboSettingsDraft, resetSaveInvoicingSettings, saveInvoicingSettings, submitInvoicingBrandingForm, submitInvoicingQboSettings, updateInvoicingBrandingFormDraft, updateInvoicingQboSettingsDraft, updateInvoicingSettings, } from './view/invoicing/settingsView/settingsViewReducer';
1239
1239
  export { getInvoicingBrandingFormView, getInvoicingQboSettingsFormView, getInvoicingSettings, getInvoicingSettingsFetchState, getInvoicingSettingsHubView, getInvoicingSettingsView, } from './view/invoicing/settingsView/settingsViewSelector';
1240
1240
  export type { InvoicingBrandingFormView, InvoicingQboSettingsFormView, InvoicingSettingsHubView, InvoicingSettingsView, } from './view/invoicing/settingsView/settingsViewSelector';
1241
1241
  export type { InvoicingBrandingFormLocalData } from './view/invoicing/settingsView/invoicingBrandingFormConfig';
1242
+ export type { InvoicingQboSettingsLocalData } from './view/invoicing/settingsView/invoicingQboSettingsFormConfig';
1243
+ export { INVOICING_QBO_ACCOUNT_MAPPING_CODES, toInvoicingQboAccountMappingCode, } from './entity/invoicing/invoicingCommonPayload';
1244
+ export type { InvoicingQboAccountMappingCode } from './entity/invoicing/invoicingCommonPayload';
1245
+ export { entityToInvoicingQboSettingsLocalData, initialInvoicingQboSettingsLocalData, invoicingQboSettingsLocalDataToPayload, } from './view/invoicing/settingsView/invoicingQboSettingsFormConfig';
1242
1246
  export { INVOICING_BUSINESS_ADDRESS_TYPE, entityToInvoicingBrandingFormLocalData, initialInvoicingBrandingFormLocalData, } from './view/invoicing/settingsView/invoicingBrandingFormConfig';
1243
1247
  export { isStripeConnectedFromSettings } from './view/invoicing/settingsView/invoicingSettingsHelpers';
1244
1248
  export { fetchInvoicingAccountingPickers, fetchInvoicingQboConnection, fetchInvoicingQboSyncHealth, retryInvoicingQboSyncTask, startInvoicingQboBackfill, } from './view/invoicing/invoicingQboView/invoicingQboViewReducer';
package/lib/index.js CHANGED
@@ -83,7 +83,7 @@ exports.runInvoicingCatalogPlanAction = exports.getInvoicingInvoiceActionState =
83
83
  exports.getInvoicingSetupIntentFetchState = exports.getInvoicingSetupIntent = exports.getInvoicingSentPaymentLinkMagicUrl = exports.getInvoicingSentPaymentLinkEmail = exports.getInvoicingPlaidLinkTokenFetchState = exports.getInvoicingPlaidLinkToken = exports.getInvoicingPaymentMethodSaveState = exports.getInvoicingPaymentLinkSendState = exports.sendInvoicingPaymentLink = exports.saveInvoicingPaymentMethod = exports.resetInvoicingCustomerPaymentMethod = exports.fetchInvoicingPlaidLinkToken = exports.createInvoicingSetupIntent = exports.getInvoicingCustomerDetail = exports.fetchInvoicingCustomerDetailPage = exports.fetchInvoicingCustomerDetail = exports.getInvoicingCustomerListView = exports.INVOICING_CUSTOMER_COLUMNS = exports.ALL_INVOICING_CUSTOMER_TAB_IDS = exports.ALL_INVOICING_CUSTOMER_SORT_KEYS = exports.updateInvoicingCustomerFilters = exports.setInvoicingCustomerActiveTab = exports.fetchInvoicingCustomerListPage = exports.fetchInvoicingCustomerList = exports.fetchInvoicingCustomerCounts = exports.updateInvoicingCustomers = exports.removeInvoicingCustomer = exports.INVOICING_LIST_PAGE_SIZE = exports.getInvoicingDataImportActionState = exports.uploadInvoicingMigrationFiles = exports.startInvoicingMigration = exports.rollbackInvoicingMigration = exports.retryInvoicingMigration = exports.connectInvoicingChargebee = exports.getInvoicingDataImportView = exports.setInvoicingActiveMigrationSessionId = exports.fetchInvoicingMigrationSessions = exports.fetchInvoicingMigrationSession = exports.fetchInvoicingMigrationDiagnostics = exports.fetchInvoicingDataImportStatus = exports.getInvoicingPaymentActionState = exports.runInvoicingPaymentAction = exports.getInvoicingDunningActionState = exports.runInvoicingDunningAction = exports.getInvoicingSubscriptionActionState = exports.runInvoicingSubscriptionAction = exports.getInvoicingDiscountActionState = exports.runInvoicingDiscountAction = exports.getInvoicingCatalogActionState = exports.runInvoicingCatalogProductAction = void 0;
84
84
  exports.updateInvoicingCouponFilters = exports.setInvoicingCouponActiveTab = exports.fetchInvoicingCouponListPage = exports.fetchInvoicingCouponList = exports.fetchInvoicingCouponCounts = exports.updateInvoicingCoupons = exports.removeInvoicingCoupon = exports.getInvoicingCreditNoteDetail = exports.getInvoicingCreditNoteById = exports.fetchInvoicingCreditNoteDetail = exports.getInvoicingCreditNoteListView = exports.INVOICING_CREDIT_NOTE_COLUMNS = exports.ALL_INVOICING_CREDIT_NOTE_TAB_IDS = exports.ALL_INVOICING_CREDIT_NOTE_SORT_KEYS = exports.updateInvoicingCreditNoteFilters = exports.setInvoicingCreditNoteActiveTab = exports.fetchInvoicingCreditNoteListPage = exports.fetchInvoicingCreditNoteList = exports.fetchInvoicingCreditNoteCounts = exports.updateInvoicingCreditNotes = exports.removeInvoicingCreditNote = exports.getInvoicingTransactionDetail = exports.getInvoicingTransactionById = exports.fetchInvoicingTransactionDetail = exports.getInvoicingTransactionListView = exports.INVOICING_TRANSACTION_COLUMNS = exports.ALL_INVOICING_TRANSACTION_TAB_IDS = exports.ALL_INVOICING_TRANSACTION_SORT_KEYS = exports.updateInvoicingTransactionFilters = exports.setInvoicingTransactionActiveTab = exports.fetchInvoicingTransactionListPage = exports.fetchInvoicingTransactionList = exports.updateInvoicingTransactions = exports.removeInvoicingTransaction = exports.getInvoicingSubscriptionDetail = exports.getInvoicingSubscriptionById = exports.fetchInvoicingSubscriptionDetail = exports.getInvoicingSubscriptionListView = exports.INVOICING_SUBSCRIPTION_COLUMNS = exports.ALL_INVOICING_SUBSCRIPTION_TAB_IDS = exports.ALL_INVOICING_SUBSCRIPTION_SORT_KEYS = exports.updateInvoicingSubscriptionFilters = exports.setInvoicingSubscriptionActiveTab = exports.fetchInvoicingSubscriptionListPage = exports.fetchInvoicingSubscriptionList = exports.fetchInvoicingSubscriptionCounts = exports.updateInvoicingSubscriptions = exports.removeInvoicingSubscription = exports.resetPromotionalCreditAction = exports.submitAddPromotionalCredits = void 0;
85
85
  exports.connectInvoicingStripe = exports.getInvoicingProductById = exports.getInvoicingPlanById = exports.getInvoicingCatalogItemDetail = exports.fetchInvoicingCatalogItemDetail = exports.getInvoicingCatalogListView = exports.INVOICING_PRODUCT_COLUMNS = exports.ALL_INVOICING_PRODUCT_SORT_KEYS = exports.updateInvoicingCatalogProductFilters = exports.updateInvoicingCatalogPlanFilters = exports.fetchInvoicingCatalogProductList = exports.fetchInvoicingCatalogPlanList = exports.fetchInvoicingCatalogListPage = exports.fetchInvoicingCatalogCounts = exports.updateInvoicingProducts = exports.removeInvoicingProduct = exports.updateInvoicingPlans = exports.removeInvoicingPlan = exports.mergeInvoicingPlanSubFamily = exports.getInvoicingDunningEmailPreview = exports.getInvoicingDunningCaseDetail = exports.getInvoicingDunningCaseById = exports.invalidateInvoicingDunningEmailPreview = exports.fetchInvoicingDunningEmailPreviewPage = exports.fetchInvoicingDunningCaseDetail = exports.clearInvoicingDunningCaseDetailView = exports.getInvoicingDunningCaseListView = exports.INVOICING_DUNNING_CASE_COLUMNS = exports.ALL_INVOICING_DUNNING_CASE_TAB_IDS = exports.ALL_INVOICING_DUNNING_CASE_SORT_KEYS = exports.updateInvoicingDunningCaseFilters = exports.setInvoicingDunningCaseActiveTab = exports.fetchInvoicingDunningCaseListPage = exports.fetchInvoicingDunningCaseList = exports.fetchInvoicingDunningCaseCounts = exports.updateInvoicingDunningCases = exports.removeInvoicingDunningCase = exports.getInvoicingCouponDetail = exports.fetchInvoicingCouponDetail = exports.getInvoicingCouponById = exports.getInvoicingCouponListView = exports.getInvoicingCouponListNextCursor = exports.getInvoicingCouponListItems = exports.getInvoicingCouponListHasMore = exports.getInvoicingCouponListFilters = exports.getInvoicingCouponListFetchState = exports.getInvoicingCouponCounts = exports.INVOICING_COUPON_COLUMNS = exports.ALL_INVOICING_COUPON_TAB_IDS = exports.ALL_INVOICING_COUPON_SORT_KEYS = void 0;
86
- exports.getInvoicingOnboardingGateView = exports.getInvoicingConfigView = exports.updateInvoicingConfig = exports.resetInvoicingConfigActionStates = exports.fetchInvoicingConfig = exports.enableInvoicing = exports.acceptInvoicingTerms = exports.withInvoicingQboAccountMappingId = exports.toInvoicingQboCustomerMatchingMode = exports.toInvoicingNamedOptionsByKey = exports.getInvoicingQboAccountMappingId = exports.INVOICING_QBO_CUSTOMER_MATCHING_MODES = exports.getInvoicingQboView = exports.invoicingAccountsForQboAccountTypes = exports.INVOICING_INCOME_ACCOUNT_TYPES = exports.startInvoicingQboBackfill = exports.retryInvoicingQboSyncTask = exports.fetchInvoicingQboSyncHealth = exports.fetchInvoicingQboConnection = exports.fetchInvoicingAccountingPickers = exports.isStripeConnectedFromSettings = exports.initialInvoicingBrandingFormLocalData = exports.entityToInvoicingBrandingFormLocalData = exports.INVOICING_BUSINESS_ADDRESS_TYPE = exports.getInvoicingSettingsView = exports.getInvoicingSettingsHubView = exports.getInvoicingSettingsFetchState = exports.getInvoicingSettings = exports.getInvoicingQboSettingsFormView = exports.getInvoicingBrandingFormView = exports.updateInvoicingSettings = exports.updateInvoicingQboSettingsDraft = exports.updateInvoicingBrandingFormDraft = exports.submitInvoicingBrandingForm = exports.saveInvoicingSettings = exports.resetSaveInvoicingSettings = exports.resetInvoicingQboSettingsDraft = exports.resetInvoicingBrandingFormDraft = exports.fetchInvoicingSettings = exports.disconnectInvoicingStripe = void 0;
86
+ exports.getInvoicingOnboardingGateView = exports.getInvoicingConfigView = exports.updateInvoicingConfig = exports.resetInvoicingConfigActionStates = exports.fetchInvoicingConfig = exports.enableInvoicing = exports.acceptInvoicingTerms = exports.withInvoicingQboAccountMappingId = exports.toInvoicingQboCustomerMatchingMode = exports.toInvoicingNamedOptionsByKey = exports.getInvoicingQboAccountMappingId = exports.INVOICING_QBO_CUSTOMER_MATCHING_MODES = exports.getInvoicingQboView = exports.invoicingAccountsForQboAccountTypes = exports.INVOICING_INCOME_ACCOUNT_TYPES = exports.startInvoicingQboBackfill = exports.retryInvoicingQboSyncTask = exports.fetchInvoicingQboSyncHealth = exports.fetchInvoicingQboConnection = exports.fetchInvoicingAccountingPickers = exports.isStripeConnectedFromSettings = exports.initialInvoicingBrandingFormLocalData = exports.entityToInvoicingBrandingFormLocalData = exports.INVOICING_BUSINESS_ADDRESS_TYPE = exports.invoicingQboSettingsLocalDataToPayload = exports.initialInvoicingQboSettingsLocalData = exports.entityToInvoicingQboSettingsLocalData = exports.toInvoicingQboAccountMappingCode = exports.INVOICING_QBO_ACCOUNT_MAPPING_CODES = exports.getInvoicingSettingsView = exports.getInvoicingSettingsHubView = exports.getInvoicingSettingsFetchState = exports.getInvoicingSettings = exports.getInvoicingQboSettingsFormView = exports.getInvoicingBrandingFormView = exports.updateInvoicingSettings = exports.updateInvoicingQboSettingsDraft = exports.updateInvoicingBrandingFormDraft = exports.submitInvoicingQboSettings = exports.submitInvoicingBrandingForm = exports.saveInvoicingSettings = exports.resetSaveInvoicingSettings = exports.resetInvoicingQboSettingsDraft = exports.resetInvoicingBrandingFormDraft = exports.fetchInvoicingSettings = exports.disconnectInvoicingStripe = void 0;
87
87
  const allowedValue_1 = require("./commonStateTypes/allowedValue");
88
88
  Object.defineProperty(exports, "isAllowedValueWithCode", { enumerable: true, get: function () { return allowedValue_1.isAllowedValueWithCode; } });
89
89
  Object.defineProperty(exports, "isAllowedValueWithID", { enumerable: true, get: function () { return allowedValue_1.isAllowedValueWithID; } });
@@ -3095,6 +3095,7 @@ Object.defineProperty(exports, "resetInvoicingQboSettingsDraft", { enumerable: t
3095
3095
  Object.defineProperty(exports, "resetSaveInvoicingSettings", { enumerable: true, get: function () { return settingsViewReducer_2.resetSaveInvoicingSettings; } });
3096
3096
  Object.defineProperty(exports, "saveInvoicingSettings", { enumerable: true, get: function () { return settingsViewReducer_2.saveInvoicingSettings; } });
3097
3097
  Object.defineProperty(exports, "submitInvoicingBrandingForm", { enumerable: true, get: function () { return settingsViewReducer_2.submitInvoicingBrandingForm; } });
3098
+ Object.defineProperty(exports, "submitInvoicingQboSettings", { enumerable: true, get: function () { return settingsViewReducer_2.submitInvoicingQboSettings; } });
3098
3099
  Object.defineProperty(exports, "updateInvoicingBrandingFormDraft", { enumerable: true, get: function () { return settingsViewReducer_2.updateInvoicingBrandingFormDraft; } });
3099
3100
  Object.defineProperty(exports, "updateInvoicingQboSettingsDraft", { enumerable: true, get: function () { return settingsViewReducer_2.updateInvoicingQboSettingsDraft; } });
3100
3101
  Object.defineProperty(exports, "updateInvoicingSettings", { enumerable: true, get: function () { return settingsViewReducer_2.updateInvoicingSettings; } });
@@ -3105,6 +3106,13 @@ Object.defineProperty(exports, "getInvoicingSettings", { enumerable: true, get:
3105
3106
  Object.defineProperty(exports, "getInvoicingSettingsFetchState", { enumerable: true, get: function () { return settingsViewSelector_2.getInvoicingSettingsFetchState; } });
3106
3107
  Object.defineProperty(exports, "getInvoicingSettingsHubView", { enumerable: true, get: function () { return settingsViewSelector_2.getInvoicingSettingsHubView; } });
3107
3108
  Object.defineProperty(exports, "getInvoicingSettingsView", { enumerable: true, get: function () { return settingsViewSelector_2.getInvoicingSettingsView; } });
3109
+ var invoicingCommonPayload_2 = require("./entity/invoicing/invoicingCommonPayload");
3110
+ Object.defineProperty(exports, "INVOICING_QBO_ACCOUNT_MAPPING_CODES", { enumerable: true, get: function () { return invoicingCommonPayload_2.INVOICING_QBO_ACCOUNT_MAPPING_CODES; } });
3111
+ Object.defineProperty(exports, "toInvoicingQboAccountMappingCode", { enumerable: true, get: function () { return invoicingCommonPayload_2.toInvoicingQboAccountMappingCode; } });
3112
+ var invoicingQboSettingsFormConfig_1 = require("./view/invoicing/settingsView/invoicingQboSettingsFormConfig");
3113
+ Object.defineProperty(exports, "entityToInvoicingQboSettingsLocalData", { enumerable: true, get: function () { return invoicingQboSettingsFormConfig_1.entityToInvoicingQboSettingsLocalData; } });
3114
+ Object.defineProperty(exports, "initialInvoicingQboSettingsLocalData", { enumerable: true, get: function () { return invoicingQboSettingsFormConfig_1.initialInvoicingQboSettingsLocalData; } });
3115
+ Object.defineProperty(exports, "invoicingQboSettingsLocalDataToPayload", { enumerable: true, get: function () { return invoicingQboSettingsFormConfig_1.invoicingQboSettingsLocalDataToPayload; } });
3108
3116
  var invoicingBrandingFormConfig_1 = require("./view/invoicing/settingsView/invoicingBrandingFormConfig");
3109
3117
  Object.defineProperty(exports, "INVOICING_BUSINESS_ADDRESS_TYPE", { enumerable: true, get: function () { return invoicingBrandingFormConfig_1.INVOICING_BUSINESS_ADDRESS_TYPE; } });
3110
3118
  Object.defineProperty(exports, "entityToInvoicingBrandingFormLocalData", { enumerable: true, get: function () { return invoicingBrandingFormConfig_1.entityToInvoicingBrandingFormLocalData; } });
@@ -3123,12 +3131,12 @@ Object.defineProperty(exports, "INVOICING_INCOME_ACCOUNT_TYPES", { enumerable: t
3123
3131
  Object.defineProperty(exports, "invoicingAccountsForQboAccountTypes", { enumerable: true, get: function () { return invoicingQboViewSelector_1.invoicingAccountsForQboAccountTypes; } });
3124
3132
  var invoicingQboViewSelector_2 = require("./view/invoicing/invoicingQboView/invoicingQboViewSelector");
3125
3133
  Object.defineProperty(exports, "getInvoicingQboView", { enumerable: true, get: function () { return invoicingQboViewSelector_2.getInvoicingQboView; } });
3126
- var invoicingCommonPayload_2 = require("./entity/invoicing/invoicingCommonPayload");
3127
- Object.defineProperty(exports, "INVOICING_QBO_CUSTOMER_MATCHING_MODES", { enumerable: true, get: function () { return invoicingCommonPayload_2.INVOICING_QBO_CUSTOMER_MATCHING_MODES; } });
3128
- Object.defineProperty(exports, "getInvoicingQboAccountMappingId", { enumerable: true, get: function () { return invoicingCommonPayload_2.getInvoicingQboAccountMappingId; } });
3129
- Object.defineProperty(exports, "toInvoicingNamedOptionsByKey", { enumerable: true, get: function () { return invoicingCommonPayload_2.toInvoicingNamedOptionsByKey; } });
3130
- Object.defineProperty(exports, "toInvoicingQboCustomerMatchingMode", { enumerable: true, get: function () { return invoicingCommonPayload_2.toInvoicingQboCustomerMatchingMode; } });
3131
- Object.defineProperty(exports, "withInvoicingQboAccountMappingId", { enumerable: true, get: function () { return invoicingCommonPayload_2.withInvoicingQboAccountMappingId; } });
3134
+ var invoicingCommonPayload_3 = require("./entity/invoicing/invoicingCommonPayload");
3135
+ Object.defineProperty(exports, "INVOICING_QBO_CUSTOMER_MATCHING_MODES", { enumerable: true, get: function () { return invoicingCommonPayload_3.INVOICING_QBO_CUSTOMER_MATCHING_MODES; } });
3136
+ Object.defineProperty(exports, "getInvoicingQboAccountMappingId", { enumerable: true, get: function () { return invoicingCommonPayload_3.getInvoicingQboAccountMappingId; } });
3137
+ Object.defineProperty(exports, "toInvoicingNamedOptionsByKey", { enumerable: true, get: function () { return invoicingCommonPayload_3.toInvoicingNamedOptionsByKey; } });
3138
+ Object.defineProperty(exports, "toInvoicingQboCustomerMatchingMode", { enumerable: true, get: function () { return invoicingCommonPayload_3.toInvoicingQboCustomerMatchingMode; } });
3139
+ Object.defineProperty(exports, "withInvoicingQboAccountMappingId", { enumerable: true, get: function () { return invoicingCommonPayload_3.withInvoicingQboAccountMappingId; } });
3132
3140
  // ── Invoicing: config ─────────────────────────────────────────────────────────
3133
3141
  var invoicingConfigViewReducer_1 = require("./view/invoicing/invoicingConfigView/invoicingConfigViewReducer");
3134
3142
  Object.defineProperty(exports, "acceptInvoicingTerms", { enumerable: true, get: function () { return invoicingConfigViewReducer_1.acceptInvoicingTerms; } });
@@ -1,5 +1,5 @@
1
1
  import { updateAddresses } from '../../../../entity/address/addressReducer';
2
2
  import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
3
- import { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, invoicingStripeConnectionFailure, saveInvoicingSettings, saveInvoicingSettingsFailure, saveInvoicingSettingsSuccess, updateInvoicingSettings, updateInvoicingSettingsFailure, updateInvoicingStripeConnection } from '../settingsViewReducer';
3
+ import { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, invoicingStripeConnectionFailure, saveInvoicingSettings, saveInvoicingSettingsFailure, saveInvoicingSettingsSuccess, submitInvoicingQboSettings, updateInvoicingSettings, updateInvoicingSettingsFailure, updateInvoicingStripeConnection } from '../settingsViewReducer';
4
4
  /** Every action the settings epics accept or emit. */
5
- export type InvoicingSettingsViewActionType = ReturnType<typeof fetchInvoicingSettings> | ReturnType<typeof updateInvoicingSettings> | ReturnType<typeof updateInvoicingSettingsFailure> | ReturnType<typeof saveInvoicingSettings> | ReturnType<typeof saveInvoicingSettingsSuccess> | ReturnType<typeof saveInvoicingSettingsFailure> | ReturnType<typeof connectInvoicingStripe> | ReturnType<typeof disconnectInvoicingStripe> | ReturnType<typeof updateInvoicingStripeConnection> | ReturnType<typeof invoicingStripeConnectionFailure> | ReturnType<typeof updateAddresses> | ReturnType<typeof openSnackbar>;
5
+ export type InvoicingSettingsViewActionType = ReturnType<typeof fetchInvoicingSettings> | ReturnType<typeof updateInvoicingSettings> | ReturnType<typeof updateInvoicingSettingsFailure> | ReturnType<typeof saveInvoicingSettings> | ReturnType<typeof saveInvoicingSettingsSuccess> | ReturnType<typeof submitInvoicingQboSettings> | ReturnType<typeof saveInvoicingSettingsFailure> | ReturnType<typeof connectInvoicingStripe> | ReturnType<typeof disconnectInvoicingStripe> | ReturnType<typeof updateInvoicingStripeConnection> | ReturnType<typeof invoicingStripeConnectionFailure> | ReturnType<typeof updateAddresses> | ReturnType<typeof openSnackbar>;
@@ -0,0 +1,11 @@
1
+ import { ActionsObservable, StateObservable } from 'redux-observable';
2
+ import { Observable } from 'rxjs';
3
+ import { RootState } from '../../../../rootStateTypes';
4
+ import { InvoicingSettingsViewActionType } from './settingsViewActionType';
5
+ /**
6
+ * Saves the QBO local data. The screen fires this without a payload — the local
7
+ * data is already in the store, so sending it back through the action would make
8
+ * the page the carrier for state it does not own. Converting to the request body
9
+ * happens here too, keeping the wire shape out of the screen.
10
+ */
11
+ export declare const submitInvoicingQboSettingsEpic: (actions$: ActionsObservable<InvoicingSettingsViewActionType>, state$: StateObservable<RootState>) => Observable<InvoicingSettingsViewActionType>;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.submitInvoicingQboSettingsEpic = void 0;
4
+ const rxjs_1 = require("rxjs");
5
+ const operators_1 = require("rxjs/operators");
6
+ const invoicingQboSettingsFormConfig_1 = require("../invoicingQboSettingsFormConfig");
7
+ const settingsViewReducer_1 = require("../settingsViewReducer");
8
+ /**
9
+ * Saves the QBO local data. The screen fires this without a payload — the local
10
+ * data is already in the store, so sending it back through the action would make
11
+ * the page the carrier for state it does not own. Converting to the request body
12
+ * happens here too, keeping the wire shape out of the screen.
13
+ */
14
+ const submitInvoicingQboSettingsEpic = (actions$, state$) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.submitInvoicingQboSettings.match), (0, operators_1.withLatestFrom)(state$), (0, operators_1.mergeMap)(([, state]) => {
15
+ const { qboDraft } = state.invoicingSettingsViewState;
16
+ // No local data means the settings response has not landed, so there is
17
+ // nothing the user could have edited yet.
18
+ if (qboDraft == null) {
19
+ return rxjs_1.EMPTY;
20
+ }
21
+ return (0, rxjs_1.of)((0, settingsViewReducer_1.saveInvoicingSettings)({
22
+ settings: { qbo: (0, invoicingQboSettingsFormConfig_1.invoicingQboSettingsLocalDataToPayload)(qboDraft) },
23
+ snackbarSection: 'invoicing_qbo_settings_save',
24
+ }));
25
+ }));
26
+ exports.submitInvoicingQboSettingsEpic = submitInvoicingQboSettingsEpic;
@@ -0,0 +1,28 @@
1
+ import { InvoicingQboAccountMappingCode, InvoicingQboSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
2
+ /**
3
+ * The QBO configuration page's local data. A client shape, not the wire one: the
4
+ * page edits a flat `accountIdByMappingCode` map keyed by the config's mapping
5
+ * codes, where the payload carries one field pair per slot and two shapes for
6
+ * each. {@link entityToInvoicingQboSettingsLocalData} and
7
+ * {@link invoicingQboSettingsLocalDataToPayload} convert at the boundary.
8
+ */
9
+ export interface InvoicingQboSettingsLocalData {
10
+ /** Mapping slot to the QuickBooks account id the picker selected. */
11
+ accountIdByMappingCode: Partial<Record<InvoicingQboAccountMappingCode, string>>;
12
+ autoCreateItems: boolean;
13
+ closedPeriodVoidAsCreditMemo: boolean;
14
+ customerMatching: string;
15
+ isSyncEnabled: boolean;
16
+ /** ISO date, empty when unset — the picker clears to empty, not to null. */
17
+ syncStartDate: string;
18
+ trackingCategoriesEnabled: boolean;
19
+ }
20
+ export declare const initialInvoicingQboSettingsLocalData: InvoicingQboSettingsLocalData;
21
+ /** The settings response as the page edits it. */
22
+ export declare const entityToInvoicingQboSettingsLocalData: (qbo: InvoicingQboSettingsPayload | null | undefined) => InvoicingQboSettingsLocalData;
23
+ /**
24
+ * The local data as the request body. Only the mappings the page holds are sent;
25
+ * an empty id means the slot was never set, so it is left out rather than sent
26
+ * blank.
27
+ */
28
+ export declare const invoicingQboSettingsLocalDataToPayload: (localData: InvoicingQboSettingsLocalData) => InvoicingQboSettingsPayload;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.invoicingQboSettingsLocalDataToPayload = exports.entityToInvoicingQboSettingsLocalData = exports.initialInvoicingQboSettingsLocalData = void 0;
4
+ const invoicingCommonPayload_1 = require("../../../entity/invoicing/invoicingCommonPayload");
5
+ exports.initialInvoicingQboSettingsLocalData = {
6
+ accountIdByMappingCode: {},
7
+ autoCreateItems: false,
8
+ closedPeriodVoidAsCreditMemo: false,
9
+ customerMatching: '',
10
+ isSyncEnabled: false,
11
+ syncStartDate: '',
12
+ trackingCategoriesEnabled: false,
13
+ };
14
+ /** The settings response as the page edits it. */
15
+ const entityToInvoicingQboSettingsLocalData = (qbo) => {
16
+ const accountIdByMappingCode = {};
17
+ invoicingCommonPayload_1.INVOICING_QBO_ACCOUNT_MAPPING_CODES.forEach((code) => {
18
+ const accountId = (0, invoicingCommonPayload_1.getInvoicingQboAccountMappingId)(qbo?.account_mappings ?? undefined, code);
19
+ if (accountId != null) {
20
+ accountIdByMappingCode[code] = accountId;
21
+ }
22
+ });
23
+ return {
24
+ accountIdByMappingCode,
25
+ autoCreateItems: qbo?.auto_create_items === true,
26
+ closedPeriodVoidAsCreditMemo: qbo?.closed_period_void_as_credit_memo === true,
27
+ customerMatching: qbo?.customer_matching ?? '',
28
+ isSyncEnabled: qbo?.enabled === true,
29
+ syncStartDate: qbo?.sync_start_date ?? '',
30
+ trackingCategoriesEnabled: qbo?.tracking_categories_enabled === true,
31
+ };
32
+ };
33
+ exports.entityToInvoicingQboSettingsLocalData = entityToInvoicingQboSettingsLocalData;
34
+ /**
35
+ * The local data as the request body. Only the mappings the page holds are sent;
36
+ * an empty id means the slot was never set, so it is left out rather than sent
37
+ * blank.
38
+ */
39
+ const invoicingQboSettingsLocalDataToPayload = (localData) => {
40
+ let accountMappings = {};
41
+ invoicingCommonPayload_1.INVOICING_QBO_ACCOUNT_MAPPING_CODES.forEach((code) => {
42
+ const accountId = localData.accountIdByMappingCode[code] ?? '';
43
+ if (accountId !== '') {
44
+ accountMappings = (0, invoicingCommonPayload_1.withInvoicingQboAccountMappingId)(accountMappings, code, accountId);
45
+ }
46
+ });
47
+ return {
48
+ account_mappings: accountMappings,
49
+ auto_create_items: localData.autoCreateItems,
50
+ closed_period_void_as_credit_memo: localData.closedPeriodVoidAsCreditMemo,
51
+ customer_matching: localData.customerMatching,
52
+ enabled: localData.isSyncEnabled,
53
+ sync_start_date: localData.syncStartDate !== '' ? localData.syncStartDate : null,
54
+ tracking_categories_enabled: localData.trackingCategoriesEnabled,
55
+ };
56
+ };
57
+ exports.invoicingQboSettingsLocalDataToPayload = invoicingQboSettingsLocalDataToPayload;
@@ -1,7 +1,8 @@
1
- import { InvoicingQboSettingsPayload, InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
1
+ import { InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
2
2
  import { SnackbarMessageSections } from '../../../entity/snackbar/snackbarTypes';
3
3
  import { ZeniAPIStatus } from '../../../responsePayload';
4
4
  import { InvoicingBrandingFormLocalData } from './invoicingBrandingFormConfig';
5
+ import { InvoicingQboSettingsLocalData } from './invoicingQboSettingsFormConfig';
5
6
  import { StripeConnectCredentials } from './settingsViewPayload';
6
7
  import { InvoicingSettingsViewState } from './settingsViewState';
7
8
  export interface InvoicingStripeConnectionUpdate {
@@ -20,7 +21,7 @@ export declare const initialState: InvoicingSettingsViewState;
20
21
  export declare const fetchInvoicingSettings: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/fetchInvoicingSettings">, updateInvoicingSettings: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingSettingsPayload, "invoicingSettingsView/updateInvoicingSettings">, updateInvoicingSettingsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingSettingsView/updateInvoicingSettingsFailure">, saveInvoicingSettings: import("@reduxjs/toolkit").ActionCreatorWithPayload<SaveInvoicingSettingsPayload, "invoicingSettingsView/saveInvoicingSettings">, saveInvoicingSettingsSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingSettingsPayload, "invoicingSettingsView/saveInvoicingSettingsSuccess">, saveInvoicingSettingsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingSettingsView/saveInvoicingSettingsFailure">, resetSaveInvoicingSettings: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/resetSaveInvoicingSettings">, updateInvoicingBrandingFormDraft: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
21
22
  localData: InvoicingBrandingFormLocalData;
22
23
  }, "invoicingSettingsView/updateInvoicingBrandingFormDraft">, submitInvoicingBrandingForm: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/submitInvoicingBrandingForm">, resetInvoicingBrandingFormDraft: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/resetInvoicingBrandingFormDraft">, updateInvoicingQboSettingsDraft: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
23
- localData: InvoicingQboSettingsPayload;
24
- }, "invoicingSettingsView/updateInvoicingQboSettingsDraft">, resetInvoicingQboSettingsDraft: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/resetInvoicingQboSettingsDraft">, connectInvoicingStripe: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[credentials: StripeConnectCredentials], StripeConnectCredentials, "invoicingSettingsView/connectInvoicingStripe", never, never>, disconnectInvoicingStripe: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/disconnectInvoicingStripe">, updateInvoicingStripeConnection: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingStripeConnectionUpdate, "invoicingSettingsView/updateInvoicingStripeConnection">, invoicingStripeConnectionFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingSettingsView/invoicingStripeConnectionFailure">;
24
+ localData: InvoicingQboSettingsLocalData;
25
+ }, "invoicingSettingsView/updateInvoicingQboSettingsDraft">, submitInvoicingQboSettings: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/submitInvoicingQboSettings">, resetInvoicingQboSettingsDraft: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/resetInvoicingQboSettingsDraft">, connectInvoicingStripe: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[credentials: StripeConnectCredentials], StripeConnectCredentials, "invoicingSettingsView/connectInvoicingStripe", never, never>, disconnectInvoicingStripe: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/disconnectInvoicingStripe">, updateInvoicingStripeConnection: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingStripeConnectionUpdate, "invoicingSettingsView/updateInvoicingStripeConnection">, invoicingStripeConnectionFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingSettingsView/invoicingStripeConnectionFailure">;
25
26
  declare const _default: import("redux").Reducer<InvoicingSettingsViewState>;
26
27
  export default _default;
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.invoicingStripeConnectionFailure = exports.updateInvoicingStripeConnection = exports.disconnectInvoicingStripe = exports.connectInvoicingStripe = exports.resetInvoicingQboSettingsDraft = exports.updateInvoicingQboSettingsDraft = exports.resetInvoicingBrandingFormDraft = exports.submitInvoicingBrandingForm = exports.updateInvoicingBrandingFormDraft = exports.resetSaveInvoicingSettings = exports.saveInvoicingSettingsFailure = exports.saveInvoicingSettingsSuccess = exports.saveInvoicingSettings = exports.updateInvoicingSettingsFailure = exports.updateInvoicingSettings = exports.fetchInvoicingSettings = exports.initialState = void 0;
4
+ exports.invoicingStripeConnectionFailure = exports.updateInvoicingStripeConnection = exports.disconnectInvoicingStripe = exports.connectInvoicingStripe = exports.resetInvoicingQboSettingsDraft = exports.submitInvoicingQboSettings = exports.updateInvoicingQboSettingsDraft = exports.resetInvoicingBrandingFormDraft = exports.submitInvoicingBrandingForm = exports.updateInvoicingBrandingFormDraft = exports.resetSaveInvoicingSettings = exports.saveInvoicingSettingsFailure = exports.saveInvoicingSettingsSuccess = exports.saveInvoicingSettings = exports.updateInvoicingSettingsFailure = exports.updateInvoicingSettings = exports.fetchInvoicingSettings = exports.initialState = void 0;
5
5
  const toolkit_1 = require("@reduxjs/toolkit");
6
6
  const rootActions_1 = require("../../../rootActions");
7
+ const invoicingQboSettingsFormConfig_1 = require("./invoicingQboSettingsFormConfig");
7
8
  exports.initialState = {
8
9
  fetchState: 'Not-Started',
9
10
  error: undefined,
@@ -26,6 +27,11 @@ const settingsView = (0, toolkit_1.createSlice)({
26
27
  draft.settings = action.payload;
27
28
  draft.fetchState = 'Completed';
28
29
  draft.error = undefined;
30
+ // Seed the QBO page's local data from the response. An edit already in
31
+ // progress wins: a refetch behind the user must not discard it.
32
+ if (draft.qboDraft == null) {
33
+ draft.qboDraft = (0, invoicingQboSettingsFormConfig_1.entityToInvoicingQboSettingsLocalData)(action.payload.qbo);
34
+ }
29
35
  },
30
36
  updateInvoicingSettingsFailure(draft, action) {
31
37
  draft.fetchState = 'Error';
@@ -40,9 +46,9 @@ const settingsView = (0, toolkit_1.createSlice)({
40
46
  saveInvoicingSettingsSuccess(draft, action) {
41
47
  draft.settings = action.payload;
42
48
  draft.saveFetchState = { fetchState: 'Completed', error: undefined };
43
- // The server is authoritative again, so the draft steps aside rather than
44
- // shadowing what was just persisted.
45
- draft.qboDraft = undefined;
49
+ // Re-seeded from what was just persisted, so the page keeps working off
50
+ // local data while showing the server's version of it.
51
+ draft.qboDraft = (0, invoicingQboSettingsFormConfig_1.entityToInvoicingQboSettingsLocalData)(action.payload.qbo);
46
52
  },
47
53
  saveInvoicingSettingsFailure(draft, action) {
48
54
  draft.saveFetchState = { fetchState: 'Error', error: action.payload };
@@ -64,6 +70,11 @@ const settingsView = (0, toolkit_1.createSlice)({
64
70
  updateInvoicingQboSettingsDraft(draft, action) {
65
71
  draft.qboDraft = action.payload.localData;
66
72
  },
73
+ // Trigger only — handled by submitInvoicingQboSettingsEpic, which reads the
74
+ // local data and converts it to the request body.
75
+ submitInvoicingQboSettings(draft) {
76
+ draft.saveFetchState = { fetchState: 'In-Progress', error: undefined };
77
+ },
67
78
  resetInvoicingQboSettingsDraft(draft) {
68
79
  draft.qboDraft = undefined;
69
80
  },
@@ -98,5 +109,5 @@ const settingsView = (0, toolkit_1.createSlice)({
98
109
  });
99
110
  },
100
111
  });
101
- _a = settingsView.actions, exports.fetchInvoicingSettings = _a.fetchInvoicingSettings, exports.updateInvoicingSettings = _a.updateInvoicingSettings, exports.updateInvoicingSettingsFailure = _a.updateInvoicingSettingsFailure, exports.saveInvoicingSettings = _a.saveInvoicingSettings, exports.saveInvoicingSettingsSuccess = _a.saveInvoicingSettingsSuccess, exports.saveInvoicingSettingsFailure = _a.saveInvoicingSettingsFailure, exports.resetSaveInvoicingSettings = _a.resetSaveInvoicingSettings, exports.updateInvoicingBrandingFormDraft = _a.updateInvoicingBrandingFormDraft, exports.submitInvoicingBrandingForm = _a.submitInvoicingBrandingForm, exports.resetInvoicingBrandingFormDraft = _a.resetInvoicingBrandingFormDraft, exports.updateInvoicingQboSettingsDraft = _a.updateInvoicingQboSettingsDraft, exports.resetInvoicingQboSettingsDraft = _a.resetInvoicingQboSettingsDraft, exports.connectInvoicingStripe = _a.connectInvoicingStripe, exports.disconnectInvoicingStripe = _a.disconnectInvoicingStripe, exports.updateInvoicingStripeConnection = _a.updateInvoicingStripeConnection, exports.invoicingStripeConnectionFailure = _a.invoicingStripeConnectionFailure;
112
+ _a = settingsView.actions, exports.fetchInvoicingSettings = _a.fetchInvoicingSettings, exports.updateInvoicingSettings = _a.updateInvoicingSettings, exports.updateInvoicingSettingsFailure = _a.updateInvoicingSettingsFailure, exports.saveInvoicingSettings = _a.saveInvoicingSettings, exports.saveInvoicingSettingsSuccess = _a.saveInvoicingSettingsSuccess, exports.saveInvoicingSettingsFailure = _a.saveInvoicingSettingsFailure, exports.resetSaveInvoicingSettings = _a.resetSaveInvoicingSettings, exports.updateInvoicingBrandingFormDraft = _a.updateInvoicingBrandingFormDraft, exports.submitInvoicingBrandingForm = _a.submitInvoicingBrandingForm, exports.resetInvoicingBrandingFormDraft = _a.resetInvoicingBrandingFormDraft, exports.updateInvoicingQboSettingsDraft = _a.updateInvoicingQboSettingsDraft, exports.submitInvoicingQboSettings = _a.submitInvoicingQboSettings, exports.resetInvoicingQboSettingsDraft = _a.resetInvoicingQboSettingsDraft, exports.connectInvoicingStripe = _a.connectInvoicingStripe, exports.disconnectInvoicingStripe = _a.disconnectInvoicingStripe, exports.updateInvoicingStripeConnection = _a.updateInvoicingStripeConnection, exports.invoicingStripeConnectionFailure = _a.invoicingStripeConnectionFailure;
102
113
  exports.default = settingsView.reducer;
@@ -1,11 +1,12 @@
1
1
  import { NestedAccountHierarchyForReport } from '../../../commonStateTypes/accountView/nestedAccountID';
2
2
  import { FetchState, FetchStateAndError } from '../../../commonStateTypes/common';
3
- import { InvoicingDunningActionOption, InvoicingNamedOption, InvoicingQboAccountMappingKindOption, InvoicingQboSettingsPayload, InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
3
+ import { InvoicingDunningActionOption, InvoicingNamedOption, InvoicingQboAccountMappingKindOption, InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
4
4
  import { ZeniAPIStatus } from '../../../responsePayload';
5
5
  import { RootState } from '../../../rootStateTypes';
6
6
  import { InvoicingQboConnection, InvoicingQboSyncHealth } from '../invoicingQboView/invoicingQboViewPayload';
7
7
  import { InvoicingAccountingOption } from '../invoicingQboView/invoicingQboViewSelector';
8
8
  import { InvoicingBrandingFormLocalData } from './invoicingBrandingFormConfig';
9
+ import { InvoicingQboSettingsLocalData } from './invoicingQboSettingsFormConfig';
9
10
  /**
10
11
  * Shared primitive: the raw invoicing settings. Consumed internally by other
11
12
  * CES selectors (create-invoice, customer-detail, overview) and by non-settings
@@ -98,7 +99,7 @@ export interface InvoicingQboSettingsFormView {
98
99
  /** The persisted sync toggle — the backfill guard checks that, not the draft. */
99
100
  isSyncEnabledSaved: boolean;
100
101
  /** The draft the page edits, seeded from the settings response. */
101
- localData: InvoicingQboSettingsPayload;
102
+ localData: InvoicingQboSettingsLocalData;
102
103
  nestedAccountHierarchy: NestedAccountHierarchyForReport[];
103
104
  retryFetchStateByTaskId: Record<string, FetchStateAndError>;
104
105
  saveState: FetchStateAndError;
@@ -7,6 +7,7 @@ const addressViewSelector_1 = require("../../addressView/addressViewSelector");
7
7
  const invoicingConfigViewSelector_1 = require("../invoicingConfigView/invoicingConfigViewSelector");
8
8
  const invoicingQboViewSelector_1 = require("../invoicingQboView/invoicingQboViewSelector");
9
9
  const invoicingBrandingFormConfig_1 = require("./invoicingBrandingFormConfig");
10
+ const invoicingQboSettingsFormConfig_1 = require("./invoicingQboSettingsFormConfig");
10
11
  /**
11
12
  * Shared primitive: the raw invoicing settings. Consumed internally by other
12
13
  * CES selectors (create-invoice, customer-detail, overview) and by non-settings
@@ -58,7 +59,12 @@ function deriveInvoicingEnablePrerequisites(settings, isQboConnected, qboAccount
58
59
  // configured would let `every` pass vacuously and unlock the button early.
59
60
  const isQboConfigured = isQboConnected &&
60
61
  qboAccountMappingKindOptions.length > 0 &&
61
- qboAccountMappingKindOptions.every((option) => (0, invoicingCommonPayload_1.getInvoicingQboAccountMappingId)(accountMappings, option.code) != null);
62
+ qboAccountMappingKindOptions.every((option) => {
63
+ // A kind the client has no slot for cannot count as configured.
64
+ const code = (0, invoicingCommonPayload_1.toInvoicingQboAccountMappingCode)(option.code);
65
+ return (code != null &&
66
+ (0, invoicingCommonPayload_1.getInvoicingQboAccountMappingId)(accountMappings, code) != null);
67
+ });
62
68
  return {
63
69
  canEnable: isStripeConnected && isQboConfigured,
64
70
  isQboConfigured,
@@ -127,7 +133,9 @@ const getInvoicingQboSettingsFormView = (state) => {
127
133
  fetchState === 'In-Progress' ||
128
134
  (0, invoicingQboViewSelector_1.isInvoicingAccountingPickerDataLoading)(state),
129
135
  isSyncEnabledSaved: settings?.qbo?.enabled === true,
130
- localData: qboDraft ?? settings?.qbo ?? {},
136
+ // Seeded in the reducer when the settings response lands, so this is a plain
137
+ // read rather than a second place that decides what the page starts from.
138
+ localData: qboDraft ?? invoicingQboSettingsFormConfig_1.initialInvoicingQboSettingsLocalData,
131
139
  nestedAccountHierarchy: qboView.nestedAccountHierarchy,
132
140
  retryFetchStateByTaskId: qboView.retryFetchStateByTaskId,
133
141
  saveState: saveFetchState.fetchState === 'Not-Started' && error != null
@@ -1,6 +1,7 @@
1
1
  import { FetchStateAndError, FetchedState } from '../../../commonStateTypes/common';
2
- import { InvoicingQboSettingsPayload, InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
2
+ import { InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
3
3
  import { InvoicingBrandingFormLocalData } from './invoicingBrandingFormConfig';
4
+ import { InvoicingQboSettingsLocalData } from './invoicingQboSettingsFormConfig';
4
5
  export interface InvoicingSettingsViewState extends FetchedState {
5
6
  saveFetchState: FetchStateAndError;
6
7
  stripeFetchState: FetchStateAndError;
@@ -11,6 +12,6 @@ export interface InvoicingSettingsViewState extends FetchedState {
11
12
  * half-finished edit survives navigating away. Undefined until first edited,
12
13
  * which is what makes the server's settings the fallback.
13
14
  */
14
- qboDraft?: InvoicingQboSettingsPayload;
15
+ qboDraft?: InvoicingQboSettingsLocalData;
15
16
  settings?: InvoicingSettingsPayload;
16
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.2.10-betaAK1",
3
+ "version": "5.2.10-betaAK2",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",