From 792409de119240766992219f36454dd8c156de3c Mon Sep 17 00:00:00 2001 From: XingQue Date: Fri, 10 Jul 2026 04:22:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=20audit=5Ffreeze=5Ffeature=20?= =?UTF-8?q?=E7=A7=BB=E5=88=B0=20yonghu=20=E5=BA=94=E7=94=A8=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Django=20=E6=97=A0=E6=B3=95=E5=8F=91?= =?UTF-8?q?=E7=8E=B0=E5=91=BD=E4=BB=A4=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit a_long_dianjing 不在 INSTALLED_APPS 中,management 命令不会被加载。 Co-authored-by: Cursor --- yonghu/management/__init__.py | 0 yonghu/management/commands/__init__.py | 0 .../commands/audit_freeze_feature.py | 46 +++++-------------- 3 files changed, 11 insertions(+), 35 deletions(-) create mode 100644 yonghu/management/__init__.py create mode 100644 yonghu/management/commands/__init__.py rename {a_long_dianjing => yonghu}/management/commands/audit_freeze_feature.py (90%) diff --git a/yonghu/management/__init__.py b/yonghu/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/yonghu/management/commands/__init__.py b/yonghu/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/a_long_dianjing/management/commands/audit_freeze_feature.py b/yonghu/management/commands/audit_freeze_feature.py similarity index 90% rename from a_long_dianjing/management/commands/audit_freeze_feature.py rename to yonghu/management/commands/audit_freeze_feature.py index 8f45fb6..7a78e96 100644 --- a/a_long_dianjing/management/commands/audit_freeze_feature.py +++ b/yonghu/management/commands/audit_freeze_feature.py @@ -23,13 +23,11 @@ from django.db import connection from django.db.models import Q, Sum from yonghu.freeze_service import ( - DONGJIE_MODE_FIXED, DONGJIE_MODE_RATIO, FREEZE_LEIXING_SET, FreezeConfig, compute_freeze_split, get_leixing_meta, - is_freeze_leixing, ) from yonghu.models import ( TixianDongjieGonggongPeizhi, @@ -163,7 +161,6 @@ def check_algorithm_unit_tests(report: AuditReport): failures = [] cases = [ - # (name, balance, pool, config, apply, expect_withdraw, expect_freeze, expect_freeze_only) ('无配置', '100', '0', None, '50', '50', '0', False), ('比例10%_表例_申请50', '100', '0', FreezeConfig(1, decimal.Decimal('0.10'), decimal.Decimal('0'), 'p'), '50', '50', '10', False), ('比例10%_表例_申请90', '100', '0', FreezeConfig(1, decimal.Decimal('0.10'), decimal.Decimal('0'), 'p'), '90', '90', '10', False), @@ -191,7 +188,6 @@ def check_algorithm_unit_tests(report: AuditReport): except Exception as e: failures.append(f'{name}: {e}') - # 手续费应基于 withdraw_jine 而非 apply_jine(比例30%余额100申请50 → withdraw=50) r = compute_freeze_split( _q('100'), _q('0'), FreezeConfig(DONGJIE_MODE_RATIO, decimal.Decimal('0.30'), decimal.Decimal('0'), 'p'), @@ -222,10 +218,7 @@ def check_negative_pools(report: AuditReport): def check_pool_vs_logs(report: AuditReport, sample_limit: int = 50): - """ - 冻结池余额 vs 流水账:对每个有流水的用户, - expected_pool = sum(申请冻结) - sum(管理员解冻) - """ + """冻结池余额 vs 流水账""" mismatches = [] log_groups = ( TixianDongjieJilu.objects @@ -249,7 +242,6 @@ def check_pool_vs_logs(report: AuditReport, sample_limit: int = 50): mismatches.append(f'{yid} leixing={lx} 池={actual} 流水推算={expected} 差={actual - expected}') count += 1 - # 也检查有池余额但无流水的异常(可能是历史手工改库) orphan_pools = _find_pools_without_logs(limit=10) detail_parts = [] if mismatches: @@ -272,10 +264,7 @@ def _get_pool_balance(yonghuid: str, leixing: int) -> Optional[decimal.Decimal]: Model = meta['model'] pool_field = meta['pool'] try: - if leixing in (1, 5): - obj = Model.objects.get(user__yonghuid=yonghuid) - else: - obj = Model.objects.get(user__yonghuid=yonghuid) + obj = Model.objects.get(user__yonghuid=yonghuid) return _q(getattr(obj, pool_field)) except Model.DoesNotExist: return None @@ -307,10 +296,8 @@ def check_tixian_record_fields(report: AuditReport, limit: int = 200): fee = _q(t.shouxufei) arrive = _q(t.jine) freeze = _q(t.benchi_dongjie_jine) - # 到账 + 手续费 应等于申请扣款额 if abs((arrive + fee) - sj) > decimal.Decimal('0.02'): issues.append(f'tixian#{t.id} shenqing={sj} fee={fee} arrive={arrive} 不平') - # 有冻结时申请扣款应 > 0(freeze_only 不应有 tixian 记录) if sj <= 0 and freeze > 0: issues.append(f'tixian#{t.id} 有冻结但 shenqing_jine=0(异常:freeze_only 不应建单)') if freeze < 0: @@ -328,7 +315,7 @@ def check_tixian_record_fields(report: AuditReport, limit: int = 200): def check_audit_sync(report: AuditReport, limit: int = 100): - """自动打款:审核单与提现记录 benchi_dongjie / shenqing_jine 同步""" + """自动打款:审核单与提现记录同步""" issues = [] audits = list( TixianShenheJilu.objects @@ -358,10 +345,7 @@ def check_code_wiring(report: AuditReport): """接口/模块是否接入(只读 import)""" issues = [] try: - from django.urls import get_resolver - urls = {p.name for p in get_resolver().url_patterns if hasattr(p, 'name') and p.name} - # 递归找 houtai - resolver = get_resolver() + resolver = __import__('django.urls', fromlist=['get_resolver']).get_resolver() houtai_found = False for pattern in resolver.url_patterns: if hasattr(pattern, 'url_patterns') and 'houtai' in str(pattern.pattern): @@ -373,17 +357,12 @@ def check_code_wiring(report: AuditReport): except Exception as e: issues.append(f'URL检查异常: {e}') - modules = [ - 'yonghu.freeze_service', - 'houtai.dongjie_views', - ] - for mod in modules: + for mod in ('yonghu.freeze_service', 'houtai.dongjie_views'): try: __import__(mod) except Exception as e: issues.append(f'无法导入 {mod}: {e}') - # 手动/自动是否都接 freeze import inspect from yonghu import views as yv from yonghu import tixian_shenhe_services as ts @@ -400,9 +379,7 @@ def check_code_wiring(report: AuditReport): def check_final_business_rules_doc(report: AuditReport): - """ - 对照「最终确认」业务规则(与用户线上一致,非 md 初稿第六节驳回回滚冻结) - """ + """对照最终确认业务规则""" rules = [ '支持 leixing 1/2/5/6', '手动+自动打款共用冻结', @@ -411,12 +388,12 @@ def check_final_business_rules_doc(report: AuditReport): '驳回:仅退 shenqing_jine,冻结池不回滚', '管理员解冻:池→余额', ] - impl_notes = [] - impl_notes.append(f'FREEZE_LEIXING_SET={sorted(FREEZE_LEIXING_SET)}') - impl_notes.append('驳回逻辑: refund_balance(shenqing_jine) 无 benchi 回滚 — 见 tixian_shenhe_services.refund_balance') - impl_notes.append('流水 caozuo 仅 1申请冻结/3管理员解冻,无驳回回滚类型(符合最终规则)') + impl_notes = [ + f'FREEZE_LEIXING_SET={sorted(FREEZE_LEIXING_SET)}', + '驳回逻辑: refund_balance(shenqing_jine) 无 benchi 回滚', + '流水 caozuo 仅 1申请冻结/3管理员解冻', + ] - # 验证驳回代码确实不回滚冻结 import inspect from yonghu.tixian_shenhe_services import refund_balance, reject_audit_and_refund src_reject = inspect.getsource(reject_audit_and_refund) @@ -431,7 +408,6 @@ def check_final_business_rules_doc(report: AuditReport): def check_global_switch_default(report: AuditReport): - """总开关默认关闭,不影响未开启时的存量用户""" from peizhi.models import WithdrawConfig wc = WithdrawConfig.objects.filter(id=1).first() enabled = bool(wc.dongjie_quanju_enabled) if wc else False