93 lines
4.0 KiB
Python
93 lines
4.0 KiB
Python
"""
|
||
恢复被 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'
|
||
))
|