This commit is contained in:
Mrx
2026-05-19 17:21:16 +08:00
parent 8c301de7d2
commit 40f12ac1cf
3 changed files with 359 additions and 65 deletions

View File

@@ -8,10 +8,31 @@ import (
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/shujubao"
)
// QYGL4B2EItem 返回列表项
type QYGL4B2EItem struct {
PublishTime string `json:"publish_time"`
CaseType string `json:"case_type"`
ID int64 `json:"id"`
Department string `json:"department"`
TaxpayerName string `json:"taxpayer_name"`
}
// QYGL4B2EResponse 最终返回结构
type QYGL4B2EResponse struct {
Total int64 `json:"total"`
Items []QYGL4B2EItem `json:"items"`
}
// ProcessQYGL4B2ERequest QYGL4B2E API处理方法 - 税收违法
func ProcessQYGL4B2ERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
func ProcessQYGL4B2ERequest(
ctx context.Context,
params []byte,
deps *processors.ProcessorDependencies,
) ([]byte, error) {
var paramsDto dto.QYGL5A3CReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
@@ -21,39 +42,89 @@ func ProcessQYGL4B2ERequest(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// 设置默认值
// 默认值
pageSize := paramsDto.PageSize
if pageSize == 0 {
pageSize = int64(20)
pageSize = 20
}
pageNum := paramsDto.PageNum
if pageNum == 0 {
pageNum = int64(1)
pageNum = 1
}
// 构建API调用参数
apiParams := map[string]string{
"keyword": paramsDto.EntCode,
"pageSize": strconv.FormatInt(pageSize, 10),
"pageNum": strconv.FormatInt(pageNum, 10),
// 调用外部接口
reqParams := map[string]interface{}{
"key": "c67673dd2e92deb2d2ec91b87bb0a81c",
"creditCode": paramsDto.EntCode,
}
// 调用天眼查API - 税收违法
response, err := deps.TianYanChaService.CallAPI(ctx, "TaxContravention", apiParams)
apiPath := "/communication/personal/10233"
data, err := deps.ShujubaoService.CallAPI(ctx, apiPath, reqParams)
if err != nil {
return nil, convertTianYanChaError(err)
if errors.Is(err, shujubao.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
}
// 检查天眼查API调用是否成功
if !response.Success {
return nil, errors.Join(processors.ErrDatasource, errors.New(response.Message))
if errors.Is(err, shujubao.ErrQueryEmpty) {
return nil, errors.Join(processors.ErrNotFound, err)
}
// 返回天眼查响应数据
respBytes, err := json.Marshal(response.Data)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
// 原始返回结构处理 - data 是 map[string]interface{} 类型
dataMap, ok := data.(map[string]interface{})
if !ok {
return nil, errors.Join(processors.ErrSystem, errors.New("data不是map类型"))
}
// 提取 total
total := int64(0)
if v, ok := dataMap["total"]; ok {
switch val := v.(type) {
case float64:
total = int64(val)
case int:
total = int64(val)
case string:
total, _ = strconv.ParseInt(val, 10, 64)
}
}
// 提取 items 数组
srcItems := make([]map[string]interface{}, 0)
if v, ok := dataMap["items"]; ok {
if arr, ok := v.([]interface{}); ok {
for _, item := range arr {
if itemMap, ok := item.(map[string]interface{}); ok {
srcItems = append(srcItems, itemMap)
}
}
}
}
// 构造返回数据
resp := QYGL4B2EResponse{
Total: total,
Items: make([]QYGL4B2EItem, 0, len(srcItems)),
}
getString := func(item map[string]interface{}, key string) string {
if v, ok := item[key]; ok {
if str, ok := v.(string); ok {
return str
}
}
return ""
}
for i, v := range srcItems {
resp.Items = append(resp.Items, QYGL4B2EItem{
ID: int64(i + 1),
TaxpayerName: getString(v, "entityName"),
Department: getString(v, "belongDepartment"),
CaseType: getString(v, "caseType"),
PublishTime: getString(v, "illegalTime"),
})
}
return json.Marshal(resp)
}

View File

@@ -8,8 +8,59 @@ import (
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/shujubao"
)
/*
## 返回字段说明
| 返回值字段 | 字段类型 | 字段说明 | 备注 |
|------------|----------|----------|------|
| total | Number | int(11) | 总数 |
| items | Array | | |
| _child | Object | | |
| taxIdNumber | String | varchar(150) | 纳税人识别号 |
| newOwnTaxBalance | String | varchar(20) | 当前新发生欠税余额 |
| ownTaxAmount | String | varchar(50) | 欠税金额 |
| publishDate | String | 日期 | 发布时间 |
| ownTaxBalance | String | varchar(20) | 欠税余额 |
| type | String | varchar(10) | 税务类型 |
| personIdNumber | String | varchar(150) | 证件号码 |
| taxCategory | String | varchar(255) | 欠税税种 |
| taxpayerType | String | varchar(10) | 纳税人类型 |
| personIdName | String | varchar(50) | 法人证件名称 |
| name | String | varchar(255) | 纳税人名称 |
| location | String | varchar(150) | 经营地点 |
| department | String | varchar(200) | 税务机关 |
| regType | String | varchar(50) | 注册类型 |
| legalpersonName | String | varchar(150) | 法人或负责人名称 |
*/
// QYGL7D9AItem 返回列表项
type QYGL7D9AItem struct {
TaxIdNumber string `json:"taxIdNumber"`
NewOwnTaxBalance string `json:"newOwnTaxBalance"`
OwnTaxAmount string `json:"ownTaxAmount"`
PublishDate string `json:"publishDate"`
OwnTaxBalance string `json:"ownTaxBalance"`
Type string `json:"type"`
PersonIdNumber string `json:"personIdNumber"`
TaxCategory string `json:"taxCategory"`
TaxpayerType string `json:"taxpayerType"`
PersonIdName string `json:"personIdName"`
Name string `json:"name"`
Location string `json:"location"`
Department string `json:"department"`
RegType string `json:"regType"`
LegalpersonName string `json:"legalpersonName"`
}
// QYGL7D9AResponse 最终返回结构
type QYGL7D9AResponse struct {
Total int64 `json:"total"`
Items []QYGL7D9AItem `json:"items"`
}
// ProcessQYGL7D9ARequest QYGL7D9A API处理方法 - 欠税公告
func ProcessQYGL7D9ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.QYGL5A3CReq
@@ -21,39 +72,99 @@ func ProcessQYGL7D9ARequest(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// 设置默认值
// 默认值
pageSize := paramsDto.PageSize
if pageSize == 0 {
pageSize = int64(20)
pageSize = 20
}
pageNum := paramsDto.PageNum
if pageNum == 0 {
pageNum = int64(1)
pageNum = 1
}
// 构建API调用参数
apiParams := map[string]string{
"keyword": paramsDto.EntCode,
"pageSize": strconv.FormatInt(pageSize, 10),
"pageNum": strconv.FormatInt(pageNum, 10),
// 调用外部接口
reqParams := map[string]interface{}{
"key": "9ad1365cb0580863a239b0255649fb1a",
"creditCode": paramsDto.EntCode,
}
// 调用天眼查API - 欠税公告
response, err := deps.TianYanChaService.CallAPI(ctx, "OwnTax", apiParams)
apiPath := "/communication/personal/10235"
data, err := deps.ShujubaoService.CallAPI(ctx, apiPath, reqParams)
if err != nil {
return nil, convertTianYanChaError(err)
if errors.Is(err, shujubao.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
}
// 检查天眼查API调用是否成功
if !response.Success {
return nil, errors.Join(processors.ErrDatasource, errors.New(response.Message))
if errors.Is(err, shujubao.ErrQueryEmpty) {
return nil, errors.Join(processors.ErrNotFound, err)
}
// 返回天眼查响应数据
respBytes, err := json.Marshal(response.Data)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
// 原始返回结构处理 - data 是 map[string]interface{} 类型
dataMap, ok := data.(map[string]interface{})
if !ok {
return nil, errors.Join(processors.ErrSystem, errors.New("data不是map类型"))
}
// 提取 total
totalStr := ""
if v, ok := dataMap["total"]; ok {
if str, ok := v.(string); ok {
totalStr = str
}
}
// 提取 items 数组
srcItems := make([]map[string]interface{}, 0)
if v, ok := dataMap["items"]; ok {
if arr, ok := v.([]interface{}); ok {
for _, item := range arr {
if itemMap, ok := item.(map[string]interface{}); ok {
srcItems = append(srcItems, itemMap)
}
}
}
}
// 构造返回数据(缺失字段留空字符串)
resp := QYGL7D9AResponse{
Total: 0,
Items: make([]QYGL7D9AItem, 0, len(srcItems)),
}
getString := func(item map[string]interface{}, key string) string {
if v, ok := item[key]; ok {
if str, ok := v.(string); ok {
return str
}
}
return ""
}
for _, v := range srcItems {
resp.Items = append(resp.Items, QYGL7D9AItem{
TaxIdNumber: getString(v, "taxpayerCode"),
NewOwnTaxBalance: getString(v, "thisOwedAmount"),
OwnTaxAmount: getString(v, "totalOwedAmount"),
PublishDate: getString(v, "publishDate"),
OwnTaxBalance: getString(v, "beforeOwedAmount"),
Type: getString(v, "taxBureauType"),
PersonIdNumber: "",
TaxCategory: getString(v, "taxOwedType"),
TaxpayerType: "",
PersonIdName: "",
Name: getString(v, "entityName"),
Location: getString(v, "businessAddress"),
Department: getString(v, "taxBureauName"),
RegType: "",
LegalpersonName: getString(v, "legalPerson"),
})
}
// total 转 int64
if totalStr != "" {
resp.Total, _ = strconv.ParseInt(totalStr, 10, 64)
}
return json.Marshal(resp)
}

View File

@@ -8,8 +8,50 @@ import (
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/shujubao"
)
/*
## 返回字段说明
| 字段名 | 类型 | 说明 |
|--------|------|------|
| items | array | 融资历史记录列表,无记录时为空数组 |
| items[].round | string | 融资轮次 |
| items[].amount | string | 融资金额 |
| items[].date | string | 融资日期格式YYYY-MM-DD |
| items[].investors | array of string | 投资方列表 |
| items[].postValuation | string | 融资后估值 |
| items[].preValuation | string | 融资前估值 |
| items[].currency | string | 币种 |
| items[].intro | string | 项目简介 |
| items[].shareRatio | string | 持股比例 |
| total | integer | 符合条件的融资记录总数,无记录时为 0 |
| pageNum | integer | 当前页码 |
| pageSize | integer | 每页记录条数 |
*/
// QYGL8B4DItem 融资历史单项
type QYGL8B4DItem struct {
Round string `json:"round"`
Amount string `json:"amount"`
Date string `json:"date"`
Investors []string `json:"investors"`
PostValuation string `json:"postValuation"`
PreValuation string `json:"preValuation"`
Currency string `json:"currency"`
Intro string `json:"intro"`
ShareRatio string `json:"shareRatio"`
}
// QYGL8B4DResponse 融资历史返回结构
type QYGL8B4DResponse struct {
Items []QYGL8B4DItem `json:"items"`
Total int64 `json:"total"`
PageNum int64 `json:"pageNum"`
PageSize int64 `json:"pageSize"`
}
// ProcessQYGL8B4DRequest QYGL8B4D API处理方法 - 融资历史
func ProcessQYGL8B4DRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.QYGL8B4DReq
@@ -21,7 +63,7 @@ func ProcessQYGL8B4DRequest(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// 设置默认值
// 默认值
pageSize := paramsDto.PageSize
if pageSize == 0 {
pageSize = int64(20)
@@ -31,29 +73,99 @@ func ProcessQYGL8B4DRequest(ctx context.Context, params []byte, deps *processors
pageNum = int64(1)
}
// 构建API调用参数
apiParams := map[string]string{
"keyword": paramsDto.EntCode,
"pageSize": strconv.FormatInt(pageSize, 10),
"pageNum": strconv.FormatInt(pageNum, 10),
// 调用外部接口
reqParams := map[string]interface{}{
"key": "8887a17748d767b0a1f417171108873f",
"creditCode": paramsDto.EntCode,
}
// 调用天眼查API - 融资历史
response, err := deps.TianYanChaService.CallAPI(ctx, "FinancingHistory", apiParams)
apiPath := "/communication/personal/10435"
data, err := deps.ShujubaoService.CallAPI(ctx, apiPath, reqParams)
if err != nil {
return nil, convertTianYanChaError(err)
if errors.Is(err, shujubao.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
}
// 检查天眼查API调用是否成功
if !response.Success {
return nil, errors.Join(processors.ErrDatasource, errors.New(response.Message))
if errors.Is(err, shujubao.ErrQueryEmpty) {
return nil, errors.Join(processors.ErrNotFound, err)
}
// 返回天眼查响应数据
respBytes, err := json.Marshal(response.Data)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
// 原始返回结构处理 - data 是 map[string]interface{} 类型
dataMap, ok := data.(map[string]interface{})
if !ok {
return nil, errors.Join(processors.ErrSystem, errors.New("data不是map类型"))
}
// 提取 page 对象中的 totalRecords
totalRecords := ""
if page, ok := dataMap["page"].(map[string]interface{}); ok {
if v, ok := page["totalRecords"]; ok {
if str, ok := v.(string); ok {
totalRecords = str
}
}
}
// 提取 records 数组(不是 items
records := make([]map[string]interface{}, 0)
if v, ok := dataMap["records"]; ok {
if arr, ok := v.([]interface{}); ok {
for _, item := range arr {
if itemMap, ok := item.(map[string]interface{}); ok {
records = append(records, itemMap)
}
}
}
}
// 构造返回数据
resp := QYGL8B4DResponse{
Items: make([]QYGL8B4DItem, 0, len(records)),
PageNum: pageNum,
PageSize: pageSize,
}
for _, item := range records {
// 提取字段,使用类型断言
getString := func(key string) string {
if v, ok := item[key]; ok {
if str, ok := v.(string); ok {
return str
}
}
return ""
}
investAmount := getString("investAmount")
afterValuation := getString("afterInvestValuation")
// 计算持股比例:持股比例 = 本轮投资金额 / 投后估值 × 100%
shareRatio := ""
investAmountFloat, err1 := strconv.ParseFloat(investAmount, 64)
afterValuationFloat, err2 := strconv.ParseFloat(afterValuation, 64)
if err1 == nil && err2 == nil && afterValuationFloat > 0 {
ratio := investAmountFloat / afterValuationFloat * 100
shareRatio = strconv.FormatFloat(ratio, 'f', 2, 64) // 保留两位小数
}
resp.Items = append(resp.Items, QYGL8B4DItem{
Round: getString("financingRound"),
Amount: investAmount,
Date: getString("financingDate"),
Investors: []string{getString("financingRoundInvestor")},
PostValuation: afterValuation,
PreValuation: getString("beforeInvestValuation"),
Currency: getString("currency"),
Intro: "",
ShareRatio: shareRatio,
})
}
// total
if totalRecords != "" {
resp.Total, _ = strconv.ParseInt(totalRecords, 10, 64)
}
return json.Marshal(resp)
}