Coverage for polar/models/wallet.py: 90%
28 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 12:42 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 12:42 +0000
1from enum import StrEnum
2from typing import TYPE_CHECKING
3from uuid import UUID
5from sqlalchemy import ForeignKey, String, UniqueConstraint, Uuid, func, select
6from sqlalchemy.ext.associationproxy import AssociationProxy, association_proxy
7from sqlalchemy.orm import (
8 Mapped,
9 column_property,
10 declared_attr,
11 mapped_column,
12 relationship,
13)
15from polar.kit.db.models.base import RecordModel
16from polar.kit.extensions.sqlalchemy.types import StringEnum
18if TYPE_CHECKING: 18 ↛ 19line 18 didn't jump to line 19 because the condition on line 18 was never true
19 from .customer import Customer
20 from .organization import Organization
23class WalletType(StrEnum):
24 usage = "usage"
25 billing = "billing"
28class Wallet(RecordModel):
29 __tablename__ = "wallets"
30 __table_args__ = (UniqueConstraint("type", "currency", "customer_id"),)
32 type: Mapped[WalletType] = mapped_column(StringEnum(WalletType), nullable=False)
33 currency: Mapped[str] = mapped_column(String(3))
34 customer_id: Mapped[UUID] = mapped_column(
35 Uuid,
36 ForeignKey("customers.id", ondelete="cascade"),
37 unique=True,
38 )
40 @declared_attr
41 def customer(cls) -> Mapped["Customer"]:
42 return relationship("Customer", lazy="raise_on_sql")
44 organization: AssociationProxy["Organization"] = association_proxy(
45 "customer", "organization"
46 )
48 @declared_attr
49 def balance(cls) -> Mapped[int]:
50 from .wallet_transaction import WalletTransaction
52 return column_property(
53 select(func.coalesce(func.sum(WalletTransaction.amount), 0))
54 .where(WalletTransaction.wallet_id == cls.id)
55 .correlate_except(WalletTransaction)
56 .scalar_subquery()
57 )