"""俱乐部维度财务统计(供 /jituan/houtai/caiwu,旧 /houtai/caiwu 不变)。""" from datetime import date, datetime, timedelta 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 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 _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 返回结构一致;收入/支出只读 daily_income_stat、daily_payout_stat。""" 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) payout_qs = _daily_payout_qs(request) scope = resolve_club_scope(request) # 四个板子:全平台合计(与 /houtai/caiwu 一致,读 date 字段) today_inc = DailyIncomeStat.query.filter(date=today).aggregate( total_amount=Sum('total_amount'), total_count=Sum('total_count'), ) today_income_amount = float(today_inc['total_amount'] or 0.00) today_income_count = int(today_inc['total_count'] or 0) today_pay = DailyPayoutStat.query.filter(date=today).aggregate( total_amount=Sum('total_amount'), total_count=Sum('total_count'), ) today_payout_amount = float(today_pay['total_amount'] or 0.00) today_payout_count = int(today_pay['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) 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_income_qs = _daily_income_qs(request) scoped_payout_qs = _daily_payout_qs(request) scoped_total_income = float(scoped_income_qs.aggregate(total=Sum('total_amount'))['total'] or 0.00) scoped_total_payout = float(scoped_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) income_by_date = { str(row['date']): { 'income': float(row['total_amount'] or 0), 'income_count': int(row['total_count'] or 0), } for row in DailyIncomeStat.query.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 DailyPayoutStat.query.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), }) return { 'club_id': club_id, 'scope': resolve_club_scope(request), '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, }