kamau1 commited on
Commit
8324cf9
·
1 Parent(s): 1c7add8

fix: add missing Subscription model class - maps to subscriptions table for customer service subscriptions

Browse files
Files changed (1) hide show
  1. src/app/models/subscription.py +83 -0
src/app/models/subscription.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Subscription Model - Customer service subscriptions
3
+ Maps to 'subscriptions' table in docs/schema/schema.sql
4
+ """
5
+ from sqlalchemy import Column, String, Text, Date, Numeric, ForeignKey, CheckConstraint
6
+ from sqlalchemy.dialects.postgresql import UUID, JSONB
7
+ from sqlalchemy.orm import relationship
8
+ from app.models.base import BaseModel
9
+ from app.models.enums import ServiceType, SubscriptionStatus, PayoutMethod
10
+
11
+
12
+ class Subscription(BaseModel):
13
+ """
14
+ Subscription model - Tracks customer service subscriptions
15
+ Maps to 'subscriptions' table in docs/schema/schema.sql
16
+
17
+ Purpose: Represent active/inactive customer service subscriptions
18
+ Links to customers, sales orders, and projects
19
+ """
20
+ __tablename__ = "subscriptions"
21
+
22
+ # Relationships
23
+ customer_id = Column(UUID(as_uuid=True), ForeignKey('customers.id', ondelete='RESTRICT'), nullable=False)
24
+ sales_order_id = Column(UUID(as_uuid=True), ForeignKey('sales_orders.id', ondelete='SET NULL'), nullable=True)
25
+ project_id = Column(UUID(as_uuid=True), ForeignKey('projects.id', ondelete='RESTRICT'), nullable=True)
26
+
27
+ # Service Details
28
+ service_type = Column(String(50), nullable=False) # ServiceType enum
29
+ package_name = Column(Text, nullable=True)
30
+ monthly_fee = Column(Numeric(precision=12, scale=2), nullable=True)
31
+
32
+ # Service Address (where service is active)
33
+ project_region_id = Column(UUID(as_uuid=True), ForeignKey('project_regions.id', ondelete='SET NULL'), nullable=True)
34
+ service_address_line1 = Column(Text, nullable=True)
35
+ service_address_line2 = Column(Text, nullable=True)
36
+ service_maps_link = Column(Text, nullable=True)
37
+ service_latitude = Column(Numeric(precision=10, scale=7), nullable=True)
38
+ service_longitude = Column(Numeric(precision=10, scale=7), nullable=True)
39
+
40
+ # Equipment & Activation Details (Flexible JSONB storage)
41
+ equipment_details = Column(JSONB, default={}, nullable=False)
42
+ activation_details = Column(JSONB, default={}, nullable=False)
43
+
44
+ # Payment Method
45
+ payment_method = Column(String(50), nullable=True) # PayoutMethod enum
46
+ mobile_money_provider = Column(Text, nullable=True)
47
+ payment_phone = Column(Text, nullable=True)
48
+ payment_account_number = Column(Text, nullable=True)
49
+ payment_account_name = Column(Text, nullable=True)
50
+
51
+ # Lifecycle
52
+ status = Column(String(50), default='pending_activation', nullable=False) # SubscriptionStatus enum
53
+ activation_date = Column(Date, nullable=True)
54
+ cancellation_date = Column(Date, nullable=True)
55
+ suspension_date = Column(Date, nullable=True)
56
+ termination_date = Column(Date, nullable=True)
57
+
58
+ # Metadata
59
+ notes = Column(Text, nullable=True)
60
+ additional_metadata = Column(JSONB, default={}, nullable=False)
61
+ activated_by_user_id = Column(UUID(as_uuid=True), ForeignKey('users.id', ondelete='SET NULL'), nullable=True)
62
+
63
+ # Relationships
64
+ customer = relationship("Customer", back_populates="subscriptions")
65
+ sales_order = relationship("SalesOrder", foreign_keys=[sales_order_id])
66
+ project = relationship("Project", foreign_keys=[project_id])
67
+ project_region = relationship("ProjectRegion", foreign_keys=[project_region_id])
68
+ activated_by_user = relationship("User", foreign_keys=[activated_by_user_id])
69
+
70
+ # Table constraints
71
+ __table_args__ = (
72
+ CheckConstraint(
73
+ 'monthly_fee IS NULL OR monthly_fee >= 0',
74
+ name='chk_positive_fee'
75
+ ),
76
+ CheckConstraint(
77
+ 'cancellation_date IS NULL OR activation_date IS NULL OR cancellation_date >= activation_date',
78
+ name='chk_cancellation_after_activation'
79
+ ),
80
+ )
81
+
82
+ def __repr__(self):
83
+ return f"<Subscription(id='{self.id}', customer_id='{self.customer_id}', status='{self.status}')>"