Source code for subscriptionkore.core.models.plan

"""Plan domain model."""

from __future__ import annotations

from datetime import datetime
from typing import Any

from pydantic import BaseModel, Field
from ulid import ULID

from subscriptionkore.core.models.entitlement import EntitlementValueType
from subscriptionkore.core.models.value_objects import BillingPeriod, Money, ProviderReference


[docs] class PlanEntitlement(BaseModel): """Entitlement configuration for a plan.""" entitlement_id: str entitlement_key: str value: bool | int | str | None value_type: EntitlementValueType
[docs] class Plan(BaseModel): """Plan domain entity (a pricing tier for a product).""" id: str = Field(default_factory=lambda: str(ULID())) product_id: str name: str description: str | None = None provider_refs: list[ProviderReference] = Field(default_factory=list) price: Money billing_period: BillingPeriod trial_period_days: int | None = None entitlements: list[PlanEntitlement] = Field(default_factory=list) active: bool = True tier: int = Field(default=0, description="For upgrade/downgrade ordering") metadata: dict[str, Any] = Field(default_factory=dict) created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow)
[docs] def get_provider_ref(self, provider_type: str) -> ProviderReference | None: """Get provider reference for a specific provider.""" for ref in self.provider_refs: if ref.provider.value == provider_type: return ref return None
[docs] def add_provider_ref(self, ref: ProviderReference) -> None: """Add or update a provider reference.""" self.provider_refs = [r for r in self.provider_refs if r.provider != ref.provider] self.provider_refs.append(ref) self.updated_at = datetime.utcnow()
[docs] def is_upgrade_from(self, other: Plan) -> bool: """Check if this plan is an upgrade from another.""" return self.tier > other.tier
[docs] def is_downgrade_from(self, other: Plan) -> bool: """Check if this plan is a downgrade from another.""" return self.tier < other.tier
[docs] def get_entitlement_value(self, key: str) -> bool | int | str | None: """Get entitlement value by key.""" for ent in self.entitlements: if ent.entitlement_key == key: return ent.value return None
[docs] def deactivate(self) -> None: """Deactivate the plan.""" self.active = False self.updated_at = datetime.utcnow()