Commit Graph

175 Commits

Author SHA1 Message Date
d6bb46a67f feat: show maintenance note in history card expanded details
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 23:35:47 +03:00
8e6d66bef8 feat: minibar category rename + history card checklist/minibar details
- MinibarSettingsPage: Категории section — inline rename updates all items
- HistoryCard: expand button loads checklist + minibar on demand
- Minibar ✓ badge shown on history cards when minibarChecked

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 23:27:30 +03:00
d98389e2bc feat: enforce checklist/minibar completion before marking task done
- ApiError now carries errors[] array from 422 responses
- updateStatus re-throws 422 so TaskCard can surface errors
- TaskCard: minibarCheckedLocal state + 'Подтвердить проверку минибара' button
- TaskCard: async handleComplete with completionErrors display
- Backend validation errors shown inline in completion panel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 23:09:03 +03:00
3c1a6ccebf feat: checklists, minibar and deposit modules
- DB migrations 057-059: checklist_templates/items/completions, minibar_items/consumptions, hotel_deposit_settings, booking_deposits
- Backend routes: checklists (templates CRUD + task completions), minibar (items + consumptions), deposit (settings, cash/yookassa hold, release/capture)
- YooKassa service for hold/capture/cancel payments
- Frontend: ChecklistSettingsPage, MinibarSettingsPage, DepositSettingsPage
- HousekeepingPage: task cards now show checklist + minibar panel with checkboxes and quantity buttons
- BookingModal: minibar charges summary + deposit management (cash/YooKassa/release) for existing bookings
- Sidebar + App.tsx: new routes /settings/checklists, /settings/minibar, /settings/deposit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:24:53 +03:00
ed2dfd4c7f feat: TTLock UI — toast notifications, edit mappings, sector grid 2x8
- Floating toast notifications (top-center, auto-dismiss 4s) instead of
  inline alerts in section 2 — visible regardless of scroll position
- Edit button on each lock mapping (inline form, supports MAC/room/name change)
- Sector picker: 2 rows of 8 (grid-cols-8), removed "Обычно 1–10." hint
- Removed API server selector (always EU, hardcoded in save)
- Removed buildNo/floorNo fields from UI (backend defaults to 1)
- Renamed "Проверить API" → "Проверить подключение"
- Save COM-port button: HardDriveDownload → Save (floppy disk) icon
- Removed debug-only Terminal and Search buttons from workstations row
- Unmap now deletes by MAC (consistent with edit flow)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 18:58:33 +03:00
1ad2a8057a feat: TTLock — correct DLL flow with buildNo/floorNo per lock
Backend: room-locks now store/return build_no, floor_no (required by
CE_WriteCard). issue-card passes buildNo/floorNo to agent instead of
cardSectors/username/password. testApi route simplified (no OAuth).

Frontend: remove username/password fields (not needed), add buildNo/floorNo
fields to lock mapping form, show building/floor in lock list.

Migration 056: adds build_no, floor_no columns to room_lock_mappings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 11:59:38 +03:00
8c215f2dcd feat: TTLock — add Учетная запись + Пароль fields for OAuth
Per Sciener docs: OAuth requires TTHotel account credentials (Учетная запись + Пароль)
separate from developer app client_id/client_secret.

- Migration 055: add ttlock_username, ttlock_password columns
- Backend: store and pass new fields to agent
- UI: add input fields matching TTHotel PMS integration page
- Agent: getAccessToken() uses ttlockUsername/ttlockPassword when provided

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 11:46:30 +03:00
a7b59c4881 fix: TTLock — revert to 2-field credentials, improve UI hints
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 11:38:07 +03:00
84ead2af99 fix: TTLock — correct OAuth server (api.sciener.com) and API servers (euapi/cnapi)
- OAuth token: always https://api.sciener.com/oauth2/token (was euopen.ttlock.com = wrong)
- EU API: https://euapi.ttlock.com/v3/... (was euopen.ttlock.com)
- CN API: https://cnapi.ttlock.com/v3/... (was open.ttlock.com)
- Migration 054: update existing DB records with old server URLs
- UI: update radio button values to correct server names

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 11:21:37 +03:00
ee7e515f61 feat: TTLock — scan TTHotel sources for API config (CE_ConfigServer)
- Agent: ttlock:find_api_config command scans TTHotel app JS files
  for CE_ConfigServer calls, oauth2 endpoints, API server URLs
