"""七流一致自检规则测试 — 金税四期七流框架 覆盖 /root/cma_seven_flow_design_20260825.md 的7条自检规则: 1. 进销项倒挂 2. 应交税费异常 3. 账面毛利异常 4. 收入vs现金 5. 收入vs存货 6. 人员vs收入 7. 成本vs收入 规则是纯函数(不依赖DB),测试直接验证判定逻辑。 """ import pytest # ── 七流自检规则引擎(与设计方案一致) ── def rule_invoice_inverted(input_tax, output_tax): """规则1:进项税额 > 销项税额×1.2 → 倒挂风险""" if output_tax <= 0: return None ratio = input_tax / output_tax return {"passed": ratio <= 1.2, "value": round(ratio, 2), "threshold": 1.2, "level": "red" if ratio > 1.2 else "green", "message": f"进项/销项比 {ratio:.2f}(阈值1.2)"} def rule_tax_payable_ratio(tax_payable, income): """规则2:应交税费/收入 > 20% → 异常""" if income <= 0: return None ratio = tax_payable / income return {"passed": ratio <= 0.2, "value": round(ratio * 100, 1), "threshold": 20.0, "level": "red" if ratio > 0.2 else "green", "message": f"应交税费/收入 {ratio*100:.1f}%(阈值20%)"} def rule_margin_abnormal(margin_rate, industry_base=10.0): """规则3:毛利率 < 行业基准×0.5 → 异常(需解释链)""" threshold = industry_base * 0.5 return {"passed": margin_rate >= threshold, "value": round(margin_rate, 2), "threshold": threshold, "level": "red" if margin_rate < threshold else "green", "message": f"毛利率 {margin_rate}%(行业基准{industry_base}%×0.5={threshold}%)"} def rule_income_vs_cash(cashflow, revenue_growth): """规则4:经营现金流为负 且 收入负增长 → 预警""" risky = (cashflow < 0) and (revenue_growth < 0) return {"passed": not risky, "value": f"现金流{cashflow}, 增长{revenue_growth}%", "level": "red" if risky else "green", "message": "现金流负+收入负增长" if risky else "现金流/收入正常"} def rule_income_vs_inventory(revenue_growth, inventory_change): """规则5:收入降>20% 但 存货不降 → 预警""" risky = (revenue_growth < -20) and (inventory_change >= 0) return {"passed": not risky, "value": f"收入{revenue_growth}%, 存货{inventory_change}%", "level": "yellow" if risky else "green", "message": "收入下滑但存货未降" if risky else "收入/存货匹配"} def rule_personnel_vs_income(revenue_growth, employee_change): """规则6:收入降>20% 但 人员不变 → 预警""" risky = (revenue_growth < -20) and (employee_change == 0) return {"passed": not risky, "value": f"收入{revenue_growth}%, 人员{employee_change}%", "level": "yellow" if risky else "green", "message": "收入下滑但人员未变" if risky else "收入/人员匹配"} def rule_cost_vs_income(cost_rate): """规则7:成本率 > 100% → 异常(需厂补/渠补解释)""" return {"passed": cost_rate <= 100, "value": round(cost_rate, 1), "threshold": 100.0, "level": "red" if cost_rate > 100 else "green", "message": f"成本率 {cost_rate:.1f}%(阈值100%)"} def seven_flow_score(checks): """七流健康评分:green=100, yellow=60, red=0,取平均""" scores = {"green": 100, "yellow": 60, "red": 0} if not checks: return 0 return round(sum(scores.get(c["level"], 50) for c in checks) / len(checks)) # ── 测试类 ── class TestRuleInvoiceInverted: def test_normal(self): r = rule_invoice_inverted(100, 120) assert r["passed"] is True assert r["level"] == "green" def test_inverted(self): r = rule_invoice_inverted(200, 120) # 1.67 > 1.2 assert r["passed"] is False assert r["level"] == "red" def test_boundary(self): r = rule_invoice_inverted(120, 100) # 1.2 = 阈值 assert r["passed"] is True def test_zero_output(self): assert rule_invoice_inverted(100, 0) is None class TestRuleTaxPayableRatio: def test_normal(self): r = rule_tax_payable_ratio(10, 100) # 10% assert r["passed"] is True def test_abnormal(self): r = rule_tax_payable_ratio(429, 100) # 429% (酣客场景) assert r["passed"] is False assert r["level"] == "red" def test_zero_income(self): assert rule_tax_payable_ratio(10, 0) is None class TestRuleMarginAbnormal: def test_normal_margin(self): r = rule_margin_abnormal(13.0, 10.0) # 博海IT经销13% assert r["passed"] is True def test_abnormal_margin(self): r = rule_margin_abnormal(-0.43, 10.0) # 酣客账面-0.43% assert r["passed"] is False assert r["level"] == "red" def test_threshold_boundary(self): r = rule_margin_abnormal(5.0, 10.0) # = 5 = 10×0.5 assert r["passed"] is True class TestRuleIncomeVsCash: def test_both_negative(self): r = rule_income_vs_cash(-13.89, -37.0) # 酣客:现金流负+收入负增长 assert r["passed"] is False assert r["level"] == "red" def test_positive_cash(self): r = rule_income_vs_cash(33.86, -37.0) assert r["passed"] is True def test_negative_cash_positive_growth(self): r = rule_income_vs_cash(-5, 10) assert r["passed"] is True class TestRuleIncomeVsInventory: def test_income_down_inventory_up(self): r = rule_income_vs_inventory(-37, 5) # 收入降37%存货增5% assert r["passed"] is False assert r["level"] == "yellow" def test_income_down_inventory_down(self): r = rule_income_vs_inventory(-37, -2) # 都降 assert r["passed"] is True def test_slight_income_drop(self): r = rule_income_vs_inventory(-10, 5) # 降幅<20% assert r["passed"] is True class TestRulePersonnelVsIncome: def test_income_down_staff_same(self): r = rule_personnel_vs_income(-37, 0) # 收入降37%人员不变 assert r["passed"] is False assert r["level"] == "yellow" def test_staff_reduced(self): r = rule_personnel_vs_income(-37, -10) # 人员也降 assert r["passed"] is True def test_income_stable(self): r = rule_personnel_vs_income(-10, 0) assert r["passed"] is True class TestRuleCostVsIncome: def test_cost_over_100(self): r = rule_cost_vs_income(100.4) # 酣客成本率100.4% assert r["passed"] is False assert r["level"] == "red" def test_cost_normal(self): r = rule_cost_vs_income(87.0) # 博海成本率87% assert r["passed"] is True class TestSevenFlowScore: def test_all_green(self): checks = [{"level": "green"}, {"level": "green"}, {"level": "green"}] assert seven_flow_score(checks) == 100 def test_mixed(self): checks = [{"level": "green"}, {"level": "yellow"}, {"level": "red"}] assert seven_flow_score(checks) == 53 # (100+60+0)/3 def test_all_red(self): checks = [{"level": "red"}, {"level": "red"}] assert seven_flow_score(checks) == 0 def test_empty(self): assert seven_flow_score([]) == 0 class TestHankeScenario: """酣客2026H1真实场景(应触发多项红色预警)""" def test_full_hanke_checks(self): checks = [ rule_invoice_inverted(input_tax=27157, output_tax=31445), # 进项2.7亿vs销项3.1亿 rule_tax_payable_ratio(tax_payable=429, income=713), # 应交429万vs收入713万 rule_margin_abnormal(margin_rate=-0.43, industry_base=10), # 账面毛利-0.43% rule_income_vs_cash(cashflow=-13.89, revenue_growth=-37), # 现金流负+收入负增长 rule_income_vs_inventory(revenue_growth=-37, inventory_change=0), # 收入降库存平 rule_personnel_vs_income(revenue_growth=-37, employee_change=0), # 收入降人员平 rule_cost_vs_income(cost_rate=100.4), # 成本率100.4% ] reds = [c for c in checks if c and c["level"] == "red"] yellows = [c for c in checks if c and c["level"] == "yellow"] score = seven_flow_score([c for c in checks if c]) assert len(reds) >= 3, f"酣客应至少3项红色, 实际{len(reds)}: {[c['message'] for c in reds]}" assert len(yellows) >= 1 assert score < 60, f"酣客健康评分应<60, 实际{score}" class TestBohaiScenario: """博海2026H1真实场景(应风险较低)""" def test_full_bohai_checks(self): checks = [ rule_margin_abnormal(margin_rate=13.0, industry_base=10), # 毛利率13%合理 rule_cost_vs_income(cost_rate=87.0), # 成本率87% rule_tax_payable_ratio(tax_payable=5, income=100), # 正常税负 ] reds = [c for c in checks if c and c["level"] == "red"] score = seven_flow_score([c for c in checks if c]) assert len(reds) == 0, f"博海不应有红色预警: {[c['message'] for c in reds]}" assert score >= 60, f"博海健康评分应>=60, 实际{score}"