This commit is contained in:
wucongxing8150 2024-07-29 08:58:07 +08:00
parent 5dd3c44917
commit 73e41552e4
20 changed files with 638 additions and 28 deletions

View File

@ -2,9 +2,14 @@ package controller
import (
"github.com/gin-gonic/gin"
"hepa-calc-api/api/dao"
"hepa-calc-api/api/responses"
"hepa-calc-api/api/service"
"hepa-calc-api/extend/weChat"
"hepa-calc-api/global"
"hepa-calc-api/utils"
"net/http"
"time"
)
// CallBack 回调
@ -12,7 +17,7 @@ type CallBack struct{}
// WxPaySingle 微信支付回调-单项
func (r *CallBack) WxPaySingle(c *gin.Context) {
notifyReq, err := weChat.ParseNotify(c)
notifyReq, transaction, err := weChat.ParseNotify(c)
if err != nil {
responses.FailWithMessage(err.Error(), c)
return
@ -20,7 +25,195 @@ func (r *CallBack) WxPaySingle(c *gin.Context) {
// 记录日志
utils.LogJsonErr("微信支付回调-单项", notifyReq)
utils.LogJsonErr("微信支付回调-单项", transaction)
if transaction == nil {
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": "缺少订单数据"})
return
}
if transaction.OutTradeNo == nil {
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": "缺少外部订单号"})
return
}
// 查询订单
orderSingleDao := dao.OrderSingleDao{}
maps := make(map[string]interface{})
maps["order_no"] = transaction.OutTradeNo
orderSingle, err := orderSingleDao.GetOrderSingle(maps)
if err != nil || orderSingle == nil {
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": "无订单数据"})
return
}
// 验证订单状态-订单状态1:待支付 2:已完成 3:已取消)
if orderSingle.OrderStatus != 1 {
message := "订单状态:" + utils.OrderSingleStatusToString(orderSingle.OrderStatus) + " 无需处理"
c.JSON(http.StatusOK, gin.H{"code": "SUCCESS", "message": message})
return
}
// 处理支付状态
if transaction.TradeState == nil {
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": "缺少支付状态"})
return
}
// 处理支付状态
wxPayResult, err := weChat.HandlePayStatus(transaction)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": err})
return
}
// 开始事务
tx := global.Db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 修改订单
orderSingleData := make(map[string]interface{})
if wxPayResult.OrderStatus != nil {
orderSingleData["order_status"] = &wxPayResult.OrderStatus
}
orderSingleData["pay_status"] = &wxPayResult.PayStatus
if wxPayResult.PayTime != nil {
orderSingleData["pay_time"] = &wxPayResult.PayTime
}
orderSingleData["escrow_trade_no"] = transaction.TransactionId
orderSingleData["updated_at"] = time.Now().Format("2006-01-02 15:04:05")
err = orderSingleDao.EditOrderSingleById(tx, orderSingle.OrderId, orderSingleData)
if err != nil {
tx.Rollback()
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": err})
return
}
tx.Commit()
c.JSON(http.StatusOK, gin.H{"code": "SUCCESS", "message": "OK"})
}
// WxPayMember 微信支付回调-会员
func (r *CallBack) WxPayMember(c *gin.Context) {
notifyReq, transaction, err := weChat.ParseNotify(c)
if err != nil {
responses.FailWithMessage(err.Error(), c)
return
}
// 记录日志
utils.LogJsonErr("微信支付回调-会员", notifyReq)
utils.LogJsonErr("微信支付回调-会员", transaction)
if transaction == nil {
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": "缺少订单数据"})
return
}
if transaction.OutTradeNo == nil {
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": "缺少外部订单号"})
return
}
// 查询订单
orderMemberDao := dao.OrderMemberDao{}
maps := make(map[string]interface{})
maps["order_no"] = transaction.OutTradeNo
orderMember, err := orderMemberDao.GetOrderMember(maps)
if err != nil || orderMember == nil {
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": "无订单数据"})
return
}
// 验证订单状态-订单状态1:待支付 2:已完成 3:已取消)
if orderMember.OrderStatus != 1 {
message := "订单状态:" + utils.OrderSingleStatusToString(orderMember.OrderStatus) + " 无需处理"
c.JSON(http.StatusOK, gin.H{"code": "SUCCESS", "message": message})
return
}
// 处理支付状态
if transaction.TradeState == nil {
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": "缺少支付状态"})
return
}
// 处理支付状态
wxPayResult, err := weChat.HandlePayStatus(transaction)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": err})
return
}
// 获取用户数据
userDao := dao.UserDao{}
user, err := userDao.GetUserById(orderMember.UserId)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": "ERROR", "message": "用户数据错误"})
return
}
// 开始事务
tx := global.Db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 修改订单
orderSingleData := make(map[string]interface{})
if wxPayResult.OrderStatus != nil {
orderSingleData["order_status"] = &wxPayResult.OrderStatus
}
orderSingleData["pay_status"] = &wxPayResult.PayStatus
if wxPayResult.PayTime != nil {
orderSingleData["pay_time"] = &wxPayResult.PayTime
}
orderSingleData["escrow_trade_no"] = transaction.TransactionId
orderSingleData["updated_at"] = time.Now().Format("2006-01-02 15:04:05")
err = orderMemberDao.EditOrderMemberById(tx, orderMember.OrderId, orderSingleData)
if err != nil {
tx.Rollback()
c.JSON(http.StatusInternalServerError, gin.H{"code": "ERROR", "message": err})
return
}
// 处理未支付单项订单
if *wxPayResult.OrderStatus == 2 {
orderSingleService := service.OrderSingleService{}
res, err := orderSingleService.CompleteUnPayOrderSingle(tx, orderMember.UserId)
if err != nil || res == false {
tx.Rollback()
c.JSON(http.StatusInternalServerError, gin.H{"code": "ERROR", "message": err})
return
}
}
// 处理用户会员过期时间
if *wxPayResult.OrderStatus == 2 {
// 获取订单配置
systemMemberDao := dao.SystemMemberDao{}
systemMember, err := systemMemberDao.GetSystemMemberById(orderMember.SystemMemberId)
if err != nil {
tx.Rollback()
c.JSON(http.StatusInternalServerError, gin.H{"code": "ERROR", "message": "会员配置错误"})
return
}
userService := service.UserService{}
res := userService.AddUserMemberValidDate(tx, user, int(systemMember.MemberDays))
if res == false {
tx.Rollback()
c.JSON(http.StatusInternalServerError, gin.H{"code": "ERROR", "message": "增加用户会员到期时间失败"})
return
}
}
tx.Commit()
c.JSON(http.StatusOK, gin.H{"code": "SUCCESS", "message": "OK"})
}

