Files
shopdb-flask/plugins/equipment/models/equipment.py
cproudlock 78a0ee8d83 Add custom fields + warranty plugin, rework settings into two-pane shell
Feature work from the 2026-07 session:

Settings IA
- Replace the flat 27-card settings hub with a persistent two-pane shell
  (SettingsLayout.vue): grouped, searchable left rail + content pane.
- Nest all settings/* routes under the shell via router post-processing;
  shared nav catalog in settingsNav.js. Group by asset class (PCs, Printers,
  Equipment, Network) so per-type settings stop scattering.

Custom fields (core)
- customfields + customfieldvalues tables (migration 7d14), CRUD API at
  /api/customfields, per-asset value get/save.
- Settings management page + reusable CustomFieldsSection (detail) and
  CustomFieldsInputs (form) wired into all four asset types.

Warranty (new plugin)
- plugins/warranty: warranties + warrantyassets (migration 7d15), derived
  coverage status, provider abstraction (manual now; Dell/Lenovo/HP stubs).
- API CRUD + per-asset panel + report buckets; WarrantyPanel on all four
  detail pages; Warranties management page; Warranty report + Reports card.
- Seed warranty.* permissions.

Printer drivers
- printerdrivers table (migration 7d13) linked to printer models; drivers now
  surface on the matching printer's detail page.

Other
- PCDetail rebalanced (Network + Status + Warranty + custom fields on the right).
- Rename PCs list "Features" column to "Remote Access"; fix badge hover underline.
- Drop equipment islocationonly field.
- Centralize asset-type label/route maps into utils/assetTypes.js.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 15:37:21 -04:00

134 lines
4.1 KiB
Python

"""Equipment plugin models."""
from shopdb.api import db, BaseModel
class EquipmentType(BaseModel):
"""
Equipment type classification.
Examples: CNC, CMM, Lathe, Grinder, EDM, Part Marker, etc.
"""
__tablename__ = 'equipmenttypes'
equipmenttypeid = db.Column(db.Integer, primary_key=True)
equipmenttype = db.Column(db.String(100), unique=True, nullable=False)
description = db.Column(db.Text)
icon = db.Column(db.String(50), comment='Icon name for UI')
color = db.Column(db.String(20), comment='CSS color for UI/map markers')
def __repr__(self):
return f"<EquipmentType {self.equipmenttype}>"
class Equipment(BaseModel):
"""
Equipment-specific extension data.
Links to core Asset table via assetid.
Stores equipment-specific fields like type, model, vendor, etc.
"""
__tablename__ = 'equipment'
equipmentid = db.Column(db.Integer, primary_key=True)
# Link to core asset
assetid = db.Column(
db.Integer,
db.ForeignKey('assets.assetid', ondelete='CASCADE'),
unique=True,
nullable=False,
index=True
)
# Equipment classification
equipmenttypeid = db.Column(
db.Integer,
db.ForeignKey('equipmenttypes.equipmenttypeid'),
nullable=True
)
# Vendor and model
vendorid = db.Column(
db.Integer,
db.ForeignKey('vendors.vendorid'),
nullable=True
)
modelnumberid = db.Column(
db.Integer,
db.ForeignKey('models.modelnumberid'),
nullable=True
)
# Equipment-specific fields
requiresmanualconfig = db.Column(
db.Boolean,
default=False,
comment='Multi-PC machine needs manual configuration'
)
islocationonly = db.Column(
db.Boolean,
default=False,
comment='Virtual location marker (not actual equipment)'
)
# Maintenance tracking
lastmaintenancedate = db.Column(db.DateTime, nullable=True)
nextmaintenancedate = db.Column(db.DateTime, nullable=True)
maintenanceintervaldays = db.Column(db.Integer, nullable=True)
# Controller info (for CNC machines)
controllervendorid = db.Column(
db.Integer,
db.ForeignKey('vendors.vendorid'),
nullable=True,
comment='Controller vendor (e.g., FANUC)'
)
controllermodelid = db.Column(
db.Integer,
db.ForeignKey('models.modelnumberid'),
nullable=True,
comment='Controller model (e.g., 31B)'
)
# Relationships
asset = db.relationship(
'Asset',
backref=db.backref('equipment', uselist=False, lazy='joined')
)
equipmenttype = db.relationship('EquipmentType', backref='equipment')
vendor = db.relationship('Vendor', foreign_keys=[vendorid], backref='equipment_items')
model = db.relationship('Model', foreign_keys=[modelnumberid], backref='equipment_items')
controllervendor = db.relationship('Vendor', foreign_keys=[controllervendorid], backref='equipment_controllers')
controllermodel = db.relationship('Model', foreign_keys=[controllermodelid], backref='equipment_controller_models')
__table_args__ = (
db.Index('idx_equipment_type', 'equipmenttypeid'),
db.Index('idx_equipment_vendor', 'vendorid'),
)
def __repr__(self):
return f"<Equipment {self.assetid}>"
def to_dict(self):
"""Convert to dictionary with related names."""
result = super().to_dict()
# Add related object names
if self.equipmenttype:
result['equipmenttypename'] = self.equipmenttype.equipmenttype
if self.vendor:
result['vendorname'] = self.vendor.vendor
if self.model:
result['modelname'] = self.model.modelnumber
if self.model.imageurl:
result['imageurl'] = self.model.imageurl
# Add controller info
if self.controllervendor:
result['controllervendorname'] = self.controllervendor.vendor
if self.controllermodel:
result['controllermodelname'] = self.controllermodel.modelnumber
return result