Merge branch 'main' of http://1.117.67.95:3000/team/tyapi-server
This commit is contained in:
@@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
// ProcessQYGLJ1U9Request 企业全景报告处理器:并发调用企业全量(QYGLUY3S)、股权全景(QYGLJ0Q1)、司法涉诉(QYGL5S1I)、
|
||||
// 企业年报(QYGLDJ12)、税收违法(QYGL8848)、欠税公告(QYGL7D9A)。
|
||||
// 企业年报(QYGLDJ12)、税收违法(QYGL8848)、欠税公告(QYGL7D9A)、进出口信用(QYGLDJ33)。
|
||||
// 单路失败、查无、解析失败时该路按空数据处理并继续合并;仅当合并后的报告仍无任何可展示的企业要素时返回查询为空。
|
||||
func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||
// 复用 QYGLUY3S 的入参结构:企业名称/注册号/统一社会信用代码
|
||||
@@ -36,7 +36,7 @@ func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors
|
||||
data map[string]interface{}
|
||||
err error
|
||||
}
|
||||
resultsCh := make(chan apiResult, 6)
|
||||
resultsCh := make(chan apiResult, 7)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
call := func(key string, req interface{}, fn func(context.Context, []byte, *processors.ProcessorDependencies) ([]byte, error)) {
|
||||
@@ -56,7 +56,7 @@ func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors
|
||||
var m map[string]interface{}
|
||||
var uerr error
|
||||
// 根节点可能是数组或非对象,与欠税接口一致用宽松解析
|
||||
if key == "taxArrears" || key == "annualReport" || key == "taxViolation" {
|
||||
if key == "taxArrears" || key == "annualReport" || key == "taxViolation" || key == "customsCredit" {
|
||||
m, uerr = unmarshalToReportMap(resp)
|
||||
} else {
|
||||
uerr = json.Unmarshal(resp, &m)
|
||||
@@ -105,6 +105,12 @@ func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors
|
||||
"page_num": 1,
|
||||
}, ProcessQYGL7D9ARequest)
|
||||
|
||||
// 企业进出口信用核查(QYGLDJ33)
|
||||
call("customsCredit", map[string]interface{}{
|
||||
"ent_name": p.EntName,
|
||||
"ent_code": p.EntCode,
|
||||
}, ProcessQYGLDJ33Request)
|
||||
|
||||
wg.Wait()
|
||||
close(resultsCh)
|
||||
|
||||
@@ -114,6 +120,7 @@ func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors
|
||||
annualReport := map[string]interface{}{}
|
||||
taxViolation := map[string]interface{}{}
|
||||
taxArrears := map[string]interface{}{}
|
||||
customsCredit := map[string]interface{}{}
|
||||
for r := range resultsCh {
|
||||
if r.err != nil || r.data == nil {
|
||||
continue
|
||||
@@ -131,11 +138,13 @@ func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors
|
||||
taxViolation = r.data
|
||||
case "taxArrears":
|
||||
taxArrears = r.data
|
||||
case "customsCredit":
|
||||
customsCredit = r.data
|
||||
}
|
||||
}
|
||||
|
||||
// 复用构建逻辑生成企业报告结构(含年报 / 税收违法 / 欠税公告的转化结果)
|
||||
report := buildReport(jiguang, judicial, equity, annualReport, taxViolation, taxArrears)
|
||||
// 复用构建逻辑生成企业报告结构(含年报 / 税收违法 / 欠税公告 / 进出口信用的转化结果)
|
||||
report := buildReport(jiguang, judicial, equity, annualReport, taxViolation, taxArrears, customsCredit)
|
||||
if !qyglJ1U9ReportHasSubstantiveData(report) {
|
||||
return nil, errors.Join(processors.ErrNotFound, errors.New("未查询到可用于生成报告的企业数据"))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package qygl
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -8,7 +9,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func buildReport(jiguang, judicial, equity, annualRaw, taxViolationRaw, taxArrearsRaw map[string]interface{}) map[string]interface{} {
|
||||
func buildReport(jiguang, judicial, equity, annualRaw, taxViolationRaw, taxArrearsRaw, customsCreditRaw map[string]interface{}) map[string]interface{} {
|
||||
report := make(map[string]interface{})
|
||||
report["reportTime"] = time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
@@ -54,10 +55,11 @@ func buildReport(jiguang, judicial, equity, annualRaw, taxViolationRaw, taxArrea
|
||||
report["basicList"] = bl
|
||||
}
|
||||
|
||||
// QYGLDJ12 企业年报 / QYGL8848 税收违法 / QYGL7D9A 欠税公告(转化后的前端友好结构)
|
||||
// QYGLDJ12 企业年报 / QYGL8848 税收违法 / QYGL7D9A 欠税公告 / QYGLDJ33 进出口信用(转化后的前端友好结构)
|
||||
report["annualReports"] = annualReports
|
||||
report["taxViolations"] = mapTaxViolations(taxViolationRaw)
|
||||
report["ownTaxNotices"] = mapOwnTaxNotices(taxArrearsRaw)
|
||||
report["customsCredit"] = mapCustomsCredit(customsCreditRaw)
|
||||
applyQYGLJ1U9ReportFieldDefaults(report)
|
||||
return report
|
||||
}
|
||||
@@ -105,6 +107,7 @@ func applyQYGLJ1U9ReportFieldDefaults(report map[string]interface{}) {
|
||||
|
||||
report["taxViolations"] = mergeTaxViolationsDefaults(report["taxViolations"])
|
||||
report["ownTaxNotices"] = mergeOwnTaxNoticesDefaults(report["ownTaxNotices"])
|
||||
report["customsCredit"] = mergeCustomsCreditDefaults(report["customsCredit"])
|
||||
|
||||
if ro, ok := report["riskOverview"].(map[string]interface{}); ok {
|
||||
report["riskOverview"] = mergeRiskOverviewDefaults(ro)
|
||||
@@ -651,6 +654,14 @@ func qyglJ1U9ReportHasSubstantiveData(report map[string]interface{}) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if cc, ok := report["customsCredit"].(map[string]interface{}); ok {
|
||||
if intFromAny(cc["total"]) > 0 {
|
||||
return true
|
||||
}
|
||||
if items, ok := cc["items"].([]interface{}); ok && len(items) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if br, ok := report["branches"].([]interface{}); ok && len(br) > 0 {
|
||||
return true
|
||||
}
|
||||
@@ -733,7 +744,7 @@ func jiguangWithoutYearReportTables(jiguang map[string]interface{}) map[string]i
|
||||
|
||||
// BuildReportFromRawSources 供开发/测试:将各处理器原始 JSON(与 QYGLJ1U9 并发结果形态一致)走与线上一致的 buildReport 转化。
|
||||
// 任一路传入 nil 时按空 map 处理。
|
||||
func BuildReportFromRawSources(jiguang, judicial, equity, annualRaw, taxViolationRaw, taxArrearsRaw map[string]interface{}) map[string]interface{} {
|
||||
func BuildReportFromRawSources(jiguang, judicial, equity, annualRaw, taxViolationRaw, taxArrearsRaw, customsCreditRaw map[string]interface{}) map[string]interface{} {
|
||||
if jiguang == nil {
|
||||
jiguang = map[string]interface{}{}
|
||||
}
|
||||
@@ -752,7 +763,10 @@ func BuildReportFromRawSources(jiguang, judicial, equity, annualRaw, taxViolatio
|
||||
if taxArrearsRaw == nil {
|
||||
taxArrearsRaw = map[string]interface{}{}
|
||||
}
|
||||
return buildReport(jiguang, judicial, equity, annualRaw, taxViolationRaw, taxArrearsRaw)
|
||||
if customsCreditRaw == nil {
|
||||
customsCreditRaw = map[string]interface{}{}
|
||||
}
|
||||
return buildReport(jiguang, judicial, equity, annualRaw, taxViolationRaw, taxArrearsRaw, customsCreditRaw)
|
||||
}
|
||||
|
||||
// extractJSONArrayFromEnterpriseAPI 从数据宝/天眼查类响应中提取数组主体(data/list/result 等)。
|
||||
@@ -2050,6 +2064,32 @@ func mapRiskOverview(report map[string]interface{}, risks map[string]interface{}
|
||||
tags = append(tags, "存在股权出质")
|
||||
}
|
||||
|
||||
// 进出口信用风险:基于 customsCredit 汇总
|
||||
var customsCredit map[string]interface{}
|
||||
if cc, ok := report["customsCredit"].(map[string]interface{}); ok {
|
||||
customsCredit = cc
|
||||
}
|
||||
hasCustomsAbnormal := false
|
||||
hasCustomsPunish := false
|
||||
hasCustomsCancel := false
|
||||
if customsCredit != nil {
|
||||
hasCustomsAbnormal = getBool(customsCredit, "hasAbnormal")
|
||||
hasCustomsPunish = getBool(customsCredit, "hasPunish")
|
||||
hasCustomsCancel = getBool(customsCredit, "isCancelled")
|
||||
}
|
||||
addItem("海关信用异常", hasCustomsAbnormal)
|
||||
if hasCustomsAbnormal {
|
||||
tags = append(tags, "存在海关信用异常")
|
||||
}
|
||||
addItem("海关行政处罚", hasCustomsPunish)
|
||||
if hasCustomsPunish {
|
||||
tags = append(tags, "存在海关行政处罚")
|
||||
}
|
||||
addItem("海关注销或状态异常", hasCustomsCancel)
|
||||
if hasCustomsCancel {
|
||||
tags = append(tags, "海关注销或状态异常")
|
||||
}
|
||||
|
||||
// 股权结构风险:基于 shareholding 汇总
|
||||
var shareholding map[string]interface{}
|
||||
if s, ok := report["shareholding"].(map[string]interface{}); ok {
|
||||
@@ -2085,6 +2125,11 @@ func mapRiskOverview(report map[string]interface{}, risks map[string]interface{}
|
||||
penalize(getBool(risks, "hasMortgage"), 5)
|
||||
penalize(getBool(risks, "hasEquityPledges"), 5)
|
||||
|
||||
// 进出口信用风险扣分
|
||||
penalize(hasCustomsPunish, 15)
|
||||
penalize(hasCustomsAbnormal, 10)
|
||||
penalize(hasCustomsCancel, 10)
|
||||
|
||||
if shareholding != nil {
|
||||
if n, _ := shareholding["shareholderCount"].(int); n > 0 && n <= 3 {
|
||||
penalize(true, 5)
|
||||
@@ -2261,3 +2306,128 @@ func num(v interface{}) float64 {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// mapCustomsCredit QYGLDJ33 企业进出口信用核查 → { total, items, hasAbnormal, hasPunish, isCancelled }
|
||||
// 字段保留接口原始驼峰命名,补充风险标志布尔值供 riskOverview 使用。
|
||||
func mapCustomsCredit(raw map[string]interface{}) map[string]interface{} {
|
||||
out := map[string]interface{}{
|
||||
"total": 0,
|
||||
"items": []interface{}{},
|
||||
"hasAbnormal": false,
|
||||
"hasPunish": false,
|
||||
"isCancelled": false,
|
||||
}
|
||||
if raw == nil {
|
||||
return out
|
||||
}
|
||||
items := sliceOrEmpty(raw["items"])
|
||||
total := intFromAny(raw["total"])
|
||||
if total == 0 {
|
||||
total = len(items)
|
||||
}
|
||||
|
||||
hasAbnormal := false
|
||||
hasPunish := false
|
||||
isCancelled := false
|
||||
|
||||
mapped := make([]interface{}, 0, len(items))
|
||||
for _, it := range items {
|
||||
row, _ := it.(map[string]interface{})
|
||||
if row == nil {
|
||||
continue
|
||||
}
|
||||
abnormalInfo := str(row["abnormalInfo"])
|
||||
punishInfo := normalizePunishInfo(row["punishInfo"])
|
||||
cancelFlag := str(row["customsCancelFlag"])
|
||||
|
||||
if abnormalInfo != "" && abnormalInfo != "无信用信息异常情况" {
|
||||
hasAbnormal = true
|
||||
}
|
||||
if punishInfo != "" && punishInfo != "[]" && punishInfo != "无" {
|
||||
hasPunish = true
|
||||
}
|
||||
if cancelFlag != "" && cancelFlag != "正常" {
|
||||
isCancelled = true
|
||||
}
|
||||
|
||||
mapped = append(mapped, map[string]interface{}{
|
||||
"entityName": str(row["entityName"]),
|
||||
"entityNameEn": str(row["entityNameEn"]),
|
||||
"customsRegisterCode": str(row["customsRegisterCode"]),
|
||||
"customsRegisterDate": str(row["customsRegisterDate"]),
|
||||
"reportingAddress": str(row["reportingAddress"]),
|
||||
"reportingAddressEn": str(row["reportingAddressEn"]),
|
||||
"customsName": str(row["customsName"]),
|
||||
"customsBusinessType": str(row["customsBusinessType"]),
|
||||
"importExportEntityCode": str(row["importExportEntityCode"]),
|
||||
"district": str(row["district"]),
|
||||
"economicDistrict": str(row["economicDistrict"]),
|
||||
"specialArea": str(row["specialArea"]),
|
||||
"industryType": str(row["industryType"]),
|
||||
"tradeType": str(row["tradeType"]),
|
||||
"validDate": str(row["validDate"]),
|
||||
"firstRecordDate": str(row["firstRecordDate"]),
|
||||
"lastRecordDate": str(row["lastRecordDate"]),
|
||||
"customsCancelFlag": cancelFlag,
|
||||
"ifAnnualReport": str(row["ifAnnualReport"]),
|
||||
"abnormalInfo": abnormalInfo,
|
||||
"punishInfo": punishInfo,
|
||||
"customsLevel": str(row["customsLevel"]),
|
||||
"creditLevel": str(row["creditLevel"]),
|
||||
})
|
||||
}
|
||||
|
||||
out["total"] = total
|
||||
out["items"] = mapped
|
||||
out["hasAbnormal"] = hasAbnormal
|
||||
out["hasPunish"] = hasPunish
|
||||
out["isCancelled"] = isCancelled
|
||||
return out
|
||||
}
|
||||
|
||||
// mergeCustomsCreditDefaults 补全进出口信用字段默认值。
|
||||
func mergeCustomsCreditDefaults(v interface{}) map[string]interface{} {
|
||||
out, _ := v.(map[string]interface{})
|
||||
if out == nil {
|
||||
out = map[string]interface{}{}
|
||||
}
|
||||
if _, ok := out["total"]; !ok {
|
||||
out["total"] = 0
|
||||
}
|
||||
if _, ok := out["items"]; !ok {
|
||||
out["items"] = []interface{}{}
|
||||
} else {
|
||||
out["items"] = ensureSlice(out["items"])
|
||||
}
|
||||
if _, ok := out["hasAbnormal"]; !ok {
|
||||
out["hasAbnormal"] = false
|
||||
}
|
||||
if _, ok := out["hasPunish"]; !ok {
|
||||
out["hasPunish"] = false
|
||||
}
|
||||
if _, ok := out["isCancelled"]; !ok {
|
||||
out["isCancelled"] = false
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// normalizePunishInfo 将 punishInfo 统一为 JSON 字符串。
|
||||
// RecursiveParse 可能已将嵌套的 JSON 数组字符串解析为 []interface{},
|
||||
// 此处将其序列化回 JSON 字符串,确保前端能正确 JSON.parse。
|
||||
func normalizePunishInfo(v interface{}) string {
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
switch p := v.(type) {
|
||||
case string:
|
||||
return p
|
||||
case []interface{}:
|
||||
b, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return fmt.Sprint(v)
|
||||
}
|
||||
return string(b)
|
||||
default:
|
||||
return fmt.Sprint(v)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user