import logging from datetime import date from decimal import Decimal from django.db import transaction from django.db.models import F from config.models import DailyIncomeStat, DailyPayoutStat from orders.models import Order, PlatformOrderExt, MerchantOrderExt, CommissionRate from jituan.services.club_config import get_commission_rate from products.models import Gsfenhong from jituan.services.club_penalty import resolve_gsfenhong_club_id from users.models import UserDashou, UserGuanshi from backend.utils import update_guanshi_daily_by_action logger = logging.getLogger(__name__) def get_order_user_id(order): if order.Platform == 1: try: ext = PlatformOrderExt.objects.get(Order=order) return ext.BossID except PlatformOrderExt.DoesNotExist: return None elif order.Platform == 2: try: ext = MerchantOrderExt.objects.get(Order=order) return ext.MerchantID except MerchantOrderExt.DoesNotExist: return None return None def update_daily_income(amount, club_id=None): """ 原子更新当日收入统计(金额累加,笔数加1)。 用于微信支付成功回调。 """ from jituan.constants import CLUB_ID_DEFAULT cid = club_id or CLUB_ID_DEFAULT today = date.today() year, month, day = today.year, today.month, today.day with transaction.atomic(): stat, created = DailyIncomeStat.objects.select_for_update().get_or_create( date=today, club_id=cid, defaults={ 'year': year, 'month': month, 'day': day, 'total_amount': amount, 'total_count': 1, }, ) if not created: stat.total_amount = F('total_amount') + amount stat.total_count = F('total_count') + 1 stat.save(update_fields=['total_amount', 'total_count']) logger.info( f"每日收入更新[{cid}]: {today}, +{amount}元" ) def subtract_daily_income(amount, club_id=None, stat_date=None): """扣减指定日期的收入统计(repair 反向操作用)。""" from jituan.constants import CLUB_ID_DEFAULT cid = club_id or CLUB_ID_DEFAULT target = stat_date or date.today() with transaction.atomic(): stat = DailyIncomeStat.objects.select_for_update().filter( date=target, club_id=cid, ).first() if not stat: return jine = Decimal(str(amount)) zero = Decimal('0.00') new_amt = max(zero, Decimal(str(stat.total_amount or 0)) - jine) new_cnt = max(0, int(stat.total_count or 0) - 1) stat.total_amount = new_amt stat.total_count = new_cnt stat.save(update_fields=['total_amount', 'total_count']) logger.info(f"每日收入扣减[{cid}]: {target}, -{amount}元") def update_daily_payout(amount, club_id=None): """ 原子更新当日出款统计(金额累加,笔数加1)。 用于提现成功、结算打款等场景。 """ from jituan.constants import CLUB_ID_DEFAULT cid = club_id or CLUB_ID_DEFAULT today = date.today() year, month, day = today.year, today.month, today.day with transaction.atomic(): stat, created = DailyPayoutStat.objects.select_for_update().get_or_create( date=today, club_id=cid, defaults={ 'year': year, 'month': month, 'day': day, 'total_amount': amount, 'total_count': 1, }, ) if not created: stat.total_amount = F('total_amount') + amount stat.total_count = F('total_count') + 1 stat.save(update_fields=['total_amount', 'total_count']) logger.info(f"每日出款更新[{cid}]: {today}, +{amount}元") def calc_shangjia_order_fencheng(jine, club_id=None): """ 商家发单时计算打手/管事分成。 打手优先:打手+管事 > 订单金额时,管事分成为 0。 """ from jituan.constants import CLUB_ID_DEFAULT jine = Decimal(str(jine)) cid = club_id or CLUB_ID_DEFAULT rate_dashou = get_commission_rate(cid, '3') if not rate_dashou or rate_dashou <= 0: rate_dashou = Decimal('1') rate_guanshi = get_commission_rate(cid, '13') dashou_fencheng = (jine * rate_dashou).quantize(Decimal('0.01')) guanshi_raw = (jine * rate_guanshi).quantize(Decimal('0.01')) if dashou_fencheng + guanshi_raw > jine: guanshi_fencheng = Decimal('0.00') else: guanshi_fencheng = guanshi_raw return dashou_fencheng, guanshi_fencheng def settle_shangjia_order_guanshi_fenhong(order, dashou_id): """ 商家订单结单时结算管事分红(幂等,失败不抛异常阻断主流程)。 """ if getattr(order, 'Platform', None) != 2: return guanshi_fencheng = order.ManagerCommission or Decimal('0') if guanshi_fencheng <= 0: return if Gsfenhong.objects.filter(dingdan_id=order.OrderID).exists(): logger.info(f"商家订单管事分红已处理: {order.OrderID}") return if not dashou_id: return try: dashou = UserDashou.objects.select_related('user').get(user__UserUID=dashou_id) except UserDashou.DoesNotExist: logger.info(f"商家订单管事分红跳过: 打手{dashou_id}不存在") return guanshi_id = dashou.yaoqingren if not guanshi_id: logger.info(f"商家订单管事分红跳过: 打手{dashou_id}无邀请管事") return try: with transaction.atomic(): guanshi = UserGuanshi.objects.select_for_update().get(user__UserUID=guanshi_id) UserGuanshi.objects.filter(id=guanshi.id).update( yue=F('yue') + guanshi_fencheng, chongzhifenrun=F('chongzhifenrun') + guanshi_fencheng, ) user_main = dashou.user Gsfenhong.objects.create( dingdan_id=order.OrderID, guanshi=guanshi_id, dashouid=dashou_id, shuoming='商家订单分红', fenhong=guanshi_fencheng, avatar=user_main.Avatar if user_main else None, nicheng=dashou.nicheng or '未知打手', fenhong_leixing=3, club_id=resolve_gsfenhong_club_id(dingdan_id=order.OrderID, dashouid=dashou_id, order=order), ) logger.info( f"商家订单管事分红成功: 订单{order.OrderID}, 管事{guanshi_id}, " f"打手{dashou_id}, 金额{guanshi_fencheng}元" ) except UserGuanshi.DoesNotExist: logger.warning(f"商家订单管事分红跳过: 管事{guanshi_id}不存在") return except Exception as e: logger.error(f"商家订单管事分红失败: {e}", exc_info=True) return try: update_guanshi_daily_by_action( yonghuid=guanshi_id, action=3, amount=guanshi_fencheng, ) except Exception as e: logger.error(f"商家订单管事日统计更新失败: {e}")