xy_sh-20260727101126/xy_sh/internal/biz/biz.go

200 lines
4.8 KiB
Go

package biz
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"
"strings"
"time"
"xy_sh/internal/config"
"xy_sh/internal/data/impl"
"xy_sh/internal/data/model"
"xy_sh/pkg"
"xy_sh/pkg/crypto"
"xy_sh/ymt_v3"
"gitea.cdlsxd.cn/self-tools/l_request"
"xy_sh/internal/entities"
)
type OrderStore struct {
orders *impl.OrderImpl
ymtClient *ymt_v3.Client
cfg *config.Config
}
func NewOrderStore(orders *impl.OrderImpl, ymtClient *ymt_v3.Client, cfg *config.Config) *OrderStore {
return &OrderStore{
orders: orders,
ymtClient: ymtClient,
cfg: cfg,
}
}
func (o *OrderStore) CreateOrder(ctx context.Context, req *entities.OrderRequest) (*entities.OrderResponseData, error) {
var orderInfo model.XyShOrder
err := o.orders.GetByKey(ctx, "act_order_num", req.ActOrderNum, &orderInfo)
if err != nil {
return nil, err
}
if orderInfo.ID == 0 {
orderInfo = model.XyShOrder{
ActOrderNum: req.ActOrderNum,
GoodsCode: req.GoodsCode,
ActCode: req.ActCode,
Account: req.Account,
Status: entities.StatusSuccess,
CallBackURL: req.CallbackUrl,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
}
selfPublicIP, err := pkg.GetPublicIP()
if err != nil {
selfPublicIP = "120.55.12.245"
}
result, err := o.ymtClient.KeyOrder(&ymt_v3.KeyOrderRequest{
OutBizNo: req.ActOrderNum,
ActivityNo: o.cfg.Ymt.ActivityNo,
Account: req.Account,
NotifyURL: selfPublicIP + ":" + o.cfg.ServerPort + "/callback/notify",
})
if err != nil {
return nil, err
}
orderInfo.CouponNo = result.URL
orderInfo.CouponCode = result.Key
orderInfo.OrderNo = result.TradeNo
orderInfo.Status = int32(result.Status)
var validTime time.Time
if len(result.ValidEndTime) != 0 {
validTime, err = time.Parse(time.DateTime, result.ValidEndTime)
if err != nil {
return nil, fmt.Errorf("解析失败: %v\n", err)
}
}
orderInfo.ExpireTime = validTime
if orderInfo.ID == 0 {
err = o.orders.Add(ctx, &orderInfo)
}
if err != nil {
return nil, err
}
return &entities.OrderResponseData{
OrderNo: result.TradeNo,
CouponNo: result.URL,
CouponCode: result.Key,
Status: o.getStatus(result.Status, result.ValidEndTime, err),
ExpireTime: result.ValidEndTime,
}, nil
}
func (o *OrderStore) getStatus(ymtStatus uint32, ymtValidTime string, err error) int {
if err != nil {
return entities.StatusFailed
}
switch ymtStatus {
case 2:
return entities.StatusRedeemed
case 3:
return entities.StatusFailed
default:
t, err := time.Parse(time.DateTime, ymtValidTime)
if err != nil {
fmt.Printf("解析失败: %v\n", err)
return entities.StatusFailed
}
if t.Unix() <= time.Now().Unix() {
return entities.StatusExpired
}
return entities.StatusSuccess
}
}
func (o *OrderStore) QueryOrder(req *entities.QueryOrderRequest) (*entities.QueryOrderResponseData, error) {
result, err := o.ymtClient.KeyQuery(&ymt_v3.KeyQueryRequest{
TradeNo: req.OrderNo,
})
if err != nil {
return nil, err
}
resp := &entities.QueryOrderResponseData{
OrderNo: result.TradeNo,
Status: o.getStatus(result.Status, result.ValidEndTime, err),
Account: result.Account,
}
if result.URL != "" {
resp.CardInfo = &entities.CardInfo{
CouponNo: result.URL,
CouponCode: result.Key,
ExpireTime: result.ValidEndTime,
}
}
return resp, nil
}
func (o *OrderStore) HandleCallback(req *entities.CallBack) error {
callBackData := &entities.CallbackRequest{
OrderNo: req.Data.TradeNo,
ActOrderNum: req.Data.OutBizNo,
Status: o.getStatus(req.Data.Status, req.Data.ValidEndTime, nil),
Account: req.Data.Account,
CardInfo: &entities.CardInfo{
CouponNo: req.Data.Url,
CouponCode: req.Data.Key,
ExpireTime: req.Data.ValidEndTime,
},
}
sign, jsonData, err := makeEncryptedRequest(callBackData)
if err != nil {
return err
}
requset := &l_request.Request{
Method: http.MethodPost,
Json: jsonData,
Url: o.cfg.NotifyUrl,
Headers: map[string]string{
"Content-Type": "application/json",
"timestamp": fmt.Sprintf("%d", time.Now().UnixMilli()),
"sign": sign,
},
}
res, err := requset.Send()
if err != nil {
return err
}
if strings.ToLower(res.Text) != "ok" {
}
return nil
}
func makeEncryptedRequest(bizData interface{}) (string, map[string]interface{}, error) {
bizJSON, err := json.Marshal(bizData)
if err != nil {
return "", nil, fmt.Errorf("业务数据序列化失败: %v", err)
}
encryptedData, err := crypto.SM4CBCEncrypt(bizJSON)
if err != nil {
return "", nil, fmt.Errorf("加密失败: %v", err)
}
timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10)
sign := crypto.GenerateSign(timestamp, encryptedData)
reqBody := entities.EncryptedRequest{
EncryptedData: encryptedData,
}
reqJSON, _ := pkg.StructToMap(reqBody)
return sign, reqJSON, err
}