@sixtyninecommerce/admin 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/README.md +4598 -128
  2. package/dist/catalog/assets.d.ts +120 -8
  3. package/dist/catalog/assets.js +98 -12
  4. package/dist/catalog/collections.d.ts +279 -14
  5. package/dist/catalog/collections.js +246 -15
  6. package/dist/catalog/index.d.ts +9 -2
  7. package/dist/catalog/index.js +4 -0
  8. package/dist/catalog/products.d.ts +318 -17
  9. package/dist/catalog/products.js +182 -14
  10. package/dist/catalog/properties.d.ts +102 -14
  11. package/dist/catalog/properties.js +13 -0
  12. package/dist/catalog/recommendations.d.ts +261 -0
  13. package/dist/catalog/recommendations.js +145 -0
  14. package/dist/catalog/reviews.d.ts +368 -0
  15. package/dist/catalog/reviews.js +318 -0
  16. package/dist/catalog/types.d.ts +17 -1
  17. package/dist/catalog/types.js +10 -0
  18. package/dist/catalog/variant-find.d.ts +136 -0
  19. package/dist/catalog/variant-find.js +239 -0
  20. package/dist/catalog/variants.d.ts +282 -25
  21. package/dist/catalog/variants.js +173 -25
  22. package/dist/catalog/visibility.d.ts +20 -5
  23. package/dist/catalog/visibility.js +19 -1
  24. package/dist/client.d.ts +116 -9
  25. package/dist/client.js +41 -7
  26. package/dist/content/assets.d.ts +286 -0
  27. package/dist/content/assets.js +181 -0
  28. package/dist/content/items.d.ts +269 -0
  29. package/dist/content/items.js +170 -0
  30. package/dist/content/types.d.ts +282 -0
  31. package/dist/content/types.js +100 -0
  32. package/dist/customers/age-verification.d.ts +66 -0
  33. package/dist/customers/age-verification.js +79 -0
  34. package/dist/customers/credit.d.ts +263 -0
  35. package/dist/customers/credit.js +244 -0
  36. package/dist/customers/delivery-preferences.d.ts +120 -0
  37. package/dist/customers/delivery-preferences.js +97 -0
  38. package/dist/customers/groups.d.ts +207 -0
  39. package/dist/customers/groups.js +438 -0
  40. package/dist/customers/index.d.ts +447 -37
  41. package/dist/customers/index.js +313 -40
  42. package/dist/customers/invitation-status.d.ts +57 -0
  43. package/dist/customers/invitation-status.js +21 -0
  44. package/dist/customers/notes.d.ts +67 -0
  45. package/dist/customers/notes.js +51 -0
  46. package/dist/customers/notification-recipients.d.ts +97 -0
  47. package/dist/customers/notification-recipients.js +84 -0
  48. package/dist/customers/saved-lists.d.ts +42 -0
  49. package/dist/customers/saved-lists.js +61 -0
  50. package/dist/customers/vat.d.ts +83 -0
  51. package/dist/customers/vat.js +46 -0
  52. package/dist/customers/wire.d.ts +20 -0
  53. package/dist/customers/wire.js +35 -0
  54. package/dist/documents/ar.d.ts +307 -0
  55. package/dist/documents/ar.js +254 -0
  56. package/dist/documents/index.d.ts +731 -21
  57. package/dist/documents/index.js +436 -24
  58. package/dist/documents/pdf.d.ts +2 -0
  59. package/dist/documents/pdf.js +11 -0
  60. package/dist/fulfillments/create.d.ts +167 -0
  61. package/dist/fulfillments/create.js +216 -0
  62. package/dist/fulfillments/index.d.ts +121 -10
  63. package/dist/fulfillments/index.js +120 -2
  64. package/dist/fulfillments/payment-policy.d.ts +64 -0
  65. package/dist/fulfillments/payment-policy.js +140 -0
  66. package/dist/fulfillments/warehouse.d.ts +724 -0
  67. package/dist/fulfillments/warehouse.js +914 -0
  68. package/dist/geo/index.d.ts +119 -0
  69. package/dist/geo/index.js +107 -0
  70. package/dist/index.d.ts +129 -30
  71. package/dist/index.js +47 -9
  72. package/dist/integrations/afas-actions.d.ts +234 -0
  73. package/dist/integrations/afas-actions.js +310 -0
  74. package/dist/integrations/afas-types.d.ts +483 -0
  75. package/dist/integrations/afas-types.js +5 -0
  76. package/dist/integrations/afas.d.ts +234 -0
  77. package/dist/integrations/afas.js +290 -0
  78. package/dist/integrations/connections.d.ts +103 -0
  79. package/dist/integrations/connections.js +55 -0
  80. package/dist/integrations/esp.d.ts +313 -0
  81. package/dist/integrations/esp.js +169 -0
  82. package/dist/integrations/exact-online-types.d.ts +423 -0
  83. package/dist/integrations/exact-online-types.js +6 -0
  84. package/dist/integrations/exact-online.d.ts +248 -0
  85. package/dist/integrations/exact-online.js +376 -0
  86. package/dist/integrations/index.d.ts +40 -0
  87. package/dist/integrations/index.js +24 -0
  88. package/dist/integrations/pipeline-keys.d.ts +13 -0
  89. package/dist/integrations/pipeline-keys.js +22 -0
  90. package/dist/integrations/pipelines.d.ts +114 -0
  91. package/dist/integrations/pipelines.js +46 -0
  92. package/dist/integrations/types.d.ts +322 -0
  93. package/dist/integrations/types.js +8 -0
  94. package/dist/jobs/bulk-action-run.d.ts +11 -2
  95. package/dist/jobs/bulk-action-run.js +4 -5
  96. package/dist/locations/index.d.ts +66 -0
  97. package/dist/locations/index.js +31 -0
  98. package/dist/meta/index.d.ts +162 -0
  99. package/dist/orders/bulk.d.ts +75 -0
  100. package/dist/orders/bulk.js +150 -0
  101. package/dist/orders/cancel-with-money.d.ts +227 -0
  102. package/dist/orders/cancel-with-money.js +153 -0
  103. package/dist/orders/commit-edit.d.ts +7 -1
  104. package/dist/orders/commit-edit.js +5 -1
  105. package/dist/orders/deposit-policy.d.ts +103 -0
  106. package/dist/orders/deposit-policy.js +202 -0
  107. package/dist/orders/drafts.d.ts +800 -0
  108. package/dist/orders/drafts.js +771 -0
  109. package/dist/orders/fields.d.ts +245 -0
  110. package/dist/orders/fields.js +188 -0
  111. package/dist/orders/get.d.ts +29 -19
  112. package/dist/orders/get.js +17 -8
  113. package/dist/orders/index.d.ts +125 -5
  114. package/dist/orders/index.js +35 -2
  115. package/dist/orders/lifecycle.d.ts +128 -0
  116. package/dist/orders/lifecycle.js +158 -0
  117. package/dist/orders/line-price-preview.d.ts +7 -2
  118. package/dist/orders/list.d.ts +222 -0
  119. package/dist/orders/list.js +377 -0
  120. package/dist/orders/manual-discounts.d.ts +11 -2
  121. package/dist/orders/manual-discounts.js +2 -0
  122. package/dist/orders/manual-pricing.d.ts +5 -0
  123. package/dist/orders/order-entry.d.ts +20 -7
  124. package/dist/orders/plan-edit.d.ts +1 -1
  125. package/dist/orders/plan-edit.js +4 -1
  126. package/dist/orders/settings.d.ts +201 -0
  127. package/dist/orders/settings.js +325 -0
  128. package/dist/orders/status.d.ts +159 -13
  129. package/dist/orders/status.js +21 -0
  130. package/dist/orders/surcharges.d.ts +8 -1
  131. package/dist/orders/surcharges.js +3 -2
  132. package/dist/payments/account-credit.d.ts +30 -0
  133. package/dist/payments/account-credit.js +19 -0
  134. package/dist/payments/ar.d.ts +292 -0
  135. package/dist/payments/ar.js +223 -0
  136. package/dist/payments/connected-account.d.ts +47 -0
  137. package/dist/payments/connected-account.js +61 -0
  138. package/dist/payments/credit-noted-fields.d.ts +12 -0
  139. package/dist/payments/credit-noted-fields.js +37 -0
  140. package/dist/payments/index.d.ts +263 -10
  141. package/dist/payments/index.js +133 -1
  142. package/dist/payments/methods.d.ts +332 -0
  143. package/dist/payments/methods.js +363 -0
  144. package/dist/payments/mollie-methods.d.ts +159 -0
  145. package/dist/payments/mollie-methods.js +141 -0
  146. package/dist/payments/payment-links.d.ts +180 -0
  147. package/dist/payments/payment-links.js +97 -0
  148. package/dist/payments/provider-keys.d.ts +150 -0
  149. package/dist/payments/provider-keys.js +118 -0
  150. package/dist/payments/providers.d.ts +86 -11
  151. package/dist/payments/providers.js +29 -0
  152. package/dist/payments/requests.d.ts +144 -0
  153. package/dist/payments/requests.js +92 -0
  154. package/dist/payments/store-credit-fields.d.ts +15 -0
  155. package/dist/payments/store-credit-fields.js +51 -0
  156. package/dist/pickups/index.d.ts +104 -0
  157. package/dist/pickups/index.js +105 -0
  158. package/dist/platform/channels.d.ts +132 -0
  159. package/dist/platform/channels.js +128 -0
  160. package/dist/platform/geo.d.ts +123 -0
  161. package/dist/platform/geo.js +144 -0
  162. package/dist/platform/tax.d.ts +154 -0
  163. package/dist/platform/tax.js +139 -0
  164. package/dist/pos/anomalies.d.ts +158 -0
  165. package/dist/pos/anomalies.js +64 -0
  166. package/dist/pos/assisted-selling.d.ts +79 -0
  167. package/dist/pos/assisted-selling.js +38 -0
  168. package/dist/pos/exchanges.d.ts +103 -0
  169. package/dist/pos/exchanges.js +22 -0
  170. package/dist/pos/gift-cards.d.ts +135 -0
  171. package/dist/pos/gift-cards.js +47 -0
  172. package/dist/pos/index.d.ts +2125 -32
  173. package/dist/pos/index.js +742 -4
  174. package/dist/pos/no-receipt.d.ts +94 -0
  175. package/dist/pos/no-receipt.js +25 -0
  176. package/dist/pos/offline-sales.d.ts +187 -0
  177. package/dist/pos/offline-sales.js +116 -0
  178. package/dist/pos/pay-by-link.d.ts +143 -0
  179. package/dist/pos/pay-by-link.js +57 -0
  180. package/dist/pos/quick-keys.d.ts +103 -0
  181. package/dist/pos/quick-keys.js +45 -0
  182. package/dist/pos/reports.d.ts +360 -0
  183. package/dist/pos/reports.js +62 -0
  184. package/dist/pos/returns.d.ts +217 -0
  185. package/dist/pos/returns.js +53 -0
  186. package/dist/pricing/bulk-coupons.d.ts +139 -0
  187. package/dist/pricing/bulk-coupons.js +112 -0
  188. package/dist/pricing/index.d.ts +177 -4
  189. package/dist/pricing/index.js +176 -1
  190. package/dist/pricing/price-lists.d.ts +604 -0
  191. package/dist/pricing/price-lists.js +600 -0
  192. package/dist/pricing/vouchers.d.ts +103 -0
  193. package/dist/pricing/vouchers.js +69 -0
  194. package/dist/purchasing/alerts.d.ts +89 -0
  195. package/dist/purchasing/alerts.js +62 -0
  196. package/dist/purchasing/cost.d.ts +110 -0
  197. package/dist/purchasing/cost.js +86 -0
  198. package/dist/purchasing/index.d.ts +36 -0
  199. package/dist/purchasing/index.js +16 -0
  200. package/dist/purchasing/purchase-orders.d.ts +548 -0
  201. package/dist/purchasing/purchase-orders.js +491 -0
  202. package/dist/purchasing/replenishment.d.ts +281 -0
  203. package/dist/purchasing/replenishment.js +240 -0
  204. package/dist/purchasing/settings.d.ts +152 -0
  205. package/dist/purchasing/settings.js +181 -0
  206. package/dist/purchasing/suppliers.d.ts +476 -0
  207. package/dist/purchasing/suppliers.js +438 -0
  208. package/dist/quotes/index.d.ts +501 -0
  209. package/dist/quotes/index.js +439 -0
  210. package/dist/reports/index.d.ts +71 -8
  211. package/dist/reports/index.js +74 -11
  212. package/dist/returns/index.d.ts +818 -0
  213. package/dist/returns/index.js +844 -0
  214. package/dist/search/index.d.ts +174 -0
  215. package/dist/search/index.js +125 -0
  216. package/dist/shipping/definitions.d.ts +29 -0
  217. package/dist/shipping/definitions.js +47 -0
  218. package/dist/shipping/fulfillment-profiles.d.ts +174 -0
  219. package/dist/shipping/fulfillment-profiles.js +104 -0
  220. package/dist/shipping/hendriks.d.ts +97 -0
  221. package/dist/shipping/hendriks.js +50 -0
  222. package/dist/shipping/index.d.ts +48 -0
  223. package/dist/shipping/index.js +25 -0
  224. package/dist/shipping/methods.d.ts +198 -0
  225. package/dist/shipping/methods.js +240 -0
  226. package/dist/shipping/myparcel.d.ts +254 -0
  227. package/dist/shipping/myparcel.js +178 -0
  228. package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
  229. package/dist/shipping/parcel-rule.d.ts +6 -5
  230. package/dist/shipping/parcel-rule.js +21 -23
  231. package/dist/shipping/rate-tables.d.ts +179 -0
  232. package/dist/shipping/rate-tables.js +184 -0
  233. package/dist/stock/index.d.ts +10 -3
  234. package/dist/stock/index.js +3 -0
  235. package/dist/stock/locations.d.ts +144 -0
  236. package/dist/stock/locations.js +168 -0
  237. package/dist/stock/transfers.d.ts +216 -43
  238. package/dist/stock/transfers.js +140 -13
  239. package/dist/stored-value/index.d.ts +214 -4
  240. package/dist/stored-value/index.js +152 -0
  241. package/dist/subscriptions/index.d.ts +682 -0
  242. package/dist/subscriptions/index.js +815 -0
  243. package/dist/tax/index.d.ts +76 -1
  244. package/dist/tax/index.js +50 -0
  245. package/dist/tenant/email-style.d.ts +102 -0
  246. package/dist/tenant/email-style.js +72 -0
  247. package/dist/tenant/email-templates.d.ts +66 -0
  248. package/dist/tenant/email-templates.js +54 -0
  249. package/dist/tenant/notifications.d.ts +23 -17
  250. package/dist/tenant/settings-sources.d.ts +1 -1
  251. package/dist/tenant/time-zone.d.ts +17 -0
  252. package/dist/tenant/time-zone.js +11 -0
  253. package/dist/types.d.ts +51 -4
  254. package/dist/users/index.d.ts +3 -0
  255. package/dist/users/index.js +2 -0
  256. package/dist/users/warehouses.d.ts +50 -0
  257. package/dist/users/warehouses.js +51 -0
  258. package/package.json +2 -2
