Skip to content

Commit

Permalink
Add a register instances table
Browse files Browse the repository at this point in the history
Closes #279 on github.
  • Loading branch information
sde1000 committed Feb 9, 2024
1 parent f02685f commit ff8837b
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 21 deletions.
28 changes: 25 additions & 3 deletions quicktill/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,28 @@ class TransactionMeta(Base):
""")


register_seq = Sequence('register_seq')


class Register(Base):
"""A register instance
An entry is made in this table each time the register starts
up. References to this table are then used to ensure a user is
only active on at most one register at a time.
"""
__tablename__ = 'registers'
id = Column(Integer, register_seq, nullable=False, primary_key=True)
version = Column(
String(), nullable=False, doc="Software version of the register")
startup_time = Column(DateTime(), nullable=False,
server_default=func.current_timestamp())
config_name = Column(String(), nullable=False)
terminal_name = Column(String(), nullable=False)

users = relationship('User', back_populates='register')


user_seq = Sequence('user_seq')


Expand All @@ -833,8 +855,7 @@ class User(Base, Logged):
ondelete='SET NULL'),
nullable=True, unique=True,
doc="Transaction being worked on by this user")
register = Column(String(), nullable=True,
doc="Terminal most recently used by this user")
register_id = Column(Integer, ForeignKey('registers.id'), nullable=True)
message = Column(String(), nullable=True,
doc="Message to present to user on their next keypress")
last_seen = Column(DateTime)
Expand All @@ -847,6 +868,7 @@ class User(Base, Logged):
viewonly=True)
transaction = relationship(Transaction, backref=backref(
'user', uselist=False))
register = relationship(Register)

tillweb_viewname = "tillweb-till-user"
tillweb_argname = "userid"
Expand All @@ -873,7 +895,7 @@ def logtext(self):
DECLARE
BEGIN
IF NEW.transid IS DISTINCT FROM OLD.transid
OR NEW.register IS DISTINCT FROM OLD.register THEN
OR NEW.register_id IS DISTINCT FROM OLD.register_id THEN
PERFORM pg_notify('user_register', CAST(NEW.id AS text));
END IF;
RETURN NEW;
Expand Down
12 changes: 9 additions & 3 deletions quicktill/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,17 @@ def notify_user_register(id_str):
except Exception:
return
with td.orm_session():
user = td.s.query(User).get(id)
user = td.s.query(User)\
.options(joinedload('register'))\
.get(id)
if not user:
return
print(f"user_register: {user.fullname} now at register "
f"{user.register} with transaction {user.trans_id}")
if user.register:
print(f"user_register: {user.fullname} now at register "
f"{user.register_id} ({user.register.terminal_name}) "
f"with transaction {user.trans_id}")
else:
print(f"user_register: {user.fullname} now not at a register")

@staticmethod
def notify_group_membership_changed(blank):
Expand Down
17 changes: 5 additions & 12 deletions quicktill/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
from sqlalchemy.orm import subqueryload
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import undefer
import uuid

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -178,12 +177,6 @@
user.action_descriptions['sell-dept'] = \
"Sell items using a department key"

# Whenever the register is started it generates a new unique ID for
# itself. This is used to distinguish register instances that are
# running at the same time, so they can coordinate moving transactions
# and users between registers.
register_instance = str(uuid.uuid4())


class RegisterPlugin(metaclass=plugins.InstancePluginMount):
"""A plugin to add functionality to the register
Expand Down Expand Up @@ -798,7 +791,7 @@ def __init__(self, user, hotkeys, autolock=None, timeout=300):
self.hotkeys = hotkeys
self.defaultprompt = "Ready"
# Set user's current register to be us
self.user.dbuser.register = register_instance
self.user.dbuser.register_id = tillconfig.register_id
# Save user's current transaction because it is unset by clear()
candidate_trans = self.user.dbuser.transaction
self._clear()
Expand Down Expand Up @@ -3158,7 +3151,7 @@ def entry(self):
# repeat it here because it is possible we may not have been
# entered in response to a keypress - a timer event, for
# example.
if self.user.dbuser.register != register_instance:
if self.user.dbuser.register_id != tillconfig.register_id:
# If the register in the database isn't us, lock immediately
self.deselect()
return False
Expand Down Expand Up @@ -3204,7 +3197,7 @@ def entry_noninteractive(self):
call the deselect() method.
"""
self.user.dbuser = td.s.query(User).get(self.user.userid)
if self.user.dbuser.register != register_instance:
if self.user.dbuser.register_id != tillconfig.register_id:
# User has logged in somewhere else
return False
if self.transid and not self.user.dbuser.transaction:
Expand Down Expand Up @@ -3315,7 +3308,7 @@ def hotkeypress(self, k):

# Check that the user hasn't moved to another terminal. If
# they have, lock immediately.
if self.user.dbuser.register != register_instance:
if self.user.dbuser.register_id != tillconfig.register_id:
self.deselect()
return super().hotkeypress(k)

Expand All @@ -3331,7 +3324,7 @@ def hotkeypress(self, k):
def select(self, u):
# Called when the appropriate user token is presented
self.user = u # Permissions might have changed!
self.user.dbuser.register = register_instance
self.user.dbuser.register_id = tillconfig.register_id
td.s.flush()
if self.locked:
self.locked = False
Expand Down
11 changes: 9 additions & 2 deletions quicktill/till.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from . import listen
from . import barcode
from .version import version
from .models import Session, PayType, Business, zero
from .models import Session, PayType, Business, Register, zero
import subprocess
from sqlalchemy.orm import joinedload

Expand Down Expand Up @@ -260,10 +260,17 @@ def run(args):
listen.listener.listen_for("update", runtill.update_notified)

# Load config from database, update database with new config items,
# initialise config change listener
# initialise config change listener, and generate a new register ID
with td.orm_session():
config.ConfigItem.listen_for_changes(listen.listener)
config.ConfigItem.preload()
reg = Register(version=version,
config_name=tillconfig.configname,
terminal_name=tillconfig.terminal_name)
td.s.add(reg)
td.s.flush()
tillconfig.register_id = reg.id
td.s.commit()

dbg_kbd = None
try:
Expand Down
5 changes: 5 additions & 0 deletions quicktill/tillconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@

terminal_name = "default"

# A new register_id is generated each time the register is started. It
# is used by the register to ensure each user is only active on one
# register at a time.
register_id = None

keyboard = None
keyboard_right = None

Expand Down
8 changes: 7 additions & 1 deletion release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,21 @@ What's new:
To upgrade the database:

- run "runtill syncdb" to create the new stocktype metadata table
and registers table

- run psql and give the following commands to the database:

```
BEGIN;
ALTER TABLE users
DROP COLUMN register,
ADD COLUMN register_id integer,
ADD COLUMN last_seen timestamp without time zone;
ALTER TABLE users
ADD CONSTRAINT users_register_id_fkey FOREIGN KEY (register_id) REFERENCES public.registers(id);
ALTER TABLE stocklines
ADD COLUMN note character varying DEFAULT ''::character varying NOT NULL;
Expand All @@ -39,7 +45,7 @@ CREATE OR REPLACE FUNCTION notify_user_change() RETURNS trigger
DECLARE
BEGIN
IF NEW.transid IS DISTINCT FROM OLD.transid
OR NEW.register IS DISTINCT FROM OLD.register THEN
OR NEW.register_id IS DISTINCT FROM OLD.register_id THEN
PERFORM pg_notify('user_register', CAST(NEW.id AS text));
END IF;
RETURN NEW;
Expand Down

0 comments on commit ff8837b

Please sign in to comment.