@aglyn/plugins-commerce 1.0.0-beta.231 → 1.0.0-beta.233
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/package.json +13 -13
- package/src/lib/components/cart-extras.d.ts +6 -0
- package/src/lib/components/cart-extras.js +4 -1
- package/src/lib/components/cart-extras.js.map +1 -1
- package/src/lib/components/cart-fulfillment.d.ts +117 -0
- package/src/lib/components/cart-fulfillment.js +367 -0
- package/src/lib/components/cart-fulfillment.js.map +1 -0
- package/src/lib/components/cart.js +52 -10
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/commerce-console-page.js +42 -1
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/catalog-organization-card.component.js +1 -0
- package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
- package/src/lib/components/console/host-orders-card.component.js +42 -11
- package/src/lib/components/console/host-orders-card.component.js.map +1 -1
- package/src/lib/components/console/local-delivery-settings-card.component.d.ts +37 -0
- package/src/lib/components/console/local-delivery-settings-card.component.js +542 -0
- package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -0
- package/src/lib/components/console/locations-card.component.js +177 -3
- package/src/lib/components/console/locations-card.component.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +10 -0
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/order-local-fulfillment-panel.component.d.ts +44 -0
- package/src/lib/components/console/order-local-fulfillment-panel.component.js +265 -0
- package/src/lib/components/console/order-local-fulfillment-panel.component.js.map +1 -0
- package/src/lib/components/console/order-offline-notice.component.d.ts +12 -0
- package/src/lib/components/console/order-offline-notice.component.js +53 -0
- package/src/lib/components/console/order-offline-notice.component.js.map +1 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.d.ts +35 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.js +222 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-api.d.ts +24 -1
- package/src/lib/components/console/pos/pos-api.js +13 -0
- package/src/lib/components/console/pos/pos-api.js.map +1 -1
- package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +12 -0
- package/src/lib/components/console/pos/pos-item-dialog.component.js +10 -8
- package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-kiosk-queue.component.d.ts +22 -0
- package/src/lib/components/console/pos/pos-kiosk-queue.component.js +168 -0
- package/src/lib/components/console/pos/pos-kiosk-queue.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +18 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js +116 -1
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +8 -0
- package/src/lib/components/console/pos/pos-tender-panel.component.js +77 -18
- package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -1
- package/src/lib/components/console/pos/use-pos-display.d.ts +5 -2
- package/src/lib/components/console/pos/use-pos-display.js +3 -2
- package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
- package/src/lib/components/console/pos-devices-card.component.js +2 -2
- package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
- package/src/lib/components/console/pos-display/pairing-screen.d.ts +5 -2
- package/src/lib/components/console/pos-display/pairing-screen.js +7 -5
- package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -1
- package/src/lib/components/console/pos-display/pos-display-api.d.ts +7 -1
- package/src/lib/components/console/pos-display/pos-display-api.js +7 -2
- package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.d.ts +41 -0
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.js +275 -0
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.d.ts +32 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.js +344 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.d.ts +12 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.js +257 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.d.ts +114 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js +189 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.d.ts +16 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js +80 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js.map +1 -0
- package/src/lib/components/console/pos-kiosk-page.component.d.ts +28 -0
- package/src/lib/components/console/pos-kiosk-page.component.js +791 -0
- package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.d.ts +44 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.js +69 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.d.ts +7 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.js +135 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.d.ts +32 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js +287 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.d.ts +63 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.js +145 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.js.map +1 -0
- package/src/lib/components/console/pos-offline/register-offline.d.ts +24 -0
- package/src/lib/components/console/pos-offline/register-offline.js +24 -0
- package/src/lib/components/console/pos-offline/register-offline.js.map +1 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.d.ts +85 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.js +542 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +72 -17
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -1
- package/src/lib/components/console/pos-page.component.js +228 -51
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/pos-zones.d.ts +23 -0
- package/src/lib/components/console/pos-zones.js +31 -0
- package/src/lib/components/console/pos-zones.js.map +1 -0
- package/src/lib/components/console/product-editor-dialog.component.js +10 -64
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +46 -30
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/shipping-settings-card.component.js +1 -1
- package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
- package/src/lib/components/console/stock-movements-card.component.js +48 -16
- package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
- package/src/lib/components/console/store-zones.d.ts +8 -1
- package/src/lib/components/console/store-zones.js +11 -1
- package/src/lib/components/console/store-zones.js.map +1 -1
- package/src/lib/components/console/storefront-tax-summary-card.component.js +1 -0
- package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -1
- package/src/lib/components/order-status.js +66 -0
- package/src/lib/components/order-status.js.map +1 -1
- package/src/lib/components/product-detail.js +42 -15
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/constants/local-fulfillment-list-query.d.ts +48 -0
- package/src/lib/constants/local-fulfillment-list-query.js +84 -0
- package/src/lib/constants/local-fulfillment-list-query.js.map +1 -0
- package/src/lib/constants/orders-list-query.d.ts +7 -2
- package/src/lib/constants/orders-list-query.js +89 -8
- package/src/lib/constants/orders-list-query.js.map +1 -1
- package/src/lib/constants/pos-shift-list-query.d.ts +22 -0
- package/src/lib/constants/pos-shift-list-query.js +115 -0
- package/src/lib/constants/pos-shift-list-query.js.map +1 -0
- package/src/lib/constants/product-list-query.d.ts +6 -1
- package/src/lib/constants/product-list-query.js +77 -8
- package/src/lib/constants/product-list-query.js.map +1 -1
- package/src/lib/constants/stock-movement-query.d.ts +3 -2
- package/src/lib/constants/stock-movement-query.js +52 -8
- package/src/lib/constants/stock-movement-query.js.map +1 -1
- package/src/lib/declarations.server.js +21 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/model/buyer-notifications.d.ts +5 -3
- package/src/lib/model/buyer-notifications.js +25 -4
- package/src/lib/model/buyer-notifications.js.map +1 -1
- package/src/lib/model/commerce-orders.d.ts +103 -1
- package/src/lib/model/commerce-orders.js +2 -1
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-pos-kiosk.d.ts +175 -0
- package/src/lib/model/commerce-pos-kiosk.js +147 -0
- package/src/lib/model/commerce-pos-kiosk.js.map +1 -0
- package/src/lib/model/commerce-pos-offline.d.ts +234 -0
- package/src/lib/model/commerce-pos-offline.js +301 -0
- package/src/lib/model/commerce-pos-offline.js.map +1 -0
- package/src/lib/model/commerce-pos-ops.d.ts +16 -6
- package/src/lib/model/commerce-pos-ops.js +12 -4
- package/src/lib/model/commerce-pos-ops.js.map +1 -1
- package/src/lib/model/commerce-pos.d.ts +13 -1
- package/src/lib/model/commerce-pos.js +5 -4
- package/src/lib/model/commerce-pos.js.map +1 -1
- package/src/lib/model/commerce-stock-holds.d.ts +24 -3
- package/src/lib/model/commerce-stock-holds.js +26 -8
- package/src/lib/model/commerce-stock-holds.js.map +1 -1
- package/src/lib/model/commerce.d.ts +7 -1
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/index.d.ts +5 -0
- package/src/lib/model/index.js +5 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/local-fulfillment-settings.d.ts +178 -0
- package/src/lib/model/local-fulfillment-settings.js +361 -0
- package/src/lib/model/local-fulfillment-settings.js.map +1 -0
- package/src/lib/model/order-list-fields.d.ts +10 -1
- package/src/lib/model/order-list-fields.js +1 -0
- package/src/lib/model/order-list-fields.js.map +1 -1
- package/src/lib/model/order-local-fulfillment.d.ts +131 -0
- package/src/lib/model/order-local-fulfillment.js +125 -0
- package/src/lib/model/order-local-fulfillment.js.map +1 -0
- package/src/lib/model/order-shipping-export.js +4 -0
- package/src/lib/model/order-shipping-export.js.map +1 -1
- package/src/lib/model/order-status-view.d.ts +20 -1
- package/src/lib/model/order-status-view.js +60 -6
- package/src/lib/model/order-status-view.js.map +1 -1
- package/src/lib/model/product-write.d.ts +186 -0
- package/src/lib/model/product-write.js +116 -0
- package/src/lib/model/product-write.js.map +1 -0
- package/src/lib/plugin-config.js +6 -2
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +11 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/pos-kiosk-config.d.ts +26 -0
- package/src/lib/pos-kiosk-config.js +59 -0
- package/src/lib/pos-kiosk-config.js.map +1 -0
- package/src/lib/server/api-v1/openapi.js +8 -0
- package/src/lib/server/api-v1/openapi.js.map +1 -1
- package/src/lib/server/api-v1/order-view.d.ts +19 -0
- package/src/lib/server/api-v1/order-view.js +35 -0
- package/src/lib/server/api-v1/order-view.js.map +1 -1
- package/src/lib/server/billing-webhook.js +238 -87
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cart-checkout.d.ts +2 -0
- package/src/lib/server/cart-checkout.js +173 -13
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/channel-order-updates.d.ts +50 -0
- package/src/lib/server/channel-order-updates.js +290 -0
- package/src/lib/server/channel-order-updates.js.map +1 -0
- package/src/lib/server/channel-orders.d.ts +85 -0
- package/src/lib/server/channel-orders.js +543 -0
- package/src/lib/server/channel-orders.js.map +1 -0
- package/src/lib/server/checkout-extras.js +18 -4
- package/src/lib/server/checkout-extras.js.map +1 -1
- package/src/lib/server/checkout.js +71 -14
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/local-fulfillment-status.d.ts +86 -0
- package/src/lib/server/local-fulfillment-status.js +379 -0
- package/src/lib/server/local-fulfillment-status.js.map +1 -0
- package/src/lib/server/local-fulfillment.d.ts +190 -0
- package/src/lib/server/local-fulfillment.js +580 -0
- package/src/lib/server/local-fulfillment.js.map +1 -0
- package/src/lib/server/membership-register.js +3 -1
- package/src/lib/server/membership-register.js.map +1 -1
- package/src/lib/server/order-notifications.js +61 -0
- package/src/lib/server/order-notifications.js.map +1 -1
- package/src/lib/server/pos-display.d.ts +27 -1
- package/src/lib/server/pos-display.js +50 -9
- package/src/lib/server/pos-display.js.map +1 -1
- package/src/lib/server/pos-kiosk-principal.d.ts +29 -0
- package/src/lib/server/pos-kiosk-principal.js +42 -0
- package/src/lib/server/pos-kiosk-principal.js.map +1 -0
- package/src/lib/server/pos-kiosk.d.ts +54 -0
- package/src/lib/server/pos-kiosk.js +972 -0
- package/src/lib/server/pos-kiosk.js.map +1 -0
- package/src/lib/server/pos-offline-sync.d.ts +85 -0
- package/src/lib/server/pos-offline-sync.js +765 -0
- package/src/lib/server/pos-offline-sync.js.map +1 -0
- package/src/lib/server/pos-order.js +22 -4
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/pos-payment.d.ts +6 -0
- package/src/lib/server/pos-payment.js +225 -6
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/pos-print.js +5 -0
- package/src/lib/server/pos-print.js.map +1 -1
- package/src/lib/server/pos-return.js +27 -0
- package/src/lib/server/pos-return.js.map +1 -1
- package/src/lib/server/pos-sale.d.ts +6 -0
- package/src/lib/server/pos-sale.js +2 -0
- package/src/lib/server/pos-sale.js.map +1 -1
- package/src/lib/server/pos-shift.js +8 -1
- package/src/lib/server/pos-shift.js.map +1 -1
- package/src/lib/server/product-catalog.js +5 -1
- package/src/lib/server/product-catalog.js.map +1 -1
- package/src/lib/server/product-drafts.d.ts +5 -1
- package/src/lib/server/product-drafts.js +3 -3
- package/src/lib/server/product-drafts.js.map +1 -1
- package/src/lib/server/product-writer.d.ts +19 -0
- package/src/lib/server/product-writer.js +261 -0
- package/src/lib/server/product-writer.js.map +1 -0
- package/src/lib/server/products-write.d.ts +61 -0
- package/src/lib/server/products-write.js +375 -0
- package/src/lib/server/products-write.js.map +1 -0
- package/src/lib/server/refund.js +3 -0
- package/src/lib/server/refund.js.map +1 -1
- package/src/lib/server/stock-hold.d.ts +9 -1
- package/src/lib/server/stock-hold.js +15 -7
- package/src/lib/server/stock-hold.js.map +1 -1
- package/src/lib/server.js +21 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/tenant-emails.js +161 -0
- package/src/lib/tenant-emails.js.map +1 -1
- package/src/lib/testing/memory-firestore.d.ts +16 -3
- package/src/lib/testing/memory-firestore.js +11 -3
- package/src/lib/testing/memory-firestore.js.map +1 -1
- package/src/lib/transfer/products.server.d.ts +5 -0
- package/src/lib/transfer/products.server.js +2 -2
- package/src/lib/transfer/products.server.js.map +1 -1
|
@@ -13,8 +13,10 @@
|
|
|
13
13
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
|
-
*/ import {
|
|
16
|
+
*/ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
17
|
+
import { fulfillmentIsActive, fulfillmentLineQuantities } from "./order-fulfillment.js";
|
|
17
18
|
import { carrierLabelFor, fulfillmentTrackingUrl } from "./tracking-url.js";
|
|
19
|
+
import { ORDER_LOCAL_DELIVERY_STATUS_LABELS, ORDER_PICKUP_STATUS_LABELS, orderLocalDeliveryStatus, orderPickupStatus } from "./order-local-fulfillment.js";
|
|
18
20
|
const STATUS_LABELS = {
|
|
19
21
|
pending: 'Awaiting payment',
|
|
20
22
|
paid: 'Confirmed',
|
|
@@ -33,13 +35,22 @@ function eventAt(order, ...events) {
|
|
|
33
35
|
return found ? Number(found.atMs) || null : null;
|
|
34
36
|
}
|
|
35
37
|
/** Builds the public projection. Pure; the caller has verified the link. */ export function buildOrderStatusView(input) {
|
|
36
|
-
var _order_lineItems, _order_fulfillments, _order_refundedLineItemIds, _ref, _order_amountCents, _eventAt, _ref1, _STATUS_LABELS_status, _ref2, _ref3, _ref4, _ref5, _order_refundedCents, _order_extras, _input_actions;
|
|
38
|
+
var _order_lineItems, _order_fulfillments, _order_refundedLineItemIds, _ref, _order_amountCents, _eventAt, _ref1, _STATUS_LABELS_status, _ref2, _ref3, _ref4, _ref5, _order_refundedCents, _order_extras, _input_actions, _pickup_locationName, _pickup_address, _pickup_hours, _pickup_instructions, _delivery_windowLabel;
|
|
37
39
|
var _shipments_;
|
|
38
40
|
const { order } = input;
|
|
39
41
|
const lineItems = (_order_lineItems = order.lineItems) != null ? _order_lineItems : [];
|
|
40
42
|
const active = ((_order_fulfillments = order.fulfillments) != null ? _order_fulfillments : []).filter(fulfillmentIsActive);
|
|
43
|
+
// A handover is not a parcel (AGL-3624): it has no carrier or tracking,
|
|
44
|
+
// and the pickup or delivery block below says what happened.
|
|
45
|
+
const parcels = active.filter((fulfillment)=>!fulfillment.handover);
|
|
41
46
|
const shippedByLine = new Map();
|
|
42
|
-
const
|
|
47
|
+
for (const fulfillment of active.filter((entry)=>entry.handover)){
|
|
48
|
+
for (const entry of fulfillmentLineQuantities(order, fulfillment)){
|
|
49
|
+
var _shippedByLine_get;
|
|
50
|
+
shippedByLine.set(entry.lineItemId, ((_shippedByLine_get = shippedByLine.get(entry.lineItemId)) != null ? _shippedByLine_get : 0) + entry.quantity);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const shipments = parcels.map((fulfillment)=>{
|
|
43
54
|
var _fulfillment_id, _fulfillment_trackingNumber;
|
|
44
55
|
const quantities = fulfillmentLineQuantities(order, fulfillment);
|
|
45
56
|
for (const entry of quantities){
|
|
@@ -95,6 +106,8 @@ function eventAt(order, ...events) {
|
|
|
95
106
|
done: status !== 'pending' && paidAtMs !== null
|
|
96
107
|
}
|
|
97
108
|
];
|
|
109
|
+
const pickup = order.fulfillmentMethod === 'pickup' ? order.pickup : undefined;
|
|
110
|
+
const delivery = order.fulfillmentMethod === 'local_delivery' ? order.localDelivery : undefined;
|
|
98
111
|
if (status === 'cancelled') {
|
|
99
112
|
steps.push({
|
|
100
113
|
key: 'cancelled',
|
|
@@ -102,6 +115,32 @@ function eventAt(order, ...events) {
|
|
|
102
115
|
atMs: eventAt(order, 'cancelled'),
|
|
103
116
|
done: true
|
|
104
117
|
});
|
|
118
|
+
} else if (pickup) {
|
|
119
|
+
const pickupStatus = orderPickupStatus(pickup.status);
|
|
120
|
+
steps.push({
|
|
121
|
+
key: 'ready_for_pickup',
|
|
122
|
+
label: 'Ready for pickup',
|
|
123
|
+
atMs: Number(pickup.readyAtMs) || null,
|
|
124
|
+
done: pickupStatus !== 'preparing'
|
|
125
|
+
}, {
|
|
126
|
+
key: 'picked_up',
|
|
127
|
+
label: 'Picked up',
|
|
128
|
+
atMs: Number(pickup.pickedUpAtMs) || null,
|
|
129
|
+
done: pickupStatus === 'picked_up'
|
|
130
|
+
});
|
|
131
|
+
} else if (delivery) {
|
|
132
|
+
const deliveryStatus = orderLocalDeliveryStatus(delivery.status);
|
|
133
|
+
steps.push({
|
|
134
|
+
key: 'out_for_delivery',
|
|
135
|
+
label: 'Out for delivery',
|
|
136
|
+
atMs: Number(delivery.outForDeliveryAtMs) || null,
|
|
137
|
+
done: deliveryStatus === 'out_for_delivery' || deliveryStatus === 'delivered'
|
|
138
|
+
}, {
|
|
139
|
+
key: 'delivered',
|
|
140
|
+
label: 'Delivered',
|
|
141
|
+
atMs: Number(delivery.deliveredAtMs) || deliveredAt,
|
|
142
|
+
done: deliveryStatus === 'delivered' || status === 'delivered'
|
|
143
|
+
});
|
|
105
144
|
} else {
|
|
106
145
|
steps.push({
|
|
107
146
|
key: 'shipped',
|
|
@@ -127,11 +166,11 @@ function eventAt(order, ...events) {
|
|
|
127
166
|
done: true
|
|
128
167
|
});
|
|
129
168
|
}
|
|
130
|
-
return {
|
|
169
|
+
return _extends({
|
|
131
170
|
storeName: input.storeName,
|
|
132
171
|
number: input.number,
|
|
133
172
|
status,
|
|
134
|
-
statusLabel: (_STATUS_LABELS_status = STATUS_LABELS[status]) != null ? _STATUS_LABELS_status : 'Confirmed',
|
|
173
|
+
statusLabel: pickup && status !== 'refunded' && status !== 'cancelled' ? ORDER_PICKUP_STATUS_LABELS[orderPickupStatus(pickup.status)] : delivery && status !== 'refunded' && status !== 'cancelled' ? ORDER_LOCAL_DELIVERY_STATUS_LABELS[orderLocalDeliveryStatus(delivery.status)] : (_STATUS_LABELS_status = STATUS_LABELS[status]) != null ? _STATUS_LABELS_status : 'Confirmed',
|
|
135
174
|
createdAtMs,
|
|
136
175
|
currency: input.currency || 'USD',
|
|
137
176
|
lines,
|
|
@@ -150,7 +189,22 @@ function eventAt(order, ...events) {
|
|
|
150
189
|
shipments,
|
|
151
190
|
steps,
|
|
152
191
|
actions: (_input_actions = input.actions) != null ? _input_actions : []
|
|
153
|
-
}
|
|
192
|
+
}, pickup ? {
|
|
193
|
+
pickup: {
|
|
194
|
+
locationName: String((_pickup_locationName = pickup.locationName) != null ? _pickup_locationName : ''),
|
|
195
|
+
address: (_pickup_address = pickup.address) != null ? _pickup_address : null,
|
|
196
|
+
hours: (_pickup_hours = pickup.hours) != null ? _pickup_hours : null,
|
|
197
|
+
instructions: (_pickup_instructions = pickup.instructions) != null ? _pickup_instructions : null,
|
|
198
|
+
status: orderPickupStatus(pickup.status),
|
|
199
|
+
statusLabel: ORDER_PICKUP_STATUS_LABELS[orderPickupStatus(pickup.status)]
|
|
200
|
+
}
|
|
201
|
+
} : {}, delivery ? {
|
|
202
|
+
localDelivery: {
|
|
203
|
+
windowLabel: (_delivery_windowLabel = delivery.windowLabel) != null ? _delivery_windowLabel : null,
|
|
204
|
+
status: orderLocalDeliveryStatus(delivery.status),
|
|
205
|
+
statusLabel: ORDER_LOCAL_DELIVERY_STATUS_LABELS[orderLocalDeliveryStatus(delivery.status)]
|
|
206
|
+
}
|
|
207
|
+
} : {});
|
|
154
208
|
}
|
|
155
209
|
|
|
156
210
|
//# sourceMappingURL=order-status-view.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/order-status-view.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 { HostOrder, OrderStatus } from './commerce-orders'\nimport { fulfillmentIsActive, fulfillmentLineQuantities } from './order-fulfillment'\nimport { carrierLabelFor, fulfillmentTrackingUrl } from './tracking-url'\n\n/**\n * What the guest order-status page shows (AGL-3610): the ONE projection of an\n * order that leaves the server for a visitor holding a signed link.\n *\n * Allow-listed, never spread: an order document carries the buyer's email,\n * phone and addresses, Stripe ids, risk signals and the merchant's notes, and\n * a forwarded link must disclose no more than the email it arrived in. Every\n * field below is one the buyer's own receipt or shipping email already\n * states. New fields are added here deliberately, or not at all.\n */\nexport interface OrderStatusLine {\n name: string\n variantLabel: string | null\n quantity: number\n amountCents: number\n /** Units of this line in an active shipment. */\n shippedQuantity: number\n refunded: boolean\n}\n\nexport interface OrderStatusShipment {\n id: string\n atMs: number\n carrier: string | null\n trackingNumber: string | null\n trackingUrl: string | null\n lines: Array<{ name: string; quantity: number }>\n}\n\nexport interface OrderStatusStep {\n key: 'placed' | 'paid' | 'shipped' | 'delivered' | 'cancelled' | 'refunded'\n label: string\n atMs: number | null\n done: boolean\n}\n\n/**\n * Something the buyer can do from the page — \"Request a return\" is the case\n * the order-processing lane (AGL-3611) adds through\n * `registerOrderStatusActions` on the server. The page renders each as a\n * button to `url`; it knows nothing of what the action is.\n */\nexport interface OrderStatusAction {\n id: string\n label: string\n url: string\n}\n\nexport interface OrderStatusView {\n storeName: string\n number: string\n status: OrderStatus\n /** The status as a buyer reads it. */\n statusLabel: string\n createdAtMs: number | null\n currency: string\n lines: OrderStatusLine[]\n totals: {\n itemsCents: number\n shippingCents: number\n taxCents: number\n discountCents: number\n totalCents: number\n refundedCents: number\n }\n /**\n * Optional lines the buyer took at checkout (AGL-3635) — \"Package\n * protection\" — by the name and price their receipt states. Optional so\n * an answer from before this field reads as none.\n */\n extras?: Array<{ label: string; amountCents: number }>\n shipments: OrderStatusShipment[]\n steps: OrderStatusStep[]\n actions: OrderStatusAction[]\n}\n\nconst STATUS_LABELS: Record<OrderStatus, string> = {\n pending: 'Awaiting payment',\n paid: 'Confirmed',\n partially_fulfilled: 'Partly shipped',\n fulfilled: 'Shipped',\n delivered: 'Delivered',\n cancelled: 'Canceled',\n refunded: 'Refunded',\n}\n\nfunction eventAt(order: HostOrder, ...events: string[]): number | null {\n const found = (order.timeline ?? []).find((entry) =>\n events.includes(String(entry?.event ?? '')),\n )\n return found ? Number(found.atMs) || null : null\n}\n\n/** Builds the public projection. Pure; the caller has verified the link. */\nexport function buildOrderStatusView(input: {\n order: HostOrder\n orderId: string\n storeName: string\n currency?: string\n number: string\n actions?: OrderStatusAction[]\n}): OrderStatusView {\n const { order } = input\n const lineItems = order.lineItems ?? []\n const active = (order.fulfillments ?? []).filter(fulfillmentIsActive)\n const shippedByLine = new Map<number, number>()\n const shipments: OrderStatusShipment[] = active\n .map((fulfillment) => {\n const quantities = fulfillmentLineQuantities(order, fulfillment)\n for (const entry of quantities) {\n shippedByLine.set(\n entry.lineItemId,\n (shippedByLine.get(entry.lineItemId) ?? 0) + entry.quantity,\n )\n }\n return {\n id: String(fulfillment.id ?? ''),\n atMs: Number(fulfillment.atMs) || 0,\n carrier: fulfillment.carrier ? carrierLabelFor(fulfillment.carrier) : null,\n trackingNumber: fulfillment.trackingNumber ?? null,\n trackingUrl: fulfillmentTrackingUrl(fulfillment),\n lines: quantities.map((entry) => ({\n name: String(lineItems[entry.lineItemId]?.name ?? 'Item'),\n quantity: entry.quantity,\n })),\n }\n })\n .sort((a, b) => a.atMs - b.atMs)\n const refundedLines = new Set(order.refundedLineItemIds ?? [])\n const lines: OrderStatusLine[] = lineItems.map((line, index) => ({\n name: String(line.name ?? 'Item'),\n variantLabel: line.variantLabel ?? null,\n quantity: Number(line.quantity) || 0,\n amountCents: (Number(line.unitAmountCents) || 0) * (Number(line.quantity) || 0),\n shippedQuantity: Math.min(Number(line.quantity) || 0, shippedByLine.get(index) ?? 0),\n refunded: refundedLines.has(index),\n }))\n const totals = order.totals\n const totalCents = totals?.totalCents ?? Number(order.amountCents ?? 0)\n const status = order.status\n const createdAtMs = Number(order.createdAtMs) || null\n const paidAtMs = eventAt(order, 'paid') ?? (status !== 'pending' ? createdAtMs : null)\n const firstShipAt = shipments[0]?.atMs ?? eventAt(order, 'fulfilled', 'partially_fulfilled')\n const deliveredAt = eventAt(order, 'delivered')\n const steps: OrderStatusStep[] = [\n { key: 'placed', label: 'Order placed', atMs: createdAtMs, done: true },\n {\n key: 'paid',\n label: 'Payment confirmed',\n atMs: paidAtMs,\n done: status !== 'pending' && paidAtMs !== null,\n },\n ]\n if (status === 'cancelled') {\n steps.push({ key: 'cancelled', label: 'Canceled', atMs: eventAt(order, 'cancelled'), done: true })\n } else {\n steps.push(\n {\n key: 'shipped',\n label: status === 'partially_fulfilled' ? 'Partly shipped' : 'Shipped',\n atMs: firstShipAt,\n done: ['partially_fulfilled', 'fulfilled', 'delivered'].includes(status) ||\n shipments.length > 0,\n },\n {\n key: 'delivered',\n label: 'Delivered',\n atMs: deliveredAt,\n done: status === 'delivered' || deliveredAt !== null,\n },\n )\n }\n if (status === 'refunded') {\n steps.push({ key: 'refunded', label: 'Refunded', atMs: eventAt(order, 'refund'), done: true })\n }\n return {\n storeName: input.storeName,\n number: input.number,\n status,\n statusLabel: STATUS_LABELS[status] ?? 'Confirmed',\n createdAtMs,\n currency: input.currency || 'USD',\n lines,\n totals: {\n itemsCents: totals?.itemsCents ?? lines.reduce((sum, line) => sum + line.amountCents, 0),\n shippingCents: totals?.shippingCents ?? 0,\n taxCents: totals?.taxCents ?? 0,\n discountCents: totals?.discountCents ?? 0,\n totalCents,\n refundedCents: Number(order.refundedCents ?? 0) || 0,\n },\n extras: (order.extras ?? [])\n .filter((extra) => extra && Number(extra.amountCents) > 0)\n .map((extra) => ({ label: String(extra.label || 'Extra'), amountCents: Number(extra.amountCents) })),\n shipments,\n steps,\n actions: input.actions ?? [],\n }\n}\n"],"names":["fulfillmentIsActive","fulfillmentLineQuantities","carrierLabelFor","fulfillmentTrackingUrl","STATUS_LABELS","pending","paid","partially_fulfilled","fulfilled","delivered","cancelled","refunded","eventAt","order","events","found","timeline","find","entry","includes","String","event","Number","atMs","buildOrderStatusView","input","shipments","lineItems","active","fulfillments","filter","shippedByLine","Map","map","fulfillment","quantities","set","lineItemId","get","quantity","id","carrier","trackingNumber","trackingUrl","lines","name","sort","a","b","refundedLines","Set","refundedLineItemIds","line","index","variantLabel","amountCents","unitAmountCents","shippedQuantity","Math","min","has","totals","totalCents","status","createdAtMs","paidAtMs","firstShipAt","deliveredAt","steps","key","label","done","push","length","storeName","number","statusLabel","currency","itemsCents","reduce","sum","shippingCents","taxCents","discountCents","refundedCents","extras","extra","actions"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/order-status-view.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 { HostOrder, OrderStatus } from './commerce-orders'\nimport { fulfillmentIsActive, fulfillmentLineQuantities } from './order-fulfillment'\nimport { carrierLabelFor, fulfillmentTrackingUrl } from './tracking-url'\nimport {\n ORDER_LOCAL_DELIVERY_STATUS_LABELS,\n ORDER_PICKUP_STATUS_LABELS,\n orderLocalDeliveryStatus,\n orderPickupStatus,\n type OrderLocalDeliveryStatus,\n type OrderPickupStatus,\n} from './order-local-fulfillment'\n\n/**\n * What the guest order-status page shows (AGL-3610): the ONE projection of an\n * order that leaves the server for a visitor holding a signed link.\n *\n * Allow-listed, never spread: an order document carries the buyer's email,\n * phone and addresses, Stripe ids, risk signals and the merchant's notes, and\n * a forwarded link must disclose no more than the email it arrived in. Every\n * field below is one the buyer's own receipt or shipping email already\n * states. New fields are added here deliberately, or not at all.\n */\nexport interface OrderStatusLine {\n name: string\n variantLabel: string | null\n quantity: number\n amountCents: number\n /** Units of this line in an active shipment. */\n shippedQuantity: number\n refunded: boolean\n}\n\nexport interface OrderStatusShipment {\n id: string\n atMs: number\n carrier: string | null\n trackingNumber: string | null\n trackingUrl: string | null\n lines: Array<{ name: string; quantity: number }>\n}\n\nexport interface OrderStatusStep {\n key:\n | 'placed'\n | 'paid'\n | 'shipped'\n | 'delivered'\n | 'cancelled'\n | 'refunded'\n // Pickup and the store's own delivery (AGL-3624).\n | 'ready_for_pickup'\n | 'picked_up'\n | 'out_for_delivery'\n label: string\n atMs: number | null\n done: boolean\n}\n\n/**\n * Something the buyer can do from the page — \"Request a return\" is the case\n * the order-processing lane (AGL-3611) adds through\n * `registerOrderStatusActions` on the server. The page renders each as a\n * button to `url`; it knows nothing of what the action is.\n */\nexport interface OrderStatusAction {\n id: string\n label: string\n url: string\n}\n\nexport interface OrderStatusView {\n storeName: string\n number: string\n status: OrderStatus\n /** The status as a buyer reads it. */\n statusLabel: string\n createdAtMs: number | null\n currency: string\n lines: OrderStatusLine[]\n totals: {\n itemsCents: number\n shippingCents: number\n taxCents: number\n discountCents: number\n totalCents: number\n refundedCents: number\n }\n /**\n * Optional lines the buyer took at checkout (AGL-3635) — \"Package\n * protection\" — by the name and price their receipt states. Optional so\n * an answer from before this field reads as none.\n */\n extras?: Array<{ label: string; amountCents: number }>\n shipments: OrderStatusShipment[]\n steps: OrderStatusStep[]\n actions: OrderStatusAction[]\n /**\n * Where to collect a pickup order (AGL-3624) — the location the buyer chose\n * and its hours, as the ready-for-pickup email states them.\n */\n pickup?: {\n locationName: string\n address: string | null\n hours: string | null\n instructions: string | null\n status: OrderPickupStatus\n statusLabel: string\n }\n /** When the store's own driver brings it (AGL-3624). */\n localDelivery?: {\n windowLabel: string | null\n status: OrderLocalDeliveryStatus\n statusLabel: string\n }\n}\n\nconst STATUS_LABELS: Record<OrderStatus, string> = {\n pending: 'Awaiting payment',\n paid: 'Confirmed',\n partially_fulfilled: 'Partly shipped',\n fulfilled: 'Shipped',\n delivered: 'Delivered',\n cancelled: 'Canceled',\n refunded: 'Refunded',\n}\n\nfunction eventAt(order: HostOrder, ...events: string[]): number | null {\n const found = (order.timeline ?? []).find((entry) =>\n events.includes(String(entry?.event ?? '')),\n )\n return found ? Number(found.atMs) || null : null\n}\n\n/** Builds the public projection. Pure; the caller has verified the link. */\nexport function buildOrderStatusView(input: {\n order: HostOrder\n orderId: string\n storeName: string\n currency?: string\n number: string\n actions?: OrderStatusAction[]\n}): OrderStatusView {\n const { order } = input\n const lineItems = order.lineItems ?? []\n const active = (order.fulfillments ?? []).filter(fulfillmentIsActive)\n // A handover is not a parcel (AGL-3624): it has no carrier or tracking,\n // and the pickup or delivery block below says what happened.\n const parcels = active.filter((fulfillment) => !fulfillment.handover)\n const shippedByLine = new Map<number, number>()\n for (const fulfillment of active.filter((entry) => entry.handover)) {\n for (const entry of fulfillmentLineQuantities(order, fulfillment)) {\n shippedByLine.set(entry.lineItemId, (shippedByLine.get(entry.lineItemId) ?? 0) + entry.quantity)\n }\n }\n const shipments: OrderStatusShipment[] = parcels\n .map((fulfillment) => {\n const quantities = fulfillmentLineQuantities(order, fulfillment)\n for (const entry of quantities) {\n shippedByLine.set(\n entry.lineItemId,\n (shippedByLine.get(entry.lineItemId) ?? 0) + entry.quantity,\n )\n }\n return {\n id: String(fulfillment.id ?? ''),\n atMs: Number(fulfillment.atMs) || 0,\n carrier: fulfillment.carrier ? carrierLabelFor(fulfillment.carrier) : null,\n trackingNumber: fulfillment.trackingNumber ?? null,\n trackingUrl: fulfillmentTrackingUrl(fulfillment),\n lines: quantities.map((entry) => ({\n name: String(lineItems[entry.lineItemId]?.name ?? 'Item'),\n quantity: entry.quantity,\n })),\n }\n })\n .sort((a, b) => a.atMs - b.atMs)\n const refundedLines = new Set(order.refundedLineItemIds ?? [])\n const lines: OrderStatusLine[] = lineItems.map((line, index) => ({\n name: String(line.name ?? 'Item'),\n variantLabel: line.variantLabel ?? null,\n quantity: Number(line.quantity) || 0,\n amountCents: (Number(line.unitAmountCents) || 0) * (Number(line.quantity) || 0),\n shippedQuantity: Math.min(Number(line.quantity) || 0, shippedByLine.get(index) ?? 0),\n refunded: refundedLines.has(index),\n }))\n const totals = order.totals\n const totalCents = totals?.totalCents ?? Number(order.amountCents ?? 0)\n const status = order.status\n const createdAtMs = Number(order.createdAtMs) || null\n const paidAtMs = eventAt(order, 'paid') ?? (status !== 'pending' ? createdAtMs : null)\n const firstShipAt = shipments[0]?.atMs ?? eventAt(order, 'fulfilled', 'partially_fulfilled')\n const deliveredAt = eventAt(order, 'delivered')\n const steps: OrderStatusStep[] = [\n { key: 'placed', label: 'Order placed', atMs: createdAtMs, done: true },\n {\n key: 'paid',\n label: 'Payment confirmed',\n atMs: paidAtMs,\n done: status !== 'pending' && paidAtMs !== null,\n },\n ]\n const pickup = order.fulfillmentMethod === 'pickup' ? order.pickup : undefined\n const delivery = order.fulfillmentMethod === 'local_delivery' ? order.localDelivery : undefined\n if (status === 'cancelled') {\n steps.push({ key: 'cancelled', label: 'Canceled', atMs: eventAt(order, 'cancelled'), done: true })\n } else if (pickup) {\n const pickupStatus = orderPickupStatus(pickup.status)\n steps.push(\n {\n key: 'ready_for_pickup',\n label: 'Ready for pickup',\n atMs: Number(pickup.readyAtMs) || null,\n done: pickupStatus !== 'preparing',\n },\n {\n key: 'picked_up',\n label: 'Picked up',\n atMs: Number(pickup.pickedUpAtMs) || null,\n done: pickupStatus === 'picked_up',\n },\n )\n } else if (delivery) {\n const deliveryStatus = orderLocalDeliveryStatus(delivery.status)\n steps.push(\n {\n key: 'out_for_delivery',\n label: 'Out for delivery',\n atMs: Number(delivery.outForDeliveryAtMs) || null,\n done: deliveryStatus === 'out_for_delivery' || deliveryStatus === 'delivered',\n },\n {\n key: 'delivered',\n label: 'Delivered',\n atMs: Number(delivery.deliveredAtMs) || deliveredAt,\n done: deliveryStatus === 'delivered' || status === 'delivered',\n },\n )\n } else {\n steps.push(\n {\n key: 'shipped',\n label: status === 'partially_fulfilled' ? 'Partly shipped' : 'Shipped',\n atMs: firstShipAt,\n done: ['partially_fulfilled', 'fulfilled', 'delivered'].includes(status) ||\n shipments.length > 0,\n },\n {\n key: 'delivered',\n label: 'Delivered',\n atMs: deliveredAt,\n done: status === 'delivered' || deliveredAt !== null,\n },\n )\n }\n if (status === 'refunded') {\n steps.push({ key: 'refunded', label: 'Refunded', atMs: eventAt(order, 'refund'), done: true })\n }\n return {\n storeName: input.storeName,\n number: input.number,\n status,\n statusLabel:\n pickup && status !== 'refunded' && status !== 'cancelled'\n ? ORDER_PICKUP_STATUS_LABELS[orderPickupStatus(pickup.status)]\n : delivery && status !== 'refunded' && status !== 'cancelled'\n ? ORDER_LOCAL_DELIVERY_STATUS_LABELS[orderLocalDeliveryStatus(delivery.status)]\n : (STATUS_LABELS[status] ?? 'Confirmed'),\n createdAtMs,\n currency: input.currency || 'USD',\n lines,\n totals: {\n itemsCents: totals?.itemsCents ?? lines.reduce((sum, line) => sum + line.amountCents, 0),\n shippingCents: totals?.shippingCents ?? 0,\n taxCents: totals?.taxCents ?? 0,\n discountCents: totals?.discountCents ?? 0,\n totalCents,\n refundedCents: Number(order.refundedCents ?? 0) || 0,\n },\n extras: (order.extras ?? [])\n .filter((extra) => extra && Number(extra.amountCents) > 0)\n .map((extra) => ({ label: String(extra.label || 'Extra'), amountCents: Number(extra.amountCents) })),\n shipments,\n steps,\n actions: input.actions ?? [],\n ...(pickup\n ? {\n pickup: {\n locationName: String(pickup.locationName ?? ''),\n address: pickup.address ?? null,\n hours: pickup.hours ?? null,\n instructions: pickup.instructions ?? null,\n status: orderPickupStatus(pickup.status),\n statusLabel: ORDER_PICKUP_STATUS_LABELS[orderPickupStatus(pickup.status)],\n },\n }\n : {}),\n ...(delivery\n ? {\n localDelivery: {\n windowLabel: delivery.windowLabel ?? null,\n status: orderLocalDeliveryStatus(delivery.status),\n statusLabel: ORDER_LOCAL_DELIVERY_STATUS_LABELS[orderLocalDeliveryStatus(delivery.status)],\n },\n }\n : {}),\n }\n}\n"],"names":["fulfillmentIsActive","fulfillmentLineQuantities","carrierLabelFor","fulfillmentTrackingUrl","ORDER_LOCAL_DELIVERY_STATUS_LABELS","ORDER_PICKUP_STATUS_LABELS","orderLocalDeliveryStatus","orderPickupStatus","STATUS_LABELS","pending","paid","partially_fulfilled","fulfilled","delivered","cancelled","refunded","eventAt","order","events","found","timeline","find","entry","includes","String","event","Number","atMs","buildOrderStatusView","input","pickup","delivery","shipments","lineItems","active","fulfillments","filter","parcels","fulfillment","handover","shippedByLine","Map","set","lineItemId","get","quantity","map","quantities","id","carrier","trackingNumber","trackingUrl","lines","name","sort","a","b","refundedLines","Set","refundedLineItemIds","line","index","variantLabel","amountCents","unitAmountCents","shippedQuantity","Math","min","has","totals","totalCents","status","createdAtMs","paidAtMs","firstShipAt","deliveredAt","steps","key","label","done","fulfillmentMethod","undefined","localDelivery","push","pickupStatus","readyAtMs","pickedUpAtMs","deliveryStatus","outForDeliveryAtMs","deliveredAtMs","length","storeName","number","statusLabel","currency","itemsCents","reduce","sum","shippingCents","taxCents","discountCents","refundedCents","extras","extra","actions","locationName","address","hours","instructions","windowLabel"],"mappings":"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"}
|
|
@@ -0,0 +1,186 @@
|
|
|
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 HostProduct, type InventoryAdjustment, type InventoryAdjustmentReason, type SmartCollectionRules } from './commerce';
|
|
18
|
+
/** A product as the editor holds it: the stored fields plus keys the listener or a seed may carry. */
|
|
19
|
+
export type EditedProduct = HostProduct & {
|
|
20
|
+
$id?: string;
|
|
21
|
+
skus?: string[];
|
|
22
|
+
barcodes?: string[];
|
|
23
|
+
stockHolds?: Record<string, unknown>;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The fields a product save writes, before its collection membership and its
|
|
27
|
+
* timestamps: the product as edited, with
|
|
28
|
+
*
|
|
29
|
+
* - `$id` dropped (AGL-1374): the listener's synthetic key, never a field;
|
|
30
|
+
* - the seed's `skus` / `barcodes` dropped (AGL-3321): `productSearchFields`
|
|
31
|
+
* omits each when no variant has one, so a seeded copy would outlive the
|
|
32
|
+
* last SKU;
|
|
33
|
+
* - the trimmed name with the search keys derived from it, together, so the
|
|
34
|
+
* two cannot drift (AGL-2501);
|
|
35
|
+
* - a slug, the primary variant's price, the stock fields, the first image
|
|
36
|
+
* and `updatedAtMs`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function productSaveFields(current: EditedProduct, nowMs: number): {
|
|
39
|
+
imageUrl: string;
|
|
40
|
+
updatedAtMs: number;
|
|
41
|
+
inventory: number | null;
|
|
42
|
+
soldOut: boolean;
|
|
43
|
+
slug: string;
|
|
44
|
+
priceUsd: number;
|
|
45
|
+
name: string;
|
|
46
|
+
nameLower: string;
|
|
47
|
+
nameTokens: string[];
|
|
48
|
+
nameReversed: string;
|
|
49
|
+
skus?: string[];
|
|
50
|
+
barcodes?: string[];
|
|
51
|
+
priceFromCents?: number;
|
|
52
|
+
description?: string;
|
|
53
|
+
type: import("./commerce").ProductType;
|
|
54
|
+
status: import("./commerce").ProductStatus;
|
|
55
|
+
mediaUrls?: string[];
|
|
56
|
+
categoryIds?: string[];
|
|
57
|
+
collectionIds?: string[];
|
|
58
|
+
tags?: string[];
|
|
59
|
+
options?: import("./commerce").ProductOption[];
|
|
60
|
+
variants: import("./commerce").ProductVariant[];
|
|
61
|
+
seo?: {
|
|
62
|
+
title?: string;
|
|
63
|
+
description?: string;
|
|
64
|
+
imageUrl?: string;
|
|
65
|
+
};
|
|
66
|
+
channel?: import("./product-channel").ProductChannelFacts;
|
|
67
|
+
supplierId?: string;
|
|
68
|
+
oversellPolicy?: "deny" | "backorder";
|
|
69
|
+
taxExempt?: boolean;
|
|
70
|
+
digitalFiles?: Array<{
|
|
71
|
+
url: string;
|
|
72
|
+
fileName: string;
|
|
73
|
+
version?: string;
|
|
74
|
+
}>;
|
|
75
|
+
downloadLimit?: number;
|
|
76
|
+
subscription?: {
|
|
77
|
+
interval: "month" | "year";
|
|
78
|
+
trialDays?: number;
|
|
79
|
+
};
|
|
80
|
+
subscriptionOptional?: boolean;
|
|
81
|
+
gatedVideos?: Array<{
|
|
82
|
+
url: string;
|
|
83
|
+
title?: string;
|
|
84
|
+
}>;
|
|
85
|
+
relatedProductIds?: string[];
|
|
86
|
+
shipping?: import("./commerce").ProductShippingFacts;
|
|
87
|
+
giftCard?: boolean;
|
|
88
|
+
lowStockThreshold?: number;
|
|
89
|
+
modifierGroups?: import("./product-modifiers").ProductModifierGroup[];
|
|
90
|
+
posQuickKey?: boolean;
|
|
91
|
+
createdAtMs?: number;
|
|
92
|
+
deletedAt?: number | null;
|
|
93
|
+
stockHolds?: Record<string, unknown>;
|
|
94
|
+
};
|
|
95
|
+
/** What the smart-collection rules are matched against: the saved name with the product's own facts. */
|
|
96
|
+
export declare function productMembershipInput(fields: {
|
|
97
|
+
name: string;
|
|
98
|
+
}, current: Pick<HostProduct, 'type' | 'tags' | 'categoryIds' | 'variants'>): {
|
|
99
|
+
name: string;
|
|
100
|
+
type: import("./commerce").ProductType;
|
|
101
|
+
tags: string[];
|
|
102
|
+
categoryIds: string[];
|
|
103
|
+
variants: import("./commerce").ProductVariant[];
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* An EDIT's replacing write, without its membership and server timestamp:
|
|
107
|
+
* live stock holds are not the editor's to write (AGL-2356), so the seed's
|
|
108
|
+
* are dropped and the stored ones carried; the product stays live
|
|
109
|
+
* (`deletedAt: null`, AGL-3321).
|
|
110
|
+
*/
|
|
111
|
+
export declare function productEditWrite(fields: ReturnType<typeof productSaveFields>, liveHolds: Record<string, unknown> | null | undefined): {
|
|
112
|
+
deletedAt: any;
|
|
113
|
+
stockHolds?: Record<string, unknown>;
|
|
114
|
+
imageUrl: string;
|
|
115
|
+
updatedAtMs: number;
|
|
116
|
+
inventory: number | null;
|
|
117
|
+
soldOut: boolean;
|
|
118
|
+
slug: string;
|
|
119
|
+
priceUsd: number;
|
|
120
|
+
name: string;
|
|
121
|
+
nameLower: string;
|
|
122
|
+
nameTokens: string[];
|
|
123
|
+
nameReversed: string;
|
|
124
|
+
skus?: string[];
|
|
125
|
+
barcodes?: string[];
|
|
126
|
+
priceFromCents?: number;
|
|
127
|
+
description?: string;
|
|
128
|
+
type: import("./commerce").ProductType;
|
|
129
|
+
status: import("./commerce").ProductStatus;
|
|
130
|
+
mediaUrls?: string[];
|
|
131
|
+
categoryIds?: string[];
|
|
132
|
+
collectionIds?: string[];
|
|
133
|
+
tags?: string[];
|
|
134
|
+
options?: import("./commerce").ProductOption[];
|
|
135
|
+
variants: import("./commerce").ProductVariant[];
|
|
136
|
+
seo?: {
|
|
137
|
+
title?: string;
|
|
138
|
+
description?: string;
|
|
139
|
+
imageUrl?: string;
|
|
140
|
+
};
|
|
141
|
+
channel?: import("./product-channel").ProductChannelFacts;
|
|
142
|
+
supplierId?: string;
|
|
143
|
+
oversellPolicy?: "deny" | "backorder";
|
|
144
|
+
taxExempt?: boolean;
|
|
145
|
+
digitalFiles?: Array<{
|
|
146
|
+
url: string;
|
|
147
|
+
fileName: string;
|
|
148
|
+
version?: string;
|
|
149
|
+
}>;
|
|
150
|
+
downloadLimit?: number;
|
|
151
|
+
subscription?: {
|
|
152
|
+
interval: "month" | "year";
|
|
153
|
+
trialDays?: number;
|
|
154
|
+
};
|
|
155
|
+
subscriptionOptional?: boolean;
|
|
156
|
+
gatedVideos?: Array<{
|
|
157
|
+
url: string;
|
|
158
|
+
title?: string;
|
|
159
|
+
}>;
|
|
160
|
+
relatedProductIds?: string[];
|
|
161
|
+
shipping?: import("./commerce").ProductShippingFacts;
|
|
162
|
+
giftCard?: boolean;
|
|
163
|
+
lowStockThreshold?: number;
|
|
164
|
+
modifierGroups?: import("./product-modifiers").ProductModifierGroup[];
|
|
165
|
+
posQuickKey?: boolean;
|
|
166
|
+
createdAtMs?: number;
|
|
167
|
+
};
|
|
168
|
+
/** A smart collection as `hosts/{hostId}/collections` stores it, as the membership rules read it. */
|
|
169
|
+
export declare function smartCollectionRulesOf(id: string, data: Record<string, unknown>): SmartCollectionRules;
|
|
170
|
+
/** One stock adjustment, as the Adjust stock dialog asks for it. */
|
|
171
|
+
export interface StockAdjustment {
|
|
172
|
+
variantId: string;
|
|
173
|
+
delta: number;
|
|
174
|
+
reason: InventoryAdjustmentReason;
|
|
175
|
+
locationId?: string;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The product update and the ledger row one stock adjustment writes: the
|
|
179
|
+
* variants with the count moved, the stock fields that move with it
|
|
180
|
+
* (AGL-3321), and the same `inventoryAdjustments` row the sale webhook writes
|
|
181
|
+
* (AGL-281). A zero or non-numeric delta writes nothing.
|
|
182
|
+
*/
|
|
183
|
+
export declare function stockAdjustmentWrite(product: HostProduct, productId: string, adjustment: StockAdjustment, nowMs: number): {
|
|
184
|
+
update: Record<string, unknown>;
|
|
185
|
+
ledger: InventoryAdjustment;
|
|
186
|
+
} | null;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
3
|
+
/**
|
|
4
|
+
* @license
|
|
5
|
+
* Copyright 2026 Aglyn LLC
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/ import { adjustVariantInventory, commerceSlug, productSearchFields, productStockFields } from "./commerce.js";
|
|
19
|
+
/**
|
|
20
|
+
* The fields a product save writes, before its collection membership and its
|
|
21
|
+
* timestamps: the product as edited, with
|
|
22
|
+
*
|
|
23
|
+
* - `$id` dropped (AGL-1374): the listener's synthetic key, never a field;
|
|
24
|
+
* - the seed's `skus` / `barcodes` dropped (AGL-3321): `productSearchFields`
|
|
25
|
+
* omits each when no variant has one, so a seeded copy would outlive the
|
|
26
|
+
* last SKU;
|
|
27
|
+
* - the trimmed name with the search keys derived from it, together, so the
|
|
28
|
+
* two cannot drift (AGL-2501);
|
|
29
|
+
* - a slug, the primary variant's price, the stock fields, the first image
|
|
30
|
+
* and `updatedAtMs`.
|
|
31
|
+
*/ export function productSaveFields(current, nowMs) {
|
|
32
|
+
var _ref, _ref1, _ref2;
|
|
33
|
+
var _current_mediaUrls;
|
|
34
|
+
const { $id: _syntheticId, skus: _seededSkus, barcodes: _seededBarcodes } = current, currentFields = _object_without_properties_loose(current, [
|
|
35
|
+
"$id",
|
|
36
|
+
"skus",
|
|
37
|
+
"barcodes"
|
|
38
|
+
]);
|
|
39
|
+
const primaryVariant = current.variants[0];
|
|
40
|
+
return _extends({}, currentFields, productSearchFields({
|
|
41
|
+
name: current.name.trim().slice(0, 120),
|
|
42
|
+
variants: current.variants
|
|
43
|
+
}), {
|
|
44
|
+
slug: current.slug || commerceSlug(current.name),
|
|
45
|
+
priceUsd: (_ref = primaryVariant == null ? void 0 : primaryVariant.priceUsd) != null ? _ref : 0
|
|
46
|
+
}, productStockFields({
|
|
47
|
+
variants: current.variants,
|
|
48
|
+
oversellPolicy: current.oversellPolicy
|
|
49
|
+
}), {
|
|
50
|
+
imageUrl: (_ref1 = (_ref2 = (_current_mediaUrls = current.mediaUrls) == null ? void 0 : _current_mediaUrls[0]) != null ? _ref2 : current.imageUrl) != null ? _ref1 : null,
|
|
51
|
+
updatedAtMs: nowMs
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/** What the smart-collection rules are matched against: the saved name with the product's own facts. */ export function productMembershipInput(fields, current) {
|
|
55
|
+
return {
|
|
56
|
+
name: fields.name,
|
|
57
|
+
type: current.type,
|
|
58
|
+
tags: current.tags,
|
|
59
|
+
categoryIds: current.categoryIds,
|
|
60
|
+
variants: current.variants
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* An EDIT's replacing write, without its membership and server timestamp:
|
|
65
|
+
* live stock holds are not the editor's to write (AGL-2356), so the seed's
|
|
66
|
+
* are dropped and the stored ones carried; the product stays live
|
|
67
|
+
* (`deletedAt: null`, AGL-3321).
|
|
68
|
+
*/ export function productEditWrite(fields, liveHolds) {
|
|
69
|
+
const { stockHolds: _seededHolds } = fields, withoutHolds = _object_without_properties_loose(fields, [
|
|
70
|
+
"stockHolds"
|
|
71
|
+
]);
|
|
72
|
+
return _extends({}, withoutHolds, liveHolds ? {
|
|
73
|
+
stockHolds: liveHolds
|
|
74
|
+
} : {}, {
|
|
75
|
+
deletedAt: null
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/** A smart collection as `hosts/{hostId}/collections` stores it, as the membership rules read it. */ export function smartCollectionRulesOf(id, data) {
|
|
79
|
+
var _data_rules;
|
|
80
|
+
return {
|
|
81
|
+
id,
|
|
82
|
+
rules: (_data_rules = data['rules']) != null ? _data_rules : [],
|
|
83
|
+
matchAll: data['matchAll']
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The product update and the ledger row one stock adjustment writes: the
|
|
88
|
+
* variants with the count moved, the stock fields that move with it
|
|
89
|
+
* (AGL-3321), and the same `inventoryAdjustments` row the sale webhook writes
|
|
90
|
+
* (AGL-281). A zero or non-numeric delta writes nothing.
|
|
91
|
+
*/ export function stockAdjustmentWrite(product, productId, adjustment, nowMs) {
|
|
92
|
+
const delta = Math.round(Number(adjustment.delta));
|
|
93
|
+
if (!delta) return null;
|
|
94
|
+
const variants = adjustVariantInventory(product, adjustment.variantId, delta, adjustment.locationId || undefined);
|
|
95
|
+
return {
|
|
96
|
+
update: _extends({
|
|
97
|
+
variants
|
|
98
|
+
}, productStockFields(_extends({}, product, {
|
|
99
|
+
variants
|
|
100
|
+
})), {
|
|
101
|
+
updatedAtMs: nowMs
|
|
102
|
+
}),
|
|
103
|
+
ledger: _extends({
|
|
104
|
+
productId,
|
|
105
|
+
variantId: adjustment.variantId,
|
|
106
|
+
delta,
|
|
107
|
+
reason: adjustment.reason
|
|
108
|
+
}, adjustment.locationId ? {
|
|
109
|
+
locationId: adjustment.locationId
|
|
110
|
+
} : {}, {
|
|
111
|
+
atMs: nowMs
|
|
112
|
+
})
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
//# sourceMappingURL=product-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/product-write.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 {\n adjustVariantInventory,\n commerceSlug,\n type HostProduct,\n type InventoryAdjustment,\n type InventoryAdjustmentReason,\n productSearchFields,\n productStockFields,\n type SmartCollectionRules,\n} from './commerce'\n\n/*\n * WHAT A PRODUCT SAVE AND A STOCK ADJUSTMENT WRITE, worked out once.\n *\n * The console's product editor and its Adjust stock dialog compute these\n * fields in the browser before their Firestore writes; the native apps save\n * through `commerce/products/save` and `commerce/products/stock`, which run\n * this same code on the server. One computation, so a product saved from a\n * phone carries exactly the search keys, stock verdict, price, image and\n * smart-collection membership the console would have written.\n */\n\n/** A product as the editor holds it: the stored fields plus keys the listener or a seed may carry. */\nexport type EditedProduct = HostProduct & {\n $id?: string\n skus?: string[]\n barcodes?: string[]\n stockHolds?: Record<string, unknown>\n}\n\n/**\n * The fields a product save writes, before its collection membership and its\n * timestamps: the product as edited, with\n *\n * - `$id` dropped (AGL-1374): the listener's synthetic key, never a field;\n * - the seed's `skus` / `barcodes` dropped (AGL-3321): `productSearchFields`\n * omits each when no variant has one, so a seeded copy would outlive the\n * last SKU;\n * - the trimmed name with the search keys derived from it, together, so the\n * two cannot drift (AGL-2501);\n * - a slug, the primary variant's price, the stock fields, the first image\n * and `updatedAtMs`.\n */\nexport function productSaveFields(current: EditedProduct, nowMs: number) {\n const {\n $id: _syntheticId,\n skus: _seededSkus,\n barcodes: _seededBarcodes,\n ...currentFields\n } = current\n const primaryVariant = current.variants[0]\n return {\n ...currentFields,\n ...productSearchFields({\n name: current.name.trim().slice(0, 120),\n variants: current.variants,\n }),\n slug: current.slug || commerceSlug(current.name),\n priceUsd: primaryVariant?.priceUsd ?? 0,\n ...productStockFields({\n variants: current.variants,\n oversellPolicy: current.oversellPolicy,\n }),\n imageUrl: current.mediaUrls?.[0] ?? current.imageUrl ?? null,\n updatedAtMs: nowMs,\n }\n}\n\n/** What the smart-collection rules are matched against: the saved name with the product's own facts. */\nexport function productMembershipInput(\n fields: { name: string },\n current: Pick<HostProduct, 'type' | 'tags' | 'categoryIds' | 'variants'>,\n) {\n return {\n name: fields.name,\n type: current.type,\n tags: current.tags,\n categoryIds: current.categoryIds,\n variants: current.variants,\n }\n}\n\n/**\n * An EDIT's replacing write, without its membership and server timestamp:\n * live stock holds are not the editor's to write (AGL-2356), so the seed's\n * are dropped and the stored ones carried; the product stays live\n * (`deletedAt: null`, AGL-3321).\n */\nexport function productEditWrite(\n fields: ReturnType<typeof productSaveFields>,\n liveHolds: Record<string, unknown> | null | undefined,\n) {\n const { stockHolds: _seededHolds, ...withoutHolds } = fields as typeof fields & {\n stockHolds?: Record<string, unknown>\n }\n return {\n ...withoutHolds,\n ...(liveHolds ? { stockHolds: liveHolds } : {}),\n deletedAt: null,\n }\n}\n\n/** A smart collection as `hosts/{hostId}/collections` stores it, as the membership rules read it. */\nexport function smartCollectionRulesOf(id: string, data: Record<string, unknown>): SmartCollectionRules {\n return {\n id,\n rules: (data['rules'] as SmartCollectionRules['rules']) ?? [],\n matchAll: data['matchAll'] as boolean | undefined,\n }\n}\n\n/** One stock adjustment, as the Adjust stock dialog asks for it. */\nexport interface StockAdjustment {\n variantId: string\n delta: number\n reason: InventoryAdjustmentReason\n locationId?: string\n}\n\n/**\n * The product update and the ledger row one stock adjustment writes: the\n * variants with the count moved, the stock fields that move with it\n * (AGL-3321), and the same `inventoryAdjustments` row the sale webhook writes\n * (AGL-281). A zero or non-numeric delta writes nothing.\n */\nexport function stockAdjustmentWrite(\n product: HostProduct,\n productId: string,\n adjustment: StockAdjustment,\n nowMs: number,\n): { update: Record<string, unknown>; ledger: InventoryAdjustment } | null {\n const delta = Math.round(Number(adjustment.delta))\n if (!delta) return null\n const variants = adjustVariantInventory(product, adjustment.variantId, delta, adjustment.locationId || undefined)\n return {\n update: {\n variants,\n ...productStockFields({ ...product, variants }),\n updatedAtMs: nowMs,\n },\n ledger: {\n productId,\n variantId: adjustment.variantId,\n delta,\n reason: adjustment.reason,\n ...(adjustment.locationId ? { locationId: adjustment.locationId } : {}),\n atMs: nowMs,\n },\n }\n}\n"],"names":["adjustVariantInventory","commerceSlug","productSearchFields","productStockFields","productSaveFields","current","nowMs","$id","_syntheticId","skus","_seededSkus","barcodes","_seededBarcodes","currentFields","primaryVariant","variants","name","trim","slice","slug","priceUsd","oversellPolicy","imageUrl","mediaUrls","updatedAtMs","productMembershipInput","fields","type","tags","categoryIds","productEditWrite","liveHolds","stockHolds","_seededHolds","withoutHolds","deletedAt","smartCollectionRulesOf","id","data","rules","matchAll","stockAdjustmentWrite","product","productId","adjustment","delta","Math","round","Number","variantId","locationId","undefined","update","ledger","reason","atMs"],"mappings":";;AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,sBAAsB,EACtBC,YAAY,EAIZC,mBAAmB,EACnBC,kBAAkB,QAEb,gBAAY;AAqBnB;;;;;;;;;;;;CAYC,GACD,OAAO,SAASC,kBAAkBC,OAAsB,EAAEC,KAAa;cAoBzDD;QAAAA;IAnBZ,MAAM,EACJE,KAAKC,YAAY,EACjBC,MAAMC,WAAW,EACjBC,UAAUC,eAAe,EAE1B,GAAGP,SADCQ,iDACDR;;;;;IACJ,MAAMS,iBAAiBT,QAAQU,QAAQ,CAAC,EAAE;IAC1C,OAAO,aACFF,eACAX,oBAAoB;QACrBc,MAAMX,QAAQW,IAAI,CAACC,IAAI,GAAGC,KAAK,CAAC,GAAG;QACnCH,UAAUV,QAAQU,QAAQ;IAC5B;QACAI,MAAMd,QAAQc,IAAI,IAAIlB,aAAaI,QAAQW,IAAI;QAC/CI,QAAQ,UAAEN,kCAAAA,eAAgBM,QAAQ,mBAAI;OACnCjB,mBAAmB;QACpBY,UAAUV,QAAQU,QAAQ;QAC1BM,gBAAgBhB,QAAQgB,cAAc;IACxC;QACAC,QAAQ,GAAEjB,kBAAAA,qBAAAA,QAAQkB,SAAS,qBAAjBlB,kBAAmB,CAAC,EAAE,oBAAIA,QAAQiB,QAAQ,YAA1CjB,QAA8C;QACxDmB,aAAalB;;AAEjB;AAEA,sGAAsG,GACtG,OAAO,SAASmB,uBACdC,MAAwB,EACxBrB,OAAwE;IAExE,OAAO;QACLW,MAAMU,OAAOV,IAAI;QACjBW,MAAMtB,QAAQsB,IAAI;QAClBC,MAAMvB,QAAQuB,IAAI;QAClBC,aAAaxB,QAAQwB,WAAW;QAChCd,UAAUV,QAAQU,QAAQ;IAC5B;AACF;AAEA;;;;;CAKC,GACD,OAAO,SAASe,iBACdJ,MAA4C,EAC5CK,SAAqD;IAErD,MAAM,EAAEC,YAAYC,YAAY,EAAmB,GAAGP,QAAjBQ,gDAAiBR;;;IAGtD,OAAO,aACFQ,cACCH,YAAY;QAAEC,YAAYD;IAAU,IAAI,CAAC;QAC7CI,WAAW;;AAEf;AAEA,mGAAmG,GACnG,OAAO,SAASC,uBAAuBC,EAAU,EAAEC,IAA6B;QAGpEA;IAFV,OAAO;QACLD;QACAE,KAAK,GAAGD,cAAAA,IAAI,CAAC,QAAQ,YAAbA,cAAmD,EAAE;QAC7DE,UAAUF,IAAI,CAAC,WAAW;IAC5B;AACF;AAUA;;;;;CAKC,GACD,OAAO,SAASG,qBACdC,OAAoB,EACpBC,SAAiB,EACjBC,UAA2B,EAC3BtC,KAAa;IAEb,MAAMuC,QAAQC,KAAKC,KAAK,CAACC,OAAOJ,WAAWC,KAAK;IAChD,IAAI,CAACA,OAAO,OAAO;IACnB,MAAM9B,WAAWf,uBAAuB0C,SAASE,WAAWK,SAAS,EAAEJ,OAAOD,WAAWM,UAAU,IAAIC;IACvG,OAAO;QACLC,QAAQ;YACNrC;WACGZ,mBAAmB,aAAKuC;YAAS3B;;YACpCS,aAAalB;;QAEf+C,QAAQ;YACNV;YACAM,WAAWL,WAAWK,SAAS;YAC/BJ;YACAS,QAAQV,WAAWU,MAAM;WACrBV,WAAWM,UAAU,GAAG;YAAEA,YAAYN,WAAWM,UAAU;QAAC,IAAI,CAAC;YACrEK,MAAMjD;;IAEV;AACF"}
|
package/src/lib/plugin-config.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
17
17
|
import { posTipPercentages } from "./model/commerce-pos.js";
|
|
18
18
|
import { POS_OPS_CONFIG_DEFAULTS, POS_OPS_CONFIG_FIELDS } from "./pos-ops-config.js";
|
|
19
|
+
import { POS_KIOSK_CONFIG_DEFAULTS, POS_KIOSK_CONFIG_FIELDS } from "./pos-kiosk-config.js";
|
|
19
20
|
/**
|
|
20
21
|
* The ceiling a register may discount to, when the merchant has not set one
|
|
21
22
|
* (AGL-2161).
|
|
@@ -108,7 +109,10 @@ import { POS_OPS_CONFIG_DEFAULTS, POS_OPS_CONFIG_FIELDS } from "./pos-ops-config
|
|
|
108
109
|
},
|
|
109
110
|
// RUNNING THE REGISTER (AGL-3609): shifts, refund limits, the idle lock
|
|
110
111
|
// and what a printed receipt carries.
|
|
111
|
-
...POS_OPS_CONFIG_FIELDS
|
|
112
|
+
...POS_OPS_CONFIG_FIELDS,
|
|
113
|
+
// THE SELF-SERVICE KIOSK (AGL-3623): pay at counter, the idle reset and
|
|
114
|
+
// its welcome line.
|
|
115
|
+
...POS_KIOSK_CONFIG_FIELDS
|
|
112
116
|
],
|
|
113
117
|
defaults: _extends({
|
|
114
118
|
posMaxDiscountPct: POS_MAX_DISCOUNT_PCT_DEFAULT,
|
|
@@ -117,7 +121,7 @@ import { POS_OPS_CONFIG_DEFAULTS, POS_OPS_CONFIG_FIELDS } from "./pos-ops-config
|
|
|
117
121
|
posReceiptDefault: 'ask',
|
|
118
122
|
posDisplayMessage: '',
|
|
119
123
|
posDisplayMarketingOptIn: true
|
|
120
|
-
}, POS_OPS_CONFIG_DEFAULTS)
|
|
124
|
+
}, POS_OPS_CONFIG_DEFAULTS, POS_KIOSK_CONFIG_DEFAULTS)
|
|
121
125
|
};
|
|
122
126
|
/**
|
|
123
127
|
* The register settings out of a merged commerce config, with every value
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/commerce/src/lib/plugin-config.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 { PluginConfigSchema } from '@aglyn/aglyn'\nimport { posTipPercentages } from './model/commerce-pos'\nimport { POS_OPS_CONFIG_DEFAULTS, POS_OPS_CONFIG_FIELDS } from './pos-ops-config'\n\n/**\n * The ceiling a register may discount to, when the merchant has not set one\n * (AGL-2161).\n *\n * 100, i.e. today's behaviour exactly. That is deliberate and is the one\n * number in this fix that is NOT a safety judgement:\n *\n * - A full comp is a legitimate register operation — a damaged item, a\n * goodwill gesture, a staff meal — and every merchant on the platform has\n * had it since POS shipped.\n * - Any lower default would change what merchants charge their own customers\n * on the day it deployed, without them asking. Picking that number is a\n * merchant policy decision, not a bug fix, and inventing one here would be\n * the same class of mistake as inventing a billing rate.\n *\n * What AGL-2161 actually fixes is that there was no ceiling to set and no\n * refusal when one was exceeded: the request body's `discountPct` was clamped\n * into range and rung up, so a register sending `150` silently comped the\n * whole sale. The ceiling is now real, enforced server-side, refused rather\n * than clamped, and one config value away from being lower.\n */\nexport const POS_MAX_DISCOUNT_PCT_DEFAULT = 100\n\n/**\n * Commerce plugin config schema (AGL-428 framework, AGL-2161 adopter).\n *\n * PURE DATA (type-only aglyn import), the same shape as bookings': the client\n * barrel registers it via '@aglyn/aglyn' and the /server entry via\n * '@aglyn/aglyn/server', so neither bundle drags in the other's barrel.\n *\n * `min`/`max` are not decoration — `mergePluginConfig` coerces a stored value\n * into the declared range and falls back to the default on junk, so the\n * ceiling itself cannot be forged out of bounds by a manager editing the\n * settings doc directly.\n */\nexport const COMMERCE_CONFIG_SCHEMA: PluginConfigSchema = {\n pluginId: 'commerce',\n fields: [\n {\n key: 'posMaxDiscountPct',\n label: 'Maximum register discount (%)',\n type: 'number',\n min: 0,\n max: 100,\n description:\n 'The largest discount the point of sale will accept on a sale. ' +\n 'A register that asks for more is refused, and the sale is not rung ' +\n 'up. Set to 0 to stop staff discounting at the register entirely.',\n },\n // THE REGISTER'S TIPS, RECEIPTS AND CUSTOMER DISPLAY (AGL-3607, AGL-3608).\n // Off by default: a store that never asked for tips does not start\n // asking its customers for one on the day this ships.\n {\n key: 'posTippingEnabled',\n label: 'Ask for tips at the register',\n type: 'boolean',\n description:\n 'Offers the customer a tip on the card reader and on the customer ' +\n 'display. Tips are yours: they are not counted as sales and carry no ' +\n 'platform fee.',\n },\n {\n key: 'posTipPercentages',\n label: 'Tip choices (%)',\n type: 'string',\n description:\n 'Up to four percentages, separated by commas, shown to the customer ' +\n 'as tip buttons. The customer can also enter an amount or choose no tip.',\n },\n {\n key: 'posReceiptDefault',\n label: 'Receipts at the register',\n type: 'select',\n options: [\n { value: 'ask', label: 'Ask the customer' },\n { value: 'print', label: 'Always print' },\n { value: 'none', label: 'No receipt unless asked' },\n ],\n description:\n 'With a customer display paired, \"Ask the customer\" lets them choose ' +\n 'email, print or no receipt on their own screen.',\n },\n {\n key: 'posDisplayMessage',\n label: 'Customer display welcome',\n type: 'string',\n description:\n 'The line the customer display shows under your store name between ' +\n 'sales. Leave blank for \"Welcome\".',\n },\n {\n key: 'posDisplayMarketingOptIn',\n label: 'Offer email sign-up on the customer display',\n type: 'boolean',\n description:\n 'Shows an unticked \"Email me news and offers\" box when a customer ' +\n 'asks for an email receipt. Only a ticked box adds them to your ' +\n 'marketing audience.',\n },\n // RUNNING THE REGISTER (AGL-3609): shifts, refund limits, the idle lock\n // and what a printed receipt carries.\n ...POS_OPS_CONFIG_FIELDS,\n ],\n defaults: {\n posMaxDiscountPct: POS_MAX_DISCOUNT_PCT_DEFAULT,\n posTippingEnabled: false,\n posTipPercentages: '15, 18, 20, 25',\n posReceiptDefault: 'ask',\n posDisplayMessage: '',\n posDisplayMarketingOptIn: true,\n ...POS_OPS_CONFIG_DEFAULTS,\n },\n}\n\n/** The register's tip, receipt and display settings, resolved for one site. */\nexport interface PosRegisterSettings {\n tippingEnabled: boolean\n tipPercentages: number[]\n receiptDefault: 'ask' | 'print' | 'none'\n displayMessage: string\n displayMarketingOptIn: boolean\n}\n\n/**\n * The register settings out of a merged commerce config, with every value\n * typed and bounded so the register, the display and the server agree.\n */\nexport function posRegisterSettings(\n config: Record<string, unknown> | null | undefined,\n): PosRegisterSettings {\n const receipt = String(config?.['posReceiptDefault'] ?? 'ask')\n return {\n tippingEnabled: config?.['posTippingEnabled'] === true,\n tipPercentages: posTipPercentages(config?.['posTipPercentages']),\n receiptDefault:\n receipt === 'print' || receipt === 'none' ? receipt : 'ask',\n displayMessage: String(config?.['posDisplayMessage'] ?? '').trim().slice(0, 120),\n displayMarketingOptIn: config?.['posDisplayMarketingOptIn'] !== false,\n }\n}\n\n/**\n * The ceiling for one org, read defensively (AGL-2161).\n *\n * Spelled here rather than at the call site so the POS route and any later\n * reader cannot disagree about what a missing or malformed value means. The\n * framework has already clamped and defaulted by the time this runs; the\n * second `Number.isFinite` guard is for the schema-less case, where\n * `getPluginConfig` returns the raw doc untouched.\n */\nexport function posMaxDiscountPct(\n config: Record<string, unknown> | null | undefined,\n): number {\n const raw = Number(config?.['posMaxDiscountPct'])\n if (!Number.isFinite(raw)) return POS_MAX_DISCOUNT_PCT_DEFAULT\n return Math.min(100, Math.max(0, raw))\n}\n"],"names":["posTipPercentages","POS_OPS_CONFIG_DEFAULTS","POS_OPS_CONFIG_FIELDS","POS_MAX_DISCOUNT_PCT_DEFAULT","COMMERCE_CONFIG_SCHEMA","pluginId","fields","key","label","type","min","max","description","options","value","defaults","posMaxDiscountPct","posTippingEnabled","posReceiptDefault","posDisplayMessage","posDisplayMarketingOptIn","posRegisterSettings","config","receipt","String","tippingEnabled","tipPercentages","receiptDefault","displayMessage","trim","slice","displayMarketingOptIn","raw","Number","isFinite","Math"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;AAGD,SAASA,iBAAiB,QAAQ,0BAAsB;AACxD,SAASC,uBAAuB,EAAEC,qBAAqB,QAAQ,sBAAkB;
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/commerce/src/lib/plugin-config.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 { PluginConfigSchema } from '@aglyn/aglyn'\nimport { posTipPercentages } from './model/commerce-pos'\nimport { POS_OPS_CONFIG_DEFAULTS, POS_OPS_CONFIG_FIELDS } from './pos-ops-config'\nimport { POS_KIOSK_CONFIG_DEFAULTS, POS_KIOSK_CONFIG_FIELDS } from './pos-kiosk-config'\n\n/**\n * The ceiling a register may discount to, when the merchant has not set one\n * (AGL-2161).\n *\n * 100, i.e. today's behaviour exactly. That is deliberate and is the one\n * number in this fix that is NOT a safety judgement:\n *\n * - A full comp is a legitimate register operation — a damaged item, a\n * goodwill gesture, a staff meal — and every merchant on the platform has\n * had it since POS shipped.\n * - Any lower default would change what merchants charge their own customers\n * on the day it deployed, without them asking. Picking that number is a\n * merchant policy decision, not a bug fix, and inventing one here would be\n * the same class of mistake as inventing a billing rate.\n *\n * What AGL-2161 actually fixes is that there was no ceiling to set and no\n * refusal when one was exceeded: the request body's `discountPct` was clamped\n * into range and rung up, so a register sending `150` silently comped the\n * whole sale. The ceiling is now real, enforced server-side, refused rather\n * than clamped, and one config value away from being lower.\n */\nexport const POS_MAX_DISCOUNT_PCT_DEFAULT = 100\n\n/**\n * Commerce plugin config schema (AGL-428 framework, AGL-2161 adopter).\n *\n * PURE DATA (type-only aglyn import), the same shape as bookings': the client\n * barrel registers it via '@aglyn/aglyn' and the /server entry via\n * '@aglyn/aglyn/server', so neither bundle drags in the other's barrel.\n *\n * `min`/`max` are not decoration — `mergePluginConfig` coerces a stored value\n * into the declared range and falls back to the default on junk, so the\n * ceiling itself cannot be forged out of bounds by a manager editing the\n * settings doc directly.\n */\nexport const COMMERCE_CONFIG_SCHEMA: PluginConfigSchema = {\n pluginId: 'commerce',\n fields: [\n {\n key: 'posMaxDiscountPct',\n label: 'Maximum register discount (%)',\n type: 'number',\n min: 0,\n max: 100,\n description:\n 'The largest discount the point of sale will accept on a sale. ' +\n 'A register that asks for more is refused, and the sale is not rung ' +\n 'up. Set to 0 to stop staff discounting at the register entirely.',\n },\n // THE REGISTER'S TIPS, RECEIPTS AND CUSTOMER DISPLAY (AGL-3607, AGL-3608).\n // Off by default: a store that never asked for tips does not start\n // asking its customers for one on the day this ships.\n {\n key: 'posTippingEnabled',\n label: 'Ask for tips at the register',\n type: 'boolean',\n description:\n 'Offers the customer a tip on the card reader and on the customer ' +\n 'display. Tips are yours: they are not counted as sales and carry no ' +\n 'platform fee.',\n },\n {\n key: 'posTipPercentages',\n label: 'Tip choices (%)',\n type: 'string',\n description:\n 'Up to four percentages, separated by commas, shown to the customer ' +\n 'as tip buttons. The customer can also enter an amount or choose no tip.',\n },\n {\n key: 'posReceiptDefault',\n label: 'Receipts at the register',\n type: 'select',\n options: [\n { value: 'ask', label: 'Ask the customer' },\n { value: 'print', label: 'Always print' },\n { value: 'none', label: 'No receipt unless asked' },\n ],\n description:\n 'With a customer display paired, \"Ask the customer\" lets them choose ' +\n 'email, print or no receipt on their own screen.',\n },\n {\n key: 'posDisplayMessage',\n label: 'Customer display welcome',\n type: 'string',\n description:\n 'The line the customer display shows under your store name between ' +\n 'sales. Leave blank for \"Welcome\".',\n },\n {\n key: 'posDisplayMarketingOptIn',\n label: 'Offer email sign-up on the customer display',\n type: 'boolean',\n description:\n 'Shows an unticked \"Email me news and offers\" box when a customer ' +\n 'asks for an email receipt. Only a ticked box adds them to your ' +\n 'marketing audience.',\n },\n // RUNNING THE REGISTER (AGL-3609): shifts, refund limits, the idle lock\n // and what a printed receipt carries.\n ...POS_OPS_CONFIG_FIELDS,\n // THE SELF-SERVICE KIOSK (AGL-3623): pay at counter, the idle reset and\n // its welcome line.\n ...POS_KIOSK_CONFIG_FIELDS,\n ],\n defaults: {\n posMaxDiscountPct: POS_MAX_DISCOUNT_PCT_DEFAULT,\n posTippingEnabled: false,\n posTipPercentages: '15, 18, 20, 25',\n posReceiptDefault: 'ask',\n posDisplayMessage: '',\n posDisplayMarketingOptIn: true,\n ...POS_OPS_CONFIG_DEFAULTS,\n ...POS_KIOSK_CONFIG_DEFAULTS,\n },\n}\n\n/** The register's tip, receipt and display settings, resolved for one site. */\nexport interface PosRegisterSettings {\n tippingEnabled: boolean\n tipPercentages: number[]\n receiptDefault: 'ask' | 'print' | 'none'\n displayMessage: string\n displayMarketingOptIn: boolean\n}\n\n/**\n * The register settings out of a merged commerce config, with every value\n * typed and bounded so the register, the display and the server agree.\n */\nexport function posRegisterSettings(\n config: Record<string, unknown> | null | undefined,\n): PosRegisterSettings {\n const receipt = String(config?.['posReceiptDefault'] ?? 'ask')\n return {\n tippingEnabled: config?.['posTippingEnabled'] === true,\n tipPercentages: posTipPercentages(config?.['posTipPercentages']),\n receiptDefault:\n receipt === 'print' || receipt === 'none' ? receipt : 'ask',\n displayMessage: String(config?.['posDisplayMessage'] ?? '').trim().slice(0, 120),\n displayMarketingOptIn: config?.['posDisplayMarketingOptIn'] !== false,\n }\n}\n\n/**\n * The ceiling for one org, read defensively (AGL-2161).\n *\n * Spelled here rather than at the call site so the POS route and any later\n * reader cannot disagree about what a missing or malformed value means. The\n * framework has already clamped and defaulted by the time this runs; the\n * second `Number.isFinite` guard is for the schema-less case, where\n * `getPluginConfig` returns the raw doc untouched.\n */\nexport function posMaxDiscountPct(\n config: Record<string, unknown> | null | undefined,\n): number {\n const raw = Number(config?.['posMaxDiscountPct'])\n if (!Number.isFinite(raw)) return POS_MAX_DISCOUNT_PCT_DEFAULT\n return Math.min(100, Math.max(0, raw))\n}\n"],"names":["posTipPercentages","POS_OPS_CONFIG_DEFAULTS","POS_OPS_CONFIG_FIELDS","POS_KIOSK_CONFIG_DEFAULTS","POS_KIOSK_CONFIG_FIELDS","POS_MAX_DISCOUNT_PCT_DEFAULT","COMMERCE_CONFIG_SCHEMA","pluginId","fields","key","label","type","min","max","description","options","value","defaults","posMaxDiscountPct","posTippingEnabled","posReceiptDefault","posDisplayMessage","posDisplayMarketingOptIn","posRegisterSettings","config","receipt","String","tippingEnabled","tipPercentages","receiptDefault","displayMessage","trim","slice","displayMarketingOptIn","raw","Number","isFinite","Math"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;AAGD,SAASA,iBAAiB,QAAQ,0BAAsB;AACxD,SAASC,uBAAuB,EAAEC,qBAAqB,QAAQ,sBAAkB;AACjF,SAASC,yBAAyB,EAAEC,uBAAuB,QAAQ,wBAAoB;AAEvF;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,MAAMC,+BAA+B,IAAG;AAE/C;;;;;;;;;;;CAWC,GACD,OAAO,MAAMC,yBAA6C;IACxDC,UAAU;IACVC,QAAQ;QACN;YACEC,KAAK;YACLC,OAAO;YACPC,MAAM;YACNC,KAAK;YACLC,KAAK;YACLC,aACE,mEACA,wEACA;QACJ;QACA,2EAA2E;QAC3E,mEAAmE;QACnE,sDAAsD;QACtD;YACEL,KAAK;YACLC,OAAO;YACPC,MAAM;YACNG,aACE,sEACA,yEACA;QACJ;QACA;YACEL,KAAK;YACLC,OAAO;YACPC,MAAM;YACNG,aACE,wEACA;QACJ;QACA;YACEL,KAAK;YACLC,OAAO;YACPC,MAAM;YACNI,SAAS;gBACP;oBAAEC,OAAO;oBAAON,OAAO;gBAAmB;gBAC1C;oBAAEM,OAAO;oBAASN,OAAO;gBAAe;gBACxC;oBAAEM,OAAO;oBAAQN,OAAO;gBAA0B;aACnD;YACDI,aACE,yEACA;QACJ;QACA;YACEL,KAAK;YACLC,OAAO;YACPC,MAAM;YACNG,aACE,uEACA;QACJ;QACA;YACEL,KAAK;YACLC,OAAO;YACPC,MAAM;YACNG,aACE,sEACA,oEACA;QACJ;QACA,wEAAwE;QACxE,sCAAsC;WACnCZ;QACH,wEAAwE;QACxE,oBAAoB;WACjBE;KACJ;IACDa,UAAU;QACRC,mBAAmBb;QACnBc,mBAAmB;QACnBnB,mBAAmB;QACnBoB,mBAAmB;QACnBC,mBAAmB;QACnBC,0BAA0B;OACvBrB,yBACAE;AAEP,EAAC;AAWD;;;CAGC,GACD,OAAO,SAASoB,oBACdC,MAAkD;;IAElD,MAAMC,UAAUC,eAAOF,0BAAAA,MAAQ,CAAC,oBAAoB,mBAAI;IACxD,OAAO;QACLG,gBAAgBH,CAAAA,0BAAAA,MAAQ,CAAC,oBAAoB,MAAK;QAClDI,gBAAgB5B,kBAAkBwB,0BAAAA,MAAQ,CAAC,oBAAoB;QAC/DK,gBACEJ,YAAY,WAAWA,YAAY,SAASA,UAAU;QACxDK,gBAAgBJ,gBAAOF,0BAAAA,MAAQ,CAAC,oBAAoB,oBAAI,IAAIO,IAAI,GAAGC,KAAK,CAAC,GAAG;QAC5EC,uBAAuBT,CAAAA,0BAAAA,MAAQ,CAAC,2BAA2B,MAAK;IAClE;AACF;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASN,kBACdM,MAAkD;IAElD,MAAMU,MAAMC,OAAOX,0BAAAA,MAAQ,CAAC,oBAAoB;IAChD,IAAI,CAACW,OAAOC,QAAQ,CAACF,MAAM,OAAO7B;IAClC,OAAOgC,KAAKzB,GAAG,CAAC,KAAKyB,KAAKxB,GAAG,CAAC,GAAGqB;AACnC"}
|
package/src/lib/plugin.js
CHANGED
|
@@ -18,6 +18,7 @@ import { mdiStorefrontOutline } from "@aglyn/shared-data-mdi";
|
|
|
18
18
|
import { lazy } from "react";
|
|
19
19
|
const PosConsolePage = lazy(()=>import("./components/console/pos-page.component.js"));
|
|
20
20
|
/** The customer display (AGL-3608): loads only on the public page that shows it. */ const PosDisplayPage = lazy(()=>import("./components/console/pos-display-page.component.js"));
|
|
21
|
+
const PosKioskPage = lazy(()=>import("./components/console/pos-kiosk-page.component.js"));
|
|
21
22
|
const CommerceGlanceCard = lazy(()=>import("./components/console/commerce-glance-card.component.js"));
|
|
22
23
|
const NewestSiteUsersCard = lazy(()=>import("./components/console/newest-site-users-card.component.js"));
|
|
23
24
|
const SiteMemberPurchases = lazy(()=>import("./components/console/site-member-purchases.component.js"));
|
|
@@ -30,6 +31,7 @@ import { registerCommerceZones } from "./components/console/product-zones.js";
|
|
|
30
31
|
import { registerCommerceOrderZones } from "./components/console/order-zones.js";
|
|
31
32
|
import { registerCommerceReturnZones } from "./components/console/return-zones.js";
|
|
32
33
|
import { registerCommerceStoreZones } from "./components/console/store-zones.js";
|
|
34
|
+
import { registerCommercePosZones } from "./components/console/pos-zones.js";
|
|
33
35
|
import { registerCommerceTransferUi } from "./transfer/register-transfer-ui.js";
|
|
34
36
|
import { COMMERCE_SEARCH_SOURCES } from "./model/commerce-search-sources.js";
|
|
35
37
|
import { COMMERCE_CONFIG_SCHEMA } from "./plugin-config.js";
|
|
@@ -58,6 +60,8 @@ import { COMMERCE_CONFIG_SCHEMA } from "./plugin-config.js";
|
|
|
58
60
|
registerCommerceReturnZones();
|
|
59
61
|
// The orders list's bulk actions and the store's Settings (AGL-3612).
|
|
60
62
|
registerCommerceStoreZones();
|
|
63
|
+
// The register's orders from other channels — a delivery app's (AGL-3644).
|
|
64
|
+
registerCommercePosZones();
|
|
61
65
|
// Its import and export resources' names and the products wizard's own
|
|
62
66
|
// step (AGL-3531); the server halves register from the console's server
|
|
63
67
|
// declarations.
|
|
@@ -81,6 +85,13 @@ import { COMMERCE_CONFIG_SCHEMA } from "./plugin-config.js";
|
|
|
81
85
|
path: '/pos-display',
|
|
82
86
|
title: 'Customer display',
|
|
83
87
|
Component: PosDisplayPage
|
|
88
|
+
},
|
|
89
|
+
// The self-service kiosk (AGL-3623), paired the same way with a kiosk
|
|
90
|
+
// code; `server/pos-kiosk.ts` refuses every call without its token.
|
|
91
|
+
{
|
|
92
|
+
path: '/pos-kiosk',
|
|
93
|
+
title: 'Self-service kiosk',
|
|
94
|
+
Component: PosKioskPage
|
|
84
95
|
}
|
|
85
96
|
],
|
|
86
97
|
// Dashboard/analytics glance card (AGL-419): rendered through the
|