Coverage for polar/models/organization_review.py: 92%

37 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-12-05 15:52 +0000

1from datetime import datetime 1ab

2from enum import StrEnum 1ab

3from typing import TYPE_CHECKING, Any 1ab

4from uuid import UUID 1ab

5 

6from sqlalchemy import TIMESTAMP, ForeignKey, String, Text, Uuid 1ab

7from sqlalchemy.dialects.postgresql import JSONB 1ab

8from sqlalchemy.orm import Mapped, declared_attr, mapped_column, relationship 1ab

9 

10from polar.kit.db.models import RecordModel 1ab

11 

12if TYPE_CHECKING: 12 ↛ 13line 12 didn't jump to line 13 because the condition on line 12 was never true1ab

13 from polar.models.organization import Organization 

14 

15 

16class OrganizationReview(RecordModel): 1ab

17 """Model to store AI validation responses for organizations.""" 

18 

19 class Verdict(StrEnum): 1ab

20 PASS = "PASS" 1ab

21 FAIL = "FAIL" 1ab

22 UNCERTAIN = "UNCERTAIN" 1ab

23 

24 class AppealDecision(StrEnum): 1ab

25 APPROVED = "approved" 1ab

26 REJECTED = "rejected" 1ab

27 

28 __tablename__ = "organization_reviews" 1ab

29 

30 organization_id: Mapped[UUID] = mapped_column( 1ab

31 Uuid, 

32 ForeignKey("organizations.id", ondelete="cascade"), 

33 nullable=False, 

34 unique=True, 

35 index=True, 

36 ) 

37 

38 verdict: Mapped[Verdict] = mapped_column(String, nullable=False) 1ab

39 risk_score: Mapped[float] = mapped_column(nullable=False) 1ab

40 violated_sections: Mapped[list[str]] = mapped_column( 1ab

41 JSONB, nullable=False, default=list 

42 ) 

43 reason: Mapped[str] = mapped_column(Text, nullable=False) 1ab

44 

45 timed_out: Mapped[bool] = mapped_column(nullable=False, default=False) 1ab

46 model_used: Mapped[str] = mapped_column(String, nullable=False) 1ab

47 

48 organization_details_snapshot: Mapped[dict[str, Any]] = mapped_column( 1ab

49 JSONB, nullable=False, default=dict 

50 ) 

51 

52 validated_at: Mapped[datetime] = mapped_column( 1ab

53 TIMESTAMP(timezone=True), nullable=False, default=lambda: datetime.now() 

54 ) 

55 

56 # Appeal fields 

57 appeal_submitted_at: Mapped[datetime | None] = mapped_column( 1ab

58 TIMESTAMP(timezone=True), nullable=True, default=None 

59 ) 

60 appeal_reason: Mapped[str | None] = mapped_column(Text, nullable=True, default=None) 1ab

61 appeal_reviewed_at: Mapped[datetime | None] = mapped_column( 1ab

62 TIMESTAMP(timezone=True), nullable=True, default=None 

63 ) 

64 appeal_decision: Mapped[AppealDecision | None] = mapped_column( 1ab

65 String, nullable=True, default=None 

66 ) 

67 

68 @declared_attr 1ab

69 def organization(cls) -> Mapped["Organization"]: 1ab

70 return relationship("Organization", lazy="raise", back_populates="review") 1ab

71 

72 def __repr__(self) -> str: 1ab

73 return f"OrganizationReview(id={self.id}, organization_id={self.organization_id}, verdict={self.verdict})"