diff --git a/internal/domains/api/services/processors/dwbg/dwbg6a2c_calc_risk.go b/internal/domains/api/services/processors/dwbg/dwbg6a2c_calc_risk.go index 6449298..4f63a2e 100644 --- a/internal/domains/api/services/processors/dwbg/dwbg6a2c_calc_risk.go +++ b/internal/domains/api/services/processors/dwbg/dwbg6a2c_calc_risk.go @@ -54,10 +54,8 @@ func calcSinanRisk(report map[string]interface{}, apiData map[string]interface{} riskList["groupFraud"] = 1 } - if flxgdea9 := asMap(getMapValue(apiData, "FLXGDEA9")); flxgdea9 != nil { - if industryBlacklistHit(xypString(flxgdea9, "level")) { - riskList["industryBlacklist"] = 1 - } + if level := flxgdea9Level(apiData); industryBlacklistHit(level) { + riskList["industryBlacklist"] = 1 } riskList["highRiskArea"] = 0 @@ -102,10 +100,8 @@ func calcSinanRisk(report map[string]interface{}, apiData map[string]interface{} riskPoint["limitCasesFlag"] = 1 } - if flxgdea9 := asMap(getMapValue(apiData, "FLXGDEA9")); flxgdea9 != nil { - if securityLevelHit(xypString(flxgdea9, "level")) { - riskPoint["securityRisk"] = 1 - } + if securityLevelHit(flxgdea9Level(apiData)) { + riskPoint["securityRisk"] = 1 } if antiFraudHit(asMap(getMapValue(apiData, "FLXG8B4D"))) { diff --git a/internal/domains/api/services/processors/dwbg/dwbg6a2c_map.go b/internal/domains/api/services/processors/dwbg/dwbg6a2c_map.go index 516dbb5..3bcdfd6 100644 --- a/internal/domains/api/services/processors/dwbg/dwbg6a2c_map.go +++ b/internal/domains/api/services/processors/dwbg/dwbg6a2c_map.go @@ -184,11 +184,7 @@ func buildSinanAntiFraudInfo(apiData map[string]interface{}) map[string]interfac func buildSinanSecurityInfo(apiData map[string]interface{}) map[string]interface{} { info := emptySecurityInfo() - flxg := asMap(getMapValue(apiData, "FLXGDEA9")) - if flxg == nil { - return info - } - level := xypString(flxg, "level") + level := flxgdea9Level(apiData) if level == "" || level == "0" { return info } @@ -511,10 +507,6 @@ func jrzq1d09Map(apiData map[string]interface{}) map[string]interface{} { return asMap(getMapValue(apiData, "JRZQ1D09")) } -func flxg7e8fMap(apiData map[string]interface{}) map[string]interface{} { - return asMap(getMapValue(apiData, "FLXG7E8F")) -} - func maxTotMons(jrzq map[string]interface{}) int { maxVal := 0 for _, period := range []string{"m6", "m12"} { diff --git a/internal/domains/api/services/processors/dwbg/dwbg6a2c_test.go b/internal/domains/api/services/processors/dwbg/dwbg6a2c_test.go index 3b5c1de..55c8d21 100644 --- a/internal/domains/api/services/processors/dwbg/dwbg6a2c_test.go +++ b/internal/domains/api/services/processors/dwbg/dwbg6a2c_test.go @@ -2,6 +2,8 @@ package dwbg import ( "encoding/json" + "os" + "path/filepath" "strings" "testing" @@ -327,6 +329,106 @@ func TestBuildJudicialLeaseReportWithCases(t *testing.T) { } } +func TestT2SampleJudicialAndSecurityMapping(t *testing.T) { + base := filepath.Join("..", "..", "..", "..", "..", "..", "..", "司南报告") + load := func(name string) map[string]interface{} { + b, err := os.ReadFile(filepath.Join(base, name)) + if err != nil { + t.Fatalf("read %s: %v", name, err) + } + var m map[string]interface{} + if err := json.Unmarshal(b, &m); err != nil { + t.Fatalf("unmarshal %s: %v", name, err) + } + return m + } + + params := dto.DWBG6A2CReq{ + Name: "何志勇", + IDCard: "45212719910201152X", + MobileNo: "18277111590", + } + apiData := map[string]interface{}{ + "FLXG7E8F": load("t2-1.json"), + "FLXGDEA9": load("t2-2.json"), + } + report := transformToSinanReport(apiData, params, zap.NewNop()) + + jlr := report["judicialLeaseReport"].(map[string]interface{}) + courtInfo := jlr["courtInfo"].(map[string]interface{}) + if courtInfo["criminalCasesCount"] != 4 { + t.Fatalf("criminalCasesCount = %v, want 4", courtInfo["criminalCasesCount"]) + } + newMult := courtInfo["newMultCourtInfo"].(map[string]interface{}) + criminalCases, ok := newMult["criminalCases"].([]interface{}) + if !ok || len(criminalCases) != 4 { + t.Fatalf("criminalCases = %v, want 4 items", newMult["criminalCases"]) + } + overview := jlr["caseOverviewInfo"].(map[string]interface{}) + if overview["beigaoTotalCasesCounts"] != 2 { + t.Fatalf("beigaoTotalCasesCounts = %v, want 2", overview["beigaoTotalCasesCounts"]) + } + if overview["leastCaseTime"] != "2019(2)" { + t.Fatalf("leastCaseTime = %v, want 2019(2)", overview["leastCaseTime"]) + } + + security := report["securityInfo"].(map[string]interface{}) + if security["escape"] != 1 || security["icase"] != 1 { + t.Fatalf("securityInfo A => %+v", security) + } + if security["ikey"] != 1 { + t.Fatalf("securityInfo D5 => ikey=%v", security["ikey"]) + } + + riskPoint := report["riskPoint"].(map[string]interface{}) + if riskPoint["judicialRisk"] != 1 || riskPoint["legalCasesFlag"] != 1 { + t.Fatalf("riskPoint judicial flags = %+v", riskPoint) + } + if riskPoint["securityRisk"] != 1 { + t.Fatalf("securityRisk = %v, want 1", riskPoint["securityRisk"]) + } +} + +func TestT2SampleWithDataWrapper(t *testing.T) { + base := filepath.Join("..", "..", "..", "..", "..", "..", "..", "司南报告") + load := func(name string) map[string]interface{} { + b, err := os.ReadFile(filepath.Join(base, name)) + if err != nil { + t.Fatalf("read %s: %v", name, err) + } + var m map[string]interface{} + if err := json.Unmarshal(b, &m); err != nil { + t.Fatalf("unmarshal %s: %v", name, err) + } + return m + } + + params := dto.DWBG6A2CReq{ + Name: "何志勇", + IDCard: "45212719910201152X", + MobileNo: "18277111590", + } + apiData := map[string]interface{}{ + "FLXG7E8F": map[string]interface{}{"data": load("t2-1.json")}, + "FLXGDEA9": map[string]interface{}{"data": load("t2-2.json")}, + } + report := transformToSinanReport(apiData, params, zap.NewNop()) + + jlr := report["judicialLeaseReport"].(map[string]interface{}) + courtInfo := jlr["courtInfo"].(map[string]interface{}) + if courtInfo["criminalCasesCount"] != 4 { + t.Fatalf("wrapped criminalCasesCount = %v, want 4", courtInfo["criminalCasesCount"]) + } + security := report["securityInfo"].(map[string]interface{}) + if security["escape"] != 1 || security["ikey"] != 1 { + t.Fatalf("wrapped securityInfo = %+v", security) + } + riskList := report["riskList"].(map[string]interface{}) + if riskList["industryBlacklist"] != 1 { + t.Fatalf("wrapped industryBlacklist = %v, want 1", riskList["industryBlacklist"]) + } +} + func TestM1PlusCountCaps(t *testing.T) { apiData := map[string]interface{}{ "JRZQ5E9F": map[string]interface{}{ diff --git a/internal/domains/api/services/processors/dwbg/dwbg6a2c_unwrap.go b/internal/domains/api/services/processors/dwbg/dwbg6a2c_unwrap.go new file mode 100644 index 0000000..2aff755 --- /dev/null +++ b/internal/domains/api/services/processors/dwbg/dwbg6a2c_unwrap.go @@ -0,0 +1,80 @@ +package dwbg + +import ( + "encoding/json" + "strings" + + "tyapi-server/internal/domains/api/services/processors/flxg" +) + +// unwrapSinanSubAPIMap 解包子接口响应中常见的 data / result 嵌套层。 +func unwrapSinanSubAPIMap(m map[string]interface{}) map[string]interface{} { + if m == nil { + return nil + } + if data := asMap(m["data"]); data != nil { + return unwrapSinanSubAPIMap(data) + } + if result := asMap(m["result"]); result != nil && shouldUnwrapResult(m) { + return unwrapSinanSubAPIMap(result) + } + return m +} + +func shouldUnwrapResult(m map[string]interface{}) bool { + for _, key := range []string{"level", "riskCode", "judicial_data", "lawsuitStat", "breachCaseList", "consumptionRestrictionList"} { + if _, ok := m[key]; ok { + return false + } + } + return true +} + +func subAPIPayload(val interface{}) map[string]interface{} { + m := asMap(val) + if m == nil { + if s, ok := val.(string); ok { + s = strings.TrimSpace(s) + if s != "" && (strings.HasPrefix(s, "{") || strings.HasPrefix(s, "[")) { + var parsed map[string]interface{} + if json.Unmarshal([]byte(s), &parsed) == nil { + m = parsed + } + } + } + } + if m == nil { + return nil + } + return unwrapSinanSubAPIMap(m) +} + +func flxg7e8fMap(apiData map[string]interface{}) map[string]interface{} { + payload := subAPIPayload(getMapValue(apiData, "FLXG7E8F")) + if payload == nil { + return nil + } + if jd := asMap(payload["judicial_data"]); jd != nil { + return map[string]interface{}{"judicial_data": jd} + } + if asMap(payload["lawsuitStat"]) != nil || payload["breachCaseList"] != nil || payload["consumptionRestrictionList"] != nil { + return map[string]interface{}{"judicial_data": payload} + } + return payload +} + +func flxgdea9Map(apiData map[string]interface{}) map[string]interface{} { + return subAPIPayload(getMapValue(apiData, "FLXGDEA9")) +} + +func flxgdea9Level(apiData map[string]interface{}) string { + payload := flxgdea9Map(apiData) + if payload == nil { + return "" + } + level := strings.TrimSpace(flxg.LevelFromPayload(payload)) + if level == "0" { + return "" + } + return level +} diff --git a/internal/domains/api/services/processors/flxg/flxgdea9_transform.go b/internal/domains/api/services/processors/flxg/flxgdea9_transform.go index b295626..12e5762 100644 --- a/internal/domains/api/services/processors/flxg/flxgdea9_transform.go +++ b/internal/domains/api/services/processors/flxg/flxgdea9_transform.go @@ -44,6 +44,18 @@ var riskCodeBitLevelMappings = map[int]string{ 24: "E", // 5年前 SJTLAJ } +// LevelFromPayload 从 FLXGDEA9 处理器输出或 nuoer 原始 payload 提取 level 字符串。 +func LevelFromPayload(data map[string]interface{}) string { + if data == nil { + return "0" + } + result := mapNuoerIdRiskToResponse(data) + if level, ok := result["level"].(string); ok { + return level + } + return "0" +} + // mapNuoerIdRiskToResponse 将 nuoer 响应(2json.md)转为对外结构(1json.md): // 解包 result,将 riskCode 转为 level。 func mapNuoerIdRiskToResponse(data map[string]interface{}) map[string]interface{} {