@aglyn/plugins-commerce 1.0.0-beta.232 → 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.
Files changed (228) hide show
  1. package/package.json +13 -13
  2. package/src/lib/components/cart-extras.d.ts +6 -0
  3. package/src/lib/components/cart-extras.js +4 -1
  4. package/src/lib/components/cart-extras.js.map +1 -1
  5. package/src/lib/components/cart-fulfillment.d.ts +117 -0
  6. package/src/lib/components/cart-fulfillment.js +367 -0
  7. package/src/lib/components/cart-fulfillment.js.map +1 -0
  8. package/src/lib/components/cart.js +52 -10
  9. package/src/lib/components/cart.js.map +1 -1
  10. package/src/lib/components/commerce-console-page.js +42 -1
  11. package/src/lib/components/commerce-console-page.js.map +1 -1
  12. package/src/lib/components/console/host-orders-card.component.js +38 -10
  13. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  14. package/src/lib/components/console/local-delivery-settings-card.component.d.ts +37 -0
  15. package/src/lib/components/console/local-delivery-settings-card.component.js +542 -0
  16. package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -0
  17. package/src/lib/components/console/locations-card.component.js +177 -3
  18. package/src/lib/components/console/locations-card.component.js.map +1 -1
  19. package/src/lib/components/console/order-detail-dialog.component.js +10 -0
  20. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  21. package/src/lib/components/console/order-local-fulfillment-panel.component.d.ts +44 -0
  22. package/src/lib/components/console/order-local-fulfillment-panel.component.js +265 -0
  23. package/src/lib/components/console/order-local-fulfillment-panel.component.js.map +1 -0
  24. package/src/lib/components/console/order-offline-notice.component.d.ts +12 -0
  25. package/src/lib/components/console/order-offline-notice.component.js +53 -0
  26. package/src/lib/components/console/order-offline-notice.component.js.map +1 -0
  27. package/src/lib/components/console/pickup-delivery-queue-card.component.d.ts +35 -0
  28. package/src/lib/components/console/pickup-delivery-queue-card.component.js +222 -0
  29. package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -0
  30. package/src/lib/components/console/pos/pos-api.d.ts +24 -1
  31. package/src/lib/components/console/pos/pos-api.js +13 -0
  32. package/src/lib/components/console/pos/pos-api.js.map +1 -1
  33. package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +12 -0
  34. package/src/lib/components/console/pos/pos-item-dialog.component.js +10 -8
  35. package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
  36. package/src/lib/components/console/pos/pos-kiosk-queue.component.d.ts +22 -0
  37. package/src/lib/components/console/pos/pos-kiosk-queue.component.js +168 -0
  38. package/src/lib/components/console/pos/pos-kiosk-queue.component.js.map +1 -0
  39. package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +18 -0
  40. package/src/lib/components/console/pos/pos-tender-dialogs.component.js +116 -1
  41. package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -1
  42. package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +8 -0
  43. package/src/lib/components/console/pos/pos-tender-panel.component.js +77 -18
  44. package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -1
  45. package/src/lib/components/console/pos/use-pos-display.d.ts +5 -2
  46. package/src/lib/components/console/pos/use-pos-display.js +3 -2
  47. package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
  48. package/src/lib/components/console/pos-devices-card.component.js +2 -2
  49. package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
  50. package/src/lib/components/console/pos-display/pairing-screen.d.ts +5 -2
  51. package/src/lib/components/console/pos-display/pairing-screen.js +7 -5
  52. package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -1
  53. package/src/lib/components/console/pos-display/pos-display-api.d.ts +7 -1
  54. package/src/lib/components/console/pos-display/pos-display-api.js +7 -2
  55. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
  56. package/src/lib/components/console/pos-kiosk/kiosk-checkout.d.ts +41 -0
  57. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js +275 -0
  58. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js.map +1 -0
  59. package/src/lib/components/console/pos-kiosk/kiosk-menu.d.ts +32 -0
  60. package/src/lib/components/console/pos-kiosk/kiosk-menu.js +344 -0
  61. package/src/lib/components/console/pos-kiosk/kiosk-menu.js.map +1 -0
  62. package/src/lib/components/console/pos-kiosk/kiosk-staff.d.ts +12 -0
  63. package/src/lib/components/console/pos-kiosk/kiosk-staff.js +257 -0
  64. package/src/lib/components/console/pos-kiosk/kiosk-staff.js.map +1 -0
  65. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.d.ts +114 -0
  66. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js +189 -0
  67. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js.map +1 -0
  68. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.d.ts +16 -0
  69. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js +80 -0
  70. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js.map +1 -0
  71. package/src/lib/components/console/pos-kiosk-page.component.d.ts +28 -0
  72. package/src/lib/components/console/pos-kiosk-page.component.js +791 -0
  73. package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -0
  74. package/src/lib/components/console/pos-offline/pos-offline-api.d.ts +44 -0
  75. package/src/lib/components/console/pos-offline/pos-offline-api.js +69 -0
  76. package/src/lib/components/console/pos-offline/pos-offline-api.js.map +1 -0
  77. package/src/lib/components/console/pos-offline/pos-offline-banner.component.d.ts +7 -0
  78. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js +135 -0
  79. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js.map +1 -0
  80. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.d.ts +32 -0
  81. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js +287 -0
  82. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js.map +1 -0
  83. package/src/lib/components/console/pos-offline/pos-offline-store.d.ts +63 -0
  84. package/src/lib/components/console/pos-offline/pos-offline-store.js +145 -0
  85. package/src/lib/components/console/pos-offline/pos-offline-store.js.map +1 -0
  86. package/src/lib/components/console/pos-offline/register-offline.d.ts +24 -0
  87. package/src/lib/components/console/pos-offline/register-offline.js +24 -0
  88. package/src/lib/components/console/pos-offline/register-offline.js.map +1 -0
  89. package/src/lib/components/console/pos-offline/use-pos-offline.d.ts +85 -0
  90. package/src/lib/components/console/pos-offline/use-pos-offline.js +542 -0
  91. package/src/lib/components/console/pos-offline/use-pos-offline.js.map +1 -0
  92. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +72 -17
  93. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -1
  94. package/src/lib/components/console/pos-page.component.js +174 -27
  95. package/src/lib/components/console/pos-page.component.js.map +1 -1
  96. package/src/lib/components/console/products-hub-card.component.js +35 -10
  97. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  98. package/src/lib/components/console/shipping-settings-card.component.js +1 -1
  99. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
  100. package/src/lib/components/console/stock-movements-card.component.js +48 -16
  101. package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
  102. package/src/lib/components/console/store-zones.d.ts +8 -1
  103. package/src/lib/components/console/store-zones.js +11 -1
  104. package/src/lib/components/console/store-zones.js.map +1 -1
  105. package/src/lib/components/order-status.js +66 -0
  106. package/src/lib/components/order-status.js.map +1 -1
  107. package/src/lib/components/product-detail.js +42 -15
  108. package/src/lib/components/product-detail.js.map +1 -1
  109. package/src/lib/constants/local-fulfillment-list-query.d.ts +48 -0
  110. package/src/lib/constants/local-fulfillment-list-query.js +84 -0
  111. package/src/lib/constants/local-fulfillment-list-query.js.map +1 -0
  112. package/src/lib/constants/orders-list-query.d.ts +7 -2
  113. package/src/lib/constants/orders-list-query.js +89 -8
  114. package/src/lib/constants/orders-list-query.js.map +1 -1
  115. package/src/lib/constants/pos-shift-list-query.d.ts +22 -0
  116. package/src/lib/constants/pos-shift-list-query.js +115 -0
  117. package/src/lib/constants/pos-shift-list-query.js.map +1 -0
  118. package/src/lib/constants/product-list-query.d.ts +6 -1
  119. package/src/lib/constants/product-list-query.js +77 -8
  120. package/src/lib/constants/product-list-query.js.map +1 -1
  121. package/src/lib/constants/stock-movement-query.d.ts +3 -2
  122. package/src/lib/constants/stock-movement-query.js +52 -8
  123. package/src/lib/constants/stock-movement-query.js.map +1 -1
  124. package/src/lib/model/buyer-notifications.d.ts +5 -3
  125. package/src/lib/model/buyer-notifications.js +25 -4
  126. package/src/lib/model/buyer-notifications.js.map +1 -1
  127. package/src/lib/model/commerce-orders.d.ts +59 -0
  128. package/src/lib/model/commerce-orders.js.map +1 -1
  129. package/src/lib/model/commerce-pos-kiosk.d.ts +175 -0
  130. package/src/lib/model/commerce-pos-kiosk.js +147 -0
  131. package/src/lib/model/commerce-pos-kiosk.js.map +1 -0
  132. package/src/lib/model/commerce-pos-offline.d.ts +234 -0
  133. package/src/lib/model/commerce-pos-offline.js +301 -0
  134. package/src/lib/model/commerce-pos-offline.js.map +1 -0
  135. package/src/lib/model/commerce-pos-ops.d.ts +16 -6
  136. package/src/lib/model/commerce-pos-ops.js +12 -4
  137. package/src/lib/model/commerce-pos-ops.js.map +1 -1
  138. package/src/lib/model/commerce-pos.d.ts +13 -1
  139. package/src/lib/model/commerce-pos.js +5 -4
  140. package/src/lib/model/commerce-pos.js.map +1 -1
  141. package/src/lib/model/commerce-stock-holds.d.ts +24 -3
  142. package/src/lib/model/commerce-stock-holds.js +26 -8
  143. package/src/lib/model/commerce-stock-holds.js.map +1 -1
  144. package/src/lib/model/commerce.d.ts +3 -0
  145. package/src/lib/model/commerce.js.map +1 -1
  146. package/src/lib/model/index.d.ts +4 -0
  147. package/src/lib/model/index.js +4 -0
  148. package/src/lib/model/index.js.map +1 -1
  149. package/src/lib/model/local-fulfillment-settings.d.ts +178 -0
  150. package/src/lib/model/local-fulfillment-settings.js +361 -0
  151. package/src/lib/model/local-fulfillment-settings.js.map +1 -0
  152. package/src/lib/model/order-list-fields.d.ts +10 -1
  153. package/src/lib/model/order-list-fields.js +1 -0
  154. package/src/lib/model/order-list-fields.js.map +1 -1
  155. package/src/lib/model/order-local-fulfillment.d.ts +131 -0
  156. package/src/lib/model/order-local-fulfillment.js +125 -0
  157. package/src/lib/model/order-local-fulfillment.js.map +1 -0
  158. package/src/lib/model/order-shipping-export.js +4 -0
  159. package/src/lib/model/order-shipping-export.js.map +1 -1
  160. package/src/lib/model/order-status-view.d.ts +20 -1
  161. package/src/lib/model/order-status-view.js +60 -6
  162. package/src/lib/model/order-status-view.js.map +1 -1
  163. package/src/lib/plugin-config.js +6 -2
  164. package/src/lib/plugin-config.js.map +1 -1
  165. package/src/lib/plugin.js +8 -0
  166. package/src/lib/plugin.js.map +1 -1
  167. package/src/lib/pos-kiosk-config.d.ts +26 -0
  168. package/src/lib/pos-kiosk-config.js +59 -0
  169. package/src/lib/pos-kiosk-config.js.map +1 -0
  170. package/src/lib/server/api-v1/openapi.js +8 -0
  171. package/src/lib/server/api-v1/openapi.js.map +1 -1
  172. package/src/lib/server/api-v1/order-view.d.ts +19 -0
  173. package/src/lib/server/api-v1/order-view.js +35 -0
  174. package/src/lib/server/api-v1/order-view.js.map +1 -1
  175. package/src/lib/server/billing-webhook.js +238 -87
  176. package/src/lib/server/billing-webhook.js.map +1 -1
  177. package/src/lib/server/cart-checkout.d.ts +2 -0
  178. package/src/lib/server/cart-checkout.js +173 -13
  179. package/src/lib/server/cart-checkout.js.map +1 -1
  180. package/src/lib/server/checkout-extras.js +18 -4
  181. package/src/lib/server/checkout-extras.js.map +1 -1
  182. package/src/lib/server/checkout.js +71 -14
  183. package/src/lib/server/checkout.js.map +1 -1
  184. package/src/lib/server/local-fulfillment-status.d.ts +86 -0
  185. package/src/lib/server/local-fulfillment-status.js +379 -0
  186. package/src/lib/server/local-fulfillment-status.js.map +1 -0
  187. package/src/lib/server/local-fulfillment.d.ts +190 -0
  188. package/src/lib/server/local-fulfillment.js +580 -0
  189. package/src/lib/server/local-fulfillment.js.map +1 -0
  190. package/src/lib/server/membership-register.js +3 -1
  191. package/src/lib/server/membership-register.js.map +1 -1
  192. package/src/lib/server/order-notifications.js +61 -0
  193. package/src/lib/server/order-notifications.js.map +1 -1
  194. package/src/lib/server/pos-display.d.ts +27 -1
  195. package/src/lib/server/pos-display.js +50 -9
  196. package/src/lib/server/pos-display.js.map +1 -1
  197. package/src/lib/server/pos-kiosk-principal.d.ts +29 -0
  198. package/src/lib/server/pos-kiosk-principal.js +42 -0
  199. package/src/lib/server/pos-kiosk-principal.js.map +1 -0
  200. package/src/lib/server/pos-kiosk.d.ts +54 -0
  201. package/src/lib/server/pos-kiosk.js +972 -0
  202. package/src/lib/server/pos-kiosk.js.map +1 -0
  203. package/src/lib/server/pos-offline-sync.d.ts +85 -0
  204. package/src/lib/server/pos-offline-sync.js +765 -0
  205. package/src/lib/server/pos-offline-sync.js.map +1 -0
  206. package/src/lib/server/pos-order.js +22 -4
  207. package/src/lib/server/pos-order.js.map +1 -1
  208. package/src/lib/server/pos-payment.d.ts +6 -0
  209. package/src/lib/server/pos-payment.js +225 -6
  210. package/src/lib/server/pos-payment.js.map +1 -1
  211. package/src/lib/server/pos-print.js +5 -0
  212. package/src/lib/server/pos-print.js.map +1 -1
  213. package/src/lib/server/pos-return.js +27 -0
  214. package/src/lib/server/pos-return.js.map +1 -1
  215. package/src/lib/server/pos-sale.d.ts +6 -0
  216. package/src/lib/server/pos-sale.js +2 -0
  217. package/src/lib/server/pos-sale.js.map +1 -1
  218. package/src/lib/server/pos-shift.js +8 -1
  219. package/src/lib/server/pos-shift.js.map +1 -1
  220. package/src/lib/server/refund.js +3 -0
  221. package/src/lib/server/refund.js.map +1 -1
  222. package/src/lib/server/stock-hold.d.ts +9 -1
  223. package/src/lib/server/stock-hold.js +15 -7
  224. package/src/lib/server/stock-hold.js.map +1 -1
  225. package/src/lib/server.js +16 -0
  226. package/src/lib/server.js.map +1 -1
  227. package/src/lib/tenant-emails.js +161 -0
  228. package/src/lib/tenant-emails.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 { fulfillmentIsActive, fulfillmentLineQuantities } from "./order-fulfillment.js";
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 shipments = active.map((fulfillment)=>{
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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"}
@@ -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;AAEjF;;;;;;;;;;;;;;;;;;;;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;WACnCV;KACJ;IACDa,UAAU;QACRC,mBAAmBb;QACnBc,mBAAmB;QACnBjB,mBAAmB;QACnBkB,mBAAmB;QACnBC,mBAAmB;QACnBC,0BAA0B;OACvBnB;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,gBAAgB1B,kBAAkBsB,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"}
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"));
@@ -84,6 +85,13 @@ import { COMMERCE_CONFIG_SCHEMA } from "./plugin-config.js";
84
85
  path: '/pos-display',
85
86
  title: 'Customer display',
86
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
87
95
  }
88
96
  ],
