@zeniai/client-epic-state 5.2.85 → 5.2.87
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/entity/reconciliationReport/reconciliationReportPayload.d.ts +95 -0
- package/lib/entity/reconciliationReport/reconciliationReportPayload.js +2 -0
- package/lib/entity/reconciliationReport/reconciliationReportReducer.d.ts +7 -0
- package/lib/entity/reconciliationReport/reconciliationReportReducer.js +151 -0
- package/lib/entity/reconciliationReport/reconciliationReportSelector.d.ts +3 -0
- package/lib/entity/reconciliationReport/reconciliationReportSelector.js +10 -0
- package/lib/entity/reconciliationReport/reconciliationReportState.d.ts +107 -0
- package/lib/entity/reconciliationReport/reconciliationReportState.js +15 -0
- package/lib/epic.d.ts +2 -1
- package/lib/epic.js +2 -0
- package/lib/esm/entity/reconciliationReport/reconciliationReportPayload.js +1 -0
- package/lib/esm/entity/reconciliationReport/reconciliationReportReducer.js +146 -0
- package/lib/esm/entity/reconciliationReport/reconciliationReportSelector.js +4 -0
- package/lib/esm/entity/reconciliationReport/reconciliationReportState.js +10 -0
- package/lib/esm/epic.js +2 -0
- package/lib/esm/index.js +5 -2
- package/lib/esm/reducer.js +7 -1
- package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +5 -1
- package/lib/esm/view/expenseAutomationView/selectors/reconciliationViewSelector.js +5 -1
- package/lib/esm/view/invoicing/createInvoice/epics/fetchCreateInvoiceFormPageEpic.js +19 -5
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewPayload.js +57 -4
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +3 -1
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionDetailPageEpic.js +7 -4
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionFormPageEpic.js +1 -0
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/invoicingSubscriptionFormConfig.js +2 -0
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +6 -2
- package/lib/esm/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogPlanListEpic.js +14 -3
- package/lib/esm/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogProductListEpic.js +14 -3
- package/lib/esm/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewReducer.js +2 -0
- package/lib/esm/view/invoicing/invoicingListTabCache.js +8 -0
- package/lib/esm/view/invoicing/issueCreditNote/issueCreditNotePayload.js +24 -9
- package/lib/esm/view/reconciliationReportView/epic/fetchReconciliationReportEpic.js +29 -0
- package/lib/esm/view/reconciliationReportView/reconciliationReportViewPayload.js +1 -0
- package/lib/esm/view/reconciliationReportView/reconciliationReportViewReducer.js +44 -0
- package/lib/esm/view/reconciliationReportView/reconciliationReportViewSelector.js +10 -0
- package/lib/esm/view/reconciliationReportView/reconciliationReportViewState.js +1 -0
- package/lib/index.d.ts +7 -3
- package/lib/index.js +52 -47
- package/lib/reducer.d.ts +2 -0
- package/lib/reducer.js +7 -1
- package/lib/rootStateTypes.d.ts +5 -1
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +5 -1
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.d.ts +3 -0
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.js +5 -0
- package/lib/view/invoicing/createInvoice/epics/fetchCreateInvoiceFormPageEpic.js +18 -4
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewPayload.d.ts +11 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewPayload.js +57 -4
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.d.ts +2 -0
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +2 -0
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewState.d.ts +13 -0
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionDetailPageEpic.js +6 -3
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionFormPageEpic.js +1 -0
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/invoicingSubscriptionFormConfig.d.ts +2 -0
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/invoicingSubscriptionFormConfig.js +4 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +5 -1
- package/lib/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogPlanListEpic.js +14 -3
- package/lib/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogProductListEpic.js +14 -3
- package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewReducer.d.ts +6 -0
- package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewReducer.js +2 -0
- package/lib/view/invoicing/invoicingListTabCache.d.ts +11 -1
- package/lib/view/invoicing/invoicingListTabCache.js +10 -1
- package/lib/view/invoicing/issueCreditNote/issueCreditNotePayload.js +24 -9
- package/lib/view/reconciliationReportView/epic/fetchReconciliationReportEpic.d.ts +19 -0
- package/lib/view/reconciliationReportView/epic/fetchReconciliationReportEpic.js +33 -0
- package/lib/view/reconciliationReportView/reconciliationReportViewPayload.d.ts +3 -0
- package/lib/view/reconciliationReportView/reconciliationReportViewPayload.js +2 -0
- package/lib/view/reconciliationReportView/reconciliationReportViewReducer.d.ts +13 -0
- package/lib/view/reconciliationReportView/reconciliationReportViewReducer.js +48 -0
- package/lib/view/reconciliationReportView/reconciliationReportViewSelector.d.ts +9 -0
- package/lib/view/reconciliationReportView/reconciliationReportViewSelector.js +13 -0
- package/lib/view/reconciliationReportView/reconciliationReportViewState.d.ts +4 -0
- package/lib/view/reconciliationReportView/reconciliationReportViewState.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
+
import { mapCurrencyPayloadToCurrency } from '../../commonPayloadTypes/v2/viewAndReportPayloadv2';
|
|
3
|
+
import { toAmountWC } from '../../commonStateTypes/amount';
|
|
4
|
+
import { clearAll } from '../../rootActions';
|
|
5
|
+
import { date } from '../../zeniDayJS';
|
|
6
|
+
import { toReconciliationStatusCodeType } from '../accountRecon/accountReconState';
|
|
7
|
+
import { toReconciliationReportDataSource, toReconciliationReportMatchType, } from './reconciliationReportState';
|
|
8
|
+
export const initialState = {
|
|
9
|
+
reportsByReconciliationId: {},
|
|
10
|
+
};
|
|
11
|
+
const reconciliationReport = createSlice({
|
|
12
|
+
name: 'reconciliationReport',
|
|
13
|
+
initialState,
|
|
14
|
+
reducers: {
|
|
15
|
+
updateReconciliationReport(draft, action) {
|
|
16
|
+
const report = mapReconciliationReportPayloadToReconciliationReport(action.payload);
|
|
17
|
+
draft.reportsByReconciliationId[report.reconciliationId] = report;
|
|
18
|
+
},
|
|
19
|
+
removeReconciliationReport(draft, action) {
|
|
20
|
+
delete draft.reportsByReconciliationId[action.payload];
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
extraReducers: (builder) => {
|
|
24
|
+
builder.addCase(clearAll, (draft) => {
|
|
25
|
+
Object.assign(draft, initialState);
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
export const { updateReconciliationReport, removeReconciliationReport } = reconciliationReport.actions;
|
|
30
|
+
export default reconciliationReport.reducer;
|
|
31
|
+
function toOptionalAmount(amount, currency) {
|
|
32
|
+
if (amount == null) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
return toAmountWC(amount, currency);
|
|
36
|
+
}
|
|
37
|
+
function toOptionalDate(value) {
|
|
38
|
+
if (value == null || value === '') {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return date(value);
|
|
42
|
+
}
|
|
43
|
+
function mapCountAmount(payload, currency) {
|
|
44
|
+
return {
|
|
45
|
+
count: payload.count,
|
|
46
|
+
amount: toAmountWC(payload.amount, currency),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function mapTransactionRow(payload, currency) {
|
|
50
|
+
return {
|
|
51
|
+
transactionId: payload.transaction_id ?? undefined,
|
|
52
|
+
date: toOptionalDate(payload.date),
|
|
53
|
+
type: payload.type,
|
|
54
|
+
payee: payload.payee,
|
|
55
|
+
match: toReconciliationReportMatchType(payload.match),
|
|
56
|
+
amount: toAmountWC(payload.amount, currency),
|
|
57
|
+
clearedBalance: payload.cleared_balance != null
|
|
58
|
+
? toAmountWC(payload.cleared_balance, currency)
|
|
59
|
+
: undefined,
|
|
60
|
+
glAccount: payload.gl_account ?? undefined,
|
|
61
|
+
issueDate: toOptionalDate(payload.issue_date),
|
|
62
|
+
ageDays: payload.age_days ?? undefined,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function mapBucket(payload, currency) {
|
|
66
|
+
return {
|
|
67
|
+
count: payload.count,
|
|
68
|
+
amount: toAmountWC(payload.amount, currency),
|
|
69
|
+
transactions: payload.transactions.map((transaction) => mapTransactionRow(transaction, currency)),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function mapPaymentsDeposits(payload, currency) {
|
|
73
|
+
return {
|
|
74
|
+
payments: mapBucket(payload.payments, currency),
|
|
75
|
+
deposits: mapBucket(payload.deposits, currency),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function mapReconciliationReportPayloadToReconciliationReport(payload) {
|
|
79
|
+
const currency = mapCurrencyPayloadToCurrency(payload.currency);
|
|
80
|
+
return {
|
|
81
|
+
reconciliationId: payload.reconciliation_id,
|
|
82
|
+
companyName: payload.company_name ?? undefined,
|
|
83
|
+
account: {
|
|
84
|
+
accountId: payload.account.account_id,
|
|
85
|
+
accountName: payload.account.account_name ?? undefined,
|
|
86
|
+
accountType: payload.account.account_type ?? undefined,
|
|
87
|
+
accountSubType: payload.account.account_sub_type ?? undefined,
|
|
88
|
+
last4Digits: payload.account.last_4_digits ?? undefined,
|
|
89
|
+
maskedAccountNumber: payload.account.masked_account_number ?? undefined,
|
|
90
|
+
financialInstitution: payload.account.financial_institution ?? undefined,
|
|
91
|
+
glAccountName: payload.account.gl_account_name ?? undefined,
|
|
92
|
+
coaId: payload.account.coa_id ?? undefined,
|
|
93
|
+
},
|
|
94
|
+
period: {
|
|
95
|
+
startDate: toOptionalDate(payload.period.start_date),
|
|
96
|
+
endDate: toOptionalDate(payload.period.end_date),
|
|
97
|
+
},
|
|
98
|
+
statementDate: toOptionalDate(payload.statement_date),
|
|
99
|
+
dataSource: toReconciliationReportDataSource(payload.data_source),
|
|
100
|
+
currency,
|
|
101
|
+
status: {
|
|
102
|
+
code: toReconciliationStatusCodeType(payload.status.code),
|
|
103
|
+
label: payload.status.label,
|
|
104
|
+
},
|
|
105
|
+
reconciledAt: toOptionalDate(payload.reconciled_at),
|
|
106
|
+
reconciledBy: {
|
|
107
|
+
userId: payload.reconciled_by.user_id ?? undefined,
|
|
108
|
+
name: payload.reconciled_by.name ?? undefined,
|
|
109
|
+
},
|
|
110
|
+
disclaimer: payload.disclaimer,
|
|
111
|
+
reportReference: payload.report_reference ?? undefined,
|
|
112
|
+
locked: payload.locked,
|
|
113
|
+
summary: {
|
|
114
|
+
openingBalance: toOptionalAmount(payload.summary.opening_balance, currency),
|
|
115
|
+
clearedPayments: mapCountAmount(payload.summary.cleared_payments, currency),
|
|
116
|
+
clearedDeposits: mapCountAmount(payload.summary.cleared_deposits, currency),
|
|
117
|
+
closingBalance: toOptionalAmount(payload.summary.closing_balance, currency),
|
|
118
|
+
unclearedAsOfStatementDate: {
|
|
119
|
+
payments: mapCountAmount(payload.summary.uncleared_as_of_statement_date.payments, currency),
|
|
120
|
+
deposits: mapCountAmount(payload.summary.uncleared_as_of_statement_date.deposits, currency),
|
|
121
|
+
},
|
|
122
|
+
ledgerClosingAsOfStatementDate: toOptionalAmount(payload.summary.ledger_closing_as_of_statement_date, currency),
|
|
123
|
+
clearedAfterStatementDate: payload.summary.cleared_after_statement_date != null
|
|
124
|
+
? mapCountAmount(payload.summary.cleared_after_statement_date, currency)
|
|
125
|
+
: undefined,
|
|
126
|
+
unclearedAfterStatementDate: payload.summary.uncleared_after_statement_date != null
|
|
127
|
+
? mapCountAmount(payload.summary.uncleared_after_statement_date, currency)
|
|
128
|
+
: undefined,
|
|
129
|
+
ledgerBalanceAsOfReconciledOn: toOptionalAmount(payload.summary.ledger_balance_as_of_reconciled_on, currency),
|
|
130
|
+
bridge: {
|
|
131
|
+
bankClosing: toOptionalAmount(payload.summary.bridge.bank_closing, currency),
|
|
132
|
+
unclearedDeposits: toAmountWC(payload.summary.bridge.uncleared_deposits, currency),
|
|
133
|
+
unclearedPayments: toAmountWC(payload.summary.bridge.uncleared_payments, currency),
|
|
134
|
+
computedLedgerClosing: toOptionalAmount(payload.summary.bridge.computed_ledger_closing, currency),
|
|
135
|
+
ledgerClosing: toOptionalAmount(payload.summary.bridge.ledger_closing, currency),
|
|
136
|
+
variance: toOptionalAmount(payload.summary.bridge.variance, currency),
|
|
137
|
+
},
|
|
138
|
+
variance: toOptionalAmount(payload.summary.variance, currency),
|
|
139
|
+
},
|
|
140
|
+
details: {
|
|
141
|
+
cleared: mapPaymentsDeposits(payload.details.cleared, currency),
|
|
142
|
+
carriedForward: mapPaymentsDeposits(payload.details.carried_forward, currency),
|
|
143
|
+
unclearedAsOfStatementDate: mapPaymentsDeposits(payload.details.uncleared_as_of_statement_date, currency),
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { stringToUnion } from '../../commonStateTypes/stringToUnion';
|
|
2
|
+
const RECONCILIATION_REPORT_MATCH_TYPE = ['automatic', 'manual'];
|
|
3
|
+
export const toReconciliationReportMatchType = (value) => {
|
|
4
|
+
if (value === 'auto') {
|
|
5
|
+
return 'automatic';
|
|
6
|
+
}
|
|
7
|
+
return stringToUnion(value, RECONCILIATION_REPORT_MATCH_TYPE);
|
|
8
|
+
};
|
|
9
|
+
const RECONCILIATION_REPORT_DATA_SOURCE = ['Statement', 'Plaid'];
|
|
10
|
+
export const toReconciliationReportDataSource = (value) => stringToUnion(value, RECONCILIATION_REPORT_DATA_SOURCE);
|
package/lib/esm/epic.js
CHANGED
|
@@ -442,6 +442,7 @@ import { fetchEntityRecommendationsForLineUpdateEpic, } from './view/recommendat
|
|
|
442
442
|
import { fetchRecommendationByEntityIdEpic, } from './view/recommendation/fetchRecommendationByEntityIdEpic';
|
|
443
443
|
import { fetchRecommendationByEntityNameEpic, } from './view/recommendation/fetchRecommendationByEntityNameEpic';
|
|
444
444
|
import { submitRecommendationFeedbackEpic, } from './view/recommendation/submitRecommendationFeedbackEpic';
|
|
445
|
+
import { fetchReconciliationReportEpic, } from './view/reconciliationReportView/epic/fetchReconciliationReportEpic';
|
|
445
446
|
import { fetchReferralsEpic, } from './view/referralView/epics/fetchReferralsEpic';
|
|
446
447
|
import { fetchRewardsPlanEpic, } from './view/referralView/epics/fetchRewardsPlanEpic';
|
|
447
448
|
import { resendReferralInviteEpic, } from './view/referralView/epics/resendReferralInviteEpic';
|
|
@@ -1171,6 +1172,7 @@ const ALL_EPICS = [
|
|
|
1171
1172
|
fetchRecommendationForAccountTypeEpic,
|
|
1172
1173
|
fetchRecommendationsAndUpdateMerchantRecommendationsEpic,
|
|
1173
1174
|
fetchRecommendedTransactionRowIndexEpic,
|
|
1175
|
+
fetchReconciliationReportEpic,
|
|
1174
1176
|
fetchReferralsEpic,
|
|
1175
1177
|
fetchRegisteredInterestsEpic,
|
|
1176
1178
|
fetchReimbursementCardEpic,
|
package/lib/esm/index.js
CHANGED
|
@@ -196,7 +196,7 @@ import { clearStatementDateConflict, confirmStatementMapping, deleteAccountState
|
|
|
196
196
|
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';
|
|
197
197
|
import { getExpenseAutomationFluxAnalysisView } from './view/expenseAutomationView/selectors/fluxAnalysisViewSelector';
|
|
198
198
|
import { getNewAccrualAccountsView as getJeNewAccrualAccountsView, getNewScheduleSearchTransactionsView as getJeNewScheduleSearchTransactionsView, getNewScheduleView as getJeNewScheduleView, } from './view/expenseAutomationView/selectors/jeNewScheduleViewSelector';
|
|
199
|
-
import { getExpenseAutomationReconciliationView, getLedgerAccountIdsWithStatementOverrideWarning, getLedgerAccountsForCombinedStatementMapping, getReparseStatementStatusByAccountId, getUnavailableLedgerAccountIds, isAccountReconReport, } from './view/expenseAutomationView/selectors/reconciliationViewSelector';
|
|
199
|
+
import { getAccountReconciliationRecordsBySelectedPeriod, getExpenseAutomationReconciliationView, getLedgerAccountIdsWithStatementOverrideWarning, getLedgerAccountsForCombinedStatementMapping, getReparseStatementStatusByAccountId, getUnavailableLedgerAccountIds, isAccountReconReport, } from './view/expenseAutomationView/selectors/reconciliationViewSelector';
|
|
200
200
|
import { getExpenseAutomationTransactionView, getLastTransferEntryReplacement, } from './view/expenseAutomationView/selectors/transactionCategorizationSelector';
|
|
201
201
|
import { applyTransactionFilters } from './view/expenseAutomationView/transactionFilterHelpers';
|
|
202
202
|
import { TRANSACTION_FILTER_CATEGORIES, } from './view/expenseAutomationView/transactionFilterTypes';
|
|
@@ -274,6 +274,8 @@ import { fetchProjectList } from './view/projectList/projectListReducer';
|
|
|
274
274
|
import { getProjectList, } from './view/projectList/projectListSelector';
|
|
275
275
|
import { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName, submitRecommendationFeedback, } from './view/recommendation/recommendationReducer';
|
|
276
276
|
import { getRecommendationFeedbackSubmitState } from './view/recommendation/recommendationSelector';
|
|
277
|
+
import { fetchReconciliationReport } from './view/reconciliationReportView/reconciliationReportViewReducer';
|
|
278
|
+
import { getReconciliationReport } from './view/reconciliationReportView/reconciliationReportViewSelector';
|
|
277
279
|
import { DEFAULT_REFERRER_AMOUNT, clearReferrals, fetchReferrals, fetchRewardsPlan, resendReferralInvite, saveReferralFormDataInLocalStore, sendReferralInvite, updateReferViewed, updateReferralListSortUiState, } from './view/referralView/referralReducer';
|
|
278
280
|
import { getInviteFormView, getReferralListView, getRewardsPlanCard, } from './view/referralView/referralSelector';
|
|
279
281
|
import { AmountStatusTypes, StatusTypes, toReferralListViewSortKeyType, } from './view/referralView/referralState';
|
|
@@ -495,7 +497,7 @@ export {
|
|
|
495
497
|
// Bulk Upload Types
|
|
496
498
|
BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, DEFAULT_COMPLETED_SUB_TAB, DEFAULT_TRANSACTION_GROUP, TRANSACTION_GROUPS, toTransactionGroup, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, ALL_ACTUAL_MATCHING_IGNORE_REASONS, actualMatchingTransactionLineKey, ALL_JE_PAGE_TABS, MATCH_ACCRUAL_SEARCH_LIMIT, MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, toExpenseAutomationJEScheduleSortKey, toExpenseAutomationActualMatchingSortKey, toExpenseAutomationActualMatchingStatusFilter, toActualMatchingIgnoreReasonType, toJEPageTab, toMatchAndReverseResultStatus, toUndoReversalResultStatus, toggleJECreatedGroupCollapsed, toggleJEFailedGroupCollapsed, toggleJEPendingGroupCollapsed, updateJEScheduleTypeFilter, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, toExpenseAutomationViewTypeStrict, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, updateTransactionGroup, fetchExpenseAutomationMissingReceipts,
|
|
497
499
|
// Bulk Upload Actions
|
|
498
|
-
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, deleteCombinedStatement, 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, };
|
|
500
|
+
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, getAccountReconciliationRecordsBySelectedPeriod, getExpenseAutomationReconciliationView, getLedgerAccountIdsWithStatementOverrideWarning, getLedgerAccountsForCombinedStatementMapping, getReparseStatementStatusByAccountId, getUnavailableLedgerAccountIds, fetchReconciliationView, uploadAccountStatementIntoDocumentAI, updateExpenseAutomationReconListScrollPosition, setConnectionInProgressForAccountReconciliation, getAccountReconByAccountIdAndSelectedPeriod, toReconciliationTabsType, isAccountReconReport, updateExpenseAutomationReconReviewTabLocalData, updateExpenseAutomationSelectedDrawerAccountId, updateStatementProcessingFailed, saveExpenseAutomationReconciliationReview, updateExpenseAutomationAccountReconciliationLocalData, toReconciliationAccountSource, deleteAccountStatement, deleteCombinedStatement, 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, };
|
|
499
501
|
export { computeNewScheduleJeDetails, createOneTimeAccrual, createOneTimeAccrualFailure, createOneTimeAccrualSuccess, fetchOneTimeAccrual, getJeNewAccrualAccountsView, ignoreOneTimeAccrual, promoteOneTimeAccrual, revertJeSchedule, revertOneTimeAccrual, getJeNewScheduleSearchTransactionsView, getJeNewScheduleView, };
|
|
500
502
|
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, };
|
|
501
503
|
export { TOP_EX_TIME_PERIODS };
|
|
@@ -578,6 +580,7 @@ export { getEntityAutoCompleteResults };
|
|
|
578
580
|
export { updateEntities };
|
|
579
581
|
export { getEntityByEntityIDs };
|
|
580
582
|
export { getAddressByAddressId };
|
|
583
|
+
export { fetchReconciliationReport, getReconciliationReport, };
|
|
581
584
|
export { ALL_ACCOUNTING_CONNECTION_CREATION_MODES, isCompanyEligibleForTreasury, isCardsProductEnabledOnCompany, filterChargeCardRolesWhenProductDisabled, };
|
|
582
585
|
export { getCompanyByCompanyId, getControllersForCompany, getCompanyInfoForAllCockpitCompaniesInState, getFirstControllerEmail, getFirstControllerId, getControllersName, };
|
|
583
586
|
export { getCompanyManagementView, getPlanListZeniSku, getAddonListZeniSku, };
|
package/lib/esm/reducer.js
CHANGED
|
@@ -38,10 +38,10 @@ import invoicingCoupon, { initialState as initialInvoicingCouponState, } from '.
|
|
|
38
38
|
import invoicingCreditNote, { initialState as initialInvoicingCreditNoteState, } from './entity/invoicing/creditNote/creditNoteReducer';
|
|
39
39
|
import invoicingDunningCase, { initialState as initialInvoicingDunningCaseState, } from './entity/invoicing/dunningCase/dunningCaseReducer';
|
|
40
40
|
import invoicingInvoice, { initialState as initialInvoicingInvoiceState, } from './entity/invoicing/invoice/invoiceReducer';
|
|
41
|
+
import invoicingCatalog, { initialState as initialInvoicingCatalogState, } from './entity/invoicing/invoicingCatalog/invoicingCatalogReducer';
|
|
41
42
|
import invoicingCustomer, { initialState as initialInvoicingCustomerState, } from './entity/invoicing/invoicingCustomer/invoicingCustomerReducer';
|
|
42
43
|
import invoicingSubscription, { initialState as initialInvoicingSubscriptionState, } from './entity/invoicing/invoicingSubscription/invoicingSubscriptionReducer';
|
|
43
44
|
import invoicingTransaction, { initialState as initialInvoicingTransactionState, } from './entity/invoicing/invoicingTransaction/invoicingTransactionReducer';
|
|
44
|
-
import invoicingCatalog, { initialState as initialInvoicingCatalogState, } from './entity/invoicing/invoicingCatalog/invoicingCatalogReducer';
|
|
45
45
|
import jeSchedules, { initialState as initialJESchedulesState, } from './entity/jeSchedules/jeSchedulesReducer';
|
|
46
46
|
import merchant, { initialState as initialMerchantState, } from './entity/merchant/merchantReducer';
|
|
47
47
|
import monthEndCloseChecks, { initialState as initialMonthEndCloseChecksState, } from './entity/monthEndCloseChecks/monthEndCloseChecksReducer';
|
|
@@ -52,6 +52,7 @@ import paymentAccount, { initialState as initialPaymentAccountState, } from './e
|
|
|
52
52
|
import paymentInstrument, { initialState as initialPaymentInstrumentState, } from './entity/paymentInstrument/paymentInstrumentReducer';
|
|
53
53
|
import accountingSummary, { initialState as initialAccountingSummaryState, } from './entity/portfolio/accountingSummary/accountingSummaryReducer';
|
|
54
54
|
import project, { initialState as initialProjectState, } from './entity/project/projectReducer';
|
|
55
|
+
import reconciliationReport, { initialState as initialReconciliationReportState, } from './entity/reconciliationReport/reconciliationReportReducer';
|
|
55
56
|
import reimbursement, { initialState as initialReimbursementState, } from './entity/reimbursement/reimbursementReducer';
|
|
56
57
|
import sectionAccountsView, { initialState as initialSectionAccountsViewState, } from './entity/sectionAccountsView/sectionAccountsViewReducer';
|
|
57
58
|
import sectionClassesViewV2, { initialState as initialSectionClassesViewStateV2, } from './entity/sectionClassesViewV2/sectionClassesViewReducer';
|
|
@@ -179,6 +180,7 @@ import profitAndLossClassesView, { initialState as initialProfitAndLossClassesVi
|
|
|
179
180
|
import profitAndLossProjectView, { initialState as initialProfitAndLossProjectViewState, } from './view/profitAndLossProjectView/profitAndLossProjectViewReducer';
|
|
180
181
|
import projectList, { initialState as initialProjectListState, } from './view/projectList/projectListReducer';
|
|
181
182
|
import recommendation, { initialState as initialEntityRecommendationState, } from './view/recommendation/recommendationReducer';
|
|
183
|
+
import reconciliationReportView, { initialState as initialReconciliationReportViewState, } from './view/reconciliationReportView/reconciliationReportViewReducer';
|
|
182
184
|
import referralView, { initialState as initialReferralViewState, } from './view/referralView/referralReducer';
|
|
183
185
|
import reimbursementCard, { initialState as initialReimbursementCardState, } from './view/reimbursementCard/reimbursementCardReducer';
|
|
184
186
|
import reportUIOptionsReducer, { initialState as initialReportUIOptionsState, } from './view/reportUIOptions/reportUIOptionsReducer';
|
|
@@ -325,6 +327,7 @@ const initialEntitiesState = {
|
|
|
325
327
|
onboardingCustomerState: initialOnboardingCustomerState,
|
|
326
328
|
paymentAccountState: initialPaymentAccountState,
|
|
327
329
|
paymentInstrumentState: initialPaymentInstrumentState,
|
|
330
|
+
reconciliationReportState: initialReconciliationReportState,
|
|
328
331
|
recurringBillState: initialRecurringBillState,
|
|
329
332
|
reimbursementConfigState: initialReimbursementConfigState,
|
|
330
333
|
reimbursementState: initialReimbursementState,
|
|
@@ -493,6 +496,7 @@ const initialViewsState = {
|
|
|
493
496
|
profitAndLossState: initialProfitAndLossState,
|
|
494
497
|
projectListState: initialProjectListState,
|
|
495
498
|
realTimeApprovalState: initialRealTimeApprovalState,
|
|
499
|
+
reconciliationReportViewState: initialReconciliationReportViewState,
|
|
496
500
|
referralViewState: initialReferralViewState,
|
|
497
501
|
reimbursementCardState: initialReimbursementCardState,
|
|
498
502
|
reimbursementConfigState: initialReimbursementConfigState,
|
|
@@ -611,6 +615,7 @@ const entityReducers = {
|
|
|
611
615
|
onboardingCustomerState: onboardingCustomer,
|
|
612
616
|
paymentAccountState: paymentAccount,
|
|
613
617
|
paymentInstrumentState: paymentInstrument,
|
|
618
|
+
reconciliationReportState: reconciliationReport,
|
|
614
619
|
recurringBillState: recurringBill,
|
|
615
620
|
reimbursementConfigState: reimbursementConfig,
|
|
616
621
|
reimbursementState: reimbursement,
|
|
@@ -779,6 +784,7 @@ const viewReducers = {
|
|
|
779
784
|
profitAndLossState: profitAndLoss,
|
|
780
785
|
projectListState: projectList,
|
|
781
786
|
realTimeApprovalState: realTimeApproval,
|
|
787
|
+
reconciliationReportViewState: reconciliationReportView,
|
|
782
788
|
referralViewState: referralView,
|
|
783
789
|
reimbursementCardState: reimbursementCard,
|
|
784
790
|
reimbursementConfigState: reimbursementConfig,
|
package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isCustomerTransaction, } from '../../../entity/transaction/stateTypes/customerTransaction';
|
|
1
2
|
import { isVendorTransaction } from '../../../entity/transaction/stateTypes/vendorTransaction';
|
|
2
3
|
import { isEntityMatching, mergeTransactionAndEntityRecommendationsWithCOT, toLineEntity, } from '../../transactionDetail/transactionDetailLocalDataHelper';
|
|
3
4
|
import { isAccountUncategorized } from '../../transactionDetail/transactionDetailLocalDataHelper';
|
|
@@ -208,7 +209,10 @@ const buildLineItemById = (transaction, recommendations) => {
|
|
|
208
209
|
logo: accountLine.vendor.logo,
|
|
209
210
|
}
|
|
210
211
|
: undefined;
|
|
211
|
-
const customer = accountLine.customer
|
|
212
|
+
const customer = accountLine.customer ??
|
|
213
|
+
(isCustomerTransaction(transaction) === true
|
|
214
|
+
? transaction.customer
|
|
215
|
+
: undefined);
|
|
212
216
|
record.customer =
|
|
213
217
|
customer != null && Boolean(customer.id) && Boolean(customer.name)
|
|
214
218
|
? {
|
|
@@ -4,7 +4,7 @@ import keys from 'lodash/keys';
|
|
|
4
4
|
import omit from 'lodash/omit';
|
|
5
5
|
import orderBy from 'lodash/orderBy';
|
|
6
6
|
import { reduceAnyFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
7
|
-
import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
7
|
+
import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
|
|
8
8
|
import { getAccountsByType } from '../../../entity/account/accountSelector';
|
|
9
9
|
import { getAccountReconByAccountIdAndSelectedPeriod } from '../../../entity/accountRecon/accountReconSelector';
|
|
10
10
|
import { getCurrentTenant } from '../../../entity/tenant/tenantSelector';
|
|
@@ -473,6 +473,10 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
473
473
|
summary: summaryWithTimeSaved,
|
|
474
474
|
};
|
|
475
475
|
});
|
|
476
|
+
export function getAccountReconciliationRecordsBySelectedPeriod(state) {
|
|
477
|
+
return state.expenseAutomationReconciliationViewState
|
|
478
|
+
.accountReconciliationRecordsBySelectedPeriod;
|
|
479
|
+
}
|
|
476
480
|
export const getReparseStatementStatusByAccountId = (state, accountId) => getExpenseAutomationReconciliationView(state)
|
|
477
481
|
.accountReconciliationsByAccountID[accountId]?.reparseStatementStatus;
|
|
478
482
|
export function getLedgerAccountsForCombinedStatementMapping(accountReconciliationsByAccountID, selectedAccountId) {
|
|
@@ -2,7 +2,7 @@ import { from } from 'rxjs';
|
|
|
2
2
|
import { filter, mergeMap } from 'rxjs/operators';
|
|
3
3
|
import { fetchInvoicingCatalogPlanList, fetchInvoicingCatalogProductList, } from '../../invoicingCatalogListView/invoicingCatalogListViewReducer';
|
|
4
4
|
import { fetchInvoicingCustomerList } from '../../invoicingCustomerListView/invoicingCustomerListViewReducer';
|
|
5
|
-
import { INVOICING_LIST_ALL_TAB, getInvoicingListTab, } from '../../invoicingListTabCache';
|
|
5
|
+
import { INVOICING_LIST_ALL_TAB, getInvoicingListTab, shouldFetchFullInvoicingList, } from '../../invoicingListTabCache';
|
|
6
6
|
import { fetchInvoicingSettings } from '../../settingsView/settingsViewReducer';
|
|
7
7
|
import { fetchCreateInvoiceFormPage } from '../createInvoiceReducer';
|
|
8
8
|
/**
|
|
@@ -13,6 +13,8 @@ import { fetchCreateInvoiceFormPage } from '../createInvoiceReducer';
|
|
|
13
13
|
const shouldFetch = (fetchStateAndError, cacheOverride) => cacheOverride ||
|
|
14
14
|
(fetchStateAndError.fetchState !== 'Completed' &&
|
|
15
15
|
fetchStateAndError.fetchState !== 'In-Progress');
|
|
16
|
+
const PICKER_PLAN_FILTERS = { type: 'plan' };
|
|
17
|
+
const PICKER_PRODUCT_FILTERS = { type: 'addon|charge' };
|
|
16
18
|
/**
|
|
17
19
|
* Orchestrates the create-invoice form's option sources: on
|
|
18
20
|
* `fetchCreateInvoiceFormPage`, fans out to the customer, catalog plan, catalog
|
|
@@ -34,15 +36,27 @@ export const fetchCreateInvoiceFormPageEpic = (actions$, state$) => actions$.pip
|
|
|
34
36
|
tabId: INVOICING_LIST_ALL_TAB,
|
|
35
37
|
}));
|
|
36
38
|
}
|
|
37
|
-
if (
|
|
39
|
+
if (shouldFetchFullInvoicingList({
|
|
40
|
+
fetchState: catalogState.fetchState,
|
|
41
|
+
filters: catalogState.planFilters,
|
|
42
|
+
nextCursor: catalogState.planNextCursor,
|
|
43
|
+
sort: catalogState.planSort,
|
|
44
|
+
}, PICKER_PLAN_FILTERS, cacheOverride)) {
|
|
38
45
|
pageActions.push(fetchInvoicingCatalogPlanList({
|
|
39
|
-
|
|
46
|
+
fetchAll: true,
|
|
47
|
+
filters: PICKER_PLAN_FILTERS,
|
|
40
48
|
keepExistingListItems: false,
|
|
41
49
|
}));
|
|
42
50
|
}
|
|
43
|
-
if (
|
|
51
|
+
if (shouldFetchFullInvoicingList({
|
|
52
|
+
fetchState: catalogState.productFetchState.fetchState,
|
|
53
|
+
filters: catalogState.productFilters,
|
|
54
|
+
nextCursor: catalogState.productNextCursor,
|
|
55
|
+
sort: catalogState.productSort,
|
|
56
|
+
}, PICKER_PRODUCT_FILTERS, cacheOverride)) {
|
|
44
57
|
pageActions.push(fetchInvoicingCatalogProductList({
|
|
45
|
-
|
|
58
|
+
fetchAll: true,
|
|
59
|
+
filters: PICKER_PRODUCT_FILTERS,
|
|
46
60
|
keepExistingListItems: false,
|
|
47
61
|
}));
|
|
48
62
|
}
|
|
@@ -17,22 +17,25 @@ import { invoicingSubscriptionTodayIso, toInvoicingSubscriptionBillingCycles, to
|
|
|
17
17
|
* Sending them made every price point whose cadence the form could not express
|
|
18
18
|
* — a daily plan, for instance — fail with a 422.
|
|
19
19
|
*/
|
|
20
|
-
export const localDataToSaveInvoicingSubscriptionPayload = (localData, shippingAddress) => {
|
|
20
|
+
export const localDataToSaveInvoicingSubscriptionPayload = (localData, shippingAddress, flatFeePriceCodes = new Set()) => {
|
|
21
|
+
const itemQuantity = (priceCode, quantity) => flatFeePriceCodes.has(priceCode)
|
|
22
|
+
? 1
|
|
23
|
+
: toInvoicingSubscriptionQuantity(quantity);
|
|
21
24
|
const items = [
|
|
22
25
|
{
|
|
23
26
|
item_price_code: localData.planPriceCode,
|
|
24
27
|
item_type: 'plan',
|
|
25
|
-
quantity:
|
|
28
|
+
quantity: itemQuantity(localData.planPriceCode, localData.planQuantity),
|
|
26
29
|
},
|
|
27
30
|
...localData.addonPriceCodes.map((priceCode) => ({
|
|
28
31
|
item_price_code: priceCode,
|
|
29
32
|
item_type: 'addon',
|
|
30
|
-
quantity:
|
|
33
|
+
quantity: itemQuantity(priceCode, localData.addonQuantities[priceCode]),
|
|
31
34
|
})),
|
|
32
35
|
...localData.chargePriceCodes.map((priceCode) => ({
|
|
33
36
|
item_price_code: priceCode,
|
|
34
37
|
item_type: 'charge',
|
|
35
|
-
quantity:
|
|
38
|
+
quantity: itemQuantity(priceCode, localData.chargeQuantities[priceCode]),
|
|
36
39
|
})),
|
|
37
40
|
];
|
|
38
41
|
const setupFee = localData.setupFee?.amount;
|
|
@@ -59,11 +62,59 @@ export const localDataToSaveInvoicingSubscriptionPayload = (localData, shippingA
|
|
|
59
62
|
};
|
|
60
63
|
};
|
|
61
64
|
const toEstimateDate = (value) => value != null && value !== '' ? date(value) : undefined;
|
|
65
|
+
const isItemLevelCoupon = (discount) => discount.entity_type === 'item_level_coupon';
|
|
66
|
+
const isCoupon = (discount) => discount.entity_type === 'document_level_coupon' ||
|
|
67
|
+
discount.entity_type === 'item_level_coupon';
|
|
68
|
+
/**
|
|
69
|
+
* Name the coupon behind a line's discount. Exact when the API links a coupon
|
|
70
|
+
* row to its line (`line_item_id`); otherwise only when a single item-level
|
|
71
|
+
* coupon applies, since then every discounted line got that one.
|
|
72
|
+
*/
|
|
73
|
+
const lineDiscountLabel = (lineItem, discounts) => {
|
|
74
|
+
if (lineItem.discount_amount <= 0) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
const itemCoupons = discounts.filter(isItemLevelCoupon);
|
|
78
|
+
const linked = lineItem.id != null
|
|
79
|
+
? itemCoupons.filter((coupon) => coupon.line_item_id === lineItem.id)
|
|
80
|
+
: [];
|
|
81
|
+
if (linked.length > 0) {
|
|
82
|
+
return [...new Set(linked.map((coupon) => coupon.description))].join(', ');
|
|
83
|
+
}
|
|
84
|
+
const names = [...new Set(itemCoupons.map((coupon) => coupon.description))];
|
|
85
|
+
return names.length === 1 ? names[0] : undefined;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* One row per coupon. An item-level coupon comes back once per line it
|
|
89
|
+
* discounted, so its rows are summed; listing each would read as the same
|
|
90
|
+
* discount taken several times.
|
|
91
|
+
*/
|
|
92
|
+
const mergeCouponRows = (discounts) => {
|
|
93
|
+
const rowsByCoupon = new Map();
|
|
94
|
+
discounts.filter(isCoupon).forEach((coupon) => {
|
|
95
|
+
// The API sends `entity_id: ""` when it has none; key those by name so
|
|
96
|
+
// two unrelated coupons are not merged into one row.
|
|
97
|
+
const couponKey = coupon.entity_id != null && coupon.entity_id !== ''
|
|
98
|
+
? coupon.entity_id
|
|
99
|
+
: coupon.description;
|
|
100
|
+
const key = `${coupon.entity_type}:${couponKey}`;
|
|
101
|
+
const row = rowsByCoupon.get(key);
|
|
102
|
+
rowsByCoupon.set(key, {
|
|
103
|
+
amount: Math.round(((row?.amount ?? 0) + coupon.amount) * 100) / 100,
|
|
104
|
+
description: coupon.description,
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
return [...rowsByCoupon.values()];
|
|
108
|
+
};
|
|
62
109
|
const mapInvoiceEstimate = (payload, money) => payload == null
|
|
63
110
|
? undefined
|
|
64
111
|
: {
|
|
65
112
|
amountDue: money(payload.amount_due),
|
|
66
113
|
couponDiscountTotal: money(payload.coupon_discount_total),
|
|
114
|
+
coupons: mergeCouponRows(payload.discounts ?? []).map((coupon) => ({
|
|
115
|
+
amount: money(coupon.amount),
|
|
116
|
+
description: coupon.description,
|
|
117
|
+
})),
|
|
67
118
|
creditsApplied: money(payload.credits_applied),
|
|
68
119
|
dueDate: toEstimateDate(payload.due_date),
|
|
69
120
|
grossSubTotal: money(payload.gross_sub_total),
|
|
@@ -74,6 +125,8 @@ const mapInvoiceEstimate = (payload, money) => payload == null
|
|
|
74
125
|
dateTo: toEstimateDate(lineItem.date_to),
|
|
75
126
|
description: lineItem.description,
|
|
76
127
|
discountAmount: money(lineItem.discount_amount),
|
|
128
|
+
discountLabel: lineDiscountLabel(lineItem, payload.discounts ?? []),
|
|
129
|
+
grossAmount: money(lineItem.gross_amount ?? lineItem.amount),
|
|
77
130
|
quantity: lineItem.quantity,
|
|
78
131
|
taxAmount: lineItem.tax_amount != null
|
|
79
132
|
? money(lineItem.tax_amount)
|
|
@@ -7,7 +7,7 @@ import { getInvoicingCatalogListView, getInvoicingCatalogPrices, } from '../invo
|
|
|
7
7
|
import { getInvoicingConfigView, invoicingFieldHelpForGroup, } from '../invoicingConfigView/invoicingConfigViewSelector';
|
|
8
8
|
import { getInvoicingAllCustomers } from '../invoicingCustomerListView/invoicingCustomerListViewSelector';
|
|
9
9
|
import { getInvoicingFormDraftLocalData, isInvoicingFormDraftPending, } from '../invoicingFormDraft';
|
|
10
|
-
import { initialInvoicingSubscriptionFormLocalData } from './invoicingSubscriptionFormConfig';
|
|
10
|
+
import { initialInvoicingSubscriptionFormLocalData, invoicingPriceHasQuantity, } from './invoicingSubscriptionFormConfig';
|
|
11
11
|
import { INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE } from './invoicingSubscriptionFormConfig';
|
|
12
12
|
const notStartedEstimateView = {
|
|
13
13
|
creditsMayChange: false,
|
|
@@ -175,6 +175,7 @@ const toInvoicingPlanOption = (plan) => ({
|
|
|
175
175
|
// price point and rejects a subscription that claims a different one.
|
|
176
176
|
billingPeriod: plan.period,
|
|
177
177
|
billingPeriodUnit: plan.periodUnit,
|
|
178
|
+
hasQuantity: invoicingPriceHasQuantity(plan.pricingModel),
|
|
178
179
|
label: plan.name ?? plan.id,
|
|
179
180
|
price: invoicingUnitPrice(plan),
|
|
180
181
|
productCode: plan.productCode,
|
|
@@ -186,6 +187,7 @@ const toInvoicingCatalogItemOption = (product) => ({
|
|
|
186
187
|
// A one-time charge has no cadence, so its price is quoted flat rather than
|
|
187
188
|
// per period.
|
|
188
189
|
billingPeriodUnit: product.itemType === 'charge' ? undefined : product.periodUnit,
|
|
190
|
+
hasQuantity: invoicingPriceHasQuantity(product.pricingModel),
|
|
189
191
|
label: product.name ?? product.id,
|
|
190
192
|
price: invoicingUnitPrice(product),
|
|
191
193
|
productCode: product.productCode,
|
|
@@ -4,7 +4,7 @@ import { fetchInvoicingCouponList } from '../couponView/couponViewReducer';
|
|
|
4
4
|
import { getInvoicingCouponListFetchState } from '../couponView/couponViewSelector';
|
|
5
5
|
import { fetchInvoicingCatalogPlanList } from '../invoicingCatalogListView/invoicingCatalogListViewReducer';
|
|
6
6
|
import { fetchInvoicingConfig } from '../invoicingConfigView/invoicingConfigViewReducer';
|
|
7
|
-
import { INVOICING_LIST_ALL_TAB } from '../invoicingListTabCache';
|
|
7
|
+
import { INVOICING_LIST_ALL_TAB, shouldFetchFullInvoicingList, } from '../invoicingListTabCache';
|
|
8
8
|
import { fetchInvoicingSubscriptionDetail, fetchInvoicingSubscriptionDetailPage, } from './editInvoicingSubscriptionDetailViewReducer';
|
|
9
9
|
/**
|
|
10
10
|
* Fetch unless the endpoint is already loaded or in flight — or always when the
|
|
@@ -40,11 +40,14 @@ export const fetchInvoicingSubscriptionDetailPageEpic = (actions$, state$) => ac
|
|
|
40
40
|
// Plan and coupon lists back the names the page renders for its line
|
|
41
41
|
// items; both list slices cache, so this only refetches when asked to.
|
|
42
42
|
const catalogListState = state.invoicingCatalogListViewState;
|
|
43
|
-
if (
|
|
44
|
-
error: catalogListState.error,
|
|
43
|
+
if (shouldFetchFullInvoicingList({
|
|
45
44
|
fetchState: catalogListState.fetchState,
|
|
46
|
-
|
|
45
|
+
filters: catalogListState.planFilters,
|
|
46
|
+
nextCursor: catalogListState.planNextCursor,
|
|
47
|
+
sort: catalogListState.planSort,
|
|
48
|
+
}, { type: 'plan' }, cacheOverride)) {
|
|
47
49
|
pageActions.push(fetchInvoicingCatalogPlanList({
|
|
50
|
+
fetchAll: true,
|
|
48
51
|
filters: { type: 'plan' },
|
|
49
52
|
keepExistingListItems: false,
|
|
50
53
|
}));
|
|
@@ -20,6 +20,7 @@ export const fetchInvoicingSubscriptionFormPageEpic = (actions$) => actions$.pip
|
|
|
20
20
|
// unfiltered list would replace the store's plans with every catalog
|
|
21
21
|
// item.
|
|
22
22
|
fetchInvoicingCatalogPlanList({
|
|
23
|
+
fetchAll: true,
|
|
23
24
|
filters: { type: 'plan' },
|
|
24
25
|
keepExistingListItems: false,
|
|
25
26
|
}),
|
|
@@ -22,6 +22,8 @@ const subscriptionItemQuantities = (subscription, itemType) => {
|
|
|
22
22
|
* their day gets their own calendar date rather than yesterday's.
|
|
23
23
|
*/
|
|
24
24
|
export const invoicingSubscriptionTodayIso = () => dateNow().format('YYYY-MM-DD');
|
|
25
|
+
/** A flat fee bills its price once, so its quantity is always 1. */
|
|
26
|
+
export const invoicingPriceHasQuantity = (pricingModel) => pricingModel !== 'flat_fee';
|
|
25
27
|
/**
|
|
26
28
|
* Clamp a subscription-item quantity to the minimum the API accepts. Shared by
|
|
27
29
|
* the plan, add-on and charge items so none of them can bill a 0 or a fraction.
|
package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js
CHANGED
|
@@ -9,10 +9,11 @@ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload
|
|
|
9
9
|
import { resetNewAddressDataInLocalStore } from '../../addressView/addressViewReducer';
|
|
10
10
|
import { invalidateInvoicingCustomerDetail } from '../editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer';
|
|
11
11
|
import { invalidateInvoiceListForCustomer } from '../invoiceList/invoiceListReducer';
|
|
12
|
+
import { getInvoicingCatalogPrices } from '../invoicingCatalogListView/invoicingCatalogListViewSelector';
|
|
12
13
|
import { addInvoicingSubscriptionToList } from '../invoicingSubscriptionListView/invoicingSubscriptionListViewReducer';
|
|
13
14
|
import { localDataToSaveInvoicingSubscriptionPayload, } from './editInvoicingSubscriptionDetailViewPayload';
|
|
14
15
|
import { submitInvoicingSubscriptionForm, submitInvoicingSubscriptionFormFailure, submitInvoicingSubscriptionFormSuccess, syncInvoicingSubscriptionCoupons, } from './editInvoicingSubscriptionDetailViewReducer';
|
|
15
|
-
import { INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE } from './invoicingSubscriptionFormConfig';
|
|
16
|
+
import { INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE, invoicingPriceHasQuantity, } from './invoicingSubscriptionFormConfig';
|
|
16
17
|
const normalizeCouponCode = (value) => (value ?? '').trim().toUpperCase();
|
|
17
18
|
export const isInvoicingSubscriptionCouponChanged = (previousCouponCode, nextCouponCode) => normalizeCouponCode(previousCouponCode) !==
|
|
18
19
|
normalizeCouponCode(nextCouponCode);
|
|
@@ -25,7 +26,10 @@ export const invoicingSubscriptionSaveRequest = (rootState, id) => {
|
|
|
25
26
|
// Shipping address captured via the shared Address screen is sent as an
|
|
26
27
|
// object in the payload (same pattern as the customer save flow).
|
|
27
28
|
const shippingAddress = rootState.addressViewState.newAddressState?.[INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE]?.addressToCreate;
|
|
28
|
-
const
|
|
29
|
+
const flatFeePriceCodes = new Set(getInvoicingCatalogPrices(Object.values(rootState.invoicingCatalogState.itemByID))
|
|
30
|
+
.filter((price) => !invoicingPriceHasQuantity(price.pricingModel))
|
|
31
|
+
.flatMap((price) => price.priceCode ?? []));
|
|
32
|
+
const data = localDataToSaveInvoicingSubscriptionPayload(localData, shippingAddress, flatFeePriceCodes);
|
|
29
33
|
if (id != null) {
|
|
30
34
|
delete data.coupon_ids;
|
|
31
35
|
}
|
package/lib/esm/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogPlanListEpic.js
CHANGED
|
@@ -23,19 +23,30 @@ const buildPlanQuery = (filters, cursor, sort) => {
|
|
|
23
23
|
return params;
|
|
24
24
|
};
|
|
25
25
|
export const fetchInvoicingCatalogPlanListEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchInvoicingCatalogPlanList.match), switchMap((action) => {
|
|
26
|
-
const { filters, cursor, keepExistingListItems, sort } = action.payload;
|
|
26
|
+
const { filters, cursor, fetchAll, keepExistingListItems, sort } = action.payload;
|
|
27
27
|
const apiUrl = withQuery(`${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/catalog/plans`, buildPlanQuery(filters, cursor, sort));
|
|
28
28
|
return zeniAPI.getJSON(apiUrl).pipe(switchMap((response) => {
|
|
29
29
|
if (isSuccessResponse(response)) {
|
|
30
30
|
const items = response.data?.items ?? [];
|
|
31
|
-
|
|
31
|
+
const nextCursor = response.data?.next_cursor ?? null;
|
|
32
|
+
const pageActions = [
|
|
32
33
|
updateInvoicingCatalogItems(items, 'merge'),
|
|
33
34
|
updateInvoicingCatalogPlanList({
|
|
34
35
|
ids: items.map((item) => item.id),
|
|
35
|
-
nextCursor
|
|
36
|
+
nextCursor,
|
|
36
37
|
keepExistingListItems,
|
|
37
38
|
}),
|
|
38
39
|
];
|
|
40
|
+
if (fetchAll && nextCursor != null && nextCursor !== cursor) {
|
|
41
|
+
pageActions.push(fetchInvoicingCatalogPlanList({
|
|
42
|
+
cursor: nextCursor,
|
|
43
|
+
fetchAll,
|
|
44
|
+
filters,
|
|
45
|
+
keepExistingListItems: true,
|
|
46
|
+
sort,
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
return pageActions;
|
|
39
50
|
}
|
|
40
51
|
return of(updateInvoicingCatalogPlanListFailure(response.status));
|
|
41
52
|
}), catchError((error) => of(updateInvoicingCatalogPlanListFailure(createZeniAPIStatus('Unexpected Error', 'Fetch catalog plan list REST API call errored out ' +
|