This commit is contained in:
Mrx
2026-03-02 11:38:30 +08:00
11 changed files with 380 additions and 66 deletions

View File

@@ -276,6 +276,8 @@ wallet:
default_credit_limit: 50.00
min_amount: "100.00" # 生产环境最低充值金额
max_amount: "100000.00" # 单次最高充值金额
recharge_bonus_enabled: true # 是否启用充值赠送,设为 false 时仅展示商务洽谈提示
api_store_recharge_tip: "" # 关闭赠送时展示的提示文案,为空则使用默认文案
# 支付宝充值赠送配置
alipay_recharge_bonus:
- recharge_amount: 1000.00 # 充值1000元

View File

@@ -108,6 +108,8 @@ wallet:
default_credit_limit: 0.01
min_amount: "0.01" # 生产环境最低充值金额
max_amount: "100000.00" # 单次最高充值金额
recharge_bonus_enabled: false # 开发环境可设为 true 测试赠送
api_store_recharge_tip: "尊敬的客户,若您的充值金额较大或有批量调价需求,为获取专属商务优惠方案,请直接联系我司商务团队进行洽谈。感谢您的支持!"
# 支付宝充值赠送配置
alipay_recharge_bonus:
- recharge_amount: 0.01 # 充值1000元

View File

@@ -109,7 +109,9 @@ wallet:
default_credit_limit: 50.00
min_amount: "100.00" # 生产环境最低充值金额
max_amount: "100000.00" # 单次最高充值金额
# 支付宝充值赠送配置
recharge_bonus_enabled: false # 暂不赠送,展示商务洽谈提示
api_store_recharge_tip: "尊敬的客户,若您的充值金额较大或有批量调价需求,为获取专属商务优惠方案,请直接联系我司商务团队进行洽谈。感谢您的支持!"
# 支付宝充值赠送配置recharge_bonus_enabled 为 true 时生效)
alipay_recharge_bonus:
- recharge_amount: 1000.00 # 充值1000元
bonus_amount: 50.00 # 赠送50元

View File

