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

1from enum import StrEnum 

2from typing import TYPE_CHECKING, Any, Literal, NotRequired, overload 

3 

4from sqlalchemy.orm import Mapped 

5from sqlalchemy.util.typing import TypedDict 

6 

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 

11 

12 

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" 

30 

31 

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} 

49 

50 

51class MeterCreditedMetadata(TypedDict): 

52 meter_id: str 

53 units: int 

54 rollover: bool 

55 

56 

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] 

62 

63 

64class MeterResetMetadata(TypedDict): 

65 meter_id: str 

66 

67 

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] 

73 

74 

75class BenefitGrantMetadata(TypedDict): 

76 benefit_id: str 

77 benefit_grant_id: str 

78 benefit_type: BenefitType 

79 

80 

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] 

86 

87 

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] 

93 

94 

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] 

100 

101 

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] 

107 

108 

109class CustomerCreatedMetadata(TypedDict): 

110 customer_id: str 

111 customer_email: str 

112 customer_name: str | None 

113 customer_external_id: str | None 

114 

115 

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] 

121 

122 

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] 

129 

130 

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 

137 

138 

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] 

144 

145 

146class CustomerDeletedMetadata(TypedDict): 

147 customer_id: str 

148 customer_email: str 

149 customer_name: str | None 

150 customer_external_id: str | None 

151 

152 

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] 

158 

159 

160class SubscriptionCycledMetadata(TypedDict): 

161 subscription_id: str 

162 

163 

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] 

169 

170 

171class SubscriptionRevokedMetadata(TypedDict): 

172 subscription_id: str 

173 

174 

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] 

180 

181 

182class SubscriptionProductUpdatedMetadata(TypedDict): 

183 subscription_id: str 

184 old_product_id: str 

185 new_product_id: str 

186 

187 

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] 

193 

194 

195class SubscriptionSeatsUpdatedMetadata(TypedDict): 

196 subscription_id: str 

197 old_seats: int 

198 new_seats: int 

199 proration_behavior: str 

200 

201 

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] 

207 

208 

209class SubscriptionBillingPeriodUpdatedMetadata(TypedDict): 

210 subscription_id: str 

211 old_period_end: str 

212 new_period_end: str 

213 

214 

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] 

220 

221 

222class OrderPaidMetadata(TypedDict): 

223 order_id: str 

224 amount: int 

225 currency: str 

226 backfilled: NotRequired[bool] 

227 

228 

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] 

234 

235 

236class OrderRefundedMetadata(TypedDict): 

237 order_id: str 

238 refunded_amount: int 

239 currency: str 

240 backfilled: NotRequired[bool] 

241 

242 

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] 

248 

249 

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: ... 

257 

258 

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: ... 

266 

267 

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: ... 

275 

276 

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: ... 

284 

285 

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: ... 

293 

294 

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: ... 

302 

303 

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: ... 

311 

312 

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: ... 

320 

321 

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: ... 

329 

330 

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: ... 

338 

339 

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: ... 

347 

348 

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: ... 

356 

357 

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: ... 

365 

366 

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: ... 

374 

375 

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: ... 

383 

384 

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: ... 

392 

393 

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 )