geek payment notify api is ready

This commit is contained in:
RockYang 2024-09-18 22:24:05 +08:00
parent 2beffd3dd3
commit f887a39912
5 changed files with 79 additions and 74 deletions

View File

@ -57,7 +57,8 @@ type AlipayConfig struct {
PublicKey string // 用户公钥文件路径 PublicKey string // 用户公钥文件路径
AlipayPublicKey string // 支付宝公钥文件路径 AlipayPublicKey string // 支付宝公钥文件路径
RootCert string // Root 秘钥路径 RootCert string // Root 秘钥路径
NotifyHost string // 通知回调地址 NotifyURL string // 异步通知地址
ReturnURL string // 同步回调地址
} }
type WechatPayConfig struct { type WechatPayConfig struct {
@ -67,7 +68,8 @@ type WechatPayConfig struct {
SerialNo string // 商户证书的证书序列号 SerialNo string // 商户证书的证书序列号
PrivateKey string // 用户私钥文件路径 PrivateKey string // 用户私钥文件路径
ApiV3Key string // API V3 秘钥 ApiV3Key string // API V3 秘钥
NotifyHost string // 通知回调地址 NotifyURL string // 异步通知地址
ReturnURL string // 同步回调地址
} }
type HuPiPayConfig struct { //虎皮椒第四方支付配置 type HuPiPayConfig struct { //虎皮椒第四方支付配置
@ -76,7 +78,8 @@ type HuPiPayConfig struct { //虎皮椒第四方支付配置
AppId string // App ID AppId string // App ID
AppSecret string // app 密钥 AppSecret string // app 密钥
ApiURL string // 支付网关 ApiURL string // 支付网关
NotifyHost string // 通知回调地址 NotifyURL string // 异步通知地址
ReturnURL string // 同步回调地址
} }
// GeekPayConfig GEEK支付配置 // GeekPayConfig GEEK支付配置
@ -85,7 +88,8 @@ type GeekPayConfig struct {
AppId string // 商户 ID AppId string // 商户 ID
PrivateKey string // 私钥 PrivateKey string // 私钥
ApiURL string // API 网关 ApiURL string // API 网关
NotifyHost string // 通知回调地址 NotifyURL string // 异步通知地址
ReturnURL string // 同步回调地址
} }
type XXLConfig struct { // XXL 任务调度配置 type XXLConfig struct { // XXL 任务调度配置

View File

@ -39,6 +39,7 @@ type PaymentHandler struct {
geekPayService *payment.GeekPayService geekPayService *payment.GeekPayService
wechatPayService *payment.WechatPayService wechatPayService *payment.WechatPayService
snowflake *service.Snowflake snowflake *service.Snowflake
userService *service.UserService
fs embed.FS fs embed.FS
lock sync.Mutex lock sync.Mutex
signKey string // 用来签名的随机秘钥 signKey string // 用来签名的随机秘钥
@ -51,6 +52,7 @@ func NewPaymentHandler(
geekPayService *payment.GeekPayService, geekPayService *payment.GeekPayService,
wechatPayService *payment.WechatPayService, wechatPayService *payment.WechatPayService,
db *gorm.DB, db *gorm.DB,
userService *service.UserService,
snowflake *service.Snowflake, snowflake *service.Snowflake,
fs embed.FS) *PaymentHandler { fs embed.FS) *PaymentHandler {
return &PaymentHandler{ return &PaymentHandler{
@ -59,6 +61,7 @@ func NewPaymentHandler(
geekPayService: geekPayService, geekPayService: geekPayService,
wechatPayService: wechatPayService, wechatPayService: wechatPayService,
snowflake: snowflake, snowflake: snowflake,
userService: userService,
fs: fs, fs: fs,
lock: sync.Mutex{}, lock: sync.Mutex{},
BaseHandler: BaseHandler{ BaseHandler: BaseHandler{
@ -72,12 +75,12 @@ func NewPaymentHandler(
func (h *PaymentHandler) Pay(c *gin.Context) { func (h *PaymentHandler) Pay(c *gin.Context) {
payWay := c.Query("pay_way") payWay := c.Query("pay_way")
payType := c.Query("pay_type") payType := c.Query("pay_type")
productId := c.Query("pid") productId := c.Query("product_id")
device := c.Query("device") device := c.Query("device")
userId := c.Query("user_id") userId := c.Query("user_id")
var product model.Product var product model.Product
err := h.DB.First(&product, productId).Error err := h.DB.Debug().Where("id", productId).First(&product).Error
if err != nil { if err != nil {
resp.ERROR(c, "Product not found") resp.ERROR(c, "Product not found")
return return
@ -126,23 +129,20 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
var payURL string var payURL string
if payWay == "alipay" { // 支付宝 if payWay == "alipay" { // 支付宝
money := fmt.Sprintf("%.2f", order.Amount) money := fmt.Sprintf("%.2f", order.Amount)
notifyURL := fmt.Sprintf("%s/api/payment/notify/alipay", h.App.Config.AlipayConfig.NotifyHost)
returnURL := fmt.Sprintf("%s/member", h.App.Config.AlipayConfig.NotifyHost)
if device == "mobile" { if device == "mobile" {
payURL, err = h.alipayService.PayMobile(payment.AlipayParams{ payURL, err = h.alipayService.PayMobile(payment.AlipayParams{
OutTradeNo: orderNo, OutTradeNo: orderNo,
Subject: product.Name, Subject: product.Name,
TotalFee: money, TotalFee: money,
ReturnURL: returnURL, NotifyURL: h.App.Config.AlipayConfig.NotifyURL,
NotifyURL: notifyURL,
}) })
} else { } else {
payURL, err = h.alipayService.PayPC(payment.AlipayParams{ payURL, err = h.alipayService.PayPC(payment.AlipayParams{
OutTradeNo: orderNo, OutTradeNo: orderNo,
Subject: product.Name, Subject: product.Name,
TotalFee: money, TotalFee: money,
ReturnURL: returnURL, ReturnURL: h.App.Config.AlipayConfig.ReturnURL,
NotifyURL: notifyURL, NotifyURL: h.App.Config.AlipayConfig.NotifyURL,
}) })
} }
if err != nil { if err != nil {
@ -155,7 +155,8 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
TradeOrderId: orderNo, TradeOrderId: orderNo,
TotalFee: fmt.Sprintf("%f", order.Amount), TotalFee: fmt.Sprintf("%f", order.Amount),
Title: order.Subject, Title: order.Subject,
NotifyURL: fmt.Sprintf("%s/api/payment/notify/hupi", h.App.Config.HuPiPayConfig.NotifyHost), NotifyURL: h.App.Config.HuPiPayConfig.NotifyURL,
ReturnURL: h.App.Config.HuPiPayConfig.ReturnURL,
WapName: "GeekAI助手", WapName: "GeekAI助手",
} }
r, err := h.huPiPayService.Pay(params) r, err := h.huPiPayService.Pay(params)
@ -175,8 +176,6 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
c.Redirect(302, uri) c.Redirect(302, uri)
} else if order.PayWay == "geek" { } else if order.PayWay == "geek" {
notifyURL := fmt.Sprintf("%s/api/payment/notify/geek", h.App.Config.GeekPayConfig.NotifyHost)
returnURL := fmt.Sprintf("%s/member", h.App.Config.GeekPayConfig.NotifyHost)
params := payment.GeekPayParams{ params := payment.GeekPayParams{
OutTradeNo: orderNo, OutTradeNo: orderNo,
Method: "web", Method: "web",
@ -185,8 +184,8 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
ClientIP: c.ClientIP(), ClientIP: c.ClientIP(),
Device: device, Device: device,
Type: payType, Type: payType,
ReturnURL: returnURL, ReturnURL: h.App.Config.GeekPayConfig.ReturnURL,
NotifyURL: notifyURL, NotifyURL: h.App.Config.GeekPayConfig.NotifyURL,
} }
res, err := h.geekPayService.Pay(params) res, err := h.geekPayService.Pay(params)
@ -218,45 +217,26 @@ func (h *PaymentHandler) notify(orderNo string, tradeNo string) error {
} }
var user model.User var user model.User
res = h.DB.First(&user, order.UserId) err := h.DB.First(&user, order.UserId).Error
if res.Error != nil { if err != nil {
err := fmt.Errorf("error with fetch user info: %v", res.Error) return fmt.Errorf("error with fetch user info: %v", res.Error)
logger.Error(err)
return err
} }
var remark types.OrderRemark var remark types.OrderRemark
err := utils.JsonDecode(order.Remark, &remark) err = utils.JsonDecode(order.Remark, &remark)
if err != nil { if err != nil {
err := fmt.Errorf("error with decode order remark: %v", err) err := fmt.Errorf("error with decode order remark: %v", err)
logger.Error(err) logger.Error(err)
return err return err
} }
var opt string // 增加用户算力
var power int err = h.userService.IncreasePower(int(order.UserId), remark.Power, model.PowerLog{
if remark.Days > 0 { // VIP 充值 Type: types.PowerRecharge,
if user.ExpiredTime >= time.Now().Unix() { Model: order.PayWay,
user.ExpiredTime = time.Unix(user.ExpiredTime, 0).AddDate(0, 0, remark.Days).Unix() Remark: fmt.Sprintf("充值算力,金额:%f订单号%s", order.Amount, order.OrderNo),
opt = "VIP充值VIP 没到期,只延期不增加算力" })
} else { if err != nil {
user.ExpiredTime = time.Now().AddDate(0, 0, remark.Days).Unix()
user.Power += h.App.SysConfig.VipMonthPower
power = h.App.SysConfig.VipMonthPower
opt = "VIP充值"
}
user.Vip = true
} else { // 充值点卡,直接增加次数即可
user.Power += remark.Power
opt = "点卡充值"
power = remark.Power
}
// 更新用户信息
res = h.DB.Updates(&user)
if res.Error != nil {
err := fmt.Errorf("error with update user info: %v", res.Error)
logger.Error(err)
return err return err
} }
@ -264,29 +244,16 @@ func (h *PaymentHandler) notify(orderNo string, tradeNo string) error {
order.PayTime = time.Now().Unix() order.PayTime = time.Now().Unix()
order.Status = types.OrderPaidSuccess order.Status = types.OrderPaidSuccess
order.TradeNo = tradeNo order.TradeNo = tradeNo
res = h.DB.Updates(&order) err = h.DB.Updates(&order).Error
if res.Error != nil { if err != nil {
err := fmt.Errorf("error with update order info: %v", res.Error) return fmt.Errorf("error with update order info: %v", err)
logger.Error(err)
return err
} }
// 更新产品销量 // 更新产品销量
h.DB.Model(&model.Product{}).Where("id = ?", order.ProductId).UpdateColumn("sales", gorm.Expr("sales + ?", 1)) err = h.DB.Model(&model.Product{}).Where("id = ?", order.ProductId).
UpdateColumn("sales", gorm.Expr("sales + ?", 1)).Error
// 记录算力充值日志 if err != nil {
if power > 0 { return fmt.Errorf("error with update product sales: %v", err)
h.DB.Create(&model.PowerLog{
UserId: user.Id,
Username: user.Username,
Type: types.PowerRecharge,
Amount: power,
Balance: user.Power,
Mark: types.PowerAdd,
Model: order.PayWay,
Remark: fmt.Sprintf("%s金额%f订单号%s", opt, order.Amount, order.OrderNo),
CreatedAt: time.Now(),
})
} }
return nil return nil

View File

@ -139,9 +139,15 @@ const routes = [
{ {
path: '/admin/login', path: '/admin/login',
name: 'admin-login', name: 'admin-login',
meta: {title: 'Geek-AI 控制台登录'}, meta: {title: '控制台登录'},
component: () => import('@/views/admin/Login.vue'), component: () => import('@/views/admin/Login.vue'),
}, },
{
path: '/payReturn',
name: 'pay-return',
meta: {title: '支付回调'},
component: () => import('@/views/PayReturn.vue'),
},
{ {
name: 'admin', name: 'admin',
path: '/admin', path: '/admin',

View File

@ -106,6 +106,12 @@
</div> </div>
<el-dialog v-model="showDialog" :show-close=false hide-footer width="auto">
<div style="padding-bottom: 10px">
<el-button type="success" @click="payCallback(true)">支付成功</el-button>
<el-button type="danger" @click="payCallback(false)">支付失败</el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
@ -143,6 +149,7 @@ const payWays = ref([])
const vipInfoText = ref("") const vipInfoText = ref("")
const store = useSharedStore() const store = useSharedStore()
const profileKey = ref(0) const profileKey = ref(0)
const showDialog = ref(false)
onMounted(() => { onMounted(() => {
@ -195,6 +202,7 @@ const pay = (product, payWay) => {
}).then(res => { }).then(res => {
window.open(res.data, '_blank'); window.open(res.data, '_blank');
loading.value = false loading.value = false
showDialog.value = true
}).catch(e => { }).catch(e => {
setTimeout(() => { setTimeout(() => {
ElMessage.error("生成支付订单失败:" + e.message) ElMessage.error("生成支付订单失败:" + e.message)
@ -210,6 +218,13 @@ const redeemCallback = (success) => {
} }
} }
const payCallback = (success) => {
showDialog.value = false
if (success) {
profileKey.value += 1
}
}
</script> </script>
<style lang="stylus"> <style lang="stylus">

View File

@ -0,0 +1,13 @@
<template>
<div>
支付回调
</div>
</template>
<script setup>
import {useRouter} from "vue-router";
const router = useRouter()
console.log(router.currentRoute.value.query)
window.close()
</script>