89
97
  // Dashboard/analytics glance card (AGL-419): rendered through the
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/plugins/commerce/src/lib/plugin.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 * as Aglyn from '@aglyn/aglyn'\nimport { mdiStorefrontOutline } from '@aglyn/shared-data-mdi'\nimport { lazy } from 'react'\nconst PosConsolePage = lazy(() => import('./components/console/pos-page.component'))\n/** The customer display (AGL-3608): loads only on the public page that shows it. */\nconst PosDisplayPage = lazy(() => import('./components/console/pos-display-page.component'))\nconst CommerceGlanceCard = lazy(\n () => import('./components/console/commerce-glance-card.component'),\n)\nconst NewestSiteUsersCard = lazy(\n () => import('./components/console/newest-site-users-card.component'),\n)\nconst SiteMemberPurchases = lazy(\n () => import('./components/console/site-member-purchases.component'),\n)\nimport { COMMERCE_CONSOLE_SECTIONS } from './components/commerce-console-sections'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { COMMERCE_PERMISSIONS } from './model/plugin-permissions'\nimport { registerCommerceRecordLists } from './model/commerce-record-lists'\nimport { registerCommerceRecordRoutes } from './model/commerce-record-routes'\nimport { registerCommerceZones } from './components/console/product-zones'\nimport { registerCommerceOrderZones } from './components/console/order-zones'\nimport { registerCommerceReturnZones } from './components/console/return-zones'\nimport { registerCommerceStoreZones } from './components/console/store-zones'\nimport { registerCommercePosZones } from './components/console/pos-zones'\nimport { registerCommerceTransferUi } from './transfer/register-transfer-ui'\nimport { COMMERCE_SEARCH_SOURCES } from './model/commerce-search-sources'\nimport { COMMERCE_CONFIG_SCHEMA } from './plugin-config'\n\n/** Code-split: the Products console page only loads when opened. */\nconst CommerceConsolePage = lazy(() => import('./components/commerce-console-page'))\n\n/**\n * Console half (AGL-395): registers the Products nav item in the\n * ConsoleExtension registry so the commerce console surface is owned by the\n * plugin, like events and email. The page body still lives in the console\n * app (`/[hostId]/products`): its product editor depends on the app's media\n * browser, which transitively pulls in the org/session context, so a full\n * body relocation needs a plugin-consumable media-picker context first —\n * tracked as follow-up. The nav item omits a `Component`, so the shell's\n * nav renders the link and the existing named route serves the page.\n */\nexport function registerCommerceConsole(): void {\n // Where a product is read, for surfaces outside this plugin (AGL-3080).\n registerCommerceRecordRoutes()\n registerCommerceRecordLists()\n // The zones its product editor, products hub and CSV import dialog host,\n // with the props each hands a widget (AGL-2916, AGL-3080).\n registerCommerceZones()\n // …and the order dialog's two (AGL-3611), where a shipping plugin's widget\n // buys a label and records the shipment through the dialog's own route.\n registerCommerceOrderZones()\n // …and the return dialog's (AGL-3611), where a shipping plugin's widget\n // buys the buyer a return label and attaches it through this plugin's route.\n registerCommerceReturnZones()\n // The orders list's bulk actions and the store's Settings (AGL-3612).\n registerCommerceStoreZones()\n // The register's orders from other channels — a delivery app's (AGL-3644).\n registerCommercePosZones()\n // Its import and export resources' names and the products wizard's own\n // step (AGL-3531); the server halves register from the console's server\n // declarations.\n registerCommerceTransferUi()\n // Plugin-declared permissions (AGL-435): tier defaults ride every\n // resolved role set; custom roles override key-by-key.\n Aglyn.registerPluginPermissions(COMMERCE_PERMISSIONS)\n // Register discount ceiling (AGL-2161) — the generic settings card renders\n // it from this schema, so there is no bespoke UI to keep in sync.\n Aglyn.registerPluginConfigSchema(COMMERCE_CONFIG_SCHEMA)\n Aglyn.registerConsoleExtension({\n pluginId: BUNDLE_ID,\n displayName: 'Commerce',\n searchSources: COMMERCE_SEARCH_SOURCES,\n // The screen a register turns toward its customer (AGL-3608), at\n // `/kiosk/commerce/pos-display`. No staff session: the device proves\n // itself with the display token it got by pairing, and\n // `server/pos-display.ts` refuses every read without one.\n publicPages: [\n { path: '/pos-display', title: 'Customer display', Component: PosDisplayPage },\n ],\n // Dashboard/analytics glance card (AGL-419): rendered through the\n // shell's 'commerceGlance' widget slot.\n widgets: [\n {\n slot: 'commerceGlance',\n widgetId: 'commerce-glance',\n title: 'Commerce',\n Component: CommerceGlanceCard,\n },\n // What a site user bought — lifetime total, orders and subscriptions —\n // in their drawer on the site's Users page: the orders and\n // subscriptions are this plugin's.\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.siteMember,\n widgetId: 'commerce-site-member-purchases',\n title: 'Purchases',\n Component: SiteMemberPurchases,\n },\n ],\n navItems: [\n {\n label: 'Products',\n href: '/products',\n icon: { path: mdiStorefrontOutline.path },\n // Sections as ROUTES (AGL-2501): `/products/orders` and friends are\n // real URLs the shell resolves and gates, so the page mounts the one\n // being read instead of subscribing all six.\n sections: COMMERCE_CONSOLE_SECTIONS,\n header: {\n title: 'Products',\n icon: { path: mdiStorefrontOutline.path },\n // The overview, not `catalog`: this surface is the whole commerce\n // console — Catalog, Orders, Promotions and Reservations.\n docsTopic: 'commerce',\n },\n Component: CommerceConsolePage,\n },\n {\n // POS register (AGL-312/419): relocated from the app's /pos route —\n // the generic [pluginSlug] shell now serves it at the same URL.\n label: 'POS',\n href: '/pos',\n /*\n * WHO may open the register, declared on THIS nav item rather than on\n * the extension.\n *\n * A key here narrows one surface; a key on the extension would gate\n * every surface it registers, and Products is the sibling — a catalog\n * anyone who works on the site may open. The register is the one that\n * takes money and lists checked-in guests by name, so the two\n * genuinely have different answers and only this one is narrowed.\n *\n * `managePos` rather than a dotted catalog key because it is the key\n * the sale itself is refused by: `server/pos-order.ts` resolves the\n * member's permission map and returns 403 unless `managePos` holds.\n * The shell answers this declaration out of that same resolved map, so\n * the console offers a register exactly to the people the route will\n * accept a sale from — the gate and its server twin cannot disagree,\n * because they are reading one value.\n *\n * `pos-order.ts` stays the enforcement point regardless. This decides\n * whether the surface is built at all, which is the part a check\n * inside the page cannot do: by the time the page can refuse itself it\n * has mounted and its product, register, location and reservation\n * listeners are already open.\n */\n permission: 'managePos',\n icon: { path: mdiStorefrontOutline.path },\n header: { title: 'Point of Sale', docsTopic: 'pos' },\n Component: PosConsolePage,\n },\n ],\n })\n /*\n * The USER ACCOUNTS half, registered under its own id.\n *\n * `accounts` is a switch rather than a bundle: the member blocks and every\n * `membership/*` handler ship inside this package, which is why the id\n * carries no loader manifest entry of its own. A second extension is how a\n * card about visitor accounts is gated on the switch that decides whether\n * the site serves them — `listConsoleWidgets` filters by the workspace's\n * effective plugin ids, and `accounts` is default-OFF per site.\n *\n * A separate call rather than more widgets on the commerce extension: the\n * registry is keyed by `pluginId` and that key IS the gate, so folding this\n * card in above would have kept the dashboard defect it fixes — `Newest\n * site users` on a site whose /signin returns 404.\n */\n Aglyn.registerConsoleExtension({\n pluginId: Aglyn.ACCOUNTS_PLUGIN_ID,\n displayName: 'User Accounts',\n widgets: [\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.hostDashboard,\n widgetId: 'accounts-newest-site-users',\n title: 'Newest site users',\n Component: NewestSiteUsersCard,\n },\n ],\n })\n}\n\nexport * from './site'\n"],"names":["Aglyn","mdiStorefrontOutline","lazy","PosConsolePage","PosDisplayPage","CommerceGlanceCard","NewestSiteUsersCard","SiteMemberPurchases","COMMERCE_CONSOLE_SECTIONS","BUNDLE_ID","COMMERCE_PERMISSIONS","registerCommerceRecordLists","registerCommerceRecordRoutes","registerCommerceZones","registerCommerceOrderZones","registerCommerceReturnZones","registerCommerceStoreZones","registerCommercePosZones","registerCommerceTransferUi","COMMERCE_SEARCH_SOURCES","COMMERCE_CONFIG_SCHEMA","CommerceConsolePage","registerCommerceConsole","registerPluginPermissions","registerPluginConfigSchema","registerConsoleExtension","pluginId","displayName","searchSources","publicPages","path","title","Component","widgets","slot","widgetId","CONSOLE_WIDGET_SLOTS","siteMember","navItems","label","href","icon","sections","header","docsTopic","permission","ACCOUNTS_PLUGIN_ID","hostDashboard"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../libs/plugins/commerce/src/lib/plugin.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 * as Aglyn from '@aglyn/aglyn'\nimport { mdiStorefrontOutline } from '@aglyn/shared-data-mdi'\nimport { lazy } from 'react'\nconst PosConsolePage = lazy(() => import('./components/console/pos-page.component'))\n/** The customer display (AGL-3608): loads only on the public page that shows it. */\nconst PosDisplayPage = lazy(() => import('./components/console/pos-display-page.component'))\nconst PosKioskPage = lazy(() => import('./components/console/pos-kiosk-page.component'))\nconst CommerceGlanceCard = lazy(\n () => import('./components/console/commerce-glance-card.component'),\n)\nconst NewestSiteUsersCard = lazy(\n () => import('./components/console/newest-site-users-card.component'),\n)\nconst SiteMemberPurchases = lazy(\n () => import('./components/console/site-member-purchases.component'),\n)\nimport { COMMERCE_CONSOLE_SECTIONS } from './components/commerce-console-sections'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { COMMERCE_PERMISSIONS } from './model/plugin-permissions'\nimport { registerCommerceRecordLists } from './model/commerce-record-lists'\nimport { registerCommerceRecordRoutes } from './model/commerce-record-routes'\nimport { registerCommerceZones } from './components/console/product-zones'\nimport { registerCommerceOrderZones } from './components/console/order-zones'\nimport { registerCommerceReturnZones } from './components/console/return-zones'\nimport { registerCommerceStoreZones } from './components/console/store-zones'\nimport { registerCommercePosZones } from './components/console/pos-zones'\nimport { registerCommerceTransferUi } from './transfer/register-transfer-ui'\nimport { COMMERCE_SEARCH_SOURCES } from './model/commerce-search-sources'\nimport { COMMERCE_CONFIG_SCHEMA } from './plugin-config'\n\n/** Code-split: the Products console page only loads when opened. */\nconst CommerceConsolePage = lazy(() => import('./components/commerce-console-page'))\n\n/**\n * Console half (AGL-395): registers the Products nav item in the\n * ConsoleExtension registry so the commerce console surface is owned by the\n * plugin, like events and email. The page body still lives in the console\n * app (`/[hostId]/products`): its product editor depends on the app's media\n * browser, which transitively pulls in the org/session context, so a full\n * body relocation needs a plugin-consumable media-picker context first —\n * tracked as follow-up. The nav item omits a `Component`, so the shell's\n * nav renders the link and the existing named route serves the page.\n */\nexport function registerCommerceConsole(): void {\n // Where a product is read, for surfaces outside this plugin (AGL-3080).\n registerCommerceRecordRoutes()\n registerCommerceRecordLists()\n // The zones its product editor, products hub and CSV import dialog host,\n // with the props each hands a widget (AGL-2916, AGL-3080).\n registerCommerceZones()\n // …and the order dialog's two (AGL-3611), where a shipping plugin's widget\n // buys a label and records the shipment through the dialog's own route.\n registerCommerceOrderZones()\n // …and the return dialog's (AGL-3611), where a shipping plugin's widget\n // buys the buyer a return label and attaches it through this plugin's route.\n registerCommerceReturnZones()\n // The orders list's bulk actions and the store's Settings (AGL-3612).\n registerCommerceStoreZones()\n // The register's orders from other channels — a delivery app's (AGL-3644).\n registerCommercePosZones()\n // Its import and export resources' names and the products wizard's own\n // step (AGL-3531); the server halves register from the console's server\n // declarations.\n registerCommerceTransferUi()\n // Plugin-declared permissions (AGL-435): tier defaults ride every\n // resolved role set; custom roles override key-by-key.\n Aglyn.registerPluginPermissions(COMMERCE_PERMISSIONS)\n // Register discount ceiling (AGL-2161) — the generic settings card renders\n // it from this schema, so there is no bespoke UI to keep in sync.\n Aglyn.registerPluginConfigSchema(COMMERCE_CONFIG_SCHEMA)\n Aglyn.registerConsoleExtension({\n pluginId: BUNDLE_ID,\n displayName: 'Commerce',\n searchSources: COMMERCE_SEARCH_SOURCES,\n // The screen a register turns toward its customer (AGL-3608), at\n // `/kiosk/commerce/pos-display`. No staff session: the device proves\n // itself with the display token it got by pairing, and\n // `server/pos-display.ts` refuses every read without one.\n publicPages: [\n { path: '/pos-display', title: 'Customer display', Component: PosDisplayPage },\n // The self-service kiosk (AGL-3623), paired the same way with a kiosk\n // code; `server/pos-kiosk.ts` refuses every call without its token.\n { path: '/pos-kiosk', title: 'Self-service kiosk', Component: PosKioskPage },\n ],\n // Dashboard/analytics glance card (AGL-419): rendered through the\n // shell's 'commerceGlance' widget slot.\n widgets: [\n {\n slot: 'commerceGlance',\n widgetId: 'commerce-glance',\n title: 'Commerce',\n Component: CommerceGlanceCard,\n },\n // What a site user bought — lifetime total, orders and subscriptions —\n // in their drawer on the site's Users page: the orders and\n // subscriptions are this plugin's.\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.siteMember,\n widgetId: 'commerce-site-member-purchases',\n title: 'Purchases',\n Component: SiteMemberPurchases,\n },\n ],\n navItems: [\n {\n label: 'Products',\n href: '/products',\n icon: { path: mdiStorefrontOutline.path },\n // Sections as ROUTES (AGL-2501): `/products/orders` and friends are\n // real URLs the shell resolves and gates, so the page mounts the one\n // being read instead of subscribing all six.\n sections: COMMERCE_CONSOLE_SECTIONS,\n header: {\n title: 'Products',\n icon: { path: mdiStorefrontOutline.path },\n // The overview, not `catalog`: this surface is the whole commerce\n // console — Catalog, Orders, Promotions and Reservations.\n docsTopic: 'commerce',\n },\n Component: CommerceConsolePage,\n },\n {\n // POS register (AGL-312/419): relocated from the app's /pos route —\n // the generic [pluginSlug] shell now serves it at the same URL.\n label: 'POS',\n href: '/pos',\n /*\n * WHO may open the register, declared on THIS nav item rather than on\n * the extension.\n *\n * A key here narrows one surface; a key on the extension would gate\n * every surface it registers, and Products is the sibling — a catalog\n * anyone who works on the site may open. The register is the one that\n * takes money and lists checked-in guests by name, so the two\n * genuinely have different answers and only this one is narrowed.\n *\n * `managePos` rather than a dotted catalog key because it is the key\n * the sale itself is refused by: `server/pos-order.ts` resolves the\n * member's permission map and returns 403 unless `managePos` holds.\n * The shell answers this declaration out of that same resolved map, so\n * the console offers a register exactly to the people the route will\n * accept a sale from — the gate and its server twin cannot disagree,\n * because they are reading one value.\n *\n * `pos-order.ts` stays the enforcement point regardless. This decides\n * whether the surface is built at all, which is the part a check\n * inside the page cannot do: by the time the page can refuse itself it\n * has mounted and its product, register, location and reservation\n * listeners are already open.\n */\n permission: 'managePos',\n icon: { path: mdiStorefrontOutline.path },\n header: { title: 'Point of Sale', docsTopic: 'pos' },\n Component: PosConsolePage,\n },\n ],\n })\n /*\n * The USER ACCOUNTS half, registered under its own id.\n *\n * `accounts` is a switch rather than a bundle: the member blocks and every\n * `membership/*` handler ship inside this package, which is why the id\n * carries no loader manifest entry of its own. A second extension is how a\n * card about visitor accounts is gated on the switch that decides whether\n * the site serves them — `listConsoleWidgets` filters by the workspace's\n * effective plugin ids, and `accounts` is default-OFF per site.\n *\n * A separate call rather than more widgets on the commerce extension: the\n * registry is keyed by `pluginId` and that key IS the gate, so folding this\n * card in above would have kept the dashboard defect it fixes — `Newest\n * site users` on a site whose /signin returns 404.\n */\n Aglyn.registerConsoleExtension({\n pluginId: Aglyn.ACCOUNTS_PLUGIN_ID,\n displayName: 'User Accounts',\n widgets: [\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.hostDashboard,\n widgetId: 'accounts-newest-site-users',\n title: 'Newest site users',\n Component: NewestSiteUsersCard,\n },\n ],\n })\n}\n\nexport * from './site'\n"],"names":["Aglyn","mdiStorefrontOutline","lazy","PosConsolePage","PosDisplayPage","PosKioskPage","CommerceGlanceCard","NewestSiteUsersCard","SiteMemberPurchases","COMMERCE_CONSOLE_SECTIONS","BUNDLE_ID","COMMERCE_PERMISSIONS","registerCommerceRecordLists","registerCommerceRecordRoutes","registerCommerceZones","registerCommerceOrderZones","registerCommerceReturnZones","registerCommerceStoreZones","registerCommercePosZones","registerCommerceTransferUi","COMMERCE_SEARCH_SOURCES","COMMERCE_CONFIG_SCHEMA","CommerceConsolePage","registerCommerceConsole","registerPluginPermissions","registerPluginConfigSchema","registerConsoleExtension","pluginId","displayName","searchSources","publicPages","path","title","Component","widgets","slot","widgetId","CONSOLE_WIDGET_SLOTS","siteMember","navItems","label","href","icon","sections","header","docsTopic","permission","ACCOUNTS_PLUGIN_ID","hostDashboard"],"mappings":"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"}
@@ -0,0 +1,26 @@
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 { PluginConfigField } from '@aglyn/aglyn';
18
+ export declare const POS_KIOSK_CONFIG_FIELDS: PluginConfigField[];
19
+ export declare const POS_KIOSK_CONFIG_DEFAULTS: Record<string, unknown>;
20
+ export interface PosKioskSettings {
21
+ payAtCounter: boolean;
22
+ idleSeconds: number;
23
+ welcome: string;
24
+ }
25
+ /** Read defensively, for a config read with or without the schema. */
26
+ export declare function posKioskSettings(config: Record<string, unknown> | null | undefined): PosKioskSettings;
@@ -0,0 +1,59 @@
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 { POS_KIOSK_IDLE_SECONDS_DEFAULT, POS_KIOSK_IDLE_SECONDS_MAX, POS_KIOSK_IDLE_SECONDS_MIN, posKioskIdleSeconds } from "./model/commerce-pos-kiosk.js";
17
+ /*==========================================
18
+ * THE SELF-SERVICE KIOSK'S SETTINGS (AGL-3623). Pure data, spread into
19
+ * `COMMERCE_CONFIG_SCHEMA` beside the register's own, so the settings form,
20
+ * the kiosk route and the kiosk read one set of keys with one set of bounds.
21
+ * Tips and receipts are the register's settings: a kiosk asks for a tip
22
+ * exactly when the register does.
23
+ *=========================================*/ export const POS_KIOSK_CONFIG_FIELDS = [
24
+ {
25
+ key: 'posKioskPayAtCounter',
26
+ label: 'Kiosk: let customers pay at the counter',
27
+ type: 'boolean',
28
+ description: 'Adds "Pay at counter" to the self-service kiosk. The order goes to the ' + 'register’s queue with its number, and a cashier takes payment there.'
29
+ },
30
+ {
31
+ key: 'posKioskIdleSeconds',
32
+ label: 'Kiosk: start over after (seconds idle)',
33
+ type: 'number',
34
+ min: POS_KIOSK_IDLE_SECONDS_MIN,
35
+ max: POS_KIOSK_IDLE_SECONDS_MAX,
36
+ description: 'After this long without a touch the kiosk asks "Still there?", then ' + 'clears the cart and anything the customer typed.'
37
+ },
38
+ {
39
+ key: 'posKioskWelcome',
40
+ label: 'Kiosk welcome',
41
+ type: 'string',
42
+ description: 'The line the kiosk’s start screen shows under your store name. Leave blank for "Order here".'
43
+ }
44
+ ];
45
+ export const POS_KIOSK_CONFIG_DEFAULTS = {
46
+ posKioskPayAtCounter: true,
47
+ posKioskIdleSeconds: POS_KIOSK_IDLE_SECONDS_DEFAULT,
48
+ posKioskWelcome: ''
49
+ };
50
+ /** Read defensively, for a config read with or without the schema. */ export function posKioskSettings(config) {
51
+ var _ref;
52
+ return {
53
+ payAtCounter: (config == null ? void 0 : config['posKioskPayAtCounter']) !== false,
54
+ idleSeconds: posKioskIdleSeconds(config == null ? void 0 : config['posKioskIdleSeconds']),
55
+ welcome: String((_ref = config == null ? void 0 : config['posKioskWelcome']) != null ? _ref : '').trim().slice(0, 120)
56
+ };
57
+ }
58
+
59
+ //# sourceMappingURL=pos-kiosk-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../libs/plugins/commerce/src/lib/pos-kiosk-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 { PluginConfigField } from '@aglyn/aglyn'\nimport {\n POS_KIOSK_IDLE_SECONDS_DEFAULT,\n POS_KIOSK_IDLE_SECONDS_MAX,\n POS_KIOSK_IDLE_SECONDS_MIN,\n posKioskIdleSeconds,\n} from './model/commerce-pos-kiosk'\n\n/*==========================================\n * THE SELF-SERVICE KIOSK'S SETTINGS (AGL-3623). Pure data, spread into\n * `COMMERCE_CONFIG_SCHEMA` beside the register's own, so the settings form,\n * the kiosk route and the kiosk read one set of keys with one set of bounds.\n * Tips and receipts are the register's settings: a kiosk asks for a tip\n * exactly when the register does.\n *=========================================*/\n\nexport const POS_KIOSK_CONFIG_FIELDS: PluginConfigField[] = [\n {\n key: 'posKioskPayAtCounter',\n label: 'Kiosk: let customers pay at the counter',\n type: 'boolean',\n description:\n 'Adds \"Pay at counter\" to the self-service kiosk. The order goes to the ' +\n 'register’s queue with its number, and a cashier takes payment there.',\n },\n {\n key: 'posKioskIdleSeconds',\n label: 'Kiosk: start over after (seconds idle)',\n type: 'number',\n min: POS_KIOSK_IDLE_SECONDS_MIN,\n max: POS_KIOSK_IDLE_SECONDS_MAX,\n description:\n 'After this long without a touch the kiosk asks \"Still there?\", then ' +\n 'clears the cart and anything the customer typed.',\n },\n {\n key: 'posKioskWelcome',\n label: 'Kiosk welcome',\n type: 'string',\n description: 'The line the kiosk’s start screen shows under your store name. Leave blank for \"Order here\".',\n },\n]\n\nexport const POS_KIOSK_CONFIG_DEFAULTS: Record<string, unknown> = {\n posKioskPayAtCounter: true,\n posKioskIdleSeconds: POS_KIOSK_IDLE_SECONDS_DEFAULT,\n posKioskWelcome: '',\n}\n\nexport interface PosKioskSettings {\n payAtCounter: boolean\n idleSeconds: number\n welcome: string\n}\n\n/** Read defensively, for a config read with or without the schema. */\nexport function posKioskSettings(config: Record<string, unknown> | null | undefined): PosKioskSettings {\n return {\n payAtCounter: config?.['posKioskPayAtCounter'] !== false,\n idleSeconds: posKioskIdleSeconds(config?.['posKioskIdleSeconds']),\n welcome: String(config?.['posKioskWelcome'] ?? '').trim().slice(0, 120),\n }\n}\n"],"names":["POS_KIOSK_IDLE_SECONDS_DEFAULT","POS_KIOSK_IDLE_SECONDS_MAX","POS_KIOSK_IDLE_SECONDS_MIN","posKioskIdleSeconds","POS_KIOSK_CONFIG_FIELDS","key","label","type","description","min","max","POS_KIOSK_CONFIG_DEFAULTS","posKioskPayAtCounter","posKioskWelcome","posKioskSettings","config","payAtCounter","idleSeconds","welcome","String","trim","slice"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAGD,SACEA,8BAA8B,EAC9BC,0BAA0B,EAC1BC,0BAA0B,EAC1BC,mBAAmB,QACd,gCAA4B;AAEnC;;;;;;2CAM2C,GAE3C,OAAO,MAAMC,0BAA+C;IAC1D;QACEC,KAAK;QACLC,OAAO;QACPC,MAAM;QACNC,aACE,4EACA;IACJ;IACA;QACEH,KAAK;QACLC,OAAO;QACPC,MAAM;QACNE,KAAKP;QACLQ,KAAKT;QACLO,aACE,yEACA;IACJ;IACA;QACEH,KAAK;QACLC,OAAO;QACPC,MAAM;QACNC,aAAa;IACf;CACD,CAAA;AAED,OAAO,MAAMG,4BAAqD;IAChEC,sBAAsB;IACtBT,qBAAqBH;IACrBa,iBAAiB;AACnB,EAAC;AAQD,oEAAoE,GACpE,OAAO,SAASC,iBAAiBC,MAAkD;;IACjF,OAAO;QACLC,cAAcD,CAAAA,0BAAAA,MAAQ,CAAC,uBAAuB,MAAK;QACnDE,aAAad,oBAAoBY,0BAAAA,MAAQ,CAAC,sBAAsB;QAChEG,SAASC,eAAOJ,0BAAAA,MAAQ,CAAC,kBAAkB,mBAAI,IAAIK,IAAI,GAAGC,KAAK,CAAC,GAAG;IACrE;AACF"}
@@ -165,6 +165,14 @@ export const ORDERS_API_V1_DESCRIPTION = {
165
165
  additionalProperties: true
166
166
  }
167
167
  },
