Initial commit - Fire alarm management application

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-19 21:57:25 -05:00
commit 892ac3d23b
24 changed files with 4183 additions and 0 deletions

182
app/models.py Normal file
View File

@@ -0,0 +1,182 @@
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
db = SQLAlchemy()
class Job(db.Model):
__tablename__ = 'jobs'
id = db.Column(db.Integer, primary_key=True)
job_number = db.Column(db.String(50), unique=True, nullable=False)
job_name = db.Column(db.String(200), nullable=False)
location = db.Column(db.String(300))
percent_complete = db.Column(db.Float, default=0.0)
est_starting_qtr = db.Column(db.String(50))
# Budget fields
fire_alarm_budget = db.Column(db.Float, default=0.0)
labor_estimate = db.Column(db.Float, default=0.0)
material_estimate = db.Column(db.Float, default=0.0)
amount_left_on_contract = db.Column(db.Float, default=0.0)
# Assignment fields
pm_assigned = db.Column(db.String(100))
aor = db.Column(db.String(50))
fire_vendor = db.Column(db.String(100))
install_partner = db.Column(db.String(100))
ps_or_install = db.Column(db.String(50))
subcontractor = db.Column(db.String(100))
pci = db.Column(db.String(50))
# Communication
voip_or_phone = db.Column(db.String(50))
plans = db.Column(db.String(50))
# Notes
notes = db.Column(db.Text)
issues = db.Column(db.Text)
# Milestones
milestone_1 = db.Column(db.String(200))
milestone_2 = db.Column(db.String(200))
milestone_3 = db.Column(db.String(200))
milestone_4 = db.Column(db.String(200))
milestone_5 = db.Column(db.String(200))
milestone_6 = db.Column(db.String(200))
milestone_7 = db.Column(db.String(200))
# Key dates
elevator_final = db.Column(db.Date)
pretest = db.Column(db.Date)
final_date = db.Column(db.Date)
co_drop_dead_date = db.Column(db.Date)
# Other
number_of_units = db.Column(db.Integer)
sep_club_house = db.Column(db.String(50))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Relationships
phases = db.relationship('Phase', backref='job', lazy=True, cascade='all, delete-orphan')
materials = db.relationship('Material', backref='job', lazy=True, cascade='all, delete-orphan')
def to_dict(self):
return {
'id': self.id,
'job_number': self.job_number,
'job_name': self.job_name,
'location': self.location,
'percent_complete': self.percent_complete,
'est_starting_qtr': self.est_starting_qtr,
'fire_alarm_budget': self.fire_alarm_budget,
'labor_estimate': self.labor_estimate,
'material_estimate': self.material_estimate,
'amount_left_on_contract': self.amount_left_on_contract,
'pm_assigned': self.pm_assigned,
'aor': self.aor,
'fire_vendor': self.fire_vendor,
'install_partner': self.install_partner,
'ps_or_install': self.ps_or_install,
'subcontractor': self.subcontractor,
'pci': self.pci,
'voip_or_phone': self.voip_or_phone,
'plans': self.plans,
'notes': self.notes,
'issues': self.issues,
'milestone_1': self.milestone_1,
'milestone_2': self.milestone_2,
'milestone_3': self.milestone_3,
'milestone_4': self.milestone_4,
'milestone_5': self.milestone_5,
'milestone_6': self.milestone_6,
'milestone_7': self.milestone_7,
'elevator_final': self.elevator_final.isoformat() if self.elevator_final else None,
'pretest': self.pretest.isoformat() if self.pretest else None,
'final_date': self.final_date.isoformat() if self.final_date else None,
'co_drop_dead_date': self.co_drop_dead_date.isoformat() if self.co_drop_dead_date else None,
'number_of_units': self.number_of_units,
'sep_club_house': self.sep_club_house,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
}
class Phase(db.Model):
__tablename__ = 'phases'
id = db.Column(db.Integer, primary_key=True)
job_id = db.Column(db.Integer, db.ForeignKey('jobs.id'), nullable=False)
phase_type = db.Column(db.String(50)) # rough_in, trim, commissioning, final, turnover
phase_number = db.Column(db.Integer)
points = db.Column(db.Integer, default=0)
mobilization_date = db.Column(db.Date)
start_date = db.Column(db.Date)
due_date = db.Column(db.Date)
completion_date = db.Column(db.Date)
men_on_site = db.Column(db.Integer, default=0)
completed = db.Column(db.Boolean, default=False)
due_date_met = db.Column(db.Boolean)
pci_man_hours = db.Column(db.Float, default=0.0)
rer_fire_mgmt_hours = db.Column(db.Float, default=0.0)
rer_fire_mgmt_hours_avl = db.Column(db.Float, default=0.0)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'job_id': self.job_id,
'phase_type': self.phase_type,
'phase_number': self.phase_number,
'points': self.points,
'mobilization_date': self.mobilization_date.isoformat() if self.mobilization_date else None,
'start_date': self.start_date.isoformat() if self.start_date else None,
'due_date': self.due_date.isoformat() if self.due_date else None,
'completion_date': self.completion_date.isoformat() if self.completion_date else None,
'men_on_site': self.men_on_site,
'completed': self.completed,
'due_date_met': self.due_date_met,
'pci_man_hours': self.pci_man_hours,
'rer_fire_mgmt_hours': self.rer_fire_mgmt_hours,
'rer_fire_mgmt_hours_avl': self.rer_fire_mgmt_hours_avl,
}
class Material(db.Model):
__tablename__ = 'materials'
id = db.Column(db.Integer, primary_key=True)
job_id = db.Column(db.Integer, db.ForeignKey('jobs.id'), nullable=False)
part_number = db.Column(db.String(100))
quantity = db.Column(db.Integer, default=0)
ordered = db.Column(db.Boolean, default=False)
received = db.Column(db.Boolean, default=False)
received_qty = db.Column(db.Integer, default=0)
received_by = db.Column(db.String(100))
delivered_qty = db.Column(db.Integer, default=0)
delivered_to = db.Column(db.String(200))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'job_id': self.job_id,
'part_number': self.part_number,
'quantity': self.quantity,
'ordered': self.ordered,
'received': self.received,
'received_qty': self.received_qty,
'received_by': self.received_by,
'delivered_qty': self.delivered_qty,
'delivered_to': self.delivered_to,
}