This commit is contained in:
2026-07-24 12:05:48 +08:00
parent edbdc4eafe
commit 903835ede1
3 changed files with 231 additions and 1 deletions

View File

@@ -42,5 +42,9 @@ func ProcessJRZQ0OO1Request(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
transformed, err := transformJRZQ0OO1Response(respBytes)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return transformed, nil
}

View File

@@ -0,0 +1,70 @@
package jrzq
import (
"encoding/json"
"fmt"
"strings"
)
// JRZQ0OO1 字段命名约定:{窗口}_{机构类型}_{事件}_{指标}
// 窗口: m1/m3/m6/m12
// 机构类型: 省略=全部贷款bank=银行cfc=消金sloan=小贷
// 事件: total/severe_overdue/overdue/repay_fail/repay_ok/repay_remind/
//
// disburse_fail/disburse_ok/audit_fail/audit_ok/apply/register/verify_code/marketing/other
//
// 指标: cnt=次数org=机构数
var (
jrzq0OO1Periods = []string{"m1", "m3", "m6", "m12"}
jrzq0OO1InstTypes = []string{"", "bank", "cfc", "sloan"}
jrzq0OO1Events = []string{
"total", "severe_overdue", "overdue", "repay_fail", "repay_ok",
"repay_remind", "disburse_fail", "disburse_ok", "audit_fail", "audit_ok",
"apply", "register", "verify_code", "marketing", "other",
}
jrzq0OO1Metrics = []string{"cnt", "org"}
// jrzq0OO1FieldMap B001-B480 -> 语义化扁平字段名
jrzq0OO1FieldMap = buildJRZQ0OO1FieldMap()
)
func buildJRZQ0OO1FieldMap() map[string]string {
m := make(map[string]string, 480)
n := 1
for _, period := range jrzq0OO1Periods {
for _, inst := range jrzq0OO1InstTypes {
for _, event := range jrzq0OO1Events {
for _, metric := range jrzq0OO1Metrics {
key := fmt.Sprintf("B%03d", n)
parts := []string{period}
if inst != "" {
parts = append(parts, inst)
}
parts = append(parts, event, metric)
m[key] = strings.Join(parts, "_")
n++
}
}
}
}
return m
}
// transformJRZQ0OO1Response 将 Info360 的 Bxxx 字段重命名为语义化扁平字段。
// 未在映射表中的键原样保留。
func transformJRZQ0OO1Response(respBytes []byte) ([]byte, error) {
var raw map[string]interface{}
if err := json.Unmarshal(respBytes, &raw); err != nil {
return nil, err
}
out := make(map[string]interface{}, len(raw))
for k, v := range raw {
if renamed, ok := jrzq0OO1FieldMap[k]; ok {
out[renamed] = v
continue
}
out[k] = v
}
return json.Marshal(out)
}

View File

