189 lines
6.5 KiB
Python
189 lines
6.5 KiB
Python
"""
|
|
Project domain metadata enrichment.
|
|
Handles Project, ProjectSession, and ProjectPunchlist entities.
|
|
"""
|
|
from typing import Dict, Any, Set
|
|
|
|
from asgiref.sync import sync_to_async
|
|
|
|
from core.models.enums import EventTypeChoices
|
|
|
|
|
|
PROJECT_EVENTS: Set[str] = {
|
|
EventTypeChoices.PROJECT_CREATED,
|
|
EventTypeChoices.PROJECT_UPDATED,
|
|
EventTypeChoices.PROJECT_STATUS_CHANGED,
|
|
EventTypeChoices.PROJECT_COMPLETED,
|
|
EventTypeChoices.PROJECT_CANCELLED,
|
|
EventTypeChoices.PROJECT_DISPATCHED,
|
|
EventTypeChoices.PROJECT_SESSION_OPENED,
|
|
EventTypeChoices.PROJECT_SESSION_CLOSED,
|
|
EventTypeChoices.PROJECT_SESSION_REVERTED,
|
|
EventTypeChoices.PROJECT_TASK_COMPLETED,
|
|
EventTypeChoices.PROJECT_TASK_UNCOMPLETED,
|
|
EventTypeChoices.PROJECT_PUNCHLIST_CREATED,
|
|
EventTypeChoices.PROJECT_PUNCHLIST_UPDATED,
|
|
EventTypeChoices.PROJECT_PUNCHLIST_DELETED,
|
|
}
|
|
|
|
|
|
async def enrich_project_domain(entity_type: str, entity_id: str) -> Dict[str, Any]:
|
|
"""Enrich metadata for project-domain events."""
|
|
if entity_type == 'Project':
|
|
return await _load_project_metadata(entity_id)
|
|
elif entity_type == 'ProjectSession':
|
|
return await _load_project_session_metadata(entity_id)
|
|
elif entity_type == 'ProjectPunchlist':
|
|
return await _load_project_punchlist_metadata(entity_id)
|
|
return {}
|
|
|
|
|
|
async def _load_project_metadata(entity_id: str) -> Dict[str, Any]:
|
|
"""Load metadata from a Project entity."""
|
|
from core.models.project import Project
|
|
|
|
def _load():
|
|
try:
|
|
project = Project.objects.select_related(
|
|
'customer',
|
|
'account_address',
|
|
'account_address__account',
|
|
'account_address__account__customer',
|
|
).get(pk=entity_id)
|
|
|
|
return _extract_project_metadata(project)
|
|
except Project.DoesNotExist:
|
|
return {}
|
|
|
|
return await sync_to_async(_load)()
|
|
|
|
|
|
async def _load_project_session_metadata(entity_id: str) -> Dict[str, Any]:
|
|
"""Load metadata from a ProjectSession entity."""
|
|
from core.models.session import ProjectSession
|
|
|
|
def _load():
|
|
try:
|
|
session = ProjectSession.objects.select_related(
|
|
'project',
|
|
'customer',
|
|
'account_address',
|
|
'account_address__account',
|
|
'account_address__account__customer',
|
|
).get(pk=entity_id)
|
|
|
|
return _extract_project_session_metadata(session)
|
|
except ProjectSession.DoesNotExist:
|
|
return {}
|
|
|
|
return await sync_to_async(_load)()
|
|
|
|
|
|
async def _load_project_punchlist_metadata(entity_id: str) -> Dict[str, Any]:
|
|
"""Load metadata from a ProjectPunchlist entity."""
|
|
from core.models.project_punchlist import ProjectPunchlist
|
|
|
|
def _load():
|
|
try:
|
|
punchlist = ProjectPunchlist.objects.select_related(
|
|
'project',
|
|
'project__customer',
|
|
'project__account_address',
|
|
'project__account_address__account',
|
|
).get(pk=entity_id)
|
|
|
|
metadata = {'project_id': str(punchlist.project_id)}
|
|
if punchlist.project:
|
|
metadata.update(_extract_project_metadata(punchlist.project))
|
|
return metadata
|
|
except ProjectPunchlist.DoesNotExist:
|
|
return {}
|
|
|
|
return await sync_to_async(_load)()
|
|
|
|
|
|
def _extract_project_metadata(project) -> Dict[str, Any]:
|
|
"""Extract metadata dict from a pre-loaded Project object."""
|
|
metadata = {}
|
|
|
|
# Project name
|
|
if project.name:
|
|
metadata['project_name'] = project.name
|
|
|
|
# Date
|
|
if project.date:
|
|
metadata['date'] = str(project.date)
|
|
|
|
# Projects can be affiliated with account (via account_address) OR direct customer
|
|
if project.account_address_id and project.account_address:
|
|
# Account-affiliated project
|
|
if project.account_address.account:
|
|
metadata['account_name'] = project.account_address.account.name or ''
|
|
if project.account_address.account.customer:
|
|
metadata['customer_name'] = project.account_address.account.customer.name or ''
|
|
|
|
# Address from account_address
|
|
address_parts = []
|
|
if project.account_address.street_address:
|
|
address_parts.append(project.account_address.street_address)
|
|
if project.account_address.city:
|
|
address_parts.append(project.account_address.city)
|
|
if address_parts:
|
|
metadata['address'] = ', '.join(address_parts)
|
|
|
|
elif project.customer:
|
|
# Direct customer project (no account affiliation)
|
|
metadata['customer_name'] = project.customer.name or ''
|
|
# Use customer name as account_name fallback for template compatibility
|
|
metadata['account_name'] = project.customer.name or ''
|
|
|
|
# Address from project fields
|
|
address_parts = []
|
|
if project.street_address:
|
|
address_parts.append(project.street_address)
|
|
if project.city:
|
|
address_parts.append(project.city)
|
|
if address_parts:
|
|
metadata['address'] = ', '.join(address_parts)
|
|
|
|
return metadata
|
|
|
|
|
|
def _extract_project_session_metadata(session) -> Dict[str, Any]:
|
|
"""Extract metadata dict from a preloaded ProjectSession object."""
|
|
metadata = {}
|
|
|
|
# Project ID for reference
|
|
if session.project_id:
|
|
metadata['project_id'] = str(session.project_id)
|
|
|
|
# Project name and date
|
|
if session.project:
|
|
if session.project.name:
|
|
metadata['project_name'] = session.project.name
|
|
if session.project.date:
|
|
metadata['date'] = str(session.project.date)
|
|
|
|
# Account/customer via account_address path
|
|
if session.account_address_id and session.account_address:
|
|
if session.account_address.account:
|
|
metadata['account_name'] = session.account_address.account.name or ''
|
|
if session.account_address.account.customer:
|
|
metadata['customer_name'] = session.account_address.account.customer.name or ''
|
|
|
|
# Address
|
|
address_parts = []
|
|
if session.account_address.street_address:
|
|
address_parts.append(session.account_address.street_address)
|
|
if session.account_address.city:
|
|
address_parts.append(session.account_address.city)
|
|
if address_parts:
|
|
metadata['address'] = ', '.join(address_parts)
|
|
|
|
elif session.customer:
|
|
# Direct customer project
|
|
metadata['customer_name'] = session.customer.name or ''
|
|
metadata['account_name'] = session.customer.name or ''
|
|
|
|
return metadata
|