Skip to content

Commit 891712d

Browse files
committed
Don't store a detached User instance in user.dbuser
Fixes #220 and #313 on github. user.database_user.dbuser is now a read-only attribute that returns a User instance from the current ORM session.
1 parent 78b294b commit 891712d

File tree

7 files changed

+11
-29
lines changed

7 files changed

+11
-29
lines changed

quicktill/card.py

-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ def enter(self):
124124

125125
trans = td.s.get(Transaction, self.transid)
126126
user = ui.current_user().dbuser
127-
td.s.add(user)
128127
if not trans or trans.closed:
129128
ui.infopopup(["The transaction was closed before the payment "
130129
"could be recorded. The payment has been "

quicktill/cash.py

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def add_payment(self, transaction, description, amount):
3939
# Typically used by other payment drivers for cashback, or by
4040
# the register when deferring part-paid transactions
4141
user = ui.current_user().dbuser
42-
td.s.add(user)
4342
p = Payment(transaction=transaction, paytype=self.paytype,
4443
text=description, amount=amount, user=user,
4544
source=tillconfig.terminal_name)

quicktill/managestock.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -248,19 +248,18 @@ def stock_purge_internal(source):
248248

249249
# Mark all these stockitems as finished, removing them from being
250250
# on sale as we go
251-
user = ui.current_user()
252-
user = user.dbuser if user and hasattr(user, 'dbuser') else None
251+
dbu = user.current_dbuser()
253252
for item in finished:
254253
if item.stockline:
255254
# Directly connected to a stockline
256255
td.s.add(StockAnnotation(
257-
stockitem=item, atype="stop", user=user,
256+
stockitem=item, atype="stop", user=dbu,
258257
text=f"{item.stockline.name} (display stockline, {source})"))
259258
else:
260259
# Indirectly connected via a continuous stockline
261260
for sl in item.stocktype.stocklines:
262261
td.s.add(StockAnnotation(
263-
stockitem=item, atype="stop", user=user,
262+
stockitem=item, atype="stop", user=dbu,
264263
text=f"{sl.name} (continuous stockline, {source})"))
265264
item.finished = datetime.datetime.now()
266265
item.finishcode_id = 'empty' # guaranteed to exist

quicktill/register.py

+2-13
Original file line numberDiff line numberDiff line change
@@ -2631,7 +2631,6 @@ def clear_and_lock_register(self):
26312631
# We set the user's current transaction to None and dismiss
26322632
# the current register page, most likely returning to the lock
26332633
# screen on the next time around the event loop.
2634-
self.user.dbuser = td.s.get(User, self.user.userid)
26352634
self.user.dbuser.transaction = None
26362635
td.s.flush()
26372636
self.deselect()
@@ -2640,7 +2639,6 @@ def recalltrans(self, transid):
26402639
# We refresh the user object as if in enter() here, but don't
26412640
# bother with the full works because we're replacing the current
26422641
# transaction anyway!
2643-
self.user.dbuser = td.s.get(User, self.user.userid)
26442642
self._clear()
26452643
self._redraw()
26462644
if transid:
@@ -3202,14 +3200,6 @@ def entry(self):
32023200
it isn't. If False is returned, this function may have popped
32033201
up a dialog box.
32043202
"""
3205-
# Fetch the current user database object. We don't recreate
3206-
# the user.database_user object because that's unlikely to
3207-
# change often; we're just interested in the transaction and
3208-
# register fields. The fetch from the database has probably
3209-
# already been done in hotkeypress() - here we are fetching
3210-
# from the sqlalchemy session's map
3211-
self.user.dbuser = td.s.get(User, self.user.userid)
3212-
32133203
# This check has already been done in hotkeypress(). We
32143204
# repeat it here because it is possible we may not have been
32153205
# entered in response to a keypress - a timer event, for
@@ -3259,7 +3249,6 @@ def entry_noninteractive(self):
32593249
If this returns False, the caller should clean up and then
32603250
call the deselect() method.
32613251
"""
3262-
self.user.dbuser = td.s.get(User, self.user.userid)
32633252
if self.user.dbuser.register_id != tillconfig.register_id:
32643253
# User has logged in somewhere else
32653254
return False
@@ -3369,13 +3358,13 @@ def hotkeypress(self, k):
33693358
# the user.database_user object because that's unlikely to
33703359
# change often; we're just interested in the transaction and
33713360
# register fields.
3372-
self.user.dbuser = td.s.get(
3361+
dbuser = td.s.get(
33733362
User, self.user.userid,
33743363
options=[joinedload(User.transaction)])
33753364

33763365
# Check that the user hasn't moved to another terminal. If
33773366
# they have, lock immediately.
3378-
if self.user.dbuser.register_id != tillconfig.register_id:
3367+
if dbuser.register_id != tillconfig.register_id:
33793368
self.deselect()
33803369
return super().hotkeypress(k)
33813370

quicktill/squareterminal.py

-1
Original file line numberDiff line numberDiff line change
@@ -1563,7 +1563,6 @@ def _create_pending_payment(
15631563
"payment was started."], title="Error")
15641564
return
15651565
user = ui.current_user().dbuser
1566-
td.s.add(user) # hack! See github issue #220
15671566
p = Payment(transaction=reg_trans, amount=zero, paytype=pm,
15681567
text=pm.description, user=user,
15691568
source=tillconfig.terminal_name, pending=True)

quicktill/stock.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,8 @@ def finish(self):
124124
ui.infopopup(["You can't add a blank annotation!"], title="Error")
125125
return
126126
annotation = self.annfield.f or ""
127-
cu = ui.current_user()
128-
user = cu.dbuser if cu and hasattr(cu, "dbuser") else None
129127
td.s.add(StockAnnotation(stockitem=item, type=anntype, text=annotation,
130-
user=user))
128+
user=user.current_dbuser()))
131129
td.s.flush()
132130
self.dismiss()
133131
ui.infopopup(

quicktill/user.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,16 @@ class database_user(built_in_user):
287287
"""
288288
def __init__(self, user):
289289
self.userid = user.id
290-
self.dbuser = user
291290
super().__init__(
292291
user.fullname, user.shortname,
293292
permissions=[p.id for p in user.permissions],
294293
is_superuser=user.superuser)
295294
self.password_set = (user.password is not None)
296295

296+
@property
297+
def dbuser(self):
298+
return td.s.get(User, self.userid)
299+
297300

298301
def load_user(userid):
299302
"""Load the specified user from the database
@@ -399,7 +402,7 @@ def token_login(t):
399402
ui.toast(f"User '{u.fullname}' is not active.")
400403
return
401404

402-
different_user = ui.current_user() and ui.current_user().dbuser != u
405+
different_user = current_dbuser() != u
403406

404407
if require_user_passwords() and not u.password:
405408
if different_user:
@@ -1013,10 +1016,6 @@ def save(self):
10131016
u.webuser = wn if len(wn) > 0 else None
10141017
u.enabled = self.actfield.read()
10151018
self.dismiss()
1016-
# Update current_user().dbuser to ensure it is in the database
1017-
# session; it may be a detached instance in some circumstances
1018-
cu = ui.current_user()
1019-
cu.dbuser = td.s.get(User, cu.userid)
10201019
log(f"Updated details for user {u.logref}")
10211020

10221021

0 commit comments

Comments
 (0)