MCPcopy Create free account
hub / github.com/0xUnixIO/pulse / handleInvoicePaid

Method handleInvoicePaid

internal/payment/webhook.go:262–349  ·  view source on GitHub ↗
(event stripe.Event)

Source from the content-addressed store, hash-verified

260}
261
262func (d *WebhookDeps) handleInvoicePaid(event stripe.Event) {
263 var invoice struct {
264 ID string `json:"id"`
265 Subscription string `json:"subscription"`
266 Customer string `json:"customer"`
267 BillingReason string `json:"billing_reason"`
268 }
269 if err := json.Unmarshal(event.Data.Raw, &invoice); err != nil {
270 log.Printf("payment: unmarshal invoice: %v", err)
271 return
272 }
273 if invoice.Subscription == "" {
274 return
275 }
276 // 首次订阅已由 checkout.session.completed 处理,跳过避免双倍延期
277 if invoice.BillingReason == "subscription_create" {
278 return
279 }
280
281 order, err := d.OrderStore.GetOrderByStripeSubscription(invoice.Subscription)
282 if err != nil {
283 log.Printf("payment: get order by subscription %s: %v", invoice.Subscription, err)
284 return
285 }
286 if order.UserID == "" {
287 return
288 }
289
290 // 幂等性:原子地认领 invoice,防止并发重试导致双倍续费(Stripe 保证至少一次投递)。
291 if invoice.ID != "" {
292 claimed, err := d.OrderStore.ClaimInvoice(order.ID, invoice.ID)
293 if err != nil {
294 log.Printf("payment: claim invoice %s for order %s: %v", invoice.ID, order.ID, err)
295 return
296 }
297 if !claimed {
298 log.Printf("payment: invoice %s already processed for order %s, skipping", invoice.ID, order.ID)
299 return
300 }
301 }
302
303 plan, err := d.PlanStore.GetPlan(order.PlanID)
304 if err != nil {
305 log.Printf("payment: get plan %s for invoice: %v", order.PlanID, err)
306 return
307 }
308
309 user, err := d.UserStore.GetUser(order.UserID)
310 if err != nil {
311 log.Printf("payment: get user %s for invoice: %v", order.UserID, err)
312 return
313 }
314
315 now := time.Now().UTC()
316 base := now
317 if user.ExpireAt != nil && user.ExpireAt.After(now) {
318 base = *user.ExpireAt
319 }

Callers 1

HandleWebhookMethod · 0.95

Calls 6

AddMethod · 0.80
ClaimInvoiceMethod · 0.65
GetPlanMethod · 0.65
GetUserMethod · 0.65
UpsertUserMethod · 0.65

Tested by

no test coverage detected