fix: 启用服务号回调、协议强制签署校验、消息会话数据修复配套接口
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2522,6 +2522,11 @@ class ShangjiaPaifaView(APIView):
|
||||
def post(self, request):
|
||||
logger.info(f"商家派单请求: user_id={request.user.yonghuid}, data={request.data}")
|
||||
|
||||
from peizhi.xieyi_service import check_xieyi_or_response
|
||||
blocked = check_xieyi_or_response(request.user.yonghuid, 'shangjia')
|
||||
if blocked:
|
||||
return blocked
|
||||
|
||||
try:
|
||||
data = request.data
|
||||
|
||||
@@ -4137,6 +4142,11 @@ class QiangdanView(APIView):
|
||||
if not dingdan_id:
|
||||
return Response({'code': 400, 'msg': '订单ID不能为空'}, status=400)
|
||||
|
||||
from peizhi.xieyi_service import check_xieyi_or_response
|
||||
blocked = check_xieyi_or_response(request.user.yonghuid, 'dashou')
|
||||
if blocked:
|
||||
return blocked
|
||||
|
||||
chat_success = False
|
||||
try:
|
||||
with transaction.atomic():
|
||||
|
||||
@@ -39,6 +39,7 @@ def _serialize_admin(item):
|
||||
'content_text': item.content_text or '',
|
||||
'version': item.version,
|
||||
'is_active': item.is_active,
|
||||
'must_sign': item.must_sign,
|
||||
'sort_order': item.sort_order,
|
||||
'images': [
|
||||
{'id': img.id, 'image_path': img.image_path, 'sort_order': img.sort_order}
|
||||
@@ -104,6 +105,7 @@ class XieyiModifyAPIView(APIView):
|
||||
content_title=request.data.get('content_title', ''),
|
||||
content_text=request.data.get('content_text', ''),
|
||||
is_active=bool(request.data.get('is_active', True)),
|
||||
must_sign=bool(request.data.get('must_sign', True)),
|
||||
sort_order=int(request.data.get('sort_order', 0)),
|
||||
)
|
||||
return Response({'code': 0, 'msg': '创建成功', 'data': _serialize_admin(item)})
|
||||
@@ -137,6 +139,8 @@ class XieyiModifyAPIView(APIView):
|
||||
content_changed = True
|
||||
if 'is_active' in request.data:
|
||||
item.is_active = bool(request.data.get('is_active'))
|
||||
if 'must_sign' in request.data:
|
||||
item.must_sign = bool(request.data.get('must_sign'))
|
||||
if 'sort_order' in request.data:
|
||||
item.sort_order = int(request.data.get('sort_order', 0))
|
||||
if 'bump_version' in request.data and request.data.get('bump_version'):
|
||||
|
||||
16
peizhi/migrations/0018_xcx_xieyi_must_sign.py
Normal file
16
peizhi/migrations/0018_xcx_xieyi_must_sign.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('peizhi', '0017_xcx_xieyi'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='xcxxieyi',
|
||||
name='must_sign',
|
||||
field=models.BooleanField(default=True, verbose_name='是否强制签署'),
|
||||
),
|
||||
]
|
||||
@@ -748,6 +748,7 @@ class XcxXieyi(models.Model):
|
||||
content_text = models.TextField(blank=True, default='', verbose_name='文字内容')
|
||||
version = models.PositiveIntegerField(default=1, verbose_name='版本号')
|
||||
is_active = models.BooleanField(default=True, verbose_name='是否启用')
|
||||
must_sign = models.BooleanField(default=True, verbose_name='是否强制签署')
|
||||
sort_order = models.IntegerField(default=0, verbose_name='排序')
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
|
||||
@@ -11,7 +11,7 @@ from .xcx_config_views import (
|
||||
XcxSysPeizhiQueryView, XcxSysPeizhiUpdateView,
|
||||
XcxPageZiyuanQueryView, XcxPageZiyuanUpdateView, XcxPageZiyuanUploadView,
|
||||
)
|
||||
from .xieyi_views import XieyiListView, XieyiDetailView, XieyiSignStatusView, XieyiSignView
|
||||
from .xieyi_views import XieyiListView, XieyiDetailView, XieyiSignStatusView, XieyiSignView, XieyiCheckView
|
||||
|
||||
urlpatterns = [
|
||||
path('shangpingonggao/', ShangpinGonggaoView.as_view(), name='商品公告轮播获取'),
|
||||
@@ -55,6 +55,7 @@ urlpatterns = [
|
||||
path('xcxyzsc', XcxPageZiyuanUploadView.as_view(), name='管理员上传页面资源'),
|
||||
path('xieyihq', XieyiListView.as_view(), name='小程序获取协议列表'),
|
||||
path('xieyixq', XieyiDetailView.as_view(), name='小程序获取协议详情'),
|
||||
path('xieyijc', XieyiCheckView.as_view(), name='小程序检查协议签署'),
|
||||
path('xieyizt', XieyiSignStatusView.as_view(), name='小程序查询协议签署状态'),
|
||||
path('xieyiqm', XieyiSignView.as_view(), name='小程序签署协议'),
|
||||
]
|
||||
56
peizhi/xieyi_service.py
Normal file
56
peizhi/xieyi_service.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""协议签署校验 — 供接单/派单等接口调用"""
|
||||
from rest_framework.response import Response
|
||||
|
||||
from peizhi.models import XcxXieyi, XcxXieyiQianshu
|
||||
|
||||
XIEYI_BLOCK_CODE = 4601
|
||||
|
||||
|
||||
def get_unsigned_xieyi_list(yonghuid: str, shenfen: str):
|
||||
"""返回未签署当前版本的必签协议列表"""
|
||||
if not yonghuid or not shenfen:
|
||||
return []
|
||||
active = XcxXieyi.objects.filter(
|
||||
shenfen=shenfen, is_active=True, must_sign=True,
|
||||
).order_by('sort_order', 'id')
|
||||
unsigned = []
|
||||
for xieyi in active:
|
||||
signed = XcxXieyiQianshu.objects.filter(
|
||||
yonghuid=yonghuid,
|
||||
xieyi_id=xieyi.id,
|
||||
xieyi_version=xieyi.version,
|
||||
).exists()
|
||||
if not signed:
|
||||
unsigned.append(xieyi)
|
||||
return unsigned
|
||||
|
||||
|
||||
def serialize_unsigned_brief(xieyi_list):
|
||||
return [
|
||||
{
|
||||
'id': x.id,
|
||||
'title': x.title,
|
||||
'shenfen': x.shenfen,
|
||||
'version': x.version,
|
||||
}
|
||||
for x in xieyi_list
|
||||
]
|
||||
|
||||
|
||||
def xieyi_required_response(unsigned_list):
|
||||
return Response({
|
||||
'code': XIEYI_BLOCK_CODE,
|
||||
'msg': '请先阅读并签署用户协议',
|
||||
'data': {
|
||||
'all_signed': False,
|
||||
'unsigned': serialize_unsigned_brief(unsigned_list),
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
def check_xieyi_or_response(yonghuid: str, shenfen: str):
|
||||
"""未签署则返回 Response,已签署返回 None"""
|
||||
unsigned = get_unsigned_xieyi_list(yonghuid, shenfen)
|
||||
if unsigned:
|
||||
return xieyi_required_response(unsigned)
|
||||
return None
|
||||
@@ -10,6 +10,7 @@ from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from peizhi.models import XcxXieyi, XcxXieyiImage, XcxXieyiQianshu
|
||||
from peizhi.xieyi_service import get_unsigned_xieyi_list, serialize_unsigned_brief
|
||||
from utils.oss_utils import upload_to_oss, validate_image
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -42,6 +43,7 @@ def _serialize_xieyi(item, yonghuid=None, include_images=False):
|
||||
'content_text': item.content_text or '',
|
||||
'version': item.version,
|
||||
'is_active': item.is_active,
|
||||
'must_sign': item.must_sign,
|
||||
'sort_order': item.sort_order,
|
||||
'signed': signed,
|
||||
}
|
||||
@@ -91,6 +93,28 @@ class XieyiDetailView(APIView):
|
||||
})
|
||||
|
||||
|
||||
class XieyiCheckView(APIView):
|
||||
"""POST /peizhi/xieyijc — 检查必签协议是否已全部签署(后端为准)"""
|
||||
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
parser_classes = [JSONParser]
|
||||
|
||||
def post(self, request):
|
||||
shenfen = (request.data.get('shenfen') or '').strip()
|
||||
if shenfen not in VALID_SHENFEN:
|
||||
return Response({'code': 400, 'msg': '无效的身份参数', 'data': None})
|
||||
yonghuid = request.user.yonghuid
|
||||
unsigned = get_unsigned_xieyi_list(yonghuid, shenfen)
|
||||
return Response({
|
||||
'code': 0,
|
||||
'msg': 'success',
|
||||
'data': {
|
||||
'all_signed': len(unsigned) == 0,
|
||||
'unsigned': serialize_unsigned_brief(unsigned),
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
class XieyiSignStatusView(APIView):
|
||||
"""POST /peizhi/xieyizt — 是否已签署当前版本"""
|
||||
|
||||
@@ -176,5 +200,6 @@ class XieyiSignView(APIView):
|
||||
'id': record.id,
|
||||
'signature_path': oss_path,
|
||||
'signed_at': record.signed_at.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'all_signed': len(get_unsigned_xieyi_list(yonghuid, item.shenfen)) == 0,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -82,7 +82,7 @@ urlpatterns = [
|
||||
# 打手申诉接口
|
||||
path('dscfss', DashouShensuView.as_view(), name='打手处罚上诉申请'),
|
||||
path('sjcfjlhq', ShangjiaChufaJiluHuoquView.as_view(), name='商家处罚记录获取'),
|
||||
#path('officialcallback', csrf_exempt(WeixinOfficialCallbackView.as_view()), name='用户关注取关服务号回调'),
|
||||
path('officialcallback', csrf_exempt(WeixinOfficialCallbackView.as_view()), name='用户关注取关服务号回调'),
|
||||
|
||||
path('kefujinru', KefuLoginView.as_view(), name='客服登录'),
|
||||
path('kfjrhqzl', KefuStatsView.as_view(), name='客服获取数据'),
|
||||
|
||||
Reference in New Issue
Block a user