- Backend: POST /ttlock/find-api-config route
- UI: Search button on each workstation row to trigger scan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 11:10:40 +03:00
92821a8436 fix: replace Wifi icon with Globe for TTLock API test button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 00:48:04 +03:00
54469e7ad1 feat: TTLock diagnostics — test cloud API button + fix api_server SELECT bug
- Fix: api_server was missing from SELECT in issue-card route (always fell back to EU default)
- Add "Проверить API" button in Step 1 that calls ttlock:test_api via agent
- Agent: testCloudApi() — gets OAuth token + lists locks, returns count
- Agent: apiPost() now includes response body in error message (was just HTTP status)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 00:45:32 +03:00
a986470f8e feat: TTLock API server selector (EU vs China) + pass apiServer to agent
- Add api_server column to hotel_ttlock_config (migration 053)
- GET/PATCH config includes apiServer field
- issue-card passes apiServer to agent command
- Agent: WriteCardCmd.apiServer optional, all API calls use it
- TTLockPage: radio buttons EU/China with hint about 404 error

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:48:37 +03:00
1da3373f29 fix: xlsx static import + type cast for TS build
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:16:38 +03:00
1ec3664886 feat: TTLockPage — import locks from TTHotel XLS file
- Parse .xls/.xlsx via SheetJS (xlsx package)
- Auto-match Door Name → room number; unmatched rows kept with empty room
- Preview table: green=matched, amber=unmatched, grey=already mapped
- Per-row room dropdown for manual correction before import
- room_id nullable in room_lock_mappings (migration 052)
- Conflict key changed from (hotel_id, room_id) to (hotel_id, lock_mac)
- LEFT JOIN in GET room-locks to show unmatched locks
- DELETE by UUID or MAC depending on whether room is assigned

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:08:24 +03:00
ea63dec525 fix: TTLockPage — move alerts to workstations section
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 22:56:09 +03:00
061fc165b5 feat: TTLock page redesign — sector circles, COM dropdown, DLL diagnostics
- SectorPicker: circles 1–16, click to toggle (blue=selected, gray=not)
- COM port: dropdown populated from agent's serial ports list + refresh button
- Per-workstation buttons: HardDriveDownload (save), Zap (test encoder)
- Workstations without COM port shown as dimmed with amber 'Энкодер не настроен'
- DLL entry point error shown with hint to check TTHotel libs/index.js
- Backend: GET /ttlock/dll-info?workstation_id= → reads TTHotel index.js via agent
- api.ts: added dllInfo() call

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 22:11:22 +03:00
f837a84db5 feat: TTLock encoder per workstation (Option A)
- Migration 051: add ttlock_com_port to workstations, drop com_port/workstation_id from hotel_ttlock_config
- Backend workstations PATCH: accepts ttlock_com_port alongside name
- Backend ttlock: test/issue-card use per-workstation com_port; auto-select online encoder if workstationId not specified
- TTLockPage Step 2: per-workstation table with COM port input, Save, Test buttons per row
- BookingDetailPanel: auto-issue if 1 encoder online, picker modal if multiple
- api.ts: TTLockConfig/Update cleaned up, Workstation gets ttlockComPort, issueCard/testEncoder updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 23:40:29 +03:00
948744e077 feat: tariff selector in BookingModal
- Migration 050: add tariff_id FK to bookings table
- Backend: accept tariff_id in POST/PATCH bookings
- Frontend: load active tariffs in BookingModal, show tariff dropdown
- Price calculation applies tariff modifier (percent or fixed) before discount
- tariffId forwarded through CalendarPage → api.bookings.create/update

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 21:02:56 +03:00
249492cf3a feat: TTLock settings redesign — correct TTHotel DLL architecture
- Settings page rebuilt with 3-step flow:
  Step 1: client_id / client_secret (from TTHotel → Settings → Integrations)
  Step 2: workstation + COM port + card sectors
  Step 3: room → lock MAC address mapping (from lock.ttlock.com)
- Agent command ttlock:write_card now uses lockMac, comPort, cardSectors
  instead of cloud-only lockId approach
- New agent command ttlock:ping_encoder for encoder connectivity check
- Migration 049_ttlock_v2.sql: lock_mac TEXT replaces lock_id BIGINT,
  card_sectors + com_port added, ttlock_username/password removed
- API types updated: TTLockConfig, RoomLockMapping, CardIssuance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 16:29:30 +03:00
be92d026e8 feat: TTLock integration + fix agent offline status
- Add TTLock electronic lock module: settings page, room-lock mapping,
  card issuance via agent command (ttlock:write_card)
- Fix agent offline: EquipmentPage now polls every 30s + reacts to
  workstation:online/offline WebSocket events instantly
- Backend broadcasts workstation online/offline events to hotel clients
  via existing WebSocket (agent-ws.ts)
