This commit is contained in:
2026-04-27 11:56:41 +08:00
parent a10604178d
commit cef9612526
11 changed files with 298 additions and 86 deletions

View File

@@ -716,7 +716,7 @@ func (s *CertificationApplicationServiceImpl) HandleEsignCallback(
}
// 生成合同
err = s.generateAndAddContractFile(txCtx, cert, record.CompanyName, record.LegalPersonName, record.UnifiedSocialCode, record.EnterpriseAddress, record.LegalPersonPhone, record.LegalPersonID)
err = s.generateAndAddContractFile(txCtx, cert, record.CompanyName, record.UnifiedSocialCode, record.EnterpriseAddress, pickAuthorizedRepName(record, record.LegalPersonName))
if err != nil {
return err
}
@@ -1351,7 +1351,7 @@ func (s *CertificationApplicationServiceImpl) completeEnterpriseVerification(
}
// 生成合同
err = s.generateAndAddContractFile(ctx, cert, record.CompanyName, record.LegalPersonName, record.UnifiedSocialCode, record.EnterpriseAddress, record.LegalPersonPhone, record.LegalPersonID)
err = s.generateAndAddContractFile(ctx, cert, record.CompanyName, record.UnifiedSocialCode, record.EnterpriseAddress, pickAuthorizedRepName(record, record.LegalPersonName))
if err != nil {
return err
}
@@ -1368,32 +1368,33 @@ func (s *CertificationApplicationServiceImpl) completeEnterpriseVerification(
return nil
}
// pickAuthorizedRepName 合同模板「客户授权代表」: 优先企业提交记录中的授权代表, 否则为法定代表人
func pickAuthorizedRepName(record *entities.EnterpriseInfoSubmitRecord, legalPersonName string) string {
if record != nil && strings.TrimSpace(record.AuthorizedRepName) != "" {
return strings.TrimSpace(record.AuthorizedRepName)
}
return legalPersonName
}
// generateAndAddContractFile 生成并添加合同文件的公共方法
func (s *CertificationApplicationServiceImpl) generateAndAddContractFile(
ctx context.Context,
cert *entities.Certification,
companyName string,
legalPersonName string,
unifiedSocialCode string,
enterpriseAddress string,
legalPersonPhone string,
legalPersonID string,
authorizedRepName string,
) error {
s.logger.Info("合同生成-步骤1-开始填充合同模板",
zap.String("user_id", cert.UserID),
zap.String("company_name", companyName))
// 控件 key 与 e 签宝合同模板中控件名一致(新合同)
fileComponent := map[string]string{
"YFCompanyName": companyName,
"YFCompanyName2": companyName,
"YFLegalPersonName": legalPersonName,
"YFLegalPersonName2": legalPersonName,
"YFUnifiedSocialCode": unifiedSocialCode,
"YFEnterpriseAddress": enterpriseAddress,
"YFContactPerson": legalPersonName,
"YFMobile": legalPersonPhone,
"SignDate": time.Now().Format("2006年01月02日"),
"SignDate2": time.Now().Format("2006年01月02日"),
"SignDate3": time.Now().Format("2006年01月02日"),
"jfqym": companyName,
"jfqym2": companyName,
"jfsqdb": authorizedRepName,
"jftyshxydm": unifiedSocialCode,
"jflxdz": enterpriseAddress,
}
fillTemplateResp, err := s.esignClient.FillTemplate(fileComponent)
if err != nil {
@@ -1423,8 +1424,12 @@ func (s *CertificationApplicationServiceImpl) updateContractFile(ctx context.Con
return fmt.Errorf("获取企业信息失败: %w", err)
}
ei := enterpriseInfo.EnterpriseInfo
submitRec, _ := s.enterpriseInfoSubmitRecordRepo.FindLatestByUserID(ctx, cert.UserID)
authRep := pickAuthorizedRepName(submitRec, ei.LegalPersonName)
// 生成合同
err = s.generateAndAddContractFile(ctx, cert, enterpriseInfo.EnterpriseInfo.CompanyName, enterpriseInfo.EnterpriseInfo.LegalPersonName, enterpriseInfo.EnterpriseInfo.UnifiedSocialCode, enterpriseInfo.EnterpriseInfo.EnterpriseAddress, enterpriseInfo.EnterpriseInfo.LegalPersonPhone, enterpriseInfo.EnterpriseInfo.LegalPersonID)
err = s.generateAndAddContractFile(ctx, cert, ei.CompanyName, ei.UnifiedSocialCode, ei.EnterpriseAddress, authRep)
if err != nil {
return err
}

View File

@@ -265,7 +265,7 @@ type SMSConfig struct {
type TencentSMSConfig struct {
SecretId string `mapstructure:"secret_id"`
SecretKey string `mapstructure:"secret_key"`
Region string `mapstructure:"region"` // 如 ap-guangzhou可空则默认 ap-guangzhou
Region string `mapstructure:"region"` // 如 ap-guangzhou可空则默认 ap-guangzhou
Endpoint string `mapstructure:"endpoint"` // 可空,默认 sms.tencentcloudapi.com
SmsSdkAppId string `mapstructure:"sms_sdk_app_id"` // SdkAppId
SignName string `mapstructure:"sign_name"`
@@ -494,12 +494,17 @@ type MuziLevelFileConfig struct {
// AliPayConfig 支付宝配置
type AliPayConfig struct {
AppID string `mapstructure:"app_id"`
PrivateKey string `mapstructure:"private_key"`
AlipayPublicKey string `mapstructure:"alipay_public_key"`
IsProduction bool `mapstructure:"is_production"`
NotifyURL string `mapstructure:"notify_url"`
ReturnURL string `mapstructure:"return_url"`
Mode string `mapstructure:"mode"`
AppID string `mapstructure:"app_id"`
PrivateKey string `mapstructure:"private_key"`
AlipayPublicKey string `mapstructure:"alipay_public_key"`
AppCertPath string `mapstructure:"app_cert_path"`
AlipayCertPath string `mapstructure:"alipay_cert_path"`
AlipayRootCertPath string `mapstructure:"alipay_root_cert_path"`
EncryptKey string `mapstructure:"encrypt_key"`
IsProduction bool `mapstructure:"is_production"`
NotifyURL string `mapstructure:"notify_url"`
ReturnURL string `mapstructure:"return_url"`
}
// WxpayConfig 微信支付配置

View File

@@ -319,12 +319,17 @@ func NewContainer() *Container {
// 支付宝支付服务
func(cfg *config.Config) *payment.AliPayService {
config := payment.AlipayConfig{
AppID: cfg.AliPay.AppID,
PrivateKey: cfg.AliPay.PrivateKey,
AlipayPublicKey: cfg.AliPay.AlipayPublicKey,
IsProduction: cfg.AliPay.IsProduction,
NotifyUrl: cfg.AliPay.NotifyURL,
ReturnURL: cfg.AliPay.ReturnURL,
Mode: cfg.AliPay.Mode,
AppID: cfg.AliPay.AppID,
PrivateKey: cfg.AliPay.PrivateKey,
AlipayPublicKey: cfg.AliPay.AlipayPublicKey,
AppCertPath: cfg.AliPay.AppCertPath,
AlipayCertPath: cfg.AliPay.AlipayCertPath,
AlipayRootCertPath: cfg.AliPay.AlipayRootCertPath,
EncryptKey: cfg.AliPay.EncryptKey,
IsProduction: cfg.AliPay.IsProduction,
NotifyUrl: cfg.AliPay.NotifyURL,
ReturnURL: cfg.AliPay.ReturnURL,
}
return payment.NewAliPayService(config)
},

View File

@@ -28,13 +28,13 @@ func (s *SignFlowService) UpdateConfig(config *Config) {
// 创建包含多个签署人的签署流程,支持自动盖章和手动签署
func (s *SignFlowService) Create(req *CreateSignFlowRequest) (string, error) {
fmt.Println("开始创建签署流程...")
fmt.Println("(将创建包含甲方自动盖章和乙方手动签署的流程)")
fmt.Println("(将创建包含甲方手动签署和乙方自动盖章的流程)")
// 构建甲方签署人信息(自动盖章
partyASigner := s.buildPartyASigner(req.FileID)
// 构建甲方签署人信息(手动签署
partyASigner := s.buildPartyASigner(req.FileID, req.SignerAccount, req.SignerName, req.TransactorPhone, req.TransactorName, req.TransactorIDCardNum)
// 构建乙方签署人信息(手动签署
partyBSigner := s.buildPartyBSigner(req.FileID, req.SignerAccount, req.SignerName, req.TransactorPhone, req.TransactorName, req.TransactorIDCardNum)
// 构建乙方签署人信息(自动盖章
partyBSigner := s.buildPartyBSigner(req.FileID)
signers := []SignerInfo{partyASigner, partyBSigner}
@@ -128,34 +128,11 @@ func (s *SignFlowService) GetSignURL(signFlowID, psnAccount, orgName string) (st
return response.Data.Url, response.Data.ShortUrl, nil
}
// buildPartyASigner 构建甲方签署人信息(自动盖章
func (s *SignFlowService) buildPartyASigner(fileID string) SignerInfo {
return SignerInfo{
SignConfig: &SignConfig{SignOrder: 1},
SignerType: SignerTypeOrg,
SignFields: []SignField{
{
CustomBizNum: "甲方签章",
FileId: fileID,
NormalSignFieldConfig: &NormalSignFieldConfig{
AutoSign: true,
SignFieldStyle: SignFieldStyleNormal,
SignFieldPosition: &SignFieldPosition{
PositionPage: "8",
PositionX: 200,
PositionY: 430,
},
},
},
},
}
}
// buildPartyBSigner 构建乙方签署人信息(手动签署)
func (s *SignFlowService) buildPartyBSigner(fileID, signerAccount, signerName, transactorPhone, transactorName, transactorIDCardNum string) SignerInfo {
// buildPartyASigner 构建甲方签署人信息(手动签署
func (s *SignFlowService) buildPartyASigner(fileID, signerAccount, signerName, transactorPhone, transactorName, transactorIDCardNum string) SignerInfo {
return SignerInfo{
SignConfig: &SignConfig{
SignOrder: 2,
SignOrder: 1,
},
AuthConfig: &AuthConfig{
PsnAvailableAuthModes: []string{AuthModeMobile3},
@@ -182,15 +159,15 @@ func (s *SignFlowService) buildPartyBSigner(fileID, signerAccount, signerName, t
},
SignFields: []SignField{
{
CustomBizNum: "方签章",
CustomBizNum: "方签章",
FileId: fileID,
NormalSignFieldConfig: &NormalSignFieldConfig{
AutoSign: false,
SignFieldStyle: SignFieldStyleNormal,
SignFieldPosition: &SignFieldPosition{
PositionPage: "8",
PositionX: 450,
PositionY: 430,
PositionPage: "10",
PositionX: 165,
PositionY: 197,
},
OrgSealBizTypes: "PUBLIC",
},
@@ -199,6 +176,41 @@ func (s *SignFlowService) buildPartyBSigner(fileID, signerAccount, signerName, t
}
}
// buildPartyBSigner 构建乙方签署人信息(自动盖章)
func (s *SignFlowService) buildPartyBSigner(fileID string) SignerInfo {
return SignerInfo{
SignConfig: &SignConfig{SignOrder: 2},
SignerType: SignerTypeOrg,
SignFields: []SignField{
{
CustomBizNum: "乙方签章",
FileId: fileID,
NormalSignFieldConfig: &NormalSignFieldConfig{
AutoSign: true,
SignFieldStyle: SignFieldStyleNormal,
SignFieldPosition: &SignFieldPosition{
PositionPage: "10",
PositionX: 403,
PositionY: 197,
},
},
},
{
CustomBizNum: "乙方骑缝章", // 建议设唯一标识,便于调试
FileId:fileID,
NormalSignFieldConfig: &NormalSignFieldConfig{
AutoSign: true, // 骑缝章也支持自动签署
SignFieldStyle: SignFieldStyleSeam, // 必须为 2Edges
SignFieldPosition: &SignFieldPosition{
AcrossPageMode: "ALL", // 覆盖全部页面(推荐)
PositionY:694.0, // 您指定的 Y 坐标float64
},
},
},
},
}
}
// buildSignFlowConfig 构建签署流程配置
func (s *SignFlowService) buildSignFlowConfig() SignFlowConfig {
return SignFlowConfig{

View File

@@ -170,6 +170,7 @@ type NormalSignFieldConfig struct {
// SignFieldPosition 签署区位置
type SignFieldPosition struct {
AcrossPageMode string `json:"acrossPageMode"` // 跨页模式ALL-全部页面
PositionPage string `json:"positionPage"` // 页码
PositionX float64 `json:"positionX"` // X坐标
PositionY float64 `json:"positionY"` // Y坐标

View File

@@ -15,12 +15,17 @@ import (
)
type AlipayConfig struct {
AppID string
PrivateKey string
AlipayPublicKey string
IsProduction bool
NotifyUrl string
ReturnURL string // 同步回调地址
AppID string
Mode string
PrivateKey string
AlipayPublicKey string
AppCertPath string
AlipayCertPath string
AlipayRootCertPath string
EncryptKey string
IsProduction bool
NotifyUrl string
ReturnURL string // 同步回调地址
}
type AliPayService struct {
config AlipayConfig
@@ -34,11 +39,30 @@ func NewAliPayService(config AlipayConfig) *AliPayService {
panic(fmt.Sprintf("创建支付宝客户端失败: %v", err))
}
// 加载支付宝公钥
err = client.LoadAliPayPublicKey(config.AlipayPublicKey)
if err != nil {
panic(fmt.Sprintf("加载支付宝公钥失败: %v", err))
if config.Mode == "cert" {
// 证书模式:加载应用公钥证书、支付宝公钥证书、支付宝根证书
if err = client.LoadAppCertPublicKeyFromFile(config.AppCertPath); err != nil {
panic(fmt.Sprintf("加载应用公钥证书失败: %v", err))
}
if err = client.LoadAlipayCertPublicKeyFromFile(config.AlipayCertPath); err != nil {
panic(fmt.Sprintf("加载支付宝公钥证书失败: %v", err))
}
if err = client.LoadAliPayRootCertFromFile(config.AlipayRootCertPath); err != nil {
panic(fmt.Sprintf("加载根证书失败: %v", err))
}
} else {
// 默认密钥模式:加载支付宝公钥
err = client.LoadAliPayPublicKey(config.AlipayPublicKey)
if err != nil {
panic(fmt.Sprintf("加载支付宝公钥失败: %v", err))
}
}
// 可选开启支付宝接口内容加密AES
if config.EncryptKey != "" {
client.SetEncryptKey(config.EncryptKey)
}
return &AliPayService{
config: config,
AlipayClient: client,