Files
Django/jituan/services/caiwu_stats.py
2026-06-24 21:35:55 +08:00

246 lines
9.5 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.
"""俱乐部维度财务统计(供 /jituan/houtai/caiwu旧 /houtai/caiwu 不变)。"""
from calendar import monthrange
from datetime import date, datetime, timedelta
from decimal import Decimal
from django.db.models import Sum
from jituan.services.club_context import (
filter_club_char_field,
filter_queryset_by_club,
resolve_club_id_from_request,
resolve_club_scope,
)
from jituan.constants import DATA_SCOPE_ALL
from config.models import DailyIncomeStat, DailyPayoutStat, Szjilu
from orders.models import Order
from products.models import Czjilu, Huiyuangoumai
from users.models import UserDashou, UserGuanshi, UserShangjia, UserZuzhang
def _role_profile_qs(profile_model, request):
"""按俱乐部过滤角色扩展表(通过 user.ClubID"""
qs = profile_model.query.all()
if resolve_club_scope(request) == DATA_SCOPE_ALL:
return qs
return qs.filter(user__ClubID=resolve_club_id_from_request(request))
def _sum_role_balance(profile_model, balance_field, request):
return float(
_role_profile_qs(profile_model, request).aggregate(total=Sum(balance_field))['total'] or 0.00
)
def _build_szjilu_payload(request):
"""全局收支流水表 szjilu按俱乐部或集团汇总"""
if resolve_club_scope(request) == DATA_SCOPE_ALL:
agg = Szjilu.query.aggregate(
zongshouyi=Sum('TotalIncome'),
zongliushui=Sum('TotalFlow'),
zongzhichu=Sum('TotalExpense'),
jrls=Sum('DailyFlow'),
jrzc=Sum('DailyExpense'),
)
return {
'zongliushui': float(agg['zongliushui'] or 0),
'zongshouyi': float(agg['zongshouyi'] or 0),
'zongzhichu': float(agg['zongzhichu'] or 0),
'jrls': float(agg['jrls'] or 0),
'jrzc': float(agg['jrzc'] or 0),
}
from jituan.services.szjilu_accounting import get_szjilu_snapshot
return get_szjilu_snapshot(resolve_club_id_from_request(request))
def _order_qs(request):
return filter_queryset_by_club(Order.query.all(), request, club_field='ClubID')
def _czjilu_qs(request):
return filter_club_char_field(Czjilu.query.all(), request, field='club_id')
def _huiyuangoumai_qs(request):
return filter_club_char_field(Huiyuangoumai.query.all(), request, field='club_id')
def _daily_income_qs(request):
return filter_club_char_field(DailyIncomeStat.query.all(), request, field='club_id')
def _daily_payout_qs(request):
return filter_club_char_field(DailyPayoutStat.query.all(), request, field='club_id')
def build_caiwu_payload(request):
"""与 CaiwuView 返回结构一致,但按俱乐部过滤订单/充值流水。"""
today = date.today()
today_start = datetime.combine(today, datetime.min.time())
today_end = today_start + timedelta(days=1)
club_id = resolve_club_id_from_request(request)
order_qs = _order_qs(request)
cz_qs = _czjilu_qs(request)
hy_qs = _huiyuangoumai_qs(request)
income_qs = _daily_income_qs(request)
payout_qs = _daily_payout_qs(request)
scope = resolve_club_scope(request)
today_income_qs = income_qs.filter(date=today)
today_payout_qs = payout_qs.filter(date=today)
inc_agg = today_income_qs.aggregate(
total_amount=Sum('total_amount'),
total_count=Sum('total_count'),
)
today_income_amount = float(inc_agg['total_amount'] or 0.00)
today_income_count = int(inc_agg['total_count'] or 0)
pay_agg = today_payout_qs.aggregate(
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_orders = order_qs.filter(
CreateTime__gte=today_start,
CreateTime__lt=today_end,
Status__in=[1, 2, 3, 4, 5, 6, 7, 8],
)
today_order_count = today_orders.count()
today_order_amount = float(today_orders.aggregate(total=Sum('Amount'))['total'] or 0.00)
today_completed = order_qs.filter(
CreateTime__gte=today_start, CreateTime__lt=today_end, Status=3,
)
today_completed_count = today_completed.count()
today_completed_amount = float(today_completed.aggregate(total=Sum('Amount'))['total'] or 0.00)
today_tuikuan = order_qs.filter(
CreateTime__gte=today_start, CreateTime__lt=today_end, Status=5,
)
today_tuikuan_count = today_tuikuan.count()
today_tuikuan_amount = float(today_tuikuan.aggregate(total=Sum('Amount'))['total'] or 0.00)
today_chongzhi = cz_qs.filter(
CreateTime__gte=today_start, CreateTime__lt=today_end, leixing=1, zhuangtai=3,
)
today_chongzhi_count = today_chongzhi.count()
today_chongzhi_amount = float(today_chongzhi.aggregate(total=Sum('jine'))['total'] or 0.00)
new_huiyuan_user_ids = hy_qs.filter(
CreateTime__gte=today_start, CreateTime__lt=today_end,
).values_list('yonghu_id', flat=True).distinct()
today_new_huiyuan = len(list(new_huiyuan_user_ids))
today_new_huiyuan_amount = 0.0
if new_huiyuan_user_ids:
amount_sum = cz_qs.filter(
CreateTime__gte=today_start,
CreateTime__lt=today_end,
yonghuid__in=new_huiyuan_user_ids,
leixing=1,
zhuangtai=3,
).aggregate(total=Sum('jine'))
today_new_huiyuan_amount = float(amount_sum['total'] or 0.0)
all_guanshi_yue = _sum_role_balance(UserGuanshi, 'yue', request)
all_dashou_yue = _sum_role_balance(UserDashou, 'yue', request)
all_zuzhang_yue = _sum_role_balance(UserZuzhang, 'ketixian_jine', request)
all_shangjia_yue = _sum_role_balance(UserShangjia, 'yue', request)
szjilu_payload = _build_szjilu_payload(request)
# 账户总收入/总支出:始终全集团合计(切换俱乐部也不变少)
total_income = float(
DailyIncomeStat.query.aggregate(total=Sum('total_amount'))['total'] or 0.00
)
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 = []
since = today - timedelta(days=30)
if scope == DATA_SCOPE_ALL:
income_by_date = {
str(row['date']): {
'income': float(row['total_amount'] or 0),
'income_count': int(row['total_count'] or 0),
}
for row in income_qs.filter(date__gte=since).values('date').annotate(
total_amount=Sum('total_amount'),
total_count=Sum('total_count'),
)
}
payout_by_date = {
str(row['date']): float(row['total_amount'] or 0)
for row in payout_qs.filter(date__gte=since).values('date').annotate(
total_amount=Sum('total_amount'),
)
}
all_dates = sorted(
set(income_by_date.keys()) | set(payout_by_date.keys()),
reverse=True,
)[:30]
for d in all_dates:
inc = income_by_date.get(d, {'income': 0.0, 'income_count': 0})
payout_amt = payout_by_date.get(d, 0.00)
daily_stats.append({
'date': d,
'income': inc['income'],
'income_count': inc['income_count'],
'payout': payout_amt,
'profit': round(inc['income'] - payout_amt, 2),
})
else:
income_list = income_qs.filter(date__gte=since).order_by('-date')[:30]
payout_dict = {
str(p.date): float(p.total_amount)
for p in payout_qs.filter(date__gte=since)
}
for inc in income_list:
d = str(inc.date)
payout_amt = payout_dict.get(d, 0.00)
daily_stats.append({
'date': d,
'income': float(inc.total_amount),
'income_count': inc.total_count,
'payout': payout_amt,
'profit': round(float(inc.total_amount) - payout_amt, 2),
})
return {
'club_id': club_id,
'scope': resolve_club_scope(request),
'szjilu': szjilu_payload,
'today_income': round(today_income_amount, 2),
'today_income_count': today_income_count,
'today_payout': round(today_payout_amount, 2),
'today_payout_count': today_payout_count,
'today_order_count': today_order_count,
'today_order_amount': round(today_order_amount, 2),
'today_completed_count': today_completed_count,
'today_completed_amount': round(today_completed_amount, 2),
'today_tuikuan_count': today_tuikuan_count,
'today_tuikuan_amount': round(today_tuikuan_amount, 2),
'today_chongzhi_count': today_chongzhi_count,
'today_chongzhi_amount': round(today_chongzhi_amount, 2),
'today_new_huiyuan': today_new_huiyuan,
'today_new_huiyuan_amount': round(today_new_huiyuan_amount, 2),
'all_guanshi_yue': round(all_guanshi_yue, 2),
'all_dashou_yue': round(all_dashou_yue, 2),
'all_zuzhang_yue': round(all_zuzhang_yue, 2),
'all_shangjia_yue': round(all_shangjia_yue, 2),
'total_income': round(total_income, 2),
'total_payout': round(total_payout, 2),
'platform_profit': platform_profit,
'daily_stats': daily_stats,
}