@mj-biz-apps/orders-core-entities-server 0.0.1 → 5.2.0
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/LICENSE +183 -0
- package/README.md +141 -2
- package/dist/AccountingBridge.d.ts +65 -0
- package/dist/AccountingBridge.d.ts.map +1 -0
- package/dist/AccountingBridge.js +102 -0
- package/dist/AccountingBridge.js.map +1 -0
- package/dist/AdvanceOrderStateOperation.d.ts +80 -0
- package/dist/AdvanceOrderStateOperation.d.ts.map +1 -0
- package/dist/AdvanceOrderStateOperation.js +267 -0
- package/dist/AdvanceOrderStateOperation.js.map +1 -0
- package/dist/ApplyAccountCreditOperation.d.ts +97 -0
- package/dist/ApplyAccountCreditOperation.d.ts.map +1 -0
- package/dist/ApplyAccountCreditOperation.js +275 -0
- package/dist/ApplyAccountCreditOperation.js.map +1 -0
- package/dist/BaseDeliveryChannel.d.ts +106 -0
- package/dist/BaseDeliveryChannel.d.ts.map +1 -0
- package/dist/BaseDeliveryChannel.js +36 -0
- package/dist/BaseDeliveryChannel.js.map +1 -0
- package/dist/BasePaymentProvider.d.ts +239 -0
- package/dist/BasePaymentProvider.d.ts.map +1 -0
- package/dist/BasePaymentProvider.js +91 -0
- package/dist/BasePaymentProvider.js.map +1 -0
- package/dist/BundleBehavior.d.ts +139 -0
- package/dist/BundleBehavior.d.ts.map +1 -0
- package/dist/BundleBehavior.js +173 -0
- package/dist/BundleBehavior.js.map +1 -0
- package/dist/BundleEngine.d.ts +60 -0
- package/dist/BundleEngine.d.ts.map +1 -0
- package/dist/BundleEngine.js +197 -0
- package/dist/BundleEngine.js.map +1 -0
- package/dist/CancelSubscriptionOperation.d.ts +98 -0
- package/dist/CancelSubscriptionOperation.d.ts.map +1 -0
- package/dist/CancelSubscriptionOperation.js +317 -0
- package/dist/CancelSubscriptionOperation.js.map +1 -0
- package/dist/CapturePaymentOperation.d.ts +62 -0
- package/dist/CapturePaymentOperation.d.ts.map +1 -0
- package/dist/CapturePaymentOperation.js +463 -0
- package/dist/CapturePaymentOperation.js.map +1 -0
- package/dist/CheckEntitlementOperation.d.ts +27 -0
- package/dist/CheckEntitlementOperation.d.ts.map +1 -0
- package/dist/CheckEntitlementOperation.js +45 -0
- package/dist/CheckEntitlementOperation.js.map +1 -0
- package/dist/CheckoutSessionService.d.ts +258 -0
- package/dist/CheckoutSessionService.d.ts.map +1 -0
- package/dist/CheckoutSessionService.js +1557 -0
- package/dist/CheckoutSessionService.js.map +1 -0
- package/dist/DeliveryBehavior.d.ts +121 -0
- package/dist/DeliveryBehavior.d.ts.map +1 -0
- package/dist/DeliveryBehavior.js +145 -0
- package/dist/DeliveryBehavior.js.map +1 -0
- package/dist/DeliveryRecipientResolver.d.ts +38 -0
- package/dist/DeliveryRecipientResolver.d.ts.map +1 -0
- package/dist/DeliveryRecipientResolver.js +93 -0
- package/dist/DeliveryRecipientResolver.js.map +1 -0
- package/dist/DeliveryResolver.d.ts +14 -0
- package/dist/DeliveryResolver.d.ts.map +1 -0
- package/dist/DeliveryResolver.js +45 -0
- package/dist/DeliveryResolver.js.map +1 -0
- package/dist/EmailDeliveryChannel.d.ts +31 -0
- package/dist/EmailDeliveryChannel.d.ts.map +1 -0
- package/dist/EmailDeliveryChannel.js +158 -0
- package/dist/EmailDeliveryChannel.js.map +1 -0
- package/dist/EntitlementBehavior.d.ts +235 -0
- package/dist/EntitlementBehavior.d.ts.map +1 -0
- package/dist/EntitlementBehavior.js +330 -0
- package/dist/EntitlementBehavior.js.map +1 -0
- package/dist/EntitlementEngine.d.ts +97 -0
- package/dist/EntitlementEngine.d.ts.map +1 -0
- package/dist/EntitlementEngine.js +338 -0
- package/dist/EntitlementEngine.js.map +1 -0
- package/dist/EntitlementGrantClaimDriver.d.ts +42 -0
- package/dist/EntitlementGrantClaimDriver.d.ts.map +1 -0
- package/dist/EntitlementGrantClaimDriver.js +158 -0
- package/dist/EntitlementGrantClaimDriver.js.map +1 -0
- package/dist/EntitlementRead.d.ts +82 -0
- package/dist/EntitlementRead.d.ts.map +1 -0
- package/dist/EntitlementRead.js +368 -0
- package/dist/EntitlementRead.js.map +1 -0
- package/dist/FulfillOrderLinesOperation.d.ts +34 -0
- package/dist/FulfillOrderLinesOperation.d.ts.map +1 -0
- package/dist/FulfillOrderLinesOperation.js +208 -0
- package/dist/FulfillOrderLinesOperation.js.map +1 -0
- package/dist/FulfillmentBehavior.d.ts +101 -0
- package/dist/FulfillmentBehavior.d.ts.map +1 -0
- package/dist/FulfillmentBehavior.js +145 -0
- package/dist/FulfillmentBehavior.js.map +1 -0
- package/dist/GLAccountResolver.d.ts +123 -0
- package/dist/GLAccountResolver.d.ts.map +1 -0
- package/dist/GLAccountResolver.js +175 -0
- package/dist/GLAccountResolver.js.map +1 -0
- package/dist/GetFulfillmentQueueOperation.d.ts +35 -0
- package/dist/GetFulfillmentQueueOperation.d.ts.map +1 -0
- package/dist/GetFulfillmentQueueOperation.js +221 -0
- package/dist/GetFulfillmentQueueOperation.js.map +1 -0
- package/dist/GetOverdueWorklistOperation.d.ts +41 -0
- package/dist/GetOverdueWorklistOperation.d.ts.map +1 -0
- package/dist/GetOverdueWorklistOperation.js +210 -0
- package/dist/GetOverdueWorklistOperation.js.map +1 -0
- package/dist/GiftCardBehavior.d.ts +97 -0
- package/dist/GiftCardBehavior.d.ts.map +1 -0
- package/dist/GiftCardBehavior.js +121 -0
- package/dist/GiftCardBehavior.js.map +1 -0
- package/dist/GiftCardEngine.d.ts +59 -0
- package/dist/GiftCardEngine.d.ts.map +1 -0
- package/dist/GiftCardEngine.js +197 -0
- package/dist/GiftCardEngine.js.map +1 -0
- package/dist/GuestOrderClaimDriver.d.ts +36 -0
- package/dist/GuestOrderClaimDriver.d.ts.map +1 -0
- package/dist/GuestOrderClaimDriver.js +161 -0
- package/dist/GuestOrderClaimDriver.js.map +1 -0
- package/dist/InvoiceBehavior.d.ts +394 -0
- package/dist/InvoiceBehavior.d.ts.map +1 -0
- package/dist/InvoiceBehavior.js +496 -0
- package/dist/InvoiceBehavior.js.map +1 -0
- package/dist/InvoiceBuilder.d.ts +48 -0
- package/dist/InvoiceBuilder.d.ts.map +1 -0
- package/dist/InvoiceBuilder.js +352 -0
- package/dist/InvoiceBuilder.js.map +1 -0
- package/dist/InvoiceDisplay.d.ts +96 -0
- package/dist/InvoiceDisplay.d.ts.map +1 -0
- package/dist/InvoiceDisplay.js +121 -0
- package/dist/InvoiceDisplay.js.map +1 -0
- package/dist/ListEntitlementsOperation.d.ts +21 -0
- package/dist/ListEntitlementsOperation.d.ts.map +1 -0
- package/dist/ListEntitlementsOperation.js +39 -0
- package/dist/ListEntitlementsOperation.js.map +1 -0
- package/dist/ManualPaymentProvider.d.ts +19 -0
- package/dist/ManualPaymentProvider.d.ts.map +1 -0
- package/dist/ManualPaymentProvider.js +92 -0
- package/dist/ManualPaymentProvider.js.map +1 -0
- package/dist/OrderEntityServer.d.ts +542 -0
- package/dist/OrderEntityServer.d.ts.map +1 -0
- package/dist/OrderEntityServer.js +2100 -0
- package/dist/OrderEntityServer.js.map +1 -0
- package/dist/OrderJournalEntryFactory.d.ts +140 -0
- package/dist/OrderJournalEntryFactory.d.ts.map +1 -0
- package/dist/OrderJournalEntryFactory.js +466 -0
- package/dist/OrderJournalEntryFactory.js.map +1 -0
- package/dist/OrderLineEntityServer.d.ts +90 -0
- package/dist/OrderLineEntityServer.d.ts.map +1 -0
- package/dist/OrderLineEntityServer.js +260 -0
- package/dist/OrderLineEntityServer.js.map +1 -0
- package/dist/OrdersSettings.d.ts +36 -0
- package/dist/OrdersSettings.d.ts.map +1 -0
- package/dist/OrdersSettings.js +147 -0
- package/dist/OrdersSettings.js.map +1 -0
- package/dist/PaymentAllocationFactory.d.ts +128 -0
- package/dist/PaymentAllocationFactory.d.ts.map +1 -0
- package/dist/PaymentAllocationFactory.js +235 -0
- package/dist/PaymentAllocationFactory.js.map +1 -0
- package/dist/PaymentHeaderEntityServer.d.ts +180 -0
- package/dist/PaymentHeaderEntityServer.d.ts.map +1 -0
- package/dist/PaymentHeaderEntityServer.js +656 -0
- package/dist/PaymentHeaderEntityServer.js.map +1 -0
- package/dist/PaymentIntentService.d.ts +101 -0
- package/dist/PaymentIntentService.d.ts.map +1 -0
- package/dist/PaymentIntentService.js +150 -0
- package/dist/PaymentIntentService.js.map +1 -0
- package/dist/PaymentJournalEntryFactory.d.ts +99 -0
- package/dist/PaymentJournalEntryFactory.d.ts.map +1 -0
- package/dist/PaymentJournalEntryFactory.js +127 -0
- package/dist/PaymentJournalEntryFactory.js.map +1 -0
- package/dist/PaymentLineEntityServer.d.ts +73 -0
- package/dist/PaymentLineEntityServer.d.ts.map +1 -0
- package/dist/PaymentLineEntityServer.js +303 -0
- package/dist/PaymentLineEntityServer.js.map +1 -0
- package/dist/PaymentProviderBehavior.d.ts +222 -0
- package/dist/PaymentProviderBehavior.d.ts.map +1 -0
- package/dist/PaymentProviderBehavior.js +368 -0
- package/dist/PaymentProviderBehavior.js.map +1 -0
- package/dist/PaymentProviderResolver.d.ts +84 -0
- package/dist/PaymentProviderResolver.d.ts.map +1 -0
- package/dist/PaymentProviderResolver.js +220 -0
- package/dist/PaymentProviderResolver.js.map +1 -0
- package/dist/PaymentReversalFactory.d.ts +107 -0
- package/dist/PaymentReversalFactory.d.ts.map +1 -0
- package/dist/PaymentReversalFactory.js +174 -0
- package/dist/PaymentReversalFactory.js.map +1 -0
- package/dist/PaymentSettlement.d.ts +56 -0
- package/dist/PaymentSettlement.d.ts.map +1 -0
- package/dist/PaymentSettlement.js +243 -0
- package/dist/PaymentSettlement.js.map +1 -0
- package/dist/PaymentTermsBehavior.d.ts +109 -0
- package/dist/PaymentTermsBehavior.d.ts.map +1 -0
- package/dist/PaymentTermsBehavior.js +172 -0
- package/dist/PaymentTermsBehavior.js.map +1 -0
- package/dist/PaymentWebhookHandler.d.ts +103 -0
- package/dist/PaymentWebhookHandler.d.ts.map +1 -0
- package/dist/PaymentWebhookHandler.js +246 -0
- package/dist/PaymentWebhookHandler.js.map +1 -0
- package/dist/PreviewPriceOperation.d.ts +62 -0
- package/dist/PreviewPriceOperation.d.ts.map +1 -0
- package/dist/PreviewPriceOperation.js +161 -0
- package/dist/PreviewPriceOperation.js.map +1 -0
- package/dist/PriceOrderOperation.d.ts +93 -0
- package/dist/PriceOrderOperation.d.ts.map +1 -0
- package/dist/PriceOrderOperation.js +146 -0
- package/dist/PriceOrderOperation.js.map +1 -0
- package/dist/ProductPriceEntityServer.d.ts +34 -0
- package/dist/ProductPriceEntityServer.d.ts.map +1 -0
- package/dist/ProductPriceEntityServer.js +97 -0
- package/dist/ProductPriceEntityServer.js.map +1 -0
- package/dist/RefundPaymentOperation.d.ts +61 -0
- package/dist/RefundPaymentOperation.d.ts.map +1 -0
- package/dist/RefundPaymentOperation.js +177 -0
- package/dist/RefundPaymentOperation.js.map +1 -0
- package/dist/RevenueRecognition.d.ts +76 -0
- package/dist/RevenueRecognition.d.ts.map +1 -0
- package/dist/RevenueRecognition.js +133 -0
- package/dist/RevenueRecognition.js.map +1 -0
- package/dist/ReversalBehavior.d.ts +82 -0
- package/dist/ReversalBehavior.d.ts.map +1 -0
- package/dist/ReversalBehavior.js +100 -0
- package/dist/ReversalBehavior.js.map +1 -0
- package/dist/ReversalResolver.d.ts +37 -0
- package/dist/ReversalResolver.d.ts.map +1 -0
- package/dist/ReversalResolver.js +96 -0
- package/dist/ReversalResolver.js.map +1 -0
- package/dist/SpawnRenewalsOperation.d.ts +109 -0
- package/dist/SpawnRenewalsOperation.d.ts.map +1 -0
- package/dist/SpawnRenewalsOperation.js +295 -0
- package/dist/SpawnRenewalsOperation.js.map +1 -0
- package/dist/StoredValuePaymentProvider.d.ts +52 -0
- package/dist/StoredValuePaymentProvider.d.ts.map +1 -0
- package/dist/StoredValuePaymentProvider.js +205 -0
- package/dist/StoredValuePaymentProvider.js.map +1 -0
- package/dist/StripeACHPaymentProvider.d.ts +50 -0
- package/dist/StripeACHPaymentProvider.d.ts.map +1 -0
- package/dist/StripeACHPaymentProvider.js +211 -0
- package/dist/StripeACHPaymentProvider.js.map +1 -0
- package/dist/StripePaymentProvider.d.ts +83 -0
- package/dist/StripePaymentProvider.d.ts.map +1 -0
- package/dist/StripePaymentProvider.js +442 -0
- package/dist/StripePaymentProvider.js.map +1 -0
- package/dist/SubscriptionBehavior.d.ts +197 -0
- package/dist/SubscriptionBehavior.d.ts.map +1 -0
- package/dist/SubscriptionBehavior.js +415 -0
- package/dist/SubscriptionBehavior.js.map +1 -0
- package/dist/checkoutCaptureAlert.d.ts +16 -0
- package/dist/checkoutCaptureAlert.d.ts.map +1 -0
- package/dist/checkoutCaptureAlert.js +55 -0
- package/dist/checkoutCaptureAlert.js.map +1 -0
- package/dist/checkoutCaptureRetry.d.ts +27 -0
- package/dist/checkoutCaptureRetry.d.ts.map +1 -0
- package/dist/checkoutCaptureRetry.js +50 -0
- package/dist/checkoutCaptureRetry.js.map +1 -0
- package/dist/claimDriverHelpers.d.ts +15 -0
- package/dist/claimDriverHelpers.d.ts.map +1 -0
- package/dist/claimDriverHelpers.js +34 -0
- package/dist/claimDriverHelpers.js.map +1 -0
- package/dist/entity-names.d.ts +15 -0
- package/dist/entity-names.d.ts.map +1 -0
- package/dist/entity-names.js +15 -0
- package/dist/entity-names.js.map +1 -0
- package/dist/identityClaimContracts.d.ts +118 -0
- package/dist/identityClaimContracts.d.ts.map +1 -0
- package/dist/identityClaimContracts.js +58 -0
- package/dist/identityClaimContracts.js.map +1 -0
- package/dist/index.d.ts +126 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +115 -0
- package/dist/index.js.map +1 -0
- package/dist/sql-guards.d.ts +78 -0
- package/dist/sql-guards.d.ts.map +1 -0
- package/dist/sql-guards.js +115 -0
- package/dist/sql-guards.js.map +1 -0
- package/package.json +50 -5
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Reading an order and everything that hangs off it, so {@link BuildDocuments} can
|
|
3
|
+
* turn it into something you send a customer.
|
|
4
|
+
*
|
|
5
|
+
* THE SPLIT IS DELIBERATE. Every decision lives in `InvoiceBehavior` where it can be exercised with
|
|
6
|
+
* a literal; this file only fetches. That is why the module has no arithmetic beyond the joins it
|
|
7
|
+
* needs to shape the rows, and why the discount is derived over there rather than read here.
|
|
8
|
+
*
|
|
9
|
+
* IT READS AND NOTHING ELSE. There is no invoice record to write, and there must not be one — see
|
|
10
|
+
* the header of `InvoiceBehavior`. A caller can render the same order a hundred times and the
|
|
11
|
+
* hundred documents will be identical, because the order is the only state involved.
|
|
12
|
+
*
|
|
13
|
+
* THE FETCH IS FLAT, NOT PER-LINE. Charges, allocations, adjustments and payments each come back in
|
|
14
|
+
* ONE view call for the whole order and are indexed in memory. A twenty-line order should not cost
|
|
15
|
+
* eighty round trips, and the shape that produces eighty round trips is the shape that looks
|
|
16
|
+
* perfectly readable.
|
|
17
|
+
*
|
|
18
|
+
* @module @mj-biz-apps/orders-core-entities-server
|
|
19
|
+
*/
|
|
20
|
+
import { RunView } from '@memberjunction/core';
|
|
21
|
+
import { BuildDocuments, CanRender, } from './InvoiceBehavior.js';
|
|
22
|
+
import { ORDER_HEADER_ENTITY } from './entity-names.js';
|
|
23
|
+
import { RequireUUID } from './sql-guards.js';
|
|
24
|
+
import { LoadOrdersEngine, OrdersEngine, ToISODate } from '@mj-biz-apps/orders-entities';
|
|
25
|
+
const ORDER_LINE_ENTITY = 'MJ_BizApps_Orders: Order Lines';
|
|
26
|
+
const ORDER_CHARGE_ENTITY = 'MJ_BizApps_Orders: Order Charges';
|
|
27
|
+
const ORDER_CHARGE_ALLOCATION_ENTITY = 'MJ_BizApps_Orders: Order Charge Allocations';
|
|
28
|
+
const ORDER_ADJUSTMENT_ENTITY = 'MJ_BizApps_Orders: Order Adjustments';
|
|
29
|
+
const ORDER_ADJUSTMENT_ALLOCATION_ENTITY = 'MJ_BizApps_Orders: Order Adjustment Allocations';
|
|
30
|
+
const PAYMENT_LINE_ENTITY = 'MJ_BizApps_Orders: Payment Lines';
|
|
31
|
+
const PAYMENT_HEADER_ENTITY = 'MJ_BizApps_Orders: Payment Headers';
|
|
32
|
+
const CHARGE_TYPE_ENTITY = 'MJ_BizApps_Orders: Charge Types';
|
|
33
|
+
const PRODUCT_ENTITY = 'MJ_BizApps_Orders: Products';
|
|
34
|
+
const PAYMENT_TERMS_TYPE_ENTITY = 'MJ_BizApps_Orders: Payment Terms Types';
|
|
35
|
+
const ADDRESS_ENTITY = 'MJ_BizApps_Common: Addresses';
|
|
36
|
+
const ADDRESS_LINK_ENTITY = 'MJ_BizApps_Common: Address Links';
|
|
37
|
+
const COMPANY_ENTITY = 'MJ: Companies';
|
|
38
|
+
/**
|
|
39
|
+
* The selling company's accounting identity. It IS-A Company, so the row shares the company's ID —
|
|
40
|
+
* which is why the issuer block can be fetched by company ID with no join.
|
|
41
|
+
*/
|
|
42
|
+
const ACCOUNTING_COMPANY_PROFILE_ENTITY = 'MJ_BizApps_Accounting: Accounting Company Profiles';
|
|
43
|
+
/** One view call, returning rows or an empty list — never a partial result presented as complete. */
|
|
44
|
+
async function view(provider, user, entityName, extraFilter, orderBy) {
|
|
45
|
+
const result = await RunView.FromMetadataProvider(provider).RunView({ EntityName: entityName, ExtraFilter: extraFilter, OrderBy: orderBy, ResultType: 'simple' }, user);
|
|
46
|
+
if (!result.Success)
|
|
47
|
+
return { rows: [], error: `${entityName}: ${result.ErrorMessage ?? 'unknown error'}` };
|
|
48
|
+
return { rows: result.Results ?? [] };
|
|
49
|
+
}
|
|
50
|
+
const str = (v) => {
|
|
51
|
+
if (v == null)
|
|
52
|
+
return null;
|
|
53
|
+
const s = String(v).trim();
|
|
54
|
+
return s.length ? s : null;
|
|
55
|
+
};
|
|
56
|
+
const num = (v) => Number(v ?? 0);
|
|
57
|
+
/**
|
|
58
|
+
* Re-exported so this file's existing importers keep resolving it here.
|
|
59
|
+
*
|
|
60
|
+
* The implementation moved to `@mj-biz-apps/orders-entities` — it was correct in this file and
|
|
61
|
+
* unreachable from Angular, which is why fifteen other sites went on hand-rolling
|
|
62
|
+
* `String(cell).slice(0, 10)` and getting `'Thu Jul 30'`.
|
|
63
|
+
*/
|
|
64
|
+
export { ToISODate };
|
|
65
|
+
/** An SQL `IN` list of quoted UUIDs, or null when there is nothing to look up. */
|
|
66
|
+
function uuidList(ids, context) {
|
|
67
|
+
const unique = [...new Set([...ids].filter(Boolean))];
|
|
68
|
+
if (!unique.length)
|
|
69
|
+
return null;
|
|
70
|
+
return unique.map((id) => `'${RequireUUID(id, context)}'`).join(',');
|
|
71
|
+
}
|
|
72
|
+
/** Postal lines for an address, skipping the parts that are not filled in. */
|
|
73
|
+
function addressLines(row) {
|
|
74
|
+
if (!row)
|
|
75
|
+
return [];
|
|
76
|
+
const cityLine = [str(row.City), [str(row.StateProvince), str(row.PostalCode)].filter(Boolean).join(' ')]
|
|
77
|
+
.filter(Boolean)
|
|
78
|
+
.join(', ');
|
|
79
|
+
return [str(row.Line1), str(row.Line2), str(row.Line3), cityLine || null, str(row.Country)].filter(Boolean);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Read one order and produce its documents — one per selling company.
|
|
83
|
+
*
|
|
84
|
+
* @param orderHeaderID The order to render.
|
|
85
|
+
* @param options `AsOf` drives only the days-until-due countdown; `OnlyCompanyID` narrows a split
|
|
86
|
+
* order to a single document without changing how the others are numbered.
|
|
87
|
+
*/
|
|
88
|
+
export async function BuildInvoiceDocuments(orderHeaderID, provider, user, options) {
|
|
89
|
+
const id = RequireUUID(orderHeaderID, 'OrderHeaderID');
|
|
90
|
+
const asOf = options?.AsOf ? String(options.AsOf).slice(0, 10) : new Date().toISOString().slice(0, 10);
|
|
91
|
+
const header = await view(provider, user, ORDER_HEADER_ENTITY, `ID = '${id}'`);
|
|
92
|
+
if (header.error)
|
|
93
|
+
return { Success: false, Message: `Could not read the order — ${header.error}`, Documents: [] };
|
|
94
|
+
if (!header.rows.length)
|
|
95
|
+
return { Success: false, Message: `No order with ID ${id}.`, Documents: [] };
|
|
96
|
+
const order = header.rows[0];
|
|
97
|
+
const renderable = CanRender(String(order.Status));
|
|
98
|
+
if (!renderable.OK)
|
|
99
|
+
return { Success: false, Message: renderable.Reason, Documents: [] };
|
|
100
|
+
const lineResult = await view(provider, user, ORDER_LINE_ENTITY, `OrderHeaderID = '${id}'`, 'LineNumber');
|
|
101
|
+
if (lineResult.error)
|
|
102
|
+
return { Success: false, Message: `Could not read the order lines — ${lineResult.error}`, Documents: [] };
|
|
103
|
+
const lineRows = lineResult.rows;
|
|
104
|
+
const lineIDs = uuidList(lineRows.map((l) => String(l.ID)), 'OrderLineID');
|
|
105
|
+
// Everything below is fetched in parallel: none of it depends on any of the rest, and the
|
|
106
|
+
// sequential version of this function was four times the latency for no benefit.
|
|
107
|
+
const [chargeResult, adjustmentResult, paymentLineResult, productResult, termsResult, addressResult] = await Promise.all([
|
|
108
|
+
view(provider, user, ORDER_CHARGE_ENTITY, `OrderHeaderID = '${id}'`, 'Sequence'),
|
|
109
|
+
view(provider, user, ORDER_ADJUSTMENT_ENTITY, `OrderHeaderID = '${id}'`, 'Sequence'),
|
|
110
|
+
view(provider, user, PAYMENT_LINE_ENTITY, `OrderHeaderID = '${id}'`),
|
|
111
|
+
(async () => {
|
|
112
|
+
const ids = uuidList(lineRows.map((l) => l.ProductID), 'ProductID');
|
|
113
|
+
return ids ? view(provider, user, PRODUCT_ENTITY, `ID IN (${ids})`) : { rows: [] };
|
|
114
|
+
})(),
|
|
115
|
+
// Terms and charge types come from the lookup cache instead of two of the round trips this
|
|
116
|
+
// batch used to make — they are seeded reference data, and an invoice render read both.
|
|
117
|
+
LoadOrdersEngine(provider, user).then(() => ({ rows: [] })),
|
|
118
|
+
(async () => {
|
|
119
|
+
const ids = uuidList([order.BillToAddressID, order.ShipToAddressID], 'AddressID');
|
|
120
|
+
return ids ? view(provider, user, ADDRESS_ENTITY, `ID IN (${ids})`) : { rows: [] };
|
|
121
|
+
})(),
|
|
122
|
+
]);
|
|
123
|
+
const readError = [chargeResult, adjustmentResult, paymentLineResult, productResult, termsResult, addressResult]
|
|
124
|
+
.map((r) => ('error' in r ? r.error : undefined))
|
|
125
|
+
.find(Boolean);
|
|
126
|
+
if (readError)
|
|
127
|
+
return { Success: false, Message: `Could not assemble the invoice — ${readError}`, Documents: [] };
|
|
128
|
+
const chargeIDs = uuidList(chargeResult.rows.map((c) => String(c.ID)), 'OrderChargeID');
|
|
129
|
+
const adjustmentIDs = uuidList(adjustmentResult.rows.map((a) => String(a.ID)), 'OrderAdjustmentID');
|
|
130
|
+
const paymentHeaderIDs = uuidList(paymentLineResult.rows.map((p) => p.PaymentHeaderID), 'PaymentHeaderID');
|
|
131
|
+
const companyIDs = uuidList([...lineRows.map((l) => l.CompanyID), order.CompanyID], 'CompanyID');
|
|
132
|
+
const [chargeAllocResult, adjustmentAllocResult, chargeTypeResult, paymentHeaderResult, companyResult, profileResult, companyAddressResult] = await Promise.all([
|
|
133
|
+
chargeIDs && lineIDs
|
|
134
|
+
? view(provider, user, ORDER_CHARGE_ALLOCATION_ENTITY, `OrderChargeID IN (${chargeIDs})`)
|
|
135
|
+
: Promise.resolve({ rows: [] }),
|
|
136
|
+
adjustmentIDs
|
|
137
|
+
? view(provider, user, ORDER_ADJUSTMENT_ALLOCATION_ENTITY, `OrderAdjustmentID IN (${adjustmentIDs})`)
|
|
138
|
+
: Promise.resolve({ rows: [] }),
|
|
139
|
+
Promise.resolve({ rows: [] }), // charge types come from the lookup cache
|
|
140
|
+
paymentHeaderIDs
|
|
141
|
+
? view(provider, user, PAYMENT_HEADER_ENTITY, `ID IN (${paymentHeaderIDs})`)
|
|
142
|
+
: Promise.resolve({ rows: [] }),
|
|
143
|
+
companyIDs ? view(provider, user, COMPANY_ENTITY, `ID IN (${companyIDs})`) : Promise.resolve({ rows: [] }),
|
|
144
|
+
// IS-A: the profile shares the company's ID, so this is a lookup and not a join. A company
|
|
145
|
+
// with no accounting profile still issues an invoice — it just has no tax line to print.
|
|
146
|
+
companyIDs
|
|
147
|
+
? view(provider, user, ACCOUNTING_COMPANY_PROFILE_ENTITY, `ID IN (${companyIDs})`)
|
|
148
|
+
: Promise.resolve({ rows: [] }),
|
|
149
|
+
(async () => {
|
|
150
|
+
const companyEntityID = provider.Entities?.find((e) => e.Name === COMPANY_ENTITY)?.ID;
|
|
151
|
+
if (!companyEntityID || !companyIDs)
|
|
152
|
+
return { rows: [] };
|
|
153
|
+
return view(provider, user, ADDRESS_LINK_ENTITY, `EntityID = '${RequireUUID(companyEntityID, 'Company entity ID')}' AND RecordID IN (${companyIDs})`, 'IsPrimary DESC, Rank');
|
|
154
|
+
})(),
|
|
155
|
+
]);
|
|
156
|
+
const secondError = [chargeAllocResult, adjustmentAllocResult, chargeTypeResult, paymentHeaderResult, companyResult, profileResult, companyAddressResult]
|
|
157
|
+
.map((r) => ('error' in r ? r.error : undefined))
|
|
158
|
+
.find(Boolean);
|
|
159
|
+
if (secondError)
|
|
160
|
+
return { Success: false, Message: `Could not assemble the invoice — ${secondError}`, Documents: [] };
|
|
161
|
+
// The issuer addresses need a third trip because they are only knowable once the links are read.
|
|
162
|
+
// It is skipped entirely when no company has an address on file, which is the common case until
|
|
163
|
+
// somebody sets one up — an invoice with no remit-to address is worse-looking than one with, and
|
|
164
|
+
// is still a correct invoice.
|
|
165
|
+
const issuerAddressIDs = uuidList(companyAddressResult.rows.map((l) => l.AddressID), 'AddressID');
|
|
166
|
+
const issuerAddressResult = issuerAddressIDs
|
|
167
|
+
? await view(provider, user, ADDRESS_ENTITY, `ID IN (${issuerAddressIDs})`)
|
|
168
|
+
: { rows: [] };
|
|
169
|
+
// ── Index everything once ────────────────────────────────────────────────────────────────────
|
|
170
|
+
const productByID = new Map(productResult.rows.map((p) => [String(p.ID), p]));
|
|
171
|
+
const engine = OrdersEngine.Instance;
|
|
172
|
+
const paymentHeaderByID = new Map(paymentHeaderResult.rows.map((p) => [String(p.ID), p]));
|
|
173
|
+
const addressByID = new Map(addressResult.rows.map((a) => [String(a.ID), a]));
|
|
174
|
+
const companyNames = new Map(companyResult.rows.map((c) => [String(c.ID), String(c.Name ?? '')]));
|
|
175
|
+
const issuerAddressByID = new Map(issuerAddressResult.rows.map((a) => [String(a.ID), a]));
|
|
176
|
+
// First link wins — the query is ordered primary-first, so a company with several addresses
|
|
177
|
+
// prints the one somebody marked as the main office rather than whichever came back first.
|
|
178
|
+
const issuerAddressByCompany = new Map();
|
|
179
|
+
for (const link of companyAddressResult.rows) {
|
|
180
|
+
const companyID = String(link.RecordID ?? '');
|
|
181
|
+
if (issuerAddressByCompany.has(companyID))
|
|
182
|
+
continue;
|
|
183
|
+
const address = issuerAddressByID.get(String(link.AddressID));
|
|
184
|
+
if (address)
|
|
185
|
+
issuerAddressByCompany.set(companyID, address);
|
|
186
|
+
}
|
|
187
|
+
const profileByID = new Map(profileResult.rows.map((p) => [String(p.ID), p]));
|
|
188
|
+
const issuers = new Map(companyResult.rows.map((c) => {
|
|
189
|
+
const companyID = String(c.ID);
|
|
190
|
+
const profile = profileByID.get(companyID);
|
|
191
|
+
return [
|
|
192
|
+
companyID,
|
|
193
|
+
{
|
|
194
|
+
CompanyID: companyID,
|
|
195
|
+
Name: String(c.Name ?? ''),
|
|
196
|
+
AddressLines: addressLines(issuerAddressByCompany.get(companyID)),
|
|
197
|
+
Email: null,
|
|
198
|
+
Phone: null,
|
|
199
|
+
Website: str(c.Website),
|
|
200
|
+
TaxID: str(profile?.FederalTaxID),
|
|
201
|
+
CurrencyCode: str(profile?.FunctionalCurrencyCode),
|
|
202
|
+
},
|
|
203
|
+
];
|
|
204
|
+
}));
|
|
205
|
+
const allocationsByCharge = new Map();
|
|
206
|
+
for (const alloc of chargeAllocResult.rows) {
|
|
207
|
+
const key = String(alloc.OrderChargeID);
|
|
208
|
+
const bucket = allocationsByCharge.get(key) ?? [];
|
|
209
|
+
bucket.push({ OrderLineID: String(alloc.OrderLineID), Amount: num(alloc.Amount) });
|
|
210
|
+
allocationsByCharge.set(key, bucket);
|
|
211
|
+
}
|
|
212
|
+
const allocationsByAdjustment = new Map();
|
|
213
|
+
for (const alloc of adjustmentAllocResult.rows) {
|
|
214
|
+
const key = String(alloc.OrderAdjustmentID);
|
|
215
|
+
const bucket = allocationsByAdjustment.get(key) ?? [];
|
|
216
|
+
bucket.push({ OrderLineID: String(alloc.OrderLineID), Amount: num(alloc.Amount) });
|
|
217
|
+
allocationsByAdjustment.set(key, bucket);
|
|
218
|
+
}
|
|
219
|
+
// ── Shape the facts ──────────────────────────────────────────────────────────────────────────
|
|
220
|
+
const terms = engine.PaymentTermsTypeByID(order.PaymentTermsTypeID);
|
|
221
|
+
const orderFacts = {
|
|
222
|
+
ID: String(order.ID),
|
|
223
|
+
OrderNumber: String(order.OrderNumber ?? ''),
|
|
224
|
+
OrderType: str(order.OrderType),
|
|
225
|
+
OrderDate: ToISODate(order.OrderDate) ?? asOf,
|
|
226
|
+
Status: String(order.Status ?? ''),
|
|
227
|
+
CompanyID: String(order.CompanyID ?? ''),
|
|
228
|
+
CompanyName: str(order.Company) ?? '',
|
|
229
|
+
TotalGross: num(order.TotalGross),
|
|
230
|
+
AmountPaid: num(order.AmountPaid),
|
|
231
|
+
Balance: num(order.Balance),
|
|
232
|
+
DueDate: ToISODate(order.DueDate),
|
|
233
|
+
PaymentStatus: str(order.PaymentStatus),
|
|
234
|
+
ExternalDocumentNumber: str(order.ExternalDocumentNumber),
|
|
235
|
+
ReversesOrderHeaderID: str(order.ReversesOrderHeaderID),
|
|
236
|
+
ReversesOrderNumber: str(order.ReversesOrderHeader),
|
|
237
|
+
ReversalReason: str(order.ReversalReason),
|
|
238
|
+
Description: str(order.Description),
|
|
239
|
+
PaymentTermsName: str(order.PaymentTermsType),
|
|
240
|
+
PaymentTermsNetDays: terms?.NetDays != null ? Number(terms.NetDays) : null,
|
|
241
|
+
};
|
|
242
|
+
const lines = lineRows.map((l) => {
|
|
243
|
+
const product = l.ProductID ? productByID.get(String(l.ProductID)) : undefined;
|
|
244
|
+
return {
|
|
245
|
+
ID: String(l.ID),
|
|
246
|
+
LineNumber: Number(l.LineNumber ?? 0),
|
|
247
|
+
ProductID: str(l.ProductID),
|
|
248
|
+
// The line's own description wins over the product name: it is what somebody typed for
|
|
249
|
+
// THIS sale, and on a bill the customer's words beat the catalogue's.
|
|
250
|
+
ProductName: str(l.Product) ?? str(product?.Name) ?? 'Item',
|
|
251
|
+
ProductSKU: str(product?.SKU),
|
|
252
|
+
Description: str(l.Description),
|
|
253
|
+
CompanyID: String(l.CompanyID ?? orderFacts.CompanyID),
|
|
254
|
+
CompanyName: str(l.Company) ?? '',
|
|
255
|
+
Quantity: num(l.Quantity),
|
|
256
|
+
UnitPrice: num(l.UnitPrice),
|
|
257
|
+
DiscountAmount: num(l.DiscountAmount),
|
|
258
|
+
LineTotalNet: num(l.LineTotalNet),
|
|
259
|
+
ChargeAmount: num(l.ChargeAmount),
|
|
260
|
+
LineTax: num(l.LineTax),
|
|
261
|
+
LineTotalGross: num(l.LineTotalGross),
|
|
262
|
+
ServicePeriodStart: ToISODate(l.ServicePeriodStart),
|
|
263
|
+
ServicePeriodEnd: ToISODate(l.ServicePeriodEnd),
|
|
264
|
+
ParentOrderLineID: str(l.ParentOrderLineID),
|
|
265
|
+
IsRollupParent: l.IsRollupParent === true || l.IsRollupParent === 1,
|
|
266
|
+
ReversesOrderLineID: str(l.ReversesOrderLineID),
|
|
267
|
+
};
|
|
268
|
+
});
|
|
269
|
+
const charges = chargeResult.rows.map((c) => {
|
|
270
|
+
const type = engine.ChargeTypeByID(c.ChargeTypeID);
|
|
271
|
+
return {
|
|
272
|
+
ID: String(c.ID),
|
|
273
|
+
Name: str(c.ChargeType) ?? str(type?.Name) ?? 'Charge',
|
|
274
|
+
Category: str(type?.Category) ?? 'Surcharge',
|
|
275
|
+
Amount: num(c.Amount),
|
|
276
|
+
Rate: c.Rate == null ? null : Number(c.Rate),
|
|
277
|
+
Sequence: Number(c.Sequence ?? 0),
|
|
278
|
+
Allocations: allocationsByCharge.get(String(c.ID)) ?? [],
|
|
279
|
+
};
|
|
280
|
+
});
|
|
281
|
+
const adjustments = adjustmentResult.rows.map((a) => ({
|
|
282
|
+
ID: String(a.ID),
|
|
283
|
+
OrderLineID: str(a.OrderLineID),
|
|
284
|
+
PromotionName: str(a.Promotion),
|
|
285
|
+
PromotionCode: str(a.PromotionCode),
|
|
286
|
+
Reason: str(a.Reason),
|
|
287
|
+
Amount: num(a.Amount),
|
|
288
|
+
Allocations: allocationsByAdjustment.get(String(a.ID)) ?? [],
|
|
289
|
+
}));
|
|
290
|
+
// Payment lines are grouped into one entry per payment: a cheque split across six order lines is
|
|
291
|
+
// ONE payment on the document, not six.
|
|
292
|
+
const paymentsByHeader = new Map();
|
|
293
|
+
for (const pl of paymentLineResult.rows) {
|
|
294
|
+
const headerID = String(pl.PaymentHeaderID);
|
|
295
|
+
const paymentHeader = paymentHeaderByID.get(headerID);
|
|
296
|
+
const existing = paymentsByHeader.get(headerID) ?? {
|
|
297
|
+
PaymentHeaderID: headerID,
|
|
298
|
+
PaymentNumber: str(paymentHeader?.PaymentNumber) ?? str(pl.PaymentHeader) ?? '—',
|
|
299
|
+
PaymentDate: ToISODate(paymentHeader?.PaymentDate) ?? asOf,
|
|
300
|
+
PaymentTypeName: str(paymentHeader?.PaymentType),
|
|
301
|
+
Amount: 0,
|
|
302
|
+
Allocations: [],
|
|
303
|
+
};
|
|
304
|
+
existing.Amount = Math.round((existing.Amount + num(pl.Amount) + Number.EPSILON) * 100) / 100;
|
|
305
|
+
existing.Allocations.push({ OrderLineID: str(pl.OrderLineID), Amount: num(pl.Amount) });
|
|
306
|
+
paymentsByHeader.set(headerID, existing);
|
|
307
|
+
}
|
|
308
|
+
// A reversed payment is not money the customer still has credit for. It is excluded here rather
|
|
309
|
+
// than netted, so a refunded order shows the original balance again instead of a phantom credit.
|
|
310
|
+
const payments = [...paymentsByHeader.values()].filter((p) => {
|
|
311
|
+
const status = str(paymentHeaderByID.get(p.PaymentHeaderID)?.Status);
|
|
312
|
+
return status !== 'Reversed' && status !== 'Failed' && status !== 'Voided';
|
|
313
|
+
});
|
|
314
|
+
const billToAddress = order.BillToAddressID ? addressByID.get(String(order.BillToAddressID)) : undefined;
|
|
315
|
+
const shipToAddress = order.ShipToAddressID ? addressByID.get(String(order.ShipToAddressID)) : undefined;
|
|
316
|
+
const billTo = {
|
|
317
|
+
Name: str(order.BillToOrganization) ?? str(order.BillToPerson),
|
|
318
|
+
AttentionOf: str(order.BillToOrganization) ? str(order.BillToPerson) : null,
|
|
319
|
+
AddressLines: addressLines(billToAddress),
|
|
320
|
+
Email: null,
|
|
321
|
+
};
|
|
322
|
+
const shipTo = order.ShipToAddressID && String(order.ShipToAddressID) !== String(order.BillToAddressID ?? '')
|
|
323
|
+
? {
|
|
324
|
+
Name: str(order.ShipToOrganization) ?? str(order.ShipToPerson) ?? billTo.Name,
|
|
325
|
+
AttentionOf: null,
|
|
326
|
+
AddressLines: addressLines(shipToAddress),
|
|
327
|
+
Email: null,
|
|
328
|
+
}
|
|
329
|
+
: null;
|
|
330
|
+
const documents = BuildDocuments({
|
|
331
|
+
Order: orderFacts,
|
|
332
|
+
Lines: lines,
|
|
333
|
+
Charges: charges,
|
|
334
|
+
Adjustments: adjustments,
|
|
335
|
+
Payments: payments,
|
|
336
|
+
BillTo: billTo,
|
|
337
|
+
ShipTo: shipTo,
|
|
338
|
+
CompanyNames: companyNames,
|
|
339
|
+
Issuers: issuers,
|
|
340
|
+
AsOf: asOf,
|
|
341
|
+
OnlyCompanyID: options?.OnlyCompanyID ?? null,
|
|
342
|
+
});
|
|
343
|
+
if (options?.OnlyCompanyID && !documents.length) {
|
|
344
|
+
return {
|
|
345
|
+
Success: false,
|
|
346
|
+
Message: `Order ${orderFacts.OrderNumber} has no lines sold by company ${options.OnlyCompanyID}.`,
|
|
347
|
+
Documents: [],
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
return { Success: true, Documents: documents };
|
|
351
|
+
}
|
|
352
|
+
//# sourceMappingURL=InvoiceBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvoiceBuilder.js","sourceRoot":"","sources":["../src/InvoiceBuilder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Turning the numbers on an invoice into the strings that print on it.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS IS NOT IN THE TEMPLATE. The template language has no money formatting — Nunjucks gives
|
|
5
|
+
* you `round(2)`, which renders eleven hundred dollars as `1100` and, worse, renders a hundred and
|
|
6
|
+
* ten dollars exactly as `110` where the missing `.00` reads as a rounding error to anyone checking
|
|
7
|
+
* the column. Grouping separators, the currency symbol's position and the negative convention are
|
|
8
|
+
* locale decisions, not styling decisions, so they are made here where they can be tested and the
|
|
9
|
+
* template just prints `{{ row.AmountText }}`.
|
|
10
|
+
*
|
|
11
|
+
* WHY IT IS NOT IN THE BUILDER EITHER. Everything here is a pure function of a document plus a
|
|
12
|
+
* locale. Keeping it separate is what lets the same document render as US dollars for the customer
|
|
13
|
+
* and as raw numbers for a reconciliation check, without a second trip to the database.
|
|
14
|
+
*
|
|
15
|
+
* NEGATIVES ARE PARENTHESISED, NOT PREFIXED. `-1,200.00` and `1,200.00` differ by one character at
|
|
16
|
+
* the far left of a right-aligned column, which is exactly where the eye is not. `(1,200.00)` is the
|
|
17
|
+
* convention every accounts-payable clerk already reads, and it is unmistakable at a glance.
|
|
18
|
+
*
|
|
19
|
+
* @module @mj-biz-apps/orders-core-entities-server
|
|
20
|
+
*/
|
|
21
|
+
import type { InvoiceDocument, InvoiceRow, LadderRow } from './InvoiceBehavior.js';
|
|
22
|
+
/** How to render the numbers. The app is single-currency today; this is the seam for when it is not. */
|
|
23
|
+
export interface DisplayOptions {
|
|
24
|
+
/** BCP 47 tag. Drives grouping separators and date order. */
|
|
25
|
+
Locale?: string;
|
|
26
|
+
/** ISO 4217 code. */
|
|
27
|
+
Currency?: string;
|
|
28
|
+
}
|
|
29
|
+
/** A row as it prints: every number carries the string beside it. */
|
|
30
|
+
export interface DisplayRow extends InvoiceRow {
|
|
31
|
+
QuantityText: string;
|
|
32
|
+
UnitPriceText: string;
|
|
33
|
+
DiscountText: string;
|
|
34
|
+
AmountText: string;
|
|
35
|
+
ServicePeriodText: string | null;
|
|
36
|
+
Children: DisplayRow[];
|
|
37
|
+
}
|
|
38
|
+
/** A ladder row as it prints. */
|
|
39
|
+
export interface DisplayLadderRow extends LadderRow {
|
|
40
|
+
AmountText: string;
|
|
41
|
+
}
|
|
42
|
+
/** The whole document, ready for a template that does no arithmetic of its own. */
|
|
43
|
+
export interface DisplayInvoice extends Omit<InvoiceDocument, 'Rows' | 'Ladder' | 'Payments'> {
|
|
44
|
+
Rows: DisplayRow[];
|
|
45
|
+
Ladder: DisplayLadderRow[];
|
|
46
|
+
Payments: Array<InvoiceDocument['Payments'][number] & {
|
|
47
|
+
AmountText: string;
|
|
48
|
+
PaymentDateText: string;
|
|
49
|
+
}>;
|
|
50
|
+
OrderDateText: string;
|
|
51
|
+
DueDateText: string | null;
|
|
52
|
+
/** `Due in 22 days`, `Due today`, `21 days overdue` — or null when nothing is owed. */
|
|
53
|
+
DuePhrase: string | null;
|
|
54
|
+
ListSubtotalText: string;
|
|
55
|
+
DiscountTotalText: string;
|
|
56
|
+
NetTotalText: string;
|
|
57
|
+
ChargeTotalText: string;
|
|
58
|
+
TaxTotalText: string;
|
|
59
|
+
GrossText: string;
|
|
60
|
+
AmountPaidText: string;
|
|
61
|
+
AmountDueText: string;
|
|
62
|
+
/** `Amount due` / `Credit due you` — the label the ladder ends on, repeated for the big figure. */
|
|
63
|
+
DueLabel: string;
|
|
64
|
+
/** True when the document is settled, so the renderer can stamp it. */
|
|
65
|
+
IsSettled: boolean;
|
|
66
|
+
/** True when there is a real overdue balance — never true for a quote or a credit. */
|
|
67
|
+
IsOverdue: boolean;
|
|
68
|
+
CurrencyCode: string;
|
|
69
|
+
/** The date the document was produced, for the footer. */
|
|
70
|
+
GeneratedOnText: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Format an amount, parenthesising negatives.
|
|
74
|
+
*
|
|
75
|
+
* THE NUMBER OF DECIMALS IS THE CURRENCY'S, not a constant. Dollars and euros carry two; yen and
|
|
76
|
+
* won carry none, and a bill for `¥12,000.00` tells a Japanese customer they are being charged in
|
|
77
|
+
* some unit that is not yen. Forcing two digits is the kind of hardcoding that is invisible until
|
|
78
|
+
* the first order in a currency nobody tested with.
|
|
79
|
+
*/
|
|
80
|
+
export declare function FormatMoney(amount: number, options?: DisplayOptions): string;
|
|
81
|
+
/**
|
|
82
|
+
* Format a quantity, dropping a trailing `.00` but keeping real fractions.
|
|
83
|
+
*
|
|
84
|
+
* `3` for three of something and `2.5` for two and a half hours — printing `3.00` on a line of
|
|
85
|
+
* widgets invites the reader to look for a decimal that is not there.
|
|
86
|
+
*/
|
|
87
|
+
export declare function FormatQuantity(quantity: number, options?: DisplayOptions): string;
|
|
88
|
+
/** Format an ISO date without letting the local timezone move it a day. */
|
|
89
|
+
export declare function FormatDate(isoDate: string | null, options?: DisplayOptions): string | null;
|
|
90
|
+
/** `Due in 22 days` / `Due today` / `21 days overdue`. Null when nothing is owed. */
|
|
91
|
+
export declare function DuePhrase(daysUntilDue: number | null): string | null;
|
|
92
|
+
/** Decorate a document for printing. Pure: same document and locale in, same strings out. */
|
|
93
|
+
export declare function DecorateInvoice(doc: InvoiceDocument, options?: DisplayOptions & {
|
|
94
|
+
GeneratedOn?: string;
|
|
95
|
+
}): DisplayInvoice;
|
|
96
|
+
//# sourceMappingURL=InvoiceDisplay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvoiceDisplay.d.ts","sourceRoot":"","sources":["../src/InvoiceDisplay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEnF,wGAAwG;AACxG,MAAM,WAAW,cAAc;IAC3B,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAID,qEAAqE;AACrE,MAAM,WAAW,UAAW,SAAQ,UAAU;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,UAAU,EAAE,CAAC;CAC1B;AAED,iCAAiC;AACjC,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IAC/C,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,mFAAmF;AACnF,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;IACzF,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,QAAQ,EAAE,KAAK,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,GAAG;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAEvG,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,uFAAuF;IACvF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,mGAAmG;IACnG,QAAQ,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,SAAS,EAAE,OAAO,CAAC;IACnB,sFAAsF;IACtF,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAK5E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAKjF;AAED,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAQ1F;AAED,qFAAqF;AACrF,wBAAgB,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAMpE;AAoBD,6FAA6F;AAC7F,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAoCzH"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Turning the numbers on an invoice into the strings that print on it.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS IS NOT IN THE TEMPLATE. The template language has no money formatting — Nunjucks gives
|
|
5
|
+
* you `round(2)`, which renders eleven hundred dollars as `1100` and, worse, renders a hundred and
|
|
6
|
+
* ten dollars exactly as `110` where the missing `.00` reads as a rounding error to anyone checking
|
|
7
|
+
* the column. Grouping separators, the currency symbol's position and the negative convention are
|
|
8
|
+
* locale decisions, not styling decisions, so they are made here where they can be tested and the
|
|
9
|
+
* template just prints `{{ row.AmountText }}`.
|
|
10
|
+
*
|
|
11
|
+
* WHY IT IS NOT IN THE BUILDER EITHER. Everything here is a pure function of a document plus a
|
|
12
|
+
* locale. Keeping it separate is what lets the same document render as US dollars for the customer
|
|
13
|
+
* and as raw numbers for a reconciliation check, without a second trip to the database.
|
|
14
|
+
*
|
|
15
|
+
* NEGATIVES ARE PARENTHESISED, NOT PREFIXED. `-1,200.00` and `1,200.00` differ by one character at
|
|
16
|
+
* the far left of a right-aligned column, which is exactly where the eye is not. `(1,200.00)` is the
|
|
17
|
+
* convention every accounts-payable clerk already reads, and it is unmistakable at a glance.
|
|
18
|
+
*
|
|
19
|
+
* @module @mj-biz-apps/orders-core-entities-server
|
|
20
|
+
*/
|
|
21
|
+
const DEFAULTS = { Locale: 'en-US', Currency: 'USD' };
|
|
22
|
+
/**
|
|
23
|
+
* Format an amount, parenthesising negatives.
|
|
24
|
+
*
|
|
25
|
+
* THE NUMBER OF DECIMALS IS THE CURRENCY'S, not a constant. Dollars and euros carry two; yen and
|
|
26
|
+
* won carry none, and a bill for `¥12,000.00` tells a Japanese customer they are being charged in
|
|
27
|
+
* some unit that is not yen. Forcing two digits is the kind of hardcoding that is invisible until
|
|
28
|
+
* the first order in a currency nobody tested with.
|
|
29
|
+
*/
|
|
30
|
+
export function FormatMoney(amount, options) {
|
|
31
|
+
const { Locale, Currency } = { ...DEFAULTS, ...options };
|
|
32
|
+
const value = Math.abs(Number(amount) || 0);
|
|
33
|
+
const text = new Intl.NumberFormat(Locale, { style: 'currency', currency: Currency }).format(value);
|
|
34
|
+
return Number(amount) < 0 ? `(${text})` : text;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Format a quantity, dropping a trailing `.00` but keeping real fractions.
|
|
38
|
+
*
|
|
39
|
+
* `3` for three of something and `2.5` for two and a half hours — printing `3.00` on a line of
|
|
40
|
+
* widgets invites the reader to look for a decimal that is not there.
|
|
41
|
+
*/
|
|
42
|
+
export function FormatQuantity(quantity, options) {
|
|
43
|
+
const { Locale } = { ...DEFAULTS, ...options };
|
|
44
|
+
const value = Number(quantity) || 0;
|
|
45
|
+
const decimals = Number.isInteger(value) ? 0 : Math.min(4, (String(value).split('.')[1] ?? '').length);
|
|
46
|
+
return new Intl.NumberFormat(Locale, { minimumFractionDigits: decimals, maximumFractionDigits: decimals }).format(value);
|
|
47
|
+
}
|
|
48
|
+
/** Format an ISO date without letting the local timezone move it a day. */
|
|
49
|
+
export function FormatDate(isoDate, options) {
|
|
50
|
+
if (!isoDate)
|
|
51
|
+
return null;
|
|
52
|
+
const [y, m, d] = String(isoDate).slice(0, 10).split('-').map(Number);
|
|
53
|
+
if (!y || !m || !d)
|
|
54
|
+
return null;
|
|
55
|
+
const { Locale } = { ...DEFAULTS, ...options };
|
|
56
|
+
return new Intl.DateTimeFormat(Locale, { year: 'numeric', month: 'short', day: 'numeric', timeZone: 'UTC' }).format(new Date(Date.UTC(y, m - 1, d)));
|
|
57
|
+
}
|
|
58
|
+
/** `Due in 22 days` / `Due today` / `21 days overdue`. Null when nothing is owed. */
|
|
59
|
+
export function DuePhrase(daysUntilDue) {
|
|
60
|
+
if (daysUntilDue == null)
|
|
61
|
+
return null;
|
|
62
|
+
if (daysUntilDue === 0)
|
|
63
|
+
return 'Due today';
|
|
64
|
+
if (daysUntilDue > 0)
|
|
65
|
+
return `Due in ${daysUntilDue} day${daysUntilDue === 1 ? '' : 's'}`;
|
|
66
|
+
const overdue = Math.abs(daysUntilDue);
|
|
67
|
+
return `${overdue} day${overdue === 1 ? '' : 's'} overdue`;
|
|
68
|
+
}
|
|
69
|
+
function decorateRow(row, options) {
|
|
70
|
+
const period = row.ServicePeriodStart || row.ServicePeriodEnd
|
|
71
|
+
? `${FormatDate(row.ServicePeriodStart, options) ?? '—'} – ${FormatDate(row.ServicePeriodEnd, options) ?? '—'}`
|
|
72
|
+
: null;
|
|
73
|
+
return {
|
|
74
|
+
...row,
|
|
75
|
+
QuantityText: FormatQuantity(row.Quantity, options),
|
|
76
|
+
UnitPriceText: FormatMoney(row.UnitPrice, options),
|
|
77
|
+
// A line with no discount prints an em dash, not a zero: a column of `$0.00` down the page
|
|
78
|
+
// reads as money and pulls the eye away from the ones that are real.
|
|
79
|
+
DiscountText: row.DiscountAmount === 0 ? '—' : `−${FormatMoney(Math.abs(row.DiscountAmount), options)}`,
|
|
80
|
+
AmountText: row.IncludedInParent ? 'included' : FormatMoney(row.Amount, options),
|
|
81
|
+
ServicePeriodText: period,
|
|
82
|
+
Children: row.Children.map((c) => decorateRow(c, options)),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** Decorate a document for printing. Pure: same document and locale in, same strings out. */
|
|
86
|
+
export function DecorateInvoice(doc, options) {
|
|
87
|
+
const opts = { ...DEFAULTS, ...options };
|
|
88
|
+
const generatedOn = options?.GeneratedOn ?? new Date().toISOString().slice(0, 10);
|
|
89
|
+
const dueLabel = doc.Kind === 'Credit Memo' ? 'Credit due you' : doc.Kind === 'Quote' ? 'Quote total' : 'Amount due';
|
|
90
|
+
return {
|
|
91
|
+
...doc,
|
|
92
|
+
Rows: doc.Rows.map((r) => decorateRow(r, opts)),
|
|
93
|
+
Ladder: doc.Ladder.map((r) => ({ ...r, AmountText: FormatMoney(r.Amount, opts) })),
|
|
94
|
+
Payments: doc.Payments.map((p) => ({
|
|
95
|
+
...p,
|
|
96
|
+
AmountText: FormatMoney(p.Amount, opts),
|
|
97
|
+
PaymentDateText: FormatDate(p.PaymentDate, opts) ?? p.PaymentDate,
|
|
98
|
+
})),
|
|
99
|
+
OrderDateText: FormatDate(doc.OrderDate, opts) ?? doc.OrderDate,
|
|
100
|
+
DueDateText: FormatDate(doc.DueDate, opts),
|
|
101
|
+
DuePhrase: DuePhrase(doc.DaysUntilDue),
|
|
102
|
+
ListSubtotalText: FormatMoney(doc.ListSubtotal, opts),
|
|
103
|
+
DiscountTotalText: FormatMoney(doc.DiscountTotal, opts),
|
|
104
|
+
NetTotalText: FormatMoney(doc.NetTotal, opts),
|
|
105
|
+
ChargeTotalText: FormatMoney(doc.ChargeTotal, opts),
|
|
106
|
+
TaxTotalText: FormatMoney(doc.TaxTotal, opts),
|
|
107
|
+
GrossText: FormatMoney(doc.Gross, opts),
|
|
108
|
+
AmountPaidText: FormatMoney(doc.AmountPaid, opts),
|
|
109
|
+
// The headline figure is a magnitude — a credit memo says "Credit due you $310.72", not
|
|
110
|
+
// "$-310.72", because the label already carries the direction.
|
|
111
|
+
AmountDueText: FormatMoney(Math.abs(doc.AmountDue), opts),
|
|
112
|
+
DueLabel: dueLabel,
|
|
113
|
+
// A quote is never settled and never overdue, however its arithmetic comes out: nobody has
|
|
114
|
+
// been asked for the money yet.
|
|
115
|
+
IsSettled: doc.Kind === 'Invoice' && doc.Gross > 0 && doc.AmountDue <= 0,
|
|
116
|
+
IsOverdue: doc.Kind === 'Invoice' && doc.AmountDue > 0 && doc.DaysUntilDue != null && doc.DaysUntilDue < 0,
|
|
117
|
+
CurrencyCode: opts.Currency,
|
|
118
|
+
GeneratedOnText: FormatDate(generatedOn, opts) ?? generatedOn,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=InvoiceDisplay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvoiceDisplay.js","sourceRoot":"","sources":["../src/InvoiceDisplay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAYH,MAAM,QAAQ,GAA6B,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AA8ChF;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,OAAwB;IAChE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;IACzD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACpG,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,OAAwB;IACrE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;IAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACvG,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,qBAAqB,EAAE,QAAQ,EAAE,qBAAqB,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7H,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,UAAU,CAAC,OAAsB,EAAE,OAAwB;IACvE,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACtE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;IAC/C,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAC/G,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAClC,CAAC;AACN,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,SAAS,CAAC,YAA2B;IACjD,IAAI,YAAY,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,YAAY,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IAC3C,IAAI,YAAY,GAAG,CAAC;QAAE,OAAO,UAAU,YAAY,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAC1F,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACvC,OAAO,GAAG,OAAO,OAAO,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC;AAC/D,CAAC;AAED,SAAS,WAAW,CAAC,GAAe,EAAE,OAAuB;IACzD,MAAM,MAAM,GACR,GAAG,CAAC,kBAAkB,IAAI,GAAG,CAAC,gBAAgB;QAC1C,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,kBAAkB,EAAE,OAAO,CAAC,IAAI,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,gBAAgB,EAAE,OAAO,CAAC,IAAI,GAAG,EAAE;QAC/G,CAAC,CAAC,IAAI,CAAC;IACf,OAAO;QACH,GAAG,GAAG;QACN,YAAY,EAAE,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC;QACnD,aAAa,EAAE,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC;QAClD,2FAA2F;QAC3F,qEAAqE;QACrE,YAAY,EAAE,GAAG,CAAC,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,EAAE;QACvG,UAAU,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;QAChF,iBAAiB,EAAE,MAAM;QACzB,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;KAC7D,CAAC;AACN,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,eAAe,CAAC,GAAoB,EAAE,OAAmD;IACrG,MAAM,IAAI,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;IACzC,MAAM,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClF,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC;IAErH,OAAO;QACH,GAAG,GAAG;QACN,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAC/C,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAClF,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/B,GAAG,CAAC;YACJ,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC;YACvC,eAAe,EAAE,UAAU,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW;SACpE,CAAC,CAAC;QAEH,aAAa,EAAE,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS;QAC/D,WAAW,EAAE,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC;QAC1C,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC;QACtC,gBAAgB,EAAE,WAAW,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC;QACrD,iBAAiB,EAAE,WAAW,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC;QACvD,YAAY,EAAE,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;QAC7C,eAAe,EAAE,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC;QACnD,YAAY,EAAE,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;QAC7C,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC;QACvC,cAAc,EAAE,WAAW,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC;QACjD,wFAAwF;QACxF,+DAA+D;QAC/D,aAAa,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC;QACzD,QAAQ,EAAE,QAAQ;QAClB,2FAA2F;QAC3F,gCAAgC;QAChC,SAAS,EAAE,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC;QACxE,SAAS,EAAE,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,SAAS,GAAG,CAAC,IAAI,GAAG,CAAC,YAAY,IAAI,IAAI,IAAI,GAAG,CAAC,YAAY,GAAG,CAAC;QAC1G,YAAY,EAAE,IAAI,CAAC,QAAQ;QAC3B,eAAe,EAAE,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,WAAW;KAChE,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orders.ListEntitlements — this person's entitlement library, without N point checks.
|
|
3
|
+
*
|
|
4
|
+
* An optimisation for UI and sync, not a second source of truth. Each row is evaluated
|
|
5
|
+
* the same way `Orders.CheckEntitlement` evaluates one Code. Heavier scope than the
|
|
6
|
+
* point check (`orders:entitlement-read`) so a library key cannot become an authorization
|
|
7
|
+
* oracle for arbitrary people × codes.
|
|
8
|
+
*
|
|
9
|
+
* CONNECTS TO:
|
|
10
|
+
* LOAD: ./EntitlementRead.ts
|
|
11
|
+
* DOC: plans/entitlement-read-contract.md
|
|
12
|
+
*/
|
|
13
|
+
import { BaseRemotableOperation, type IMetadataProvider, type UserInfo } from '@memberjunction/core';
|
|
14
|
+
import { type ListEntitlementsInput, type ListEntitlementsOutput } from './EntitlementRead.js';
|
|
15
|
+
export declare class ListEntitlementsOperation extends BaseRemotableOperation<ListEntitlementsInput, ListEntitlementsOutput> {
|
|
16
|
+
OperationKey: string;
|
|
17
|
+
protected InternalExecute(input: ListEntitlementsInput, provider: IMetadataProvider, user: UserInfo): Promise<ListEntitlementsOutput>;
|
|
18
|
+
}
|
|
19
|
+
/** Tree-shaking anchor — called from the server bootstrap so the registration is retained. */
|
|
20
|
+
export declare function LoadListEntitlementsOperation(): void;
|
|
21
|
+
//# sourceMappingURL=ListEntitlementsOperation.d.ts.map
|