diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/controller/mobile/UserReturnController.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/controller/mobile/UserReturnController.java
index 5fa657ae..17048bbb 100644
--- a/mall-shop/src/main/java/com/suisung/mall/shop/order/controller/mobile/UserReturnController.java
+++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/controller/mobile/UserReturnController.java
@@ -1,6 +1,8 @@
package com.suisung.mall.shop.order.controller.mobile;
import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.api.ResultCode;
@@ -15,10 +17,7 @@ import com.suisung.mall.shop.order.vo.OrderReturnVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
/**
*
@@ -57,7 +56,7 @@ public class UserReturnController extends BaseControllerImpl {
return shopOrderReturnService.returnItem();
}
- @ApiOperation(value = "添加退款退货-部分退货,卖家也可以决定不退货退款,买家申请退款不支持。卖家可以主动退款。", notes = "添加退款退货-发货退货,卖家也可以决定不退货退款,买家申请退款不支持。卖家可以主动退款。")
+ @ApiOperation(value = "添加退款退货-部分退货", notes = "添加退款退货-发货退货,卖家也可以决定不退货退款,买家申请退款不支持。卖家可以主动退款。")
@RequestMapping(value = "/addItem", method = RequestMethod.GET)
public CommonResult addItem(OrderReturnVo orderReturnVo) {
UserDto user = getCurrentUser();
@@ -77,6 +76,26 @@ public class UserReturnController extends BaseControllerImpl {
return shopOrderReturnService.addItem(orderReturnInputVo, true);
}
+ @ApiOperation(value = "批量添加退款退货(支持多个商品)", notes = "添加退款退货-发货退货,卖家也可以决定不退货退款,买家申请退款不支持。卖家可以主动退款。")
+ @RequestMapping(value = "/addItemBatch", method = RequestMethod.POST)
+ public CommonResult addItemBatch(@RequestBody JSONObject orderReturnVoJSON) {
+ if (orderReturnVoJSON == null) {
+ return CommonResult.failed("请求参数不能为空");
+ }
+
+ OrderReturnInputVo orderReturnInputVo = JSONUtil.toBean(orderReturnVoJSON, OrderReturnInputVo.class);
+ if (orderReturnInputVo == null) {
+ return CommonResult.failed("请求参数格式不正确");
+ }
+
+ UserDto user = getCurrentUser();
+ if (user == null) {
+ return CommonResult.failed(ResultCode.NEED_LOGIN);
+ }
+
+ return shopOrderReturnService.tryAddItemBatch(orderReturnInputVo);
+ }
+
@ApiOperation(value = "添加退款退货-整单退货", notes = "添加退款退货-整单退货")
@RequestMapping(value = "/addWholeItems", method = RequestMethod.POST)
public CommonResult addWholeItems(@RequestParam(name = "order_id") String order_id) {
diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderReturnService.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderReturnService.java
index e00dcb59..e6a428c3 100644
--- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderReturnService.java
+++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderReturnService.java
@@ -50,6 +50,14 @@ public interface ShopOrderReturnService extends IBaseService {
*/
CommonResult addItem(OrderReturnInputVo orderReturnInputVo, Boolean needSendMsg);
+ /**
+ * 尝试批量添加退款退货申请(自动使用最大可退数量和金额),等待商家审核处理(同意或不同意)
+ *
+ * @param orderReturnInputVo 退款申请输入参数,支持订单多个商品退款
+ * @return CommonResult 退款申请结果
+ */
+ CommonResult tryAddItemBatch(OrderReturnInputVo orderReturnInputVo);
+
Map getReturnDetail(String return_id);
boolean processReviewList(ShopOrderReturn shopOrderReturn, Integer receiving_address);
diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java
index f6fbb494..87046f57 100644
--- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java
+++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java
@@ -4167,11 +4167,12 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl order_return_items = orderReturnItemService.find(returnItemQueryWrapper);
-
if (CollUtil.isNotEmpty(order_return_items)) {
throw new ApiException(I18nUtil._("此订单商品正在退款审核!"));
}
@@ -568,17 +568,16 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl available_return_num) {
throw new ApiException(String.format("商品 %s 的退款数量超过可退数量,最多可退 %d 件",
shopOrderItem.getItem_name(), available_return_num));
@@ -650,6 +649,208 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl data = new HashMap<>();
+
+ // 获取用户ID
+ Integer user_id = orderReturnInputVo.getUser_id();
+ if (CheckUtil.isEmpty(user_id)) {
+ UserDto user = getCurrentUser();
+ if (user == null) {
+ throw new ApiUserException(I18nUtil._("用户信息异常!"));
+ }
+ user_id = user.getId();
+ }
+
+ // 获取买家店铺ID(如果有)
+ Integer buyer_store_id = shopStoreBaseService.getStoreId(user_id);
+
+ // 获取订单信息
+ String order_id = orderReturnInputVo.getOrder_id();
+ List order_item_ids = orderReturnInputVo.getReturn_items().stream()
+ .map(OrderReturnItemInputVo::getOrder_item_id)
+ .distinct()
+ .collect(Collectors.toList());
+
+ ShopOrderInfo shopOrderInfo = shopOrderInfoService.get(order_id);
+ if (shopOrderInfo == null) {
+ throw new ApiException(I18nUtil._("此订单信息数据有误!"));
+ }
+
+ ShopOrderBase orderBase = shopOrderBaseService.get(order_id);
+ if (orderBase == null) {
+ throw new ApiException(I18nUtil._("此订单详细信息数据有误!"));
+ }
+
+ // 判断此订单商品是否有正在审核的退款单
+ QueryWrapper returnQueryWrapper = new QueryWrapper<>();
+ returnQueryWrapper.eq("order_id", order_id)
+ .eq("return_state_id", StateCode.RETURN_PROCESS_CHECK);
+ List order_return_rows = find(returnQueryWrapper);
+
+ if (CollUtil.isNotEmpty(order_return_rows)) {
+ List return_ids = order_return_rows.stream()
+ .map(ShopOrderReturn::getReturn_id)
+ .collect(Collectors.toList());
+
+ QueryWrapper returnItemQueryWrapper = new QueryWrapper<>();
+ returnItemQueryWrapper.in("order_item_id", order_item_ids)
+ .in("return_id", return_ids);
+ List order_return_items = orderReturnItemService.find(returnItemQueryWrapper);
+ if (CollUtil.isNotEmpty(order_return_items)) {
+ throw new ApiException(I18nUtil._("此订单商品正在退款审核!"));
+ }
+ }
+
+ // 检查数据权限
+ if (!CheckUtil.checkDataRights(user_id, orderBase, ShopOrderBase::getBuyer_user_id)) {
+ throw new ApiException(ResultCode.FORBIDDEN);
+ }
+
+ // 获取退款申请参数
+ String return_id = orderReturnInputVo.getReturn_id();
+ Integer return_reason_id = orderReturnInputVo.getReturn_reason_id() == null ? 0 : orderReturnInputVo.getReturn_reason_id();
+ String return_buyer_message = orderReturnInputVo.getReturn_buyer_message();
+ Integer store_id = Convert.toInt(orderBase.getStore_id());
+ String return_tel = orderReturnInputVo.getReturn_tel();
+
+ // 手机号验证
+ if (StrUtil.isNotBlank(return_tel) && !PhoneUtil.isMobile(return_tel)) {
+ throw new ApiException(I18nUtil._("手机号输入有误!"));
+ }
+
+ Date curTime = new Date();
+
+ // 构建退款单主表信息
+ ShopOrderReturn orderReturn = new ShopOrderReturn();
+ orderReturn.setReturn_id(return_id);
+ orderReturn.setOrder_id(order_id);
+ orderReturn.setBuyer_user_id(user_id);
+ orderReturn.setBuyer_store_id(buyer_store_id);
+ orderReturn.setReturn_reason_id(return_reason_id);
+ orderReturn.setReturn_buyer_message(return_buyer_message);
+ orderReturn.setStore_id(store_id);
+ orderReturn.setReturn_refund_amount(BigDecimal.ZERO);
+ orderReturn.setReturn_commision_fee(BigDecimal.ZERO);
+ orderReturn.setReturn_state_id(StateCode.RETURN_PROCESS_CHECK);
+ orderReturn.setReturn_tel(return_tel);
+ orderReturn.setReturn_year(DateUtil.year(curTime)); // 退单年份-索引查询
+ orderReturn.setReturn_month(DateUtil.month(curTime) + 1); // 退单月份-索引查询
+ orderReturn.setReturn_day(DateUtil.dayOfMonth(curTime)); // 退单日-索引查询
+ orderReturn.setReturn_reason_id(0); // 注意:这里覆盖了前面设置的return_reason_id
+ orderReturn.setReturn_store_user_id(0);
+ orderReturn.setReturn_mobile(0L);
+ orderReturn.setReturn_telephone("");
+ orderReturn.setSubsite_id(shopOrderInfo.getSubsite_id());
+
+ // 构建退款单明细信息
+ List shopOrderReturnItems = new ArrayList<>();
+ for (OrderReturnItemInputVo returnItemInputVo : orderReturnInputVo.getReturn_items()) {
+ // 获取订单商品信息
+ ShopOrderItem shopOrderItem = shopOrderItemService.get(returnItemInputVo.getOrder_item_id());
+ if (shopOrderItem == null) {
+ throw new ApiException("订单商品不存在,请检查商品ID是否正确: " + returnItemInputVo.getOrder_item_id());
+ }
+
+ // 验证是否为当前订单的商品
+ if (!order_id.equals(shopOrderItem.getOrder_id())) {
+ throw new ApiException("商品ID " + returnItemInputVo.getOrder_item_id() + " 不属于订单 " + order_id);
+ }
+
+ // 获取商品索引信息
+ ShopProductIndex shopProductIndex = shopProductIndexService.get(shopOrderItem.getProduct_id());
+ if (shopProductIndex == null) {
+ throw new ApiException("商品信息不存在,请检查商品ID是否正确: " + shopOrderItem.getProduct_id());
+ }
+
+ // 检查是否允许退货
+ boolean is_denyreturn = ifDenyReturn(shopOrderInfo, shopOrderItem, shopProductIndex);
+ if (is_denyreturn) {
+ // 获取更详细的拒绝退货原因
+ String denyReason = getDenyReturnReason(shopOrderInfo, shopOrderItem, shopProductIndex);
+ if (StrUtil.isBlank(denyReason)) {
+ denyReason = "此商品不允许退货!";
+ }
+ throw new ApiException(denyReason);
+ }
+
+ // 构建退款单明细
+ ShopOrderReturnItem orderReturnItem = new ShopOrderReturnItem();
+
+ // 检查退款数量是否超过可退数量
+ Integer order_item_quantity = shopOrderItem.getOrder_item_quantity(); // 订单中该商品的原始购买数量
+ Integer order_item_return_agree_num = ObjectUtil.defaultIfNull(shopOrderItem.getOrder_item_return_agree_num(), 0); // 订单中该商品已经同意退货的数量
+ Integer available_return_num = order_item_quantity - order_item_return_agree_num; // 当前还可以申请退款的商品数量
+ if (available_return_num <= 0) {
+ throw new ApiException(String.format("商品 %s 已无可退数量", shopOrderItem.getItem_name()));
+ }
+
+ // 检查退款金额是否合理
+ BigDecimal order_item_payment_amount = shopOrderItem.getOrder_item_payment_amount();
+ BigDecimal order_item_return_agree_amount = ObjectUtil.defaultIfNull(shopOrderItem.getOrder_item_return_agree_amount(), BigDecimal.ZERO);
+ BigDecimal available_return_amount = order_item_payment_amount.subtract(order_item_return_agree_amount);
+ if (available_return_amount.compareTo(BigDecimal.ZERO) <= 0) {
+ throw new ApiException(String.format("商品 %s 已无可退金额", shopOrderItem.getItem_name()));
+ }
+
+ String return_item_image = ObjectUtil.defaultIfBlank(
+ orderReturnInputVo.getRefund_pic(),
+ orderReturnInputVo.getUpload_img());
+
+ orderReturnItem.setOrder_item_id(returnItemInputVo.getOrder_item_id());
+ orderReturnItem.setOrder_id(order_id);
+ orderReturnItem.setReturn_item_num(available_return_num);
+ orderReturnItem.setReturn_item_subtotal(available_return_amount);
+ orderReturnItem.setReturn_reason_id(return_reason_id);
+ orderReturnItem.setReturn_item_note(return_buyer_message);
+ orderReturnItem.setReturn_item_image(return_item_image);
+ orderReturnItem.setReturn_state_id(StateCode.RETURN_PROCESS_CHECK);
+
+ shopOrderReturnItems.add(orderReturnItem);
+ }
+
+ // 保存退款单
+ if (!addReturnByItem(orderReturn, shopOrderReturnItems)) {
+ throw new ApiException(ResultCode.FAILED);
+ }
+
+ data.put("return", orderReturn);
+ data.put("items", shopOrderReturnItems);
+
+ // 打票机打印退款订单到店(异步执行)
+ shopStorePrinterService.printShopStoreReturnOrder(return_id);
+
+ // 发送消息通知, 退款提醒商家
+ String message_id = "refund-reminder";
+ Map args = new HashMap<>();
+ args.put("order_id", orderReturn.getReturn_id());
+ messageService.sendNoticeMsg(0, store_id, message_id, args);
+
+ // 发送unipush消息
+ String title = "您有一个退款的订单,请及时前往后台审核!";
+ String content = String.format("订单号:%s 退单号:[%s],时间:%s,请及时前往后台审核!",
+ order_id, orderReturn.getReturn_id(),
+ DateTimeUtils.formatDateTime(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
+ JSONObject payload = JSONUtil.createObj();
+ payload.set("category", CommonConstant.PUSH_MSG_CATE_MCH_RETURN_ORDER_LIST);
+ payload.set("orderId", order_id);
+ payload.set("returnId", orderReturn.getReturn_id());
+ pushMessageService.noticeMerchantEmployeeOrderAction(store_id, order_id, title, content, payload);
+
+ data.put("order_item_ids", order_item_ids);
+ return CommonResult.success(data);
+ }
+
/**
* 取消退货
@@ -3099,4 +3300,116 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl availableReturnNum) {
+ if (!autoCorrect) {
+ throw new ApiException(String.format("商品 %s 的退款数量超过可退数量,最多可退 %d 件",
+ shopOrderItem.getItem_name(), availableReturnNum));
+ }
+
+ // 按比例调整退款金额
+ BigDecimal ratio = BigDecimal.valueOf(availableReturnNum)
+ .divide(BigDecimal.valueOf(requestReturnNum), 6, RoundingMode.HALF_UP);
+ BigDecimal correctedAmount = requestRefundAmount.multiply(ratio);
+ return new BigDecimal[]{BigDecimal.valueOf(availableReturnNum), correctedAmount};
+ }
+
+ // 校验并处理请求退款金额是否超过可退金额
+ if (requestRefundAmount.compareTo(availableReturnAmount) > 0) {
+ if (!autoCorrect) {
+ throw new ApiException(String.format("商品 %s 的退款金额超过可退金额,最多可退 %.2f 元",
+ shopOrderItem.getItem_name(), availableReturnAmount));
+ }
+ return new BigDecimal[]{BigDecimal.valueOf(requestReturnNum), availableReturnAmount};
+ }
+
+ return new BigDecimal[]{BigDecimal.valueOf(requestReturnNum), requestRefundAmount};
+ }
+
+ /**
+ * 校验退款商品数量是否有效(专用于仅校验数量的场景)
+ *
+ * @param shopOrderItem 订单商品项
+ * @param requestReturnNum 请求退款数量
+ * @param autoCorrect 是否自动纠正数量(false:超出时抛出异常, true:超出时自动调整为最大可退数量)
+ * @return 校验后的有效退款数量
+ * @throws ApiException 当autoCorrect为false且请求数量超出可退数量时抛出异常
+ */
+ private Integer validateReturnQuantity(ShopOrderItem shopOrderItem, Integer requestReturnNum, boolean autoCorrect) {
+ // 校验请求参数有效性
+ if (requestReturnNum <= 0) {
+ throw new ApiException("退款数量必须大于0,请检查商品 " + shopOrderItem.getItem_name() + " 的退款数量");
+ }
+
+ // 计算可退数量
+ Integer orderItemQuantity = shopOrderItem.getOrder_item_quantity();
+ Integer orderItemReturnAgreeNum = ObjectUtil.defaultIfNull(shopOrderItem.getOrder_item_return_agree_num(), 0);
+ Integer availableReturnNum = orderItemQuantity - orderItemReturnAgreeNum;
+
+ // 检查是否还有可退数量
+ if (availableReturnNum <= 0) {
+ if (autoCorrect) {
+ return 0;
+ }
+ throw new ApiException(String.format("商品 %s 已无可退数量,无法申请退款", shopOrderItem.getItem_name()));
+ }
+
+ // 校验并处理请求退款数量是否超过可退数量
+ if (requestReturnNum > availableReturnNum) {
+ if (!autoCorrect) {
+ throw new ApiException(String.format("商品 %s 的退款数量超过可退数量,最多可退 %d 件",
+ shopOrderItem.getItem_name(), availableReturnNum));
+ }
+ return availableReturnNum;
+ }
+
+ return requestReturnNum;
+ }
+
+
}
\ No newline at end of file