import json from decimal import Decimal from typing import Any, List from pydantic import BaseModel, Field, field_validator from monday_com_orca_backend.typings import LabelId class LabelFinancials(BaseModel): """Pydantic model for label financials. Input payload uses UPPERCASE keys; we expose snake_case fields. Non-ID fields arrive as stringified JSON and are parsed into dicts. """ label_id: LabelId = Field(..., alias="LABEL_ID") gross: dict[str, Any] = Field(default_factory=dict, alias="GROSS") distribution_fees: dict[str, Any] = Field( default_factory=dict, alias="DISTRIBUTION_FEES" ) distribution_fees_pct: dict[str, Any] = Field( default_factory=dict, alias="DISTRIBUTION_FEES_PCT" ) @field_validator( "gross", "distribution_fees", "distribution_fees_pct", mode="before" ) @classmethod def _parse_json_fields(cls, v: Any) -> dict[str, Any]: """Accept dicts as-is, parse JSON strings, coerce falsy to empty dict. Raises ValueError if provided JSON does not decode to a dict. """ if v is None or v == "": return {} if isinstance(v, dict): return v if isinstance(v, (bytes, bytearray)): v = v.decode("utf-8") if isinstance(v, str): parsed = json.loads(v) if not isinstance(parsed, dict): raise ValueError("Expected a JSON object (dict)") return parsed raise ValueError("Expected dict or JSON string for field") class AssetCount(BaseModel): """Count and gross amount for a specific asset type.""" count: int = Field(alias="CNT", description="Count of assets for the asset type") gross: Decimal = Field(alias="GROSS", description="Gross amount for the asset type") class LabelAssets(BaseModel): """Label asset counts and gross amounts for various asset types.""" digital_releases: AssetCount = Field(alias="digital_releases") physical_releases: AssetCount = Field(alias="physical_releases") music_videos: AssetCount = Field(alias="music_videos") class AdvanceItem(BaseModel): amount: float currency: str class SalesforceMeta(BaseModel): advance: List[AdvanceItem] = Field( alias="ADVANCE", description="List of advance items, as found in Salesforce." ) label_id: int = Field(alias="LABEL_ID", description="Label ID.") label_id_raw: str = Field( alias="LABEL_ID_RAW", description=( "Raw label ID as a string, used for parsing purposes. " "It might contain non-numeric characters or be in a " "different format than LABEL_ID, even including " "multiple IDs in a single string." ), ) @field_validator("advance", mode="before") @classmethod def parse_advance_json(cls, v): if isinstance(v, str): return json.loads(v) return v @field_validator("label_id", mode="before") @classmethod def parse_label_id(cls, v): if isinstance(v, str): return int(v) return v