Files
lckt-server/service/app/order.go

280 lines
8.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package app
import (
"fmt"
"git.echol.cn/loser/lckt/model/vip"
"strconv"
"strings"
"time"
"git.echol.cn/loser/lckt/global"
"git.echol.cn/loser/lckt/model/app"
"git.echol.cn/loser/lckt/model/app/request"
"git.echol.cn/loser/lckt/model/user"
"git.echol.cn/loser/lckt/utils/wechat"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type OrderService struct{}
// Pay 发起支付
func (s *OrderService) Pay(p request.PayReq, ctx *gin.Context) (interface{}, error) {
order := app.Order{}
err := global.GVA_DB.Where("id = ? AND order_no = ?", p.OrderId, p.OrderNo).First(&order).Error
if err != nil {
global.GVA_LOG.Error("查询订单失败", zap.Error(err))
return "", err
}
if order.Status == 3 {
global.GVA_LOG.Error("订单已过期", zap.Int64("order_id", int64(order.ID)))
return "", fmt.Errorf("订单已过期")
}
if p.Mode == "h5" {
payConf, err := wechat.H5Pay(&order, ctx)
if err != nil {
global.GVA_LOG.Error("微信支付订单失败", zap.Error(err))
return "", err
}
return payConf, nil
} else if p.Mode == "jsapi" {
payConf, err := wechat.JSAPIPay(&order, ctx)
if err != nil {
global.GVA_LOG.Error("微信支付订单失败", zap.Error(err))
return "", err
}
return payConf, nil
}
return "", nil
}
func (s *OrderService) Create(o *app.Order) (*app.Order, error) {
// 生成订单号
o.OrderNo = wechat.GenerateOrderNum()
// 查询订单商品价格
price := 0
switch o.OrderType {
case 1:
err := global.GVA_DB.Table("article").Select("price").Where("id = ?", o.ArticleId).Scan(&price).Error
if err != nil {
global.GVA_LOG.Error("查询商品价格失败", zap.Error(err))
return nil, err
}
case 2:
err := global.GVA_DB.Table("lckt_vip").Select("price").Where("id = ?", o.VipId).Scan(&price).Error
if err != nil {
global.GVA_LOG.Error("查询VIP价格失败", zap.Error(err))
return nil, err
}
case 3:
// 讲师包月
//切割TeacherVipId字符串
ids := strings.Split(o.TeacherVipId, ",")
// 查询每个服务的价格并累加
totalPrice := 0
for _, id := range ids {
var p int
err := global.GVA_DB.Table("app_teacher_vip").Select("price").Where("id = ?", id).Scan(&p).Error
if err != nil {
global.GVA_LOG.Error("查询讲师包月价格失败", zap.Error(err))
return nil, err
}
totalPrice += p
}
price = totalPrice
}
o.Price = int64(price)
o.Status = 1 // 设置订单状态为未付款
// 设置openid
openId := ""
err := global.GVA_DB.Table("app_user").Where("id = ?", o.UserId).Select("open_id").Scan(&openId).Error
if err != nil {
global.GVA_LOG.Error("查询用户OpenID失败,请检查微信是否绑定", zap.Error(err))
return nil, fmt.Errorf("查询用户OpenID失败,请检查微信是否绑定")
}
o.OpenId = openId
err = global.GVA_DB.Create(&o).Error
if err != nil {
global.GVA_LOG.Error("创建订单失败", zap.Error(err))
return nil, err
}
return o, nil
}
func (s *OrderService) GetOrderDetail(id string) (order app.Order, err error) {
err = global.GVA_DB.Where("id = ?", id).First(&order).Error
if err != nil {
global.GVA_LOG.Error("获取订单详情失败", zap.Error(err))
return app.Order{}, err
}
return order, nil
}
func (s *OrderService) BalancePay(p request.BalancePay) error {
order := app.Order{}
err := global.GVA_DB.Where("id = ? AND order_no = ?", p.OrderId, p.OrderNo).First(&order).Error
if err != nil {
global.GVA_LOG.Error("查询订单失败", zap.Error(err))
return err
}
if order.Status != 1 {
global.GVA_LOG.Error("订单状态错误,无法支付", zap.Int("status", order.Status))
return err
}
// 检查用户余额是否足够
var user user.User
err = global.GVA_DB.Where("id = ?", p.UserId).First(&user).Error
if err != nil {
global.GVA_LOG.Error("查询用户信息失败", zap.Error(err))
return err
}
// 将订单价格从分转换为元(保持精度)
orderPriceInYuan := float64(order.Price) / 100.0
// 检查用户余额是否足够使用float64进行比较避免精度丢失
if user.Balance < float32(orderPriceInYuan) {
global.GVA_LOG.Error("用户余额不足",
zap.Float32("balance", user.Balance),
zap.Float64("order_price_yuan", orderPriceInYuan),
zap.Int64("order_price_cent", order.Price))
return fmt.Errorf("用户余额不足")
}
// 扣除用户余额(保持精度)
newBalance := user.Balance - float32(orderPriceInYuan)
err = global.GVA_DB.Model(&user).Where("id = ?", p.UserId).Update("balance", newBalance).Error
if err != nil {
global.GVA_LOG.Error("扣除用户余额失败", zap.Error(err))
return err
}
// 更新订单状态为已付款
order.Status = 2
err = global.GVA_DB.Model(&order).Where("id = ?", order.ID).Update("status", 2).Error
if err != nil {
global.GVA_LOG.Error("更新订单状态失败", zap.Error(err))
return err
}
// 全站Vip
if order.OrderType == 2 {
// 更新用户的会员状态
user.IsVip = 1
// 查询用户购买的会员信息
vipInfo := vip.Vip{}
err = global.GVA_DB.Model(&vip.Vip{}).Where("id = ?", order.VipId).First(&vipInfo).Error
if err != nil {
global.GVA_LOG.Error("查询会员信息失败", zap.Error(err))
return nil
}
// 计算会员的过期时间
if user.VipExpireTime != "" {
expireTime, _ := time.Parse("2006-01-02", user.VipExpireTime)
if expireTime.After(time.Now()) {
// 如果会员未过期,则在原有的基础上增加时间
user.VipExpireTime = expireTime.AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02")
} else {
// 如果会员已过期,则从当前时间开始计算
user.VipExpireTime = time.Now().AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02")
}
} else {
// 如果没有会员时间,则从当前时间开始计算
user.VipExpireTime = time.Now().AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02")
}
err = global.GVA_DB.Save(&user).Error
if err != nil {
global.GVA_LOG.Error("更新用户会员状态失败", zap.Error(err))
return nil
}
}
// 讲师包月
if order.OrderType == 3 {
// 逗号分割字符串
ids := strings.Split(order.TeacherVipId, ",")
for _, id := range ids {
teacherVip := app.UserTeacherVip{}
teacherVip.TeacherId = uint(order.TeacherId)
// 将id转为uint
teacherVipId, _ := strconv.ParseUint(id, 10, 64)
teacherVip.TeacherVipId = uint(teacherVipId)
teacherVip.UserId = uint(order.UserId)
teacherVip.ExpireAt = time.Now().AddDate(0, 1, 0).Format("2006-01-02") // 会员有效期一个月
teacherVip.IsExpire = 1 // 设置为未过期
err = global.GVA_DB.Create(&teacherVip).Error
if err != nil {
global.GVA_LOG.Error("购买讲师会员回调处理失败:", zap.Error(err))
return err
}
}
}
global.GVA_LOG.Info("余额支付成功", zap.Int64("user_id", int64(p.UserId)), zap.String("order_no", order.OrderNo))
return nil
}
// AppGetOrderList APP端获取订单列表
func (s *OrderService) AppGetOrderList(p request.GetOrderList, id uint) (orders []app.Order, total int64, err error) {
limit := p.PageSize
offset := p.PageSize * (p.Page - 1)
db := global.GVA_DB.Model(&app.Order{}).Where("user_id = ?", id)
if p.Keyword != "" {
db = db.Where("title LIKE ? ", "%"+p.Keyword+"%")
}
if p.Status != 0 {
db = db.Where("status = ?", p.Status)
}
err = db.Count(&total).Error
err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&orders).Error
if err != nil {
global.GVA_LOG.Error("获取订单列表失败", zap.Error(err))
return nil, 0, err
}
return
}
// GetOrderList APP端获取订单列表
func (s *OrderService) GetOrderList(p request.GetOrderList) (orders []app.Order, total int64, err error) {
limit := p.PageSize
offset := p.PageSize * (p.Page - 1)
db := global.GVA_DB.Model(&app.Order{})
if p.Title != "" {
db = db.Where("title LIKE ? ", "%"+p.Title+"%")
}
if p.Status != 0 {
db = db.Where("status = ?", p.Status)
}
if p.PayType != 0 {
db = db.Where("pay_type = ?", p.PayType)
}
if p.OrderType != 0 {
db = db.Where("order_type = ?", p.OrderType)
}
if p.StartTime != "" && p.EndTime != "" {
db = db.Where("created_at BETWEEN ? AND ?", p.StartTime, p.EndTime)
}
if p.Name != "" {
db = db.Where("name LIKE ? ", "%"+p.Name+"%")
}
err = db.Count(&total).Error
err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&orders).Error
if err != nil {
global.GVA_LOG.Error("获取订单列表失败", zap.Error(err))
return nil, 0, err
}
return
}