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().
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
"""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")
|
||||
Reference in New Issue
Block a user