Retire the legacy Machine model (ADR-001 cutover)
The asset/computer model is now the single source of truth. Remove the Machine instance layer end to end: - Delete models Machine, MachineStatus, PCType, MachineRelationship, InstalledApp, PrinterData; keep MachineType (models.machinetypeid still references it). - Delete the /api/machines, /api/statuses, /api/pctypes blueprints and the legacy /api/printers/legacy (PrinterData) blueprint. - Drop the deprecated communications.machineid column and its FK. - Migration 7c01 drops tables machines, machinestatuses, pctypes, machinerelationships, installedapps, printerdata (idempotent). - Fix remaining readers (applications install counts) to ComputerInstalledApp. - Frontend: remove dead machinesApi/statusesApi/pctypesApi wrappers; repoint the PC Types settings page at computer types. 143 tests pass; all asset/computer/dashboard/report/collector endpoints 200. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2,16 +2,16 @@
|
||||
|
||||
from .base import BaseModel, SoftDeleteMixin, AuditMixin
|
||||
from .asset import Asset, AssetType, AssetStatus
|
||||
from .machine import Machine, MachineType, MachineStatus, PCType
|
||||
from .machine import MachineType
|
||||
from .vendor import Vendor
|
||||
from .model import Model
|
||||
from .businessunit import BusinessUnit
|
||||
from .location import Location
|
||||
from .operatingsystem import OperatingSystem
|
||||
from .relationship import MachineRelationship, AssetRelationship, RelationshipType
|
||||
from .relationship import AssetRelationship, RelationshipType
|
||||
from .communication import Communication, CommunicationType
|
||||
from .user import User, Role, Permission
|
||||
from .application import Application, AppVersion, AppOwner, SupportTeam, InstalledApp
|
||||
from .application import Application, AppVersion, AppOwner, SupportTeam
|
||||
from .knowledgebase import KnowledgeBase
|
||||
from .setting import Setting
|
||||
from .auditlog import AuditLog
|
||||
@@ -25,11 +25,8 @@ __all__ = [
|
||||
'Asset',
|
||||
'AssetType',
|
||||
'AssetStatus',
|
||||
# Machine (legacy)
|
||||
'Machine',
|
||||
# Legacy machine type lookup (still referenced by models.machinetypeid)
|
||||
'MachineType',
|
||||
'MachineStatus',
|
||||
'PCType',
|
||||
# Reference
|
||||
'Vendor',
|
||||
'Model',
|
||||
@@ -37,7 +34,6 @@ __all__ = [
|
||||
'Location',
|
||||
'OperatingSystem',
|
||||
# Relationships
|
||||
'MachineRelationship',
|
||||
'AssetRelationship',
|
||||
'RelationshipType',
|
||||
# Communication
|
||||
@@ -52,7 +48,6 @@ __all__ = [
|
||||
'AppVersion',
|
||||
'AppOwner',
|
||||
'SupportTeam',
|
||||
'InstalledApp',
|
||||
# Knowledge Base
|
||||
'KnowledgeBase',
|
||||
# Settings
|
||||
|
||||
@@ -1,143 +1,99 @@
|
||||
"""Application tracking models."""
|
||||
|
||||
from shopdb.extensions import db
|
||||
from .base import BaseModel
|
||||
|
||||
|
||||
class AppOwner(BaseModel):
|
||||
"""Application owner/contact."""
|
||||
__tablename__ = 'appowners'
|
||||
|
||||
appownerid = db.Column(db.Integer, primary_key=True)
|
||||
appowner = db.Column(db.String(100), nullable=False)
|
||||
sso = db.Column(db.String(50))
|
||||
email = db.Column(db.String(100))
|
||||
|
||||
# Relationships
|
||||
supportteams = db.relationship('SupportTeam', back_populates='owner', lazy='dynamic')
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AppOwner {self.appowner}>"
|
||||
|
||||
|
||||
class SupportTeam(BaseModel):
|
||||
"""Application support team."""
|
||||
__tablename__ = 'supportteams'
|
||||
|
||||
supportteamid = db.Column(db.Integer, primary_key=True)
|
||||
teamname = db.Column(db.String(100), nullable=False)
|
||||
teamurl = db.Column(db.String(255))
|
||||
appownerid = db.Column(db.Integer, db.ForeignKey('appowners.appownerid'))
|
||||
|
||||
# Relationships
|
||||
owner = db.relationship('AppOwner', back_populates='supportteams')
|
||||
applications = db.relationship('Application', back_populates='supportteam', lazy='dynamic')
|
||||
|
||||
def __repr__(self):
|
||||
return f"<SupportTeam {self.teamname}>"
|
||||
|
||||
|
||||
class Application(BaseModel):
|
||||
"""Application catalog."""
|
||||
__tablename__ = 'applications'
|
||||
|
||||
appid = db.Column(db.Integer, primary_key=True)
|
||||
appname = db.Column(db.String(100), unique=True, nullable=False)
|
||||
appdescription = db.Column(db.String(255))
|
||||
supportteamid = db.Column(db.Integer, db.ForeignKey('supportteams.supportteamid'))
|
||||
isinstallable = db.Column(db.Boolean, default=False)
|
||||
applicationnotes = db.Column(db.Text)
|
||||
installpath = db.Column(db.String(255))
|
||||
applicationlink = db.Column(db.String(512))
|
||||
documentationpath = db.Column(db.String(512))
|
||||
ishidden = db.Column(db.Boolean, default=False)
|
||||
isprinter = db.Column(db.Boolean, default=False)
|
||||
islicenced = db.Column(db.Boolean, default=False)
|
||||
image = db.Column(db.String(255))
|
||||
|
||||
# Relationships
|
||||
supportteam = db.relationship('SupportTeam', back_populates='applications')
|
||||
versions = db.relationship('AppVersion', back_populates='application', lazy='dynamic')
|
||||
installed_on = db.relationship('InstalledApp', back_populates='application', lazy='dynamic')
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Application {self.appname}>"
|
||||
|
||||
|
||||
class AppVersion(db.Model):
|
||||
"""Application version tracking."""
|
||||
__tablename__ = 'appversions'
|
||||
|
||||
appversionid = db.Column(db.Integer, primary_key=True)
|
||||
appid = db.Column(db.Integer, db.ForeignKey('applications.appid'), nullable=False)
|
||||
version = db.Column(db.String(50), nullable=False)
|
||||
releasedate = db.Column(db.Date)
|
||||
notes = db.Column(db.String(255))
|
||||
dateadded = db.Column(db.DateTime, default=db.func.now())
|
||||
isactive = db.Column(db.Boolean, default=True)
|
||||
|
||||
# Relationships
|
||||
application = db.relationship('Application', back_populates='versions')
|
||||
installations = db.relationship('InstalledApp', back_populates='appversion', lazy='dynamic')
|
||||
|
||||
# Unique constraint on app + version
|
||||
__table_args__ = (
|
||||
db.UniqueConstraint('appid', 'version', name='uq_app_version'),
|
||||
)
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert to dictionary."""
|
||||
return {
|
||||
'appversionid': self.appversionid,
|
||||
'appid': self.appid,
|
||||
'version': self.version,
|
||||
'releasedate': self.releasedate.isoformat() if self.releasedate else None,
|
||||
'notes': self.notes,
|
||||
'dateadded': self.dateadded.isoformat() + 'Z' if self.dateadded else None,
|
||||
'isactive': self.isactive
|
||||
}
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AppVersion {self.application.appname if self.application else self.appid} v{self.version}>"
|
||||
|
||||
|
||||
class InstalledApp(db.Model):
|
||||
"""Junction table for applications installed on machines (PCs)."""
|
||||
__tablename__ = 'installedapps'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
machineid = db.Column(db.Integer, db.ForeignKey('machines.machineid'), nullable=False)
|
||||
appid = db.Column(db.Integer, db.ForeignKey('applications.appid'), nullable=False)
|
||||
appversionid = db.Column(db.Integer, db.ForeignKey('appversions.appversionid'))
|
||||
isactive = db.Column(db.Boolean, default=True, nullable=False)
|
||||
installeddate = db.Column(db.DateTime, default=db.func.now())
|
||||
|
||||
# Relationships
|
||||
machine = db.relationship('Machine', back_populates='installedapps')
|
||||
application = db.relationship('Application', back_populates='installed_on')
|
||||
appversion = db.relationship('AppVersion', back_populates='installations')
|
||||
|
||||
# Unique constraint - one app per machine (can have different versions over time)
|
||||
__table_args__ = (
|
||||
db.UniqueConstraint('machineid', 'appid', name='uq_machine_app'),
|
||||
)
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert to dictionary."""
|
||||
return {
|
||||
'id': self.id,
|
||||
'machineid': self.machineid,
|
||||
'appid': self.appid,
|
||||
'appversionid': self.appversionid,
|
||||
'isactive': self.isactive,
|
||||
'installeddate': self.installeddate.isoformat() + 'Z' if self.installeddate else None,
|
||||
'application': {
|
||||
'appid': self.application.appid,
|
||||
'appname': self.application.appname,
|
||||
'appdescription': self.application.appdescription,
|
||||
} if self.application else None,
|
||||
'version': self.appversion.version if self.appversion else None
|
||||
}
|
||||
|
||||
def __repr__(self):
|
||||
return f"<InstalledApp machine={self.machineid} app={self.appid}>"
|
||||
"""Application tracking models."""
|
||||
|
||||
from shopdb.extensions import db
|
||||
from .base import BaseModel
|
||||
|
||||
|
||||
class AppOwner(BaseModel):
|
||||
"""Application owner/contact."""
|
||||
__tablename__ = 'appowners'
|
||||
|
||||
appownerid = db.Column(db.Integer, primary_key=True)
|
||||
appowner = db.Column(db.String(100), nullable=False)
|
||||
sso = db.Column(db.String(50))
|
||||
email = db.Column(db.String(100))
|
||||
|
||||
# Relationships
|
||||
supportteams = db.relationship('SupportTeam', back_populates='owner', lazy='dynamic')
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AppOwner {self.appowner}>"
|
||||
|
||||
|
||||
class SupportTeam(BaseModel):
|
||||
"""Application support team."""
|
||||
__tablename__ = 'supportteams'
|
||||
|
||||
supportteamid = db.Column(db.Integer, primary_key=True)
|
||||
teamname = db.Column(db.String(100), nullable=False)
|
||||
teamurl = db.Column(db.String(255))
|
||||
appownerid = db.Column(db.Integer, db.ForeignKey('appowners.appownerid'))
|
||||
|
||||
# Relationships
|
||||
owner = db.relationship('AppOwner', back_populates='supportteams')
|
||||
applications = db.relationship('Application', back_populates='supportteam', lazy='dynamic')
|
||||
|
||||
def __repr__(self):
|
||||
return f"<SupportTeam {self.teamname}>"
|
||||
|
||||
|
||||
class Application(BaseModel):
|
||||
"""Application catalog."""
|
||||
__tablename__ = 'applications'
|
||||
|
||||
appid = db.Column(db.Integer, primary_key=True)
|
||||
appname = db.Column(db.String(100), unique=True, nullable=False)
|
||||
appdescription = db.Column(db.String(255))
|
||||
supportteamid = db.Column(db.Integer, db.ForeignKey('supportteams.supportteamid'))
|
||||
isinstallable = db.Column(db.Boolean, default=False)
|
||||
applicationnotes = db.Column(db.Text)
|
||||
installpath = db.Column(db.String(255))
|
||||
applicationlink = db.Column(db.String(512))
|
||||
documentationpath = db.Column(db.String(512))
|
||||
ishidden = db.Column(db.Boolean, default=False)
|
||||
isprinter = db.Column(db.Boolean, default=False)
|
||||
islicenced = db.Column(db.Boolean, default=False)
|
||||
image = db.Column(db.String(255))
|
||||
|
||||
# Relationships
|
||||
supportteam = db.relationship('SupportTeam', back_populates='applications')
|
||||
versions = db.relationship('AppVersion', back_populates='application', lazy='dynamic')
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Application {self.appname}>"
|
||||
|
||||
|
||||
class AppVersion(db.Model):
|
||||
"""Application version tracking."""
|
||||
__tablename__ = 'appversions'
|
||||
|
||||
appversionid = db.Column(db.Integer, primary_key=True)
|
||||
appid = db.Column(db.Integer, db.ForeignKey('applications.appid'), nullable=False)
|
||||
version = db.Column(db.String(50), nullable=False)
|
||||
releasedate = db.Column(db.Date)
|
||||
notes = db.Column(db.String(255))
|
||||
dateadded = db.Column(db.DateTime, default=db.func.now())
|
||||
isactive = db.Column(db.Boolean, default=True)
|
||||
|
||||
# Relationships
|
||||
application = db.relationship('Application', back_populates='versions')
|
||||
|
||||
# Unique constraint on app + version
|
||||
__table_args__ = (
|
||||
db.UniqueConstraint('appid', 'version', name='uq_app_version'),
|
||||
)
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert to dictionary."""
|
||||
return {
|
||||
'appversionid': self.appversionid,
|
||||
'appid': self.appid,
|
||||
'version': self.version,
|
||||
'releasedate': self.releasedate.isoformat() if self.releasedate else None,
|
||||
'notes': self.notes,
|
||||
'dateadded': self.dateadded.isoformat() + 'Z' if self.dateadded else None,
|
||||
'isactive': self.isactive
|
||||
}
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AppVersion {self.application.appname if self.application else self.appid} v{self.version}>"
|
||||
|
||||
@@ -36,14 +36,6 @@ class Communication(BaseModel):
|
||||
comment='FK to assets table (new architecture)'
|
||||
)
|
||||
|
||||
# Legacy machine FK (for backward compatibility during migration)
|
||||
machineid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('machines.machineid'),
|
||||
nullable=True,
|
||||
comment='DEPRECATED: FK to machines table - use assetid instead'
|
||||
)
|
||||
|
||||
comtypeid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('communicationtypes.comtypeid'),
|
||||
@@ -95,9 +87,8 @@ class Communication(BaseModel):
|
||||
|
||||
__table_args__ = (
|
||||
db.Index('idx_comm_asset', 'assetid'),
|
||||
db.Index('idx_comm_machine', 'machineid'),
|
||||
db.Index('idx_comm_ip', 'ipaddress'),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Communication {self.machineid}:{self.comtype.comtype if self.comtype else 'Unknown'}>"
|
||||
return f"<Communication {self.assetid}:{self.comtype.comtype if self.comtype else 'Unknown'}>"
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
"""Unified Machine model - combines equipment and PCs."""
|
||||
"""Legacy machine type lookup.
|
||||
|
||||
The Machine instance model and its PC/status lookups were retired (ADR-001);
|
||||
assets are the platform contract. MachineType is kept only because the shared
|
||||
`models` table still references it via models.machinetypeid.
|
||||
"""
|
||||
|
||||
from shopdb.extensions import db
|
||||
from .base import BaseModel, SoftDeleteMixin, AuditMixin
|
||||
from .base import BaseModel
|
||||
|
||||
|
||||
class MachineType(BaseModel):
|
||||
@@ -24,229 +29,3 @@ class MachineType(BaseModel):
|
||||
|
||||
def __repr__(self):
|
||||
return f"<MachineType {self.machinetype}>"
|
||||
|
||||
|
||||
class MachineStatus(BaseModel):
|
||||
"""Machine status options."""
|
||||
__tablename__ = 'machinestatuses'
|
||||
|
||||
statusid = db.Column(db.Integer, primary_key=True)
|
||||
status = db.Column(db.String(50), unique=True, nullable=False)
|
||||
description = db.Column(db.Text)
|
||||
color = db.Column(db.String(20), comment='CSS color for UI')
|
||||
|
||||
def __repr__(self):
|
||||
return f"<MachineStatus {self.status}>"
|
||||
|
||||
|
||||
class PCType(BaseModel):
|
||||
"""
|
||||
PC type classification for more specific PC categorization.
|
||||
Examples: Shopfloor PC, Engineer Workstation, CMM PC, etc.
|
||||
"""
|
||||
__tablename__ = 'pctypes'
|
||||
|
||||
pctypeid = db.Column(db.Integer, primary_key=True)
|
||||
pctype = db.Column(db.String(100), unique=True, nullable=False)
|
||||
description = db.Column(db.Text)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<PCType {self.pctype}>"
|
||||
|
||||
|
||||
class Machine(BaseModel, SoftDeleteMixin, AuditMixin):
|
||||
"""
|
||||
Unified machine model for all asset types.
|
||||
|
||||
Machine types can be:
|
||||
- CNC machines, CMMs, EDMs, etc. (manufacturing equipment)
|
||||
- PCs (shopfloor PCs, engineer workstations, etc.)
|
||||
- Network devices (servers, switches, etc.) - if network_devices plugin not used
|
||||
|
||||
The machinetype.category field distinguishes between types.
|
||||
"""
|
||||
__tablename__ = 'machines'
|
||||
|
||||
machineid = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
# Identification
|
||||
machinenumber = db.Column(
|
||||
db.String(50),
|
||||
unique=True,
|
||||
nullable=False,
|
||||
index=True,
|
||||
comment='Business identifier (e.g., CMM01, G5QX1GT3ESF)'
|
||||
)
|
||||
alias = db.Column(
|
||||
db.String(100),
|
||||
comment='Friendly name'
|
||||
)
|
||||
hostname = db.Column(
|
||||
db.String(100),
|
||||
index=True,
|
||||
comment='Network hostname (for PCs)'
|
||||
)
|
||||
serialnumber = db.Column(
|
||||
db.String(100),
|
||||
index=True,
|
||||
comment='Hardware serial number'
|
||||
)
|
||||
|
||||
# Classification
|
||||
machinetypeid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('machinetypes.machinetypeid'),
|
||||
nullable=False
|
||||
)
|
||||
pctypeid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('pctypes.pctypeid'),
|
||||
nullable=True,
|
||||
comment='Set for PCs, NULL for equipment'
|
||||
)
|
||||
businessunitid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('businessunits.businessunitid'),
|
||||
nullable=True
|
||||
)
|
||||
modelnumberid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('models.modelnumberid'),
|
||||
nullable=True
|
||||
)
|
||||
vendorid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('vendors.vendorid'),
|
||||
nullable=True
|
||||
)
|
||||
|
||||
# Status
|
||||
statusid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('machinestatuses.statusid'),
|
||||
default=1,
|
||||
comment='In Use, Spare, Retired, etc.'
|
||||
)
|
||||
|
||||
# Location and mapping
|
||||
locationid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('locations.locationid'),
|
||||
nullable=True
|
||||
)
|
||||
mapleft = db.Column(db.Integer, comment='X coordinate on floor map')
|
||||
maptop = db.Column(db.Integer, comment='Y coordinate on floor map')
|
||||
islocationonly = db.Column(
|
||||
db.Boolean,
|
||||
default=False,
|
||||
comment='Virtual location marker (not actual machine)'
|
||||
)
|
||||
|
||||
# PC-specific fields (nullable for non-PC machines)
|
||||
osid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('operatingsystems.osid'),
|
||||
nullable=True
|
||||
)
|
||||
loggedinuser = db.Column(db.String(100), nullable=True)
|
||||
lastreporteddate = db.Column(db.DateTime, nullable=True)
|
||||
lastboottime = db.Column(db.DateTime, nullable=True)
|
||||
|
||||
# Features/flags
|
||||
isvnc = db.Column(db.Boolean, default=False, comment='VNC remote access enabled')
|
||||
iswinrm = db.Column(db.Boolean, default=False, comment='WinRM enabled')
|
||||
isshopfloor = db.Column(db.Boolean, default=False, comment='Shopfloor PC')
|
||||
requiresmanualconfig = db.Column(
|
||||
db.Boolean,
|
||||
default=False,
|
||||
comment='Multi-PC machine needs manual configuration'
|
||||
)
|
||||
|
||||
# Notes
|
||||
notes = db.Column(db.Text, nullable=True)
|
||||
|
||||
# Relationships
|
||||
machinetype = db.relationship('MachineType', backref='machines')
|
||||
pctype = db.relationship('PCType', backref='machines')
|
||||
businessunit = db.relationship('BusinessUnit', backref='machines')
|
||||
model = db.relationship('Model', backref='machines')
|
||||
vendor = db.relationship('Vendor', backref='machines')
|
||||
status = db.relationship('MachineStatus', backref='machines')
|
||||
location = db.relationship('Location', backref='machines')
|
||||
operatingsystem = db.relationship('OperatingSystem', backref='machines')
|
||||
|
||||
# Communications (one-to-many)
|
||||
communications = db.relationship(
|
||||
'Communication',
|
||||
backref='machine',
|
||||
cascade='all, delete-orphan',
|
||||
lazy='dynamic'
|
||||
)
|
||||
|
||||
# Installed applications (for PCs)
|
||||
installedapps = db.relationship(
|
||||
'InstalledApp',
|
||||
back_populates='machine',
|
||||
cascade='all, delete-orphan',
|
||||
lazy='dynamic'
|
||||
)
|
||||
|
||||
# Indexes
|
||||
__table_args__ = (
|
||||
db.Index('idx_machine_type_bu', 'machinetypeid', 'businessunitid'),
|
||||
db.Index('idx_machine_location', 'locationid'),
|
||||
db.Index('idx_machine_active', 'isactive'),
|
||||
db.Index('idx_machine_hostname', 'hostname'),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Machine {self.machinenumber}>"
|
||||
|
||||
@property
|
||||
def display_name(self):
|
||||
"""Get display name (alias if set, otherwise machinenumber)."""
|
||||
return self.alias or self.machinenumber
|
||||
|
||||
@property
|
||||
def derived_machinetype(self):
|
||||
"""Get machinetype from model (single source of truth)."""
|
||||
if self.model and self.model.machinetype:
|
||||
return self.model.machinetype
|
||||
return None
|
||||
|
||||
@property
|
||||
def is_pc(self):
|
||||
"""Check if this machine is a PC type."""
|
||||
mt = self.derived_machinetype
|
||||
return mt.category == 'PC' if mt else False
|
||||
|
||||
@property
|
||||
def is_equipment(self):
|
||||
"""Check if this machine is equipment."""
|
||||
mt = self.derived_machinetype
|
||||
return mt.category == 'Equipment' if mt else False
|
||||
|
||||
@property
|
||||
def is_network_device(self):
|
||||
"""Check if this machine is a network device."""
|
||||
mt = self.derived_machinetype
|
||||
return mt.category == 'Network' if mt else False
|
||||
|
||||
@property
|
||||
def is_printer(self):
|
||||
"""Check if this machine is a printer."""
|
||||
mt = self.derived_machinetype
|
||||
return mt.category == 'Printer' if mt else False
|
||||
|
||||
@property
|
||||
def primary_ip(self):
|
||||
"""Get primary IP address from communications."""
|
||||
comm = self.communications.filter_by(
|
||||
isprimary=True,
|
||||
comtypeid=1 # IP type
|
||||
).first()
|
||||
if comm:
|
||||
return comm.ipaddress
|
||||
# Fall back to any IP
|
||||
comm = self.communications.filter_by(comtypeid=1).first()
|
||||
return comm.ipaddress if comm else None
|
||||
|
||||
@@ -115,59 +115,3 @@ class AssetRelationship(BaseModel):
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AssetRelationship {self.sourceassetid} -> {self.targetassetid}>"
|
||||
|
||||
|
||||
class MachineRelationship(BaseModel):
|
||||
"""
|
||||
Relationships between machines.
|
||||
|
||||
Examples:
|
||||
- PC controls CNC machine
|
||||
- Two CNCs are dualpath partners
|
||||
"""
|
||||
__tablename__ = 'machinerelationships'
|
||||
|
||||
relationshipid = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
parentmachineid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('machines.machineid'),
|
||||
nullable=False
|
||||
)
|
||||
childmachineid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('machines.machineid'),
|
||||
nullable=False
|
||||
)
|
||||
relationshiptypeid = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('relationshiptypes.relationshiptypeid'),
|
||||
nullable=False
|
||||
)
|
||||
|
||||
notes = db.Column(db.Text)
|
||||
|
||||
# Relationships
|
||||
parent_machine = db.relationship(
|
||||
'Machine',
|
||||
foreign_keys=[parentmachineid],
|
||||
backref='child_relationships'
|
||||
)
|
||||
child_machine = db.relationship(
|
||||
'Machine',
|
||||
foreign_keys=[childmachineid],
|
||||
backref='parent_relationships'
|
||||
)
|
||||
relationship_type = db.relationship('RelationshipType', backref='relationships')
|
||||
|
||||
__table_args__ = (
|
||||
db.UniqueConstraint(
|
||||
'parentmachineid',
|
||||
'childmachineid',
|
||||
'relationshiptypeid',
|
||||
name='uq_machine_relationship'
|
||||
),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<MachineRelationship {self.parentmachineid} -> {self.childmachineid}>"
|
||||
|
||||
Reference in New Issue
Block a user