diff --git a/docs/changelog.md b/docs/changelog.md index b69c54c6..8fc404ba 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [Unreleased] +### Work In Progress +- **Allow Multiple Terminal Logins (experimental)** (2026-04-12) + - Added a persisted soft-switch `allow_multi_login` (bumped `SETTINGS_VERSION` to 107) which allows the same `Employee` to be logged into multiple terminals when enabled. + - Exposed a new Settings switch **Allow Multiple Logins** in the Settings UI (toggles and persists immediately). + - Login logic updated so `Terminal::LoginUser` and login UI checks consult `settings->allow_multi_login` before rejecting a login for a user already online. + - Files modified: `main/data/settings.hh`, `main/data/settings.cc`, `main/ui/labels.cc`, `zone/settings_zone.cc`, `main/hardware/terminal.cc`, `zone/login_zone.cc`. + - NOTE: This feature is experimental and a work in progress — bugs are likely. Use with caution and report any issues you encounter. + ### Fixed - **Auto-Update vt_data: Prevent automatic updates when disabled (2026-04-09)** - Fixed unexpected vt_data downloads/updates triggered when restarting or shutting down from non-server displays even when "Auto-Update vt_data on Startup" is OFF. diff --git a/main/data/settings.cc b/main/data/settings.cc index a1251b88..1b4b1347 100644 --- a/main/data/settings.cc +++ b/main/data/settings.cc @@ -1459,6 +1459,7 @@ Settings::Settings() expire_message3.Set("541-515-5913"); expire_message4.Set(""); allow_multi_coupons = 0; + allow_multi_login = 0; cc_print_custinfo = 0; for (i = 0; i < MAX_CDU_LINES; i++) @@ -2132,6 +2133,8 @@ int Settings::Load(const char* file) df.Read(report_start_midnight); if (version >= 79) df.Read(allow_multi_coupons); + if (version >= 107) + df.Read(allow_multi_login); if (version >= 82) df.Read(allow_iconify); if (version >= 96) @@ -2527,6 +2530,7 @@ int Settings::Save() df.Write(cc_bar_mode); df.Write(report_start_midnight); df.Write(allow_multi_coupons); + df.Write(allow_multi_login); df.Write(allow_iconify); df.Write(use_embossed_text); df.Write(use_text_antialiasing); diff --git a/main/data/settings.hh b/main/data/settings.hh index 65d85ffa..14bf1090 100644 --- a/main/data/settings.hh +++ b/main/data/settings.hh @@ -30,7 +30,7 @@ // NOTE: WHEN UPDATING SETTINGS DO NOT FORGET that you may also // need to update archive.hh and archive.cc for settings which // should be maintained historically. -constexpr int SETTINGS_VERSION = 106; // READ ABOVE +constexpr int SETTINGS_VERSION = 107; // READ ABOVE /**** Definitions & Data ****/ @@ -166,6 +166,7 @@ enum DrawerMode : std::uint8_t { #define SWITCH_F3_F4_RECORDING 32 // whether to enable F3/F4 recording/replay feature #define SWITCH_AUTO_UPDATE_VT_DATA 33 // whether to automatically download vt_data on startup #define SWITCH_BUTTON_IMAGES 34 // toggle showing images on buttons +#define SWITCH_ALLOW_MULTI_LOGIN 35 // allow same user to login on multiple terminals #define MOD_SEPARATE_NL 1 // New line #define MOD_SEPARATE_CM 2 // Comma @@ -624,6 +625,9 @@ public: int split_check_view; // default to item or seat list for SplitCheckZone? int allow_multi_coupons; + // Allow same employee to be logged into multiple terminals when set + int allow_multi_login; + // allow_user_select is primarily for ExpenseZone, but may be used elsewhere int allow_user_select; // yes == user selection, no == force term->user diff --git a/main/hardware/terminal.cc b/main/hardware/terminal.cc index c4aa40de..3d0446cc 100644 --- a/main/hardware/terminal.cc +++ b/main/hardware/terminal.cc @@ -2043,7 +2043,16 @@ int Terminal::LoginUser(Employee *employee, bool home_page) if (AllowLogins == 0) return 1; - if (employee == nullptr || (user != employee && parent->IsUserOnline(employee))) + if (employee == nullptr) + return 1; + + // Check whether multiple logins are allowed via settings + Settings *s = GetSettings(); + int allow_multi = 0; + if (s) + allow_multi = s->allow_multi_login; + + if (user != employee && parent != nullptr && parent->IsUserOnline(employee) && !allow_multi) return 1; // User already online on another terminal if (user != nullptr && user != employee) diff --git a/main/ui/labels.cc b/main/ui/labels.cc index 1de9a4eb..ec1ffdb7 100644 --- a/main/ui/labels.cc +++ b/main/ui/labels.cc @@ -448,6 +448,7 @@ const genericChar* SwitchName[] = { "24 Hour Mode", "Item Targeting", "Expand Goodwill Adjustments", "Monetary Symbol", "Show Modifiers", "Allow Multiple Coupons", + "Allow Multiple Logins", "Print All Modifiers on Receipt", "Auto Print Drawer Report", "Balance Automatic Coupons", "Enable F3/F4 Recording/Replay", "Auto-Update vt_data on Startup", "Show Button Images", nullptr}; @@ -462,6 +463,7 @@ int SwitchValue[] = { SWITCH_MEASUREMENTS, SWITCH_AUTHORIZE_METHOD, SWITCH_24HOURS, SWITCH_ITEM_TARGET, SWITCH_GOODWILL, SWITCH_MONEY_SYMBOL, SWITCH_SHOW_MODIFIERS, SWITCH_ALLOW_MULT_COUPON, + SWITCH_ALLOW_MULTI_LOGIN, SWITCH_RECEIPT_ALL_MODS, SWITCH_DRAWER_PRINT, SWITCH_BALANCE_AUTO_CPNS, SWITCH_F3_F4_RECORDING, SWITCH_AUTO_UPDATE_VT_DATA, SWITCH_BUTTON_IMAGES, -1}; diff --git a/zone/login_zone.cc b/zone/login_zone.cc index 7a1ea0de..d8714e73 100644 --- a/zone/login_zone.cc +++ b/zone/login_zone.cc @@ -417,7 +417,7 @@ int LoginZone::ClockOn(Terminal *term, int job_no) } else { - if (term->IsUserOnline(employee) && term->user != employee) + if (term->IsUserOnline(employee) && term->user != employee && !settings->allow_multi_login) { state = STATE_ON_ANOTHER_TERM; Draw(term, 0); @@ -494,7 +494,7 @@ int LoginZone::ClockOff(Terminal *term) state = STATE_NOT_ON_CLOCK; else if (sys->CountOpenChecks(employee) > 0) state = STATE_OPEN_CHECK; - else if (term->IsUserOnline(employee) && term->user != employee) + else if (term->IsUserOnline(employee) && term->user != employee && !sys->settings.allow_multi_login) state = STATE_ON_ANOTHER_TERM; else if (term->NeedDrawerBalanced(employee)) state = STATE_NEED_BALANCE; @@ -634,7 +634,7 @@ int LoginZone::Start(Terminal *term, short expedite) return 0; } - else if (term->IsUserOnline(employee)) + else if (term->IsUserOnline(employee) && !settings->allow_multi_login) { // user already logged into another term state = STATE_ON_ANOTHER_TERM; diff --git a/zone/settings_zone.cc b/zone/settings_zone.cc index 0f43d919..6a2668b6 100644 --- a/zone/settings_zone.cc +++ b/zone/settings_zone.cc @@ -271,6 +271,9 @@ RenderResult SwitchZone::Render(Terminal *term, int update_flag) case SWITCH_ALLOW_MULT_COUPON: onoff = settings->allow_multi_coupons; break; + case SWITCH_ALLOW_MULTI_LOGIN: + onoff = settings->allow_multi_login; + break; case SWITCH_RECEIPT_ALL_MODS: onoff = settings->receipt_all_modifiers; break; @@ -595,6 +598,11 @@ SignalResult SwitchZone::Touch(Terminal *term, int /*tx*/, int /*ty*/) case SWITCH_ALLOW_MULT_COUPON: settings->allow_multi_coupons ^= 1; break; + case SWITCH_ALLOW_MULTI_LOGIN: + settings->allow_multi_login ^= 1; + // Persist immediately so change survives restarts + settings->Save(); + break; case SWITCH_RECEIPT_ALL_MODS: settings->receipt_all_modifiers ^= 1; break;