from datetime import date from decimal import Decimal from pydantic import BaseModel, ConfigDict, Field TOTALS_TOLERANCE = Decimal("0.02") class ExtractedPayslip(BaseModel): model_config = ConfigDict(extra="forbid") pay_date: date pay_period_start: date | None = None pay_period_end: date | None = None employer: str | None = None currency: str = "GBP" gross_pay: Decimal income_tax: Decimal = Field(default=Decimal("0")) national_insurance: Decimal = Field(default=Decimal("0")) pension_employee: Decimal = Field(default=Decimal("0")) pension_employer: Decimal = Field(default=Decimal("0")) student_loan: Decimal = Field(default=Decimal("0")) other_deductions: dict[str, Decimal] = Field(default_factory=dict) net_pay: Decimal class WebhookPayload(BaseModel): model_config = ConfigDict(extra="forbid") document_id: int def validate_totals(p: ExtractedPayslip) -> bool: """Check that gross - deductions ≈ net within a 2p tolerance. Employer pension is excluded — it never leaves the employer's books and doesn't affect take-home pay arithmetic. """ deductions = (p.income_tax + p.national_insurance + p.pension_employee + p.student_loan + sum(p.other_deductions.values(), start=Decimal("0"))) diff = abs(p.gross_pay - deductions - p.net_pay) return diff < TOTALS_TOLERANCE