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, }