390 lines
10 KiB
Go
390 lines
10 KiB
Go
package api
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/tls"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"math/big"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/tjfoc/gmsm/sm2"
|
|
"github.com/tjfoc/gmsm/sm3"
|
|
)
|
|
|
|
// CompanyInfoService 公司信息查询服务
|
|
type CompanyInfoService struct {
|
|
httpClient *HTTPClient
|
|
userID string
|
|
privateKey string
|
|
}
|
|
|
|
// TaxHealthService 税务健康测评服务
|
|
type TaxHealthService struct {
|
|
httpClient *HTTPClient
|
|
userID string
|
|
privateKey string
|
|
}
|
|
|
|
// CompanyInfoRequest 公司信息查询请求
|
|
type CompanyInfoRequest struct {
|
|
Name string `json:"name"`
|
|
Apis []string `json:"apis"`
|
|
}
|
|
|
|
// CompanyInfoResponse 公司信息查询响应
|
|
type CompanyInfoResponse struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
Data map[string]interface{} `json:"data"`
|
|
}
|
|
|
|
// TaxEvalRequest 税务测评请求
|
|
type TaxEvalRequest struct {
|
|
ReqNo string `json:"req_no"`
|
|
Callback string `json:"callback,omitempty"`
|
|
Detail TaxEvalDetail `json:"detail"`
|
|
}
|
|
|
|
// TaxEvalDetail 税务测评详情
|
|
type TaxEvalDetail struct {
|
|
FileURL string `json:"file_url,omitempty"`
|
|
Data map[string]interface{} `json:"data,omitempty"`
|
|
CompanyName string `json:"company_name"`
|
|
Period string `json:"period"`
|
|
Year string `json:"year"`
|
|
IsVerify bool `json:"is_verify,omitempty"`
|
|
CIT float64 `json:"cit"`
|
|
VAT float64 `json:"vat"`
|
|
InputVAT float64 `json:"input_vat"`
|
|
OutputVAT float64 `json:"output_vat"`
|
|
PreCIT float64 `json:"pre_cit"`
|
|
PreVAT float64 `json:"pre_vat"`
|
|
PreInputVAT float64 `json:"pre_input_vat"`
|
|
PreOutputVAT float64 `json:"pre_output_vat"`
|
|
}
|
|
|
|
// TaxEvalResponse 税务测评响应
|
|
type TaxEvalResponse struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"msg"`
|
|
Data struct {
|
|
ReqNo string `json:"req_no"`
|
|
OrderNo string `json:"order_no"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
// TaxEvalQueryResponse 查询税务测评结果响应
|
|
type TaxEvalQueryResponse struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"msg"`
|
|
Data struct {
|
|
Status int `json:"status"`
|
|
Detail struct {
|
|
Files []string `json:"files"`
|
|
Error string `json:"error"`
|
|
} `json:"detail"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
// NewCompanyInfoService 创建公司信息查询服务
|
|
func NewCompanyInfoService(userID, privateKey string) *CompanyInfoService {
|
|
tr := &http.Transport{
|
|
TLSClientConfig: &tls.Config{
|
|
InsecureSkipVerify: true,
|
|
},
|
|
}
|
|
client := &http.Client{
|
|
Transport: tr,
|
|
Timeout: 30 * time.Second,
|
|
}
|
|
|
|
httpClient := &HTTPClient{Client: client}
|
|
|
|
return &CompanyInfoService{
|
|
httpClient: httpClient,
|
|
userID: userID,
|
|
privateKey: privateKey,
|
|
}
|
|
}
|
|
|
|
// NewTaxHealthService 创建税务健康测评服务
|
|
func NewTaxHealthService(userID, privateKey string) *TaxHealthService {
|
|
tr := &http.Transport{
|
|
TLSClientConfig: &tls.Config{
|
|
InsecureSkipVerify: true,
|
|
},
|
|
}
|
|
client := &http.Client{
|
|
Transport: tr,
|
|
Timeout: 30 * time.Second,
|
|
}
|
|
|
|
httpClient := &HTTPClient{Client: client}
|
|
|
|
return &TaxHealthService{
|
|
httpClient: httpClient,
|
|
userID: userID,
|
|
privateKey: privateKey,
|
|
}
|
|
}
|
|
|
|
// GetCompanyInfo 查询公司信息
|
|
func (s *CompanyInfoService) GetCompanyInfo(companyName string, apis []string) (*CompanyInfoResponse, error) {
|
|
// 生成随机数和时间戳
|
|
r, _ := rand.Int(rand.Reader, big.NewInt(10000))
|
|
nonce := strconv.FormatInt(time.Now().UnixNano(), 36) + strconv.FormatInt(r.Int64(), 10)
|
|
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
|
|
|
// 构建查询参数
|
|
params := url.Values{}
|
|
params.Set("name", companyName)
|
|
params.Set("api", joinAPIParams(apis))
|
|
|
|
apiURL := "https://a.cmdp.cn/cmds/v1/company/info-rest/custom?" + params.Encode()
|
|
|
|
// 生成签名
|
|
signData := s.userID + timestamp + nonce + apiURL
|
|
signature, err := s.generateSignature([]byte(signData))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("生成签名失败: %v", err)
|
|
}
|
|
|
|
// 设置请求头
|
|
headers := map[string]string{
|
|
"Accept": "application/json",
|
|
"x-gi-user-id": s.userID,
|
|
"x-gi-user-sig": signature,
|
|
"x-gi-nonce": nonce,
|
|
"x-gi-timestamp": timestamp,
|
|
}
|
|
|
|
// 发送GET请求
|
|
response, err := s.httpClient.Get(apiURL, headers)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("发送请求失败: %v", err)
|
|
}
|
|
|
|
var result CompanyInfoResponse
|
|
err = json.Unmarshal(response, &result)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("解析响应失败: %v", err)
|
|
}
|
|
|
|
return &result, nil
|
|
}
|
|
|
|
// EvaluateTaxHealth 执行税务健康测评
|
|
func (s *TaxHealthService) EvaluateTaxHealth(request TaxEvalRequest) (*TaxEvalResponse, error) {
|
|
// 生成随机数和时间戳
|
|
r, _ := rand.Int(rand.Reader, big.NewInt(10000))
|
|
nonce := strconv.FormatInt(time.Now().UnixNano(), 36) + strconv.FormatInt(r.Int64(), 10)
|
|
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
|
|
|
apiURL := "https://api.cmdp.cn/v1/eval/tax-risk"
|
|
|
|
// 序列化请求体
|
|
jsonData, err := json.Marshal(request)
|
|
fmt.Println(string(jsonData))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("序列化请求体失败: %v", err)
|
|
}
|
|
|
|
// 生成签名
|
|
signData := s.userID + timestamp + nonce + apiURL + string(jsonData)
|
|
signature, err := s.generateSignature([]byte(signData))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("生成签名失败: %v", err)
|
|
}
|
|
|
|
// 设置请求头
|
|
headers := map[string]string{
|
|
"Content-Type": "application/json",
|
|
"Accept": "application/json",
|
|
"x-gi-user-id": s.userID,
|
|
"x-gi-user-sig": signature,
|
|
"x-gi-nonce": nonce,
|
|
"x-gi-timestamp": timestamp,
|
|
}
|
|
// 发送POST请求
|
|
response, err := s.httpClient.Post(apiURL, jsonData, "application/json", headers)
|
|
fmt.Println(string(response))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("发送请求失败: %v", err)
|
|
}
|
|
var result TaxEvalResponse
|
|
err = json.Unmarshal(response, &result)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("解析响应失败: %v", err)
|
|
}
|
|
|
|
return &result, nil
|
|
}
|
|
|
|
// QueryTaxEvalResult 查询税务测评结果
|
|
func (s *TaxHealthService) QueryTaxEvalResult(orderNo string) (*TaxEvalQueryResponse, error) {
|
|
// 生成随机数和时间戳
|
|
r, _ := rand.Int(rand.Reader, big.NewInt(10000))
|
|
nonce := strconv.FormatInt(time.Now().UnixNano(), 36) + strconv.FormatInt(r.Int64(), 10)
|
|
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
|
|
|
apiURL := fmt.Sprintf("https://api.cmdp.cn/v1/eval/order/%s", orderNo)
|
|
|
|
// 生成签名
|
|
signData := s.userID + timestamp + nonce + apiURL
|
|
signature, err := s.generateSignature([]byte(signData))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("生成签名失败: %v", err)
|
|
}
|
|
|
|
// 设置请求头
|
|
headers := map[string]string{
|
|
"Accept": "application/json",
|
|
"x-gi-user-id": s.userID,
|
|
"x-gi-user-sig": signature,
|
|
"x-gi-nonce": nonce,
|
|
"x-gi-timestamp": timestamp,
|
|
}
|
|
|
|
// 发送GET请求
|
|
response, err := s.httpClient.Get(apiURL, headers)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("发送请求失败: %v", err)
|
|
}
|
|
|
|
var result TaxEvalQueryResponse
|
|
err = json.Unmarshal(response, &result)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("解析响应失败: %v", err)
|
|
}
|
|
|
|
return &result, nil
|
|
}
|
|
|
|
// generateSignature 生成签名
|
|
func (s *CompanyInfoService) generateSignature(plainText []byte) (string, error) {
|
|
privateKey, err := parsePrivateKeyFromHex(s.privateKey)
|
|
if err != nil {
|
|
return "", fmt.Errorf("解析私钥失败: %v", err)
|
|
}
|
|
|
|
digest := sm3.Sm3Sum(plainText)
|
|
signature, err := privateKey.Sign(rand.Reader, digest, nil)
|
|
if err != nil {
|
|
return "", fmt.Errorf("签名失败: %v", err)
|
|
}
|
|
|
|
return base64.StdEncoding.EncodeToString(signature), nil
|
|
}
|
|
|
|
// generateSignature 生成签名
|
|
func (s *TaxHealthService) generateSignature(plainText []byte) (string, error) {
|
|
privateKey, err := parsePrivateKeyFromHex(s.privateKey)
|
|
if err != nil {
|
|
return "", fmt.Errorf("解析私钥失败: %v", err)
|
|
}
|
|
|
|
digest := sm3.Sm3Sum(plainText)
|
|
signature, err := privateKey.Sign(rand.Reader, digest, nil)
|
|
if err != nil {
|
|
return "", fmt.Errorf("签名失败: %v", err)
|
|
}
|
|
|
|
return base64.StdEncoding.EncodeToString(signature), nil
|
|
}
|
|
|
|
// parsePrivateKeyFromHex 从十六进制字符串解析私钥
|
|
func parsePrivateKeyFromHex(privateKeyHex string) (*sm2.PrivateKey, error) {
|
|
privateKeyBytes, err := hex.DecodeString(privateKeyHex)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("解码私钥失败: %v", err)
|
|
}
|
|
|
|
d := new(big.Int).SetBytes(privateKeyBytes)
|
|
|
|
privateKey := &sm2.PrivateKey{
|
|
PublicKey: sm2.PublicKey{
|
|
Curve: sm2.P256Sm2(),
|
|
},
|
|
D: d,
|
|
}
|
|
|
|
privateKey.PublicKey.X, privateKey.PublicKey.Y = privateKey.PublicKey.Curve.ScalarBaseMult(d.Bytes())
|
|
|
|
return privateKey, nil
|
|
}
|
|
|
|
// joinAPIParams 连接API参数
|
|
func joinAPIParams(params []string) string {
|
|
result := ""
|
|
for i, param := range params {
|
|
if i > 0 {
|
|
result += ","
|
|
}
|
|
result += param
|
|
}
|
|
return result
|
|
}
|
|
|
|
// 使用示例
|
|
func ExampleUsage() {
|
|
// 替换为实际的用户ID和私钥
|
|
userID := "your_user_id"
|
|
privateKey := "your_private_key_hex"
|
|
|
|
// 创建公司信息查询服务
|
|
companyService := NewCompanyInfoService(userID, privateKey)
|
|
|
|
// 查询公司信息
|
|
companyInfo, err := companyService.GetCompanyInfo("深圳市致远速联信息技术有限公司", []string{"p_info", "p_biddings_all"})
|
|
if err != nil {
|
|
fmt.Printf("查询公司信息失败: %v\n", err)
|
|
} else {
|
|
fmt.Printf("公司信息查询结果: %+v\n", companyInfo)
|
|
}
|
|
|
|
// 创建税务健康测评服务
|
|
taxService := NewTaxHealthService(userID, privateKey)
|
|
|
|
// 准备税务测评请求数据
|
|
request := TaxEvalRequest{
|
|
ReqNo: "REQ001",
|
|
Detail: TaxEvalDetail{
|
|
CompanyName: "深圳市致远速联信息技术有限公司",
|
|
Period: "年度",
|
|
Year: "2024",
|
|
CIT: 100.0,
|
|
VAT: 50.0,
|
|
InputVAT: 30.0,
|
|
OutputVAT: 80.0,
|
|
PreCIT: 90.0,
|
|
PreVAT: 45.0,
|
|
PreInputVAT: 25.0,
|
|
PreOutputVAT: 70.0,
|
|
},
|
|
}
|
|
|
|
// 执行税务测评
|
|
evalResult, err := taxService.EvaluateTaxHealth(request)
|
|
if err != nil {
|
|
fmt.Printf("税务测评失败: %v\n", err)
|
|
} else {
|
|
fmt.Printf("税务测评提交结果: %+v\n", evalResult)
|
|
|
|
// 查询测评结果
|
|
if evalResult.Data.OrderNo != "" {
|
|
result, err := taxService.QueryTaxEvalResult(evalResult.Data.OrderNo)
|
|
if err != nil {
|
|
fmt.Printf("查询测评结果失败: %v\n", err)
|
|
} else {
|
|
fmt.Printf("测评结果: %+v\n", result)
|
|
}
|
|
}
|
|
}
|
|
}
|