hepa-calc-api/api/service/OrderMember.go
2024-09-05 16:40:22 +08:00

396 lines
12 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 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/rabbitMq"
"hepa-calc-api/extend/weChat"
"hepa-calc-api/global"
"hepa-calc-api/utils"
"math"
"time"
)
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 != "" {
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("生成订单失败")
}
// 获取会员配置数据
systemMemberDao := dao.SystemMemberDao{}
systemMember, err := systemMemberDao.GetSystemMemberById(SystemMemberId)
if err != nil {
return nil, errors.New("会员配置异常")
}
// 获取用户数据
userDao := dao.UserDao{}
user, err := userDao.GetUserById(UserId)
if err != nil || user == nil {
return nil, errors.New("用户错误")
}
// 检测会员有效期
if user.IsMember == 1 {
now := time.Now()
memberExpireDate := time.Time(*user.MemberExpireDate)
diff := memberExpireDate.Sub(now)
// 将差值转换为天数
diffDays := int(diff.Hours() / 24)
totalDays := diffDays + int(systemMember.MemberDays)
if totalDays > 180 {
return nil, errors.New("超出会员最大购买天数")
}
}
var amountTotal float64 // 总金额
var couponAmountTotal float64 // 优惠卷总金额
var paymentAmountTotal float64 // 实际付款金额
var orderStatus int // 订单状态1:待支付 2:已完成 3:已取消)
var payStatus int // 支付状态1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
var payTime *model.LocalTime // 支付时间
var escrowTradeNo string // 第三方支付流水号
// 获取会员购买价格
systemMemberService := &SystemMemberService{}
amountTotal = systemMemberService.GetUserBuyPrice(UserId, systemMember)
if err != nil {
return nil, err
}
// 检测用户优惠卷
var userCoupon *model.UserCoupon
if UserCouponId != nil {
// 检测用户是否购买过会员
userService := &UserService{}
isBuy := userService.CheckUserBuyMember(UserId)
if isBuy == true {
// 已购买过会员,无法使用优惠卷
return nil, errors.New("优惠券异常")
}
// 获取优惠卷数据
UserCouponDao := dao.UserCouponDao{}
userCoupon, err = UserCouponDao.GetUserCouponPreloadById(*UserCouponId)
if err != nil {
return nil, errors.New("优惠券异常")
}
userCouponService := &UserCouponService{}
isCanUse, err := userCouponService.CheckUserCoupon(userCoupon, SystemMemberId, 2, amountTotal)
if err != nil {
return nil, err
}
if isCanUse == false {
return nil, errors.New("价格异常")
}
// 优惠卷总金额
couponAmountTotal = userCoupon.Coupon.CouponPrice
}
// 实际付款金额
paymentAmountTotal = amountTotal - couponAmountTotal // 实际付款金额
paymentAmountTotal = math.Round(paymentAmountTotal*100) / 100
if paymentAmountTotal < 0 {
paymentAmountTotal = 0
}
if *orderPrice != paymentAmountTotal {
return nil, errors.New("价格异常")
}
orderStatus = 1 // 订单状态1:待支付 2:已完成 3:已取消)
payStatus = 1 // 支付状态1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
payTime = nil // 支付时间
// 生成订单号
orderNo := "M" + global.Snowflake.Generate().String()
// 创建订单
orderMember = &model.OrderMember{
UserId: UserId,
SystemMemberId: SystemMemberId,
OrderStatus: orderStatus,
IsDelete: 0,
PayChannel: payChannel,
PayStatus: payStatus,
PayTime: payTime,
RefundStatus: 0,
OrderNo: orderNo,
EscrowTradeNo: escrowTradeNo,
AmountTotal: amountTotal,
CouponAmountTotal: couponAmountTotal,
PaymentAmountTotal: paymentAmountTotal,
CancelStatus: 0,
CancelTime: nil,
CancelRemarks: "",
OrderRemarks: "",
}
orderMemberDao := dao.OrderMemberDao{}
orderMember, err = orderMemberDao.AddOrderMember(tx, orderMember)
if err != nil {
return nil, errors.New("订单创建失败")
}
// 创建优惠卷表
if userCoupon != nil {
orderMemberCoupon := &model.OrderMemberCoupon{
OrderId: orderMember.OrderId,
UserCouponId: *UserCouponId,
CouponName: userCoupon.Coupon.CouponName,
CouponUsePrice: userCoupon.Coupon.CouponPrice,
}
orderMemberCouponDao := dao.OrderMemberCouponDao{}
orderMemberCoupon, err = orderMemberCouponDao.AddOrderMemberCoupon(tx, orderMemberCoupon)
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("订单创建失败")
}
}
// 增加未支付取消订单延迟队列
if payChannel == 1 || payChannel == 2 {
delay := 30 * time.Minute
if config.C.Env == "dev" {
delay = 3 * time.Minute
}
data := make(map[string]interface{})
data["order_id"] = fmt.Sprintf("%d", orderMember.OrderId)
data["order_no"] = orderMember.OrderNo
data["user_id"] = fmt.Sprintf("%d", orderMember.UserId)
data["order_type"] = 2
data["pay_channel"] = orderMember.PayChannel
p := rabbitMq.PublishS{
QueueName: "cancel.unpay.order.delay.queue",
ExchangeName: "amqp.delay.direct",
RoutingKey: "CancelUnPayOrder",
Message: data,
Delay: delay,
}
err := p.PublishWithDelay()
if err != nil {
utils.LogJsonErr("添加处理取消未支付订单队列失败:", err.Error())
return nil, errors.New("订单创建失败")
}
}
return orderMember, nil
}
// CancelOrderMember 取消会员订单
// cancelReason:订单取消原因1:主动取消 2:后台取消 3:支付超时取消)
func (r *OrderMemberService) CancelOrderMember(tx *gorm.DB, orderMember *model.OrderMember, cancelReason int) (bool, error) {
// 检测多次请求
redisKey := "CancelOrderMember" + fmt.Sprintf("%d", orderMember.UserId) + fmt.Sprintf("%d", orderMember.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("取消订单失败")
}
// 订单状态1:待支付 2:已完成 3:已取消)
if orderMember.OrderStatus == 2 {
return true, errors.New("订单已完成,无法取消")
}
if orderMember.OrderStatus == 3 {
return true, errors.New("订单已取消,请勿重复操作")
}
// 取消状态0:否 1:是)
if orderMember.CancelStatus == 1 {
return true, errors.New("订单已取消")
}
// 支付状态1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
if orderMember.PayStatus == 2 {
return true, errors.New("订单已支付,无法取消")
}
// 订单退款状态0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常 7:部分退款)
if orderMember.RefundStatus == 1 {
return true, errors.New("订单已申请退款")
}
if orderMember.RefundStatus == 2 {
return true, errors.New("订单退款中")
}
if orderMember.RefundStatus == 3 {
return true, errors.New("订单已退款成功")
}
if orderMember.RefundStatus == 6 {
return true, errors.New("订单退款异常")
}
// 修改订单为取消
orderMemberDao := dao.OrderMemberDao{}
orderMemberData := make(map[string]interface{})
orderMemberData["order_status"] = 3
if cancelReason == 3 {
// 支付超时取消
orderMemberData["pay_status"] = 5
}
orderMemberData["cancel_status"] = 1
orderMemberData["cancel_time"] = time.Now().Format("2006-01-02 15:04:05")
orderMemberData["cancel_remarks"] = utils.OrderCancelReasonToString(cancelReason)
err = orderMemberDao.EditOrderMemberById(tx, orderMember.OrderId, orderMemberData)
if err != nil {
return false, errors.New("订单取消失败")
}
// 退还订单优惠卷
if orderMember.CouponAmountTotal > 0 {
err = r.OrderCouponRefund(tx, orderMember)
if err != nil {
tx.Rollback()
return false, err
}
}
return true, nil
}
// GetJsapiPrepay 获取jsapi预支付交易会话标识
func (r *OrderMemberService) GetJsapiPrepay(m *model.OrderMember) (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.Pay1281030301.MchId,
Description: "肝病算一算",
OutTradeNo: m.OrderNo,
NotifyUrl: config.C.Wechat.NotifyDomain + config.C.Wechat.MemberRefundNotifyUrl,
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 *OrderMemberService) GetAppPrepay(m *model.OrderMember) (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.Pay1281030301.MchId,
Description: "肝病算一算",
OutTradeNo: m.OrderNo,
NotifyUrl: config.C.Wechat.NotifyDomain + config.C.Wechat.MemberRefundNotifyUrl,
Amount: weChat.AppRequestAmountRequest{
Total: int64(m.PaymentAmountTotal * 100),
Currency: "CNY",
},
}
prepay, err = appRequest.GetAppPrepay()
if err != nil {
return nil, err
}
return prepay, nil
}
// OrderCouponRefund 订单优惠卷退还
func (r *OrderMemberService) OrderCouponRefund(tx *gorm.DB, order *model.OrderMember) error {
// 订单优惠金额为0无需退还优惠卷
if order.CouponAmountTotal == 0 {
return nil
}
// 获取订单优惠卷数据
orderMemberCouponDao := dao.OrderMemberCouponDao{}
orderMemberCoupons, err := orderMemberCouponDao.GetOrderMemberCouponListByOrderId(order.OrderId)
if err != nil {
return errors.New("优惠卷数据错误")
}
userCouponService := &UserCouponService{}
for _, coupon := range orderMemberCoupons {
_ = userCouponService.ReturnUserCoupon(tx, coupon.UserCouponId)
}
return nil
}