|
|
@@ -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);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|