"""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) 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, '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'), )