batch_20260710 超长导致762单全部失败;与客服手机号字段一致。 Co-authored-by: Cursor <cursoragent@cursor.com>
148 lines
5.5 KiB
Python
148 lines
5.5 KiB
Python
"""商家发单退款审核通过(与 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'
|