f
This commit is contained in:
@@ -17,9 +17,9 @@ import (
|
||||
"tyapi-server/internal/domains/api/services/processors"
|
||||
)
|
||||
|
||||
// ProcessQYGLJ1U9Request 企业全景报告处理器:并发调用企业全量(QYGLUY3S)、股权全景(QYGLJ0Q1)、司法涉诉(QYGL5S1I),
|
||||
// 以及企业年报(QYGLDJ12)、税收违法(QYGL8848)、欠税公告(QYGL7D9A);
|
||||
// 前三者走 buildReport / map*;后三者在 buildReport 中转为 annualReports、taxViolations、ownTaxNotices 供页面展示。
|
||||
// ProcessQYGLJ1U9Request 企业全景报告处理器:并发调用企业全量(QYGLUY3S)、股权全景(QYGLJ0Q1)、司法涉诉(QYGL5S1I)、
|
||||
// 企业年报(QYGLDJ12)、税收违法(QYGL8848)、欠税公告(QYGL7D9A)。
|
||||
// 单路失败、查无、解析失败时该路按空数据处理并继续合并;仅当合并后的报告仍无任何可展示的企业要素时返回查询为空。
|
||||
func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||
// 复用 QYGLUY3S 的入参结构:企业名称/注册号/统一社会信用代码
|
||||
var p dto.QYGLJ1U9Req
|
||||
@@ -30,7 +30,7 @@ func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors
|
||||
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||
}
|
||||
|
||||
// 并发调用三个已有处理器
|
||||
// 并发调用六个子处理器;单路失败或无数据时降级为空结果,仅当合并后仍无任何企业要素时返回查询为空
|
||||
type apiResult struct {
|
||||
key string
|
||||
data map[string]interface{}
|
||||
@@ -108,12 +108,15 @@ func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors
|
||||
wg.Wait()
|
||||
close(resultsCh)
|
||||
|
||||
var jiguang, judicial, equity map[string]interface{}
|
||||
var annualReport, taxViolation, taxArrears map[string]interface{}
|
||||
jiguang := map[string]interface{}{}
|
||||
judicial := map[string]interface{}{}
|
||||
equity := map[string]interface{}{}
|
||||
annualReport := map[string]interface{}{}
|
||||
taxViolation := map[string]interface{}{}
|
||||
taxArrears := map[string]interface{}{}
|
||||
for r := range resultsCh {
|
||||
if r.err != nil {
|
||||
// 任一关键数据源异常,则返回系统错误(也可以根据需求做降级)
|
||||
return nil, errors.Join(processors.ErrSystem, fmt.Errorf("%s 调用失败: %w", r.key, r.err))
|
||||
if r.err != nil || r.data == nil {
|
||||
continue
|
||||
}
|
||||
switch r.key {
|
||||
case "jiguangFull":
|
||||
@@ -130,27 +133,12 @@ func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors
|
||||
taxArrears = r.data
|
||||
}
|
||||
}
|
||||
if jiguang == nil {
|
||||
jiguang = map[string]interface{}{}
|
||||
}
|
||||
if judicial == nil {
|
||||
judicial = map[string]interface{}{}
|
||||
}
|
||||
if equity == nil {
|
||||
equity = map[string]interface{}{}
|
||||
}
|
||||
if annualReport == nil {
|
||||
annualReport = map[string]interface{}{}
|
||||
}
|
||||
if taxViolation == nil {
|
||||
taxViolation = map[string]interface{}{}
|
||||
}
|
||||
if taxArrears == nil {
|
||||
taxArrears = map[string]interface{}{}
|
||||
}
|
||||
|
||||
// 复用构建逻辑生成企业报告结构(含年报 / 税收违法 / 欠税公告的转化结果)
|
||||
report := buildReport(jiguang, judicial, equity, annualReport, taxViolation, taxArrears)
|
||||
if !qyglJ1U9ReportHasSubstantiveData(report) {
|
||||
return nil, errors.Join(processors.ErrNotFound, errors.New("未查询到可用于生成报告的企业数据"))
|
||||
}
|
||||
|
||||
// 为报告生成唯一编号并缓存,供后续通过编号查看
|
||||
reportID := saveQYGLReport(report)
|
||||
|
||||
@@ -58,9 +58,654 @@ func buildReport(jiguang, judicial, equity, annualRaw, taxViolationRaw, taxArrea
|
||||
report["annualReports"] = annualReports
|
||||
report["taxViolations"] = mapTaxViolations(taxViolationRaw)
|
||||
report["ownTaxNotices"] = mapOwnTaxNotices(taxArrearsRaw)
|
||||
applyQYGLJ1U9ReportFieldDefaults(report)
|
||||
return report
|
||||
}
|
||||
|
||||
// applyQYGLJ1U9ReportFieldDefaults 在子数据源缺失时仍保证报告字段齐全:字符串 ""、数值 0、数组 []、对象按约定填空结构(不向客户暴露「缺键」)。
|
||||
func applyQYGLJ1U9ReportFieldDefaults(report map[string]interface{}) {
|
||||
if report == nil {
|
||||
return
|
||||
}
|
||||
// 顶层字符串
|
||||
report["entName"] = str(report["entName"])
|
||||
report["creditCode"] = str(report["creditCode"])
|
||||
report["reportTime"] = str(report["reportTime"])
|
||||
|
||||
report["basic"] = mergeBasicDefaults(report["basic"])
|
||||
b, _ := report["basic"].(map[string]interface{})
|
||||
if str(report["entName"]) == "" {
|
||||
report["entName"] = str(b["entName"])
|
||||
}
|
||||
if str(report["creditCode"]) == "" {
|
||||
report["creditCode"] = str(b["creditCode"])
|
||||
}
|
||||
|
||||
report["branches"] = ensureSlice(report["branches"])
|
||||
report["guarantees"] = ensureSlice(report["guarantees"])
|
||||
report["inspections"] = ensureSlice(report["inspections"])
|
||||
report["timeline"] = ensureSlice(report["timeline"])
|
||||
report["beneficiaries"] = ensureSlice(report["beneficiaries"])
|
||||
report["annualReports"] = ensureSlice(report["annualReports"])
|
||||
if _, ok := report["basicList"]; !ok {
|
||||
report["basicList"] = []interface{}{}
|
||||
} else {
|
||||
report["basicList"] = ensureSlice(report["basicList"])
|
||||
}
|
||||
|
||||
report["shareholding"] = mergeShareholdingDefaults(report["shareholding"])
|
||||
report["controller"] = mergeControllerDefaults(report["controller"])
|
||||
report["investments"] = mergeInvestmentsDefaults(report["investments"])
|
||||
report["management"] = mergeManagementDefaults(report["management"])
|
||||
report["assets"] = mergeAssetsDefaults(report["assets"])
|
||||
report["licenses"] = mergeLicensesDefaults(report["licenses"])
|
||||
report["activities"] = mergeActivitiesDefaults(report["activities"])
|
||||
report["risks"] = mergeRisksDefaults(report["risks"])
|
||||
report["listed"] = mergeListedDefaults(report["listed"])
|
||||
|
||||
report["taxViolations"] = mergeTaxViolationsDefaults(report["taxViolations"])
|
||||
report["ownTaxNotices"] = mergeOwnTaxNoticesDefaults(report["ownTaxNotices"])
|
||||
|
||||
if ro, ok := report["riskOverview"].(map[string]interface{}); ok {
|
||||
report["riskOverview"] = mergeRiskOverviewDefaults(ro)
|
||||
} else {
|
||||
report["riskOverview"] = mergeRiskOverviewDefaults(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func mergeBasicDefaults(v interface{}) map[string]interface{} {
|
||||
out, _ := v.(map[string]interface{})
|
||||
if out == nil {
|
||||
out = map[string]interface{}{}
|
||||
}
|
||||
skel := map[string]interface{}{
|
||||
"entName": "",
|
||||
"creditCode": "",
|
||||
"regNo": "",
|
||||
"orgCode": "",
|
||||
"entType": "",
|
||||
"entTypeCode": "",
|
||||
"entityTypeCode": "",
|
||||
"establishDate": "",
|
||||
"registeredCapital": float64(0),
|
||||
"regCapCurrency": "",
|
||||
"regCapCurrencyCode": "",
|
||||
"regOrg": "",
|
||||
"regOrgCode": "",
|
||||
"regProvince": "",
|
||||
"provinceCode": "",
|
||||
"regCity": "",
|
||||
"regCityCode": "",
|
||||
"regDistrict": "",
|
||||
"districtCode": "",
|
||||
"address": "",
|
||||
"postalCode": "",
|
||||
"legalRepresentative": "",
|
||||
"compositionForm": "",
|
||||
"approvedBusinessItem": "",
|
||||
"status": "",
|
||||
"statusCode": "",
|
||||
"operationPeriodFrom": "",
|
||||
"operationPeriodTo": "",
|
||||
"approveDate": "",
|
||||
"cancelDate": "",
|
||||
"revokeDate": "",
|
||||
"cancelReason": "",
|
||||
"revokeReason": "",
|
||||
"businessScope": "",
|
||||
"lastAnnuReportYear": "",
|
||||
"oldNames": []interface{}{},
|
||||
}
|
||||
for k, def := range skel {
|
||||
if _, ok := out[k]; !ok {
|
||||
out[k] = def
|
||||
}
|
||||
}
|
||||
if out["oldNames"] == nil {
|
||||
out["oldNames"] = []interface{}{}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func ensureSlice(v interface{}) []interface{} {
|
||||
if v == nil {
|
||||
return []interface{}{}
|
||||
}
|
||||
arr, ok := v.([]interface{})
|
||||
if !ok {
|
||||
return []interface{}{}
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
func mergeShareholdingDefaults(v interface{}) map[string]interface{} {
|
||||
out, _ := v.(map[string]interface{})
|
||||
if out == nil {
|
||||
out = map[string]interface{}{}
|
||||
}
|
||||
skel := map[string]interface{}{
|
||||
"shareholders": []interface{}{},
|
||||
"equityChanges": []interface{}{},
|
||||
"equityPledges": []interface{}{},
|
||||
"paidInDetails": []interface{}{},
|
||||
"subscribedCapitalDetails": []interface{}{},
|
||||
"hasEquityPledges": false,
|
||||
"shareholderCount": 0,
|
||||
"registeredCapital": float64(0),
|
||||
"currency": "",
|
||||
"topHolderName": "",
|
||||
"topHolderPercent": float64(0),
|
||||
"top5TotalPercent": float64(0),
|
||||
}
|
||||
for k, def := range skel {
|
||||
if _, ok := out[k]; !ok {
|
||||
out[k] = def
|
||||
}
|
||||
}
|
||||
for _, k := range []string{"shareholders", "equityChanges", "equityPledges", "paidInDetails", "subscribedCapitalDetails"} {
|
||||
out[k] = ensureSlice(out[k])
|
||||
}
|
||||
if out["registeredCapital"] == nil {
|
||||
out["registeredCapital"] = float64(0)
|
||||
}
|
||||
if _, ok := out["hasEquityPledges"].(bool); !ok {
|
||||
out["hasEquityPledges"] = false
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func mergeControllerDefaults(v interface{}) map[string]interface{} {
|
||||
if m, ok := v.(map[string]interface{}); ok && m != nil {
|
||||
if m["path"] == nil {
|
||||
m["path"] = map[string]interface{}{
|
||||
"nodes": []interface{}{},
|
||||
"links": []interface{}{},
|
||||
}
|
||||
}
|
||||
if p, ok := m["path"].(map[string]interface{}); ok {
|
||||
if _, ok := p["nodes"]; !ok {
|
||||
p["nodes"] = []interface{}{}
|
||||
}
|
||||
if _, ok := p["links"]; !ok {
|
||||
p["links"] = []interface{}{}
|
||||
}
|
||||
}
|
||||
ensureStrKeys(m, []string{"id", "name", "type", "reason", "source"})
|
||||
if m["percent"] == nil {
|
||||
m["percent"] = float64(0)
|
||||
} else if _, ok := m["percent"].(float64); !ok {
|
||||
m["percent"] = num(m["percent"])
|
||||
}
|
||||
return m
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"id": "",
|
||||
"name": "",
|
||||
"type": "",
|
||||
"percent": float64(0),
|
||||
"path": map[string]interface{}{
|
||||
"nodes": []interface{}{},
|
||||
"links": []interface{}{},
|
||||
},
|
||||
"reason": "",
|
||||
"source": "",
|
||||
}
|
||||
}
|
||||
|
||||
func mergeInvestmentsDefaults(v interface{}) map[string]interface{} {
|
||||
out, _ := v.(map[string]interface{})
|
||||
if out == nil {
|
||||
out = map[string]interface{}{}
|
||||
}
|
||||
if _, ok := out["totalCount"]; !ok {
|
||||
out["totalCount"] = 0
|
||||
}
|
||||
if _, ok := out["totalAmount"]; !ok {
|
||||
out["totalAmount"] = float64(0)
|
||||
}
|
||||
if out["totalAmount"] == nil {
|
||||
out["totalAmount"] = float64(0)
|
||||
}
|
||||
out["list"] = ensureSlice(out["list"])
|
||||
out["legalRepresentativeInvestments"] = ensureSlice(out["legalRepresentativeInvestments"])
|
||||
return out
|
||||
}
|
||||
|
||||
func mergeManagementDefaults(v interface{}) map[string]interface{} {
|
||||
out, _ := v.(map[string]interface{})
|
||||
if out == nil {
|
||||
out = map[string]interface{}{}
|
||||
}
|
||||
if _, ok := out["executives"]; !ok {
|
||||
out["executives"] = []interface{}{}
|
||||
} else {
|
||||
out["executives"] = ensureSlice(out["executives"])
|
||||
}
|
||||
if _, ok := out["legalRepresentativeOtherPositions"]; !ok {
|
||||
out["legalRepresentativeOtherPositions"] = []interface{}{}
|
||||
} else {
|
||||
out["legalRepresentativeOtherPositions"] = ensureSlice(out["legalRepresentativeOtherPositions"])
|
||||
}
|
||||
if _, ok := out["employeeCount"]; !ok || out["employeeCount"] == nil {
|
||||
out["employeeCount"] = float64(0)
|
||||
}
|
||||
if _, ok := out["femaleEmployeeCount"]; !ok || out["femaleEmployeeCount"] == nil {
|
||||
out["femaleEmployeeCount"] = float64(0)
|
||||
}
|
||||
if out["socialSecurity"] == nil {
|
||||
out["socialSecurity"] = map[string]interface{}{}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func mergeAssetsDefaults(v interface{}) map[string]interface{} {
|
||||
out, _ := v.(map[string]interface{})
|
||||
if out == nil {
|
||||
out = map[string]interface{}{}
|
||||
}
|
||||
if _, ok := out["years"]; !ok {
|
||||
out["years"] = []interface{}{}
|
||||
} else {
|
||||
out["years"] = ensureSlice(out["years"])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func mergeLicensesDefaults(v interface{}) map[string]interface{} {
|
||||
out, _ := v.(map[string]interface{})
|
||||
if out == nil {
|
||||
out = map[string]interface{}{}
|
||||
}
|
||||
for _, k := range []string{"permits", "permitChanges", "ipPledges", "otherLicenses"} {
|
||||
if _, ok := out[k]; !ok {
|
||||
out[k] = []interface{}{}
|
||||
} else {
|
||||
out[k] = ensureSlice(out[k])
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func mergeActivitiesDefaults(v interface{}) map[string]interface{} {
|
||||
out, _ := v.(map[string]interface{})
|
||||
if out == nil {
|
||||
out = map[string]interface{}{}
|
||||
}
|
||||
if _, ok := out["bids"]; !ok {
|
||||
out["bids"] = []interface{}{}
|
||||
} else {
|
||||
out["bids"] = ensureSlice(out["bids"])
|
||||
}
|
||||
if _, ok := out["websites"]; !ok {
|
||||
out["websites"] = []interface{}{}
|
||||
} else {
|
||||
out["websites"] = ensureSlice(out["websites"])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func litigationTypeKeys() []string {
|
||||
return []string{
|
||||
"administrative", "implement", "preservation", "civil", "criminal",
|
||||
"bankrupt", "jurisdict", "compensate",
|
||||
}
|
||||
}
|
||||
|
||||
func defaultLitigationShell() map[string]interface{} {
|
||||
out := map[string]interface{}{"totalCases": 0}
|
||||
for _, k := range litigationTypeKeys() {
|
||||
out[k] = map[string]interface{}{
|
||||
"count": 0,
|
||||
"cases": []interface{}{},
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func mergeLitigationShape(v interface{}) map[string]interface{} {
|
||||
out := defaultLitigationShell()
|
||||
if v == nil {
|
||||
return out
|
||||
}
|
||||
m, ok := v.(map[string]interface{})
|
||||
if !ok {
|
||||
return out
|
||||
}
|
||||
known := map[string]struct{}{}
|
||||
for _, k := range litigationTypeKeys() {
|
||||
known[k] = struct{}{}
|
||||
}
|
||||
for k, val := range m {
|
||||
if k == "totalCases" {
|
||||
out["totalCases"] = intFromAny(val)
|
||||
continue
|
||||
}
|
||||
if _, isCat := known[k]; isCat {
|
||||
sm, ok := val.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
out[k] = map[string]interface{}{
|
||||
"count": intFromAny(sm["count"]),
|
||||
"cases": ensureSlice(sm["cases"]),
|
||||
}
|
||||
continue
|
||||
}
|
||||
out[k] = val
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func defaultQuickCancelShell() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"entName": "",
|
||||
"creditCode": "",
|
||||
"regNo": "",
|
||||
"regOrg": "",
|
||||
"noticeFromDate": "",
|
||||
"noticeToDate": "",
|
||||
"cancelResult": "",
|
||||
"dissents": []interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
func defaultLiquidationShell() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"principal": "",
|
||||
"members": []interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
func mergeRisksDefaults(v interface{}) map[string]interface{} {
|
||||
out, _ := v.(map[string]interface{})
|
||||
if out == nil {
|
||||
out = map[string]interface{}{}
|
||||
}
|
||||
boolKeys := []string{
|
||||
"hasCourtJudgments", "hasJudicialAssists", "hasDishonestDebtors", "hasLimitHighDebtors",
|
||||
"hasAdminPenalty", "hasException", "hasSeriousIllegal", "hasTaxOwing", "hasSeriousTaxIllegal",
|
||||
"hasMortgage", "hasEquityPledges", "hasQuickCancel",
|
||||
}
|
||||
for _, k := range boolKeys {
|
||||
if _, ok := out[k]; !ok {
|
||||
out[k] = false
|
||||
}
|
||||
}
|
||||
if _, ok := out["riskLevel"]; !ok {
|
||||
out["riskLevel"] = "低"
|
||||
}
|
||||
if _, ok := out["riskScore"]; !ok {
|
||||
out["riskScore"] = 80
|
||||
}
|
||||
for _, k := range []string{"dishonestDebtorCount", "limitHighDebtorCount"} {
|
||||
if _, ok := out[k]; !ok {
|
||||
out[k] = 0
|
||||
}
|
||||
}
|
||||
for _, k := range []string{
|
||||
"courtJudgments", "judicialAssists", "dishonestDebtors", "limitHighDebtors",
|
||||
"adminPenalties", "adminPenaltyUpdates", "exceptions", "seriousIllegals", "mortgages",
|
||||
} {
|
||||
if _, ok := out[k]; !ok {
|
||||
out[k] = []interface{}{}
|
||||
} else {
|
||||
out[k] = ensureSlice(out[k])
|
||||
}
|
||||
}
|
||||
out["litigation"] = mergeLitigationShape(out["litigation"])
|
||||
if out["quickCancel"] == nil {
|
||||
out["quickCancel"] = defaultQuickCancelShell()
|
||||
} else if qm, ok := out["quickCancel"].(map[string]interface{}); ok {
|
||||
dc := defaultQuickCancelShell()
|
||||
for k, def := range dc {
|
||||
if _, ok := qm[k]; !ok {
|
||||
qm[k] = def
|
||||
}
|
||||
}
|
||||
if qm["dissents"] == nil {
|
||||
qm["dissents"] = []interface{}{}
|
||||
} else {
|
||||
qm["dissents"] = ensureSlice(qm["dissents"])
|
||||
}
|
||||
out["quickCancel"] = qm
|
||||
}
|
||||
if out["liquidation"] == nil {
|
||||
out["liquidation"] = defaultLiquidationShell()
|
||||
} else if lm, ok := out["liquidation"].(map[string]interface{}); ok {
|
||||
dc := defaultLiquidationShell()
|
||||
for k, def := range dc {
|
||||
if _, ok := lm[k]; !ok {
|
||||
lm[k] = def
|
||||
}
|
||||
}
|
||||
if lm["members"] == nil {
|
||||
lm["members"] = []interface{}{}
|
||||
} else {
|
||||
lm["members"] = ensureSlice(lm["members"])
|
||||
}
|
||||
out["liquidation"] = lm
|
||||
}
|
||||
tr, _ := out["taxRecords"].(map[string]interface{})
|
||||
if tr == nil {
|
||||
tr = map[string]interface{}{}
|
||||
}
|
||||
for _, k := range []string{"taxLevelAYears", "seriousTaxIllegal", "taxOwings"} {
|
||||
if _, ok := tr[k]; !ok {
|
||||
tr[k] = []interface{}{}
|
||||
} else {
|
||||
tr[k] = ensureSlice(tr[k])
|
||||
}
|
||||
}
|
||||
out["taxRecords"] = tr
|
||||
return out
|
||||
}
|
||||
|
||||
// normalizeListedStock 无股票结构时用 JSON null,避免前端把 {} 当成有值而 JSON.stringify 出 "{}"。
|
||||
func normalizeListedStock(v interface{}) interface{} {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
m, ok := v.(map[string]interface{})
|
||||
if !ok {
|
||||
return v
|
||||
}
|
||||
if len(m) == 0 {
|
||||
return nil
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func mergeListedDefaults(v interface{}) map[string]interface{} {
|
||||
if m, ok := v.(map[string]interface{}); ok && m != nil {
|
||||
if _, ok := m["isListed"].(bool); !ok {
|
||||
m["isListed"] = false
|
||||
}
|
||||
co, _ := m["company"].(map[string]interface{})
|
||||
if co == nil {
|
||||
co = map[string]interface{}{}
|
||||
}
|
||||
for k, def := range map[string]interface{}{
|
||||
"bizScope": "", "creditCode": "", "regAddr": "", "regCapital": "",
|
||||
"orgCode": "", "cur": "", "curName": "",
|
||||
} {
|
||||
if _, ok := co[k]; !ok {
|
||||
co[k] = def
|
||||
}
|
||||
}
|
||||
m["company"] = co
|
||||
m["stock"] = normalizeListedStock(m["stock"])
|
||||
if _, ok := m["topShareholders"]; !ok {
|
||||
m["topShareholders"] = []interface{}{}
|
||||
} else {
|
||||
m["topShareholders"] = ensureSlice(m["topShareholders"])
|
||||
}
|
||||
if _, ok := m["listedManagers"]; !ok {
|
||||
m["listedManagers"] = []interface{}{}
|
||||
} else {
|
||||
m["listedManagers"] = ensureSlice(m["listedManagers"])
|
||||
}
|
||||
return m
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"isListed": false,
|
||||
"company": map[string]interface{}{
|
||||
"bizScope": "", "creditCode": "", "regAddr": "", "regCapital": "",
|
||||
"orgCode": "", "cur": "", "curName": "",
|
||||
},
|
||||
"stock": nil,
|
||||
"topShareholders": []interface{}{},
|
||||
"listedManagers": []interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
func mergeTaxViolationsDefaults(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"])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func mergeOwnTaxNoticesDefaults(v interface{}) map[string]interface{} {
|
||||
return mergeTaxViolationsDefaults(v)
|
||||
}
|
||||
|
||||
func mergeRiskOverviewDefaults(v interface{}) map[string]interface{} {
|
||||
out, _ := v.(map[string]interface{})
|
||||
if out == nil {
|
||||
out = map[string]interface{}{}
|
||||
}
|
||||
if _, ok := out["riskLevel"]; !ok {
|
||||
out["riskLevel"] = "低"
|
||||
}
|
||||
if _, ok := out["riskScore"]; !ok {
|
||||
out["riskScore"] = 100
|
||||
}
|
||||
if _, ok := out["tags"]; !ok {
|
||||
out["tags"] = []interface{}{}
|
||||
} else {
|
||||
out["tags"] = ensureSlice(out["tags"])
|
||||
}
|
||||
if _, ok := out["items"]; !ok {
|
||||
out["items"] = []interface{}{}
|
||||
} else {
|
||||
out["items"] = ensureSlice(out["items"])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func ensureStrKeys(m map[string]interface{}, keys []string) {
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
for _, k := range keys {
|
||||
if _, ok := m[k]; !ok {
|
||||
m[k] = ""
|
||||
} else if m[k] == nil {
|
||||
m[k] = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// qyglJ1U9ReportHasSubstantiveData 判断合并后的报告是否至少含一项可展示的企业要素。
|
||||
// 当所有子数据源均失败或等价于无数据时返回 false,用于 QYGLJ1U9 整体返回「查询为空」。
|
||||
func qyglJ1U9ReportHasSubstantiveData(report map[string]interface{}) bool {
|
||||
if report == nil {
|
||||
return false
|
||||
}
|
||||
trim := func(v interface{}) string { return strings.TrimSpace(str(v)) }
|
||||
|
||||
basic, _ := report["basic"].(map[string]interface{})
|
||||
if basic != nil {
|
||||
if trim(basic["entName"]) != "" || trim(basic["creditCode"]) != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if trim(report["entName"]) != "" || trim(report["creditCode"]) != "" {
|
||||
return true
|
||||
}
|
||||
if ar, ok := report["annualReports"].([]interface{}); ok && len(ar) > 0 {
|
||||
return true
|
||||
}
|
||||
if tv, ok := report["taxViolations"].(map[string]interface{}); ok {
|
||||
if intFromAny(tv["total"]) > 0 {
|
||||
return true
|
||||
}
|
||||
if items, ok := tv["items"].([]interface{}); ok && len(items) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if ot, ok := report["ownTaxNotices"].(map[string]interface{}); ok {
|
||||
if intFromAny(ot["total"]) > 0 {
|
||||
return true
|
||||
}
|
||||
if items, ok := ot["items"].([]interface{}); ok && len(items) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if br, ok := report["branches"].([]interface{}); ok && len(br) > 0 {
|
||||
return true
|
||||
}
|
||||
if bl, ok := report["basicList"].([]interface{}); ok && len(bl) > 0 {
|
||||
return true
|
||||
}
|
||||
if sh, ok := report["shareholding"].(map[string]interface{}); ok {
|
||||
if arr, ok := sh["shareholders"].([]interface{}); ok && len(arr) > 0 {
|
||||
return true
|
||||
}
|
||||
if intFromAny(sh["shareholderCount"]) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if inv, ok := report["investments"].(map[string]interface{}); ok {
|
||||
if arr, ok := inv["list"].([]interface{}); ok && len(arr) > 0 {
|
||||
return true
|
||||
}
|
||||
if intFromAny(inv["totalCount"]) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if ben, ok := report["beneficiaries"].([]interface{}); ok && len(ben) > 0 {
|
||||
return true
|
||||
}
|
||||
if tl, ok := report["timeline"].([]interface{}); ok && len(tl) > 0 {
|
||||
return true
|
||||
}
|
||||
if ctl, _ := report["controller"].(map[string]interface{}); ctl != nil && trim(ctl["name"]) != "" {
|
||||
return true
|
||||
}
|
||||
if risks, ok := report["risks"].(map[string]interface{}); ok {
|
||||
for _, key := range []string{
|
||||
"dishonestDebtors", "limitHighDebtors", "adminPenalties", "exceptions",
|
||||
"seriousIllegals", "mortgages", "courtJudgments", "judicialAssists",
|
||||
} {
|
||||
if arr, ok := risks[key].([]interface{}); ok && len(arr) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if lit, ok := risks["litigation"].(map[string]interface{}); ok {
|
||||
for _, v := range lit {
|
||||
sub, ok := v.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if arr, ok := sub["cases"].([]interface{}); ok && len(arr) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// jiguangWithoutYearReportTables 浅拷贝全量 map,并去掉企业全量 V2 中与「公示年报」对应的 YEARREPORT* 键。
|
||||
// 在已接入 QYGLDJ12 且年报列表非空时使用,避免 build 与 HTML 中与「十六、企业年报」重复展示。
|
||||
func jiguangWithoutYearReportTables(jiguang map[string]interface{}) map[string]interface{} {
|
||||
|
||||
203
resources/dev-report/QYGLJ1U9_客户字段说明.md
Normal file
203
resources/dev-report/QYGLJ1U9_客户字段说明.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# QYGLJ1U9 企业全景报告字段说明
|
||||
|
||||
## 一、返回对象总览
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --------------- | ------------- | -------------------------------------------------- |
|
||||
| `reportId` | string | 报告编号,可用于后续按编号访问报告页面或下载 PDF。 |
|
||||
| `reportUrl` | string | 报告访问链接。 |
|
||||
| `reportTime` | string | 报告生成时间,格式示例:`2026-03-21 19:30:45`。 |
|
||||
| `entName` | string | 企业名称。 |
|
||||
| `creditCode` | string | 统一社会信用代码。 |
|
||||
| `basic` | object | 企业主体基础信息。 |
|
||||
| `branches` | array | 分支机构列表。 |
|
||||
| `shareholding` | object | 股权结构与股东信息。 |
|
||||
| `controller` | object / null | 实际控制人信息。 |
|
||||
| `beneficiaries` | array | 最终受益人列表。 |
|
||||
| `investments` | object | 对外投资信息。 |
|
||||
| `guarantees` | array | 对外担保信息。 |
|
||||
| `management` | object | 高管、人员和社保相关信息。 |
|
||||
| `assets` | object | 资产经营类年度信息。 |
|
||||
| `licenses` | object | 行政许可、许可变更、知识产权出质等。 |
|
||||
| `activities` | object | 招投标、网站网店等经营活动信息。 |
|
||||
| `inspections` | array | 抽查检查信息。 |
|
||||
| `risks` | object | 风险与合规信息。 |
|
||||
| `timeline` | array | 工商变更时间线。 |
|
||||
| `listed` | object / null | 上市相关信息。 |
|
||||
| `riskOverview` | object | 风险总览(等级、分值、标签)。 |
|
||||
| `annualReports` | array | 企业年报列表。 |
|
||||
| `taxViolations` | object | 税收违法信息,结构为 `{ total, items }`。 |
|
||||
| `ownTaxNotices` | object | 欠税公告信息,结构为 `{ total, items }`。 |
|
||||
|
||||
---
|
||||
|
||||
## 二、核心字段说明
|
||||
|
||||
### 1) `basic` 企业主体基础信息
|
||||
|
||||
常见字段如下:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| ------------------------------------------- | ---------------- |
|
||||
| `entName` | 企业名称 |
|
||||
| `creditCode` | 统一社会信用代码 |
|
||||
| `regNo` | 注册号 |
|
||||
| `orgCode` | 组织机构代码 |
|
||||
| `entType` | 企业类型 |
|
||||
| `establishDate` | 成立日期 |
|
||||
| `registeredCapital` | 注册资本 |
|
||||
| `regCapCurrency` | 注册资本币种 |
|
||||
| `legalRepresentative` | 法定代表人 |
|
||||
| `status` | 经营状态 |
|
||||
| `operationPeriodFrom` / `operationPeriodTo` | 营业期限起止 |
|
||||
| `regOrg` | 登记机关 |
|
||||
| `address` | 企业地址 |
|
||||
| `businessScope` | 经营范围 |
|
||||
| `oldNames` | 曾用名列表 |
|
||||
|
||||
### 2) `shareholding` 股权结构
|
||||
|
||||
| 字段 | 说明 |
|
||||
| -------------------------- | ---------------------- |
|
||||
| `shareholders` | 股东列表 |
|
||||
| `shareholderCount` | 股东人数 |
|
||||
| `topHolderName` | 第一大股东名称 |
|
||||
| `topHolderPercent` | 第一大股东持股比例 |
|
||||
| `top5TotalPercent` | 前五大股东持股比例合计 |
|
||||
| `equityChanges` | 股权变更记录 |
|
||||
| `equityPledges` | 股权出质记录 |
|
||||
| `paidInDetails` | 实缴出资明细 |
|
||||
| `subscribedCapitalDetails` | 认缴出资明细 |
|
||||
|
||||
`shareholders` 常见子字段:
|
||||
`name`、`type`、`ownershipPercent`、`subscribedAmount`、`paidAmount`、`subscribedDate`、`paidDate`。
|
||||
|
||||
### 3) `controller` 实际控制人
|
||||
|
||||
常见字段:`id`、`name`、`type`、`percent`、`path`、`reason`。
|
||||
|
||||
### 4) `beneficiaries` 最终受益人
|
||||
|
||||
每条常见字段:`id`、`name`、`type`、`percent`、`path`、`reason`。
|
||||
|
||||
### 5) `investments` 对外投资
|
||||
|
||||
| 字段 | 说明 |
|
||||
| -------------------------------- | ------------------------ |
|
||||
| `totalCount` | 对外投资企业数量 |
|
||||
| `totalAmount` | 对外投资金额汇总(如有) |
|
||||
| `list` | 对外投资企业列表 |
|
||||
| `legalRepresentativeInvestments` | 法定代表人对外投资列表 |
|
||||
|
||||
`list` 常见子字段:`entName`、`creditCode`、`entStatus`、`regCap`、`investAmount`、`investPercent`。
|
||||
|
||||
### 6) `management` 管理层与人员信息
|
||||
|
||||
| 字段 | 说明 |
|
||||
| ----------------------------------- | ---------------------- |
|
||||
| `executives` | 高管列表(姓名、职务) |
|
||||
| `legalRepresentativeOtherPositions` | 法人对外任职信息 |
|
||||
| `employeeCount` | 员工人数 |
|
||||
| `femaleEmployeeCount` | 女性员工人数 |
|
||||
| `socialSecurity` | 社保相关字段集合 |
|
||||
|
||||
### 7) `assets` 资产经营信息
|
||||
|
||||
`assets.years` 为按年度的经营数据,常见字段:
|
||||
`year`、`assetTotal`、`revenueTotal`、`mainBusinessRevenue`、`taxTotal`、`equityTotal`、`profitTotal`、`netProfit`、`liabilityTotal`。
|
||||
|
||||
### 8) `licenses` 许可与资质信息
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --------------- | ---------------- |
|
||||
| `permits` | 行政许可列表 |
|
||||
| `permitChanges` | 行政许可变更列表 |
|
||||
| `ipPledges` | 知识产权出质列表 |
|
||||
| `otherLicenses` | 其他许可信息 |
|
||||
|
||||
### 9) `activities` 经营活动信息
|
||||
|
||||
| 字段 | 说明 |
|
||||
| ---------- | -------------- |
|
||||
| `bids` | 招投标信息 |
|
||||
| `websites` | 网站或网店信息 |
|
||||
|
||||
### 10) `inspections` 抽查检查
|
||||
|
||||
每条常见字段:`dataType`、`regOrg`、`inspectDate`、`result`。
|
||||
|
||||
---
|
||||
|
||||
## 三、风险相关字段
|
||||
|
||||
### 1) `riskOverview` 风险总览(建议用于首页展示)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| ----------- | ------ | ---------------------------------------------------- |
|
||||
| `riskLevel` | string | 风险等级:`低` / `中` / `高`。 |
|
||||
| `riskScore` | number | 风险分值(0-100)。 |
|
||||
| `tags` | array | 风险标签列表。 |
|
||||
| `items` | array | 各类风险项命中情况,元素结构通常为 `{ name, hit }`。 |
|
||||
|
||||
### 2) `risks` 风险详情
|
||||
|
||||
常见布尔字段:
|
||||
`hasCourtJudgments`、`hasJudicialAssists`、`hasDishonestDebtors`、`hasLimitHighDebtors`、`hasAdminPenalty`、`hasException`、`hasSeriousIllegal`、`hasTaxOwing`、`hasSeriousTaxIllegal`、`hasMortgage`、`hasEquityPledges`、`hasQuickCancel`。
|
||||
|
||||
常见明细字段:
|
||||
`dishonestDebtors`、`limitHighDebtors`、`litigation`、`adminPenalties`、`adminPenaltyUpdates`、`exceptions`、`seriousIllegals`、`mortgages`、`taxRecords`、`courtJudgments`、`judicialAssists`、`quickCancel`、`liquidation`。
|
||||
|
||||
---
|
||||
|
||||
## 四、年报与税务字段
|
||||
|
||||
### 1) `annualReports` 企业年报列表
|
||||
|
||||
每个元素代表一个年度年报,字段较多,常见包括:
|
||||
|
||||
- 基础信息(如年度、企业基本经营情况)
|
||||
- 股东与出资信息
|
||||
- 对外投资信息
|
||||
- 网站网店信息
|
||||
- 社保信息
|
||||
- 对外担保信息
|
||||
- 股权变更信息
|
||||
- 年报变更信息
|
||||
|
||||
### 2) `taxViolations` 税收违法信息
|
||||
|
||||
结构示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"total": 2,
|
||||
"items": [
|
||||
{
|
||||
"entityName": "示例企业",
|
||||
"taxpayerCode": "xxxx",
|
||||
"illegalFact": "......",
|
||||
"publishDepartment": "......",
|
||||
"illegalTime": "2025-06-12"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3) `ownTaxNotices` 欠税公告信息
|
||||
|
||||
结构示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"total": 1,
|
||||
"items": [
|
||||
{
|
||||
"taxpayerName": "示例企业",
|
||||
"taxIdNumber": "xxxx",
|
||||
"taxCategory": "增值税",
|
||||
"ownTaxBalance": "100000",
|
||||
"publishDate": "2025-12-01"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user