Card refinements

This commit is contained in:
2026-08-11 15:58:15 -04:00
parent 793dfab5c8
commit 721828b5cb
9 changed files with 134 additions and 38 deletions

View File

@@ -399,13 +399,16 @@ def warranty_report():
def dashboard_expiring():
"""Warranties running out, and ones that already have.
Already-expired first, then soonest. Expired stays on the list rather than
dropping off: a machine out of warranty is a purchasing decision someone
still has to make, and silently removing it the day it lapses is how it gets
missed entirely.
Identified the way the floor identifies them: the PC's hostname and the
MACHINE it drives. Nobody walks out looking for an asset number, and a
warranty row for a bay PC is only actionable if you know which bay.
Horizon is a setting because 90 days suits a site that budgets quarterly and
nobody else (ADR-015).
No dates. "Expired" or "expiring" is the whole decision - the exact day
matters when you are placing the order, which is what the warranty report
is for, not when you are scanning a board.
Already-expired stays listed rather than dropping off the day it lapses,
which is how one gets missed entirely.
"""
from shopdb.api import Setting
@@ -421,7 +424,7 @@ def dashboard_expiring():
horizon = today + timedelta(days=days)
rows = []
query = (db.session.query(Warranty, WarrantyAsset, Asset)
query = (db.session.query(Warranty, Asset)
.join(WarrantyAsset, WarrantyAsset.warrantyid == Warranty.warrantyid)
.join(Asset, Asset.assetid == WarrantyAsset.assetid)
.filter(Warranty.isactive.is_(True),
@@ -429,16 +432,33 @@ def dashboard_expiring():
Warranty.enddate <= horizon,
Asset.isactive.is_(True)))
for warranty, _link, asset in query.all():
for warranty, asset in query.all():
remaining = (warranty.enddate - today).days
# Reuses the machine lookup behind the warranty page's machine column,
# so the board and the report agree about which bay a PC belongs to.
machine = _related_machine(asset)
rows.append({
'assetid': asset.assetid,
'assetnumber': asset.assetnumber or asset.name or str(asset.assetid),
'enddate': warranty.enddate.isoformat(),
'provider': warranty.provider,
'daysleft': remaining,
'hostname': _hostname(asset) or asset.assetnumber or asset.name,
'machinenumber': machine['machinenumber'] if machine else None,
'state': 'expired' if remaining < 0 else 'expiring',
'daysleft': remaining,
})
rows.sort(key=lambda r: r['daysleft'])
return success_response(rows[:50])
def _hostname(asset):
"""The PC's hostname, when the covered asset is a PC.
Optional import: a lean site may not install the computers plugin, and a
warranty on a printer or a machine has no hostname at all. Falls back to
the asset number, which is what the row shows either way.
"""
try:
from plugins.computers.models import Computer
except ImportError:
return None
computer = Computer.query.filter_by(assetid=asset.assetid).first()
return computer.hostname if computer else None