package service import ( "encoding/base64" e "errors" "fmt" "github.com/xuri/excelize/v2" "gold-shop/errors" "gold-shop/global" "gold-shop/model" "gold-shop/request" "gold-shop/request/manage" "gold-shop/utils" "gold-shop/utils/excel" "gold-shop/utils/payment" "gold-shop/utils/result" "gold-shop/utils/tlpay" "gold-shop/utils/tlpay/notify" "gold-shop/utils/tlpay/param" "gorm.io/gorm" "strconv" "time" ) var PaymentService = paymentService{} type paymentService struct { } func (paymentService) GetUserPayments(userID, page, pageSize int) ([]model.Payment, int64) { payments := make([]model.Payment, pageSize) offset := (page - 1) * pageSize var total int64 global.DB.Where("user_id", userID).Order("id desc").Offset(offset).Limit(pageSize).Find(&payments) global.DB.Model(&model.Payment{}).Where("user_id", userID).Count(&total) return payments, total } func (s paymentService) Payment(userID int, paymentRequest request.PaymentRequest) (result.Data, error) { p, err := s.createPayment(userID, paymentRequest) if err != nil { return nil, err } data := result.Data{} if paymentRequest.PayType == "wxgzh" { data, err = s.wxPayment(paymentRequest, p.PaymentNo) } else if paymentRequest.PayType == "alishh" { data, err = s.aliPayment(paymentRequest, p.PaymentNo) } else if paymentRequest.PayType == "transfer" { data, err = s.transferPayment(paymentRequest, p) } else if paymentRequest.PayType == "binding" { data, err = s.bindingPayment(paymentRequest, p) } else if paymentRequest.PayType == "gateway" { data, err = s.getGatewayPayUrl(p) } else if paymentRequest.PayType == "union" { data, err = s.getUnionPayUrl(p) } else { err = errors.NewBusinessError("payType参数错误") } if err != nil { p.Status = 2 p.ErrorMessage = err.Error() global.DB.Save(p) return nil, err } p.PayOrderID = data["orderId"].(string) global.DB.Save(p) fmt.Println(data) return data, nil } func (s paymentService) wxPayment(paymentRequest request.PaymentRequest, orderID string) (result.Data, error) { param := payment.WxPayParam{} param.Remark = "payment" param.OrderId = orderID param.OpenId = paymentRequest.OpenID param.Amount = paymentRequest.Amount param.NotifyUrl = "http://api.wrtcjt.com/h5/payment-notify" res, err := payment.PayApi.WxPay(param) if err != nil { return nil, err } if res.Status != payment.Success { return nil, errors.NewBusinessError(res.Message) } data := result.Data{ "orderId": res.OrderID, "paySign": res.PaySign, "package": res.Package, "signType": res.PaySignType, "nonceStr": res.NonceStr, "appId": res.AppId, "timeStamp": res.Timestamp, } return data, nil } func (s paymentService) aliPayment(paymentRequest request.PaymentRequest, orderID string) (result.Data, error) { param := payment.AliPayParam{} param.Remark = "payment" param.OrderId = orderID param.BuyerId = paymentRequest.OpenID param.Amount = paymentRequest.Amount param.NotifyUrl = "http://api.wrtcjt.com/h5/payment-notify" res, err := payment.PayApi.AliPay(param) if err != nil { return nil, err } if res.Status != payment.Success { return nil, errors.NewBusinessError(res.Message) } data := result.Data{ "orderId": res.OrderID, "tradeNo": res.TradeNo, "paymentNo": orderID, } return data, nil } func (s paymentService) transferPayment(paymentRequest request.PaymentRequest, p *model.Payment) (result.Data, error) { param := payment.TransferPayParam{} param.Remark = "payment" param.OrderId = utils.GenerateNo("payment") param.Amount = paymentRequest.Amount param.NotifyUrl = "" res, err := payment.PayApi.TransferPay(param) if err != nil { return nil, err } if res.Status != payment.Success { return nil, errors.NewBusinessError(res.Message) } data := result.Data{ "payeeAccountName": res.PayeeAccountName, "payeeBankName": res.PayeeBankName, "payeeCardNo": res.PayeeCardNo, "orderID": res.OrderID, "paymentNo": p.PaymentNo, } return data, nil } func (s paymentService) bindingPayment(paymentRequest request.PaymentRequest, p *model.Payment) (result.Data, error) { payParam := param.PayApplyAgreeParam{} payParam.Amount = strconv.FormatFloat(paymentRequest.Amount*100, 'f', 0, 64) payParam.AgreeID = paymentRequest.AgreeID payParam.ReqSn = p.PaymentNo payParam.Currency = "CNY" payParam.Subject = "充值" payParam.TrxReserve = "充值" payParam.NotifyUrl = "http://api.wrtcjt.com/h5/binding-pay-notify" res, err := tlpay.TLPay.PayApplyAgree(payParam) if err != nil { return nil, err } if err != nil { return nil, err } if res.RetCode != "SUCCESS" { return nil, errors.NewBusinessError(res.RetMsg) } if res.TrxStatus != "1999" { return nil, errors.NewBusinessError(res.ErrMsg) } data := result.Data{ "paymentNo": p.PaymentNo, "orderId": res.TrxID, "thpInfo": base64.StdEncoding.EncodeToString([]byte(res.ThpInfo)), } return data, nil } func (s paymentService) ConfirmBindingPayment(req request.BindingPayConfirmRequest, user *model.User) (result.Data, error) { pm := &model.Payment{} err := global.DB.Where("user_id", user.ID).Where("payment_no", req.PaymentNo).Where("status", 0).First(&pm).Error if err != nil { return nil, err } thpInfo, err := base64.StdEncoding.DecodeString(req.ThpInfo) if err != nil { return nil, err } payParam := param.PayAgreeConfirmParam{} payParam.AgreeID = req.AgreeID payParam.ThpInfo = string(thpInfo) payParam.ReqSn = req.PaymentNo payParam.SmsCode = req.SmsCode res, err := tlpay.TLPay.PayAgreeConfirm(payParam) if err != nil { return nil, err } if err != nil { return nil, err } if res.RetCode != "SUCCESS" { return nil, errors.NewBusinessError(res.RetMsg) } if res.TrxStatus != "0000" { return nil, errors.NewBusinessError(res.ErrMsg) } data := result.Data{ "paymentNo": pm.PaymentNo, "orderId": res.TrxID, } return data, nil } func (s paymentService) SmsBindingPayment(req request.BindingPaySmsRequest, user *model.User) (result.Data, error) { pm := &model.Payment{} err := global.DB.Where("user_id", user.ID).Where("payment_no", req.PaymentNo).Where("status", 0).First(&pm).Error if err != nil { return nil, err } thpInfo, err := base64.StdEncoding.DecodeString(req.ThpInfo) if err != nil { return nil, err } smsParam := param.PaySmsAgreeParam{} smsParam.AgreeID = req.AgreeID smsParam.ThpInfo = string(thpInfo) smsParam.OrderID = req.PaymentNo res, err := tlpay.TLPay.PaySmsAgree(smsParam) if err != nil { return nil, err } if err != nil { return nil, err } if res.RetCode != "SUCCESS" { return nil, errors.NewBusinessError(res.RetMsg) } data := result.Data{ "paymentNo": pm.PaymentNo, } return data, nil } func (paymentService) createPayment(userID int, paymentRequest request.PaymentRequest) (*model.Payment, error) { p := model.Payment{} p.PaymentNo = utils.GenerateNo("payment") p.Amount = paymentRequest.Amount p.OpenID = paymentRequest.OpenID p.PayType = paymentRequest.PayType p.Status = 0 p.UserID = userID err := global.DB.Save(&p).Error if err != nil { return nil, errors.NewBusinessError("保存数据失败") } return &p, nil } func (s *paymentService) buildQuery(req manage.PaymentQueryRequest) *gorm.DB { tx := global.DB if req.Mobile != "" { var userIds []int global.DB.Model(&model.User{}).Where("mobile", req.Mobile).Pluck("id", &userIds) tx = tx.Where("user_id", userIds) } if req.PaymentNo != "" { tx = tx.Where("payment_no", req.PaymentNo) } if req.Status != "" { tx = tx.Where("status", req.Status) } if req.UserID != 0 { tx = tx.Where("user_id", req.UserID) } return tx } func (s *paymentService) GetPayments(req manage.PaymentQueryRequest) ([]model.Payment, int64) { payments := make([]model.Payment, req.PageSize) offset := (req.Page - 1) * req.PageSize var total int64 tx := s.buildQuery(req) tx.Preload("User").Order("id desc").Offset(offset).Limit(req.PageSize).Find(&payments) tx.Model(&model.Order{}).Count(&total) return payments, total } func (s *paymentService) GeneratePaymentsExcel(req manage.PaymentQueryRequest) *excelize.File { pageSize := 200 lastID := 0 tx := s.buildQuery(req) f := excel.NewFile() headers := []string{"支付订单号", "用户手机号", "金额", "支付状态", "支付时间"} excel.SetSimpleHeaders(headers, "Sheet1", f) for { payments := make([]model.Payment, pageSize) tx.Preload("User").Where("id > ?", lastID).Limit(pageSize).Find(&payments) count := len(payments) if count == 0 { break } s.buildPaymentsExcel(payments, "Sheet1", f) lastIndex := count - 1 lastID = payments[lastIndex].ID } return f } func (paymentService) buildPaymentsExcel(payments []model.Payment, sheet string, f *excelize.File) { row := 2 for _, p := range payments { col := 0 f.SetCellValue(sheet, excel.CellKey(row, &col), p.PaymentNo) f.SetCellValue(sheet, excel.CellKey(row, &col), p.User.Mobile) f.SetCellValue(sheet, excel.CellKey(row, &col), p.Amount) f.SetCellValue(sheet, excel.CellKey(row, &col), p.GetStatusText()) f.SetCellValue(sheet, excel.CellKey(row, &col), p.CreatedAt.Format(time.DateTime)) row++ } } func (s paymentService) AfterTransferPayNotify(req request.TransferPayNotifyRequest) error { pm := &model.Payment{} err := global.DB.Where("payment_no", req.OutOrderID).Where("status", 0).First(&pm).Error if err != nil && e.Is(err, gorm.ErrRecordNotFound) { return errors.NewBusinessError("记录不存在") } user := model.User{} global.DB.Model(&model.User{}).Where("id", pm.UserID).Find(&user) if req.PayStatus == "1" { pm.Status = 1 pm.PayerCardNo = req.PayerCardNo pm.PayerAccountName = req.PayerAccountName global.DB.Save(&user) } else { pm.Status = 2 } err = global.DB.Save(&pm).Error return err } func (s paymentService) AfterPaymentNotify(req request.PaymentNotifyRequest) error { pm := &model.Payment{} err := global.DB.Where("payment_no", req.MchOrderID).Where("status", 0).First(&pm).Error if err != nil && e.Is(err, gorm.ErrRecordNotFound) { return errors.NewBusinessError("记录不存在") } user := model.User{} global.DB.Model(&model.User{}).Where("id", pm.UserID).Find(&user) if req.PayStatus == 1 { pm.Status = 1 global.DB.Model(&user).UpdateColumn("balance", gorm.Expr("balance + ?", pm.Amount)) } else { pm.Status = 2 } err = global.DB.Save(&pm).Error return err } func (s paymentService) AfterBindingPayNotify(req notify.PayAgreeNotify) error { pm := &model.Payment{} err := global.DB.Where("payment_no", req.CusOrderID).Where("status", 0).First(&pm).Error if err != nil && e.Is(err, gorm.ErrRecordNotFound) { return errors.NewBusinessError("记录不存在") } user := model.User{} global.DB.Model(&model.User{}).Where("id", pm.UserID).Find(&user) if req.TrxStatus == "0000" { pm.Status = 1 global.DB.Model(&user).UpdateColumn("balance", gorm.Expr("balance + ?", pm.Amount)) } else { pm.Status = 2 } err = global.DB.Save(&pm).Error return err } func (s paymentService) GatewayPay(token string) (string, error) { pm := &model.Payment{} err := global.DB.Where("token", token).Where("status", 0).First(&pm).Error if err != nil { return "", err } p := param.GatewayPayParam{} p.OrderID = pm.PaymentNo p.PayType = "B2B,B2C" p.TrxAmt = strconv.FormatFloat(pm.Amount*100, 'f', 0, 64) p.LimitPay = "no_credit" p.RetUrl = "http://api.wrtcjt.com/h5/gateway-pay-ret" //p.RetUrl = "https://www.baidu.com" p.NotifyUrl = "http://api.wrtcjt.com/h5/binding-pay-notify" p.GoodsID = "1" p.GoodsInf = "充值" p.Charset = "UTF-8" str := tlpay.TLPay.GatewayPay(p) return str, nil } func (s paymentService) GatewayPayRet(ret notify.GatewayPayRet) (string, error) { return "", nil } func (s paymentService) GatewayPayApply(userID int, paymentRequest request.PaymentRequest) (result.Data, error) { pm, err := s.createPayment(userID, paymentRequest) if err != nil { return nil, err } return s.getGatewayPayUrl(pm) } func (s paymentService) getGatewayPayUrl(pm *model.Payment) (result.Data, error) { token := utils.Md5(pm.PaymentNo + strconv.Itoa(pm.UserID) + "_gateway") pm.Token = token err := global.DB.Save(pm).Error if err != nil { return nil, err } data := result.Data{"url": "http://api.wrtcjt.com/h5/gateway-pay?token=" + token, "orderId": ""} return data, nil } func (s paymentService) getUnionPayUrl(pm *model.Payment) (result.Data, error) { token := utils.Md5(pm.PaymentNo + strconv.Itoa(pm.UserID) + "_union") pm.Token = token err := global.DB.Save(pm).Error if err != nil { return nil, err } data := result.Data{"url": "http://api.wrtcjt.com/h5/union-pay?token=" + token, "orderId": ""} return data, nil } func (s paymentService) UnionPay(token string) (string, error) { pm := &model.Payment{} err := global.DB.Where("token", token).Where("status", 0).First(&pm).Error if err != nil { return "", err } p := param.UnionOrderParam{} p.ReqSn = pm.PaymentNo p.TrxAmt = strconv.FormatFloat(pm.Amount*100, 'f', 0, 64) p.LimitPay = "no_credit" p.RetUrl = "http://api.wrtcjt.com/h5/gateway-pay-ret" p.NotifyUrl = "http://api.wrtcjt.com/h5/binding-pay-notify" p.Body = "充值" p.Charset = "UTF-8" p.PayType = "VSP511" str := tlpay.TLPay.UnionPay(p) return str, nil }