- Added ProjectModel class in models/project_model.py to define structure for Filevine project data with proper type hints and conversion methods (to_dict/from_dict) - Implemented get_firestore_document() helper function in app.py for retrieving specific Firestore documents - Enhanced dashboard pagination in app.py with improved error handling and debugging output for property contacts and project IDs - Overhauled sync.py with: * Parallel processing using ThreadPoolExecutor for efficient project synchronization * Comprehensive extraction of project data from Filevine forms (newFileReview, datesAndDeadlines, propertyInfo, etc.) * Improved error handling and logging throughout the sync process * Proper handling of date conversions and field mappings from Filevine to Firestore * Added property contacts email extraction and viewing_emails array population * Added support for filtering projects by specific ProjectId (15914808) for targeted sync - Added proper initialization of Filevine client in worker threads using thread-local storage - Improved handling of optional fields and default values in ProjectModel - Added detailed logging for progress tracking during synchronization This implementation enables reliable synchronization of Filevine project data to Firestore with proper data modeling and error handling, supporting the dashboard's data requirements.
250 lines
12 KiB
Python
250 lines
12 KiB
Python
"""
|
|
Shared data model for Project entities used across the application.
|
|
This defines the structure of project data that is fetched from Filevine and stored in Firestore.
|
|
"""
|
|
|
|
from typing import List, Dict, Any, Optional
|
|
from datetime import datetime
|
|
import pytz
|
|
|
|
class ProjectModel:
|
|
"""
|
|
Data model for a Filevine project with all its associated fields.
|
|
This model defines the structure that will be used for Firestore storage
|
|
and API responses.
|
|
"""
|
|
|
|
def __init__(self,
|
|
client: str = "",
|
|
matter_description: str = "",
|
|
defendant_1: str = "",
|
|
matter_open: str = "",
|
|
notice_type: str = "",
|
|
case_number: str = "",
|
|
premises_address: str = "",
|
|
premises_city: str = "",
|
|
responsible_attorney: str = "",
|
|
staff_person: str = "",
|
|
staff_person_2: str = "",
|
|
phase_name: str = "",
|
|
completed_tasks: List[Dict[str, Any]] = None,
|
|
pending_tasks: List[Dict[str, Any]] = None,
|
|
notice_service_date: str = "",
|
|
notice_expiration_date: str = "",
|
|
case_field_date: str = "",
|
|
daily_rent_damages: str = "",
|
|
default_date: str = "",
|
|
demurrer_hearing_date: str = "",
|
|
motion_to_strike_hearing_date: str = "",
|
|
motion_to_quash_hearing_date: str = "",
|
|
other_motion_hearing_date: str = "",
|
|
msc_date: str = "",
|
|
msc_time: str = "",
|
|
msc_address: str = "",
|
|
msc_div_dept_room: str = "",
|
|
trial_date: str = "",
|
|
trial_time: str = "",
|
|
trial_address: str = "",
|
|
trial_div_dept_room: str = "",
|
|
final_result: str = "",
|
|
date_of_settlement: str = "",
|
|
final_obligation: str = "",
|
|
def_comply_stip: str = "",
|
|
judgment_date: str = "",
|
|
writ_issued_date: str = "",
|
|
scheduled_lockout: str = "",
|
|
oppose_stays: str = "",
|
|
premises_safety: str = "",
|
|
matter_gate_code: str = "",
|
|
date_possession_recovered: str = "",
|
|
attorney_fees: str = "",
|
|
costs: str = "",
|
|
documents_url: str = "",
|
|
service_attempt_date_1: str = "",
|
|
contacts: List[Dict[str, Any]] = None,
|
|
project_email_address: str = "",
|
|
number: str = "",
|
|
incident_date: str = "",
|
|
project_id: str = "",
|
|
project_name: str = "",
|
|
project_url: str = "",
|
|
property_contacts: Dict[str, Any] = None,
|
|
viewing_emails: List[str] = None
|
|
):
|
|
|
|
self.client = client
|
|
self.matter_description = matter_description
|
|
self.defendant_1 = defendant_1
|
|
self.matter_open = matter_open
|
|
self.notice_type = notice_type
|
|
self.case_number = case_number
|
|
self.premises_address = premises_address
|
|
self.premises_city = premises_city
|
|
self.responsible_attorney = responsible_attorney
|
|
self.staff_person = staff_person
|
|
self.staff_person_2 = staff_person_2
|
|
self.phase_name = phase_name
|
|
self.completed_tasks = completed_tasks or []
|
|
self.pending_tasks = pending_tasks or []
|
|
self.notice_service_date = notice_service_date
|
|
self.notice_expiration_date = notice_expiration_date
|
|
self.case_field_date = case_field_date
|
|
self.daily_rent_damages = daily_rent_damages
|
|
self.default_date = default_date
|
|
self.demurrer_hearing_date = demurrer_hearing_date
|
|
self.motion_to_strike_hearing_date = motion_to_strike_hearing_date
|
|
self.motion_to_quash_hearing_date = motion_to_quash_hearing_date
|
|
self.other_motion_hearing_date = other_motion_hearing_date
|
|
self.msc_date = msc_date
|
|
self.msc_time = msc_time
|
|
self.msc_address = msc_address
|
|
self.msc_div_dept_room = msc_div_dept_room
|
|
self.trial_date = trial_date
|
|
self.trial_time = trial_time
|
|
self.trial_address = trial_address
|
|
self.trial_div_dept_room = trial_div_dept_room
|
|
self.final_result = final_result
|
|
self.date_of_settlement = date_of_settlement
|
|
self.final_obligation = final_obligation
|
|
self.def_comply_stip = def_comply_stip
|
|
self.judgment_date = judgment_date
|
|
self.writ_issued_date = writ_issued_date
|
|
self.scheduled_lockout = scheduled_lockout
|
|
self.oppose_stays = oppose_stays
|
|
self.premises_safety = premises_safety
|
|
self.matter_gate_code = matter_gate_code
|
|
self.date_possession_recovered = date_possession_recovered
|
|
self.attorney_fees = attorney_fees
|
|
self.costs = costs
|
|
self.documents_url = documents_url
|
|
self.service_attempt_date_1 = service_attempt_date_1
|
|
self.contacts = contacts or []
|
|
self.project_email_address = project_email_address
|
|
self.number = number
|
|
self.incident_date = incident_date
|
|
self.project_id = project_id
|
|
self.project_name = project_name
|
|
self.project_url = project_url
|
|
self.property_contacts = property_contacts or {}
|
|
self.viewing_emails = viewing_emails or []
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
"""Convert the ProjectModel to a dictionary for Firestore storage."""
|
|
return {
|
|
"client": self.client,
|
|
"matter_description": self.matter_description,
|
|
"defendant_1": self.defendant_1,
|
|
"matter_open": self.matter_open,
|
|
"notice_type": self.notice_type,
|
|
"case_number": self.case_number,
|
|
"premises_address": self.premises_address,
|
|
"premises_city": self.premises_city,
|
|
"responsible_attorney": self.responsible_attorney,
|
|
"staff_person": self.staff_person,
|
|
"staff_person_2": self.staff_person_2,
|
|
"phase_name": self.phase_name,
|
|
"completed_tasks": self.completed_tasks,
|
|
"pending_tasks": self.pending_tasks,
|
|
"notice_service_date": self.notice_service_date,
|
|
"notice_expiration_date": self.notice_expiration_date,
|
|
"case_field_date": self.case_field_date,
|
|
"daily_rent_damages": self.daily_rent_damages,
|
|
"default_date": self.default_date,
|
|
"demurrer_hearing_date": self.demurrer_hearing_date,
|
|
"motion_to_strike_hearing_date": self.motion_to_strike_hearing_date,
|
|
"motion_to_quash_hearing_date": self.motion_to_quash_hearing_date,
|
|
"other_motion_hearing_date": self.other_motion_hearing_date,
|
|
"msc_date": self.msc_date,
|
|
"msc_time": self.msc_time,
|
|
"msc_address": self.msc_address,
|
|
"msc_div_dept_room": self.msc_div_dept_room,
|
|
"trial_date": self.trial_date,
|
|
"trial_time": self.trial_time,
|
|
"trial_address": self.trial_address,
|
|
"trial_div_dept_room": self.trial_div_dept_room,
|
|
"final_result": self.final_result,
|
|
"date_of_settlement": self.date_of_settlement,
|
|
"final_obligation": self.final_obligation,
|
|
"def_comply_stip": self.def_comply_stip,
|
|
"judgment_date": self.judgment_date,
|
|
"writ_issued_date": self.writ_issued_date,
|
|
"scheduled_lockout": self.scheduled_lockout,
|
|
"oppose_stays": self.oppose_stays,
|
|
"premises_safety": self.premises_safety,
|
|
"matter_gate_code": self.matter_gate_code,
|
|
"date_possession_recovered": self.date_possession_recovered,
|
|
"attorney_fees": self.attorney_fees,
|
|
"costs": self.costs,
|
|
"documents_url": self.documents_url,
|
|
"service_attempt_date_1": self.service_attempt_date_1,
|
|
"contacts": self.contacts,
|
|
"ProjectEmailAddress": self.project_email_address,
|
|
"Number": self.number,
|
|
"IncidentDate": self.incident_date,
|
|
"ProjectId": self.project_id,
|
|
"ProjectName": self.project_name,
|
|
"ProjectUrl": self.project_url,
|
|
"property_contacts": self.property_contacts,
|
|
"viewing_emails": self.viewing_emails
|
|
}
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: Dict[str, Any]) -> 'ProjectModel':
|
|
"""Create a ProjectModel instance from a dictionary (e.g., from Firestore)."""
|
|
return cls(
|
|
client=data.get("client", ""),
|
|
matter_description=data.get("matter_description", ""),
|
|
defendant_1=data.get("defendant_1", ""),
|
|
matter_open=data.get("matter_open", ""),
|
|
notice_type=data.get("notice_type", ""),
|
|
case_number=data.get("case_number", ""),
|
|
premises_address=data.get("premises_address", ""),
|
|
premises_city=data.get("premises_city", ""),
|
|
responsible_attorney=data.get("responsible_attorney", ""),
|
|
staff_person=data.get("staff_person", ""),
|
|
staff_person_2=data.get("staff_person_2", ""),
|
|
phase_name=data.get("phase_name", ""),
|
|
completed_tasks=data.get("completed_tasks", []),
|
|
pending_tasks=data.get("pending_tasks", []),
|
|
notice_service_date=data.get("notice_service_date", ""),
|
|
notice_expiration_date=data.get("notice_expiration_date", ""),
|
|
case_field_date=data.get("case_field_date", ""),
|
|
daily_rent_damages=data.get("daily_rent_damages", ""),
|
|
default_date=data.get("default_date", ""),
|
|
demurrer_hearing_date=data.get("demurrer_hearing_date", ""),
|
|
motion_to_strike_hearing_date=data.get("motion_to_strike_hearing_date", ""),
|
|
motion_to_quash_hearing_date=data.get("motion_to_quash_hearing_date", ""),
|
|
other_motion_hearing_date=data.get("other_motion_hearing_date", ""),
|
|
msc_date=data.get("msc_date", ""),
|
|
msc_time=data.get("msc_time", ""),
|
|
msc_address=data.get("msc_address", ""),
|
|
msc_div_dept_room=data.get("msc_div_dept_room", ""),
|
|
trial_date=data.get("trial_date", ""),
|
|
trial_time=data.get("trial_time", ""),
|
|
trial_address=data.get("trial_address", ""),
|
|
trial_div_dept_room=data.get("trial_div_dept_room", ""),
|
|
final_result=data.get("final_result", ""),
|
|
date_of_settlement=data.get("date_of_settlement", ""),
|
|
final_obligation=data.get("final_obligation", ""),
|
|
def_comply_stip=data.get("def_comply_stip", ""),
|
|
judgment_date=data.get("judgment_date", ""),
|
|
writ_issued_date=data.get("writ_issued_date", ""),
|
|
scheduled_lockout=data.get("scheduled_lockout", ""),
|
|
oppose_stays=data.get("oppose_stays", ""),
|
|
premises_safety=data.get("premises_safety", ""),
|
|
matter_gate_code=data.get("matter_gate_code", ""),
|
|
date_possession_recovered=data.get("date_possession_recovered", ""),
|
|
attorney_fees=data.get("attorney_fees", ""),
|
|
costs=data.get("costs", ""),
|
|
documents_url=data.get("documents_url", ""),
|
|
service_attempt_date_1=data.get("service_attempt_date_1", ""),
|
|
contacts=data.get("contacts", []),
|
|
project_email_address=data.get("ProjectEmailAddress", ""),
|
|
number=data.get("Number", ""),
|
|
incident_date=data.get("IncidentDate", ""),
|
|
project_id=data.get("ProjectId", ""),
|
|
project_name=data.get("ProjectName", ""),
|
|
project_url=data.get("ProjectUrl", ""),
|
|
property_contacts=data.get("property_contacts", {}),
|
|
viewing_emails=data.get("viewing_emails", [])
|
|
) |