You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

170 lines
6.3 KiB

package pay
import (
"context"
"yunyan/comm"
"yunyan/lego/sys/log"
"yunyan/pb"
"yunyan/sys/pay/appleiap"
"yunyan/sys/pay/googleiap"
"yunyan/sys/pay/paypal"
"fmt"
"strings"
"time"
)
// @Summary 验证订单
// @Description 验证支付订单是否有效
// @Tags User
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param user body pb.PayAskOrCancelReq true "发送绑定请求"
// @Success 200 {object} comm.HttpResult{data=pb.PayPayOrderAskResp} "成功返回"
// @Router /api/home/pay_verifyorder [post]
func (this *apiComp) VerifyOrder(session comm.IUserSession, req *pb.PayAskOrCancelReq) (resp *pb.PayPayOrderAskResp, errdata *pb.ErrorData) {
var (
model *pb.DBPayOrder
user *pb.DBUser
err error
)
if req.Orderid == "" {
if orders, _, err0 := this.module.model.getUserPayOrders(session.GetUserId(), 1, 50); err0 == nil {
for _, o := range orders {
if o.Status == pb.PayOrderStatus_PAY_ORDER_PENDING {
req.Orderid = o.OrderId
break
}
}
}
}
// 查询订单
if model, err = this.module.model.getPayOrder(req.Orderid); err != nil {
errdata = &pb.ErrorData{
Code: pb.ErrorCode_PayOrderNotFound,
Message: "查询订单失败:" + fmt.Sprintf("%v", err),
}
return
}
// 查询用户
if user, err = this.module.model.getUser(session.GetUserId()); err != nil {
errdata = &pb.ErrorData{
Code: pb.ErrorCode_DBError,
Message: "查询用户失败:" + fmt.Sprintf("%v", err),
}
return
}
this.module.Debug("VerifyOrder", log.Field{Key: "order", Value: model})
// Google/Apple 主动查询与校验:仅在订单未支付时进行
if model.Status == pb.PayOrderStatus_PAY_ORDER_PENDING {
ctx, cancel := context.WithTimeout(context.Background(), 8*time.Second)
defer cancel()
// PayPal 主动执行 capture 扣款
if model.PaymentMethod == pb.PaymentMethod_PayPal {
if model.TransactionId == "" {
errdata = &pb.ErrorData{Code: pb.ErrorCode_PayOrderNotFound, Message: "缺少 PayPal 订单号,无法执行 capture"}
return
}
captureJSON, err := paypal.CaptureOrder(ctx, model.TransactionId)
if err != nil {
if this.module.analyze != nil {
this.module.analyze.Report(&comm.StatEvent{Type: comm.StatEventOrderFailed, Uid: model.Uid})
}
errdata = &pb.ErrorData{Code: pb.ErrorCode_PayCreateOrderFail, Message: "PayPal capture 失败:" + fmt.Sprintf("%v", err)}
return
}
// 简单判定:返回中包含 status=COMPLETED 视为支付成功
if !strings.Contains(captureJSON, "\"status\":\"COMPLETED\"") {
if this.module.analyze != nil {
this.module.analyze.Report(&comm.StatEvent{Type: comm.StatEventOrderFailed, Uid: model.Uid})
}
errdata = &pb.ErrorData{Code: pb.ErrorCode_PayCreateOrderFail, Message: "PayPal capture 未完成"}
return
}
// 扣款成功,更新订单并发放资源
model.Status = pb.PayOrderStatus_PAY_ORDER_PAID
model.PayTime = time.Now().Unix()
if err = this.deliverResourceByOrder(user, model); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_ResourceDeliveryError, Message: "发放资源失败:" + fmt.Sprintf("%v", err)}
return
}
if err = this.module.model.updatePayOrder(model); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_PayOrderStatusError, Message: "更新订单状态失败:" + fmt.Sprintf("%v", err)}
return
}
}
// Apple IAP 主动校验
if model.PaymentMethod == pb.PaymentMethod_AppleIAP {
if req.AppleReceiptData == "" {
errdata = &pb.ErrorData{Code: pb.ErrorCode_ReqParameterError, Message: "缺少苹果收据数据或交易ID"}
return
}
var ok bool
if req.AppleUseTransactionId {
ok, err = appleiap.VerifyTransaction(ctx, req.AppleReceiptData)
} else {
ok, err = appleiap.VerifyReceipt(ctx, req.AppleReceiptData)
}
if err != nil || !ok {
if this.module.analyze != nil {
this.module.analyze.Report(&comm.StatEvent{Type: comm.StatEventOrderFailed, Uid: model.Uid})
}
errdata = &pb.ErrorData{Code: pb.ErrorCode_PayNotifyDecryptFail, Message: "Apple IAP 校验失败:" + fmt.Sprintf("%v", err)}
return
}
// 校验通过,更新订单并发放资源
model.Status = pb.PayOrderStatus_PAY_ORDER_PAID
model.PayTime = time.Now().Unix()
if err = this.deliverResourceByOrder(user, model); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_ResourceDeliveryError, Message: "发放资源失败:" + fmt.Sprintf("%v", err)}
return
}
if err = this.module.model.updatePayOrder(model); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_PayOrderStatusError, Message: "更新订单状态失败:" + fmt.Sprintf("%v", err)}
return
}
}
// Google IAP 主动校验
if model.PaymentMethod == pb.PaymentMethod_GoogleIAP {
if req.GooglePackageName == "" || req.GoogleProductId == "" || req.GooglePurchaseToken == "" {
errdata = &pb.ErrorData{Code: pb.ErrorCode_ReqParameterError, Message: "缺少谷歌校验所需参数"}
return
}
var ok bool
if req.GoogleIsSubscription {
ok, err = googleiap.VerifySubscriptionPurchase(ctx, req.GooglePackageName, req.GoogleProductId, req.GooglePurchaseToken)
} else {
ok, err = googleiap.VerifyProductPurchase(ctx, req.GooglePackageName, req.GoogleProductId, req.GooglePurchaseToken)
}
if err != nil || !ok {
if this.module.analyze != nil {
this.module.analyze.Report(&comm.StatEvent{Type: comm.StatEventOrderFailed, Uid: model.Uid})
}
errdata = &pb.ErrorData{Code: pb.ErrorCode_PayNotifyDecryptFail, Message: "Google IAP 校验失败:" + fmt.Sprintf("%v", err)}
return
}
// 校验通过,更新订单并发放资源
model.Status = pb.PayOrderStatus_PAY_ORDER_PAID
model.PayTime = time.Now().Unix()
if err = this.deliverResourceByOrder(user, model); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_ResourceDeliveryError, Message: "发放资源失败:" + fmt.Sprintf("%v", err)}
return
}
if err = this.module.model.updatePayOrder(model); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_PayOrderStatusError, Message: "更新订单状态失败:" + fmt.Sprintf("%v", err)}
return
}
}
} else if model.Status == pb.PayOrderStatus_PAY_ORDER_PAID {
this.module.Debug("VerifyOrder 已经完成", log.Field{Key: "order", Value: model})
}
resp = &pb.PayPayOrderAskResp{
Order: model,
User: user,
}
return
}