商家罚款增加平台审核:新增状态5、证据图、审核API;审核通过前不影响抢单,提现仍拦截未结案罚单
This commit is contained in:
@@ -444,7 +444,7 @@ class OrderPlayerHistory(QModel):
|
||||
class Penalty(QModel):
|
||||
"""罚单表——平台各类处罚信息
|
||||
|
||||
状态码:1=待缴纳, 2=已缴纳, 3=申诉中, 4=已驳回
|
||||
状态码:1=待缴纳, 2=已缴纳, 3=申诉中, 4=已驳回, 5=平台审核中
|
||||
被处罚者身份(shenfen):1=打手, 2=管事, 3=商家, 4=组长
|
||||
"""
|
||||
|
||||
@@ -475,7 +475,7 @@ class Penalty(QModel):
|
||||
db_column='guanliandingdan_id', verbose_name='关联订单ID',
|
||||
)
|
||||
Status = models.IntegerField(
|
||||
choices=[(1, '待缴纳'), (2, '已缴纳'), (3, '申诉中'), (4, '已驳回')],
|
||||
choices=[(1, '待缴纳'), (2, '已缴纳'), (3, '申诉中'), (4, '已驳回'), (5, '平台审核中')],
|
||||
default=1, db_index=True,
|
||||
db_column='zhuangtai', verbose_name='罚单状态',
|
||||
)
|
||||
|
||||
@@ -2294,6 +2294,20 @@ class ShangjiaDingdanXiangqingView(APIView):
|
||||
if fadan_obj:
|
||||
ct = fmt_datetime(fadan_obj.CreateTime)
|
||||
ut = fmt_datetime(fadan_obj.UpdateTime)
|
||||
zhengju_urls = list(
|
||||
PenaltyAppealImage.query.filter(Penalty=fadan_obj, Purpose=1).values_list('ImageURL', flat=True)
|
||||
)
|
||||
shensu_urls = list(
|
||||
PenaltyAppealImage.query.filter(Penalty=fadan_obj, Purpose=2).values_list('ImageURL', flat=True)
|
||||
)
|
||||
zhengju_imgs = [
|
||||
{'id': t.id, 'url': t.ImageURL}
|
||||
for t in PenaltyAppealImage.query.filter(Penalty=fadan_obj, Purpose=1)
|
||||
]
|
||||
shensu_imgs = [
|
||||
{'id': t.id, 'url': t.ImageURL}
|
||||
for t in PenaltyAppealImage.query.filter(Penalty=fadan_obj, Purpose=2)
|
||||
]
|
||||
fadan_dict = {
|
||||
'id': fadan_obj.id,
|
||||
'chufaliyou': fadan_obj.Reason or '',
|
||||
@@ -2306,6 +2320,8 @@ class ShangjiaDingdanXiangqingView(APIView):
|
||||
'yingde_fenhong': float(fadan_obj.ApplicantBonusAmount or 0),
|
||||
'fenhong_lilv': float(fadan_obj.ApplicantBonusRate or 0),
|
||||
'fenhong_yiruzhang': bool(fadan_obj.BonusCredited),
|
||||
'zhengju_tupian': zhengju_imgs,
|
||||
'shensu_tupian': shensu_imgs,
|
||||
'CreateTime': ct,
|
||||
'create_time': ct,
|
||||
'UpdateTime': ut,
|
||||
@@ -4147,6 +4163,20 @@ class DashouCOSZhengshuView(APIView):
|
||||
).first()
|
||||
if not fadan:
|
||||
return Response({'code': 403, 'msg': '罚单不存在或无权操作'}, status=403)
|
||||
elif yongtu == 'fakuan_evidence_draft':
|
||||
# 商家申请罚款前上传证据图(仅需订单归属校验)
|
||||
if not dingdan_id:
|
||||
return Response({'code': 400, 'msg': '缺少订单ID'}, status=400)
|
||||
try:
|
||||
shangjia_profile = request.user.ShopProfile
|
||||
if shangjia_profile.zhuangtai != 1:
|
||||
return Response({'code': 403, 'msg': '商家状态异常'}, status=403)
|
||||
except Exception:
|
||||
return Response({'code': 403, 'msg': '非商家无权上传'}, status=403)
|
||||
try:
|
||||
MerchantOrderExt.query.get(Order__OrderID=dingdan_id, MerchantID=request.user.UserUID)
|
||||
except MerchantOrderExt.DoesNotExist:
|
||||
return Response({'code': 403, 'msg': '订单不存在或无权操作'}, status=403)
|
||||
else:
|
||||
# 默认为订单相关,需要验证订单且打手必须接单
|
||||
try:
|
||||
@@ -4190,6 +4220,10 @@ class DashouCOSZhengshuView(APIView):
|
||||
resources.append(
|
||||
f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/fakuan/shangjiafakuan/zhengju/*"
|
||||
)
|
||||
elif yongtu == 'fakuan_evidence_draft':
|
||||
resources.append(
|
||||
f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/fakuan/shangjiafakuan/zhengju/*"
|
||||
)
|
||||
else:
|
||||
resources.append(
|
||||
f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/order/{dingdan_id}/*"
|
||||
@@ -6801,10 +6835,19 @@ class ShangjiaFakuanApplyView(APIView):
|
||||
chufa_liyou = request.data.get('chufa_liyou', '').strip()
|
||||
fakuanjine = request.data.get('fakuanjine', 0)
|
||||
yingxiang_qiangdan = int(request.data.get('yingxiang_qiangdan', 1))
|
||||
evidence_urls = request.data.get('evidence_urls') or []
|
||||
|
||||
if not dingdan_id or not chufa_liyou or not fakuanjine:
|
||||
return Response({'code': 2, 'msg': '参数不完整'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if not isinstance(evidence_urls, list):
|
||||
return Response({'code': 2, 'msg': '证据图片格式错误'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
evidence_urls = [str(u).strip() for u in evidence_urls if str(u).strip()]
|
||||
if len(evidence_urls) > 9:
|
||||
return Response({'code': 2, 'msg': '证据图片最多9张'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
if len(evidence_urls) < 1:
|
||||
return Response({'code': 2, 'msg': '请至少上传1张证据图片'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
try:
|
||||
fakuanjine = float(fakuanjine)
|
||||
if fakuanjine <= 0:
|
||||
@@ -6838,6 +6881,8 @@ class ShangjiaFakuanApplyView(APIView):
|
||||
if staff_member is not None:
|
||||
staff_kefu_id = getattr(staff_member, 'staff_user_id', None) or None
|
||||
|
||||
from utils.penalty_status import PENALTY_PLATFORM_AUDIT
|
||||
|
||||
with transaction.atomic():
|
||||
fadan = Penalty.query.create(
|
||||
PenalizedUserID=dashou_id,
|
||||
@@ -6846,7 +6891,7 @@ class ShangjiaFakuanApplyView(APIView):
|
||||
Reason=chufa_liyou,
|
||||
FineAmount=fakuanjine,
|
||||
RelatedOrderID=dingdan_id,
|
||||
Status=1, # 待缴纳
|
||||
Status=PENALTY_PLATFORM_AUDIT, # 平台审核中,通过后变为待缴纳
|
||||
AffectsGrabbing=yingxiang_qiangdan,
|
||||
ApplicantIdentity=5, # 申请人是商家
|
||||
ClubID=resolve_penalty_club_id(
|
||||
@@ -6858,9 +6903,16 @@ class ShangjiaFakuanApplyView(APIView):
|
||||
),
|
||||
ShopStaffUserID=staff_kefu_id,
|
||||
)
|
||||
for url in evidence_urls:
|
||||
PenaltyAppealImage.query.create(
|
||||
Penalty=fadan,
|
||||
PenalizedUserID=dashou_id,
|
||||
ImageURL=url,
|
||||
Purpose=1,
|
||||
)
|
||||
lock_penalty_bonus(fadan)
|
||||
logger.info(f"商家{shangjia_id}对订单{dingdan_id}打手{dashou_id}罚款成功,金额{fakuanjine}")
|
||||
return Response({'code': 0, 'msg': '罚款申请已提交'})
|
||||
logger.info(f"商家{shangjia_id}对订单{dingdan_id}打手{dashou_id}提交罚款申请(平台审核),金额{fakuanjine}")
|
||||
return Response({'code': 0, 'msg': '罚款申请已提交,等待平台审核', 'data': {'fadan_id': fadan.id}})
|
||||
|
||||
|
||||
class ShangjiaFakuaiXiugaiView(APIView):
|
||||
@@ -6944,8 +6996,9 @@ class ShangjiaFakuaiXiugaiView(APIView):
|
||||
return Response({'code': 0, 'msg': '退款理由修改成功'})
|
||||
|
||||
def _modify_penalty(self, fadan, liyou, jine_str, processor_id=None):
|
||||
"""修改罚款(仅状态1待缴纳 或 3申诉中)"""
|
||||
if fadan.Status not in (1, 3):
|
||||
"""修改罚款(待缴纳 / 申诉中 / 平台审核中)"""
|
||||
from utils.penalty_status import PENALTY_PENDING_PAY, PENALTY_APPEALING, PENALTY_PLATFORM_AUDIT
|
||||
if fadan.Status not in (PENALTY_PENDING_PAY, PENALTY_APPEALING, PENALTY_PLATFORM_AUDIT):
|
||||
return Response({'code': 400, 'msg': '当前罚单状态不可修改'})
|
||||
if not liyou.strip():
|
||||
return Response({'code': 400, 'msg': '罚款理由不能为空'})
|
||||
@@ -6966,13 +7019,14 @@ class ShangjiaFakuaiXiugaiView(APIView):
|
||||
return Response({'code': 0, 'msg': '罚款修改成功'})
|
||||
|
||||
def _cancel_penalty(self, fadan, liyou, processor_id=None):
|
||||
"""撤销罚款(状态1或3 → 状态4 已驳回)"""
|
||||
if fadan.Status not in (1, 3):
|
||||
"""撤销罚款(待缴纳 / 申诉中 / 平台审核中 → 已驳回)"""
|
||||
from utils.penalty_status import PENALTY_PENDING_PAY, PENALTY_APPEALING, PENALTY_PLATFORM_AUDIT, PENALTY_REJECTED
|
||||
if fadan.Status not in (PENALTY_PENDING_PAY, PENALTY_APPEALING, PENALTY_PLATFORM_AUDIT):
|
||||
return Response({'code': 400, 'msg': '当前罚单状态不可撤销'})
|
||||
if not liyou.strip():
|
||||
return Response({'code': 400, 'msg': '驳回理由不能为空'})
|
||||
with transaction.atomic():
|
||||
fadan.Status = 4 # 已驳回
|
||||
fadan.Status = PENALTY_REJECTED # 已驳回
|
||||
fadan.RejectReason = liyou[:500]
|
||||
if processor_id:
|
||||
fadan.ProcessorID = processor_id
|
||||
@@ -6981,8 +7035,9 @@ class ShangjiaFakuaiXiugaiView(APIView):
|
||||
return Response({'code': 0, 'msg': '罚款已撤销(驳回)'})
|
||||
|
||||
def _resubmit_penalty(self, fadan, liyou, jine_str, processor_id=None):
|
||||
"""再次申请罚款(状态4 → 状态1,修改理由和金额)"""
|
||||
if fadan.Status != 4:
|
||||
"""再次申请罚款(已驳回 → 平台审核中)"""
|
||||
from utils.penalty_status import PENALTY_REJECTED, PENALTY_PLATFORM_AUDIT
|
||||
if fadan.Status != PENALTY_REJECTED:
|
||||
return Response({'code': 400, 'msg': '只有已驳回的罚单可再次申请'})
|
||||
if not liyou.strip():
|
||||
return Response({'code': 400, 'msg': '罚款理由不能为空'})
|
||||
@@ -6993,7 +7048,7 @@ class ShangjiaFakuaiXiugaiView(APIView):
|
||||
except:
|
||||
return Response({'code': 400, 'msg': '罚款金额必须为正数'})
|
||||
with transaction.atomic():
|
||||
fadan.Status = 1 # 待缴纳
|
||||
fadan.Status = PENALTY_PLATFORM_AUDIT
|
||||
fadan.Reason = liyou[:500]
|
||||
fadan.FineAmount = jine
|
||||
fadan.RejectReason = '' # 清空驳回理由
|
||||
@@ -7007,7 +7062,8 @@ class ShangjiaFakuaiXiugaiView(APIView):
|
||||
|
||||
def _manage_penalty_evidence(self, fadan, data):
|
||||
"""管理罚单证据图片(Purpose=1),与申诉图片严格隔离"""
|
||||
if fadan.Status not in (1, 3):
|
||||
from utils.penalty_status import PENALTY_PENDING_PAY, PENALTY_APPEALING, PENALTY_PLATFORM_AUDIT
|
||||
if fadan.Status not in (PENALTY_PENDING_PAY, PENALTY_APPEALING, PENALTY_PLATFORM_AUDIT):
|
||||
return Response({'code': 400, 'msg': '当前罚单状态不可修改证据图片'})
|
||||
add_urls = data.get('add_urls') or []
|
||||
remove_ids = data.get('remove_ids') or []
|
||||
@@ -7018,6 +7074,9 @@ class ShangjiaFakuaiXiugaiView(APIView):
|
||||
PenaltyAppealImage.query.filter(
|
||||
Penalty=fadan, Purpose=1, id__in=remove_ids
|
||||
).delete()
|
||||
existing_count = PenaltyAppealImage.query.filter(Penalty=fadan, Purpose=1).count()
|
||||
if existing_count + len(add_urls) > 9:
|
||||
return Response({'code': 400, 'msg': '证据图片最多9张'})
|
||||
for url in add_urls:
|
||||
url = str(url).strip()
|
||||
if not url:
|
||||
|
||||
Reference in New Issue
Block a user