"""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")