@zeniai/client-epic-state 5.2.86 → 5.2.88
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/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/esm/view/settingsView/epic/saveNotificationSettingsEpic.js +7 -0
- package/lib/esm/view/settingsView/settingsViewHelpers.js +1 -0
- package/lib/esm/view/settingsView/settingsViewReducer.js +16 -1
- package/lib/esm/view/settingsView/settingsViewState.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/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/lib/view/settingsView/epic/saveNotificationSettingsEpic.js +7 -0
- package/lib/view/settingsView/settingsViewHelpers.js +1 -0
- package/lib/view/settingsView/settingsViewPayload.d.ts +2 -0
- package/lib/view/settingsView/settingsViewReducer.js +16 -1
- package/lib/view/settingsView/settingsViewState.d.ts +2 -2
- package/lib/view/settingsView/settingsViewState.js +1 -0
- package/package.json +1 -1
package/lib/rootStateTypes.d.ts
CHANGED
|
@@ -37,10 +37,10 @@ import { InvoicingCouponState } from './entity/invoicing/coupon/couponState';
|
|
|
37
37
|
import { InvoicingCreditNoteState } from './entity/invoicing/creditNote/creditNoteState';
|
|
38
38
|
import { InvoicingDunningCaseState } from './entity/invoicing/dunningCase/dunningCaseState';
|
|
39
39
|
import { InvoiceState as InvoicingInvoiceState } from './entity/invoicing/invoice/invoiceState';
|
|
40
|
+
import { InvoicingCatalogState } from './entity/invoicing/invoicingCatalog/invoicingCatalogState';
|
|
40
41
|
import { InvoicingCustomerState } from './entity/invoicing/invoicingCustomer/invoicingCustomerState';
|
|
41
42
|
import { InvoicingSubscriptionState } from './entity/invoicing/invoicingSubscription/invoicingSubscriptionState';
|
|
42
43
|
import { InvoicingTransactionState } from './entity/invoicing/invoicingTransaction/invoicingTransactionState';
|
|
43
|
-
import { InvoicingCatalogState } from './entity/invoicing/invoicingCatalog/invoicingCatalogState';
|
|
44
44
|
import { JESchedulesState } from './entity/jeSchedules/jeSchedulesState';
|
|
45
45
|
import { MerchantState } from './entity/merchant/merchant';
|
|
46
46
|
import { MonthEndCloseChecksState } from './entity/monthEndCloseChecks/monthEndCloseChecksState';
|
|
@@ -51,6 +51,7 @@ import { PaymentAccountState } from './entity/paymentAccount/paymentAccountState
|
|
|
51
51
|
import { PaymentInstrumentState } from './entity/paymentInstrument/paymentInstrument';
|
|
52
52
|
import { AccountingSummaryState } from './entity/portfolio/accountingSummary/accountingSummaryState';
|
|
53
53
|
import { ProjectState } from './entity/project/projectState';
|
|
54
|
+
import { ReconciliationReportState } from './entity/reconciliationReport/reconciliationReportState';
|
|
54
55
|
import { ReimbursementState } from './entity/reimbursement/reimbursementState';
|
|
55
56
|
import { SectionAccountsViewState } from './entity/sectionAccountsView/sectionAccountsViewState';
|
|
56
57
|
import { SectionClassesViewStateV2 } from './entity/sectionClassesViewV2/sectionClassesViewState';
|
|
@@ -176,6 +177,7 @@ import { ProfitAndLossClassesViewState } from './view/profitAndLossClassesView/p
|
|
|
176
177
|
import { ProfitAndLossProjectViewState } from './view/profitAndLossProjectView/profitAndLossProjectViewState';
|
|
177
178
|
import { ProjectListState } from './view/projectList/projectListState';
|
|
178
179
|
import { EntityRecommendationState } from './view/recommendation/recommendationState';
|
|
180
|
+
import { ReconciliationReportViewState } from './view/reconciliationReportView/reconciliationReportViewState';
|
|
179
181
|
import { ReferralViewState } from './view/referralView/referralState';
|
|
180
182
|
import { ReimbursementCardState } from './view/reimbursementCard/reimbursementCardState';
|
|
181
183
|
import { ReportUIOptionsState } from './view/reportUIOptions/reportUIOptionsState';
|
|
@@ -321,6 +323,7 @@ export type EntitiesState = {
|
|
|
321
323
|
paymentAccountState: PaymentAccountState;
|
|
322
324
|
paymentInstrumentState: PaymentInstrumentState;
|
|
323
325
|
projectState: ProjectState;
|
|
326
|
+
reconciliationReportState: ReconciliationReportState;
|
|
324
327
|
recurringBillState: RecurringBillState;
|
|
325
328
|
reimbursementConfigState: ReimbursementConfigState;
|
|
326
329
|
reimbursementState: ReimbursementState;
|
|
@@ -489,6 +492,7 @@ export type ViewsState = {
|
|
|
489
492
|
profitAndLossState: ProfitAndLossWithForecastState;
|
|
490
493
|
projectListState: ProjectListState;
|
|
491
494
|
realTimeApprovalState: RealTimeApprovalState;
|
|
495
|
+
reconciliationReportViewState: ReconciliationReportViewState;
|
|
492
496
|
referralViewState: ReferralViewState;
|
|
493
497
|
reimbursementCardState: ReimbursementCardState;
|
|
494
498
|
reimbursementConfigState: ReimbursementConfigState;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { ID } from '../../../commonStateTypes/common';
|
|
2
|
+
import { MonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
2
3
|
import { ReportIDPlusForecastID } from '../../../commonStateTypes/viewAndReport/viewAndReport';
|
|
3
4
|
import { AccountBase } from '../../../entity/account/accountState';
|
|
4
5
|
import { RootState } from '../../../rootStateTypes';
|
|
5
6
|
import { AccountReconciliationByAccount, ExpenseAutomationReconciliationViewSelector } from '../selectorTypes/reconciliationViewSelectorTypes';
|
|
7
|
+
import { AccountReconciliationRecords } from '../types/reconciliationViewState';
|
|
6
8
|
export declare const getExpenseAutomationReconciliationView: (state: RootState) => ExpenseAutomationReconciliationViewSelector;
|
|
9
|
+
export declare function getAccountReconciliationRecordsBySelectedPeriod(state: RootState): Record<MonthYearPeriodId, AccountReconciliationRecords>;
|
|
7
10
|
export declare const getReparseStatementStatusByAccountId: (state: RootState, accountId: ID) => import("../../../commonStateTypes/common").FetchStateAndError;
|
|
8
11
|
export declare function getLedgerAccountsForCombinedStatementMapping(accountReconciliationsByAccountID: Record<ID, AccountReconciliationByAccount>, selectedAccountId: ID): AccountBase[];
|
|
9
12
|
export declare function getUnavailableLedgerAccountIds(accountReconciliationsByAccountID: Record<ID, AccountReconciliationByAccount>): ID[];
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.isAccountReconReport = exports.getReparseStatementStatusByAccountId = exports.getExpenseAutomationReconciliationView = void 0;
|
|
7
|
+
exports.getAccountReconciliationRecordsBySelectedPeriod = getAccountReconciliationRecordsBySelectedPeriod;
|
|
7
8
|
exports.getLedgerAccountsForCombinedStatementMapping = getLedgerAccountsForCombinedStatementMapping;
|
|
8
9
|
exports.getUnavailableLedgerAccountIds = getUnavailableLedgerAccountIds;
|
|
9
10
|
exports.getLedgerAccountIdsWithStatementOverrideWarning = getLedgerAccountIdsWithStatementOverrideWarning;
|
|
@@ -482,6 +483,10 @@ exports.getExpenseAutomationReconciliationView = (0, toolkit_1.createSelector)((
|
|
|
482
483
|
summary: summaryWithTimeSaved,
|
|
483
484
|
};
|
|
484
485
|
});
|
|
486
|
+
function getAccountReconciliationRecordsBySelectedPeriod(state) {
|
|
487
|
+
return state.expenseAutomationReconciliationViewState
|
|
488
|
+
.accountReconciliationRecordsBySelectedPeriod;
|
|
489
|
+
}
|
|
485
490
|
const getReparseStatementStatusByAccountId = (state, accountId) => (0, exports.getExpenseAutomationReconciliationView)(state)
|
|
486
491
|
.accountReconciliationsByAccountID[accountId]?.reparseStatementStatus;
|
|
487
492
|
exports.getReparseStatementStatusByAccountId = getReparseStatementStatusByAccountId;
|
|
@@ -16,6 +16,8 @@ const createInvoiceReducer_1 = require("../createInvoiceReducer");
|
|
|
16
16
|
const shouldFetch = (fetchStateAndError, cacheOverride) => cacheOverride ||
|
|
17
17
|
(fetchStateAndError.fetchState !== 'Completed' &&
|
|
18
18
|
fetchStateAndError.fetchState !== 'In-Progress');
|
|
19
|
+
const PICKER_PLAN_FILTERS = { type: 'plan' };
|
|
20
|
+
const PICKER_PRODUCT_FILTERS = { type: 'addon|charge' };
|
|
19
21
|
/**
|
|
20
22
|
* Orchestrates the create-invoice form's option sources: on
|
|
21
23
|
* `fetchCreateInvoiceFormPage`, fans out to the customer, catalog plan, catalog
|
|
@@ -37,15 +39,27 @@ const fetchCreateInvoiceFormPageEpic = (actions$, state$) => actions$.pipe((0, o
|
|
|
37
39
|
tabId: invoicingListTabCache_1.INVOICING_LIST_ALL_TAB,
|
|
38
40
|
}));
|
|
39
41
|
}
|
|
40
|
-
if (
|
|
42
|
+
if ((0, invoicingListTabCache_1.shouldFetchFullInvoicingList)({
|
|
43
|
+
fetchState: catalogState.fetchState,
|
|
44
|
+
filters: catalogState.planFilters,
|
|
45
|
+
nextCursor: catalogState.planNextCursor,
|
|
46
|
+
sort: catalogState.planSort,
|
|
47
|
+
}, PICKER_PLAN_FILTERS, cacheOverride)) {
|
|
41
48
|
pageActions.push((0, invoicingCatalogListViewReducer_1.fetchInvoicingCatalogPlanList)({
|
|
42
|
-
|
|
49
|
+
fetchAll: true,
|
|
50
|
+
filters: PICKER_PLAN_FILTERS,
|
|
43
51
|
keepExistingListItems: false,
|
|
44
52
|
}));
|
|
45
53
|
}
|
|
46
|
-
if (
|
|
54
|
+
if ((0, invoicingListTabCache_1.shouldFetchFullInvoicingList)({
|
|
55
|
+
fetchState: catalogState.productFetchState.fetchState,
|
|
56
|
+
filters: catalogState.productFilters,
|
|
57
|
+
nextCursor: catalogState.productNextCursor,
|
|
58
|
+
sort: catalogState.productSort,
|
|
59
|
+
}, PICKER_PRODUCT_FILTERS, cacheOverride)) {
|
|
47
60
|
pageActions.push((0, invoicingCatalogListViewReducer_1.fetchInvoicingCatalogProductList)({
|
|
48
|
-
|
|
61
|
+
fetchAll: true,
|
|
62
|
+
filters: PICKER_PRODUCT_FILTERS,
|
|
49
63
|
keepExistingListItems: false,
|
|
50
64
|
}));
|
|
51
65
|
}
|
|
@@ -18,7 +18,7 @@ export type SaveInvoicingSubscriptionResponse = ZeniAPIResponse<InvoicingSubscri
|
|
|
18
18
|
* Sending them made every price point whose cadence the form could not express
|
|
19
19
|
* — a daily plan, for instance — fail with a 422.
|
|
20
20
|
*/
|
|
21
|
-
export declare const localDataToSaveInvoicingSubscriptionPayload: (localData: InvoicingSubscriptionFormLocalData, shippingAddress?: AddressUpdatableInfo) => Record<string, unknown>;
|
|
21
|
+
export declare const localDataToSaveInvoicingSubscriptionPayload: (localData: InvoicingSubscriptionFormLocalData, shippingAddress?: AddressUpdatableInfo, flatFeePriceCodes?: ReadonlySet<string>) => Record<string, unknown>;
|
|
22
22
|
export type RunInvoicingSubscriptionActionResponse = ZeniAPIResponse<InvoicingSubscriptionPayload>;
|
|
23
23
|
/** Snake_case request bodies for subscription action endpoints. */
|
|
24
24
|
export type ApplyCouponBody = {
|
|
@@ -82,8 +82,17 @@ interface InvoicingSubscriptionEstimateLineItemPayload {
|
|
|
82
82
|
unit_amount: number;
|
|
83
83
|
date_from?: string;
|
|
84
84
|
date_to?: string;
|
|
85
|
+
gross_amount?: number;
|
|
86
|
+
id?: string;
|
|
85
87
|
tax_amount?: number | null;
|
|
86
88
|
}
|
|
89
|
+
interface InvoicingSubscriptionEstimateDiscountPayload {
|
|
90
|
+
amount: number;
|
|
91
|
+
description: string;
|
|
92
|
+
entity_type: string;
|
|
93
|
+
entity_id?: string;
|
|
94
|
+
line_item_id?: string | null;
|
|
95
|
+
}
|
|
87
96
|
interface InvoicingSubscriptionInvoiceEstimatePayload {
|
|
88
97
|
amount_due: number;
|
|
89
98
|
coupon_discount_total: number;
|
|
@@ -94,6 +103,7 @@ interface InvoicingSubscriptionInvoiceEstimatePayload {
|
|
|
94
103
|
sub_total: number;
|
|
95
104
|
tax: number | null;
|
|
96
105
|
total: number;
|
|
106
|
+
discounts?: InvoicingSubscriptionEstimateDiscountPayload[];
|
|
97
107
|
due_date?: string;
|
|
98
108
|
invoice_date?: string;
|
|
99
109
|
}
|
|
@@ -20,22 +20,25 @@ const invoicingSubscriptionFormConfig_1 = require("./invoicingSubscriptionFormCo
|
|
|
20
20
|
* Sending them made every price point whose cadence the form could not express
|
|
21
21
|
* — a daily plan, for instance — fail with a 422.
|
|
22
22
|
*/
|
|
23
|
-
const localDataToSaveInvoicingSubscriptionPayload = (localData, shippingAddress) => {
|
|
23
|
+
const localDataToSaveInvoicingSubscriptionPayload = (localData, shippingAddress, flatFeePriceCodes = new Set()) => {
|
|
24
|
+
const itemQuantity = (priceCode, quantity) => flatFeePriceCodes.has(priceCode)
|
|
25
|
+
? 1
|
|
26
|
+
: (0, invoicingSubscriptionFormConfig_1.toInvoicingSubscriptionQuantity)(quantity);
|
|
24
27
|
const items = [
|
|
25
28
|
{
|
|
26
29
|
item_price_code: localData.planPriceCode,
|
|
27
30
|
item_type: 'plan',
|
|
28
|
-
quantity: (
|
|
31
|
+
quantity: itemQuantity(localData.planPriceCode, localData.planQuantity),
|
|
29
32
|
},
|
|
30
33
|
...localData.addonPriceCodes.map((priceCode) => ({
|
|
31
34
|
item_price_code: priceCode,
|
|
32
35
|
item_type: 'addon',
|
|
33
|
-
quantity: (
|
|
36
|
+
quantity: itemQuantity(priceCode, localData.addonQuantities[priceCode]),
|
|
34
37
|
})),
|
|
35
38
|
...localData.chargePriceCodes.map((priceCode) => ({
|
|
36
39
|
item_price_code: priceCode,
|
|
37
40
|
item_type: 'charge',
|
|
38
|
-
quantity: (
|
|
41
|
+
quantity: itemQuantity(priceCode, localData.chargeQuantities[priceCode]),
|
|
39
42
|
})),
|
|
40
43
|
];
|
|
41
44
|
const setupFee = localData.setupFee?.amount;
|
|
@@ -63,11 +66,59 @@ const localDataToSaveInvoicingSubscriptionPayload = (localData, shippingAddress)
|
|
|
63
66
|
};
|
|
64
67
|
exports.localDataToSaveInvoicingSubscriptionPayload = localDataToSaveInvoicingSubscriptionPayload;
|
|
65
68
|
const toEstimateDate = (value) => value != null && value !== '' ? (0, zeniDayJS_1.date)(value) : undefined;
|
|
69
|
+
const isItemLevelCoupon = (discount) => discount.entity_type === 'item_level_coupon';
|
|
70
|
+
const isCoupon = (discount) => discount.entity_type === 'document_level_coupon' ||
|
|
71
|
+
discount.entity_type === 'item_level_coupon';
|
|
72
|
+
/**
|
|
73
|
+
* Name the coupon behind a line's discount. Exact when the API links a coupon
|
|
74
|
+
* row to its line (`line_item_id`); otherwise only when a single item-level
|
|
75
|
+
* coupon applies, since then every discounted line got that one.
|
|
76
|
+
*/
|
|
77
|
+
const lineDiscountLabel = (lineItem, discounts) => {
|
|
78
|
+
if (lineItem.discount_amount <= 0) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
const itemCoupons = discounts.filter(isItemLevelCoupon);
|
|
82
|
+
const linked = lineItem.id != null
|
|
83
|
+
? itemCoupons.filter((coupon) => coupon.line_item_id === lineItem.id)
|
|
84
|
+
: [];
|
|
85
|
+
if (linked.length > 0) {
|
|
86
|
+
return [...new Set(linked.map((coupon) => coupon.description))].join(', ');
|
|
87
|
+
}
|
|
88
|
+
const names = [...new Set(itemCoupons.map((coupon) => coupon.description))];
|
|
89
|
+
return names.length === 1 ? names[0] : undefined;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* One row per coupon. An item-level coupon comes back once per line it
|
|
93
|
+
* discounted, so its rows are summed; listing each would read as the same
|
|
94
|
+
* discount taken several times.
|
|
95
|
+
*/
|
|
96
|
+
const mergeCouponRows = (discounts) => {
|
|
97
|
+
const rowsByCoupon = new Map();
|
|
98
|
+
discounts.filter(isCoupon).forEach((coupon) => {
|
|
99
|
+
// The API sends `entity_id: ""` when it has none; key those by name so
|
|
100
|
+
// two unrelated coupons are not merged into one row.
|
|
101
|
+
const couponKey = coupon.entity_id != null && coupon.entity_id !== ''
|
|
102
|
+
? coupon.entity_id
|
|
103
|
+
: coupon.description;
|
|
104
|
+
const key = `${coupon.entity_type}:${couponKey}`;
|
|
105
|
+
const row = rowsByCoupon.get(key);
|
|
106
|
+
rowsByCoupon.set(key, {
|
|
107
|
+
amount: Math.round(((row?.amount ?? 0) + coupon.amount) * 100) / 100,
|
|
108
|
+
description: coupon.description,
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
return [...rowsByCoupon.values()];
|
|
112
|
+
};
|
|
66
113
|
const mapInvoiceEstimate = (payload, money) => payload == null
|
|
67
114
|
? undefined
|
|
68
115
|
: {
|
|
69
116
|
amountDue: money(payload.amount_due),
|
|
70
117
|
couponDiscountTotal: money(payload.coupon_discount_total),
|
|
118
|
+
coupons: mergeCouponRows(payload.discounts ?? []).map((coupon) => ({
|
|
119
|
+
amount: money(coupon.amount),
|
|
120
|
+
description: coupon.description,
|
|
121
|
+
})),
|
|
71
122
|
creditsApplied: money(payload.credits_applied),
|
|
72
123
|
dueDate: toEstimateDate(payload.due_date),
|
|
73
124
|
grossSubTotal: money(payload.gross_sub_total),
|
|
@@ -78,6 +129,8 @@ const mapInvoiceEstimate = (payload, money) => payload == null
|
|
|
78
129
|
dateTo: toEstimateDate(lineItem.date_to),
|
|
79
130
|
description: lineItem.description,
|
|
80
131
|
discountAmount: money(lineItem.discount_amount),
|
|
132
|
+
discountLabel: lineDiscountLabel(lineItem, payload.discounts ?? []),
|
|
133
|
+
grossAmount: money(lineItem.gross_amount ?? lineItem.amount),
|
|
81
134
|
quantity: lineItem.quantity,
|
|
82
135
|
taxAmount: lineItem.tax_amount != null
|
|
83
136
|
? money(lineItem.tax_amount)
|
|
@@ -147,6 +147,8 @@ export interface InvoicingSubscriptionOption {
|
|
|
147
147
|
billingCycles?: number;
|
|
148
148
|
billingPeriod?: number;
|
|
149
149
|
billingPeriodUnit?: string;
|
|
150
|
+
/** Catalog options only: false for a flat fee, which takes no quantity. */
|
|
151
|
+
hasQuantity?: boolean;
|
|
150
152
|
price?: Amount;
|
|
151
153
|
productCode?: string;
|
|
152
154
|
subtitle?: string;
|
|
@@ -182,6 +182,7 @@ const toInvoicingPlanOption = (plan) => ({
|
|
|
182
182
|
// price point and rejects a subscription that claims a different one.
|
|
183
183
|
billingPeriod: plan.period,
|
|
184
184
|
billingPeriodUnit: plan.periodUnit,
|
|
185
|
+
hasQuantity: (0, invoicingSubscriptionFormConfig_1.invoicingPriceHasQuantity)(plan.pricingModel),
|
|
185
186
|
label: plan.name ?? plan.id,
|
|
186
187
|
price: invoicingUnitPrice(plan),
|
|
187
188
|
productCode: plan.productCode,
|
|
@@ -193,6 +194,7 @@ const toInvoicingCatalogItemOption = (product) => ({
|
|
|
193
194
|
// A one-time charge has no cadence, so its price is quoted flat rather than
|
|
194
195
|
// per period.
|
|
195
196
|
billingPeriodUnit: product.itemType === 'charge' ? undefined : product.periodUnit,
|
|
197
|
+
hasQuantity: (0, invoicingSubscriptionFormConfig_1.invoicingPriceHasQuantity)(product.pricingModel),
|
|
196
198
|
label: product.name ?? product.id,
|
|
197
199
|
price: invoicingUnitPrice(product),
|
|
198
200
|
productCode: product.productCode,
|
|
@@ -41,19 +41,32 @@ export interface InvoicingSubscriptionFormLocalData {
|
|
|
41
41
|
setupFee?: Amount;
|
|
42
42
|
}
|
|
43
43
|
export interface InvoicingSubscriptionEstimateLineItem {
|
|
44
|
+
/** After the line's own (item-level) coupons. */
|
|
44
45
|
amount: Amount;
|
|
45
46
|
description: string;
|
|
47
|
+
/** Item-level coupons on this line; invoice-level coupons are not spread here. */
|
|
46
48
|
discountAmount: Amount;
|
|
49
|
+
/** Before any coupon, so the lines add up to `grossSubTotal`. */
|
|
50
|
+
grossAmount: Amount;
|
|
47
51
|
quantity: number;
|
|
48
52
|
unitAmount: Amount;
|
|
49
53
|
dateFrom?: ZeniDate;
|
|
50
54
|
dateTo?: ZeniDate;
|
|
55
|
+
/** The coupon behind `discountAmount`, when it can be told; see the mapper. */
|
|
56
|
+
discountLabel?: string;
|
|
51
57
|
taxAmount?: Amount;
|
|
52
58
|
}
|
|
59
|
+
/** A coupon the estimate applies, named, for the totals. */
|
|
60
|
+
export interface InvoicingSubscriptionEstimateCoupon {
|
|
61
|
+
amount: Amount;
|
|
62
|
+
description: string;
|
|
63
|
+
}
|
|
53
64
|
/** An invoice the save would raise now, or the next one it would raise later. */
|
|
54
65
|
export interface InvoicingSubscriptionInvoiceEstimate {
|
|
55
66
|
amountDue: Amount;
|
|
56
67
|
couponDiscountTotal: Amount;
|
|
68
|
+
/** Item- and invoice-level coupons, one row each; they sum to `couponDiscountTotal`. */
|
|
69
|
+
coupons: InvoicingSubscriptionEstimateCoupon[];
|
|
57
70
|
/** Refundable credits plus excess payments; promotional credits are separate. */
|
|
58
71
|
creditsApplied: Amount;
|
|
59
72
|
grossSubTotal: Amount;
|
|
@@ -43,11 +43,14 @@ const fetchInvoicingSubscriptionDetailPageEpic = (actions$, state$) => actions$.
|
|
|
43
43
|
// Plan and coupon lists back the names the page renders for its line
|
|
44
44
|
// items; both list slices cache, so this only refetches when asked to.
|
|
45
45
|
const catalogListState = state.invoicingCatalogListViewState;
|
|
46
|
-
if (
|
|
47
|
-
error: catalogListState.error,
|
|
46
|
+
if ((0, invoicingListTabCache_1.shouldFetchFullInvoicingList)({
|
|
48
47
|
fetchState: catalogListState.fetchState,
|
|
49
|
-
|
|
48
|
+
filters: catalogListState.planFilters,
|
|
49
|
+
nextCursor: catalogListState.planNextCursor,
|
|
50
|
+
sort: catalogListState.planSort,
|
|
51
|
+
}, { type: 'plan' }, cacheOverride)) {
|
|
50
52
|
pageActions.push((0, invoicingCatalogListViewReducer_1.fetchInvoicingCatalogPlanList)({
|
|
53
|
+
fetchAll: true,
|
|
51
54
|
filters: { type: 'plan' },
|
|
52
55
|
keepExistingListItems: false,
|
|
53
56
|
}));
|
|
@@ -23,6 +23,7 @@ const fetchInvoicingSubscriptionFormPageEpic = (actions$) => actions$.pipe((0, o
|
|
|
23
23
|
// unfiltered list would replace the store's plans with every catalog
|
|
24
24
|
// item.
|
|
25
25
|
(0, invoicingCatalogListViewReducer_1.fetchInvoicingCatalogPlanList)({
|
|
26
|
+
fetchAll: true,
|
|
26
27
|
filters: { type: 'plan' },
|
|
27
28
|
keepExistingListItems: false,
|
|
28
29
|
}),
|
package/lib/view/invoicing/editInvoicingSubscriptionDetailView/invoicingSubscriptionFormConfig.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export declare const INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE: "invoicing_su
|
|
|
8
8
|
* their day gets their own calendar date rather than yesterday's.
|
|
9
9
|
*/
|
|
10
10
|
export declare const invoicingSubscriptionTodayIso: () => string;
|
|
11
|
+
/** A flat fee bills its price once, so its quantity is always 1. */
|
|
12
|
+
export declare const invoicingPriceHasQuantity: (pricingModel?: string) => boolean;
|
|
11
13
|
/**
|
|
12
14
|
* Clamp a subscription-item quantity to the minimum the API accepts. Shared by
|
|
13
15
|
* the plan, add-on and charge items so none of them can bill a 0 or a fraction.
|
package/lib/view/invoicing/editInvoicingSubscriptionDetailView/invoicingSubscriptionFormConfig.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.entityToInvoicingSubscriptionFormLocalData = exports.initialInvoicingSubscriptionFormLocalData = exports.toInvoicingSubscriptionBillingCycles = exports.toInvoicingSubscriptionQuantity = exports.invoicingSubscriptionTodayIso = exports.INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE = void 0;
|
|
3
|
+
exports.entityToInvoicingSubscriptionFormLocalData = exports.initialInvoicingSubscriptionFormLocalData = exports.toInvoicingSubscriptionBillingCycles = exports.toInvoicingSubscriptionQuantity = exports.invoicingPriceHasQuantity = exports.invoicingSubscriptionTodayIso = exports.INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE = void 0;
|
|
4
4
|
const zeniDayJS_1 = require("../../../zeniDayJS");
|
|
5
5
|
/** `AddressType` key used when the subscription form opens the shared Address screen. */
|
|
6
6
|
exports.INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE = 'invoicing_subscription_shipping_address';
|
|
@@ -26,6 +26,9 @@ const subscriptionItemQuantities = (subscription, itemType) => {
|
|
|
26
26
|
*/
|
|
27
27
|
const invoicingSubscriptionTodayIso = () => (0, zeniDayJS_1.dateNow)().format('YYYY-MM-DD');
|
|
28
28
|
exports.invoicingSubscriptionTodayIso = invoicingSubscriptionTodayIso;
|
|
29
|
+
/** A flat fee bills its price once, so its quantity is always 1. */
|
|
30
|
+
const invoicingPriceHasQuantity = (pricingModel) => pricingModel !== 'flat_fee';
|
|
31
|
+
exports.invoicingPriceHasQuantity = invoicingPriceHasQuantity;
|
|
29
32
|
/**
|
|
30
33
|
* Clamp a subscription-item quantity to the minimum the API accepts. Shared by
|
|
31
34
|
* the plan, add-on and charge items so none of them can bill a 0 or a fraction.
|
package/lib/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js
CHANGED
|
@@ -12,6 +12,7 @@ const responsePayload_1 = require("../../../responsePayload");
|
|
|
12
12
|
const addressViewReducer_1 = require("../../addressView/addressViewReducer");
|
|
13
13
|
const editInvoicingCustomerDetailViewReducer_1 = require("../editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer");
|
|
14
14
|
const invoiceListReducer_1 = require("../invoiceList/invoiceListReducer");
|
|
15
|
+
const invoicingCatalogListViewSelector_1 = require("../invoicingCatalogListView/invoicingCatalogListViewSelector");
|
|
15
16
|
const invoicingSubscriptionListViewReducer_1 = require("../invoicingSubscriptionListView/invoicingSubscriptionListViewReducer");
|
|
16
17
|
const editInvoicingSubscriptionDetailViewPayload_1 = require("./editInvoicingSubscriptionDetailViewPayload");
|
|
17
18
|
const editInvoicingSubscriptionDetailViewReducer_1 = require("./editInvoicingSubscriptionDetailViewReducer");
|
|
@@ -29,7 +30,10 @@ const invoicingSubscriptionSaveRequest = (rootState, id) => {
|
|
|
29
30
|
// Shipping address captured via the shared Address screen is sent as an
|
|
30
31
|
// object in the payload (same pattern as the customer save flow).
|
|
31
32
|
const shippingAddress = rootState.addressViewState.newAddressState?.[invoicingSubscriptionFormConfig_1.INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE]?.addressToCreate;
|
|
32
|
-
const
|
|
33
|
+
const flatFeePriceCodes = new Set((0, invoicingCatalogListViewSelector_1.getInvoicingCatalogPrices)(Object.values(rootState.invoicingCatalogState.itemByID))
|
|
34
|
+
.filter((price) => !(0, invoicingSubscriptionFormConfig_1.invoicingPriceHasQuantity)(price.pricingModel))
|
|
35
|
+
.flatMap((price) => price.priceCode ?? []));
|
|
36
|
+
const data = (0, editInvoicingSubscriptionDetailViewPayload_1.localDataToSaveInvoicingSubscriptionPayload)(localData, shippingAddress, flatFeePriceCodes);
|
|
33
37
|
if (id != null) {
|
|
34
38
|
delete data.coupon_ids;
|
|
35
39
|
}
|
package/lib/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogPlanListEpic.js
CHANGED
|
@@ -26,19 +26,30 @@ const buildPlanQuery = (filters, cursor, sort) => {
|
|
|
26
26
|
return params;
|
|
27
27
|
};
|
|
28
28
|
const fetchInvoicingCatalogPlanListEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(invoicingCatalogListViewReducer_1.fetchInvoicingCatalogPlanList.match), (0, operators_1.switchMap)((action) => {
|
|
29
|
-
const { filters, cursor, keepExistingListItems, sort } = action.payload;
|
|
29
|
+
const { filters, cursor, fetchAll, keepExistingListItems, sort } = action.payload;
|
|
30
30
|
const apiUrl = (0, invoicingApiHelper_1.withQuery)(`${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/catalog/plans`, buildPlanQuery(filters, cursor, sort));
|
|
31
31
|
return zeniAPI.getJSON(apiUrl).pipe((0, operators_1.switchMap)((response) => {
|
|
32
32
|
if ((0, responsePayload_1.isSuccessResponse)(response)) {
|
|
33
33
|
const items = response.data?.items ?? [];
|
|
34
|
-
|
|
34
|
+
const nextCursor = response.data?.next_cursor ?? null;
|
|
35
|
+
const pageActions = [
|
|
35
36
|
(0, invoicingCatalogReducer_1.updateInvoicingCatalogItems)(items, 'merge'),
|
|
36
37
|
(0, invoicingCatalogListViewReducer_1.updateInvoicingCatalogPlanList)({
|
|
37
38
|
ids: items.map((item) => item.id),
|
|
38
|
-
nextCursor
|
|
39
|
+
nextCursor,
|
|
39
40
|
keepExistingListItems,
|
|
40
41
|
}),
|
|
41
42
|
];
|
|
43
|
+
if (fetchAll && nextCursor != null && nextCursor !== cursor) {
|
|
44
|
+
pageActions.push((0, invoicingCatalogListViewReducer_1.fetchInvoicingCatalogPlanList)({
|
|
45
|
+
cursor: nextCursor,
|
|
46
|
+
fetchAll,
|
|
47
|
+
filters,
|
|
48
|
+
keepExistingListItems: true,
|
|
49
|
+
sort,
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
return pageActions;
|
|
42
53
|
}
|
|
43
54
|
return (0, rxjs_1.of)((0, invoicingCatalogListViewReducer_1.updateInvoicingCatalogPlanListFailure)(response.status));
|
|
44
55
|
}), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, invoicingCatalogListViewReducer_1.updateInvoicingCatalogPlanListFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Fetch catalog plan list REST API call errored out ' +
|
package/lib/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogProductListEpic.js
CHANGED
|
@@ -26,19 +26,30 @@ const buildProductQuery = (filters, cursor, sort) => {
|
|
|
26
26
|
return params;
|
|
27
27
|
};
|
|
28
28
|
const fetchInvoicingCatalogProductListEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(invoicingCatalogListViewReducer_1.fetchInvoicingCatalogProductList.match), (0, operators_1.switchMap)((action) => {
|
|
29
|
-
const { filters, cursor, keepExistingListItems, sort } = action.payload;
|
|
29
|
+
const { filters, cursor, fetchAll, keepExistingListItems, sort } = action.payload;
|
|
30
30
|
const apiUrl = (0, invoicingApiHelper_1.withQuery)(`${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/catalog/plans`, buildProductQuery(filters, cursor, sort));
|
|
31
31
|
return zeniAPI.getJSON(apiUrl).pipe((0, operators_1.switchMap)((response) => {
|
|
32
32
|
if ((0, responsePayload_1.isSuccessResponse)(response)) {
|
|
33
33
|
const items = response.data?.items ?? [];
|
|
34
|
-
|
|
34
|
+
const nextCursor = response.data?.next_cursor ?? null;
|
|
35
|
+
const pageActions = [
|
|
35
36
|
(0, invoicingCatalogReducer_1.updateInvoicingCatalogItems)(items, 'merge'),
|
|
36
37
|
(0, invoicingCatalogListViewReducer_1.updateInvoicingCatalogProductList)({
|
|
37
38
|
ids: items.map((item) => item.id),
|
|
38
|
-
nextCursor
|
|
39
|
+
nextCursor,
|
|
39
40
|
keepExistingListItems,
|
|
40
41
|
}),
|
|
41
42
|
];
|
|
43
|
+
if (fetchAll && nextCursor != null && nextCursor !== cursor) {
|
|
44
|
+
pageActions.push((0, invoicingCatalogListViewReducer_1.fetchInvoicingCatalogProductList)({
|
|
45
|
+
cursor: nextCursor,
|
|
46
|
+
fetchAll,
|
|
47
|
+
filters,
|
|
48
|
+
keepExistingListItems: true,
|
|
49
|
+
sort,
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
return pageActions;
|
|
42
53
|
}
|
|
43
54
|
return (0, rxjs_1.of)((0, invoicingCatalogListViewReducer_1.updateInvoicingCatalogProductListFailure)(response.status));
|
|
44
55
|
}), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, invoicingCatalogListViewReducer_1.updateInvoicingCatalogProductListFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Fetch catalog product list REST API call errored out ' +
|
|
@@ -6,12 +6,15 @@ import { InvoicingCatalogListViewState, InvoicingCatalogPlanFilters, InvoicingCa
|
|
|
6
6
|
export declare const initialState: InvoicingCatalogListViewState;
|
|
7
7
|
export declare const fetchInvoicingCatalogPlanList: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[payload: {
|
|
8
8
|
cursor?: string;
|
|
9
|
+
/** Keep requesting the next page until the list is complete. */
|
|
10
|
+
fetchAll?: boolean;
|
|
9
11
|
filters?: InvoicingCatalogPlanFilters;
|
|
10
12
|
keepExistingListItems?: boolean;
|
|
11
13
|
sort?: InvoicingListSort;
|
|
12
14
|
}], {
|
|
13
15
|
filters: InvoicingCatalogPlanFilters;
|
|
14
16
|
cursor: string | undefined;
|
|
17
|
+
fetchAll: boolean;
|
|
15
18
|
keepExistingListItems: boolean;
|
|
16
19
|
sort: InvoicingListSort | undefined;
|
|
17
20
|
}, "invoicingCatalogListView/fetchInvoicingCatalogPlanList", never, never>, updateInvoicingCatalogPlanList: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
@@ -20,12 +23,15 @@ export declare const fetchInvoicingCatalogPlanList: import("@reduxjs/toolkit").A
|
|
|
20
23
|
nextCursor: string | null;
|
|
21
24
|
}, "invoicingCatalogListView/updateInvoicingCatalogPlanList">, updateInvoicingCatalogPlanListFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingCatalogListView/updateInvoicingCatalogPlanListFailure">, fetchInvoicingCatalogProductList: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[payload: {
|
|
22
25
|
cursor?: string;
|
|
26
|
+
/** Keep requesting the next page until the list is complete. */
|
|
27
|
+
fetchAll?: boolean;
|
|
23
28
|
filters?: InvoicingCatalogProductFilters;
|
|
24
29
|
keepExistingListItems?: boolean;
|
|
25
30
|
sort?: InvoicingListSort;
|
|
26
31
|
}], {
|
|
27
32
|
filters: InvoicingCatalogProductFilters;
|
|
28
33
|
cursor: string | undefined;
|
|
34
|
+
fetchAll: boolean;
|
|
29
35
|
keepExistingListItems: boolean;
|
|
30
36
|
sort: InvoicingListSort | undefined;
|
|
31
37
|
}, "invoicingCatalogListView/fetchInvoicingCatalogProductList", never, never>, updateInvoicingCatalogProductList: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
@@ -40,6 +40,7 @@ const invoicingCatalogListView = (0, toolkit_1.createSlice)({
|
|
|
40
40
|
payload: {
|
|
41
41
|
filters: payload.filters ?? {},
|
|
42
42
|
cursor: payload.cursor,
|
|
43
|
+
fetchAll: payload.fetchAll ?? false,
|
|
43
44
|
keepExistingListItems: payload.keepExistingListItems ?? false,
|
|
44
45
|
sort: payload.sort,
|
|
45
46
|
},
|
|
@@ -74,6 +75,7 @@ const invoicingCatalogListView = (0, toolkit_1.createSlice)({
|
|
|
74
75
|
payload: {
|
|
75
76
|
filters: payload.filters ?? {},
|
|
76
77
|
cursor: payload.cursor,
|
|
78
|
+
fetchAll: payload.fetchAll ?? false,
|
|
77
79
|
keepExistingListItems: payload.keepExistingListItems ?? false,
|
|
78
80
|
sort: payload.sort,
|
|
79
81
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FetchStateAndError, ID } from '../../commonStateTypes/common';
|
|
1
|
+
import { FetchState, FetchStateAndError, ID } from '../../commonStateTypes/common';
|
|
2
2
|
import { ZeniAPIStatus } from '../../responsePayload';
|
|
3
3
|
import { InvoicingListSort } from './invoicingApiHelper';
|
|
4
4
|
/**
|
|
@@ -42,6 +42,16 @@ export declare const isSameInvoicingListQuery: (a: {
|
|
|
42
42
|
filters: object;
|
|
43
43
|
sort?: InvoicingListSort;
|
|
44
44
|
}) => boolean;
|
|
45
|
+
/**
|
|
46
|
+
* For a picker that searches client-side: reuse only a complete list fetched
|
|
47
|
+
* with the picker's own query, else load every page of it.
|
|
48
|
+
*/
|
|
49
|
+
export declare const shouldFetchFullInvoicingList: (list: {
|
|
50
|
+
fetchState: FetchState;
|
|
51
|
+
filters: object;
|
|
52
|
+
nextCursor: string | null;
|
|
53
|
+
sort?: InvoicingListSort;
|
|
54
|
+
}, pickerFilters: object, cacheOverride: boolean) => boolean;
|
|
45
55
|
/** What opening a tab should fetch, if anything. */
|
|
46
56
|
export type InvoicingListTabFetch = {
|
|
47
57
|
kind: 'none';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isSameInvoicingListQuery = exports.invoicingListStatusParam = exports.invoicingListFetchTab = exports.invoicingListSourceTab = exports.getInvoicingListTab = exports.INVOICING_LIST_ALL_TAB = void 0;
|
|
3
|
+
exports.shouldFetchFullInvoicingList = exports.isSameInvoicingListQuery = exports.invoicingListStatusParam = exports.invoicingListFetchTab = exports.invoicingListSourceTab = exports.getInvoicingListTab = exports.INVOICING_LIST_ALL_TAB = void 0;
|
|
4
4
|
exports.planInvoicingListTabFetch = planInvoicingListTabFetch;
|
|
5
5
|
exports.startInvoicingListTabFetch = startInvoicingListTabFetch;
|
|
6
6
|
exports.completeInvoicingListTabFetch = completeInvoicingListTabFetch;
|
|
@@ -46,6 +46,15 @@ const isSameInvoicingListQuery = (a, b) => {
|
|
|
46
46
|
a.sort?.dir === b.sort?.dir);
|
|
47
47
|
};
|
|
48
48
|
exports.isSameInvoicingListQuery = isSameInvoicingListQuery;
|
|
49
|
+
/**
|
|
50
|
+
* For a picker that searches client-side: reuse only a complete list fetched
|
|
51
|
+
* with the picker's own query, else load every page of it.
|
|
52
|
+
*/
|
|
53
|
+
const shouldFetchFullInvoicingList = (list, pickerFilters, cacheOverride) => cacheOverride ||
|
|
54
|
+
list.fetchState !== 'Completed' ||
|
|
55
|
+
list.nextCursor != null ||
|
|
56
|
+
!(0, exports.isSameInvoicingListQuery)({ filters: list.filters, sort: list.sort }, { filters: pickerFilters });
|
|
57
|
+
exports.shouldFetchFullInvoicingList = shouldFetchFullInvoicingList;
|
|
49
58
|
/**
|
|
50
59
|
* Fetch a tab that is empty or failed; top up one that holds less than a page
|
|
51
60
|
* while the server says there is more; leave a full or complete one cached.
|
|
@@ -37,18 +37,33 @@ const localDataToIssueCreditNotePayload = (localData) => {
|
|
|
37
37
|
};
|
|
38
38
|
};
|
|
39
39
|
exports.localDataToIssueCreditNotePayload = localDataToIssueCreditNotePayload;
|
|
40
|
+
/**
|
|
41
|
+
* The rate a unit was actually billed at. A plan or add-on line covering
|
|
42
|
+
* several periods carries the per-period `unit_amount` but the full term in
|
|
43
|
+
* `amount`, so only `amount` / `quantity` lets crediting every unit reach what
|
|
44
|
+
* the line billed.
|
|
45
|
+
*/
|
|
46
|
+
const billedUnitAmount = (lineItem) => lineItem.quantity > 0
|
|
47
|
+
? {
|
|
48
|
+
...lineItem.amount,
|
|
49
|
+
amount: Math.round((lineItem.amount.amount / lineItem.quantity) * 100) / 100,
|
|
50
|
+
}
|
|
51
|
+
: lineItem.unitAmount;
|
|
40
52
|
const initializeIssueCreditNoteDraftFromInvoice = (invoice) => ({
|
|
41
53
|
invoiceId: invoice.id,
|
|
42
54
|
reasonCode: '',
|
|
43
55
|
type: '',
|
|
44
|
-
lineItems: (invoice.lineItems ?? []).map((lineItem) =>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
lineItems: (invoice.lineItems ?? []).map((lineItem) => {
|
|
57
|
+
const unitAmount = billedUnitAmount(lineItem);
|
|
58
|
+
return {
|
|
59
|
+
description: lineItem.description,
|
|
60
|
+
id: lineItem.id,
|
|
61
|
+
maxQuantity: lineItem.quantity,
|
|
62
|
+
maxUnitAmount: unitAmount,
|
|
63
|
+
quantity: String(lineItem.quantity),
|
|
64
|
+
selected: true,
|
|
65
|
+
unitAmount,
|
|
66
|
+
};
|
|
67
|
+
}),
|
|
53
68
|
});
|
|
54
69
|
exports.initializeIssueCreditNoteDraftFromInvoice = initializeIssueCreditNoteDraftFromInvoice;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
|
+
import { updateReconciliationReport } from '../../../entity/reconciliationReport/reconciliationReportReducer';
|
|
3
|
+
import { RootState } from '../../../rootStateTypes';
|
|
4
|
+
import { ZeniAPI } from '../../../zeniAPI';
|
|
5
|
+
import { fetchReconciliationReport, fetchReconciliationReportFailure, fetchReconciliationReportSuccess } from '../reconciliationReportViewReducer';
|
|
6
|
+
export type ActionType = ReturnType<typeof fetchReconciliationReport> | ReturnType<typeof updateReconciliationReport> | ReturnType<typeof fetchReconciliationReportSuccess> | ReturnType<typeof fetchReconciliationReportFailure>;
|
|
7
|
+
export declare const fetchReconciliationReportEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => import("rxjs").Observable<{
|
|
8
|
+
payload: import("../../../entity/reconciliationReport/reconciliationReportPayload").ReconciliationReportPayload;
|
|
9
|
+
type: "reconciliationReport/updateReconciliationReport";
|
|
10
|
+
} | {
|
|
11
|
+
payload: string;
|
|
12
|
+
type: "reconciliationReportView/fetchReconciliationReportSuccess";
|
|
13
|
+
} | {
|
|
14
|
+
payload: {
|
|
15
|
+
reconciliationId: import("../../..").ID;
|
|
16
|
+
status: import("../../../zeniAPIStatus").ZeniAPIStatus;
|
|
17
|
+
};
|
|
18
|
+
type: "reconciliationReportView/fetchReconciliationReportFailure";
|
|
19
|
+
}>;
|