168
+ credits: {
169
+ type: 'array',
170
+ description: 'Store credit another plugin kept that paid part of the sale, such as rewards: `[{ providerId, pluginId, reference, label, last4, amountCents, appliedAs }]`. `appliedAs` is `discount` for a checkout redemption and `tender` for a register payment. Empty when there were none.',
171
+ items: {
172
+ type: 'object',
173
+ additionalProperties: true
174
+ }
175
+ },
168
176
  refundedCents: int('Amount refunded so far.'),
169
177
  disputed: bool('Whether a chargeback is open.'),
170
178
  taxMode: nullable(str('The tax regime: `stripe-automatic` (Stripe Tax, collected and remitted by the platform as marketplace facilitator), `manual` (your own rate) or `none`. `null` on an order from before it was recorded.')),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/server/api-v1/openapi.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 type ApiV1ResourceDescription,\n booleanField as bool,\n integerField as int,\n nullableField as nullable,\n objectKindField as OBJECT_FIELD,\n openObjectField as objectOf,\n postalAddressField as ADDRESS,\n queryParam as q,\n RECORD_STAMPS as STAMPS,\n stringField as str,\n stringListField as strList,\n} from '@aglyn/tenant-data-admin/server/api-v1-description'\n\n/**\n * A site's products and orders as the customer API's OpenAPI document\n * describes them — what the console's builder turns into paths, tags and\n * schemas, and the MCP tools derive from. Transcribed unchanged from the\n * builder's own list when the resources moved here (AGL-3080);\n * `api-v1-openapi.spec.ts` holds the document to every endpoint the\n * documentation promises.\n */\nexport const PRODUCTS_API_V1_DESCRIPTION: ApiV1ResourceDescription = {\n tag: 'Products',\n description: 'A site’s catalog. Read-only over the API.',\n schemaName: 'Product',\n required: ['id', 'object', 'name'],\n fields: {\n id: str('Product id.'),\n object: OBJECT_FIELD('product'),\n name: str('Product name.'),\n slug: str('URL slug.'),\n description: nullable(str('Description.')),\n type: str('Product type.'),\n status: str('Publication status.'),\n tags: strList('Free-form tags.'),\n categoryIds: strList('Categories this product belongs to.'),\n mediaUrls: strList('Image URLs.'),\n options: { type: 'array', description: 'Option definitions, e.g. size.', items: { type: 'object', additionalProperties: true } },\n variants: { type: 'array', description: 'Purchasable variants.', items: { type: 'object', additionalProperties: true } },\n inventory: nullable(int('Stock on hand, when tracked.')),\n subscription: nullable(objectOf('Subscription terms, when the product is one.')),\n ...STAMPS,\n },\n ops: [\n { path: '/v1/sites/{siteId}/products', method: 'get', operationId: 'listProducts', summary: 'List products', list: true, returns: 'Product', description: 'Rows deleted since they were written are dropped after the read, so pages can come back short.', pathParams: [{ name: 'siteId', description: 'Site id.' }] },\n { path: '/v1/sites/{siteId}/products/{productId}', method: 'get', operationId: 'getProduct', summary: 'Retrieve a product', returns: 'Product', pathParams: [{ name: 'siteId', description: 'Site id.' }, { name: 'productId', description: 'Product id.' }] },\n ],\n}\n\nexport const ORDERS_API_V1_DESCRIPTION: ApiV1ResourceDescription = {\n tag: 'Orders',\n description: 'A site’s orders. Status moves are constrained.',\n schemaName: 'Order',\n required: ['id', 'object', 'number', 'status'],\n writable: ['status', 'carrier', 'trackingNumber', 'trackingUrl', 'lineItems', 'notify'],\n writeOnly: {\n status: { type: 'string', enum: ['fulfilled', 'delivered'], description: 'The status to move the order to.' },\n carrier: str('Free text, e.g. `UPS`. Trimmed to 40 characters. USPS, UPS, FedEx, DHL, Canada Post, Royal Mail and Australia Post get a tracking link.'),\n trackingNumber: str('Free text. Trimmed to 60 characters.'),\n trackingUrl: str('An https tracking link, for a carrier the link is not derived for.'),\n lineItems: {\n type: 'array',\n description:\n 'With `status: fulfilled`, the units this shipment covers: `[{ lineItemId, quantity }]`, where `lineItemId` is the line’s index. Omitted, the shipment covers everything still to ship. More than is left is `409 conflict` (`code: \"over_fulfilled\"`). Send an `Idempotency-Key` header so a retried partial shipment is recorded once.',\n items: { type: 'object', additionalProperties: true },\n },\n notify: bool('Whether the buyer is told about this shipment. Defaults to true.'),\n },\n writeRequired: ['status'],\n fields: {\n id: str('Order id.'),\n object: OBJECT_FIELD('order'),\n number: int('Human-facing order number.'),\n status: str('Order status.'),\n channel: str('`online` by default. Older orders carry no stored value, so `?channel=online` drops them after the read.'),\n currency: str('ISO 4217 code.'),\n customerEmail: nullable(str('Customer email.')),\n customerName: nullable(str('Customer name.')),\n lineItems: { type: 'array', description: 'What was bought.', items: { type: 'object', additionalProperties: true } },\n totals: objectOf('Money totals, in the smallest unit of `currency`. `extrasCents` is the optional lines the buyer added at checkout, inside `totalCents` and outside `itemsCents`.'),\n extras: { type: 'array', description: 'Optional lines the buyer added at checkout, such as package protection: `[{ id, pluginId, key, label, amountCents, quoteRef }]`. Empty when there were none.', items: { type: 'object', additionalProperties: true } },\n refundedCents: int('Amount refunded so far.'),\n disputed: bool('Whether a chargeback is open.'),\n taxMode: nullable(str('The tax regime: `stripe-automatic` (Stripe Tax, collected and remitted by the platform as marketplace facilitator), `manual` (your own rate) or `none`. `null` on an order from before it was recorded.')),\n taxEngine: nullable(objectOf('The tax service you connected, when one was asked for this sale’s tax: `provider` (`avalara` or `taxjar`), `providerLabel`, `status` (`quoted` when its tax was charged, `fallback` when it did not answer and your own rate was charged), `reason` (`timeout` or `error` on a fallback) and `sandbox`. `null` when no service was asked.')),\n shippingAddress: ADDRESS(),\n couponCode: nullable(str('Coupon applied.')),\n fulfillments: { type: 'array', description: 'Shipments and deliveries.', items: { type: 'object', additionalProperties: true } },\n created: STAMPS.created,\n },\n ops: [\n { path: '/v1/sites/{siteId}/orders', method: 'get', operationId: 'listOrders', summary: 'List orders', list: true, returns: 'Order', filters: [q('channel', '`online` is a default rather than a stored value, so filtering on it drops older orders after the read.'), q('status', 'Order status.')], pathParams: [{ name: 'siteId', description: 'Site id.' }] },\n { path: '/v1/sites/{siteId}/orders/{orderId}', method: 'get', operationId: 'getOrder', summary: 'Retrieve an order', returns: 'Order', pathParams: [{ name: 'siteId', description: 'Site id.' }, { name: 'orderId', description: 'Order id.' }] },\n { path: '/v1/sites/{siteId}/orders/{orderId}', method: 'patch', operationId: 'updateOrder', summary: 'Move an order’s status', accepts: 'OrderWrite', returns: 'Order', description: 'An illegal transition is `409 conflict` (`code: \"order_transition\"`), and the message names the status it is in.', pathParams: [{ name: 'siteId', description: 'Site id.' }, { name: 'orderId', description: 'Order id.' }] },\n ],\n}\n"],"names":["booleanField","bool","integerField","int","nullableField","nullable","objectKindField","OBJECT_FIELD","openObjectField","objectOf","postalAddressField","ADDRESS","queryParam","q","RECORD_STAMPS","STAMPS","stringField","str","stringListField","strList","PRODUCTS_API_V1_DESCRIPTION","tag","description","schemaName","required","fields","id","object","name","slug","type","status","tags","categoryIds","mediaUrls","options","items","additionalProperties","variants","inventory","subscription","ops","path","method","operationId","summary","list","returns","pathParams","ORDERS_API_V1_DESCRIPTION","writable","writeOnly","enum","carrier","trackingNumber","trackingUrl","lineItems","notify","writeRequired","number","channel","currency","customerEmail","customerName","totals","extras","refundedCents","disputed","taxMode","taxEngine","shippingAddress","couponCode","fulfillments","created","filters","accepts"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/server/api-v1/openapi.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 type ApiV1ResourceDescription,\n booleanField as bool,\n integerField as int,\n nullableField as nullable,\n objectKindField as OBJECT_FIELD,\n openObjectField as objectOf,\n postalAddressField as ADDRESS,\n queryParam as q,\n RECORD_STAMPS as STAMPS,\n stringField as str,\n stringListField as strList,\n} from '@aglyn/tenant-data-admin/server/api-v1-description'\n\n/**\n * A site's products and orders as the customer API's OpenAPI document\n * describes them — what the console's builder turns into paths, tags and\n * schemas, and the MCP tools derive from. Transcribed unchanged from the\n * builder's own list when the resources moved here (AGL-3080);\n * `api-v1-openapi.spec.ts` holds the document to every endpoint the\n * documentation promises.\n */\nexport const PRODUCTS_API_V1_DESCRIPTION: ApiV1ResourceDescription = {\n tag: 'Products',\n description: 'A site’s catalog. Read-only over the API.',\n schemaName: 'Product',\n required: ['id', 'object', 'name'],\n fields: {\n id: str('Product id.'),\n object: OBJECT_FIELD('product'),\n name: str('Product name.'),\n slug: str('URL slug.'),\n description: nullable(str('Description.')),\n type: str('Product type.'),\n status: str('Publication status.'),\n tags: strList('Free-form tags.'),\n categoryIds: strList('Categories this product belongs to.'),\n mediaUrls: strList('Image URLs.'),\n options: { type: 'array', description: 'Option definitions, e.g. size.', items: { type: 'object', additionalProperties: true } },\n variants: { type: 'array', description: 'Purchasable variants.', items: { type: 'object', additionalProperties: true } },\n inventory: nullable(int('Stock on hand, when tracked.')),\n subscription: nullable(objectOf('Subscription terms, when the product is one.')),\n ...STAMPS,\n },\n ops: [\n { path: '/v1/sites/{siteId}/products', method: 'get', operationId: 'listProducts', summary: 'List products', list: true, returns: 'Product', description: 'Rows deleted since they were written are dropped after the read, so pages can come back short.', pathParams: [{ name: 'siteId', description: 'Site id.' }] },\n { path: '/v1/sites/{siteId}/products/{productId}', method: 'get', operationId: 'getProduct', summary: 'Retrieve a product', returns: 'Product', pathParams: [{ name: 'siteId', description: 'Site id.' }, { name: 'productId', description: 'Product id.' }] },\n ],\n}\n\nexport const ORDERS_API_V1_DESCRIPTION: ApiV1ResourceDescription = {\n tag: 'Orders',\n description: 'A site’s orders. Status moves are constrained.',\n schemaName: 'Order',\n required: ['id', 'object', 'number', 'status'],\n writable: ['status', 'carrier', 'trackingNumber', 'trackingUrl', 'lineItems', 'notify'],\n writeOnly: {\n status: { type: 'string', enum: ['fulfilled', 'delivered'], description: 'The status to move the order to.' },\n carrier: str('Free text, e.g. `UPS`. Trimmed to 40 characters. USPS, UPS, FedEx, DHL, Canada Post, Royal Mail and Australia Post get a tracking link.'),\n trackingNumber: str('Free text. Trimmed to 60 characters.'),\n trackingUrl: str('An https tracking link, for a carrier the link is not derived for.'),\n lineItems: {\n type: 'array',\n description:\n 'With `status: fulfilled`, the units this shipment covers: `[{ lineItemId, quantity }]`, where `lineItemId` is the line’s index. Omitted, the shipment covers everything still to ship. More than is left is `409 conflict` (`code: \"over_fulfilled\"`). Send an `Idempotency-Key` header so a retried partial shipment is recorded once.',\n items: { type: 'object', additionalProperties: true },\n },\n notify: bool('Whether the buyer is told about this shipment. Defaults to true.'),\n },\n writeRequired: ['status'],\n fields: {\n id: str('Order id.'),\n object: OBJECT_FIELD('order'),\n number: int('Human-facing order number.'),\n status: str('Order status.'),\n channel: str('`online` by default. Older orders carry no stored value, so `?channel=online` drops them after the read.'),\n currency: str('ISO 4217 code.'),\n customerEmail: nullable(str('Customer email.')),\n customerName: nullable(str('Customer name.')),\n lineItems: { type: 'array', description: 'What was bought.', items: { type: 'object', additionalProperties: true } },\n totals: objectOf('Money totals, in the smallest unit of `currency`. `extrasCents` is the optional lines the buyer added at checkout, inside `totalCents` and outside `itemsCents`.'),\n extras: { type: 'array', description: 'Optional lines the buyer added at checkout, such as package protection: `[{ id, pluginId, key, label, amountCents, quoteRef }]`. Empty when there were none.', items: { type: 'object', additionalProperties: true } },\n credits: { type: 'array', description: 'Store credit another plugin kept that paid part of the sale, such as rewards: `[{ providerId, pluginId, reference, label, last4, amountCents, appliedAs }]`. `appliedAs` is `discount` for a checkout redemption and `tender` for a register payment. Empty when there were none.', items: { type: 'object', additionalProperties: true } },\n refundedCents: int('Amount refunded so far.'),\n disputed: bool('Whether a chargeback is open.'),\n taxMode: nullable(str('The tax regime: `stripe-automatic` (Stripe Tax, collected and remitted by the platform as marketplace facilitator), `manual` (your own rate) or `none`. `null` on an order from before it was recorded.')),\n taxEngine: nullable(objectOf('The tax service you connected, when one was asked for this sale’s tax: `provider` (`avalara` or `taxjar`), `providerLabel`, `status` (`quoted` when its tax was charged, `fallback` when it did not answer and your own rate was charged), `reason` (`timeout` or `error` on a fallback) and `sandbox`. `null` when no service was asked.')),\n shippingAddress: ADDRESS(),\n couponCode: nullable(str('Coupon applied.')),\n fulfillments: { type: 'array', description: 'Shipments and deliveries.', items: { type: 'object', additionalProperties: true } },\n created: STAMPS.created,\n },\n ops: [\n { path: '/v1/sites/{siteId}/orders', method: 'get', operationId: 'listOrders', summary: 'List orders', list: true, returns: 'Order', filters: [q('channel', '`online` is a default rather than a stored value, so filtering on it drops older orders after the read.'), q('status', 'Order status.')], pathParams: [{ name: 'siteId', description: 'Site id.' }] },\n { path: '/v1/sites/{siteId}/orders/{orderId}', method: 'get', operationId: 'getOrder', summary: 'Retrieve an order', returns: 'Order', pathParams: [{ name: 'siteId', description: 'Site id.' }, { name: 'orderId', description: 'Order id.' }] },\n { path: '/v1/sites/{siteId}/orders/{orderId}', method: 'patch', operationId: 'updateOrder', summary: 'Move an order’s status', accepts: 'OrderWrite', returns: 'Order', description: 'An illegal transition is `409 conflict` (`code: \"order_transition\"`), and the message names the status it is in.', pathParams: [{ name: 'siteId', description: 'Site id.' }, { name: 'orderId', description: 'Order id.' }] },\n ],\n}\n"],"names":["booleanField","bool","integerField","int","nullableField","nullable","objectKindField","OBJECT_FIELD","openObjectField","objectOf","postalAddressField","ADDRESS","queryParam","q","RECORD_STAMPS","STAMPS","stringField","str","stringListField","strList","PRODUCTS_API_V1_DESCRIPTION","tag","description","schemaName","required","fields","id","object","name","slug","type","status","tags","categoryIds","mediaUrls","options","items","additionalProperties","variants","inventory","subscription","ops","path","method","operationId","summary","list","returns","pathParams","ORDERS_API_V1_DESCRIPTION","writable","writeOnly","enum","carrier","trackingNumber","trackingUrl","lineItems","notify","writeRequired","number","channel","currency","customerEmail","customerName","totals","extras","credits","refundedCents","disputed","taxMode","taxEngine","shippingAddress","couponCode","fulfillments","created","filters","accepts"],"mappings":"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"}
@@ -46,6 +46,15 @@ export declare function orderViewFromData(id: string, data: Record<string, any>)
46
46
  amountCents: number;
47
47
  quoteRef: string;
48
48
  }[];
49
+ credits: {
50
+ providerId: string;
51
+ pluginId: string;
52
+ reference: string;
53
+ label: string;
54
+ last4: string;
55
+ amountCents: number;
56
+ appliedAs: "discount" | "tender";
57
+ }[];
49
58
  refundedCents: number;
50
59
  taxMode: string;
51
60
  taxEngine: import("../../model/commerce-tax-engine").OrderTaxEngineStamp;
@@ -65,3 +74,13 @@ export declare function orderViewFromData(id: string, data: Record<string, any>)
65
74
  }[];
66
75
  created: unknown;
67
76
  };
77
+ /** The plugin credits an order carries, online and at the register (AGL-3640). */
78
+ export declare function orderCreditsView(data: Record<string, any>): Array<{
79
+ providerId: string;
80
+ pluginId: string;
81
+ reference: string;
82
+ label: string;
83
+ last4: string;
84
+ amountCents: number;
85
+ appliedAs: 'discount' | 'tender';
86
+ }>;