- New DB migration 048_ttlock.sql: hotel_ttlock_config, room_lock_mappings,
  card_issuances tables
- New backend routes: GET/PATCH ttlock/config, POST ttlock/token,
  GET ttlock/locks, POST/DELETE ttlock/room-locks, POST issue-card
- "Выдать ключ (TTLock)" button in BookingDetailPanel for confirmed/checked_in
- TTLock page added to sidebar under Настройки

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 15:46:17 +03:00
7a3772d1cf fix: add error handling and loading state to tariff save 2026-03-31 11:36:46 +03:00
f6d3c78dd0 feat: rental drafts, room modal cleanup, tariff auto-code
- New hotels get 3 rental object templates (tennis/sauna/conference) as drafts (is_active=false)
- RentalPage: draft templates shown separately with Activate/Delete buttons
- Migration 047: adds is_active column to rental_objects
- RoomModal: hide bed type/status/housekeeping in create mode; optional price (from category); restructured Places tab with extra beds constructor
- TariffsPage: auto-generate tariff code from name initials if code field is empty
- types: ExtraPlace.beds for extra place bed configuration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 11:19:54 +03:00
1970afdd13 fix: registration form — phone mask, required fields, snake_case body
- Address and phone now required (frontend + backend)
- Phone input mask: +7 (XXX) XXX-XX-XX
- Fix Bad Request: register body now sends snake_case keys
  (req() converts camelCase→snake_case, backend schema updated to match)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 11:23:24 +03:00
0088457f51 feat: add WiFi authorization module
- Backend: hotel_wifi_settings table (migration 046), CRUD routes
- Public API endpoint /api/wifi-auth/verify for captive portal
- Auth methods: room+lastname, room+birthdate, room+any, room_only
- Frontend: WiFiPage with settings, token management, setup guide
- Guide tabs: MikroTik, UniFi, Universal with copy-paste instructions
- Sidebar: WiFi item in Settings group

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 12:08:51 +03:00
46524077a0 fix: collapse ping section by default, expand on click
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 10:39:18 +03:00
a443ec9d28 fix: hide reconnect button when agent is online; add printer encoding/paper_width settings
- WorkstationCard: show RefreshCw reconnect only when agentId set but offline
- DeviceForm: add encoding (utf8/cp866) and paper_width fields for network printers
- Backend: pass device.config in test_device command to agent

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 10:31:17 +03:00
11300bccbf feat: ping through agent — send ICMP ping from workstation via agent
Adds a ping tool in the Equipment page workstation card (visible when
agent is online). User enters an IP/hostname, the request goes through
the PMS backend → WebSocket → agent → executes ping -n 4, returns
raw output displayed in a monospace block.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 10:08:38 +03:00
ad01bc7f4d feat: auto-close pair modal on agent connect, center close button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 17:07:50 +03:00
471fc17ce8 fix: equipment buttons uniform height, trustProxy for real client IP
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 16:35:04 +03:00
fa32da8034 fix: hide COM-port selector for KKT devices (uses DTO web service, not COM)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 23:34:59 +03:00
0dfcd7f33f fix: read camelCase config keys from API response (dto_pass, dto_user, etc.)
transformKeys converts all nested JSONB keys to camelCase, so reading
dto_pass from config returned undefined, falling back to default '30'.
Now reads dtoPass (camelCase) with dto_pass as fallback for compatibility.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 23:31:58 +03:00
bf785b763f fix: hide NetUP server URL field in agent mode, derive from device config
- TvWelcomePage: hide server URL input when connection_type=agent
- Test button enabled in agent mode without serverUrl
- Backend test endpoint: derive server_url from workstation netup device
- getNetupCfg: resolve URL from netup device in agent mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 21:06:33 +03:00
ccd366a5ad fix: equipment name refresh, hostname sync from agent hello
- WorkstationCard: useEffect to sync name state when ws.name prop changes
- agent-ws: update hostname column on hello message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 20:29:27 +03:00
0e51f8326a fix: COM ports stale closure bug, remove USB printer option
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 18:41:46 +03:00
1358dda7f9 feat: Equipment page — KKT hides connection, Windows printer, COM retry; agent update banner
- EquipmentPage: KKT hides USB/COM/Network buttons (DTO handles connection)
- EquipmentPage: Printer adds Windows connection type — lists installed printers from agent
- EquipmentPage: COM port section has retry button (↺)
- api.ts: add listPrinters, extend connection type
- workstations.ts: add /printers endpoint (list_printers command)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 18:30:06 +03:00
13dac3f227 fix: EquipmentPage TS errors — stray bracket and testDevice return type
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 18:08:47 +03:00
69f0a051a7 feat: KKT dto_device_id — multiple KKTs per DTO instance
- EquipmentPage: added "ID устройства в ДТО" field (config.dto_device_id),
  shown on device card as #1
