Initial commit: add compliance_checks table, per-check metadata on assets, and compliance audit trail
This commit is contained in:
114
app/models/asset.py
Normal file
114
app/models/asset.py
Normal file
@@ -0,0 +1,114 @@
|
||||
from datetime import datetime
|
||||
from app.extensions import db
|
||||
|
||||
ASSET_TYPES = [
|
||||
'Laptop', 'Desktop', 'Monitor', 'Keyboard', 'Mouse',
|
||||
'Headset', 'Docking Station', 'Printer', 'Scanner',
|
||||
'Tablet', 'Phone', 'Server', 'Network Equipment', 'Other',
|
||||
]
|
||||
|
||||
ASSET_STATUSES = [
|
||||
('available', 'Available'),
|
||||
('assigned', 'Assigned'),
|
||||
('maintenance', 'In Maintenance'),
|
||||
('retired', 'Retired'),
|
||||
('lost', 'Lost / Stolen'),
|
||||
]
|
||||
|
||||
|
||||
class Asset(db.Model):
|
||||
"""Hardware asset tracked by serial number and/or service tag."""
|
||||
__tablename__ = 'assets'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
# Primary identifiers
|
||||
serial_number = db.Column(db.String(200), unique=True, nullable=False, index=True)
|
||||
service_tag = db.Column(db.String(200), unique=True, nullable=True, index=True)
|
||||
asset_tag = db.Column(db.String(100), nullable=True) # internal barcode / tag
|
||||
|
||||
# Classification
|
||||
asset_type = db.Column(db.String(50), nullable=False)
|
||||
brand = db.Column(db.String(100), nullable=True)
|
||||
model = db.Column(db.String(150), nullable=True)
|
||||
|
||||
# Technical specs (optional)
|
||||
processor = db.Column(db.String(200), nullable=True)
|
||||
ram_gb = db.Column(db.Integer, nullable=True)
|
||||
storage_gb = db.Column(db.Integer, nullable=True)
|
||||
operating_system = db.Column(db.String(100), nullable=True)
|
||||
mac_address = db.Column(db.String(50), nullable=True)
|
||||
|
||||
# Procurement
|
||||
purchase_date = db.Column(db.Date, nullable=True)
|
||||
warranty_expiry = db.Column(db.Date, nullable=True)
|
||||
purchase_price = db.Column(db.Numeric(10, 2), nullable=True)
|
||||
supplier = db.Column(db.String(200), nullable=True)
|
||||
po_number = db.Column(db.String(100), nullable=True)
|
||||
|
||||
# Current state
|
||||
status = db.Column(db.String(30), default='available', nullable=False)
|
||||
location = db.Column(db.String(200), nullable=True)
|
||||
notes = db.Column(db.Text, nullable=True)
|
||||
|
||||
# Compliance / IT checks — Desktop & Laptop only
|
||||
inventory_number = db.Column(db.String(100), nullable=True)
|
||||
ad_device_name = db.Column(db.String(150), nullable=True)
|
||||
location_note = db.Column(db.Text, nullable=True) # free-text location note
|
||||
|
||||
# Current boolean state
|
||||
encryption_checked = db.Column(db.Boolean, default=False, nullable=False)
|
||||
backup_checked = db.Column(db.Boolean, default=False, nullable=False)
|
||||
hr_notified = db.Column(db.Boolean, default=False, nullable=False)
|
||||
|
||||
# Who last changed each check and when
|
||||
encryption_checked_by_id = db.Column(db.Integer, db.ForeignKey('admin_users.id'), nullable=True)
|
||||
encryption_checked_at = db.Column(db.DateTime, nullable=True)
|
||||
backup_checked_by_id = db.Column(db.Integer, db.ForeignKey('admin_users.id'), nullable=True)
|
||||
backup_checked_at = db.Column(db.DateTime, nullable=True)
|
||||
hr_notified_by_id = db.Column(db.Integer, db.ForeignKey('admin_users.id'), nullable=True)
|
||||
hr_notified_at = db.Column(db.DateTime, nullable=True)
|
||||
|
||||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
created_by_id = db.Column(db.Integer, db.ForeignKey('admin_users.id'), nullable=True)
|
||||
|
||||
# Relationships
|
||||
assignments = db.relationship(
|
||||
'Assignment', backref='asset', lazy='dynamic', cascade='all, delete-orphan'
|
||||
)
|
||||
paperwork_docs = db.relationship(
|
||||
'Paperwork', backref='asset', lazy='dynamic'
|
||||
)
|
||||
compliance_checks = db.relationship(
|
||||
'ComplianceCheck', back_populates='asset', lazy='dynamic',
|
||||
cascade='all, delete-orphan',
|
||||
order_by='ComplianceCheck.performed_at.desc()',
|
||||
)
|
||||
created_by = db.relationship('AdminUser', foreign_keys=[created_by_id])
|
||||
encryption_checked_by = db.relationship('AdminUser', foreign_keys=[encryption_checked_by_id])
|
||||
backup_checked_by = db.relationship('AdminUser', foreign_keys=[backup_checked_by_id])
|
||||
hr_notified_by = db.relationship('AdminUser', foreign_keys=[hr_notified_by_id])
|
||||
|
||||
@property
|
||||
def current_assignment(self):
|
||||
return self.assignments.filter_by(is_active=True).first()
|
||||
|
||||
@property
|
||||
def current_user(self):
|
||||
a = self.current_assignment
|
||||
return a.user if a else None
|
||||
|
||||
@property
|
||||
def status_badge(self):
|
||||
colours = {
|
||||
'available': 'success',
|
||||
'assigned': 'primary',
|
||||
'maintenance': 'warning',
|
||||
'retired': 'secondary',
|
||||
'lost': 'danger',
|
||||
}
|
||||
return colours.get(self.status, 'secondary')
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Asset sn={self.serial_number} type={self.asset_type}>'
|
||||
Reference in New Issue
Block a user