From 531b3b2932368c4cfac49928cf6ae760d8432acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=B9=E9=B9=8F=E9=A3=9E?= Date: Tue, 17 Mar 2026 10:15:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(quotation):=20=E6=B7=BB=E5=8A=A0=E9=9A=8F?= =?UTF-8?q?=E6=9C=BA=E9=85=8D=E4=BB=B6=E5=92=8C=E4=BA=A4=E6=9C=BA=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在PDF模板中添加表格样式和随机配件、交机服务表格展示 - 新增备件总价字段到购物车配件实体类 - 设置购物车VO默认系数为BigDecimal.ONE - 调整价格计算逻辑,添加折扣率处理 - 保存购物车数据到数据库 - 添加币种和汇率一致性校验 - 更新PDF导出功能的文档设置方法 - 为配件和服务请求类添加数据验证注解 - 设置配件费和服务费默认值为零 - 修改币种验证从NotBlank为NotNull - 为配件和服务列表添加@Valid注解进行嵌套验证 --- .../controller/app/ShoppingController.java | 47 +++++++++++-------- .../request/ShoppingSaveAccessoryRequest.java | 6 +++ .../pojo/request/ShoppingSaveRequest.java | 13 +++-- .../request/ShoppingSaveServiceRequest.java | 5 ++ .../quotation/pojo/vo/ShoppingCartVO.java | 2 +- .../src/main/resources/templates/pdf.html | 44 ++++++++++++++++- .../QuotationShoppingCartAccessory.java | 5 ++ 7 files changed, 95 insertions(+), 27 deletions(-) diff --git a/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/controller/app/ShoppingController.java b/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/controller/app/ShoppingController.java index 634c8cea..1fe69b5e 100644 --- a/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/controller/app/ShoppingController.java +++ b/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/controller/app/ShoppingController.java @@ -173,20 +173,22 @@ public class ShoppingController extends ControllerBase { .setTotalFee(modelPrice.getAmount()) .setActualFee(modelPrice.getAmount()); log.debug("机型【{}】售价为{}", request.getModelNo(), modelPrice); + //系数 + Pair 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()); +// 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); } } - //系数 - Pair pair = getRatio(request.getModelId()); - BigDecimal standardRatio = pair.getLeft(), optionalRatio = pair.getRight(); - log.debug("机型【{}】标准配件系数为{},可选配件系数为{}", request.getModelNo(), standardRatio, optionalRatio); if (!request.getShowLowestPrice()) { //方案 QuotationUserPlanModelItem planModelItem = userPlanModelItemService.getEffectiveForUser(request.getModelId(), AppUserUtil.isAgent() ? 1 : 0, AppUserUtil.getUserId()); @@ -198,13 +200,16 @@ public class ShoppingController extends ControllerBase { } 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.setActualFee(vo.getTotalFee().subtract(vo.getDiscount()).multiply(standardRatio)); + 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 parts = modelConfigService.getEffectives(modelPrice.getPriceId(), categoryId, MultilingualUtil.getLanguage()); @@ -305,6 +310,7 @@ public class ShoppingController extends ControllerBase { ).collect(Collectors.toList()) ); } + shoppingCartService.save(cart); return ApiResult.success(cartId); } @@ -368,6 +374,10 @@ public class ShoppingController extends ControllerBase { .throwMessage("客户名称不一致"); VUtils.trueThrowBusinessError(carts.stream().map(QuotationShoppingCart::getTargetId).collect(Collectors.toSet()).size() > 1) .throwMessage("报价对象不一致"); + VUtils.trueThrowBusinessError(carts.stream().map(QuotationShoppingCart::getCurrency).collect(Collectors.toSet()).size() > 1) + .throwMessage("币种不一致"); + VUtils.trueThrowBusinessError(carts.stream().map(QuotationShoppingCart::getExchangeRate).collect(Collectors.toSet()).size() > 1) + .throwMessage("汇率不一致"); QuotationShoppingOrder order = new QuotationShoppingOrder() .setCreateByType(AppUserUtil.isAgent() ? 1 : 0) .setCreateBy(AppUserUtil.getUserName()) @@ -538,23 +548,22 @@ public class ShoppingController extends ControllerBase { // * 报价单-复制报价单 // */ // @PostMapping("/quotation/copy") -// public ApiResult copyQuotation(@Valid @RequestBody QuotationCopyRequest request){ +// public ApiResult copyQuotation(@Valid @RequestBody QuotationCopyRequest request) { // QuotationShoppingOrder order = shoppingOrderService.getById(request.getId()); // VUtils.trueThrowBusinessError(Objects.isNull(order)).throwMessage("未找到报价单"); // List orderItems = shoppingOrderItemService.lambdaQuery() // .eq(QuotationShoppingOrderItem::getOrderId, request.getId()) // .list(); -// List carts = shoppingCartService.lambdaQuery() -// .in(QuotationShoppingCart::getId, orderItems.stream().map(QuotationShoppingOrderItem::getCartId).collect(Collectors.toList())) -// .list(); +// VUtils.trueThrowBusinessError(orderItems.size() > 1).throwMessage("多机型报价单不能复制"); +// QuotationShoppingCart cart = shoppingCartService.getById(orderItems.get(0).getCartId()); // ShoppingCartVO vo = new ShoppingCartVO() -// .setModelId(request.getModelId()) +// .setModelId(cart.getModelId()) // .setTargetId(request.getTargetId()) // .setCustomerName(request.getCustomerName()) -// .setPriceId(modelPrice.getPriceId()) -// .setConfigId(modelPrice.getConfigId()) -// .setTotalFee(modelPrice.getAmount()) -// .setActualFee(modelPrice.getAmount()); +// .setPriceId(cart.getPriceId()) +// .setConfigId(cart.getConfigId()) +// .setTotalFee(cart.getAmount()) +// .setActualFee(cart.getAmount()); // log.debug("机型【{}】售价为{}", request.getModelNo(), modelPrice); // if (AppUserUtil.isAgent()) { // //代理商 @@ -709,7 +718,7 @@ public class ShoppingController extends ControllerBase { * 报价单-导出PDF */ @GetMapping("/quotation/exportToPdf") - public void exportToPdf(HttpServletResponse response, @RequestParam @NotNull(message = "报价单id不能为空") Long id){ + public void exportToPdf(HttpServletResponse response, @RequestParam @NotNull(message = "报价单id不能为空") Long id) { // QuotationShoppingOrder order = shoppingOrderService.getById(id); // VUtils.trueThrowBusinessError(Objects.isNull(order)).throwMessage("未找到报价单"); Map order = new HashMap<>(); @@ -735,7 +744,7 @@ public class ShoppingController extends ControllerBase { ITextRenderer renderer = new ITextRenderer(); renderer.getFontResolver().addFont("fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); URL baseUrl = new ClassPathResource("templates/").getURL(); - renderer.setDocumentFromString(html,baseUrl.toString()); + renderer.setDocumentFromString(html, baseUrl.toString()); renderer.layout(); try (OutputStream outputStream = response.getOutputStream()) { renderer.createPDF(outputStream); diff --git a/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveAccessoryRequest.java b/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveAccessoryRequest.java index 01fc2a8b..2f85ed5e 100644 --- a/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveAccessoryRequest.java +++ b/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveAccessoryRequest.java @@ -2,6 +2,8 @@ package com.nflg.mobilebroken.quotation.pojo.request; import lombok.Data; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; import java.math.BigDecimal; @Data @@ -10,6 +12,7 @@ public class ShoppingSaveAccessoryRequest { /** * 物料编号 */ + @NotBlank private String materialNo; /** @@ -20,15 +23,18 @@ public class ShoppingSaveAccessoryRequest { /** * 备件数量 */ + @NotNull private Integer num; /** * 备件单价 */ + @NotNull private BigDecimal amount; /** * 备件总价 */ + @NotNull private BigDecimal totalAmount; } diff --git a/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveRequest.java b/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveRequest.java index bb0da50b..95326a83 100644 --- a/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveRequest.java +++ b/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveRequest.java @@ -1,10 +1,13 @@ package com.nflg.mobilebroken.quotation.pojo.request; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; +import javax.validation.Valid; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Null; import java.math.BigDecimal; import java.util.List; @@ -100,14 +103,12 @@ public class ShoppingSaveRequest { /** * 随机配件总价 */ - @NotNull - private BigDecimal accessoryFee; + private BigDecimal accessoryFee = BigDecimal.ZERO; /** * 交机服务总价 */ - @NotNull - private BigDecimal serviceFee; + private BigDecimal serviceFee = BigDecimal.ZERO; /** * 交货方式,字典id @@ -147,7 +148,7 @@ public class ShoppingSaveRequest { /** * 币种,字典id */ - @NotBlank + @NotNull private Long currency; /** @@ -169,10 +170,12 @@ public class ShoppingSaveRequest { /** * 随机配件 */ + @Valid private List accessories; /** * 交机服务 */ + @Valid private List services; } diff --git a/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveServiceRequest.java b/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveServiceRequest.java index 8488ddc4..ee800f36 100644 --- a/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveServiceRequest.java +++ b/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/request/ShoppingSaveServiceRequest.java @@ -2,6 +2,7 @@ package com.nflg.mobilebroken.quotation.pojo.request; import lombok.Data; +import javax.validation.constraints.NotNull; import java.math.BigDecimal; @Data @@ -10,20 +11,24 @@ public class ShoppingSaveServiceRequest { /** * 工程师人数 */ + @NotNull private Integer userNum; /** * 服务天数 */ + @NotNull private Integer days; /** * 单人天费用 */ + @NotNull private BigDecimal fee; /** * 服务总费用 */ + @NotNull private BigDecimal totalFee; } diff --git a/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/vo/ShoppingCartVO.java b/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/vo/ShoppingCartVO.java index 87345d4e..053f1116 100644 --- a/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/vo/ShoppingCartVO.java +++ b/nflg-mobilebroken-quotation/src/main/java/com/nflg/mobilebroken/quotation/pojo/vo/ShoppingCartVO.java @@ -41,7 +41,7 @@ public class ShoppingCartVO { /** * 默认系数,没有方案时使用 */ - private BigDecimal defaultRatio; + private BigDecimal defaultRatio = BigDecimal.ONE; /** * 客户名称 diff --git a/nflg-mobilebroken-quotation/src/main/resources/templates/pdf.html b/nflg-mobilebroken-quotation/src/main/resources/templates/pdf.html index 28617c95..62ae8398 100644 --- a/nflg-mobilebroken-quotation/src/main/resources/templates/pdf.html +++ b/nflg-mobilebroken-quotation/src/main/resources/templates/pdf.html @@ -44,6 +44,16 @@ .data1 { width: 100%; } + + table, th, td { + border: black 1px solid; + border-collapse: collapse; + padding: 5px; + } + + table { + width: 100%; + } @@ -129,8 +139,38 @@
其他配置
油漆要求
其它要求说明
-
其它要求费用
- +
随机配件
+ + + + + + + + + + + + + + + +
物料编号备件名称备件数量备件单价备件总金额
+
交机服务
+ + + + + + + + + + + + + +
工程师人数服务天数单人天费用服务总费用
\ No newline at end of file diff --git a/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/entity/QuotationShoppingCartAccessory.java b/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/entity/QuotationShoppingCartAccessory.java index 9e8e2fdb..679e1211 100644 --- a/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/entity/QuotationShoppingCartAccessory.java +++ b/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/entity/QuotationShoppingCartAccessory.java @@ -50,6 +50,11 @@ public class QuotationShoppingCartAccessory implements Serializable { */ private BigDecimal amount; + /** + * 备件总价 + */ + private BigDecimal totalAmount; + /** * 优惠金额 */