Coverage for polar/models/subscription_product_price.py: 55%

30 statements  

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

1from typing import TYPE_CHECKING, Self 1ab

2from uuid import UUID 1ab

3 

4from sqlalchemy import ForeignKey, Integer, Uuid 1ab

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

6 

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

8from polar.models.product_price import ( 1ab

9 LegacyRecurringProductPriceCustom, 

10 LegacyRecurringProductPriceFixed, 

11 ProductPrice, 

12 ProductPriceCustom, 

13 ProductPriceFixed, 

14 ProductPriceSeatUnit, 

15) 

16 

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

18 from polar.models import Subscription 

19 

20 

21class SubscriptionProductPrice(RecordModel): 1ab

22 __tablename__ = "subscription_product_prices" 1ab

23 

24 subscription_id: Mapped[UUID] = mapped_column( 1ab

25 Uuid, 

26 ForeignKey("subscriptions.id", ondelete="cascade"), 

27 primary_key=True, 

28 ) 

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

30 Uuid, 

31 ForeignKey("product_prices.id", ondelete="restrict"), 

32 primary_key=True, 

33 ) 

34 amount: Mapped[int] = mapped_column(Integer, nullable=False) 1ab

35 

36 @declared_attr 1ab

37 def product_price(cls) -> Mapped["ProductPrice"]: 1ab

38 # This is an association table, so eager loading makes sense 

39 return relationship("ProductPrice", lazy="joined") 1ab

40 

41 @declared_attr 1ab

42 def subscription(cls) -> Mapped["Subscription"]: 1ab

43 return relationship("Subscription", lazy="raise_on_sql") 1ab

44 

45 @classmethod 1ab

46 def from_price( 1ab

47 cls, 

48 price: "ProductPrice", 

49 amount: int | None = None, 

50 seats: int | None = None, 

51 ) -> Self: 

52 if isinstance(price, ProductPriceFixed | LegacyRecurringProductPriceFixed): 

53 amount = price.price_amount 

54 elif isinstance(price, ProductPriceCustom | LegacyRecurringProductPriceCustom): 

55 assert amount is not None, "amount must be provided for custom prices" 

56 elif isinstance(price, ProductPriceSeatUnit): 

57 assert seats is not None, "seats must be provided for seat-based prices" 

58 amount = price.calculate_amount(seats) 

59 else: 

60 amount = 0 

61 return cls(product_price=price, amount=amount)