Files
fegger 17e0496d2f Add OcrResponse schema and tighten invoice validation
- Adds OcrResponse Pydantic schema for OCR branch JSON output.

- Validates invoice_date and due_date as strict ISO 8601 calendar dates.

- Adds field descriptions to InvoiceLineItem for clearer VLM prompts.

- Expands schema tests for dates, decimal coercion, negatives, and line_items_sum().
2026-08-21 16:44:09 +02:00

85 lines
2.3 KiB
Python

"""Tests for invoice schema validation."""
from __future__ import annotations
from decimal import Decimal
import pytest
from pydantic import ValidationError
from odoo_ocr.schemas import ExtractedInvoice, InvoiceLineItem
def test_accepts_valid_iso_dates() -> None:
invoice = ExtractedInvoice(
vendor_name="A",
invoice_number="1",
invoice_date="2024-01-01",
due_date="2024-02-01",
)
assert invoice.invoice_date == "2024-01-01"
assert invoice.due_date == "2024-02-01"
def test_rejects_non_iso_date_format() -> None:
with pytest.raises(ValidationError, match="ISO 8601"):
ExtractedInvoice(
vendor_name="A",
invoice_number="1",
invoice_date="May 1, 2024",
)
def test_rejects_invalid_calendar_date() -> None:
with pytest.raises(ValidationError, match="not a valid calendar date"):
ExtractedInvoice(
vendor_name="A",
invoice_number="1",
invoice_date="2024-02-30",
)
def test_due_date_optional() -> None:
invoice = ExtractedInvoice(
vendor_name="A",
invoice_number="1",
invoice_date="2024-01-01",
)
assert invoice.due_date is None
def test_invoice_line_item_decimal_coercion() -> None:
line = InvoiceLineItem(
description="Widgets",
quantity="2",
unit_price="10.5",
total_price="21.0",
tax_rate="20",
)
assert line.quantity == Decimal("2")
assert line.unit_price == Decimal("10.5")
assert line.total_price == Decimal("21.0")
assert line.tax_rate == Decimal("20")
def test_invoice_line_item_rejects_negative_values() -> None:
with pytest.raises(ValidationError):
InvoiceLineItem(description="X", quantity=-1)
with pytest.raises(ValidationError):
InvoiceLineItem(description="X", unit_price=-1)
with pytest.raises(ValidationError):
InvoiceLineItem(description="X", tax_rate=-5)
def test_line_items_sum() -> None:
invoice = ExtractedInvoice(
vendor_name="A",
invoice_number="1",
invoice_date="2024-01-01",
line_items=[
InvoiceLineItem(description="X", total_price=Decimal("100")),
InvoiceLineItem(description="Y", total_price=Decimal("50.50")),
],
)
assert invoice.line_items_sum() == Decimal("150.50")