Files
Django/config/management/commands/recover_wechat_income_stats.py
2026-06-24 21:21:54 +08:00

93 lines
4.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
恢复被 repair_wechat_income 搞乱的收入统计。
repair 会对已入账订单重复加钱200 变 900
本命令:删当日错误日志 → 按真实微信支付重建 → 扣回 szjilu 多记部分。
用法:
1. 先预览python manage.py recover_wechat_income_stats
2. 看「重建后」金额是否对(应接近真实收入,如 200 左右)
3. 确认后python manage.py recover_wechat_income_stats --yes
4. 若多日错乱python manage.py recover_wechat_income_stats --days 7 --yes
5. 最后全量对齐日统计表python manage.py recover_wechat_income_stats --yes --rebuild-all-daily
"""
from datetime import date, timedelta
from django.core.management.base import BaseCommand
from django.db.models import Sum
from config.models import DailyIncomeStat
from jituan.services.szjilu_accounting import (
rebuild_all_daily_income_from_logs,
recover_income_stats_for_date,
)
class Command(BaseCommand):
help = '恢复 repair_wechat_income 重复记账(先预览,--yes 执行)'
def add_arguments(self, parser):
parser.add_argument('--date', type=str, default='', help='日期 YYYY-MM-DD默认今天')
parser.add_argument('--days', type=int, default=1, help='向前恢复几天')
parser.add_argument('--yes', action='store_true', help='确认执行')
parser.add_argument(
'--rebuild-all-daily',
action='store_true',
help='恢复后按 platform_income_log 全量重写 daily_income_stat纠正累计总收入',
)
def handle(self, *args, **options):
if options['date']:
end_day = date.fromisoformat(options['date'])
else:
end_day = date.today()
days = max(1, int(options['days'] or 1))
start_day = end_day - timedelta(days=days - 1)
dry_run = not options['yes']
if dry_run:
self.stdout.write(self.style.WARNING(
'【预览】未改数据库。下面「重建后」应是正确金额。\n'
))
else:
self.stdout.write(self.style.WARNING('【执行】正在恢复...\n'))
for i in range(days):
d = start_day + timedelta(days=i)
r = recover_income_stats_for_date(d, dry_run=dry_run)
self.stdout.write(f'=== {r["date"]} ===')
self.stdout.write(
f' 错乱前日统计: {r["before_daily_amount"]:.2f} 元 / {r["before_daily_count"]}'
)
self.stdout.write(
f' 当日幂等日志: {r["before_log_amount"]:.2f} 元 / {r["before_log_count"]}'
)
self.stdout.write(self.style.SUCCESS(
f' 重建后(正确值): {r["after_amount"]:.2f} 元 / {r["after_count"]}'
))
if r['items']:
self.stdout.write(' 明细:')
for ref, cid, amt, kind in r['items']:
self.stdout.write(f' {ref} {amt}元 club={cid} ({kind})')
if not dry_run and options['rebuild_all_daily']:
n = rebuild_all_daily_income_from_logs()
self.stdout.write(self.style.SUCCESS(f'已按日志全量重写 daily_income_stat: {n}'))
if not dry_run:
agg = DailyIncomeStat.objects.filter(date=end_day).aggregate(
amt=Sum('total_amount'),
cnt=Sum('total_count'),
)
self.stdout.write(self.style.SUCCESS(
f'\n数据库今日日统计现为: {float(agg["amt"] or 0):.2f} 元 / {int(agg["cnt"] or 0)}'
))
self.stdout.write(self.style.SUCCESS('恢复完成,请刷新后台财务页。'))
else:
self.stdout.write(self.style.WARNING(
'\n预览完成。重建后金额对的话执行:\n'
' python manage.py recover_wechat_income_stats --yes\n'
'累计总收入仍不对再加:\n'
' python manage.py recover_wechat_income_stats --yes --rebuild-all-daily'
))