fix: 严格校验体验会员不可提现,抢单按会员类型匹配
展示层 clumber 与提现/抢单权限分离:佣金提现须正式会员并双重拦截体验期;抢单走 resolve_order_membership_ids + 总会员包含判断。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -317,7 +317,10 @@ def _build_clumber_from_paid_czjilu(yonghu_id):
|
|||||||
|
|
||||||
|
|
||||||
def ensure_grab_pool_clumber(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
|
from jituan.services.member_recharge import sync_member_entitlements_for_user
|
||||||
|
|
||||||
sync_member_entitlements_for_user(yonghu_id)
|
sync_member_entitlements_for_user(yonghu_id)
|
||||||
|
|||||||
@@ -900,14 +900,62 @@ def confirm_member_recharge_paid(dingdan_id, yonghuid):
|
|||||||
|
|
||||||
|
|
||||||
def dashou_in_active_trial_period(yonghuid):
|
def dashou_in_active_trial_period(yonghuid):
|
||||||
"""打手是否处于未过期的体验会员期(限制佣金提现)。"""
|
"""打手是否处于未过期的体验会员期(禁止佣金提现;与抢单池展示逻辑无关)。"""
|
||||||
|
from jituan.services.huiyuan_bundle import huiyuan_ids_match
|
||||||
|
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
return Huiyuangoumai.query.filter(
|
for rec in Huiyuangoumai.query.filter(yonghu_id=yonghuid):
|
||||||
yonghu_id=yonghuid,
|
if rec.jiance_shifou_daoqi():
|
||||||
is_trial=True,
|
continue
|
||||||
huiyuan_zhuangtai=1,
|
if rec.huiyuan_zhuangtai != 1:
|
||||||
daoqi_time__gt=now,
|
continue
|
||||||
).exists()
|
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=''):
|
def extend_member_entitlement_admin(yonghuid, huiyuan_id, days, club_id=None, operator_note=''):
|
||||||
|
|||||||
@@ -540,7 +540,10 @@ class QiangdanView(APIView):
|
|||||||
return {'success': True, 'message': '验证通过'}
|
return {'success': True, 'message': '验证通过'}
|
||||||
|
|
||||||
def _validate_huiyuan_requirement(self, order, dashou_yonghuid):
|
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
|
from jituan.services.club_context import resolve_effective_club_id
|
||||||
|
|
||||||
club_id = None
|
club_id = None
|
||||||
@@ -548,9 +551,15 @@ class QiangdanView(APIView):
|
|||||||
club_id = resolve_effective_club_id(self.request, self.request.user)
|
club_id = resolve_effective_club_id(self.request, self.request.user)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
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': True, 'message': '会员验证通过'}
|
||||||
return {'success': False, 'message': '未开通对应会员,无法抢此订单'}
|
return {'success': False, 'message': '未开通对应会员或会员已过期,无法抢此订单'}
|
||||||
|
|
||||||
def _validate_yajin_requirement(self, order, dashou_profile):
|
def _validate_yajin_requirement(self, order, dashou_profile):
|
||||||
yajin_required = order.CommissionReq or 0
|
yajin_required = order.CommissionReq or 0
|
||||||
|
|||||||
@@ -178,13 +178,13 @@ def calc_fee_amounts(jine, feilv):
|
|||||||
|
|
||||||
def check_dashou_has_valid_huiyuan(yonghuid):
|
def check_dashou_has_valid_huiyuan(yonghuid):
|
||||||
"""
|
"""
|
||||||
打手至少持有一个未过期会员(Huiyuangoumai + jiance_shifou_daoqi 同步状态)
|
打手至少持有一个未过期会员(含体验,用于接单等场景)
|
||||||
返回 (True, '') 或 (False, 原因)
|
返回 (True, '') 或 (False, 原因)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
records = Huiyuangoumai.query.filter(yonghu_id=yonghuid)
|
records = Huiyuangoumai.query.filter(yonghu_id=yonghuid)
|
||||||
if not records.exists():
|
if not records.exists():
|
||||||
return False, '您暂无会员记录,无法提现'
|
return False, '您暂无会员记录,无法操作'
|
||||||
|
|
||||||
for record in records:
|
for record in records:
|
||||||
is_expired = record.jiance_shifou_daoqi()
|
is_expired = record.jiance_shifou_daoqi()
|
||||||
@@ -193,8 +193,27 @@ def check_dashou_has_valid_huiyuan(yonghuid):
|
|||||||
return False, '您的会员已全部过期,请先续费后再操作'
|
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 = (
|
TRIAL_COMMISSION_WITHDRAW_MSG = (
|
||||||
'体验会员期间不可提现佣金,请升级正式会员或待体验到期'
|
'体验会员不可提现佣金,请购买正式会员'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -228,7 +247,7 @@ def validate_withdraw_eligibility(user_main, leixing, jine):
|
|||||||
return False, '有订单进行中,请完成后提现', {}
|
return False, '有订单进行中,请完成后提现', {}
|
||||||
if dashou.jifen != 10:
|
if dashou.jifen != 10:
|
||||||
return False, '积分不足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:
|
if not huiyuan_ok:
|
||||||
return False, huiyuan_msg, {}
|
return False, huiyuan_msg, {}
|
||||||
trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(yonghuid)
|
trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(yonghuid)
|
||||||
@@ -357,7 +376,7 @@ def validate_collect_eligibility(user_main, leixing):
|
|||||||
return False, '您有订单进行中,请完成后再收款'
|
return False, '您有订单进行中,请完成后再收款'
|
||||||
if dashou.jifen != 10:
|
if dashou.jifen != 10:
|
||||||
return False, '积分不足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:
|
if not huiyuan_ok:
|
||||||
return False, huiyuan_msg
|
return False, huiyuan_msg
|
||||||
trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(yonghuid)
|
trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(yonghuid)
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ from ..tixian_shenhe_services import (
|
|||||||
mark_transfer_success, release_collect_quota_for_record,
|
mark_transfer_success, release_collect_quota_for_record,
|
||||||
close_audit_wechat_failed, query_wechat_transfer_bill,
|
close_audit_wechat_failed, query_wechat_transfer_bill,
|
||||||
check_shijidaozhang_within_limit,
|
check_shijidaozhang_within_limit,
|
||||||
|
check_dashou_has_formal_huiyuan_for_withdraw,
|
||||||
check_dashou_trial_blocks_commission_withdraw,
|
check_dashou_trial_blocks_commission_withdraw,
|
||||||
WX_STATE_FAIL, WX_STATE_SUCCESS, WX_STATE_WAIT, WX_STATE_CANCELING,
|
WX_STATE_FAIL, WX_STATE_SUCCESS, WX_STATE_WAIT, WX_STATE_CANCELING,
|
||||||
)
|
)
|
||||||
@@ -295,12 +296,12 @@ class ShoukuanXinxiShangchuanView(APIView):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
# ========== 订单状态常量(请根据您的实际业务修改)==========
|
# ========== 订单状态常量(请根据您的实际业务修改)==========
|
||||||
# 假设状态值:已完成=9,已退款=10(示例,实际以您的项目为准)
|
# 假设状态值:已完成=9,已退款=10(示例,实际以您的项目为准)
|
||||||
ORDER_STATUS_COMPLETED = 3 # 订单已完成
|
ORDER_STATUS_COMPLETED = 3 # 订单已完成
|
||||||
ORDER_STATUS_REFUNDED = 5 # 订单已退款
|
ORDER_STATUS_REFUNDED = 5 # 订单已退款
|
||||||
ORDER_STATUS_FAIL = 6
|
ORDER_STATUS_FAIL = 6
|
||||||
# 进行中状态(不可提现)例如:待接单、已接单、进行中等,您需要定义排除列表
|
# 进行中状态(不可提现)例如:待接单、已接单、进行中等,您需要定义排除列表
|
||||||
FORBIDDEN_STATUS_FOR_WITHDRAW = [1, 2, 3, 4, 5, 6, 7, 8] # 除已完成和已退款外的所有状态
|
FORBIDDEN_STATUS_FOR_WITHDRAW = [1, 2, 3, 4, 5, 6, 7, 8] # 除已完成和已退款外的所有状态
|
||||||
|
|
||||||
|
|
||||||
@@ -533,6 +534,10 @@ class TixianShenqingView(APIView):
|
|||||||
if dashou.yue < jine:
|
if dashou.yue < jine:
|
||||||
return {'code': 13, 'msg': f'余额不足,当前余额: {dashou.yue}'}
|
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)
|
trial_ok, trial_msg = check_dashou_trial_blocks_commission_withdraw(user_main.UserUID)
|
||||||
if not trial_ok:
|
if not trial_ok:
|
||||||
return {'code': 16, 'msg': trial_msg}
|
return {'code': 16, 'msg': trial_msg}
|
||||||
|
|||||||
Reference in New Issue
Block a user