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" "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 || isCanUse == false { return nil, errors.New("价格异常") } // 优惠卷总金额 couponAmountTotal = userCoupon.Coupon.CouponPrice } // 实际付款金额 paymentAmountTotal = amountTotal - couponAmountTotal // 实际付款金额 if paymentAmountTotal < 0 { return nil, errors.New("价格异常") } 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 = 1 * 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 false, errors.New("订单已完成,无法取消") } if orderMember.OrderStatus == 3 { return false, errors.New("订单已取消,请勿重复操作") } // 取消状态(0:否 1:是) if orderMember.CancelStatus == 1 { return false, errors.New("订单已取消") } // 支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款) if orderMember.PayStatus == 2 { return false, errors.New("订单已支付,无法取消") } // 订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常 7:部分退款) if orderMember.RefundStatus == 1 { return false, errors.New("订单已申请退款") } if orderMember.RefundStatus == 2 { return false, errors.New("订单退款中") } if orderMember.RefundStatus == 3 { return false, errors.New("订单已退款成功") } if orderMember.RefundStatus == 6 { return false, 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("订单取消失败") } // 处理支付金额为0时退还优惠卷问题 if orderMember.PaymentAmountTotal == 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 }