@@ -0,0 +1,94 @@
1
+ import type { Transport } from '@sixtyninecommerce/core';
2
+ import type { Call } from '../types.js';
3
+ /**
4
+ * Returns without a receipt (POS engine sprint 21): goods come back with no sale to return them
5
+ * against, as a document of their own (`NR-000001`, never an order). Each line at its current
6
+ * catalogue price incl. tax (or a lower typed price), its tax reversed per line; the money goes to
7
+ * a named customer's store credit or, where the store allows it, out of a till's open drawer with a
8
+ * manager. Money is integer minor units of the store's currency.
9
+ *
10
+ * - `policy.get` / `policy.set`: the store's rules (off, cash off, no limits until saved). `set`
11
+ * needs UpdateSettings; an omitted field keeps its value, null clears a limit. Refused
12
+ * `POS_NO_RECEIPT_POLICY_INVALID` (`extensions.field`).
13
+ * - `quote`: what a return would do now (lines, tax, total, what today's cap still allows, the
14
+ * cash to hand out). A read; why it cannot be done now is `blockedBy`, never thrown.
15
+ *
16
+ * The return itself (`posNoReceiptReturn`) is taken at a PAIRED TILL: it pays out of, and is
17
+ * counted in, that till's open drawer, so a headless till (a machine principal) is refused
18
+ * `POS_PRINCIPAL_REQUIRED` and this module offers no `create` yet.
19
+ */
20
+ export type PosNoReceiptPayout = 'STORE_CREDIT' | 'CASH';
21
+ export interface PosNoReceiptReturnPolicy {
22
+ enabled: boolean;
23
+ /** Cash may be paid out (always with a manager and a reason). */
24
+ cashAllowed: boolean;
25
+ /** Highest total of one return; null: none. */
26
+ maxPerReturn: number | null;
27
+ /** Highest total per day (the till location's zone), both payouts; null: none. */
28
+ dailyCap: number | null;
29
+ currencyCode: string;
30
+ /** The store can credit a customer's store credit (a stored-value method and the entitlement). */
31
+ storeCreditAvailable: boolean;
32
+ }
33
+ /** What `policy.set` changes: an omitted field keeps its value; null clears a limit. */
34
+ export interface PosNoReceiptReturnPolicyInput {
35
+ enabled?: boolean;
36
+ cashAllowed?: boolean;
37
+ maxPerReturn?: number | null;
38
+ dailyCap?: number | null;
39
+ }
40
+ export interface PosNoReceiptQuoteInput {
41
+ lines?: Array<{
42
+ variantId: string;
43
+ quantity: number;
44
+ unitPriceWithTax?: number;
45
+ }>;
46
+ customerId?: string;
47
+ /** Omitted: STORE_CREDIT. */
48
+ payout?: PosNoReceiptPayout;
49
+ }
50
+ export interface PosNoReceiptLine {
51
+ variantId: string;
52
+ name: string;
53
+ sku: string;
54
+ quantity: number;
55
+ catalogueUnitPriceWithTax: number;
56
+ unitPriceWithTax: number;
57
+ lineTotal: number;
58
+ /** Percent. */
59
+ taxRate: number;
60
+ lineTax: number;
61
+ restockable: boolean;
62
+ reasonCode: string | null;
63
+ restock: boolean | null;
64
+ }
65
+ export interface PosNoReceiptQuote {
66
+ currencyCode: string;
67
+ lines: PosNoReceiptLine[];
68
+ total: number;
69
+ tax: number;
70
+ taxSummary: Array<{
71
+ taxRate: number;
72
+ base: number;
73
+ tax: number;
74
+ }>;
75
+ policy: PosNoReceiptReturnPolicy;
76
+ remainingToday: number | null;
77
+ cashPaidOut: number;
78
+ restockLocationName: string | null;
79
+ /** A POS_NO_RECEIPT_* code (or POS_SESSION_REQUIRED), or null. More may come. */
80
+ blockedBy: string | null;
81
+ blockedReason: string | null;
82
+ }
83
+ export interface PosNoReceiptModule {
84
+ policy: {
85
+ get(options?: Call): Promise<PosNoReceiptReturnPolicy>;
86
+ set(input: PosNoReceiptReturnPolicyInput, options?: Call): Promise<PosNoReceiptReturnPolicy>;
87
+ };
88
+ /** What a return without a receipt would do now. Writes nothing. */
89
+ quote(input: PosNoReceiptQuoteInput, options?: Call): Promise<PosNoReceiptQuote>;
90
+ }
91
+ export declare const POS_NO_RECEIPT_RETURN_POLICY_QUERY = "query PosNoReceiptReturnPolicy { posNoReceiptReturnPolicy { enabled cashAllowed maxPerReturn dailyCap currencyCode storeCreditAvailable } }";
92
+ export declare const SET_POS_NO_RECEIPT_RETURN_POLICY_MUTATION = "mutation SetPosNoReceiptReturnPolicy($input: PosNoReceiptReturnPolicyInput!) { setPosNoReceiptReturnPolicy(input: $input) { enabled cashAllowed maxPerReturn dailyCap currencyCode storeCreditAvailable } }";
93
+ export declare const POS_NO_RECEIPT_RETURN_QUOTE_QUERY = "query PosNoReceiptReturnQuote($input: PosNoReceiptQuoteInput!) { posNoReceiptReturnQuote(input: $input) { currencyCode lines { variantId name sku quantity catalogueUnitPriceWithTax unitPriceWithTax lineTotal taxRate lineTax restockable reasonCode restock } total tax taxSummary { taxRate base tax } policy { enabled cashAllowed maxPerReturn dailyCap currencyCode storeCreditAvailable } remainingToday cashPaidOut restockLocationName blockedBy blockedReason } }";
94
+ export declare function createPosNoReceiptModule(transport: Transport): PosNoReceiptModule;
@@ -0,0 +1,25 @@
1
+ const POLICY_FIELDS = 'enabled cashAllowed maxPerReturn dailyCap currencyCode storeCreditAvailable';
2
+ const LINE_FIELDS = 'variantId name sku quantity catalogueUnitPriceWithTax unitPriceWithTax lineTotal taxRate lineTax restockable reasonCode restock';
3
+ export const POS_NO_RECEIPT_RETURN_POLICY_QUERY = `query PosNoReceiptReturnPolicy { posNoReceiptReturnPolicy { ${POLICY_FIELDS} } }`;
4
+ export const SET_POS_NO_RECEIPT_RETURN_POLICY_MUTATION = `mutation SetPosNoReceiptReturnPolicy($input: PosNoReceiptReturnPolicyInput!) { setPosNoReceiptReturnPolicy(input: $input) { ${POLICY_FIELDS} } }`;
5
+ export const POS_NO_RECEIPT_RETURN_QUOTE_QUERY = `query PosNoReceiptReturnQuote($input: PosNoReceiptQuoteInput!) { posNoReceiptReturnQuote(input: $input) { currencyCode lines { ${LINE_FIELDS} } total tax taxSummary { taxRate base tax } policy { ${POLICY_FIELDS} } remainingToday cashPaidOut restockLocationName blockedBy blockedReason } }`;
6
+ export function createPosNoReceiptModule(transport) {
7
+ const gql = async (query, variables, options) => transport.graphql({ api: 'admin', query, variables }, options);
8
+ return {
9
+ policy: {
10
+ async get(options) {
11
+ const data = await gql(POS_NO_RECEIPT_RETURN_POLICY_QUERY, {}, options);
12
+ return data.posNoReceiptReturnPolicy;
13
+ },
14
+ async set(input, options) {
15
+ // Sent as given: an omitted field keeps its value, an explicit null clears a limit.
16
+ const data = await gql(SET_POS_NO_RECEIPT_RETURN_POLICY_MUTATION, { input: { ...input } }, options);
17
+ return data.setPosNoReceiptReturnPolicy;
18
+ },
19
+ },
20
+ async quote(input, options) {
21
+ const data = await gql(POS_NO_RECEIPT_RETURN_QUOTE_QUERY, { input }, options);
22
+ return data.posNoReceiptReturnQuote;
23
+ },
24
+ };
25
+ }
@@ -0,0 +1,187 @@
1
+ import { type Page, type Transport } from '@sixtyninecommerce/core';
2
+ import type { Call, ListOptions } from '../types.js';
3
+ /**
4
+ * Offline cash sales (engine sprint 45, shipped dark): a till that loses its connection may keep
5
+ * selling for cash, within the store's limits, and sends each sale when it is back. The engine
6
+ * records each sale once, at the prices the till charged, into the drawer it was rung in; a sale
7
+ * it cannot record as rung waits for a manager.
8
+ *
9
+ * - `admin.pos.settings.offlineCashSales()` / `setOfflineCashSales(input)`: the store's switch
10
+ * (off by default) and its three limits, with whether the store can sell offline now.
11
+ * - `admin.pos.offlineSales.list` / `resolve`: the manager's queue. `needs_review` (recorded, a
12
+ * reason to look at) and `refused` (nothing recorded but the row) wait until a manager marks
13
+ * them handled with a note; `recorded` needs nobody.
14
+ * - `admin.pos.devices.offlineSalesToReview()`: how many of each device's offline sales wait.
15
+ *
16
+ * The replay itself (`posRecordOfflineSale`) is a paired till's door alone: a machine principal
17
+ * is online by nature, so this SDK offers no method for it. An engine before 45 answers every
18
+ * call here `GRAPHQL_VALIDATION_FAILED` (or a 400 the transport reports as `BAD_REQUEST`); each
19
+ * is a document of its own, so every other call keeps working there.
20
+ */
21
+ /**
22
+ * The bounds of each limit, both inclusive, and the engine's default for a store that never saved
23
+ * them. Money in minor units of the store's default currency; minutes count from the server's
24
+ * last answer to the till. Outside the bounds the save is refused `POS_OFFLINE_POLICY_INVALID`.
25
+ */
26
+ export declare const POS_OFFLINE_CASH_SALES_LIMITS: {
27
+ readonly maxSaleAmount: {
28
+ readonly min: 100;
29
+ readonly max: 500000;
30
+ readonly default: 10000;
31
+ };
32
+ readonly maxSalesPerOutage: {
33
+ readonly min: 1;
34
+ readonly max: 200;
35
+ readonly default: 25;
36
+ };
37
+ readonly maxOfflineMinutes: {
38
+ readonly min: 15;
39
+ readonly max: 720;
40
+ readonly default: 240;
41
+ };
42
+ };
43
+ /** What a manager writes when marking an offline sale handled: 1 to this many characters, trimmed. */
44
+ export declare const POS_OFFLINE_SALE_NOTE_MAX_LENGTH = 500;
45
+ /** Why a store cannot sell offline now, in the order the engine lists them. More may come. */
46
+ export declare const POS_OFFLINE_NOT_READY_REASONS: readonly ["prices_exclude_tax", "automatic_promotions", "no_cash_method", "pos_disabled"];
47
+ export type PosOfflineNotReadyReason = (typeof POS_OFFLINE_NOT_READY_REASONS)[number];
48
+ /**
49
+ * Why the engine refused or flagged an offline sale, in the order an answer lists them: the
50
+ * refusals first (`item_gone` to `rounding_mismatch`: nothing was recorded but the row), then the
51
+ * reviews (`price_changed` to `sold_at_suspect`: the sale is recorded). More may come.
52
+ */
53
+ export declare const POS_OFFLINE_SALE_REASONS: readonly ["item_gone", "drawer_closed", "currency_changed", "prices_exclude_tax", "out_of_stock", "gift_card", "total_mismatch", "rounding_mismatch", "price_changed", "not_fulfilled", "cashier_changed", "policy_off", "over_cap", "sold_at_suspect"];
54
+ export type PosOfflineSaleReason = (typeof POS_OFFLINE_SALE_REASONS)[number];
55
+ /**
56
+ * `recorded` (the order, the cash and the receipt number exist, as the till rang it),
57
+ * `needs_review` (recorded, with a reason to look at) or `refused` (nothing but this row). More
58
+ * may come: show an unknown status as it is.
59
+ */
60
+ export type PosOfflineSaleStatus = 'recorded' | 'needs_review' | 'refused';
61
+ /** A store's offline cash sales (engine sprint 45): the switch, its limits, and its readiness. */
62
+ export interface PosOfflineCashSales {
63
+ /** Off until a manager turns it on. */
64
+ enabled: boolean;
65
+ /** The largest offline sale, minor units of the store's default currency. */
66
+ maxSaleAmount: number;
67
+ /** Offline sales a till makes in one outage. */
68
+ maxSalesPerOutage: number;
69
+ /** Minutes after the server last answered that a till still sells offline. */
70
+ maxOfflineMinutes: number;
71
+ /** Whether this store can sell offline now: switched on is not enough. */
72
+ ready: boolean;
73
+ /** Why not; empty when ready. Strings, so a reason a newer engine adds never fails a read. */
74
+ notReadyReasons: Array<PosOfflineNotReadyReason | (string & {})>;
75
+ }
76
+ /** What `setOfflineCashSales` stores: every field, each within {@link POS_OFFLINE_CASH_SALES_LIMITS}. */
77
+ export interface PosOfflineCashSalesInput {
78
+ enabled: boolean;
79
+ maxSaleAmount: number;
80
+ maxSalesPerOutage: number;
81
+ maxOfflineMinutes: number;
82
+ }
83
+ /** One line of an offline sale: what the till charged, and the server's price beside it. */
84
+ export interface PosOfflineSaleLine {
85
+ variantId: string;
86
+ quantity: number;
87
+ /** The unit price with tax the till charged, minor units. */
88
+ unitPriceWithTax: number;
89
+ /**
90
+ * The server's unit price with tax when the sale was recorded; null when the variant was gone or
91
+ * the sale was refused before it was built.
92
+ */
93
+ serverUnitPriceWithTax: number | null;
94
+ }
95
+ /** An offline sale as the engine recorded or refused it (engine sprint 45). Money in minor units. */
96
+ export interface PosOfflineSale {
97
+ id: string;
98
+ deviceId: string;
99
+ /** The till's name as the store names it now; null when it is gone. */
100
+ deviceLabel: string | null;
101
+ /** The drawer the till had open when it sold. */
102
+ registerSessionId: string;
103
+ /** The till's own id for the sale (a uuid). */
104
+ offlineSaleId: string;
105
+ /** The number printed on the provisional receipt the customer took. */
106
+ provisionalReceiptNumber: string;
107
+ /** When the till completed it, by the till's clock. */
108
+ soldAt: string;
109
+ /** When the engine received it. */
110
+ recordedAt: string;
111
+ status: PosOfflineSaleStatus | (string & {});
112
+ /** {@link PosOfflineSaleReason}s; strings, so one a newer engine adds never fails a read. */
113
+ reasons: Array<PosOfflineSaleReason | (string & {})>;
114
+ /** The order it became; null when refused. */
115
+ orderId: string | null;
116
+ orderCode: string | null;
117
+ /** The final receipt number; null when refused. */
118
+ receiptNumber: string | null;
119
+ currencyCode: string;
120
+ totalWithTax: number;
121
+ cashTendered: number;
122
+ changeGiven: number;
123
+ /** The cash rounding the till applied, signed. */
124
+ cashRounding: number;
125
+ lines: PosOfflineSaleLine[];
126
+ /** The cashier signed in when the till sent it (verified), as the store names them now. */
127
+ staffName: string | null;
128
+ /** The cashier the till says rang it up: its claim. */
129
+ claimedStaffName: string | null;
130
+ /** When a manager marked it handled; null while it waits (or for a `recorded` sale). */
131
+ resolvedAt: string | null;
132
+ resolvedByUserName: string | null;
133
+ /** What the manager wrote they did about it. Staff text. */
134
+ resolutionNote: string | null;
135
+ }
136
+ /** `open` (the default): the sales a manager must still handle; `all`: every offline sale. */
137
+ export type PosOfflineSaleFilter = 'open' | 'all';
138
+ export interface PosOfflineSaleListOptions extends ListOptions {
139
+ filter?: PosOfflineSaleFilter;
140
+ /** One device's sales. */
141
+ deviceId?: string;
142
+ }
143
+ /** How many of a device's offline sales wait for a manager (the fleet's `offlineSalesToReview`). */
144
+ export interface PosDeviceOfflineSalesToReview {
145
+ deviceId: string;
146
+ /** `needs_review` or `refused`, not yet handled. */
147
+ offlineSalesToReview: number;
148
+ }
149
+ export interface PosOfflineSalesModule {
150
+ /**
151
+ * The store's offline sales, newest first (`posOfflineSales`). `filter: 'open'` (the default)
152
+ * keeps the ones a manager must still handle (`needs_review` or `refused`, not yet handled);
153
+ * `'all'` every one. `deviceId` keeps one device's. `limit` is at most 100 (50 when omitted);
154
+ * `after` is the previous page's cursor; `total` counts the whole filter. A location-restricted
155
+ * caller sees the tills at its locations only. Refused `POS_LIST_RANGE_INVALID`
156
+ * (`extensions.field`, `reason`). Needs `UpdateSettings` or `ManagePosDevices`.
157
+ */
158
+ list(options?: PosOfflineSaleListOptions): Promise<Page<PosOfflineSale>>;
159
+ /**
160
+ * Mark an offline sale handled, with what was done about it (`note`: 1 to 500 characters once
161
+ * trimmed, no control character but a line break or a tab). Nothing is recorded again: fix the
162
+ * order, the stock or the drawer first, then say so here. Idempotent by state: the same note
163
+ * again answers the sale unchanged. Refused `POS_OFFLINE_NOTE_INVALID` (`ValidationError`,
164
+ * `details[0].field` `note`), `POS_OFFLINE_SALE_NOT_FOUND` (`NotFoundError`: another store's, a
165
+ * till the caller may not see, an unknown id, or a `recorded` sale, which needs nobody) and
166
+ * `POS_OFFLINE_SALE_RESOLVED` (`BusinessRuleError`, `extensions.resolvedAt`: already handled
167
+ * with another note). Needs `UpdateSettings` or `ManagePosDevices`.
168
+ */
169
+ resolve(input: {
170
+ id: string;
171
+ note: string;
172
+ }, options?: Call): Promise<PosOfflineSale>;
173
+ }
174
+ export declare const POS_OFFLINE_CASH_SALES_QUERY = "query PosOfflineCashSales { getPosConfig { offlineCashSales { enabled maxSaleAmount maxSalesPerOutage maxOfflineMinutes ready notReadyReasons } } }";
175
+ export declare const SET_POS_OFFLINE_CASH_SALES_MUTATION = "mutation SetPosOfflineCashSales($input: PosOfflineCashSalesInput!) { setPosOfflineCashSales(input: $input) { enabled maxSaleAmount maxSalesPerOutage maxOfflineMinutes ready notReadyReasons } }";
176
+ export declare const POS_OFFLINE_SALES_QUERY = "query PosOfflineSales($input: PosOfflineSaleListInput) { posOfflineSales(input: $input) { items { id deviceId deviceLabel registerSessionId offlineSaleId provisionalReceiptNumber soldAt recordedAt status reasons orderId orderCode receiptNumber currencyCode totalWithTax cashTendered changeGiven cashRounding lines { variantId quantity unitPriceWithTax serverUnitPriceWithTax } staffName claimedStaffName resolvedAt resolvedByUserName resolutionNote } totalItems } }";
177
+ export declare const RESOLVE_POS_OFFLINE_SALE_MUTATION = "mutation ResolvePosOfflineSale($input: ResolvePosOfflineSaleInput!) { resolvePosOfflineSale(input: $input) { id deviceId deviceLabel registerSessionId offlineSaleId provisionalReceiptNumber soldAt recordedAt status reasons orderId orderCode receiptNumber currencyCode totalWithTax cashTendered changeGiven cashRounding lines { variantId quantity unitPriceWithTax serverUnitPriceWithTax } staffName claimedStaffName resolvedAt resolvedByUserName resolutionNote } }";
178
+ export declare const POS_DEVICE_OFFLINE_SALES_TO_REVIEW_QUERY = "query PosDeviceOfflineSalesToReview($stockLocationId: ID) { posDeviceFleet(stockLocationId: $stockLocationId) { device { id } offlineSalesToReview } }";
179
+ /** `admin.pos.settings.offlineCashSales()`: null when POS was never set up. */
180
+ export declare function readOfflineCashSales(transport: Transport, options?: Call): Promise<PosOfflineCashSales | null>;
181
+ /** `admin.pos.settings.setOfflineCashSales(input)`: the four fields, as given. */
182
+ export declare function writeOfflineCashSales(transport: Transport, input: PosOfflineCashSalesInput, options?: Call): Promise<PosOfflineCashSales>;
183
+ /** `admin.pos.devices.offlineSalesToReview()`: one row per device the fleet lists, whole. */
184
+ export declare function readOfflineSalesToReview(transport: Transport, options?: {
185
+ stockLocationId?: string;
186
+ } & Call): Promise<PosDeviceOfflineSalesToReview[]>;
187
+ export declare function createPosOfflineSalesModule(transport: Transport): PosOfflineSalesModule;
@@ -0,0 +1,116 @@
1
+ import { pageFromVendureList, readOffsetCursor, } from '@sixtyninecommerce/core';
2
+ /**
3
+ * Offline cash sales (engine sprint 45, shipped dark): a till that loses its connection may keep
4
+ * selling for cash, within the store's limits, and sends each sale when it is back. The engine
5
+ * records each sale once, at the prices the till charged, into the drawer it was rung in; a sale
6
+ * it cannot record as rung waits for a manager.
7
+ *
8
+ * - `admin.pos.settings.offlineCashSales()` / `setOfflineCashSales(input)`: the store's switch
9
+ * (off by default) and its three limits, with whether the store can sell offline now.
10
+ * - `admin.pos.offlineSales.list` / `resolve`: the manager's queue. `needs_review` (recorded, a
11
+ * reason to look at) and `refused` (nothing recorded but the row) wait until a manager marks
12
+ * them handled with a note; `recorded` needs nobody.
13
+ * - `admin.pos.devices.offlineSalesToReview()`: how many of each device's offline sales wait.
14
+ *
15
+ * The replay itself (`posRecordOfflineSale`) is a paired till's door alone: a machine principal
16
+ * is online by nature, so this SDK offers no method for it. An engine before 45 answers every
17
+ * call here `GRAPHQL_VALIDATION_FAILED` (or a 400 the transport reports as `BAD_REQUEST`); each
18
+ * is a document of its own, so every other call keeps working there.
19
+ */
20
+ /**
21
+ * The bounds of each limit, both inclusive, and the engine's default for a store that never saved
22
+ * them. Money in minor units of the store's default currency; minutes count from the server's
23
+ * last answer to the till. Outside the bounds the save is refused `POS_OFFLINE_POLICY_INVALID`.
24
+ */
25
+ export const POS_OFFLINE_CASH_SALES_LIMITS = {
26
+ maxSaleAmount: { min: 100, max: 500_000, default: 10_000 },
27
+ maxSalesPerOutage: { min: 1, max: 200, default: 25 },
28
+ maxOfflineMinutes: { min: 15, max: 720, default: 240 },
29
+ };
30
+ /** What a manager writes when marking an offline sale handled: 1 to this many characters, trimmed. */
31
+ export const POS_OFFLINE_SALE_NOTE_MAX_LENGTH = 500;
32
+ /** Why a store cannot sell offline now, in the order the engine lists them. More may come. */
33
+ export const POS_OFFLINE_NOT_READY_REASONS = [
34
+ 'prices_exclude_tax',
35
+ 'automatic_promotions',
36
+ 'no_cash_method',
37
+ 'pos_disabled',
38
+ ];
39
+ /**
40
+ * Why the engine refused or flagged an offline sale, in the order an answer lists them: the
41
+ * refusals first (`item_gone` to `rounding_mismatch`: nothing was recorded but the row), then the
42
+ * reviews (`price_changed` to `sold_at_suspect`: the sale is recorded). More may come.
43
+ */
44
+ export const POS_OFFLINE_SALE_REASONS = [
45
+ 'item_gone',
46
+ 'drawer_closed',
47
+ 'currency_changed',
48
+ 'prices_exclude_tax',
49
+ 'out_of_stock',
50
+ 'gift_card',
51
+ 'total_mismatch',
52
+ 'rounding_mismatch',
53
+ 'price_changed',
54
+ 'not_fulfilled',
55
+ 'cashier_changed',
56
+ 'policy_off',
57
+ 'over_cap',
58
+ 'sold_at_suspect',
59
+ ];
60
+ const DEFAULT_PAGE = 50;
61
+ const MAX_PAGE = 100;
62
+ const POLICY_FIELDS = 'enabled maxSaleAmount maxSalesPerOutage maxOfflineMinutes ready notReadyReasons';
63
+ const SALE_FIELDS = 'id deviceId deviceLabel registerSessionId offlineSaleId provisionalReceiptNumber soldAt recordedAt status reasons orderId orderCode receiptNumber currencyCode totalWithTax cashTendered changeGiven cashRounding lines { variantId quantity unitPriceWithTax serverUnitPriceWithTax } staffName claimedStaffName resolvedAt resolvedByUserName resolutionNote';
64
+ export const POS_OFFLINE_CASH_SALES_QUERY = `query PosOfflineCashSales { getPosConfig { offlineCashSales { ${POLICY_FIELDS} } } }`;
65
+ export const SET_POS_OFFLINE_CASH_SALES_MUTATION = `mutation SetPosOfflineCashSales($input: PosOfflineCashSalesInput!) { setPosOfflineCashSales(input: $input) { ${POLICY_FIELDS} } }`;
66
+ export const POS_OFFLINE_SALES_QUERY = `query PosOfflineSales($input: PosOfflineSaleListInput) { posOfflineSales(input: $input) { items { ${SALE_FIELDS} } totalItems } }`;
67
+ export const RESOLVE_POS_OFFLINE_SALE_MUTATION = `mutation ResolvePosOfflineSale($input: ResolvePosOfflineSaleInput!) { resolvePosOfflineSale(input: $input) { ${SALE_FIELDS} } }`;
68
+ // The fleet's count beside the device's id alone, its own document: the fleet read
69
+ // (`POS_DEVICE_FLEET_QUERY`) never names it, so an engine before 45 keeps answering the fleet.
70
+ export const POS_DEVICE_OFFLINE_SALES_TO_REVIEW_QUERY = 'query PosDeviceOfflineSalesToReview($stockLocationId: ID) { posDeviceFleet(stockLocationId: $stockLocationId) { device { id } offlineSalesToReview } }';
71
+ function gqlOf(transport) {
72
+ return async (query, variables, options) => transport.graphql({ api: 'admin', query, variables }, options);
73
+ }
74
+ /** `admin.pos.settings.offlineCashSales()`: null when POS was never set up. */
75
+ export async function readOfflineCashSales(transport, options) {
76
+ const data = await gqlOf(transport)(POS_OFFLINE_CASH_SALES_QUERY, {}, options);
77
+ return data.getPosConfig?.offlineCashSales ?? null;
78
+ }
79
+ /** `admin.pos.settings.setOfflineCashSales(input)`: the four fields, as given. */
80
+ export async function writeOfflineCashSales(transport, input, options) {
81
+ const { enabled, maxSaleAmount, maxSalesPerOutage, maxOfflineMinutes } = input;
82
+ const data = await gqlOf(transport)(SET_POS_OFFLINE_CASH_SALES_MUTATION, { input: { enabled, maxSaleAmount, maxSalesPerOutage, maxOfflineMinutes } }, options);
83
+ return data.setPosOfflineCashSales;
84
+ }
85
+ /** `admin.pos.devices.offlineSalesToReview()`: one row per device the fleet lists, whole. */
86
+ export async function readOfflineSalesToReview(transport, options) {
87
+ const data = await gqlOf(transport)(POS_DEVICE_OFFLINE_SALES_TO_REVIEW_QUERY, { stockLocationId: options?.stockLocationId ?? null }, options);
88
+ return data.posDeviceFleet.map((row) => ({
89
+ deviceId: row.device.id,
90
+ offlineSalesToReview: row.offlineSalesToReview,
91
+ }));
92
+ }
93
+ export function createPosOfflineSalesModule(transport) {
94
+ const gql = gqlOf(transport);
95
+ async function salePage(skip, take, options) {
96
+ const input = { skip, take };
97
+ if (options?.filter !== undefined)
98
+ input.filter = options.filter;
99
+ if (options?.deviceId !== undefined)
100
+ input.deviceId = options.deviceId;
101
+ const data = await gql(POS_OFFLINE_SALES_QUERY, { input }, options);
102
+ return pageFromVendureList(data.posOfflineSales, skip, take, (cursor) => salePage(readOffsetCursor(cursor), take, options));
103
+ }
104
+ return {
105
+ async list(options) {
106
+ const take = Math.min(Math.max(Math.trunc(options?.limit ?? DEFAULT_PAGE), 1), MAX_PAGE);
107
+ const skip = options?.after === undefined ? 0 : readOffsetCursor(options.after);
108
+ return salePage(skip, take, options);
109
+ },
110
+ async resolve(input, options) {
111
+ // Sent as given: the engine trims and judges the note (POS_OFFLINE_NOTE_INVALID).
112
+ const data = await gql(RESOLVE_POS_OFFLINE_SALE_MUTATION, { input: { id: input.id, note: input.note } }, options);
113
+ return data.resolvePosOfflineSale;
114
+ },
115
+ };
116
+ }
@@ -0,0 +1,143 @@
1
+ import type { Transport } from '@sixtyninecommerce/core';
2
+ import type { Call } from '../types.js';
3
+ /**
4
+ * Pay by link at the till (engine C5, row 41): the till asks the customer to pay part or all of an
5
+ * open till sale through a link (shown as a QR code), which opens the store's online checkout on
6
+ * the customer's phone. The payment provider's webhook records the money on the sale; none of
7
+ * these calls does. While a link is open its amount is held back from every other tender
8
+ * (`outstanding` leaves it out) and the sale's money cannot change. Off until the store switches
9
+ * it on and picks the hosted payment method customers pay with.
10
+ *
11
+ * A headless till is a supported caller of every till money door: the link create is keyed like a
12
+ * tender (`idempotencyKey`), its check and cancel take no key (they read the state and are safe to
13
+ * repeat). An engine before C5 answers every call `GRAPHQL_VALIDATION_FAILED`.
14
+ */
15
+ /** A link's life in minutes (the store's policy). */
16
+ export declare const POS_PAY_BY_LINK_EXPIRY_MINUTES: {
17
+ readonly min: 5;
18
+ readonly max: 120;
19
+ readonly default: 30;
20
+ };
21
+ export interface PosPayByLinkPolicy {
22
+ enabled: boolean;
23
+ /** The code of the store's hosted payment method a link opens; null until chosen. */
24
+ methodCode: string | null;
25
+ /** 5-120; 30 by default. */
26
+ expiryMinutes: number;
27
+ }
28
+ export interface PosPayByLinkPolicyInput {
29
+ /** Omitted keeps the stored value. Switching on needs a method. */
30
+ enabled?: boolean;
31
+ methodCode?: string;
32
+ expiryMinutes?: number;
33
+ }
34
+ /** Whether the till may offer pay by link for a sale. */
35
+ export interface PosPayByLinkOptions {
36
+ available: boolean;
37
+ /**
38
+ * Why not: `OFF`, `NO_METHOD`, `METHOD_UNUSABLE`, `NO_RETURN_PAGE`, `NOT_ENTITLED`,
39
+ * `NOT_CONFIGURED`; more may come. Null when available.
40
+ */
41
+ reason: string | null;
42
+ methodName: string | null;
43
+ expiryMinutes: number;
44
+ }
45
+ export interface PosPaymentRequest {
46
+ id: string;
47
+ amount: number;
48
+ currencyCode: string;
49
+ /** `OPEN`, `PAID`, `EXPIRED` or `CANCELLED`; more may come. */
50
+ status: string;
51
+ closeReason: string | null;
52
+ /** The link to show as a QR code; null once it is closed. A bearer link: never log it. */
53
+ url: string | null;
54
+ expiresAt: string;
55
+ createdAt: string;
56
+ /** How many checkouts the customer opened with it. */
57
+ attemptCount: number;
58
+ paymentId: string | null;
59
+ }
60
+ /** The sale's money with its links (`PosTenderState`), integer minor units. */
61
+ export interface PosLinkTenderState {
62
+ orderId: string;
63
+ total: number;
64
+ settled: number;
65
+ pending: number;
66
+ /** What the OPEN links ask for, already left out of `outstanding`. */
67
+ requested: number;
68
+ /** What a new tender may take: total − settled − pending − requested, at least 0. */
69
+ outstanding: number;
70
+ covered: boolean;
71
+ paymentRequests: PosPaymentRequest[];
72
+ }
73
+ export interface PosPaymentRequestResult {
74
+ request: PosPaymentRequest;
75
+ tenderState: PosLinkTenderState;
76
+ }
77
+ export interface PosPaymentRequestOutcomeResult {
78
+ requestId: string;
79
+ /** `paid`, `pending`, `cancelled` or `unknown`; treat one you do not know as `unknown`. */
80
+ outcome: string;
81
+ /**
82
+ * Why, when pending, unknown or forced: `POS_PAYMENT_REQUEST_WAITING`, `…_CHECKOUT_OPEN`,
83
+ * `…_PAID_LANDING`, `…_PROVIDER_UNREACHABLE`, `…_FORCED`. Null otherwise.
84
+ */
85
+ reasonCode: string | null;
86
+ tenderState: PosLinkTenderState;
87
+ }
88
+ /** A till call's cashier: a paired DEVICE's PIN session; a machine principal omits it. */
89
+ type TillCall = Call & {
90
+ staffToken?: string;
91
+ };
92
+ export interface PosPayByLinkModule {
93
+ /** The store's policy. Needs `UpdateSettings` or `ManagePosDevices`. */
94
+ policy(options?: Call): Promise<PosPayByLinkPolicy>;
95
+ /**
96
+ * Set it (omitted fields keep their value). Needs `UpdateSettings`. Refusals:
97
+ * `POS_PAY_BY_LINK_POLICY_INVALID` (`field`: `expiryMinutes` outside 5-120, a blank `methodCode`,
98
+ * or switched on with no method), `POS_PAY_BY_LINK_METHOD_UNUSABLE` (`reason`: switched on with a
99
+ * method that cannot open an online checkout here), `ORGANIZATION_WORKSPACE_NOT_A_STORE`.
100
+ */
101
+ setPolicy(input: PosPayByLinkPolicyInput, options?: Call): Promise<PosPayByLinkPolicy>;
102
+ /** Whether a link may be offered for this sale, and why not. Read only. */
103
+ options(orderId: string, options?: Call): Promise<PosPayByLinkOptions>;
104
+ /**
105
+ * Open a link for `amount` (at most what the sale still owes) on an open till sale; readies it
106
+ * for payment. Keyed: a repeat with the same `idempotencyKey` answers the same link. Refusals:
107
+ * `POS_PAY_BY_LINK_UNAVAILABLE` (`reason`), `POS_PAY_BY_LINK_TILL_CART_ONLY` (an order no till
108
+ * opened: send a link from the back office), `POS_PAYMENT_REQUEST_OPEN` (one open link per sale),
109
+ * `POS_TENDER_EXCEEDS_OUTSTANDING` (`requested`).
110
+ */
111
+ request(input: {
112
+ orderId: string;
113
+ amount: number;
114
+ }, options: TillCall & {
115
+ idempotencyKey: string;
116
+ }): Promise<PosPaymentRequestResult>;
117
+ /** How a link is doing; never records money. Refused `POS_PAYMENT_REQUEST_NOT_FOUND`. */
118
+ check(input: {
119
+ orderId: string;
120
+ requestId: string;
121
+ }, options?: TillCall): Promise<PosPaymentRequestOutcomeResult>;
122
+ /**
123
+ * Close a link: only when no checkout of the customer's can still pay, else it answers pending or
124
+ * unknown and stays open. `force` closes it anyway and needs a manager: a manager's own
125
+ * `staffToken` or a manager's `approvalToken` (`POS_MANAGER_REQUIRED` otherwise); a payment that
126
+ * lands afterwards is recorded on the sale and refunded like any other.
127
+ */
128
+ cancel(input: {
129
+ orderId: string;
130
+ requestId: string;
131
+ force?: boolean;
132
+ }, options?: TillCall & {
133
+ approvalToken?: string;
134
+ }): Promise<PosPaymentRequestOutcomeResult>;
135
+ }
136
+ export declare const POS_PAY_BY_LINK_POLICY_QUERY = "query PosPayByLinkPolicy { posPayByLinkPolicy { enabled methodCode expiryMinutes } }";
137
+ export declare const SET_POS_PAY_BY_LINK_POLICY_MUTATION = "mutation SetPosPayByLinkPolicy($input: PosPayByLinkPolicyInput!) { setPosPayByLinkPolicy(input: $input) { enabled methodCode expiryMinutes } }";
138
+ export declare const POS_PAY_BY_LINK_OPTIONS_QUERY = "query PosPayByLinkOptions($orderId: ID!) { posPayByLinkOptions(orderId: $orderId) { available reason methodName expiryMinutes } }";
139
+ export declare const POS_REQUEST_PAYMENT_MUTATION = "mutation PosRequestPayment($input: PosRequestPaymentInput!, $staffToken: String) { posRequestPayment(input: $input, staffToken: $staffToken) { request { id amount currencyCode status closeReason url expiresAt createdAt attemptCount paymentId } tenderState { orderId total settled pending requested outstanding covered paymentRequests { id amount currencyCode status closeReason url expiresAt createdAt attemptCount paymentId } } } }";
140
+ export declare const POS_CHECK_PAYMENT_REQUEST_MUTATION = "mutation PosCheckPaymentRequest($input: PosPaymentRequestInput!, $staffToken: String) { posCheckPaymentRequest(input: $input, staffToken: $staffToken) { requestId outcome reasonCode tenderState { orderId total settled pending requested outstanding covered paymentRequests { id amount currencyCode status closeReason url expiresAt createdAt attemptCount paymentId } } } }";
141
+ export declare const POS_CANCEL_PAYMENT_REQUEST_MUTATION = "mutation PosCancelPaymentRequest($input: PosCancelPaymentRequestInput!, $staffToken: String, $approvalToken: String) { posCancelPaymentRequest(input: $input, staffToken: $staffToken, approvalToken: $approvalToken) { requestId outcome reasonCode tenderState { orderId total settled pending requested outstanding covered paymentRequests { id amount currencyCode status closeReason url expiresAt createdAt attemptCount paymentId } } } }";
142
+ export declare function createPosPayByLinkModule(transport: Transport): PosPayByLinkModule;
143
+ export {};
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Pay by link at the till (engine C5, row 41): the till asks the customer to pay part or all of an
3
+ * open till sale through a link (shown as a QR code), which opens the store's online checkout on
4
+ * the customer's phone. The payment provider's webhook records the money on the sale; none of
5
+ * these calls does. While a link is open its amount is held back from every other tender
6
+ * (`outstanding` leaves it out) and the sale's money cannot change. Off until the store switches
7
+ * it on and picks the hosted payment method customers pay with.
8
+ *
9
+ * A headless till is a supported caller of every till money door: the link create is keyed like a
10
+ * tender (`idempotencyKey`), its check and cancel take no key (they read the state and are safe to
11
+ * repeat). An engine before C5 answers every call `GRAPHQL_VALIDATION_FAILED`.
12
+ */
13
+ /** A link's life in minutes (the store's policy). */
14
+ export const POS_PAY_BY_LINK_EXPIRY_MINUTES = { min: 5, max: 120, default: 30 };
15
+ const POLICY_FIELDS = 'enabled methodCode expiryMinutes';
16
+ const REQUEST_FIELDS = 'id amount currencyCode status closeReason url expiresAt createdAt attemptCount paymentId';
17
+ const STATE_FIELDS = `orderId total settled pending requested outstanding covered paymentRequests { ${REQUEST_FIELDS} }`;
18
+ const OUTCOME_FIELDS = `requestId outcome reasonCode tenderState { ${STATE_FIELDS} }`;
19
+ export const POS_PAY_BY_LINK_POLICY_QUERY = `query PosPayByLinkPolicy { posPayByLinkPolicy { ${POLICY_FIELDS} } }`;
20
+ export const SET_POS_PAY_BY_LINK_POLICY_MUTATION = `mutation SetPosPayByLinkPolicy($input: PosPayByLinkPolicyInput!) { setPosPayByLinkPolicy(input: $input) { ${POLICY_FIELDS} } }`;
21
+ export const POS_PAY_BY_LINK_OPTIONS_QUERY = 'query PosPayByLinkOptions($orderId: ID!) { posPayByLinkOptions(orderId: $orderId) { available reason methodName expiryMinutes } }';
22
+ export const POS_REQUEST_PAYMENT_MUTATION = `mutation PosRequestPayment($input: PosRequestPaymentInput!, $staffToken: String) { posRequestPayment(input: $input, staffToken: $staffToken) { request { ${REQUEST_FIELDS} } tenderState { ${STATE_FIELDS} } } }`;
23
+ export const POS_CHECK_PAYMENT_REQUEST_MUTATION = `mutation PosCheckPaymentRequest($input: PosPaymentRequestInput!, $staffToken: String) { posCheckPaymentRequest(input: $input, staffToken: $staffToken) { ${OUTCOME_FIELDS} } }`;
24
+ export const POS_CANCEL_PAYMENT_REQUEST_MUTATION = `mutation PosCancelPaymentRequest($input: PosCancelPaymentRequestInput!, $staffToken: String, $approvalToken: String) { posCancelPaymentRequest(input: $input, staffToken: $staffToken, approvalToken: $approvalToken) { ${OUTCOME_FIELDS} } }`;
25
+ export function createPosPayByLinkModule(transport) {
26
+ const gql = async (query, variables, options) => transport.graphql({ api: 'admin', query, variables }, options);
27
+ return {
28
+ async policy(options) {
29
+ const data = await gql(POS_PAY_BY_LINK_POLICY_QUERY, {}, options);
30
+ return data.posPayByLinkPolicy;
31
+ },
32
+ async setPolicy(input, options) {
33
+ const data = await gql(SET_POS_PAY_BY_LINK_POLICY_MUTATION, { input }, options);
34
+ return data.setPosPayByLinkPolicy;
35
+ },
36
+ async options(orderId, options) {
37
+ const data = await gql(POS_PAY_BY_LINK_OPTIONS_QUERY, { orderId }, options);
38
+ return data.posPayByLinkOptions;
39
+ },
40
+ async request(input, options) {
41
+ const key = options?.idempotencyKey;
42
+ if (typeof key !== 'string' || key.trim() === '') {
43
+ throw new TypeError('payByLink.request needs options.idempotencyKey (a fresh UUIDv7 per link; resend it only to retry the same link).');
44
+ }
45
+ const data = await gql(POS_REQUEST_PAYMENT_MUTATION, { input: { ...input, idempotencyKey: key }, staffToken: options.staffToken }, options);
46
+ return data.posRequestPayment;
47
+ },
48
+ async check(input, options) {
49
+ const data = await gql(POS_CHECK_PAYMENT_REQUEST_MUTATION, { input, staffToken: options?.staffToken }, options);
50
+ return data.posCheckPaymentRequest;
51
+ },
52
+ async cancel(input, options) {
53
+ const data = await gql(POS_CANCEL_PAYMENT_REQUEST_MUTATION, { input, staffToken: options?.staffToken, approvalToken: options?.approvalToken }, options);
54
+ return data.posCancelPaymentRequest;
55
+ },
56
+ };
57
+ }