@@ -110,6 +110,8 @@ type AlipayRechargeOrderResponse struct {
type RechargeConfigResponse struct {
MinAmount string `json:"min_amount"` // 最低充值金额
MaxAmount string `json:"max_amount"` // 最高充值金额
RechargeBonusEnabled bool `json:"recharge_bonus_enabled"` // 是否启用充值赠送
ApiStoreRechargeTip string `json:"api_store_recharge_tip"` // API 商店充值提示(大额/批量联系商务)
AlipayRechargeBonus []AlipayRechargeBonusRuleResponse `json:"alipay_recharge_bonus"`
}

View File

@@ -1337,16 +1337,25 @@ func (s *FinanceApplicationServiceImpl) GetAdminRechargeRecords(ctx context.Cont
// GetRechargeConfig 获取充值配置
func (s *FinanceApplicationServiceImpl) GetRechargeConfig(ctx context.Context) (*responses.RechargeConfigResponse, error) {
bonus := make([]responses.AlipayRechargeBonusRuleResponse, 0, len(s.config.Wallet.AliPayRechargeBonus))
bonus := make([]responses.AlipayRechargeBonusRuleResponse, 0)
if s.config.Wallet.RechargeBonusEnabled && len(s.config.Wallet.AliPayRechargeBonus) > 0 {
bonus = make([]responses.AlipayRechargeBonusRuleResponse, 0, len(s.config.Wallet.AliPayRechargeBonus))
for _, rule := range s.config.Wallet.AliPayRechargeBonus {
bonus = append(bonus, responses.AlipayRechargeBonusRuleResponse{
RechargeAmount: rule.RechargeAmount,
BonusAmount: rule.BonusAmount,
})
}
}
tip := s.config.Wallet.ApiStoreRechargeTip
if tip == "" && !s.config.Wallet.RechargeBonusEnabled {
tip = "尊敬的客户,若您的充值金额较大或有批量调价需求,为获取专属商务优惠方案,请直接联系我司商务团队进行洽谈。感谢您的支持!"
}
return &responses.RechargeConfigResponse{
MinAmount: s.config.Wallet.MinAmount,
MaxAmount: s.config.Wallet.MaxAmount,
RechargeBonusEnabled: s.config.Wallet.RechargeBonusEnabled,
ApiStoreRechargeTip: tip,
AlipayRechargeBonus: bonus,
}, nil
}
@@ -1651,9 +1660,9 @@ func (s *FinanceApplicationServiceImpl) processWechatPaymentSuccess(ctx context.
return nil
}
// 计算充值赠送金额(复用支付宝的赠送逻辑)
// 计算充值赠送金额(复用支付宝的赠送逻辑,受 recharge_bonus_enabled 开关控制
bonusAmount := decimal.Zero
if len(s.config.Wallet.AliPayRechargeBonus) > 0 {
if s.config.Wallet.RechargeBonusEnabled && len(s.config.Wallet.AliPayRechargeBonus) > 0 {
for i := len(s.config.Wallet.AliPayRechargeBonus) - 1; i >= 0; i-- {
rule := s.config.Wallet.AliPayRechargeBonus[i]
if amount.GreaterThanOrEqual(decimal.NewFromFloat(rule.RechargeAmount)) {

View File

@@ -334,6 +334,8 @@ type WalletConfig struct {
DefaultCreditLimit float64 `mapstructure:"default_credit_limit"`
MinAmount string `mapstructure:"min_amount"` // 最低充值金额
MaxAmount string `mapstructure:"max_amount"` // 最高充值金额
RechargeBonusEnabled bool `mapstructure:"recharge_bonus_enabled"` // 是否启用充值赠送,关闭后仅展示商务洽谈提示
ApiStoreRechargeTip string `mapstructure:"api_store_recharge_tip"` // API 商店充值提示文案(大额/批量需求联系商务)
AliPayRechargeBonus []AliPayRechargeBonusRule `mapstructure:"alipay_recharge_bonus"`
BalanceAlert BalanceAlertConfig `mapstructure:"balance_alert"`
}

View File

@@ -1524,7 +1524,7 @@ func buildElementVerificationDetail(apiData map[string]interface{}, log *zap.Log
}
detail["belongRisks"] = belongRisks
// 公安重点人员核验产品highRiskFlag keyPersonCheckList
// 公安重点人员核验产品highRiskFlag keyPersonCheckList 五项是否命中决定
flxgdea9Data := getMapValue(apiData, "FLXGDEA9")
keyPersonCheckList := make(map[string]interface{})
keyPersonCheckList["num"] = "1"
@@ -1538,7 +1538,6 @@ func buildElementVerificationDetail(apiData map[string]interface{}, log *zap.Log
if flxgdea9Map, ok := flxgdea9Data.(map[string]interface{}); ok {
level, ok := flxgdea9Map["level"].(string)
if !ok {
// 尝试从其他可能的字段获取
if levelVal, exists := flxgdea9Map["level"]; exists {
if levelStr, ok := levelVal.(string); ok {
level = levelStr
@@ -1548,19 +1547,14 @@ func buildElementVerificationDetail(apiData map[string]interface{}, log *zap.Log
}
}
// 仅根据 level 解析并填充 keyPersonCheckList 五项
if level != "" && level != "0" {
// 有风险设置highRiskFlag为1高风险
detail["highRiskFlag"] = 1
// 解析level字段填充keyPersonCheckList
levelParts := strings.Split(level, ",")
for _, part := range levelParts {
part = strings.TrimSpace(part)
if part == "" || part == "0" {
continue
}
// 根据level代码判断风险类型
if strings.HasPrefix(part, "A") {
keyPersonCheckList["fontFlag"] = 1
}
@@ -1577,14 +1571,27 @@ func buildElementVerificationDetail(apiData map[string]interface{}, log *zap.Log
keyPersonCheckList["sheJiaoTongFlag"] = 1
}
}
} else {
// 无风险设置highRiskFlag为2低风险
detail["highRiskFlag"] = 2
}
}
}
detail["keyPersonCheckList"] = keyPersonCheckList
// 仅根据 keyPersonCheckList 五项判定 highRiskFlag不看是否有数据
// 五项均未命中 → 0 无风险;仅 sheJiaoTongFlag 命中 → 2 低风险;其他任一项命中 → 1 高风险
otherHit := keyPersonFlagEq1(keyPersonCheckList, "fontFlag") ||
keyPersonFlagEq1(keyPersonCheckList, "jingJiFontFlag") ||
keyPersonFlagEq1(keyPersonCheckList, "fangAiFlag") ||
keyPersonFlagEq1(keyPersonCheckList, "zhongDianFlag")
sheJiaoHit := keyPersonFlagEq1(keyPersonCheckList, "sheJiaoTongFlag")
if otherHit {
detail["highRiskFlag"] = 1 // 高风险
} else if sheJiaoHit {
detail["highRiskFlag"] = 2 // 低风险:仅涉交通命中
} else {
detail["highRiskFlag"] = 0 // 无风险:五项均未命中
}
// 设置默认值
if _, exists := detail["sjsysFlag"]; !exists {
detail["sjsysFlag"] = 0
@@ -3862,40 +3869,73 @@ func buildLeasingRiskAssessment(apiData map[string]interface{}, log *zap.Logger)
assessment[fieldNameNight] = fmt.Sprintf("%s/%s", idNightAllnum, cellNightAllnum)
}
// 判断风险标识:如果有申请记录,设置为高风险
hasApplication := false
for _, apiPeriod := range periodMap {
fieldName := fmt.Sprintf("alc_%s_id_allnum", apiPeriod)
// 尝试多种类型string、int、float64
if allnum, ok := jrzq1d09Map[fieldName].(string); ok && allnum != "" && allnum != "0" {
hasApplication = true
break
} else if allnum, ok := jrzq1d09Map[fieldName].(int); ok && allnum > 0 {
hasApplication = true
break
} else if allnum, ok := jrzq1d09Map[fieldName].(float64); ok && allnum > 0 {
hasApplication = true
break
}
// 也检查cell字段
fieldNameCell := fmt.Sprintf("alc_%s_cell_allnum", apiPeriod)
if allnum, ok := jrzq1d09Map[fieldNameCell].(string); ok && allnum != "" && allnum != "0" {
hasApplication = true
break
} else if allnum, ok := jrzq1d09Map[fieldNameCell].(int); ok && allnum > 0 {
hasApplication = true
break
} else if allnum, ok := jrzq1d09Map[fieldNameCell].(float64); ok && allnum > 0 {
hasApplication = true
break
// 仅使用近12月Last12对应 m12的次数作为判断依据
// totalCount 取身份证维度和手机号维度中的较大值,而不是两者相加
totalCount := 0
idKey12 := "alc_m12_id_allnum"
cellKey12 := "alc_m12_cell_allnum"
idCount := 0
cellCount := 0
// 身份证维度近12月
if v, ok := jrzq1d09Map[idKey12]; ok {
switch vv := v.(type) {
case string:
if vv != "" && vv != "0" {
if parsed, err := strconv.Atoi(vv); err == nil {
idCount = parsed
}
}
// 风险标识:如果有申请记录,风险较高;如果没有申请记录,风险较低
// 注意riskFlag的值0=未查得1=低风险2=高风险
if hasApplication {
assessment["riskFlag"] = 2 // 有申请记录,风险较高
case float64:
if vv > 0 {
idCount = int(vv)
}
case int:
if vv > 0 {
idCount = vv
}
}
}
// 手机号维度近12月
if v, ok := jrzq1d09Map[cellKey12]; ok {
switch vv := v.(type) {
case string:
if vv != "" && vv != "0" {
if parsed, err := strconv.Atoi(vv); err == nil {
cellCount = parsed
}
}
case float64:
if vv > 0 {
cellCount = int(vv)
}
case int:
if vv > 0 {
cellCount = vv
}
}
}
// 使用身份证和手机号两个维度中的较大值作为近12月总次数
if idCount >= cellCount {
totalCount = idCount
} else {
assessment["riskFlag"] = 1 // 无申请记录,风险较低
totalCount = cellCount
}
// 根据近12月总申请次数设置风险标识
// - totalCount == 0 -> 0 无风险 / 未查得
// - 0 < totalCount <= 10 -> 2 低风险(有少量租赁申请)
// - totalCount > 10 -> 1 高风险(租赁申请很多)
if totalCount == 0 {
assessment["riskFlag"] = 0
} else if totalCount <= 10 {
assessment["riskFlag"] = 2
} else {
assessment["riskFlag"] = 1
}
}
}
@@ -3912,6 +3952,22 @@ func getMapValue(data map[string]interface{}, key string) interface{} {
return nil
}
// keyPersonFlagEq1 判断 keyPersonCheckList 中某标识是否为 1支持 int/float64
func keyPersonFlagEq1(m map[string]interface{}, key string) bool {
v, ok := m[key]
if !ok {
return false
}
switch vv := v.(type) {
case int:
return vv == 1
case float64:
return vv == 1
default:
return false
}
}
func maskName(name string) string {
if name == "" {
return ""

View File

@@ -0,0 +1,219 @@
# 谛听多维报告DWBG8B4D风险标识判断标准
本文档汇总 `dwbg8b4d_processor.go` 中所有风险标识(*Flag / riskFlag的判定规则与数据来源便于查阅和评审。
---
## 一、elementVerificationDetail要素核验产品内风险标识
### 1. sjsysFlag手机三要素简版风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 未查得 | 无 YYSYH6D2 数据或无法解析 |
| 1 | 高风险 | YYSYH6D2.result ≠ "0"(身份证+手机号+姓名 不一致) |
| 2 | 低风险 | YYSYH6D2.result == "0"(三要素一致) |
**数据源**YYSYH6D2手机三要素简版
---
### 2. sfzeysFlag身份证二要素风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 未查得 | 无 IVYZ9K7F 数据或 status/desc/result 无法解析 |
| 1 | 高风险 | 核验结果不为「一致」 |
| 2 | 低风险 | 核验结果为「一致」 |
**数据源**IVYZ9K7F身份证二要素。status 来自 data.status、desc 或 result0=一致非0=不一致)。
---
### 3. onlineRiskFlag手机在网时长风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 未查得 | 无 YYSY8B1C 数据或 inTime 为空 |
| 1 | 高风险 | inTime == "0" 或 "3"(在网时长极短) |
| 2 | 低风险 | inTime 为其他非空值 |
**数据源**YYSY8B1C手机在网时长
---
### 4. phoneVailRiskFlag手机信息验证风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 未查得 | 无 YYSYE7V5 数据或 status 无法解析 |
| 1 | 高风险 | status == 1不在网 |
| 2 | 低风险 | status == 0在网/实号) |
**数据源**YYSYE7V5手机在网状态等
---
### 5. belongRiskFlag身份证号与手机号归属地风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 未查得 | 无 YYSY9E4A 或 YYSYH6D2或户籍/归属地任一方为空 |
| 1 | 高风险 | 户籍所在地与号码归属地**不一致**(经智能比较) |
| 2 | 低风险 | 户籍所在地与号码归属地**一致** |
**数据源**YYSY9E4A号码归属地、YYSYH6D2address 作户籍)。使用 `compareLocation` 做省/市归一化后比较。
---
### 6. highRiskFlag公安重点人员核验风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 无风险 | keyPersonCheckList 五项fontFlag、jingJiFontFlag、fangAiFlag、zhongDianFlag、sheJiaoTongFlag**均为 0** |
| 1 | 高风险 | **任一项** fontFlag / jingJiFontFlag / fangAiFlag / zhongDianFlag 为 1涉刑/经侦/妨害/重点/涉交通以外) |
| 2 | 低风险 | **仅** sheJiaoTongFlag 为 1仅涉交通命中其余为 0 |
**数据源**FLXGDEA9 的 level 解析后填充 keyPersonCheckListA→fontFlag, B→jingJiFontFlag, C→fangAiFlag, D→zhongDianFlag, E→sheJiaoTongFlag。**不看是否有数据**,仅根据五项当前值判定。
---
## 二、overdueRiskProduct逾期风险产品内风险标识
### 7. lyjlhyFlag履约/借贷逾期类风险标识)
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 未查得 | 无 JRZQ5E9F 数据(默认) |
| 1 | 高风险 | 当前存在未结清逾期 **或** 近 7/14/30 天有逾期hasUnsettledOverdue=="逾期" 或 overdueLast7Days/14Days/30Days 任一为「逾期」) |
| 2 | 低风险 | 有 JRZQ5E9F 数据且无上述逾期情况 |
**数据源**JRZQ5E9F借选指数评估字段xyp_cpl0044、xyp_cpl0029、xyp_cpl0030、xyp_cpl0031 等。
---
### 8. dkzhktjFlag贷款综合情况风险标识
**lyjlhyFlag** 使用同一套逻辑,同时赋值:有逾期或近期逾期则为 1否则为 2。
**数据源**JRZQ5E9F。
---
### 9. tsmdyzFlag特殊名单验证风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 未查得 | 无 JRZQ8A2D 数据(默认) |
| 1 | 高风险 | specialListVerification 列表**非空**(身份证或手机号任一侧命中:法院失信人/被执行人、银行/非银中风险/一般风险/高风险等任一) |
| 2 | 低风险 | 有 JRZQ8A2D 数据且 specialListVerification 为空 |
**数据源**JRZQ8A2D特殊名单验证 B。命中规则id/cell 下对应字段值为 "0" 表示命中(如 court_bad、court_executed、bank_lost 等)。
---
## 三、multCourtInfo司法风险核验产品内风险标识
### 10. legalCasesFlag涉案公告案件风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 无 | 无 FLXG7E8F 或 lawsuitStat 下无民事/刑事/行政/保全/破产案件 |
| 1 | 高风险 | legalCases 列表**非空**(民事、刑事、行政、保全、破产任一类 cases 非空) |
**数据源**FLXG7E8F个人司法涉诉查询→ judicial_data.lawsuitStat → civil/criminal/administrative/preservation/bankrupt.cases。
---
### 11. executionCasesFlag执行案件风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 无 | 无 FLXG7E8F 或 implement.cases 为空 |
| 1 | 高风险 | executionCases 列表**非空** |
**数据源**FLXG7E8F → judicial_data.lawsuitStat.implement.cases。
---
### 12. disinCasesFlag失信案件风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 无 | 无 FLXG7E8F 或 breachCaseList 为空 |
| 1 | 高风险 | disinCases 列表**非空** |
**数据源**FLXG7E8F → judicial_data.breachCaseList。
---
### 13. limitCasesFlag限高案件风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 无 | 无 FLXG7E8F 或 consumptionRestrictionList 为空 |
| 1 | 高风险 | limitCases 列表**非空** |
**数据源**FLXG7E8F → judicial_data.consumptionRestrictionList。
---
## 四、loanEvaluationVerificationDetail借贷评估产品内风险标识
### 14. riskFlag借贷评估风险标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 未查得 | 无 JRZQ6F2A 或 risk_screen_v2.variables[0].variableValue 无法解析 |
| 1 | 高风险 | checkLoanRisk 为 true**任一时间段**d7/d15/m1/m3银行或非银申请次数 **≥ 10**als_{period}_id_bank_allnum / als_{period}_id_nbank_allnum |
| 2 | 低风险 | 有数据且 checkLoanRisk 为 false |
**数据源**JRZQ6F2A借贷意向验证 A→ risk_screen_v2.variables[0].variableValue。
---
## 五、leasingRiskAssessment租赁风险评估产品内风险标识
### 15. riskFlag租赁风险评估标识
| 取值 | 含义 | 判断条件 |
|------|--------|----------|
| 0 | 无风险 | 近 12 月m12**总次数为 0**(身份证维度 alc_m12_id_allnum 与手机号维度 alc_m12_cell_allnum 取**较大值**后为 0 |
| 1 | 高风险 | 近 12 月总次数 **> 10** |
| 2 | 低风险 | 近 12 月总次数 **110**(含 10 |
**数据源**JRZQ1D093C 租赁申请意向)。**仅用近 12 月Last12 / m12**totalCount = max(idCount, cellCount)。
---
## 六、riskWarning规则风险提示内各项命中规则摘要
以下为「命中即置 1」的规则未命中或未查得均为 0。不改变上述各产品内 *Flag 的取值含义。
| 类别 | 字段示例 | 命中条件(简要) |
|----------------|----------|------------------|
| 要素核查 | idCardTwoElementMismatch | IVYZ9K7F 二要素结果非「一致」 |
| | phoneThreeElementMismatch | YYSYH6D2.result ≠ "0" |
| 运营商/在网 | shortPhoneDuration | YYSY8B1C.inTime == "0" |
| | shortPhoneDurationSlight | YYSY8B1C.inTime == "3" |
| | noPhoneDuration | YYSYE7V5.status==1 且 desc 含「风险」 |
| 归属地 | idCardPhoneProvinceMismatch | 户籍与号码归属地智能比较不一致 |
| 公安重点人员 | hasCriminalRecord / isEconomyFront / isDisrupSocial / isKeyPerson / isTrafficRelated | FLXGDEA9.level 解析后 A/B/C/D/E 前缀 |
| 涉赌涉诈 | isAntiFraudInfo | FLXG8B4D 中 moneyLaundering/deceiver/gamblerPlayer/gamblerBanker 任一项非空且非"0" |
| 逾期/名单 | hitHighRiskBankLastTwoYears / hitHighRiskNonBankLastTwoYears / hitCurrentOverdue | JRZQ8A2D.id 下 bank_lost/nbank_lost/bank_overdue/nbank_overdue 等字段值为 "0"(命中) |
| 司法 | hitCivilCase / hitCriminalRisk / hitExecutionCase / hitAdministrativeCase / hitPreservationReview / hitBankruptcyAndLiquidation | FLXG7E8F 对应案件类型 **cases 数组非空**(不依 count |
| 借贷意向 | frequentApplicationRecent | 近 d7/d15/m1 银行或非银申请次数 **≥ 10**JRZQ6F2A |
| | frequentBankApplications / moreFrequentBankApplications | 近 m6+m12 银行申请总次数 **≥ 20** / **≥ 15** |
| | frequentNonBankApplications / moreFrequentNonBankApplications | 近 m6+m12 非银申请总次数 **≥ 20** / **≥ 15** |
| 租赁申请 | veryFrequentRentalApplications / frequentRentalApplications | JRZQ1D09 近 m3+m6+m12每期取 id/cell 较大值再累加)总次数 **≥ 20** / **≥ 15** |
| 偿债压力 | highDebtPressure | JRZQ5E9F 当前逾期金额或当前逾期机构数非空且非 "0"/"1" |
---
## 七、风险取值约定(通用)
- **0**:未查得 / 无风险 / 无命中(依字段语义)
- **1**:高风险 / 命中
- **2**:低风险(仅部分 *Flag 使用,如 sjsysFlag、sfzeysFlag、onlineRiskFlag、phoneVailRiskFlag、belongRiskFlag、highRiskFlag、lyjlhyFlag、dkzhktjFlag、tsmdyzFlag、loanEvaluation riskFlag、leasingRiskAssessment riskFlag
文档版本:根据当前 `dwbg8b4d_processor.go` 逻辑整理,若有代码变更请同步更新本文档。

View File

@@ -15,9 +15,9 @@ import (
"tyapi-server/internal/shared/interfaces"
)
// calculateAlipayRechargeBonus 计算支付宝充值赠送金额
// calculateAlipayRechargeBonus 计算支付宝充值赠送金额(受 recharge_bonus_enabled 开关控制)
func calculateAlipayRechargeBonus(rechargeAmount decimal.Decimal, walletConfig *config.WalletConfig) decimal.Decimal {
if walletConfig == nil || len(walletConfig.AliPayRechargeBonus) == 0 {
if walletConfig == nil || !walletConfig.RechargeBonusEnabled || len(walletConfig.AliPayRechargeBonus) == 0 {
return decimal.Zero
}

View File

@@ -10,8 +10,9 @@ import (
)
func TestCalculateAlipayRechargeBonus(t *testing.T) {
// 创建测试配置
// 创建测试配置(开启赠送)
walletConfig := &config.WalletConfig{
RechargeBonusEnabled: true,
AliPayRechargeBonus: []config.AliPayRechargeBonusRule{
{RechargeAmount: 1000.00, BonusAmount: 50.00}, // 充1000送50
{RechargeAmount: 5000.00, BonusAmount: 300.00}, // 充5000送300
@@ -74,6 +75,7 @@ func TestCalculateAlipayRechargeBonus(t *testing.T) {
func TestCalculateAlipayRechargeBonus_EmptyConfig(t *testing.T) {
// 测试空配置
walletConfig := &config.WalletConfig{
RechargeBonusEnabled: true,
AliPayRechargeBonus: []config.AliPayRechargeBonusRule{},
}
@@ -85,4 +87,17 @@ func TestCalculateAlipayRechargeBonus_EmptyConfig(t *testing.T) {
assert.True(t, bonus.Equal(decimal.Zero), "nil配置应该返回零赠送金额")
}
func TestCalculateAlipayRechargeBonus_Disabled(t *testing.T) {
// 关闭赠送时,任意金额均不赠送
walletConfig := &config.WalletConfig{
RechargeBonusEnabled: false,
AliPayRechargeBonus: []config.AliPayRechargeBonusRule{
{RechargeAmount: 1000.00, BonusAmount: 50.00},
{RechargeAmount: 10000.00, BonusAmount: 800.00},
},
}
bonus := calculateAlipayRechargeBonus(decimal.NewFromFloat(10000.00), walletConfig)
assert.True(t, bonus.Equal(decimal.Zero), "关闭赠送时应返回零")
}

View File

@@ -84,20 +84,25 @@ func TestEncryptWithInvalidKey(t *testing.T) {
}
func TestDecryptWithInvalidData(t *testing.T) {
key := "1234567890abcdef1234567890abcdef"
key := "af4ca0098e6a202a5c08c413ebd9fd62"
// 测试无效的加密数据
invalidData := []string{
"", // 空数据
"invalid_base64", // 无效的Base64
"dGVzdA==", // 有效的Base64但不是AES加密数据
"i96w+SDjwENjuvsokMFbLw==",
"oaihmICgEcszWMk0gXoB12E/ygF4g78x0/sC3/KHnBk=",
"5bx+WvXvdNRVVOp9UuNFHg==",
}
for _, data := range invalidData {
_, err := Decrypt(data, key)
decrypted, err := Decrypt(data, key)
if err == nil {
t.Errorf("使用无效数据 %s 应该返回错误", data)
}
fmt.Println("data: ", data)
fmt.Println("decrypted: ", decrypted)
}
}