@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
package/lib/esm/index.js
CHANGED
|
@@ -189,7 +189,7 @@ import { acknowledgeBulkUploadConfirmMatchComplete, bulkUploadAutomatchingTimedO
|
|
|
189
189
|
import { clearStatementDateConflict, confirmStatementMapping, deleteAccountStatement, excludeAccountFromReconciliation, fetchReconciliation as fetchReconciliationView, includeAccountInReconciliation, parseCombinedStatement, parseStatement, parseStatementFailure, parseStatementSuccess, reparseStatement, reparseStatementFailure, reparseStatementSuccess, resetReparseStatementStatus, saveReconciliationDetail as saveExpenseAutomationReconciliationDetail, saveReconciliationReview as saveExpenseAutomationReconciliationReview, setConnectionInProgressForAccount as setConnectionInProgressForAccountReconciliation, setStatementParseInProgress, setStatementProcessingDismissedToBackground, submitCombinedStatementUpdate, submitStatementUpdate, updateAccountReconciliationLocalData as updateExpenseAutomationAccountReconciliationLocalData, updateSelectedAccountId as updateExpenseAutomationAccountReconciliationSelectedAccountId, updateSelectedTab as updateExpenseAutomationAccountReconciliationSelectedTab, updateReconListScrollPosition as updateExpenseAutomationReconListScrollPosition, updateReviewTabSortState as updateExpenseAutomationReconReviewTabListSortState, updateReviewTabLocalData as updateExpenseAutomationReconReviewTabLocalData, updateReconcileTabListScrollState as updateExpenseAutomationReconcileTabListScrollState, updateReconcileTabListSortState as updateExpenseAutomationReconcileTabListSortState, updateReconcileTabLocalData as updateExpenseAutomationReconcileTabLocalData, updateSelectedDrawerAccountId as updateExpenseAutomationSelectedDrawerAccountId, updateNodeCollapseState, updateParsedStatementData, updateStatementProcessingBackgroundCompletedSteps, updateStatementProcessingFailed, updateStatementUpdateLocalData, updateStatementUploadChosen, uploadAccountStatement, } from './view/expenseAutomationView/reducers/reconciliationViewReducer';
|
|
190
190
|
import { backgroundRefetchReviewTab, clearExpenseAutomationTransactionsView, fetchTransactionCategorization, fetchTransactionCategorizationFailure, fetchTransactionCategorizationView, initializeTransactionCategorizationViewLocalData, markCategoryClassRecommendationsFailureForCategorization, markTransactionAsNotMiscategorized, removeTransactionFromAllTabs, saveTransactionCategorization, saveTransactionCategorizationLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, setEntityRecommendationForLineIdsForCategorization, syncTransactionCategorizationFromDetailSave, updateCurrentSelectedTransactionCategorizationTab, updateSelectedCheckboxTransactionIds, updateSelectedCustomerForTransaction, updateSelectedTransactionId, updateSelectedVendorForTransaction, updateTransactionCategorization, updateTransactionCategorizationCompletedSubTab, updateTransactionCategorizationSaveStatus, updateTransactionCategorizationUIState, updateTransactionCategorizationUploadReceiptState, updateTransactionFilters, updateTransactionGroup, uploadTransactionCategorizationReceiptSuccess, } from './view/expenseAutomationView/reducers/transactionsViewReducer';
|
|
191
191
|
import { getExpenseAutomationFluxAnalysisView } from './view/expenseAutomationView/selectors/fluxAnalysisViewSelector';
|
|
192
|
-
import { getExpenseAutomationReconciliationView, getLedgerAccountsForCombinedStatementMapping, getReparseStatementStatusByAccountId, getUnavailableLedgerAccountIds, isAccountReconReport, } from './view/expenseAutomationView/selectors/reconciliationViewSelector';
|
|
192
|
+
import { getExpenseAutomationReconciliationView, getLedgerAccountIdsWithStatementOverrideWarning, getLedgerAccountsForCombinedStatementMapping, getReparseStatementStatusByAccountId, getUnavailableLedgerAccountIds, isAccountReconReport, } from './view/expenseAutomationView/selectors/reconciliationViewSelector';
|
|
193
193
|
import { getExpenseAutomationTransactionView, getLastTransferEntryReplacement, } from './view/expenseAutomationView/selectors/transactionCategorizationSelector';
|
|
194
194
|
import { applyTransactionFilters } from './view/expenseAutomationView/transactionFilterHelpers';
|
|
195
195
|
import { TRANSACTION_FILTER_CATEGORIES, } from './view/expenseAutomationView/transactionFilterTypes';
|
|
@@ -485,7 +485,7 @@ export {
|
|
|
485
485
|
// Bulk Upload Types
|
|
486
486
|
BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, DEFAULT_COMPLETED_SUB_TAB, DEFAULT_TRANSACTION_GROUP, TRANSACTION_GROUPS, toTransactionGroup, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, toExpenseAutomationJEScheduleMainTab, toExpenseAutomationJEScheduleSortKey, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, updateTransactionGroup, fetchExpenseAutomationMissingReceipts,
|
|
487
487
|
// Bulk Upload Actions
|
|
488
|
-
bulkUploadReceipts, bulkUploadAutomatchingTimedOut, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, restoreBulkUploadAutomatchingOnMount, restoreBulkUploadMatchingState, updateBulkUploadProgress, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, clearBulkUploadBatchDetailsForScopeChange, markBatchDetailRefreshAttempted, refreshBatchDetailsForBatchId, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, setBulkUploadUploadedFileCount, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete, fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, fetchFluxAnalysisView, clearExpenseAutomationFluxAnalysisView, updateOperatingExpensesIdsForReview as updateFluxOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview as updateFluxAnalysisSelectedSectionIdsForReview, reviewFluxAnalysisView, updateExpenseAutomationMissingReceiptUploadState, updateExpenseAutomationMissingReceiptsUIState, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, getExpenseAutomationFluxAnalysisView, updateCurrentSelectedView, updateCurrentSelectedPeriod, getExpenseAutomationTransactionView, getLastTransferEntryReplacement, updateFluxAnalysisViewUIState, updateFluxAnalysisViewPageMetaData, MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, excludeAccountFromReconciliation, includeAccountInReconciliation, saveExpenseAutomationReconciliationDetail, updateExpenseAutomationReconcileTabListScrollState, updateExpenseAutomationReconReviewTabListSortState, updateExpenseAutomationReconcileTabListSortState, updateExpenseAutomationReconcileTabLocalData, updateExpenseAutomationAccountReconciliationSelectedTab, updateExpenseAutomationAccountReconciliationSelectedAccountId, getExpenseAutomationReconciliationView, getLedgerAccountsForCombinedStatementMapping, getReparseStatementStatusByAccountId, getUnavailableLedgerAccountIds, fetchReconciliationView, uploadAccountStatementIntoDocumentAI, updateExpenseAutomationReconListScrollPosition, setConnectionInProgressForAccountReconciliation, getAccountReconByAccountIdAndSelectedPeriod, toReconciliationTabsType, isAccountReconReport, updateExpenseAutomationReconReviewTabLocalData, updateExpenseAutomationSelectedDrawerAccountId, updateStatementProcessingFailed, saveExpenseAutomationReconciliationReview, updateExpenseAutomationAccountReconciliationLocalData, toReconciliationAccountSource, deleteAccountStatement, uploadAccountStatement, parseCombinedStatement, parseStatement, parseStatementSuccess, parseStatementFailure, reparseStatement, reparseStatementSuccess, reparseStatementFailure, resetReparseStatementStatus, updateParsedStatementData, updateNodeCollapseState, updateStatementUploadChosen, submitCombinedStatementUpdate, submitStatementUpdate, clearStatementDateConflict, confirmStatementMapping, updateStatementUpdateLocalData, isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType, isReviewTransactionCreditCardPaymentType, isReviewTransactionDepositType, isReviewTransactionExpenseType, isReviewTransactionCreditCardCreditType, setStatementParseInProgress, setStatementProcessingDismissedToBackground, updateStatementProcessingBackgroundCompletedSteps, };
|
|
488
|
+
bulkUploadReceipts, bulkUploadAutomatchingTimedOut, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, restoreBulkUploadAutomatchingOnMount, restoreBulkUploadMatchingState, updateBulkUploadProgress, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, clearBulkUploadBatchDetailsForScopeChange, markBatchDetailRefreshAttempted, refreshBatchDetailsForBatchId, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, setBulkUploadUploadedFileCount, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete, fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, fetchFluxAnalysisView, clearExpenseAutomationFluxAnalysisView, updateOperatingExpensesIdsForReview as updateFluxOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview as updateFluxAnalysisSelectedSectionIdsForReview, reviewFluxAnalysisView, updateExpenseAutomationMissingReceiptUploadState, updateExpenseAutomationMissingReceiptsUIState, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, getExpenseAutomationFluxAnalysisView, updateCurrentSelectedView, updateCurrentSelectedPeriod, getExpenseAutomationTransactionView, getLastTransferEntryReplacement, updateFluxAnalysisViewUIState, updateFluxAnalysisViewPageMetaData, MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, excludeAccountFromReconciliation, includeAccountInReconciliation, saveExpenseAutomationReconciliationDetail, updateExpenseAutomationReconcileTabListScrollState, updateExpenseAutomationReconReviewTabListSortState, updateExpenseAutomationReconcileTabListSortState, updateExpenseAutomationReconcileTabLocalData, updateExpenseAutomationAccountReconciliationSelectedTab, updateExpenseAutomationAccountReconciliationSelectedAccountId, getExpenseAutomationReconciliationView, getLedgerAccountIdsWithStatementOverrideWarning, getLedgerAccountsForCombinedStatementMapping, getReparseStatementStatusByAccountId, getUnavailableLedgerAccountIds, fetchReconciliationView, uploadAccountStatementIntoDocumentAI, updateExpenseAutomationReconListScrollPosition, setConnectionInProgressForAccountReconciliation, getAccountReconByAccountIdAndSelectedPeriod, toReconciliationTabsType, isAccountReconReport, updateExpenseAutomationReconReviewTabLocalData, updateExpenseAutomationSelectedDrawerAccountId, updateStatementProcessingFailed, saveExpenseAutomationReconciliationReview, updateExpenseAutomationAccountReconciliationLocalData, toReconciliationAccountSource, deleteAccountStatement, uploadAccountStatement, parseCombinedStatement, parseStatement, parseStatementSuccess, parseStatementFailure, reparseStatement, reparseStatementSuccess, reparseStatementFailure, resetReparseStatementStatus, updateParsedStatementData, updateNodeCollapseState, updateStatementUploadChosen, submitCombinedStatementUpdate, submitStatementUpdate, clearStatementDateConflict, confirmStatementMapping, updateStatementUpdateLocalData, isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType, isReviewTransactionCreditCardPaymentType, isReviewTransactionDepositType, isReviewTransactionExpenseType, isReviewTransactionCreditCardCreditType, setStatementParseInProgress, setStatementProcessingDismissedToBackground, updateStatementProcessingBackgroundCompletedSteps, };
|
|
489
489
|
export { fetchTransactionCategorization, fetchTransactionCategorizationView, updateTransactionCategorizationUIState, updateTransactionFilters, updateSelectedCheckboxTransactionIds, markCategoryClassRecommendationsFailureForCategorization, setEntityRecommendationForLineIdsForCategorization, initializeTransactionCategorizationViewLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, createTransferEntry, createTransferEntryFailure, createTransferEntryReplacedTransaction, createTransferEntrySuccess, resetCreateTransferEntryStatus, clearTransferEntryRouteReplacement, fetchAccountsForTransferFlow, removeTransactionFromAllTabs, clearExpenseAutomationTransactionsView, toTransactionsSortKey, };
|
|
490
490
|
export { TOP_EX_TIME_PERIODS };
|
|
491
491
|
export { toTimeframeTick, mapTimePeriodtoTimeframeTick, toTimePeriod, toAbsoluteDay, toMonthYearPeriodId, convertToPeriod, };
|
|
@@ -768,7 +768,7 @@ export { INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE, entityToInvoicingSubscrip
|
|
|
768
768
|
export { getEditInvoicingSubscriptionDetailViewState, getInvoicingSubscriptionFormView, } from './view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector';
|
|
769
769
|
export { archiveInvoicingCatalogSubFamily, createInvoicingCatalogSubFamily, resetEditInvoicingCatalogItemDetailView, saveInvoicingCatalogItem, submitInvoicingCatalogItemForm, updateInvoicingCatalogItemFormDraft, } from './view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer';
|
|
770
770
|
export { catalogDetailEditValuesToSavePayload, createSubFamilyFormToPayload, planToCatalogDetailEditValues, productToCreateSubFamilyFormValues, } from './view/invoicing/editInvoicingCatalogItemDetailView/catalogDetailEditPayload';
|
|
771
|
-
export { INVOICING_CATALOG_APPLICABILITY_VALUES, INVOICING_CATALOG_PRICING_MODEL_VALUES, INVOICING_CATALOG_PRORATION_VALUES, INVOICING_CATALOG_TIER_TYPE_VALUES, blankInvoicingCatalogSubFamily, blankInvoicingCatalogTier, entityToInvoicingCatalogItemFormLocalData, initialInvoicingCatalogItemFormLocalData, isTieredCatalogPricingModel, } from './view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormConfig';
|
|
771
|
+
export { INVOICING_CATALOG_APPLICABILITY_VALUES, INVOICING_CATALOG_PRICING_MODEL_VALUES, INVOICING_CATALOG_PRORATION_VALUES, INVOICING_CATALOG_TIER_TYPE_VALUES, blankInvoicingCatalogSubFamily, blankInvoicingCatalogTier, entityToInvoicingCatalogItemFormLocalData, invoicingProductToCatalogItemFormSubFamily, initialInvoicingCatalogItemFormLocalData, isTieredCatalogPricingModel, } from './view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormConfig';
|
|
772
772
|
export { getEditInvoicingCatalogItemDetailViewState, getInvoicingApplicableCatalogItemOptions, getInvoicingCatalogItemFormView, getSavedInvoicingCatalogItemId, getSavedInvoicingCatalogItemKind, } from './view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector';
|
|
773
773
|
export { resetEditInvoicingCouponDetailView, saveInvoicingCoupon, submitInvoicingCouponForm, updateInvoicingCouponFormDraft, } from './view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer';
|
|
774
774
|
export { entityToInvoicingCouponFormLocalData, initialInvoicingCouponFormLocalData, } from './view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewState';
|
|
@@ -856,8 +856,9 @@ export { INVOICING_BUSINESS_ADDRESS_TYPE, entityToInvoicingBrandingFormLocalData
|
|
|
856
856
|
export { isStripeConnectedFromSettings } from './view/invoicing/settingsView/invoicingSettingsHelpers';
|
|
857
857
|
// ── Invoicing: QBO integration ────────────────────────────────────────────────
|
|
858
858
|
export { fetchInvoicingAccountingPickers, fetchInvoicingQboConnection, fetchInvoicingQboSyncHealth, retryInvoicingQboSyncTask, startInvoicingQboBackfill, } from './view/invoicing/invoicingQboView/invoicingQboViewReducer';
|
|
859
|
-
export {
|
|
859
|
+
export { invoicingAccountsForQboAccountTypes } from './view/invoicing/invoicingQboView/invoicingQboViewSelector';
|
|
860
860
|
export { getInvoicingQboView } from './view/invoicing/invoicingQboView/invoicingQboViewSelector';
|
|
861
|
+
export { getInvoicingCatalogAccountingLookup } from './view/invoicing/invoicingQboView/invoicingQboViewSelector';
|
|
861
862
|
export { INVOICING_QBO_CUSTOMER_MATCHING_MODES, getInvoicingQboAccountMappingId, toInvoicingNamedOptionsByKey, toInvoicingQboCustomerMatchingMode, } from './entity/invoicing/invoicingCommonPayload';
|
|
862
863
|
// ── Invoicing: config ─────────────────────────────────────────────────────────
|
|
863
864
|
export { acceptInvoicingTerms, enableInvoicing, fetchInvoicingConfig, resetInvoicingConfigActionStates, updateInvoicingConfig, } from './view/invoicing/invoicingConfigView/invoicingConfigViewReducer';
|
package/lib/esm/view/expenseAutomationView/epics/accountRecon/confirmStatementMappingEpic.js
CHANGED
|
@@ -4,11 +4,27 @@ import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
5
|
import { isConfirmStatementMappingConflictResponse, transformConfirmStatementMappingConflictToState, transformConfirmStatementMappingPayloadToState, } from '../../payload/reconciliationPayload';
|
|
6
6
|
import { confirmStatementMapping, confirmStatementMappingFailure, confirmStatementMappingSuccess, } from '../../reducers/reconciliationViewReducer';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
function createConfirmStatementMappingErrorSnackbar(apiMessage) {
|
|
8
|
+
const trimmedApiMessage = apiMessage?.trim();
|
|
9
|
+
if (trimmedApiMessage != null && trimmedApiMessage !== '') {
|
|
10
|
+
return openSnackbar({
|
|
11
|
+
messageSection: 'confirm_statement_mapping',
|
|
12
|
+
messageText: 'failed',
|
|
13
|
+
type: 'error',
|
|
14
|
+
variables: [
|
|
15
|
+
{
|
|
16
|
+
variableName: '_api-error_',
|
|
17
|
+
variableValue: trimmedApiMessage,
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return openSnackbar({
|
|
23
|
+
messageSection: 'confirm_statement_mapping',
|
|
24
|
+
messageText: 'failed',
|
|
25
|
+
type: 'error',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
12
28
|
export const confirmStatementMappingEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(confirmStatementMapping.match), exhaustMap((action) => {
|
|
13
29
|
const { accountId, selectedPeriod, statementUploadId, accountMappings } = action.payload;
|
|
14
30
|
const confirmMappingApi$ = zeniAPI.postAndGetJSON(`${zeniAPI.apiEndPoints.reconciliationMicroServiceBaseUrl}/1.0/reconciliation/statements/${statementUploadId}/confirm-mapping`, {
|
|
@@ -33,11 +49,11 @@ export const confirmStatementMappingEpic = (actions$, _state$, zeniAPI) => actio
|
|
|
33
49
|
selectedPeriod,
|
|
34
50
|
error: response.status,
|
|
35
51
|
mappingConflict,
|
|
36
|
-
}),
|
|
52
|
+
}), createConfirmStatementMappingErrorSnackbar(response.status.message));
|
|
37
53
|
}), catchError((error) => of(confirmStatementMappingFailure({
|
|
38
54
|
accountId,
|
|
39
55
|
selectedPeriod,
|
|
40
56
|
error: createZeniAPIStatus('Unexpected Error', 'Confirm Statement Mapping REST API call errored out ' +
|
|
41
57
|
(error instanceof Error ? error.message : String(error))),
|
|
42
|
-
}),
|
|
58
|
+
}), createConfirmStatementMappingErrorSnackbar())));
|
|
43
59
|
}));
|
package/lib/esm/view/expenseAutomationView/epics/accountRecon/updateCombinedStatementInfoEpic.js
CHANGED
|
@@ -3,9 +3,9 @@ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
|
|
|
3
3
|
import { toMonthYearPeriodId } from '../../../../commonStateTypes/timePeriod';
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
5
|
import { mapCombinedStatementUpdateLocalDataToRequestBody } from '../../helpers/mapStatementUpdateLocalDataToRequestBody';
|
|
6
|
-
import { getStatementUploadsFromParsedData } from '../../selectors/statementParseViewSelector';
|
|
7
6
|
import { isStatementDateConflictResponse, transformStatementDateConflictToState, transformUpdateStatementInfoPayloadToState, } from '../../payload/reconciliationPayload';
|
|
8
7
|
import { submitCombinedStatementUpdate, submitStatementUpdateFailure, submitStatementUpdateSuccess, updateParsedStatementData, } from '../../reducers/reconciliationViewReducer';
|
|
8
|
+
import { getStatementUploadsFromParsedData } from '../../selectors/statementParseViewSelector';
|
|
9
9
|
export const updateCombinedStatementInfoEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(submitCombinedStatementUpdate.match), switchMap((action) => {
|
|
10
10
|
const { accountId, selectedPeriod } = action.payload;
|
|
11
11
|
const accountRecon = state$.value.expenseAutomationReconciliationViewState
|
|
@@ -254,7 +254,7 @@ export function transformConfirmStatementMappingConflictToState(response) {
|
|
|
254
254
|
}
|
|
255
255
|
export function transformUpdateStatementInfoPayloadToState(payload) {
|
|
256
256
|
if (isUpdateStatementInfoCombinedResponsePayload(payload) === true) {
|
|
257
|
-
const statementUploads = payload.statement_uploads.map(transformStatementUploadPayloadToState);
|
|
257
|
+
const statementUploads = payload.statement_uploads.map((item) => transformStatementUploadPayloadToState(item.statement_upload));
|
|
258
258
|
const anchorUpload = statementUploads.find((upload) => upload.statementMeta.isCombinedStatementAnchor === true) ?? statementUploads[0];
|
|
259
259
|
return {
|
|
260
260
|
statementUpload: anchorUpload,
|
|
@@ -464,6 +464,7 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
464
464
|
accountRecon.confirmStatementMappingConflict = null;
|
|
465
465
|
if (accountRecon.localData != null) {
|
|
466
466
|
accountRecon.localData.statementUpdateLocalDataByUploadId = undefined;
|
|
467
|
+
accountRecon.localData.combinedStatementAccountMappings = undefined;
|
|
467
468
|
}
|
|
468
469
|
if (statementAccountScope != null) {
|
|
469
470
|
accountRecon.localData = {
|
|
@@ -542,6 +543,7 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
542
543
|
accountRecon.confirmStatementMappingConflict = null;
|
|
543
544
|
if (accountRecon.localData != null) {
|
|
544
545
|
accountRecon.localData.statementUpdateLocalDataByUploadId = undefined;
|
|
546
|
+
accountRecon.localData.combinedStatementAccountMappings = undefined;
|
|
545
547
|
accountRecon.localData.statementAccountScope = undefined;
|
|
546
548
|
}
|
|
547
549
|
}
|
|
@@ -772,6 +774,9 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
772
774
|
};
|
|
773
775
|
accountRecon.confirmStatementMappingConflict = null;
|
|
774
776
|
accountRecon.confirmedCombinedStatementUploads = statementUploads;
|
|
777
|
+
if (accountRecon.localData != null) {
|
|
778
|
+
accountRecon.localData.combinedStatementAccountMappings = undefined;
|
|
779
|
+
}
|
|
775
780
|
const combinedStatementDetails = accountRecon.parsedStatementData?.statementUpload
|
|
776
781
|
.combinedStatementDetails;
|
|
777
782
|
if (combinedStatementDetails != null) {
|
|
@@ -475,8 +475,18 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
475
475
|
});
|
|
476
476
|
export const getReparseStatementStatusByAccountId = (state, accountId) => getExpenseAutomationReconciliationView(state)
|
|
477
477
|
.accountReconciliationsByAccountID[accountId]?.reparseStatementStatus;
|
|
478
|
-
export function getLedgerAccountsForCombinedStatementMapping(accountReconciliationsByAccountID) {
|
|
479
|
-
|
|
478
|
+
export function getLedgerAccountsForCombinedStatementMapping(accountReconciliationsByAccountID, selectedAccountId) {
|
|
479
|
+
const selectedAccountType = accountReconciliationsByAccountID[selectedAccountId]?.accountReconEntity
|
|
480
|
+
.account.accountType;
|
|
481
|
+
const shouldFilterByPaymentAccountType = selectedAccountType === 'bank' || selectedAccountType === 'credit_card';
|
|
482
|
+
return Object.values(accountReconciliationsByAccountID)
|
|
483
|
+
.map((accountReconciliation) => accountReconciliation.accountReconEntity.account)
|
|
484
|
+
.filter((account) => {
|
|
485
|
+
if (shouldFilterByPaymentAccountType !== true) {
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
return account.accountType === selectedAccountType;
|
|
489
|
+
});
|
|
480
490
|
}
|
|
481
491
|
const UNAVAILABLE_LEDGER_ACCOUNT_RECON_STATUSES = new Set(['in_progress', 'reconciled', 'reconciled_on_qbo']);
|
|
482
492
|
export function getUnavailableLedgerAccountIds(accountReconciliationsByAccountID) {
|
|
@@ -488,6 +498,27 @@ export function getUnavailableLedgerAccountIds(accountReconciliationsByAccountID
|
|
|
488
498
|
})
|
|
489
499
|
.map((accountReconciliation) => accountReconciliation.accountReconEntity.account.accountId);
|
|
490
500
|
}
|
|
501
|
+
/** Selectable accounts that already have a statement — mapping will override that work. */
|
|
502
|
+
export function getLedgerAccountIdsWithStatementOverrideWarning(accountReconciliationsByAccountID, selectedAccountId) {
|
|
503
|
+
return Object.values(accountReconciliationsByAccountID)
|
|
504
|
+
.filter((accountReconciliation) => {
|
|
505
|
+
const entity = accountReconciliation.accountReconEntity;
|
|
506
|
+
const accountId = entity.account.accountId;
|
|
507
|
+
if (selectedAccountId != null && accountId === selectedAccountId) {
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
const hasUploadedStatement = entity.statementStatus?.code === 'uploaded' ||
|
|
511
|
+
entity.statementMetaData?.file != null ||
|
|
512
|
+
accountReconciliation.statementParseInProgress === true;
|
|
513
|
+
if (hasUploadedStatement !== true) {
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
const statusCode = entity.reconciliationStatus?.code;
|
|
517
|
+
return (statusCode == null ||
|
|
518
|
+
UNAVAILABLE_LEDGER_ACCOUNT_RECON_STATUSES.has(statusCode) !== true);
|
|
519
|
+
})
|
|
520
|
+
.map((accountReconciliation) => accountReconciliation.accountReconEntity.account.accountId);
|
|
521
|
+
}
|
|
491
522
|
export const isAccountReconReport = (reportId) => {
|
|
492
523
|
return reportId.endsWith('reconciliation');
|
|
493
524
|
};
|
package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/catalogDetailEditPayload.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { buildAccountingDetail, } from './editInvoicingCatalogItemDetailViewPayload';
|
|
1
2
|
import { invoicingProductToCatalogItemFormSubFamily, isTieredCatalogPricingModel, } from './invoicingCatalogItemFormConfig';
|
|
2
3
|
const trimOrUndefined = (value) => value.trim() !== '' ? value.trim() : undefined;
|
|
3
4
|
const trimOrNull = (value) => value.trim() !== '' ? value.trim() : null;
|
|
@@ -35,7 +36,7 @@ const tierToPayload = (tier) => ({
|
|
|
35
36
|
pricing_type: tier.pricingType,
|
|
36
37
|
starting_unit: Number(tier.startingUnit) || 1,
|
|
37
38
|
});
|
|
38
|
-
const subFamilyToProductUpdate = (subFamily, itemType) => {
|
|
39
|
+
const subFamilyToProductUpdate = (subFamily, itemType, lookup) => {
|
|
39
40
|
const tiered = isTieredCatalogPricingModel(subFamily.pricingModel);
|
|
40
41
|
const data = {
|
|
41
42
|
billing_cycles: hasValue(subFamily.billingCycles)
|
|
@@ -62,9 +63,12 @@ const subFamilyToProductUpdate = (subFamily, itemType) => {
|
|
|
62
63
|
if (itemType === 'addon') {
|
|
63
64
|
data.proration_type = subFamily.prorationType;
|
|
64
65
|
}
|
|
66
|
+
// `null` rather than omitted when empty: an absent key on an update reads as
|
|
67
|
+
// "leave it alone", so a cleared account or class could never be saved.
|
|
68
|
+
data.accounting_detail = buildAccountingDetail(subFamily, lookup) ?? null;
|
|
65
69
|
return { data, id: subFamily.id };
|
|
66
70
|
};
|
|
67
|
-
export const catalogDetailEditValuesToSavePayload = (values, itemType = 'plan', originalSubFamilies) => {
|
|
71
|
+
export const catalogDetailEditValuesToSavePayload = (values, lookup, itemType = 'plan', originalSubFamilies) => {
|
|
68
72
|
const planData = {
|
|
69
73
|
applicable_items: values.itemApplicability === 'restricted' ? values.applicableItems : [],
|
|
70
74
|
enabled_for_checkout: values.enabledForCheckout,
|
|
@@ -96,12 +100,12 @@ export const catalogDetailEditValuesToSavePayload = (values, itemType = 'plan',
|
|
|
96
100
|
planData.unit = unit;
|
|
97
101
|
}
|
|
98
102
|
const productUpdates = values.subFamilies.flatMap((subFamily) => {
|
|
99
|
-
const update = subFamilyToProductUpdate(subFamily, itemType);
|
|
103
|
+
const update = subFamilyToProductUpdate(subFamily, itemType, lookup);
|
|
100
104
|
const original = originalSubFamilies?.find((product) => product.id === subFamily.id);
|
|
101
105
|
if (original == null) {
|
|
102
106
|
return [update];
|
|
103
107
|
}
|
|
104
|
-
const originalUpdate = subFamilyToProductUpdate(subFamilyToEditValues(original), itemType);
|
|
108
|
+
const originalUpdate = subFamilyToProductUpdate(subFamilyToEditValues(original), itemType, lookup);
|
|
105
109
|
const changedData = Object.fromEntries(Object.entries(update.data).filter(([key, value]) => JSON.stringify(value) !== JSON.stringify(originalUpdate.data[key])));
|
|
106
110
|
return Object.keys(changedData).length > 0
|
|
107
111
|
? [{ data: changedData, id: update.id }]
|
|
@@ -113,21 +117,28 @@ export const catalogDetailEditValuesToSavePayload = (values, itemType = 'plan',
|
|
|
113
117
|
};
|
|
114
118
|
};
|
|
115
119
|
/** Build POST /catalog/products body for Create sub-family. */
|
|
116
|
-
export const createSubFamilyFormToPayload = (itemId, itemType, values) => {
|
|
120
|
+
export const createSubFamilyFormToPayload = (itemId, itemType, values, lookup) => {
|
|
117
121
|
const name = values.name.trim();
|
|
118
122
|
const priceCode = trimOrUndefined(values.priceCode) ?? toProductCode(name);
|
|
119
123
|
const tiered = isTieredCatalogPricingModel(values.pricingModel);
|
|
120
124
|
const payload = {
|
|
121
125
|
currency_code: 'USD',
|
|
122
126
|
free_quantity: Number(values.freeQuantity) || 0,
|
|
123
|
-
is_taxable:
|
|
127
|
+
is_taxable: values.isTaxable,
|
|
124
128
|
item_id: itemId,
|
|
125
129
|
name,
|
|
126
130
|
price: tiered ? 0 : (values.priceDollars?.amount ?? 0),
|
|
127
131
|
price_code: priceCode,
|
|
128
132
|
pricing_model: values.pricingModel || 'flat_fee',
|
|
129
|
-
show_description_in_invoices:
|
|
133
|
+
show_description_in_invoices: values.showDescriptionInInvoices,
|
|
134
|
+
show_description_in_quotes: values.showDescriptionInQuotes,
|
|
130
135
|
};
|
|
136
|
+
// The same accounting body the item payload sends, so a price point created
|
|
137
|
+
// from the dialog carries the account and class the form would have given it.
|
|
138
|
+
const accountingDetail = buildAccountingDetail(values, lookup);
|
|
139
|
+
if (accountingDetail != null) {
|
|
140
|
+
payload.accounting_detail = accountingDetail;
|
|
141
|
+
}
|
|
131
142
|
if (tiered) {
|
|
132
143
|
payload.tiers = (values.tiers ?? []).map(tierToPayload);
|
|
133
144
|
}
|
|
@@ -157,10 +168,13 @@ export const createSubFamilyFormToPayload = (itemId, itemType, values) => {
|
|
|
157
168
|
return payload;
|
|
158
169
|
};
|
|
159
170
|
export const productToCreateSubFamilyFormValues = (product) => ({
|
|
171
|
+
accountingCategory: product?.accountingDetail?.accountingCategory1 ?? '',
|
|
172
|
+
accountingCode: product?.accountingDetail?.accountingCode ?? '',
|
|
160
173
|
billingCycles: product?.billingCycles != null ? String(product.billingCycles) : '',
|
|
161
174
|
description: product?.description ?? '',
|
|
162
175
|
freeQuantity: product?.freeQuantity != null ? String(product.freeQuantity) : '0',
|
|
163
176
|
invoiceNotes: product?.invoiceNotes ?? '',
|
|
177
|
+
isTaxable: product?.isTaxable ?? true,
|
|
164
178
|
name: product?.name != null ? `${product.name} (copy)` : '',
|
|
165
179
|
period: product?.period != null ? String(product.period) : '1',
|
|
166
180
|
periodUnit: product?.periodUnit ?? 'month',
|
|
@@ -168,6 +182,9 @@ export const productToCreateSubFamilyFormValues = (product) => ({
|
|
|
168
182
|
priceDollars: product?.price,
|
|
169
183
|
pricingModel: product?.pricingModel ?? 'flat_fee',
|
|
170
184
|
prorationType: product?.prorationType ?? 'site_default',
|
|
185
|
+
showDescriptionInInvoices: product?.showDescriptionInInvoices ?? true,
|
|
186
|
+
showDescriptionInQuotes: product?.showDescriptionInQuotes ?? false,
|
|
187
|
+
sku: product?.accountingDetail?.sku ?? '',
|
|
171
188
|
trialEndAction: product?.trialEndAction ?? 'site_default',
|
|
172
189
|
trialPeriod: product?.trialPeriod != null ? String(product.trialPeriod) : '',
|
|
173
190
|
trialPeriodUnit: product?.trialPeriodUnit ?? 'day',
|
|
@@ -9,7 +9,7 @@ const toProductCode = (value) => value
|
|
|
9
9
|
.toLowerCase()
|
|
10
10
|
.replace(/[^a-z0-9]+/g, '-')
|
|
11
11
|
.replace(/^-|-$/g, '');
|
|
12
|
-
const buildAccountingDetail = (subFamily, lookup) => {
|
|
12
|
+
export const buildAccountingDetail = (subFamily, lookup) => {
|
|
13
13
|
const detail = {};
|
|
14
14
|
if (subFamily.sku.trim() !== '') {
|
|
15
15
|
detail.sku = subFamily.sku.trim();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createSelector } from '@reduxjs/toolkit';
|
|
2
2
|
import { getInvoicingPlanById, getInvoicingPlansByIds, } from '../../../entity/invoicing/plan/planSelector';
|
|
3
3
|
import { getInvoicingConfigView, invoicingFieldHelpForGroup, } from '../invoicingConfigView/invoicingConfigViewSelector';
|
|
4
|
-
import {
|
|
4
|
+
import { getInvoicingQboView, isInvoicingAccountingPickerDataLoading, isInvoicingQboConnected, } from '../invoicingQboView/invoicingQboViewSelector';
|
|
5
5
|
import { INVOICING_CATALOG_APPLICABILITY_VALUES, INVOICING_CATALOG_PRICING_MODEL_VALUES, INVOICING_CATALOG_PRORATION_VALUES, INVOICING_CATALOG_TIER_TYPE_VALUES, entityToInvoicingCatalogItemFormLocalData, } from './invoicingCatalogItemFormConfig';
|
|
6
6
|
export const getEditInvoicingCatalogItemDetailViewState = (state) => ({
|
|
7
7
|
fetchState: state.editInvoicingCatalogItemDetailViewState.fetchState,
|
|
@@ -49,17 +49,15 @@ export const getInvoicingCatalogItemFormView = (state, id) => {
|
|
|
49
49
|
const applicableItemOptions = id != null
|
|
50
50
|
? allApplicableItemOptions.filter((option) => option.id !== id)
|
|
51
51
|
: allApplicableItemOptions;
|
|
52
|
-
const
|
|
52
|
+
const qboView = isInvoicingQboConnected(state)
|
|
53
|
+
? getInvoicingQboView(state)
|
|
54
|
+
: undefined;
|
|
53
55
|
const { billingPeriodUnitOptions, catalogItemTypeOptions, catalogTierTypeOptionsByPricingModel, catalogTrialEndActionOptions, catalogTrialUnitOptions, } = getInvoicingConfigView(state);
|
|
54
56
|
return {
|
|
55
57
|
fieldHelp: invoicingFieldHelpForGroup(state, 'catalog'),
|
|
56
58
|
isQboPickerDataLoading: isInvoicingAccountingPickerDataLoading(state),
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
: [],
|
|
60
|
-
qboIncomeAccountHierarchy: isQboConnected
|
|
61
|
-
? invoicingAccountHierarchyForTypes(state, INVOICING_INCOME_ACCOUNT_TYPES)
|
|
62
|
-
: [],
|
|
59
|
+
qboAccountHierarchy: qboView?.nestedAccountHierarchy ?? [],
|
|
60
|
+
qboClassHierarchy: qboView?.nestedClassHierarchy ?? [],
|
|
63
61
|
applicabilityValues: INVOICING_CATALOG_APPLICABILITY_VALUES,
|
|
64
62
|
applicableItemOptions,
|
|
65
63
|
localData,
|
package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogSubFamilyEpics.js
CHANGED
|
@@ -2,6 +2,8 @@ import { of } from 'rxjs';
|
|
|
2
2
|
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
3
|
import { mergeInvoicingPlanSubFamily } from '../../../entity/invoicing/plan/planReducer';
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../responsePayload';
|
|
5
|
+
import { getInvoicingCatalogAccountingLookup } from '../invoicingQboView/invoicingQboViewSelector';
|
|
6
|
+
import { createSubFamilyFormToPayload } from './catalogDetailEditPayload';
|
|
5
7
|
import { archiveInvoicingCatalogSubFamily, createInvoicingCatalogSubFamily, submitInvoicingCatalogItemFormFailure, submitInvoicingCatalogItemFormSuccess, } from './editInvoicingCatalogItemDetailViewReducer';
|
|
6
8
|
const subFamilySuccessActions = (parentItemId, subFamilyPayload) => [
|
|
7
9
|
mergeInvoicingPlanSubFamily(parentItemId, subFamilyPayload),
|
|
@@ -10,8 +12,12 @@ const subFamilySuccessActions = (parentItemId, subFamilyPayload) => [
|
|
|
10
12
|
kind: 'plan',
|
|
11
13
|
}),
|
|
12
14
|
];
|
|
13
|
-
export const createInvoicingCatalogSubFamilyEpic = (actions$,
|
|
14
|
-
const {
|
|
15
|
+
export const createInvoicingCatalogSubFamilyEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(createInvoicingCatalogSubFamily.match), mergeMap((action) => {
|
|
16
|
+
const { itemType, parentItemId, values } = action.payload;
|
|
17
|
+
const state = state$.value;
|
|
18
|
+
// Built here so the dialog can stay in picked ids: resolving one to the
|
|
19
|
+
// account record the payload carries needs the shared account list.
|
|
20
|
+
const data = createSubFamilyFormToPayload(parentItemId, itemType, values, getInvoicingCatalogAccountingLookup(state));
|
|
15
21
|
const baseUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0`;
|
|
16
22
|
return zeniAPI
|
|
17
23
|
.postAndGetJSON(`${baseUrl}/catalog/products`, data)
|
package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js
CHANGED
|
@@ -6,26 +6,31 @@ import { apiErrorSnackbarVariables } from '../../../entity/snackbar/snackbarApiE
|
|
|
6
6
|
import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
7
7
|
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
8
8
|
import { addInvoicingCatalogItem } from '../invoicingCatalogListView/invoicingCatalogListViewReducer';
|
|
9
|
-
import {
|
|
9
|
+
import { getInvoicingCatalogAccountingLookup } from '../invoicingQboView/invoicingQboViewSelector';
|
|
10
|
+
import { catalogDetailEditValuesToSavePayload, } from './catalogDetailEditPayload';
|
|
10
11
|
import { localDataToSaveInvoicingCatalogItemPayload, } from './editInvoicingCatalogItemDetailViewPayload';
|
|
11
12
|
import { saveInvoicingCatalogItem, submitInvoicingCatalogItemForm, submitInvoicingCatalogItemFormFailure, submitInvoicingCatalogItemFormSuccess, } from './editInvoicingCatalogItemDetailViewReducer';
|
|
12
13
|
export const saveInvoicingCatalogItemEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter((action) => submitInvoicingCatalogItemForm.match(action) ||
|
|
13
14
|
saveInvoicingCatalogItem.match(action)), mergeMap((action) => {
|
|
14
15
|
const { id } = action.payload;
|
|
15
|
-
|
|
16
|
+
const state = state$.value;
|
|
17
|
+
const accountingLookup = getInvoicingCatalogAccountingLookup(state);
|
|
18
|
+
// Both sources are form values, turned into request bodies here so the
|
|
19
|
+
// picked account and class become the records the service stores: the
|
|
20
|
+
// detail page's edit form, or the create/edit form's draft.
|
|
16
21
|
let data;
|
|
22
|
+
let editProductUpdates;
|
|
17
23
|
if (saveInvoicingCatalogItem.match(action)) {
|
|
18
|
-
|
|
24
|
+
const { editValues, itemType, originalSubFamilies } = action.payload;
|
|
25
|
+
const savePayload = catalogDetailEditValuesToSavePayload(editValues, accountingLookup, itemType, originalSubFamilies);
|
|
26
|
+
data = savePayload.planData;
|
|
27
|
+
editProductUpdates = savePayload.productUpdates;
|
|
19
28
|
}
|
|
20
29
|
else {
|
|
21
|
-
const viewState = state
|
|
30
|
+
const viewState = state.editInvoicingCatalogItemDetailViewState;
|
|
22
31
|
const localData = (id != null ? viewState.editDraftById[id] : viewState.newItemDraft) ??
|
|
23
32
|
viewState.newItemDraft;
|
|
24
|
-
|
|
25
|
-
data = localDataToSaveInvoicingCatalogItemPayload(localData, id == null, {
|
|
26
|
-
accountByQboId: (qboId) => invoicingQboAccountByQboId(state, qboId),
|
|
27
|
-
classByQboId: (qboId) => invoicingQboClassByQboId(state, qboId),
|
|
28
|
-
});
|
|
33
|
+
data = localDataToSaveInvoicingCatalogItemPayload(localData, id == null, accountingLookup);
|
|
29
34
|
}
|
|
30
35
|
const baseUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0`;
|
|
31
36
|
const path = id != null
|
|
@@ -88,7 +93,7 @@ export const saveInvoicingCatalogItemEpic = (actions$, state$, zeniAPI) => actio
|
|
|
88
93
|
return resultActions;
|
|
89
94
|
};
|
|
90
95
|
const productUpdates = saveInvoicingCatalogItem.match(action)
|
|
91
|
-
? (
|
|
96
|
+
? (editProductUpdates ?? [])
|
|
92
97
|
: [];
|
|
93
98
|
if (productUpdates.length === 0) {
|
|
94
99
|
return completeSave([]);
|
package/lib/esm/view/invoicing/invoicingQboView/epics/fetchInvoicingAccountingPickersEpic.js
CHANGED
|
@@ -18,7 +18,6 @@ export const fetchInvoicingAccountingPickersEpic = (actions$, state$) => actions
|
|
|
18
18
|
accountList.fetchState !== 'In-Progress') {
|
|
19
19
|
// Same arguments the vendor and categorization screens pass, so this
|
|
20
20
|
// shares their cached list rather than replacing it with a narrower one.
|
|
21
|
-
// Invoicing narrows to income accounts when it builds its options.
|
|
22
21
|
actions.push(fetchAccountList(INVOICING_ACCOUNT_LIST_KEY, true));
|
|
23
22
|
}
|
|
24
23
|
const classList = state.classListState;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { createSelector } from '@reduxjs/toolkit';
|
|
1
2
|
import { getAccountList, getNestedAccountListHierarchy, } from '../../accountList/accountListSelector';
|
|
2
3
|
import { getClassList, getNestedClassListHierarchy, } from '../../classList/classListSelector';
|
|
3
4
|
// The shared bucket, fetched with the same arguments as the other consumers so
|
|
4
|
-
// whichever screen loads first satisfies the rest. Invoicing
|
|
5
|
-
// accounts
|
|
5
|
+
// whichever screen loads first satisfies the rest. Invoicing renders the same
|
|
6
|
+
// accounts they do, so it does not need its own copy.
|
|
6
7
|
export const INVOICING_ACCOUNT_LIST_KEY = 'accountList';
|
|
7
8
|
/** Whether QBO is connected, without building the option lists to find out. */
|
|
8
9
|
export const isInvoicingQboConnected = (state) => state.invoicingQboViewState.connection?.connected === true;
|
|
@@ -29,14 +30,6 @@ export const isInvoicingAccountingPickerDataLoading = (state) => {
|
|
|
29
30
|
};
|
|
30
31
|
/** The QBO connection fetch on its own, without building the bundled view. */
|
|
31
32
|
export const getInvoicingQboConnectionFetchState = (state) => state.invoicingQboViewState.connectionFetchState;
|
|
32
|
-
/**
|
|
33
|
-
* Account types that can back invoicing revenue. Named here so screens ask for
|
|
34
|
-
* "income accounts" rather than repeating the accounting service's vocabulary.
|
|
35
|
-
*/
|
|
36
|
-
export const INVOICING_INCOME_ACCOUNT_TYPES = [
|
|
37
|
-
'income',
|
|
38
|
-
'other_income',
|
|
39
|
-
];
|
|
40
33
|
/**
|
|
41
34
|
* The account behind a picker value. The pickers submit the QuickBooks id, so
|
|
42
35
|
* that is what callers hold; the payload builders need the whole entity to send
|
|
@@ -77,6 +70,17 @@ export const invoicingQboClassByQboId = (state, qboId) => {
|
|
|
77
70
|
return undefined;
|
|
78
71
|
}
|
|
79
72
|
};
|
|
73
|
+
/**
|
|
74
|
+
* The resolver every catalog and settings payload builder needs: a picked
|
|
75
|
+
* QuickBooks id turned back into the account or class record the request body
|
|
76
|
+
* carries. Memoized so callers get one stable object rather than a fresh pair of
|
|
77
|
+
* closures per store change, which in `mapStateToProps` would re-render on every
|
|
78
|
+
* unrelated action.
|
|
79
|
+
*/
|
|
80
|
+
export const getInvoicingCatalogAccountingLookup = createSelector((state) => state, (state) => ({
|
|
81
|
+
accountByQboId: (qboId) => invoicingQboAccountByQboId(state, qboId),
|
|
82
|
+
classByQboId: (qboId) => invoicingQboClassByQboId(state, qboId),
|
|
83
|
+
}));
|
|
80
84
|
/**
|
|
81
85
|
* Accounts and classes as the invoicing pickers need them. Both come from the
|
|
82
86
|
* shared accounting-service lists, so whatever another screen already loaded
|
|
@@ -84,17 +88,12 @@ export const invoicingQboClassByQboId = (state, qboId) => {
|
|
|
84
88
|
* API stores; an account without one cannot be posted, so it is dropped rather
|
|
85
89
|
* than offered.
|
|
86
90
|
*/
|
|
87
|
-
const invoicingAccountingOptions = (state
|
|
91
|
+
const invoicingAccountingOptions = (state) => {
|
|
88
92
|
const { accounts } = getAccountList(state.accountState, state.accountListState, INVOICING_ACCOUNT_LIST_KEY);
|
|
89
93
|
return accounts.flatMap((account) => {
|
|
90
94
|
if (account.qboId == null || account.isDeleted === true) {
|
|
91
95
|
return [];
|
|
92
96
|
}
|
|
93
|
-
if (accountTypes != null &&
|
|
94
|
-
(account.accountType == null ||
|
|
95
|
-
!accountTypes.includes(account.accountType))) {
|
|
96
|
-
return [];
|
|
97
|
-
}
|
|
98
97
|
return [
|
|
99
98
|
{
|
|
100
99
|
id: String(account.qboId),
|
|
@@ -151,26 +150,6 @@ const invoicingAccountingClassOptions = (state) => {
|
|
|
151
150
|
},
|
|
152
151
|
]);
|
|
153
152
|
};
|
|
154
|
-
/**
|
|
155
|
-
* The account tree narrowed to the given account types. The tree itself carries
|
|
156
|
-
* no account type, so the flat account list supplies that and the matching
|
|
157
|
-
* `qboId`s are kept — which is why callers that only need "income accounts, as a
|
|
158
|
-
* tree" do not have to hold a second flat list to filter with.
|
|
159
|
-
*/
|
|
160
|
-
export const invoicingAccountHierarchyForTypes = (state, accountTypes) => {
|
|
161
|
-
const allowedQboIds = new Set(invoicingAccountingOptions(state, accountTypes).map((account) => account.id));
|
|
162
|
-
const keepMatching = (nodes) => nodes.flatMap((node) => {
|
|
163
|
-
const children = keepMatching(node.children);
|
|
164
|
-
const isMatch = node.qboId != null && allowedQboIds.has(String(node.qboId));
|
|
165
|
-
// A parent that is not itself a match is still kept when it holds one, so
|
|
166
|
-
// the tree's shape survives the filter.
|
|
167
|
-
if (!isMatch && children.length === 0) {
|
|
168
|
-
return [];
|
|
169
|
-
}
|
|
170
|
-
return [{ ...node, children }];
|
|
171
|
-
});
|
|
172
|
-
return keepMatching(getNestedAccountListHierarchy(state.accountListState, INVOICING_ACCOUNT_LIST_KEY));
|
|
173
|
-
};
|
|
174
153
|
/**
|
|
175
154
|
* Single bundled view for the QBO integration settings screen — the
|
|
176
155
|
* connection, the account and class options, sync health, and the fetch/action
|