Commit graph

42 commits

Author SHA1 Message Date
ac1b371722 Add iOS install hint + Apple PWA meta tags
iOS Safari has no beforeinstallprompt API, so the portal's Install
button (?install=1) silently did nothing there. IosInstallHint now
shows Share -> Add to Home Screen steps on Safari, or a prompt to
switch to Safari first if opened in another iOS browser/in-app
webview (those can't install PWAs on iOS at all).

Also added apple-mobile-web-app-title + apple-touch-icon so the
home screen icon isn't a page screenshot.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 14:12:12 +00:00
73d2c713d4 Fix F&B last-7-days fill to span month boundary
"Fill F&B from last 7 days" only drew from the current month's elapsed
days, so early in a month (e.g. the 3rd) it only had 1-2 actual days to
repeat instead of a true trailing 7-day window. Add a dedicated
last7-fnb endpoint that fetches a real 7-day window ending yesterday,
reaching back into the prior month when needed.
2026-08-03 09:31:08 +00:00
d1c50c77d0 Fix NewBook reports using invented bookings_list params and field names
Arrivals, departures, stayovers, and bookings-by-source were sending
request params (arrival_date_from, departure_date_from, stayover_date_from)
and reading response fields (arrival_date, booking_ref, no_nights) that
don't exist in NewBook's API — causing API errors. Switched to the real
bookings_list contract (period_from/period_to/list_type) and field names
(booking_arrival, booking_departure, reference, booking_length, etc.)
already proven working in room-planner, hvac, and kitchen's integrations.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 10:32:22 +00:00
51b6142651 Scope PWA manifest to app's own path instead of origin root
Every installed PWA claimed scope "/", so Android link-capturing routed
navigation for any app on the shared origin into whichever PWA had it.
2026-07-29 13:47:15 +00:00
1efcc941bb Switch Utilities table to per-meter rows, add 12-month trend charts
Table now matches the format used elsewhere in the app: one row per
meter (Consumption/Usage/Standing/Extras/VAT/Total/Basis/Period
Estimate) instead of a category rollup, mirroring the utilities app's
own Reports/Estimates pages (basis text, merged extras column).

Adds two charts below the table: total utility cost (this year vs
prior year) and one small per-category consumption chart (this year
vs prior year), both fed by the new /api/internal/trend endpoint,
aligned to the report's own month so paging to an older week shows
the right trailing-12-month window rather than today's.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 14:59:18 +00:00
0afecc2e24 Fix 404 calling utilities internal API — route through nginx slug prefix
The utilities app's backend isn't published to the host, only its
nginx frontend on :3080. Its internal.js routes are mounted at bare
/api/internal/... with no slug prefix, so callers must go through the
/utilities/api/ nginx location (which strips the prefix and forwards
to the backend's /api/... path) rather than hitting /api/internal/...
directly — the latter has no matching nginx location and 404s.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 14:48:12 +00:00
203639af78 Configure utilities API creds via Settings UI, not .env
Follows the same app_settings/DB pattern already used for the
Forecasting integration: utilities_url and utilities_api_key are now
editable from Reports Settings, with env vars kept only as a fallback.
Avoids needing to SSH in and hand-edit .env to authenticate against
the utilities app's internal API.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 14:38:15 +00:00
dfd3a506d1 Wire real utility cost data into Weekly Actuals report
Replaces the Utilities placeholder with a cost-breakdown table by
category (usage/standing/CCL/RAB levy/fixed extras/VAT/total) sourced
from the utilities app's internal API, plus a projected-total note for
the current month. Mirrors the existing forecasting integration
pattern (best-effort fetch, doesn't break the rest of the report on
failure). Also adds the missing UTILITIES_URL/UTILITIES_API_KEY env
vars to docker-compose.yml, needed by both this and the pre-existing
directors-forecast integration.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 14:32:48 +00:00
932302ebe2 Fix directors forecast report counting stale pickup for past days
The report endpoint's totalPickup/totalRooms summed every day's
pickup override regardless of whether the day had already passed,
even though a past day's actual accommodation revenue already
supersedes it (fAccomm ignores pickup for those days). This
overstated Probable Pickup and the month's rooms estimate. Also
fixed pickup.accomm to sum each day's own rate instead of
multiplying the total by a flat session rate.
2026-07-27 16:38:53 +00:00
9e9e1d7400 Pull utilities readings/costs/estimate into Directors Forecast report
Adds a utilities-client.js mirroring the existing forecasting-client
HTTP pattern (UTILITIES_URL/UTILITIES_API_KEY). Directors report
response gains a separate `utilities` field; degrades gracefully with
an error string if the utilities app is unreachable or unconfigured.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 17:33:35 +00:00
21224c0ebe Fix session-expiry redirect breaking standalone PWA out of its shell
Same fix as maintenance/room-planner: manifest scope was the app's
own base path instead of "/", and AuthGate unconditionally hard-
navigated window.top to the central /login on session expiry even
when not embedded in the portal iframe — together these dropped an
installed/standalone reports PWA into the portal's framed browser
view instead of staying in its own window.

AuthGate now only bounces to central login when actually embedded
(passing ?from= so it returns here afterwards); standalone or
directly-opened tabs get an in-app login form and never navigate
away. Also wired up the previously-dead inactivity auto-logout timer.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 17:07:00 +00:00
2f335c99c5 Save computed forecast dry/wet on worksheet save; report reads saved values
Worksheet save now persists forecast_dry/forecast_wet per day to day_overrides
so the report page always shows the same totals the user saw on the worksheet,
rather than making a second independent forecasting API call that can return
slightly different values.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 19:07:29 +00:00
9530125509 Add DOW-aligned LY toggle to directors forecast worksheet and report
Checkbox in the header switches between 364-day same-weekday comparison
and same calendar-date last year. Default remains DOW-aligned.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 18:29:02 +00:00
2e8a908f05 Hide pickup cell value for past days in directors forecast worksheet
Past dates already excluded from pickup calculation; suppress display to
avoid giving the impression the stored override is still active.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 17:52:38 +00:00
293eb4c6e7 Rename ML± column to Pickup± in directors forecast worksheet
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 17:47:42 +00:00
e9899ce7d5 Fix worksheet past-date display: pickup, dry/wet, and room cap
Past dates: zero out pickup (override ignored), use actuals for dry/wet
(fall back to override/forecast only if no actual exists), lock dry/wet
inputs read-only. Pickup + OTB total is now capped at available rooms
so occupancy can't exceed 100%. Totals row also excludes past pickup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 17:33:09 +00:00
53a631fe93 Apply desktop viewport to WeeklyActual and report view; responsive on welcome screen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 09:08:26 +00:00
3a8661127a Add useFrameViewport hook; apply desktop mode to DirectorsForecast
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 09:00:35 +00:00
e02e558e81 Revert viewport to device-width — burger menu handles mobile nav
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 08:54:51 +00:00
7cf6f14aeb Add burger menu to mobile top-bar — sidebar slides in with backdrop overlay
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-21 08:36:54 +00:00
552c11864d Force desktop viewport (width=1280) — info-heavy display not suited to responsive layout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 23:15:55 +00:00
99da231b29 Add .gitignore and remove tracked node_modules/dist
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 14:38:40 +00:00
1c411e402e Add settings page for managing forecasting API key and URL via UI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 14:37:36 +00:00
cae411eae7 Add Fill F&B from last 7 days button to worksheet toolbar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 14:22:00 +00:00
b40bf96263 Fix print layout — keep side-by-side charts in columns
Removed display:block override on .wa-charts-row; charts that sit
two-per-row on screen now do the same on paper instead of stacking.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 14:10:09 +00:00
ffa13d6e57 Restructure weekly actuals charts — Sales History section + month cumulative
Backend:
- Always fetch full calendar month (not truncated at week ending)
- Add month_daily[] to response (per-day TY/LY by dept, is_actual flag)

Frontend:
- New 'Sales History' section with:
  - Monthly dept line chart: 12-month x-axis, TY vs prior year per dept
    (Rooms/Dry/Wet solid, LY dashed — same colour per dept)
  - Rolling 12-month average trend (moved from Month Progress)
- Month Progress section gains cumulative line chart:
  - X-axis = day of month, 6 lines (3 TY solid + 3 LY dashed)
  - TY lines stop at week ending; LY spans full month

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 14:03:51 +00:00
7f0d1057c1 Fix print layout for weekly actuals report
- Override overflow:hidden on .page-content and .app-shell so the full
  report flows to paper instead of clipping at screen height
- break-inside:avoid on each section so they land whole on a page
- Charts stack vertically on print (full width each) rather than 2-col grid
- Hide sidebar, toolbar; reset backgrounds and shadows for clean output

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 13:53:09 +00:00
6a2990b34e Add 24-month dept split chart below rolling trend
Stacked bar chart (Rooms/Dry/Wet) for the previous 12 months and last
12 months side by side, with a reference line marking the boundary.
No extra API calls — data comes from the existing 36-month fetch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 13:49:15 +00:00
4744e74dfa Fix week nav arrows — use local date string to avoid BST offset bug
toISOString() returns UTC, so midnight local in BST (UTC+1) lands on
the previous UTC day, making each arrow step 6 days instead of 7.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 13:45:50 +00:00
8da7e46d72 Fix monthly trend chart — rolling 12-month average with LY comparison
Replace raw monthly totals with a proper rolling 12-month average trend.
Fetches 36 months of data; the 12 display points each show the average
of the 12 months ending on that point (TY) and the same window shifted
back a year (LY), producing a smooth upward trend vs last year.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 13:38:59 +00:00
b97358e9fb Add Weekly Actuals directors report with charts
Full weekly actuals report matching the spreadsheet layout:
- Week summary table (Rooms/Dry/Wet vs Budget vs Last Year vs Last Week)
- Grouped bar chart + dept split pie chart
- 5-week rolling summary table
- Occupancy table by day of week (rooms, occ%, ARR, RevPAR)
- Month progress to date (totals + dept split) with progress bar chart
- 12-month turnover trend line chart by dept
- Utilities placeholder (pending meter readings app)

Budget values come from the forecasting API which distributes monthly
budget proportionally to daily sales — so high-demand weeks (e.g.
Christmas) carry a higher budget share. Gross shown as net × 1.20.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 13:07:19 +00:00
29a119f51d Vertical tab order on worksheet override inputs (pickup → dry → wet columns)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 12:42:32 +00:00
822ce2f970 Use per-day available_rooms from forecasting API (overflow excluded)
Switch from a single total_rooms scalar to rm.available_rooms per day,
now that the forecasting public API returns it from daily_occupancy.
Fixes worksheet Avail column showing 80 (total physical beds) instead
of the correct occupancy-reportable room count.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 10:51:58 +00:00
fc903564fb Fix TypeScript types on Directors Forecast API functions
Add explicit generic return types to dfGetWorksheet/dfSaveWorksheet/
dfGetReport so TypeScript can infer the response shape in the component.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 10:37:09 +00:00
bd9ddbeda9 Switch Directors Forecast to use forecasting API instead of direct DB
Replace queryForecast/forecast-db.js with fetch() calls to the
forecasting app's public API (/forecasting/api/public/forecast/revenue
and /forecast/rooms). This removes the need for cross-DB grants and the
FORECAST_DATABASE_URL — all data comes from FORECASTING_API_KEY +
FORECASTING_URL. The DOW-history algorithm is also removed since the
covers model in the forecasting API already handles dry/wet future
forecasts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 10:36:08 +00:00
018957123f Add Directors Forecast interactive report section
Embeds a Directors Forecast section in the Reports sidebar (hard-coded
under "Directors Reports"). Worksheet tab: day-by-day OTB grid with
editable pickup rooms, dry/wet overrides, ML suggestion column and live
forecast recalculation. Report tab: forecast vs budget vs last-year
comparison, occupancy summary, weekly revenue bands and snapshot tracking.

Backend: forecast-db.js (read-only pool to forecasting_db), new tables
(forecast_sessions, day_overrides, forecast_snapshots) and full REST
routes under /api/directors-forecast. docker-compose FORECAST_DATABASE_URL
added.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-20 10:24:47 +00:00
92e2c48f48 Sync shared components — sidebar scrollbar, Layout, AuthGate updates
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-14 12:07:11 +00:00
da6d50ff95 Add shared device inactivity timeout to AuthGate 2026-07-13 11:53:06 +00:00
df3aec7bc5 Replace letter icons with Lucide PWA icons 2026-07-11 20:30:13 +00:00
e9f1d4fdea Make reports installable as a PWA
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-11 11:27:01 +00:00
803332e6a3 Fix expired session showing EmbeddedFallback instead of login page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-10 11:44:01 +00:00
0511ac8d82 Scaffold custom reports app (LXC 122 · /reports)
Framework for categorised custom reports pulling from NewBook, ResOS,
SambaPOS, and internal data. Report tree with collapsible categories
and subcategories; date-range params; run-audit log in reports_db.

Initial reports: NewBook arrivals/departures/stayovers/bookings-by-source,
ResOS covers/revenue, SambaPOS sales-summary/top-products, internal run-history.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-06 12:58:19 +00:00