import json from datetime import date from decimal import Decimal import pytest from pydantic import ValidationError as PydanticValidationError from cyclone.parsers.models import ( Address, BillingProvider, ClaimHeader, ClaimOutput, Diagnosis, Envelope, Payer, Procedure, ServiceLine, Subscriber, ValidationIssue, ValidationReport, ) def test_address_round_trip(): a = Address(line1="1100 East Main St", line2="Suite A", city="Montrose", state="CO", zip="81401") d = a.model_dump() assert d["line1"] == "1100 East Main St" assert d["line2"] == "Suite A" assert Address.model_validate(d) == a def test_address_line2_optional(): a = Address(line1="1 Main", city="X", state="CO", zip="80000") assert a.line2 is None def test_subscriber_splits_name(): s = Subscriber(first_name="John", last_name="Doe", member_id="ABC", dob=date(1980, 1, 1), gender="M", address=Address(line1="x", city="x", state="CO", zip="80000")) assert s.first_name == "John" assert s.gender == "M" def test_service_line_units_are_decimal(): sl = ServiceLine( line_number=1, procedure=Procedure(qualifier="HC", code="99213", modifiers=[]), charge=Decimal("100.00"), unit_type="UN", units=Decimal("1.0"), ) assert sl.units == Decimal("1.0") def test_claim_header_total_charge_decimal(): h = ClaimHeader(claim_id="C1", total_charge=Decimal("151.72"), place_of_service="12", frequency_code="1", provider_signature="Y", assignment="Y", release_of_info="Y", prior_auth="3173") assert h.total_charge == Decimal("151.72") def test_validation_issue_strict_severity(): issue = ValidationIssue(rule="R001", severity="error", message="bad") assert issue.severity == "error" with pytest.raises(PydanticValidationError): ValidationIssue(rule="R001", severity="WTF", message="bad") def test_validation_report_passed_true_when_no_errors(): r = ValidationReport(passed=True, errors=[], warnings=[]) assert r.passed is True def test_envelope_serializes_to_iso_date(): e = Envelope( sender_id="11525703", receiver_id="COMEDASSISTPROG", control_number="991102977", transaction_date=date(2026, 6, 11), transaction_time="081417", implementation_guide="005010X222A1", ) d = e.model_dump() assert d["transaction_date"] == "2026-06-11" def test_claim_output_full_round_trip(): claim = ClaimOutput( claim_id="C1", control_number="991102977", transaction_date=date(2026, 6, 11), billing_provider=BillingProvider(name="X", npi="1234567890", tax_id="123456789", address=Address(line1="1", city="x", state="CO", zip="80000")), subscriber=Subscriber(first_name="J", last_name="D", member_id="M", dob=date(1980, 1, 1), gender="M", address=Address(line1="1", city="x", state="CO", zip="80000")), payer=Payer(name="P", id="SKCO0"), claim=ClaimHeader(claim_id="C1", total_charge=Decimal("100"), place_of_service="12", frequency_code="1", provider_signature="Y", assignment="Y", release_of_info="Y"), diagnoses=[Diagnosis(code="R69", qualifier="ABK")], service_lines=[], validation=ValidationReport(passed=True, errors=[], warnings=[]), raw_segments=[["CLM", "C1", "100"]], ) blob = json.loads(claim.model_dump_json()) assert blob["claim_id"] == "C1" assert blob["billing_provider"]["npi"] == "1234567890" assert blob["raw_segments"] == [["CLM", "C1", "100"]] assert ClaimOutput.model_validate(blob).claim_id == "C1"