@aglyn/plugins-commerce 1.0.0-beta.218 → 1.0.0-beta.220
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/README.md +6 -0
- package/package.json +14 -14
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -19
- package/src/index.js.map +1 -1
- package/src/lib/components/cart.js +2 -1
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/console/catalog-organization-card.component.js +665 -459
- package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
- package/src/lib/components/console/host-orders-card.component.js +2 -1
- package/src/lib/components/console/host-orders-card.component.js.map +1 -1
- package/src/lib/components/console/member-posts-card.component.js +1 -1
- package/src/lib/components/console/member-posts-card.component.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +8 -7
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/payments-settings-card.component.js +2 -2
- package/src/lib/components/console/payments-settings-card.component.js.map +1 -1
- package/src/lib/components/console/product-editor-dialog.component.js +1221 -889
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/product-zones.d.ts +184 -0
- package/src/lib/components/console/product-zones.js +54 -0
- package/src/lib/components/console/product-zones.js.map +1 -0
- package/src/lib/components/console/products-hub-card.component.js +3 -2
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/products-hub-zone.component.d.ts +1 -1
- package/src/lib/components/console/products-hub-zone.component.js +2 -1
- package/src/lib/components/console/products-hub-zone.component.js.map +1 -1
- package/src/lib/components/console/site-member-purchases.component.d.ts +24 -0
- package/src/lib/components/console/site-member-purchases.component.js +339 -0
- package/src/lib/components/console/site-member-purchases.component.js.map +1 -0
- package/src/lib/components/console/store-settings-card.component.js +2 -2
- package/src/lib/components/console/store-settings-card.component.js.map +1 -1
- package/src/lib/components/console/storefront-tax-summary-card.component.js +1 -1
- package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -1
- package/src/lib/components/member-signup.js +2 -2
- package/src/lib/components/member-signup.js.map +1 -1
- package/src/lib/components/newsletter-signup.js +2 -2
- package/src/lib/components/newsletter-signup.js.map +1 -1
- package/src/lib/components/product-detail.js +2 -1
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/components/product-grid.js +1 -1
- package/src/lib/components/product-grid.js.map +1 -1
- package/src/lib/constants/operator-alerts.js +5 -3
- package/src/lib/constants/operator-alerts.js.map +1 -1
- package/src/lib/constants/storefront-payments.d.ts +33 -0
- package/src/lib/constants/storefront-payments.js +35 -0
- package/src/lib/constants/storefront-payments.js.map +1 -0
- package/src/lib/declarations.server.d.ts +3 -1
- package/src/lib/declarations.server.js +19 -1
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/model/commerce-io.js +1 -1
- package/src/lib/model/commerce-io.js.map +1 -1
- package/src/lib/model/commerce-record-lists.d.ts +31 -0
- package/src/lib/model/commerce-record-lists.js +45 -0
- package/src/lib/model/commerce-record-lists.js.map +1 -0
- package/src/lib/model/commerce-record-routes.d.ts +45 -0
- package/src/lib/model/commerce-record-routes.js +72 -0
- package/src/lib/model/commerce-record-routes.js.map +1 -0
- package/src/lib/model/commerce-search-sources.d.ts +21 -0
- package/src/lib/model/commerce-search-sources.js +42 -0
- package/src/lib/model/commerce-search-sources.js.map +1 -0
- package/src/lib/model/commerce-topics.d.ts +20 -0
- package/src/lib/model/commerce-topics.js +33 -0
- package/src/lib/model/commerce-topics.js.map +1 -0
- package/src/lib/model/index.d.ts +1 -0
- package/src/lib/model/index.js +1 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/product-record.d.ts +32 -0
- package/src/lib/model/product-record.js +82 -0
- package/src/lib/model/product-record.js.map +1 -0
- package/src/lib/model/site-member-purchases.d.ts +48 -0
- package/src/lib/model/site-member-purchases.js +50 -0
- package/src/lib/model/site-member-purchases.js.map +1 -0
- package/src/lib/model/storefront-tax-summary.d.ts +121 -0
- package/src/lib/model/storefront-tax-summary.js +148 -0
- package/src/lib/model/storefront-tax-summary.js.map +1 -0
- package/src/lib/plan-entitlements.d.ts +35 -0
- package/src/lib/plan-entitlements.js +54 -0
- package/src/lib/plan-entitlements.js.map +1 -0
- package/src/lib/plugin.js +21 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/billing-webhook.js +387 -248
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cart-checkout.js +3 -3
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/checkout.js +2 -2
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/connect.js +5 -5
- package/src/lib/server/connect.js.map +1 -1
- package/src/lib/server/draft-order.js +2 -2
- package/src/lib/server/draft-order.js.map +1 -1
- package/src/lib/server/gift-cards.js +7 -3
- package/src/lib/server/gift-cards.js.map +1 -1
- package/src/lib/server/low-stock.js +3 -1
- package/src/lib/server/low-stock.js.map +1 -1
- package/src/lib/server/member-post.js +2 -2
- package/src/lib/server/member-post.js.map +1 -1
- package/src/lib/server/membership-admin-password.js +4 -1
- package/src/lib/server/membership-admin-password.js.map +1 -1
- package/src/lib/server/membership-content.js +1 -1
- package/src/lib/server/membership-content.js.map +1 -1
- package/src/lib/server/membership-register.js +13 -2
- package/src/lib/server/membership-register.js.map +1 -1
- package/src/lib/server/newsletter.js +32 -19
- package/src/lib/server/newsletter.js.map +1 -1
- package/src/lib/server/pos-order.js +3 -3
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/process-abandoned.js +4 -2
- package/src/lib/server/process-abandoned.js.map +1 -1
- package/src/lib/server/process-restock.js +7 -5
- package/src/lib/server/process-restock.js.map +1 -1
- package/src/lib/server/product-record-index.d.ts +19 -0
- package/src/lib/server/product-record-index.js +83 -0
- package/src/lib/server/product-record-index.js.map +1 -0
- package/src/lib/server/reconcile-stock.js +1 -1
- package/src/lib/server/reconcile-stock.js.map +1 -1
- package/src/lib/server/reserve-stock.js +6 -1
- package/src/lib/server/reserve-stock.js.map +1 -1
- package/src/lib/server/reserve.js +2 -2
- package/src/lib/server/reserve.js.map +1 -1
- package/src/lib/server/revenue-source.d.ts +130 -0
- package/src/lib/server/revenue-source.js +286 -0
- package/src/lib/server/revenue-source.js.map +1 -0
- package/src/lib/server/supplier-outbox.js +16 -1
- package/src/lib/server/supplier-outbox.js.map +1 -1
- package/src/lib/server/supplier-update.js +19 -9
- package/src/lib/server/supplier-update.js.map +1 -1
- package/src/lib/server/tax-profile.d.ts +8 -5
- package/src/lib/server/tax-profile.js +22 -5
- package/src/lib/server/tax-profile.js.map +1 -1
- package/src/lib/server/tax-return-source.d.ts +125 -0
- package/src/lib/server/tax-return-source.js +524 -0
- package/src/lib/server/tax-return-source.js.map +1 -0
- package/src/lib/server/tax-summary.d.ts +92 -0
- package/src/lib/server/tax-summary.js +258 -0
- package/src/lib/server/tax-summary.js.map +1 -0
- package/src/lib/server.d.ts +1 -0
- package/src/lib/server.js +23 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/starter-templates.d.ts +19 -0
- package/src/lib/starter-templates.js +157 -0
- package/src/lib/starter-templates.js.map +1 -0
- package/src/lib/tenant-emails.d.ts +33 -0
- package/src/lib/tenant-emails.js +551 -0
- package/src/lib/tenant-emails.js.map +1 -0
- package/src/lib/testing/stand-in-crm-record-routes.d.ts +25 -0
- package/src/lib/testing/stand-in-crm-record-routes.js +46 -0
- package/src/lib/testing/stand-in-crm-record-routes.js.map +1 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { type PluginRecordListSource } from '@aglyn/aglyn/plugin-manager/plugin-record-lists';
|
|
18
|
+
/**
|
|
19
|
+
* A site's products, FOUND in the console for another plugin's picker
|
|
20
|
+
* (AGL-3080) — a deal adding a product as a line, priced from the catalog.
|
|
21
|
+
*
|
|
22
|
+
* A search, not a listing: the first word typed is matched as a prefix of a
|
|
23
|
+
* word in an ACTIVE product's name, ordered by name — a draft or archived
|
|
24
|
+
* product is not offered for sale. With nothing typed, at the organization,
|
|
25
|
+
* where no catalog lives, and for a listing, from which no product is
|
|
26
|
+
* installed, the source answers none. Each record is `productIndexedRecord`'s,
|
|
27
|
+
* the server index's shape, with its price and its priced variants.
|
|
28
|
+
*/
|
|
29
|
+
export declare const productRecordListSource: PluginRecordListSource;
|
|
30
|
+
/** Called from the console registrar, owner named for a spec that calls it directly. */
|
|
31
|
+
export declare function registerCommerceRecordLists(): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ import { nameSearchToken } from "@aglyn/aglyn/app-utils/name-search";
|
|
17
|
+
import { registerPluginRecordListSource } from "@aglyn/aglyn/plugin-manager/plugin-record-lists";
|
|
18
|
+
import { collection, limit, orderBy, query, where } from "firebase/firestore";
|
|
19
|
+
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
20
|
+
import { productIndexedRecord } from "./product-record.js";
|
|
21
|
+
/**
|
|
22
|
+
* A site's products, FOUND in the console for another plugin's picker
|
|
23
|
+
* (AGL-3080) — a deal adding a product as a line, priced from the catalog.
|
|
24
|
+
*
|
|
25
|
+
* A search, not a listing: the first word typed is matched as a prefix of a
|
|
26
|
+
* word in an ACTIVE product's name, ordered by name — a draft or archived
|
|
27
|
+
* product is not offered for sale. With nothing typed, at the organization,
|
|
28
|
+
* where no catalog lives, and for a listing, from which no product is
|
|
29
|
+
* installed, the source answers none. Each record is `productIndexedRecord`'s,
|
|
30
|
+
* the server index's shape, with its price and its priced variants.
|
|
31
|
+
*/ export const productRecordListSource = {
|
|
32
|
+
query (firestore, request) {
|
|
33
|
+
const token = nameSearchToken(request.search);
|
|
34
|
+
if (!request.hostId || !token || request.installedFrom) return null;
|
|
35
|
+
return query(collection(firestore, 'hosts', request.hostId, 'products'), where('status', '==', 'active'), where('nameTokens', 'array-contains', token), orderBy('nameLower'), limit(request.limit));
|
|
36
|
+
},
|
|
37
|
+
record: productIndexedRecord
|
|
38
|
+
};
|
|
39
|
+
/** Called from the console registrar, owner named for a spec that calls it directly. */ export function registerCommerceRecordLists() {
|
|
40
|
+
registerPluginRecordListSource('product', productRecordListSource, {
|
|
41
|
+
pluginId: BUNDLE_ID
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=commerce-record-lists.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/commerce-record-lists.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { nameSearchToken } from '@aglyn/aglyn/app-utils/name-search'\nimport {\n registerPluginRecordListSource,\n type PluginRecordListSource,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-lists'\nimport { collection, limit, orderBy, query, where } from 'firebase/firestore'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { productIndexedRecord } from './product-record'\n\n/**\n * A site's products, FOUND in the console for another plugin's picker\n * (AGL-3080) — a deal adding a product as a line, priced from the catalog.\n *\n * A search, not a listing: the first word typed is matched as a prefix of a\n * word in an ACTIVE product's name, ordered by name — a draft or archived\n * product is not offered for sale. With nothing typed, at the organization,\n * where no catalog lives, and for a listing, from which no product is\n * installed, the source answers none. Each record is `productIndexedRecord`'s,\n * the server index's shape, with its price and its priced variants.\n */\nexport const productRecordListSource: PluginRecordListSource = {\n query(firestore, request) {\n const token = nameSearchToken(request.search)\n if (!request.hostId || !token || request.installedFrom) return null\n return query(\n collection(firestore, 'hosts', request.hostId, 'products'),\n where('status', '==', 'active'),\n where('nameTokens', 'array-contains', token),\n orderBy('nameLower'),\n limit(request.limit),\n )\n },\n record: productIndexedRecord,\n}\n\n/** Called from the console registrar, owner named for a spec that calls it directly. */\nexport function registerCommerceRecordLists(): void {\n registerPluginRecordListSource('product', productRecordListSource, { pluginId: BUNDLE_ID })\n}\n"],"names":["nameSearchToken","registerPluginRecordListSource","collection","limit","orderBy","query","where","BUNDLE_ID","productIndexedRecord","productRecordListSource","firestore","request","token","search","hostId","installedFrom","record","registerCommerceRecordLists","pluginId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,eAAe,QAAQ,qCAAoC;AACpE,SACEC,8BAA8B,QAEzB,kDAAiD;AACxD,SAASC,UAAU,EAAEC,KAAK,EAAEC,OAAO,EAAEC,KAAK,EAAEC,KAAK,QAAQ,qBAAoB;AAC7E,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,oBAAoB,QAAQ,sBAAkB;AAEvD;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,0BAAkD;IAC7DJ,OAAMK,SAAS,EAAEC,OAAO;QACtB,MAAMC,QAAQZ,gBAAgBW,QAAQE,MAAM;QAC5C,IAAI,CAACF,QAAQG,MAAM,IAAI,CAACF,SAASD,QAAQI,aAAa,EAAE,OAAO;QAC/D,OAAOV,MACLH,WAAWQ,WAAW,SAASC,QAAQG,MAAM,EAAE,aAC/CR,MAAM,UAAU,MAAM,WACtBA,MAAM,cAAc,kBAAkBM,QACtCR,QAAQ,cACRD,MAAMQ,QAAQR,KAAK;IAEvB;IACAa,QAAQR;AACV,EAAC;AAED,sFAAsF,GACtF,OAAO,SAASS;IACdhB,+BAA+B,WAAWQ,yBAAyB;QAAES,UAAUX;IAAU;AAC3F"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
* See the License for the specific language governing permissions and
|
|
12
|
+
* limitations under the License.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Where a product and an order are read, published for every other surface
|
|
16
|
+
* (AGL-3080).
|
|
17
|
+
*
|
|
18
|
+
* A surface elsewhere — the AI plugin's job drawer opening a product it
|
|
19
|
+
* drafted, a contact's timeline opening the order it names, a person's page
|
|
20
|
+
* listing their orders — asks the record-route registry for `product` or
|
|
21
|
+
* `order` rather than spelling this plugin's console path, and gets `null`
|
|
22
|
+
* (text instead of a link) where this plugin is not loaded.
|
|
23
|
+
*
|
|
24
|
+
* Both are a site's, so only a site has an address. The catalog has no page
|
|
25
|
+
* per product — a product opens in the hub's editor — so the record answers
|
|
26
|
+
* the catalog a caller would find it in. An order opens as a dialog over the
|
|
27
|
+
* Orders list, which reads {@link ORDERS_ORDER_PARAM} on arrival; the list
|
|
28
|
+
* narrowed to one buyer reads {@link ORDERS_CUSTOMER_PARAM}.
|
|
29
|
+
*/
|
|
30
|
+
/** The nav slug the shell resolves the catalog by. */
|
|
31
|
+
export declare const PRODUCTS_SLUG = "products";
|
|
32
|
+
/** The query key the Orders list opens one order's dialog by. */
|
|
33
|
+
export declare const ORDERS_ORDER_PARAM = "order";
|
|
34
|
+
/**
|
|
35
|
+
* The query key the Orders list narrows to one buyer by — the same word the
|
|
36
|
+
* CRM's contacts list opens a person by, so a reader who edits one URL into
|
|
37
|
+
* the other is not surprised.
|
|
38
|
+
*/
|
|
39
|
+
export declare const ORDERS_CUSTOMER_PARAM = "email";
|
|
40
|
+
/**
|
|
41
|
+
* Called from the console registrar. The owner is named rather than read off
|
|
42
|
+
* the loader's marker, so the route registers the same way under a spec that
|
|
43
|
+
* calls the registrar directly.
|
|
44
|
+
*/
|
|
45
|
+
export declare function registerCommerceRecordRoutes(): void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
* See the License for the specific language governing permissions and
|
|
12
|
+
* limitations under the License.
|
|
13
|
+
*/ import { buildRoute, Route } from "@aglyn/aglyn/app-utils/console-routes";
|
|
14
|
+
import { registerPluginRecordRoute } from "@aglyn/aglyn/plugin-manager/plugin-record-routes";
|
|
15
|
+
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
16
|
+
/**
|
|
17
|
+
* Where a product and an order are read, published for every other surface
|
|
18
|
+
* (AGL-3080).
|
|
19
|
+
*
|
|
20
|
+
* A surface elsewhere — the AI plugin's job drawer opening a product it
|
|
21
|
+
* drafted, a contact's timeline opening the order it names, a person's page
|
|
22
|
+
* listing their orders — asks the record-route registry for `product` or
|
|
23
|
+
* `order` rather than spelling this plugin's console path, and gets `null`
|
|
24
|
+
* (text instead of a link) where this plugin is not loaded.
|
|
25
|
+
*
|
|
26
|
+
* Both are a site's, so only a site has an address. The catalog has no page
|
|
27
|
+
* per product — a product opens in the hub's editor — so the record answers
|
|
28
|
+
* the catalog a caller would find it in. An order opens as a dialog over the
|
|
29
|
+
* Orders list, which reads {@link ORDERS_ORDER_PARAM} on arrival; the list
|
|
30
|
+
* narrowed to one buyer reads {@link ORDERS_CUSTOMER_PARAM}.
|
|
31
|
+
*/ /** The nav slug the shell resolves the catalog by. */ export const PRODUCTS_SLUG = 'products';
|
|
32
|
+
/** The query key the Orders list opens one order's dialog by. */ export const ORDERS_ORDER_PARAM = 'order';
|
|
33
|
+
/**
|
|
34
|
+
* The query key the Orders list narrows to one buyer by — the same word the
|
|
35
|
+
* CRM's contacts list opens a person by, so a reader who edits one URL into
|
|
36
|
+
* the other is not surprised.
|
|
37
|
+
*/ export const ORDERS_CUSTOMER_PARAM = 'email';
|
|
38
|
+
function catalog(context) {
|
|
39
|
+
return context.host ? buildRoute(Route.HOST_PLUGIN, {
|
|
40
|
+
orgSlug: context.orgSlug,
|
|
41
|
+
host: context.host,
|
|
42
|
+
pluginSlug: PRODUCTS_SLUG
|
|
43
|
+
}) : null;
|
|
44
|
+
}
|
|
45
|
+
function orders(context, key, value) {
|
|
46
|
+
const list = catalog(context);
|
|
47
|
+
if (!list) return null;
|
|
48
|
+
return key && value ? `${list}/orders?${new URLSearchParams({
|
|
49
|
+
[key]: value
|
|
50
|
+
}).toString()}` : `${list}/orders`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Called from the console registrar. The owner is named rather than read off
|
|
54
|
+
* the loader's marker, so the route registers the same way under a spec that
|
|
55
|
+
* calls the registrar directly.
|
|
56
|
+
*/ export function registerCommerceRecordRoutes() {
|
|
57
|
+
registerPluginRecordRoute('product', {
|
|
58
|
+
list: catalog,
|
|
59
|
+
record: catalog
|
|
60
|
+
}, {
|
|
61
|
+
pluginId: BUNDLE_ID
|
|
62
|
+
});
|
|
63
|
+
registerPluginRecordRoute('order', {
|
|
64
|
+
list: (context)=>orders(context),
|
|
65
|
+
record: (context, id)=>orders(context, ORDERS_ORDER_PARAM, id),
|
|
66
|
+
byEmail: (context, email)=>orders(context, ORDERS_CUSTOMER_PARAM, email)
|
|
67
|
+
}, {
|
|
68
|
+
pluginId: BUNDLE_ID
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
//# sourceMappingURL=commerce-record-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/commerce-record-routes.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport { buildRoute, Route } from '@aglyn/aglyn/app-utils/console-routes'\nimport {\n registerPluginRecordRoute,\n type PluginRecordRouteContext,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-routes'\nimport { BUNDLE_ID } from '../constants/bundle-common'\n\n/**\n * Where a product and an order are read, published for every other surface\n * (AGL-3080).\n *\n * A surface elsewhere — the AI plugin's job drawer opening a product it\n * drafted, a contact's timeline opening the order it names, a person's page\n * listing their orders — asks the record-route registry for `product` or\n * `order` rather than spelling this plugin's console path, and gets `null`\n * (text instead of a link) where this plugin is not loaded.\n *\n * Both are a site's, so only a site has an address. The catalog has no page\n * per product — a product opens in the hub's editor — so the record answers\n * the catalog a caller would find it in. An order opens as a dialog over the\n * Orders list, which reads {@link ORDERS_ORDER_PARAM} on arrival; the list\n * narrowed to one buyer reads {@link ORDERS_CUSTOMER_PARAM}.\n */\n\n/** The nav slug the shell resolves the catalog by. */\nexport const PRODUCTS_SLUG = 'products'\n\n/** The query key the Orders list opens one order's dialog by. */\nexport const ORDERS_ORDER_PARAM = 'order'\n\n/**\n * The query key the Orders list narrows to one buyer by — the same word the\n * CRM's contacts list opens a person by, so a reader who edits one URL into\n * the other is not surprised.\n */\nexport const ORDERS_CUSTOMER_PARAM = 'email'\n\nfunction catalog(context: PluginRecordRouteContext): string | null {\n return context.host\n ? buildRoute(Route.HOST_PLUGIN, {\n orgSlug: context.orgSlug,\n host: context.host,\n pluginSlug: PRODUCTS_SLUG,\n })\n : null\n}\n\nfunction orders(context: PluginRecordRouteContext, key?: string, value?: string): string | null {\n const list = catalog(context)\n if (!list) return null\n return key && value\n ? `${list}/orders?${new URLSearchParams({ [key]: value }).toString()}`\n : `${list}/orders`\n}\n\n/**\n * Called from the console registrar. The owner is named rather than read off\n * the loader's marker, so the route registers the same way under a spec that\n * calls the registrar directly.\n */\nexport function registerCommerceRecordRoutes(): void {\n registerPluginRecordRoute(\n 'product',\n { list: catalog, record: catalog },\n { pluginId: BUNDLE_ID },\n )\n registerPluginRecordRoute(\n 'order',\n {\n list: (context) => orders(context),\n record: (context, id) => orders(context, ORDERS_ORDER_PARAM, id),\n byEmail: (context, email) => orders(context, ORDERS_CUSTOMER_PARAM, email),\n },\n { pluginId: BUNDLE_ID },\n )\n}\n"],"names":["buildRoute","Route","registerPluginRecordRoute","BUNDLE_ID","PRODUCTS_SLUG","ORDERS_ORDER_PARAM","ORDERS_CUSTOMER_PARAM","catalog","context","host","HOST_PLUGIN","orgSlug","pluginSlug","orders","key","value","list","URLSearchParams","toString","registerCommerceRecordRoutes","record","pluginId","id","byEmail","email"],"mappings":"AAAA;;;;;;;;;;;;CAYC,GAGD,SAASA,UAAU,EAAEC,KAAK,QAAQ,wCAAuC;AACzE,SACEC,yBAAyB,QAEpB,mDAAkD;AACzD,SAASC,SAAS,QAAQ,gCAA4B;AAEtD;;;;;;;;;;;;;;;CAeC,GAED,oDAAoD,GACpD,OAAO,MAAMC,gBAAgB,WAAU;AAEvC,+DAA+D,GAC/D,OAAO,MAAMC,qBAAqB,QAAO;AAEzC;;;;CAIC,GACD,OAAO,MAAMC,wBAAwB,QAAO;AAE5C,SAASC,QAAQC,OAAiC;IAChD,OAAOA,QAAQC,IAAI,GACfT,WAAWC,MAAMS,WAAW,EAAE;QAC5BC,SAASH,QAAQG,OAAO;QACxBF,MAAMD,QAAQC,IAAI;QAClBG,YAAYR;IACd,KACA;AACN;AAEA,SAASS,OAAOL,OAAiC,EAAEM,GAAY,EAAEC,KAAc;IAC7E,MAAMC,OAAOT,QAAQC;IACrB,IAAI,CAACQ,MAAM,OAAO;IAClB,OAAOF,OAAOC,QACV,GAAGC,KAAK,QAAQ,EAAE,IAAIC,gBAAgB;QAAE,CAACH,IAAI,EAAEC;IAAM,GAAGG,QAAQ,IAAI,GACpE,GAAGF,KAAK,OAAO,CAAC;AACtB;AAEA;;;;CAIC,GACD,OAAO,SAASG;IACdjB,0BACE,WACA;QAAEc,MAAMT;QAASa,QAAQb;IAAQ,GACjC;QAAEc,UAAUlB;IAAU;IAExBD,0BACE,SACA;QACEc,MAAM,CAACR,UAAYK,OAAOL;QAC1BY,QAAQ,CAACZ,SAASc,KAAOT,OAAOL,SAASH,oBAAoBiB;QAC7DC,SAAS,CAACf,SAASgB,QAAUX,OAAOL,SAASF,uBAAuBkB;IACtE,GACA;QAAEH,UAAUlB;IAAU;AAE1B"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
* See the License for the specific language governing permissions and
|
|
12
|
+
* limitations under the License.
|
|
13
|
+
*/
|
|
14
|
+
import type { ConsoleSearchSource } from '@aglyn/aglyn';
|
|
15
|
+
/**
|
|
16
|
+
* What the console's search finds in a store (AGL-3080): its products, by
|
|
17
|
+
* name or slug, opening on the site's Products page. Read only where the plan
|
|
18
|
+
* carries commerce and allows the site products, so a workspace that holds
|
|
19
|
+
* none never spends a read on them.
|
|
20
|
+
*/
|
|
21
|
+
export declare const COMMERCE_SEARCH_SOURCES: readonly ConsoleSearchSource[];
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
* See the License for the specific language governing permissions and
|
|
12
|
+
* limitations under the License.
|
|
13
|
+
*/ import { buildRoute, Route } from "@aglyn/aglyn/app-utils/console-routes";
|
|
14
|
+
import { PRODUCTS_SLUG } from "./commerce-record-routes.js";
|
|
15
|
+
/**
|
|
16
|
+
* What the console's search finds in a store (AGL-3080): its products, by
|
|
17
|
+
* name or slug, opening on the site's Products page. Read only where the plan
|
|
18
|
+
* carries commerce and allows the site products, so a workspace that holds
|
|
19
|
+
* none never spends a read on them.
|
|
20
|
+
*/ export const COMMERCE_SEARCH_SOURCES = [
|
|
21
|
+
{
|
|
22
|
+
id: 'products',
|
|
23
|
+
group: 'Products',
|
|
24
|
+
noun: 'products',
|
|
25
|
+
scope: 'host',
|
|
26
|
+
collection: 'products',
|
|
27
|
+
nameField: 'name',
|
|
28
|
+
extraFields: [
|
|
29
|
+
'slug'
|
|
30
|
+
],
|
|
31
|
+
entitlementKey: 'productsPerHost',
|
|
32
|
+
featureFlag: 'commerce',
|
|
33
|
+
order: 160,
|
|
34
|
+
href: (_row, { orgSlug, host })=>host ? buildRoute(Route.HOST_PLUGIN, {
|
|
35
|
+
orgSlug,
|
|
36
|
+
host,
|
|
37
|
+
pluginSlug: PRODUCTS_SLUG
|
|
38
|
+
}) : null
|
|
39
|
+
}
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=commerce-search-sources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/commerce-search-sources.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ConsoleSearchSource } from '@aglyn/aglyn'\nimport { buildRoute, Route } from '@aglyn/aglyn/app-utils/console-routes'\nimport { PRODUCTS_SLUG } from './commerce-record-routes'\n\n/**\n * What the console's search finds in a store (AGL-3080): its products, by\n * name or slug, opening on the site's Products page. Read only where the plan\n * carries commerce and allows the site products, so a workspace that holds\n * none never spends a read on them.\n */\nexport const COMMERCE_SEARCH_SOURCES: readonly ConsoleSearchSource[] = [\n {\n id: 'products',\n group: 'Products',\n noun: 'products',\n scope: 'host',\n collection: 'products',\n nameField: 'name',\n extraFields: ['slug'],\n entitlementKey: 'productsPerHost',\n featureFlag: 'commerce',\n order: 160,\n href: (_row, { orgSlug, host }) =>\n host\n ? buildRoute(Route.HOST_PLUGIN, { orgSlug, host, pluginSlug: PRODUCTS_SLUG })\n : null,\n },\n]\n"],"names":["buildRoute","Route","PRODUCTS_SLUG","COMMERCE_SEARCH_SOURCES","id","group","noun","scope","collection","nameField","extraFields","entitlementKey","featureFlag","order","href","_row","orgSlug","host","HOST_PLUGIN","pluginSlug"],"mappings":"AAAA;;;;;;;;;;;;CAYC,GAGD,SAASA,UAAU,EAAEC,KAAK,QAAQ,wCAAuC;AACzE,SAASC,aAAa,QAAQ,8BAA0B;AAExD;;;;;CAKC,GACD,OAAO,MAAMC,0BAA0D;IACrE;QACEC,IAAI;QACJC,OAAO;QACPC,MAAM;QACNC,OAAO;QACPC,YAAY;QACZC,WAAW;QACXC,aAAa;YAAC;SAAO;QACrBC,gBAAgB;QAChBC,aAAa;QACbC,OAAO;QACPC,MAAM,CAACC,MAAM,EAAEC,OAAO,EAAEC,IAAI,EAAE,GAC5BA,OACIjB,WAAWC,MAAMiB,WAAW,EAAE;gBAAEF;gBAASC;gBAAME,YAAYjB;YAAc,KACzE;IACR;CACD,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/** Regular news and stories, including a site's posts to its members. */
|
|
18
|
+
export declare const NEWSLETTER_TOPIC_ID = "newsletter";
|
|
19
|
+
/** New products, restocks, and changes to what a site offers. */
|
|
20
|
+
export declare const PRODUCT_UPDATES_TOPIC_ID = "product-updates";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /*==========================================
|
|
17
|
+
* THE STREAMS THIS PLUGIN'S MAIL IS SENT UNDER.
|
|
18
|
+
*
|
|
19
|
+
* Declared in `plugins.config.json` (`subscriptionTopics`), which is where
|
|
20
|
+
* their names, descriptions and preference-page order live; named here
|
|
21
|
+
* wherever a send declares which stream it belongs to, because a mistyped id
|
|
22
|
+
* does not fail loudly. It names a stream nobody has opted out of, so the
|
|
23
|
+
* send path finds no opt-out and the send goes to everybody — the control
|
|
24
|
+
* silently doing nothing.
|
|
25
|
+
*
|
|
26
|
+
* Each value is a wire format: a Firestore path component and a component of
|
|
27
|
+
* the unsubscribe link's signed subject, so changing one orphans every
|
|
28
|
+
* opt-out already recorded against it. A cart reminder rides the platform's
|
|
29
|
+
* default stream (`DEFAULT_SUBSCRIPTION_TOPIC_ID`), as a campaign does.
|
|
30
|
+
*=========================================*/ /** Regular news and stories, including a site's posts to its members. */ export const NEWSLETTER_TOPIC_ID = 'newsletter';
|
|
31
|
+
/** New products, restocks, and changes to what a site offers. */ export const PRODUCT_UPDATES_TOPIC_ID = 'product-updates';
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=commerce-topics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/commerce-topics.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * THE STREAMS THIS PLUGIN'S MAIL IS SENT UNDER.\n *\n * Declared in `plugins.config.json` (`subscriptionTopics`), which is where\n * their names, descriptions and preference-page order live; named here\n * wherever a send declares which stream it belongs to, because a mistyped id\n * does not fail loudly. It names a stream nobody has opted out of, so the\n * send path finds no opt-out and the send goes to everybody — the control\n * silently doing nothing.\n *\n * Each value is a wire format: a Firestore path component and a component of\n * the unsubscribe link's signed subject, so changing one orphans every\n * opt-out already recorded against it. A cart reminder rides the platform's\n * default stream (`DEFAULT_SUBSCRIPTION_TOPIC_ID`), as a campaign does.\n *=========================================*/\n\n/** Regular news and stories, including a site's posts to its members. */\nexport const NEWSLETTER_TOPIC_ID = 'newsletter'\n\n/** New products, restocks, and changes to what a site offers. */\nexport const PRODUCT_UPDATES_TOPIC_ID = 'product-updates'\n"],"names":["NEWSLETTER_TOPIC_ID","PRODUCT_UPDATES_TOPIC_ID"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;2CAc2C,GAE3C,uEAAuE,GACvE,OAAO,MAAMA,sBAAsB,aAAY;AAE/C,+DAA+D,GAC/D,OAAO,MAAMC,2BAA2B,kBAAiB"}
|
package/src/lib/model/index.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export * from './commerce-cart';
|
|
|
26
26
|
export * from './commerce-connect-transfer';
|
|
27
27
|
export * from './commerce-discounts';
|
|
28
28
|
export * from './commerce-dispute';
|
|
29
|
+
export * from './commerce-topics';
|
|
29
30
|
export * from './commerce-gift-cards';
|
|
30
31
|
export * from './commerce-io';
|
|
31
32
|
export * from './commerce-orders';
|
package/src/lib/model/index.js
CHANGED
|
@@ -24,6 +24,7 @@ export * from "./commerce-cart.js";
|
|
|
24
24
|
export * from "./commerce-connect-transfer.js";
|
|
25
25
|
export * from "./commerce-discounts.js";
|
|
26
26
|
export * from "./commerce-dispute.js";
|
|
27
|
+
export * from "./commerce-topics.js";
|
|
27
28
|
export * from "./commerce-gift-cards.js";
|
|
28
29
|
export * from "./commerce-io.js";
|
|
29
30
|
export * from "./commerce-orders.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/index.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Commerce domain model (AGL-411): pure types + logic relocated from the\n * core `@aglyn/aglyn` app-utils — the commerce plugin owns its domain.\n * Context-free and framework-free, so both the plugin's client components\n * and its `/server` handlers (and other plugins/apps via\n * `@aglyn/plugins-commerce/model`) can import it.\n */\nexport * from './commerce'\nexport * from './commerce-cart'\nexport * from './commerce-connect-transfer'\nexport * from './commerce-discounts'\nexport * from './commerce-dispute'\nexport * from './commerce-gift-cards'\nexport * from './commerce-io'\nexport * from './commerce-orders'\nexport * from './commerce-promotions'\nexport * from './commerce-reservations'\nexport * from './commerce-shipping'\nexport * from './commerce-stock-holds'\nexport * from './commerce-subscription-status'\nexport * from './commerce-tax'\nexport * from './commerce-tax-decision'\nexport * from './order-figures'\nexport * from './order-list-fields'\nexport * from './purchase-analytics'\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;CAMC,GACD,cAAc,gBAAY;AAC1B,cAAc,qBAAiB;AAC/B,cAAc,iCAA6B;AAC3C,cAAc,0BAAsB;AACpC,cAAc,wBAAoB;AAClC,cAAc,2BAAuB;AACrC,cAAc,mBAAe;AAC7B,cAAc,uBAAmB;AACjC,cAAc,2BAAuB;AACrC,cAAc,6BAAyB;AACvC,cAAc,yBAAqB;AACnC,cAAc,4BAAwB;AACtC,cAAc,oCAAgC;AAC9C,cAAc,oBAAgB;AAC9B,cAAc,6BAAyB;AACvC,cAAc,qBAAiB;AAC/B,cAAc,yBAAqB;AACnC,cAAc,0BAAsB"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/index.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Commerce domain model (AGL-411): pure types + logic relocated from the\n * core `@aglyn/aglyn` app-utils — the commerce plugin owns its domain.\n * Context-free and framework-free, so both the plugin's client components\n * and its `/server` handlers (and other plugins/apps via\n * `@aglyn/plugins-commerce/model`) can import it.\n */\nexport * from './commerce'\nexport * from './commerce-cart'\nexport * from './commerce-connect-transfer'\nexport * from './commerce-discounts'\nexport * from './commerce-dispute'\nexport * from './commerce-topics'\nexport * from './commerce-gift-cards'\nexport * from './commerce-io'\nexport * from './commerce-orders'\nexport * from './commerce-promotions'\nexport * from './commerce-reservations'\nexport * from './commerce-shipping'\nexport * from './commerce-stock-holds'\nexport * from './commerce-subscription-status'\nexport * from './commerce-tax'\nexport * from './commerce-tax-decision'\nexport * from './order-figures'\nexport * from './order-list-fields'\nexport * from './purchase-analytics'\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;CAMC,GACD,cAAc,gBAAY;AAC1B,cAAc,qBAAiB;AAC/B,cAAc,iCAA6B;AAC3C,cAAc,0BAAsB;AACpC,cAAc,wBAAoB;AAClC,cAAc,uBAAmB;AACjC,cAAc,2BAAuB;AACrC,cAAc,mBAAe;AAC7B,cAAc,uBAAmB;AACjC,cAAc,2BAAuB;AACrC,cAAc,6BAAyB;AACvC,cAAc,yBAAqB;AACnC,cAAc,4BAAwB;AACtC,cAAc,oCAAgC;AAC9C,cAAc,oBAAgB;AAC9B,cAAc,6BAAyB;AACvC,cAAc,qBAAiB;AAC/B,cAAc,yBAAqB;AACnC,cAAc,0BAAsB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { PluginIndexedRecord } from '@aglyn/aglyn/plugin-manager/plugin-record-index';
|
|
18
|
+
/**
|
|
19
|
+
* One stored product as this plugin shares it with another (AGL-3080) — the
|
|
20
|
+
* one shape its server index (`product-record-index.ts`) and its console list
|
|
21
|
+
* source (`commerce-record-lists.ts`) both answer.
|
|
22
|
+
*
|
|
23
|
+
* `null` for a deleted product and an unnamed one. Otherwise its `facts`:
|
|
24
|
+
* `type` (`physical` | `digital` | `service` | the stored value),
|
|
25
|
+
* `description`, `tags: string[]`, `categoryIds: string[]`,
|
|
26
|
+
* `options: Array<{ name, values: string[] }>`, `imageUrl` (the first
|
|
27
|
+
* photo's stored media value, or `null`), `seoTitle`, `seoDescription`,
|
|
28
|
+
* `priceUsd` (the product's own price in dollars, or `null`) and
|
|
29
|
+
* `variants: Array<{ id, options: Record<string, string>, priceUsd }>` —
|
|
30
|
+
* each priced variant as stored, empty for a product without variants.
|
|
31
|
+
*/
|
|
32
|
+
export declare function productIndexedRecord(id: string, data: Readonly<Record<string, unknown>> | undefined): PluginIndexedRecord | null;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /**
|
|
17
|
+
* One stored product as this plugin shares it with another (AGL-3080) — the
|
|
18
|
+
* one shape its server index (`product-record-index.ts`) and its console list
|
|
19
|
+
* source (`commerce-record-lists.ts`) both answer.
|
|
20
|
+
*
|
|
21
|
+
* `null` for a deleted product and an unnamed one. Otherwise its `facts`:
|
|
22
|
+
* `type` (`physical` | `digital` | `service` | the stored value),
|
|
23
|
+
* `description`, `tags: string[]`, `categoryIds: string[]`,
|
|
24
|
+
* `options: Array<{ name, values: string[] }>`, `imageUrl` (the first
|
|
25
|
+
* photo's stored media value, or `null`), `seoTitle`, `seoDescription`,
|
|
26
|
+
* `priceUsd` (the product's own price in dollars, or `null`) and
|
|
27
|
+
* `variants: Array<{ id, options: Record<string, string>, priceUsd }>` —
|
|
28
|
+
* each priced variant as stored, empty for a product without variants.
|
|
29
|
+
*/ export function productIndexedRecord(id, data) {
|
|
30
|
+
var _data_seo;
|
|
31
|
+
if (!data || data['deletedAt'] != null) return null;
|
|
32
|
+
const name = str(data['name']);
|
|
33
|
+
if (!name) return null;
|
|
34
|
+
const seo = (_data_seo = data['seo']) != null ? _data_seo : {};
|
|
35
|
+
const mediaUrls = Array.isArray(data['mediaUrls']) ? data['mediaUrls'] : [];
|
|
36
|
+
return {
|
|
37
|
+
id,
|
|
38
|
+
name,
|
|
39
|
+
facts: {
|
|
40
|
+
type: data['type'],
|
|
41
|
+
description: str(data['description']),
|
|
42
|
+
tags: strings(data['tags']),
|
|
43
|
+
categoryIds: strings(data['categoryIds']),
|
|
44
|
+
options: (Array.isArray(data['options']) ? data['options'] : []).map((option)=>{
|
|
45
|
+
const record = option != null ? option : {};
|
|
46
|
+
return {
|
|
47
|
+
name: str(record['name']),
|
|
48
|
+
values: strings(record['values'])
|
|
49
|
+
};
|
|
50
|
+
}),
|
|
51
|
+
imageUrl: str(mediaUrls[0]) || str(data['imageUrl']) || null,
|
|
52
|
+
seoTitle: str(seo['title']),
|
|
53
|
+
seoDescription: str(seo['description']),
|
|
54
|
+
priceUsd: price(data['priceUsd']),
|
|
55
|
+
variants: (Array.isArray(data['variants']) ? data['variants'] : []).map((variant)=>{
|
|
56
|
+
var _record_options;
|
|
57
|
+
const record = variant != null ? variant : {};
|
|
58
|
+
const options = (_record_options = record['options']) != null ? _record_options : {};
|
|
59
|
+
return {
|
|
60
|
+
id: str(record['id']),
|
|
61
|
+
options: Object.fromEntries(Object.entries(options).map(([key, value])=>[
|
|
62
|
+
key,
|
|
63
|
+
str(value)
|
|
64
|
+
])),
|
|
65
|
+
priceUsd: price(record['priceUsd'])
|
|
66
|
+
};
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function str(value) {
|
|
72
|
+
return typeof value === 'string' ? value : '';
|
|
73
|
+
}
|
|
74
|
+
function strings(value) {
|
|
75
|
+
return (Array.isArray(value) ? value : []).map(str).filter(Boolean);
|
|
76
|
+
}
|
|
77
|
+
function price(value) {
|
|
78
|
+
const parsed = typeof value === 'number' ? value : Number(value);
|
|
79
|
+
return value === null || value === undefined || value === '' || !Number.isFinite(parsed) ? null : parsed;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=product-record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/product-record.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { PluginIndexedRecord } from '@aglyn/aglyn/plugin-manager/plugin-record-index'\n\n/**\n * One stored product as this plugin shares it with another (AGL-3080) — the\n * one shape its server index (`product-record-index.ts`) and its console list\n * source (`commerce-record-lists.ts`) both answer.\n *\n * `null` for a deleted product and an unnamed one. Otherwise its `facts`:\n * `type` (`physical` | `digital` | `service` | the stored value),\n * `description`, `tags: string[]`, `categoryIds: string[]`,\n * `options: Array<{ name, values: string[] }>`, `imageUrl` (the first\n * photo's stored media value, or `null`), `seoTitle`, `seoDescription`,\n * `priceUsd` (the product's own price in dollars, or `null`) and\n * `variants: Array<{ id, options: Record<string, string>, priceUsd }>` —\n * each priced variant as stored, empty for a product without variants.\n */\nexport function productIndexedRecord(\n id: string,\n data: Readonly<Record<string, unknown>> | undefined,\n): PluginIndexedRecord | null {\n if (!data || data['deletedAt'] != null) return null\n const name = str(data['name'])\n if (!name) return null\n const seo = (data['seo'] ?? {}) as Record<string, unknown>\n const mediaUrls = Array.isArray(data['mediaUrls']) ? data['mediaUrls'] : []\n return {\n id,\n name,\n facts: {\n type: data['type'],\n description: str(data['description']),\n tags: strings(data['tags']),\n categoryIds: strings(data['categoryIds']),\n options: (Array.isArray(data['options']) ? data['options'] : []).map((option) => {\n const record = (option ?? {}) as Record<string, unknown>\n return { name: str(record['name']), values: strings(record['values']) }\n }),\n imageUrl: str(mediaUrls[0]) || str(data['imageUrl']) || null,\n seoTitle: str(seo['title']),\n seoDescription: str(seo['description']),\n priceUsd: price(data['priceUsd']),\n variants: (Array.isArray(data['variants']) ? data['variants'] : []).map((variant) => {\n const record = (variant ?? {}) as Record<string, unknown>\n const options = (record['options'] ?? {}) as Record<string, unknown>\n return {\n id: str(record['id']),\n options: Object.fromEntries(Object.entries(options).map(([key, value]) => [key, str(value)])),\n priceUsd: price(record['priceUsd']),\n }\n }),\n },\n }\n}\n\nfunction str(value: unknown): string {\n return typeof value === 'string' ? value : ''\n}\n\nfunction strings(value: unknown): string[] {\n return (Array.isArray(value) ? value : []).map(str).filter(Boolean)\n}\n\nfunction price(value: unknown): number | null {\n const parsed = typeof value === 'number' ? value : Number(value)\n return value === null || value === undefined || value === '' || !Number.isFinite(parsed) ? null : parsed\n}\n"],"names":["productIndexedRecord","id","data","name","str","seo","mediaUrls","Array","isArray","facts","type","description","tags","strings","categoryIds","options","map","option","record","values","imageUrl","seoTitle","seoDescription","priceUsd","price","variants","variant","Object","fromEntries","entries","key","value","filter","Boolean","parsed","Number","undefined","isFinite"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAID;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASA,qBACdC,EAAU,EACVC,IAAmD;QAKtCA;IAHb,IAAI,CAACA,QAAQA,IAAI,CAAC,YAAY,IAAI,MAAM,OAAO;IAC/C,MAAMC,OAAOC,IAAIF,IAAI,CAAC,OAAO;IAC7B,IAAI,CAACC,MAAM,OAAO;IAClB,MAAME,OAAOH,YAAAA,IAAI,CAAC,MAAM,YAAXA,YAAe,CAAC;IAC7B,MAAMI,YAAYC,MAAMC,OAAO,CAACN,IAAI,CAAC,YAAY,IAAIA,IAAI,CAAC,YAAY,GAAG,EAAE;IAC3E,OAAO;QACLD;QACAE;QACAM,OAAO;YACLC,MAAMR,IAAI,CAAC,OAAO;YAClBS,aAAaP,IAAIF,IAAI,CAAC,cAAc;YACpCU,MAAMC,QAAQX,IAAI,CAAC,OAAO;YAC1BY,aAAaD,QAAQX,IAAI,CAAC,cAAc;YACxCa,SAAS,AAACR,CAAAA,MAAMC,OAAO,CAACN,IAAI,CAAC,UAAU,IAAIA,IAAI,CAAC,UAAU,GAAG,EAAE,AAAD,EAAGc,GAAG,CAAC,CAACC;gBACpE,MAAMC,SAAUD,iBAAAA,SAAU,CAAC;gBAC3B,OAAO;oBAAEd,MAAMC,IAAIc,MAAM,CAAC,OAAO;oBAAGC,QAAQN,QAAQK,MAAM,CAAC,SAAS;gBAAE;YACxE;YACAE,UAAUhB,IAAIE,SAAS,CAAC,EAAE,KAAKF,IAAIF,IAAI,CAAC,WAAW,KAAK;YACxDmB,UAAUjB,IAAIC,GAAG,CAAC,QAAQ;YAC1BiB,gBAAgBlB,IAAIC,GAAG,CAAC,cAAc;YACtCkB,UAAUC,MAAMtB,IAAI,CAAC,WAAW;YAChCuB,UAAU,AAAClB,CAAAA,MAAMC,OAAO,CAACN,IAAI,CAAC,WAAW,IAAIA,IAAI,CAAC,WAAW,GAAG,EAAE,AAAD,EAAGc,GAAG,CAAC,CAACU;oBAEtDR;gBADjB,MAAMA,SAAUQ,kBAAAA,UAAW,CAAC;gBAC5B,MAAMX,WAAWG,kBAAAA,MAAM,CAAC,UAAU,YAAjBA,kBAAqB,CAAC;gBACvC,OAAO;oBACLjB,IAAIG,IAAIc,MAAM,CAAC,KAAK;oBACpBH,SAASY,OAAOC,WAAW,CAACD,OAAOE,OAAO,CAACd,SAASC,GAAG,CAAC,CAAC,CAACc,KAAKC,MAAM,GAAK;4BAACD;4BAAK1B,IAAI2B;yBAAO;oBAC3FR,UAAUC,MAAMN,MAAM,CAAC,WAAW;gBACpC;YACF;QACF;IACF;AACF;AAEA,SAASd,IAAI2B,KAAc;IACzB,OAAO,OAAOA,UAAU,WAAWA,QAAQ;AAC7C;AAEA,SAASlB,QAAQkB,KAAc;IAC7B,OAAO,AAACxB,CAAAA,MAAMC,OAAO,CAACuB,SAASA,QAAQ,EAAE,AAAD,EAAGf,GAAG,CAACZ,KAAK4B,MAAM,CAACC;AAC7D;AAEA,SAAST,MAAMO,KAAc;IAC3B,MAAMG,SAAS,OAAOH,UAAU,WAAWA,QAAQI,OAAOJ;IAC1D,OAAOA,UAAU,QAAQA,UAAUK,aAAaL,UAAU,MAAM,CAACI,OAAOE,QAAQ,CAACH,UAAU,OAAOA;AACpG"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Lifetime purchase math for a site's visitor accounts (AGL-546). Pure —
|
|
19
|
+
* operates on raw `hosts/{hostId}/orders` doc shapes (both the v1
|
|
20
|
+
* `totals.totalCents` form and the legacy flat `amountCents` form) so a
|
|
21
|
+
* member's purchases can be totalled from the docs already loaded. The stale
|
|
22
|
+
* `siteMembers.purchaseCents` field this replaces was never written.
|
|
23
|
+
*/
|
|
24
|
+
/** The slice of an order doc the lifetime total needs. */
|
|
25
|
+
export interface PurchaseTotalOrder {
|
|
26
|
+
status?: string;
|
|
27
|
+
/** Legacy Commerce Starter flat total (cents). */
|
|
28
|
+
amountCents?: number;
|
|
29
|
+
/** Orders v1 totals block. */
|
|
30
|
+
totals?: {
|
|
31
|
+
totalCents?: number;
|
|
32
|
+
};
|
|
33
|
+
/** Cents refunded so far (partial or full), a lost chargeback included. */
|
|
34
|
+
refundedCents?: number;
|
|
35
|
+
}
|
|
36
|
+
/** Charged cents for one order: v1 total, else legacy amount. */
|
|
37
|
+
export declare function orderChargedCents(order: PurchaseTotalOrder): number;
|
|
38
|
+
/**
|
|
39
|
+
* Sum of what the member actually paid: charged totals minus refunds,
|
|
40
|
+
* skipping never-charged (pending/cancelled) orders. Each order clamps at
|
|
41
|
+
* zero so an over-recorded refund cannot drag the lifetime negative.
|
|
42
|
+
*
|
|
43
|
+
* `refundedCents` carries a lost chargeback as well as a refund (AGL-1787),
|
|
44
|
+
* and money reversed is money reversed whichever door it left by, so the
|
|
45
|
+
* whole figure is netted; only a LABEL splits the two
|
|
46
|
+
* (`splitOrderReversal`, AGL-1810).
|
|
47
|
+
*/
|
|
48
|
+
export declare function computeLifetimePurchaseCents(orders: readonly PurchaseTotalOrder[]): number;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /**
|
|
17
|
+
* Lifetime purchase math for a site's visitor accounts (AGL-546). Pure —
|
|
18
|
+
* operates on raw `hosts/{hostId}/orders` doc shapes (both the v1
|
|
19
|
+
* `totals.totalCents` form and the legacy flat `amountCents` form) so a
|
|
20
|
+
* member's purchases can be totalled from the docs already loaded. The stale
|
|
21
|
+
* `siteMembers.purchaseCents` field this replaces was never written.
|
|
22
|
+
*/ /** The slice of an order doc the lifetime total needs. */ /** Orders that never charged the customer don't count toward lifetime. */ const UNCHARGED_STATUSES = new Set([
|
|
23
|
+
'pending',
|
|
24
|
+
'cancelled'
|
|
25
|
+
]);
|
|
26
|
+
/** Charged cents for one order: v1 total, else legacy amount. */ export function orderChargedCents(order) {
|
|
27
|
+
var _ref, _ref1;
|
|
28
|
+
var _order_totals;
|
|
29
|
+
return Number((_ref = (_ref1 = (_order_totals = order.totals) == null ? void 0 : _order_totals.totalCents) != null ? _ref1 : order.amountCents) != null ? _ref : 0) || 0;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Sum of what the member actually paid: charged totals minus refunds,
|
|
33
|
+
* skipping never-charged (pending/cancelled) orders. Each order clamps at
|
|
34
|
+
* zero so an over-recorded refund cannot drag the lifetime negative.
|
|
35
|
+
*
|
|
36
|
+
* `refundedCents` carries a lost chargeback as well as a refund (AGL-1787),
|
|
37
|
+
* and money reversed is money reversed whichever door it left by, so the
|
|
38
|
+
* whole figure is netted; only a LABEL splits the two
|
|
39
|
+
* (`splitOrderReversal`, AGL-1810).
|
|
40
|
+
*/ export function computeLifetimePurchaseCents(orders) {
|
|
41
|
+
return orders.reduce((sum, order)=>{
|
|
42
|
+
var _order_status, _order_refundedCents;
|
|
43
|
+
if (UNCHARGED_STATUSES.has(String((_order_status = order.status) != null ? _order_status : ''))) return sum;
|
|
44
|
+
const charged = orderChargedCents(order);
|
|
45
|
+
const refunded = Math.max(0, Number((_order_refundedCents = order.refundedCents) != null ? _order_refundedCents : 0) || 0);
|
|
46
|
+
return sum + Math.max(0, charged - refunded);
|
|
47
|
+
}, 0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=site-member-purchases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/site-member-purchases.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Lifetime purchase math for a site's visitor accounts (AGL-546). Pure —\n * operates on raw `hosts/{hostId}/orders` doc shapes (both the v1\n * `totals.totalCents` form and the legacy flat `amountCents` form) so a\n * member's purchases can be totalled from the docs already loaded. The stale\n * `siteMembers.purchaseCents` field this replaces was never written.\n */\n\n/** The slice of an order doc the lifetime total needs. */\nexport interface PurchaseTotalOrder {\n status?: string\n /** Legacy Commerce Starter flat total (cents). */\n amountCents?: number\n /** Orders v1 totals block. */\n totals?: { totalCents?: number }\n /** Cents refunded so far (partial or full), a lost chargeback included. */\n refundedCents?: number\n}\n\n/** Orders that never charged the customer don't count toward lifetime. */\nconst UNCHARGED_STATUSES = new Set(['pending', 'cancelled'])\n\n/** Charged cents for one order: v1 total, else legacy amount. */\nexport function orderChargedCents(order: PurchaseTotalOrder): number {\n return Number(order.totals?.totalCents ?? order.amountCents ?? 0) || 0\n}\n\n/**\n * Sum of what the member actually paid: charged totals minus refunds,\n * skipping never-charged (pending/cancelled) orders. Each order clamps at\n * zero so an over-recorded refund cannot drag the lifetime negative.\n *\n * `refundedCents` carries a lost chargeback as well as a refund (AGL-1787),\n * and money reversed is money reversed whichever door it left by, so the\n * whole figure is netted; only a LABEL splits the two\n * (`splitOrderReversal`, AGL-1810).\n */\nexport function computeLifetimePurchaseCents(\n orders: readonly PurchaseTotalOrder[],\n): number {\n return orders.reduce((sum, order) => {\n if (UNCHARGED_STATUSES.has(String(order.status ?? ''))) return sum\n const charged = orderChargedCents(order)\n const refunded = Math.max(0, Number(order.refundedCents ?? 0) || 0)\n return sum + Math.max(0, charged - refunded)\n }, 0)\n}\n"],"names":["UNCHARGED_STATUSES","Set","orderChargedCents","order","Number","totals","totalCents","amountCents","computeLifetimePurchaseCents","orders","reduce","sum","has","String","status","charged","refunded","Math","max","refundedCents"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;CAMC,GAED,wDAAwD,GAWxD,wEAAwE,GACxE,MAAMA,qBAAqB,IAAIC,IAAI;IAAC;IAAW;CAAY;AAE3D,+DAA+D,GAC/D,OAAO,SAASC,kBAAkBC,KAAyB;QAC3CA;QAAAA;IAAd,OAAOC,QAAOD,iBAAAA,gBAAAA,MAAME,MAAM,qBAAZF,cAAcG,UAAU,oBAAIH,MAAMI,WAAW,YAA7CJ,OAAiD,MAAM;AACvE;AAEA;;;;;;;;;CASC,GACD,OAAO,SAASK,6BACdC,MAAqC;IAErC,OAAOA,OAAOC,MAAM,CAAC,CAACC,KAAKR;YACSA,eAEEA;QAFpC,IAAIH,mBAAmBY,GAAG,CAACC,QAAOV,gBAAAA,MAAMW,MAAM,YAAZX,gBAAgB,MAAM,OAAOQ;QAC/D,MAAMI,UAAUb,kBAAkBC;QAClC,MAAMa,WAAWC,KAAKC,GAAG,CAAC,GAAGd,QAAOD,uBAAAA,MAAMgB,aAAa,YAAnBhB,uBAAuB,MAAM;QACjE,OAAOQ,MAAMM,KAAKC,GAAG,CAAC,GAAGH,UAAUC;IACrC,GAAG;AACL"}
|