qnc-server-old/service/order.go
2024-09-14 10:48:09 +08:00

237 lines
8.6 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"
"encoding/json"
"errors"
"fmt"
"github.com/smartwalle/alipay/v3"
wxcore "github.com/wechatpay-apiv3/wechatpay-go/core"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/h5"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
"log"
"net/http"
"qnc-server/config"
"qnc-server/db"
"qnc-server/global"
"qnc-server/model/model"
"qnc-server/utils"
)
type OrderService struct {
}
func (a *OrderService) QueryConsumedOrder(userid uint, productEn string) (payOrder model.PayOrder, err error) {
err = db.DB.Joins("JOIN product ON product.id = pay_order.product_id").Where("pay_order.userid = ? AND pay_order.pay_status = ? AND pay_order.has_consumed = ? AND product.product_en = ?", userid, model.PayStatusSuccess, model.NotConsumed, productEn).First(&payOrder).Error
return
}
// 付款消费
func (a *OrderService) OrderConsumed(payOrder model.PayOrder) {
payOrder.HasConsumed = 1
err := db.DB.Save(&payOrder).Error
if err != nil {
log.Printf("消费订单失败:%v", err)
}
}
// 失效并退款
func (a *OrderService) OrderFailure(payOrder model.PayOrder) {
payOrder.HasConsumed = 2
err := db.DB.Save(&payOrder).Error
if err != nil {
log.Printf("失效订单失败:%v", err)
}
}
func (a *OrderService) GetList(pageSize int, pageNum int, userId uint) (list []model.PayOrder, err error) {
offset := (pageNum - 1) * pageSize
result := db.DB.Preload("Product").Where("userid = ? AND pay_status IN ?", userId, []string{model.PayStatusSuccess, model.PayStatusRefund, model.PayStatusUnderRefund}).Order("id desc").Limit(pageSize).Offset(offset).Find(&list)
if result.Error != nil {
return list, result.Error
}
return list, nil
}
func (a *OrderService) GetOrderByid(id uint) (order *model.PayOrder, err error) {
order = &model.PayOrder{}
err = db.DB.Preload("Product").Where("id = ?", id).First(order).Error
if err != nil {
return
}
return
}
// 微信小程序或公众号
func (a *OrderService) WechatJSAPIPrepay(appid string, mchID string, product model.Product, outTradeNo string, amount int64, openid string, platform string, client *wxcore.Client) (resp *jsapi.PrepayWithRequestPaymentResponse, err error) {
prepayReq := jsapi.PrepayRequest{
Appid: &appid,
Mchid: &mchID,
Description: wxcore.String(product.ProductName),
OutTradeNo: wxcore.String(outTradeNo), // 唯一的订单号
Attach: wxcore.String(product.Description),
NotifyUrl: wxcore.String(fmt.Sprintf("%s/%s", config.ConfigData.WxPay.NotifyURL, platform)), // 回调地址,需替换为实际地址
Amount: &jsapi.Amount{
Total: wxcore.Int64(amount), // 订单金额,单位为分
},
Payer: &jsapi.Payer{
Openid: wxcore.String(openid), // 用户的 OpenID通过前端传入
}}
// 发起预支付请求
svc := jsapi.JsapiApiService{Client: client}
resp, _, err = svc.PrepayWithRequestPayment(ctx, prepayReq)
if err != nil {
return nil, err
}
return resp, nil
}
// 浏览器H5
func (a *OrderService) WechatH5Prepay(appid string, mchID string, product model.Product, outTradeNo string, amount int64, userIP string, client *wxcore.Client) (resp *h5.PrepayResponse, err error) {
prepayReq := h5.PrepayRequest{
Appid: wxcore.String(appid),
Mchid: wxcore.String(mchID),
Description: wxcore.String(product.ProductName),
OutTradeNo: wxcore.String(outTradeNo), // 唯一的订单号
Attach: wxcore.String(product.Description),
NotifyUrl: wxcore.String(config.ConfigData.WxPay.NotifyURL), // 回调地址,需替换为实际地址
Amount: &h5.Amount{
Total: wxcore.Int64(amount), // 订单金额,单位为分
},
SceneInfo: &h5.SceneInfo{
PayerClientIp: wxcore.String(userIP), // 可通过前端传入
H5Info: &h5.H5Info{
Type: wxcore.String("Wap"),
//AppName: wxcore.String("全能查"),
//AppUrl: wxcore.String("https://你的域名"),
},
},
}
// 发起预支付请求
svc := h5.H5ApiService{Client: client}
resp, _, err = svc.Prepay(context.Background(), prepayReq)
if err != nil {
return nil, err
}
return resp, nil
}
func (a *OrderService) WeChatRefund(order model.PayOrder) (err error) {
var client *wxcore.Client
switch order.Platform {
case model.PlatformMPWEIXIN:
client = global.GlobalData.PayClient
case model.PlatformMPH5:
client = global.GlobalData.PayH5Client
}
outRefundNo := utils.GenerateOrderRefundNumber()
svc := refunddomestic.RefundsApiService{Client: client}
resp, result, err := svc.Create(ctx,
refunddomestic.CreateRequest{
OutTradeNo: wxcore.String(order.OutTradeNo),
OutRefundNo: wxcore.String(outRefundNo), //退款单号
NotifyUrl: wxcore.String(fmt.Sprintf("%s/%s", config.ConfigData.WxPay.RefundNotifyURL, order.Platform)),
Amount: &refunddomestic.AmountReq{
Currency: wxcore.String("CNY"),
Refund: wxcore.Int64(order.Amount),
Total: wxcore.Int64(order.Amount),
},
},
)
if err != nil {
// 处理错误
log.Printf("微信订单申请退款错误:%s", err)
return errors.New(fmt.Sprintf("微信订单申请退款错误:%s", err))
} else {
// 处理返回结果
log.Printf("微信订单申请退款 response status=%d resp=%s", result.Response.StatusCode, resp)
order.PayStatus = model.PayStatusUnderRefund
err = db.DB.Save(order).Error
if err != nil {
log.Printf("微信订单退状态修改失败 underRefund Error:%v", err)
return errors.New(fmt.Sprintf("微信订单退状态修改失败 underRefund Error:%v", err))
}
return nil
}
}
// 创建投诉回调URL
func (a *OrderService) RegisterComplaintNotificationURL(client *wxcore.Client, platform string) {
url := "https://api.mch.weixin.qq.com/v3/merchant-service/complaint-notifications"
// 请求体数据
requestBody := map[string]string{
"url": fmt.Sprintf("%s/%s/pay/complaint_callback/%s", config.ConfigData.Server.Domain, config.ConfigData.Server.Prefix, platform), // 你的回调URL
}
// 将请求体序列化为 JSON
requestBodyJson, err := json.Marshal(requestBody)
if err != nil {
log.Fatalf("【%s创建投诉回调URL】请求体JSON序列化失败: %v", platform, err)
}
// 发送POST请求
result, err := client.Post(context.Background(), url, requestBodyJson)
if err != nil {
// 尝试解析响应内容,获取详细错误信息
var response map[string]interface{}
if err := json.NewDecoder(result.Response.Body).Decode(&response); err != nil {
log.Fatalf("【%s创建投诉回调URL】解析错误响应失败: %v", platform, err)
}
// 检查错误代码和信息
if responseCode, ok := response["code"].(string); ok && responseCode == "PARAM_ERROR" {
if responseMessage, ok := response["message"].(string); ok && responseMessage == "数据已存在" {
log.Printf("【%s创建投诉回调URL】数据已存在不需要重新创建: %+v\n", platform, response)
return
}
}
log.Fatalf("【%s创建投诉回调URL】请求失败: %v", platform, err)
}
// 处理响应
defer result.Response.Body.Close()
// 检查请求状态
if result.Response.StatusCode != http.StatusOK {
log.Fatalf("【%s创建投诉回调URL】请求失败状态码: %v", platform, result.Response.StatusCode)
}
// 解析响应
var response map[string]interface{}
if err := json.NewDecoder(result.Response.Body).Decode(&response); err != nil {
log.Fatalf("【%s创建投诉回调URL】解析响应失败: %v", platform, err)
}
log.Printf("【%s创建投诉回调URL】投诉通知回调URL创建成功: %+v\n", platform, response)
return
}
func (a *OrderService) AliRefund(ctx context.Context, payOrder model.PayOrder) error {
// 创建退款请求参数
refund := alipay.TradeRefund{}
refund.OutTradeNo = payOrder.OutTradeNo
refund.RefundAmount = utils.ConvertCentsToYuan(int(payOrder.Amount)) // 退款金额,单位元
refund.OutRequestNo = fmt.Sprintf("ali_refund_%s", utils.GenerateOrderNumber()) // 生成的唯一退款请求号
// 发起退款请求
refundResp, err := global.GlobalData.AliPayClient.TradeRefund(ctx, refund)
if err != nil {
log.Printf("【阿里支付退款】退款请求错误:%v", err)
return fmt.Errorf("refund request failed")
}
if refundResp.IsSuccess() {
// 更新订单状态
err = db.DB.Model(&model.PayOrder{}).Where("out_trade_no = ?", payOrder.OutTradeNo).Updates(model.PayOrder{
PayStatus: model.PayStatusRefund,
}).Error
if err != nil {
log.Printf("【阿里支付退款】订单更新错误:%v", err)
return fmt.Errorf("order update failed")
}
return nil
} else {
log.Printf("【阿里支付退款】退款失败:%v", refundResp.SubMsg)
return fmt.Errorf("refund failed: %s", refundResp.SubMsg)
}
}