Coverage for polar/event/system.py: 48%
154 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, Any, Literal, NotRequired, overload
4from sqlalchemy.orm import Mapped
5from sqlalchemy.util.typing import TypedDict
7from polar.kit.address import AddressDict
8from polar.models import Customer, Event, Organization
9from polar.models.benefit import BenefitType
10from polar.models.event import EventSource
13class SystemEvent(StrEnum):
14 meter_credited = "meter.credited"
15 meter_reset = "meter.reset"
16 benefit_granted = "benefit.granted"
17 benefit_cycled = "benefit.cycled"
18 benefit_updated = "benefit.updated"
19 benefit_revoked = "benefit.revoked"
20 subscription_cycled = "subscription.cycled"
21 subscription_revoked = "subscription.revoked"
22 subscription_product_updated = "subscription.product_updated"
23 subscription_seats_updated = "subscription.seats_updated"
24 subscription_billing_period_updated = "subscription.billing_period_updated"
25 order_paid = "order.paid"
26 order_refunded = "order.refunded"
27 customer_created = "customer.created"
28 customer_updated = "customer.updated"
29 customer_deleted = "customer.deleted"
32SYSTEM_EVENT_LABELS: dict[str, str] = {
33 "benefit.granted": "Benefit Granted",
34 "benefit.cycled": "Benefit Cycled",
35 "benefit.updated": "Benefit Updated",
36 "benefit.revoked": "Benefit Revoked",
37 "subscription.cycled": "Subscription Cycled",
38 "subscription.revoked": "Subscription Revoked",
39 "subscription.product_updated": "Subscription Product Updated",
40 "order.paid": "Order Paid",
41 "order.refunded": "Order Refunded",
42 "subscription.seats_updated": "Subscription Seats Updated",
43 "customer.created": "Customer Created",
44 "customer.updated": "Customer Updated",
45 "customer.deleted": "Customer Deleted",
46 "meter.credited": "Meter Credited",
47 "meter.reset": "Meter Reset",
48}
51class MeterCreditedMetadata(TypedDict):
52 meter_id: str
53 units: int
54 rollover: bool
57class MeterCreditedEvent(Event):
58 if TYPE_CHECKING: 58 ↛ anywhereline 58 didn't jump anywhere: it always raised an exception.
59 source: Mapped[Literal[EventSource.system]]
60 name: Mapped[Literal[SystemEvent.meter_credited]]
61 user_metadata: Mapped[MeterCreditedMetadata] # type: ignore[assignment]
64class MeterResetMetadata(TypedDict):
65 meter_id: str
68class MeterResetEvent(Event):
69 if TYPE_CHECKING: 69 ↛ anywhereline 69 didn't jump anywhere: it always raised an exception.
70 source: Mapped[Literal[EventSource.system]]
71 name: Mapped[Literal[SystemEvent.meter_reset]]
72 user_metadata: Mapped[MeterResetMetadata] # type: ignore[assignment]
75class BenefitGrantMetadata(TypedDict):
76 benefit_id: str
77 benefit_grant_id: str
78 benefit_type: BenefitType
81class BenefitGrantedEvent(Event):
82 if TYPE_CHECKING: 82 ↛ anywhereline 82 didn't jump anywhere: it always raised an exception.
83 source: Mapped[Literal[EventSource.system]]
84 name: Mapped[Literal[SystemEvent.benefit_granted]]
85 user_metadata: Mapped[BenefitGrantMetadata] # type: ignore[assignment]
88class BenefitCycledEvent(Event):
89 if TYPE_CHECKING: 89 ↛ anywhereline 89 didn't jump anywhere: it always raised an exception.
90 source: Mapped[Literal[EventSource.system]]
91 name: Mapped[Literal[SystemEvent.benefit_cycled]]
92 user_metadata: Mapped[BenefitGrantMetadata] # type: ignore[assignment]
95class BenefitUpdatedEvent(Event):
96 if TYPE_CHECKING: 96 ↛ anywhereline 96 didn't jump anywhere: it always raised an exception.
97 source: Mapped[Literal[EventSource.system]]
98 name: Mapped[Literal[SystemEvent.benefit_updated]]
99 user_metadata: Mapped[BenefitGrantMetadata] # type: ignore[assignment]
102class BenefitRevokedEvent(Event):
103 if TYPE_CHECKING: 103 ↛ anywhereline 103 didn't jump anywhere: it always raised an exception.
104 source: Mapped[Literal[EventSource.system]]
105 name: Mapped[Literal[SystemEvent.benefit_revoked]]
106 user_metadata: Mapped[BenefitGrantMetadata] # type: ignore[assignment]
109class CustomerCreatedMetadata(TypedDict):
110 customer_id: str
111 customer_email: str
112 customer_name: str | None
113 customer_external_id: str | None
116class CustomerCreatedEvent(Event):
117 if TYPE_CHECKING: 117 ↛ anywhereline 117 didn't jump anywhere: it always raised an exception.
118 source: Mapped[Literal[EventSource.system]]
119 name: Mapped[Literal[SystemEvent.customer_created]]
120 user_metadata: Mapped[CustomerCreatedMetadata] # type: ignore[assignment]
123class CustomerUpdatedFields(TypedDict):
124 name: NotRequired[str | None]
125 email: NotRequired[str | None]
126 billing_address: NotRequired[AddressDict | None]
127 tax_id: NotRequired[str | None]
128 metadata: NotRequired[dict[str, str | int | bool] | None]
131class CustomerUpdatedMetadata(TypedDict):
132 customer_id: str
133 customer_email: str
134 customer_name: str | None
135 customer_external_id: str | None
136 updated_fields: CustomerUpdatedFields
139class CustomerUpdatedEvent(Event):
140 if TYPE_CHECKING: 140 ↛ anywhereline 140 didn't jump anywhere: it always raised an exception.
141 source: Mapped[Literal[EventSource.system]]
142 name: Mapped[Literal[SystemEvent.customer_updated]]
143 user_metadata: Mapped[CustomerUpdatedMetadata] # type: ignore[assignment]
146class CustomerDeletedMetadata(TypedDict):
147 customer_id: str
148 customer_email: str
149 customer_name: str | None
150 customer_external_id: str | None
153class CustomerDeletedEvent(Event):
154 if TYPE_CHECKING: 154 ↛ anywhereline 154 didn't jump anywhere: it always raised an exception.
155 source: Mapped[Literal[EventSource.system]]
156 name: Mapped[Literal[SystemEvent.customer_deleted]]
157 user_metadata: Mapped[CustomerDeletedMetadata] # type: ignore[assignment]
160class SubscriptionCycledMetadata(TypedDict):
161 subscription_id: str
164class SubscriptionCycledEvent(Event):
165 if TYPE_CHECKING: 165 ↛ anywhereline 165 didn't jump anywhere: it always raised an exception.
166 source: Mapped[Literal[EventSource.system]]
167 name: Mapped[Literal[SystemEvent.subscription_cycled]]
168 user_metadata: Mapped[SubscriptionCycledMetadata] # type: ignore[assignment]
171class SubscriptionRevokedMetadata(TypedDict):
172 subscription_id: str
175class SubscriptionRevokedEvent(Event):
176 if TYPE_CHECKING: 176 ↛ anywhereline 176 didn't jump anywhere: it always raised an exception.
177 source: Mapped[Literal[EventSource.system]]
178 name: Mapped[Literal[SystemEvent.subscription_revoked]]
179 user_metadata: Mapped[SubscriptionRevokedMetadata] # type: ignore[assignment]
182class SubscriptionProductUpdatedMetadata(TypedDict):
183 subscription_id: str
184 old_product_id: str
185 new_product_id: str
188class SubscriptionProductUpdatedEvent(Event):
189 if TYPE_CHECKING: 189 ↛ anywhereline 189 didn't jump anywhere: it always raised an exception.
190 source: Mapped[Literal[EventSource.system]]
191 name: Mapped[Literal[SystemEvent.subscription_product_updated]]
192 user_metadata: Mapped[SubscriptionProductUpdatedMetadata] # type: ignore[assignment]
195class SubscriptionSeatsUpdatedMetadata(TypedDict):
196 subscription_id: str
197 old_seats: int
198 new_seats: int
199 proration_behavior: str
202class SubscriptionSeatsUpdatedEvent(Event):
203 if TYPE_CHECKING: 203 ↛ anywhereline 203 didn't jump anywhere: it always raised an exception.
204 source: Mapped[Literal[EventSource.system]]
205 name: Mapped[Literal[SystemEvent.subscription_seats_updated]]
206 user_metadata: Mapped[SubscriptionSeatsUpdatedMetadata] # type: ignore[assignment]
209class SubscriptionBillingPeriodUpdatedMetadata(TypedDict):
210 subscription_id: str
211 old_period_end: str
212 new_period_end: str
215class SubscriptionBillingPeriodUpdatedEvent(Event):
216 if TYPE_CHECKING: 216 ↛ anywhereline 216 didn't jump anywhere: it always raised an exception.
217 source: Mapped[Literal[EventSource.system]]
218 name: Mapped[Literal[SystemEvent.subscription_billing_period_updated]]
219 user_metadata: Mapped[SubscriptionBillingPeriodUpdatedMetadata] # type: ignore[assignment]
222class OrderPaidMetadata(TypedDict):
223 order_id: str
224 amount: int
225 currency: str
226 backfilled: NotRequired[bool]
229class OrderPaidEvent(Event):
230 if TYPE_CHECKING: 230 ↛ anywhereline 230 didn't jump anywhere: it always raised an exception.
231 source: Mapped[Literal[EventSource.system]]
232 name: Mapped[Literal[SystemEvent.order_paid]]
233 user_metadata: Mapped[OrderPaidMetadata] # type: ignore[assignment]
236class OrderRefundedMetadata(TypedDict):
237 order_id: str
238 refunded_amount: int
239 currency: str
240 backfilled: NotRequired[bool]
243class OrderRefundedEvent(Event):
244 if TYPE_CHECKING: 244 ↛ anywhereline 244 didn't jump anywhere: it always raised an exception.
245 source: Mapped[Literal[EventSource.system]]
246 name: Mapped[Literal[SystemEvent.order_refunded]]
247 user_metadata: Mapped[OrderRefundedMetadata] # type: ignore[assignment]
250@overload
251def build_system_event( 251 ↛ anywhereline 251 didn't jump anywhere: it always raised an exception.
252 name: Literal[SystemEvent.meter_credited],
253 customer: Customer,
254 organization: Organization,
255 metadata: MeterCreditedMetadata,
256) -> Event: ...
259@overload
260def build_system_event( 260 ↛ anywhereline 260 didn't jump anywhere: it always raised an exception.
261 name: Literal[SystemEvent.meter_reset],
262 customer: Customer,
263 organization: Organization,
264 metadata: MeterResetMetadata,
265) -> Event: ...
268@overload
269def build_system_event( 269 ↛ anywhereline 269 didn't jump anywhere: it always raised an exception.
270 name: Literal[SystemEvent.benefit_granted],
271 customer: Customer,
272 organization: Organization,
273 metadata: BenefitGrantMetadata,
274) -> Event: ...
277@overload
278def build_system_event( 278 ↛ anywhereline 278 didn't jump anywhere: it always raised an exception.
279 name: Literal[SystemEvent.benefit_cycled],
280 customer: Customer,
281 organization: Organization,
282 metadata: BenefitGrantMetadata,
283) -> Event: ...
286@overload
287def build_system_event( 287 ↛ anywhereline 287 didn't jump anywhere: it always raised an exception.
288 name: Literal[SystemEvent.benefit_updated],
289 customer: Customer,
290 organization: Organization,
291 metadata: BenefitGrantMetadata,
292) -> Event: ...
295@overload
296def build_system_event( 296 ↛ anywhereline 296 didn't jump anywhere: it always raised an exception.
297 name: Literal[SystemEvent.benefit_revoked],
298 customer: Customer,
299 organization: Organization,
300 metadata: BenefitGrantMetadata,
301) -> Event: ...
304@overload
305def build_system_event( 305 ↛ anywhereline 305 didn't jump anywhere: it always raised an exception.
306 name: Literal[SystemEvent.customer_created],
307 customer: Customer,
308 organization: Organization,
309 metadata: CustomerCreatedMetadata,
310) -> Event: ...
313@overload
314def build_system_event( 314 ↛ anywhereline 314 didn't jump anywhere: it always raised an exception.
315 name: Literal[SystemEvent.customer_updated],
316 customer: Customer,
317 organization: Organization,
318 metadata: CustomerUpdatedMetadata,
319) -> Event: ...
322@overload
323def build_system_event( 323 ↛ anywhereline 323 didn't jump anywhere: it always raised an exception.
324 name: Literal[SystemEvent.customer_deleted],
325 customer: Customer,
326 organization: Organization,
327 metadata: CustomerDeletedMetadata,
328) -> Event: ...
331@overload
332def build_system_event( 332 ↛ anywhereline 332 didn't jump anywhere: it always raised an exception.
333 name: Literal[SystemEvent.subscription_cycled],
334 customer: Customer,
335 organization: Organization,
336 metadata: SubscriptionCycledMetadata,
337) -> Event: ...
340@overload
341def build_system_event( 341 ↛ anywhereline 341 didn't jump anywhere: it always raised an exception.
342 name: Literal[SystemEvent.subscription_revoked],
343 customer: Customer,
344 organization: Organization,
345 metadata: SubscriptionRevokedMetadata,
346) -> Event: ...
349@overload
350def build_system_event( 350 ↛ anywhereline 350 didn't jump anywhere: it always raised an exception.
351 name: Literal[SystemEvent.subscription_product_updated],
352 customer: Customer,
353 organization: Organization,
354 metadata: SubscriptionProductUpdatedMetadata,
355) -> Event: ...
358@overload
359def build_system_event( 359 ↛ anywhereline 359 didn't jump anywhere: it always raised an exception.
360 name: Literal[SystemEvent.subscription_seats_updated],
361 customer: Customer,
362 organization: Organization,
363 metadata: SubscriptionSeatsUpdatedMetadata,
364) -> Event: ...
367@overload
368def build_system_event( 368 ↛ anywhereline 368 didn't jump anywhere: it always raised an exception.
369 name: Literal[SystemEvent.subscription_billing_period_updated],
370 customer: Customer,
371 organization: Organization,
372 metadata: SubscriptionBillingPeriodUpdatedMetadata,
373) -> Event: ...
376@overload
377def build_system_event( 377 ↛ anywhereline 377 didn't jump anywhere: it always raised an exception.
378 name: Literal[SystemEvent.order_paid],
379 customer: Customer,
380 organization: Organization,
381 metadata: OrderPaidMetadata,
382) -> Event: ...
385@overload
386def build_system_event( 386 ↛ anywhereline 386 didn't jump anywhere: it always raised an exception.
387 name: Literal[SystemEvent.order_refunded],
388 customer: Customer,
389 organization: Organization,
390 metadata: OrderRefundedMetadata,
391) -> Event: ...
394def build_system_event(
395 name: SystemEvent,
396 customer: Customer,
397 organization: Organization,
398 metadata: Any,
399) -> Event:
400 return Event(
401 name=name,
402 source=EventSource.system,
403 customer_id=customer.id,
404 organization=organization,
405 user_metadata=metadata,
406 )