A provider lookup answers whether a unit is covered. It does not produce the invoice or the extended-warranty certificate, and a manually entered warranty had nowhere to keep one - so the proof stayed in somebody's mailbox until they left. Two columns rather than one: the served URL of the stored document, and the name the vendor sent it under, because "Dell invoice 4471.pdf" is what a person recognises a year later and "warranty-12.pdf" is not. The download route sends the original name back. Authenticated in both directions, unlike an asset photo: an invoice carries pricing and a service tag. One document per warranty, replacing any prior extension so a re-upload as .pdf does not leave the old .png behind claiming to be current. Capped at 25MB - a certificate is a document, not a disk image. Office formats are allowed because purchase records genuinely arrive as .msg and .xlsx, not only as PDFs.
107 lines
3.7 KiB
Python
107 lines
3.7 KiB
Python
"""Warranty models.
|
|
|
|
A Warranty is provider-agnostic (manual entry, or looked up from Dell/Lenovo/HP
|
|
later). It links to one or more assets via warrantyassets. Coverage status is
|
|
DERIVED from enddate at read time, never stored, so it is always current.
|
|
"""
|
|
|
|
from datetime import date, timedelta
|
|
|
|
from shopdb.api import db
|
|
|
|
# Window before enddate where a warranty counts as "expiring soon".
|
|
EXPIRING_WINDOW_DAYS = 180
|
|
|
|
# Derived status -> display color (hex). Reused by the frontend status badge.
|
|
STATUS_COLORS = {
|
|
'active': '#4CAF50',
|
|
'expiring': '#FF9800',
|
|
'expired': '#F44336',
|
|
'unknown': '#9E9E9E',
|
|
}
|
|
|
|
|
|
def derive_status(enddate, today=None):
|
|
"""Coverage status from an end date. Never stored - always computed."""
|
|
if not enddate:
|
|
return 'unknown'
|
|
today = today or date.today()
|
|
if enddate < today:
|
|
return 'expired'
|
|
if enddate <= today + timedelta(days=EXPIRING_WINDOW_DAYS):
|
|
return 'expiring'
|
|
return 'active'
|
|
|
|
|
|
class Warranty(db.Model):
|
|
__tablename__ = 'warranties'
|
|
|
|
warrantyid = db.Column(db.Integer, primary_key=True)
|
|
vendor = db.Column(db.String(100), nullable=False)
|
|
# Service tag / serial the provider identifies the unit by.
|
|
servicetag = db.Column(db.String(100))
|
|
# Where the record came from: manual, dell, lenovo, hp.
|
|
provider = db.Column(db.String(20), nullable=False, server_default='manual')
|
|
servicelevel = db.Column(db.String(150))
|
|
startdate = db.Column(db.Date)
|
|
enddate = db.Column(db.Date)
|
|
# When a provider lookup last refreshed this record.
|
|
lastcheckeddate = db.Column(db.DateTime)
|
|
notes = db.Column(db.Text)
|
|
|
|
# Proof of cover: the purchase invoice, the extended-warranty certificate,
|
|
# whatever the vendor sent. A provider lookup answers "is it covered"; this
|
|
# answers "prove it" months later, when the email it arrived in is gone.
|
|
# Stores the served URL, not the original filename - see the upload route.
|
|
proofurl = db.Column(db.String(500))
|
|
prooffilename = db.Column(db.String(255))
|
|
|
|
isactive = db.Column(db.Boolean, nullable=False, server_default='1')
|
|
|
|
links = db.relationship('WarrantyAsset', back_populates='warranty',
|
|
cascade='all, delete-orphan')
|
|
|
|
def status(self, today=None):
|
|
return derive_status(self.enddate, today)
|
|
|
|
def to_dict(self, today=None):
|
|
status = self.status(today)
|
|
return {
|
|
'warrantyid': self.warrantyid,
|
|
'vendor': self.vendor,
|
|
'servicetag': self.servicetag,
|
|
'provider': self.provider,
|
|
'servicelevel': self.servicelevel,
|
|
'startdate': self.startdate.isoformat() if self.startdate else None,
|
|
'enddate': self.enddate.isoformat() if self.enddate else None,
|
|
'lastcheckeddate': self.lastcheckeddate.isoformat() + 'Z' if self.lastcheckeddate else None,
|
|
'notes': self.notes,
|
|
'proofurl': self.proofurl,
|
|
'prooffilename': self.prooffilename,
|
|
'isactive': bool(self.isactive),
|
|
'status': status,
|
|
'statuscolor': STATUS_COLORS.get(status, STATUS_COLORS['unknown']),
|
|
}
|
|
|
|
|
|
class WarrantyAsset(db.Model):
|
|
__tablename__ = 'warrantyassets'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
warrantyid = db.Column(
|
|
db.Integer,
|
|
db.ForeignKey('warranties.warrantyid', ondelete='CASCADE'),
|
|
nullable=False
|
|
)
|
|
assetid = db.Column(
|
|
db.Integer,
|
|
db.ForeignKey('assets.assetid', ondelete='CASCADE'),
|
|
nullable=False
|
|
)
|
|
|
|
warranty = db.relationship('Warranty', back_populates='links')
|
|
|
|
__table_args__ = (
|
|
db.UniqueConstraint('warrantyid', 'assetid', name='uq_warrantyasset_warranty_asset'),
|
|
)
|