# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ Document reference models for typed document references in workflows. """ from typing import List, Optional from pydantic import BaseModel, Field from modules.shared.i18nRegistry import i18nModel class DocumentReference(BaseModel): """Base class for document references""" pass @i18nModel("Dokumentlisten-Referenz") class DocumentListReference(DocumentReference): """Reference to a document list via message label""" messageId: Optional[str] = Field( None, description="Optional message ID for cross-round references", json_schema_extra={"label": "Nachrichten-ID"}, ) label: str = Field( description="Document list label", json_schema_extra={"label": "Bezeichnung"}, ) def to_string(self) -> str: """Convert to string format: docList:messageId:label or docList:label""" if self.messageId: return f"docList:{self.messageId}:{self.label}" return f"docList:{self.label}" @i18nModel("Dokumentelement-Referenz") class DocumentItemReference(DocumentReference): """Reference to a specific document item""" documentId: str = Field( description="Document ID", json_schema_extra={"label": "Dokument-ID"}, ) fileName: Optional[str] = Field( None, description="Optional file name", json_schema_extra={"label": "Dateiname"}, ) def to_string(self) -> str: """Convert to string format: docItem:documentId:fileName or docItem:documentId""" if self.fileName: return f"docItem:{self.documentId}:{self.fileName}" return f"docItem:{self.documentId}" @i18nModel("Dokumentreferenz-Liste") class DocumentReferenceList(BaseModel): """List of document references with conversion methods""" references: List[DocumentReference] = Field( default_factory=list, description="List of document references", json_schema_extra={"label": "Referenzen"}, ) def to_string_list(self) -> List[str]: """Convert all references to string list""" return [ref.to_string() for ref in self.references] @classmethod def from_string_list(cls, stringList: List[str]) -> "DocumentReferenceList": """Parse string list to typed references Supports formats: - docList:label - docList:messageId:label - docItem:documentId - docItem:documentId:fileName """ references = [] for refStr in stringList: if not refStr or not isinstance(refStr, str): continue refStr = refStr.strip() # Parse docList: references if refStr.startswith("docList:"): parts = refStr[8:].split(":", 1) # Remove "docList:" prefix if len(parts) == 2: # docList:messageId:label messageId, label = parts references.append(DocumentListReference(messageId=messageId, label=label)) elif len(parts) == 1 and parts[0]: # docList:label references.append(DocumentListReference(label=parts[0])) # Parse docItem: references elif refStr.startswith("docItem:"): parts = refStr[8:].split(":", 1) # Remove "docItem:" prefix if len(parts) == 2: # docItem:documentId:fileName documentId, fileName = parts references.append(DocumentItemReference(documentId=documentId, fileName=fileName)) elif len(parts) == 1 and parts[0]: # docItem:documentId references.append(DocumentItemReference(documentId=parts[0])) # Unknown format - skip or log warning else: # Try to parse as simple string (backward compatibility) # Assume it's a label if it doesn't match known patterns if refStr: references.append(DocumentListReference(label=refStr)) return cls(references=references)