Compare commits

..

22 Commits

Author SHA1 Message Date
Mrx
e246271a24 f 2026-04-23 18:18:47 +08:00
Mrx
a1024ed4b2 f 2026-04-23 17:59:23 +08:00
Mrx
d6b78a5d6d Merge branch 'main' of http://1.117.67.95:3000/team/tyapi-server 2026-04-23 10:55:02 +08:00
Mrx
61c6cc4f35 370982199012037272 2026-04-23 10:55:01 +08:00
cdd1e00745 Merge branch 'main' of http://1.117.67.95:3000/team/tyapi-server 2026-04-21 21:03:56 +08:00
46ba4e048c f 2026-04-21 21:02:02 +08:00
Mrx
3156539319 f 2026-04-21 17:03:03 +08:00
Mrx
dad8abad16 f 2026-04-21 16:24:57 +08:00
Mrx
5f62261c11 f 2026-04-21 16:23:35 +08:00
a0b2105339 f 2026-04-20 19:41:29 +08:00
83e71ae81b f 2026-04-20 19:11:49 +08:00
8675961207 Merge branch 'main' of http://1.117.67.95:3000/team/tyapi-server 2026-04-20 18:45:35 +08:00
4bd6f51728 f 2026-04-20 18:45:34 +08:00
Mrx
cd1db5276a f 2026-04-20 16:58:19 +08:00
Mrx
2f653be375 f 2026-04-20 15:22:25 +08:00
Mrx
9c3fb97b3f f 2026-04-20 10:27:55 +08:00
Mrx
b6053983d9 f 2026-04-18 17:45:18 +08:00
Mrx
c3b16c0ffe ff 2026-04-18 16:41:06 +08:00
Mrx
5f6cca5369 f 2026-04-17 18:41:54 +08:00
Mrx
a01226c7c0 f 2026-04-17 18:37:19 +08:00
Mrx
e67465a58d Merge branch 'main' of http://1.117.67.95:3000/team/tyapi-server 2026-04-16 19:32:23 +08:00
Mrx
75316b10cb f 2026-04-16 19:32:22 +08:00
27 changed files with 2211 additions and 155 deletions

View File

@@ -399,6 +399,7 @@ WechatH5:
# =========================================== # ===========================================
# 🔍 天眼查配置 # 🔍 天眼查配置
# =========================================== # ===========================================
tianyancha: tianyancha:
base_url: http://open.api.tianyancha.com/services base_url: http://open.api.tianyancha.com/services
api_key: e6a43dc9-786e-4a16-bb12-392b8201d8e2 api_key: e6a43dc9-786e-4a16-bb12-392b8201d8e2

View File

