@aglyn/plugins-commerce 1.0.0-beta.277 → 1.0.0-beta.282
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 +17 -14
- package/src/lib/components/commerce-console-page.js +33 -1
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/payments-settings-card.component.js +1 -1
- package/src/lib/components/console/payments-settings-card.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-hardware-api.d.ts +122 -0
- package/src/lib/components/console/pos/pos-hardware-api.js +90 -0
- package/src/lib/components/console/pos/pos-hardware-api.js.map +1 -0
- package/src/lib/components/console/pos/pos-reader-splash-api.d.ts +58 -0
- package/src/lib/components/console/pos/pos-reader-splash-api.js +101 -0
- package/src/lib/components/console/pos/pos-reader-splash-api.js.map +1 -0
- package/src/lib/components/console/pos-devices-card.component.js +5 -0
- package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
- package/src/lib/components/console/pos-hardware-card.component.d.ts +26 -0
- package/src/lib/components/console/pos-hardware-card.component.js +456 -0
- package/src/lib/components/console/pos-hardware-card.component.js.map +1 -0
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.d.ts +14 -0
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.js +519 -0
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.d.ts +27 -0
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js +444 -0
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-check-in-zone.component.d.ts +9 -0
- package/src/lib/components/console/pos-ops/pos-check-in-zone.component.js +37 -0
- package/src/lib/components/console/pos-ops/pos-check-in-zone.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.d.ts +24 -0
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +346 -0
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-customer-lookup.component.d.ts +5 -1
- package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js +83 -4
- package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-day-totals-card.component.d.ts +35 -0
- package/src/lib/components/console/pos-ops/pos-day-totals-card.component.js +546 -0
- package/src/lib/components/console/pos-ops/pos-day-totals-card.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +2 -1
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +20 -1
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-ops-api.d.ts +1 -1
- package/src/lib/components/console/pos-ops/pos-ops-api.js.map +1 -1
- package/src/lib/components/console/pos-page.component.js +6 -3
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/pos-reader-splash-setting.component.d.ts +22 -0
- package/src/lib/components/console/pos-reader-splash-setting.component.js +275 -0
- package/src/lib/components/console/pos-reader-splash-setting.component.js.map +1 -0
- package/src/lib/components/console/pos-reader-splash-staff-page.component.d.ts +14 -0
- package/src/lib/components/console/pos-reader-splash-staff-page.component.js +301 -0
- package/src/lib/components/console/pos-reader-splash-staff-page.component.js.map +1 -0
- package/src/lib/components/console/pos-zones.d.ts +37 -3
- package/src/lib/components/console/pos-zones.js +11 -1
- package/src/lib/components/console/pos-zones.js.map +1 -1
- package/src/lib/components/console/product-check-in-fields.component.d.ts +20 -0
- package/src/lib/components/console/product-check-in-fields.component.js +172 -0
- package/src/lib/components/console/product-check-in-fields.component.js.map +1 -0
- package/src/lib/components/console/product-editor-dialog.component.js +48 -9
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/product-register-fields.component.d.ts +12 -0
- package/src/lib/components/console/product-register-fields.component.js +39 -1
- package/src/lib/components/console/product-register-fields.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +21 -6
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/reservations-card.component.js +239 -70
- package/src/lib/components/console/reservations-card.component.js.map +1 -1
- package/src/lib/components/reservation-widget.js +16 -0
- package/src/lib/components/reservation-widget.js.map +1 -1
- package/src/lib/constants/operator-alerts.d.ts +6 -0
- package/src/lib/constants/operator-alerts.js +20 -1
- package/src/lib/constants/operator-alerts.js.map +1 -1
- package/src/lib/declarations.console-server.js +7 -0
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/declarations.d.ts +26 -0
- package/src/lib/declarations.js +34 -0
- package/src/lib/declarations.js.map +1 -0
- package/src/lib/model/commerce-check-in-product.d.ts +37 -0
- package/src/lib/model/commerce-check-in-product.js +49 -0
- package/src/lib/model/commerce-check-in-product.js.map +1 -0
- package/src/lib/model/commerce-check-in.d.ts +187 -0
- package/src/lib/model/commerce-check-in.js +468 -0
- package/src/lib/model/commerce-check-in.js.map +1 -0
- package/src/lib/model/commerce-pos-day-report.d.ts +209 -0
- package/src/lib/model/commerce-pos-day-report.js +572 -0
- package/src/lib/model/commerce-pos-day-report.js.map +1 -0
- package/src/lib/model/commerce-pos-offline.d.ts +65 -3
- package/src/lib/model/commerce-pos-offline.js +104 -7
- package/src/lib/model/commerce-pos-offline.js.map +1 -1
- package/src/lib/model/commerce-pos-ops.d.ts +3 -0
- package/src/lib/model/commerce-pos-ops.js +1 -0
- package/src/lib/model/commerce-pos-ops.js.map +1 -1
- package/src/lib/model/commerce-pos.d.ts +43 -3
- package/src/lib/model/commerce-pos.js +73 -5
- package/src/lib/model/commerce-pos.js.map +1 -1
- package/src/lib/model/commerce-reservations.d.ts +73 -7
- package/src/lib/model/commerce-reservations.js +90 -10
- package/src/lib/model/commerce-reservations.js.map +1 -1
- package/src/lib/model/commerce.d.ts +40 -0
- package/src/lib/model/commerce.js +22 -4
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/index.d.ts +1 -0
- package/src/lib/model/index.js +1 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/plugin-permissions.d.ts +1 -1
- package/src/lib/model/plugin-permissions.js +2 -1
- package/src/lib/model/plugin-permissions.js.map +1 -1
- package/src/lib/model/pos-hardware.d.ts +288 -0
- package/src/lib/model/pos-hardware.js +499 -0
- package/src/lib/model/pos-hardware.js.map +1 -0
- package/src/lib/model/pos-offline-card-limits.d.ts +20 -0
- package/src/lib/model/pos-offline-card-limits.js +28 -0
- package/src/lib/model/pos-offline-card-limits.js.map +1 -0
- package/src/lib/model/pos-reader-splash.d.ts +114 -0
- package/src/lib/model/pos-reader-splash.js +141 -0
- package/src/lib/model/pos-reader-splash.js.map +1 -0
- package/src/lib/model/product-write.d.ts +6 -0
- package/src/lib/plugin-config.d.ts +10 -0
- package/src/lib/plugin-config.js +40 -0
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +28 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/cart-checkout.js +3 -1
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/cart.js +12 -1
- package/src/lib/server/cart.js.map +1 -1
- package/src/lib/server/catalog.js +49 -12
- package/src/lib/server/catalog.js.map +1 -1
- package/src/lib/server/checkout-extras.js +1 -1
- package/src/lib/server/checkout-extras.js.map +1 -1
- package/src/lib/server/checkout.js +7 -0
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/person-eraser.d.ts +8 -1
- package/src/lib/server/person-eraser.js +23 -1
- package/src/lib/server/person-eraser.js.map +1 -1
- package/src/lib/server/pos-check-in.d.ts +49 -0
- package/src/lib/server/pos-check-in.js +652 -0
- package/src/lib/server/pos-check-in.js.map +1 -0
- package/src/lib/server/pos-day-report.d.ts +46 -0
- package/src/lib/server/pos-day-report.js +299 -0
- package/src/lib/server/pos-day-report.js.map +1 -0
- package/src/lib/server/pos-hardware-admin.d.ts +50 -0
- package/src/lib/server/pos-hardware-admin.js +366 -0
- package/src/lib/server/pos-hardware-admin.js.map +1 -0
- package/src/lib/server/pos-hardware-notify.d.ts +27 -0
- package/src/lib/server/pos-hardware-notify.js +142 -0
- package/src/lib/server/pos-hardware-notify.js.map +1 -0
- package/src/lib/server/pos-hardware-user-eraser.d.ts +26 -0
- package/src/lib/server/pos-hardware-user-eraser.js +67 -0
- package/src/lib/server/pos-hardware-user-eraser.js.map +1 -0
- package/src/lib/server/pos-hardware-webhook.d.ts +31 -0
- package/src/lib/server/pos-hardware-webhook.js +176 -0
- package/src/lib/server/pos-hardware-webhook.js.map +1 -0
- package/src/lib/server/pos-hardware.d.ts +58 -0
- package/src/lib/server/pos-hardware.js +234 -0
- package/src/lib/server/pos-hardware.js.map +1 -0
- package/src/lib/server/pos-offline-card-reconcile.d.ts +38 -0
- package/src/lib/server/pos-offline-card-reconcile.js +58 -0
- package/src/lib/server/pos-offline-card-reconcile.js.map +1 -0
- package/src/lib/server/pos-offline-sync.d.ts +32 -0
- package/src/lib/server/pos-offline-sync.js +191 -15
- package/src/lib/server/pos-offline-sync.js.map +1 -1
- package/src/lib/server/pos-ops-routes.d.ts +4 -2
- package/src/lib/server/pos-ops-routes.js +14 -2
- package/src/lib/server/pos-ops-routes.js.map +1 -1
- package/src/lib/server/pos-order.js +39 -51
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/pos-payment.js +8 -4
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/pos-reader-splash-admin.d.ts +36 -0
- package/src/lib/server/pos-reader-splash-admin.js +295 -0
- package/src/lib/server/pos-reader-splash-admin.js.map +1 -0
- package/src/lib/server/pos-reader-splash-render.d.ts +40 -0
- package/src/lib/server/pos-reader-splash-render.js +138 -0
- package/src/lib/server/pos-reader-splash-render.js.map +1 -0
- package/src/lib/server/pos-reader-splash-server.d.ts +32 -0
- package/src/lib/server/pos-reader-splash-server.js +32 -0
- package/src/lib/server/pos-reader-splash-server.js.map +1 -0
- package/src/lib/server/pos-reader-splash.d.ts +105 -0
- package/src/lib/server/pos-reader-splash.js +548 -0
- package/src/lib/server/pos-reader-splash.js.map +1 -0
- package/src/lib/server/pos-sale.d.ts +2 -1
- package/src/lib/server/pos-sale.js +3 -1
- package/src/lib/server/pos-sale.js.map +1 -1
- package/src/lib/server/pos-terminal.d.ts +67 -4
- package/src/lib/server/pos-terminal.js +239 -32
- package/src/lib/server/pos-terminal.js.map +1 -1
- package/src/lib/server/process-restock.js +4 -0
- package/src/lib/server/process-restock.js.map +1 -1
- package/src/lib/server/product-card.js +2 -2
- package/src/lib/server/product-card.js.map +1 -1
- package/src/lib/server/product-catalog.d.ts +2 -0
- package/src/lib/server/product-catalog.js +11 -4
- package/src/lib/server/product-catalog.js.map +1 -1
- package/src/lib/server/product.js +3 -1
- package/src/lib/server/product.js.map +1 -1
- package/src/lib/server/related.js +8 -1
- package/src/lib/server/related.js.map +1 -1
- package/src/lib/server/reservation-availability-query.d.ts +35 -0
- package/src/lib/server/reservation-availability-query.js +34 -0
- package/src/lib/server/reservation-availability-query.js.map +1 -0
- package/src/lib/server/reservation-availability.d.ts +21 -0
- package/src/lib/server/reservation-availability.js +64 -10
- package/src/lib/server/reservation-availability.js.map +1 -1
- package/src/lib/server/reservation-walk-in.d.ts +28 -0
- package/src/lib/server/reservation-walk-in.js +166 -0
- package/src/lib/server/reservation-walk-in.js.map +1 -0
- package/src/lib/server/reserve.js +13 -10
- package/src/lib/server/reserve.js.map +1 -1
- package/src/lib/server/reviews.js +3 -1
- package/src/lib/server/reviews.js.map +1 -1
- package/src/lib/server/site-page-resolver.js +5 -2
- package/src/lib/server/site-page-resolver.js.map +1 -1
- package/src/lib/server.js +26 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/fake-firestore.js +72 -0
- package/src/lib/testing/fake-firestore.js.map +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { type PosDayReport } from '../../../model/commerce-pos-day-report';
|
|
18
|
+
export interface PosDayTotalsCardProps {
|
|
19
|
+
hostId: string;
|
|
20
|
+
/** The viewer may work the register: what the route's gate asks. */
|
|
21
|
+
canManagePos?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** The day totals as a printable 80 mm document, like the Z report. */
|
|
24
|
+
export declare function posDayReportDocument(input: {
|
|
25
|
+
report: PosDayReport;
|
|
26
|
+
}): string;
|
|
27
|
+
/**
|
|
28
|
+
* Day totals (AGL-4037): beside the shift history, for a store with a
|
|
29
|
+
* register, on a plan with the point of sale.
|
|
30
|
+
*/
|
|
31
|
+
export declare function PosDayTotalsCard(props: PosDayTotalsCardProps): import("react").JSX.Element;
|
|
32
|
+
export declare namespace PosDayTotalsCard {
|
|
33
|
+
var displayName: string;
|
|
34
|
+
}
|
|
35
|
+
export default PosDayTotalsCard;
|
|
@@ -0,0 +1,546 @@
|
|
|
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 { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
19
|
+
import { pluginDocsHelp } from "@aglyn/aglyn";
|
|
20
|
+
import { CardDisplay } from "@aglyn/shared-ui-jsx";
|
|
21
|
+
import { ListTable } from "@aglyn/shared-ui-jsx/components/list-table.component";
|
|
22
|
+
import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
|
|
23
|
+
import { useFirestore, useFirestoreCollection, useUser } from "@aglyn/tenant-feature-instance";
|
|
24
|
+
import { Alert, Button, Chip, Divider, Stack, Typography } from "@mui/material";
|
|
25
|
+
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
|
|
26
|
+
import { DatePicker } from "@mui/x-date-pickers/DatePicker";
|
|
27
|
+
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
|
|
28
|
+
import { collection, documentId, limit, orderBy, query } from "firebase/firestore";
|
|
29
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
30
|
+
import { posDayRangeLabel, posDayReportIsEmpty, posDayReportSections, POS_DAY_REPORT_MAX_DAYS, POS_DAY_REPORT_ROUTE } from "../../../model/commerce-pos-day-report.js";
|
|
31
|
+
import { formatReceiptMoney } from "../../../model/commerce-receipt.js";
|
|
32
|
+
import { escapeHtml } from "../../../utils/escape-html.js";
|
|
33
|
+
import CommerceStatTile from "../commerce-stat-tile.component.js";
|
|
34
|
+
import { EntitlementGatedCard } from "../entitlement-gate.component.js";
|
|
35
|
+
import { POS_RECEIPT_STYLES } from "./pos-receipt.js";
|
|
36
|
+
import { printPosDocument } from "./pos-shift-report.component.js";
|
|
37
|
+
const HEADER = 'Day totals';
|
|
38
|
+
const HELP = pluginDocsHelp('posOperations', {
|
|
39
|
+
anchor: '#day-and-event-totals'
|
|
40
|
+
});
|
|
41
|
+
const DAY_FORMAT = 'YYYY-MM-DD';
|
|
42
|
+
/** A time as the shifts table lists it, in the viewer's locale. */ const when = (ms)=>ms ? new Date(ms).toLocaleString([], {
|
|
43
|
+
month: 'short',
|
|
44
|
+
day: 'numeric',
|
|
45
|
+
hour: 'numeric',
|
|
46
|
+
minute: '2-digit'
|
|
47
|
+
}) : '';
|
|
48
|
+
/** The day totals as a printable 80 mm document, like the Z report. */ export function posDayReportDocument(input) {
|
|
49
|
+
const money = (cents)=>formatReceiptMoney(cents, input.report.currency);
|
|
50
|
+
const body = posDayReportSections(input.report, money).map((section)=>`<hr class="rule"><div class="title">${escapeHtml(section.section.toUpperCase())}</div>` + section.rows.map((row)=>`<div class="row${row.strong ? ' total' : ''}"><span>${escapeHtml(row.label)}</span><span>${escapeHtml(row.value)}</span></div>`).join('')).join('');
|
|
51
|
+
return '<!doctype html><html><head><meta charset="utf-8">' + `<title>DAY TOTALS</title><style>${POS_RECEIPT_STYLES}</style></head><body>` + `<div class="receipt"><div class="center"><div class="store">${escapeHtml(input.report.storeName || 'Register')}</div>` + `<div class="title">DAY TOTALS</div><div class="muted">${escapeHtml(posDayRangeLabel(input.report))}</div></div>` + `${body}</div></body></html>`;
|
|
52
|
+
}
|
|
53
|
+
function DrawerRows(props) {
|
|
54
|
+
const drawers = posDayReportSections(props.report, props.money).find((section)=>section.section === 'Cash drawers');
|
|
55
|
+
return /*#__PURE__*/ _jsx(Stack, {
|
|
56
|
+
spacing: 0.5,
|
|
57
|
+
children: drawers == null ? void 0 : drawers.rows.map((row)=>/*#__PURE__*/ _jsxs(Stack, {
|
|
58
|
+
direction: "row",
|
|
59
|
+
sx: {
|
|
60
|
+
justifyContent: 'space-between',
|
|
61
|
+
gap: 2
|
|
62
|
+
},
|
|
63
|
+
children: [
|
|
64
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
65
|
+
variant: "body2",
|
|
66
|
+
color: row.strong ? 'text.primary' : 'text.secondary',
|
|
67
|
+
children: row.label
|
|
68
|
+
}),
|
|
69
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
70
|
+
variant: row.strong ? 'subtitle2' : 'body2',
|
|
71
|
+
sx: {
|
|
72
|
+
fontVariantNumeric: 'tabular-nums'
|
|
73
|
+
},
|
|
74
|
+
children: row.value
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
}, row.label))
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function Section(props) {
|
|
81
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
82
|
+
spacing: 1,
|
|
83
|
+
children: [
|
|
84
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
85
|
+
variant: "overline",
|
|
86
|
+
children: props.title
|
|
87
|
+
}),
|
|
88
|
+
props.children
|
|
89
|
+
]
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function PosDayTotalsBody(props) {
|
|
93
|
+
const { hostId, canManagePos = false } = props;
|
|
94
|
+
const { data: user } = useUser();
|
|
95
|
+
const [from, setFrom] = useState(null);
|
|
96
|
+
const [to, setTo] = useState(null);
|
|
97
|
+
const [answer, setAnswer] = useState({
|
|
98
|
+
state: 'idle'
|
|
99
|
+
});
|
|
100
|
+
const [exporting, setExporting] = useState(false);
|
|
101
|
+
const url = useCallback((format)=>{
|
|
102
|
+
const params = new URLSearchParams({
|
|
103
|
+
hostId
|
|
104
|
+
});
|
|
105
|
+
if (from == null ? void 0 : from.isValid()) params.set('from', from.format(DAY_FORMAT));
|
|
106
|
+
if (to == null ? void 0 : to.isValid()) params.set('to', to.format(DAY_FORMAT));
|
|
107
|
+
if (format) params.set('format', format);
|
|
108
|
+
return `${POS_DAY_REPORT_ROUTE}?${params.toString()}`;
|
|
109
|
+
}, [
|
|
110
|
+
hostId,
|
|
111
|
+
from,
|
|
112
|
+
to
|
|
113
|
+
]);
|
|
114
|
+
useEffect(()=>{
|
|
115
|
+
if (!user || !canManagePos) return;
|
|
116
|
+
let live = true;
|
|
117
|
+
setAnswer({
|
|
118
|
+
state: 'loading'
|
|
119
|
+
});
|
|
120
|
+
void (async ()=>{
|
|
121
|
+
try {
|
|
122
|
+
const response = await authorizedFetch(user, url(), {
|
|
123
|
+
method: 'GET'
|
|
124
|
+
});
|
|
125
|
+
const body = await response.json().catch(()=>({}));
|
|
126
|
+
if (!live) return;
|
|
127
|
+
setAnswer(response.ok && body.report ? {
|
|
128
|
+
state: 'ready',
|
|
129
|
+
report: body.report
|
|
130
|
+
} : {
|
|
131
|
+
state: 'error',
|
|
132
|
+
error: body.error || 'The day totals could not be read.'
|
|
133
|
+
});
|
|
134
|
+
} catch (unused) {
|
|
135
|
+
if (live) setAnswer({
|
|
136
|
+
state: 'error',
|
|
137
|
+
error: 'The day totals could not be read. Check the connection.'
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
})();
|
|
141
|
+
return ()=>{
|
|
142
|
+
live = false;
|
|
143
|
+
};
|
|
144
|
+
}, [
|
|
145
|
+
user,
|
|
146
|
+
canManagePos,
|
|
147
|
+
url
|
|
148
|
+
]);
|
|
149
|
+
const report = answer.state === 'ready' ? answer.report : null;
|
|
150
|
+
const money = useCallback((cents)=>{
|
|
151
|
+
var _ref;
|
|
152
|
+
return formatReceiptMoney(cents, (_ref = report == null ? void 0 : report.currency) != null ? _ref : 'usd');
|
|
153
|
+
}, [
|
|
154
|
+
report == null ? void 0 : report.currency
|
|
155
|
+
]);
|
|
156
|
+
const moneyColumn = useCallback((field, headerName, minWidth = 110)=>({
|
|
157
|
+
field,
|
|
158
|
+
headerName,
|
|
159
|
+
type: 'number',
|
|
160
|
+
minWidth,
|
|
161
|
+
flex: 1,
|
|
162
|
+
valueFormatter: (value)=>value == null ? '—' : money(value)
|
|
163
|
+
}), [
|
|
164
|
+
money
|
|
165
|
+
]);
|
|
166
|
+
const tenderColumns = useMemo(()=>[
|
|
167
|
+
{
|
|
168
|
+
field: 'label',
|
|
169
|
+
headerName: 'Tender',
|
|
170
|
+
flex: 1,
|
|
171
|
+
minWidth: 140
|
|
172
|
+
},
|
|
173
|
+
moneyColumn('salesCents', 'Sales'),
|
|
174
|
+
moneyColumn('refundsCents', 'Refunds'),
|
|
175
|
+
moneyColumn('netCents', 'Net')
|
|
176
|
+
], [
|
|
177
|
+
moneyColumn
|
|
178
|
+
]);
|
|
179
|
+
const salesColumns = useCallback((nameHeader)=>[
|
|
180
|
+
{
|
|
181
|
+
field: 'name',
|
|
182
|
+
headerName: nameHeader,
|
|
183
|
+
flex: 1,
|
|
184
|
+
minWidth: 140
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
field: 'orderCount',
|
|
188
|
+
headerName: 'Orders',
|
|
189
|
+
type: 'number',
|
|
190
|
+
minWidth: 90
|
|
191
|
+
},
|
|
192
|
+
moneyColumn('grossSalesCents', 'Gross sales'),
|
|
193
|
+
moneyColumn('tipsCents', 'Tips', 90),
|
|
194
|
+
moneyColumn('refundsCents', 'Refunds'),
|
|
195
|
+
moneyColumn('netSalesCents', 'Net sales')
|
|
196
|
+
], [
|
|
197
|
+
moneyColumn
|
|
198
|
+
]);
|
|
199
|
+
const registerColumns = useMemo(()=>salesColumns('Register'), [
|
|
200
|
+
salesColumns
|
|
201
|
+
]);
|
|
202
|
+
const cashierColumns = useMemo(()=>salesColumns('Cashier'), [
|
|
203
|
+
salesColumns
|
|
204
|
+
]);
|
|
205
|
+
const shiftColumns = useMemo(()=>[
|
|
206
|
+
{
|
|
207
|
+
field: 'registerName',
|
|
208
|
+
headerName: 'Register',
|
|
209
|
+
minWidth: 120,
|
|
210
|
+
flex: 1
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
field: 'openedAtMs',
|
|
214
|
+
headerName: 'Opened',
|
|
215
|
+
minWidth: 140,
|
|
216
|
+
valueFormatter: (value)=>when(value)
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
field: 'closedAtMs',
|
|
220
|
+
headerName: 'Closed',
|
|
221
|
+
minWidth: 140,
|
|
222
|
+
// Open shifts sort after every closed one, by when they opened.
|
|
223
|
+
valueGetter: (_value, row)=>{
|
|
224
|
+
var _row_closedAtMs, _row_openedAtMs;
|
|
225
|
+
return (_row_closedAtMs = row['closedAtMs']) != null ? _row_closedAtMs : Number.MAX_SAFE_INTEGER - ((_row_openedAtMs = row['openedAtMs']) != null ? _row_openedAtMs : 0);
|
|
226
|
+
},
|
|
227
|
+
renderCell: ({ row })=>row['status'] === 'open' ? /*#__PURE__*/ _jsx(Chip, {
|
|
228
|
+
size: "small",
|
|
229
|
+
color: "success",
|
|
230
|
+
label: "Open"
|
|
231
|
+
}) : when(row['closedAtMs'])
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
field: 'openedByName',
|
|
235
|
+
headerName: 'Opened by',
|
|
236
|
+
minWidth: 130
|
|
237
|
+
},
|
|
238
|
+
moneyColumn('openingFloatCents', 'Starting cash'),
|
|
239
|
+
moneyColumn('netSalesCents', 'Net sales'),
|
|
240
|
+
moneyColumn('expectedCashCents', 'Expected'),
|
|
241
|
+
moneyColumn('countedCashCents', 'Counted'),
|
|
242
|
+
{
|
|
243
|
+
field: 'varianceCents',
|
|
244
|
+
headerName: 'Variance',
|
|
245
|
+
type: 'number',
|
|
246
|
+
minWidth: 110,
|
|
247
|
+
renderCell: ({ row })=>row['varianceCents'] != null ? /*#__PURE__*/ _jsx(Chip, {
|
|
248
|
+
size: "small",
|
|
249
|
+
variant: "outlined",
|
|
250
|
+
color: row['varianceCents'] === 0 ? 'success' : 'warning',
|
|
251
|
+
label: money(row['varianceCents'])
|
|
252
|
+
}) : '—'
|
|
253
|
+
}
|
|
254
|
+
], [
|
|
255
|
+
moneyColumn,
|
|
256
|
+
money
|
|
257
|
+
]);
|
|
258
|
+
const rows = useMemo(()=>report ? {
|
|
259
|
+
tenders: report.byTender.map((row)=>_extends({}, row, {
|
|
260
|
+
$id: row.method
|
|
261
|
+
})),
|
|
262
|
+
registers: report.byRegister.map((row)=>_extends({}, row, {
|
|
263
|
+
$id: row.registerId || 'none'
|
|
264
|
+
})),
|
|
265
|
+
cashiers: report.byCashier.map((row)=>_extends({}, row, {
|
|
266
|
+
$id: row.memberId || 'none'
|
|
267
|
+
})),
|
|
268
|
+
shifts: report.shifts.map((row)=>_extends({}, row, {
|
|
269
|
+
$id: `${row.registerId}/${row.shiftId}`
|
|
270
|
+
}))
|
|
271
|
+
} : null, [
|
|
272
|
+
report
|
|
273
|
+
]);
|
|
274
|
+
const exportCsv = async ()=>{
|
|
275
|
+
if (!user || !report) return;
|
|
276
|
+
setExporting(true);
|
|
277
|
+
try {
|
|
278
|
+
const response = await authorizedFetch(user, url('csv'), {
|
|
279
|
+
method: 'GET'
|
|
280
|
+
});
|
|
281
|
+
if (!response.ok) {
|
|
282
|
+
const body = await response.json().catch(()=>({}));
|
|
283
|
+
setAnswer({
|
|
284
|
+
state: 'error',
|
|
285
|
+
error: body.error || 'The spreadsheet could not be made.'
|
|
286
|
+
});
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const blob = new Blob([
|
|
290
|
+
await response.text()
|
|
291
|
+
], {
|
|
292
|
+
type: 'text/csv;charset=utf-8'
|
|
293
|
+
});
|
|
294
|
+
const href = URL.createObjectURL(blob);
|
|
295
|
+
const link = document.createElement('a');
|
|
296
|
+
link.href = href;
|
|
297
|
+
link.download = `day-totals-${report.from}${report.to === report.from ? '' : `-to-${report.to}`}.csv`;
|
|
298
|
+
link.click();
|
|
299
|
+
window.setTimeout(()=>URL.revokeObjectURL(href), 1000);
|
|
300
|
+
} finally{
|
|
301
|
+
setExporting(false);
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
const print = ()=>{
|
|
305
|
+
if (!report) return;
|
|
306
|
+
printPosDocument(posDayReportDocument({
|
|
307
|
+
report
|
|
308
|
+
}));
|
|
309
|
+
};
|
|
310
|
+
const lastDay = (from == null ? void 0 : from.isValid()) ? from.add(POS_DAY_REPORT_MAX_DAYS - 1, 'day') : undefined;
|
|
311
|
+
return /*#__PURE__*/ _jsx(CardDisplay, {
|
|
312
|
+
header: HEADER,
|
|
313
|
+
help: HELP,
|
|
314
|
+
HeaderProps: {
|
|
315
|
+
action: /*#__PURE__*/ _jsxs(Stack, {
|
|
316
|
+
direction: "row",
|
|
317
|
+
spacing: 1,
|
|
318
|
+
children: [
|
|
319
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
320
|
+
size: "small",
|
|
321
|
+
onClick: ()=>void exportCsv(),
|
|
322
|
+
disabled: !report || exporting,
|
|
323
|
+
children: 'Export CSV'
|
|
324
|
+
}),
|
|
325
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
326
|
+
size: "small",
|
|
327
|
+
onClick: print,
|
|
328
|
+
disabled: !report,
|
|
329
|
+
children: 'Print'
|
|
330
|
+
})
|
|
331
|
+
]
|
|
332
|
+
})
|
|
333
|
+
},
|
|
334
|
+
contentGutterX: true,
|
|
335
|
+
contentGutterY: true,
|
|
336
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
337
|
+
spacing: 2.5,
|
|
338
|
+
children: [
|
|
339
|
+
!canManagePos ? /*#__PURE__*/ _jsx(Alert, {
|
|
340
|
+
severity: "info",
|
|
341
|
+
children: 'Day totals are for members who can use the register: a site admin or editor with the "Use the point of sale" permission.'
|
|
342
|
+
}) : null,
|
|
343
|
+
/*#__PURE__*/ _jsx(LocalizationProvider, {
|
|
344
|
+
dateAdapter: AdapterDayjs,
|
|
345
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
346
|
+
direction: {
|
|
347
|
+
xs: 'column',
|
|
348
|
+
sm: 'row'
|
|
349
|
+
},
|
|
350
|
+
spacing: 1.5,
|
|
351
|
+
sx: {
|
|
352
|
+
alignItems: {
|
|
353
|
+
sm: 'center'
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
children: [
|
|
357
|
+
/*#__PURE__*/ _jsx(DatePicker, {
|
|
358
|
+
label: "From",
|
|
359
|
+
value: from,
|
|
360
|
+
onChange: (value)=>{
|
|
361
|
+
setFrom(value);
|
|
362
|
+
if ((value == null ? void 0 : value.isValid()) && (to == null ? void 0 : to.isValid()) && (to.isBefore(value) || to.diff(value, 'day') >= POS_DAY_REPORT_MAX_DAYS)) {
|
|
363
|
+
setTo(value);
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
disabled: !canManagePos,
|
|
367
|
+
slotProps: {
|
|
368
|
+
textField: {
|
|
369
|
+
size: 'small'
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}),
|
|
373
|
+
/*#__PURE__*/ _jsx(DatePicker, _extends({
|
|
374
|
+
label: "To",
|
|
375
|
+
value: to,
|
|
376
|
+
onChange: setTo
|
|
377
|
+
}, (from == null ? void 0 : from.isValid()) ? {
|
|
378
|
+
minDate: from
|
|
379
|
+
} : {}, lastDay ? {
|
|
380
|
+
maxDate: lastDay
|
|
381
|
+
} : {}, {
|
|
382
|
+
disabled: !canManagePos,
|
|
383
|
+
slotProps: {
|
|
384
|
+
textField: {
|
|
385
|
+
size: 'small'
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
})),
|
|
389
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
390
|
+
size: "small",
|
|
391
|
+
disabled: !canManagePos || !from && !to,
|
|
392
|
+
onClick: ()=>{
|
|
393
|
+
setFrom(null);
|
|
394
|
+
setTo(null);
|
|
395
|
+
},
|
|
396
|
+
children: 'Today'
|
|
397
|
+
})
|
|
398
|
+
]
|
|
399
|
+
})
|
|
400
|
+
}),
|
|
401
|
+
answer.state === 'loading' ? /*#__PURE__*/ _jsx(Typography, {
|
|
402
|
+
variant: "body2",
|
|
403
|
+
color: "text.secondary",
|
|
404
|
+
children: 'Adding up every register…'
|
|
405
|
+
}) : null,
|
|
406
|
+
answer.state === 'error' ? /*#__PURE__*/ _jsx(Alert, {
|
|
407
|
+
severity: "warning",
|
|
408
|
+
children: answer.error
|
|
409
|
+
}) : null,
|
|
410
|
+
report && rows ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
411
|
+
children: [
|
|
412
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
413
|
+
variant: "body2",
|
|
414
|
+
color: "text.secondary",
|
|
415
|
+
children: `${posDayRangeLabel(report)} · ${report.timeZone} · every register and cashier`
|
|
416
|
+
}),
|
|
417
|
+
report.truncated ? /*#__PURE__*/ _jsx(Alert, {
|
|
418
|
+
severity: "warning",
|
|
419
|
+
children: 'These days had more activity than one report reads; the figures are partial. Choose fewer days.'
|
|
420
|
+
}) : null,
|
|
421
|
+
posDayReportIsEmpty(report) ? /*#__PURE__*/ _jsx(Typography, {
|
|
422
|
+
variant: "body2",
|
|
423
|
+
color: "text.secondary",
|
|
424
|
+
children: 'No register sales, returns or shifts on these days.'
|
|
425
|
+
}) : /*#__PURE__*/ _jsxs(_Fragment, {
|
|
426
|
+
children: [
|
|
427
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
428
|
+
direction: "row",
|
|
429
|
+
spacing: 3,
|
|
430
|
+
sx: {
|
|
431
|
+
flexWrap: 'wrap',
|
|
432
|
+
rowGap: 1.5
|
|
433
|
+
},
|
|
434
|
+
children: [
|
|
435
|
+
/*#__PURE__*/ _jsx(CommerceStatTile, {
|
|
436
|
+
label: "Net sales",
|
|
437
|
+
value: money(report.totals.netSalesCents)
|
|
438
|
+
}),
|
|
439
|
+
/*#__PURE__*/ _jsx(CommerceStatTile, {
|
|
440
|
+
label: "Gross sales",
|
|
441
|
+
value: money(report.totals.grossSalesCents)
|
|
442
|
+
}),
|
|
443
|
+
/*#__PURE__*/ _jsx(CommerceStatTile, {
|
|
444
|
+
label: "Orders",
|
|
445
|
+
value: String(report.totals.orderCount)
|
|
446
|
+
}),
|
|
447
|
+
/*#__PURE__*/ _jsx(CommerceStatTile, {
|
|
448
|
+
label: "Tips",
|
|
449
|
+
value: money(report.totals.tipsCents)
|
|
450
|
+
}),
|
|
451
|
+
/*#__PURE__*/ _jsx(CommerceStatTile, {
|
|
452
|
+
label: "Tax",
|
|
453
|
+
value: money(report.totals.taxCents)
|
|
454
|
+
}),
|
|
455
|
+
/*#__PURE__*/ _jsx(CommerceStatTile, {
|
|
456
|
+
label: "Discounts",
|
|
457
|
+
value: money(report.totals.discountsCents)
|
|
458
|
+
}),
|
|
459
|
+
/*#__PURE__*/ _jsx(CommerceStatTile, {
|
|
460
|
+
label: `Refunds (${report.totals.refundCount})`,
|
|
461
|
+
value: money(report.totals.refundsCents)
|
|
462
|
+
})
|
|
463
|
+
]
|
|
464
|
+
}),
|
|
465
|
+
/*#__PURE__*/ _jsx(Section, {
|
|
466
|
+
title: "By tender",
|
|
467
|
+
children: /*#__PURE__*/ _jsx(ListTable, {
|
|
468
|
+
"aria-label": "Day totals by tender",
|
|
469
|
+
rows: rows.tenders,
|
|
470
|
+
columns: tenderColumns,
|
|
471
|
+
hideFooter: true,
|
|
472
|
+
noRowsLabel: "No sales"
|
|
473
|
+
})
|
|
474
|
+
}),
|
|
475
|
+
/*#__PURE__*/ _jsx(Section, {
|
|
476
|
+
title: "By register",
|
|
477
|
+
children: /*#__PURE__*/ _jsx(ListTable, {
|
|
478
|
+
"aria-label": "Day totals by register",
|
|
479
|
+
rows: rows.registers,
|
|
480
|
+
columns: registerColumns,
|
|
481
|
+
hideFooter: true,
|
|
482
|
+
noRowsLabel: "No register sales"
|
|
483
|
+
})
|
|
484
|
+
}),
|
|
485
|
+
/*#__PURE__*/ _jsx(Section, {
|
|
486
|
+
title: "By cashier",
|
|
487
|
+
children: /*#__PURE__*/ _jsx(ListTable, {
|
|
488
|
+
"aria-label": "Day totals by cashier",
|
|
489
|
+
rows: rows.cashiers,
|
|
490
|
+
columns: cashierColumns,
|
|
491
|
+
hideFooter: true,
|
|
492
|
+
noRowsLabel: "No cashier sales"
|
|
493
|
+
})
|
|
494
|
+
}),
|
|
495
|
+
/*#__PURE__*/ _jsx(Divider, {}),
|
|
496
|
+
/*#__PURE__*/ _jsx(Section, {
|
|
497
|
+
title: "Cash drawers",
|
|
498
|
+
children: /*#__PURE__*/ _jsx(DrawerRows, {
|
|
499
|
+
report: report,
|
|
500
|
+
money: money
|
|
501
|
+
})
|
|
502
|
+
}),
|
|
503
|
+
/*#__PURE__*/ _jsx(Section, {
|
|
504
|
+
title: "Shifts",
|
|
505
|
+
children: /*#__PURE__*/ _jsx(ListTable, {
|
|
506
|
+
"aria-label": "Shifts on these days",
|
|
507
|
+
rows: rows.shifts,
|
|
508
|
+
columns: shiftColumns,
|
|
509
|
+
noRowsLabel: "No shifts on these days"
|
|
510
|
+
})
|
|
511
|
+
})
|
|
512
|
+
]
|
|
513
|
+
})
|
|
514
|
+
]
|
|
515
|
+
}) : null
|
|
516
|
+
]
|
|
517
|
+
})
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Day totals (AGL-4037): beside the shift history, for a store with a
|
|
522
|
+
* register, on a plan with the point of sale.
|
|
523
|
+
*/ export function PosDayTotalsCard(props) {
|
|
524
|
+
const firestore = useFirestore();
|
|
525
|
+
// Whether the store has a register at all: the first by id is enough to
|
|
526
|
+
// answer, and an id order drops no register.
|
|
527
|
+
const { data: registers, status } = useFirestoreCollection(()=>query(collection(firestore, 'hosts', props.hostId, 'registers'), orderBy(documentId()), limit(1)), [
|
|
528
|
+
firestore,
|
|
529
|
+
props.hostId
|
|
530
|
+
], {
|
|
531
|
+
idField: '$id'
|
|
532
|
+
});
|
|
533
|
+
if (status === 'success' && !(registers == null ? void 0 : registers.length)) return null;
|
|
534
|
+
return /*#__PURE__*/ _jsx(EntitlementGatedCard, {
|
|
535
|
+
hostId: props.hostId,
|
|
536
|
+
feature: "pos",
|
|
537
|
+
header: HEADER,
|
|
538
|
+
help: HELP,
|
|
539
|
+
upsell: 'Totals for a day or an event across every register, shift and cashier come with the point of sale.',
|
|
540
|
+
children: /*#__PURE__*/ _jsx(PosDayTotalsBody, _extends({}, props))
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
PosDayTotalsCard.displayName = 'PosDayTotalsCard';
|
|
544
|
+
export default PosDayTotalsCard;
|
|
545
|
+
|
|
546
|
+
//# sourceMappingURL=pos-day-totals-card.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-ops/pos-day-totals-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { ListTable } from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useFirestore, useFirestoreCollection, useUser } from '@aglyn/tenant-feature-instance'\nimport { Alert, Button, Chip, Divider, Stack, Typography } from '@mui/material'\nimport type { GridColDef } from '@mui/x-data-grid'\nimport { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'\nimport { DatePicker } from '@mui/x-date-pickers/DatePicker'\nimport { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'\nimport type { Dayjs } from 'dayjs'\nimport { collection, documentId, limit, orderBy, query } from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState, type ReactNode } from 'react'\nimport {\n posDayRangeLabel,\n posDayReportIsEmpty,\n posDayReportSections,\n POS_DAY_REPORT_MAX_DAYS,\n POS_DAY_REPORT_ROUTE,\n type PosDayReport,\n} from '../../../model/commerce-pos-day-report'\nimport { formatReceiptMoney } from '../../../model/commerce-receipt'\nimport { escapeHtml } from '../../../utils/escape-html'\nimport CommerceStatTile from '../commerce-stat-tile.component'\nimport { EntitlementGatedCard } from '../entitlement-gate.component'\nimport { POS_RECEIPT_STYLES } from './pos-receipt'\nimport { printPosDocument } from './pos-shift-report.component'\n\n/*==========================================\n * DAY TOTALS (AGL-4037): one day's or one event's sales across every\n * register, shift and cashier, from `GET /api/commerce/pos-day-report`.\n *\n * The figures are the server's: the card formats them and never sums them.\n * Every table holds a whole, bounded answer (seven tenders at most, the\n * site's registers, its staff, the range's shifts), so the grid sorts each\n * by any column itself.\n *=========================================*/\n\nexport interface PosDayTotalsCardProps {\n hostId: string\n /** The viewer may work the register: what the route's gate asks. */\n canManagePos?: boolean\n}\n\nconst HEADER = 'Day totals'\nconst HELP = pluginDocsHelp('posOperations', { anchor: '#day-and-event-totals' })\nconst DAY_FORMAT = 'YYYY-MM-DD'\n\ntype Answer =\n | { state: 'idle' | 'loading' }\n | { state: 'ready'; report: PosDayReport }\n | { state: 'error'; error: string }\n\n/** A time as the shifts table lists it, in the viewer's locale. */\nconst when = (ms?: number | null) =>\n ms\n ? new Date(ms).toLocaleString([], { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' })\n : ''\n\n/** The day totals as a printable 80 mm document, like the Z report. */\nexport function posDayReportDocument(input: { report: PosDayReport }): string {\n const money = (cents: number) => formatReceiptMoney(cents, input.report.currency)\n const body = posDayReportSections(input.report, money)\n .map(\n (section) =>\n `<hr class=\"rule\"><div class=\"title\">${escapeHtml(section.section.toUpperCase())}</div>` +\n section.rows\n .map(\n (row) =>\n `<div class=\"row${row.strong ? ' total' : ''}\"><span>${escapeHtml(row.label)}</span><span>${escapeHtml(row.value)}</span></div>`,\n )\n .join(''),\n )\n .join('')\n return (\n '<!doctype html><html><head><meta charset=\"utf-8\">' +\n `<title>DAY TOTALS</title><style>${POS_RECEIPT_STYLES}</style></head><body>` +\n `<div class=\"receipt\"><div class=\"center\"><div class=\"store\">${escapeHtml(input.report.storeName || 'Register')}</div>` +\n `<div class=\"title\">DAY TOTALS</div><div class=\"muted\">${escapeHtml(posDayRangeLabel(input.report))}</div></div>` +\n `${body}</div></body></html>`\n )\n}\n\nfunction DrawerRows(props: { report: PosDayReport; money: (cents: number) => string }) {\n const drawers = posDayReportSections(props.report, props.money).find((section) => section.section === 'Cash drawers')\n return (\n <Stack spacing={0.5}>\n {drawers?.rows.map((row) => (\n <Stack key={row.label} direction=\"row\" sx={{ justifyContent: 'space-between', gap: 2 }}>\n <Typography variant=\"body2\" color={row.strong ? 'text.primary' : 'text.secondary'}>\n {row.label}\n </Typography>\n <Typography variant={row.strong ? 'subtitle2' : 'body2'} sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {row.value}\n </Typography>\n </Stack>\n ))}\n </Stack>\n )\n}\n\nfunction Section(props: { title: string; children: ReactNode }) {\n return (\n <Stack spacing={1}>\n <Typography variant=\"overline\">{props.title}</Typography>\n {props.children}\n </Stack>\n )\n}\n\nfunction PosDayTotalsBody(props: PosDayTotalsCardProps) {\n const { hostId, canManagePos = false } = props\n const { data: user } = useUser()\n const [from, setFrom] = useState<Dayjs | null>(null)\n const [to, setTo] = useState<Dayjs | null>(null)\n const [answer, setAnswer] = useState<Answer>({ state: 'idle' })\n const [exporting, setExporting] = useState(false)\n\n const url = useCallback(\n (format?: 'csv') => {\n const params = new URLSearchParams({ hostId })\n if (from?.isValid()) params.set('from', from.format(DAY_FORMAT))\n if (to?.isValid()) params.set('to', to.format(DAY_FORMAT))\n if (format) params.set('format', format)\n return `${POS_DAY_REPORT_ROUTE}?${params.toString()}`\n },\n [hostId, from, to],\n )\n\n useEffect(() => {\n if (!user || !canManagePos) return\n let live = true\n setAnswer({ state: 'loading' })\n void (async () => {\n try {\n const response = await authorizedFetch(user as never, url(), { method: 'GET' })\n const body = (await response.json().catch(() => ({}))) as { report?: PosDayReport; error?: string }\n if (!live) return\n setAnswer(\n response.ok && body.report\n ? { state: 'ready', report: body.report }\n : { state: 'error', error: body.error || 'The day totals could not be read.' },\n )\n } catch {\n if (live) setAnswer({ state: 'error', error: 'The day totals could not be read. Check the connection.' })\n }\n })()\n return () => {\n live = false\n }\n }, [user, canManagePos, url])\n\n const report = answer.state === 'ready' ? answer.report : null\n const money = useCallback((cents: number) => formatReceiptMoney(cents, report?.currency ?? 'usd'), [report?.currency])\n const moneyColumn = useCallback(\n (field: string, headerName: string, minWidth = 110): GridColDef => ({\n field,\n headerName,\n type: 'number',\n minWidth,\n flex: 1,\n valueFormatter: (value: number | null | undefined) => (value == null ? '—' : money(value)),\n }),\n [money],\n )\n\n const tenderColumns = useMemo<GridColDef[]>(\n () => [\n { field: 'label', headerName: 'Tender', flex: 1, minWidth: 140 },\n moneyColumn('salesCents', 'Sales'),\n moneyColumn('refundsCents', 'Refunds'),\n moneyColumn('netCents', 'Net'),\n ],\n [moneyColumn],\n )\n const salesColumns = useCallback(\n (nameHeader: string): GridColDef[] => [\n { field: 'name', headerName: nameHeader, flex: 1, minWidth: 140 },\n { field: 'orderCount', headerName: 'Orders', type: 'number', minWidth: 90 },\n moneyColumn('grossSalesCents', 'Gross sales'),\n moneyColumn('tipsCents', 'Tips', 90),\n moneyColumn('refundsCents', 'Refunds'),\n moneyColumn('netSalesCents', 'Net sales'),\n ],\n [moneyColumn],\n )\n const registerColumns = useMemo(() => salesColumns('Register'), [salesColumns])\n const cashierColumns = useMemo(() => salesColumns('Cashier'), [salesColumns])\n const shiftColumns = useMemo<GridColDef[]>(\n () => [\n { field: 'registerName', headerName: 'Register', minWidth: 120, flex: 1 },\n {\n field: 'openedAtMs',\n headerName: 'Opened',\n minWidth: 140,\n valueFormatter: (value: number) => when(value),\n },\n {\n field: 'closedAtMs',\n headerName: 'Closed',\n minWidth: 140,\n // Open shifts sort after every closed one, by when they opened.\n valueGetter: (_value: unknown, row: Record<string, any>) =>\n row['closedAtMs'] ?? Number.MAX_SAFE_INTEGER - (row['openedAtMs'] ?? 0),\n renderCell: ({ row }: { row: Record<string, any> }) =>\n row['status'] === 'open' ? <Chip size=\"small\" color=\"success\" label=\"Open\" /> : when(row['closedAtMs']),\n },\n { field: 'openedByName', headerName: 'Opened by', minWidth: 130 },\n moneyColumn('openingFloatCents', 'Starting cash'),\n moneyColumn('netSalesCents', 'Net sales'),\n moneyColumn('expectedCashCents', 'Expected'),\n moneyColumn('countedCashCents', 'Counted'),\n {\n field: 'varianceCents',\n headerName: 'Variance',\n type: 'number',\n minWidth: 110,\n renderCell: ({ row }: { row: Record<string, any> }) =>\n row['varianceCents'] != null ? (\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color={row['varianceCents'] === 0 ? 'success' : 'warning'}\n label={money(row['varianceCents'])}\n />\n ) : (\n '—'\n ),\n },\n ],\n [moneyColumn, money],\n )\n\n const rows = useMemo(\n () =>\n report\n ? {\n tenders: report.byTender.map((row) => ({ ...row, $id: row.method })),\n registers: report.byRegister.map((row) => ({ ...row, $id: row.registerId || 'none' })),\n cashiers: report.byCashier.map((row) => ({ ...row, $id: row.memberId || 'none' })),\n shifts: report.shifts.map((row) => ({ ...row, $id: `${row.registerId}/${row.shiftId}` })),\n }\n : null,\n [report],\n )\n\n const exportCsv = async () => {\n if (!user || !report) return\n setExporting(true)\n try {\n const response = await authorizedFetch(user as never, url('csv'), { method: 'GET' })\n if (!response.ok) {\n const body = (await response.json().catch(() => ({}))) as { error?: string }\n setAnswer({ state: 'error', error: body.error || 'The spreadsheet could not be made.' })\n return\n }\n const blob = new Blob([await response.text()], { type: 'text/csv;charset=utf-8' })\n const href = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = href\n link.download = `day-totals-${report.from}${report.to === report.from ? '' : `-to-${report.to}`}.csv`\n link.click()\n window.setTimeout(() => URL.revokeObjectURL(href), 1000)\n } finally {\n setExporting(false)\n }\n }\n\n const print = () => {\n if (!report) return\n printPosDocument(posDayReportDocument({ report }))\n }\n\n const lastDay = from?.isValid() ? from.add(POS_DAY_REPORT_MAX_DAYS - 1, 'day') : undefined\n\n return (\n <CardDisplay\n header={HEADER}\n help={HELP}\n HeaderProps={{\n action: (\n <Stack direction=\"row\" spacing={1}>\n <Button size=\"small\" onClick={() => void exportCsv()} disabled={!report || exporting}>\n {'Export CSV'}\n </Button>\n <Button size=\"small\" onClick={print} disabled={!report}>\n {'Print'}\n </Button>\n </Stack>\n ),\n }}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2.5}>\n {!canManagePos ? (\n <Alert severity=\"info\">\n {'Day totals are for members who can use the register: a site admin or editor with the \"Use the point of sale\" permission.'}\n </Alert>\n ) : null}\n <LocalizationProvider dateAdapter={AdapterDayjs}>\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={1.5} sx={{ alignItems: { sm: 'center' } }}>\n <DatePicker\n label=\"From\"\n value={from}\n onChange={(value) => {\n setFrom(value)\n if (value?.isValid() && to?.isValid() && (to.isBefore(value) || to.diff(value, 'day') >= POS_DAY_REPORT_MAX_DAYS)) {\n setTo(value)\n }\n }}\n disabled={!canManagePos}\n slotProps={{ textField: { size: 'small' } }}\n />\n <DatePicker\n label=\"To\"\n value={to}\n onChange={setTo}\n {...(from?.isValid() ? { minDate: from } : {})}\n {...(lastDay ? { maxDate: lastDay } : {})}\n disabled={!canManagePos}\n slotProps={{ textField: { size: 'small' } }}\n />\n <Button\n size=\"small\"\n disabled={!canManagePos || (!from && !to)}\n onClick={() => {\n setFrom(null)\n setTo(null)\n }}\n >\n {'Today'}\n </Button>\n </Stack>\n </LocalizationProvider>\n {answer.state === 'loading' ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Adding up every register…'}\n </Typography>\n ) : null}\n {answer.state === 'error' ? <Alert severity=\"warning\">{answer.error}</Alert> : null}\n {report && rows ? (\n <>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`${posDayRangeLabel(report)} · ${report.timeZone} · every register and cashier`}\n </Typography>\n {report.truncated ? (\n <Alert severity=\"warning\">\n {'These days had more activity than one report reads; the figures are partial. Choose fewer days.'}\n </Alert>\n ) : null}\n {posDayReportIsEmpty(report) ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No register sales, returns or shifts on these days.'}\n </Typography>\n ) : (\n <>\n <Stack direction=\"row\" spacing={3} sx={{ flexWrap: 'wrap', rowGap: 1.5 }}>\n <CommerceStatTile label=\"Net sales\" value={money(report.totals.netSalesCents)} />\n <CommerceStatTile label=\"Gross sales\" value={money(report.totals.grossSalesCents)} />\n <CommerceStatTile label=\"Orders\" value={String(report.totals.orderCount)} />\n <CommerceStatTile label=\"Tips\" value={money(report.totals.tipsCents)} />\n <CommerceStatTile label=\"Tax\" value={money(report.totals.taxCents)} />\n <CommerceStatTile label=\"Discounts\" value={money(report.totals.discountsCents)} />\n <CommerceStatTile\n label={`Refunds (${report.totals.refundCount})`}\n value={money(report.totals.refundsCents)}\n />\n </Stack>\n <Section title=\"By tender\">\n <ListTable aria-label=\"Day totals by tender\" rows={rows.tenders} columns={tenderColumns} hideFooter noRowsLabel=\"No sales\" />\n </Section>\n <Section title=\"By register\">\n <ListTable aria-label=\"Day totals by register\" rows={rows.registers} columns={registerColumns} hideFooter noRowsLabel=\"No register sales\" />\n </Section>\n <Section title=\"By cashier\">\n <ListTable aria-label=\"Day totals by cashier\" rows={rows.cashiers} columns={cashierColumns} hideFooter noRowsLabel=\"No cashier sales\" />\n </Section>\n <Divider />\n <Section title=\"Cash drawers\">\n <DrawerRows report={report} money={money} />\n </Section>\n <Section title=\"Shifts\">\n {/* The one table that grows with the range: the grid pages it. */}\n <ListTable aria-label=\"Shifts on these days\" rows={rows.shifts} columns={shiftColumns} noRowsLabel=\"No shifts on these days\" />\n </Section>\n </>\n )}\n </>\n ) : null}\n </Stack>\n </CardDisplay>\n )\n}\n\n/**\n * Day totals (AGL-4037): beside the shift history, for a store with a\n * register, on a plan with the point of sale.\n */\nexport function PosDayTotalsCard(props: PosDayTotalsCardProps) {\n const firestore = useFirestore()\n // Whether the store has a register at all: the first by id is enough to\n // answer, and an id order drops no register.\n const { data: registers, status } = useFirestoreCollection<any>(\n () =>\n query(collection(firestore, 'hosts', props.hostId, 'registers'), orderBy(documentId()), limit(1)),\n [firestore, props.hostId],\n { idField: '$id' },\n )\n if (status === 'success' && !registers?.length) return null\n return (\n <EntitlementGatedCard\n hostId={props.hostId}\n feature=\"pos\"\n header={HEADER}\n help={HELP}\n upsell={'Totals for a day or an event across every register, shift and cashier come with the point of sale.'}\n >\n <PosDayTotalsBody {...props} />\n </EntitlementGatedCard>\n )\n}\n\nPosDayTotalsCard.displayName = 'PosDayTotalsCard'\n\nexport default PosDayTotalsCard\n"],"names":["pluginDocsHelp","CardDisplay","ListTable","authorizedFetch","useFirestore","useFirestoreCollection","useUser","Alert","Button","Chip","Divider","Stack","Typography","AdapterDayjs","DatePicker","LocalizationProvider","collection","documentId","limit","orderBy","query","useCallback","useEffect","useMemo","useState","posDayRangeLabel","posDayReportIsEmpty","posDayReportSections","POS_DAY_REPORT_MAX_DAYS","POS_DAY_REPORT_ROUTE","formatReceiptMoney","escapeHtml","CommerceStatTile","EntitlementGatedCard","POS_RECEIPT_STYLES","printPosDocument","HEADER","HELP","anchor","DAY_FORMAT","when","ms","Date","toLocaleString","month","day","hour","minute","posDayReportDocument","input","money","cents","report","currency","body","map","section","toUpperCase","rows","row","strong","label","value","join","storeName","DrawerRows","props","drawers","find","spacing","direction","sx","justifyContent","gap","variant","color","fontVariantNumeric","Section","title","children","PosDayTotalsBody","hostId","canManagePos","data","user","from","setFrom","to","setTo","answer","setAnswer","state","exporting","setExporting","url","format","params","URLSearchParams","isValid","set","toString","live","response","method","json","catch","ok","error","moneyColumn","field","headerName","minWidth","type","flex","valueFormatter","tenderColumns","salesColumns","nameHeader","registerColumns","cashierColumns","shiftColumns","valueGetter","_value","Number","MAX_SAFE_INTEGER","renderCell","size","tenders","byTender","$id","registers","byRegister","registerId","cashiers","byCashier","memberId","shifts","shiftId","exportCsv","blob","Blob","text","href","URL","createObjectURL","link","document","createElement","download","click","window","setTimeout","revokeObjectURL","print","lastDay","add","undefined","header","help","HeaderProps","action","onClick","disabled","contentGutterX","contentGutterY","severity","dateAdapter","xs","sm","alignItems","onChange","isBefore","diff","slotProps","textField","minDate","maxDate","timeZone","truncated","flexWrap","rowGap","totals","netSalesCents","grossSalesCents","String","orderCount","tipsCents","taxCents","discountsCents","refundCount","refundsCents","aria-label","columns","hideFooter","noRowsLabel","PosDayTotalsCard","firestore","status","idField","length","feature","upsell","displayName"],"mappings":"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"}
|