Files
Django/orders/services/merchant_refund_approve.py
XingQue 6689b7af00 fix: 批量退款处理人ID默认138377,限制chuliid最长11位
batch_20260710 超长导致762单全部失败;与客服手机号字段一致。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 23:21:23 +08:00

148 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""商家发单退款审核通过(与 KefuMerchantRefundView / 后台同意退款业务一致)。"""
import logging
from decimal import Decimal
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from backend.utils import update_dashou_daily_by_action, update_shangjia_daily
from orders.models import Order, RefundRecord
from users.business_models import User
logger = logging.getLogger(__name__)
# tuikuanjilu.chuliid / RefundRecord.ProcessorID 数据库列最长 11
PROCESSOR_ID_MAX_LEN = 11
def normalize_processor_id(processor_id, *, default='138377'):
"""处理人 ID 须 <=11 位(与客服手机号字段一致),超长则截断。"""
val = (processor_id or default or '').strip()
if not val:
val = default
if len(val) > PROCESSOR_ID_MAX_LEN:
logger.warning(
'processor_id 超长已截断: %s -> %s',
val, val[:PROCESSOR_ID_MAX_LEN],
)
val = val[:PROCESSOR_ID_MAX_LEN]
return val
class MerchantRefundApproveError(Exception):
"""单笔商家退款同意失败。"""
def approve_merchant_refund_order(
order,
*,
processor_id='138377',
tuikuan_liyou='',
require_status_4=True,
):
"""
同意商家发单退款Platform=2
与 POST /yonghu/kefusjtk 核心事务一致:
- 订单 Status → 5已退款
- 打手 tuikuanliang+1、zhuangtai=1
- 商家 tuikuan+1、余额+订单金额(子客服额度单除外)
- RefundRecord ApplyStatus → 1
- update_shangjia_daily(action=3)、update_dashou_daily_by_action(action=3)
返回 (True, 'ok');失败抛 MerchantRefundApproveError。
"""
dingdan_id = order.OrderID
processor_id = normalize_processor_id(processor_id)
if order.Platform != 2:
raise MerchantRefundApproveError(f'订单 {dingdan_id} 不是商家发单(Platform=2)')
if require_status_4 and order.Status != 4:
raise MerchantRefundApproveError(
f'订单 {dingdan_id} 状态={order.Status},非退款审核中(4)',
)
if not require_status_4 and order.Status not in (1, 7, 2, 8, 4):
raise MerchantRefundApproveError(
f'订单 {dingdan_id} 状态={order.Status},不允许退款',
)
jine = order.Amount
if jine is None:
raise MerchantRefundApproveError(f'订单 {dingdan_id} 缺少订单金额')
try:
shangjia_id = order.shangjia_kuozhan.MerchantID
except ObjectDoesNotExist as exc:
raise MerchantRefundApproveError(f'订单 {dingdan_id} 缺少商家扩展信息') from exc
jiedan_dashou_id = order.PlayerID
with transaction.atomic():
locked = Order.objects.select_for_update().select_related('shangjia_kuozhan').get(
pk=order.pk,
)
if require_status_4 and locked.Status != 4:
raise MerchantRefundApproveError(
f'订单 {dingdan_id} 并发冲突:当前状态={locked.Status}',
)
if locked.Platform != 2:
raise MerchantRefundApproveError(f'订单 {dingdan_id} 不是商家发单')
locked.Status = 5
if tuikuan_liyou:
locked.RefundReason = tuikuan_liyou
if processor_id:
locked.AssignedCS = processor_id
locked.save(update_fields=['Status', 'RefundReason', 'AssignedCS', 'UpdateTime'])
if jiedan_dashou_id:
try:
dashou_user = User.objects.select_for_update().get(UserUID=jiedan_dashou_id)
dashou_profile = dashou_user.DashouProfile
dashou_profile.tuikuanliang += 1
dashou_profile.zhuangtai = 1
dashou_profile.save(update_fields=['tuikuanliang', 'zhuangtai'])
except (User.DoesNotExist, ObjectDoesNotExist):
logger.warning('商家退款:打手 %s 不存在,跳过', jiedan_dashou_id)
from merchant_ops.services.wallet import is_staff_quota_order
try:
shangjia_user = User.objects.select_for_update().get(UserUID=shangjia_id)
shangjia_profile = shangjia_user.ShopProfile
shangjia_profile.tuikuan += 1
if not is_staff_quota_order(dingdan_id):
shangjia_profile.yue += jine
shangjia_profile.save(update_fields=['tuikuan', 'yue'])
except (User.DoesNotExist, ObjectDoesNotExist):
logger.warning('商家退款:商家 %s 不存在,跳过', shangjia_id)
try:
refund_record = RefundRecord.objects.select_for_update().get(OrderID=dingdan_id)
refund_record.ApplyStatus = 1
refund_record.ProcessorID = processor_id
refund_record.save(update_fields=['ApplyStatus', 'ProcessorID', 'UpdateTime'])
except RefundRecord.DoesNotExist:
logger.warning('商家退款:订单 %s 无 RefundRecord跳过更新', dingdan_id)
update_shangjia_daily(
yonghuid=shangjia_id,
amount=Decimal(str(jine)),
action=3,
order_id=dingdan_id,
)
if jiedan_dashou_id and order.PlayerCommission is not None:
try:
update_dashou_daily_by_action(
yonghuid=jiedan_dashou_id,
amount=order.PlayerCommission,
action=3,
)
except Exception as exc:
logger.error('打手每日统计更新失败 order=%s err=%s', dingdan_id, exc)
logger.info('同意商家退款成功 order=%s processor=%s', dingdan_id, processor_id)
return True, 'ok'