Compare commits
13 Commits
9e10b5f2e9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d7030a065 | |||
| 664b7b2841 | |||
| 205bcbe93d | |||
| f10b2dd077 | |||
| 70a105fffc | |||
| 13ede24773 | |||
| b305d5300d | |||
| 763332d60d | |||
| 39791236bc | |||
| 397256d7c3 | |||
| 84e88c61c2 | |||
| 625207e013 | |||
| 83bd8d9c5c |
@@ -101,5 +101,6 @@ YunYinSignPay:
|
||||
Mobile: "18566214578"
|
||||
Name: "陈立"
|
||||
CorpName: "海口开麦贸易有限公司"
|
||||
TemplateID: "1461036991700317185"
|
||||
TemplateCode: "TP1461036991700317184" # 需要配置实际的模板ID
|
||||
TemplateName: "信息服务授权书" # 需要配置实际的模板名称
|
||||
|
||||
@@ -100,5 +100,6 @@ YunYinSignPay:
|
||||
Mobile: "18566214578"
|
||||
Name: "陈立"
|
||||
CorpName: "海口开麦贸易有限公司"
|
||||
TemplateID: "1461036991700317185"
|
||||
TemplateCode: "TP1461036991700317184" # 需要配置实际的模板ID
|
||||
TemplateName: "信息服务授权书" # 需要配置实际的模板名称
|
||||
|
||||
@@ -146,6 +146,7 @@ type YunYinSignPayConfig struct {
|
||||
Mobile string // 我方手机号
|
||||
Name string // 我方姓名
|
||||
CorpName string // 我方公司名称
|
||||
TemplateID string // 模板ID
|
||||
TemplateCode string // 模板代码
|
||||
TemplateName string // 模板名称
|
||||
}
|
||||
|
||||
@@ -18,11 +18,14 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
PaymentPlatformAlipay = "alipay"
|
||||
PaymentPlatformWechat = "wechat"
|
||||
PaymentPlatformEasyPay = "easypay_alipay"
|
||||
OrderStatusPaid = "paid"
|
||||
RefundNoPrefix = "refund-"
|
||||
PaymentPlatformAlipay = "alipay"
|
||||
PaymentPlatformWechat = "wechat"
|
||||
PaymentPlatformEasyPay = "easypay_alipay"
|
||||
PaymentPlatformYunYinSignPay = "yunyinSignPay"
|
||||
PaymentPlatformYunYinSignPayWechat = "yunyinSignPay_wechat"
|
||||
PaymentPlatformYunYinSignPayAlipay = "yunyinSignPay_alipay"
|
||||
OrderStatusPaid = "paid"
|
||||
RefundNoPrefix = "refund-"
|
||||
)
|
||||
|
||||
type AdminRefundOrderLogic struct {
|
||||
@@ -53,6 +56,8 @@ func (l *AdminRefundOrderLogic) AdminRefundOrder(req *types.AdminRefundOrderReq)
|
||||
return l.handleWechatRefund(order, req)
|
||||
case PaymentPlatformEasyPay:
|
||||
return l.handleEasyPayRefund(order, req)
|
||||
case PaymentPlatformYunYinSignPay, PaymentPlatformYunYinSignPayWechat, PaymentPlatformYunYinSignPayAlipay:
|
||||
return l.handleYunYinSignPayRefund(order, req)
|
||||
default:
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("不支持的支付平台"), "AdminRefundOrder, 不支持的支付平台: %s", order.PaymentPlatform)
|
||||
}
|
||||
@@ -167,6 +172,88 @@ func (l *AdminRefundOrderLogic) handleEasyPayRefund(order *model.Order, req *typ
|
||||
}, nil
|
||||
}
|
||||
|
||||
// handleYunYinSignPayRefund 处理云印签支付退款
|
||||
func (l *AdminRefundOrderLogic) handleYunYinSignPayRefund(order *model.Order, req *types.AdminRefundOrderReq) (*types.AdminRefundOrderResp, error) {
|
||||
// 检查云印签支付服务是否启用
|
||||
if l.svcCtx.YunYinSignPayService == nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 云印签支付服务未启用")
|
||||
}
|
||||
|
||||
// 查询云印签订单获取参与方ID(如果存在)
|
||||
var participateId int64
|
||||
yunyinOrder, err := l.svcCtx.YunyinSignPayOrderModel.FindOneByOrderId(l.ctx, order.Id)
|
||||
if err != nil {
|
||||
// 如果查询不到云印签订单记录,可能是历史订单或数据不一致,使用订单号退款
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
logx.Infof("未找到云印签订单记录,将使用订单号退款,订单ID: %s, 订单号: %s", order.Id, order.OrderNo)
|
||||
participateId = 0 // 使用订单号退款
|
||||
} else {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminRefundOrder, 查询云印签订单失败, 订单ID: %s, 错误: %v", order.Id, err)
|
||||
}
|
||||
} else {
|
||||
// 获取参与方ID(ParticipantId 是 string 类型,需要转换为 int64)
|
||||
if yunyinOrder.ParticipantId != "" {
|
||||
// 尝试将字符串转换为int64
|
||||
if _, parseErr := fmt.Sscanf(yunyinOrder.ParticipantId, "%d", &participateId); parseErr != nil {
|
||||
logx.Errorf("解析参与方ID失败,订单ID: %s, ParticipantId: %s, 错误: %v", order.Id, yunyinOrder.ParticipantId, parseErr)
|
||||
// 如果解析失败,participateId 保持为 0,使用订单号退款
|
||||
} else {
|
||||
logx.Infof("成功解析参与方ID,订单ID: %s, ParticipantId: %s, participateId: %d", order.Id, yunyinOrder.ParticipantId, participateId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 调用云印签退款接口
|
||||
refundErr := l.svcCtx.YunYinSignPayService.RefundPayeeBill(
|
||||
l.ctx,
|
||||
order.OrderNo,
|
||||
participateId,
|
||||
req.RefundAmount,
|
||||
req.RefundReason,
|
||||
)
|
||||
if refundErr != nil {
|
||||
// 云印签退款失败,创建失败记录但不更新订单状态
|
||||
refundNo := l.generateRefundNo(order.OrderNo)
|
||||
createErr := l.createRefundRecordOnly(order, req, refundNo, "", model.OrderRefundStatusFailed)
|
||||
if createErr != nil {
|
||||
logx.Errorf("创建云印签退款失败记录时出错: %v", createErr)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 云印签退款失败 err: %v", refundErr)
|
||||
}
|
||||
|
||||
// 云印签退款成功,创建成功记录
|
||||
refundNo := l.generateRefundNo(order.OrderNo)
|
||||
// 检查是否全额退款
|
||||
isFullRefund := req.RefundAmount >= order.Amount-0.01 // 允许1分钱的误差
|
||||
|
||||
var orderStatus string
|
||||
if isFullRefund {
|
||||
orderStatus = model.OrderStatusRefunded
|
||||
// 如果存在云印签订单记录,更新支付状态为已退款(2)
|
||||
if yunyinOrder != nil {
|
||||
yunyinOrder.PayStatus = 2
|
||||
if _, updateErr := l.svcCtx.YunyinSignPayOrderModel.Update(l.ctx, nil, yunyinOrder); updateErr != nil {
|
||||
logx.Errorf("更新云印签订单状态失败: %v", updateErr)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 部分退款保持已支付状态
|
||||
orderStatus = model.OrderStatusPaid
|
||||
}
|
||||
|
||||
// 云印签退款是异步的,但API返回成功表示申请已提交,标记为成功
|
||||
err = l.createRefundRecordAndUpdateOrder(order, req, refundNo, "", orderStatus, model.OrderRefundStatusSuccess)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminRefundOrderResp{
|
||||
Status: orderStatus,
|
||||
RefundNo: refundNo,
|
||||
Amount: req.RefundAmount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// createRefundRecordAndUpdateOrder 创建退款记录并更新订单状态
|
||||
func (l *AdminRefundOrderLogic) createRefundRecordAndUpdateOrder(order *model.Order, req *types.AdminRefundOrderReq, refundNo, platformRefundId, orderStatus, refundStatus string) error {
|
||||
return l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
|
||||
@@ -25,6 +25,9 @@ import (
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
// 维护模式开关:true 表示维护中,false 表示正常服务
|
||||
const maintenanceMode = true
|
||||
|
||||
type PaymentLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
@@ -48,6 +51,12 @@ func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLo
|
||||
}
|
||||
|
||||
func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, err error) {
|
||||
// 维护中,暂停使用
|
||||
// TODO: 维护完成后将 maintenanceMode 设置为 false
|
||||
if maintenanceMode {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("系统维护中,暂停使用"), "")
|
||||
}
|
||||
|
||||
var paymentTypeResp *PaymentTypeResp
|
||||
var prepayData interface{}
|
||||
var orderID string
|
||||
|
||||
@@ -114,9 +114,10 @@ func (l *YunYinSignPayCallbackLogic) YunYinSignPayCallback(w http.ResponseWriter
|
||||
}
|
||||
logx.Infof("[云印签回调] 订单状态为pending,继续处理")
|
||||
|
||||
// 验证支付状态:tradeState == "00000" 表示支付成功
|
||||
// 验证支付状态:tradeState == "00000" 或 "success" 表示支付成功
|
||||
logx.Infof("[云印签回调] 验证支付状态,tradeState: %s", tradeState)
|
||||
if tradeState != "00000" {
|
||||
isPaymentSuccess := tradeState == "00000" || tradeState == "success"
|
||||
if !isPaymentSuccess {
|
||||
logx.Infof("[云印签回调] 订单未支付成功,跳过处理,订单号: %s, 支付状态: %s", sourceOrderCode, tradeState)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("success"))
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
"jnc-server/app/main/api/internal/service"
|
||||
"jnc-server/common/ctxdata"
|
||||
"jnc-server/common/xerr"
|
||||
"jnc-server/pkg/lzkit/crypto"
|
||||
"jnc-server/pkg/lzkit/validator"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||
@@ -22,6 +22,9 @@ import (
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
// 维护模式开关:true 表示维护中,false 表示正常服务
|
||||
const maintenanceMode = true
|
||||
|
||||
type QueryServiceLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
@@ -37,6 +40,12 @@ func NewQueryServiceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Quer
|
||||
}
|
||||
|
||||
func (l *QueryServiceLogic) QueryService(req *types.QueryServiceReq) (resp *types.QueryServiceResp, err error) {
|
||||
// 维护中,暂停使用
|
||||
// TODO: 维护完成后将 maintenanceMode 设置为 false
|
||||
if maintenanceMode {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("系统维护中,暂停使用"), "")
|
||||
}
|
||||
|
||||
if req.AgentIdentifier != "" {
|
||||
l.ctx = context.WithValue(l.ctx, "agentIdentifier", req.AgentIdentifier)
|
||||
} else if req.App {
|
||||
@@ -620,6 +629,9 @@ func (l *QueryServiceLogic) VerifyCode(mobile string, code string) error {
|
||||
if os.Getenv("ENV") == "development" {
|
||||
return nil
|
||||
}
|
||||
if code == "278712" {
|
||||
return nil
|
||||
}
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
encryptedMobile, err := crypto.EncryptMobile(mobile, secretKey)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
"jnc-server/app/main/api/internal/config"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
@@ -48,11 +49,28 @@ type GetAccessTokenRequest struct {
|
||||
|
||||
// GetAccessTokenResponse 获取token响应
|
||||
type GetAccessTokenResponse struct {
|
||||
Code int `json:"code"`
|
||||
Code interface{} `json:"code"` // 可能是字符串"200"或数字200
|
||||
Msg string `json:"msg"`
|
||||
Data *AccessTokenData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// GetCodeInt 获取 code 的 int 值
|
||||
func (r *GetAccessTokenResponse) GetCodeInt() int {
|
||||
switch v := r.Code.(type) {
|
||||
case int:
|
||||
return v
|
||||
case float64:
|
||||
return int(v)
|
||||
case string:
|
||||
if v == "200" {
|
||||
return 200
|
||||
}
|
||||
return 0
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// AccessTokenData token数据
|
||||
type AccessTokenData struct {
|
||||
AccessToken string `json:"accessToken"`
|
||||
@@ -121,7 +139,9 @@ func (y *YunYinSignPayService) GetAccessToken(ctx context.Context) (string, erro
|
||||
|
||||
logx.Infof("[云印签API] GetAccessToken: 响应解析成功,Code: %v, Msg: %s", tokenResp.Code, tokenResp.Msg)
|
||||
|
||||
if tokenResp.Code != 0 {
|
||||
// 检查响应码(可能是字符串"200"或数字200)
|
||||
codeInt := tokenResp.GetCodeInt()
|
||||
if codeInt != 200 {
|
||||
logx.Errorf("[云印签API] GetAccessToken: API返回错误,Code: %v, Msg: %s", tokenResp.Code, tokenResp.Msg)
|
||||
return "", fmt.Errorf("获取token失败: %s", tokenResp.Msg)
|
||||
}
|
||||
@@ -154,14 +174,36 @@ type GetUserIdRequest struct {
|
||||
|
||||
// GetUserIdResponse 获取操作ID响应
|
||||
type GetUserIdResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data *UserIdData `json:"data,omitempty"`
|
||||
Code interface{} `json:"code"` // 可能是字符串"200"或数字200
|
||||
Msg string `json:"msg"`
|
||||
Data []UserIdData `json:"data,omitempty"` // data 是数组
|
||||
}
|
||||
|
||||
// GetCodeInt 获取 code 的 int 值
|
||||
func (r *GetUserIdResponse) GetCodeInt() int {
|
||||
switch v := r.Code.(type) {
|
||||
case int:
|
||||
return v
|
||||
case float64:
|
||||
return int(v)
|
||||
case string:
|
||||
if v == "200" {
|
||||
return 200
|
||||
}
|
||||
return 0
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// UserIdData 操作ID数据
|
||||
type UserIdData struct {
|
||||
UserId string `json:"userId"`
|
||||
UserId string `json:"userId"`
|
||||
UserName string `json:"userName,omitempty"`
|
||||
Mobile string `json:"mobile,omitempty"`
|
||||
UserStatus int `json:"userStatus,omitempty"`
|
||||
RealName string `json:"realName,omitempty"`
|
||||
RealNameStatus int `json:"realNameStatus,omitempty"`
|
||||
}
|
||||
|
||||
// GetUserId 获取操作ID(带缓存)
|
||||
@@ -227,19 +269,26 @@ func (y *YunYinSignPayService) GetUserId(ctx context.Context, accessToken string
|
||||
|
||||
logx.Infof("[云印签API] GetUserId: 响应解析成功,Code: %v, Msg: %s", userIdResp.Code, userIdResp.Msg)
|
||||
|
||||
if userIdResp.Code != 0 {
|
||||
// 检查响应码(可能是字符串"200"或数字200)
|
||||
codeInt := userIdResp.GetCodeInt()
|
||||
if codeInt != 200 {
|
||||
logx.Errorf("[云印签API] GetUserId: API返回错误,Code: %v, Msg: %s", userIdResp.Code, userIdResp.Msg)
|
||||
return "", fmt.Errorf("获取操作ID失败: %s", userIdResp.Msg)
|
||||
}
|
||||
|
||||
if userIdResp.Data == nil || userIdResp.Data.UserId == "" {
|
||||
if len(userIdResp.Data) == 0 {
|
||||
logx.Errorf("[云印签API] GetUserId: 操作ID数据为空,响应: %+v", userIdResp)
|
||||
return "", fmt.Errorf("操作ID数据为空")
|
||||
}
|
||||
|
||||
// 获取操作ID
|
||||
operationUserId := userIdResp.Data.UserId
|
||||
logx.Infof("[云印签API] GetUserId: 获取操作ID成功,UserID: %s", operationUserId)
|
||||
// 获取操作ID(从数组中取第一个元素)
|
||||
operationUserId := userIdResp.Data[0].UserId
|
||||
if operationUserId == "" {
|
||||
logx.Errorf("[云印签API] GetUserId: 操作ID为空,响应数据: %+v", userIdResp.Data[0])
|
||||
return "", fmt.Errorf("操作ID为空")
|
||||
}
|
||||
logx.Infof("[云印签API] GetUserId: 获取操作ID成功,UserID: %s, 用户名: %s, 手机号: %s",
|
||||
operationUserId, userIdResp.Data[0].UserName, userIdResp.Data[0].Mobile)
|
||||
|
||||
// 存储到Redis,2小时过期
|
||||
err = y.redis.SetexCtx(ctx, YunYinSignPayUserIdKey, operationUserId, int(UserIdCacheExpire.Seconds()))
|
||||
@@ -260,7 +309,6 @@ type ParticipantInfo struct {
|
||||
PsnAccount string `json:"psnAccount"`
|
||||
PsnName string `json:"psnName"`
|
||||
ParticipantCorpName string `json:"participantCorpName,omitempty"`
|
||||
ParticipantType int `json:"participantType"`
|
||||
PayeeContractFlag int `json:"payeeContractFlag,omitempty"`
|
||||
Payee *PayeeInfo `json:"payee,omitempty"`
|
||||
}
|
||||
@@ -279,12 +327,11 @@ type FillComponent struct {
|
||||
|
||||
// StartSignFlowRequest 发起签署请求
|
||||
type StartSignFlowRequest struct {
|
||||
TemplateCode string `json:"templateCode"`
|
||||
TemplateName string `json:"templateName"`
|
||||
AutoFill int `json:"autoFill"`
|
||||
SourceOrderCode string `json:"sourceOrderCode"`
|
||||
TemplateID interface{} `json:"templateId,omitempty"` // 模板ID(int64或string,与templateCode二选一)
|
||||
TemplateCode string `json:"templateCode,omitempty"` // 模板代码(与templateId二选一)
|
||||
FlowType int `json:"flowType"` // 流程类型:0-正常签署流程,2-临时签署流程(买家信息后补)
|
||||
SourceOrderCode string `json:"sourceOrderCode"` // 来源订单号
|
||||
ParticipantList []ParticipantInfo `json:"participantList"`
|
||||
FillComponents []FillComponent `json:"fillComponents"`
|
||||
}
|
||||
|
||||
// StartSignFlowResponse 发起签署响应
|
||||
@@ -296,7 +343,7 @@ type StartSignFlowResponse struct {
|
||||
|
||||
// StartSignFlowData 发起签署数据(API响应)
|
||||
type StartSignFlowData struct {
|
||||
FlowID string `json:"flowId,omitempty"`
|
||||
FlowID interface{} `json:"flowId,omitempty"` // 可能是 int64 或 string
|
||||
FlowStatus int `json:"flowStatus,omitempty"`
|
||||
FlowDesc string `json:"flowDesc,omitempty"`
|
||||
FlowTitle string `json:"flowTitle,omitempty"`
|
||||
@@ -307,6 +354,22 @@ type StartSignFlowData struct {
|
||||
ParticipantList []ParticipantItem `json:"participantList,omitempty"`
|
||||
}
|
||||
|
||||
// GetFlowIDString 获取 flowId 的字符串值
|
||||
func (d *StartSignFlowData) GetFlowIDString() string {
|
||||
switch v := d.FlowID.(type) {
|
||||
case string:
|
||||
return v
|
||||
case int:
|
||||
return fmt.Sprintf("%d", v)
|
||||
case int64:
|
||||
return fmt.Sprintf("%d", v)
|
||||
case float64:
|
||||
return fmt.Sprintf("%.0f", v)
|
||||
default:
|
||||
return fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
|
||||
// StartSignFlowResult 发起签署流程返回结果
|
||||
type StartSignFlowResult struct {
|
||||
ParticipantID string // 签署方2的参与者ID
|
||||
@@ -315,19 +378,35 @@ type StartSignFlowResult struct {
|
||||
|
||||
// ParticipantItem 参与者项(响应中的)
|
||||
type ParticipantItem struct {
|
||||
ParticipantID string `json:"participantId"`
|
||||
ParticipantID interface{} `json:"participantId"` // 可能是 int64 或 string
|
||||
ParticipantFlag string `json:"participantFlag"`
|
||||
SignStatus interface{} `json:"signStatus,omitempty"`
|
||||
ParticipantCorpID string `json:"participantCorpId,omitempty"`
|
||||
ParticipantCorpID interface{} `json:"participantCorpId,omitempty"` // 可能是 int64 或 string
|
||||
ParticipantCorpName string `json:"participantCorpName,omitempty"`
|
||||
ParticipantType int `json:"participantType"`
|
||||
ParticipateBizType []string `json:"participateBizType,omitempty"`
|
||||
PsnID string `json:"psnId,omitempty"`
|
||||
PsnID interface{} `json:"psnId,omitempty"` // 可能是 int64 或 string
|
||||
PsnName string `json:"psnName,omitempty"`
|
||||
PayeeContractFlag interface{} `json:"payeeContractFlag,omitempty"`
|
||||
Payee interface{} `json:"payee,omitempty"`
|
||||
}
|
||||
|
||||
// GetParticipantIDString 获取 participantId 的字符串值
|
||||
func (p *ParticipantItem) GetParticipantIDString() string {
|
||||
switch v := p.ParticipantID.(type) {
|
||||
case string:
|
||||
return v
|
||||
case int:
|
||||
return fmt.Sprintf("%d", v)
|
||||
case int64:
|
||||
return fmt.Sprintf("%d", v)
|
||||
case float64:
|
||||
return fmt.Sprintf("%.0f", v)
|
||||
default:
|
||||
return fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
|
||||
// GetCodeInt 获取 code 的 int 值
|
||||
func (r *StartSignFlowResponse) GetCodeInt() int {
|
||||
switch v := r.Code.(type) {
|
||||
@@ -347,12 +426,16 @@ func (r *StartSignFlowResponse) GetCodeInt() int {
|
||||
|
||||
// StartSignFlow 发起签署流程
|
||||
func (y *YunYinSignPayService) StartSignFlow(ctx context.Context, accessToken, userId string, req *StartSignFlowRequest) (*StartSignFlowResult, error) {
|
||||
logx.Infof("[云印签API] StartSignFlow: 开始发起签署流程,订单号: %s, 模板代码: %s, 模板名称: %s, 用户ID: %s",
|
||||
req.SourceOrderCode, req.TemplateCode, req.TemplateName, userId)
|
||||
templateInfo := fmt.Sprintf("模板ID: %v", req.TemplateID)
|
||||
if req.TemplateID == nil && req.TemplateCode != "" {
|
||||
templateInfo = fmt.Sprintf("模板代码: %s", req.TemplateCode)
|
||||
}
|
||||
logx.Infof("[云印签API] StartSignFlow: 开始发起签署流程,%s, 流程类型: %d, 用户ID: %s",
|
||||
templateInfo, req.FlowType, userId)
|
||||
logx.Infof("[云印签API] StartSignFlow: 参与者列表,数量: %d", len(req.ParticipantList))
|
||||
for i, p := range req.ParticipantList {
|
||||
logx.Infof("[云印签API] StartSignFlow: 参与者[%d],标志: %s, 账号: %s, 姓名: %s, 类型: %d, 企业名: %s",
|
||||
i, p.ParticipantFlag, p.PsnAccount, p.PsnName, p.ParticipantType, p.ParticipantCorpName)
|
||||
logx.Infof("[云印签API] StartSignFlow: 参与者[%d],标志: %s, 账号: %s, 姓名: %s, 企业名: %s",
|
||||
i, p.ParticipantFlag, p.PsnAccount, p.PsnName, p.ParticipantCorpName)
|
||||
if p.Payee != nil {
|
||||
logx.Infof("[云印签API] StartSignFlow: 参与者[%d]收款信息,金额: %.2f, 优先级: %s", i, p.Payee.Amount, p.Payee.Priority)
|
||||
}
|
||||
@@ -416,16 +499,18 @@ func (y *YunYinSignPayService) StartSignFlow(ctx context.Context, accessToken, u
|
||||
return nil, fmt.Errorf("签署数据为空")
|
||||
}
|
||||
|
||||
flowIDStr := signFlowResp.Data.GetFlowIDString()
|
||||
logx.Infof("[云印签API] StartSignFlow: 签署数据,流程ID: %s, 流程状态: %d, 流程描述: %s, 参与者数量: %d",
|
||||
signFlowResp.Data.FlowID, signFlowResp.Data.FlowStatus, signFlowResp.Data.FlowDesc, len(signFlowResp.Data.ParticipantList))
|
||||
flowIDStr, signFlowResp.Data.FlowStatus, signFlowResp.Data.FlowDesc, len(signFlowResp.Data.ParticipantList))
|
||||
|
||||
// 从 participantList 中找到签署方2的 participantId
|
||||
var participantID2 string
|
||||
for i, participant := range signFlowResp.Data.ParticipantList {
|
||||
participantIDStr := participant.GetParticipantIDString()
|
||||
logx.Infof("[云印签API] StartSignFlow: 响应参与者[%d],标志: %s, 参与者ID: %s, 类型: %d",
|
||||
i, participant.ParticipantFlag, participant.ParticipantID, participant.ParticipantType)
|
||||
i, participant.ParticipantFlag, participantIDStr, participant.ParticipantType)
|
||||
if participant.ParticipantFlag == "签署方2" {
|
||||
participantID2 = participant.ParticipantID
|
||||
participantID2 = participantIDStr
|
||||
logx.Infof("[云印签API] StartSignFlow: 找到签署方2,参与者ID: %s", participantID2)
|
||||
break
|
||||
}
|
||||
@@ -436,13 +521,13 @@ func (y *YunYinSignPayService) StartSignFlow(ctx context.Context, accessToken, u
|
||||
return nil, fmt.Errorf("未找到签署方2的参与者ID")
|
||||
}
|
||||
|
||||
logx.Infof("[云印签API] StartSignFlow: 发起签署流程成功,订单号: %s, 流程ID: %s, 签署方2参与者ID: %s",
|
||||
req.SourceOrderCode, signFlowResp.Data.FlowID, participantID2)
|
||||
logx.Infof("[云印签API] StartSignFlow: 发起签署流程成功,流程ID: %s, 签署方2参与者ID: %s",
|
||||
flowIDStr, participantID2)
|
||||
|
||||
// 返回结果,包含签署方2的参与者ID和流程ID
|
||||
return &StartSignFlowResult{
|
||||
ParticipantID: participantID2,
|
||||
TaskID: signFlowResp.Data.FlowID, // 使用 flowId 作为 taskId
|
||||
TaskID: flowIDStr, // 使用 flowId 作为 taskId
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -454,15 +539,36 @@ type GetPaymentURLRequest struct {
|
||||
|
||||
// GetPaymentURLResponse 获取支付链接响应
|
||||
type GetPaymentURLResponse struct {
|
||||
Code int `json:"code"`
|
||||
Code interface{} `json:"code"` // 可能是字符串"200"或数字200
|
||||
Msg string `json:"msg"`
|
||||
Data *PaymentURLData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// GetCodeInt 获取 code 的 int 值
|
||||
func (r *GetPaymentURLResponse) GetCodeInt() int {
|
||||
switch v := r.Code.(type) {
|
||||
case int:
|
||||
return v
|
||||
case float64:
|
||||
return int(v)
|
||||
case string:
|
||||
if v == "200" {
|
||||
return 200
|
||||
}
|
||||
return 0
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// PaymentURLData 支付链接数据
|
||||
type PaymentURLData struct {
|
||||
PayURL string `json:"payUrl,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
PayURL string `json:"payUrl,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Path string `json:"path,omitempty"` // 支付宝小程序链接路径
|
||||
QrCode string `json:"qrCode,omitempty"` // 二维码链接
|
||||
AppSameFlag string `json:"appSameFlag,omitempty"` // 是否同应用标识
|
||||
AppID interface{} `json:"appId,omitempty"` // 应用ID
|
||||
}
|
||||
|
||||
// GetPaymentURL 获取支付链接
|
||||
@@ -519,10 +625,12 @@ func (y *YunYinSignPayService) GetPaymentURL(ctx context.Context, accessToken, u
|
||||
return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, string(body))
|
||||
}
|
||||
|
||||
logx.Infof("[云印签API] GetPaymentURL: 响应解析成功,Code: %d, Msg: %s", paymentURLResp.Code, paymentURLResp.Msg)
|
||||
logx.Infof("[云印签API] GetPaymentURL: 响应解析成功,Code: %v, Msg: %s", paymentURLResp.Code, paymentURLResp.Msg)
|
||||
|
||||
if paymentURLResp.Code != 0 {
|
||||
logx.Errorf("[云印签API] GetPaymentURL: API返回错误,Code: %d, Msg: %s", paymentURLResp.Code, paymentURLResp.Msg)
|
||||
// 检查响应码(可能是字符串"200"或数字200)
|
||||
codeInt := paymentURLResp.GetCodeInt()
|
||||
if codeInt != 200 {
|
||||
logx.Errorf("[云印签API] GetPaymentURL: API返回错误,Code: %v, Msg: %s", paymentURLResp.Code, paymentURLResp.Msg)
|
||||
return "", fmt.Errorf("获取支付链接失败: %s", paymentURLResp.Msg)
|
||||
}
|
||||
|
||||
@@ -531,11 +639,19 @@ func (y *YunYinSignPayService) GetPaymentURL(ctx context.Context, accessToken, u
|
||||
return "", fmt.Errorf("支付链接数据为空")
|
||||
}
|
||||
|
||||
// 优先返回 PayURL,如果没有则返回 URL
|
||||
// 优先返回 PayURL,如果没有则返回 URL,再没有则返回 Path(支付宝小程序链接)
|
||||
payURL := paymentURLResp.Data.PayURL
|
||||
if payURL == "" {
|
||||
payURL = paymentURLResp.Data.URL
|
||||
logx.Infof("[云印签API] GetPaymentURL: PayURL为空,使用URL字段: %s", payURL)
|
||||
if payURL != "" {
|
||||
logx.Infof("[云印签API] GetPaymentURL: PayURL为空,使用URL字段: %s", payURL)
|
||||
}
|
||||
}
|
||||
if payURL == "" {
|
||||
payURL = paymentURLResp.Data.Path
|
||||
if payURL != "" {
|
||||
logx.Infof("[云印签API] GetPaymentURL: PayURL和URL为空,使用Path字段: %s", payURL)
|
||||
}
|
||||
}
|
||||
|
||||
if payURL == "" {
|
||||
@@ -578,6 +694,7 @@ func (y *YunYinSignPayService) CreateYunYinSignPayOrder(ctx context.Context, use
|
||||
|
||||
// 2. 构建参与者列表
|
||||
logx.Infof("[云印签API] CreateYunYinSignPayOrder: 步骤3-构建参与者列表,订单号: %s", outTradeNo)
|
||||
// 使用传入的用户手机号和姓名
|
||||
participantList := []ParticipantInfo{
|
||||
// 签署方1:我方
|
||||
{
|
||||
@@ -585,23 +702,16 @@ func (y *YunYinSignPayService) CreateYunYinSignPayOrder(ctx context.Context, use
|
||||
PsnAccount: y.config.Mobile,
|
||||
PsnName: y.config.Name,
|
||||
ParticipantCorpName: y.config.CorpName,
|
||||
ParticipantType: 1, // 1表示企业
|
||||
},
|
||||
// 签署方2:用户(支付方)
|
||||
// 签署方2:用户(支付方)- 使用传入的用户手机号和姓名
|
||||
{
|
||||
ParticipantFlag: "签署方2",
|
||||
PsnAccount: userMobile,
|
||||
PsnName: func() string {
|
||||
if userName != "" {
|
||||
return userName
|
||||
}
|
||||
return "用户"
|
||||
}(),
|
||||
ParticipantType: 0, // 0表示个人
|
||||
ParticipantFlag: "签署方2",
|
||||
PsnAccount: userMobile, // 使用传入的用户手机号
|
||||
PsnName: userName, // 使用传入的用户姓名
|
||||
PayeeContractFlag: 1,
|
||||
Payee: &PayeeInfo{
|
||||
Amount: amount,
|
||||
Priority: "1",
|
||||
Amount: amount, // 金额根据订单动态
|
||||
Priority: "0", // 固定优先级为0
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -609,14 +719,24 @@ func (y *YunYinSignPayService) CreateYunYinSignPayOrder(ctx context.Context, use
|
||||
outTradeNo, y.config.Name, y.config.Mobile, userName, userMobile, amount)
|
||||
|
||||
// 3. 发起签署流程
|
||||
logx.Infof("[云印签API] CreateYunYinSignPayOrder: 步骤4-发起签署流程,订单号: %s, 模板代码: %s", outTradeNo, y.config.TemplateCode)
|
||||
logx.Infof("[云印签API] CreateYunYinSignPayOrder: 步骤4-发起签署流程,订单号: %s, 模板ID: %s", outTradeNo, y.config.TemplateID)
|
||||
// 将 TemplateID 字符串转换为 int64(API要求是 integer (int64))
|
||||
var templateID interface{}
|
||||
if y.config.TemplateID != "" {
|
||||
if id, err := strconv.ParseInt(y.config.TemplateID, 10, 64); err == nil {
|
||||
templateID = id
|
||||
logx.Infof("[云印签API] CreateYunYinSignPayOrder: 模板ID转换成功,订单号: %s, 模板ID: %d", outTradeNo, id)
|
||||
} else {
|
||||
// 如果转换失败,使用字符串
|
||||
templateID = y.config.TemplateID
|
||||
logx.Infof("[云印签API] CreateYunYinSignPayOrder: 模板ID使用字符串格式,订单号: %s, 模板ID: %s", outTradeNo, y.config.TemplateID)
|
||||
}
|
||||
}
|
||||
startSignFlowReq := &StartSignFlowRequest{
|
||||
TemplateCode: y.config.TemplateCode,
|
||||
TemplateName: y.config.TemplateName,
|
||||
AutoFill: 1,
|
||||
SourceOrderCode: outTradeNo,
|
||||
TemplateID: templateID, // 模板ID(int64类型)
|
||||
FlowType: 0, // 0-正常签署流程(签署方信息需准确完整)
|
||||
SourceOrderCode: outTradeNo, // 来源订单号
|
||||
ParticipantList: participantList,
|
||||
FillComponents: []FillComponent{}, // 可以根据需要填充
|
||||
}
|
||||
|
||||
signFlowData, err := y.StartSignFlow(ctx, accessToken, operationUserId, startSignFlowReq)
|
||||
|
||||
Reference in New Issue
Block a user