@aglyn/plugins-commerce 1.0.0-beta.232 → 1.0.0-beta.234
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +13 -13
- package/src/lib/components/cart-extras.d.ts +6 -0
- package/src/lib/components/cart-extras.js +4 -1
- package/src/lib/components/cart-extras.js.map +1 -1
- package/src/lib/components/cart-fulfillment.d.ts +117 -0
- package/src/lib/components/cart-fulfillment.js +367 -0
- package/src/lib/components/cart-fulfillment.js.map +1 -0
- package/src/lib/components/cart.js +52 -10
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/commerce-console-page.js +42 -1
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/host-orders-card.component.js +38 -10
- package/src/lib/components/console/host-orders-card.component.js.map +1 -1
- package/src/lib/components/console/local-delivery-settings-card.component.d.ts +37 -0
- package/src/lib/components/console/local-delivery-settings-card.component.js +542 -0
- package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -0
- package/src/lib/components/console/locations-card.component.js +177 -3
- package/src/lib/components/console/locations-card.component.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +10 -0
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/order-local-fulfillment-panel.component.d.ts +44 -0
- package/src/lib/components/console/order-local-fulfillment-panel.component.js +265 -0
- package/src/lib/components/console/order-local-fulfillment-panel.component.js.map +1 -0
- package/src/lib/components/console/order-offline-notice.component.d.ts +12 -0
- package/src/lib/components/console/order-offline-notice.component.js +53 -0
- package/src/lib/components/console/order-offline-notice.component.js.map +1 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.d.ts +35 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.js +222 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-api.d.ts +24 -1
- package/src/lib/components/console/pos/pos-api.js +13 -0
- package/src/lib/components/console/pos/pos-api.js.map +1 -1
- package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +12 -0
- package/src/lib/components/console/pos/pos-item-dialog.component.js +10 -8
- package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-kiosk-queue.component.d.ts +22 -0
- package/src/lib/components/console/pos/pos-kiosk-queue.component.js +168 -0
- package/src/lib/components/console/pos/pos-kiosk-queue.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +18 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js +116 -1
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +8 -0
- package/src/lib/components/console/pos/pos-tender-panel.component.js +77 -18
- package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -1
- package/src/lib/components/console/pos/use-pos-display.d.ts +5 -2
- package/src/lib/components/console/pos/use-pos-display.js +3 -2
- package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
- package/src/lib/components/console/pos-devices-card.component.js +2 -2
- package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
- package/src/lib/components/console/pos-display/pairing-screen.d.ts +5 -2
- package/src/lib/components/console/pos-display/pairing-screen.js +7 -5
- package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -1
- package/src/lib/components/console/pos-display/pos-display-api.d.ts +7 -1
- package/src/lib/components/console/pos-display/pos-display-api.js +7 -2
- package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.d.ts +41 -0
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.js +275 -0
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.d.ts +32 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.js +344 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.d.ts +12 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.js +257 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.d.ts +114 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js +189 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.d.ts +16 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js +80 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js.map +1 -0
- package/src/lib/components/console/pos-kiosk-page.component.d.ts +28 -0
- package/src/lib/components/console/pos-kiosk-page.component.js +791 -0
- package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.d.ts +44 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.js +69 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.d.ts +7 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.js +135 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.d.ts +32 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js +287 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.d.ts +63 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.js +145 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.js.map +1 -0
- package/src/lib/components/console/pos-offline/register-offline.d.ts +24 -0
- package/src/lib/components/console/pos-offline/register-offline.js +24 -0
- package/src/lib/components/console/pos-offline/register-offline.js.map +1 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.d.ts +85 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.js +542 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +72 -17
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -1
- package/src/lib/components/console/pos-page.component.js +174 -27
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +35 -10
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/shipping-settings-card.component.js +1 -1
- package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
- package/src/lib/components/console/stock-movements-card.component.js +48 -16
- package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
- package/src/lib/components/console/store-zones.d.ts +8 -1
- package/src/lib/components/console/store-zones.js +11 -1
- package/src/lib/components/console/store-zones.js.map +1 -1
- package/src/lib/components/order-status.js +66 -0
- package/src/lib/components/order-status.js.map +1 -1
- package/src/lib/components/product-detail.js +42 -15
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/constants/local-fulfillment-list-query.d.ts +48 -0
- package/src/lib/constants/local-fulfillment-list-query.js +84 -0
- package/src/lib/constants/local-fulfillment-list-query.js.map +1 -0
- package/src/lib/constants/orders-list-query.d.ts +7 -2
- package/src/lib/constants/orders-list-query.js +89 -8
- package/src/lib/constants/orders-list-query.js.map +1 -1
- package/src/lib/constants/pos-shift-list-query.d.ts +22 -0
- package/src/lib/constants/pos-shift-list-query.js +115 -0
- package/src/lib/constants/pos-shift-list-query.js.map +1 -0
- package/src/lib/constants/product-list-query.d.ts +6 -1
- package/src/lib/constants/product-list-query.js +77 -8
- package/src/lib/constants/product-list-query.js.map +1 -1
- package/src/lib/constants/stock-movement-query.d.ts +3 -2
- package/src/lib/constants/stock-movement-query.js +52 -8
- package/src/lib/constants/stock-movement-query.js.map +1 -1
- package/src/lib/model/buyer-notifications.d.ts +5 -3
- package/src/lib/model/buyer-notifications.js +25 -4
- package/src/lib/model/buyer-notifications.js.map +1 -1
- package/src/lib/model/commerce-orders.d.ts +59 -0
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-pos-kiosk.d.ts +175 -0
- package/src/lib/model/commerce-pos-kiosk.js +147 -0
- package/src/lib/model/commerce-pos-kiosk.js.map +1 -0
- package/src/lib/model/commerce-pos-offline.d.ts +234 -0
- package/src/lib/model/commerce-pos-offline.js +301 -0
- package/src/lib/model/commerce-pos-offline.js.map +1 -0
- package/src/lib/model/commerce-pos-ops.d.ts +16 -6
- package/src/lib/model/commerce-pos-ops.js +12 -4
- package/src/lib/model/commerce-pos-ops.js.map +1 -1
- package/src/lib/model/commerce-pos.d.ts +13 -1
- package/src/lib/model/commerce-pos.js +5 -4
- package/src/lib/model/commerce-pos.js.map +1 -1
- package/src/lib/model/commerce-stock-holds.d.ts +24 -3
- package/src/lib/model/commerce-stock-holds.js +26 -8
- package/src/lib/model/commerce-stock-holds.js.map +1 -1
- package/src/lib/model/commerce.d.ts +3 -0
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/index.d.ts +4 -0
- package/src/lib/model/index.js +4 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/local-fulfillment-settings.d.ts +178 -0
- package/src/lib/model/local-fulfillment-settings.js +361 -0
- package/src/lib/model/local-fulfillment-settings.js.map +1 -0
- package/src/lib/model/order-list-fields.d.ts +10 -1
- package/src/lib/model/order-list-fields.js +1 -0
- package/src/lib/model/order-list-fields.js.map +1 -1
- package/src/lib/model/order-local-fulfillment.d.ts +131 -0
- package/src/lib/model/order-local-fulfillment.js +125 -0
- package/src/lib/model/order-local-fulfillment.js.map +1 -0
- package/src/lib/model/order-shipping-export.js +4 -0
- package/src/lib/model/order-shipping-export.js.map +1 -1
- package/src/lib/model/order-status-view.d.ts +20 -1
- package/src/lib/model/order-status-view.js +60 -6
- package/src/lib/model/order-status-view.js.map +1 -1
- package/src/lib/plugin-config.js +6 -2
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +8 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/pos-kiosk-config.d.ts +26 -0
- package/src/lib/pos-kiosk-config.js +59 -0
- package/src/lib/pos-kiosk-config.js.map +1 -0
- package/src/lib/server/api-v1/openapi.js +8 -0
- package/src/lib/server/api-v1/openapi.js.map +1 -1
- package/src/lib/server/api-v1/order-view.d.ts +19 -0
- package/src/lib/server/api-v1/order-view.js +35 -0
- package/src/lib/server/api-v1/order-view.js.map +1 -1
- package/src/lib/server/billing-webhook.js +238 -87
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cart-checkout.d.ts +2 -0
- package/src/lib/server/cart-checkout.js +173 -13
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/checkout-extras.js +18 -4
- package/src/lib/server/checkout-extras.js.map +1 -1
- package/src/lib/server/checkout.js +71 -14
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/local-fulfillment-status.d.ts +86 -0
- package/src/lib/server/local-fulfillment-status.js +379 -0
- package/src/lib/server/local-fulfillment-status.js.map +1 -0
- package/src/lib/server/local-fulfillment.d.ts +190 -0
- package/src/lib/server/local-fulfillment.js +580 -0
- package/src/lib/server/local-fulfillment.js.map +1 -0
- package/src/lib/server/membership-register.js +3 -1
- package/src/lib/server/membership-register.js.map +1 -1
- package/src/lib/server/order-notifications.js +61 -0
- package/src/lib/server/order-notifications.js.map +1 -1
- package/src/lib/server/pos-display.d.ts +27 -1
- package/src/lib/server/pos-display.js +50 -9
- package/src/lib/server/pos-display.js.map +1 -1
- package/src/lib/server/pos-kiosk-principal.d.ts +29 -0
- package/src/lib/server/pos-kiosk-principal.js +42 -0
- package/src/lib/server/pos-kiosk-principal.js.map +1 -0
- package/src/lib/server/pos-kiosk.d.ts +54 -0
- package/src/lib/server/pos-kiosk.js +972 -0
- package/src/lib/server/pos-kiosk.js.map +1 -0
- package/src/lib/server/pos-offline-sync.d.ts +85 -0
- package/src/lib/server/pos-offline-sync.js +765 -0
- package/src/lib/server/pos-offline-sync.js.map +1 -0
- package/src/lib/server/pos-order.js +22 -4
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/pos-payment.d.ts +6 -0
- package/src/lib/server/pos-payment.js +225 -6
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/pos-print.js +5 -0
- package/src/lib/server/pos-print.js.map +1 -1
- package/src/lib/server/pos-return.js +27 -0
- package/src/lib/server/pos-return.js.map +1 -1
- package/src/lib/server/pos-sale.d.ts +6 -0
- package/src/lib/server/pos-sale.js +2 -0
- package/src/lib/server/pos-sale.js.map +1 -1
- package/src/lib/server/pos-shift.js +8 -1
- package/src/lib/server/pos-shift.js.map +1 -1
- package/src/lib/server/refund.js +3 -0
- package/src/lib/server/refund.js.map +1 -1
- package/src/lib/server/stock-hold.d.ts +9 -1
- package/src/lib/server/stock-hold.js +15 -7
- package/src/lib/server/stock-hold.js.map +1 -1
- package/src/lib/server.js +16 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/tenant-emails.js +161 -0
- package/src/lib/tenant-emails.js.map +1 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as CommerceModel from '../../../model';
|
|
2
|
+
import { type PosOfflineFlag, type PosOfflineKit, type PosOfflineSale, type PosOfflineStockConflict } from '../../../model/commerce-pos-offline';
|
|
3
|
+
import type { RegisterLine } from '../pos/pos-cart-panel.component';
|
|
4
|
+
import { fetchPosOfflineKit } from './pos-offline-api';
|
|
5
|
+
import { openPosOfflineStore, type PosOfflineProduct, type PosOfflineQueuedSale } from './pos-offline-store';
|
|
6
|
+
type User = Parameters<typeof fetchPosOfflineKit>[0];
|
|
7
|
+
/** A sale the server answered for with something to check. */
|
|
8
|
+
export interface PosOfflineSyncNotice {
|
|
9
|
+
saleKey: string;
|
|
10
|
+
orderId: string;
|
|
11
|
+
number: number | null;
|
|
12
|
+
flags: PosOfflineFlag[];
|
|
13
|
+
stockConflicts: PosOfflineStockConflict[];
|
|
14
|
+
}
|
|
15
|
+
/** A cash sale the register just rang offline, for its receipt step. */
|
|
16
|
+
export interface PosOfflineRungSale {
|
|
17
|
+
saleKey: string;
|
|
18
|
+
sale: PosOfflineSale;
|
|
19
|
+
/** The order the receipt prints, shaped as the stored order will be. */
|
|
20
|
+
order: CommerceModel.HostOrder & {
|
|
21
|
+
createdAtMs: number;
|
|
22
|
+
customerName?: string | null;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export interface PosOfflineState {
|
|
26
|
+
/** The register is offline right now. */
|
|
27
|
+
offline: boolean;
|
|
28
|
+
/** This device can sell offline: storage opened and the kit says yes. */
|
|
29
|
+
ready: boolean;
|
|
30
|
+
/** Why it cannot, in the cashier's words, when it cannot. */
|
|
31
|
+
unavailableReason: string | null;
|
|
32
|
+
kit: PosOfflineKit | null;
|
|
33
|
+
/** Sales on this device that have not synced, oldest first. */
|
|
34
|
+
queue: PosOfflineQueuedSale[];
|
|
35
|
+
syncing: boolean;
|
|
36
|
+
/** Why the last sync could not run, when the server refused it outright. */
|
|
37
|
+
syncError: string | null;
|
|
38
|
+
/** Synced sales the server flagged, until the cashier dismisses them. */
|
|
39
|
+
notices: PosOfflineSyncNotice[];
|
|
40
|
+
/** The products the offline grid shows for a search and a chip. */
|
|
41
|
+
gridProducts(search: string, categoryId: string, quickKeysId: string): PosOfflineProduct[];
|
|
42
|
+
/** A product and variant by barcode or SKU from the cached catalog. */
|
|
43
|
+
findByCode(code: string): {
|
|
44
|
+
product: PosOfflineProduct;
|
|
45
|
+
variant: any;
|
|
46
|
+
} | null;
|
|
47
|
+
/** The totals the basket rings offline, or `null` when it cannot. */
|
|
48
|
+
totalsFor(lines: RegisterLine[], discountPct: number): CommerceModel.OrderTotals | null;
|
|
49
|
+
/** Queues one cash sale; `null` (and nothing taken) when it cannot be kept. */
|
|
50
|
+
ringCashSale(input: {
|
|
51
|
+
lines: RegisterLine[];
|
|
52
|
+
discountPct: number;
|
|
53
|
+
cashTenderedCents: number;
|
|
54
|
+
customer?: {
|
|
55
|
+
email?: string | null;
|
|
56
|
+
name?: string | null;
|
|
57
|
+
kind?: string;
|
|
58
|
+
id?: string;
|
|
59
|
+
} | null;
|
|
60
|
+
}): Promise<PosOfflineRungSale | null>;
|
|
61
|
+
/** A register call failed at the network. */
|
|
62
|
+
reportNetworkFailure(): void;
|
|
63
|
+
syncNow(): Promise<void>;
|
|
64
|
+
dismissNotices(): void;
|
|
65
|
+
/** Removes a refused sale the server will never take, after the cashier confirms. */
|
|
66
|
+
discard(saleKey: string): Promise<void>;
|
|
67
|
+
}
|
|
68
|
+
export interface UsePosOfflineInput {
|
|
69
|
+
hostId: string;
|
|
70
|
+
user: User | null | undefined;
|
|
71
|
+
registerId: string;
|
|
72
|
+
/** The open shift on the register as last seen, if any. */
|
|
73
|
+
openShiftId?: string | null;
|
|
74
|
+
locationId?: string;
|
|
75
|
+
cashierAssertion?: string;
|
|
76
|
+
/** Products the live grid holds; kept for the device as they arrive. */
|
|
77
|
+
liveProducts: ReadonlyArray<Record<string, any>>;
|
|
78
|
+
/** Reads the whole sellable catalog for the device (the grid's own query). */
|
|
79
|
+
loadCatalog?: () => Promise<Array<Record<string, any>>>;
|
|
80
|
+
/** Opens the device store; injected by specs. */
|
|
81
|
+
openStore?: typeof openPosOfflineStore;
|
|
82
|
+
now?: () => number;
|
|
83
|
+
}
|
|
84
|
+
export declare function usePosOffline(input: UsePosOfflineInput): PosOfflineState;
|
|
85
|
+
export {};
|
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
19
|
+
import * as CommerceModel from "../../../model/index.js";
|
|
20
|
+
import { posOfflineChangeCents, posOfflineSaleTotals, POS_OFFLINE_SYNC_BATCH_MAX } from "../../../model/commerce-pos-offline.js";
|
|
21
|
+
import { fetchPosOfflineKit, newPosOfflineSaleKey, syncPosOfflineSales } from "./pos-offline-api.js";
|
|
22
|
+
import { openPosOfflineStore, posOfflineProduct } from "./pos-offline-store.js";
|
|
23
|
+
/*==========================================
|
|
24
|
+
* THE REGISTER, OFFLINE (AGL-3625).
|
|
25
|
+
*
|
|
26
|
+
* WHEN IS IT OFFLINE: when the browser says so, or when a register call
|
|
27
|
+
* failed at the network — a Wi-Fi that is "connected" to a router with no
|
|
28
|
+
* uplink looks online to `navigator.onLine`. While offline it probes the sync
|
|
29
|
+
* route every few seconds; the first answer brings it back.
|
|
30
|
+
*
|
|
31
|
+
* WHAT IT KEEPS: the kit and the catalog, refreshed while online, and the
|
|
32
|
+
* queue (see `pos-offline-store.ts`).
|
|
33
|
+
*
|
|
34
|
+
* HOW IT SYNCS: on reconnect, on mount, and after every offline sale while
|
|
35
|
+
* online again, in batches, one sync at a time. A sale leaves the device only
|
|
36
|
+
* when the server has answered for it — recorded, or a replay of a recording —
|
|
37
|
+
* so a connection that drops mid-request leaves it queued, and sending it
|
|
38
|
+
* again is safe: the server lands a sale key once.
|
|
39
|
+
*=========================================*/ /** How often the kit is refreshed while online. */ const KIT_REFRESH_MS = 10 * 60 * 1000;
|
|
40
|
+
/** How often the whole catalog is re-read for the device. */ const CATALOG_REFRESH_MS = 30 * 60 * 1000;
|
|
41
|
+
/** How often an offline register asks whether the server answers again. */ const PROBE_MS = 15 * 1000;
|
|
42
|
+
/**
|
|
43
|
+
* The shift open on the register as last seen: the live register document's
|
|
44
|
+
* answer when the page has one (including "none"), the kit's otherwise.
|
|
45
|
+
*/ function lastKnownShift(live, kit, registerId) {
|
|
46
|
+
var _ref;
|
|
47
|
+
var _kit_registers_find;
|
|
48
|
+
if (live !== undefined) return live || null;
|
|
49
|
+
return (_ref = (_kit_registers_find = kit.registers.find((register)=>register.id === registerId)) == null ? void 0 : _kit_registers_find.openShiftId) != null ? _ref : null;
|
|
50
|
+
}
|
|
51
|
+
function browserOnline() {
|
|
52
|
+
return typeof navigator === 'undefined' || navigator.onLine !== false;
|
|
53
|
+
}
|
|
54
|
+
export function usePosOffline(input) {
|
|
55
|
+
var _ref, _input_now, _input_openStore, _kit_unavailableReason;
|
|
56
|
+
const { hostId, user, registerId } = input;
|
|
57
|
+
const uid = (_ref = user == null ? void 0 : user.uid) != null ? _ref : '';
|
|
58
|
+
const now = (_input_now = input.now) != null ? _input_now : Date.now;
|
|
59
|
+
const openStore = (_input_openStore = input.openStore) != null ? _input_openStore : openPosOfflineStore;
|
|
60
|
+
const [store, setStore] = useState(null);
|
|
61
|
+
const [storeFailed, setStoreFailed] = useState(false);
|
|
62
|
+
const [kit, setKit] = useState(null);
|
|
63
|
+
const [catalog, setCatalog] = useState([]);
|
|
64
|
+
const [queue, setQueue] = useState([]);
|
|
65
|
+
const [navigatorOnline, setNavigatorOnline] = useState(browserOnline);
|
|
66
|
+
const [networkFailed, setNetworkFailed] = useState(false);
|
|
67
|
+
const [syncing, setSyncing] = useState(false);
|
|
68
|
+
const [syncError, setSyncError] = useState(null);
|
|
69
|
+
const [notices, setNotices] = useState([]);
|
|
70
|
+
const offline = !navigatorOnline || networkFailed;
|
|
71
|
+
const latest = useRef(input);
|
|
72
|
+
latest.current = input;
|
|
73
|
+
const userRef = useRef(user);
|
|
74
|
+
userRef.current = user;
|
|
75
|
+
// The device store, for this member at this site.
|
|
76
|
+
useEffect(()=>{
|
|
77
|
+
let active = true;
|
|
78
|
+
setStore(null);
|
|
79
|
+
setStoreFailed(false);
|
|
80
|
+
setKit(null);
|
|
81
|
+
setCatalog([]);
|
|
82
|
+
setQueue([]);
|
|
83
|
+
if (!uid || !hostId) return undefined;
|
|
84
|
+
void openStore({
|
|
85
|
+
uid,
|
|
86
|
+
hostId
|
|
87
|
+
}).then(async (opened)=>{
|
|
88
|
+
if (!active) return;
|
|
89
|
+
if (!opened) {
|
|
90
|
+
setStoreFailed(true);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
var _saved_products;
|
|
95
|
+
const [saved, sales] = await Promise.all([
|
|
96
|
+
opened.loadKit(),
|
|
97
|
+
opened.listSales()
|
|
98
|
+
]);
|
|
99
|
+
if (!active) return;
|
|
100
|
+
if (saved == null ? void 0 : saved.kit) setKit(saved.kit);
|
|
101
|
+
if (saved == null ? void 0 : (_saved_products = saved.products) == null ? void 0 : _saved_products.length) setCatalog(saved.products);
|
|
102
|
+
setQueue(sales);
|
|
103
|
+
setStore(opened);
|
|
104
|
+
} catch (unused) {
|
|
105
|
+
if (active) setStoreFailed(true);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return ()=>{
|
|
109
|
+
active = false;
|
|
110
|
+
};
|
|
111
|
+
}, [
|
|
112
|
+
uid,
|
|
113
|
+
hostId,
|
|
114
|
+
openStore
|
|
115
|
+
]);
|
|
116
|
+
useEffect(()=>{
|
|
117
|
+
const goOnline = ()=>{
|
|
118
|
+
setNavigatorOnline(true);
|
|
119
|
+
setNetworkFailed(false);
|
|
120
|
+
};
|
|
121
|
+
const goOffline = ()=>setNavigatorOnline(false);
|
|
122
|
+
window.addEventListener('online', goOnline);
|
|
123
|
+
window.addEventListener('offline', goOffline);
|
|
124
|
+
return ()=>{
|
|
125
|
+
window.removeEventListener('online', goOnline);
|
|
126
|
+
window.removeEventListener('offline', goOffline);
|
|
127
|
+
};
|
|
128
|
+
}, []);
|
|
129
|
+
// The kit and the catalog, while online.
|
|
130
|
+
const kitSavedAt = useRef(0);
|
|
131
|
+
const catalogSavedAt = useRef(0);
|
|
132
|
+
const refreshKit = useCallback(async ()=>{
|
|
133
|
+
var _ref, _ref1;
|
|
134
|
+
const signedIn = userRef.current;
|
|
135
|
+
if (!store || !signedIn) return;
|
|
136
|
+
const answer = await fetchPosOfflineKit(signedIn, hostId);
|
|
137
|
+
if ('error' in answer) {
|
|
138
|
+
if (answer.status === 0) setNetworkFailed(true);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const fresh = answer.body.kit;
|
|
142
|
+
let products = null;
|
|
143
|
+
const load = latest.current.loadCatalog;
|
|
144
|
+
if (load && now() - catalogSavedAt.current > CATALOG_REFRESH_MS) {
|
|
145
|
+
try {
|
|
146
|
+
products = (await load()).map(posOfflineProduct).filter(Boolean);
|
|
147
|
+
catalogSavedAt.current = now();
|
|
148
|
+
} catch (unused) {
|
|
149
|
+
products = null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
kitSavedAt.current = now();
|
|
153
|
+
setKit(fresh);
|
|
154
|
+
if (products) setCatalog(products);
|
|
155
|
+
const saved = await store.loadKit().catch(()=>null);
|
|
156
|
+
await store.saveKit({
|
|
157
|
+
kit: fresh,
|
|
158
|
+
kitSavedAtMs: kitSavedAt.current,
|
|
159
|
+
products: (_ref = products != null ? products : saved == null ? void 0 : saved.products) != null ? _ref : [],
|
|
160
|
+
catalogSavedAtMs: products ? catalogSavedAt.current : (_ref1 = saved == null ? void 0 : saved.catalogSavedAtMs) != null ? _ref1 : 0
|
|
161
|
+
}).catch(()=>undefined);
|
|
162
|
+
}, [
|
|
163
|
+
store,
|
|
164
|
+
hostId,
|
|
165
|
+
now
|
|
166
|
+
]);
|
|
167
|
+
useEffect(()=>{
|
|
168
|
+
if (!store || offline || !uid) return undefined;
|
|
169
|
+
void refreshKit();
|
|
170
|
+
const timer = window.setInterval(()=>void refreshKit(), KIT_REFRESH_MS);
|
|
171
|
+
return ()=>window.clearInterval(timer);
|
|
172
|
+
}, [
|
|
173
|
+
store,
|
|
174
|
+
offline,
|
|
175
|
+
uid,
|
|
176
|
+
refreshKit
|
|
177
|
+
]);
|
|
178
|
+
// Products the live grid shows are merged into the device's catalog, so a
|
|
179
|
+
// product rung up online is sellable offline even past the snapshot.
|
|
180
|
+
const liveKey = input.liveProducts.map((product)=>{
|
|
181
|
+
var _product_$id;
|
|
182
|
+
return String((_product_$id = product['$id']) != null ? _product_$id : '');
|
|
183
|
+
}).join(',');
|
|
184
|
+
useEffect(()=>{
|
|
185
|
+
if (!store || offline || !input.liveProducts.length) return;
|
|
186
|
+
setCatalog((current)=>{
|
|
187
|
+
const byId = new Map(current.map((product)=>[
|
|
188
|
+
product.$id,
|
|
189
|
+
product
|
|
190
|
+
]));
|
|
191
|
+
let changed = false;
|
|
192
|
+
for (const product of latest.current.liveProducts){
|
|
193
|
+
const trimmed = posOfflineProduct(product);
|
|
194
|
+
if (!trimmed) continue;
|
|
195
|
+
if (JSON.stringify(byId.get(trimmed.$id)) !== JSON.stringify(trimmed)) changed = true;
|
|
196
|
+
byId.set(trimmed.$id, trimmed);
|
|
197
|
+
}
|
|
198
|
+
if (!changed) return current;
|
|
199
|
+
const next = [
|
|
200
|
+
...byId.values()
|
|
201
|
+
];
|
|
202
|
+
void store.loadKit().then((saved)=>{
|
|
203
|
+
var _ref, _ref1, _ref2;
|
|
204
|
+
return store.saveKit({
|
|
205
|
+
kit: (_ref = saved == null ? void 0 : saved.kit) != null ? _ref : null,
|
|
206
|
+
kitSavedAtMs: (_ref1 = saved == null ? void 0 : saved.kitSavedAtMs) != null ? _ref1 : 0,
|
|
207
|
+
products: next,
|
|
208
|
+
catalogSavedAtMs: (_ref2 = saved == null ? void 0 : saved.catalogSavedAtMs) != null ? _ref2 : 0
|
|
209
|
+
});
|
|
210
|
+
}).catch(()=>undefined);
|
|
211
|
+
return next;
|
|
212
|
+
});
|
|
213
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- keyed on the ids the grid holds
|
|
214
|
+
}, [
|
|
215
|
+
store,
|
|
216
|
+
offline,
|
|
217
|
+
liveKey
|
|
218
|
+
]);
|
|
219
|
+
// The sync.
|
|
220
|
+
const syncInFlight = useRef(false);
|
|
221
|
+
const syncNow = useCallback(async ()=>{
|
|
222
|
+
const signedIn = userRef.current;
|
|
223
|
+
if (!store || !signedIn || syncInFlight.current) return;
|
|
224
|
+
syncInFlight.current = true;
|
|
225
|
+
setSyncing(true);
|
|
226
|
+
try {
|
|
227
|
+
const all = await store.listSales();
|
|
228
|
+
const waiting = all.filter((entry)=>entry.state === 'queued' && entry.sale.signedInUid === uid);
|
|
229
|
+
if (!waiting.length) {
|
|
230
|
+
// Nothing to send: one empty call says whether the route answers.
|
|
231
|
+
if (networkFailed) {
|
|
232
|
+
const probe = await syncPosOfflineSales(signedIn, hostId, []);
|
|
233
|
+
if (probe.ok || probe.status !== 0) setNetworkFailed(false);
|
|
234
|
+
}
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const flagged = [];
|
|
238
|
+
for(let at = 0; at < waiting.length; at += POS_OFFLINE_SYNC_BATCH_MAX){
|
|
239
|
+
var _answer_body_results;
|
|
240
|
+
const batch = waiting.slice(at, at + POS_OFFLINE_SYNC_BATCH_MAX);
|
|
241
|
+
const answer = await syncPosOfflineSales(signedIn, hostId, batch.map((entry)=>entry.sale));
|
|
242
|
+
if ('error' in answer) {
|
|
243
|
+
if (answer.status === 0) setNetworkFailed(true);
|
|
244
|
+
else setSyncError(answer.error);
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
setSyncError(null);
|
|
248
|
+
setNetworkFailed(false);
|
|
249
|
+
const byKey = new Map(batch.map((entry)=>[
|
|
250
|
+
entry.saleKey,
|
|
251
|
+
entry
|
|
252
|
+
]));
|
|
253
|
+
for (const result of (_answer_body_results = answer.body.results) != null ? _answer_body_results : []){
|
|
254
|
+
const entry = byKey.get(result.saleKey);
|
|
255
|
+
if (!entry) continue;
|
|
256
|
+
if (result.status === 'recorded' || result.status === 'replayed') {
|
|
257
|
+
var _result_flags;
|
|
258
|
+
await store.removeSale(entry.saleKey);
|
|
259
|
+
if ((_result_flags = result.flags) == null ? void 0 : _result_flags.length) {
|
|
260
|
+
var _result_orderId, _result_number, _result_stockConflicts;
|
|
261
|
+
flagged.push({
|
|
262
|
+
saleKey: result.saleKey,
|
|
263
|
+
orderId: (_result_orderId = result.orderId) != null ? _result_orderId : result.saleKey,
|
|
264
|
+
number: (_result_number = result.number) != null ? _result_number : null,
|
|
265
|
+
flags: result.flags,
|
|
266
|
+
stockConflicts: (_result_stockConflicts = result.stockConflicts) != null ? _result_stockConflicts : []
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
// A transient failure stays queued; every other refusal waits for
|
|
272
|
+
// the cashier, still on the device, with the server's sentence.
|
|
273
|
+
await store.putSale(_extends({}, entry, {
|
|
274
|
+
attempts: entry.attempts + 1,
|
|
275
|
+
state: result.reason === 'failed' || result.reason === 'wrong-staff' ? 'queued' : 'refused'
|
|
276
|
+
}, result.error ? {
|
|
277
|
+
error: result.error
|
|
278
|
+
} : {}, result.reason ? {
|
|
279
|
+
reason: result.reason
|
|
280
|
+
} : {}));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (flagged.length) setNotices((current)=>[
|
|
284
|
+
...current,
|
|
285
|
+
...flagged
|
|
286
|
+
]);
|
|
287
|
+
} catch (unused) {
|
|
288
|
+
// Storage or the network went away mid-sync; the queue is as it was.
|
|
289
|
+
} finally{
|
|
290
|
+
setQueue(await store.listSales().catch(()=>[]));
|
|
291
|
+
syncInFlight.current = false;
|
|
292
|
+
setSyncing(false);
|
|
293
|
+
}
|
|
294
|
+
}, [
|
|
295
|
+
store,
|
|
296
|
+
uid,
|
|
297
|
+
hostId,
|
|
298
|
+
networkFailed
|
|
299
|
+
]);
|
|
300
|
+
// Sync on reconnect, on mount, and while offline-by-failure keep probing.
|
|
301
|
+
useEffect(()=>{
|
|
302
|
+
if (!store || offline) return;
|
|
303
|
+
void syncNow();
|
|
304
|
+
}, [
|
|
305
|
+
store,
|
|
306
|
+
offline,
|
|
307
|
+
syncNow
|
|
308
|
+
]);
|
|
309
|
+
useEffect(()=>{
|
|
310
|
+
if (!store || !networkFailed || !navigatorOnline) return undefined;
|
|
311
|
+
const timer = window.setInterval(()=>void syncNow(), PROBE_MS);
|
|
312
|
+
return ()=>window.clearInterval(timer);
|
|
313
|
+
}, [
|
|
314
|
+
store,
|
|
315
|
+
networkFailed,
|
|
316
|
+
navigatorOnline,
|
|
317
|
+
syncNow
|
|
318
|
+
]);
|
|
319
|
+
const unavailableReason = storeFailed ? 'This browser is not keeping data for the register (a private window, or storage is blocked), so offline selling is unavailable.' : !store ? 'Getting the register ready to sell offline…' : !kit ? 'Connect once so the register can get ready to sell offline.' : !kit.available ? (_kit_unavailableReason = kit.unavailableReason) != null ? _kit_unavailableReason : 'Offline selling is unavailable for this site.' : !catalog.length ? 'The register has no catalog saved for offline selling yet.' : kit.requireOpenShift && !lastKnownShift(input.openShiftId, kit, registerId) ? 'Open a shift before going offline: this site requires one for every sale.' : null;
|
|
320
|
+
const ready = unavailableReason === null;
|
|
321
|
+
const gridProducts = useCallback((search, categoryId, quickKeysId)=>{
|
|
322
|
+
const typed = search.trim().toLowerCase();
|
|
323
|
+
return catalog.filter((product)=>product['status'] === undefined || product['status'] === 'active').filter((product)=>!product['deletedAt']).filter((product)=>{
|
|
324
|
+
var _product_name;
|
|
325
|
+
// A degraded grid over the device's own copy: there is no query to
|
|
326
|
+
// ask while offline, so the copy is narrowed in memory.
|
|
327
|
+
if (typed) return String((_product_name = product.name) != null ? _product_name : '').toLowerCase().includes(typed);
|
|
328
|
+
if (categoryId === quickKeysId && quickKeysId) return product['posQuickKey'] === true;
|
|
329
|
+
if (categoryId) return Array.isArray(product['categoryIds']) && product['categoryIds'].includes(categoryId);
|
|
330
|
+
return true;
|
|
331
|
+
}).sort((a, b)=>{
|
|
332
|
+
var _a_name, _b_name;
|
|
333
|
+
return String((_a_name = a.name) != null ? _a_name : '').localeCompare(String((_b_name = b.name) != null ? _b_name : ''));
|
|
334
|
+
}).map((product)=>_extends({}, CommerceModel.liftLegacyProduct(product), {
|
|
335
|
+
$id: product.$id
|
|
336
|
+
}));
|
|
337
|
+
}, [
|
|
338
|
+
catalog
|
|
339
|
+
]);
|
|
340
|
+
const findByCode = useCallback((code)=>{
|
|
341
|
+
const needle = code.trim().toLowerCase();
|
|
342
|
+
if (!needle) return null;
|
|
343
|
+
for (const raw of catalog){
|
|
344
|
+
var _product_variants;
|
|
345
|
+
const product = _extends({}, CommerceModel.liftLegacyProduct(raw), {
|
|
346
|
+
$id: raw.$id
|
|
347
|
+
});
|
|
348
|
+
const variant = ((_product_variants = product['variants']) != null ? _product_variants : []).find((item)=>{
|
|
349
|
+
var _ref, _ref1;
|
|
350
|
+
return String((_ref = item == null ? void 0 : item.barcode) != null ? _ref : '').trim().toLowerCase() === needle || String((_ref1 = item == null ? void 0 : item.sku) != null ? _ref1 : '').trim().toLowerCase() === needle;
|
|
351
|
+
});
|
|
352
|
+
if (variant) return {
|
|
353
|
+
product,
|
|
354
|
+
variant
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
return null;
|
|
358
|
+
}, [
|
|
359
|
+
catalog
|
|
360
|
+
]);
|
|
361
|
+
const totalsFor = useCallback((lines, discountPct)=>{
|
|
362
|
+
if (!(kit == null ? void 0 : kit.available) || !lines.length) return null;
|
|
363
|
+
return posOfflineSaleTotals({
|
|
364
|
+
lines,
|
|
365
|
+
discountPct,
|
|
366
|
+
tax: kit.tax
|
|
367
|
+
});
|
|
368
|
+
}, [
|
|
369
|
+
kit
|
|
370
|
+
]);
|
|
371
|
+
const ringInFlight = useRef(false);
|
|
372
|
+
const ringCashSale = useCallback(async (sale)=>{
|
|
373
|
+
const context = latest.current;
|
|
374
|
+
if (!store || !(kit == null ? void 0 : kit.available) || !uid || ringInFlight.current) return null;
|
|
375
|
+
if (sale.discountPct > kit.maxDiscountPct) return null;
|
|
376
|
+
const totals = posOfflineSaleTotals({
|
|
377
|
+
lines: sale.lines,
|
|
378
|
+
discountPct: sale.discountPct,
|
|
379
|
+
tax: kit.tax
|
|
380
|
+
});
|
|
381
|
+
if (sale.cashTenderedCents < totals.totalCents) return null;
|
|
382
|
+
ringInFlight.current = true;
|
|
383
|
+
try {
|
|
384
|
+
var _ref;
|
|
385
|
+
const saleKey = newPosOfflineSaleKey();
|
|
386
|
+
const soldAtMs = now();
|
|
387
|
+
const byId = new Map(catalog.map((product)=>[
|
|
388
|
+
product.$id,
|
|
389
|
+
product
|
|
390
|
+
]));
|
|
391
|
+
const lines = sale.lines.map((line)=>{
|
|
392
|
+
var _ref;
|
|
393
|
+
var _line_modifiers;
|
|
394
|
+
const product = byId.get(line.productId);
|
|
395
|
+
const variant = ((_ref = product == null ? void 0 : product['variants']) != null ? _ref : []).find((item)=>(item == null ? void 0 : item.id) === line.variantId);
|
|
396
|
+
return _extends({
|
|
397
|
+
productId: line.productId
|
|
398
|
+
}, line.variantId ? {
|
|
399
|
+
variantId: line.variantId
|
|
400
|
+
} : {}, {
|
|
401
|
+
name: line.name
|
|
402
|
+
}, line.variantLabel ? {
|
|
403
|
+
variantLabel: line.variantLabel
|
|
404
|
+
} : {}, (variant == null ? void 0 : variant.sku) ? {
|
|
405
|
+
sku: String(variant.sku)
|
|
406
|
+
} : {}, (product == null ? void 0 : product['type']) ? {
|
|
407
|
+
productType: product['type']
|
|
408
|
+
} : {}, {
|
|
409
|
+
quantity: line.quantity,
|
|
410
|
+
unitAmountCents: line.unitAmountCents
|
|
411
|
+
}, ((_line_modifiers = line.modifiers) == null ? void 0 : _line_modifiers.length) ? {
|
|
412
|
+
modifiers: line.modifiers
|
|
413
|
+
} : {});
|
|
414
|
+
});
|
|
415
|
+
const shiftId = lastKnownShift(context.openShiftId, kit, registerId);
|
|
416
|
+
const customer = sale.customer ? _extends({}, sale.customer.email ? {
|
|
417
|
+
email: sale.customer.email
|
|
418
|
+
} : {}, sale.customer.name ? {
|
|
419
|
+
name: sale.customer.name
|
|
420
|
+
} : {}, sale.customer.kind && sale.customer.kind !== 'none' && sale.customer.id ? {
|
|
421
|
+
kind: sale.customer.kind,
|
|
422
|
+
id: sale.customer.id
|
|
423
|
+
} : {}) : undefined;
|
|
424
|
+
const queued = _extends({
|
|
425
|
+
v: 1,
|
|
426
|
+
saleKey,
|
|
427
|
+
hostId,
|
|
428
|
+
orgId: kit.orgId,
|
|
429
|
+
signedInUid: uid,
|
|
430
|
+
registerId,
|
|
431
|
+
shiftId
|
|
432
|
+
}, context.locationId ? {
|
|
433
|
+
locationId: context.locationId
|
|
434
|
+
} : {}, context.cashierAssertion ? {
|
|
435
|
+
cashierAssertion: context.cashierAssertion
|
|
436
|
+
} : {}, {
|
|
437
|
+
soldAtMs,
|
|
438
|
+
lines,
|
|
439
|
+
discountPct: sale.discountPct,
|
|
440
|
+
totals,
|
|
441
|
+
cashTenderedCents: sale.cashTenderedCents,
|
|
442
|
+
changeCents: posOfflineChangeCents(totals.totalCents, sale.cashTenderedCents)
|
|
443
|
+
}, customer && Object.keys(customer).length ? {
|
|
444
|
+
customer
|
|
445
|
+
} : {});
|
|
446
|
+
// The sale is real only once the device holds it: a write that fails
|
|
447
|
+
// answers null, and the cashier is told before taking any cash.
|
|
448
|
+
await store.putSale({
|
|
449
|
+
saleKey,
|
|
450
|
+
sale: queued,
|
|
451
|
+
state: 'queued',
|
|
452
|
+
queuedAtMs: soldAtMs,
|
|
453
|
+
attempts: 0
|
|
454
|
+
});
|
|
455
|
+
setQueue(await store.listSales());
|
|
456
|
+
return {
|
|
457
|
+
saleKey,
|
|
458
|
+
sale: queued,
|
|
459
|
+
order: {
|
|
460
|
+
status: 'paid',
|
|
461
|
+
channel: 'pos',
|
|
462
|
+
registerId,
|
|
463
|
+
lineItems: lines.map((line)=>_extends({}, line, {
|
|
464
|
+
modifiers: undefined
|
|
465
|
+
})),
|
|
466
|
+
totals,
|
|
467
|
+
payments: [
|
|
468
|
+
{
|
|
469
|
+
id: 'pay_cash',
|
|
470
|
+
method: 'cash',
|
|
471
|
+
amountCents: totals.totalCents,
|
|
472
|
+
status: 'succeeded',
|
|
473
|
+
atMs: soldAtMs,
|
|
474
|
+
cashTenderedCents: sale.cashTenderedCents,
|
|
475
|
+
changeCents: queued.changeCents
|
|
476
|
+
}
|
|
477
|
+
],
|
|
478
|
+
createdAtMs: soldAtMs,
|
|
479
|
+
customerName: (_ref = customer == null ? void 0 : customer.name) != null ? _ref : null
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
} catch (unused) {
|
|
483
|
+
return null;
|
|
484
|
+
} finally{
|
|
485
|
+
ringInFlight.current = false;
|
|
486
|
+
}
|
|
487
|
+
}, [
|
|
488
|
+
store,
|
|
489
|
+
kit,
|
|
490
|
+
uid,
|
|
491
|
+
catalog,
|
|
492
|
+
hostId,
|
|
493
|
+
registerId,
|
|
494
|
+
now
|
|
495
|
+
]);
|
|
496
|
+
const reportNetworkFailure = useCallback(()=>setNetworkFailed(true), []);
|
|
497
|
+
const dismissNotices = useCallback(()=>setNotices([]), []);
|
|
498
|
+
const discard = useCallback(async (saleKey)=>{
|
|
499
|
+
if (!store) return;
|
|
500
|
+
await store.removeSale(saleKey).catch(()=>undefined);
|
|
501
|
+
setQueue(await store.listSales().catch(()=>[]));
|
|
502
|
+
}, [
|
|
503
|
+
store
|
|
504
|
+
]);
|
|
505
|
+
return useMemo(()=>({
|
|
506
|
+
offline,
|
|
507
|
+
ready,
|
|
508
|
+
unavailableReason,
|
|
509
|
+
kit,
|
|
510
|
+
queue,
|
|
511
|
+
syncing,
|
|
512
|
+
syncError,
|
|
513
|
+
notices,
|
|
514
|
+
gridProducts,
|
|
515
|
+
findByCode,
|
|
516
|
+
totalsFor,
|
|
517
|
+
ringCashSale,
|
|
518
|
+
reportNetworkFailure,
|
|
519
|
+
syncNow,
|
|
520
|
+
dismissNotices,
|
|
521
|
+
discard
|
|
522
|
+
}), [
|
|
523
|
+
offline,
|
|
524
|
+
ready,
|
|
525
|
+
unavailableReason,
|
|
526
|
+
kit,
|
|
527
|
+
queue,
|
|
528
|
+
syncing,
|
|
529
|
+
syncError,
|
|
530
|
+
notices,
|
|
531
|
+
gridProducts,
|
|
532
|
+
findByCode,
|
|
533
|
+
totalsFor,
|
|
534
|
+
ringCashSale,
|
|
535
|
+
reportNetworkFailure,
|
|
536
|
+
syncNow,
|
|
537
|
+
dismissNotices,
|
|
538
|
+
discard
|
|
539
|
+
]);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
//# sourceMappingURL=use-pos-offline.js.map
|