Files
JQC_multi_tenant/app/models/work_order.py
T

70 lines
2.6 KiB
Python

"""
app/models/work_order.py
------------------------
Vendor work orders (phase36).
A work order dispatches an existing Issue to an external contractor by email.
The contractor opens a tokenized public link (no account required) to see the
scoped issue details and to Acknowledge and then mark the work Completed. Staff
see the work-order status on the issue and are notified on each vendor action.
Builds on the existing free-text `vendor_*` fields on Issue (phase26) — a work
order is the "send it and track it" layer on top of that.
"""
import secrets
from app import db
from app.utils.time_utils import now_eastern
class IssueWorkOrder(db.Model):
__tablename__ = 'issue_work_orders'
id = db.Column(db.Integer, primary_key=True)
issue_id = db.Column(
db.Integer, db.ForeignKey('issues.id', ondelete='CASCADE'),
nullable=False, index=True
)
vendor_name = db.Column(db.String(150), nullable=False)
vendor_email = db.Column(db.String(255), nullable=False)
# Unguessable public access token (URL path segment). Never exposed to
# anyone but the vendor who receives the emailed link.
token = db.Column(db.String(64), nullable=False, unique=True, index=True)
status = db.Column(
db.Enum('sent', 'acknowledged', 'completed'),
nullable=False, default='sent'
)
message = db.Column(db.Text, nullable=True) # staff → vendor instructions
vendor_note = db.Column(db.Text, nullable=True) # vendor → staff completion note
sent_at = db.Column(db.DateTime, nullable=False, default=now_eastern)
acknowledged_at = db.Column(db.DateTime, nullable=True)
completed_at = db.Column(db.DateTime, nullable=True)
created_by = db.Column(
db.Integer, db.ForeignKey('users.id', ondelete='SET NULL'), nullable=True
)
created_at = db.Column(db.DateTime, nullable=False, default=now_eastern)
# Relationships
issue = db.relationship('Issue', backref=db.backref(
'work_orders', lazy='dynamic', cascade='all, delete-orphan',
order_by='IssueWorkOrder.created_at.desc()'))
creator = db.relationship('User', foreign_keys=[created_by])
@staticmethod
def new_token():
"""Return a fresh unguessable token (43 url-safe chars ≈ 256 bits)."""
return secrets.token_urlsafe(32)
@property
def status_label(self):
return {'sent': 'Sent', 'acknowledged': 'Acknowledged',
'completed': 'Completed'}.get(self.status, self.status)
def __repr__(self):
return f'<IssueWorkOrder {self.id} issue={self.issue_id} {self.status}>'