Browse Source

新增律师处理退款接口

zhangchen 3 weeks ago
parent
commit
f60c55de96

+ 13 - 1
alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerClientConsultationOrderController.java

@@ -149,6 +149,18 @@ public class LawyerClientConsultationOrderController {
     }
 
 
-
+    @ApiOperation("退款申请处理(律师端)")
+    @ApiOperationSupport(order = 7)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "lawyerId", value = "律师ID", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "orderId", value = "订单ID", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "processAction", value = "处理动作:1-同意,2-反对", dataType = "String", paramType = "query", required = true),
+            @ApiImplicitParam(name = "rejectRefundReason", value = "拒绝退款原因", dataType = "String", paramType = "query", required = false)
+    })
+    @PostMapping("/refundApplyProcess")
+    public R<Boolean> refundApplyProcess(@RequestParam Integer lawyerId, @RequestParam Integer orderId, @RequestParam String processAction, @RequestParam String rejectRefundReason) {
+        log.info("LawyerConsultationOrderController.completeOrder?lawyerId={},orderId{},processAction{},rejectRefundReason{}", lawyerId, orderId, processAction, rejectRefundReason);
+        return lawyerClientConsultationOrderService.refundApplyProcess(lawyerId, orderId, processAction, rejectRefundReason);
+    }
 }
 

+ 12 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/LawyerClientConsultationOrderService.java

@@ -61,5 +61,17 @@ public interface LawyerClientConsultationOrderService extends IService<LawyerCon
      * @return R<Boolean> 是否成功
      */
     R<Boolean> requestRefund(Integer id, String refundReason);
+
+
+    /**
+     * 退款申请处理
+     *
+     * @param lawyerId 律师ID
+     * @param orderId 订单ID
+     * @param processAction 处理动作
+     * @param rejectRefundReason 拒绝原因
+     * @return R<Boolean> 是否成功
+     */
+    R<Boolean> refundApplyProcess(Integer lawyerId, Integer orderId, String processAction, String rejectRefundReason);
 }
 

+ 372 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerClientConsultationOrderServiceImpl.java

@@ -19,9 +19,13 @@ import shop.alien.entity.result.R;
 import shop.alien.entity.store.LawyerConsultationOrder;
 import shop.alien.entity.store.LawyerServiceArea;
 import shop.alien.entity.store.LawyerUser;
+import shop.alien.entity.store.LifeNotice;
+import shop.alien.entity.store.LifeUser;
 import shop.alien.entity.store.dto.LawyerConsultationOrderDto;
 import shop.alien.entity.store.dto.PayStatusRequest;
 import shop.alien.entity.store.vo.LawyerConsultationOrderVO;
+import shop.alien.entity.store.vo.WebSocketVo;
+import shop.alien.lawyer.config.WebSocketProcess;
 import shop.alien.lawyer.feign.AlienStoreFeign;
 import shop.alien.lawyer.service.LawyerClientConsultationOrderService;
 import shop.alien.lawyer.service.LawyerConsultationOrderService;
@@ -31,7 +35,11 @@ import shop.alien.mapper.LawyerConsultationOrderMapper;
 import shop.alien.mapper.LawyerExpertiseAreaMapper;
 import shop.alien.mapper.LawyerServiceAreaMapper;
 import shop.alien.mapper.LawyerUserMapper;
+import shop.alien.mapper.LifeNoticeMapper;
+import shop.alien.mapper.LifeUserMapper;
 import shop.alien.util.common.constant.LawyerStatusEnum;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
 
 import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
@@ -57,6 +65,39 @@ public class LawyerClientConsultationOrderServiceImpl extends ServiceImpl<Lawyer
     private final LawyerUserMapper lawyerUserMapper;
     private final OrderExpirationService orderExpirationService;
     private final AlienStoreFeign alienStoreFeign;
