Initial commit: event-driven UK payslip ingest service
Extracted from /home/wizard/code monorepo into its own repo so Woodpecker CI can watch it. Identical content to /home/wizard/code commit e426028. See README.md for overview, env vars, and Paperless workflow config. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
57484619c1
27 changed files with 2878 additions and 0 deletions
42
payslip_ingest/schema.py
Normal file
42
payslip_ingest/schema.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue