"""各俱乐部全局收支流水(szjilu)统一记账。""" import logging from decimal import Decimal from django.db import IntegrityError, transaction 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, } 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 record_wechat_income_once(amount, club_id=None, biz_ref=None): """ 微信入账:同一 biz_ref 只记一次 daily_income_stat + szjilu。 返回 True=本次新入账;False=已记过(重复回调/重复代码路径)。 """ ref = (biz_ref or '').strip() if not ref: raise ValueError('biz_ref 不能为空') cid = normalize_szjilu_club_id(club_id) jine = Decimal(str(amount)) from orders.utils import update_daily_income 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 try: update_daily_income(jine, cid) apply_szjilu_income(jine, cid) except Exception: PlatformIncomeLog.objects.filter(biz_ref=ref).delete() 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