package alipay import ( "errors" "fmt" "os" "path/filepath" "recook/internal/api/mobile/pay/public" "recook/internal/back" "recook/internal/dbc" "recook/internal/domain" "recook/internal/model/order" "recook/internal/model/pay" "recook/internal/service/comFunc" "recook/tools" "strconv" "time" "github.com/gin-gonic/gin" "github.com/jinzhu/gorm" "github.com/shopspring/decimal" "github.com/smartwalle/alipay/v3" ) type createH5AlipayReq struct { UserID uint `json:"userId" validate:"required,numeric"` OrderID uint `json:"orderId" validate:"required,numeric"` } func createH5Order(orderID uint, ip string, userID uint) (error, string) { now := time.Now().Unix() var od []order.Information if err := dbc.DB.Find(&od, "virtual_id = ?", orderID).Error; err != nil { return err, "" } if err := public.UpdateVirtualPay(orderID); err != nil { return err, "" } amount := decimal.Zero for _, v := range od { if err := public.ValidateOrderInfo(&v, now); err != nil { return err, "" } amount = amount.Add(v.ActualTotalAmount) } // 零支付 if amount.IsZero() { return errors.New("接口调用错误"), "" } var detail pay.AlipayH5Detail if err := dbc.DB.First(&detail, "order_id = ?", orderID).Error; err != nil && err != gorm.ErrRecordNotFound { return err, "" } if detail.ID > 0 { tx := dbc.DB.Begin() { for _, v := range od { if v.PayMethod != order.AlipayH5ForOrderInfo { if err := tx.Model(&v).Updates(order.Information{ PayIP: ip, TradeNo: detail.TradeNo, PayMethod: order.AlipayH5ForOrderInfo, }).Error; err != nil { tx.Rollback() return err, "" } } } } tx.Commit() return nil, detail.CreateOrderSign } else { if url, tradeNo, err := genUrl(od[0].Title, userID, orderID, amount); err != nil { return errors.New("失败"), "" } else { tx := dbc.DB.Begin() { for _, v := range od { if err = dbc.DB.Model(&v).Updates(order.Information{ PayIP: ip, TradeNo: tradeNo, PayMethod: order.AlipayH5ForOrderInfo, }).Error; err != nil { tx.Rollback() return err, "" } } detail = pay.AlipayH5Detail{ OrderId: int64(orderID), TradeNo: tradeNo, CreateOrderSign: url, } if err = tx.Create(&detail).Error; err != nil { tx.Rollback() return err, "" } } tx.Commit() return nil, url } } } /** 逻辑处理从之前的app支付过来的 */ func CreateH5Alipay(c *gin.Context) { var p createH5AlipayReq err := tools.ParseParams(&p, c) if err != nil { back.Fail(c, err.Error()) return } if !public.Judge(p.OrderID) { if err, result := createH5Order(p.OrderID, c.ClientIP(), p.UserID); err != nil { back.Err(c, err.Error()) return } else { back.Suc(c, "操作成功", gin.H{ "payUrl": result, }) return } } if err = public.UpdateNormalPay(p.OrderID); err != nil { back.Err(c, err.Error()) return } now := time.Now().Unix() var orderInfo order.Information err = dbc.DB.First(&orderInfo, "id = ?", p.OrderID).Error if err != nil { back.Err(c, err.Error()) return } // 零支付 if orderInfo.ActualTotalAmount.Equal(decimal.NewFromFloat(0.0)) { back.Fail(c, "接口调用错误") return } err = public.ValidateOrderInfo(&orderInfo, now) if err != nil { back.Fail(c, err.Error()) return } var detail pay.AlipayH5Detail err = dbc.DB.First(&detail, "order_id = ?", orderInfo.ID).Error if err != nil && !gorm.IsRecordNotFoundError(err) { back.Err(c, err.Error()) return } if detail.ID > 0 { // 如果生成过记录了 back.Suc(c, "", gin.H{ "payUrl": detail.CreateOrderSign, }) if orderInfo.PayMethod != order.AlipayH5ForOrderInfo { err = dbc.DB.Model(&orderInfo).Updates(order.Information{ PayIP: c.ClientIP(), TradeNo: detail.TradeNo, PayMethod: order.AlipayH5ForOrderInfo, }).Error if err != nil { back.Err(c, err.Error()) return } } } else { if url, tradeNo, err := genUrl(orderInfo.Title, p.UserID, orderInfo.ID, orderInfo.ActualTotalAmount); err != nil { back.Fail(c, "失败") } else { err = dbc.DB.Model(&orderInfo).Updates(order.Information{ PayIP: c.ClientIP(), TradeNo: tradeNo, PayMethod: order.AlipayH5ForOrderInfo, }).Error if err != nil { back.Err(c, err.Error()) return } detail = pay.AlipayH5Detail{ OrderId: int64(orderInfo.ID), TradeNo: tradeNo, CreateOrderSign: url, } dbc.DB.Create(&detail) back.Suc(c, "", gin.H{ "payUrl": url, }) } } } func genUrl(title string, userID uint, orderID uint, actualAmount decimal.Decimal) (string, string, error) { var privateKey = RecookToAliPayPrivateKeyForTest client, err := alipay.New(AppID0602, privateKey, true) if err != nil { errMsg := fmt.Sprintf("加载出现错误%s,", err) comFunc.PrintErr(errMsg) return "", "", err } dir, _ := os.Executable() exPath := filepath.Dir(dir) alipayH5Path := exPath + "/credentials/alipay_h5/" err = client.LoadAppPublicCertFromFile(alipayH5Path + "appCertPublicKey_2021001152664931.crt") // 加载应用公钥证书 if err != nil { panic(err) } err = client.LoadAliPayRootCertFromFile(alipayH5Path + "alipayRootCert.crt") // 加载支付宝根证书 if err != nil { panic(err) } err = client.LoadAliPayPublicCertFromFile(alipayH5Path + "alipayCertPublicKey_RSA2.crt") // 加载支付宝公钥证书 if err != nil { panic(err) } var pa = alipay.TradeWapPay{} // 回调地址 pa.NotifyURL = domain.GetName() + "/api/v1/pay/alipay/h5_callback" // 跳转页面 pa.ReturnURL = "https://h5.reecook.cn/app/paydone.html" // 应该是商城名称 pa.Subject = title // 生成唯一订单号 outTradeNo := public.GenerateOrderAliPayOutTradeNo(userID, orderID) pa.OutTradeNo = outTradeNo amount, _ := strconv.ParseFloat(actualAmount.String(), 2) pa.TotalAmount = strconv.FormatFloat(amount, 'f', 2, 64) pa.ProductCode = "AlipayH5" // pa.ProductCode = "QUICK_WAP_WAY" pa.TimeExpire = time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04") pa.TimeoutExpress = time.Now().Add(15 * time.Minute).Format("2006-01-02 15:04:05") // bs, _ := json.Marshal(pa) // beego.Info(string(bs)) payUrl, err := client.TradeWapPay(pa) if err != nil { errMsg := fmt.Sprintf("alipay-h5 支付出现错误%s,", err) comFunc.PrintErr(errMsg) return "", "", err } var payURL = payUrl.String() return payURL, outTradeNo, nil }