Initial import: shopdb-flask multi-site asset platform

Flask + Vue rewrite of the classic-ASP shopdb, built as a plugin
framework so sister GE Aerospace sites can adopt it. Product version
0.7.0-pre-0.8.0, plugin contract 0.11.0, 966 backend tests.

Key entry points:
- docs/INSTALL-WINDOWS-IIS.md - tested Windows + IIS install runbook
  (own-site and subpath deployment methods)
- docs/PILOT-DEPLOY.md - production pilot: stand up + import + verify
- docs/IMPORT-API.md - schema-agnostic legacy data import contract
- scripts/site_imports/wjf/ - West Jefferson reference import loader
- docs/adr/ - twelve accepted architecture decision records
This commit is contained in:
2026-07-14 07:58:51 -04:00
commit a9d0dfff4a
599 changed files with 88557 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
"""Warranty plugin models."""
from .warranty import Warranty, WarrantyAsset, derive_status, STATUS_COLORS
__all__ = ['Warranty', 'WarrantyAsset', 'derive_status', 'STATUS_COLORS']

View File

@@ -0,0 +1,96 @@
"""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'),
)