fix: 商品基础数据容错避免500;类型专区按俱乐部上架并管专区
具体俱乐部只返回已上架类型;上架/下架允许 7007a 或 8080a。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -146,83 +146,104 @@ class GetProductBaseDataView(APIView):
|
||||
from jituan.services.club_context import filter_club_char_field, resolve_club_scope
|
||||
from jituan.constants import DATA_SCOPE_ALL
|
||||
from jituan.services.club_write import resolve_club_id_for_write
|
||||
from shop.services.shenhe_config import get_or_create_shenhe_config, is_zhi_kan_shenhe_enabled
|
||||
|
||||
type_qs = ShangpinLeixing.query.all().order_by('paixu')
|
||||
# 批量聚合商品数量,避免循环内 N+1 count(按俱乐部)
|
||||
_public_sp = filter_club_char_field(
|
||||
Shangpin.query.filter(
|
||||
dianpu__isnull=True, dianpu_leixing__isnull=True, leixing_id__isnull=False
|
||||
),
|
||||
request,
|
||||
field='club_id',
|
||||
)
|
||||
_type_counts = {
|
||||
item['leixing_id']: item['cnt']
|
||||
for item in _public_sp.values('leixing_id').annotate(cnt=Count('id'))
|
||||
}
|
||||
type_list = []
|
||||
for t in type_qs:
|
||||
product_count = _type_counts.get(t.id, 0)
|
||||
type_list.append({
|
||||
'id': t.id,
|
||||
'jieshao': t.jieshao or '',
|
||||
'tupian_url': t.tupian_url or '',
|
||||
'paixu': t.paixu,
|
||||
'shenhezhuangtai': t.shenhezhuangtai,
|
||||
'product_count': product_count,
|
||||
})
|
||||
|
||||
# 获取专区(按俱乐部隔离;集团汇总看全部)
|
||||
zone_qs = filter_club_char_field(
|
||||
ShangpinZhuanqu.query.all().order_by('paixu'), request, field='club_id'
|
||||
)
|
||||
_zone_counts = {
|
||||
item['zhuanqu_id']: item['cnt']
|
||||
for item in filter_club_char_field(
|
||||
try:
|
||||
type_qs = ShangpinLeixing.query.all().order_by('paixu')
|
||||
# 批量聚合商品数量,避免循环内 N+1 count(按俱乐部)
|
||||
_public_sp = filter_club_char_field(
|
||||
Shangpin.query.filter(
|
||||
dianpu__isnull=True, dianpu_leixing__isnull=True, zhuanqu_id__isnull=False
|
||||
dianpu__isnull=True, dianpu_leixing__isnull=True, leixing_id__isnull=False
|
||||
),
|
||||
request,
|
||||
field='club_id',
|
||||
).values('zhuanqu_id').annotate(cnt=Count('id'))
|
||||
}
|
||||
zone_list = []
|
||||
for z in zone_qs:
|
||||
product_count = _zone_counts.get(z.id, 0)
|
||||
zone_list.append({
|
||||
'id': z.id,
|
||||
'mingzi': z.mingzi or '',
|
||||
'leixing_id': z.leixing_id,
|
||||
'paixu': z.paixu,
|
||||
'shenhezhuangtai': z.shenhezhuangtai,
|
||||
'product_count': product_count,
|
||||
'club_id': getattr(z, 'club_id', '') or '',
|
||||
})
|
||||
|
||||
# 获取所有会员(只需 ID、介绍、价格)
|
||||
member_list = list(Huiyuan.query.all().values('huiyuan_id', 'jieshao', 'jiage'))
|
||||
|
||||
# 本俱乐部「只看审核」开关(集团汇总不下发可写状态)
|
||||
club_scoped = resolve_club_scope(request) != DATA_SCOPE_ALL
|
||||
zhi_kan_shenhe = True
|
||||
club_id = ''
|
||||
if club_scoped:
|
||||
club_id = resolve_club_id_for_write(request) or ''
|
||||
get_or_create_shenhe_config(club_id)
|
||||
zhi_kan_shenhe = is_zhi_kan_shenhe_enabled(club_id)
|
||||
|
||||
return Response({
|
||||
'code': 0,
|
||||
'data': {
|
||||
'type_list': type_list,
|
||||
'zone_list': zone_list,
|
||||
'member_list': member_list,
|
||||
'zhi_kan_shenhe': zhi_kan_shenhe,
|
||||
'club_scoped': club_scoped,
|
||||
'club_id': club_id,
|
||||
)
|
||||
# 用 Django QS 聚合,避免 Fluent values 链在部分环境下异常
|
||||
_type_counts = {
|
||||
item['leixing_id']: item['cnt']
|
||||
for item in _public_sp.values('leixing_id').annotate(cnt=Count('id'))
|
||||
}
|
||||
})
|
||||
type_list = []
|
||||
for t in type_qs:
|
||||
product_count = _type_counts.get(t.id, 0)
|
||||
type_list.append({
|
||||
'id': t.id,
|
||||
'jieshao': t.jieshao or '',
|
||||
'tupian_url': t.tupian_url or '',
|
||||
'paixu': t.paixu,
|
||||
'shenhezhuangtai': t.shenhezhuangtai,
|
||||
'product_count': product_count,
|
||||
})
|
||||
|
||||
# 获取专区(按俱乐部隔离;集团汇总看全部)
|
||||
zone_qs = filter_club_char_field(
|
||||
ShangpinZhuanqu.query.all().order_by('paixu'), request, field='club_id'
|
||||
)
|
||||
_zone_counts = {
|
||||
item['zhuanqu_id']: item['cnt']
|
||||
for item in filter_club_char_field(
|
||||
Shangpin.query.filter(
|
||||
dianpu__isnull=True, dianpu_leixing__isnull=True, zhuanqu_id__isnull=False
|
||||
),
|
||||
request,
|
||||
field='club_id',
|
||||
).values('zhuanqu_id').annotate(cnt=Count('id'))
|
||||
}
|
||||
zone_list = []
|
||||
for z in zone_qs:
|
||||
product_count = _zone_counts.get(z.id, 0)
|
||||
zone_list.append({
|
||||
'id': z.id,
|
||||
'mingzi': z.mingzi or '',
|
||||
'leixing_id': z.leixing_id,
|
||||
'paixu': z.paixu,
|
||||
'shenhezhuangtai': z.shenhezhuangtai,
|
||||
'product_count': product_count,
|
||||
'club_id': getattr(z, 'club_id', '') or '',
|
||||
})
|
||||
|
||||
# 获取所有会员(只需 ID、介绍、价格)
|
||||
member_list = []
|
||||
for m in Huiyuan.query.all().values('huiyuan_id', 'jieshao', 'jiage'):
|
||||
member_list.append({
|
||||
'huiyuan_id': m['huiyuan_id'],
|
||||
'jieshao': m['jieshao'] or '',
|
||||
'jiage': float(m['jiage'] or 0),
|
||||
})
|
||||
|
||||
# 本俱乐部「只看审核」开关(集团汇总不下发可写状态)
|
||||
club_scoped = resolve_club_scope(request) != DATA_SCOPE_ALL
|
||||
zhi_kan_shenhe = True
|
||||
club_id = ''
|
||||
if club_scoped:
|
||||
club_id = resolve_club_id_for_write(request) or ''
|
||||
try:
|
||||
from shop.services.shenhe_config import (
|
||||
get_or_create_shenhe_config,
|
||||
is_zhi_kan_shenhe_enabled,
|
||||
)
|
||||
get_or_create_shenhe_config(club_id)
|
||||
zhi_kan_shenhe = is_zhi_kan_shenhe_enabled(club_id)
|
||||
except Exception:
|
||||
logging.getLogger(__name__).exception(
|
||||
'读取只看审核配置失败 club_id=%s(请确认已 migrate shop 0004)',
|
||||
club_id,
|
||||
)
|
||||
zhi_kan_shenhe = True
|
||||
|
||||
return Response({
|
||||
'code': 0,
|
||||
'data': {
|
||||
'type_list': type_list,
|
||||
'zone_list': zone_list,
|
||||
'member_list': member_list,
|
||||
'zhi_kan_shenhe': zhi_kan_shenhe,
|
||||
'club_scoped': club_scoped,
|
||||
'club_id': club_id,
|
||||
}
|
||||
})
|
||||
except Exception:
|
||||
logging.getLogger(__name__).exception('GetProductBaseDataView 失败')
|
||||
return Response({'code': 500, 'msg': '获取商品基础数据失败,请稍后重试'})
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -237,69 +237,84 @@ class GetProductTypeZoneView(APIView):
|
||||
if '7007a' not in permissions:
|
||||
return Response({'code': 403, 'msg': '您无权访问此页面'})
|
||||
|
||||
# 查询专区数量(按俱乐部隔离;集团汇总看全部)
|
||||
zone_qs_for_count = filter_club_char_field(
|
||||
ShangpinZhuanqu.query.all(), request, field='club_id'
|
||||
)
|
||||
zone_count_rows = zone_qs_for_count.values('leixing_id').annotate(cnt=Count('id'))
|
||||
zone_count_map = {row['leixing_id']: row['cnt'] for row in zone_count_rows}
|
||||
|
||||
types = ShangpinLeixing.query.all().order_by('-paixu') # paixu 越大越靠前
|
||||
type_list = []
|
||||
for t in types:
|
||||
# 从预聚合的 map 中取专区数量
|
||||
zone_count = zone_count_map.get(t.id, 0)
|
||||
type_list.append({
|
||||
'id': t.id,
|
||||
'jieshao': t.jieshao or '',
|
||||
'tupian_url': t.tupian_url or '',
|
||||
'yaoqiuleixing': t.yaoqiuleixing,
|
||||
'huiyuan_id': t.huiyuan_id or '',
|
||||
'yongjin': float(t.yongjin) if t.yongjin is not None else None,
|
||||
'shenhezhuangtai': t.shenhezhuangtai,
|
||||
'paixu': t.paixu,
|
||||
'product_count': zone_count,
|
||||
})
|
||||
|
||||
# 查询专区(按俱乐部隔离)
|
||||
zones = filter_club_char_field(
|
||||
ShangpinZhuanqu.query.all().order_by('-paixu'), request, field='club_id'
|
||||
)
|
||||
zone_list = [
|
||||
{
|
||||
'id': z.id,
|
||||
'mingzi': z.mingzi or '',
|
||||
'leixing_id': z.leixing_id,
|
||||
'shenhezhuangtai': z.shenhezhuangtai,
|
||||
'paixu': z.paixu,
|
||||
'club_id': getattr(z, 'club_id', '') or '',
|
||||
}
|
||||
for z in zones
|
||||
]
|
||||
|
||||
# 查询所有会员(只返回 id、介绍、价格)
|
||||
members = Huiyuan.query.all().values('huiyuan_id', 'jieshao', 'jiage')
|
||||
member_list = [
|
||||
{
|
||||
'huiyuan_id': m['huiyuan_id'],
|
||||
'jieshao': m['jieshao'],
|
||||
'jiage': float(m['jiage']),
|
||||
}
|
||||
for m in members
|
||||
]
|
||||
|
||||
from jituan.constants import DATA_SCOPE_ALL
|
||||
from jituan.services.club_context import resolve_club_scope
|
||||
from jituan.services.club_context import resolve_club_scope, resolve_club_id_from_request
|
||||
from jituan.services.club_shangpin_leixing import build_club_leixing_admin_list
|
||||
|
||||
return Response({
|
||||
'code': 0,
|
||||
'data': {
|
||||
'type_list': type_list,
|
||||
'zone_list': zone_list,
|
||||
'member_list': member_list,
|
||||
'club_scoped': resolve_club_scope(request) != DATA_SCOPE_ALL,
|
||||
club_scoped = resolve_club_scope(request) != DATA_SCOPE_ALL
|
||||
club_id = resolve_club_id_from_request(request)
|
||||
|
||||
try:
|
||||
zone_qs_for_count = filter_club_char_field(
|
||||
ShangpinZhuanqu.query.all(), request, field='club_id'
|
||||
)
|
||||
zone_count_map = {
|
||||
row['leixing_id']: row['cnt']
|
||||
for row in zone_qs_for_count.values('leixing_id').annotate(cnt=Count('id'))
|
||||
}
|
||||
})
|
||||
|
||||
if club_scoped:
|
||||
# 具体俱乐部:仅本俱乐部已上架类型(与抢单端一致)
|
||||
admin_payload = build_club_leixing_admin_list(request)
|
||||
type_list = []
|
||||
for item in (admin_payload.get('list') or []):
|
||||
type_list.append({
|
||||
**item,
|
||||
'product_count': zone_count_map.get(item['id'], 0),
|
||||
'club_enabled': True,
|
||||
})
|
||||
else:
|
||||
type_list = []
|
||||
for t in ShangpinLeixing.query.all().order_by('-paixu'):
|
||||
type_list.append({
|
||||
'id': t.id,
|
||||
'jieshao': t.jieshao or '',
|
||||
'tupian_url': t.tupian_url or '',
|
||||
'yaoqiuleixing': t.yaoqiuleixing,
|
||||
'huiyuan_id': t.huiyuan_id or '',
|
||||
'yongjin': float(t.yongjin) if t.yongjin is not None else None,
|
||||
'shenhezhuangtai': t.shenhezhuangtai,
|
||||
'paixu': t.paixu,
|
||||
'product_count': zone_count_map.get(t.id, 0),
|
||||
})
|
||||
|
||||
zones = filter_club_char_field(
|
||||
ShangpinZhuanqu.query.all().order_by('-paixu'), request, field='club_id'
|
||||
)
|
||||
zone_list = [
|
||||
{
|
||||
'id': z.id,
|
||||
'mingzi': z.mingzi or '',
|
||||
'leixing_id': z.leixing_id,
|
||||
'shenhezhuangtai': z.shenhezhuangtai,
|
||||
'paixu': z.paixu,
|
||||
'club_id': getattr(z, 'club_id', '') or '',
|
||||
}
|
||||
for z in zones
|
||||
]
|
||||
|
||||
member_list = [
|
||||
{
|
||||
'huiyuan_id': m['huiyuan_id'],
|
||||
'jieshao': m['jieshao'] or '',
|
||||
'jiage': float(m['jiage'] or 0),
|
||||
}
|
||||
for m in Huiyuan.query.all().values('huiyuan_id', 'jieshao', 'jiage')
|
||||
]
|
||||
|
||||
return Response({
|
||||
'code': 0,
|
||||
'data': {
|
||||
'type_list': type_list,
|
||||
'zone_list': zone_list,
|
||||
'member_list': member_list,
|
||||
'club_scoped': club_scoped,
|
||||
'club_id': club_id if club_scoped else '',
|
||||
}
|
||||
})
|
||||
except Exception:
|
||||
logging.getLogger(__name__).exception('GetProductTypeZoneView 失败')
|
||||
return Response({'code': 500, 'msg': '获取类型专区失败,请稍后重试'})
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,13 @@ from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from backend.view import verify_kefu_permission
|
||||
|
||||
# 小程序配置 8080a 或 商品类型专区 7007a 均可上架/下架
|
||||
CLUB_LEIXING_PERMS = ('8080a', '7007a')
|
||||
|
||||
|
||||
def _has_club_leixing_perm(permissions):
|
||||
return any(p in permissions for p in CLUB_LEIXING_PERMS)
|
||||
|
||||
|
||||
class ClubShangpinLeixingListView(APIView):
|
||||
"""POST /jituan/houtai/club-leixing-list"""
|
||||
@@ -19,7 +26,7 @@ class ClubShangpinLeixingListView(APIView):
|
||||
kefu, permissions = verify_kefu_permission(request, phone)
|
||||
if kefu is None:
|
||||
return permissions
|
||||
if '8080a' not in permissions:
|
||||
if not _has_club_leixing_perm(permissions):
|
||||
return Response({'code': 403, 'msg': '无权限管理小程序商品类型'})
|
||||
from jituan.services.club_shangpin_leixing import build_club_leixing_admin_list
|
||||
payload = build_club_leixing_admin_list(request)
|
||||
@@ -38,7 +45,7 @@ class ClubShangpinLeixingCatalogView(APIView):
|
||||
kefu, permissions = verify_kefu_permission(request, phone)
|
||||
if kefu is None:
|
||||
return permissions
|
||||
if '8080a' not in permissions:
|
||||
if not _has_club_leixing_perm(permissions):
|
||||
return Response({'code': 403, 'msg': '无权限'})
|
||||
from jituan.services.club_shangpin_leixing import build_club_leixing_catalog
|
||||
return Response({'code': 0, 'data': build_club_leixing_catalog(request)})
|
||||
@@ -57,7 +64,7 @@ class ClubShangpinLeixingEnableView(APIView):
|
||||
kefu, permissions = verify_kefu_permission(request, phone)
|
||||
if kefu is None:
|
||||
return permissions
|
||||
if '8080a' not in permissions:
|
||||
if not _has_club_leixing_perm(permissions):
|
||||
return Response({'code': 403, 'msg': '无权限'})
|
||||
from jituan.services.club_shangpin_leixing import enable_leixing_for_club
|
||||
data, err = enable_leixing_for_club(request, int(leixing_id), request.data.get('paixu'))
|
||||
@@ -79,7 +86,7 @@ class ClubShangpinLeixingDisableView(APIView):
|
||||
kefu, permissions = verify_kefu_permission(request, phone)
|
||||
if kefu is None:
|
||||
return permissions
|
||||
if '8080a' not in permissions:
|
||||
if not _has_club_leixing_perm(permissions):
|
||||
return Response({'code': 403, 'msg': '无权限'})
|
||||
from jituan.services.club_shangpin_leixing import disable_leixing_for_club
|
||||
data, err = disable_leixing_for_club(request, int(leixing_id))
|
||||
|
||||
Reference in New Issue
Block a user