306 lines
8.7 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-admin-api/api/dao"
"hepa-calc-admin-api/api/model"
"hepa-calc-admin-api/config"
"hepa-calc-admin-api/extend/weChat"
"hepa-calc-admin-api/global"
"hepa-calc-admin-api/utils"
"strconv"
"time"
)
type OrderMemberService struct {
}
// CancelOrderMember 取消会员订单
// cancelReason:订单取消原因1:主动取消 2:后台取消 3:支付超时取消)
func (r *OrderMemberService) CancelOrderMember(tx *gorm.DB, orderMember *model.OrderMember, refundAmount *float64, 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("订单退款异常")
}
// 修改订单为取消
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)
orderMemberData["updated_at"] = time.Now().Format("2006-01-02 15:04:05")
orderMemberDao := dao.OrderMemberDao{}
err = orderMemberDao.EditOrderMemberById(tx, orderMember.OrderId, orderMemberData)
if err != nil {
return false, errors.New("订单取消失败")
}
// 退还订单优惠卷
if orderMember.CouponAmountTotal != 0 {
// 获取订单优惠卷数据
orderMemberCouponDao := dao.OrderMemberCouponDao{}
orderMemberCoupon, err := orderMemberCouponDao.GetOrderMemberCouponByOrderId(orderMember.OrderId)
if err != nil {
tx.Rollback()
return false, errors.New("订单取消失败")
}
userCouponService := &UserCouponService{}
userCouponService.ReturnUserCoupon(tx, orderMemberCoupon.UserCouponId)
}
// 退还订单优惠卷
err = r.OrderCouponRefund(tx, orderMember)
if err != nil {
tx.Rollback()
return false, err
}
// 订单退款
_, err = r.OrderRefund(tx, orderMember, refundAmount, utils.OrderCancelReasonToString(cancelReason))
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.RefundNotifyDomain + 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.RefundNotifyDomain + 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
}
// OrderRefund 订单退款
func (r *OrderMemberService) OrderRefund(tx *gorm.DB, order *model.OrderMember, refundAmount *float64, refundReason string) (*model.OrderMemberRefund, error) {
var refundStatus int
var successTime *time.Time
var refundId string
// 判断订单支付状态1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
if order.PayStatus != 2 {
// 非已支付,无需退款
return nil, nil
}
// 检测退款金额
if *refundAmount > order.PaymentAmountTotal {
return nil, errors.New("退款金额不可超过实付金额")
}
// 退款编号
refundNo := strconv.FormatInt(global.Snowflake.Generate().Int64(), 10)
// 退款金额为0
if *refundAmount <= 0 {
// 支付金额为0模拟退款
refundId = "模拟退款:" + strconv.FormatInt(global.Snowflake.Generate().Int64(), 10)
refundStatus = 3
now := time.Now()
successTime = &now
}
// 退款金额大于0
if *refundAmount > 0 {
refundRequest := weChat.RefundRequest{
TransactionId: order.EscrowTradeNo,
OutTradeNo: order.OrderNo,
OutRefundNo: refundNo,
Reason: refundReason,
RefundAmount: int64(*refundAmount * 100),
PaymentAmountTotal: int64(order.PaymentAmountTotal * 100),
NotifyUrl: config.C.Wechat.RefundNotifyDomain + config.C.Wechat.MemberRefundNotifyUrl,
}
refund, err := refundRequest.Refund()
if err != nil {
return nil, err
}
// 处理退款状态
wxPayRefundResult, err := weChat.HandlePayRefundStatus(refund)
if err != nil {
return nil, err
}
refundStatus = wxPayRefundResult.RefundStatus
successTime = wxPayRefundResult.SuccessTime
if refund.RefundId == nil {
return nil, errors.New("缺少退款订单编号")
}
// 退款编号
refundId = *refund.RefundId
}
// 新增退款表
orderRefund := &model.OrderMemberRefund{
UserId: order.UserId,
OrderId: order.OrderId,
OrderNo: order.OrderNo,
RefundNo: refundNo,
RefundId: refundId,
RefundStatus: refundStatus,
RefundTotal: *refundAmount,
RefundReason: refundReason,
}
if refundStatus == 3 && successTime != nil {
t := model.LocalTime(*successTime)
orderRefund.SuccessTime = &t
}
orderMemberRefundDao := dao.OrderMemberRefundDao{}
orderMemberRefund, err := orderMemberRefundDao.AddOrderMemberRefund(tx, orderRefund)
if err != nil || orderMemberRefund == nil {
return nil, errors.New(err.Error())
}
return orderMemberRefund, 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
}