@@ -0,0 +1,156 @@
package jrzq
import (
"encoding/json"
"testing"
)
func TestBuildJRZQ0OO1FieldMap_CountAndBounds(t *testing.T) {
if len(jrzq0OO1FieldMap) != 480 {
t.Fatalf("expected 480 mappings, got %d", len(jrzq0OO1FieldMap))
}
if got, want := jrzq0OO1FieldMap["B001"], "m1_total_cnt"; got != want {
t.Fatalf("B001: got %q want %q", got, want)
}
if got, want := jrzq0OO1FieldMap["B480"], "m12_sloan_other_org"; got != want {
t.Fatalf("B480: got %q want %q", got, want)
}
}
func TestJRZQ0OO1FieldMap_DocSpotChecks(t *testing.T) {
cases := map[string]string{
"B001": "m1_total_cnt", // 最近1个月贷款类总次数
"B009": "m1_repay_ok_cnt", // 最近1个月还款成功次数
"B031": "m1_bank_total_cnt", // 最近1个月银行类贷款总次数
"B129": "m3_repay_ok_cnt", // 最近3个月还款成功次数
"B130": "m3_repay_ok_org", // 最近3个月还款成功机构数
"B133": "m3_disburse_fail_cnt", // 最近3个月放款失败次数
"B134": "m3_disburse_fail_org", // 最近3个月放款失败机构数
"B157": "m3_bank_repay_fail_cnt", // 最近3个月银行类还款失败次数
"B158": "m3_bank_repay_fail_org", // 最近3个月银行类还款失败机构数
"B219": "m3_sloan_repay_ok_cnt", // 最近3个月小贷类还款成功次数
"B220": "m3_sloan_repay_ok_org", // 最近3个月小贷类还款成功机构数
"B223": "m3_sloan_disburse_fail_cnt", // 最近3个月小贷类放款失败次数
"B224": "m3_sloan_disburse_fail_org", // 最近3个月小贷类放款失败机构数
"B247": "m6_repay_fail_cnt", // 最近6个月还款失败次数
"B248": "m6_repay_fail_org", // 最近6个月还款失败机构数
"B257": "m6_audit_fail_cnt", // 最近6个月审核失败次数
"B258": "m6_audit_fail_org", // 最近6个月审核失败机构数
"B261": "m6_apply_cnt", // 最近6个月贷款申请次数
"B262": "m6_apply_org", // 最近6个月贷款申请机构数
"B285": "m6_bank_disburse_ok_cnt", // 最近6个月银行类放款成功次数
"B286": "m6_bank_disburse_ok_org", // 最近6个月银行类放款成功机构数
"B347": "m6_sloan_audit_fail_cnt", // 最近6个月小贷类审核失败次数
"B348": "m6_sloan_audit_fail_org", // 最近6个月小贷类审核失败机构数
"B351": "m6_sloan_apply_cnt", // 最近6个月小贷类贷款申请次数
"B352": "m6_sloan_apply_org", // 最近6个月小贷类贷款申请机构数
"B375": "m12_disburse_ok_cnt", // 最近12个月放款成功次数
"B376": "m12_disburse_ok_org", // 最近12个月放款成功机构数
"B061": "m1_cfc_total_cnt", // 最近1个月持牌消金类贷款总次数
"B301": "m6_cfc_total_cnt", // 最近6个月消金类贷款总次数
}
for src, want := range cases {
if got := jrzq0OO1FieldMap[src]; got != want {
t.Errorf("%s: got %q want %q", src, got, want)
}
}
}
func TestTransformJRZQ0OO1Response_Sample(t *testing.T) {
in := []byte(`{
"B129": 6,
"B130": 3,
"B133": 4,
"B134": 2,
"B157": 2,
"B158": 1,
"B219": 6,
"B220": 3,
"B223": 4,
"B224": 2,
"B247": 2,
"B248": 1,
"B257": 6,
"B258": 3,
"B261": 4,
"B262": 2,
"B285": 2,
"B286": 1,
"B347": 6,
"B348": 3,
"B351": 4,
"B352": 2,
"B375": 2,
"B376": 1
}`)
outBytes, err := transformJRZQ0OO1Response(in)
if err != nil {
t.Fatal(err)
}
var out map[string]interface{}
if err := json.Unmarshal(outBytes, &out); err != nil {
t.Fatal(err)
}
want := map[string]float64{
"m3_repay_ok_cnt": 6,
"m3_repay_ok_org": 3,
"m3_disburse_fail_cnt": 4,
"m3_disburse_fail_org": 2,
"m3_bank_repay_fail_cnt": 2,
"m3_bank_repay_fail_org": 1,
"m3_sloan_repay_ok_cnt": 6,
"m3_sloan_repay_ok_org": 3,
"m3_sloan_disburse_fail_cnt": 4,
"m3_sloan_disburse_fail_org": 2,
"m6_repay_fail_cnt": 2,
"m6_repay_fail_org": 1,
"m6_audit_fail_cnt": 6,
"m6_audit_fail_org": 3,
"m6_apply_cnt": 4,
"m6_apply_org": 2,
"m6_bank_disburse_ok_cnt": 2,
"m6_bank_disburse_ok_org": 1,
"m6_sloan_audit_fail_cnt": 6,
"m6_sloan_audit_fail_org": 3,
"m6_sloan_apply_cnt": 4,
"m6_sloan_apply_org": 2,
"m12_disburse_ok_cnt": 2,
"m12_disburse_ok_org": 1,
}
if len(out) != len(want) {
t.Fatalf("field count: got %d want %d, out=%v", len(out), len(want), out)
}
for k, w := range want {
got, ok := out[k]
if !ok {
t.Errorf("missing key %s", k)
continue
}
num, ok := got.(float64)
if !ok || num != w {
t.Errorf("%s: got %#v want %v", k, got, w)
}
}
}
func TestTransformJRZQ0OO1Response_KeepUnknown(t *testing.T) {
in := []byte(`{"B001":1,"extra":"x"}`)
outBytes, err := transformJRZQ0OO1Response(in)
if err != nil {
t.Fatal(err)
}
var out map[string]interface{}
if err := json.Unmarshal(outBytes, &out); err != nil {
t.Fatal(err)
}
if _, ok := out["m1_total_cnt"]; !ok {
t.Fatal("expected m1_total_cnt")
}
if out["extra"] != "x" {
t.Fatalf("expected extra kept, got %#v", out["extra"])
}
}