You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
476 lines
13 KiB
Go
476 lines
13 KiB
Go
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
|
|
}
|