Compare commits

...

5 Commits

Author SHA1 Message Date
Gucheng
73226b818e Delete object/payment_test.go 2026-01-30 14:09:54 +08:00
copilot-swe-agent[bot]
bca8d2d44e Refactor to use IsTerminalState helper function
- Add IsTerminalState helper function to pp package
- Use helper function in payment.go for cleaner code
- Update tests to use helper function
- Reduces code duplication and improves maintainability

Co-authored-by: nomeguy <85475922+nomeguy@users.noreply.github.com>
2026-01-30 01:46:47 +00:00
copilot-swe-agent[bot]
358d1c454c Add tests for payment state change detection
- Test duplicate state detection logic
- Verify terminal state handling
- Validate webhook prevention for unchanged states
- Cover wechatpay duplicate notification scenarios

Co-authored-by: nomeguy <85475922+nomeguy@users.noreply.github.com>
2026-01-30 01:43:10 +00:00
copilot-swe-agent[bot]
b5c8e7f097 Fix duplicate webhook events when payment state unchanged
- Add state change check before updating payment
- Only trigger webhooks when payment state actually changes
- Prevents duplicate webhook events from redundant provider notifications
- Fixes issue where wechatpay sends multiple Created and Paid events

Co-authored-by: nomeguy <85475922+nomeguy@users.noreply.github.com>
2026-01-30 01:41:43 +00:00
copilot-swe-agent[bot]
8885aee341 Initial plan 2026-01-30 01:36:31 +00:00
2 changed files with 23 additions and 6 deletions

View File

@@ -210,18 +210,29 @@ func NotifyPayment(body []byte, owner string, paymentName string, lang string) (
}
// Check if payment is already in a terminal state to prevent duplicate processing
if payment.State == pp.PaymentStatePaid || payment.State == pp.PaymentStateError ||
payment.State == pp.PaymentStateCanceled || payment.State == pp.PaymentStateTimeout {
if pp.IsTerminalState(payment.State) {
return payment, nil
}
// Determine the new payment state
var newState pp.PaymentState
var newMessage string
if err != nil {
payment.State = pp.PaymentStateError
payment.Message = err.Error()
newState = pp.PaymentStateError
newMessage = err.Error()
} else {
payment.State = notifyResult.PaymentStatus
payment.Message = notifyResult.NotifyMessage
newState = notifyResult.PaymentStatus
newMessage = notifyResult.NotifyMessage
}
// Check if the payment state would actually change
// This prevents duplicate webhook events when providers send redundant notifications
if payment.State == newState {
return payment, nil
}
payment.State = newState
payment.Message = newMessage
_, err = UpdatePayment(payment.GetId(), payment)
if err != nil {
return nil, err

View File

@@ -24,6 +24,12 @@ const (
PaymentStateError PaymentState = "Error"
)
// IsTerminalState checks if a payment state is terminal (cannot transition to other states)
func IsTerminalState(state PaymentState) bool {
return state == PaymentStatePaid || state == PaymentStateError ||
state == PaymentStateCanceled || state == PaymentStateTimeout
}
const (
PaymentEnvWechatBrowser = "WechatBrowser"
)