feat: 会员体验版、俱乐部分离上架与分红计数加固
扩展 club_huiyuan_price/huiyuangoumai/czjilu/gsfenhong 字段;微信购会员强制写 czjilu+收支入账;formal_cishu 仅统计正式已支付单;关闭余额购会员;俱乐部上架/下架 API。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
38
products/migrations/0006_member_trial_fields.py
Normal file
38
products/migrations/0006_member_trial_fields.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('products', '0005_duoci_fenhong_club_id'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='huiyuangoumai',
|
||||
name='is_trial',
|
||||
field=models.BooleanField(default=False, verbose_name='当前是否为体验权益'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='huiyuangoumai',
|
||||
name='has_used_trial',
|
||||
field=models.BooleanField(default=False, verbose_name='是否已购买过体验版'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='czjilu',
|
||||
name='is_trial',
|
||||
field=models.BooleanField(default=False, verbose_name='是否体验会员单'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='czjilu',
|
||||
name='purchase_days',
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True, null=True, verbose_name='下单锁定有效天数',
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='gsfenhong',
|
||||
name='is_trial',
|
||||
field=models.BooleanField(default=False, verbose_name='是否体验会员分红'),
|
||||
),
|
||||
]
|
||||
@@ -172,6 +172,8 @@ class Huiyuangoumai(QModel):
|
||||
club_id = models.CharField(
|
||||
max_length=16, default='xq', db_index=True, verbose_name='所属俱乐部',
|
||||
)
|
||||
is_trial = models.BooleanField(default=False, verbose_name='当前是否为体验权益')
|
||||
has_used_trial = models.BooleanField(default=False, verbose_name='是否已购买过体验版')
|
||||
|
||||
class Meta:
|
||||
db_table = 'huiyuangoumai'
|
||||
@@ -218,6 +220,10 @@ class Czjilu(QModel):
|
||||
club_id = models.CharField(
|
||||
max_length=16, default='xq', db_index=True, verbose_name='所属俱乐部',
|
||||
)
|
||||
is_trial = models.BooleanField(default=False, verbose_name='是否体验会员单')
|
||||
purchase_days = models.PositiveIntegerField(
|
||||
null=True, blank=True, verbose_name='下单锁定有效天数',
|
||||
)
|
||||
CreateTime = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
UpdateTime = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
class Meta:
|
||||
@@ -258,6 +264,7 @@ class Gsfenhong(QModel):
|
||||
club_id = models.CharField(
|
||||
max_length=16, default='xq', db_index=True, verbose_name='所属俱乐部',
|
||||
)
|
||||
is_trial = models.BooleanField(default=False, verbose_name='是否体验会员分红')
|
||||
|
||||
class Meta:
|
||||
db_table = 'gsfenhong'
|
||||
|
||||
@@ -267,7 +267,7 @@ class DashouHuiyuanList(APIView):
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 3. 仅返回本俱乐部可售会员(club_huiyuan_price 已配置且启用)
|
||||
from jituan.services.member_recharge import club_huiyuan_sellable
|
||||
from jituan.services.member_recharge import club_huiyuan_sellable, can_purchase_trial
|
||||
|
||||
club_id = resolve_effective_club_id(request, request.user)
|
||||
huiyuan_queryset = Huiyuan.query.all().only(
|
||||
@@ -275,15 +275,27 @@ class DashouHuiyuanList(APIView):
|
||||
).order_by('jiage')
|
||||
|
||||
huiyuan_list = []
|
||||
yonghuid = request.user.UserUID
|
||||
for huiyuan in huiyuan_queryset:
|
||||
sellable, club_price = club_huiyuan_sellable(club_id, huiyuan.huiyuan_id)
|
||||
sellable, club_price, formal_days = club_huiyuan_sellable(
|
||||
club_id, huiyuan.huiyuan_id, is_trial=False,
|
||||
)
|
||||
if not sellable or not club_price:
|
||||
continue
|
||||
trial_ok, _ = can_purchase_trial(yonghuid, huiyuan.huiyuan_id, club_id)
|
||||
trial_sellable, trial_price, trial_days = club_huiyuan_sellable(
|
||||
club_id, huiyuan.huiyuan_id, is_trial=True,
|
||||
)
|
||||
huiyuan_list.append({
|
||||
'id': huiyuan.huiyuan_id,
|
||||
'mingzi': huiyuan.jieshao,
|
||||
'jiage': float(club_price),
|
||||
'formal_days': formal_days,
|
||||
'jieshao': huiyuan.jtjieshao,
|
||||
'trial_enabled': bool(trial_sellable),
|
||||
'trial_price': float(trial_price) if trial_sellable else 0,
|
||||
'trial_days': trial_days if trial_sellable else 0,
|
||||
'can_buy_trial': bool(trial_ok and trial_sellable),
|
||||
})
|
||||
|
||||
# 5. 返回数据
|
||||
@@ -1381,6 +1393,7 @@ class HuiyuanGoumai(APIView):
|
||||
try:
|
||||
# 1. 获取会员ID参数
|
||||
huiyuanid = request.data.get('huiyuanid')
|
||||
is_trial = bool(request.data.get('is_trial') or request.data.get('isTrial'))
|
||||
if not huiyuanid:
|
||||
return Response({
|
||||
'code': 400,
|
||||
@@ -1413,12 +1426,15 @@ class HuiyuanGoumai(APIView):
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
club_id = resolve_effective_club_id(request, request.user)
|
||||
from jituan.services.member_recharge import club_huiyuan_sellable
|
||||
sellable, club_price = club_huiyuan_sellable(club_id, huiyuanid)
|
||||
if not sellable:
|
||||
from jituan.services.member_recharge import validate_member_purchase
|
||||
|
||||
ok, err_msg, club_price, purchase_days = validate_member_purchase(
|
||||
request.user.UserUID, huiyuanid, club_id, is_trial,
|
||||
)
|
||||
if not ok:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '该俱乐部未配置此会员价格,请联系管理员'
|
||||
'message': err_msg or '不可购买',
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 5. 生成订单ID(前缀CzHY表示会员充值)
|
||||
@@ -1442,11 +1458,14 @@ class HuiyuanGoumai(APIView):
|
||||
shuoming=shuoming,
|
||||
huiyuan_id=huiyuanid, # 存储会员ID
|
||||
club_id=club_id,
|
||||
is_trial=is_trial,
|
||||
purchase_days=int(purchase_days),
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"创建会员充值订单: 用户{request.user.UserUID}, 订单{dingdanid}, "
|
||||
f"会员{huiyuanid}, 俱乐部{club_id}, 金额{jine}元")
|
||||
f"会员{huiyuanid}, 俱乐部{club_id}, 体验={is_trial}, "
|
||||
f"金额{jine}元, 天数{purchase_days}")
|
||||
|
||||
# 7. 生成微信支付参数
|
||||
try:
|
||||
@@ -1477,6 +1496,8 @@ class HuiyuanGoumai(APIView):
|
||||
'dingdanid': dingdanid,
|
||||
'club_id': club_id,
|
||||
'jine': jine,
|
||||
'is_trial': is_trial,
|
||||
'purchase_days': purchase_days,
|
||||
}, status=status.HTTP_200_OK)
|
||||
|
||||
except Exception as e:
|
||||
@@ -5862,8 +5883,11 @@ class DsqrgmdhView(APIView):
|
||||
if shenfen_id not in [1, 2, 3, 4]:
|
||||
return Response({'code': 400, 'msg': 'shenfen_id 必须为 1/2/3/4'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if leixing == 1 and not huiyuan_id:
|
||||
return Response({'code': 400, 'msg': '购买会员时必须提供 huiyuan_id'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
if leixing == 1:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'msg': '会员购买仅支持微信支付,请使用会员充值页面',
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
if leixing == 2:
|
||||
if not yajin_jine:
|
||||
return Response({'code': 400, 'msg': '购买押金时必须提供 yajin_jine'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
Reference in New Issue
Block a user