Files
Django/jituan/services/szjilu_accounting.py
2026-06-24 20:58:28 +08:00

150 lines
4.6 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.
"""各俱乐部全局收支流水szjilu统一记账。"""
import logging
from decimal import Decimal
from django.db import IntegrityError, transaction
from django.db.utils import OperationalError, ProgrammingError
from config.models import PlatformIncomeLog, Szjilu
from jituan.constants import CLUB_ID_DEFAULT
logger = logging.getLogger(__name__)
_ZERO = Decimal('0.00')
_SZJILU_DEFAULTS = {
'TotalIncome': _ZERO,
'TotalFlow': _ZERO,
'TotalExpense': _ZERO,
'DailyExpense': _ZERO,
'DailyFlow': _ZERO,
}
_PLATFORM_LOG_ERRORS = (ProgrammingError, OperationalError)
def normalize_szjilu_club_id(club_id):
return (club_id or '').strip() or CLUB_ID_DEFAULT
def _get_szjilu_for_update(club_id):
cid = normalize_szjilu_club_id(club_id)
szjilu, _ = Szjilu.objects.select_for_update().get_or_create(
club_id=cid,
defaults=dict(_SZJILU_DEFAULTS),
)
return szjilu
def apply_szjilu_income(amount, club_id=None):
"""平台收入:总收益、总流水、今日流水增加。"""
jine = Decimal(str(amount))
with transaction.atomic():
szjilu = _get_szjilu_for_update(club_id)
szjilu.TotalIncome += jine
szjilu.TotalFlow += jine
szjilu.DailyFlow += jine
szjilu.save()
def _apply_income_stats(amount, club_id):
"""写入 daily_income_stat + szjilu核心统计必须成功"""
from orders.utils import update_daily_income
cid = normalize_szjilu_club_id(club_id)
jine = Decimal(str(amount))
update_daily_income(jine, cid)
apply_szjilu_income(jine, cid)
def record_wechat_income_once(amount, club_id=None, biz_ref=None):
"""
微信入账:同一 biz_ref 只记一次 daily_income_stat + szjilu。
返回 True=本次新入账False=已记过(重复回调)。
若 platform_income_log 表不可用,仍记入收入(与改造前一致,不能因幂等表故障丢统计)。
"""
ref = (biz_ref or '').strip()
if not ref:
raise ValueError('biz_ref 不能为空')
cid = normalize_szjilu_club_id(club_id)
jine = Decimal(str(amount))
try:
with transaction.atomic():
PlatformIncomeLog.objects.create(
biz_ref=ref,
club_id=cid,
amount=jine,
)
except IntegrityError:
logger.info('平台入账已存在,跳过重复记账 biz_ref=%s', ref)
return False
except _PLATFORM_LOG_ERRORS as exc:
logger.warning(
'platform_income_log 不可用(%s),跳过幂等直接记入收入 biz_ref=%s',
exc, ref,
)
_apply_income_stats(jine, cid)
return True
except Exception as exc:
logger.error(
'platform_income_log 写入异常,仍记入收入 biz_ref=%s err=%s',
ref, exc, exc_info=True,
)
_apply_income_stats(jine, cid)
return True
try:
_apply_income_stats(jine, cid)
except Exception:
try:
PlatformIncomeLog.objects.filter(biz_ref=ref).delete()
except Exception:
pass
raise
logger.info('平台入账记账成功 biz_ref=%s club=%s amount=%s', ref, cid, jine)
return True
def apply_szjilu_expense(amount, club_id=None):
"""平台出款/支出:总收益减少,总支出、今日支出增加。"""
jine = Decimal(str(amount))
with transaction.atomic():
szjilu = _get_szjilu_for_update(club_id)
szjilu.TotalIncome -= jine
szjilu.TotalExpense += jine
szjilu.DailyExpense += jine
szjilu.save()
def get_szjilu_snapshot(club_id=None):
"""读取某俱乐部收支汇总;无记录时返回零值。"""
cid = normalize_szjilu_club_id(club_id)
row = Szjilu.query.filter(club_id=cid).first()
if not row:
return {
'zongliushui': 0.0,
'zongshouyi': 0.0,
'zongzhichu': 0.0,
'jrls': 0.0,
'jrzc': 0.0,
}
return {
'zongliushui': float(row.TotalFlow or _ZERO),
'zongshouyi': float(row.TotalIncome or _ZERO),
'zongzhichu': float(row.TotalExpense or _ZERO),
'jrls': float(row.DailyFlow or _ZERO),
'jrzc': float(row.DailyExpense or _ZERO),
}
def reset_all_daily_szjilu():
"""每日清零:所有俱乐部的今日流水/今日支出。"""
updated = 0
with transaction.atomic():
for szjilu in Szjilu.objects.select_for_update().all():
szjilu.DailyExpense = _ZERO
szjilu.DailyFlow = _ZERO
szjilu.save(update_fields=['DailyExpense', 'DailyFlow', 'UpdateTime'])
updated += 1
return updated