fix: separate penalty czjilu from merchant recharge and correct finance stats
This commit is contained in:
219
backend/view.py
219
backend/view.py
@@ -7663,228 +7663,29 @@ class CwqtczhqView(APIView):
|
||||
if 'qtczcaiwu' not in permissions:
|
||||
return Response({'code': 403, 'msg': '无其他充值财务查看权限'}, status=403)
|
||||
|
||||
from jituan.services.finance_detail_stats import build_chongzhi_finance_payload
|
||||
|
||||
granularity = request.data.get('granularity', 'day')
|
||||
year = request.data.get('year')
|
||||
month = request.data.get('month')
|
||||
types = request.data.get('types', [2, 3, 4, 5, 6]) # 默认全部
|
||||
types = request.data.get('types', [2, 3, 4, 5, 6])
|
||||
summary_date = request.data.get('summary_date')
|
||||
|
||||
if isinstance(types, list) and len(types) == 0:
|
||||
types = [2, 3, 4, 5, 6]
|
||||
|
||||
now = date.today()
|
||||
data, err = build_chongzhi_finance_payload(
|
||||
request, granularity, year, month, types, summary_date,
|
||||
)
|
||||
if err:
|
||||
return Response({'code': 1, 'msg': err}, status=400)
|
||||
|
||||
# ---------- 时间范围(用于曲线图) ----------
|
||||
if granularity == 'day':
|
||||
if not year or not month:
|
||||
return Response({'code': 1, 'msg': '按日统计需要年份和月份'}, status=400)
|
||||
start_date = date(year, month, 1)
|
||||
end_date = date(year, month + 1, 1) if month < 12 else date(year + 1, 1, 1)
|
||||
trunc_func = TruncDate('CreateTime')
|
||||
# 默认汇总日期
|
||||
if not summary_date:
|
||||
summary_date = now.strftime('%Y-%m-%d')
|
||||
summary_q = datetime.strptime(summary_date, '%Y-%m-%d').date()
|
||||
elif granularity == 'month':
|
||||
if not year:
|
||||
return Response({'code': 1, 'msg': '按月统计需要年份'}, status=400)
|
||||
start_date = date(year, 1, 1)
|
||||
end_date = date(year + 1, 1, 1)
|
||||
trunc_func = TruncMonth('CreateTime')
|
||||
if not summary_date:
|
||||
summary_date = now.strftime('%Y-%m')
|
||||
summary_q = datetime.strptime(summary_date + '-01', '%Y-%m-%d').date()
|
||||
elif granularity == 'year':
|
||||
year = year or now.year
|
||||
start_date = date(year, 1, 1)
|
||||
end_date = date(year + 1, 1, 1)
|
||||
trunc_func = TruncYear('CreateTime')
|
||||
if not summary_date:
|
||||
summary_date = str(year)
|
||||
summary_q = date(year, 1, 1)
|
||||
else:
|
||||
return Response({'code': 1, 'msg': '无效的颗粒度'}, status=400)
|
||||
|
||||
start_dt = datetime.combine(start_date, datetime.min.time())
|
||||
end_dt = datetime.combine(end_date, datetime.min.time())
|
||||
|
||||
# ---------- 构建时间序列 ----------
|
||||
time_series_map = {} # period_str -> { type_code: {count, amount, profit, fenhong_count, fenhong_amount} }
|
||||
|
||||
def ensure_date(ds):
|
||||
if ds not in time_series_map:
|
||||
time_series_map[ds] = {}
|
||||
return time_series_map[ds]
|
||||
|
||||
# 1. 处理充值记录(Czjilu)—— 完全不变
|
||||
cz_types = [t for t in types if t in [2, 3, 4, 5]]
|
||||
if cz_types:
|
||||
cz_qs = filter_queryset_by_club(
|
||||
Czjilu.query.filter(
|
||||
CreateTime__gte=start_dt,
|
||||
CreateTime__lt=end_dt,
|
||||
leixing__in=cz_types,
|
||||
zhuangtai=3,
|
||||
),
|
||||
request,
|
||||
).annotate(
|
||||
period=trunc_func
|
||||
).values('period', 'leixing').annotate(
|
||||
total_count=Count('id'),
|
||||
total_amount=Sum('jine')
|
||||
).order_by('period', 'leixing')
|
||||
|
||||
for item in cz_qs:
|
||||
period_str = item['period'].strftime('%Y-%m-%d') if granularity == 'day' else \
|
||||
item['period'].strftime('%Y-%m') if granularity == 'month' else \
|
||||
item['period'].strftime('%Y')
|
||||
lx = item['leixing']
|
||||
amount = float(item['total_amount'] or 0)
|
||||
count = item['total_count']
|
||||
# 收益:积分(3)收益为金额本身,其他为0
|
||||
profit = amount if lx == 3 else 0.0
|
||||
|
||||
day_data = ensure_date(period_str)
|
||||
day_data[str(lx)] = {
|
||||
'count': count,
|
||||
'amount': amount,
|
||||
'profit': profit,
|
||||
'fenhong_count': 0, # 充值类型无分红
|
||||
'fenhong_amount': 0.0
|
||||
}
|
||||
|
||||
# 2. 处理罚款(Penalty)—— 修改:直接从 Penalty 表获取分红总额和分红笔数
|
||||
if 6 in types:
|
||||
# 使用一次聚合查询,同时获取罚款笔数、罚款金额、分红总额、分红笔数
|
||||
penalty_qs = filter_penalty_qs(
|
||||
Penalty.query.filter(
|
||||
CreateTime__gte=start_dt,
|
||||
CreateTime__lt=end_dt,
|
||||
Status=2,
|
||||
),
|
||||
request,
|
||||
).annotate(
|
||||
period=trunc_func
|
||||
).values('period').annotate(
|
||||
penalty_count=Count('id'),
|
||||
penalty_amount=Sum('FineAmount'),
|
||||
# 直接使用罚单表中的申请人分红金额字段
|
||||
fenhong_amount=Sum('ApplicantBonusAmount'),
|
||||
fenhong_count=Count('id', filter=Q(ApplicantBonusAmount__gt=0))
|
||||
).order_by('period')
|
||||
|
||||
for item in penalty_qs:
|
||||
period_str = item['period'].strftime('%Y-%m-%d') if granularity == 'day' else \
|
||||
item['period'].strftime('%Y-%m') if granularity == 'month' else \
|
||||
item['period'].strftime('%Y')
|
||||
day_data = ensure_date(period_str)
|
||||
penalty_amt = float(item['penalty_amount'] or 0)
|
||||
fenhong_amt = float(item['fenhong_amount'] or 0)
|
||||
profit = round(penalty_amt - fenhong_amt, 2)
|
||||
day_data['6'] = {
|
||||
'count': item['penalty_count'],
|
||||
'amount': penalty_amt,
|
||||
'profit': profit,
|
||||
'fenhong_count': item['fenhong_count'],
|
||||
'fenhong_amount': fenhong_amt
|
||||
}
|
||||
|
||||
# 构造有序时间序列列表
|
||||
time_series = []
|
||||
for period_str in sorted(time_series_map.keys()):
|
||||
entry = {'date': period_str, 'types': {}}
|
||||
for type_code in sorted(time_series_map[period_str].keys()):
|
||||
entry['types'][type_code] = time_series_map[period_str][type_code]
|
||||
time_series.append(entry)
|
||||
|
||||
# ---------- 汇总指定日期(summary)—— 完全保留原逻辑,仅将罚款部分改为从 Penalty 表直接取分红 ----------
|
||||
summary_result = {'by_type': {}, 'total_count': 0, 'total_amount': 0.0, 'total_profit': 0.0}
|
||||
|
||||
# 汇总充值类型(完全不变)
|
||||
for lx in cz_types:
|
||||
filter_kwargs = {
|
||||
'leixing': lx,
|
||||
'zhuangtai': 3,
|
||||
}
|
||||
if granularity == 'day':
|
||||
filter_kwargs['CreateTime__date'] = summary_q
|
||||
elif granularity == 'month':
|
||||
filter_kwargs['CreateTime__year'] = summary_q.year
|
||||
filter_kwargs['CreateTime__month'] = summary_q.month
|
||||
else:
|
||||
filter_kwargs['CreateTime__year'] = summary_q.year
|
||||
agg = filter_queryset_by_club(
|
||||
Czjilu.query.filter(**filter_kwargs), request,
|
||||
).aggregate(count=Count('id'), amount=Sum('jine'))
|
||||
count = agg['count'] or 0
|
||||
amount = float(agg['amount'] or 0)
|
||||
profit = amount if lx == 3 else 0.0
|
||||
summary_result['by_type'][str(lx)] = {
|
||||
'count': count,
|
||||
'amount': round(amount, 2),
|
||||
'profit': round(profit, 2),
|
||||
'fenhong_count': 0,
|
||||
'fenhong_amount': 0.0
|
||||
}
|
||||
summary_result['total_count'] += count
|
||||
summary_result['total_amount'] += amount
|
||||
summary_result['total_profit'] += profit
|
||||
|
||||
# 汇总罚款(修改:从 Penalty 表直接取分红,不再查询 PenaltyBonus)
|
||||
if 6 in types:
|
||||
penalty_filter = {
|
||||
'Status': 2,
|
||||
}
|
||||
if granularity == 'day':
|
||||
penalty_filter['CreateTime__date'] = summary_q
|
||||
elif granularity == 'month':
|
||||
penalty_filter['CreateTime__year'] = summary_q.year
|
||||
penalty_filter['CreateTime__month'] = summary_q.month
|
||||
else:
|
||||
penalty_filter['CreateTime__year'] = summary_q.year
|
||||
|
||||
# 一次聚合:罚款笔数、金额、分红总额、分红笔数
|
||||
agg = filter_penalty_qs(
|
||||
Penalty.query.filter(**penalty_filter), request,
|
||||
).aggregate(
|
||||
count=Count('id'),
|
||||
amount=Sum('FineAmount'),
|
||||
fenhong_amount=Sum('ApplicantBonusAmount'),
|
||||
fenhong_count=Count('id', filter=Q(ApplicantBonusAmount__gt=0))
|
||||
)
|
||||
penalty_count = agg['count'] or 0
|
||||
penalty_amount = float(agg['amount'] or 0)
|
||||
fh_amount = float(agg['fenhong_amount'] or 0)
|
||||
fh_count = agg['fenhong_count'] or 0
|
||||
profit = round(penalty_amount - fh_amount, 2)
|
||||
|
||||
summary_result['by_type']['6'] = {
|
||||
'count': penalty_count,
|
||||
'amount': round(penalty_amount, 2),
|
||||
'profit': profit,
|
||||
'fenhong_count': fh_count,
|
||||
'fenhong_amount': round(fh_amount, 2)
|
||||
}
|
||||
summary_result['total_count'] += penalty_count
|
||||
summary_result['total_amount'] += penalty_amount
|
||||
summary_result['total_profit'] += profit
|
||||
|
||||
summary_result['total_amount'] = round(summary_result['total_amount'], 2)
|
||||
summary_result['total_profit'] = round(summary_result['total_profit'], 2)
|
||||
|
||||
return Response({
|
||||
'code': 0,
|
||||
'msg': 'ok',
|
||||
'data': {
|
||||
'time_series': time_series,
|
||||
'summary': summary_result
|
||||
}
|
||||
})
|
||||
return Response({'code': 0, 'msg': 'ok', 'data': data})
|
||||
except Exception as e:
|
||||
logger.exception("CwqtczhqView 接口错误")
|
||||
return Response({'code': 1, 'msg': f'服务器内部错误: {str(e)}'}, status=500)
|
||||
|
||||
'''class CwqtczhqView(APIView):
|
||||
'''class CwqtczhqView_LEGACY(APIView):
|
||||
"""
|
||||
其他充值/罚款数据统计(非会员充值)
|
||||
POST /houtai/cwqtczhq
|
||||
|
||||
Reference in New Issue
Block a user