diff --git a/backend/urls.py b/backend/urls.py index 36253c4..4274d97 100644 --- a/backend/urls.py +++ b/backend/urls.py @@ -12,7 +12,7 @@ from .view import (GetRolePermissionView, ShopModifyView, ShopPublicTypeAndAuditView, ShopListForProductView, ShopProductModifyView, ShopProductTypeMappingView, ProductListView, ProductModifyView, KefuChatPermissionsView, FineApplyView, PunishDashouView, - FaKuanTongJiView, FaKuanLieBiaoView, FaKuanChuLiView, FaKuanChuangJianView, + FaKuanTongJiView, FaKuanLieBiaoView, FaKuanChuLiView, FaKuanChuangJianView, FaKuanPingTaiShenHeView, HqbkxxView,BkxgView,CaiwuView,CwhybkhqView, HybkjtsjView, SzxxView, CwddhqlxView, CwhqjtddsjView, CwqtczhqView, KhpzhqView, ChzsgcView,KhgglView, ShgxgsjView, KhjlglView, KhjlczView, ZxkfghdsView) from config.views import MiniappScriptHoutaiListView, MiniappScriptHoutaiModifyView @@ -89,6 +89,7 @@ urlpatterns = [ path('htglyhqcfsltj', FaKuanTongJiView.as_view(),name='后台罚单统计图片'), # 罚款统计 path('hthqfklb', FaKuanLieBiaoView.as_view(),name='后台罚单列表'), # 罚款列表 path('glyclfk', FaKuanChuLiView.as_view(),name='后台罚单操作'), # 处理罚款 + path('glyptshfk', FaKuanPingTaiShenHeView.as_view(), name='后台罚款平台审核'), path('htfksc', FaKuanChuangJianView.as_view(),name='后台生成罚单'), # 创建罚款 path('kffkdssq', FineApplyView.as_view(), name='客服罚款申请'), # 客服罚款申请 path('kpcf', PunishDashouView.as_view(), name='客服处罚打手'), # 客服处罚打手 diff --git a/backend/view.py b/backend/view.py index 05e86e5..1329b40 100644 --- a/backend/view.py +++ b/backend/view.py @@ -6609,6 +6609,72 @@ class FaKuanChuLiView(APIView): return Response({'code': 500, 'msg': '系统繁忙'}) +class FaKuanPingTaiShenHeView(APIView): + """ + 平台审核商家提交的罚款(同意/驳回) + POST /houtai/glyptshfk + action: platform_approve | platform_reject + """ + permission_classes = [IsAuthenticated] + parser_classes = [MultiPartParser, FormParser, JSONParser] + + def post(self, request): + try: + from utils.penalty_status import ( + PENALTY_PLATFORM_AUDIT, PENALTY_PENDING_PAY, PENALTY_APPEALING, PENALTY_REJECTED, + ) + username = request.data.get('username', '').strip() + penalty_id = request.data.get('penalty_id') or request.data.get('fadan_id') + action = request.data.get('action', '').strip() + chuli_liyou = request.data.get('chuli_liyou', '').strip() + + if not all([username, penalty_id, action]): + return Response({'code': 400, 'msg': '参数不完整'}) + + kefu, permissions = verify_kefu_permission(request, username) + if kefu is None: + return permissions + + with transaction.atomic(): + try: + penalty = Penalty.objects.select_for_update().get(id=penalty_id) + except Penalty.DoesNotExist: + return Response({'code': 404, 'msg': '罚单不存在'}) + + deny = forbid_penalty_out_of_scope(request, penalty) + if deny: + return deny + + if penalty.Status != PENALTY_PLATFORM_AUDIT: + return Response({'code': 400, 'msg': '当前状态不可平台审核'}) + + if not check_fadan_permission(permissions, penalty.Identity): + return Response({'code': 403, 'msg': '无权限处理该类罚单'}) + + if action == 'platform_approve': + if penalty.AppealReason: + penalty.Status = PENALTY_APPEALING + else: + penalty.Status = PENALTY_PENDING_PAY + penalty.ApproveReason = chuli_liyou or penalty.ApproveReason or '' + elif action == 'platform_reject': + penalty.Status = PENALTY_REJECTED + penalty.RejectReason = chuli_liyou or '平台审核驳回' + else: + return Response({'code': 400, 'msg': '无效的操作类型'}) + + penalty.ProcessorID = request.user.Phone + penalty.ProcessorIdentity = 3 + penalty.save() + + logger.info(f"罚款平台审核成功: {penalty_id}, 操作: {action}") + return Response({'code': 0, 'msg': '平台审核完成'}) + + except Exception as e: + logger.error(f"罚款平台审核异常: {traceback.format_exc()}") + return Response({'code': 500, 'msg': '系统繁忙'}) + + class FaKuanChuangJianView(APIView): """ 管理员创建罚款 diff --git a/jituan/urls.py b/jituan/urls.py index 5e8f0c8..b4da7d2 100644 --- a/jituan/urls.py +++ b/jituan/urls.py @@ -6,6 +6,7 @@ from backend.view import ( ClubMemberDisableView, ClubMemberEnableView, FaKuanChuLiView, + FaKuanPingTaiShenHeView, FaKuanChuangJianView, FaKuanLieBiaoView, FaKuanTongJiView, @@ -125,6 +126,7 @@ urlpatterns = [ path('houtai/htglyhqcfsltj', FaKuanTongJiView.as_view(), name='jituan_penalty_stats'), path('houtai/hthqfklb', FaKuanLieBiaoView.as_view(), name='jituan_penalty_list'), path('houtai/glyclfk', FaKuanChuLiView.as_view(), name='jituan_penalty_action'), + path('houtai/glyptshfk', FaKuanPingTaiShenHeView.as_view(), name='jituan_penalty_platform_audit'), path('houtai/htfksc', FaKuanChuangJianView.as_view(), name='jituan_penalty_create'), path('houtai/kefu-cfgl', KefuPunishmentListView.as_view(), name='jituan_kefu_cfgl'), path('houtai/khggl', KhgglView.as_view(), name='jituan_khggl'), diff --git a/orders/models.py b/orders/models.py index a722474..7228efd 100644 --- a/orders/models.py +++ b/orders/models.py @@ -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='罚单状态', ) diff --git a/orders/views.py b/orders/views.py index 5e81611..586c790 100644 --- a/orders/views.py +++ b/orders/views.py @@ -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: diff --git a/users/views.py b/users/views.py index 1adf674..66d5e7c 100644 --- a/users/views.py +++ b/users/views.py @@ -11601,6 +11601,7 @@ class FaKuanJiFenTongJiView(APIView): total=Count('id'), daijiaona=Count('id', filter=Q(Status=1)), shensuzhong=Count('id', filter=Q(Status=3)), + pingtai_shenhe=Count('id', filter=Q(Status=5)), yijiaona=Count('id', filter=Q(Status=2)), yibohui=Count('id', filter=Q(Status=4)), ) @@ -11622,6 +11623,7 @@ class FaKuanJiFenTongJiView(APIView): "total": fadan_stats['total'], "daijiaona": fadan_stats['daijiaona'], "shensuzhong": fadan_stats['shensuzhong'], + "pingtai_shenhe": fadan_stats['pingtai_shenhe'], "yijiaona": fadan_stats['yijiaona'], "yibohui": fadan_stats['yibohui'], }, @@ -11686,7 +11688,7 @@ class DaShouFaKuanLieBiaoView(APIView): qs = Penalty.query.filter(PenalizedUserID=yonghuid) # 状态筛选 - if zhuangtai is not None and int(zhuangtai) in [1, 2, 3, 4]: + if zhuangtai is not None and int(zhuangtai) in [1, 2, 3, 4, 5]: qs = qs.filter(Status=int(zhuangtai)) # 订单号模糊搜索 @@ -11805,6 +11807,8 @@ class ShangjiaCufaTongjiView(APIView): yijiaona_jine=Sum('FineAmount', filter=Q(Status=2)), shensuzhong=Count('id', filter=Q(Status=3)), shensuzhong_jine=Sum('FineAmount', filter=Q(Status=3)), + pingtai_shenhe=Count('id', filter=Q(Status=5)), + pingtai_shenhe_jine=Sum('FineAmount', filter=Q(Status=5)), yibohui=Count('id', filter=Q(Status=4)), yibohui_jine=Sum('FineAmount', filter=Q(Status=4)), shijidaozhang_jine=Sum( @@ -11842,6 +11846,8 @@ class ShangjiaCufaTongjiView(APIView): 'yijiaona_jine': _money_str(fadan_agg['yijiaona_jine']), 'shensuzhong': fadan_agg['shensuzhong'] or 0, 'shensuzhong_jine': _money_str(fadan_agg['shensuzhong_jine']), + 'pingtai_shenhe': fadan_agg['pingtai_shenhe'] or 0, + 'pingtai_shenhe_jine': _money_str(fadan_agg['pingtai_shenhe_jine']), 'yibohui': fadan_agg['yibohui'] or 0, 'yibohui_jine': _money_str(fadan_agg['yibohui_jine']), 'shijidaozhang_jine': _money_str(fadan_agg['shijidaozhang_jine']), @@ -11889,7 +11895,7 @@ class ShangjiaFakuanLieBiaoView(APIView): sousuo_dingdan_id = str(request.data.get('sousuo_dingdan_id', '')).strip() qs = Penalty.query.filter(ApplicantID=yonghuid) - if zhuangtai is not None and int(zhuangtai) in [1, 2, 3, 4]: + if zhuangtai is not None and int(zhuangtai) in [1, 2, 3, 4, 5]: qs = qs.filter(Status=int(zhuangtai)) if sousuo_dingdan_id: qs = qs.filter(RelatedOrderID__icontains=sousuo_dingdan_id) @@ -12002,14 +12008,23 @@ class FaKuanShenSuView(APIView): except Penalty.DoesNotExist: return Response({'code': 404, 'msg': '罚单不存在或无权操作'}, status=404) - # 只允许待缴纳状态(状态1)且没有驳回理由的罚单申诉 - if fadan.Status != 1: + # 待缴纳(1)或平台审核中(5)可申诉;平台审核中仅保存申诉内容,不改变状态 + from utils.penalty_status import ( + PENALTY_PENDING_PAY, PENALTY_APPEALING, PENALTY_PLATFORM_AUDIT, + ) + if fadan.Status not in (PENALTY_PENDING_PAY, PENALTY_PLATFORM_AUDIT): return Response({'code': 400, 'msg': '罚单状态不允许申诉'}, status=400) - if fadan.RejectReason: + if fadan.Status == PENALTY_PENDING_PAY and fadan.RejectReason: return Response({'code': 400, 'msg': '该罚单申诉已被驳回,不可再次申诉'}, status=400) - # 更新罚单状态为申诉中,并记录理由 - fadan.Status = 3 + if not isinstance(tupian_urls, list): + return Response({'code': 400, 'msg': '申诉图片格式错误'}, status=400) + tupian_urls = [str(u).strip() for u in tupian_urls if str(u).strip()] + if len(tupian_urls) > 9: + return Response({'code': 400, 'msg': '申诉图片最多9张'}, status=400) + + if fadan.Status == PENALTY_PENDING_PAY: + fadan.Status = PENALTY_APPEALING fadan.AppealReason = shensu_liyou fadan.save() diff --git a/utils/fadan_utils.py b/utils/fadan_utils.py index 7f3faf7..85f9221 100644 --- a/utils/fadan_utils.py +++ b/utils/fadan_utils.py @@ -1,5 +1,9 @@ # utils/fadan_utils.py from orders.models import Penalty +from utils.penalty_status import ( + PENALTY_GRAB_BLOCK_STATUSES, + PENALTY_WITHDRAW_BLOCK_STATUSES, +) import logging logger = logging.getLogger('xiaochengxu') @@ -19,11 +23,11 @@ def check_fadan_qiangdan_eligible(yonghuid: str, action_type: int) -> tuple: """ try: if action_type == 1: - # 抢单:仅当存在“影响抢单”且“未解决”的罚单时拦截(待缴纳或申诉中) + # 抢单:仅「影响抢单」且「平台审核通过后仍未结案」的罚单拦截 blocked = Penalty.objects.filter( PenalizedUserID=yonghuid, AffectsGrabbing=1, - Status__in=[1, 3] # 1=待缴纳, 3=申诉中 + Status__in=PENALTY_GRAB_BLOCK_STATUSES, ).exists() if blocked: logger.info(f"用户 {yonghuid} 抢单被拦截:存在未解决的影响抢单罚单") @@ -31,10 +35,10 @@ def check_fadan_qiangdan_eligible(yonghuid: str, action_type: int) -> tuple: return (True, "无罚单限制") elif action_type == 2: - # 提现:只要存在任意未解决的罚单(待缴纳/申诉中),不论是否影响抢单,一律禁止提现 + # 提现:平台审核中 / 待缴纳 / 申诉中 均禁止提现 blocked = Penalty.objects.filter( PenalizedUserID=yonghuid, - Status__in=[1, 3] # 1=待缴纳, 3=申诉中 + Status__in=PENALTY_WITHDRAW_BLOCK_STATUSES, ).exists() if blocked: logger.info(f"用户 {yonghuid} 提现被拦截:存在未解决的罚单") diff --git a/utils/penalty_status.py b/utils/penalty_status.py new file mode 100644 index 0000000..be39299 --- /dev/null +++ b/utils/penalty_status.py @@ -0,0 +1,21 @@ +"""金额罚单 fadan 状态常量(与 orders.models.Penalty.Status 一致)""" + +PENALTY_PENDING_PAY = 1 # 待缴纳(平台审核通过后) +PENALTY_PAID = 2 # 已缴纳 +PENALTY_APPEALING = 3 # 申诉中 +PENALTY_REJECTED = 4 # 已驳回 / 打手申诉成功 +PENALTY_PLATFORM_AUDIT = 5 # 平台审核中(商家提交后,审核通过前) + +# 影响抢单:仅平台审核通过后的未结案罚单 +PENALTY_GRAB_BLOCK_STATUSES = (PENALTY_PENDING_PAY, PENALTY_APPEALING) + +# 影响提现:含平台审核中 +PENALTY_WITHDRAW_BLOCK_STATUSES = (PENALTY_PENDING_PAY, PENALTY_APPEALING, PENALTY_PLATFORM_AUDIT) + +PENALTY_STATUS_LABELS = { + 1: '待缴纳', + 2: '已缴纳', + 3: '申诉中', + 4: '已驳回', + 5: '平台审核中', +}