89 lines
3.2 KiB
Python
89 lines
3.2 KiB
Python
"""全局自检:路由、数据、财务展示。用法: python scripts/global_check.py"""
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(__file__).resolve().parent.parent
|
||
sys.path.insert(0, str(ROOT))
|
||
|
||
ISSUES = []
|
||
|
||
|
||
def issue(level, code, msg):
|
||
ISSUES.append((level, code, msg))
|
||
print(f'[{level}] {code}: {msg}')
|
||
|
||
|
||
def main():
|
||
from app import create_app
|
||
from models import (
|
||
db, StudentAccount, Course, MonthlySnapshot, RechargeRecord,
|
||
ConsumptionRecord, RefundRecord,
|
||
)
|
||
|
||
app = create_app()
|
||
with app.app_context():
|
||
# 数据健康
|
||
n_recharge = RechargeRecord.query.count()
|
||
n_consume = ConsumptionRecord.query.count()
|
||
n_snap = MonthlySnapshot.query.count()
|
||
n_course_price = Course.query.filter(Course.price_per_hour > 0).count()
|
||
n_orig = StudentAccount.query.filter(
|
||
StudentAccount.original_price_per_lesson > 0,
|
||
).count()
|
||
|
||
if n_snap > 100 and n_recharge == 0 and n_consume == 0:
|
||
issue(
|
||
'INFO', 'DATA-01',
|
||
'业务数据主要来自 Excel 快照(充值/消课表为空),统计页应看「课时核对表」月份',
|
||
)
|
||
if n_snap > 0 and n_orig == 0:
|
||
issue(
|
||
'WARN', 'DATA-02',
|
||
'账户未写入 original_price_per_lesson;已支持从快照单价回填,请重启 app',
|
||
)
|
||
if n_course_price == 0:
|
||
issue(
|
||
'WARN', 'DATA-03',
|
||
'课程表 price_per_hour 均为 0,建议在「课程管理」维护原价单价',
|
||
)
|
||
|
||
# 路由冒烟
|
||
client = app.test_client()
|
||
client.post('/login', data={'username': 'admin', 'password': 'admin123'})
|
||
paths = [
|
||
'/students', '/students/detail/1', '/statistics',
|
||
'/keshibiao/snapshots?year=2026&month=4',
|
||
]
|
||
for p in paths:
|
||
r = client.get(p, follow_redirects=True)
|
||
if r.status_code >= 500:
|
||
issue('FAIL', 'HTTP', f'{p} -> {r.status_code}')
|
||
|
||
# 财务计算抽样
|
||
from finance_display import account_refund_display, build_refund_preview
|
||
from keshi_display import attach_latest_snapshots, snapshot_lessons_display, get_latest_period
|
||
|
||
py, pm = get_latest_period()
|
||
acc = StudentAccount.query.first()
|
||
if acc:
|
||
snap = attach_latest_snapshots([acc], py, pm).get(acc.id)
|
||
lg = snapshot_lessons_display(snap, acc) if snap else {}
|
||
d = account_refund_display(acc, lg, snap)
|
||
if d['kind'] == 'no_price' and snap and float(snap.unit_price or 0) > 0:
|
||
issue(
|
||
'WARN', 'FIN-01',
|
||
'快照有单价但应退仍为「-」,请重启以执行单价回填',
|
||
)
|
||
|
||
print('\n=== 汇总 ===')
|
||
if not ISSUES:
|
||
print('未发现阻塞性问题。')
|
||
else:
|
||
fails = [i for i in ISSUES if i[0] == 'FAIL']
|
||
print(f'共 {len(ISSUES)} 条(失败 {len(fails)})')
|
||
return 1 if any(i[0] == 'FAIL' for i in ISSUES) else 0
|
||
|
||
|
||
if __name__ == '__main__':
|
||
sys.exit(main())
|