feat(shopping): 优化报价单复制功能并新增复制获取机型接口

- 在AdminShoppingController中简化返回成功数据逻辑,移除未使用的汇率处理代码
- 新增CartsForCopyVO数据结构,封装购物车ID与机型信息,用于机型列表展示
- 修改QuotationCopyRequest,调整字段命名为更符合业务语义的cartId,新增区域字段支持多区域报价
- ShoppingController中新增接口getCartsForCopy,支持根据报价单ID获取报价单中机型列表
- 重构copyQuotation方法,基于购物车ID复制报价单,完善多区域、多权限、价格有效性等校验
- 复制逻辑中优化购物车价格及配件组装,确保部件配置正确返回,提升用户体验
- 修复导出PDF时传参格式,保证导出功能稳定调用
This commit is contained in:
曹鹏飞 2026-05-21 17:33:39 +08:00
parent ebc621b23f
commit 96757d9535
4 changed files with 163 additions and 21 deletions

View File

@ -76,10 +76,7 @@ public class AdminShoppingController extends ControllerBase {
if (CollectionUtil.isEmpty(datas.getRecords())) {
return ApiResult.success(PageData.empty());
}
return ApiResult.success(datas, data -> {
//TODO 设置汇率价格
return data;
});
return ApiResult.success(datas);
}
/**

View File

@ -22,10 +22,7 @@ import com.nflg.mobilebroken.common.pojo.vo.SimpleUserVO;
import com.nflg.mobilebroken.common.util.*;
import com.nflg.mobilebroken.quotation.controller.ControllerBase;
import com.nflg.mobilebroken.quotation.pojo.request.*;
import com.nflg.mobilebroken.quotation.pojo.vo.QuotationOrderInfoVO;
import com.nflg.mobilebroken.quotation.pojo.vo.ShoppingCartPartGroupVO;
import com.nflg.mobilebroken.quotation.pojo.vo.ShoppingCartPartVO;
import com.nflg.mobilebroken.quotation.pojo.vo.ShoppingCartVO;
import com.nflg.mobilebroken.quotation.pojo.vo.*;
import com.nflg.mobilebroken.quotation.service.PdfExportService;
import com.nflg.mobilebroken.repository.entity.*;
import com.nflg.mobilebroken.repository.service.*;
@ -805,24 +802,147 @@ public class ShoppingController extends ControllerBase {
// return ApiResult.success();
// }
/**
* 报价单-获取报价单中的机型列表
*/
@GetMapping("/quotation/getCartsForCopy")
public ApiResult<List<CartsForCopyVO>> getCartsForCopy(@RequestParam Long orderId) {
QuotationShoppingOrder order = shoppingOrderService.getById(orderId);
VUtils.trueThrowBusinessError(Objects.isNull(order)).throwMessage("未找到报价单");
return ApiResult.success(shoppingOrderService.getCarts(orderId)
.stream()
.map(cart -> new CartsForCopyVO(cart.getId(), cart.getModelNo()))
.collect(Collectors.toList())
);
}
/**
* 报价单-复制报价单
*/
@PostMapping("/quotation/copy")
public ApiResult<Void> copyQuotation(@Valid @RequestBody QuotationCopyRequest request) {
QuotationShoppingOrder order = shoppingOrderService.getById(request.getId());
VUtils.trueThrowBusinessError(Objects.isNull(order)).throwMessage("未找到报价单");
List<QuotationShoppingOrderItem> orderItems = shoppingOrderItemService.lambdaQuery()
.eq(QuotationShoppingOrderItem::getOrderId, request.getId())
.list();
VUtils.trueThrowBusinessError(orderItems.size() > 1).throwMessage("多机型报价单不能复制");
QuotationShoppingCart cart = shoppingCartService.getById(orderItems.get(0).getCartId());
public ApiResult<ShoppingCartVO> copyQuotation(@Valid @RequestBody QuotationCopyRequest request) {
String qc = getQuotationCode();
VUtils.trueThrowBusinessError(StrUtil.isBlank(qc)).throwMessage("请联系管理员为您开放权限");
QuotationShoppingCart cart = shoppingCartService.getById(request.getCartId());
VUtils.trueThrowBusinessError(Objects.isNull(cart)).throwMessage("未找到数据");
VUtils.trueThrowBusinessError(priceService.getById(cart.getPriceId()).getPriceStatus() != 1)
.throwMessage("报价配置已失效");
VUtils.trueThrowBusinessError(Objects.isNull(request.getAreaId()) && isMultiRegionQuotationsUser())
.throwMessage("请选择区域");
Long categoryId = Objects.isNull(request.getAreaId()) ? getCategoryId() : request.getAreaId();
// ProductModel model = productModelService.lambdaQuery().eq(ProductModel::getState, 1).eq(ProductModel::getNo, request.getModelNo()).one();
// VUtils.trueThrowBusinessError(Objects.isNull(model)).throwMessage("未找到该机型");
VUtils.trueThrowBusinessError(AppUserUtil.isAgent() && forbidService.isForbid(cart.getModelId(), 1, request.getTargetId()))
.throwMessage("该机型已禁售");
return ApiResult.success();
// ModelPrice1VO modelPrice = priceService.getModelPrice(request.getModelId(), categoryId);
// VUtils.trueThrowBusinessError(Objects.isNull(modelPrice)).throwMessage("该机型尚未设置价格");
ShoppingCartVO vo = new ShoppingCartVO()
.setModelId(cart.getModelId())
.setTargetId(request.getTargetId())
.setCustomerName(request.getCustomerName())
.setPriceId(cart.getPriceId())
.setDefaultRatio(cart.getDefaultRatio())
.setPlanItemId(cart.getPlanItemId())
.setConfigId(cart.getConfigId())
.setDiscount(cart.getDiscount())
.setTotalFee(cart.getStandardFee().add(cart.getOptionalFee()))
.setActualFee(cart.getStandardFee().add(cart.getOptionalFee()));
// //系数
// Pair<BigDecimal, BigDecimal> pair = getRatio(request.getModelId());
// BigDecimal standardRatio = pair.getLeft(), optionalRatio = pair.getRight(), discountRatio = BigDecimal.ONE;
// log.debug("机型【{}】标准配件系数为{},可选配件系数为{}", request.getModelNo(), standardRatio, optionalRatio);
// if (AppUserUtil.isAgent()) {
// //代理商
// QuotationDiscountDTO discountDTO = discountService.getEffectiveForCustomer(request.getModelId(), request.getTargetId(), categoryId);
// if (Objects.nonNull(discountDTO)) {
// vo.setDiscountId(discountDTO.getDiscountId());
//// vo.setActualFee(vo.getTotalFee().multiply(discountDTO.getRatio()));
//// vo.setDiscount(vo.getTotalFee().subtract(vo.getActualFee()));
//// log.debug("机型【{}】打折后价格为{},优惠{}", request.getModelNo(), vo.getActualFee(), vo.getDiscount());
// discountRatio = discountDTO.getRatio();
// log.debug("机型【{}】折扣为{}", request.getModelNo(), discountRatio);
// }
// }
// if (!request.getShowLowestPrice()) {
// //方案
// QuotationUserPlanModelItem planModelItem = userPlanModelItemService.getEffectiveForUser(request.getModelId(), AppUserUtil.isAgent() ? 1 : 0, AppUserUtil.getUserId());
// if (Objects.nonNull(planModelItem)) {
// log.debug("机型【{}】方案为{},系数:{}", request.getModelNo(), planModelItem.getName(), planModelItem.getRatio());
// standardRatio = NumberUtil.multiply(standardRatio, planModelItem.getRatio());
// log.debug("机型【{}】标准配件系数为{},可选配件系数为{}", request.getModelNo(), standardRatio, optionalRatio);
// vo.setPlanItemId(planModelItem.getId());
// } else {
// QuotationUserPlanDefault userPlanDefault = userPlanDefaultService.getEffectiveForUser(AppUserUtil.isAgent() ? 1 : 0, AppUserUtil.getUserId());
// if (Objects.nonNull(userPlanDefault)) {
// vo.setDefaultRatio(userPlanDefault.getRatio());
// log.debug("用户方案默认系数为{}", userPlanDefault.getRatio());
// standardRatio = NumberUtil.multiply(standardRatio, userPlanDefault.getRatio());
// log.debug("机型【{}】标准配件系数为{},可选配件系数为{}", request.getModelNo(), standardRatio, optionalRatio);
// }
// }
// }
// vo.setTotalFee(NumberUtil.multiply(vo.getTotalFee(), standardRatio));
// vo.setActualFee(NumberUtil.multiply(vo.getTotalFee(), discountRatio));
// vo.setDiscount(vo.getTotalFee().subtract(vo.getActualFee()));
// log.debug("机型【{}】价格为{},优惠{}", request.getModelNo(), vo.getActualFee(), vo.getDiscount());
//获取部件配置
// List<ModelConfigEffectiveDTO> parts = modelConfigService.getEffectives(modelPrice.getConfigId(), modelPrice.getPriceId(), categoryId, MultilingualUtil.getLanguage());
List<ModelConfigEffectiveDTO> parts = shoppingCartItemService.getParts(cart.getId(), MultilingualUtil.getLanguage());
VUtils.trueThrowBusinessError(CollectionUtil.isEmpty(parts)).throwMessage("未获取到部件信息");
vo.setStandardParts(parts.stream()
.filter(part -> part.getParentId() == 0L && part.getType() == 1)
.map(part -> {
ShoppingCartPartVO vi = convert(part, BigDecimal.ONE);
vi.setChildren(
parts.stream()
.filter(pi -> pi.getParentId().equals(part.getId()))
.map(pi -> convert(pi, BigDecimal.ONE))
.collect(Collectors.groupingBy(ShoppingCartPartVO::getGroupName))
.entrySet()
.stream()
.map(kv -> new ShoppingCartPartGroupVO()
.setGroupName(kv.getKey())
.setItems(kv.getValue()
.stream()
.sorted(Comparator.comparing(ShoppingCartPartVO::getType).reversed())
.collect(Collectors.toList())
)
)
.sorted(Comparator.comparing(ShoppingCartPartGroupVO::getGroupName))
.collect(Collectors.toList())
);
vi.setHasSelect(true);
return vi;
}
).collect(Collectors.toList())
);
vo.setOptionalParts(parts.stream()
.filter(part -> part.getParentId() == 0L && part.getType() == 0)
.map(part -> {
ShoppingCartPartVO vi = convert(part, BigDecimal.ONE);
vi.setChildren(
parts.stream()
.filter(pi -> pi.getParentId().equals(part.getId()))
.map(pi -> convert(pi, BigDecimal.ONE))
.collect(Collectors.groupingBy(ShoppingCartPartVO::getGroupName))
.entrySet()
.stream()
.map(kv -> new ShoppingCartPartGroupVO()
.setGroupName(kv.getKey())
.setItems(kv.getValue()
.stream()
.sorted(Comparator.comparing(ShoppingCartPartVO::getType).reversed())
.collect(Collectors.toList())
)
)
.sorted(Comparator.comparing(ShoppingCartPartGroupVO::getGroupName))
.collect(Collectors.toList())
);
return vi;
}
).collect(Collectors.toList())
);
return ApiResult.success(vo);
}
/**
@ -891,7 +1011,7 @@ public class ShoppingController extends ControllerBase {
*/
@GetMapping("/export")
public void exportPdf(HttpServletResponse response, @RequestParam Long id) throws IOException {
pdfExportService.export(id,response);
pdfExportService.export(id, response);
}
/**

View File

@ -1,5 +1,6 @@
package com.nflg.mobilebroken.quotation.pojo.request;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@ -9,10 +10,10 @@ import javax.validation.constraints.NotNull;
public class QuotationCopyRequest {
/**
* 报价ID
* 购物车id
*/
@NotNull
private Long id;
private Long cartId;
/**
* 客户名称
@ -25,4 +26,9 @@ public class QuotationCopyRequest {
*/
@NotNull
private Integer targetId;
/**
* 区域国内/国外字典id
*/
private Long areaId;
}

View File

@ -0,0 +1,19 @@
package com.nflg.mobilebroken.quotation.pojo.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class CartsForCopyVO {
/**
* 购物车ID
*/
private Long cartId;
/**
* 机型
*/
private String modelNo;
}