ai-lls-lib 1.4.0rc2__py3-none-any.whl → 1.4.0rc4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ai_lls_lib/__init__.py +1 -1
- ai_lls_lib/auth/__init__.py +4 -4
- ai_lls_lib/auth/context_parser.py +68 -68
- ai_lls_lib/cli/__init__.py +3 -3
- ai_lls_lib/cli/__main__.py +30 -30
- ai_lls_lib/cli/aws_client.py +115 -115
- ai_lls_lib/cli/commands/__init__.py +3 -3
- ai_lls_lib/cli/commands/admin.py +174 -174
- ai_lls_lib/cli/commands/cache.py +142 -142
- ai_lls_lib/cli/commands/stripe.py +377 -377
- ai_lls_lib/cli/commands/test_stack.py +216 -216
- ai_lls_lib/cli/commands/verify.py +111 -111
- ai_lls_lib/cli/env_loader.py +122 -122
- ai_lls_lib/core/__init__.py +3 -3
- ai_lls_lib/core/cache.py +106 -106
- ai_lls_lib/core/models.py +77 -77
- ai_lls_lib/core/processor.py +295 -295
- ai_lls_lib/core/verifier.py +84 -84
- ai_lls_lib/payment/__init__.py +13 -13
- ai_lls_lib/payment/credit_manager.py +186 -193
- ai_lls_lib/payment/models.py +102 -102
- ai_lls_lib/payment/stripe_manager.py +487 -487
- ai_lls_lib/payment/webhook_processor.py +215 -215
- ai_lls_lib/providers/__init__.py +7 -7
- ai_lls_lib/providers/base.py +28 -28
- ai_lls_lib/providers/external.py +87 -87
- ai_lls_lib/providers/stub.py +48 -48
- ai_lls_lib/testing/__init__.py +3 -3
- ai_lls_lib/testing/fixtures.py +104 -104
- {ai_lls_lib-1.4.0rc2.dist-info → ai_lls_lib-1.4.0rc4.dist-info}/METADATA +1 -1
- ai_lls_lib-1.4.0rc4.dist-info/RECORD +33 -0
- ai_lls_lib-1.4.0rc2.dist-info/RECORD +0 -33
- {ai_lls_lib-1.4.0rc2.dist-info → ai_lls_lib-1.4.0rc4.dist-info}/WHEEL +0 -0
- {ai_lls_lib-1.4.0rc2.dist-info → ai_lls_lib-1.4.0rc4.dist-info}/entry_points.txt +0 -0
ai_lls_lib/payment/models.py
CHANGED
@@ -1,102 +1,102 @@
|
|
1
|
-
"""Payment data models with legacy shape compatibility."""
|
2
|
-
|
3
|
-
from dataclasses import dataclass
|
4
|
-
from typing import Optional, Dict, Any
|
5
|
-
from enum import Enum
|
6
|
-
|
7
|
-
|
8
|
-
class PlanType(Enum):
|
9
|
-
"""Plan types matching legacy frontend expectations."""
|
10
|
-
PREPAID = "prepaid"
|
11
|
-
POSTPAID = "postpaid"
|
12
|
-
INTRO = "intro"
|
13
|
-
|
14
|
-
|
15
|
-
class SubscriptionStatus(Enum):
|
16
|
-
"""Subscription statuses."""
|
17
|
-
ACTIVE = "active"
|
18
|
-
PAUSED = "paused"
|
19
|
-
CANCELLED = "cancelled"
|
20
|
-
PAST_DUE = "past_due"
|
21
|
-
|
22
|
-
|
23
|
-
@dataclass
|
24
|
-
class Plan:
|
25
|
-
"""
|
26
|
-
Plan model matching legacy frontend data structure.
|
27
|
-
Maps from Stripe Price/Product to legacy fields.
|
28
|
-
"""
|
29
|
-
plan_reference: str # Stripe price ID or legacy reference
|
30
|
-
plan_type: str # prepaid, postpaid, intro
|
31
|
-
plan_name: str # STANDARD, POWER, ELITE, UNLIMITED
|
32
|
-
plan_subtitle: str
|
33
|
-
plan_amount: float # Price in USD
|
34
|
-
plan_credits: Optional[int] # Number of credits or None for unlimited
|
35
|
-
plan_credits_text: str # Display text like "5,000 credits"
|
36
|
-
percent_off: str # Discount percentage display text
|
37
|
-
|
38
|
-
# Additional fields for internal use
|
39
|
-
stripe_price_id: Optional[str] = None
|
40
|
-
stripe_product_id: Optional[str] = None
|
41
|
-
|
42
|
-
def to_dict(self) -> Dict[str, Any]:
|
43
|
-
"""Convert to dictionary for JSON serialization."""
|
44
|
-
result = {
|
45
|
-
"plan_reference": self.plan_reference,
|
46
|
-
"plan_type": self.plan_type,
|
47
|
-
"plan_name": self.plan_name,
|
48
|
-
"plan_subtitle": self.plan_subtitle,
|
49
|
-
"plan_amount": self.plan_amount,
|
50
|
-
"plan_credits": self.plan_credits,
|
51
|
-
"plan_credits_text": self.plan_credits_text,
|
52
|
-
"percent_off": self.percent_off
|
53
|
-
}
|
54
|
-
|
55
|
-
# Add variable_amount flag for VARIABLE product
|
56
|
-
if self.plan_name == "VARIABLE":
|
57
|
-
result["variable_amount"] = True
|
58
|
-
|
59
|
-
return result
|
60
|
-
|
61
|
-
@classmethod
|
62
|
-
def from_stripe_price(cls, price: Dict[str, Any], product: Dict[str, Any]) -> "Plan":
|
63
|
-
"""
|
64
|
-
Create Plan from Stripe Price and Product objects.
|
65
|
-
Maps Stripe metadata to legacy fields.
|
66
|
-
"""
|
67
|
-
metadata = price.get("metadata", {})
|
68
|
-
|
69
|
-
# Determine plan type
|
70
|
-
if price.get("recurring"):
|
71
|
-
plan_type = "postpaid"
|
72
|
-
else:
|
73
|
-
plan_type = metadata.get("plan_type", "prepaid")
|
74
|
-
|
75
|
-
# Extract credits
|
76
|
-
credits_str = metadata.get("credits", "")
|
77
|
-
if credits_str.lower() == "unlimited":
|
78
|
-
plan_credits = None
|
79
|
-
plan_credits_text = "Unlimited"
|
80
|
-
elif credits_str:
|
81
|
-
try:
|
82
|
-
plan_credits = int(credits_str)
|
83
|
-
plan_credits_text = f"{plan_credits:,} credits"
|
84
|
-
except ValueError:
|
85
|
-
plan_credits = None
|
86
|
-
plan_credits_text = credits_str
|
87
|
-
else:
|
88
|
-
plan_credits = None
|
89
|
-
plan_credits_text = ""
|
90
|
-
|
91
|
-
return cls(
|
92
|
-
plan_reference=metadata.get("plan_reference", price["id"]),
|
93
|
-
plan_type=plan_type,
|
94
|
-
plan_name=metadata.get("tier", product.get("name", "")).upper(),
|
95
|
-
plan_subtitle=metadata.get("plan_subtitle", product.get("description", "")),
|
96
|
-
plan_amount=price["unit_amount"] / 100.0, # Convert cents to dollars
|
97
|
-
plan_credits=plan_credits,
|
98
|
-
plan_credits_text=metadata.get("plan_credits_text", plan_credits_text),
|
99
|
-
percent_off=metadata.get("percent_off", ""),
|
100
|
-
stripe_price_id=price["id"],
|
101
|
-
stripe_product_id=product["id"]
|
102
|
-
)
|
1
|
+
"""Payment data models with legacy shape compatibility."""
|
2
|
+
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import Optional, Dict, Any
|
5
|
+
from enum import Enum
|
6
|
+
|
7
|
+
|
8
|
+
class PlanType(Enum):
|
9
|
+
"""Plan types matching legacy frontend expectations."""
|
10
|
+
PREPAID = "prepaid"
|
11
|
+
POSTPAID = "postpaid"
|
12
|
+
INTRO = "intro"
|
13
|
+
|
14
|
+
|
15
|
+
class SubscriptionStatus(Enum):
|
16
|
+
"""Subscription statuses."""
|
17
|
+
ACTIVE = "active"
|
18
|
+
PAUSED = "paused"
|
19
|
+
CANCELLED = "cancelled"
|
20
|
+
PAST_DUE = "past_due"
|
21
|
+
|
22
|
+
|
23
|
+
@dataclass
|
24
|
+
class Plan:
|
25
|
+
"""
|
26
|
+
Plan model matching legacy frontend data structure.
|
27
|
+
Maps from Stripe Price/Product to legacy fields.
|
28
|
+
"""
|
29
|
+
plan_reference: str # Stripe price ID or legacy reference
|
30
|
+
plan_type: str # prepaid, postpaid, intro
|
31
|
+
plan_name: str # STANDARD, POWER, ELITE, UNLIMITED
|
32
|
+
plan_subtitle: str
|
33
|
+
plan_amount: float # Price in USD
|
34
|
+
plan_credits: Optional[int] # Number of credits or None for unlimited
|
35
|
+
plan_credits_text: str # Display text like "5,000 credits"
|
36
|
+
percent_off: str # Discount percentage display text
|
37
|
+
|
38
|
+
# Additional fields for internal use
|
39
|
+
stripe_price_id: Optional[str] = None
|
40
|
+
stripe_product_id: Optional[str] = None
|
41
|
+
|
42
|
+
def to_dict(self) -> Dict[str, Any]:
|
43
|
+
"""Convert to dictionary for JSON serialization."""
|
44
|
+
result = {
|
45
|
+
"plan_reference": self.plan_reference,
|
46
|
+
"plan_type": self.plan_type,
|
47
|
+
"plan_name": self.plan_name,
|
48
|
+
"plan_subtitle": self.plan_subtitle,
|
49
|
+
"plan_amount": self.plan_amount,
|
50
|
+
"plan_credits": self.plan_credits,
|
51
|
+
"plan_credits_text": self.plan_credits_text,
|
52
|
+
"percent_off": self.percent_off
|
53
|
+
}
|
54
|
+
|
55
|
+
# Add variable_amount flag for VARIABLE product
|
56
|
+
if self.plan_name == "VARIABLE":
|
57
|
+
result["variable_amount"] = True
|
58
|
+
|
59
|
+
return result
|
60
|
+
|
61
|
+
@classmethod
|
62
|
+
def from_stripe_price(cls, price: Dict[str, Any], product: Dict[str, Any]) -> "Plan":
|
63
|
+
"""
|
64
|
+
Create Plan from Stripe Price and Product objects.
|
65
|
+
Maps Stripe metadata to legacy fields.
|
66
|
+
"""
|
67
|
+
metadata = price.get("metadata", {})
|
68
|
+
|
69
|
+
# Determine plan type
|
70
|
+
if price.get("recurring"):
|
71
|
+
plan_type = "postpaid"
|
72
|
+
else:
|
73
|
+
plan_type = metadata.get("plan_type", "prepaid")
|
74
|
+
|
75
|
+
# Extract credits
|
76
|
+
credits_str = metadata.get("credits", "")
|
77
|
+
if credits_str.lower() == "unlimited":
|
78
|
+
plan_credits = None
|
79
|
+
plan_credits_text = "Unlimited"
|
80
|
+
elif credits_str:
|
81
|
+
try:
|
82
|
+
plan_credits = int(credits_str)
|
83
|
+
plan_credits_text = f"{plan_credits:,} credits"
|
84
|
+
except ValueError:
|
85
|
+
plan_credits = None
|
86
|
+
plan_credits_text = credits_str
|
87
|
+
else:
|
88
|
+
plan_credits = None
|
89
|
+
plan_credits_text = ""
|
90
|
+
|
91
|
+
return cls(
|
92
|
+
plan_reference=metadata.get("plan_reference", price["id"]),
|
93
|
+
plan_type=plan_type,
|
94
|
+
plan_name=metadata.get("tier", product.get("name", "")).upper(),
|
95
|
+
plan_subtitle=metadata.get("plan_subtitle", product.get("description", "")),
|
96
|
+
plan_amount=price["unit_amount"] / 100.0, # Convert cents to dollars
|
97
|
+
plan_credits=plan_credits,
|
98
|
+
plan_credits_text=metadata.get("plan_credits_text", plan_credits_text),
|
99
|
+
percent_off=metadata.get("percent_off", ""),
|
100
|
+
stripe_price_id=price["id"],
|
101
|
+
stripe_product_id=product["id"]
|
102
|
+
)
|