Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
b2a40d33
authored
Apr 15, 2026
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: enhance Stripe webhook handling for async payment events
parent
bf130c5c
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
70 additions
and
3 deletions
+70
-3
controller/topup_stripe.go
+70
-3
No files found.
controller/topup_stripe.go
View file @
b2a40d33
...
@@ -146,6 +146,12 @@ func RequestStripePay(c *gin.Context) {
...
@@ -146,6 +146,12 @@ func RequestStripePay(c *gin.Context) {
}
}
func
StripeWebhook
(
c
*
gin
.
Context
)
{
func
StripeWebhook
(
c
*
gin
.
Context
)
{
if
setting
.
StripeWebhookSecret
==
""
{
log
.
Println
(
"Stripe Webhook Secret 未配置,拒绝处理"
)
c
.
AbortWithStatus
(
http
.
StatusForbidden
)
return
}
payload
,
err
:=
io
.
ReadAll
(
c
.
Request
.
Body
)
payload
,
err
:=
io
.
ReadAll
(
c
.
Request
.
Body
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"解析Stripe Webhook参数失败: %v
\n
"
,
err
)
log
.
Printf
(
"解析Stripe Webhook参数失败: %v
\n
"
,
err
)
...
@@ -154,8 +160,7 @@ func StripeWebhook(c *gin.Context) {
...
@@ -154,8 +160,7 @@ func StripeWebhook(c *gin.Context) {
}
}
signature
:=
c
.
GetHeader
(
"Stripe-Signature"
)
signature
:=
c
.
GetHeader
(
"Stripe-Signature"
)
endpointSecret
:=
setting
.
StripeWebhookSecret
event
,
err
:=
webhook
.
ConstructEventWithOptions
(
payload
,
signature
,
setting
.
StripeWebhookSecret
,
webhook
.
ConstructEventOptions
{
event
,
err
:=
webhook
.
ConstructEventWithOptions
(
payload
,
signature
,
endpointSecret
,
webhook
.
ConstructEventOptions
{
IgnoreAPIVersionMismatch
:
true
,
IgnoreAPIVersionMismatch
:
true
,
})
})
...
@@ -170,6 +175,10 @@ func StripeWebhook(c *gin.Context) {
...
@@ -170,6 +175,10 @@ func StripeWebhook(c *gin.Context) {
sessionCompleted
(
event
)
sessionCompleted
(
event
)
case
stripe
.
EventTypeCheckoutSessionExpired
:
case
stripe
.
EventTypeCheckoutSessionExpired
:
sessionExpired
(
event
)
sessionExpired
(
event
)
case
stripe
.
EventTypeCheckoutSessionAsyncPaymentSucceeded
:
sessionAsyncPaymentSucceeded
(
event
)
case
stripe
.
EventTypeCheckoutSessionAsyncPaymentFailed
:
sessionAsyncPaymentFailed
(
event
)
default
:
default
:
log
.
Printf
(
"不支持的Stripe Webhook事件类型: %s
\n
"
,
event
.
Type
)
log
.
Printf
(
"不支持的Stripe Webhook事件类型: %s
\n
"
,
event
.
Type
)
}
}
...
@@ -186,7 +195,65 @@ func sessionCompleted(event stripe.Event) {
...
@@ -186,7 +195,65 @@ func sessionCompleted(event stripe.Event) {
return
return
}
}
// Try complete subscription order first
paymentStatus
:=
event
.
GetObjectValue
(
"payment_status"
)
if
paymentStatus
!=
"paid"
{
log
.
Printf
(
"Stripe Checkout 支付尚未完成,payment_status: %s, ref: %s(等待异步支付结果)"
,
paymentStatus
,
referenceId
)
return
}
fulfillOrder
(
event
,
referenceId
,
customerId
)
}
// sessionAsyncPaymentSucceeded handles delayed payment methods (bank transfer, SEPA, etc.)
// that confirm payment after the checkout session completes.
func
sessionAsyncPaymentSucceeded
(
event
stripe
.
Event
)
{
customerId
:=
event
.
GetObjectValue
(
"customer"
)
referenceId
:=
event
.
GetObjectValue
(
"client_reference_id"
)
log
.
Printf
(
"Stripe 异步支付成功: %s"
,
referenceId
)
fulfillOrder
(
event
,
referenceId
,
customerId
)
}
// sessionAsyncPaymentFailed marks orders as failed when delayed payment methods
// ultimately fail (e.g. bank transfer not received, SEPA rejected).
func
sessionAsyncPaymentFailed
(
event
stripe
.
Event
)
{
referenceId
:=
event
.
GetObjectValue
(
"client_reference_id"
)
log
.
Printf
(
"Stripe 异步支付失败: %s"
,
referenceId
)
if
len
(
referenceId
)
==
0
{
log
.
Println
(
"异步支付失败事件未提供支付单号"
)
return
}
LockOrder
(
referenceId
)
defer
UnlockOrder
(
referenceId
)
topUp
:=
model
.
GetTopUpByTradeNo
(
referenceId
)
if
topUp
==
nil
{
log
.
Println
(
"异步支付失败,充值订单不存在:"
,
referenceId
)
return
}
if
topUp
.
Status
!=
common
.
TopUpStatusPending
{
log
.
Printf
(
"异步支付失败,订单状态非pending: %s, ref: %s"
,
topUp
.
Status
,
referenceId
)
return
}
topUp
.
Status
=
common
.
TopUpStatusFailed
if
err
:=
topUp
.
Update
();
err
!=
nil
{
log
.
Printf
(
"标记充值订单失败出错: %v, ref: %s"
,
err
,
referenceId
)
return
}
log
.
Printf
(
"充值订单已标记为失败: %s"
,
referenceId
)
}
// fulfillOrder is the shared logic for crediting quota after payment is confirmed.
func
fulfillOrder
(
event
stripe
.
Event
,
referenceId
string
,
customerId
string
)
{
if
len
(
referenceId
)
==
0
{
log
.
Println
(
"未提供支付单号"
)
return
}
LockOrder
(
referenceId
)
LockOrder
(
referenceId
)
defer
UnlockOrder
(
referenceId
)
defer
UnlockOrder
(
referenceId
)
payload
:=
map
[
string
]
any
{
payload
:=
map
[
string
]
any
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment