From b54904a9f236bee8540d1bb1c706cda23fe853fa Mon Sep 17 00:00:00 2001 From: XingQue Date: Wed, 8 Jul 2026 14:26:16 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=B8=A5=E6=A0=BC=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E4=BD=93=E9=AA=8C=E4=BC=9A=E5=91=98=E4=B8=8D=E5=8F=AF=E6=8F=90?= =?UTF-8?q?=E7=8E=B0=EF=BC=8C=E6=8A=A2=E5=8D=95=E6=8C=89=E4=BC=9A=E5=91=98?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 展示层 clumber 与提现/抢单权限分离:佣金提现须正式会员并双重拦截体验期;抢单走 resolve_order_membership_ids + 总会员包含判断。 Co-authored-by: Cursor --- jituan/services/huiyuan_bundle.py | 5 ++- jituan/services/member_recharge.py | 62 ++++++++++++++++++++++++++---- orders/views/dashou.py | 15 ++++++-- users/tixian_shenhe_services.py | 29 +++++++++++--- users/views/tixian.py | 17 +++++--- 5 files changed, 106 insertions(+), 22 deletions(-) diff --git a/jituan/services/huiyuan_bundle.py b/jituan/services/huiyuan_bundle.py index e57fa9c..3c6d992 100644 --- a/jituan/services/huiyuan_bundle.py +++ b/jituan/services/huiyuan_bundle.py @@ -317,7 +317,10 @@ def _build_clumber_from_paid_czjilu(yonghu_id): def ensure_grab_pool_clumber(yonghu_id): - """抢单池:同步权益 + huiyuangoumai + 已付充值单兜底,体验会员按正式返回。""" + """ + 【仅抢单池展示】同步权益并构造 clumber,供老小程序识别会员。 + 不得用于提现/收款等权限校验;提现须走 check_dashou_has_formal_huiyuan_for_withdraw。 + """ from jituan.services.member_recharge import sync_member_entitlements_for_user sync_member_entitlements_for_user(yonghu_id) diff --git a/jituan/services/member_recharge.py b/jituan/services/member_recharge.py index f493a4b..d30a29b 100644 --- a/jituan/services/member_recharge.py +++ b/jituan/services/member_recharge.py @@ -900,14 +900,62 @@ def confirm_member_recharge_paid(dingdan_id, yonghuid): def dashou_in_active_trial_period(yonghuid): - """打手是否处于未过期的体验会员期(限制佣金提现)。""" + """打手是否处于未过期的体验会员期(禁止佣金提现;与抢单池展示逻辑无关)。""" + from jituan.services.huiyuan_bundle import huiyuan_ids_match + now = timezone.now() - return Huiyuangoumai.query.filter( - yonghu_id=yonghuid, - is_trial=True, - huiyuan_zhuangtai=1, - daoqi_time__gt=now, - ).exists() + for rec in Huiyuangoumai.query.filter(yonghu_id=yonghuid): + if rec.jiance_shifou_daoqi(): + continue + if rec.huiyuan_zhuangtai != 1: + continue + if rec.is_trial: + return True + + for order in Czjilu.query.filter( + yonghuid=yonghuid, + leixing=MEMBER_LEIXING, + zhuangtai=MEMBER_PAID_STATUS, + ).order_by('-CreateTime')[:30]: + cid = getattr(order, 'club_id', None) or CLUB_ID_DEFAULT + if not _order_is_trial_like(order, cid): + continue + hid = order.huiyuan_id + if not hid: + continue + has_formal = False + for rec in Huiyuangoumai.query.filter(yonghu_id=yonghuid): + if rec.is_trial: + continue + if ( + huiyuan_ids_match(rec.huiyuan_id, hid) + and not rec.jiance_shifou_daoqi() + and rec.huiyuan_zhuangtai == 1 + ): + has_formal = True + break + if has_formal: + continue + days = int(getattr(order, 'purchase_days', None) or 0) + if days <= 0: + _, _, days = club_huiyuan_sellable(cid, hid, is_trial=True) + days = max(days, 1) + start = order.CreateTime or now + if timezone.is_naive(start): + start = timezone.make_aware(start, timezone.get_current_timezone()) + if start + timedelta(days=days) > now: + return True + return False + + +def dashou_has_active_formal_huiyuan(yonghuid): + """打手是否持有未过期的正式会员(非体验)。""" + for rec in Huiyuangoumai.query.filter(yonghu_id=yonghuid): + if rec.is_trial: + continue + if not rec.jiance_shifou_daoqi() and rec.huiyuan_zhuangtai == 1: + return True + return False def extend_member_entitlement_admin(yonghuid, huiyuan_id, days, club_id=None, operator_note=''): diff --git a/orders/views/dashou.py b/orders/views/dashou.py index 7c642ff..390db24 100644 --- a/orders/views/dashou.py +++ b/orders/views/dashou.py @@ -540,7 +540,10 @@ class QiangdanView(APIView): return {'success': True, 'message': '验证通过'} def _validate_huiyuan_requirement(self, order, dashou_yonghuid): - from jituan.services.huiyuan_bundle import user_has_huiyuan_access + from jituan.services.huiyuan_bundle import ( + user_has_huiyuan_access_any, + resolve_order_membership_ids, + ) from jituan.services.club_context import resolve_effective_club_id club_id = None @@ -548,9 +551,15 @@ class QiangdanView(APIView): club_id = resolve_effective_club_id(self.request, self.request.user) except Exception: pass - if user_has_huiyuan_access(dashou_yonghuid, order.MembershipID, club_id=club_id): + order_dict = { + 'MembershipID': order.MembershipID, + 'GrabRequirement': order.GrabRequirement, + 'ProductTypeID': order.ProductTypeID, + } + required_ids = resolve_order_membership_ids(order_dict) + if user_has_huiyuan_access_any(dashou_yonghuid, required_ids, club_id=club_id): return {'success': True, 'message': '会员验证通过'} - return {'success': False, 'message': '未开通对应会员,无法抢此订单'} + return {'success': False, 'message': '未开通对应会员或会员已过期,无法抢此订单'} def _validate_yajin_requirement(self, order, dashou_profile): yajin_required = order.CommissionReq or 0 diff --git a/users/tixian_shenhe_services.py b/users/tixian_shenhe_services.py index 575ad2e..e55cb80 100644 --- a/users/tixian_shenhe_services.py +++ b/users/tixian_shenhe_services.py @@ -178,13 +178,13 @@ def calc_fee_amounts(jine, feilv): def check_dashou_has_valid_huiyuan(yonghuid): """ - 打手至少持有一个未过期会员(Huiyuangoumai + jiance_shifou_daoqi 同步状态) + 打手至少持有一个未过期会员(含体验,用于接单等场景) 返回 (True, '') 或 (False, 原因) """ records = Huiyuangoumai.query.filter(yonghu_id=yonghuid) if not records.exists(): - return False, '您暂无会员记录,无法提现' + return False, '您暂无会员记录,无法操作' for record in records: is_expired = record.jiance_shifou_daoqi() @@ -193,8 +193,27 @@ def check_dashou_has_valid_huiyuan(yonghuid): return False, '您的会员已全部过期,请先续费后再操作' +def check_dashou_has_formal_huiyuan_for_withdraw(yonghuid): + """ + 打手佣金提现/收款:必须持有未过期的正式会员。 + 体验会员期内一律拒绝;体验到期后须购买正式会员。 + """ + from jituan.services.member_recharge import ( + dashou_has_active_formal_huiyuan, + dashou_in_active_trial_period, + ) + + if dashou_has_active_formal_huiyuan(yonghuid): + return True, '' + if dashou_in_active_trial_period(yonghuid): + return False, '体验会员不可提现佣金,请购买正式会员' + if not Huiyuangoumai.query.filter(yonghu_id=yonghuid).exists(): + return False, '您暂无会员记录,无法提现' + return False, '您的会员已全部过期,请购买正式会员后提现' + + TRIAL_COMMISSION_WITHDRAW_MSG = ( - '体验会员期间不可提现佣金,请升级正式会员或待体验到期' + '体验会员不可提现佣金,请购买正式会员' ) @@ -228,7 +247,7 @@ def validate_withdraw_eligibility(user_main, leixing, jine): return False, '有订单进行中,请完成后提现', {} if dashou.jifen != 10: return False, '积分不足10分,请补充积分后提现', {} - huiyuan_ok, huiyuan_msg = check_dashou_has_valid_huiyuan(yonghuid) + 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) @@ -357,7 +376,7 @@ def validate_collect_eligibility(user_main, leixing): return False, '您有订单进行中,请完成后再收款' if dashou.jifen != 10: return False, '积分不足10分,无法收款' - huiyuan_ok, huiyuan_msg = check_dashou_has_valid_huiyuan(yonghuid) + 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) diff --git a/users/views/tixian.py b/users/views/tixian.py index 757a237..7d42ad4 100644 --- a/users/views/tixian.py +++ b/users/views/tixian.py @@ -71,6 +71,7 @@ from ..tixian_shenhe_services import ( mark_transfer_success, release_collect_quota_for_record, close_audit_wechat_failed, query_wechat_transfer_bill, check_shijidaozhang_within_limit, + check_dashou_has_formal_huiyuan_for_withdraw, check_dashou_trial_blocks_commission_withdraw, WX_STATE_FAIL, WX_STATE_SUCCESS, WX_STATE_WAIT, WX_STATE_CANCELING, ) @@ -295,12 +296,12 @@ class ShoukuanXinxiShangchuanView(APIView): return None -# ========== 订单状态常量(请根据您的实际业务修改)========== -# 假设状态值:已完成=9,已退款=10(示例,实际以您的项目为准) -ORDER_STATUS_COMPLETED = 3 # 订单已完成 -ORDER_STATUS_REFUNDED = 5 # 订单已退款 -ORDER_STATUS_FAIL = 6 -# 进行中状态(不可提现)例如:待接单、已接单、进行中等,您需要定义排除列表 +# ========== 订单状态常量(请根据您的实际业务修改)========== +# 假设状态值:已完成=9,已退款=10(示例,实际以您的项目为准) +ORDER_STATUS_COMPLETED = 3 # 订单已完成 +ORDER_STATUS_REFUNDED = 5 # 订单已退款 +ORDER_STATUS_FAIL = 6 +# 进行中状态(不可提现)例如:待接单、已接单、进行中等,您需要定义排除列表 FORBIDDEN_STATUS_FOR_WITHDRAW = [1, 2, 3, 4, 5, 6, 7, 8] # 除已完成和已退款外的所有状态 @@ -533,6 +534,10 @@ class TixianShenqingView(APIView): 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} + trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(user_main.UserUID) if not trial_ok: return {'code': 16, 'msg': trial_msg}