fix: separate penalty czjilu from merchant recharge and correct finance stats

This commit is contained in:
XingQue
2026-06-27 18:50:32 +08:00
parent 65477592af
commit 54f8e23488
9 changed files with 249 additions and 240 deletions

View File

@@ -20,6 +20,12 @@ def _club_id_from_user_uid(uid):
return None
def penalty_cz_club_id(fadan):
"""罚款支付 czjilu.club_id与罚单归属一致申请人俱乐部"""
cid = (getattr(fadan, 'ClubID', None) or '').strip()
return cid or CLUB_ID_DEFAULT
def resolve_penalty_club_id(
order=None,
penalized_user_id=None,

View File

@@ -1,7 +1,8 @@
"""财务子模块统计(订单/会员/其他充值),供 /jituan/houtai/*;旧 /houtai/* 不变。"""
from datetime import date, datetime
from decimal import Decimal
from django.db.models import Count, Q, Sum
from django.db.models import Case, Count, DecimalField, Q, Sum, Value, When
from django.db.models.functions import TruncDate, TruncMonth, TruncYear
from jituan.constants import DATA_SCOPE_ALL
@@ -13,6 +14,7 @@ from jituan.services.club_context import (
)
from jituan.services.club_penalty import filter_gsfenhong_qs, filter_penalty_qs
from orders.models import Order, Penalty
from products.czjilu_types import CZJILU_LEIXING_SHANGJIA, exclude_penalty_from_cz_qs
from products.models import Czjilu, Gsfenhong, Huiyuan, ShangpinLeixing
from rank.models import Bankuai
@@ -77,6 +79,57 @@ def _summary_date_filter(granularity, summary_q, field_prefix='CreateTime'):
return {f'{field_prefix}__year': summary_q.year}
def _penalty_trunc_func(granularity):
if granularity == 'day':
return TruncDate('UpdateTime')
if granularity == 'month':
return TruncMonth('UpdateTime')
return TruncYear('UpdateTime')
def _penalty_fenhong_aggregates():
"""罚款分红只统计已入账BonusCredited与 process_fadan_fenhong 一致。"""
zero = Value(Decimal('0.00'), output_field=DecimalField(max_digits=12, decimal_places=2))
return {
'fenhong_amount': Sum(
Case(
When(BonusCredited=True, then='ApplicantBonusAmount'),
default=zero,
output_field=DecimalField(max_digits=12, decimal_places=2),
)
),
'fenhong_count': Count(
'id',
filter=Q(BonusCredited=True, ApplicantBonusAmount__gt=0),
),
}
def _czjilu_finance_qs(request, start_dt, end_dt, cz_types):
"""充值财务 czjilu已支付type4 排除罚款误标。"""
qs = filter_queryset_by_club(
Czjilu.query.filter(
CreateTime__gte=start_dt,
CreateTime__lt=end_dt,
leixing__in=cz_types,
zhuangtai=3,
),
request,
)
if CZJILU_LEIXING_SHANGJIA in cz_types:
qs = exclude_penalty_from_cz_qs(qs)
return qs
def _czjilu_summary_qs(request, lx, granularity, summary_q):
filter_kwargs = {'leixing': lx, 'zhuangtai': 3}
filter_kwargs.update(_summary_date_filter(granularity, summary_q))
qs = filter_queryset_by_club(Czjilu.query.filter(**filter_kwargs), request)
if lx == CZJILU_LEIXING_SHANGJIA:
qs = exclude_penalty_from_cz_qs(qs)
return qs
def build_order_types_payload():
types = ShangpinLeixing.query.filter(shenhezhuangtai=1).values('id', 'jieshao')
return list(types)
@@ -209,15 +262,9 @@ def build_chongzhi_finance_payload(request, granularity, year, month, types=None
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(
cz_qs = _czjilu_finance_qs(request, start_dt, end_dt, cz_types).annotate(
period=trunc_func,
).values('period', 'leixing').annotate(
total_count=Count('id'),
total_amount=Sum('jine'),
).order_by('period', 'leixing')
@@ -242,14 +289,18 @@ def build_chongzhi_finance_payload(request, granularity, year, month, types=None
}
if 6 in types:
penalty_trunc = _penalty_trunc_func(granularity)
penalty_qs = filter_penalty_qs(
Penalty.query.filter(CreateTime__gte=start_dt, CreateTime__lt=end_dt, Status=2),
Penalty.query.filter(
UpdateTime__gte=start_dt,
UpdateTime__lt=end_dt,
Status=2,
),
request,
).annotate(period=trunc_func).values('period').annotate(
).annotate(period=penalty_trunc).values('period').annotate(
penalty_count=Count('id'),
penalty_amount=Sum('FineAmount'),
fenhong_amount=Sum('ApplicantBonusAmount'),
fenhong_count=Count('id', filter=Q(ApplicantBonusAmount__gt=0)),
**_penalty_fenhong_aggregates(),
).order_by('period')
for item in penalty_qs:
@@ -279,9 +330,7 @@ def build_chongzhi_finance_payload(request, granularity, year, month, types=None
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}
filter_kwargs.update(_summary_date_filter(granularity, summary_q))
agg = filter_queryset_by_club(Czjilu.query.filter(**filter_kwargs), request).aggregate(
agg = _czjilu_summary_qs(request, lx, granularity, summary_q).aggregate(
count=Count('id'), amount=Sum('jine'),
)
count = agg['count'] or 0
@@ -300,12 +349,11 @@ def build_chongzhi_finance_payload(request, granularity, year, month, types=None
if 6 in types:
penalty_filter = {'Status': 2}
penalty_filter.update(_summary_date_filter(granularity, summary_q))
penalty_filter.update(_summary_date_filter(granularity, summary_q, field_prefix='UpdateTime'))
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_fenhong_aggregates(),
)
penalty_count = agg['count'] or 0
penalty_amount = float(agg['amount'] or 0)

View File

@@ -309,8 +309,8 @@ def sync_szjilu_income_from_logs():
# 订单已付款且非退款repair 错误地把 Status=5 退款单也计入了收入)
_ORDER_INCOME_STATUSES = [1, 2, 3, 4, 6, 7, 8]
# 微信充值类 czjilu会员/押金/积分/商家/罚单/考核
_CZ_WECHAT_LEIXING = [1, 2, 3, 4, 5]
# 微信充值类 czjilu会员/押金/积分/商家/考核/罚款
_CZ_WECHAT_LEIXING = [1, 2, 3, 4, 5, 6]
def collect_canonical_wechat_income_for_date(stat_date, existing_refs=None):
@@ -701,7 +701,7 @@ def reset_all_daily_szjilu():
# 合法微信支付收入(不含退款 Status=5
_LEGIT_ORDER_STATUSES = [1, 2, 3, 4, 6, 7, 8]
_LEGIT_CZ_LEIXING = [1, 2, 3, 4, 5]
_LEGIT_CZ_LEIXING = [1, 2, 3, 4, 5, 6]
def collect_legitimate_wechat_payments(since_year, until_year):