Coverage for polar/models/benefit.py: 77%
50 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 15:52 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 15:52 +0000
1from enum import StrEnum 1ab
2from typing import TYPE_CHECKING 1ab
3from uuid import UUID 1ab
5from sqlalchemy import Boolean, ForeignKey, Text, Uuid 1ab
6from sqlalchemy.dialects.postgresql import JSONB 1ab
7from sqlalchemy.orm import Mapped, declared_attr, mapped_column, relationship 1ab
9from polar.exceptions import PolarError 1ab
10from polar.kit.db.models import RecordModel 1ab
11from polar.kit.extensions.sqlalchemy.types import StringEnum 1ab
12from polar.kit.metadata import MetadataMixin 1ab
14if TYPE_CHECKING: 14 ↛ 15line 14 didn't jump to line 15 because the condition on line 14 was never true1ab
15 from polar.benefit.strategies import BenefitProperties
16 from polar.models import BenefitGrant, Organization
19class TaxApplicationMustBeSpecified(PolarError): 1ab
20 def __init__(self, type: "BenefitType") -> None: 1ab
21 self.type = type
22 message = "The tax application should be specified for this type."
23 super().__init__(message)
26class BenefitType(StrEnum): 1ab
27 custom = "custom" 1ab
28 discord = "discord" 1ab
29 github_repository = "github_repository" 1ab
30 downloadables = "downloadables" 1ab
31 license_keys = "license_keys" 1ab
32 meter_credit = "meter_credit" 1ab
34 def get_display_name(self) -> str: 1ab
35 return {
36 BenefitType.custom: "Custom",
37 BenefitType.discord: "Discord",
38 BenefitType.github_repository: "GitHub Repository",
39 BenefitType.downloadables: "Downloadables",
40 BenefitType.license_keys: "License Keys",
41 BenefitType.meter_credit: "Meter Credit",
42 }[self]
44 def is_tax_applicable(self) -> bool: 1ab
45 try:
46 _is_tax_applicable_map: dict[BenefitType, bool] = {
47 BenefitType.custom: True,
48 BenefitType.discord: True,
49 BenefitType.github_repository: True,
50 BenefitType.downloadables: True,
51 BenefitType.license_keys: True,
52 BenefitType.meter_credit: True,
53 }
54 return _is_tax_applicable_map[self]
55 except KeyError as e:
56 raise TaxApplicationMustBeSpecified(self) from e
59class Benefit(MetadataMixin, RecordModel): 1ab
60 __tablename__ = "benefits" 1ab
62 type: Mapped[BenefitType] = mapped_column( 1ab
63 StringEnum(BenefitType), nullable=False, index=True
64 )
65 description: Mapped[str] = mapped_column(Text, nullable=False) 1ab
66 is_tax_applicable: Mapped[bool] = mapped_column( 1ab
67 Boolean, nullable=False, default=False
68 )
69 selectable: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True) 1ab
70 deletable: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True) 1ab
71 organization_id: Mapped[UUID] = mapped_column( 1ab
72 Uuid,
73 ForeignKey("organizations.id", ondelete="cascade"),
74 nullable=False,
75 index=True,
76 )
78 @declared_attr 1ab
79 def properties(cls) -> Mapped["BenefitProperties"]: 1ab
80 return mapped_column("properties", JSONB, nullable=False, default=dict) 1ab
82 @declared_attr 1ab
83 def organization(cls) -> Mapped["Organization"]: 1ab
84 return relationship("Organization", lazy="raise") 1ab
86 @declared_attr 1ab
87 def grants(cls) -> Mapped["list[BenefitGrant]"]: 1ab
88 return relationship( 1ab
89 "BenefitGrant", lazy="raise", back_populates="benefit", viewonly=True
90 )