Coverage for polar/models/payment_method.py: 88%

24 statements  

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

1from typing import TYPE_CHECKING, Any 1ab

2from uuid import UUID 1ab

3 

4from sqlalchemy import ForeignKey, String, UniqueConstraint, Uuid 1ab

5from sqlalchemy.dialects.postgresql import JSONB 1ab

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

7 

8from polar.enums import PaymentProcessor 1ab

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

10from polar.kit.extensions.sqlalchemy.types import StrEnumType 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 .customer import Customer 

14 

15 

16class PaymentMethod(RecordModel): 1ab

17 __tablename__ = "payment_methods" 1ab

18 __table_args__ = (UniqueConstraint("processor", "processor_id", "customer_id"),) 1ab

19 

20 processor: Mapped[PaymentProcessor] = mapped_column( 1ab

21 StrEnumType(PaymentProcessor), index=True, nullable=False 

22 ) 

23 processor_id: Mapped[str] = mapped_column(String, index=True, nullable=False) 1ab

24 type: Mapped[str] = mapped_column(String, index=True, nullable=False) 1ab

25 method_metadata: Mapped[dict[str, Any]] = mapped_column( 1ab

26 JSONB, nullable=False, default=dict 

27 ) 

28 

29 customer_id: Mapped[UUID] = mapped_column( 1ab

30 Uuid, 

31 ForeignKey("customers.id", ondelete="cascade"), 

32 nullable=False, 

33 index=True, 

34 ) 

35 

36 @declared_attr 1ab

37 def customer(cls) -> Mapped["Customer"]: 1ab

38 return relationship( 1ab

39 "Customer", 

40 lazy="raise", 

41 back_populates="payment_methods", 

42 foreign_keys=[cls.customer_id], # type: ignore 

43 ) 

44 

45 @property 1ab

46 def fingerprint(self) -> str | None: 1ab

47 return self.method_metadata.get("fingerprint")