- api.ts: typed config.dto_device_id in WorkstationDevice

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 17:29:26 +03:00
c081ab5c74 feat: configurable DTO login/password per KKT device
- Equipment page: add login/password fields in KKT fiscal mode form
- Stored in device config JSON (dto_user, dto_pass)
- Backend passes credentials to agent in test_device command
- Agent uses per-device credentials for all ATOL DTO API calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 16:20:36 +03:00
8eb83a5189 fix: NetUp device form — hide purpose/USB/COM, auto-select network
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 15:03:09 +03:00
be311a2b30 fix: download button always visible; KKT test shows DTO setup instructions
- Download button shows even without latest release (grayed out state)
- KKT test error "ДТО не запущен" now shows 3-step setup guide with atol.ru link

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 14:39:00 +03:00
f882cb2481 feat: KKT fiscal/non-fiscal mode, multi-KKT per workstation, DTO port per device
- Migration 045: fiscal_mode + dto_port columns on workstation_devices
- Backend: pass fiscal_mode/dto_port to agent in test_device command
- Agent atol.ts: remove global DTO singleton, accept dtoPort per function call
- Agent test_device: returns real KKT info (model, serial, FN, shift status)
- Equipment page: fiscal/non-fiscal toggle + DTO port field when adding KKT
- Equipment page: show fiscal mode badge on device card, DTO port if non-default
- Equipment page: KKT test result shows model, serial, FN, shift status

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 14:06:44 +03:00
2caf717131 feat: NetUP via agent — proxy HTTP requests through Windows workstation
- Migration 044: add connection_type + agent_workstation_id to netup_settings
- Backend: netupReqViaCfg routes requests via agent WebSocket when connection_type=agent
- Agent: add netup_request command handler (proxies HTTP to local NetUP server)
- TvWelcomePage: add connection mode toggle (direct / via agent) + workstation selector
- Hint changes: URL placeholder shows local IP when agent mode selected

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 13:53:55 +03:00
0cce5f566f feat: agent version tracking, update button, device test, COM port list
- Migration 043: agent_version in workstations, netup device type
- agent-ws: sendCommandAndWait for async commands, save version on hello
- workstations route: list-ports, test-device, update, update-all endpoints
- agent-release route: GET /api/agents/latest-release reads latest.yml
- app.ts: serve /agent-updates/ static files
- api.ts: fix camelCase→snake_case for outgoing requests (fixes null:null)
- api.ts: new methods testDevice, sendUpdate, updateAll, listPorts
- EquipmentPage: version badge, update button, test (zap) button per device
- EquipmentPage: COM-port dropdown loaded from agent when online

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 13:05:23 +03:00
b2b2034f4c feat: COM-port support for workstation devices + agent UI fixes
- EquipmentPage: add COM-port connection type with port field (COM1, /dev/ttyUSB0)
- api.ts: add comPort field to WorkstationDevice type
- workstations route: pass com_port to INSERT/PATCH
- migration 042: extend connection check constraint to include 'com', add com_port column
- agent index.html: highlight first cell on load, reset input on unpair

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 12:41:31 +03:00
ee7ee78c5d fix: pair code modal — auto-regenerate on expiry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 11:28:25 +03:00
72f8582e97 fix: pair code timer — expiresAt camelCase after snake→camel transform
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 11:11:41 +03:00
4cfa98d7f0 fix: EquipmentPage — input class, code modal layout (no wrapping)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 10:47:08 +03:00
239846c077 fix: TS errors — EquipmentPage purpose cast, PosPage NodeJS.Timeout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 23:18:51 +03:00
fbb06265f9 feat: касса — полная переработка PosPage + интеграция с агентом
- PosPage.tsx: полный редизайн вокруг реальной кассовой работы
  • Автодетект агента (localhost:9000), статус смены каждые 15с
  • Экраны: агент не подключён / смена закрыта / смена истекла / касса
  • Шапка смены: №, длительность, остаток наличных, статус ОФД
  • Кнопки: X-отчёт, Внести/Изъять наличные, Закрыть смену
  • Левая панель: гости с балансом + быстрые услуги
  • Правая панель: чек с количеством, итого, выбор наличные/карта
  • Экран успеха после пробития чека с номером ФД
- agent.ts: клиент localhost:9000 — identity + все kkt операции
- index.css: btn-danger класс

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 18:55:12 +03:00