add fix id_car
This commit is contained in:
@@ -437,7 +437,7 @@ zhicha:
|
|||||||
# 🌐 木子数据配置
|
# 🌐 木子数据配置
|
||||||
# ===========================================
|
# ===========================================
|
||||||
muzi:
|
muzi:
|
||||||
url: "https://carv.m0101.com/magic/carv/pubin/service/academic"
|
url: "https://carv.m0101.com/magic/carv/pubin/service"
|
||||||
app_id: "713014138179585"
|
app_id: "713014138179585"
|
||||||
app_secret: "bd4090ac652c404c80e90ebbdcd6ba1d"
|
app_secret: "bd4090ac652c404c80e90ebbdcd6ba1d"
|
||||||
timeout: 60s
|
timeout: 60s
|
||||||
|
|||||||
@@ -504,27 +504,7 @@ func (s *ComponentReportOrderService) CreatePaymentOrder(ctx context.Context, re
|
|||||||
zap.String("code_url", codeURL),
|
zap.String("code_url", codeURL),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建一个临时下载记录,用于跟踪支付状态,但不生成报告文件
|
|
||||||
download := &productEntities.ComponentReportDownload{
|
|
||||||
UserID: req.UserID,
|
|
||||||
ProductID: req.ProductID,
|
|
||||||
ProductCode: product.Code,
|
|
||||||
ProductName: product.Name,
|
|
||||||
OrderID: &createdPurchaseOrder.ID, // 关联购买订单ID
|
|
||||||
OrderNumber: &outTradeNo, // 外部订单号
|
|
||||||
ExpiresAt: calculateExpiryTime(), // 30天后过期
|
|
||||||
// 注意:这里不设置FilePath,因为文件将在支付成功后生成
|
|
||||||
}
|
|
||||||
|
|
||||||
err = s.componentReportRepo.Create(ctx, download)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("创建下载记录失败", zap.Error(err))
|
|
||||||
// 不中断流程,即使创建下载记录失败也继续返回订单信息
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回支付响应,包含支付URL
|
// 返回支付响应,包含支付URL
|
||||||
// 使用购买订单ID而不是下载记录ID,以便前端可以正确检查支付状态
|
|
||||||
response := &CreatePaymentOrderResponse{
|
response := &CreatePaymentOrderResponse{
|
||||||
OrderID: createdPurchaseOrder.ID, // 修改为购买订单ID
|
OrderID: createdPurchaseOrder.ID, // 修改为购买订单ID
|
||||||
OrderNo: createdPurchaseOrder.OrderNo,
|
OrderNo: createdPurchaseOrder.OrderNo,
|
||||||
@@ -535,7 +515,6 @@ func (s *ComponentReportOrderService) CreatePaymentOrder(ctx context.Context, re
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.logger.Info("========== 支付订单创建完成 ==========",
|
s.logger.Info("========== 支付订单创建完成 ==========",
|
||||||
zap.String("download_id", download.ID),
|
|
||||||
zap.String("purchase_order_id", createdPurchaseOrder.ID),
|
zap.String("purchase_order_id", createdPurchaseOrder.ID),
|
||||||
zap.String("order_no", createdPurchaseOrder.OrderNo),
|
zap.String("order_no", createdPurchaseOrder.OrderNo),
|
||||||
zap.String("user_id", req.UserID),
|
zap.String("user_id", req.UserID),
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ func ProcessIVYZ3P9MRequest(ctx context.Context, params []byte, deps *processors
|
|||||||
if returnType == "" {
|
if returnType == "" {
|
||||||
returnType = "1"
|
returnType = "1"
|
||||||
}
|
}
|
||||||
|
paramSign := map[string]interface{}{
|
||||||
|
"returnType": returnType,
|
||||||
|
"realName": encryptedName,
|
||||||
|
"certCode": encryptedCertCode,
|
||||||
|
}
|
||||||
|
|
||||||
reqData := map[string]interface{}{
|
reqData := map[string]interface{}{
|
||||||
"realName": encryptedName,
|
"realName": encryptedName,
|
||||||
@@ -43,7 +48,8 @@ func ProcessIVYZ3P9MRequest(ctx context.Context, params []byte, deps *processors
|
|||||||
"returnType": returnType,
|
"returnType": returnType,
|
||||||
}
|
}
|
||||||
|
|
||||||
respData, err := deps.MuziService.CallAPI(ctx, "PC0041", reqData)
|
|
||||||
|
respData, err := deps.MuziService.CallAPI(ctx, "PC0041", "/academic",reqData,paramSign)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, muzi.ErrDatasource):
|
case errors.Is(err, muzi.ErrDatasource):
|
||||||
|
|||||||
@@ -23,15 +23,19 @@ func ProcessQCXG4896Request(ctx context.Context, params []byte, deps *processors
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
paramSign := map[string]interface{}{
|
||||||
|
"paramName": "licenseNo",
|
||||||
|
"paramValue": paramsDto.PlateNo,
|
||||||
|
}
|
||||||
|
|
||||||
reqData := map[string]interface{}{
|
reqData := map[string]interface{}{
|
||||||
"paramName": "licenseNo",
|
"paramName": "licenseNo",
|
||||||
"paramValue": paramsDto.PlateNo,
|
"paramValue": paramsDto.PlateNo,
|
||||||
"startTime": strings.Split(paramsDto.AuthDate, "-")[0],
|
"startTime": strings.Split(paramsDto.AuthDate, "-")[0],
|
||||||
"endTime": strings.Split(paramsDto.AuthDate, "-")[1],
|
"endTime": strings.Split(paramsDto.AuthDate, "-")[1],
|
||||||
}
|
}
|
||||||
|
|
||||||
respData, err := deps.MuziService.CallAPI(ctx, "PC0031", reqData)
|
respData, err := deps.MuziService.CallAPI(ctx, "PC0031", "/hailingScoreBySearch", reqData,paramSign)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, muzi.ErrDatasource):
|
case errors.Is(err, muzi.ErrDatasource):
|
||||||
@@ -44,4 +48,5 @@ func ProcessQCXG4896Request(ctx context.Context, params []byte, deps *processors
|
|||||||
}
|
}
|
||||||
|
|
||||||
return respData, nil
|
return respData, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tyapi-server/internal/shared/external_logger"
|
"tyapi-server/internal/shared/external_logger"
|
||||||
@@ -90,13 +91,14 @@ func (m *MuziService) generateRequestID() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CallAPI 调用木子数据接口
|
// CallAPI 调用木子数据接口
|
||||||
func (m *MuziService) CallAPI(ctx context.Context, prodCode string, params map[string]interface{}) (json.RawMessage, error) {
|
func (m *MuziService) CallAPI(ctx context.Context, prodCode string, path string, params map[string]interface{},paramSign map[string]interface{}) (json.RawMessage, error) {
|
||||||
requestID := m.generateRequestID()
|
requestID := m.generateRequestID()
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
timestamp := strconv.FormatInt(now.UnixMilli(), 10)
|
timestamp := strconv.FormatInt(now.UnixMilli(), 10)
|
||||||
|
|
||||||
flatParams := flattenParams(params)
|
flatParams := flattenParams(params)
|
||||||
signParts := collectSignatureValues(params)
|
|
||||||
|
signParts := collectSignatureValues(paramSign)
|
||||||
signature := m.GenerateSignature(prodCode, timestamp, signParts...)
|
signature := m.GenerateSignature(prodCode, timestamp, signParts...)
|
||||||
|
|
||||||
// 从上下文获取链路ID
|
// 从上下文获取链路ID
|
||||||
@@ -128,7 +130,21 @@ func (m *MuziService) CallAPI(ctx context.Context, prodCode string, params map[s
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req, reqErr := http.NewRequestWithContext(ctx, http.MethodPost, m.config.URL, bytes.NewBuffer(bodyBytes))
|
// 构建完整的URL,拼接路径参数
|
||||||
|
fullURL := m.config.URL
|
||||||
|
if path != "" {
|
||||||
|
// 确保路径以/开头
|
||||||
|
if !strings.HasPrefix(path, "/") {
|
||||||
|
path = "/" + path
|
||||||
|
}
|
||||||
|
// 确保URL不以/结尾,避免双斜杠
|
||||||
|
if strings.HasSuffix(fullURL, "/") {
|
||||||
|
fullURL = fullURL[:len(fullURL)-1]
|
||||||
|
}
|
||||||
|
fullURL += path
|
||||||
|
}
|
||||||
|
|
||||||
|
req, reqErr := http.NewRequestWithContext(ctx, http.MethodPost, fullURL, bytes.NewBuffer(bodyBytes))
|
||||||
if reqErr != nil {
|
if reqErr != nil {
|
||||||
err := errors.Join(ErrSystem, reqErr)
|
err := errors.Join(ErrSystem, reqErr)
|
||||||
if m.logger != nil {
|
if m.logger != nil {
|
||||||
|
|||||||
@@ -300,49 +300,87 @@ func (h *ComponentReportHandler) GenerateAndDownloadZip(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否已存在有效的下载记录
|
// 直接检查用户是否有已支付的购买记录,而不是查询下载记录
|
||||||
download, err := h.componentReportRepo.GetActiveDownload(c.Request.Context(), userID, req.ProductID)
|
orders, _, err := h.purchaseOrderRepo.GetByUserID(c.Request.Context(), userID, 100, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("查询用户下载记录失败", zap.Error(err), zap.String("user_id", userID), zap.String("product_id", req.ProductID))
|
h.logger.Error("查询用户购买记录失败", zap.Error(err), zap.String("user_id", userID), zap.String("product_id", req.ProductID))
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{
|
c.JSON(http.StatusInternalServerError, gin.H{
|
||||||
"code": 500,
|
"code": 500,
|
||||||
"message": "查询下载记录失败",
|
"message": "查询购买记录失败",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果不存在有效的下载记录,尝试创建一个
|
// 查找有效的已支付订单
|
||||||
if download == nil {
|
var validOrder *finance_entities.PurchaseOrder
|
||||||
download, err = h.createDownloadRecordIfEligible(c.Request.Context(), userID, req.ProductID)
|
for _, order := range orders {
|
||||||
if err != nil {
|
if order.ProductID == req.ProductID && order.Status == finance_entities.PurchaseOrderStatusPaid {
|
||||||
h.logger.Error("创建下载记录失败", zap.Error(err), zap.String("user_id", userID), zap.String("product_id", req.ProductID))
|
validOrder = order
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if strings.Contains(err.Error(), "无购买记录") || strings.Contains(err.Error(), "购买未支付") {
|
// 如果没有找到已支付订单,尝试创建一个(可能订单刚创建但状态未更新)
|
||||||
c.JSON(http.StatusForbidden, gin.H{
|
if validOrder == nil {
|
||||||
"code": 403,
|
// 查找该产品的待支付订单
|
||||||
"message": "无下载权限,请先完成购买",
|
var pendingOrder *finance_entities.PurchaseOrder
|
||||||
})
|
for _, order := range orders {
|
||||||
} else {
|
if order.ProductID == req.ProductID && order.Status == finance_entities.PurchaseOrderStatusCreated {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{
|
pendingOrder = order
|
||||||
"code": 500,
|
break
|
||||||
"message": "创建下载记录失败",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return
|
}
|
||||||
|
|
||||||
|
// 如果有待支付订单,尝试主动查询支付状态
|
||||||
|
if pendingOrder != nil {
|
||||||
|
h.logger.Info("发现待支付订单,尝试主动查询支付状态",
|
||||||
|
zap.String("order_id", pendingOrder.ID),
|
||||||
|
zap.String("pay_channel", pendingOrder.PayChannel))
|
||||||
|
|
||||||
|
// 如果是支付宝订单,主动查询状态
|
||||||
|
if pendingOrder.PayChannel == "alipay" && h.aliPayService != nil {
|
||||||
|
// 这里可以调用支付宝查询服务,但为了简化,我们只记录日志
|
||||||
|
h.logger.Info("支付宝订单状态待查询,但当前实现简化处理",
|
||||||
|
zap.String("order_id", pendingOrder.ID))
|
||||||
|
}
|
||||||
|
// 如果是微信订单,主动查询状态
|
||||||
|
if pendingOrder.PayChannel == "wechat" && h.wechatPayService != nil {
|
||||||
|
// 这里可以调用微信查询服务,但为了简化,我们只记录日志
|
||||||
|
h.logger.Info("微信订单状态待查询,但当前实现简化处理",
|
||||||
|
zap.String("order_id", pendingOrder.ID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.logger.Error("用户没有已支付的购买记录", zap.String("user_id", userID), zap.String("product_id", req.ProductID))
|
||||||
|
c.JSON(http.StatusForbidden, gin.H{
|
||||||
|
"code": 403,
|
||||||
|
"message": "无下载权限,请先完成购买",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建下载记录(仅用于记录,不影响下载流程)
|
||||||
|
download, err := h.componentReportRepo.GetActiveDownload(c.Request.Context(), userID, req.ProductID)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Warn("查询现有下载记录失败,将创建新记录", zap.Error(err), zap.String("user_id", userID), zap.String("product_id", req.ProductID))
|
||||||
|
download = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不存在有效的下载记录,创建一个
|
||||||
|
if download == nil {
|
||||||
|
download, err = h.createDownloadRecordForPaidOrder(c.Request.Context(), validOrder)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Warn("创建下载记录失败,但继续处理下载请求", zap.Error(err), zap.String("order_id", validOrder.ID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查下载记录是否仍有效
|
// 检查下载记录是否仍有效
|
||||||
if !download.CanDownload() {
|
if download != nil && !download.CanDownload() {
|
||||||
h.logger.Warn("下载记录已过期",
|
h.logger.Warn("下载记录已过期,但基于已支付订单继续处理",
|
||||||
zap.String("user_id", userID),
|
zap.String("user_id", userID),
|
||||||
zap.String("product_id", req.ProductID),
|
zap.String("product_id", req.ProductID),
|
||||||
)
|
)
|
||||||
c.JSON(http.StatusForbidden, gin.H{
|
// 不再阻止下载,因为已确认用户有有效的已支付订单
|
||||||
"code": 403,
|
|
||||||
"message": "下载权限已过期,请重新购买",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新下载次数和最后下载时间
|
// 更新下载次数和最后下载时间
|
||||||
@@ -1513,3 +1551,69 @@ func calculateExpiryTime() *time.Time {
|
|||||||
expiry := now.AddDate(0, 0, 30) // 30天后过期
|
expiry := now.AddDate(0, 0, 30) // 30天后过期
|
||||||
return &expiry
|
return &expiry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createDownloadRecordForPaidOrder 为已支付订单创建下载记录
|
||||||
|
func (h *ComponentReportHandler) createDownloadRecordForPaidOrder(ctx context.Context, order *finance_entities.PurchaseOrder) (*entities.ComponentReportDownload, error) {
|
||||||
|
// 获取产品信息
|
||||||
|
product, err := h.productRepo.GetByID(ctx, order.ProductID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("获取产品信息失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建下载记录
|
||||||
|
download := &entities.ComponentReportDownload{
|
||||||
|
UserID: order.UserID,
|
||||||
|
ProductID: order.ProductID,
|
||||||
|
ProductCode: order.ProductCode,
|
||||||
|
ProductName: order.ProductName,
|
||||||
|
OrderID: &order.ID,
|
||||||
|
OrderNumber: &order.OrderNo,
|
||||||
|
ExpiresAt: calculateExpiryTime(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是组合包,获取子产品信息
|
||||||
|
if product.IsPackage {
|
||||||
|
packageItems, err := h.getSubProductsByProductID(ctx, order.ProductID)
|
||||||
|
if err == nil && len(packageItems) > 0 {
|
||||||
|
var subProductIDs []string
|
||||||
|
var subProductCodes []string
|
||||||
|
|
||||||
|
// 获取子产品的详细信息
|
||||||
|
for _, item := range packageItems {
|
||||||
|
if item.Product != nil {
|
||||||
|
subProductIDs = append(subProductIDs, item.Product.ID)
|
||||||
|
subProductCodes = append(subProductCodes, item.Product.Code)
|
||||||
|
} else {
|
||||||
|
// 如果关联的Product为nil,需要单独查询
|
||||||
|
subProduct, err := h.productRepo.GetByID(ctx, item.ProductID)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Warn("获取子产品信息失败", zap.Error(err), zap.String("product_id", item.ProductID))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
subProductIDs = append(subProductIDs, subProduct.ID)
|
||||||
|
subProductCodes = append(subProductCodes, subProduct.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subProductIDsJSON, _ := json.Marshal(subProductIDs)
|
||||||
|
subProductCodesJSON, _ := json.Marshal(subProductCodes)
|
||||||
|
download.SubProductIDs = string(subProductIDsJSON)
|
||||||
|
download.SubProductCodes = string(subProductCodesJSON)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存下载记录
|
||||||
|
err = h.componentReportRepo.Create(ctx, download)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("创建下载记录失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.logger.Info("创建下载记录成功",
|
||||||
|
zap.String("user_id", order.UserID),
|
||||||
|
zap.String("product_id", order.ProductID),
|
||||||
|
zap.String("order_id", order.ID),
|
||||||
|
zap.String("download_id", download.ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
return download, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user