adobe-to-docusign-migrator/src/models/normalized_template.py

79 lines
2.5 KiB
Python

"""
normalized_template.py
-----------------------
Platform-agnostic intermediate schema that decouples Adobe Sign extraction
from DocuSign composition. Both platforms' data is converted to/from this
model so neither side is tightly coupled.
"""
from __future__ import annotations
from enum import Enum
from typing import Any, Optional
from pydantic import BaseModel, Field
class ActionType(str, Enum):
SIGN = "SIGN"
APPROVE = "APPROVE"
CC = "CC"
ACKNOWLEDGE = "ACKNOWLEDGE"
class NormalizedRole(BaseModel):
name: str
order: int
action_type: ActionType = ActionType.SIGN
class NormalizedField(BaseModel):
"""One form field in the normalized intermediate representation."""
type: str # e.g. "signature", "text", "checkbox"
label: str
page: int
x: float
y: float
width: float
height: float
required: bool = False
read_only: bool = False
role_name: str = "" # which role this field belongs to
options: list[str] = Field(default_factory=list) # for dropdown/radio
validation: str = "" # e.g. "DATE", "NUMBER"
content_type: str = "" # e.g. "SIGNATURE_DATE", "SIGNER_NAME"
conditional_parent_label: Optional[str] = None
conditional_parent_value: Optional[str] = None
raw: dict[str, Any] = Field(default_factory=dict) # original source data
class NormalizedDocument(BaseModel):
name: str
content_base64: str = "" # base64-encoded PDF bytes
checksum_sha256: str = "" # SHA-256 hex of raw bytes before encoding
source_path: str = ""
class NormalizedTemplate(BaseModel):
"""
Platform-agnostic representation of an eSignature template.
Used as the bridge between Adobe Sign and DocuSign.
"""
name: str
description: str = ""
email_subject: str = ""
email_message: str = ""
roles: list[NormalizedRole] = Field(default_factory=list)
documents: list[NormalizedDocument] = Field(default_factory=list)
fields: list[NormalizedField] = Field(default_factory=list)
reminder_enabled: bool = False
expiration_days: Optional[int] = None
source_id: str = "" # original Adobe Sign template ID
unsupported_features: list[str] = Field(default_factory=list)
def role_names(self) -> list[str]:
return [r.name for r in self.roles]
def fields_for_role(self, role_name: str) -> list[NormalizedField]:
return [f for f in self.fields if f.role_name == role_name]