From d141fef203aeb51dbd9aa5060a83111dcae9d914 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Wed, 22 Jul 2026 10:12:51 -0400 Subject: [PATCH] printedparts: show revision at kiosk; low-stock email uses gage tag + item link Kiosk now displays the scanned revision (badge, quantity, and done screens) so the operator sees which revision they checked out - it was already recorded on the take, just not shown. Low-stock email now uses the gage lab tag (was the internal item code) and links to the item page when site_base_url is set (new core setting, category email; emails have no request context to derive the URL). --- plugins/printedparts/api/routes.py | 13 ++++++++++--- plugins/printedparts/frontend/views/PartsKiosk.vue | 4 ++++ shopdb/core/api/settings.py | 8 ++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/plugins/printedparts/api/routes.py b/plugins/printedparts/api/routes.py index ba48c12..f55a983 100644 --- a/plugins/printedparts/api/routes.py +++ b/plugins/printedparts/api/routes.py @@ -330,13 +330,20 @@ def _send_lowstock_alert(item): Recipients: Setting printedparts_alert_email (comma-separated), falling back to the site's alert_recipients. Never fails the transaction - the ledger write already committed.""" - from shopdb.api import send_email, send_alert - subject = (f'Low stock: {item.itemname} ({item.itemcode}) - ' + from shopdb.api import send_email, send_alert, Setting + code = item.gagelabtag or item.itemcode + subject = (f'Low stock: {item.itemname} ({code}) - ' f'{item.quantityonhand} left') - html = (f'

{item.itemname} ({item.itemcode}) is down ' + # Absolute link to the item page when the site base URL is configured + # (e.g. https:///ops). Emails have no request context to derive it. + base = (Setting.get('site_base_url') or '').rstrip('/') + link_html = (f'

' + f'View {code}

') if base else '' + html = (f'

{item.itemname} ({code}) is down ' f'to {item.quantityonhand} ' f'(threshold {item.lowstockthreshold}).

' f'

Bin: {item.binlocation or "-"}

' + f'{link_html}' f'

Time to print more.

') try: recipients = _alert_recipients() diff --git a/plugins/printedparts/frontend/views/PartsKiosk.vue b/plugins/printedparts/frontend/views/PartsKiosk.vue index 53d4e9a..89684be 100644 --- a/plugins/printedparts/frontend/views/PartsKiosk.vue +++ b/plugins/printedparts/frontend/views/PartsKiosk.vue @@ -40,6 +40,7 @@

{{ item.itemname }}

{{ item.gagelabtag || item.itemcode }} - {{ item.quantityonhand }} on hand

+

Revision {{ scannedRevision }}

Scan your badge or tap in your SSO

@@ -62,6 +63,7 @@

{{ item.itemname }}

{{ item.quantityonhand }} on hand

+

Revision {{ scannedRevision }}

How many are you taking?

@@ -82,6 +84,7 @@

Done - {{ doneMessage }}

+

Checked out revision {{ scannedRevision }}

Starting over in a few seconds...

@@ -222,6 +225,7 @@ function reset() { } .kiosk-prompt { font-size: 1.6rem; font-weight: 600; } .kiosk-hint { color: var(--text-light); } +.kiosk-rev { font-size: 1.3rem; font-weight: 700; color: var(--primary); margin-top: 0.25rem; } .kiosk-error { background: var(--danger); color: #fff; diff --git a/shopdb/core/api/settings.py b/shopdb/core/api/settings.py index 5f93cd3..939ffa4 100644 --- a/shopdb/core/api/settings.py +++ b/shopdb/core/api/settings.py @@ -830,6 +830,14 @@ def build_default_settings(): 'category': 'email', 'description': 'Default email recipients for alerts (comma-separated)' }, + { + 'key': 'site_base_url', + 'value': '', + 'valuetype': 'string', + 'category': 'email', + 'description': 'Public base URL of this site (e.g. ' + 'https://host/ops), used to build links in emails' + }, # Audit log settings { 'key': 'audit_retention_days',