feat(quotation): 添加购物车功能并重构相关接口

- 修改代码生成器配置,从 quotation_shopping_cart_service 切换到
  quotation_shopping_order_adjust 表
- 在 ShoppingController 中添加 javax.validation.constraints.NotEmpty
  导入
- 将购物车相关接口路径统一添加 /cart 前缀
- 修改 getRatio 方法参数,移除冗余的 categoryId 参数
- 新增 generate 方法用于生成报价单,包含购物车验证逻辑
- 移除 ShoppingSaveRequest 中 exchangeRate 字段的 @NotNull 验证
- 新增 QuotationShoppingOrder、QuotationShoppingOrderAdjust 和
  QuotationShoppingOrderItem 相关实体类
- 为新实体类添加对应的 Mapper 接口和实现类
- 为新实体类创建 MyBatis XML 映射文件
This commit is contained in:
曹鹏飞 2026-03-11 17:39:13 +08:00
parent 6439afad38
commit ec3e7c71c8
18 changed files with 378 additions and 9 deletions

View File

@ -26,6 +26,7 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
@ -78,7 +79,7 @@ public class ShoppingController extends ControllerBase {
/**
* 获取报价对象
*/
@GetMapping("/getTargets")
@GetMapping("/cart/getTargets")
public ApiResult<List<SimpleUserVO>> getTargets() {
if (AppUserUtil.isAgent()) {
return ApiResult.success(appUserService.getCustomers(AppUserUtil.getUserId())
@ -102,7 +103,7 @@ public class ShoppingController extends ControllerBase {
/**
* 根据机型查询售价
*/
@PostMapping("/init")
@PostMapping("/cart/init")
public ApiResult<ShoppingCartVO> init(@Valid @RequestBody ShoppingInitRequest request) {
Long categoryId = getCategoryId();
ModelPrice1VO modelPrice = priceService.getModelPrice(request.getModelId(), categoryId);
@ -127,7 +128,7 @@ public class ShoppingController extends ControllerBase {
}
}
//系数
Pair<BigDecimal, BigDecimal> pair = getRatio(request.getModelId(), categoryId);
Pair<BigDecimal, BigDecimal> pair = getRatio(request.getModelId());
BigDecimal standardRatio = pair.getLeft(), optionalRatio = pair.getRight();
log.debug("机型【{}】标准配件系数为{},可选配件系数为{}", request.getModelNo(), standardRatio, optionalRatio);
vo.setActualFee(vo.getActualFee().multiply(standardRatio));
@ -171,7 +172,7 @@ public class ShoppingController extends ControllerBase {
* 保存购物车
*/
@Transactional
@PostMapping("/save")
@PostMapping("/cart/save")
public ApiResult<Long> save(@Valid @RequestBody ShoppingSaveRequest request) {
QuotationShoppingCart cart;
if (Objects.nonNull(request.getId())) {
@ -237,7 +238,7 @@ public class ShoppingController extends ControllerBase {
/**
* 查询购物车
*/
@PostMapping("/search")
@PostMapping("/cart/search")
public ApiResult<PageData<ShoppingSearchVO>> search(@Valid @RequestBody ShoppingSearchRequest request) {
return ApiResult.success(shoppingCartService.search(request, MultilingualUtil.getLanguage()));
}
@ -246,7 +247,7 @@ public class ShoppingController extends ControllerBase {
* 删除购物车
*/
@Transactional
@PostMapping("/delete")
@PostMapping("/cart/delete")
public ApiResult<Void> delete(@RequestParam Long id) {
QuotationShoppingCart cart = shoppingCartService.getById(id);
VUtils.trueThrowBusinessError(Objects.isNull(cart)).throwMessage("未找到购物车信息");
@ -264,7 +265,27 @@ public class ShoppingController extends ControllerBase {
return ApiResult.success();
}
private Pair<BigDecimal, BigDecimal> getRatio(Long modelId, Long categoryId) {
/**
* 生成报价单
*/
@PostMapping("/quotation/generate")
private ApiResult<Void> generate(@RequestBody @NotEmpty List<Long> cartIds) {
List<QuotationShoppingCart> carts = shoppingCartService.lambdaQuery()
.eq(QuotationShoppingCart::getStatus, 0)
.eq(QuotationShoppingCart::getCreateByType, AppUserUtil.isAgent() ? 1 : 0)
.eq(QuotationShoppingCart::getCreateById, AppUserUtil.getUserId())
.in(QuotationShoppingCart::getId, cartIds)
.list();
VUtils.trueThrowBusinessError(CollectionUtil.isEmpty(carts)).throwMessage("未找到购物车信息");
VUtils.trueThrowBusinessError(carts.stream().map(QuotationShoppingCart::getCustomerName).collect(Collectors.toSet()).size() > 1)
.throwMessage("客户名称不一致");
VUtils.trueThrowBusinessError(carts.stream().map(QuotationShoppingCart::getTargetId).collect(Collectors.toSet()).size() > 1)
.throwMessage("报价对象不一致");
//TODO
return ApiResult.success();
}
private Pair<BigDecimal, BigDecimal> getRatio(Long modelId) {
Pair<BigDecimal, BigDecimal> pair = Pair.of(BigDecimal.ONE, BigDecimal.ONE);
if (AppUserUtil.isAgent()) {
//代理商

View File

@ -153,7 +153,6 @@ public class ShoppingSaveRequest {
/**
* 汇率
*/
@NotNull
private BigDecimal exchangeRate;
/**

View File

@ -0,0 +1,93 @@
package com.nflg.mobilebroken.repository.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
* 报价-报价单
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("quotation_shopping_order")
public class QuotationShoppingOrder implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
/**
* 报价编号
*/
private String no;
/**
* 客户名称
*/
private String customerName;
/**
* 报价对象
*/
private Integer targetId;
/**
* 优惠金额
*/
private BigDecimal discount;
/**
* 总价
*/
private BigDecimal totalFee;
/**
* 实际总价
*/
private BigDecimal actualFee;
/**
* 报价生效时间
*/
private String effectiveStartTime;
/**
* 报价失效时间
*/
private String effectiveEndTime;
/**
* 创建人类型0内部人员1代理商
*/
private Integer createByType;
/**
* 创建人id
*/
private Integer createById;
/**
* 创建人
*/
private String createBy;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 最后修改时间
*/
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,48 @@
package com.nflg.mobilebroken.repository.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
* 报价-报价单-调价记录
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("quotation_shopping_order_adjust")
public class QuotationShoppingOrderAdjust implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
/**
* 报价单id
*/
private Long orderId;
/**
* 优惠金额
*/
private BigDecimal discount;
/**
* 实际总价
*/
private BigDecimal actualFee;
/**
* 创建时间
*/
private LocalDateTime createTime;
}

View File

@ -0,0 +1,37 @@
package com.nflg.mobilebroken.repository.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
* 报价-报价单-子项
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("quotation_shopping_order_item")
public class QuotationShoppingOrderItem implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
/**
* 购物车id
*/
private Long cartId;
/**
* 标配价格调价后价格
*/
private BigDecimal standardFee;
}

View File

@ -0,0 +1,16 @@
package com.nflg.mobilebroken.repository.mapper;
import com.nflg.mobilebroken.repository.entity.QuotationShoppingOrderAdjust;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 报价-报价单-调价记录 Mapper 接口
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
public interface QuotationShoppingOrderAdjustMapper extends BaseMapper<QuotationShoppingOrderAdjust> {
}

View File

@ -0,0 +1,16 @@
package com.nflg.mobilebroken.repository.mapper;
import com.nflg.mobilebroken.repository.entity.QuotationShoppingOrderItem;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 报价-报价单-子项 Mapper 接口
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
public interface QuotationShoppingOrderItemMapper extends BaseMapper<QuotationShoppingOrderItem> {
}

View File

@ -0,0 +1,16 @@
package com.nflg.mobilebroken.repository.mapper;
import com.nflg.mobilebroken.repository.entity.QuotationShoppingOrder;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 报价-报价单 Mapper 接口
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
public interface QuotationShoppingOrderMapper extends BaseMapper<QuotationShoppingOrder> {
}

View File

@ -0,0 +1,16 @@
package com.nflg.mobilebroken.repository.service;
import com.nflg.mobilebroken.repository.entity.QuotationShoppingOrderAdjust;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 报价-报价单-调价记录 服务类
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
public interface IQuotationShoppingOrderAdjustService extends IService<QuotationShoppingOrderAdjust> {
}

View File

@ -0,0 +1,16 @@
package com.nflg.mobilebroken.repository.service;
import com.nflg.mobilebroken.repository.entity.QuotationShoppingOrderItem;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 报价-报价单-子项 服务类
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
public interface IQuotationShoppingOrderItemService extends IService<QuotationShoppingOrderItem> {
}

View File

@ -0,0 +1,16 @@
package com.nflg.mobilebroken.repository.service;
import com.nflg.mobilebroken.repository.entity.QuotationShoppingOrder;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 报价-报价单 服务类
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
public interface IQuotationShoppingOrderService extends IService<QuotationShoppingOrder> {
}

View File

@ -0,0 +1,20 @@
package com.nflg.mobilebroken.repository.service.impl;
import com.nflg.mobilebroken.repository.entity.QuotationShoppingOrderAdjust;
import com.nflg.mobilebroken.repository.mapper.QuotationShoppingOrderAdjustMapper;
import com.nflg.mobilebroken.repository.service.IQuotationShoppingOrderAdjustService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 报价-报价单-调价记录 服务实现类
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
@Service
public class QuotationShoppingOrderAdjustServiceImpl extends ServiceImpl<QuotationShoppingOrderAdjustMapper, QuotationShoppingOrderAdjust> implements IQuotationShoppingOrderAdjustService {
}

View File

@ -0,0 +1,20 @@
package com.nflg.mobilebroken.repository.service.impl;
import com.nflg.mobilebroken.repository.entity.QuotationShoppingOrderItem;
import com.nflg.mobilebroken.repository.mapper.QuotationShoppingOrderItemMapper;
import com.nflg.mobilebroken.repository.service.IQuotationShoppingOrderItemService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 报价-报价单-子项 服务实现类
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
@Service
public class QuotationShoppingOrderItemServiceImpl extends ServiceImpl<QuotationShoppingOrderItemMapper, QuotationShoppingOrderItem> implements IQuotationShoppingOrderItemService {
}

View File

@ -0,0 +1,20 @@
package com.nflg.mobilebroken.repository.service.impl;
import com.nflg.mobilebroken.repository.entity.QuotationShoppingOrder;
import com.nflg.mobilebroken.repository.mapper.QuotationShoppingOrderMapper;
import com.nflg.mobilebroken.repository.service.IQuotationShoppingOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 报价-报价单 服务实现类
* </p>
*
* @author 代码生成器生成
* @since 2026
*/
@Service
public class QuotationShoppingOrderServiceImpl extends ServiceImpl<QuotationShoppingOrderMapper, QuotationShoppingOrder> implements IQuotationShoppingOrderService {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nflg.mobilebroken.repository.mapper.QuotationShoppingOrderAdjustMapper">
</mapper>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nflg.mobilebroken.repository.mapper.QuotationShoppingOrderItemMapper">
</mapper>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nflg.mobilebroken.repository.mapper.QuotationShoppingOrderMapper">
</mapper>

View File

@ -33,7 +33,7 @@ public class CodeGeneratorTest {
, Paths.get(System.getProperty("user.dir")) + "/src/main/resources/mapper"))
)
.strategyConfig(builder -> {
builder.addInclude("quotation_shopping_cart_service") //只生成指定表
builder.addInclude("quotation_shopping_order_adjust") //只生成指定表
.entityBuilder()
.enableLombok()
.enableChainModel()