@sixtyninecommerce/admin 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5772 -118
- package/dist/auth/index.d.ts +7 -1
- package/dist/auth/index.js +8 -1
- package/dist/catalog/assets.d.ts +120 -8
- package/dist/catalog/assets.js +98 -12
- package/dist/catalog/collections.d.ts +279 -14
- package/dist/catalog/collections.js +246 -15
- package/dist/catalog/documents.d.ts +142 -0
- package/dist/catalog/documents.js +114 -0
- package/dist/catalog/index.d.ts +54 -6
- package/dist/catalog/index.js +10 -1
- package/dist/catalog/metadata.d.ts +244 -0
- package/dist/catalog/metadata.js +220 -0
- package/dist/catalog/products.d.ts +159 -19
- package/dist/catalog/products.js +88 -13
- package/dist/catalog/properties.d.ts +140 -14
- package/dist/catalog/properties.js +65 -1
- package/dist/catalog/recommendations.d.ts +288 -0
- package/dist/catalog/recommendations.js +237 -0
- package/dist/catalog/reviews.d.ts +381 -0
- package/dist/catalog/reviews.js +325 -0
- package/dist/catalog/types.d.ts +17 -1
- package/dist/catalog/types.js +10 -0
- package/dist/catalog/variant-find.d.ts +136 -0
- package/dist/catalog/variant-find.js +239 -0
- package/dist/catalog/variants.d.ts +293 -26
- package/dist/catalog/variants.js +164 -7
- package/dist/catalog/visibility.d.ts +38 -7
- package/dist/catalog/visibility.js +19 -1
- package/dist/client.d.ts +121 -9
- package/dist/client.js +53 -14
- package/dist/content/assets.d.ts +285 -0
- package/dist/content/assets.js +181 -0
- package/dist/content/forms.d.ts +332 -1
- package/dist/content/forms.js +140 -4
- package/dist/content/items.d.ts +292 -0
- package/dist/content/items.js +170 -0
- package/dist/content/menus.d.ts +254 -0
- package/dist/content/menus.js +70 -0
- package/dist/content/strings.d.ts +137 -0
- package/dist/content/strings.js +82 -0
- package/dist/content/types.d.ts +282 -0
- package/dist/content/types.js +100 -0
- package/dist/customers/age-verification.d.ts +66 -0
- package/dist/customers/age-verification.js +79 -0
- package/dist/customers/credit.d.ts +263 -0
- package/dist/customers/credit.js +244 -0
- package/dist/customers/delivery-preferences.d.ts +120 -0
- package/dist/customers/delivery-preferences.js +97 -0
- package/dist/customers/delivery-terms.d.ts +44 -0
- package/dist/customers/delivery-terms.js +32 -0
- package/dist/customers/groups.d.ts +207 -0
- package/dist/customers/groups.js +438 -0
- package/dist/customers/index.d.ts +462 -37
- package/dist/customers/index.js +317 -40
- package/dist/customers/invitation-status.d.ts +57 -0
- package/dist/customers/invitation-status.js +21 -0
- package/dist/customers/notes.d.ts +67 -0
- package/dist/customers/notes.js +51 -0
- package/dist/customers/notification-recipients.d.ts +97 -0
- package/dist/customers/notification-recipients.js +84 -0
- package/dist/customers/saved-lists.d.ts +42 -0
- package/dist/customers/saved-lists.js +61 -0
- package/dist/customers/vat.d.ts +83 -0
- package/dist/customers/vat.js +46 -0
- package/dist/customers/wire.d.ts +20 -0
- package/dist/customers/wire.js +35 -0
- package/dist/documents/ar.d.ts +307 -0
- package/dist/documents/ar.js +254 -0
- package/dist/documents/emails.d.ts +150 -0
- package/dist/documents/emails.js +220 -0
- package/dist/documents/index.d.ts +744 -21
- package/dist/documents/index.js +438 -24
- package/dist/documents/pdf.d.ts +2 -0
- package/dist/documents/pdf.js +11 -0
- package/dist/fulfillments/create.d.ts +167 -0
- package/dist/fulfillments/create.js +216 -0
- package/dist/fulfillments/index.d.ts +163 -11
- package/dist/fulfillments/index.js +135 -6
- package/dist/fulfillments/payment-policy.d.ts +64 -0
- package/dist/fulfillments/payment-policy.js +140 -0
- package/dist/fulfillments/warehouse.d.ts +724 -0
- package/dist/fulfillments/warehouse.js +914 -0
- package/dist/geo/index.d.ts +119 -0
- package/dist/geo/index.js +107 -0
- package/dist/index.d.ts +147 -39
- package/dist/index.js +51 -12
- package/dist/integrations/afas-actions.d.ts +234 -0
- package/dist/integrations/afas-actions.js +310 -0
- package/dist/integrations/afas-types.d.ts +483 -0
- package/dist/integrations/afas-types.js +5 -0
- package/dist/integrations/afas.d.ts +234 -0
- package/dist/integrations/afas.js +290 -0
- package/dist/integrations/connections.d.ts +103 -0
- package/dist/integrations/connections.js +55 -0
- package/dist/integrations/esp.d.ts +313 -0
- package/dist/integrations/esp.js +169 -0
- package/dist/integrations/exact-online-types.d.ts +965 -0
- package/dist/integrations/exact-online-types.js +6 -0
- package/dist/integrations/exact-online.d.ts +784 -0
- package/dist/integrations/exact-online.js +1089 -0
- package/dist/integrations/index.d.ts +44 -3
- package/dist/integrations/index.js +23 -3
- package/dist/integrations/pipeline-discoveries.d.ts +65 -0
- package/dist/integrations/pipeline-discoveries.js +65 -0
- package/dist/integrations/pipeline-keys.d.ts +13 -0
- package/dist/integrations/pipeline-keys.js +22 -0
- package/dist/integrations/pipeline-runs.d.ts +119 -0
- package/dist/integrations/pipeline-runs.js +87 -0
- package/dist/integrations/pipelines.d.ts +87 -15
- package/dist/integrations/pipelines.js +41 -22
- package/dist/integrations/price-import.d.ts +223 -0
- package/dist/integrations/price-import.js +124 -0
- package/dist/integrations/types.d.ts +367 -3
- package/dist/integrations/types.js +4 -3
- package/dist/locations/index.d.ts +66 -0
- package/dist/locations/index.js +31 -0
- package/dist/meta/index.d.ts +172 -0
- package/dist/metafields/index.d.ts +8 -1
- package/dist/metafields/index.js +10 -0
- package/dist/orders/cancel-with-money.d.ts +237 -0
- package/dist/orders/cancel-with-money.js +155 -0
- package/dist/orders/commit-edit.d.ts +23 -1
- package/dist/orders/commit-edit.js +19 -2
- package/dist/orders/deposit-policy.d.ts +3 -1
- package/dist/orders/drafts.d.ts +800 -0
- package/dist/orders/drafts.js +771 -0
- package/dist/orders/fields.d.ts +245 -0
- package/dist/orders/fields.js +188 -0
- package/dist/orders/get.d.ts +29 -19
- package/dist/orders/get.js +17 -8
- package/dist/orders/index.d.ts +66 -15
- package/dist/orders/index.js +25 -2
- package/dist/orders/lifecycle.d.ts +128 -0
- package/dist/orders/lifecycle.js +158 -0
- package/dist/orders/line-price-preview.d.ts +7 -2
- package/dist/orders/list.d.ts +243 -0
- package/dist/orders/list.js +487 -0
- package/dist/orders/manual-discounts.d.ts +13 -5
- package/dist/orders/manual-pricing.d.ts +5 -0
- package/dist/orders/money-view.d.ts +149 -0
- package/dist/orders/money-view.js +99 -0
- package/dist/orders/order-entry.d.ts +20 -7
- package/dist/orders/plan-edit.d.ts +34 -2
- package/dist/orders/plan-edit.js +112 -11
- package/dist/orders/settings.d.ts +201 -0
- package/dist/orders/settings.js +325 -0
- package/dist/orders/status.d.ts +159 -13
- package/dist/orders/status.js +21 -0
- package/dist/orders/surcharges.d.ts +20 -1
- package/dist/orders/surcharges.js +37 -11
- package/dist/payments/account-credit.d.ts +46 -0
- package/dist/payments/account-credit.js +42 -0
- package/dist/payments/ar.d.ts +292 -0
- package/dist/payments/ar.js +223 -0
- package/dist/payments/connected-account.d.ts +47 -0
- package/dist/payments/connected-account.js +61 -0
- package/dist/payments/credit-noted-fields.d.ts +19 -0
- package/dist/payments/credit-noted-fields.js +69 -0
- package/dist/payments/customer-consent.d.ts +30 -0
- package/dist/payments/customer-consent.js +49 -0
- package/dist/payments/index.d.ts +340 -19
- package/dist/payments/index.js +151 -1
- package/dist/payments/methods.d.ts +303 -8
- package/dist/payments/methods.js +337 -7
- package/dist/payments/mollie-methods.d.ts +159 -0
- package/dist/payments/mollie-methods.js +141 -0
- package/dist/payments/payment-links.d.ts +180 -0
- package/dist/payments/payment-links.js +97 -0
- package/dist/payments/provider-keys.d.ts +150 -0
- package/dist/payments/provider-keys.js +118 -0
- package/dist/payments/providers.d.ts +86 -11
- package/dist/payments/providers.js +29 -0
- package/dist/payments/requests.d.ts +147 -0
- package/dist/payments/requests.js +93 -0
- package/dist/payments/store-credit-fields.d.ts +15 -0
- package/dist/payments/store-credit-fields.js +51 -0
- package/dist/pickups/index.d.ts +106 -0
- package/dist/pickups/index.js +108 -0
- package/dist/platform/channels.d.ts +132 -0
- package/dist/platform/channels.js +128 -0
- package/dist/platform/email-gateways.d.ts +165 -0
- package/dist/platform/email-gateways.js +78 -0
- package/dist/platform/geo.d.ts +123 -0
- package/dist/platform/geo.js +144 -0
- package/dist/platform/tax.d.ts +162 -0
- package/dist/platform/tax.js +169 -0
- package/dist/pos/anomalies.d.ts +158 -0
- package/dist/pos/anomalies.js +64 -0
- package/dist/pos/assisted-selling.d.ts +79 -0
- package/dist/pos/assisted-selling.js +38 -0
- package/dist/pos/exchanges.d.ts +108 -0
- package/dist/pos/exchanges.js +22 -0
- package/dist/pos/gift-cards.d.ts +135 -0
- package/dist/pos/gift-cards.js +47 -0
- package/dist/pos/index.d.ts +2370 -58
- package/dist/pos/index.js +854 -7
- package/dist/pos/no-receipt.d.ts +94 -0
- package/dist/pos/no-receipt.js +25 -0
- package/dist/pos/offline-sales.d.ts +228 -0
- package/dist/pos/offline-sales.js +170 -0
- package/dist/pos/pay-by-link.d.ts +143 -0
- package/dist/pos/pay-by-link.js +57 -0
- package/dist/pos/quick-keys.d.ts +103 -0
- package/dist/pos/quick-keys.js +45 -0
- package/dist/pos/reports.d.ts +360 -0
- package/dist/pos/reports.js +62 -0
- package/dist/pos/returns.d.ts +244 -0
- package/dist/pos/returns.js +83 -0
- package/dist/pricing/bulk-coupons.d.ts +139 -0
- package/dist/pricing/bulk-coupons.js +112 -0
- package/dist/pricing/index.d.ts +174 -4
- package/dist/pricing/index.js +174 -1
- package/dist/pricing/price-lists.d.ts +606 -0
- package/dist/pricing/price-lists.js +600 -0
- package/dist/purchasing/alerts.d.ts +104 -0
- package/dist/purchasing/alerts.js +88 -0
- package/dist/purchasing/backorders.d.ts +61 -0
- package/dist/purchasing/backorders.js +92 -0
- package/dist/purchasing/cost.d.ts +110 -0
- package/dist/purchasing/cost.js +86 -0
- package/dist/purchasing/index.d.ts +54 -0
- package/dist/purchasing/index.js +24 -0
- package/dist/purchasing/links.d.ts +263 -0
- package/dist/purchasing/links.js +192 -0
- package/dist/purchasing/purchase-orders.d.ts +551 -0
- package/dist/purchasing/purchase-orders.js +491 -0
- package/dist/purchasing/receipts.d.ts +396 -0
- package/dist/purchasing/receipts.js +287 -0
- package/dist/purchasing/replenishment.d.ts +281 -0
- package/dist/purchasing/replenishment.js +240 -0
- package/dist/purchasing/returns.d.ts +273 -0
- package/dist/purchasing/returns.js +229 -0
- package/dist/purchasing/settings.d.ts +152 -0
- package/dist/purchasing/settings.js +181 -0
- package/dist/purchasing/suppliers.d.ts +476 -0
- package/dist/purchasing/suppliers.js +438 -0
- package/dist/quotes/index.d.ts +518 -0
- package/dist/quotes/index.js +439 -0
- package/dist/reports/index.d.ts +71 -8
- package/dist/reports/index.js +74 -11
- package/dist/returns/index.d.ts +675 -21
- package/dist/returns/index.js +756 -11
- package/dist/search/index.d.ts +76 -1
- package/dist/search/index.js +63 -0
- package/dist/seo/config.d.ts +128 -0
- package/dist/seo/config.js +95 -0
- package/dist/seo/redirects.d.ts +125 -0
- package/dist/seo/redirects.js +60 -1
- package/dist/seo/settings.d.ts +147 -0
- package/dist/seo/settings.js +209 -0
- package/dist/shipping/definitions.d.ts +29 -0
- package/dist/shipping/definitions.js +47 -0
- package/dist/shipping/fulfillment-profiles.d.ts +174 -0
- package/dist/shipping/fulfillment-profiles.js +104 -0
- package/dist/shipping/hendriks.d.ts +97 -0
- package/dist/shipping/hendriks.js +50 -0
- package/dist/shipping/index.d.ts +54 -0
- package/dist/shipping/index.js +27 -0
- package/dist/shipping/methods.d.ts +205 -0
- package/dist/shipping/methods.js +240 -0
- package/dist/shipping/myparcel.d.ts +668 -0
- package/dist/shipping/myparcel.js +466 -0
- package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
- package/dist/shipping/parcel-rule.d.ts +6 -5
- package/dist/shipping/parcel-rule.js +21 -23
- package/dist/shipping/rate-tables.d.ts +324 -0
- package/dist/shipping/rate-tables.js +390 -0
- package/dist/shipping/ship-to-countries.d.ts +75 -0
- package/dist/shipping/ship-to-countries.js +47 -0
- package/dist/stock/by-location.d.ts +86 -0
- package/dist/stock/by-location.js +94 -0
- package/dist/stock/index.d.ts +18 -4
- package/dist/stock/index.js +7 -0
- package/dist/stock/locations.d.ts +144 -0
- package/dist/stock/locations.js +168 -0
- package/dist/stock/settings.d.ts +106 -0
- package/dist/stock/settings.js +103 -0
- package/dist/stock/transfers.d.ts +386 -52
- package/dist/stock/transfers.js +222 -17
- package/dist/stored-value/index.d.ts +312 -11
- package/dist/stored-value/index.js +223 -4
- package/dist/subscriptions/index.d.ts +682 -0
- package/dist/subscriptions/index.js +815 -0
- package/dist/tax/display-policy.d.ts +105 -0
- package/dist/tax/display-policy.js +84 -0
- package/dist/tax/index.d.ts +79 -1
- package/dist/tax/index.js +52 -0
- package/dist/tenant/email-style.d.ts +102 -0
- package/dist/tenant/email-style.js +72 -0
- package/dist/tenant/email-templates.d.ts +287 -0
- package/dist/tenant/email-templates.js +271 -0
- package/dist/tenant/notifications.d.ts +23 -17
- package/dist/tenant/settings-sources.d.ts +1 -1
- package/dist/tenant/time-zone.d.ts +17 -0
- package/dist/tenant/time-zone.js +11 -0
- package/dist/types.d.ts +50 -3
- package/dist/users/index.d.ts +3 -0
- package/dist/users/index.js +2 -0
- package/dist/users/warehouses.d.ts +50 -0
- package/dist/users/warehouses.js +51 -0
- 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,228 @@
|
|
|
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 `price_over_limit`: 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_over_limit", "price_changed", "not_fulfilled", "cashier_changed", "policy_off", "over_cap", "sold_at_suspect", "cashier_unverified", "item_gone_stand_in", "stock_short_stand_in", "total_corrected", "rounding_as_rung"];
|
|
54
|
+
export type PosOfflineSaleReason = (typeof POS_OFFLINE_SALE_REASONS)[number];
|
|
55
|
+
/**
|
|
56
|
+
* The reasons the engine REFUSES a sale for (nothing recorded but its row): `item_gone` to
|
|
57
|
+
* `price_over_limit`. Every other reason is a review of a recorded sale. A reason this release does
|
|
58
|
+
* not know is neither: show it as it is.
|
|
59
|
+
*/
|
|
60
|
+
export declare const POS_OFFLINE_SALE_REFUSAL_REASONS: readonly PosOfflineSaleReason[];
|
|
61
|
+
/**
|
|
62
|
+
* `recorded` (the order, the cash and the receipt number exist, as the till rang it),
|
|
63
|
+
* `needs_review` (recorded, with a reason to look at) or `refused` (nothing but this row). More
|
|
64
|
+
* may come: show an unknown status as it is.
|
|
65
|
+
*/
|
|
66
|
+
export type PosOfflineSaleStatus = 'recorded' | 'needs_review' | 'refused';
|
|
67
|
+
/** A store's offline cash sales (engine sprint 45): the switch, its limits, and its readiness. */
|
|
68
|
+
export interface PosOfflineCashSales {
|
|
69
|
+
/** Off until a manager turns it on. */
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
/** The largest offline sale, minor units of the store's default currency. */
|
|
72
|
+
maxSaleAmount: number;
|
|
73
|
+
/** Offline sales a till makes in one outage. */
|
|
74
|
+
maxSalesPerOutage: number;
|
|
75
|
+
/** Minutes after the server last answered that a till still sells offline. */
|
|
76
|
+
maxOfflineMinutes: number;
|
|
77
|
+
/** Whether this store can sell offline now: switched on is not enough. */
|
|
78
|
+
ready: boolean;
|
|
79
|
+
/** Why not; empty when ready. Strings, so a reason a newer engine adds never fails a read. */
|
|
80
|
+
notReadyReasons: Array<PosOfflineNotReadyReason | (string & {})>;
|
|
81
|
+
}
|
|
82
|
+
/** What `setOfflineCashSales` stores: every field, each within {@link POS_OFFLINE_CASH_SALES_LIMITS}. */
|
|
83
|
+
export interface PosOfflineCashSalesInput {
|
|
84
|
+
enabled: boolean;
|
|
85
|
+
maxSaleAmount: number;
|
|
86
|
+
maxSalesPerOutage: number;
|
|
87
|
+
maxOfflineMinutes: number;
|
|
88
|
+
}
|
|
89
|
+
/** One line of an offline sale: what the till charged, and the server's price beside it. */
|
|
90
|
+
export interface PosOfflineSaleLine {
|
|
91
|
+
variantId: string;
|
|
92
|
+
quantity: number;
|
|
93
|
+
/** The unit price with tax the till charged, minor units. */
|
|
94
|
+
unitPriceWithTax: number;
|
|
95
|
+
/**
|
|
96
|
+
* The server's unit price with tax when the sale was recorded; null when the variant was gone or
|
|
97
|
+
* the sale was refused before it was built.
|
|
98
|
+
*/
|
|
99
|
+
serverUnitPriceWithTax: number | null;
|
|
100
|
+
}
|
|
101
|
+
/** An offline sale as the engine recorded or refused it (engine sprint 45). Money in minor units. */
|
|
102
|
+
export interface PosOfflineSale {
|
|
103
|
+
id: string;
|
|
104
|
+
deviceId: string;
|
|
105
|
+
/** The till's name as the store names it now; null when it is gone. */
|
|
106
|
+
deviceLabel: string | null;
|
|
107
|
+
/** The drawer the till had open when it sold. */
|
|
108
|
+
registerSessionId: string;
|
|
109
|
+
/** The till's own id for the sale (a uuid). */
|
|
110
|
+
offlineSaleId: string;
|
|
111
|
+
/** The number printed on the provisional receipt the customer took. */
|
|
112
|
+
provisionalReceiptNumber: string;
|
|
113
|
+
/** When the till completed it, by the till's clock. */
|
|
114
|
+
soldAt: string;
|
|
115
|
+
/** When the engine received it. */
|
|
116
|
+
recordedAt: string;
|
|
117
|
+
status: PosOfflineSaleStatus | (string & {});
|
|
118
|
+
/** {@link PosOfflineSaleReason}s; strings, so one a newer engine adds never fails a read. */
|
|
119
|
+
reasons: Array<PosOfflineSaleReason | (string & {})>;
|
|
120
|
+
/** The order it became; null when refused. */
|
|
121
|
+
orderId: string | null;
|
|
122
|
+
orderCode: string | null;
|
|
123
|
+
/** The final receipt number; null when refused. */
|
|
124
|
+
receiptNumber: string | null;
|
|
125
|
+
currencyCode: string;
|
|
126
|
+
totalWithTax: number;
|
|
127
|
+
cashTendered: number;
|
|
128
|
+
changeGiven: number;
|
|
129
|
+
/** The cash rounding the till applied, signed. */
|
|
130
|
+
cashRounding: number;
|
|
131
|
+
lines: PosOfflineSaleLine[];
|
|
132
|
+
/** The cashier signed in when the till sent it (verified), as the store names them now. */
|
|
133
|
+
staffName: string | null;
|
|
134
|
+
/** The cashier the till says rang it up: its claim. */
|
|
135
|
+
claimedStaffName: string | null;
|
|
136
|
+
/** When a manager marked it handled; null while it waits (or for a `recorded` sale). */
|
|
137
|
+
resolvedAt: string | null;
|
|
138
|
+
resolvedByUserName: string | null;
|
|
139
|
+
/** What the manager wrote they did about it. Staff text. */
|
|
140
|
+
resolutionNote: string | null;
|
|
141
|
+
/**
|
|
142
|
+
* When a manager recorded it again (engine with POS polish PR 6), and their name now. Answered
|
|
143
|
+
* by `recordAgain` and `list` (an engine before PR 6 answers its list without them: absent);
|
|
144
|
+
* absent from `resolve`.
|
|
145
|
+
*/
|
|
146
|
+
recordedAgainAt?: string | null;
|
|
147
|
+
recordedAgainByUserName?: string | null;
|
|
148
|
+
/**
|
|
149
|
+
* The drawer the sale's cash went into once recorded (its order's): the one it was rung in, or
|
|
150
|
+
* the one a manager recorded it again into (engine with POS polish PR 6); null while nothing is
|
|
151
|
+
* recorded, absent from an older engine (link `registerSessionId` then).
|
|
152
|
+
*/
|
|
153
|
+
cashRegisterSessionId?: string | null;
|
|
154
|
+
}
|
|
155
|
+
/** `open` (the default): the sales a manager must still handle; `all`: every offline sale. */
|
|
156
|
+
export type PosOfflineSaleFilter = 'open' | 'all';
|
|
157
|
+
export interface PosOfflineSaleListOptions extends ListOptions {
|
|
158
|
+
filter?: PosOfflineSaleFilter;
|
|
159
|
+
/** One device's sales. */
|
|
160
|
+
deviceId?: string;
|
|
161
|
+
}
|
|
162
|
+
/** How many of a device's offline sales wait for a manager (the fleet's `offlineSalesToReview`). */
|
|
163
|
+
export interface PosDeviceOfflineSalesToReview {
|
|
164
|
+
deviceId: string;
|
|
165
|
+
/** `needs_review` or `refused`, not yet handled. */
|
|
166
|
+
offlineSalesToReview: number;
|
|
167
|
+
}
|
|
168
|
+
export interface PosOfflineSalesModule {
|
|
169
|
+
/**
|
|
170
|
+
* The store's offline sales, newest first (`posOfflineSales`). `filter: 'open'` (the default)
|
|
171
|
+
* keeps the ones a manager must still handle (`needs_review` or `refused`, not yet handled);
|
|
172
|
+
* `'all'` every one. `deviceId` keeps one device's. `limit` is at most 100 (50 when omitted);
|
|
173
|
+
* `after` is the previous page's cursor; `total` counts the whole filter. A location-restricted
|
|
174
|
+
* caller sees the tills at its locations only. Refused `POS_LIST_RANGE_INVALID`
|
|
175
|
+
* (`extensions.field`, `reason`). Needs `UpdateSettings` or `ManagePosDevices`.
|
|
176
|
+
*/
|
|
177
|
+
list(options?: PosOfflineSaleListOptions): Promise<Page<PosOfflineSale>>;
|
|
178
|
+
/**
|
|
179
|
+
* Mark an offline sale handled, with what was done about it (`note`: 1 to 500 characters once
|
|
180
|
+
* trimmed, no control character but a line break or a tab). Nothing is recorded again: fix the
|
|
181
|
+
* order, the stock or the drawer first, then say so here. Idempotent by state: the same note
|
|
182
|
+
* again answers the sale unchanged. Refused `POS_OFFLINE_NOTE_INVALID` (`ValidationError`,
|
|
183
|
+
* `details[0].field` `note`), `POS_OFFLINE_SALE_NOT_FOUND` (`NotFoundError`: another store's, a
|
|
184
|
+
* till the caller may not see, an unknown id, or a `recorded` sale, which needs nobody) and
|
|
185
|
+
* `POS_OFFLINE_SALE_RESOLVED` (`BusinessRuleError`, `extensions.resolvedAt`: already handled
|
|
186
|
+
* with another note). Needs `UpdateSettings` or `ManagePosDevices`.
|
|
187
|
+
*/
|
|
188
|
+
resolve(input: {
|
|
189
|
+
id: string;
|
|
190
|
+
note: string;
|
|
191
|
+
}, options?: Call): Promise<PosOfflineSale>;
|
|
192
|
+
/**
|
|
193
|
+
* Record a REFUSED offline sale again (engine with POS polish PR 6): the engine builds it the
|
|
194
|
+
* way the till's replay does, into the sale's own drawer while that is open, else the open drawer
|
|
195
|
+
* `registerSessionId` names (ignored while the own one is open); it is attributed to the caller
|
|
196
|
+
* (`recordedAgainAt`, `recordedAgainByUserName`). A sale refused again stays `refused` with its new
|
|
197
|
+
* reasons; one recorded again already answers as it is. Refused `POS_OFFLINE_SALE_NOT_FOUND`
|
|
198
|
+
* (`NotFoundError`: another store's, a till the caller may not see, an unknown id, or a sale that
|
|
199
|
+
* is not refused) and `POS_OFFLINE_SALE_DRAWER_INVALID` (`ValidationError`,
|
|
200
|
+
* `extensions.registerSessionId`: the own drawer is closed and none, or no open drawer of the
|
|
201
|
+
* store, was named) and `LOCATION_NOT_ALLOWED` (`PermissionDeniedError`: the drawer, the sale's
|
|
202
|
+
* own or the one named, stands at a location a location-restricted caller may not act at).
|
|
203
|
+
* Needs `UpdateSettings` or `ManagePosDevices`, and `CreateOrder` (it records an order and its
|
|
204
|
+
* cash). An engine before PR 6 refuses the document.
|
|
205
|
+
*/
|
|
206
|
+
recordAgain(input: {
|
|
207
|
+
id: string;
|
|
208
|
+
registerSessionId?: string;
|
|
209
|
+
}, options?: Call): Promise<PosOfflineSale>;
|
|
210
|
+
}
|
|
211
|
+
export declare const POS_OFFLINE_CASH_SALES_QUERY = "query PosOfflineCashSales { getPosConfig { offlineCashSales { enabled maxSaleAmount maxSalesPerOutage maxOfflineMinutes ready notReadyReasons } } }";
|
|
212
|
+
export declare const SET_POS_OFFLINE_CASH_SALES_MUTATION = "mutation SetPosOfflineCashSales($input: PosOfflineCashSalesInput!) { setPosOfflineCashSales(input: $input) { enabled maxSaleAmount maxSalesPerOutage maxOfflineMinutes ready notReadyReasons } }";
|
|
213
|
+
/** The list, naming who recorded a sale again (engine POS polish PR 6). */
|
|
214
|
+
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 recordedAgainAt recordedAgainByUserName cashRegisterSessionId } totalItems } }";
|
|
215
|
+
/** The list as an engine before PR 6 reads it: sent once that engine refused the fields. */
|
|
216
|
+
export declare const POS_OFFLINE_SALES_QUERY_BEFORE_RECORD_AGAIN = "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 } }";
|
|
217
|
+
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 } }";
|
|
218
|
+
export declare const RECORD_POS_OFFLINE_SALE_AGAIN_MUTATION = "mutation RecordPosOfflineSaleAgain($input: RecordPosOfflineSaleAgainInput!) { recordPosOfflineSaleAgain(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 recordedAgainAt recordedAgainByUserName cashRegisterSessionId } }";
|
|
219
|
+
export declare const POS_DEVICE_OFFLINE_SALES_TO_REVIEW_QUERY = "query PosDeviceOfflineSalesToReview($stockLocationId: ID) { posDeviceFleet(stockLocationId: $stockLocationId) { device { id } offlineSalesToReview } }";
|
|
220
|
+
/** `admin.pos.settings.offlineCashSales()`: null when POS was never set up. */
|
|
221
|
+
export declare function readOfflineCashSales(transport: Transport, options?: Call): Promise<PosOfflineCashSales | null>;
|
|
222
|
+
/** `admin.pos.settings.setOfflineCashSales(input)`: the four fields, as given. */
|
|
223
|
+
export declare function writeOfflineCashSales(transport: Transport, input: PosOfflineCashSalesInput, options?: Call): Promise<PosOfflineCashSales>;
|
|
224
|
+
/** `admin.pos.devices.offlineSalesToReview()`: one row per device the fleet lists, whole. */
|
|
225
|
+
export declare function readOfflineSalesToReview(transport: Transport, options?: {
|
|
226
|
+
stockLocationId?: string;
|
|
227
|
+
} & Call): Promise<PosDeviceOfflineSalesToReview[]>;
|
|
228
|
+
export declare function createPosOfflineSalesModule(transport: Transport): PosOfflineSalesModule;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { pageFromVendureList, readOffsetCursor, } from '@sixtyninecommerce/core';
|
|
2
|
+
import { isUnknownFieldRejection } from '../payments/store-credit-fields.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 const POS_OFFLINE_CASH_SALES_LIMITS = {
|
|
27
|
+
maxSaleAmount: { min: 100, max: 500_000, default: 10_000 },
|
|
28
|
+
maxSalesPerOutage: { min: 1, max: 200, default: 25 },
|
|
29
|
+
maxOfflineMinutes: { min: 15, max: 720, default: 240 },
|
|
30
|
+
};
|
|
31
|
+
/** What a manager writes when marking an offline sale handled: 1 to this many characters, trimmed. */
|
|
32
|
+
export const POS_OFFLINE_SALE_NOTE_MAX_LENGTH = 500;
|
|
33
|
+
/** Why a store cannot sell offline now, in the order the engine lists them. More may come. */
|
|
34
|
+
export const POS_OFFLINE_NOT_READY_REASONS = [
|
|
35
|
+
'prices_exclude_tax',
|
|
36
|
+
'automatic_promotions',
|
|
37
|
+
'no_cash_method',
|
|
38
|
+
'pos_disabled',
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* Why the engine refused or flagged an offline sale, in the order an answer lists them: the
|
|
42
|
+
* refusals first (`item_gone` to `price_over_limit`: nothing was recorded but the row), then the
|
|
43
|
+
* reviews (`price_changed` to `sold_at_suspect`: the sale is recorded). More may come.
|
|
44
|
+
*/
|
|
45
|
+
export const POS_OFFLINE_SALE_REASONS = [
|
|
46
|
+
'item_gone',
|
|
47
|
+
'drawer_closed',
|
|
48
|
+
'currency_changed',
|
|
49
|
+
'prices_exclude_tax',
|
|
50
|
+
'out_of_stock',
|
|
51
|
+
'gift_card',
|
|
52
|
+
'total_mismatch',
|
|
53
|
+
'rounding_mismatch',
|
|
54
|
+
'price_over_limit',
|
|
55
|
+
'price_changed',
|
|
56
|
+
'not_fulfilled',
|
|
57
|
+
'cashier_changed',
|
|
58
|
+
'policy_off',
|
|
59
|
+
'over_cap',
|
|
60
|
+
'sold_at_suspect',
|
|
61
|
+
'cashier_unverified',
|
|
62
|
+
'item_gone_stand_in',
|
|
63
|
+
'stock_short_stand_in',
|
|
64
|
+
'total_corrected',
|
|
65
|
+
'rounding_as_rung',
|
|
66
|
+
];
|
|
67
|
+
/**
|
|
68
|
+
* The reasons the engine REFUSES a sale for (nothing recorded but its row): `item_gone` to
|
|
69
|
+
* `price_over_limit`. Every other reason is a review of a recorded sale. A reason this release does
|
|
70
|
+
* not know is neither: show it as it is.
|
|
71
|
+
*/
|
|
72
|
+
export const POS_OFFLINE_SALE_REFUSAL_REASONS = [
|
|
73
|
+
'item_gone',
|
|
74
|
+
'drawer_closed',
|
|
75
|
+
'currency_changed',
|
|
76
|
+
'prices_exclude_tax',
|
|
77
|
+
'out_of_stock',
|
|
78
|
+
'gift_card',
|
|
79
|
+
'total_mismatch',
|
|
80
|
+
'rounding_mismatch',
|
|
81
|
+
'price_over_limit',
|
|
82
|
+
];
|
|
83
|
+
const DEFAULT_PAGE = 50;
|
|
84
|
+
const MAX_PAGE = 100;
|
|
85
|
+
const POLICY_FIELDS = 'enabled maxSaleAmount maxSalesPerOutage maxOfflineMinutes ready notReadyReasons';
|
|
86
|
+
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';
|
|
87
|
+
export const POS_OFFLINE_CASH_SALES_QUERY = `query PosOfflineCashSales { getPosConfig { offlineCashSales { ${POLICY_FIELDS} } } }`;
|
|
88
|
+
export const SET_POS_OFFLINE_CASH_SALES_MUTATION = `mutation SetPosOfflineCashSales($input: PosOfflineCashSalesInput!) { setPosOfflineCashSales(input: $input) { ${POLICY_FIELDS} } }`;
|
|
89
|
+
/** The list, naming who recorded a sale again (engine POS polish PR 6). */
|
|
90
|
+
export const POS_OFFLINE_SALES_QUERY = `query PosOfflineSales($input: PosOfflineSaleListInput) { posOfflineSales(input: $input) { items { ${SALE_FIELDS} recordedAgainAt recordedAgainByUserName cashRegisterSessionId } totalItems } }`;
|
|
91
|
+
/** The list as an engine before PR 6 reads it: sent once that engine refused the fields. */
|
|
92
|
+
export const POS_OFFLINE_SALES_QUERY_BEFORE_RECORD_AGAIN = `query PosOfflineSales($input: PosOfflineSaleListInput) { posOfflineSales(input: $input) { items { ${SALE_FIELDS} } totalItems } }`;
|
|
93
|
+
export const RESOLVE_POS_OFFLINE_SALE_MUTATION = `mutation ResolvePosOfflineSale($input: ResolvePosOfflineSaleInput!) { resolvePosOfflineSale(input: $input) { ${SALE_FIELDS} } }`;
|
|
94
|
+
// Engine POS polish PR 6: only this document selects who recorded it again.
|
|
95
|
+
export const RECORD_POS_OFFLINE_SALE_AGAIN_MUTATION = `mutation RecordPosOfflineSaleAgain($input: RecordPosOfflineSaleAgainInput!) { recordPosOfflineSaleAgain(input: $input) { ${SALE_FIELDS} recordedAgainAt recordedAgainByUserName cashRegisterSessionId } }`;
|
|
96
|
+
// The fleet's count beside the device's id alone, its own document: the fleet read
|
|
97
|
+
// (`POS_DEVICE_FLEET_QUERY`) never names it, so an engine before 45 keeps answering the fleet.
|
|
98
|
+
export const POS_DEVICE_OFFLINE_SALES_TO_REVIEW_QUERY = 'query PosDeviceOfflineSalesToReview($stockLocationId: ID) { posDeviceFleet(stockLocationId: $stockLocationId) { device { id } offlineSalesToReview } }';
|
|
99
|
+
function gqlOf(transport) {
|
|
100
|
+
return async (query, variables, options) => transport.graphql({ api: 'admin', query, variables }, options);
|
|
101
|
+
}
|
|
102
|
+
/** `admin.pos.settings.offlineCashSales()`: null when POS was never set up. */
|
|
103
|
+
export async function readOfflineCashSales(transport, options) {
|
|
104
|
+
const data = await gqlOf(transport)(POS_OFFLINE_CASH_SALES_QUERY, {}, options);
|
|
105
|
+
return data.getPosConfig?.offlineCashSales ?? null;
|
|
106
|
+
}
|
|
107
|
+
/** `admin.pos.settings.setOfflineCashSales(input)`: the four fields, as given. */
|
|
108
|
+
export async function writeOfflineCashSales(transport, input, options) {
|
|
109
|
+
const { enabled, maxSaleAmount, maxSalesPerOutage, maxOfflineMinutes } = input;
|
|
110
|
+
const data = await gqlOf(transport)(SET_POS_OFFLINE_CASH_SALES_MUTATION, { input: { enabled, maxSaleAmount, maxSalesPerOutage, maxOfflineMinutes } }, options);
|
|
111
|
+
return data.setPosOfflineCashSales;
|
|
112
|
+
}
|
|
113
|
+
/** `admin.pos.devices.offlineSalesToReview()`: one row per device the fleet lists, whole. */
|
|
114
|
+
export async function readOfflineSalesToReview(transport, options) {
|
|
115
|
+
const data = await gqlOf(transport)(POS_DEVICE_OFFLINE_SALES_TO_REVIEW_QUERY, { stockLocationId: options?.stockLocationId ?? null }, options);
|
|
116
|
+
return data.posDeviceFleet.map((row) => ({
|
|
117
|
+
deviceId: row.device.id,
|
|
118
|
+
offlineSalesToReview: row.offlineSalesToReview,
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
export function createPosOfflineSalesModule(transport) {
|
|
122
|
+
const gql = gqlOf(transport);
|
|
123
|
+
// An engine before PR 6 refused the list's record-again fields once: every later page asks
|
|
124
|
+
// without them (one refused request per module, not per page).
|
|
125
|
+
let listBeforeRecordAgain = false;
|
|
126
|
+
async function listDocument(variables, options) {
|
|
127
|
+
if (!listBeforeRecordAgain) {
|
|
128
|
+
try {
|
|
129
|
+
return await gql(POS_OFFLINE_SALES_QUERY, variables, options);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
// Refused before it ran: the same read without the fields. Any other failure is the read's.
|
|
133
|
+
if (!isUnknownFieldRejection(error))
|
|
134
|
+
throw error;
|
|
135
|
+
listBeforeRecordAgain = true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return gql(POS_OFFLINE_SALES_QUERY_BEFORE_RECORD_AGAIN, variables, options);
|
|
139
|
+
}
|
|
140
|
+
async function salePage(skip, take, options) {
|
|
141
|
+
const input = { skip, take };
|
|
142
|
+
if (options?.filter !== undefined)
|
|
143
|
+
input.filter = options.filter;
|
|
144
|
+
if (options?.deviceId !== undefined)
|
|
145
|
+
input.deviceId = options.deviceId;
|
|
146
|
+
const data = await listDocument({ input }, options);
|
|
147
|
+
return pageFromVendureList(data.posOfflineSales, skip, take, (cursor) => salePage(readOffsetCursor(cursor), take, options));
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
async list(options) {
|
|
151
|
+
const take = Math.min(Math.max(Math.trunc(options?.limit ?? DEFAULT_PAGE), 1), MAX_PAGE);
|
|
152
|
+
const skip = options?.after === undefined ? 0 : readOffsetCursor(options.after);
|
|
153
|
+
return salePage(skip, take, options);
|
|
154
|
+
},
|
|
155
|
+
async resolve(input, options) {
|
|
156
|
+
// Sent as given: the engine trims and judges the note (POS_OFFLINE_NOTE_INVALID).
|
|
157
|
+
const data = await gql(RESOLVE_POS_OFFLINE_SALE_MUTATION, { input: { id: input.id, note: input.note } }, options);
|
|
158
|
+
return data.resolvePosOfflineSale;
|
|
159
|
+
},
|
|
160
|
+
async recordAgain(input, options) {
|
|
161
|
+
const data = await gql(RECORD_POS_OFFLINE_SALE_AGAIN_MUTATION, {
|
|
162
|
+
input: {
|
|
163
|
+
id: input.id,
|
|
164
|
+
...(input.registerSessionId ? { registerSessionId: input.registerSessionId } : {}),
|
|
165
|
+
},
|
|
166
|
+
}, options);
|
|
167
|
+
return data.recordPosOfflineSaleAgain;
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|