+    private final LifeNoticeMapper lifeNoticeMapper;
+    private final LifeUserMapper lifeUserMapper;
+    private final WebSocketProcess webSocketProcess;
+
+    /**
+     * 系统发送者ID常量
+     */
+    private static final String SYSTEM_SENDER_ID = "system";
+
+    /**
+     * 同意退款动作标识
+     */
+    private static final String ACTION_AGREE = "1";
+
+    /**
+     * 拒绝退款动作标识
+     */
+    private static final String ACTION_REJECT = "2";
+
+    /**
+     * 已申请退款状态
+     */
+    private static final String REFUND_STATUS_APPLIED = "1";
+
+    /**
+     * 律师已拒绝退款状态
+     */
+    private static final String REFUND_STATUS_REJECTED = "2";
+
+    /**
+     * 律师已同意退款状态
+     */
+    private static final String REFUND_STATUS_AGREED = "3";
 
     @Value("${order.coefficient}")
     private String coefficient;
@@ -738,5 +779,336 @@ public class LawyerClientConsultationOrderServiceImpl extends ServiceImpl<Lawyer
 
         return R.data(true, "退款申请已提交,请等待处理");
     }
+
+    /**
+     * 退款申请处理(律师端)
+     * <p>
+     * 处理退款申请前会进行以下校验:
+     * 1. 参数校验:律师ID、订单ID、处理动作不能为空
+     * 2. 订单存在性校验:订单必须存在
+     * 3. 订单归属校验:订单必须属于该律师
+     * 4. 退款状态校验:订单必须处于已申请退款状态
+     * 5. 处理动作校验:处理动作必须为同意(1)或拒绝(2)
+     * 6. 拒绝原因校验:拒绝时必须提供拒绝原因
+     * </p>
+     * <p>
+     * 处理逻辑:
+     * - 同意退款:将订单状态设置为已退款(5),申请退款状态设置为已同意(3),并发送同意通知
+     * - 拒绝退款:将申请退款状态设置为已拒绝(2),更新拒绝原因,并发送拒绝通知
+     * </p>
+     *
+     * @param lawyerId          律师ID
+     * @param orderId           订单ID
+     * @param processAction     处理动作:1-同意,2-拒绝
+     * @param rejectRefundReason 拒绝原因(拒绝时必填)
+     * @return 处理结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R<Boolean> refundApplyProcess(Integer lawyerId, Integer orderId, String processAction, String rejectRefundReason) {
+        log.info("开始处理退款申请,律师ID={}, 订单ID={}, 处理动作={}, 拒绝原因={}", 
+                lawyerId, orderId, processAction, rejectRefundReason);
+
+        // 1. 参数校验
+        if (lawyerId == null || lawyerId <= 0) {
+            log.warn("处理退款申请失败:律师ID为空或无效,lawyerId={}", lawyerId);
+            return R.fail("律师ID不能为空");
+        }
+
+        if (orderId == null || orderId <= 0) {
+            log.warn("处理退款申请失败:订单ID为空或无效,orderId={}", orderId);
+            return R.fail("订单ID不能为空");
+        }
+
+        if (!StringUtils.hasText(processAction)) {
+            log.warn("处理退款申请失败:处理动作为空,订单ID={}", orderId);
+            return R.fail("处理动作不能为空");
+        }
+
+        // 2. 处理动作校验
+        if (!ACTION_AGREE.equals(processAction) && !ACTION_REJECT.equals(processAction)) {
+            log.warn("处理退款申请失败:处理动作无效,订单ID={}, 处理动作={}", orderId, processAction);
+            return R.fail("处理动作无效,1-同意,2-拒绝");
+        }
+
+        // 3. 拒绝原因校验:拒绝时必须提供拒绝原因
+        if (ACTION_REJECT.equals(processAction) && !StringUtils.hasText(rejectRefundReason)) {
+            log.warn("处理退款申请失败:拒绝退款时必须提供拒绝原因,订单ID={}", orderId);
+            return R.fail("拒绝退款时必须提供拒绝原因");
+        }
+
+        // 4. 查询订单信息
+        LawyerConsultationOrder order = consultationOrderMapper.selectById(orderId);
+        if (order == null) {
+            log.warn("处理退款申请失败:订单不存在,订单ID={}", orderId);
+            return R.fail("订单不存在");
+        }
+
+        // 5. 订单归属校验:订单必须属于该律师
+        Integer orderLawyerId = order.getLawyerUserId();
+        if (orderLawyerId == null || !lawyerId.equals(orderLawyerId)) {
+            log.warn("处理退款申请失败:订单不属于该律师,订单ID={}, 订单律师ID={}, 请求律师ID={}", 
+                    orderId, orderLawyerId, lawyerId);
+            return R.fail("订单不属于该律师,无法处理退款申请");
+        }
+
+        // 6. 退款状态校验:订单必须处于已申请退款状态
+        String applyRefundStatus = order.getApplyRefundStatus();
+        if (!REFUND_STATUS_APPLIED.equals(applyRefundStatus)) {
+            log.warn("处理退款申请失败:订单未申请退款或已处理,订单ID={}, 订单编号={}, 退款状态={}", 
+                    orderId, order.getOrderNumber(), applyRefundStatus);
+            return R.fail("订单未申请退款或已处理,无法重复处理");
+        }
+
+        // 7. 根据处理动作进行相应处理
+        if (ACTION_AGREE.equals(processAction)) {
+            return processAgreeRefund(order);
+        } else {
+            return processRejectRefund(order, rejectRefundReason);
+        }
+    }
+
+    /**
+     * 处理同意退款
+     * <p>
+     * 1. 更新订单状态为已退款(5)
+     * 2. 更新申请退款状态为已同意(3)
+     * 3. 发送同意退款通知给申请人
+     * </p>
+     *
+     * @param order 订单对象
+     * @return 处理结果
+     */
+    private R<Boolean> processAgreeRefund(LawyerConsultationOrder order) {
+        log.info("开始处理同意退款,订单ID={}, 订单编号={}", order.getId(), order.getOrderNumber());
+
+        try {
+            // 1. 更新订单状态和退款状态
+            LambdaUpdateWrapper<LawyerConsultationOrder> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(LawyerConsultationOrder::getId, order.getId())
+                    .set(LawyerConsultationOrder::getOrderStatus, LawyerStatusEnum.REFUNDED.getStatus())
+                    .set(LawyerConsultationOrder::getApplyRefundStatus, REFUND_STATUS_AGREED)
+                    .set(LawyerConsultationOrder::getUpdatedTime, new Date());
+
+            int updateCount = consultationOrderMapper.update(null, updateWrapper);
+            if (updateCount <= 0) {
+                log.error("处理同意退款失败:更新订单状态失败,订单ID={}, 订单编号={}", 
+                        order.getId(), order.getOrderNumber());
+                return R.fail("处理同意退款失败,请稍后重试");
+            }
+
+            // 2. 发送同意退款通知给申请人
+            sendRefundAgreeNotice(order);
+
+            log.info("处理同意退款成功,订单ID={}, 订单编号={}", order.getId(), order.getOrderNumber());
+            return R.data(true, "已同意退款申请");
+        } catch (Exception e) {
+            log.error("处理同意退款异常,订单ID={}, 订单编号={}, 异常信息={}", 
+                    order.getId(), order.getOrderNumber(), e.getMessage(), e);
+            return R.fail("处理同意退款失败,请稍后重试");
+        }
+    }
+
+    /**
+     * 处理拒绝退款
+     * <p>
+     * 1. 更新申请退款状态为已拒绝(2)
+     * 2. 更新拒绝退款原因
+     * 3. 发送拒绝退款通知给申请人
+     * </p>
+     *
+     * @param order              订单对象
+     * @param rejectRefundReason 拒绝原因
+     * @return 处理结果
+     */
+    private R<Boolean> processRejectRefund(LawyerConsultationOrder order, String rejectRefundReason) {
+        log.info("开始处理拒绝退款,订单ID={}, 订单编号={}, 拒绝原因={}", 
+                order.getId(), order.getOrderNumber(), rejectRefundReason);
+
+        try {
+            // 1. 更新订单退款状态和拒绝原因
+            LambdaUpdateWrapper<LawyerConsultationOrder> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(LawyerConsultationOrder::getId, order.getId())
+                    .set(LawyerConsultationOrder::getApplyRefundStatus, REFUND_STATUS_REJECTED)
+                    .set(LawyerConsultationOrder::getRejectRefundReason, rejectRefundReason)
+                    .set(LawyerConsultationOrder::getUpdatedTime, new Date());
+
+            int updateCount = consultationOrderMapper.update(null, updateWrapper);
+            if (updateCount <= 0) {
+                log.error("处理拒绝退款失败:更新订单状态失败,订单ID={}, 订单编号={}", 
+                        order.getId(), order.getOrderNumber());
+                return R.fail("处理拒绝退款失败,请稍后重试");
+            }
+
+            // 2. 发送拒绝退款通知给申请人
+            sendRefundRejectNotice(order, rejectRefundReason);
+
+            log.info("处理拒绝退款成功,订单ID={}, 订单编号={}", order.getId(), order.getOrderNumber());
+            return R.data(true, "已拒绝退款申请");
+        } catch (Exception e) {
+            log.error("处理拒绝退款异常,订单ID={}, 订单编号={}, 异常信息={}", 
+                    order.getId(), order.getOrderNumber(), e.getMessage(), e);
+            return R.fail("处理拒绝退款失败,请稍后重试");
+        }
+    }
+
+    /**
+     * 发送同意退款通知给申请人
+     *
+     * @param order 订单对象
+     */
+    private void sendRefundAgreeNotice(LawyerConsultationOrder order) {
+        try {
+            Integer clientUserId = order.getClientUserId();
+            if (clientUserId == null) {
+                log.warn("发送同意退款通知失败:客户端用户ID为空,订单ID={}", order.getId());
+                return;
+            }
+
+            // 获取申请人接收ID
+            String receiverId = getClientReceiverId(clientUserId);
+            if (!StringUtils.hasText(receiverId)) {
+                log.warn("发送同意退款通知失败:获取申请人接收ID失败,订单ID={}, 用户ID={}", 
+                        order.getId(), clientUserId);
+                return;
+            }
+
+            // 构建通知消息
+            String orderNumber = order.getOrderNumber() != null ? order.getOrderNumber() : "";
+            String message = String.format("您的编号为%s的订单,律师已同意您的退款申请,订单金额将在1-3个工作日原路返还,请注意查收。", 
+                    orderNumber);
+
+            // 创建并保存通知
+            LifeNotice lifeNotice = createRefundNotice(order.getId(), receiverId, "退款申请处理通知", message);
+            int noticeResult = lifeNoticeMapper.insert(lifeNotice);
+            if (noticeResult <= 0) {
+                log.warn("发送同意退款通知失败:保存通知失败,订单ID={}", order.getId());
+                return;
+            }
+
+            // 发送WebSocket消息
+            sendWebSocketMessage(receiverId, lifeNotice);
+
+            log.info("发送同意退款通知成功,接收人ID={}, 订单编号={}", receiverId, orderNumber);
+        } catch (Exception e) {
+            log.error("发送同意退款通知异常,订单ID={}, 异常信息={}", order.getId(), e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 发送拒绝退款通知给申请人
+     *
+     * @param order              订单对象
+     * @param rejectRefundReason 拒绝原因
+     */
+    private void sendRefundRejectNotice(LawyerConsultationOrder order, String rejectRefundReason) {
+        try {
+            Integer clientUserId = order.getClientUserId();
+            if (clientUserId == null) {
+                log.warn("发送拒绝退款通知失败:客户端用户ID为空,订单ID={}", order.getId());
+                return;
+            }
+
+            // 获取申请人接收ID
+            String receiverId = getClientReceiverId(clientUserId);
+            if (!StringUtils.hasText(receiverId)) {
+                log.warn("发送拒绝退款通知失败:获取申请人接收ID失败,订单ID={}, 用户ID={}", 
+                        order.getId(), clientUserId);
+                return;
+            }
+
+            // 构建通知消息
+            String orderNumber = order.getOrderNumber() != null ? order.getOrderNumber() : "";
+            String rejectReason = StringUtils.hasText(rejectRefundReason) ? rejectRefundReason : "无";
+            String message = String.format("您的编号为%s的订单,律师已拒绝您的退款申请。拒绝原因:%s。如您仍有疑问,可通过举报的方式提交平台审核", 
+                    orderNumber, rejectReason);
+
+            // 创建并保存通知
+            LifeNotice lifeNotice = createRefundNotice(order.getId(), receiverId, "退款申请处理通知", message);
+            int noticeResult = lifeNoticeMapper.insert(lifeNotice);
+            if (noticeResult <= 0) {
+                log.warn("发送拒绝退款通知失败:保存通知失败,订单ID={}", order.getId());
+                return;
+            }
+
+            // 发送WebSocket消息
+            sendWebSocketMessage(receiverId, lifeNotice);
+
+            log.info("发送拒绝退款通知成功,接收人ID={}, 订单编号={}", receiverId, orderNumber);
+        } catch (Exception e) {
+            log.error("发送拒绝退款通知异常,订单ID={}, 异常信息={}", order.getId(), e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 获取客户端用户接收ID
+     *
+     * @param clientUserId 客户端用户ID
+     * @return 接收人ID,格式:user_ + 手机号
+     */
+    private String getClientReceiverId(Integer clientUserId) {
+        if (clientUserId == null || clientUserId <= 0) {
+            log.warn("获取客户端用户接收ID失败:用户ID为空或无效");
+            return null;
+        }
+
+        try {
+            LifeUser lifeUser = lifeUserMapper.selectById(clientUserId);
+            if (lifeUser != null && StringUtils.hasText(lifeUser.getUserPhone())) {
+                return "user_" + lifeUser.getUserPhone();
+            }
+        } catch (Exception e) {
+            log.error("获取客户端用户手机号异常,用户ID={}, 异常信息={}", clientUserId, e.getMessage(), e);
+        }
+
+        log.warn("获取客户端用户手机号失败,用户ID={}", clientUserId);
+        return null;
+    }
+
+    /**
+     * 创建退款通知对象
+     *
+     * @param businessId 业务ID(订单ID)
+     * @param receiverId 接收人ID
+     * @param title      通知标题
+     * @param message    通知消息
+     * @return 通知对象
+     */
+    private LifeNotice createRefundNotice(Integer businessId, String receiverId, String title, String message) {
+        LifeNotice lifeNotice = new LifeNotice();
+        lifeNotice.setSenderId(SYSTEM_SENDER_ID);
+        lifeNotice.setBusinessId(businessId);
+        lifeNotice.setReceiverId(receiverId);
+        lifeNotice.setTitle(title);
+        lifeNotice.setNoticeType(1);
+        lifeNotice.setIsRead(0);
+
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("message", message);
+        lifeNotice.setContext(jsonObject.toJSONString());
+
+        return lifeNotice;
+    }
+
+    /**
+     * 发送WebSocket消息
+     *
+     * @param receiverId 接收人ID
+     * @param lifeNotice 通知对象
+     */
+    private void sendWebSocketMessage(String receiverId, LifeNotice lifeNotice) {
+        try {
+            WebSocketVo webSocketVo = new WebSocketVo();
+            webSocketVo.setSenderId(SYSTEM_SENDER_ID);
+            webSocketVo.setReceiverId(receiverId);
+            webSocketVo.setCategory("notice");
+            webSocketVo.setNoticeType("1");
+            webSocketVo.setIsRead(0);
+            webSocketVo.setText(JSON.toJSONString(lifeNotice));
+            webSocketProcess.sendMessage(receiverId, JSON.toJSONString(webSocketVo));
+        } catch (Exception e) {
+            log.error("发送WebSocket消息异常,接收人ID={}, 异常信息={}", receiverId, e.getMessage(), e);
+        }
+    }
 }