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).
This commit is contained in:
@@ -330,13 +330,20 @@ def _send_lowstock_alert(item):
|
|||||||
Recipients: Setting printedparts_alert_email (comma-separated), falling
|
Recipients: Setting printedparts_alert_email (comma-separated), falling
|
||||||
back to the site's alert_recipients. Never fails the transaction - the
|
back to the site's alert_recipients. Never fails the transaction - the
|
||||||
ledger write already committed."""
|
ledger write already committed."""
|
||||||
from shopdb.api import send_email, send_alert
|
from shopdb.api import send_email, send_alert, Setting
|
||||||
subject = (f'Low stock: {item.itemname} ({item.itemcode}) - '
|
code = item.gagelabtag or item.itemcode
|
||||||
|
subject = (f'Low stock: {item.itemname} ({code}) - '
|
||||||
f'{item.quantityonhand} left')
|
f'{item.quantityonhand} left')
|
||||||
html = (f'<p><strong>{item.itemname}</strong> ({item.itemcode}) is down '
|
# Absolute link to the item page when the site base URL is configured
|
||||||
|
# (e.g. https://<host>/ops). Emails have no request context to derive it.
|
||||||
|
base = (Setting.get('site_base_url') or '').rstrip('/')
|
||||||
|
link_html = (f'<p><a href="{base}/printedparts/{item.printeditemid}">'
|
||||||
|
f'View {code}</a></p>') if base else ''
|
||||||
|
html = (f'<p><strong>{item.itemname}</strong> ({code}) is down '
|
||||||
f'to <strong>{item.quantityonhand}</strong> '
|
f'to <strong>{item.quantityonhand}</strong> '
|
||||||
f'(threshold {item.lowstockthreshold}).</p>'
|
f'(threshold {item.lowstockthreshold}).</p>'
|
||||||
f'<p>Bin: {item.binlocation or "-"}</p>'
|
f'<p>Bin: {item.binlocation or "-"}</p>'
|
||||||
|
f'{link_html}'
|
||||||
f'<p>Time to print more.</p>')
|
f'<p>Time to print more.</p>')
|
||||||
try:
|
try:
|
||||||
recipients = _alert_recipients()
|
recipients = _alert_recipients()
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2>{{ item.itemname }}</h2>
|
<h2>{{ item.itemname }}</h2>
|
||||||
<p class="kiosk-hint">{{ item.gagelabtag || item.itemcode }} - {{ item.quantityonhand }} on hand</p>
|
<p class="kiosk-hint">{{ item.gagelabtag || item.itemcode }} - {{ item.quantityonhand }} on hand</p>
|
||||||
|
<p v-if="scannedRevision != null" class="kiosk-rev">Revision {{ scannedRevision }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="kiosk-prompt">Scan your badge or tap in your SSO</p>
|
<p class="kiosk-prompt">Scan your badge or tap in your SSO</p>
|
||||||
@@ -62,6 +63,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2>{{ item.itemname }}</h2>
|
<h2>{{ item.itemname }}</h2>
|
||||||
<p class="kiosk-hint">{{ item.quantityonhand }} on hand</p>
|
<p class="kiosk-hint">{{ item.quantityonhand }} on hand</p>
|
||||||
|
<p v-if="scannedRevision != null" class="kiosk-rev">Revision {{ scannedRevision }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="kiosk-prompt">How many are you taking?</p>
|
<p class="kiosk-prompt">How many are you taking?</p>
|
||||||
@@ -82,6 +84,7 @@
|
|||||||
<!-- done -->
|
<!-- done -->
|
||||||
<section v-else-if="step === 'done'" class="kiosk-step">
|
<section v-else-if="step === 'done'" class="kiosk-step">
|
||||||
<p class="kiosk-success">Done - {{ doneMessage }}</p>
|
<p class="kiosk-success">Done - {{ doneMessage }}</p>
|
||||||
|
<p v-if="scannedRevision != null" class="kiosk-hint">Checked out revision {{ scannedRevision }}</p>
|
||||||
<p class="kiosk-hint">Starting over in a few seconds...</p>
|
<p class="kiosk-hint">Starting over in a few seconds...</p>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@@ -222,6 +225,7 @@ function reset() {
|
|||||||
}
|
}
|
||||||
.kiosk-prompt { font-size: 1.6rem; font-weight: 600; }
|
.kiosk-prompt { font-size: 1.6rem; font-weight: 600; }
|
||||||
.kiosk-hint { color: var(--text-light); }
|
.kiosk-hint { color: var(--text-light); }
|
||||||
|
.kiosk-rev { font-size: 1.3rem; font-weight: 700; color: var(--primary); margin-top: 0.25rem; }
|
||||||
.kiosk-error {
|
.kiosk-error {
|
||||||
background: var(--danger);
|
background: var(--danger);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|||||||
@@ -830,6 +830,14 @@ def build_default_settings():
|
|||||||
'category': 'email',
|
'category': 'email',
|
||||||
'description': 'Default email recipients for alerts (comma-separated)'
|
'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
|
# Audit log settings
|
||||||
{
|
{
|
||||||
'key': 'audit_retention_days',
|
'key': 'audit_retention_days',
|
||||||
|
|||||||
Reference in New Issue
Block a user