Files
Django/config/management/commands/undo_repair_wechat_income.py

134 lines
5.3 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 造成的重复记账。
你当时执行的指令是:
python manage.py repair_wechat_income
或:
python manage.py repair_wechat_income --date 2026-06-24 --days 7
repair 逻辑:按「当日创建的已支付订单/充值单」逐条 +金额、+笔数、写 platform_income_log、加 szjilu。
本命令用完全相同扫描列表,逐条反向 -金额、-笔数、删日志、减 szjilu。
用法:
1. 预览(不改库):
python manage.py undo_repair_wechat_income
2. 确认后撤销(加多少减多少):
python manage.py undo_repair_wechat_income --yes
3. 若当时带了参数,必须一致:
python manage.py undo_repair_wechat_income --date 2026-06-01 --days 30 --run-date 2026-06-24 --yes
--run-date = 你执行 repair 那天,默认今天)
4. 全部清零(恢复到 0
python manage.py undo_repair_wechat_income --zero-all --yes
"""
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 (
undo_repair_wechat_income_period,
zero_all_income_statistics,
)
class Command(BaseCommand):
help = '反向撤销 repair_wechat_income 造成的收支重复记账'
def add_arguments(self, parser):
parser.add_argument(
'--date', type=str, default='',
help='与 repair 相同的 --date扫描区间结束日默认今天',
)
parser.add_argument(
'--days', type=int, default=1,
help='与 repair 相同的 --days默认 1',
)
parser.add_argument(
'--run-date', type=str, default='',
help='你执行 repair 的日期(金额被记到哪天的 daily默认今天',
)
parser.add_argument('--yes', action='store_true', help='确认执行')
parser.add_argument(
'--zero-all', action='store_true',
help='收支统计全部清零日收入、日志、szjilu 收入流水归零)',
)
def handle(self, *args, **options):
if options['zero_all']:
self._zero_all(not options['yes'])
return
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)
if options['run_date']:
inflation_date = date.fromisoformat(options['run_date'])
else:
inflation_date = date.today()
dry_run = not options['yes']
self.stdout.write(self.style.WARNING(
'========== 反向撤销 repair_wechat_income ==========\n'
f'原 repair 扫描区间: {start_day} ~ {end_day} --days {days}\n'
f'金额被记到日统计日期: {inflation_date} --run-date\n'
))
if dry_run:
self.stdout.write('【预览】未改数据库\n')
else:
self.stdout.write('【执行】正在反向扣减...\n')
r = undo_repair_wechat_income_period(
start_day, end_day, inflation_date, dry_run=dry_run,
)
self.stdout.write(f' 将撤销条数: {r["undo_count"]}')
self.stdout.write(f' 将扣减金额: {r["undo_amount"]:.2f}')
self.stdout.write(
f' 执行前 {inflation_date} 日统计: {r["before_daily_on_inflation_date"]:.2f}'
)
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:
self.stdout.write(self.style.SUCCESS(
f'\n执行后 {inflation_date} 日统计: {r.get("after_daily_on_inflation_date", 0):.2f}'
))
self.stdout.write(self.style.SUCCESS('反向撤销完成,请刷新后台财务页。'))
else:
self.stdout.write(self.style.WARNING(
'\n预览完成。确认后执行(参数与 repair 保持一致):\n'
f' python manage.py undo_repair_wechat_income --date {end_day} --days {days} '
f'--run-date {inflation_date} --yes\n'
'全部清零:\n'
' python manage.py undo_repair_wechat_income --zero-all --yes'
))
def _zero_all(self, dry_run):
agg = DailyIncomeStat.objects.aggregate(amt=Sum('total_amount'), cnt=Sum('total_count'))
self.stdout.write(self.style.ERROR(
'========== 收支统计全部清零 ==========\n'
f'当前 daily_income_stat 合计: {float(agg["amt"] or 0):.2f} 元 / {int(agg["cnt"] or 0)}\n'
'将删除: platform_income_log 全部、daily_income_stat 全部\n'
'将归零: szjilu.TotalIncome / TotalFlow / DailyFlow\n'
))
if dry_run:
self.stdout.write(self.style.WARNING(
'预览。确认清零:\n'
' python manage.py undo_repair_wechat_income --zero-all --yes'
))
return
zero_all_income_statistics()
self.stdout.write(self.style.SUCCESS('已全部清零。请刷新后台。'))