Permit Tracking Automation
Overview
This skill implements automated permit tracking for construction projects. Monitor permit status, manage document requirements, track deadlines, and integrate with local authority systems.
Capabilities:
- Permit application tracking
- Document management
- Deadline monitoring
- Status notifications
- Compliance checking
- Renewal automation
Quick Start
from dataclasses import dataclass, field
from datetime import date, datetime, timedelta
from typing import List, Dict, Optional
from enum import Enum
class PermitType(Enum):
BUILDING = "building"
ELECTRICAL = "electrical"
PLUMBING = "plumbing"
MECHANICAL = "mechanical"
FIRE = "fire"
DEMOLITION = "demolition"
EXCAVATION = "excavation"
OCCUPANCY = "occupancy"
ENVIRONMENTAL = "environmental"
SPECIAL_USE = "special_use"
class PermitStatus(Enum):
DRAFT = "draft"
SUBMITTED = "submitted"
UNDER_REVIEW = "under_review"
REVISION_REQUIRED = "revision_required"
APPROVED = "approved"
ISSUED = "issued"
ACTIVE = "active"
EXPIRED = "expired"
CLOSED = "closed"
@dataclass
class Permit:
permit_id: str
permit_type: PermitType
jurisdiction: str
status: PermitStatus
application_date: date
issued_date: Optional[date] = None
expiry_date: Optional[date] = None
description: str = ""
required_documents: List[str] = field(default_factory=list)
submitted_documents: List[str] = field(default_factory=list)
def check_permit_status(permit: Permit) -> Dict:
"""Check permit status and upcoming deadlines"""
today = date.today()
alerts = []
# Check expiry
if permit.expiry_date:
days_to_expiry = (permit.expiry_date - today).days
if days_to_expiry < 0:
alerts.append({'type': 'expired', 'message': 'Permit has expired'})
elif days_to_expiry <= 30:
alerts.append({'type': 'expiring_soon', 'days': days_to_expiry})
# Check missing documents
missing_docs = set(permit.required_documents) - set(permit.submitted_documents)
if missing_docs:
alerts.append({'type': 'missing_documents', 'documents': list(missing_docs)})
return {
'permit_id': permit.permit_id,
'status': permit.status.value,
'alerts': alerts,
'is_valid': permit.status in [PermitStatus.ACTIVE, PermitStatus.ISSUED] and
(permit.expiry_date is None or permit.expiry_date >= today)
}
# Example
permit = Permit(
permit_id="BP-2024-001",
permit_type=PermitType.BUILDING,
jurisdiction="City of Moscow",
status=PermitStatus.ACTIVE,
application_date=date(2024, 1, 15),
issued_date=date(2024, 2, 1),
expiry_date=date.today() + timedelta(days=25),
required_documents=["drawings", "specs", "survey"],
submitted_documents=["drawings", "specs"]
)
status = check_permit_status(permit)
print(f"Valid: {status['is_valid']}, Alerts: {status['alerts']}")
Comprehensive Permit Management System
Permit Data Model
from dataclasses import dataclass, field
from datetime import date, datetime, timedelta
from typing import List, Dict, Optional, Tuple
from enum import Enum
import uuid
@dataclass
class Jurisdiction:
jurisdiction_id: str
name: str
region: str
country: str
permit_portal_url: Optional[str] = None
contact_email: Optional[str] = None
contact_phone: Optional[str] = None
typical_review_days: Dict[str, int] = field(default_factory=dict)
@dataclass
class RequiredDocument:
document_id: str
document_type: str
description: str
is_mandatory: bool = True
format_requirements: str = ""
template_url: Optional[str] = None
@dataclass
class SubmittedDocument:
document_id: str
document_type: str
filename: str
file_path: str
submitted_date: date
version: int = 1
status: str = "submitted" # submitted, accepted, rejected
reviewer_comments: str = ""
@dataclass
class Inspection:
inspection_id: str
inspection_type: str
scheduled_date: Optional[date] = None
completed_date: Optional[date] = None
inspector: str = ""
result: str = "" # passed, failed, conditional
notes: str = ""
required_corrections: List[str] = field(default_factory=list)
@dataclass
class Fee:
fee_id: str
fee_type: str
amount: float
due_date: date
paid_date: Optional[date] = None
receipt_number: str = ""
@dataclass
class PermitApplication:
# Identification
application_id: str
permit_number: Optional[str] = None
permit_type: PermitType = PermitType.BUILDING
jurisdiction: Jurisdiction = None
# Project reference
project_id: str = ""
project_name: str = ""
project_address: str = ""
parcel_number: str = ""
# Applicant
applicant_name: str = ""
applicant_company: str = ""
applicant_license: str = ""
owner_name: str = ""
# Status
status: PermitStatus = PermitStatus.DRAFT
current_phase: str = ""
submission_date: Optional[date] = None
approval_date: Optional[date] = None
issued_date: Optional[date] = None
expiry_date: Optional[date] = None
# Work scope
work_description: str = ""
project_value: float = 0
building_area_sqm: float = 0
occupancy_type: str = ""
# Documents
required_documents: List[RequiredDocument] = field(default_factory=list)
submitted_documents: List[SubmittedDocument] = field(default_factory=list)
# Inspections
inspections: List[Inspection] = field(default_factory=list)
# Fees
fees: List[Fee] = field(default_factory=list)
# Timeline
review_comments: List[Dict] = field(default_factory=list)
status_history: List[Dict] = field(default_factory=list)
def get_document_status(self) -> Dict:
"""Get document submission status"""
required_types = {d.document_type for d in self.required_documents if d.is_mandatory}
submitted_types = {d.document_type for d in self.submitted_documents}
return {
'required': len(required_types),
'submitted': len(submitted_types),
'missing': list(required_types - submitted_types),
'complete': required_types.issubset(submitted_types)
}
def get_fee_status(self) -> Dict:
"""Get fee payment status"""
total = sum(f.amount for f in self.fees)
paid = sum(f.amount for f in self.fees if f.paid_date)
overdue = [f for f in self.fees if not f.paid_date and f.due_date < date.today()]
return {
'total_amount': total,
'paid_amount': paid,
'outstanding': total - paid,
'overdue_fees': len(overdue)
}
Permit Tracking Engine
from datetime import date, datetime, timedelta
from typing import List, Dict, Optional
import json
class PermitTracker:
"""Track and manage construction permits"""
def __init__(self, project_id: str):
self.project_id = project_id
self.applications: Dict[str, PermitApplication] = {}
self.jurisdictions: Dict[str, Jurisdiction] = {}
def add_jurisdiction(self, jurisdiction: Jurisdiction):
"""Register jurisdiction"""
self.jurisdictions[jurisdiction.jurisdiction_id] = jurisdiction
def create_application(self, permit_type: PermitType,
jurisdiction_id: str,
project_name: str,
project_address: str) -> PermitApplication:
"""Create new permit application"""
jurisdiction = self.jurisdictions.get(jurisdiction_id)
app = PermitApplication(
application_id=f"APP-{uuid.uuid4().hex[:8].upper()}",
permit_type=permit_type,
jurisdiction=jurisdiction,
project_id=self.project_id,
project_name=project_name,
project_address=project_address,