fix: 财务接口+恢复今日收入
This commit is contained in:
70
config/management/commands/rebuild_income_stats.py
Normal file
70
config/management/commands/rebuild_income_stats.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
"""
|
||||||
|
【终极恢复】清空全部收支脏数据,按真实微信支付逐笔重建。
|
||||||
|
|
||||||
|
只执行这一条,不要再用 repair / undo / fix:
|
||||||
|
|
||||||
|
预览:python manage.py rebuild_income_stats
|
||||||
|
执行:python manage.py rebuild_income_stats --yes
|
||||||
|
"""
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
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_income_stats_from_scratch
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = '清空收支脏数据,按真实微信支付逐笔重建(终极恢复)'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('--since-year', type=int, default=0, help='从哪一年扫,默认去年')
|
||||||
|
parser.add_argument('--until-year', type=int, default=0, help='到哪一年,默认今年')
|
||||||
|
parser.add_argument('--yes', action='store_true', help='确认执行')
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
until_year = options['until_year'] or date.today().year
|
||||||
|
since_year = options['since_year'] or (until_year - 1)
|
||||||
|
dry_run = not options['yes']
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
self.stdout.write(self.style.WARNING('【预览】未改数据库\n'))
|
||||||
|
else:
|
||||||
|
self.stdout.write(self.style.ERROR(
|
||||||
|
'【执行】删除全部收入日志和日统计,按真实支付重建...\n'
|
||||||
|
))
|
||||||
|
|
||||||
|
r = rebuild_income_stats_from_scratch(
|
||||||
|
since_year=since_year, until_year=until_year, dry_run=dry_run,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.stdout.write(f'=== {since_year} ~ {until_year} ===')
|
||||||
|
self.stdout.write(f' 错乱前 daily 合计: {r["before_daily_total"]:.2f} 元')
|
||||||
|
self.stdout.write(f' 错乱前 log: {r["before_log_total"]:.2f} 元 / {r["before_log_count"]} 条')
|
||||||
|
self.stdout.write(self.style.SUCCESS(
|
||||||
|
f' 重建后合计: {r["after_total"]:.2f} 元 / {r["after_count"]} 笔'
|
||||||
|
))
|
||||||
|
self.stdout.write(self.style.SUCCESS(
|
||||||
|
f' 重建后本月: {r["month_amount"]:.2f} 元'
|
||||||
|
))
|
||||||
|
self.stdout.write(self.style.SUCCESS(
|
||||||
|
f' 重建后今日: {r["today_amount"]:.2f} 元 / {r["today_count"]} 笔 ← 看这条'
|
||||||
|
))
|
||||||
|
|
||||||
|
if not dry_run:
|
||||||
|
self.stdout.write(self.style.SUCCESS(
|
||||||
|
f'\ndaily 表合计: {r.get("after_daily_total", 0):.2f} 元'
|
||||||
|
))
|
||||||
|
agg = DailyIncomeStat.objects.filter(date=date.today()).aggregate(
|
||||||
|
amt=Sum('total_amount'), cnt=Sum('total_count'),
|
||||||
|
)
|
||||||
|
self.stdout.write(
|
||||||
|
f'今日 daily 行合计: {float(agg["amt"] or 0):.2f} 元 / {int(agg["cnt"] or 0)} 笔'
|
||||||
|
)
|
||||||
|
self.stdout.write(self.style.SUCCESS('\n完成。刷新后台财务页。'))
|
||||||
|
else:
|
||||||
|
self.stdout.write(self.style.WARNING(
|
||||||
|
f'\n今日 {r["today_amount"]:.2f} 元对的话:\n'
|
||||||
|
f' python manage.py rebuild_income_stats --yes'
|
||||||
|
))
|
||||||
48
config/management/commands/repopulate_today_income.py
Normal file
48
config/management/commands/repopulate_today_income.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
"""只恢复今日收入(修复后台四个板子显示 0)。"""
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db.models import Sum
|
||||||
|
|
||||||
|
from config.models import DailyIncomeStat
|
||||||
|
from jituan.services.szjilu_accounting import repopulate_today_income_stats
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = '重建今日 daily_income_stat(修复财务页今日收入为 0)'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('--date', type=str, default='', help='日期 YYYY-MM-DD,默认今天')
|
||||||
|
parser.add_argument('--yes', action='store_true', help='确认执行')
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
stat_date = date.fromisoformat(options['date']) if options['date'] else date.today()
|
||||||
|
dry_run = not options['yes']
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
self.stdout.write(self.style.WARNING('【预览】\n'))
|
||||||
|
else:
|
||||||
|
self.stdout.write(self.style.WARNING('【执行】重建今日收入...\n'))
|
||||||
|
|
||||||
|
r = repopulate_today_income_stats(stat_date, dry_run=dry_run)
|
||||||
|
self.stdout.write(f'日期: {r["date"]}')
|
||||||
|
self.stdout.write(f' 当前: {r["before_amount"]:.2f} 元 / {r["before_count"]} 笔')
|
||||||
|
self.stdout.write(self.style.SUCCESS(
|
||||||
|
f' 重建后: {r["after_amount"]:.2f} 元 / {r["after_count"]} 笔'
|
||||||
|
))
|
||||||
|
if r['items']:
|
||||||
|
for ref, cid, amt, kind in r['items']:
|
||||||
|
self.stdout.write(f' {ref} {amt}元 club={cid} ({kind})')
|
||||||
|
|
||||||
|
if not dry_run:
|
||||||
|
agg = DailyIncomeStat.objects.filter(date=stat_date).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('请刷新后台财务页。')
|
||||||
|
else:
|
||||||
|
self.stdout.write(self.style.WARNING(
|
||||||
|
'\n确认后: python manage.py repopulate_today_income --yes'
|
||||||
|
))
|
||||||
@@ -90,26 +90,20 @@ def build_caiwu_payload(request):
|
|||||||
scope = resolve_club_scope(request)
|
scope = resolve_club_scope(request)
|
||||||
today_income_qs = income_qs.filter(date=today)
|
today_income_qs = income_qs.filter(date=today)
|
||||||
today_payout_qs = payout_qs.filter(date=today)
|
today_payout_qs = payout_qs.filter(date=today)
|
||||||
if scope == DATA_SCOPE_ALL:
|
|
||||||
inc_agg = today_income_qs.aggregate(
|
inc_agg = today_income_qs.aggregate(
|
||||||
total_amount=Sum('total_amount'),
|
total_amount=Sum('total_amount'),
|
||||||
total_count=Sum('total_count'),
|
total_count=Sum('total_count'),
|
||||||
)
|
)
|
||||||
today_income_amount = float(inc_agg['total_amount'] or 0.00)
|
today_income_amount = float(inc_agg['total_amount'] or 0.00)
|
||||||
today_income_count = int(inc_agg['total_count'] or 0)
|
today_income_count = int(inc_agg['total_count'] or 0)
|
||||||
pay_agg = today_payout_qs.aggregate(
|
|
||||||
total_amount=Sum('total_amount'),
|
pay_agg = today_payout_qs.aggregate(
|
||||||
total_count=Sum('total_count'),
|
total_amount=Sum('total_amount'),
|
||||||
)
|
total_count=Sum('total_count'),
|
||||||
today_payout_amount = float(pay_agg['total_amount'] or 0.00)
|
)
|
||||||
today_payout_count = int(pay_agg['total_count'] or 0)
|
today_payout_amount = float(pay_agg['total_amount'] or 0.00)
|
||||||
else:
|
today_payout_count = int(pay_agg['total_count'] or 0)
|
||||||
today_income = today_income_qs.first()
|
|
||||||
today_income_amount = float(today_income.total_amount) if today_income else 0.00
|
|
||||||
today_income_count = today_income.total_count if today_income else 0
|
|
||||||
today_payout = today_payout_qs.first()
|
|
||||||
today_payout_amount = float(today_payout.total_amount) if today_payout else 0.00
|
|
||||||
today_payout_count = today_payout.total_count if today_payout else 0
|
|
||||||
|
|
||||||
today_orders = order_qs.filter(
|
today_orders = order_qs.filter(
|
||||||
CreateTime__gte=today_start,
|
CreateTime__gte=today_start,
|
||||||
@@ -160,10 +154,17 @@ def build_caiwu_payload(request):
|
|||||||
|
|
||||||
szjilu_payload = _build_szjilu_payload(request)
|
szjilu_payload = _build_szjilu_payload(request)
|
||||||
|
|
||||||
# 账户总收入/总支出:日收支统计表全历史 SUM(与「每日收支详细」按年汇总一致)
|
# 账户总收入/总支出:始终全集团合计(切换俱乐部也不变少)
|
||||||
total_income = float(income_qs.aggregate(total=Sum('total_amount'))['total'] or 0.00)
|
total_income = float(
|
||||||
total_payout = float(payout_qs.aggregate(total=Sum('total_amount'))['total'] or 0.00)
|
DailyIncomeStat.query.aggregate(total=Sum('total_amount'))['total'] or 0.00
|
||||||
platform_profit = round(total_income - total_payout, 2)
|
)
|
||||||
|
total_payout = float(
|
||||||
|
DailyPayoutStat.query.aggregate(total=Sum('total_amount'))['total'] or 0.00
|
||||||
|
)
|
||||||
|
# 俱乐部利润:当前视图范围内累计收入减累计支出
|
||||||
|
scoped_total_income = float(income_qs.aggregate(total=Sum('total_amount'))['total'] or 0.00)
|
||||||
|
scoped_total_payout = float(payout_qs.aggregate(total=Sum('total_amount'))['total'] or 0.00)
|
||||||
|
platform_profit = round(scoped_total_income - scoped_total_payout, 2)
|
||||||
|
|
||||||
daily_stats = []
|
daily_stats = []
|
||||||
since = today - timedelta(days=30)
|
since = today - timedelta(days=30)
|
||||||
|
|||||||
@@ -738,3 +738,283 @@ def reset_all_daily_szjilu():
|
|||||||
szjilu.save(update_fields=['DailyExpense', 'DailyFlow', 'UpdateTime'])
|
szjilu.save(update_fields=['DailyExpense', 'DailyFlow', 'UpdateTime'])
|
||||||
updated += 1
|
updated += 1
|
||||||
return updated
|
return updated
|
||||||
|
|
||||||
|
|
||||||
|
# 合法微信支付收入(不含退款 Status=5)
|
||||||
|
_LEGIT_ORDER_STATUSES = [1, 2, 3, 4, 6, 7, 8]
|
||||||
|
_LEGIT_CZ_LEIXING = [1, 2, 3, 4, 5]
|
||||||
|
|
||||||
|
|
||||||
|
def collect_legitimate_wechat_payments(since_year, until_year):
|
||||||
|
"""
|
||||||
|
从业务单据重建:每笔 biz_ref 全局只出现一次。
|
||||||
|
返回 [(biz_ref, club_id, amount, stat_date, pay_datetime, kind), ...]
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from orders.models import Order
|
||||||
|
from products.models import Czjilu
|
||||||
|
|
||||||
|
start = datetime(since_year, 1, 1)
|
||||||
|
end = datetime(until_year + 1, 1, 1)
|
||||||
|
seen = {}
|
||||||
|
items = []
|
||||||
|
|
||||||
|
def _add(ref, club_id, amount, pay_dt, kind):
|
||||||
|
ref = (ref or '').strip()
|
||||||
|
if not ref or ref in seen:
|
||||||
|
return
|
||||||
|
jine = Decimal(str(amount or 0))
|
||||||
|
if jine <= 0:
|
||||||
|
return
|
||||||
|
cid = normalize_szjilu_club_id(club_id)
|
||||||
|
if not pay_dt:
|
||||||
|
pay_dt = datetime.now()
|
||||||
|
stat_d = pay_dt.date() if hasattr(pay_dt, 'date') else pay_dt
|
||||||
|
seen[ref] = True
|
||||||
|
items.append((ref, cid, jine, stat_d, pay_dt, kind))
|
||||||
|
|
||||||
|
for od in Order.query.filter(
|
||||||
|
CreateTime__gte=start,
|
||||||
|
CreateTime__lt=end,
|
||||||
|
Status__in=_LEGIT_ORDER_STATUSES,
|
||||||
|
):
|
||||||
|
_add(
|
||||||
|
f'order:{od.OrderID}',
|
||||||
|
getattr(od, 'ClubID', None),
|
||||||
|
od.Amount,
|
||||||
|
od.CreateTime,
|
||||||
|
'order',
|
||||||
|
)
|
||||||
|
|
||||||
|
for cz in Czjilu.query.filter(
|
||||||
|
CreateTime__gte=start,
|
||||||
|
CreateTime__lt=end,
|
||||||
|
zhuangtai=3,
|
||||||
|
leixing__in=_LEGIT_CZ_LEIXING,
|
||||||
|
):
|
||||||
|
_add(
|
||||||
|
f'cz:{cz.dingdan_id}',
|
||||||
|
getattr(cz, 'club_id', None),
|
||||||
|
cz.jine,
|
||||||
|
cz.CreateTime,
|
||||||
|
f'cz_{cz.leixing}',
|
||||||
|
)
|
||||||
|
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def rebuild_income_stats_from_scratch(since_year=None, until_year=None, dry_run=True):
|
||||||
|
"""
|
||||||
|
终极恢复:清空全部收支脏数据 → 按真实微信支付逐笔重建(每笔唯一)。
|
||||||
|
"""
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from django.db.models import Sum
|
||||||
|
|
||||||
|
until_year = until_year or date.today().year
|
||||||
|
since_year = since_year or (until_year - 1)
|
||||||
|
|
||||||
|
before = {
|
||||||
|
'daily': float(DailyIncomeStat.objects.aggregate(t=Sum('total_amount'))['t'] or 0),
|
||||||
|
'logs': 0,
|
||||||
|
'log_cnt': 0,
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
before['logs'] = float(PlatformIncomeLog.objects.aggregate(t=Sum('amount'))['t'] or 0)
|
||||||
|
before['log_cnt'] = PlatformIncomeLog.objects.count()
|
||||||
|
except _PLATFORM_LOG_ERRORS:
|
||||||
|
pass
|
||||||
|
|
||||||
|
items = collect_legitimate_wechat_payments(since_year, until_year)
|
||||||
|
total_amt = sum((x[2] for x in items), _ZERO)
|
||||||
|
today = date.today()
|
||||||
|
today_amt = sum((x[2] for x in items if x[3] == today), _ZERO)
|
||||||
|
today_cnt = sum(1 for x in items if x[3] == today)
|
||||||
|
|
||||||
|
month_amt = sum(
|
||||||
|
(x[2] for x in items if x[3].year == today.year and x[3].month == today.month),
|
||||||
|
_ZERO,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = {
|
||||||
|
'since_year': since_year,
|
||||||
|
'until_year': until_year,
|
||||||
|
'before_daily_total': before['daily'],
|
||||||
|
'before_log_total': before['logs'],
|
||||||
|
'before_log_count': before['log_cnt'],
|
||||||
|
'after_total': float(total_amt),
|
||||||
|
'after_count': len(items),
|
||||||
|
'today_amount': float(today_amt),
|
||||||
|
'today_count': today_cnt,
|
||||||
|
'month_amount': float(month_amt),
|
||||||
|
'items': items,
|
||||||
|
'dry_run': dry_run,
|
||||||
|
}
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
return result
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
try:
|
||||||
|
PlatformIncomeLog.objects.all().delete()
|
||||||
|
except _PLATFORM_LOG_ERRORS as exc:
|
||||||
|
raise RuntimeError(f'platform_income_log 不可用: {exc}') from exc
|
||||||
|
DailyIncomeStat.objects.all().delete()
|
||||||
|
|
||||||
|
by_day_club = defaultdict(lambda: {'amt': _ZERO, 'cnt': 0})
|
||||||
|
for ref, cid, jine, stat_d, pay_dt, _kind in items:
|
||||||
|
log = PlatformIncomeLog.objects.create(biz_ref=ref, club_id=cid, amount=jine)
|
||||||
|
if pay_dt:
|
||||||
|
PlatformIncomeLog.objects.filter(pk=log.pk).update(CreateTime=pay_dt)
|
||||||
|
key = (stat_d, cid)
|
||||||
|
by_day_club[key]['amt'] += jine
|
||||||
|
by_day_club[key]['cnt'] += 1
|
||||||
|
|
||||||
|
for (stat_d, cid), agg in by_day_club.items():
|
||||||
|
DailyIncomeStat.objects.create(
|
||||||
|
date=stat_d,
|
||||||
|
club_id=cid,
|
||||||
|
year=stat_d.year,
|
||||||
|
month=stat_d.month,
|
||||||
|
day=stat_d.day,
|
||||||
|
total_amount=agg['amt'],
|
||||||
|
total_count=agg['cnt'],
|
||||||
|
)
|
||||||
|
|
||||||
|
today_d = date.today()
|
||||||
|
club_ids = set(by_day_club.keys())
|
||||||
|
club_ids |= {(today_d, row.club_id) for row in Szjilu.objects.all()}
|
||||||
|
|
||||||
|
all_clubs = {cid for _, cid in club_ids}
|
||||||
|
for cid in all_clubs:
|
||||||
|
total = PlatformIncomeLog.objects.filter(club_id=cid).aggregate(
|
||||||
|
t=Sum('amount'),
|
||||||
|
)['t'] or _ZERO
|
||||||
|
today_flow = PlatformIncomeLog.objects.filter(
|
||||||
|
club_id=cid, CreateTime__date=today_d,
|
||||||
|
).aggregate(t=Sum('amount'))['t'] or _ZERO
|
||||||
|
szjilu, _ = Szjilu.objects.select_for_update().get_or_create(
|
||||||
|
club_id=cid,
|
||||||
|
defaults=dict(_SZJILU_DEFAULTS),
|
||||||
|
)
|
||||||
|
szjilu.TotalIncome = total
|
||||||
|
szjilu.TotalFlow = total
|
||||||
|
szjilu.DailyFlow = today_flow
|
||||||
|
szjilu.save(update_fields=['TotalIncome', 'TotalFlow', 'DailyFlow', 'UpdateTime'])
|
||||||
|
|
||||||
|
result['after_daily_total'] = float(
|
||||||
|
DailyIncomeStat.objects.aggregate(t=Sum('total_amount'))['t'] or 0
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def collect_today_live_wechat_payments(stat_date=None):
|
||||||
|
"""今日实时微信支付(含当日下单或当日完成支付的订单/充值)。"""
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
from orders.models import Order
|
||||||
|
from products.models import Czjilu
|
||||||
|
|
||||||
|
stat_date = stat_date or date.today()
|
||||||
|
day_start = datetime.combine(stat_date, datetime.min.time())
|
||||||
|
day_end = day_start + timedelta(days=1)
|
||||||
|
seen = {}
|
||||||
|
items = []
|
||||||
|
|
||||||
|
def _add(ref, club_id, amount, kind):
|
||||||
|
ref = (ref or '').strip()
|
||||||
|
if not ref or ref in seen:
|
||||||
|
return
|
||||||
|
jine = Decimal(str(amount or 0))
|
||||||
|
if jine <= 0:
|
||||||
|
return
|
||||||
|
cid = normalize_szjilu_club_id(club_id)
|
||||||
|
seen[ref] = True
|
||||||
|
items.append((ref, cid, jine, kind))
|
||||||
|
|
||||||
|
for od in Order.query.filter(Status__in=_LEGIT_ORDER_STATUSES).filter(
|
||||||
|
Q(CreateTime__gte=day_start, CreateTime__lt=day_end)
|
||||||
|
| Q(UpdateTime__gte=day_start, UpdateTime__lt=day_end),
|
||||||
|
):
|
||||||
|
_add(f'order:{od.OrderID}', getattr(od, 'ClubID', None), od.Amount, 'order')
|
||||||
|
|
||||||
|
for cz in Czjilu.query.filter(zhuangtai=3, leixing__in=_LEGIT_CZ_LEIXING).filter(
|
||||||
|
Q(CreateTime__gte=day_start, CreateTime__lt=day_end)
|
||||||
|
| Q(UpdateTime__gte=day_start, UpdateTime__lt=day_end),
|
||||||
|
):
|
||||||
|
_add(f'cz:{cz.dingdan_id}', getattr(cz, 'club_id', None), cz.jine, f'cz_{cz.leixing}')
|
||||||
|
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def repopulate_today_income_stats(stat_date=None, dry_run=True):
|
||||||
|
"""只重建指定日期的日收入(不删历史其它天),修复今日显示为 0。"""
|
||||||
|
from collections import defaultdict
|
||||||
|
from datetime import datetime, time as dt_time
|
||||||
|
|
||||||
|
from django.db.models import Sum
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
stat_date = stat_date or date.today()
|
||||||
|
before = DailyIncomeStat.objects.filter(date=stat_date).aggregate(
|
||||||
|
amt=Sum('total_amount'), cnt=Sum('total_count'),
|
||||||
|
)
|
||||||
|
items = collect_today_live_wechat_payments(stat_date)
|
||||||
|
total = sum((x[2] for x in items), _ZERO)
|
||||||
|
|
||||||
|
result = {
|
||||||
|
'date': str(stat_date),
|
||||||
|
'before_amount': float(before['amt'] or 0),
|
||||||
|
'before_count': int(before['cnt'] or 0),
|
||||||
|
'after_amount': float(total),
|
||||||
|
'after_count': len(items),
|
||||||
|
'items': items,
|
||||||
|
'dry_run': dry_run,
|
||||||
|
}
|
||||||
|
if dry_run:
|
||||||
|
return result
|
||||||
|
|
||||||
|
pay_ts = timezone.make_aware(datetime.combine(stat_date, dt_time(12, 0, 0)))
|
||||||
|
with transaction.atomic():
|
||||||
|
DailyIncomeStat.objects.filter(date=stat_date).delete()
|
||||||
|
|
||||||
|
by_club = defaultdict(lambda: {'amt': _ZERO, 'cnt': 0})
|
||||||
|
for ref, cid, jine, _kind in items:
|
||||||
|
if not income_log_exists(ref):
|
||||||
|
try:
|
||||||
|
log = PlatformIncomeLog.objects.create(biz_ref=ref, club_id=cid, amount=jine)
|
||||||
|
PlatformIncomeLog.objects.filter(pk=log.pk).update(CreateTime=pay_ts)
|
||||||
|
except IntegrityError:
|
||||||
|
pass
|
||||||
|
by_club[cid]['amt'] += jine
|
||||||
|
by_club[cid]['cnt'] += 1
|
||||||
|
|
||||||
|
for cid, agg in by_club.items():
|
||||||
|
DailyIncomeStat.objects.create(
|
||||||
|
date=stat_date,
|
||||||
|
club_id=cid,
|
||||||
|
year=stat_date.year,
|
||||||
|
month=stat_date.month,
|
||||||
|
day=stat_date.day,
|
||||||
|
total_amount=agg['amt'],
|
||||||
|
total_count=agg['cnt'],
|
||||||
|
)
|
||||||
|
|
||||||
|
today_d = date.today()
|
||||||
|
for cid, agg in by_club.items():
|
||||||
|
szjilu, _ = Szjilu.objects.select_for_update().get_or_create(
|
||||||
|
club_id=cid, defaults=dict(_SZJILU_DEFAULTS),
|
||||||
|
)
|
||||||
|
if stat_date == today_d:
|
||||||
|
szjilu.DailyFlow = agg['amt']
|
||||||
|
total_all = PlatformIncomeLog.objects.filter(club_id=cid).aggregate(
|
||||||
|
t=Sum('amount'),
|
||||||
|
)['t'] or _ZERO
|
||||||
|
szjilu.TotalIncome = total_all
|
||||||
|
szjilu.TotalFlow = total_all
|
||||||
|
szjilu.save(update_fields=['TotalIncome', 'TotalFlow', 'DailyFlow', 'UpdateTime'])
|
||||||
|
|
||||||
|
return result
|
||||||
|
|||||||
@@ -33,14 +33,14 @@ def get_order_user_id(order):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def update_daily_income(amount, club_id=None):
|
def update_daily_income(amount, club_id=None, stat_date=None):
|
||||||
"""
|
"""
|
||||||
原子更新当日收入统计(金额累加,笔数加1)。
|
原子更新当日收入统计(金额累加,笔数加1)。
|
||||||
用于微信支付成功回调。
|
用于微信支付成功回调。
|
||||||
"""
|
"""
|
||||||
from jituan.constants import CLUB_ID_DEFAULT
|
from jituan.constants import CLUB_ID_DEFAULT
|
||||||
cid = club_id or CLUB_ID_DEFAULT
|
cid = club_id or CLUB_ID_DEFAULT
|
||||||
today = date.today()
|
today = stat_date or date.today()
|
||||||
year, month, day = today.year, today.month, today.day
|
year, month, day = today.year, today.month, today.day
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
|
|||||||
Reference in New Issue
Block a user