Skip to content

Commit 075ad17

Browse files
committed
Prevent multiple open sessions existing at once
The trigger used to prevent multiple open sessions from being created was not reliable. This commit removes it, and replaces it with a unique constraint on session endtime, with NULLS NOT DISTINCT so only one row with a null endtime can exist at any time. Closes #309 on github.
1 parent 8e4fbec commit 075ad17

4 files changed

Lines changed: 22 additions & 22 deletions

File tree

quicktill/models.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,11 @@ class Session(Base, Logged):
409409
date = Column('sessiondate', Date, nullable=False)
410410
accinfo = Column(String(), nullable=True, doc="Accounting system info")
411411

412+
__table_args__ = (
413+
UniqueConstraint("endtime", postgresql_nulls_not_distinct=True,
414+
name="max_one_open_session"),
415+
)
416+
412417
tillweb_viewname = "tillweb-session"
413418
tillweb_argname = "sessionid"
414419
tillweb_index_description = "Sessions"
@@ -635,25 +640,6 @@ def previous(self):
635640
return self._prevsession
636641

637642

638-
add_ddl(Session.__table__, """
639-
CREATE OR REPLACE FUNCTION check_max_one_session_open() RETURNS trigger AS $$
640-
BEGIN
641-
IF (SELECT count(*) FROM sessions WHERE endtime IS NULL)>1 THEN
642-
RAISE EXCEPTION 'there is already an open session'
643-
USING ERRCODE = 'integrity_constraint_violation';
644-
END IF;
645-
RETURN NULL;
646-
END;
647-
$$ LANGUAGE plpgsql;
648-
CREATE CONSTRAINT TRIGGER max_one_session_open
649-
AFTER INSERT OR UPDATE ON sessions
650-
FOR EACH ROW EXECUTE PROCEDURE check_max_one_session_open();
651-
""", """
652-
DROP TRIGGER max_one_session_open ON sessions;
653-
DROP FUNCTION check_max_one_session_open();
654-
""")
655-
656-
657643
class SessionMeta(Base):
658644
"""Metadata on a session
659645

quicktill/session.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from . import payment
55
from . import config
66
from .models import PayType, Session, SessionTotal, Transaction, zero
7+
import sqlalchemy.exc
78
from sqlalchemy.orm import undefer
89
from sqlalchemy.sql import select, func, desc
910
from .plugins import InstancePluginMount
@@ -89,8 +90,14 @@ def key_enter(self):
8990
return
9091
self.dismiss()
9192
sc = Session(date=date)
92-
td.s.add(sc)
93-
td.s.flush()
93+
try:
94+
td.s.add(sc)
95+
td.s.commit()
96+
except sqlalchemy.exc.IntegrityError:
97+
td.s.rollback()
98+
ui.infopopup(["A new session has already been started."],
99+
title="Error")
100+
return
94101
deferred = trans_restore()
95102
td.foodorder_reset()
96103
log.info("Started session number %d", sc.id)

release-notes.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ BEGIN;
1818
ALTER TABLE sessions
1919
ALTER COLUMN starttime SET DEFAULT CURRENT_TIMESTAMP;
2020
21+
DROP TRIGGER max_one_session_open ON sessions;
22+
23+
DROP FUNCTION check_max_one_session_open();
24+
25+
ALTER TABLE sessions
26+
ADD CONSTRAINT max_one_open_session UNIQUE NULLS NOT DISTINCT (endtime);
27+
2128
COMMIT;
2229
```
2330

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ install_requires =
1717
psycopg2 ~= 2.9
1818
reportlab
1919
httplib2
20-
sqlalchemy >= 2.0
20+
sqlalchemy >= 2.0.16
2121
qrcode
2222
requests
2323
requests-oauthlib

0 commit comments

Comments
 (0)