From 080c55bf2ad37143a13c8461fe9d8dd9a84df9f5 Mon Sep 17 00:00:00 2001 From: XingQue Date: Tue, 4 Aug 2026 12:47:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=B1=E4=B9=90=E9=83=A8=E7=BB=84?= =?UTF-8?q?=E9=98=9F=E5=BC=80=E5=85=B3=E4=B8=8E=E6=8F=90=E7=8E=B0=E4=BC=9A?= =?UTF-8?q?=E5=91=98/=E7=A7=AF=E5=88=86=E9=97=A8=E6=A7=9B=E5=88=86?= =?UTF-8?q?=E5=BA=97=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jituan/services/team_recruit_switch.py | 55 +++++++++++++ .../services/withdraw_eligibility_switch.py | 75 +++++++++++++++++ jituan/views.py | 38 +++++++++ orders/services/team_recruit.py | 4 + orders/views/zudui.py | 14 ++++ users/tixian_shenhe_services.py | 80 +++++++++++++------ users/views/tixian.py | 26 +++--- 7 files changed, 257 insertions(+), 35 deletions(-) create mode 100644 jituan/services/team_recruit_switch.py create mode 100644 jituan/services/withdraw_eligibility_switch.py diff --git a/jituan/services/team_recruit_switch.py b/jituan/services/team_recruit_switch.py new file mode 100644 index 0000000..aa6c2ab --- /dev/null +++ b/jituan/services/team_recruit_switch.py @@ -0,0 +1,55 @@ +"""俱乐部:是否允许打手组队(config_json)。 + +默认关闭:未配置或显式关闭时,打手不可开启/加入组队。 +""" +import logging + +logger = logging.getLogger(__name__) + +CONFIG_KEY = 'dashou_team_recruit_enabled' + + +def _club(club_id: str): + cid = (club_id or '').strip() + if not cid: + return None + from jituan.models import Club + club = Club.query.filter(club_id=cid).first() + if not club and cid != cid.lower(): + club = Club.query.filter(club_id=cid.lower()).first() + return club + + +def _as_bool(raw, default=False) -> bool: + if raw is None: + return default + if isinstance(raw, str): + return raw.strip().lower() in ('1', 'true', 'yes', 'on') + return bool(raw) + + +def is_dashou_team_recruit_enabled(club_id: str) -> bool: + """开启=允许本俱乐部打手组队;关闭(默认)=不可开队/入队。""" + club = _club(club_id) + if not club: + return False + try: + cfg = club.config_json or {} + if CONFIG_KEY not in cfg: + return False + return _as_bool(cfg.get(CONFIG_KEY), False) + except Exception: + logger.exception('read dashou_team_recruit_enabled failed club=%s', club_id) + return False + + +def set_dashou_team_recruit_enabled(club, enabled: bool) -> None: + cfg = dict(getattr(club, 'config_json', None) or {}) + cfg[CONFIG_KEY] = bool(enabled) + club.config_json = cfg + + +def ensure_dashou_team_recruit_enabled(club_id: str) -> None: + """未开启则抛 ValueError,供组队服务统一拦截。""" + if not is_dashou_team_recruit_enabled(club_id): + raise ValueError('本俱乐部未开放组队功能') diff --git a/jituan/services/withdraw_eligibility_switch.py b/jituan/services/withdraw_eligibility_switch.py new file mode 100644 index 0000000..1ee4576 --- /dev/null +++ b/jituan/services/withdraw_eligibility_switch.py @@ -0,0 +1,75 @@ +"""俱乐部:打手提现/收款是否校验正式会员与积分(config_json)。 + +默认开启(与现网硬门槛一致): +- 须持有有效正式/赠送会员(体验会员不可提佣金) +- 积分须 ≥ 10 + +关闭后:对应校验整段跳过,不再看会员/积分。 +仅影响打手佣金提现(leixing=1)与押金提取(leixing=5)的申请与自动收款校验。 +""" +import logging + +logger = logging.getLogger(__name__) + +REQUIRE_HUIYUAN_KEY = 'withdraw_require_formal_huiyuan' +REQUIRE_JIFEN_KEY = 'withdraw_require_jifen' +JIFEN_MIN = 10 + + +def _club(club_id: str): + cid = (club_id or '').strip() + if not cid: + return None + from jituan.models import Club + club = Club.query.filter(club_id=cid).first() + if not club and cid != cid.lower(): + club = Club.query.filter(club_id=cid.lower()).first() + return club + + +def _as_bool(raw, default: bool) -> bool: + if raw is None: + return default + if isinstance(raw, str): + s = raw.strip().lower() + if s in ('1', 'true', 'yes', 'on'): + return True + if s in ('0', 'false', 'no', 'off'): + return False + return default + return bool(raw) + + +def _read_bool_default_true(club_id: str, key: str) -> bool: + """缺省/读失败均按 True,避免误关导致免校验放钱。""" + club = _club(club_id) + if not club: + return True + try: + cfg = club.config_json or {} + if key not in cfg: + return True + return _as_bool(cfg.get(key), True) + except Exception: + logger.exception('read %s failed club=%s', key, club_id) + return True + + +def is_withdraw_require_formal_huiyuan(club_id: str) -> bool: + return _read_bool_default_true(club_id, REQUIRE_HUIYUAN_KEY) + + +def is_withdraw_require_jifen(club_id: str) -> bool: + return _read_bool_default_true(club_id, REQUIRE_JIFEN_KEY) + + +def set_withdraw_require_formal_huiyuan(club, enabled: bool) -> None: + cfg = dict(getattr(club, 'config_json', None) or {}) + cfg[REQUIRE_HUIYUAN_KEY] = bool(enabled) + club.config_json = cfg + + +def set_withdraw_require_jifen(club, enabled: bool) -> None: + cfg = dict(getattr(club, 'config_json', None) or {}) + cfg[REQUIRE_JIFEN_KEY] = bool(enabled) + club.config_json = cfg diff --git a/jituan/views.py b/jituan/views.py index f281de4..929a1d0 100644 --- a/jituan/views.py +++ b/jituan/views.py @@ -638,6 +638,11 @@ class ClubManageView(APIView): is_dashou_chat_allow_without_member, ) from jituan.services.yajin_jifen_switch import is_yajin_purchase_fill_jifen + from jituan.services.team_recruit_switch import is_dashou_team_recruit_enabled + from jituan.services.withdraw_eligibility_switch import ( + is_withdraw_require_formal_huiyuan, + is_withdraw_require_jifen, + ) cfg_json = club.config_json or {} base = { @@ -659,6 +664,9 @@ class ClubManageView(APIView): 'dashou_chat_allow_without_member': is_dashou_chat_allow_without_member(club.club_id), 'dashou_chat_yajin_threshold': float(get_dashou_chat_yajin_threshold(club.club_id)), 'yajin_purchase_fill_jifen': is_yajin_purchase_fill_jifen(club.club_id), + 'dashou_team_recruit_enabled': is_dashou_team_recruit_enabled(club.club_id), + 'withdraw_require_formal_huiyuan': is_withdraw_require_formal_huiyuan(club.club_id), + 'withdraw_require_jifen': is_withdraw_require_jifen(club.club_id), } if full: mch_key = self._effective_mch_key(club) @@ -769,6 +777,36 @@ class ClubManageView(APIView): set_yajin_purchase_fill_jifen(club, enabled) if 'config_json' not in update_fields: update_fields.append('config_json') + if 'dashou_team_recruit_enabled' in request.data: + from jituan.services.team_recruit_switch import set_dashou_team_recruit_enabled + raw = request.data.get('dashou_team_recruit_enabled') + if isinstance(raw, str): + enabled = raw.strip().lower() in ('1', 'true', 'yes', 'on') + else: + enabled = bool(raw) + set_dashou_team_recruit_enabled(club, enabled) + if 'config_json' not in update_fields: + update_fields.append('config_json') + if 'withdraw_require_formal_huiyuan' in request.data: + from jituan.services.withdraw_eligibility_switch import set_withdraw_require_formal_huiyuan + raw = request.data.get('withdraw_require_formal_huiyuan') + if isinstance(raw, str): + enabled = raw.strip().lower() in ('1', 'true', 'yes', 'on') + else: + enabled = bool(raw) + set_withdraw_require_formal_huiyuan(club, enabled) + if 'config_json' not in update_fields: + update_fields.append('config_json') + if 'withdraw_require_jifen' in request.data: + from jituan.services.withdraw_eligibility_switch import set_withdraw_require_jifen + raw = request.data.get('withdraw_require_jifen') + if isinstance(raw, str): + enabled = raw.strip().lower() in ('1', 'true', 'yes', 'on') + else: + enabled = bool(raw) + set_withdraw_require_jifen(club, enabled) + if 'config_json' not in update_fields: + update_fields.append('config_json') if update_fields: club.save(update_fields=update_fields) return Response({ diff --git a/orders/services/team_recruit.py b/orders/services/team_recruit.py index 93ff006..cd62262 100644 --- a/orders/services/team_recruit.py +++ b/orders/services/team_recruit.py @@ -287,9 +287,11 @@ def open_recruit( max_fine_rate=None, ): from orders.models import TeamRecruit, TeamMember + from jituan.services.team_recruit_switch import ensure_dashou_team_recruit_enabled oid = order.OrderID club_id = (getattr(order, 'ClubID', None) or '').strip() or 'xq' + ensure_dashou_team_recruit_enabled(club_id) if int(order.Status or 0) != 2: raise ValueError('仅进行中订单可开启组队') if (order.PlayerID or '') != leader_uid: @@ -474,6 +476,7 @@ def join_recruit(*, recruit_id: int, user_uid: str, game_id: str, request=None, from orders.models import TeamRecruit, TeamMember, Order from users.models import UserDashou from utils.fadan_utils import check_fadan_qiangdan_eligible + from jituan.services.team_recruit_switch import ensure_dashou_team_recruit_enabled game_id = (game_id or '').strip() if not game_id: @@ -485,6 +488,7 @@ def join_recruit(*, recruit_id: int, user_uid: str, game_id: str, request=None, # 组队强制本俱乐部:不认跨店互通抢单 if require_club_id and (rec.club_id or '') != require_club_id: raise ValueError('仅本俱乐部可加入组队') + ensure_dashou_team_recruit_enabled(rec.club_id or require_club_id or '') if rec.status != TeamRecruit.STATUS_RECRUITING: raise ValueError('招募已结束') if int(rec.joined_count or 0) >= int(rec.need_count or 0): diff --git a/orders/views/zudui.py b/orders/views/zudui.py index 9cfe897..f550635 100644 --- a/orders/views/zudui.py +++ b/orders/views/zudui.py @@ -166,6 +166,19 @@ class ZuduiDatingView(APIView): club, err = _require_club(request) if err: return err + from jituan.services.team_recruit_switch import is_dashou_team_recruit_enabled + if not is_dashou_team_recruit_enabled(club): + return Response({ + 'code': 0, + 'msg': '本俱乐部未开放组队功能', + 'data': { + 'list': [], + 'total': 0, + 'page': 1, + 'page_size': 10, + 'team_recruit_enabled': False, + }, + }) page = max(1, int(request.data.get('page') or 1)) page_size = min(50, max(1, int(request.data.get('page_size') or 10))) leixing = request.data.get('leixing_id') @@ -222,6 +235,7 @@ class ZuduiDatingView(APIView): 'page': page, 'page_size': page_size, 'has_more': start + len(rows) < total, + 'team_recruit_enabled': True, **badge, }, }) diff --git a/users/tixian_shenhe_services.py b/users/tixian_shenhe_services.py index 54be461..ae377e8 100644 --- a/users/tixian_shenhe_services.py +++ b/users/tixian_shenhe_services.py @@ -356,14 +356,21 @@ def validate_withdraw_eligibility(user_main, leixing, jine): return False, '您不是打手身份,无法提现佣金', {} if dashou.zhanghaozhuangtai != 1: return False, '打手账号已被封禁,无法提现', {} - if dashou.jifen < 10: - return False, '积分不足10分,请补充积分后提现', {} - huiyuan_ok, huiyuan_msg = check_dashou_has_formal_huiyuan_for_withdraw(yonghuid) - if not huiyuan_ok: - return False, huiyuan_msg, {} - trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(yonghuid) - if not trial_ok: - return False, trial_msg, {} + from jituan.services.withdraw_eligibility_switch import ( + is_withdraw_require_formal_huiyuan, + is_withdraw_require_jifen, + JIFEN_MIN, + ) + club_id = club_id_for_tixian_yonghuid(yonghuid) + if is_withdraw_require_jifen(club_id) and dashou.jifen < JIFEN_MIN: + return False, f'积分不足{JIFEN_MIN}分,请补充积分后提现', {} + if is_withdraw_require_formal_huiyuan(club_id): + huiyuan_ok, huiyuan_msg = check_dashou_has_formal_huiyuan_for_withdraw(yonghuid) + if not huiyuan_ok: + return False, huiyuan_msg, {} + trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(yonghuid) + if not trial_ok: + return False, trial_msg, {} if _dashou_has_orders_blocking_withdraw_apply(yonghuid): return False, '您还有未完成或未退款的订单,请先处理完毕再提现', {} if _dashou_has_open_penalties(yonghuid): @@ -412,11 +419,18 @@ def validate_withdraw_eligibility(user_main, leixing, jine): return False, '您不是打手身份,无法提取押金', {} if dashou.zhanghaozhuangtai != 1: return False, '打手账号已禁用,无法提取押金', {} - if dashou.jifen < 10: - return False, '积分不足10分,请补充积分后提取押金', {} - huiyuan_ok, huiyuan_msg = check_dashou_has_formal_huiyuan_for_withdraw(yonghuid) - if not huiyuan_ok: - return False, huiyuan_msg, {} + from jituan.services.withdraw_eligibility_switch import ( + is_withdraw_require_formal_huiyuan, + is_withdraw_require_jifen, + JIFEN_MIN, + ) + club_id = club_id_for_tixian_yonghuid(yonghuid) + if is_withdraw_require_jifen(club_id) and dashou.jifen < JIFEN_MIN: + return False, f'积分不足{JIFEN_MIN}分,请补充积分后提取押金', {} + if is_withdraw_require_formal_huiyuan(club_id): + huiyuan_ok, huiyuan_msg = check_dashou_has_formal_huiyuan_for_withdraw(yonghuid) + if not huiyuan_ok: + return False, huiyuan_msg, {} if dashou.yajin < jine: return False, f'押金余额不足,当前押金: {dashou.yajin}', {} if _dashou_has_orders_blocking_withdraw_apply(yonghuid): @@ -488,14 +502,21 @@ def validate_collect_eligibility(user_main, leixing): return False, '打手账号已被封禁,无法收款' if dashou.zhuangtai != 1: return False, '您有订单进行中,请完成后再收款' - if dashou.jifen < 10: - return False, '积分不足10分,无法收款' - huiyuan_ok, huiyuan_msg = check_dashou_has_formal_huiyuan_for_withdraw(yonghuid) - if not huiyuan_ok: - return False, huiyuan_msg - trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(yonghuid) - if not trial_ok: - return False, trial_msg + from jituan.services.withdraw_eligibility_switch import ( + is_withdraw_require_formal_huiyuan, + is_withdraw_require_jifen, + JIFEN_MIN, + ) + club_id = club_id_for_tixian_yonghuid(yonghuid) + if is_withdraw_require_jifen(club_id) and dashou.jifen < JIFEN_MIN: + return False, f'积分不足{JIFEN_MIN}分,无法收款' + if is_withdraw_require_formal_huiyuan(club_id): + huiyuan_ok, huiyuan_msg = check_dashou_has_formal_huiyuan_for_withdraw(yonghuid) + if not huiyuan_ok: + return False, huiyuan_msg + trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(yonghuid) + if not trial_ok: + return False, trial_msg if _dashou_has_orders_blocking_withdraw_apply(yonghuid): return False, '您还有进行中的订单,请完成后再收款' if _dashou_has_open_penalties(yonghuid): @@ -511,11 +532,18 @@ def validate_collect_eligibility(user_main, leixing): return False, '打手账号已禁用,无法收款' if dashou.zhuangtai != 1: return False, '您有订单进行中,请完成后再收款' - if dashou.jifen < 10: - return False, '积分不足10分,无法收款' - huiyuan_ok, huiyuan_msg = check_dashou_has_formal_huiyuan_for_withdraw(yonghuid) - if not huiyuan_ok: - return False, huiyuan_msg + from jituan.services.withdraw_eligibility_switch import ( + is_withdraw_require_formal_huiyuan, + is_withdraw_require_jifen, + JIFEN_MIN, + ) + club_id = club_id_for_tixian_yonghuid(yonghuid) + if is_withdraw_require_jifen(club_id) and dashou.jifen < JIFEN_MIN: + return False, f'积分不足{JIFEN_MIN}分,无法收款' + if is_withdraw_require_formal_huiyuan(club_id): + huiyuan_ok, huiyuan_msg = check_dashou_has_formal_huiyuan_for_withdraw(yonghuid) + if not huiyuan_ok: + return False, huiyuan_msg if _dashou_has_orders_blocking_withdraw_apply(yonghuid): return False, '您还有进行中的订单,请完成后再收款' if _dashou_has_open_penalties(yonghuid): diff --git a/users/views/tixian.py b/users/views/tixian.py index fed5c9e..4cab5a8 100644 --- a/users/views/tixian.py +++ b/users/views/tixian.py @@ -515,7 +515,7 @@ class TixianShenqingView(APIView): # ==================== 校验函数 ==================== def _check_dashou_commission_withdraw(self, user_main, jine): - """打手佣金提现校验""" + """打手佣金提现校验(遗留辅助;主路径用 validate_withdraw_eligibility)""" try: dashou = UserDashou.query.get(user=user_main) except ObjectDoesNotExist: @@ -525,18 +525,26 @@ class TixianShenqingView(APIView): return {'code': 11, 'msg': '打手账号已被封禁,无法提现'} if dashou.zhuangtai != 1: return {'code': 12, 'msg': '您有订单进行中,请完成后提现'} - if dashou.jifen < 10: - return {'code': 15, 'msg': '积分不足10分,请补充积分后提现'} + from jituan.services.wechat_pay import club_id_for_tixian_yonghuid + from jituan.services.withdraw_eligibility_switch import ( + is_withdraw_require_formal_huiyuan, + is_withdraw_require_jifen, + JIFEN_MIN, + ) + club_id = club_id_for_tixian_yonghuid(user_main.UserUID) + if is_withdraw_require_jifen(club_id) and dashou.jifen < JIFEN_MIN: + return {'code': 15, 'msg': f'积分不足{JIFEN_MIN}分,请补充积分后提现'} if dashou.yue < jine: return {'code': 13, 'msg': f'余额不足,当前余额: {dashou.yue}'} - formal_ok, formal_msg = check_dashou_has_formal_huiyuan_for_withdraw(user_main.UserUID) - if not formal_ok: - return {'code': 14, 'msg': formal_msg} + if is_withdraw_require_formal_huiyuan(club_id): + formal_ok, formal_msg = check_dashou_has_formal_huiyuan_for_withdraw(user_main.UserUID) + if not formal_ok: + return {'code': 14, 'msg': formal_msg} - trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(user_main.UserUID) - if not trial_ok: - return {'code': 16, 'msg': trial_msg} + trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(user_main.UserUID) + if not trial_ok: + return {'code': 16, 'msg': trial_msg} return {'code': 0, 'msg': 'ok', 'data': {'nicheng': dashou.nicheng or ''}}