@@ -226,13 +226,19 @@ func (s *ApiApplicationServiceImpl) validateApiCall(ctx context.Context, cmd *co
// 4. 验证IP白名单非开发环境 // 4. 验证IP白名单非开发环境
if !s.config.App.IsDevelopment() && !cmd.Options.IsDebug { if !s.config.App.IsDevelopment() && !cmd.Options.IsDebug {
whiteListIPs := make([]string, 0, len(apiUser.WhiteList))
for _, item := range apiUser.WhiteList {
whiteListIPs = append(whiteListIPs, item.IPAddress)
}
// 添加调试日志 // 添加调试日志
s.logger.Info("开始验证白名单", s.logger.Info("开始验证白名单",
zap.String("userId", apiUser.UserId), zap.String("userId", apiUser.UserId),
zap.String("clientIP", cmd.ClientIP), zap.String("clientIP", cmd.ClientIP),
zap.Bool("isDevelopment", s.config.App.IsDevelopment()), zap.Bool("isDevelopment", s.config.App.IsDevelopment()),
zap.Bool("isDebug", cmd.Options.IsDebug), zap.Bool("isDebug", cmd.Options.IsDebug),
zap.Int("whiteListCount", len(apiUser.WhiteList))) zap.Int("whiteListCount", len(apiUser.WhiteList)),
zap.Strings("whiteListIPs", whiteListIPs))
// 输出白名单详细信息(用于调试) // 输出白名单详细信息(用于调试)
for idx, item := range apiUser.WhiteList { for idx, item := range apiUser.WhiteList {
@@ -246,10 +252,13 @@ func (s *ApiApplicationServiceImpl) validateApiCall(ctx context.Context, cmd *co
s.logger.Error("IP不在白名单内", s.logger.Error("IP不在白名单内",
zap.String("userId", apiUser.UserId), zap.String("userId", apiUser.UserId),
zap.String("ip", cmd.ClientIP), zap.String("ip", cmd.ClientIP),
zap.Int("whiteListSize", len(apiUser.WhiteList))) zap.Int("whiteListSize", len(apiUser.WhiteList)),
zap.Strings("whiteListIPs", whiteListIPs))
return nil, ErrInvalidIP return nil, ErrInvalidIP
} }
s.logger.Info("白名单验证通过", zap.String("ip", cmd.ClientIP)) s.logger.Info("白名单验证通过",
zap.String("ip", cmd.ClientIP),
zap.Strings("whiteListIPs", whiteListIPs))
} }
// 5. 验证钱包状态 // 5. 验证钱包状态

View File

@@ -499,6 +499,12 @@ type IVYZ7F3AReq struct {
Name string `json:"name" validate:"required,min=1,validName"` Name string `json:"name" validate:"required,min=1,validName"`
Authorized string `json:"authorized" validate:"required,oneof=0 1"` Authorized string `json:"authorized" validate:"required,oneof=0 1"`
} }
type IVYZRAX1Req struct {
Name string `json:"name" validate:"required,min=1,validName"`
IDCard string `json:"id_card" validate:"required,validIDCard"`
MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"`
Authorized string `json:"authorized" validate:"required,oneof=0 1"`
}
type IVYZ3P9MReq struct { type IVYZ3P9MReq struct {
IDCard string `json:"id_card" validate:"required,validIDCard"` IDCard string `json:"id_card" validate:"required,validIDCard"`
@@ -665,6 +671,11 @@ type QYGLDJ12Req struct {
EntCode string `json:"ent_code" validate:"omitempty,validUSCI"` EntCode string `json:"ent_code" validate:"omitempty,validUSCI"`
EntRegNo string `json:"ent_reg_no" validate:"omitempty"` EntRegNo string `json:"ent_reg_no" validate:"omitempty"`
} }
type QYGLDJ33Req struct {
EntName string `json:"ent_name" validate:"omitempty,min=1,validEnterpriseName"`
EntCode string `json:"ent_code" validate:"omitempty,validUSCI"`
EntRegNo string `json:"ent_reg_no" validate:"omitempty"`
}
type YYSY6D9AReq struct { type YYSY6D9AReq struct {
MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"` MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"`
IDCard string `json:"id_card" validate:"required,validIDCard"` IDCard string `json:"id_card" validate:"required,validIDCard"`
@@ -1048,6 +1059,13 @@ type IVYZA1B3Req struct {
PhotoData string `json:"photo_data" validate:"required,validBase64Image"` PhotoData string `json:"photo_data" validate:"required,validBase64Image"`
} }
type IVYZFIC1Req struct {
IDCard string `json:"id_card" validate:"required,validIDCard"`
Name string `json:"name" validate:"required,min=1,validName"`
PhotoData string `json:"photo_data" validate:"omitempty,validBase64Image"`
ImageUrl string `json:"+" validate:"omitempty,url"`
}
type IVYZC4R9Req struct { type IVYZC4R9Req struct {
IDCard string `json:"id_card" validate:"required,validIDCard"` IDCard string `json:"id_card" validate:"required,validIDCard"`
Name string `json:"name" validate:"required,min=1,validName"` Name string `json:"name" validate:"required,min=1,validName"`

View File

@@ -248,6 +248,7 @@ func registerAllProcessors(combService *comb.CombService) {
"QYGLUY3S": qygl.ProcessQYGLUY3SRequest, //企业经营状态全景查询 "QYGLUY3S": qygl.ProcessQYGLUY3SRequest, //企业经营状态全景查询
"QYGLDJ12": qygl.ProcessQYGLDJ12Request, //企业年报信息核验 "QYGLDJ12": qygl.ProcessQYGLDJ12Request, //企业年报信息核验
"QYGL8848": qygl.ProcessQYGL8848Request, //企业税收违法核查 "QYGL8848": qygl.ProcessQYGL8848Request, //企业税收违法核查
"QYGLDJ33": qygl.ProcessQYGLDJ33Request, //企业年报信息核验
// YYSY系列处理器 // YYSY系列处理器
"YYSY35TA": yysy.ProcessYYSY35TARequest, //运营商归属地数卖 "YYSY35TA": yysy.ProcessYYSY35TARequest, //运营商归属地数卖
@@ -318,6 +319,7 @@ func registerAllProcessors(combService *comb.CombService) {
"IVYZ1J7H": ivyz.ProcessIVYZ1J7HRequest, //行驶证核查v2 "IVYZ1J7H": ivyz.ProcessIVYZ1J7HRequest, //行驶证核查v2
"IVYZ9K7F": ivyz.ProcessIVYZ9K7FRequest, //身份证实名认证即时版 "IVYZ9K7F": ivyz.ProcessIVYZ9K7FRequest, //身份证实名认证即时版
"IVYZA1B3": ivyz.ProcessIVYZA1B3Request, //公安三要素人脸识别 "IVYZA1B3": ivyz.ProcessIVYZA1B3Request, //公安三要素人脸识别
"IVYZFIC1": ivyz.ProcessIVYZFIC1Request, //人脸身份证比对(数脉)
"IVYZN2P8": ivyz.ProcessIVYZN2P8Request, //身份证实名认证政务版 "IVYZN2P8": ivyz.ProcessIVYZN2P8Request, //身份证实名认证政务版
"IVYZX5QZ": ivyz.ProcessIVYZX5QZRequest, //活体检测 "IVYZX5QZ": ivyz.ProcessIVYZX5QZRequest, //活体检测
"IVYZX5Q2": ivyz.ProcessIVYZX5Q2Request, //活体识别步骤二 "IVYZX5Q2": ivyz.ProcessIVYZX5Q2Request, //活体识别步骤二
@@ -328,6 +330,9 @@ func registerAllProcessors(combService *comb.CombService) {
"IVYZ38SR": ivyz.ProcessIVYZ38SRRequest, //婚姻状态核验(双人) "IVYZ38SR": ivyz.ProcessIVYZ38SRRequest, //婚姻状态核验(双人)
"IVYZ48SR": ivyz.ProcessIVYZ48SRRequest, //婚姻状态核验V2双人 "IVYZ48SR": ivyz.ProcessIVYZ48SRRequest, //婚姻状态核验V2双人
"IVYZ5E22": ivyz.ProcessIVYZ5E22Request, //双人婚姻评估查询zhicha版本 "IVYZ5E22": ivyz.ProcessIVYZ5E22Request, //双人婚姻评估查询zhicha版本
"IVYZRAX1": ivyz.ProcessIVYZRAX1Request, //融安信用分
"IVYZRAX2": ivyz.ProcessIVYZRAX2Request,//融御反欺诈分
// COMB系列处理器 - 只注册有自定义逻辑的组合包 // COMB系列处理器 - 只注册有自定义逻辑的组合包
"COMB86PM": comb.ProcessCOMB86PMRequest, // 有自定义逻辑重命名ApiCode "COMB86PM": comb.ProcessCOMB86PMRequest, // 有自定义逻辑重命名ApiCode

View File

@@ -241,6 +241,7 @@ func (s *FormConfigServiceImpl) getDTOStruct(ctx context.Context, apiCode string
"YYSYK8R3": &dto.YYSYK8R3Req{}, //手机空号检测查询 "YYSYK8R3": &dto.YYSYK8R3Req{}, //手机空号检测查询
"YYSYF2T7": &dto.YYSYF2T7Req{}, //手机二次放号检测查询 "YYSYF2T7": &dto.YYSYF2T7Req{}, //手机二次放号检测查询
"IVYZA1B3": &dto.IVYZA1B3Req{}, //公安三要素人脸识别 "IVYZA1B3": &dto.IVYZA1B3Req{}, //公安三要素人脸识别
"IVYZFIC1": &dto.IVYZFIC1Req{}, //人脸身份证比对(数脉)
"IVYZX5QZ": &dto.IVYZX5QZReq{}, //活体识别 "IVYZX5QZ": &dto.IVYZX5QZReq{}, //活体识别
"IVYZN2P8": &dto.IVYZ9K7FReq{}, //身份证实名认证政务版 "IVYZN2P8": &dto.IVYZ9K7FReq{}, //身份证实名认证政务版
"YYSYH6F3": &dto.YYSYH6F3Req{}, //运营商三要素简版即时版查询 "YYSYH6F3": &dto.YYSYH6F3Req{}, //运营商三要素简版即时版查询
@@ -274,6 +275,9 @@ func (s *FormConfigServiceImpl) getDTOStruct(ctx context.Context, apiCode string
"IVYZ48SR": &dto.IVYZ48SRReq{}, //婚姻状态核验V2双人 "IVYZ48SR": &dto.IVYZ48SRReq{}, //婚姻状态核验V2双人
"IVYZ5E22": &dto.IVYZ5E22Req{}, //双人婚姻评估查询zhicha版本 "IVYZ5E22": &dto.IVYZ5E22Req{}, //双人婚姻评估查询zhicha版本
"DWBG5SAM": &dto.DWBG5SAMReq{}, //天远指迷报告 "DWBG5SAM": &dto.DWBG5SAMReq{}, //天远指迷报告
"QYGLDJ33": &dto.QYGLDJ33Req{}, //企业年报信息核验
"IVYZRAX1": &dto.IVYZRAX1Req{},//融安信用分
"IVYZRAX2": &dto.IVYZRAX1Req{},//融御反欺诈
} }
// 优先返回已配置的DTO // 优先返回已配置的DTO
@@ -635,7 +639,7 @@ func (s *FormConfigServiceImpl) generatePlaceholder(jsonTag string, fieldType st
"notice_model": "请输入车辆型号", "notice_model": "请输入车辆型号",
"vlphoto_data": "请输入行驶证图片", "vlphoto_data": "请输入行驶证图片",
"carplate_type": "请选择车辆号牌类型01-大型汽车 02-小型汽车 03-使馆汽车 04-领馆汽车 05-境外汽车 06-外籍汽车 07-普通摩托车 08-轻便摩托车 09-使馆摩托车 10-领馆摩托车 11-境外摩托车 12-外籍摩托车 13-低速车 14-拖拉机 15-挂车 16-教练汽车 17-教练摩托车 20-临时入境汽车 21-临时入境摩托车 22-临时行驶车 23-警用汽车 24-警用摩托 51-新能源大型车 52-新能源小型车)", "carplate_type": "请选择车辆号牌类型01-大型汽车 02-小型汽车 03-使馆汽车 04-领馆汽车 05-境外汽车 06-外籍汽车 07-普通摩托车 08-轻便摩托车 09-使馆摩托车 10-领馆摩托车 11-境外摩托车 12-外籍摩托车 13-低速车 14-拖拉机 15-挂车 16-教练汽车 17-教练摩托车 20-临时入境汽车 21-临时入境摩托车 22-临时行驶车 23-警用汽车 24-警用摩托 51-新能源大型车 52-新能源小型车)",
"image_url": "请输入行驶证图片地址", "image_url": "请输入入参图片地址",
"reg_url": "请输入车辆登记证图片地址", "reg_url": "请输入车辆登记证图片地址",
"token": "请输入token", "token": "请输入token",
"vehicle_name": "请输入车型名称", "vehicle_name": "请输入车型名称",

View File

@@ -25,7 +25,7 @@ func ProcessFLXG0V4BRequest(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err) return nil, errors.Join(processors.ErrInvalidParam, err)
} }
// 去掉司法案件案件去掉身份证号码 // 去掉司法案件案件去掉身份证号码
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" { if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "370982199012037272" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" || paramsDto.IDCard == "410482198504029333" || paramsDto.IDCard == "370982199012037272" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空")) return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
} }
encryptedName, err := deps.WestDexService.Encrypt(paramsDto.Name) encryptedName, err := deps.WestDexService.Encrypt(paramsDto.Name)

View File

@@ -20,7 +20,7 @@ func ProcessFLXG5A3BRequest(ctx context.Context, params []byte, deps *processors
if err := deps.Validator.ValidateStruct(paramsDto); err != nil { if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err) return nil, errors.Join(processors.ErrInvalidParam, err)
} }
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" || paramsDto.IDCard == "410482198504029333" { if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "370982199012037272" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" || paramsDto.IDCard == "410482198504029333" || paramsDto.IDCard == "370982199012037272" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空")) return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
} }
encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name) encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)

View File

@@ -7,7 +7,7 @@ import (
"tyapi-server/internal/domains/api/dto" "tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors" "tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/xingwei" "tyapi-server/internal/infrastructure/external/zhicha"
) )
// ProcessFLXG7E8FRequest FLXG7E8F API处理方法 - 个人司法数据查询 // ProcessFLXG7E8FRequest FLXG7E8F API处理方法 - 个人司法数据查询
@@ -20,30 +20,225 @@ func ProcessFLXG7E8FRequest(ctx context.Context, params []byte, deps *processors
if err := deps.Validator.ValidateStruct(paramsDto); err != nil { if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err) return nil, errors.Join(processors.ErrInvalidParam, err)
} }
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" || paramsDto.IDCard == "410482198504029333" { if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "370982199012037272" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" || paramsDto.IDCard == "410482198504029333" || paramsDto.IDCard == "370982199012037272" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空")) return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
} }
// 构建请求数据,将项目规范的字段名转换为 XingweiService 需要的字段名
reqData := map[string]interface{}{ encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
"name": paramsDto.Name, if err != nil {
"idCardNum": paramsDto.IDCard, return nil, errors.Join(processors.ErrSystem, err)
"phoneNumber": paramsDto.MobileNo,
} }
// 调用行为数据API使用指定的project_id encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
projectID := "CDJ-1101695378264092672"
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
if err != nil { if err != nil {
if errors.Is(err, xingwei.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, xingwei.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, xingwei.ErrSystem) {
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": "1",
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI006", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else { } else {
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
} }
} }
respMap, ok := respData.(map[string]interface{})
if !ok {
return nil, errors.Join(processors.ErrSystem, errors.New("响应格式错误"))
}
result := map[string]interface{}{
"judicial_data": mapFLXG5A3BToJudicialData(respMap),
}
respBytes, err := json.Marshal(result)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil return respBytes, nil
} }
func mapFLXG5A3BToJudicialData(resp map[string]interface{}) map[string]interface{} {
judicialData := map[string]interface{}{
"consumptionRestrictionList": mapXgbzxrToConsumptionRestriction(asSlice(resp["xgbzxr"])),
"breachCaseList": mapSxbzxrToBreachCaseList(asSlice(resp["sxbzxr"])),
"lawsuitStat": normalizeLawsuitStat(asMap(resp["entout"])),
}
return judicialData
}
func mapXgbzxrToConsumptionRestriction(items []interface{}) []map[string]interface{} {
result := make([]map[string]interface{}, 0, len(items))
for _, item := range items {
m := asMap(item)
if len(m) == 0 {
continue
}
result = append(result, map[string]interface{}{
"caseNumber": m["ah"],
"id": m["id"],
"issueDate": m["fbrq"],
"executiveCourt": m["zxfy"],
"fileDate": m["larq"],
})
}
return result
}
func mapSxbzxrToBreachCaseList(items []interface{}) []map[string]interface{} {
result := make([]map[string]interface{}, 0, len(items))
for _, item := range items {
m := asMap(item)
if len(m) == 0 {
continue
}
result = append(result, map[string]interface{}{
"caseNumber": m["ah"],
"issueDate": m["fbrq"],
"id": m["id"],
"fileDate": m["larq"],
"fulfillStatus": m["lxqk"],
"estimatedJudgementAmount": m["pjje_gj"],
"province": m["sf"],
"sex": m["xb"],
"concreteDetails": m["xwqx"],
"obligation": m["yw"],
"executiveCourt": m["zxfy"],
"enforcementBasisOrganization": m["zxyjdw"],
"enforcementBasisNumber": m["zxyjwh"],
})
}
return result
}
func normalizeLawsuitStat(entout map[string]interface{}) map[string]interface{} {
lawsuitStat := defaultLawsuitStat()
for k, v := range entout {
switch k {
case "cases_tree":
lawsuitStat[k] = normalizeCasesTree(asMap(v))
case "count":
lawsuitStat[k] = normalizeCount(asMap(v))
case "preservation", "administrative", "civil", "implement", "criminal", "bankrupt":
lawsuitStat[k] = normalizeCaseSection(asMap(v))
default:
lawsuitStat[k] = v
}
}
return lawsuitStat
}
func defaultLawsuitStat() map[string]interface{} {
return map[string]interface{}{
"crc": 0,
"cases_tree": normalizeCasesTree(map[string]interface{}{}),
"count": normalizeCount(map[string]interface{}{}),
"preservation": normalizeCaseSection(map[string]interface{}{}),
"administrative": normalizeCaseSection(map[string]interface{}{}),
"civil": normalizeCaseSection(map[string]interface{}{}),
"implement": normalizeCaseSection(map[string]interface{}{}),
"criminal": normalizeCaseSection(map[string]interface{}{}),
"bankrupt": normalizeCaseSection(map[string]interface{}{}),
}
}
func normalizeCasesTree(src map[string]interface{}) map[string]interface{} {
dst := map[string]interface{}{
"administrative": []interface{}{},
"criminal": []interface{}{},
"civil": []interface{}{},
}
for _, key := range []string{"administrative", "criminal", "civil"} {
if v, ok := src[key]; ok {
dst[key] = asSlice(v)
}
}
return dst
}
func normalizeCaseSection(src map[string]interface{}) map[string]interface{} {
dst := map[string]interface{}{
"cases": []interface{}{},
"count": normalizeCount(map[string]interface{}{}),
}
if v, ok := src["cases"]; ok {
dst["cases"] = asSlice(v)
}
if v, ok := src["count"]; ok {
dst["count"] = normalizeCount(asMap(v))
}
return dst
}
func normalizeCount(src map[string]interface{}) map[string]interface{} {
dst := map[string]interface{}{
"money_yuangao": 0,
"area_stat": "",
"count_jie_beigao": 0,
"count_total": 0,
"money_wei_yuangao": 0,
"count_wei_total": 0,
"money_wei_beigao": 0,
"count_other": 0,
"money_beigao": 0,
"count_yuangao": 0,
"money_jie_other": 0,
"money_total": 0,
"money_wei_total": 0,
"count_wei_yuangao": 0,
"ay_stat": "",
"count_beigao": 0,
"money_jie_yuangao": 0,
"jafs_stat": "",
"money_jie_beigao": 0,
"count_wei_beigao": 0,
"count_jie_other": 0,
"count_jie_total": 0,
"count_wei_other": 0,
"money_other": 0,
"count_jie_yuangao": 0,
"money_jie_total": 0,
"money_wei_other": 0,
"money_wei_percent": 0,
"larq_stat": "",
}
for k, v := range src {
dst[k] = v
}
return dst
}
func asMap(v interface{}) map[string]interface{} {
if v == nil {
return map[string]interface{}{}
}
if m, ok := v.(map[string]interface{}); ok {
return m
}
return map[string]interface{}{}
}
func asSlice(v interface{}) []interface{} {
if v == nil {
return []interface{}{}
}
if s, ok := v.([]interface{}); ok {
return s
}
return []interface{}{}
}

View File

@@ -20,7 +20,7 @@ func ProcessFLXGCA3DRequest(ctx context.Context, params []byte, deps *processors
if err := deps.Validator.ValidateStruct(paramsDto); err != nil { if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err) return nil, errors.Join(processors.ErrInvalidParam, err)
} }
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" { if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "370982199012037272" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" || paramsDto.IDCard == "410482198504029333" || paramsDto.IDCard == "370982199012037272" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空")) return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
} }
encryptedName, err := deps.WestDexService.Encrypt(paramsDto.Name) encryptedName, err := deps.WestDexService.Encrypt(paramsDto.Name)

View File

@@ -25,7 +25,7 @@ func ProcessFLXGDEA9Request(ctx context.Context, params []byte, deps *processors
if err != nil { if err != nil {
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
} }
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" { if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "370982199012037272" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" || paramsDto.IDCard == "410482198504029333" || paramsDto.IDCard == "370982199012037272" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空")) return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
} }
encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard) encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)

View File

@@ -0,0 +1,64 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/muzi"
)
// ProcessIVYZ3P9MRequest IVYZ3P9M API处理方法 - 学历查询实时版
func ProcessIVYZ3P9MRequest_2(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ3P9MReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
encryptedName, err := deps.MuziService.Encrypt(paramsDto.Name)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedCertCode, err := deps.MuziService.Encrypt(paramsDto.IDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
// 处理 returnType 参数,默认为 "1"
returnType := paramsDto.ReturnType
if returnType == "" {
returnType = "1"
}
paramSign := map[string]interface{}{
"returnType": returnType,
"realName": encryptedName,
"certCode": encryptedCertCode,
}
reqData := map[string]interface{}{
"realName": encryptedName,
"certCode": encryptedCertCode,
"returnType": returnType,
}
respData, err := deps.MuziService.CallAPI(ctx, "PC0041", "/academic", reqData, paramSign)
if err != nil {
switch {
case errors.Is(err, muzi.ErrDatasource):
return nil, errors.Join(processors.ErrDatasource, err)
case errors.Is(err, muzi.ErrSystem):
return nil, errors.Join(processors.ErrSystem, err)
default:
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respData, nil
}

View File

@@ -4,10 +4,11 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"strings"
"tyapi-server/internal/domains/api/dto" "tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors" "tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/muzi" "tyapi-server/internal/infrastructure/external/zhicha"
) )
// ProcessIVYZ3P9MRequest IVYZ3P9M API处理方法 - 学历查询实时版 // ProcessIVYZ3P9MRequest IVYZ3P9M API处理方法 - 学历查询实时版
@@ -21,45 +22,147 @@ func ProcessIVYZ3P9MRequest(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err) return nil, errors.Join(processors.ErrInvalidParam, err)
} }
encryptedName, err := deps.MuziService.Encrypt(paramsDto.Name) encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
if err != nil { if err != nil {
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
} }
encryptedCertCode, err := deps.MuziService.Encrypt(paramsDto.IDCard) encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
if err != nil { if err != nil {
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
} }
// 处理 returnType 参数,默认为 "1"
returnType := paramsDto.ReturnType
if returnType == "" {
returnType = "1"
}
paramSign := map[string]interface{}{
"returnType": returnType,
"realName": encryptedName,
"certCode": encryptedCertCode,
}
reqData := map[string]interface{}{ reqData := map[string]interface{}{
"realName": encryptedName, "name": encryptedName,
"certCode": encryptedCertCode, "idCard": encryptedIDCard,
"returnType": returnType, "authorized": "1",
} }
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI1004", reqData)
respData, err := deps.MuziService.CallAPI(ctx, "PC0041", "/academic",reqData,paramSign)
if err != nil { if err != nil {
switch { if errors.Is(err, zhicha.ErrDatasource) {
case errors.Is(err, muzi.ErrDatasource):
return nil, errors.Join(processors.ErrDatasource, err) return nil, errors.Join(processors.ErrDatasource, err)
case errors.Is(err, muzi.ErrSystem): }
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
}
out, err := mapZCI1004ToIVYZ3P9M(respData, paramsDto.Name, paramsDto.IDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return json.Marshal(out)
}
type zci1004Item struct {
EndDate string `json:"endDate"`
EducationLevel string `json:"educationLevel"`
LearningForm string `json:"learningForm"`
}
type ivyz3p9mItem struct {
GraduationDate string `json:"graduationDate"`
StudentName string `json:"studentName"`
EducationLevel string `json:"educationLevel"`
LearningForm string `json:"learningForm"`
IDNumber string `json:"idNumber"`
}
func mapZCI1004ToIVYZ3P9M(respData interface{}, name, idCard string) ([]ivyz3p9mItem, error) {
respBytes, err := json.Marshal(respData)
if err != nil {
return nil, err
}
var source []zci1004Item
if err := json.Unmarshal(respBytes, &source); err != nil {
var wrapped struct {
Data []zci1004Item `json:"data"`
}
if err2 := json.Unmarshal(respBytes, &wrapped); err2 != nil {
return nil, err
}
source = wrapped.Data
}
out := make([]ivyz3p9mItem, 0, len(source))
for _, it := range source {
out = append(out, ivyz3p9mItem{
GraduationDate: normalizeDateDigits(it.EndDate),
StudentName: name,
EducationLevel: mapEducationLevelToCode(it.EducationLevel),
LearningForm: mapLearningFormToCode(it.LearningForm),
IDNumber: idCard,
})
}
return out, nil
}
func mapEducationLevelToCode(level string) string {
v := normalizeText(level)
switch {
case strings.Contains(v, "第二学士"):
return "5"
case strings.Contains(v, "博士"):
return "4"
case strings.Contains(v, "硕士"):
return "3"
case strings.Contains(v, "本科"):
return "2"
case strings.Contains(v, "专科"), strings.Contains(v, "大专"):
return "1"
default: default:
return nil, errors.Join(processors.ErrSystem, err) return "99"
} }
} }
return respData, nil func mapLearningFormToCode(form string) string {
v := normalizeText(form)
switch {
case strings.Contains(v, "脱产"):
return "1"
case strings.Contains(v, "普通全日制"):
return "2"
case strings.Contains(v, "全日制"):
return "3"
case strings.Contains(v, "开放教育"), strings.Contains(v, "开放大学"):
return "4"
case strings.Contains(v, "夜大学"), strings.Contains(v, "夜大"):
return "5"
case strings.Contains(v, "函授"):
return "6"
case strings.Contains(v, "网络教育"), strings.Contains(v, "网教"), strings.Contains(v, "远程教育"):
return "7"
case strings.Contains(v, "非全日制"):
return "8"
case strings.Contains(v, "业余"):
return "9"
case strings.Contains(v, "自学考试"), strings.Contains(v, "自考"):
// 自考在既有枚举中无直对应,兼容并入“业余”
return "9"
default:
return "99"
}
}
func normalizeDateDigits(s string) string {
trimmed := strings.TrimSpace(s)
if trimmed == "" {
return ""
}
var b strings.Builder
for _, ch := range trimmed {
if ch >= '0' && ch <= '9' {
b.WriteRune(ch)
}
}
return b.String()
}
func normalizeText(s string) string {
v := strings.TrimSpace(strings.ToLower(s))
v = strings.ReplaceAll(v, " ", "")
v = strings.ReplaceAll(v, "-", "")
v = strings.ReplaceAll(v, "_", "")
return v
} }

View File

@@ -0,0 +1,55 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"strings"
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/shumai"
)
// ProcessIVYZFIC1Request IVYZFIC1 人脸身份证比对 API 处理方法(数脉)
func ProcessIVYZFIC1Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZFIC1Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
if strings.TrimSpace(paramsDto.PhotoData) == "" && strings.TrimSpace(paramsDto.ImageUrl) == "" {
return nil, errors.Join(processors.ErrInvalidParam, errors.New("image和url至少传一个"))
}
reqFormData := map[string]interface{}{
"idcard": paramsDto.IDCard,
"name": paramsDto.Name,
"image": paramsDto.PhotoData,
"url": paramsDto.ImageUrl,
}
apiPath := "/v4/face_id_card/compare"
// 先尝试政务接口,再回退实时接口
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, true)
if err != nil {
respBytes, err = deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, false)
if err != nil {
if errors.Is(err, shumai.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, shumai.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
return nil, errors.Join(processors.ErrSystem, err)
}
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,68 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessIVYZRAX1Request IVYZRAX1 API处理方法 - 融安信用分
func ProcessIVYZRAX1Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZRAX1Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
// if err != nil {
// return nil, errors.Join(processors.ErrSystem, err)
// }
// encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
// if err != nil {
// return nil, errors.Join(processors.ErrSystem, err)
// }
// encryptedMoblie, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
// if err != nil {
// return nil, errors.Join(processors.ErrSystem, err)
// }
md5Name := deps.ZhichaService.MD5(paramsDto.Name)
md5IDCard := deps.ZhichaService.MD5(paramsDto.IDCard)
md5Mobile := deps.ZhichaService.MD5(paramsDto.MobileNo)
reqData := map[string]interface{}{
// "name": encryptedName,
// "idCard": encryptedIDCard,
// "phone": encryptedMoblie,
"authorized": paramsDto.Authorized,
"name": md5Name,
"idCard": md5IDCard,
"phone": md5Mobile,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI084", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 将响应数据转换为JSON字节
respBytes, err := json.Marshal(respData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -0,0 +1,68 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessIVYZRAX2Request IVYZRAX2 API处理方法 - 融御反欺诈分
func ProcessIVYZRAX2Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZRAX1Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
// if err != nil {
// return nil, errors.Join(processors.ErrSystem, err)
// }
// encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
// if err != nil {
// return nil, errors.Join(processors.ErrSystem, err)
// }
// encryptedMoblie, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
// if err != nil {
// return nil, errors.Join(processors.ErrSystem, err)
// }
md5Name := deps.ZhichaService.MD5(paramsDto.Name)
md5IDCard := deps.ZhichaService.MD5(paramsDto.IDCard)
md5Mobile := deps.ZhichaService.MD5(paramsDto.MobileNo)
reqData := map[string]interface{}{
// "name": encryptedName,
// "idCard": encryptedIDCard,
// "phone": encryptedMoblie,
"authorized": paramsDto.Authorized,
"name": md5Name,
"idCard": md5IDCard,
"phone": md5Mobile,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI083", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 将响应数据转换为JSON字节
respBytes, err := json.Marshal(respData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -4,10 +4,15 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"math"
"strconv"
"strings"
"time"
"tyapi-server/internal/domains/api/dto" "tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors" "tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/xingwei" "tyapi-server/internal/infrastructure/external/shumai"
) )
// ProcessIVYZZQT3Request IVYZZQT3 人脸比对V3API处理方法 // ProcessIVYZZQT3Request IVYZZQT3 人脸比对V3API处理方法
@@ -21,31 +26,187 @@ func ProcessIVYZZQT3Request(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err) return nil, errors.Join(processors.ErrInvalidParam, err)
} }
// 构建请求数据使用xingwei服务的正确字段名 // 使用数脉接口进行人脸身份证比对
reqData := map[string]interface{}{ reqFormData := map[string]interface{}{
"idcard": paramsDto.IDCard,
"name": paramsDto.Name, "name": paramsDto.Name,
"idCardNum": paramsDto.IDCard,
"image": paramsDto.PhotoData, "image": paramsDto.PhotoData,
} }
// 调用行为数据API使用指定的project_id apiPath := "/v4/face_id_card/compare"
projectID := "CDJ-1104321430396268544"
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData) // 先尝试政务接口,再回退实时接口
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, true)
if err != nil { if err != nil {
if errors.Is(err, xingwei.ErrNotFound) { respBytes, err = deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, false)
// 查空情况,返回特定的查空错误 if err != nil {
if errors.Is(err, shumai.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err) return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, xingwei.ErrDatasource) { } else if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err) return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, xingwei.ErrSystem) { } else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
} else { }
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
} }
} }
return respBytes, nil outBytes, err := mapShumaiFaceCompareToIVYZZQT3(respBytes)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return outBytes, nil
}
type shumaiFaceCompareResp struct {
OrderNo string `json:"order_no"`
Score interface{} `json:"score"`
Msg string `json:"msg"`
Incorrect interface{} `json:"incorrect"`
}
type ivyzzqt3Out struct {
HandleTime string `json:"handleTime"`
ResultData ivyzzqt3OutResultData `json:"resultData"`
OrderNo string `json:"orderNo"`
}
type ivyzzqt3OutResultData struct {
VerificationCode string `json:"verification_code"`
VerificationResult string `json:"verification_result"`
VerificationMessage string `json:"verification_message"`
Similarity string `json:"similarity"`
}
func mapShumaiFaceCompareToIVYZZQT3(respBytes []byte) ([]byte, error) {
var r shumaiFaceCompareResp
if err := json.Unmarshal(respBytes, &r); err != nil {
return nil, err
}
score := parseScoreToFloat64(r.Score)
similarity := strconv.Itoa(int(math.Round(mapScoreToSimilarity(score))))
verificationResult := mapScoreToVerificationResult(score)
verificationMessage := strings.TrimSpace(r.Msg)
if verificationMessage == "" {
verificationMessage = mapScoreToVerificationMessage(score)
}
out := ivyzzqt3Out{
HandleTime: time.Now().Format("2006-01-02 15:04:05"),
OrderNo: strings.TrimSpace(r.OrderNo),
ResultData: ivyzzqt3OutResultData{
VerificationCode: mapVerificationCode(verificationResult, r.Incorrect),
VerificationResult: verificationResult,
VerificationMessage: verificationMessage,
Similarity: similarity,
},
}
return json.Marshal(out)
}
func mapScoreToVerificationResult(score float64) string {
if score >= 0.45 {
return "valid"
}
// 旧结构仅支持 valid/invalid不能确定场景按 invalid 返回
return "invalid"
}
func mapScoreToVerificationMessage(score float64) string {
if score < 0.40 {
return "系统判断为不同人"
}
if score < 0.45 {
return "不能确定是否为同一人"
}
return "系统判断为同一人"
}
func mapScoreToSimilarity(score float64) float64 {
// 将 score(0~1) 分段映射到 similarity(0~1000),并对齐业务阈值:
// 0.40 -> 6000.45 -> 700
if score <= 0 {
return 0
}
if score >= 1 {
return 1000
}
if score < 0.40 {
// [0, 0.40) -> [0, 600)
return (score / 0.40) * 600
}
if score < 0.45 {
// [0.40, 0.45) -> [600, 700)
return 600 + ((score-0.40)/0.05)*100
}
// [0.45, 1] -> [700, 1000]
return 700 + ((score-0.45)/0.55)*300
}
func parseScoreToFloat64(v interface{}) float64 {
switch t := v.(type) {
case float64:
return t
case float32:
return float64(t)
case int:
return float64(t)
case int32:
return float64(t)
case int64:
return float64(t)
case json.Number:
if f, err := t.Float64(); err == nil {
return f
}
case string:
s := strings.TrimSpace(t)
if s == "" {
return 0
}
if f, err := strconv.ParseFloat(s, 64); err == nil {
return f
}
}
return 0
}
func valueToString(v interface{}) string {
switch t := v.(type) {
case string:
return strings.TrimSpace(t)
case json.Number:
return t.String()
case float64:
return strconv.FormatFloat(t, 'f', -1, 64)
case float32:
return strconv.FormatFloat(float64(t), 'f', -1, 64)
case int:
return strconv.Itoa(t)
case int32:
return strconv.FormatInt(int64(t), 10)
case int64:
return strconv.FormatInt(t, 10)
default:
if v == nil {
return ""
}
return strings.TrimSpace(fmt.Sprint(v))
}
}
func mapVerificationCode(verificationResult string, upstreamIncorrect interface{}) string {
if verificationResult == "valid" {
return "1000"
}
if verificationResult == "invalid" {
return "2006"
}
// 兜底:若后续扩展出其它结果,保持可追溯
if s := valueToString(upstreamIncorrect); s != "" {
return s
}
return "2006"
} }

View File

@@ -4,13 +4,15 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"math"
"strconv"
"tyapi-server/internal/domains/api/dto" "tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors" "tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/xingwei" "tyapi-server/internal/infrastructure/external/zhicha"
) )
// ProcessJRZQ0L85Request JRZQ0L85 API处理方法 - xingwei service // ProcessJRZQ0L85Request JRZQ0L85 API处理方法 - 个人信用分
func ProcessJRZQ0L85Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) { func ProcessJRZQ0L85Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.JRZQ0L85Req var paramsDto dto.JRZQ0L85Req
if err := json.Unmarshal(params, &paramsDto); err != nil { if err := json.Unmarshal(params, &paramsDto); err != nil {
@@ -21,27 +23,100 @@ func ProcessJRZQ0L85Request(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err) return nil, errors.Join(processors.ErrInvalidParam, err)
} }
// 构建请求数据,将项目规范的字段名转换为 XingweiService 需要的字段名 encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
reqData := map[string]interface{}{ if err != nil {
"name": paramsDto.Name, return nil, errors.Join(processors.ErrSystem, err)
"idCardNum": paramsDto.IDCard,
"phoneNumber": paramsDto.MobileNo,
} }
// 调用行为数据API使用指定的project_id encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
projectID := "CDJ-1101695364016041984"
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
if err != nil { if err != nil {
if errors.Is(err, xingwei.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, xingwei.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, xingwei.ErrSystem) {
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
}
encryptedMobileNo, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"phone": encryptedMobileNo,
"authorized": "1",
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI021", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else { } else {
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
} }
} }
score := "-1"
if m, ok := respData.(map[string]interface{}); ok {
if raw, exists := m["xyp_cpl0081"]; exists {
if v, ok := parseToFloat64(raw); ok {
score = mapXypToGeneralScore(v)
}
}
}
result := map[string]interface{}{
"score_120_General": score,
}
respBytes, err := json.Marshal(result)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil return respBytes, nil
} }
func parseToFloat64(v interface{}) (float64, bool) {
switch value := v.(type) {
case float64:
return value, true
case string:
if value == "" {
return 0, false
}
f, err := strconv.ParseFloat(value, 64)
if err != nil {
return 0, false
}
return f, true
case json.Number:
f, err := value.Float64()
if err != nil {
return 0, false
}
return f, true
default:
return 0, false
}
}
func mapXypToGeneralScore(xyp float64) string {
// xyp_cpl0081: 0~1值越大风险越高
// score_120_General: 300~900值越大信用越好。
if xyp < 0 {
xyp = 0
}
if xyp > 1 {
xyp = 1
}
score := 900 - xyp*600
scoreInt := int(math.Round(score))
if scoreInt < 300 {
scoreInt = 300
}
if scoreInt > 900 {
scoreInt = 900
}
return strconv.Itoa(scoreInt)
}

View File

@@ -0,0 +1,833 @@
package jrzq
var jrzq6F2AVariableKeys = []string{
"flag_applyloanstr",
"als_d7_id_pdl_allnum",
"als_d7_id_pdl_orgnum",
"als_d7_id_caon_allnum",
"als_d7_id_caon_orgnum",
"als_d7_id_rel_allnum",
"als_d7_id_rel_orgnum",
"als_d7_id_caoff_allnum",
"als_d7_id_caoff_orgnum",
"als_d7_id_cooff_allnum",
"als_d7_id_cooff_orgnum",
"als_d7_id_af_allnum",
"als_d7_id_af_orgnum",
"als_d7_id_coon_allnum",
"als_d7_id_coon_orgnum",
"als_d7_id_oth_allnum",
"als_d7_id_oth_orgnum",
"als_d7_id_bank_selfnum",
"als_d7_id_bank_allnum",
"als_d7_id_bank_tra_allnum",
"als_d7_id_bank_ret_allnum",
"als_d7_id_bank_orgnum",
"als_d7_id_bank_tra_orgnum",
"als_d7_id_bank_ret_orgnum",
"als_d7_id_bank_week_allnum",
"als_d7_id_bank_week_orgnum",
"als_d7_id_bank_night_allnum",
"als_d7_id_bank_night_orgnum",
"als_d7_id_nbank_selfnum",
"als_d7_id_nbank_allnum",
"als_d7_id_nbank_p2p_allnum",
"als_d7_id_nbank_mc_allnum",
"als_d7_id_nbank_ca_allnum",
"als_d7_id_nbank_cf_allnum",
"als_d7_id_nbank_com_allnum",
"als_d7_id_nbank_oth_allnum",
"als_d7_id_nbank_nsloan_allnum",
"als_d7_id_nbank_autofin_allnum",
"als_d7_id_nbank_sloan_allnum",
"als_d7_id_nbank_cons_allnum",
"als_d7_id_nbank_finlea_allnum",
"als_d7_id_nbank_else_allnum",
"als_d7_id_nbank_orgnum",
"als_d7_id_nbank_p2p_orgnum",
"als_d7_id_nbank_mc_orgnum",
"als_d7_id_nbank_ca_orgnum",
"als_d7_id_nbank_cf_orgnum",
"als_d7_id_nbank_com_orgnum",
"als_d7_id_nbank_oth_orgnum",
"als_d7_id_nbank_nsloan_orgnum",
"als_d7_id_nbank_autofin_orgnum",
"als_d7_id_nbank_sloan_orgnum",
"als_d7_id_nbank_cons_orgnum",
"als_d7_id_nbank_finlea_orgnum",
"als_d7_id_nbank_else_orgnum",
"als_d7_id_nbank_week_allnum",
"als_d7_id_nbank_week_orgnum",
"als_d7_id_nbank_night_allnum",
"als_d7_id_nbank_night_orgnum",
"als_d7_cell_pdl_allnum",
"als_d7_cell_pdl_orgnum",
"als_d7_cell_caon_allnum",
"als_d7_cell_caon_orgnum",
"als_d7_cell_rel_allnum",
"als_d7_cell_rel_orgnum",
"als_d7_cell_caoff_allnum",
"als_d7_cell_caoff_orgnum",
"als_d7_cell_cooff_allnum",
"als_d7_cell_cooff_orgnum",
"als_d7_cell_af_allnum",
"als_d7_cell_af_orgnum",
"als_d7_cell_coon_allnum",
"als_d7_cell_coon_orgnum",
"als_d7_cell_oth_allnum",
"als_d7_cell_oth_orgnum",
"als_d7_cell_bank_selfnum",
"als_d7_cell_bank_allnum",
"als_d7_cell_bank_tra_allnum",
"als_d7_cell_bank_ret_allnum",
"als_d7_cell_bank_orgnum",
"als_d7_cell_bank_tra_orgnum",
"als_d7_cell_bank_ret_orgnum",
"als_d7_cell_bank_week_allnum",
"als_d7_cell_bank_week_orgnum",
"als_d7_cell_bank_night_allnum",
"als_d7_cell_bank_night_orgnum",
"als_d7_cell_nbank_selfnum",
"als_d7_cell_nbank_allnum",
"als_d7_cell_nbank_p2p_allnum",
"als_d7_cell_nbank_mc_allnum",
"als_d7_cell_nbank_ca_allnum",
"als_d7_cell_nbank_cf_allnum",
"als_d7_cell_nbank_com_allnum",
"als_d7_cell_nbank_oth_allnum",
"als_d7_cell_nbank_nsloan_allnum",
"als_d7_cell_nbank_autofin_allnum",
"als_d7_cell_nbank_sloan_allnum",
"als_d7_cell_nbank_cons_allnum",
"als_d7_cell_nbank_finlea_allnum",
"als_d7_cell_nbank_else_allnum",
"als_d7_cell_nbank_orgnum",
"als_d7_cell_nbank_p2p_orgnum",
"als_d7_cell_nbank_mc_orgnum",
"als_d7_cell_nbank_ca_orgnum",
"als_d7_cell_nbank_cf_orgnum",
"als_d7_cell_nbank_com_orgnum",
"als_d7_cell_nbank_oth_orgnum",
"als_d7_cell_nbank_nsloan_orgnum",
"als_d7_cell_nbank_autofin_orgnum",
"als_d7_cell_nbank_sloan_orgnum",
"als_d7_cell_nbank_cons_orgnum",
"als_d7_cell_nbank_finlea_orgnum",
"als_d7_cell_nbank_else_orgnum",
"als_d7_cell_nbank_week_allnum",
"als_d7_cell_nbank_week_orgnum",
"als_d7_cell_nbank_night_allnum",
"als_d7_cell_nbank_night_orgnum",
"als_d15_id_pdl_allnum",
"als_d15_id_pdl_orgnum",
"als_d15_id_caon_allnum",
"als_d15_id_caon_orgnum",
"als_d15_id_rel_allnum",
"als_d15_id_rel_orgnum",
"als_d15_id_caoff_allnum",
"als_d15_id_caoff_orgnum",
"als_d15_id_cooff_allnum",
"als_d15_id_cooff_orgnum",
"als_d15_id_af_allnum",
"als_d15_id_af_orgnum",
"als_d15_id_coon_allnum",
"als_d15_id_coon_orgnum",
"als_d15_id_oth_allnum",
"als_d15_id_oth_orgnum",
"als_d15_id_bank_selfnum",
"als_d15_id_bank_allnum",
"als_d15_id_bank_tra_allnum",
"als_d15_id_bank_ret_allnum",
"als_d15_id_bank_orgnum",
"als_d15_id_bank_tra_orgnum",
"als_d15_id_bank_ret_orgnum",
"als_d15_id_bank_week_allnum",
"als_d15_id_bank_week_orgnum",
"als_d15_id_bank_night_allnum",
"als_d15_id_bank_night_orgnum",
"als_d15_id_nbank_selfnum",
"als_d15_id_nbank_allnum",
"als_d15_id_nbank_p2p_allnum",
"als_d15_id_nbank_mc_allnum",
"als_d15_id_nbank_ca_allnum",
"als_d15_id_nbank_cf_allnum",
"als_d15_id_nbank_com_allnum",
"als_d15_id_nbank_oth_allnum",
"als_d15_id_nbank_nsloan_allnum",
"als_d15_id_nbank_autofin_allnum",
"als_d15_id_nbank_sloan_allnum",
"als_d15_id_nbank_cons_allnum",
"als_d15_id_nbank_finlea_allnum",
"als_d15_id_nbank_else_allnum",
"als_d15_id_nbank_orgnum",
"als_d15_id_nbank_p2p_orgnum",
"als_d15_id_nbank_mc_orgnum",
"als_d15_id_nbank_ca_orgnum",
"als_d15_id_nbank_cf_orgnum",
"als_d15_id_nbank_com_orgnum",
"als_d15_id_nbank_oth_orgnum",
"als_d15_id_nbank_nsloan_orgnum",
"als_d15_id_nbank_autofin_orgnum",
"als_d15_id_nbank_sloan_orgnum",
"als_d15_id_nbank_cons_orgnum",
"als_d15_id_nbank_finlea_orgnum",
"als_d15_id_nbank_else_orgnum",
"als_d15_id_nbank_week_allnum",
"als_d15_id_nbank_week_orgnum",
"als_d15_id_nbank_night_allnum",
"als_d15_id_nbank_night_orgnum",
"als_d15_cell_pdl_allnum",
"als_d15_cell_pdl_orgnum",
"als_d15_cell_caon_allnum",
"als_d15_cell_caon_orgnum",
"als_d15_cell_rel_allnum",
"als_d15_cell_rel_orgnum",
"als_d15_cell_caoff_allnum",
"als_d15_cell_caoff_orgnum",
"als_d15_cell_cooff_allnum",
"als_d15_cell_cooff_orgnum",
"als_d15_cell_af_allnum",
"als_d15_cell_af_orgnum",
"als_d15_cell_coon_allnum",
"als_d15_cell_coon_orgnum",
"als_d15_cell_oth_allnum",
"als_d15_cell_oth_orgnum",
"als_d15_cell_bank_selfnum",
"als_d15_cell_bank_allnum",
"als_d15_cell_bank_tra_allnum",
"als_d15_cell_bank_ret_allnum",
"als_d15_cell_bank_orgnum",
"als_d15_cell_bank_tra_orgnum",
"als_d15_cell_bank_ret_orgnum",
"als_d15_cell_bank_week_allnum",
"als_d15_cell_bank_week_orgnum",
"als_d15_cell_bank_night_allnum",
"als_d15_cell_bank_night_orgnum",
"als_d15_cell_nbank_selfnum",
"als_d15_cell_nbank_allnum",
"als_d15_cell_nbank_p2p_allnum",
"als_d15_cell_nbank_mc_allnum",
"als_d15_cell_nbank_ca_allnum",
"als_d15_cell_nbank_cf_allnum",
"als_d15_cell_nbank_com_allnum",
"als_d15_cell_nbank_oth_allnum",
"als_d15_cell_nbank_nsloan_allnum",
"als_d15_cell_nbank_autofin_allnum",
"als_d15_cell_nbank_sloan_allnum",
"als_d15_cell_nbank_cons_allnum",
"als_d15_cell_nbank_finlea_allnum",
"als_d15_cell_nbank_else_allnum",
"als_d15_cell_nbank_orgnum",
"als_d15_cell_nbank_p2p_orgnum",
"als_d15_cell_nbank_mc_orgnum",
"als_d15_cell_nbank_ca_orgnum",
"als_d15_cell_nbank_cf_orgnum",
"als_d15_cell_nbank_com_orgnum",
"als_d15_cell_nbank_oth_orgnum",
"als_d15_cell_nbank_nsloan_orgnum",
"als_d15_cell_nbank_autofin_orgnum",
"als_d15_cell_nbank_sloan_orgnum",
"als_d15_cell_nbank_cons_orgnum",
"als_d15_cell_nbank_finlea_orgnum",
"als_d15_cell_nbank_else_orgnum",
"als_d15_cell_nbank_week_allnum",
"als_d15_cell_nbank_week_orgnum",
"als_d15_cell_nbank_night_allnum",
"als_d15_cell_nbank_night_orgnum",
"als_m1_id_pdl_allnum",
"als_m1_id_pdl_orgnum",
"als_m1_id_caon_allnum",
"als_m1_id_caon_orgnum",
"als_m1_id_rel_allnum",
"als_m1_id_rel_orgnum",
"als_m1_id_caoff_allnum",
"als_m1_id_caoff_orgnum",
"als_m1_id_cooff_allnum",
"als_m1_id_cooff_orgnum",
"als_m1_id_af_allnum",
"als_m1_id_af_orgnum",
"als_m1_id_coon_allnum",
"als_m1_id_coon_orgnum",
"als_m1_id_oth_allnum",
"als_m1_id_oth_orgnum",
"als_m1_id_bank_selfnum",
"als_m1_id_bank_allnum",
"als_m1_id_bank_tra_allnum",
"als_m1_id_bank_ret_allnum",
"als_m1_id_bank_orgnum",
"als_m1_id_bank_tra_orgnum",
"als_m1_id_bank_ret_orgnum",
"als_m1_id_bank_week_allnum",
"als_m1_id_bank_week_orgnum",
"als_m1_id_bank_night_allnum",
"als_m1_id_bank_night_orgnum",
"als_m1_id_nbank_selfnum",
"als_m1_id_nbank_allnum",
"als_m1_id_nbank_p2p_allnum",
"als_m1_id_nbank_mc_allnum",
"als_m1_id_nbank_ca_allnum",
"als_m1_id_nbank_cf_allnum",
"als_m1_id_nbank_com_allnum",
"als_m1_id_nbank_oth_allnum",
"als_m1_id_nbank_nsloan_allnum",
"als_m1_id_nbank_autofin_allnum",
"als_m1_id_nbank_sloan_allnum",
"als_m1_id_nbank_cons_allnum",
"als_m1_id_nbank_finlea_allnum",
"als_m1_id_nbank_else_allnum",
"als_m1_id_nbank_orgnum",
"als_m1_id_nbank_p2p_orgnum",
"als_m1_id_nbank_mc_orgnum",
"als_m1_id_nbank_ca_orgnum",
"als_m1_id_nbank_cf_orgnum",
"als_m1_id_nbank_com_orgnum",
"als_m1_id_nbank_oth_orgnum",
"als_m1_id_nbank_nsloan_orgnum",
"als_m1_id_nbank_autofin_orgnum",
"als_m1_id_nbank_sloan_orgnum",
"als_m1_id_nbank_cons_orgnum",
"als_m1_id_nbank_finlea_orgnum",
"als_m1_id_nbank_else_orgnum",
"als_m1_id_nbank_week_allnum",
"als_m1_id_nbank_week_orgnum",
"als_m1_id_nbank_night_allnum",
"als_m1_id_nbank_night_orgnum",
"als_m1_cell_pdl_allnum",
"als_m1_cell_pdl_orgnum",
"als_m1_cell_caon_allnum",
"als_m1_cell_caon_orgnum",
"als_m1_cell_rel_allnum",
"als_m1_cell_rel_orgnum",
"als_m1_cell_caoff_allnum",
"als_m1_cell_caoff_orgnum",
"als_m1_cell_cooff_allnum",
"als_m1_cell_cooff_orgnum",
"als_m1_cell_af_allnum",
"als_m1_cell_af_orgnum",
"als_m1_cell_coon_allnum",
"als_m1_cell_coon_orgnum",
"als_m1_cell_oth_allnum",
"als_m1_cell_oth_orgnum",
"als_m1_cell_bank_selfnum",
"als_m1_cell_bank_allnum",
"als_m1_cell_bank_tra_allnum",
"als_m1_cell_bank_ret_allnum",
"als_m1_cell_bank_orgnum",
"als_m1_cell_bank_tra_orgnum",
"als_m1_cell_bank_ret_orgnum",
"als_m1_cell_bank_week_allnum",
"als_m1_cell_bank_week_orgnum",
"als_m1_cell_bank_night_allnum",
"als_m1_cell_bank_night_orgnum",
"als_m1_cell_nbank_selfnum",
"als_m1_cell_nbank_allnum",
"als_m1_cell_nbank_p2p_allnum",
"als_m1_cell_nbank_mc_allnum",
"als_m1_cell_nbank_ca_allnum",
"als_m1_cell_nbank_cf_allnum",
"als_m1_cell_nbank_com_allnum",
"als_m1_cell_nbank_oth_allnum",
"als_m1_cell_nbank_nsloan_allnum",
"als_m1_cell_nbank_autofin_allnum",
"als_m1_cell_nbank_sloan_allnum",
"als_m1_cell_nbank_cons_allnum",
"als_m1_cell_nbank_finlea_allnum",
"als_m1_cell_nbank_else_allnum",
"als_m1_cell_nbank_orgnum",
"als_m1_cell_nbank_p2p_orgnum",
"als_m1_cell_nbank_mc_orgnum",
"als_m1_cell_nbank_ca_orgnum",
"als_m1_cell_nbank_cf_orgnum",
"als_m1_cell_nbank_com_orgnum",
"als_m1_cell_nbank_oth_orgnum",
"als_m1_cell_nbank_nsloan_orgnum",
"als_m1_cell_nbank_autofin_orgnum",
"als_m1_cell_nbank_sloan_orgnum",
"als_m1_cell_nbank_cons_orgnum",
"als_m1_cell_nbank_finlea_orgnum",
"als_m1_cell_nbank_else_orgnum",
"als_m1_cell_nbank_week_allnum",
"als_m1_cell_nbank_week_orgnum",
"als_m1_cell_nbank_night_allnum",
"als_m1_cell_nbank_night_orgnum",
"als_m3_id_max_inteday",
"als_m3_id_min_inteday",
"als_m3_id_tot_mons",
"als_m3_id_avg_monnum",
"als_m3_id_max_monnum",
"als_m3_id_min_monnum",
"als_m3_id_pdl_allnum",
"als_m3_id_pdl_orgnum",
"als_m3_id_caon_allnum",
"als_m3_id_caon_orgnum",
"als_m3_id_rel_allnum",
"als_m3_id_rel_orgnum",
"als_m3_id_caoff_allnum",
"als_m3_id_caoff_orgnum",
"als_m3_id_cooff_allnum",
"als_m3_id_cooff_orgnum",
"als_m3_id_af_allnum",
"als_m3_id_af_orgnum",
"als_m3_id_coon_allnum",
"als_m3_id_coon_orgnum",
"als_m3_id_oth_allnum",
"als_m3_id_oth_orgnum",
"als_m3_id_bank_selfnum",
"als_m3_id_bank_allnum",
"als_m3_id_bank_tra_allnum",
"als_m3_id_bank_ret_allnum",
"als_m3_id_bank_orgnum",
"als_m3_id_bank_tra_orgnum",
"als_m3_id_bank_ret_orgnum",
"als_m3_id_bank_tot_mons",
"als_m3_id_bank_avg_monnum",
"als_m3_id_bank_max_monnum",
"als_m3_id_bank_min_monnum",
"als_m3_id_bank_max_inteday",
"als_m3_id_bank_min_inteday",
"als_m3_id_bank_week_allnum",
"als_m3_id_bank_week_orgnum",
"als_m3_id_bank_night_allnum",
"als_m3_id_bank_night_orgnum",
"als_m3_id_nbank_selfnum",
"als_m3_id_nbank_allnum",
"als_m3_id_nbank_p2p_allnum",
"als_m3_id_nbank_mc_allnum",
"als_m3_id_nbank_ca_allnum",
"als_m3_id_nbank_cf_allnum",
"als_m3_id_nbank_com_allnum",
"als_m3_id_nbank_oth_allnum",
"als_m3_id_nbank_nsloan_allnum",
"als_m3_id_nbank_autofin_allnum",
"als_m3_id_nbank_sloan_allnum",
"als_m3_id_nbank_cons_allnum",
"als_m3_id_nbank_finlea_allnum",
"als_m3_id_nbank_else_allnum",
"als_m3_id_nbank_orgnum",
"als_m3_id_nbank_p2p_orgnum",
"als_m3_id_nbank_mc_orgnum",
"als_m3_id_nbank_ca_orgnum",
"als_m3_id_nbank_cf_orgnum",
"als_m3_id_nbank_com_orgnum",
"als_m3_id_nbank_oth_orgnum",
"als_m3_id_nbank_nsloan_orgnum",
"als_m3_id_nbank_autofin_orgnum",
"als_m3_id_nbank_sloan_orgnum",
"als_m3_id_nbank_cons_orgnum",
"als_m3_id_nbank_finlea_orgnum",
"als_m3_id_nbank_else_orgnum",
"als_m3_id_nbank_tot_mons",
"als_m3_id_nbank_avg_monnum",
"als_m3_id_nbank_max_monnum",
"als_m3_id_nbank_min_monnum",
"als_m3_id_nbank_max_inteday",
"als_m3_id_nbank_min_inteday",
"als_m3_id_nbank_week_allnum",
"als_m3_id_nbank_week_orgnum",
"als_m3_id_nbank_night_allnum",
"als_m3_id_nbank_night_orgnum",
"als_m3_cell_max_inteday",
"als_m3_cell_min_inteday",
"als_m3_cell_tot_mons",
"als_m3_cell_avg_monnum",
"als_m3_cell_max_monnum",
"als_m3_cell_min_monnum",
"als_m3_cell_pdl_allnum",
"als_m3_cell_pdl_orgnum",
"als_m3_cell_caon_allnum",
"als_m3_cell_caon_orgnum",
"als_m3_cell_rel_allnum",
"als_m3_cell_rel_orgnum",
"als_m3_cell_caoff_allnum",
"als_m3_cell_caoff_orgnum",
"als_m3_cell_cooff_allnum",
"als_m3_cell_cooff_orgnum",
"als_m3_cell_af_allnum",
"als_m3_cell_af_orgnum",
"als_m3_cell_coon_allnum",
"als_m3_cell_coon_orgnum",
"als_m3_cell_oth_allnum",
"als_m3_cell_oth_orgnum",
"als_m3_cell_bank_selfnum",
"als_m3_cell_bank_allnum",
"als_m3_cell_bank_tra_allnum",
"als_m3_cell_bank_ret_allnum",
"als_m3_cell_bank_orgnum",
"als_m3_cell_bank_tra_orgnum",
"als_m3_cell_bank_ret_orgnum",
"als_m3_cell_bank_tot_mons",
"als_m3_cell_bank_avg_monnum",
"als_m3_cell_bank_max_monnum",
"als_m3_cell_bank_min_monnum",
"als_m3_cell_bank_max_inteday",
"als_m3_cell_bank_min_inteday",
"als_m3_cell_bank_week_allnum",
"als_m3_cell_bank_week_orgnum",
"als_m3_cell_bank_night_allnum",
"als_m3_cell_bank_night_orgnum",
"als_m3_cell_nbank_selfnum",
"als_m3_cell_nbank_allnum",
"als_m3_cell_nbank_p2p_allnum",
"als_m3_cell_nbank_mc_allnum",
"als_m3_cell_nbank_ca_allnum",
"als_m3_cell_nbank_cf_allnum",
"als_m3_cell_nbank_com_allnum",
"als_m3_cell_nbank_oth_allnum",
"als_m3_cell_nbank_nsloan_allnum",
"als_m3_cell_nbank_autofin_allnum",
"als_m3_cell_nbank_sloan_allnum",
"als_m3_cell_nbank_cons_allnum",
"als_m3_cell_nbank_finlea_allnum",
"als_m3_cell_nbank_else_allnum",
"als_m3_cell_nbank_orgnum",
"als_m3_cell_nbank_p2p_orgnum",
"als_m3_cell_nbank_mc_orgnum",
"als_m3_cell_nbank_ca_orgnum",
"als_m3_cell_nbank_cf_orgnum",
"als_m3_cell_nbank_com_orgnum",
"als_m3_cell_nbank_oth_orgnum",
"als_m3_cell_nbank_nsloan_orgnum",
"als_m3_cell_nbank_autofin_orgnum",
"als_m3_cell_nbank_sloan_orgnum",
"als_m3_cell_nbank_cons_orgnum",
"als_m3_cell_nbank_finlea_orgnum",
"als_m3_cell_nbank_else_orgnum",
"als_m3_cell_nbank_tot_mons",
"als_m3_cell_nbank_avg_monnum",
"als_m3_cell_nbank_max_monnum",
"als_m3_cell_nbank_min_monnum",
"als_m3_cell_nbank_max_inteday",
"als_m3_cell_nbank_min_inteday",
"als_m3_cell_nbank_week_allnum",
"als_m3_cell_nbank_week_orgnum",
"als_m3_cell_nbank_night_allnum",
"als_m3_cell_nbank_night_orgnum",
"als_m6_id_max_inteday",
"als_m6_id_min_inteday",
"als_m6_id_tot_mons",
"als_m6_id_avg_monnum",
"als_m6_id_max_monnum",
"als_m6_id_min_monnum",
"als_m6_id_pdl_allnum",
"als_m6_id_pdl_orgnum",
"als_m6_id_caon_allnum",
"als_m6_id_caon_orgnum",
"als_m6_id_rel_allnum",
"als_m6_id_rel_orgnum",
"als_m6_id_caoff_allnum",
"als_m6_id_caoff_orgnum",
"als_m6_id_cooff_allnum",
"als_m6_id_cooff_orgnum",
"als_m6_id_af_allnum",
"als_m6_id_af_orgnum",
"als_m6_id_coon_allnum",
"als_m6_id_coon_orgnum",
"als_m6_id_oth_allnum",
"als_m6_id_oth_orgnum",
"als_m6_id_bank_selfnum",
"als_m6_id_bank_allnum",
"als_m6_id_bank_tra_allnum",
"als_m6_id_bank_ret_allnum",
"als_m6_id_bank_orgnum",
"als_m6_id_bank_tra_orgnum",
"als_m6_id_bank_ret_orgnum",
"als_m6_id_bank_tot_mons",
"als_m6_id_bank_avg_monnum",
"als_m6_id_bank_max_monnum",
"als_m6_id_bank_min_monnum",
"als_m6_id_bank_max_inteday",
"als_m6_id_bank_min_inteday",
"als_m6_id_bank_week_allnum",
"als_m6_id_bank_week_orgnum",
"als_m6_id_bank_night_allnum",
"als_m6_id_bank_night_orgnum",
"als_m6_id_nbank_selfnum",
"als_m6_id_nbank_allnum",
"als_m6_id_nbank_p2p_allnum",
"als_m6_id_nbank_mc_allnum",
"als_m6_id_nbank_ca_allnum",
"als_m6_id_nbank_cf_allnum",
"als_m6_id_nbank_com_allnum",
"als_m6_id_nbank_oth_allnum",
"als_m6_id_nbank_nsloan_allnum",
"als_m6_id_nbank_autofin_allnum",
"als_m6_id_nbank_sloan_allnum",
"als_m6_id_nbank_cons_allnum",
"als_m6_id_nbank_finlea_allnum",
"als_m6_id_nbank_else_allnum",
"als_m6_id_nbank_orgnum",
"als_m6_id_nbank_p2p_orgnum",
"als_m6_id_nbank_mc_orgnum",
"als_m6_id_nbank_ca_orgnum",
"als_m6_id_nbank_cf_orgnum",
"als_m6_id_nbank_com_orgnum",
"als_m6_id_nbank_oth_orgnum",
"als_m6_id_nbank_nsloan_orgnum",
"als_m6_id_nbank_autofin_orgnum",
"als_m6_id_nbank_sloan_orgnum",
"als_m6_id_nbank_cons_orgnum",
"als_m6_id_nbank_finlea_orgnum",
"als_m6_id_nbank_else_orgnum",
"als_m6_id_nbank_tot_mons",
"als_m6_id_nbank_avg_monnum",
"als_m6_id_nbank_max_monnum",
"als_m6_id_nbank_min_monnum",
"als_m6_id_nbank_max_inteday",
"als_m6_id_nbank_min_inteday",
"als_m6_id_nbank_week_allnum",
"als_m6_id_nbank_week_orgnum",
"als_m6_id_nbank_night_allnum",
"als_m6_id_nbank_night_orgnum",
"als_m6_cell_max_inteday",
"als_m6_cell_min_inteday",
"als_m6_cell_tot_mons",
"als_m6_cell_avg_monnum",
"als_m6_cell_max_monnum",
"als_m6_cell_min_monnum",
"als_m6_cell_pdl_allnum",
"als_m6_cell_pdl_orgnum",
"als_m6_cell_caon_allnum",
"als_m6_cell_caon_orgnum",
"als_m6_cell_rel_allnum",
"als_m6_cell_rel_orgnum",
"als_m6_cell_caoff_allnum",
"als_m6_cell_caoff_orgnum",
"als_m6_cell_cooff_allnum",
"als_m6_cell_cooff_orgnum",
"als_m6_cell_af_allnum",
"als_m6_cell_af_orgnum",
"als_m6_cell_coon_allnum",
"als_m6_cell_coon_orgnum",
"als_m6_cell_oth_allnum",
"als_m6_cell_oth_orgnum",
"als_m6_cell_bank_selfnum",
"als_m6_cell_bank_allnum",
"als_m6_cell_bank_tra_allnum",
"als_m6_cell_bank_ret_allnum",
"als_m6_cell_bank_orgnum",
"als_m6_cell_bank_tra_orgnum",
"als_m6_cell_bank_ret_orgnum",
"als_m6_cell_bank_tot_mons",
"als_m6_cell_bank_avg_monnum",
"als_m6_cell_bank_max_monnum",
"als_m6_cell_bank_min_monnum",
"als_m6_cell_bank_max_inteday",
"als_m6_cell_bank_min_inteday",
"als_m6_cell_bank_week_allnum",
"als_m6_cell_bank_week_orgnum",
"als_m6_cell_bank_night_allnum",
"als_m6_cell_bank_night_orgnum",
"als_m6_cell_nbank_selfnum",
"als_m6_cell_nbank_allnum",
"als_m6_cell_nbank_p2p_allnum",
"als_m6_cell_nbank_mc_allnum",
"als_m6_cell_nbank_ca_allnum",
"als_m6_cell_nbank_cf_allnum",
"als_m6_cell_nbank_com_allnum",
"als_m6_cell_nbank_oth_allnum",
"als_m6_cell_nbank_nsloan_allnum",
"als_m6_cell_nbank_autofin_allnum",
"als_m6_cell_nbank_sloan_allnum",
"als_m6_cell_nbank_cons_allnum",
"als_m6_cell_nbank_finlea_allnum",
"als_m6_cell_nbank_else_allnum",
"als_m6_cell_nbank_orgnum",
"als_m6_cell_nbank_p2p_orgnum",
"als_m6_cell_nbank_mc_orgnum",
"als_m6_cell_nbank_ca_orgnum",
"als_m6_cell_nbank_cf_orgnum",
"als_m6_cell_nbank_com_orgnum",
"als_m6_cell_nbank_oth_orgnum",
"als_m6_cell_nbank_nsloan_orgnum",
"als_m6_cell_nbank_autofin_orgnum",
"als_m6_cell_nbank_sloan_orgnum",
"als_m6_cell_nbank_cons_orgnum",
"als_m6_cell_nbank_finlea_orgnum",
"als_m6_cell_nbank_else_orgnum",
"als_m6_cell_nbank_tot_mons",
"als_m6_cell_nbank_avg_monnum",
"als_m6_cell_nbank_max_monnum",
"als_m6_cell_nbank_min_monnum",
"als_m6_cell_nbank_max_inteday",
"als_m6_cell_nbank_min_inteday",
"als_m6_cell_nbank_week_allnum",
"als_m6_cell_nbank_week_orgnum",
"als_m6_cell_nbank_night_allnum",
"als_m6_cell_nbank_night_orgnum",
"als_m12_id_max_inteday",
"als_m12_id_min_inteday",
"als_m12_id_tot_mons",
"als_m12_id_avg_monnum",
"als_m12_id_max_monnum",
"als_m12_id_min_monnum",
"als_m12_id_pdl_allnum",
"als_m12_id_pdl_orgnum",
"als_m12_id_caon_allnum",
"als_m12_id_caon_orgnum",
"als_m12_id_rel_allnum",
"als_m12_id_rel_orgnum",
"als_m12_id_caoff_allnum",
"als_m12_id_caoff_orgnum",
"als_m12_id_cooff_allnum",
"als_m12_id_cooff_orgnum",
"als_m12_id_af_allnum",
"als_m12_id_af_orgnum",
"als_m12_id_coon_allnum",
"als_m12_id_coon_orgnum",
"als_m12_id_oth_allnum",
"als_m12_id_oth_orgnum",
"als_m12_id_bank_selfnum",
"als_m12_id_bank_allnum",
"als_m12_id_bank_tra_allnum",
"als_m12_id_bank_ret_allnum",
"als_m12_id_bank_orgnum",
"als_m12_id_bank_tra_orgnum",
"als_m12_id_bank_ret_orgnum",
"als_m12_id_bank_tot_mons",
"als_m12_id_bank_avg_monnum",
"als_m12_id_bank_max_monnum",
"als_m12_id_bank_min_monnum",
"als_m12_id_bank_max_inteday",
"als_m12_id_bank_min_inteday",
"als_m12_id_bank_week_allnum",
"als_m12_id_bank_week_orgnum",
"als_m12_id_bank_night_allnum",
"als_m12_id_bank_night_orgnum",
"als_m12_id_nbank_selfnum",
"als_m12_id_nbank_allnum",
"als_m12_id_nbank_p2p_allnum",
"als_m12_id_nbank_mc_allnum",
"als_m12_id_nbank_ca_allnum",
"als_m12_id_nbank_cf_allnum",
"als_m12_id_nbank_com_allnum",
"als_m12_id_nbank_oth_allnum",
"als_m12_id_nbank_nsloan_allnum",
"als_m12_id_nbank_autofin_allnum",
"als_m12_id_nbank_sloan_allnum",
"als_m12_id_nbank_cons_allnum",
"als_m12_id_nbank_finlea_allnum",
"als_m12_id_nbank_else_allnum",
"als_m12_id_nbank_orgnum",
"als_m12_id_nbank_p2p_orgnum",
"als_m12_id_nbank_mc_orgnum",
"als_m12_id_nbank_ca_orgnum",
"als_m12_id_nbank_cf_orgnum",
"als_m12_id_nbank_com_orgnum",
"als_m12_id_nbank_oth_orgnum",
"als_m12_id_nbank_nsloan_orgnum",
"als_m12_id_nbank_autofin_orgnum",
"als_m12_id_nbank_sloan_orgnum",
"als_m12_id_nbank_cons_orgnum",
"als_m12_id_nbank_finlea_orgnum",
"als_m12_id_nbank_else_orgnum",
"als_m12_id_nbank_tot_mons",
"als_m12_id_nbank_avg_monnum",
"als_m12_id_nbank_max_monnum",
"als_m12_id_nbank_min_monnum",
"als_m12_id_nbank_max_inteday",
"als_m12_id_nbank_min_inteday",
"als_m12_id_nbank_week_allnum",
"als_m12_id_nbank_week_orgnum",
"als_m12_id_nbank_night_allnum",
"als_m12_id_nbank_night_orgnum",
"als_m12_cell_max_inteday",
"als_m12_cell_min_inteday",
"als_m12_cell_tot_mons",
"als_m12_cell_avg_monnum",
"als_m12_cell_max_monnum",
"als_m12_cell_min_monnum",
"als_m12_cell_pdl_allnum",
"als_m12_cell_pdl_orgnum",
"als_m12_cell_caon_allnum",
"als_m12_cell_caon_orgnum",
"als_m12_cell_rel_allnum",
"als_m12_cell_rel_orgnum",
"als_m12_cell_caoff_allnum",
"als_m12_cell_caoff_orgnum",
"als_m12_cell_cooff_allnum",
"als_m12_cell_cooff_orgnum",
"als_m12_cell_af_allnum",
"als_m12_cell_af_orgnum",
"als_m12_cell_coon_allnum",
"als_m12_cell_coon_orgnum",
"als_m12_cell_oth_allnum",
"als_m12_cell_oth_orgnum",
"als_m12_cell_bank_selfnum",
"als_m12_cell_bank_allnum",
"als_m12_cell_bank_tra_allnum",
"als_m12_cell_bank_ret_allnum",
"als_m12_cell_bank_orgnum",
"als_m12_cell_bank_tra_orgnum",
"als_m12_cell_bank_ret_orgnum",
"als_m12_cell_bank_tot_mons",
"als_m12_cell_bank_avg_monnum",
"als_m12_cell_bank_max_monnum",
"als_m12_cell_bank_min_monnum",
"als_m12_cell_bank_max_inteday",
"als_m12_cell_bank_min_inteday",
"als_m12_cell_bank_week_allnum",
"als_m12_cell_bank_week_orgnum",
"als_m12_cell_bank_night_allnum",
"als_m12_cell_bank_night_orgnum",
"als_m12_cell_nbank_selfnum",
"als_m12_cell_nbank_allnum",
"als_m12_cell_nbank_p2p_allnum",
"als_m12_cell_nbank_mc_allnum",
"als_m12_cell_nbank_ca_allnum",
"als_m12_cell_nbank_cf_allnum",
"als_m12_cell_nbank_com_allnum",
"als_m12_cell_nbank_oth_allnum",
"als_m12_cell_nbank_nsloan_allnum",
"als_m12_cell_nbank_autofin_allnum",
"als_m12_cell_nbank_sloan_allnum",
"als_m12_cell_nbank_cons_allnum",
"als_m12_cell_nbank_finlea_allnum",
"als_m12_cell_nbank_else_allnum",
"als_m12_cell_nbank_orgnum",
"als_m12_cell_nbank_p2p_orgnum",
"als_m12_cell_nbank_mc_orgnum",
"als_m12_cell_nbank_ca_orgnum",
"als_m12_cell_nbank_cf_orgnum",
"als_m12_cell_nbank_com_orgnum",
"als_m12_cell_nbank_oth_orgnum",
"als_m12_cell_nbank_nsloan_orgnum",
"als_m12_cell_nbank_autofin_orgnum",
"als_m12_cell_nbank_sloan_orgnum",
"als_m12_cell_nbank_cons_orgnum",
"als_m12_cell_nbank_finlea_orgnum",
"als_m12_cell_nbank_else_orgnum",
"als_m12_cell_nbank_tot_mons",
"als_m12_cell_nbank_avg_monnum",
"als_m12_cell_nbank_max_monnum",
"als_m12_cell_nbank_min_monnum",
"als_m12_cell_nbank_max_inteday",
"als_m12_cell_nbank_min_inteday",
"als_m12_cell_nbank_week_allnum",
"als_m12_cell_nbank_week_orgnum",
"als_m12_cell_nbank_night_allnum",
"als_m12_cell_nbank_night_orgnum",
"als_fst_id_bank_inteday",
"als_fst_id_nbank_inteday",
"als_fst_cell_bank_inteday",
"als_fst_cell_nbank_inteday",
"als_lst_id_bank_inteday",
"als_lst_id_bank_consnum",
"als_lst_id_bank_csinteday",
"als_lst_id_nbank_inteday",
"als_lst_id_nbank_consnum",
"als_lst_id_nbank_csinteday",
"als_lst_cell_bank_inteday",
"als_lst_cell_bank_consnum",
"als_lst_cell_bank_csinteday",
"als_lst_cell_nbank_inteday",
"als_lst_cell_nbank_consnum",
"als_lst_cell_nbank_csinteday",
}
var jrzq6F2AKeySet = func() map[string]struct{} {
m := make(map[string]struct{}, len(jrzq6F2AVariableKeys))
for _, key := range jrzq6F2AVariableKeys {
m[key] = struct{}{}
}
return m
}()

View File

@@ -4,10 +4,11 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"strings"
"tyapi-server/internal/domains/api/dto" "tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors" "tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/xingwei" "tyapi-server/internal/infrastructure/external/zhicha"
) )
// ProcessJRZQ6F2ARequest JRZQ6F2A API处理方法 - 借贷申请记录 // ProcessJRZQ6F2ARequest JRZQ6F2A API处理方法 - 借贷申请记录
@@ -21,27 +22,196 @@ func ProcessJRZQ6F2ARequest(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err) return nil, errors.Join(processors.ErrInvalidParam, err)
} }
// 构建请求数据,将项目规范的字段名转换为 XingweiService 需要的字段名 encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
reqData := map[string]interface{}{ if err != nil {
"name": paramsDto.Name, return nil, errors.Join(processors.ErrSystem, err)
"idCardNum": paramsDto.IDCard,
"phoneNumber": paramsDto.MobileNo,
} }
// 调用行为数据API使用指定的project_id encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
projectID := "CDJ-1101695369065984000"
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
if err != nil { if err != nil {
if errors.Is(err, xingwei.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, xingwei.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, xingwei.ErrSystem) {
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
}
encryptedMobileNo, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"phone": encryptedMobileNo,
"authorized": "1",
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI017", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else { } else {
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
} }
} }
respMap, ok := respData.(map[string]interface{})
if !ok {
return nil, errors.Join(processors.ErrSystem, errors.New("响应格式错误"))
}
result := mapJRZQ3C7BToJRZQ6F2A(respMap)
respBytes, err := json.Marshal(result)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil return respBytes, nil
} }
func mapJRZQ3C7BToJRZQ6F2A(src map[string]interface{}) map[string]interface{} {
variableValue := buildDefaultVariableValue()
// 如果源已经是平铺字段,优先直接覆盖,兼容不同返回形态。
copyDirectFlattenFields(variableValue, src)
periods := []string{"d7", "d15", "m1", "m3", "m6", "m12"}
for _, period := range periods {
periodData := asMap(src[period])
if len(periodData) == 0 {
continue
}
for _, scope := range []string{"id", "cell"} {
scopeData := asMap(periodData[scope])
if len(scopeData) == 0 {
continue
}
flattenPeriodScope(variableValue, period, scope, scopeData)
}
}
return map[string]interface{}{
"risk_screen_v2": map[string]interface{}{
"fulinHitFlag": 1,
"models": []interface{}{},
"variables": []interface{}{map[string]interface{}{"variableName": "bairong_applyloan_extend", "variableValue": variableValue}},
"code": "OK",
"decision": "accept",
"propertyValidations": []interface{}{},
"strategies": []interface{}{},
"scenes": []interface{}{},
"validateInfo": map[string]interface{}{"productCodes": []interface{}{}},
"id": "",
"message": "业务处理成功!",
"knowledge": map[string]interface{}{},
},
}
}
func flattenPeriodScope(target map[string]interface{}, period, scope string, scopeData map[string]interface{}) {
basePrefix := "als_" + period + "_" + scope + "_"
// 先处理 scope 级基础字段(例如 tot_mons/max_monnum/min_monnum/avg_monnum
copyScalarFields(target, basePrefix, scopeData)
for key, raw := range scopeData {
child := asMap(raw)
if len(child) == 0 {
continue
}
sectionPrefix := basePrefix + key + "_"
copyScalarFields(target, sectionPrefix, child)
// 对周末字段做兼容命名映射
copyAliasIfPresent(target, sectionPrefix, child, "weekend_allnum", "week_allnum")
copyAliasIfPresent(target, sectionPrefix, child, "weekend_orgnum", "week_orgnum")
// 对 top_* 与 *_d 字段做兜底映射,尽可能补齐常用 allnum/orgnum
if _, ok := target[sectionPrefix+"allnum"]; !ok {
copyAliasIfPresent(target, sectionPrefix, child, "top_allnum", "allnum")
copyAliasIfPresent(target, sectionPrefix, child, "allnum_d", "allnum")
}
if _, ok := target[sectionPrefix+"orgnum"]; !ok {
copyAliasIfPresent(target, sectionPrefix, child, "top_orgnum", "orgnum")
copyAliasIfPresent(target, sectionPrefix, child, "orgnum_d", "orgnum")
}
}
}
func copyScalarFields(target map[string]interface{}, prefix string, src map[string]interface{}) {
for k, v := range src {
if isScalar(v) {
setVariableField(target, prefix+normalizeMetricName(k), v)
}
}
}
func copyAliasIfPresent(target map[string]interface{}, prefix string, src map[string]interface{}, from, to string) {
if v, ok := src[from]; ok && isScalar(v) {
setVariableField(target, prefix+to, v)
}
}
func copyDirectFlattenFields(target map[string]interface{}, src map[string]interface{}) {
for k, v := range src {
if !isScalar(v) {
continue
}
// 允许直接覆盖文档字段以及兼容字段
setVariableField(target, k, v)
}
}
func normalizeMetricName(name string) string {
switch name {
case "weekend_allnum":
return "week_allnum"
case "weekend_orgnum":
return "week_orgnum"
default:
return strings.TrimSpace(name)
}
}
func isScalar(v interface{}) bool {
switch v.(type) {
case nil:
return false
case string, bool, float64, int, int32, int64, uint, uint32, uint64:
return true
default:
return false
}
}
func asMap(v interface{}) map[string]interface{} {
if v == nil {
return map[string]interface{}{}
}
if m, ok := v.(map[string]interface{}); ok {
return m
}
return map[string]interface{}{}
}
func buildDefaultVariableValue() map[string]interface{} {
m := make(map[string]interface{}, len(jrzq6F2AVariableKeys)+3)
for _, key := range jrzq6F2AVariableKeys {
m[key] = ""
}
// 兼容历史示例中出现的附加字段
m["als_Flag_applyloanstr"] = "1"
m["code"] = "00"
m["swift_number"] = ""
m["flag_applyloanstr"] = "1"
return m
}
func setVariableField(target map[string]interface{}, key string, value interface{}) {
_, inDoc := jrzq6F2AKeySet[key]
if inDoc || key == "als_Flag_applyloanstr" || key == "code" || key == "swift_number" {
target[key] = value
}
}

View File

@@ -4,10 +4,13 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"math"
"strconv"
"strings"
"tyapi-server/internal/domains/api/dto" "tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors" "tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/xingwei" "tyapi-server/internal/infrastructure/external/zhicha"
) )
// ProcessJRZQ8B3CRequest JRZQ8B3C API处理方法 - 个人消费能力等级 // ProcessJRZQ8B3CRequest JRZQ8B3C API处理方法 - 个人消费能力等级
@@ -21,27 +24,173 @@ func ProcessJRZQ8B3CRequest(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err) return nil, errors.Join(processors.ErrInvalidParam, err)
} }
// 构建请求数据,将项目规范的字段名转换为 XingweiService 需要的字段名 encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
reqData := map[string]interface{}{ if err != nil {
"name": paramsDto.Name, return nil, errors.Join(processors.ErrSystem, err)
"idCardNum": paramsDto.IDCard,
"phoneNumber": paramsDto.MobileNo,
} }
// 调用行为数据API使用指定的project_id encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
projectID := "CDJ-1101695392528920576"
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
if err != nil { if err != nil {
if errors.Is(err, xingwei.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, xingwei.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, xingwei.ErrSystem) {
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
}
encryptedMobileNo, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"phone": encryptedMobileNo,
"authorized": "1",
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI034", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else { } else {
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
} }
} }
personIncomeIndex := "-1"
if m, ok := respData.(map[string]interface{}); ok {
personIncomeIndex = mapTap010ToIncomeIndex(m["tap010"], paramsDto.IDCard)
}
respPayload := map[string]interface{}{
"personincome_index_2.0": personIncomeIndex,
}
respBytes, err := json.Marshal(respPayload)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil return respBytes, nil
} }
type incomeTier struct {
Score int
Low float64
High float64 // 上界闭区间math.Inf(1) 表示正无穷
}
var incomeTiers = []incomeTier{
{Score: 100, Low: 1000, High: 2000},
{Score: 200, Low: 2000, High: 4000},
{Score: 300, Low: 4000, High: 6000},
{Score: 400, Low: 6000, High: 8000},
{Score: 500, Low: 8000, High: 10000},
{Score: 600, Low: 10000, High: 12000},
{Score: 700, Low: 12000, High: 15000},
{Score: 800, Low: 15000, High: 20000},
{Score: 900, Low: 20000, High: 25000},
{Score: 1000, Low: 25000, High: math.Inf(1)},
}
func mapTap010ToIncomeIndex(rawTap010 interface{}, idCard string) string {
tap010, ok := parseTap010Level(rawTap010)
if !ok {
return "-1"
}
mappedLow, mappedHigh := expandTap010Range(tap010)
candidateScores := intersectedTierScores(mappedLow, mappedHigh)
if len(candidateScores) == 0 {
return "-1"
}
seed := stableSeedFromIDCard(idCard)
score := candidateScores[seed%len(candidateScores)]
return strconv.Itoa(score)
}
func parseTap010Level(v interface{}) (int, bool) {
switch value := v.(type) {
case string:
value = strings.TrimSpace(value)
if value == "" {
return 0, false
}
n, err := strconv.Atoi(value)
if err != nil {
return 0, false
}
if n < 1 || n > 4 {
return 0, false
}
return n, true
case float64:
n := int(value)
if value != float64(n) || n < 1 || n > 4 {
return 0, false
}
return n, true
default:
return 0, false
}
}
func expandTap010Range(level int) (float64, float64) {
// tap010 原区间:
// 1:(0,500) 2:[500,1000) 3:[1000,3000) 4:[3000,+inf)
// 按比例放大 9 倍映射到收入尺度,满足示例: (0,500)->(0,4500)
switch level {
case 1:
return 0, 4500
case 2:
return 4500, 9000
case 3:
return 9000, 27000
case 4:
return 27000, math.Inf(1)
default:
return 0, 0
}
}
func intersectedTierScores(low, high float64) []int {
scores := make([]int, 0, len(incomeTiers))
for _, t := range incomeTiers {
if isRangeIntersect(low, high, t.Low, t.High) {
scores = append(scores, t.Score)
}
}
return scores
}
func isRangeIntersect(aLow, aHigh, bLow, bHigh float64) bool {
return aLow <= bHigh && bLow <= aHigh
}
func stableSeedFromIDCard(idCard string) int {
if len(idCard) == 0 {
return 0
}
runes := []rune(idCard)
start := len(runes) - 4
if start < 0 {
start = 0
}
seed := 0
for _, r := range runes[start:] {
switch {
case r >= '0' && r <= '9':
seed = seed*11 + int(r-'0')
case r == 'X' || r == 'x':
seed = seed*11 + 10
default:
seed = seed*11 + int(r)%11
}
}
if seed < 0 {
return -seed
}
return seed
}

View File

@@ -47,8 +47,6 @@ func ProcessJRZQO7L1Request(ctx context.Context, params []byte, deps *processors
"city": null, "city": null,
} }
// 使用 WithSkipCode201Check 不跳过 201 错误检查,当 Code == "201" 时返回错误
// ctx = zhicha.WithSkipCode201Check(ctx)
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI080", reqData) respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI080", reqData)
if err != nil { if err != nil {
if errors.Is(err, zhicha.ErrDatasource) { if errors.Is(err, zhicha.ErrDatasource) {

View File

@@ -0,0 +1,67 @@
package qygl
import (
"context"
"encoding/json"
"errors"
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/shujubao"
)
// ProcessQYGLDJ33Request QYGLDJ33 企业进出口信用核查 API 处理方法(使用数据宝服务示例)
func ProcessQYGLDJ33Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.QYGLDJ33Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// 企业名称(entName)、统一社会信用代码(creditCode)、企业注册号(entRegNo) 至少传其一;多填时优先用 creditCode 传参
hasEntName := paramsDto.EntName != ""
hasEntCode := paramsDto.EntCode != ""
hasEntRegNo := paramsDto.EntRegNo != ""
if !hasEntName && !hasEntCode && !hasEntRegNo { // 三个都未填才报错
return nil, errors.Join(processors.ErrInvalidParam, errors.New("ent_name、ent_code、ent_reg_no 至少需要传其中一个"))
}
// 构建数据宝入参sign 外的业务参数可按需 AES 加密后作为 bodyData
reqParams := map[string]interface{}{
"key": "f51ed30b0d4208bf7e6f2ba499d49d4f",
}
if hasEntCode {
reqParams["creditCode"] = paramsDto.EntCode
} else if hasEntName {
reqParams["entName"] = paramsDto.EntName
} else if hasEntRegNo {
reqParams["regCode"] = paramsDto.EntRegNo
}
// 最终请求 URL = https://api.chinadatapay.com/communication + 拼接接口地址值,如 personal/197
apiPath := "/communication/personal/10254"
data, err := deps.ShujubaoService.CallAPI(ctx, apiPath, reqParams)
if err != nil {
if errors.Is(err, shujubao.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
}
if errors.Is(err, shujubao.ErrQueryEmpty) {
return nil, errors.Join(processors.ErrNotFound, err)
}
return nil, errors.Join(processors.ErrSystem, err)
}
// 解析响应中的 JSON 字符串(使用 qyglb4c0 中的 RecursiveParse
parsedResp, err := RecursiveParse(data)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
respBytes, err := json.Marshal(parsedResp)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -2,46 +2,44 @@ package yysy
import ( import (
"context" "context"
"encoding/json"
"errors"
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors" "tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/xingwei"
) )
// ProcessYYSY8C2DRequest YYSY8C2D API处理方法 - 运营商三要素查询 // ProcessYYSY8C2DRequest YYSY8C2D API处理方法 - 运营商三要素查询
func ProcessYYSY8C2DRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) { func ProcessYYSY8C2DRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY8C2DReq return ProcessYYSY9A1BRequest(ctx, params, deps)
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil { // var paramsDto dto.YYSY8C2DReq
return nil, errors.Join(processors.ErrInvalidParam, err) // if err := json.Unmarshal(params, &paramsDto); err != nil {
} // return nil, errors.Join(processors.ErrSystem, err)
// }
// 构建请求数据,将项目规范的字段名转换为 XingweiService 需要的字段名 // if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
reqData := map[string]interface{}{ // return nil, errors.Join(processors.ErrInvalidParam, err)
"name": paramsDto.Name, // }
"idCardNum": paramsDto.IDCard,
"phoneNumber": paramsDto.MobileNo,
}
// 调用行为数据API使用指定的project_id // // 构建请求数据,将项目规范的字段名转换为 XingweiService 需要的字段名
projectID := "CDJ-1100244702166183936" // reqData := map[string]interface{}{
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData) // "name": paramsDto.Name,
if err != nil { // "idCardNum": paramsDto.IDCard,
if errors.Is(err, xingwei.ErrNotFound) { // "phoneNumber": paramsDto.MobileNo,
return nil, errors.Join(processors.ErrNotFound, err) // }
} else if errors.Is(err, xingwei.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, xingwei.ErrSystem) {
return nil, errors.Join(processors.ErrSystem, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil // // 调用行为数据API使用指定的project_id
// projectID := "CDJ-1100244702166183936"
// respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
// if err != nil {
// if errors.Is(err, xingwei.ErrNotFound) {
// return nil, errors.Join(processors.ErrNotFound, err)
// } else if errors.Is(err, xingwei.ErrDatasource) {
// return nil, errors.Join(processors.ErrDatasource, err)
// } else if errors.Is(err, xingwei.ErrSystem) {
// return nil, errors.Join(processors.ErrSystem, err)
// } else {
// return nil, errors.Join(processors.ErrSystem, err)
// }
// }
// return respBytes, nil
} }

View File

@@ -4,9 +4,11 @@ import (
"bytes" "bytes"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/md5"
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io"
) )
const ( const (
@@ -119,3 +121,10 @@ func pkcs7Unpadding(src []byte) ([]byte, error) {
return src[:length-unpadding], nil return src[:length-unpadding], nil
} }
// MD5 使用MD5加密数据返回十六进制字符串
func MD5(data string) string {
h := md5.New()
io.WriteString(h, data)
return hex.EncodeToString(h.Sum(nil))
}

View File

@@ -212,11 +212,12 @@ func (z *ZhichaService) CallAPI(ctx context.Context, proID string, params map[st
// 201 表示查询为空兼容其它情况如果data也为空则返回空对象 // 201 表示查询为空兼容其它情况如果data也为空则返回空对象
if zhichaResp.Code == "201" { if zhichaResp.Code == "201" {
// 先做类型断言
dataMap, ok := zhichaResp.Data.(map[string]interface{}) dataMap, ok := zhichaResp.Data.(map[string]interface{})
if ok && len(dataMap) > 0 { if ok {
// 即使是 {},也原样返回
return dataMap, nil return dataMap, nil
} }
// 兜底:防止解密异常
return map[string]interface{}{}, nil return map[string]interface{}{}, nil
} }
@@ -315,6 +316,12 @@ func (z *ZhichaService) Decrypt(encryptedData string) (string, error) {
return string(unpadded), nil return string(unpadded), nil
} }
// MD5 对字符串进行MD5加密并返回32位小写十六进制字符串
func (z *ZhichaService) MD5(data string) string {
hash := md5.Sum([]byte(data))
return hex.EncodeToString(hash[:])
}
// pkcs7Padding 使用PKCS7填充数据 // pkcs7Padding 使用PKCS7填充数据
func (z *ZhichaService) pkcs7Padding(src []byte, blockSize int) []byte { func (z *ZhichaService) pkcs7Padding(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize padding := blockSize - len(src)%blockSize

View File

@@ -213,11 +213,10 @@ func newWechatPayServiceWithWxPayPubKey(c config.Config, logger *zap.Logger) *We
panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) panic(fmt.Sprintf("初始化失败,服务停止: %v", err))
} }
// 初始化 notify.Handler // 初始化 notify.Handler(纯支付公钥验签)
certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(mchID)
notifyHandler := notify.NewNotifyHandler( notifyHandler := notify.NewNotifyHandler(
mchAPIv3Key, mchAPIv3Key,
verifiers.NewSHA256WithRSACombinedVerifier(certificateVisitor, mchPublicKeyID, *mchPublicKey)) verifiers.NewSHA256WithRSAPubkeyVerifier(mchPublicKeyID, *mchPublicKey))
logger.Info("微信支付客户端初始化成功(微信支付公钥方式)") logger.Info("微信支付客户端初始化成功(微信支付公钥方式)")
return &WechatPayService{ return &WechatPayService{