增加了单项订单的接口
This commit is contained in:
parent
dfda2e2425
commit
8c84ed3656
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"hepa-calc-api/api/dao"
|
"hepa-calc-api/api/dao"
|
||||||
|
"hepa-calc-api/api/dto"
|
||||||
"hepa-calc-api/api/model"
|
"hepa-calc-api/api/model"
|
||||||
"hepa-calc-api/api/requests"
|
"hepa-calc-api/api/requests"
|
||||||
"hepa-calc-api/api/responses"
|
"hepa-calc-api/api/responses"
|
||||||
@ -35,18 +36,6 @@ func (r *Login) LoginPhone(c *gin.Context) {
|
|||||||
|
|
||||||
// LoginWx 微信授权登录
|
// LoginWx 微信授权登录
|
||||||
func (r *Login) LoginWx(c *gin.Context) {
|
func (r *Login) LoginWx(c *gin.Context) {
|
||||||
userService := service.UserService{}
|
|
||||||
// 处理用户头像
|
|
||||||
avatar, err := userService.HandleUserAvatar("https://thirdwx.qlogo.cn/mmopen/vi_32/dzhWq43iaB5GyJJUbajibSQtIt6d4Y9QPk5ImB1C14fPk6AOtcgaPztUzjKwb9kmPtqNpyCal5cEyw0YyTr1QEbdtHiaOViay4RgSpdm2XaduXA/132")
|
|
||||||
if err != nil {
|
|
||||||
responses.FailWithMessage(err.Error(), c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(avatar)
|
|
||||||
responses.Ok(c)
|
|
||||||
return
|
|
||||||
|
|
||||||
loginRequest := requests.LoginRequest{}
|
loginRequest := requests.LoginRequest{}
|
||||||
req := loginRequest.LoginWx
|
req := loginRequest.LoginWx
|
||||||
if err := c.ShouldBind(&req); err != nil {
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
@ -87,12 +76,13 @@ func (r *Login) LoginWx(c *gin.Context) {
|
|||||||
tx := global.Db.Begin()
|
tx := global.Db.Begin()
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
fmt.Println(r)
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
userService := service.UserService{}
|
|
||||||
// 处理用户头像
|
// 处理用户头像
|
||||||
|
userService := service.UserService{}
|
||||||
avatar, err := userService.HandleUserAvatar(userInfo.HeadImgUrl)
|
avatar, err := userService.HandleUserAvatar(userInfo.HeadImgUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
@ -101,7 +91,7 @@ func (r *Login) LoginWx(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 新增用户
|
// 新增用户
|
||||||
user := &model.User{
|
user = &model.User{
|
||||||
UserName: userInfo.Nickname,
|
UserName: userInfo.Nickname,
|
||||||
Mobile: "",
|
Mobile: "",
|
||||||
RegisterSource: req.Source,
|
RegisterSource: req.Source,
|
||||||
@ -123,10 +113,10 @@ func (r *Login) LoginWx(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取app用户信息
|
// 获取app用户信息
|
||||||
var result *string
|
//var result *string
|
||||||
if result == nil {
|
//if result == nil {
|
||||||
// 新增app用户信息
|
// // 新增app用户信息
|
||||||
}
|
//}
|
||||||
|
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
}
|
}
|
||||||
@ -138,10 +128,16 @@ func (r *Login) LoginWx(c *gin.Context) {
|
|||||||
|
|
||||||
// 生成jwt
|
// 生成jwt
|
||||||
jwt, err := token.NewJWT()
|
jwt, err := token.NewJWT()
|
||||||
if err != nil {
|
if err != nil || jwt == "" {
|
||||||
responses.FailWithMessage("登陆失败", c)
|
responses.FailWithMessage("登陆失败", c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
responses.OkWithData(jwt, c)
|
// 处理返回值
|
||||||
|
g := dto.LoginWxDto(user)
|
||||||
|
|
||||||
|
// 加载token
|
||||||
|
g.LoadToken(jwt)
|
||||||
|
|
||||||
|
responses.OkWithData(g, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,17 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"hepa-calc-api/api/dao"
|
"hepa-calc-api/api/dao"
|
||||||
"hepa-calc-api/api/dto"
|
"hepa-calc-api/api/dto"
|
||||||
"hepa-calc-api/api/requests"
|
"hepa-calc-api/api/requests"
|
||||||
"hepa-calc-api/api/responses"
|
"hepa-calc-api/api/responses"
|
||||||
|
"hepa-calc-api/api/service"
|
||||||
"hepa-calc-api/global"
|
"hepa-calc-api/global"
|
||||||
"hepa-calc-api/utils"
|
"hepa-calc-api/utils"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OrderSingle struct{}
|
type OrderSingle struct{}
|
||||||
@ -56,3 +60,258 @@ func (b *OrderSingle) GetOrderSinglePage(c *gin.Context) {
|
|||||||
result["data"] = g
|
result["data"] = g
|
||||||
responses.OkWithData(result, c)
|
responses.OkWithData(result, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddOrderSingle 创建单项订单
|
||||||
|
func (b *OrderSingle) AddOrderSingle(c *gin.Context) {
|
||||||
|
orderSingleRequest := requests.OrderSingleRequest{}
|
||||||
|
req := orderSingleRequest.AddOrderSingle
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
userId := c.GetInt64("UserId")
|
||||||
|
|
||||||
|
// 将 id 转换为 int64 类型
|
||||||
|
questionId, err := strconv.ParseInt(req.QuestionId, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
responses.Fail(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户优惠卷id
|
||||||
|
var userCouponId *int64
|
||||||
|
if req.UserCouponId != "" {
|
||||||
|
id, err := strconv.ParseInt(req.UserCouponId, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
responses.Fail(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userCouponId = &id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始事务
|
||||||
|
tx := global.Db.Begin()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 创建单项订单
|
||||||
|
orderSingleService := service.OrderSingleService{}
|
||||||
|
orderSingle, err := orderSingleService.AddOrderSingle(tx, userId, questionId, userCouponId, req.PayChannel)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
responses.FailWithMessage(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
// 处理返回值
|
||||||
|
orderId := fmt.Sprintf("%d", orderSingle.OrderId)
|
||||||
|
|
||||||
|
responses.OkWithData(orderId, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutCancelOrderSingle 取消单项订单
|
||||||
|
func (b *OrderSingle) PutCancelOrderSingle(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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始事务
|
||||||
|
tx := global.Db.Begin()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 取消单项订单
|
||||||
|
orderSingleService := service.OrderSingleService{}
|
||||||
|
res, err := orderSingleService.PutCancelOrderSingle(tx, userId, orderId, 1)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
responses.FailWithMessage(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if res == false {
|
||||||
|
tx.Rollback()
|
||||||
|
responses.FailWithMessage("取消订单失败", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
responses.Ok(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOrderSinglePay 获取单项订单支付数据
|
||||||
|
func (b *OrderSingle) GetOrderSinglePay(c *gin.Context) {
|
||||||
|
orderSingleRequest := requests.OrderSingleRequest{}
|
||||||
|
req := orderSingleRequest.GetOrderSinglePay
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测订单状态(1:待支付 2:已完成 3:已取消)
|
||||||
|
if orderSingle.OrderStatus != 1 {
|
||||||
|
responses.FailWithMessage("订单状态异常", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
|
||||||
|
if orderSingle.PayStatus != 1 {
|
||||||
|
responses.FailWithMessage("订单支付状态异常", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证订单过期支付时间
|
||||||
|
now := time.Now()
|
||||||
|
validTime := time.Time(orderSingle.CreatedAt).Add(30 * time.Minute)
|
||||||
|
if validTime.Before(now) {
|
||||||
|
responses.FailWithMessage("订单已过期", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理返回值
|
||||||
|
g := dto.GetOrderSinglePayDto(orderSingle)
|
||||||
|
|
||||||
|
// 获取预支付交易会话标识
|
||||||
|
if req.ClientType == 1 {
|
||||||
|
orderSingleService := service.OrderSingleService{}
|
||||||
|
prepay, err := orderSingleService.GetJsapiPrepay(orderSingle)
|
||||||
|
if err != nil {
|
||||||
|
responses.FailWithMessage("发起支付失败", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
g.PrepayJsapi = prepay
|
||||||
|
} else {
|
||||||
|
orderSingleService := service.OrderSingleService{}
|
||||||
|
prepay, err := orderSingleService.GetAppPrepay(orderSingle)
|
||||||
|
if err != nil {
|
||||||
|
responses.FailWithMessage("发起支付失败", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
g.PrepayApp = prepay
|
||||||
|
}
|
||||||
|
|
||||||
|
responses.OkWithData(g, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteOrderSingle 删除单项订单支付数据
|
||||||
|
func (b *OrderSingle) DeleteOrderSingle(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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测订单状态
|
||||||
|
if orderSingle.OrderStatus != 2 {
|
||||||
|
responses.FailWithMessage("订单不允许删除", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测订单删除状态
|
||||||
|
if orderSingle.IsDelete == 1 {
|
||||||
|
responses.Ok(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始事务
|
||||||
|
tx := global.Db.Begin()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
orderSingleData := make(map[string]interface{})
|
||||||
|
orderSingleData["is_delete"] = 1
|
||||||
|
orderSingleData["updated_at"] = time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
err = orderSingleDao.EditOrderSingleById(tx, orderId, orderSingleData)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
responses.FailWithMessage("删除失败", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
responses.Ok(c)
|
||||||
|
}
|
||||||
|
|||||||
@ -12,8 +12,8 @@ type OrderSingleDao struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetOrderSingleById 获取数据-id
|
// GetOrderSingleById 获取数据-id
|
||||||
func (r *OrderSingleDao) GetOrderSingleById(OrderSingleId int64) (m *model.OrderSingle, err error) {
|
func (r *OrderSingleDao) GetOrderSingleById(OrderId int64) (m *model.OrderSingle, err error) {
|
||||||
err = global.Db.First(&m, OrderSingleId).Error
|
err = global.Db.First(&m, OrderId).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -21,8 +21,8 @@ func (r *OrderSingleDao) GetOrderSingleById(OrderSingleId int64) (m *model.Order
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetOrderSinglePreloadById 获取数据-加载全部关联-id
|
// GetOrderSinglePreloadById 获取数据-加载全部关联-id
|
||||||
func (r *OrderSingleDao) GetOrderSinglePreloadById(OrderSingleId int64) (m *model.OrderSingle, err error) {
|
func (r *OrderSingleDao) GetOrderSinglePreloadById(OrderId int64) (m *model.OrderSingle, err error) {
|
||||||
err = global.Db.Preload(clause.Associations).First(&m, OrderSingleId).Error
|
err = global.Db.Preload(clause.Associations).First(&m, OrderId).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -39,8 +39,8 @@ func (r *OrderSingleDao) DeleteOrderSingle(tx *gorm.DB, maps interface{}) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOrderSingleById 删除-id
|
// DeleteOrderSingleById 删除-id
|
||||||
func (r *OrderSingleDao) DeleteOrderSingleById(tx *gorm.DB, OrderSingleId int64) error {
|
func (r *OrderSingleDao) DeleteOrderSingleById(tx *gorm.DB, orderId int64) error {
|
||||||
if err := tx.Delete(&model.OrderSingle{}, OrderSingleId).Error; err != nil {
|
if err := tx.Delete(&model.OrderSingle{}, orderId).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -28,6 +28,15 @@ func (r *OrderSingleCouponDao) GetOrderSingleCouponPreloadById(OrderSingleCoupon
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOrderSingleCouponByOrderId 获取数据-订单id
|
||||||
|
func (r *OrderSingleCouponDao) GetOrderSingleCouponByOrderId(orderId int64) (m *model.OrderSingleCoupon, err error) {
|
||||||
|
err = global.Db.Where("order_id = ?", orderId).First(&m).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteOrderSingleCoupon 删除
|
// DeleteOrderSingleCoupon 删除
|
||||||
func (r *OrderSingleCouponDao) DeleteOrderSingleCoupon(tx *gorm.DB, maps interface{}) error {
|
func (r *OrderSingleCouponDao) DeleteOrderSingleCoupon(tx *gorm.DB, maps interface{}) error {
|
||||||
err := tx.Where(maps).Delete(&model.OrderSingleCoupon{}).Error
|
err := tx.Where(maps).Delete(&model.OrderSingleCoupon{}).Error
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import (
|
|||||||
type CouponDto struct {
|
type CouponDto struct {
|
||||||
CouponId string `json:"coupon_id"` // 主键id
|
CouponId string `json:"coupon_id"` // 主键id
|
||||||
CouponName string `json:"coupon_name"` // 优惠券名称
|
CouponName string `json:"coupon_name"` // 优惠券名称
|
||||||
CouponType string `json:"coupon_type"` // 优惠券类型(1:无门槛 2:满减)
|
CouponType int `json:"coupon_type"` // 优惠券类型(1:无门槛 2:满减)
|
||||||
CouponStatus int `json:"coupon_status"` // 状态(1:正常 2:强制失效 3:结束 4:删除)
|
CouponStatus int `json:"coupon_status"` // 状态(1:正常 2:强制失效 3:结束 4:删除)
|
||||||
ApplicationScope int `json:"application_scope"` // 适用范围(1:全场通用)
|
ApplicationScope int `json:"application_scope"` // 适用范围(1:全场通用)
|
||||||
IsMutex int `json:"is_mutex"` // 是否互斥(0:否 1:是)
|
IsMutex int `json:"is_mutex"` // 是否互斥(0:否 1:是)
|
||||||
|
|||||||
38
api/dto/Login.go
Normal file
38
api/dto/Login.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"hepa-calc-api/api/model"
|
||||||
|
"hepa-calc-api/utils"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoginDto 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoginWxDto 微信登陆
|
||||||
|
func LoginWxDto(m *model.User) *LoginDto {
|
||||||
|
return &LoginDto{
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadToken 加载token
|
||||||
|
func (r *LoginDto) LoadToken(token string) *LoginDto {
|
||||||
|
r.Token = token
|
||||||
|
return r
|
||||||
|
}
|
||||||
@ -2,7 +2,10 @@ package dto
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/app"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
|
||||||
"hepa-calc-api/api/model"
|
"hepa-calc-api/api/model"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OrderSingleDto 订单-单项
|
// OrderSingleDto 订单-单项
|
||||||
@ -14,7 +17,7 @@ type OrderSingleDto struct {
|
|||||||
IsDelete int `json:"is_delete"` // 用户删除状态(0:否 1:是)
|
IsDelete int `json:"is_delete"` // 用户删除状态(0:否 1:是)
|
||||||
PayChannel int `json:"pay_channel"` // 支付渠道(1:h5支付 2:app支付 3:会员支付)
|
PayChannel int `json:"pay_channel"` // 支付渠道(1:h5支付 2:app支付 3:会员支付)
|
||||||
PayStatus int `json:"pay_status"` // 支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
|
PayStatus int `json:"pay_status"` // 支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
|
||||||
PayTime model.LocalTime `json:"pay_time"` // 支付时间
|
PayTime *time.Time `json:"pay_time"` // 支付时间
|
||||||
RefundStatus int `json:"refund_status"` // 订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常 7:部分退款)
|
RefundStatus int `json:"refund_status"` // 订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常 7:部分退款)
|
||||||
OrderNo string `json:"order_no"` // 系统订单编号
|
OrderNo string `json:"order_no"` // 系统订单编号
|
||||||
EscrowTradeNo string `json:"escrow_trade_no"` // 第三方支付流水号
|
EscrowTradeNo string `json:"escrow_trade_no"` // 第三方支付流水号
|
||||||
@ -22,7 +25,7 @@ type OrderSingleDto struct {
|
|||||||
CouponAmountTotal float64 `json:"coupon_amount_total"` // 优惠卷总金额
|
CouponAmountTotal float64 `json:"coupon_amount_total"` // 优惠卷总金额
|
||||||
PaymentAmountTotal float64 `json:"payment_amount_total"` // 实际付款金额
|
PaymentAmountTotal float64 `json:"payment_amount_total"` // 实际付款金额
|
||||||
CancelStatus int `json:"cancel_status"` // 取消状态(0:否 1:是)
|
CancelStatus int `json:"cancel_status"` // 取消状态(0:否 1:是)
|
||||||
CancelTime model.LocalTime `json:"cancel_time"` // 订单取消时间
|
CancelTime *time.Time `json:"cancel_time"` // 订单取消时间
|
||||||
CancelRemarks string `json:"cancel_remarks"` // 取消订单备注
|
CancelRemarks string `json:"cancel_remarks"` // 取消订单备注
|
||||||
OrderRemarks string `json:"order_remarks"` // 订单备注
|
OrderRemarks string `json:"order_remarks"` // 订单备注
|
||||||
CreatedAt model.LocalTime `json:"created_at"` // 创建时间
|
CreatedAt model.LocalTime `json:"created_at"` // 创建时间
|
||||||
@ -30,6 +33,19 @@ type OrderSingleDto struct {
|
|||||||
Question *QuestionDto `json:"question"` // 问题
|
Question *QuestionDto `json:"question"` // 问题
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OrderSinglePayDto 单项订单支付数据
|
||||||
|
type OrderSinglePayDto struct {
|
||||||
|
OrderId string `json:"order_id"` // 主键id
|
||||||
|
QuestionId string `json:"question_id"` // 问题id
|
||||||
|
OrderNo string `json:"order_no"` // 系统订单编号
|
||||||
|
AmountTotal float64 `json:"amount_total"` // 订单金额
|
||||||
|
CouponAmountTotal float64 `json:"coupon_amount_total"` // 优惠卷总金额
|
||||||
|
PaymentAmountTotal float64 `json:"payment_amount_total"` // 实际付款金额
|
||||||
|
CreatedAt model.LocalTime `json:"created_at"` // 创建时间
|
||||||
|
PrepayJsapi *jsapi.PrepayWithRequestPaymentResponse `json:"prepay_jsapi"` // 预支付交易数据-jsapi
|
||||||
|
PrepayApp *app.PrepayWithRequestPaymentResponse `json:"prepay_app"` // 预支付交易数据-app
|
||||||
|
}
|
||||||
|
|
||||||
// GetOrderSingleListDto 列表
|
// GetOrderSingleListDto 列表
|
||||||
func GetOrderSingleListDto(m []*model.OrderSingle) []*OrderSingleDto {
|
func GetOrderSingleListDto(m []*model.OrderSingle) []*OrderSingleDto {
|
||||||
// 处理返回值
|
// 处理返回值
|
||||||
@ -73,6 +89,19 @@ func GetOrderSingleListDto(m []*model.OrderSingle) []*OrderSingleDto {
|
|||||||
return responses
|
return responses
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOrderSinglePayDto 获取单项订单支付数据
|
||||||
|
func GetOrderSinglePayDto(m *model.OrderSingle) *OrderSinglePayDto {
|
||||||
|
return &OrderSinglePayDto{
|
||||||
|
OrderId: fmt.Sprintf("%d", m.OrderId),
|
||||||
|
QuestionId: fmt.Sprintf("%d", m.QuestionId),
|
||||||
|
OrderNo: m.OrderNo,
|
||||||
|
AmountTotal: m.AmountTotal,
|
||||||
|
CouponAmountTotal: m.CouponAmountTotal,
|
||||||
|
PaymentAmountTotal: m.PaymentAmountTotal,
|
||||||
|
CreatedAt: m.CreatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// LoadQuestion 加载题目数据
|
// LoadQuestion 加载题目数据
|
||||||
func (r *OrderSingleDto) LoadQuestion(m *model.Question) *OrderSingleDto {
|
func (r *OrderSingleDto) LoadQuestion(m *model.Question) *OrderSingleDto {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
|
|||||||
@ -18,7 +18,7 @@ type QuestionDto struct {
|
|||||||
SubmitCount int `json:"submit_count"` // 提交次数(提交个人信息进行了算算的人次)
|
SubmitCount int `json:"submit_count"` // 提交次数(提交个人信息进行了算算的人次)
|
||||||
PayCount int `json:"pay_count"` // 支付次数(查看报告的人次)
|
PayCount int `json:"pay_count"` // 支付次数(查看报告的人次)
|
||||||
Price float64 `json:"price"` // 价格(原价)
|
Price float64 `json:"price"` // 价格(原价)
|
||||||
DiscountPrice float64 `json:"discount_price"` // 优惠价格
|
DiscountPrice *float64 `json:"discount_price"` // 优惠价格
|
||||||
QuestionBrief string `json:"question_brief"` // 问题介绍
|
QuestionBrief string `json:"question_brief"` // 问题介绍
|
||||||
QuestionExplain string `json:"question_explain"` // 问题解释/科普
|
QuestionExplain string `json:"question_explain"` // 问题解释/科普
|
||||||
CreatedAt model.LocalTime `json:"created_at"` // 创建时间
|
CreatedAt model.LocalTime `json:"created_at"` // 创建时间
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import (
|
|||||||
type Coupon struct {
|
type Coupon struct {
|
||||||
CouponId int64 `gorm:"column:coupon_id;type:bigint(19);primary_key;comment:主键id" json:"coupon_id"`
|
CouponId int64 `gorm:"column:coupon_id;type:bigint(19);primary_key;comment:主键id" json:"coupon_id"`
|
||||||
CouponName string `gorm:"column:coupon_name;type:varchar(255);comment:优惠卷名称" json:"coupon_name"`
|
CouponName string `gorm:"column:coupon_name;type:varchar(255);comment:优惠卷名称" json:"coupon_name"`
|
||||||
CouponType string `gorm:"column:coupon_type;type:varchar(255);comment:优惠卷类型(1:无门槛 2:满减)" json:"coupon_type"`
|
CouponType int `gorm:"column:coupon_type;type:varchar(255);comment:优惠卷类型(1:无门槛 2:满减)" json:"coupon_type"`
|
||||||
CouponStatus int `gorm:"column:coupon_status;type:tinyint(1);default:1;comment:状态(1:正常 2:强制失效 3:结束 4:删除)" json:"coupon_status"`
|
CouponStatus int `gorm:"column:coupon_status;type:tinyint(1);default:1;comment:状态(1:正常 2:强制失效 3:结束 4:删除)" json:"coupon_status"`
|
||||||
ApplicationScope int `gorm:"column:application_scope;type:tinyint(1);default:1;comment:适用范围(1:全场通用 2:单项 3:会员)" json:"application_scope"`
|
ApplicationScope int `gorm:"column:application_scope;type:tinyint(1);default:1;comment:适用范围(1:全场通用 2:单项 3:会员)" json:"application_scope"`
|
||||||
IsMutex int `gorm:"column:is_mutex;type:tinyint(1);default:1;comment:是否互斥(0:否 1:是)互斥情况下无法和其他优惠卷同时使用" json:"is_mutex"`
|
IsMutex int `gorm:"column:is_mutex;type:tinyint(1);default:1;comment:是否互斥(0:否 1:是)互斥情况下无法和其他优惠卷同时使用" json:"is_mutex"`
|
||||||
|
|||||||
@ -15,7 +15,7 @@ type OrderSingle struct {
|
|||||||
IsDelete int `gorm:"column:is_delete;type:tinyint(1);default:0;comment:用户删除状态(0:否 1:是)" json:"is_delete"`
|
IsDelete int `gorm:"column:is_delete;type:tinyint(1);default:0;comment:用户删除状态(0:否 1:是)" json:"is_delete"`
|
||||||
PayChannel int `gorm:"column:pay_channel;type:tinyint(1);comment:支付渠道(1:h5支付 2:app支付 3:会员支付);NOT NULL" json:"pay_channel"`
|
PayChannel int `gorm:"column:pay_channel;type:tinyint(1);comment:支付渠道(1:h5支付 2:app支付 3:会员支付);NOT NULL" json:"pay_channel"`
|
||||||
PayStatus int `gorm:"column:pay_status;type:tinyint(1);default:1;comment:支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款);NOT NULL" json:"pay_status"`
|
PayStatus int `gorm:"column:pay_status;type:tinyint(1);default:1;comment:支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款);NOT NULL" json:"pay_status"`
|
||||||
PayTime LocalTime `gorm:"column:pay_time;type:datetime;comment:支付时间" json:"pay_time"`
|
PayTime *time.Time `gorm:"column:pay_time;type:datetime;comment:支付时间" json:"pay_time"`
|
||||||
RefundStatus int `gorm:"column:refund_status;type:tinyint(1);default:0;comment:订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常 7:部分退款);NOT NULL" json:"refund_status"`
|
RefundStatus int `gorm:"column:refund_status;type:tinyint(1);default:0;comment:订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常 7:部分退款);NOT NULL" json:"refund_status"`
|
||||||
OrderNo string `gorm:"column:order_no;type:varchar(30);comment:系统订单编号;NOT NULL" json:"order_no"`
|
OrderNo string `gorm:"column:order_no;type:varchar(30);comment:系统订单编号;NOT NULL" json:"order_no"`
|
||||||
EscrowTradeNo string `gorm:"column:escrow_trade_no;type:varchar(100);comment:第三方支付流水号;NOT NULL" json:"escrow_trade_no"`
|
EscrowTradeNo string `gorm:"column:escrow_trade_no;type:varchar(100);comment:第三方支付流水号;NOT NULL" json:"escrow_trade_no"`
|
||||||
@ -23,7 +23,7 @@ type OrderSingle struct {
|
|||||||
CouponAmountTotal float64 `gorm:"column:coupon_amount_total;type:decimal(10,2);default:0.00;comment:优惠卷总金额" json:"coupon_amount_total"`
|
CouponAmountTotal float64 `gorm:"column:coupon_amount_total;type:decimal(10,2);default:0.00;comment:优惠卷总金额" json:"coupon_amount_total"`
|
||||||
PaymentAmountTotal float64 `gorm:"column:payment_amount_total;type:decimal(10,2);default:0.00;comment:实际付款金额" json:"payment_amount_total"`
|
PaymentAmountTotal float64 `gorm:"column:payment_amount_total;type:decimal(10,2);default:0.00;comment:实际付款金额" json:"payment_amount_total"`
|
||||||
CancelStatus int `gorm:"column:cancel_status;type:tinyint(1);default:0;comment:取消状态(0:否 1:是)" json:"cancel_status"`
|
CancelStatus int `gorm:"column:cancel_status;type:tinyint(1);default:0;comment:取消状态(0:否 1:是)" json:"cancel_status"`
|
||||||
CancelTime LocalTime `gorm:"column:cancel_time;type:datetime;comment:订单取消时间" json:"cancel_time"`
|
CancelTime *time.Time `gorm:"column:cancel_time;type:datetime;comment:订单取消时间" json:"cancel_time"`
|
||||||
CancelRemarks string `gorm:"column:cancel_remarks;type:varchar(255);comment:取消订单备注" json:"cancel_remarks"`
|
CancelRemarks string `gorm:"column:cancel_remarks;type:varchar(255);comment:取消订单备注" json:"cancel_remarks"`
|
||||||
OrderRemarks string `gorm:"column:order_remarks;type:varchar(255);comment:订单备注" json:"order_remarks"`
|
OrderRemarks string `gorm:"column:order_remarks;type:varchar(255);comment:订单备注" json:"order_remarks"`
|
||||||
Model
|
Model
|
||||||
|
|||||||
@ -19,7 +19,7 @@ type Question struct {
|
|||||||
SubmitCount int `gorm:"column:submit_count;type:int(5);default:0;comment:提交次数(提交个人信息进行了算算的人次)" json:"submit_count"`
|
SubmitCount int `gorm:"column:submit_count;type:int(5);default:0;comment:提交次数(提交个人信息进行了算算的人次)" json:"submit_count"`
|
||||||
PayCount int `gorm:"column:pay_count;type:int(5);default:0;comment:支付次数(查看报告的人次)" json:"pay_count"`
|
PayCount int `gorm:"column:pay_count;type:int(5);default:0;comment:支付次数(查看报告的人次)" json:"pay_count"`
|
||||||
Price float64 `gorm:"column:price;type:decimal(10,2) unsigned;default:0.00;comment:价格(原价)" json:"price"`
|
Price float64 `gorm:"column:price;type:decimal(10,2) unsigned;default:0.00;comment:价格(原价)" json:"price"`
|
||||||
DiscountPrice float64 `gorm:"column:discount_price;type:decimal(10,2);comment:优惠价格" json:"discount_price"`
|
DiscountPrice *float64 `gorm:"column:discount_price;type:decimal(10,2);comment:优惠价格" json:"discount_price"`
|
||||||
QuestionBrief string `gorm:"column:question_brief;type:text;comment:问题介绍" json:"question_brief"`
|
QuestionBrief string `gorm:"column:question_brief;type:text;comment:问题介绍" json:"question_brief"`
|
||||||
QuestionExplain string `gorm:"column:question_explain;type:text;comment:问题解释/科普" json:"question_explain"`
|
QuestionExplain string `gorm:"column:question_explain;type:text;comment:问题解释/科普" json:"question_explain"`
|
||||||
Model
|
Model
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package requests
|
|||||||
|
|
||||||
type OrderSingleRequest struct {
|
type OrderSingleRequest struct {
|
||||||
GetOrderSinglePage // 获取单项订单列表-分页
|
GetOrderSinglePage // 获取单项订单列表-分页
|
||||||
|
AddOrderSingle // 创建单项订单
|
||||||
|
GetOrderSinglePay // 获取单项订单支付数据
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrderSinglePage 获取单项订单列表-分页
|
// GetOrderSinglePage 获取单项订单列表-分页
|
||||||
@ -18,3 +20,15 @@ type GetOrderSinglePage struct {
|
|||||||
EscrowTradeNo string `json:"escrow_trade_no" form:"escrow_trade_no" label:"第三方支付流水号"`
|
EscrowTradeNo string `json:"escrow_trade_no" form:"escrow_trade_no" label:"第三方支付流水号"`
|
||||||
CancelStatus *int `json:"cancel_status" form:"cancel_status" label:"取消状态"`
|
CancelStatus *int `json:"cancel_status" form:"cancel_status" label:"取消状态"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddOrderSingle 创建单项订单
|
||||||
|
type AddOrderSingle struct {
|
||||||
|
QuestionId string `json:"question_id" form:"question_id" label:"问题" validate:"required"`
|
||||||
|
UserCouponId string `json:"user_coupon_id" form:"user_coupon_id" label:"优惠卷"`
|
||||||
|
PayChannel int `json:"pay_channel" form:"pay_channel" label:"支付渠道" validate:"required,oneof=1 2 3"` // 支付渠道(1:h5支付 2:app支付 3:会员支付)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOrderSinglePay 获取单项订单支付数据
|
||||||
|
type GetOrderSinglePay struct {
|
||||||
|
ClientType int `json:"client_type" form:"client_type" label:"客户端类型" validate:"required,oneof=1 2"` // 客户端类型(1:h5 2:app)
|
||||||
|
}
|
||||||
|
|||||||
@ -172,6 +172,18 @@ func privateRouter(r *gin.Engine, api controller.Api) {
|
|||||||
{
|
{
|
||||||
// 获取单项订单列表-分页
|
// 获取单项订单列表-分页
|
||||||
singleGroup.GET("/page", api.OrderSingle.GetOrderSinglePage)
|
singleGroup.GET("/page", api.OrderSingle.GetOrderSinglePage)
|
||||||
|
|
||||||
|
// 创建单项订单
|
||||||
|
singleGroup.POST("", api.OrderSingle.AddOrderSingle)
|
||||||
|
|
||||||
|
// 取消单项订单
|
||||||
|
singleGroup.PUT("/cancel/:order_id", api.OrderSingle.PutCancelOrderSingle)
|
||||||
|
|
||||||
|
// 获取单项订单支付数据
|
||||||
|
singleGroup.GET("/pay/:order_id", api.OrderSingle.GetOrderSinglePay)
|
||||||
|
|
||||||
|
// 删除单项订单支付数据
|
||||||
|
singleGroup.DELETE("/:order_id", api.OrderSingle.DeleteOrderSingle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 会员订单
|
// 会员订单
|
||||||
|
|||||||
323
api/service/OrderSingle.go
Normal file
323
api/service/OrderSingle.go
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/app"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"hepa-calc-api/api/dao"
|
||||||
|
"hepa-calc-api/api/model"
|
||||||
|
"hepa-calc-api/config"
|
||||||
|
"hepa-calc-api/extend/weChat"
|
||||||
|
"hepa-calc-api/global"
|
||||||
|
"hepa-calc-api/utils"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrderSingleService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddOrderSingle 创建单项订单
|
||||||
|
func (r *OrderSingleService) AddOrderSingle(tx *gorm.DB, UserId, QuestionId int64, UserCouponId *int64, payChannel int) (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 != "" {
|
||||||
|
return nil, errors.New("请勿重复操作")
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func(redisKey string) {
|
||||||
|
global.Redis.Del(context.Background(), redisKey)
|
||||||
|
}(redisKey)
|
||||||
|
|
||||||
|
// 添加缓存
|
||||||
|
_, err = global.Redis.Set(context.Background(), redisKey, "1", (10)*time.Second).Result()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("生成订单失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取题目数据
|
||||||
|
questionDao := dao.QuestionDao{}
|
||||||
|
question, err := questionDao.GetQuestionById(QuestionId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("题目异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测题目
|
||||||
|
questionService := &QuestionService{}
|
||||||
|
isNormal, err := questionService.CheckQuestion(question)
|
||||||
|
if err != nil || isNormal == false {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var amountTotal float64 // 总金额
|
||||||
|
var couponAmountTotal float64 // 优惠卷总金额
|
||||||
|
var paymentAmountTotal float64 // 实际付款金额
|
||||||
|
|
||||||
|
// 获取问题价格
|
||||||
|
amountTotal, err = questionService.GetUserBuyPrice(UserId, QuestionId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测用户优惠卷
|
||||||
|
var userCoupon *model.UserCoupon
|
||||||
|
if UserCouponId != nil {
|
||||||
|
// 获取优惠卷数据
|
||||||
|
UserCouponDao := dao.UserCouponDao{}
|
||||||
|
userCoupon, err = UserCouponDao.GetUserCouponPreloadById(*UserCouponId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("优惠券异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
userCouponService := &UserCouponService{}
|
||||||
|
isCanUse, err := userCouponService.CheckUserCoupon(userCoupon, QuestionId, 1, amountTotal)
|
||||||
|
if err != nil || isCanUse == false {
|
||||||
|
return nil, errors.New("价格异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优惠卷总金额
|
||||||
|
couponAmountTotal = userCoupon.Coupon.CouponPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实际付款金额
|
||||||
|
paymentAmountTotal = amountTotal - couponAmountTotal
|
||||||
|
if paymentAmountTotal < 0 {
|
||||||
|
return nil, errors.New("价格异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 会员支付
|
||||||
|
if payChannel == 3 {
|
||||||
|
paymentAmountTotal = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成订单号
|
||||||
|
orderNo := global.Snowflake.Generate().String()
|
||||||
|
|
||||||
|
// 创建订单
|
||||||
|
orderSingle = &model.OrderSingle{
|
||||||
|
UserId: UserId,
|
||||||
|
QuestionId: QuestionId,
|
||||||
|
OrderStatus: 1,
|
||||||
|
IsDelete: 0,
|
||||||
|
PayChannel: payChannel,
|
||||||
|
PayStatus: 1,
|
||||||
|
PayTime: nil,
|
||||||
|
RefundStatus: 0,
|
||||||
|
OrderNo: orderNo,
|
||||||
|
EscrowTradeNo: "",
|
||||||
|
AmountTotal: amountTotal,
|
||||||
|
CouponAmountTotal: couponAmountTotal,
|
||||||
|
PaymentAmountTotal: paymentAmountTotal,
|
||||||
|
CancelStatus: 0,
|
||||||
|
CancelTime: nil,
|
||||||
|
CancelRemarks: "",
|
||||||
|
OrderRemarks: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
orderSingleDao := dao.OrderSingleDao{}
|
||||||
|
orderSingle, err = orderSingleDao.AddOrderSingle(tx, orderSingle)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("订单创建失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建优惠卷表
|
||||||
|
if userCoupon != nil {
|
||||||
|
orderSingleCoupon := &model.OrderSingleCoupon{
|
||||||
|
OrderId: orderSingle.OrderId,
|
||||||
|
UserCouponId: *UserCouponId,
|
||||||
|
CouponName: userCoupon.Coupon.CouponName,
|
||||||
|
CouponUsePrice: userCoupon.Coupon.CouponPrice,
|
||||||
|
}
|
||||||
|
|
||||||
|
orderSingleCouponDao := dao.OrderSingleCouponDao{}
|
||||||
|
orderSingleCoupon, err = orderSingleCouponDao.AddOrderSingleCoupon(tx, orderSingleCoupon)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return nil, errors.New("订单创建失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改优惠卷使用状态
|
||||||
|
userCouponDao := dao.UserCouponDao{}
|
||||||
|
|
||||||
|
userCouponData := make(map[string]interface{})
|
||||||
|
userCouponData["user_coupon_status"] = 1
|
||||||
|
userCouponData["coupon_use_date"] = time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
err := userCouponDao.EditUserCouponById(tx, userCoupon.UserCouponId, userCouponData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("订单创建失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 增加至未支付取消订单延迟队列
|
||||||
|
|
||||||
|
return orderSingle, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutCancelOrderSingle 取消单项订单
|
||||||
|
// cancelReason:订单取消原因(1:主动取消 2:后台取消 3:支付超时取消)
|
||||||
|
func (r *OrderSingleService) PutCancelOrderSingle(tx *gorm.DB, userId, orderId int64, cancelReason int) (bool, error) {
|
||||||
|
// 检测多次请求
|
||||||
|
redisKey := "PutCancelOrderSingle" + fmt.Sprintf("%d", userId) + fmt.Sprintf("%d", orderId)
|
||||||
|
res, _ := global.Redis.Get(context.Background(), redisKey).Result()
|
||||||
|
if res != "" {
|
||||||
|
return false, errors.New("请勿重复操作")
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func(redisKey string) {
|
||||||
|
global.Redis.Del(context.Background(), redisKey)
|
||||||
|
}(redisKey)
|
||||||
|
|
||||||
|
// 添加缓存
|
||||||
|
_, err := global.Redis.Set(context.Background(), redisKey, "1", (10)*time.Second).Result()
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.New("取消订单失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取订单数据
|
||||||
|
orderSingleDao := dao.OrderSingleDao{}
|
||||||
|
maps := make(map[string]interface{})
|
||||||
|
maps["user_id"] = userId
|
||||||
|
maps["order_id"] = orderId
|
||||||
|
orderSingle, err := orderSingleDao.GetOrderSingle(maps)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.New("订单异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单状态(1:待支付 2:已完成 3:已取消)
|
||||||
|
if orderSingle.OrderStatus == 2 {
|
||||||
|
return false, errors.New("订单已完成,无法取消")
|
||||||
|
}
|
||||||
|
|
||||||
|
if orderSingle.OrderStatus == 3 {
|
||||||
|
return false, errors.New("订单已取消,请勿重复操作")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消状态(0:否 1:是)
|
||||||
|
if orderSingle.CancelStatus == 1 {
|
||||||
|
return false, errors.New("订单已取消")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
|
||||||
|
if orderSingle.PayStatus == 2 {
|
||||||
|
return false, errors.New("订单已支付,无法取消")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常 7:部分退款)
|
||||||
|
if orderSingle.RefundStatus == 1 {
|
||||||
|
return false, errors.New("订单已申请退款")
|
||||||
|
}
|
||||||
|
|
||||||
|
if orderSingle.RefundStatus == 2 {
|
||||||
|
return false, errors.New("订单退款中")
|
||||||
|
}
|
||||||
|
|
||||||
|
if orderSingle.RefundStatus == 3 {
|
||||||
|
return false, errors.New("订单已退款成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
if orderSingle.RefundStatus == 6 {
|
||||||
|
return false, errors.New("订单退款异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改订单为取消
|
||||||
|
orderSingleData := make(map[string]interface{})
|
||||||
|
orderSingleData["order_status"] = 3
|
||||||
|
if cancelReason == 3 {
|
||||||
|
// 支付超时取消
|
||||||
|
orderSingleData["pay_status"] = 5
|
||||||
|
}
|
||||||
|
orderSingleData["cancel_status"] = 1
|
||||||
|
orderSingleData["cancel_time"] = time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
orderSingleData["cancel_remarks"] = utils.OrderCancelReasonToString(cancelReason)
|
||||||
|
orderSingleData["updated_at"] = time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
err = orderSingleDao.EditOrderSingleById(tx, orderId, orderSingleData)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.New("订单取消失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退还订单优惠卷
|
||||||
|
if orderSingle.CouponAmountTotal != 0 {
|
||||||
|
// 获取订单优惠卷数据
|
||||||
|
orderSingleCouponDao := dao.OrderSingleCouponDao{}
|
||||||
|
orderSingleCoupon, err := orderSingleCouponDao.GetOrderSingleCouponByOrderId(orderId)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return false, errors.New("订单取消失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
userCouponService := &UserCouponService{}
|
||||||
|
userCouponService.ReturnUserCoupon(tx, orderSingleCoupon.UserCouponId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetJsapiPrepay 获取jsapi预支付交易会话标识
|
||||||
|
func (r *OrderSingleService) GetJsapiPrepay(m *model.OrderSingle) (prepay *jsapi.PrepayWithRequestPaymentResponse, err error) {
|
||||||
|
// 获取用户数据
|
||||||
|
userDao := dao.UserDao{}
|
||||||
|
user, err := userDao.GetUserById(m.UserId)
|
||||||
|
if err != nil || user == nil {
|
||||||
|
return nil, errors.New("用户错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.OpenId != "" {
|
||||||
|
return nil, errors.New("发起支付失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
jsapiRequest := weChat.JsapiRequest{
|
||||||
|
AppId: config.C.Wechat.AppId,
|
||||||
|
MchId: config.C.Wechat.Pay1659662936.MchId,
|
||||||
|
Description: "肝病算一算",
|
||||||
|
OutTradeNo: m.OrderNo,
|
||||||
|
NotifyUrl: config.C.Wechat.RefundNotifyDomain + config.C.Wechat.RefundNotifyUrl,
|
||||||
|
Amount: weChat.JsapiRequestAmountRequest{
|
||||||
|
Total: int64(m.PaymentAmountTotal * 100),
|
||||||
|
Currency: "CNY",
|
||||||
|
},
|
||||||
|
Payer: weChat.JsapiRequestPayerRequest{OpenId: user.OpenId},
|
||||||
|
}
|
||||||
|
|
||||||
|
prepay, err = jsapiRequest.GetJsapiPrepay()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return prepay, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAppPrepay 获取app预支付交易会话标识
|
||||||
|
func (r *OrderSingleService) GetAppPrepay(m *model.OrderSingle) (prepay *app.PrepayWithRequestPaymentResponse, err error) {
|
||||||
|
// 获取用户数据
|
||||||
|
userDao := dao.UserDao{}
|
||||||
|
user, err := userDao.GetUserById(m.UserId)
|
||||||
|
if err != nil || user == nil {
|
||||||
|
return nil, errors.New("用户错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.OpenId != "" {
|
||||||
|
return nil, errors.New("发起支付失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
appRequest := weChat.AppRequest{
|
||||||
|
AppId: config.C.Wechat.AppId,
|
||||||
|
MchId: config.C.Wechat.Pay1659662936.MchId,
|
||||||
|
Description: "肝病算一算",
|
||||||
|
OutTradeNo: m.OrderNo,
|
||||||
|
NotifyUrl: config.C.Wechat.RefundNotifyDomain + config.C.Wechat.RefundNotifyUrl,
|
||||||
|
Amount: weChat.AppRequestAmountRequest{
|
||||||
|
Total: int64(m.PaymentAmountTotal * 100),
|
||||||
|
Currency: "CNY",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
prepay, err = appRequest.GetAppPrepay()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return prepay, nil
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"hepa-calc-api/api/dao"
|
"hepa-calc-api/api/dao"
|
||||||
"hepa-calc-api/api/model"
|
"hepa-calc-api/api/model"
|
||||||
)
|
)
|
||||||
@ -139,3 +140,50 @@ func (r *QuestionService) GetQuestionBuyCount(userId, questionId int64) (c int,
|
|||||||
|
|
||||||
return int(buyCount), nil
|
return int(buyCount), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserBuyPrice 获取问题价格
|
||||||
|
func (r *QuestionService) GetUserBuyPrice(userId, questionId int64) (p float64, err error) {
|
||||||
|
// 获取问题详情
|
||||||
|
questionDao := dao.QuestionDao{}
|
||||||
|
question, err := questionDao.GetQuestionById(questionId)
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.New("题目异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 问题价格
|
||||||
|
p = question.Price
|
||||||
|
|
||||||
|
if question.DiscountPrice != nil {
|
||||||
|
p = *question.DiscountPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测用户是否购买过该问题
|
||||||
|
isFirstBuy := r.CheckUserBuyQuestion(userId, questionId)
|
||||||
|
if isFirstBuy == false {
|
||||||
|
// 未购买过
|
||||||
|
systemSingleDao := dao.SystemSingleDao{}
|
||||||
|
|
||||||
|
maps := make(map[string]interface{})
|
||||||
|
systemSingle, err := systemSingleDao.GetSystemSingle(maps)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p = systemSingle.FirstTimePrice
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckQuestion 检测题目
|
||||||
|
func (r *QuestionService) CheckQuestion(m *model.Question) (bool, error) {
|
||||||
|
if m.QuestionStatus != 1 {
|
||||||
|
return false, errors.New("题目异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.IsHide != 0 {
|
||||||
|
return false, errors.New("题目异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hepa-calc-api/extend/aliyun"
|
"hepa-calc-api/extend/aliyun"
|
||||||
"hepa-calc-api/utils"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,8 +19,22 @@ func (r *UserService) HandleUserAvatar(wxAvatar string) (avatar string, err erro
|
|||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下载文件到内存
|
// 发送GET请求
|
||||||
ram, err := aliyun.GetObjectToRAM(wxAvatar)
|
resp, err := http.Get(wxAvatar)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func(Body io.ReadCloser) {
|
||||||
|
_ = Body.Close()
|
||||||
|
}(resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return "", errors.New("请求失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取响应体
|
||||||
|
respBody, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -27,15 +43,15 @@ func (r *UserService) HandleUserAvatar(wxAvatar string) (avatar string, err erro
|
|||||||
now := time.Now()
|
now := time.Now()
|
||||||
dateTimeString := now.Format("20060102150405") // 当前时间字符串
|
dateTimeString := now.Format("20060102150405") // 当前时间字符串
|
||||||
rand.New(rand.NewSource(time.Now().UnixNano())) // 设置随机数
|
rand.New(rand.NewSource(time.Now().UnixNano())) // 设置随机数
|
||||||
ossPath := "/test/医生账户" + dateTimeString + fmt.Sprintf("%d", rand.Intn(9000)+1000) + ".png"
|
ossPath := "user/avatar/" + dateTimeString + fmt.Sprintf("%d", rand.Intn(9000)+1000) + ".png"
|
||||||
|
|
||||||
// 上传oss
|
// 上传oss
|
||||||
_, err = aliyun.PutObjectByte(ossPath, []byte(ram))
|
_, err = aliyun.PutObjectByte(ossPath, respBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
ossPath = utils.AddOssDomain("/" + ossPath)
|
ossPath = "/" + ossPath
|
||||||
|
|
||||||
return ossPath, nil
|
return ossPath, nil
|
||||||
}
|
}
|
||||||
|
|||||||
116
api/service/UserCoupon.go
Normal file
116
api/service/UserCoupon.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"hepa-calc-api/api/dao"
|
||||||
|
"hepa-calc-api/api/model"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserCouponService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUserCoupon 检测用户优惠卷
|
||||||
|
func (r *UserCouponService) CheckUserCoupon(m *model.UserCoupon, id int64, orderType int, amountTotal float64) (bool, error) {
|
||||||
|
if m.UserCouponStatus == 1 {
|
||||||
|
return false, errors.New("优惠卷异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.UserCouponStatus == 2 {
|
||||||
|
return false, errors.New("优惠卷已过期,无法使用")
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
validEndTime := time.Time(m.ValidEndTime)
|
||||||
|
if validEndTime.Before(now) {
|
||||||
|
return false, errors.New("优惠卷已过期,无法使用")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Coupon == nil {
|
||||||
|
return false, errors.New("优惠卷异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测优惠卷状态
|
||||||
|
if m.Coupon.CouponStatus == 2 {
|
||||||
|
return false, errors.New("优惠卷已失效,无法使用")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Coupon.CouponStatus == 3 {
|
||||||
|
return false, errors.New("优惠卷无法使用")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Coupon.CouponStatus == 4 {
|
||||||
|
return false, errors.New("优惠卷异常,无法使用")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测价格
|
||||||
|
if m.Coupon.CouponType == 2 {
|
||||||
|
if m.Coupon.WithAmount > amountTotal {
|
||||||
|
return false, errors.New("优惠卷不符合满减金额标准,无法使用")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单项
|
||||||
|
if orderType == 1 {
|
||||||
|
if m.Coupon.ApplicationScope != 1 && m.Coupon.ApplicationScope != 2 {
|
||||||
|
return false, errors.New("优惠卷无法使用")
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != m.Coupon.QuestionId {
|
||||||
|
return false, errors.New("优惠卷无法使用")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 会员
|
||||||
|
if orderType == 2 {
|
||||||
|
if m.Coupon.ApplicationScope != 1 && m.Coupon.ApplicationScope != 3 {
|
||||||
|
return false, errors.New("优惠卷无法使用")
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != m.Coupon.SystemMemberId {
|
||||||
|
return false, errors.New("优惠卷无法使用")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测优惠劵过期时间
|
||||||
|
if m.Coupon.ValidType == 1 {
|
||||||
|
validEndTime = time.Time(m.Coupon.ValidEndTime)
|
||||||
|
if validEndTime.Before(now) {
|
||||||
|
return false, errors.New("优惠卷已过期,无法使用")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReturnUserCoupon 退还优惠卷
|
||||||
|
func (r *UserCouponService) ReturnUserCoupon(tx *gorm.DB, userCouponId int64) bool {
|
||||||
|
// 获取优惠卷数据
|
||||||
|
UserCouponDao := dao.UserCouponDao{}
|
||||||
|
userCoupon, err := UserCouponDao.GetUserCouponPreloadById(userCouponId)
|
||||||
|
if err != nil {
|
||||||
|
// 无该优惠卷数据,无需处理
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
userCouponDao := dao.UserCouponDao{}
|
||||||
|
userCouponData := make(map[string]interface{})
|
||||||
|
|
||||||
|
// 检测优惠卷过期时间。判断是否需要退还
|
||||||
|
now := time.Now()
|
||||||
|
validEndTime := time.Time(userCoupon.ValidEndTime)
|
||||||
|
if validEndTime.Before(now) {
|
||||||
|
userCouponData["user_coupon_status"] = 3
|
||||||
|
} else {
|
||||||
|
userCouponData["user_coupon_status"] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
userCouponData["coupon_use_date"] = nil
|
||||||
|
err = userCouponDao.EditUserCouponById(tx, userCoupon.UserCouponId, userCouponData)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
18
config.yaml
18
config.yaml
@ -37,7 +37,7 @@ oss:
|
|||||||
oss-access-key: LTAI5tKmFrVCghcxX7yHyGhm
|
oss-access-key: LTAI5tKmFrVCghcxX7yHyGhm
|
||||||
oss-access-key-secret: q1aiIZCJJuf92YbKk2cSXnPES4zx26
|
oss-access-key-secret: q1aiIZCJJuf92YbKk2cSXnPES4zx26
|
||||||
oss-bucket: dev-knowledge
|
oss-bucket: dev-knowledge
|
||||||
oss-endpoint: oss-cn-chengdu.aliyuncs.com
|
oss-endpoint: oss-cn-beijing.aliyuncs.com
|
||||||
oss-custom-domain-name: https://dev-knowledge.oss-cn-beijing.aliyuncs.com
|
oss-custom-domain-name: https://dev-knowledge.oss-cn-beijing.aliyuncs.com
|
||||||
|
|
||||||
# [阿里大鱼短信]
|
# [阿里大鱼短信]
|
||||||
@ -45,17 +45,17 @@ dysms:
|
|||||||
dysms-access-key: LTAI4GGygjsKhyBwvvC3CghV
|
dysms-access-key: LTAI4GGygjsKhyBwvvC3CghV
|
||||||
dysms-access-secret: rcx7lO9kQxG10m8NqNPEfEtT9IS8EI
|
dysms-access-secret: rcx7lO9kQxG10m8NqNPEfEtT9IS8EI
|
||||||
|
|
||||||
# [微信]
|
# [微信]v
|
||||||
wechat:
|
wechat:
|
||||||
app-id: wxc8ac5051745bc795
|
app-id: wxc8ac5051745bc795
|
||||||
app-secret: 678b63a8a7541e528abc3040c3cea809
|
app-secret: 678b63a8a7541e528abc3040c3cea809
|
||||||
pay-notify-url: callback/wxpay/inquiry/success
|
pay-notify-url: callback/wxpay/inquiry/success
|
||||||
refund-notify-url: callback/wxpay/inquiry/refund
|
refund-notify-url: callback/wxpay/inquiry/refund
|
||||||
refund-notify-domain: https://dev.hospital.applets.igandanyiyuan.com/
|
refund-notify-domain: https://dev.hospital.applets.igandanyiyuan.com/
|
||||||
pay-1636644248:
|
pay-1659662936:
|
||||||
mch-id: 1636644248
|
mch-id: 1659662936
|
||||||
v3-api-secret: gdxz292sjSOadN3m2pCda03NfCsmNadY
|
v3-api-secret: gdxz292sjSOadNNad2pCda03NfC2msmY
|
||||||
mch-certificate-serial-number: 7DEC0E6C57E0DC71F077F02F52406566AF39BEBB
|
mch-certificate-serial-number: 12FAA5F61708B795BB5337AE915494E2DC2CA87B
|
||||||
platform-certs: extend/weChat/certs/1659662936/wechatpay_112FCCD1B9ECC8292703AB7363C73D74B6AFDC1A.pem
|
platform-certs: extend/weChat/certs/1659662936/wechatpay_5B5C8A69CC86D1127F6B6AA06AAAF10531EEFE90.pem
|
||||||
private-key: extend/weChat/certs/1636644248/apiclient_key.pem
|
private-key: extend/weChat/certs/1659662936/apiclient_key.pem
|
||||||
certificate: extend/weChat/certs/1636644248/apiclient_cert.pem
|
certificate: extend/weChat/certs/1659662936/apiclient_cert.pem
|
||||||
@ -4,12 +4,13 @@ type Wechat struct {
|
|||||||
AppId string `mapstructure:"app-id" json:"app-id" yaml:"patient-app-id"`
|
AppId string `mapstructure:"app-id" json:"app-id" yaml:"patient-app-id"`
|
||||||
AppSecret string `mapstructure:"app-secret" json:"app-secret" yaml:"app-secret"`
|
AppSecret string `mapstructure:"app-secret" json:"app-secret" yaml:"app-secret"`
|
||||||
PayNotifyUrl string `mapstructure:"pay-notify-url" json:"pay-notify-url" yaml:"pay-notify-url"`
|
PayNotifyUrl string `mapstructure:"pay-notify-url" json:"pay-notify-url" yaml:"pay-notify-url"`
|
||||||
|
RefundNotifyDomain string `mapstructure:"refund-notify-domain" json:"refund-notify-domain" yaml:"refund-notify-domain"` // 回调域名
|
||||||
RefundNotifyUrl string `mapstructure:"refund-notify-url" json:"refund-notify-url" yaml:"refund-notify-url"`
|
RefundNotifyUrl string `mapstructure:"refund-notify-url" json:"refund-notify-url" yaml:"refund-notify-url"`
|
||||||
Pay1636644248 Pay1636644248 `mapstructure:"pay-1636644248" json:"pay-1636644248" yaml:"pay-1636644248"`
|
Pay1659662936 Pay1659662936 `mapstructure:"pay-1659662936" json:"pay-1659662936" yaml:"pay-1659662936"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pay1636644248 北京欣欣相照
|
// Pay1659662936 成都欣欣相照
|
||||||
type Pay1636644248 struct {
|
type Pay1659662936 struct {
|
||||||
MchId string `mapstructure:"mch-id" json:"mch-id" yaml:"mch-id"` // 商户号
|
MchId string `mapstructure:"mch-id" json:"mch-id" yaml:"mch-id"` // 商户号
|
||||||
V3ApiSecret string `mapstructure:"v3-api-secret" json:"v3-api-secret" yaml:"v3-api-secret"` // 商户APIv3密钥
|
V3ApiSecret string `mapstructure:"v3-api-secret" json:"v3-api-secret" yaml:"v3-api-secret"` // 商户APIv3密钥
|
||||||
MchCertificateSerialNumber string `mapstructure:"mch-certificate-serial-number" json:"mch-certificate-serial-number" yaml:"mch-certificate-serial-number"` // 商户证书序列号
|
MchCertificateSerialNumber string `mapstructure:"mch-certificate-serial-number" json:"mch-certificate-serial-number" yaml:"mch-certificate-serial-number"` // 商户证书序列号
|
||||||
|
|||||||
43
extend/weChat/base.go
Normal file
43
extend/weChat/base.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package weChat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/utils"
|
||||||
|
"hepa-calc-api/config"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 创建客户端
|
||||||
|
func createClient() (*core.Client, error) {
|
||||||
|
mchId := config.C.Wechat.Pay1659662936.MchId // 商户号
|
||||||
|
mchCertificateSerialNumber := config.C.Wechat.Pay1659662936.MchCertificateSerialNumber // 商户证书序列号
|
||||||
|
v3ApiSecret := config.C.Wechat.Pay1659662936.V3ApiSecret // 商户APIv3密钥
|
||||||
|
|
||||||
|
if mchId == "" {
|
||||||
|
return nil, errors.New("商户号错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
|
||||||
|
certsDir := filepath.Join("extend/weChat/certs", mchId, "/apiclient_key.pem")
|
||||||
|
// certsDir := filepath.Join("extend/weChat/certs", "/1636644248/apiclient_key.pem")
|
||||||
|
mchPrivateKey, err := utils.LoadPrivateKeyWithPath(certsDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("微信签名生成失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
// 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力
|
||||||
|
opts := []core.ClientOption{
|
||||||
|
option.WithWechatPayAutoAuthCipher(mchId, mchCertificateSerialNumber, mchPrivateKey, v3ApiSecret),
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := core.NewClient(ctx, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
133
extend/weChat/prepay.go
Normal file
133
extend/weChat/prepay.go
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package weChat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/app"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
JSAPI下单
|
||||||
|
APP下单
|
||||||
|
*/
|
||||||
|
|
||||||
|
// JsapiRequest 请求数据-JSAPI下单
|
||||||
|
type JsapiRequest struct {
|
||||||
|
AppId string `json:"appid" comment:"公众号ID"`
|
||||||
|
MchId string `json:"mchid" comment:"直连商户号"`
|
||||||
|
Description string `json:"description" comment:"商品描述"`
|
||||||
|
OutTradeNo string `json:"out_trade_no" comment:"商户订单号"`
|
||||||
|
NotifyUrl string `json:"notify_url" comment:"回调地址"`
|
||||||
|
Amount JsapiRequestAmountRequest `json:"amount" comment:"订单金额"`
|
||||||
|
Payer JsapiRequestPayerRequest `json:"payer" comment:"支付者"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JsapiRequestAmountRequest 订单金额信息
|
||||||
|
type JsapiRequestAmountRequest struct {
|
||||||
|
Total int64 `json:"total" comment:"订单总金额"`
|
||||||
|
Currency string `json:"currency" comment:"货币类型"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JsapiRequestPayerRequest 支付者信息
|
||||||
|
type JsapiRequestPayerRequest struct {
|
||||||
|
OpenId string `json:"openid" comment:"openid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppRequest 请求数据-APP下单
|
||||||
|
type AppRequest struct {
|
||||||
|
AppId string `json:"appid" comment:"公众号ID"`
|
||||||
|
MchId string `json:"mchid" comment:"直连商户号"`
|
||||||
|
Description string `json:"description" comment:"商品描述"`
|
||||||
|
OutTradeNo string `json:"out_trade_no" comment:"商户订单号"`
|
||||||
|
NotifyUrl string `json:"notify_url" comment:"回调地址"`
|
||||||
|
Amount AppRequestAmountRequest `json:"amount" comment:"订单金额"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppRequestAmountRequest 订单金额信息
|
||||||
|
type AppRequestAmountRequest struct {
|
||||||
|
Total int64 `json:"total" comment:"订单总金额"`
|
||||||
|
Currency string `json:"currency" comment:"货币类型"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetJsapiPrepay JSAPI下单-获取jsapi预支付交易会话
|
||||||
|
func (r JsapiRequest) GetJsapiPrepay() (prepay *jsapi.PrepayWithRequestPaymentResponse, err error) {
|
||||||
|
client, err := createClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
svc := jsapi.JsapiApiService{Client: client}
|
||||||
|
// 得到prepay_id,以及调起支付所需的参数和签名
|
||||||
|
|
||||||
|
resp, result, err := svc.PrepayWithRequestPayment(context.Background(),
|
||||||
|
jsapi.PrepayRequest{
|
||||||
|
Appid: core.String(r.AppId),
|
||||||
|
Mchid: core.String(r.MchId),
|
||||||
|
Description: core.String(r.Description),
|
||||||
|
OutTradeNo: core.String(r.OutTradeNo),
|
||||||
|
NotifyUrl: core.String(r.NotifyUrl),
|
||||||
|
Amount: &jsapi.Amount{
|
||||||
|
Total: core.Int64(r.Amount.Total),
|
||||||
|
Currency: core.String("CNY"),
|
||||||
|
},
|
||||||
|
Payer: &jsapi.Payer{
|
||||||
|
Openid: core.String(r.Payer.OpenId),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Response.StatusCode != 200 {
|
||||||
|
return nil, errors.New("发起支付失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.PrepayId == nil {
|
||||||
|
return nil, errors.New("发起支付失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAppPrepay APP下单-获取app预支付交易会话
|
||||||
|
func (r AppRequest) GetAppPrepay() (prepay *app.PrepayWithRequestPaymentResponse, err error) {
|
||||||
|
client, err := createClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
svc := app.AppApiService{Client: client}
|
||||||
|
// 得到prepay_id,以及调起支付所需的参数和签名
|
||||||
|
|
||||||
|
resp, result, err := svc.PrepayWithRequestPayment(context.Background(),
|
||||||
|
app.PrepayRequest{
|
||||||
|
Appid: core.String(r.AppId),
|
||||||
|
Mchid: core.String(r.MchId),
|
||||||
|
Description: core.String(r.Description),
|
||||||
|
OutTradeNo: core.String(r.OutTradeNo),
|
||||||
|
NotifyUrl: core.String(r.NotifyUrl),
|
||||||
|
Amount: &app.Amount{
|
||||||
|
Total: core.Int64(r.Amount.Total),
|
||||||
|
Currency: core.String("CNY"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Response.StatusCode != 200 {
|
||||||
|
return nil, errors.New("发起支付失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.PrepayId == nil {
|
||||||
|
return nil, errors.New("发起支付失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
46
extend/weChat/refund.go
Normal file
46
extend/weChat/refund.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package weChat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RefundRequest struct {
|
||||||
|
TransactionId string `json:"transaction_id" comment:"微信订单号"`
|
||||||
|
OutTradeNo string `json:"out_trade_no" comment:"商户订单号"`
|
||||||
|
OutRefundNo string `json:"out_refund_no" comment:"退款订单号"`
|
||||||
|
Reason string `json:"reason" comment:"退款原因"`
|
||||||
|
RefundAmount int64 `json:"refund_amount" comment:"退款金额"`
|
||||||
|
PaymentAmountTotal int64 `json:"payment_amount_total" comment:"支付金额"`
|
||||||
|
NotifyUrl string `json:"notify_url" comment:"回调地址"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refund 退款
|
||||||
|
func (r RefundRequest) Refund() (*refunddomestic.Refund, error) {
|
||||||
|
client, err := createClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
refundRequest := refunddomestic.CreateRequest{
|
||||||
|
TransactionId: core.String(r.TransactionId),
|
||||||
|
OutTradeNo: core.String(r.OutTradeNo),
|
||||||
|
OutRefundNo: core.String(r.OutRefundNo),
|
||||||
|
Reason: core.String(r.Reason),
|
||||||
|
NotifyUrl: core.String(r.NotifyUrl),
|
||||||
|
Amount: &refunddomestic.AmountReq{
|
||||||
|
Currency: core.String("CNY"),
|
||||||
|
Refund: core.Int64(r.RefundAmount),
|
||||||
|
Total: core.Int64(r.PaymentAmountTotal),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
svc := refunddomestic.RefundsApiService{Client: client}
|
||||||
|
resp, _, err := svc.Create(context.Background(), refundRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
@ -1,79 +0,0 @@
|
|||||||
package weChat
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
|
||||||
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
|
|
||||||
"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
|
|
||||||
"github.com/wechatpay-apiv3/wechatpay-go/utils"
|
|
||||||
"hepa-calc-api/config"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RefundRequest struct {
|
|
||||||
TransactionId string `json:"transaction_id" comment:"微信订单号"`
|
|
||||||
OutTradeNo string `json:"out_trade_no" comment:"商户订单号"`
|
|
||||||
OutRefundNo string `json:"out_refund_no" comment:"退款订单号"`
|
|
||||||
Reason string `json:"reason" comment:"退款原因"`
|
|
||||||
RefundAmount int64 `json:"refund_amount" comment:"退款金额"`
|
|
||||||
PaymentAmountTotal int64 `json:"payment_amount_total" comment:"支付金额"`
|
|
||||||
NotifyUrl string `json:"notify_url" comment:"回调地址"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refund 退款
|
|
||||||
func (r RefundRequest) Refund() (*refunddomestic.Refund, error) {
|
|
||||||
mchId := ""
|
|
||||||
mchCertificateSerialNumber := ""
|
|
||||||
v3ApiSecret := ""
|
|
||||||
|
|
||||||
mchId = config.C.Wechat.Pay1636644248.MchId
|
|
||||||
mchCertificateSerialNumber = config.C.Wechat.Pay1636644248.MchCertificateSerialNumber
|
|
||||||
v3ApiSecret = config.C.Wechat.Pay1636644248.V3ApiSecret
|
|
||||||
|
|
||||||
if mchId == "" {
|
|
||||||
return nil, errors.New("商户号错误")
|
|
||||||
}
|
|
||||||
|
|
||||||
// certsDir := "extend/weChat/certs/" + mchId + "/apiclient_key.pem"
|
|
||||||
|
|
||||||
// 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
|
|
||||||
certsDir := filepath.Join("extend/weChat/certs", mchId, "/apiclient_key.pem")
|
|
||||||
// certsDir := filepath.Join("extend/weChat/certs", "/1636644248/apiclient_key.pem")
|
|
||||||
mchPrivateKey, err := utils.LoadPrivateKeyWithPath(certsDir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("微信签名生成失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
// 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力
|
|
||||||
opts := []core.ClientOption{
|
|
||||||
option.WithWechatPayAutoAuthCipher(mchId, mchCertificateSerialNumber, mchPrivateKey, v3ApiSecret),
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := core.NewClient(ctx, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
refundRequest := refunddomestic.CreateRequest{
|
|
||||||
TransactionId: core.String(r.TransactionId),
|
|
||||||
OutTradeNo: core.String(r.OutTradeNo),
|
|
||||||
OutRefundNo: core.String(r.OutRefundNo),
|
|
||||||
Reason: core.String(r.Reason),
|
|
||||||
NotifyUrl: core.String(r.NotifyUrl),
|
|
||||||
Amount: &refunddomestic.AmountReq{
|
|
||||||
Currency: core.String("CNY"),
|
|
||||||
Refund: core.Int64(r.RefundAmount),
|
|
||||||
Total: core.Int64(r.PaymentAmountTotal),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
svc := refunddomestic.RefundsApiService{Client: client}
|
|
||||||
resp, _, err := svc.Create(ctx, refundRequest)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
@ -1,3 +1,15 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
// int转字符串
|
// OrderCancelReasonToString 订单取消原因(1:主动取消 2:后台取消 3:支付超时取消)
|
||||||
|
func OrderCancelReasonToString(i int) string {
|
||||||
|
switch i {
|
||||||
|
case 1:
|
||||||
|
return "主动取消"
|
||||||
|
case 2:
|
||||||
|
return "后台取消"
|
||||||
|
case 3:
|
||||||
|
return "支付超时取消"
|
||||||
|
default:
|
||||||
|
return "取消"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user