View File

@ -12,7 +12,6 @@ import (
"hepa-calc-api/extend/weChat"
"hepa-calc-api/global"
"hepa-calc-api/utils"
"strconv"
"time"
)
@ -20,18 +19,89 @@ type Login struct{}
// LoginPhone 手机号登录
func (r *Login) LoginPhone(c *gin.Context) {
loginRequest := requests.LoginRequest{}
req := loginRequest.LoginPhone
if err := c.ShouldBind(&req); err != nil {
responses.FailWithMessage(err.Error(), c)
return
}
// 参数验证
if err := global.Validate.Struct(req); err != nil {
responses.FailWithMessage(utils.Translate(err), c)
return
}
// 检测用户信息
userDao := dao.UserDao{}
maps := make(map[string]interface{})
maps["mobile"] = req.Mobile
user, _ := userDao.GetUser(maps)
// 新用户处理方式
if user == nil {
// 开始事务
tx := global.Db.Begin()
defer func() {
if r := recover(); r != nil {
fmt.Println(r)
tx.Rollback()
}
}()
avatar := "www.baidu.com"
// 新增用户
user = &model.User{
UserName: "",
Mobile: req.Mobile,
RegisterSource: req.Source,
OpenId: "",
UnionId: "",
Age: nil,
Sex: 0,
Avatar: avatar,
IsMember: 0,
MemberExpireDate: nil,
LoginAt: model.LocalTime(time.Now()),
LoginIp: req.LoginIp,
}
user, err := userDao.AddUser(tx, user)
if err != nil {
tx.Rollback()
responses.FailWithMessage(err.Error(), c)
return
}
fmt.Println(user)
// 获取app用户信息
//var result *string
//if result == nil {
// // 新增app用户信息
//}
tx.Commit()
}
// 下发token
token := &utils.Token{
UserId: strconv.FormatInt(1, 10),
UserId: fmt.Sprintf("%d", user.UserId),
}
// 生成jwt
jwt, err := token.NewJWT()
if err != nil {
if err != nil || jwt == "" {
responses.FailWithMessage("登陆失败", c)
return
}
responses.OkWithData(jwt, c)
// 处理返回值
g := dto.LoginMobileDto(user)
// 加载token
g.LoadToken(jwt)
responses.OkWithData(g, c)
}
// LoginWx 微信授权登录
@ -55,7 +125,6 @@ func (r *Login) LoginWx(c *gin.Context) {
responses.FailWithMessage(err.Error(), c)
return
}
fmt.Println(webAccessToken)
// 网页授权拉取用户信息
userInfo, err := weChat.GetUserInfo(webAccessToken.AccessToken, webAccessToken.OpenId)

View File

@ -214,3 +214,68 @@ func (b *OrderMember) GetOrderMemberPay(c *gin.Context) {
responses.OkWithData(g, c)
}
// GetOrderMemberPayStatus 查询订单支付状态-会员
func (b *OrderMember) GetOrderMemberPayStatus(c *gin.Context) {
userId := c.GetInt64("UserId")
id := c.Param("order_id")
if id == "" {
responses.FailWithMessage("缺少参数", c)
return
}
// 将 id 转换为 int64 类型
orderId, err := strconv.ParseInt(id, 10, 64)
if err != nil {
responses.Fail(c)
return
}
// 获取订单数据
orderMemberDao := dao.OrderMemberDao{}
maps := make(map[string]interface{})
maps["user_id"] = userId
maps["order_id"] = orderId
orderMember, err := orderMemberDao.GetOrderMember(maps)
if err != nil {
responses.FailWithMessage("订单异常", c)
return
}
// 处理返回值
g := dto.GetOrderMemberPayStatus(orderMember)
// 处理有效期
if g.PayStatus == 2 {
// 获取单项配置
systemMemberDao := dao.SystemMemberDao{}
systemMember, err := systemMemberDao.GetSystemMemberById(orderMember.SystemMemberId)
if err != nil {
responses.FailWithMessage("内部错误", c)
return
}
// 获取用户数据
userDao := dao.UserDao{}
user, err := userDao.GetUserById(orderMember.UserId)
if err != nil {
responses.FailWithMessage("用户数据错误", c)
return
}
// 获取有效期
var validTime time.Time
if user.MemberExpireDate != nil {
validTime = user.MemberExpireDate.Add(time.Duration(systemMember.MemberDays) * 24 * time.Hour)
} else {
now := time.Now()
validTime = now.Add(time.Duration(systemMember.MemberDays) * 24 * time.Hour)
}
// 加载到期时间
g.LoadValidDate(&validTime)
}
responses.OkWithData(g, c)
}

View File

@ -334,3 +334,56 @@ func (b *OrderSingle) DeleteOrderSingle(c *gin.Context) {
tx.Commit()
responses.Ok(c)
}
// GetOrderSinglePayStatus 查询订单支付状态-单项
func (b *OrderSingle) GetOrderSinglePayStatus(c *gin.Context) {
userId := c.GetInt64("UserId")
id := c.Param("order_id")
if id == "" {
responses.FailWithMessage("缺少参数", c)
return
}
// 将 id 转换为 int64 类型
orderId, err := strconv.ParseInt(id, 10, 64)
if err != nil {
responses.Fail(c)
return
}
// 获取订单数据
orderSingleDao := dao.OrderSingleDao{}
maps := make(map[string]interface{})
maps["user_id"] = userId
maps["order_id"] = orderId
orderSingle, err := orderSingleDao.GetOrderSingle(maps)
if err != nil {
responses.FailWithMessage("订单异常", c)
return
}
// 处理返回值
g := dto.GetOrderSinglePayStatus(orderSingle)
// 处理有效期
if g.PayStatus == 2 {
// 获取单项配置
systemSingleDao := dao.SystemSingleDao{}
maps = make(map[string]interface{})
systemSingle, err := systemSingleDao.GetSystemSingle(maps)
if err != nil {
responses.FailWithMessage("内部错误", c)
return
}
// 获取有效期
validTime := orderSingle.PayTime.Add(time.Duration(systemSingle.ValidDays) * 24 * time.Hour)
// 加载到期时间
g.LoadValidDate(&validTime)
}
responses.OkWithData(g, c)
}

View File

@ -229,7 +229,7 @@ func (r *Question) GetQuestionBuyStatus(c *gin.Context) {
// 判断是否还在有效期内
now := time.Now()
ValidTime := single.PayTime.Add(time.Duration(systemSingle.ValidDays))
ValidTime := single.PayTime.Add(time.Duration(systemSingle.ValidDays) * 24 * time.Hour)
if ValidTime.Before(now) {
continue
}

View File

@ -56,8 +56,8 @@ func (r *OrderMemberDao) EditOrderMember(tx *gorm.DB, maps interface{}, data int
}
// EditOrderMemberById 修改-id
func (r *OrderMemberDao) EditOrderMemberById(tx *gorm.DB, OrderMemberId int64, data interface{}) error {
err := tx.Model(&model.OrderMember{}).Where("order_id = ?", OrderMemberId).Updates(data).Error
func (r *OrderMemberDao) EditOrderMemberById(tx *gorm.DB, OrderId int64, data interface{}) error {
err := tx.Model(&model.OrderMember{}).Where("order_id = ?", OrderId).Updates(data).Error
if err != nil {
return err
}

View File

@ -56,8 +56,8 @@ func (r *OrderSingleDao) EditOrderSingle(tx *gorm.DB, maps interface{}, data int
}
// EditOrderSingleById 修改-id
func (r *OrderSingleDao) EditOrderSingleById(tx *gorm.DB, OrderSingleId int64, data interface{}) error {
err := tx.Model(&model.OrderSingle{}).Where("order_id = ?", OrderSingleId).Updates(data).Error
func (r *OrderSingleDao) EditOrderSingleById(tx *gorm.DB, orderId int64, data interface{}) error {
err := tx.Model(&model.OrderSingle{}).Where("order_id = ?", orderId).Updates(data).Error
if err != nil {
return err
}

View File

@ -7,7 +7,18 @@ import (
"time"
)
type LoginDto struct {
type WxDto struct {
UserId string `json:"user_id"` // 用户id
UserName string `json:"user_name"` // 用户名称
Mobile string `json:"mobile"` // 手机号
OpenId string `json:"open_id"` // 用户微信标识
Avatar string `json:"avatar"` // 头像
IsMember int `json:"is_member"` // 是否会员0:否 1:是)
MemberExpireDate *time.Time `json:"member_expire_date"` // 会员到期时间非会员时为null
Token string `json:"token"` // token
}
type MobileDto struct {
UserId string `json:"user_id"` // 用户id
UserName string `json:"user_name"` // 用户名称
Mobile string `json:"mobile"` // 手机号
@ -19,8 +30,21 @@ type LoginDto struct {
}
// LoginWxDto 微信登陆
func LoginWxDto(m *model.User) *LoginDto {
return &LoginDto{
func LoginWxDto(m *model.User) *WxDto {
return &WxDto{
UserId: fmt.Sprintf("%d", m.UserId),
UserName: m.UserName,
Mobile: m.Mobile,
OpenId: m.OpenId,
Avatar: utils.AddOssDomain(m.Avatar),
IsMember: m.IsMember,
MemberExpireDate: m.MemberExpireDate,
}
}
// LoginMobileDto 手机号登陆
func LoginMobileDto(m *model.User) *MobileDto {
return &MobileDto{
UserId: fmt.Sprintf("%d", m.UserId),
UserName: m.UserName,
Mobile: m.Mobile,
@ -32,7 +56,13 @@ func LoginWxDto(m *model.User) *LoginDto {
}
// LoadToken 加载token
func (r *LoginDto) LoadToken(token string) *LoginDto {
func (r *WxDto) LoadToken(token string) *WxDto {
r.Token = token
return r
}
// LoadToken 加载token
func (r *MobileDto) LoadToken(token string) *MobileDto {
r.Token = token
return r
}

View File

@ -46,6 +46,13 @@ type OrderMemberPayDto struct {
PrepayApp *app.PrepayWithRequestPaymentResponse `json:"prepay_app"` // 预支付交易数据-app
}
// OrderMemberPayStatusDto 会员订单支付状态
type OrderMemberPayStatusDto struct {
PayStatus int `json:"pay_status"` // 支付状态1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
PaymentAmountTotal float64 `json:"payment_amount_total"` // 实际付款金额
ValidDate model.LocalTime `json:"valid_date"` // 到期时间
}
// GetOrderMemberListDto 列表
func GetOrderMemberListDto(m []*model.OrderMember) []*OrderMemberDto {
// 处理返回值
@ -89,7 +96,7 @@ func GetOrderMemberListDto(m []*model.OrderMember) []*OrderMemberDto {
return responses
}
// GetOrderMemberPayDto 获取单项订单支付数据
// GetOrderMemberPayDto 获取会员订单支付数据
func GetOrderMemberPayDto(m *model.OrderMember) *OrderMemberPayDto {
return &OrderMemberPayDto{
OrderId: fmt.Sprintf("%d", m.OrderId),
@ -102,6 +109,14 @@ func GetOrderMemberPayDto(m *model.OrderMember) *OrderMemberPayDto {
}
}
// GetOrderMemberPayStatus 获取会员订单支付状态
func GetOrderMemberPayStatus(m *model.OrderMember) *OrderMemberPayStatusDto {
return &OrderMemberPayStatusDto{
PayStatus: m.PayStatus,
PaymentAmountTotal: m.PaymentAmountTotal,
}
}
// LoadSystemMember 加载会员数据
func (r *OrderMemberDto) LoadSystemMember(m *model.SystemMember) *OrderMemberDto {
if m != nil {
@ -109,3 +124,11 @@ func (r *OrderMemberDto) LoadSystemMember(m *model.SystemMember) *OrderMemberDto
}
return r
}
// LoadValidDate 加载到期时间
func (r *OrderMemberPayStatusDto) LoadValidDate(m *time.Time) *OrderMemberPayStatusDto {
if m != nil {
r.ValidDate = model.LocalTime(*m)
}
return r
}

View File

@ -46,6 +46,13 @@ type OrderSinglePayDto struct {
PrepayApp *app.PrepayWithRequestPaymentResponse `json:"prepay_app"` // 预支付交易数据-app
}
// OrderSinglePayStatusDto 单项订单支付状态
type OrderSinglePayStatusDto struct {
PayStatus int `json:"pay_status"` // 支付状态1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
PaymentAmountTotal float64 `json:"payment_amount_total"` // 实际付款金额
ValidDate model.LocalTime `json:"valid_date"` // 到期时间
}
// GetOrderSingleListDto 列表
func GetOrderSingleListDto(m []*model.OrderSingle) []*OrderSingleDto {
// 处理返回值
@ -102,6 +109,14 @@ func GetOrderSinglePayDto(m *model.OrderSingle) *OrderSinglePayDto {
}
}
// GetOrderSinglePayStatus 获取单项订单支付状态
func GetOrderSinglePayStatus(m *model.OrderSingle) *OrderSinglePayStatusDto {
return &OrderSinglePayStatusDto{
PayStatus: m.PayStatus,
PaymentAmountTotal: m.PaymentAmountTotal,
}
}
// LoadQuestion 加载题目数据
func (r *OrderSingleDto) LoadQuestion(m *model.Question) *OrderSingleDto {
if m != nil {
@ -109,3 +124,11 @@ func (r *OrderSingleDto) LoadQuestion(m *model.Question) *OrderSingleDto {
}
return r
}
// LoadValidDate 加载到期时间
func (r *OrderSinglePayStatusDto) LoadValidDate(m *time.Time) *OrderSinglePayStatusDto {
if m != nil {
r.ValidDate = model.LocalTime(*m)
}
return r
}

View File

@ -1,12 +1,20 @@
package requests
type LoginRequest struct {
LoginWx // 微信授权登录
LoginWx // 微信授权登录
LoginPhone // 手机号登录
}
// LoginWx 微信授权登录
type LoginWx struct {
Code string `json:"code" form:"code" label:"授权码"`
Source int `json:"source" form:"source" label:"来源1app 2公众号"`
Code string `json:"code" form:"code" label:"授权码" validate:"required"`
Source int `json:"source" form:"source" label:"来源" validate:"required,oneof=1 2"` // 1app 2公众号
LoginIp string `json:"login_ip" form:"login_ip" label:"登录ip"`
}
// LoginPhone 手机号登录
type LoginPhone struct {
Mobile string `json:"mobile" form:"mobile" label:"手机号" validate:"required"`
Source int `json:"source" form:"source" label:"来源)" validate:"required"` // 1app 2公众号
LoginIp string `json:"login_ip" form:"login_ip" label:"登录ip"`
}

View File

@ -100,6 +100,9 @@ func publicRouter(r *gin.Engine, api controller.Api) {
{
// 单项
wxpayGroup.POST("/single", api.CallBack.WxPaySingle)
// 会员
wxpayGroup.POST("/member", api.CallBack.WxPayMember)
}
}
}
@ -201,6 +204,9 @@ func privateRouter(r *gin.Engine, api controller.Api) {
// 删除单项订单
singleGroup.DELETE("/:order_id", api.OrderSingle.DeleteOrderSingle)
// 查询订单支付状态-单项
singleGroup.GET("/pay/status/:order_id", api.OrderSingle.GetOrderSinglePayStatus)
}
// 会员订单
@ -214,6 +220,9 @@ func privateRouter(r *gin.Engine, api controller.Api) {
// 获取会员订单支付数据
memberGroup.GET("/pay/:order_id", api.OrderMember.GetOrderMemberPay)
// 查询订单支付状态-会员
memberGroup.GET("/pay/status/:order_id", api.OrderMember.GetOrderMemberPayStatus)
}
}

View File

@ -21,7 +21,7 @@ type OrderMemberService struct {
// AddOrderMember 创建会员订单
func (r *OrderMemberService) AddOrderMember(tx *gorm.DB, UserId, SystemMemberId int64, UserCouponId *int64, payChannel int, orderPrice float64) (orderMember *model.OrderMember, err error) {
// 检测多次请求
// 检测并发请求
redisKey := "AddOrderMember" + fmt.Sprintf("%d", UserId) + fmt.Sprintf("%d", SystemMemberId)
res, _ := global.Redis.Get(context.Background(), redisKey).Result()
if res != "" {

View File

@ -20,8 +20,9 @@ type OrderSingleService struct {
}
// AddOrderSingle 创建单项订单
// payChannel:支付渠道1:h5支付 2:app支付 3:会员支付)
func (r *OrderSingleService) AddOrderSingle(tx *gorm.DB, UserId, QuestionId int64, UserCouponId *int64, payChannel int, orderPrice float64) (orderSingle *model.OrderSingle, err error) {
// 检测多次请求
// 检测并发请求
redisKey := "AddOrderSingle" + fmt.Sprintf("%d", UserId) + fmt.Sprintf("%d", QuestionId)
res, _ := global.Redis.Get(context.Background(), redisKey).Result()
if res != "" {
@ -343,3 +344,36 @@ func (r *OrderSingleService) GetAppPrepay(m *model.OrderSingle) (prepay *app.Pre
return prepay, nil
}
// CompleteUnPayOrderSingle 完成未支付单项订单-开通会员成功时使用
func (r *OrderSingleService) CompleteUnPayOrderSingle(tx *gorm.DB, userId int64) (bool, error) {
// 获取所有未支付单项订单
orderSingleDao := dao.OrderSingleDao{}
maps := make(map[string]interface{})
maps["user_id"] = userId
maps["order_status"] = 1
maps["pay_status"] = 1
maps["cancel_status"] = 0
orderSingles, err := orderSingleDao.GetOrderSingleList(maps)
if err != nil {
return false, err
}
for _, single := range orderSingles {
// 生成第三方支付流水号
escrowTradeNo := "GD" + global.Snowflake.Generate().String()
orderSingleData := make(map[string]interface{})
orderSingleData["order_status"] = 2
orderSingleData["pay_status"] = 2
orderSingleData["pay_time"] = time.Now().Format("2006-01-02 15:04:05")
orderSingleData["escrow_trade_no"] = escrowTradeNo
orderSingleData["updated_at"] = time.Now().Format("2006-01-02 15:04:05")
err = orderSingleDao.EditOrderSingleById(tx, single.OrderId, orderSingleData)
if err != nil {
return false, err
}
}
return true, nil
}

View File

@ -3,6 +3,7 @@ package service
import (
"errors"
"fmt"
"gorm.io/gorm"
"hepa-calc-api/api/dao"
"hepa-calc-api/api/model"
"hepa-calc-api/extend/aliyun"
@ -82,3 +83,25 @@ func (r *UserService) CheckUserBuyOrderMember(userId int64) bool {
return true
}
// AddUserMemberValidDate 增加用户会员过期时间
func (r *UserService) AddUserMemberValidDate(tx *gorm.DB, user *model.User, d int) bool {
userData := make(map[string]interface{})
if user.IsMember == 0 {
userData["is_member"] = 1
}
if user.MemberExpireDate == nil {
userData["is_member"] = time.Now().Format("2006-01-02 15:04:05")
} else {
userData["is_member"] = user.MemberExpireDate.Add(time.Duration(d) * 24 * time.Hour)
}
userDao := dao.UserDao{}
err := userDao.EditUserById(tx, user.UserId, userData)
if err != nil {
return false
}
return true
}

View File

@ -5,8 +5,10 @@ import (
"errors"
"github.com/wechatpay-apiv3/wechatpay-go/core"
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
"github.com/wechatpay-apiv3/wechatpay-go/utils"
"hepa-calc-api/config"
"time"
)
// 创建客户端
@ -38,3 +40,66 @@ func createClient() (*core.Client, error) {
return client, nil
}
type WxPayResult struct {
OrderStatus *int `json:"order_status"` // 订单状态1:待支付 2:已完成 3:已取消)
PayStatus *int `json:"pay_status"` // 支付状态1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
PayTime *time.Time `json:"pay_time"` // 支付时间
}
// HandlePayStatus 处理支付状态
func HandlePayStatus(t *payments.Transaction) (w *WxPayResult, err error) {
// 支付成功
if *t.TradeState == "SUCCESS" {
orderStatus := 2
w.OrderStatus = &orderStatus
payStatus := 2
w.PayStatus = &payStatus
parse, err := time.Parse("2006-01-02T15:04:05+07:00", *t.SuccessTime)
if err != nil {
return nil, errors.New("支付时间处理错误")
}
w.PayTime = &parse
if err != nil {
return nil, errors.New("支付时间错误")
}
}
switch *t.TradeState {
case "SUCCESS": // 支付成功
orderStatus := 2
w.OrderStatus = &orderStatus
payStatus := 2
w.PayStatus = &payStatus
parse, err := time.Parse("2006-01-02T15:04:05+07:00", *t.SuccessTime)
if err != nil {
return nil, errors.New("支付时间处理错误")
}
w.PayTime = &parse
if err != nil {
return nil, errors.New("支付时间错误")
}
case "CLOSED": // 已关闭
payStatus := 6
w.PayStatus = &payStatus
case "REVOKED": // 已撤销(付款码支付)
payStatus := 7
w.PayStatus = &payStatus
case "USERPAYING": // 用户支付中(付款码支付)
payStatus := 3
w.PayStatus = &payStatus
case "PAYERROR": // 支付失败(其他原因,如银行返回失败)
payStatus := 4
w.PayStatus = &payStatus
default:
return nil, errors.New("未知支付状态")
}
return w, nil
}

View File

@ -3,7 +3,6 @@ package weChat
import (
"context"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
"github.com/wechatpay-apiv3/wechatpay-go/core/downloader"
@ -14,7 +13,7 @@ import (
)
// ParseNotify 回调通知的验签与解密
func ParseNotify(c *gin.Context) (notifyReq *notify.Request, err error) {
func ParseNotify(c *gin.Context) (notifyReq *notify.Request, t *payments.Transaction, err error) {
mchId := config.C.Wechat.Pay1659662936.MchId // 商户号
mchCertificateSerialNumber := config.C.Wechat.Pay1659662936.MchCertificateSerialNumber // 商户证书序列号
v3ApiSecret := config.C.Wechat.Pay1659662936.V3ApiSecret // 商户APIv3密钥
@ -23,13 +22,13 @@ func ParseNotify(c *gin.Context) (notifyReq *notify.Request, err error) {
// 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
mchPrivateKey, err := utils.LoadPrivateKeyWithPath(privateKeyPath)
if err != nil {
return nil, errors.New("微信支付生成失败")
return nil, nil, errors.New("微信支付生成失败")
}
// 1. 使用 `RegisterDownloaderWithPrivateKey` 注册下载器
err = downloader.MgrInstance().RegisterDownloaderWithPrivateKey(c, mchPrivateKey, mchCertificateSerialNumber, mchId, v3ApiSecret)
if err != nil {
return nil, err
return nil, nil, err
}
// 2. 获取商户号对应的微信支付平台证书访问器
@ -41,9 +40,8 @@ func ParseNotify(c *gin.Context) (notifyReq *notify.Request, err error) {
notifyReq, err = handler.ParseNotifyRequest(context.Background(), c.Request, transaction)
// 如果验签未通过,或者解密失败
if err != nil {
return nil, err
return nil, nil, err
}
fmt.Println(transaction)
return notifyReq, nil
return notifyReq, transaction, nil
}

1
go.mod
View File

@ -43,6 +43,7 @@ require (
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c // indirect
github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9 // indirect

2
go.sum
View File

@ -57,6 +57,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/facebookarchive/grace v0.0.0-20180706040059-75cf19382434 h1:AFIATPhFj7mrISc4z9zEpfm4a8UfwsCWzJ+Je5jA5Rs=
github.com/facebookarchive/grace v0.0.0-20180706040059-75cf19382434/go.mod h1:PY9iiFMrFjTzegsqfKCcb+Ekk5/j0ch0sMdBwlT6atI=
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw=

View File

@ -13,3 +13,17 @@ func OrderCancelReasonToString(i int) string {
return "取消"
}
}
// OrderSingleStatusToString 订单状态1:待支付 2:已完成 3:已取消)
func OrderSingleStatusToString(i int) string {
switch i {
case 1:
return "待支付"
case 2:
return "已完成"
case 3:
return "已取消"
default:
return "未知"
}
}