feature:运费模块 计算运费 保存新增模板 查询模板
This commit is contained in:
parent
50f0b9fb31
commit
8f018e3b99
@ -0,0 +1,284 @@
|
||||
package com.sl.ms.carriage.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.EnumUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.sl.ms.base.api.common.AreaFeign;
|
||||
import com.sl.ms.carriage.domain.constant.CarriageConstant;
|
||||
import com.sl.ms.carriage.domain.dto.CarriageDTO;
|
||||
import com.sl.ms.carriage.domain.dto.WaybillDTO;
|
||||
import com.sl.ms.carriage.domain.enums.EconomicRegionEnum;
|
||||
import com.sl.ms.carriage.entity.CarriageEntity;
|
||||
import com.sl.ms.carriage.enums.CarriageExceptionEnum;
|
||||
import com.sl.ms.carriage.mapper.CarriageMapper;
|
||||
import com.sl.ms.carriage.service.CarriageService;
|
||||
import com.sl.ms.carriage.utils.CarriageUtils;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
import com.sl.transport.common.util.ObjectUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class CarriageServiceImpl extends ServiceImpl<CarriageMapper, CarriageEntity> implements CarriageService {
|
||||
|
||||
@Resource
|
||||
private AreaFeign areaFeign;
|
||||
|
||||
private CarriageEntity carriageEntity;
|
||||
|
||||
/**
|
||||
* 新增/修改运费模板
|
||||
*
|
||||
* @param carriageDto 新增/修改运费对象
|
||||
* 必填字段:templateType、transportType
|
||||
* 更新时传入id字段
|
||||
*/
|
||||
@Override
|
||||
public CarriageDTO saveOrUpdate(CarriageDTO carriageDto) {
|
||||
// 校验运费模板是否存在,如果不存在直接插入(查询条件:模板类型 运输类型 如果是修改排除当前id)
|
||||
LambdaQueryWrapper<CarriageEntity> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.eq(CarriageEntity::getTemplateType, carriageDto.getTemplateType());
|
||||
queryWrapper.eq(CarriageEntity::getTransportType, carriageDto.getTransportType());
|
||||
queryWrapper.ne(ObjectUtils.isNotEmpty(carriageDto.getId()), CarriageEntity::getId, carriageDto.getId());
|
||||
|
||||
List<CarriageEntity> carriageEntityList = super.list(queryWrapper);
|
||||
|
||||
// 如果没有重复的模板,可以直接插入或更新操作(DTo转entity 保存成功 entity转DTO)
|
||||
if (CollUtil.isEmpty(carriageEntityList)) {
|
||||
return saveOrUpdateCarriage(carriageDto);
|
||||
}
|
||||
|
||||
// 如果存在重复模板,需要判断此次插入的是否为经济区互寄,非经济区互寄不可以重复
|
||||
if (ObjectUtil.notEqual(carriageDto.getTemplateType(), CarriageConstant.ECONOMIC_ZONE)) {
|
||||
throw new SLException(CarriageExceptionEnum.NOT_ECONOMIC_ZONE_REPEAT);
|
||||
}
|
||||
|
||||
// 如果是京经济区互寄类型,需要进一步判断关联城市是否重复,通过集合取交集判断是否重复
|
||||
List<String> associatedCityList = carriageEntityList.stream().map(CarriageEntity::getAssociatedCity)
|
||||
.map(associatedCity -> StrUtil.splitToArray(associatedCity, ","))
|
||||
.flatMap(Arrays::stream)
|
||||
.collect(Collectors.toList());
|
||||
Collection<String> intersection = CollUtil.intersection(associatedCityList, carriageDto.getAssociatedCityList());
|
||||
if (CollUtil.isNotEmpty(intersection)) {
|
||||
throw new SLException(CarriageExceptionEnum.ECONOMIC_ZONE_CITY_REPEAT);
|
||||
}
|
||||
|
||||
// 如果没有重复,可以新增或更新(DTO转Entity 保存成功 entity转DTO)
|
||||
return saveOrUpdateCarriage(carriageDto);
|
||||
}
|
||||
|
||||
private CarriageDTO saveOrUpdateCarriage(CarriageDTO carriageDto) {
|
||||
CarriageEntity carriageEntity = CarriageUtils.toEntity(carriageDto);
|
||||
super.saveOrUpdate(carriageEntity);
|
||||
return CarriageUtils.toDTO(carriageEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部运费模板
|
||||
*
|
||||
* @return 运费模板对象列表
|
||||
*/
|
||||
@Override
|
||||
public List<CarriageDTO> findAll() {
|
||||
// 构造查询条件,按创建时间倒叙
|
||||
LambdaQueryWrapper<CarriageEntity> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.orderByDesc(CarriageEntity::getCreated);
|
||||
|
||||
// 查询数据库
|
||||
List<CarriageEntity> list = super.list(queryWrapper);
|
||||
|
||||
// 将结果转换为DTO类型,使用CarriageUtils工具类
|
||||
return list.stream().map(CarriageUtils::toDTO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 运费计算
|
||||
*
|
||||
* @param waybillDTO 运费计算对象
|
||||
* @return 运费模板对象,不仅包含模板数据还包含:computeWeight、expense 字段
|
||||
*/
|
||||
@Override
|
||||
public CarriageDTO compute(WaybillDTO waybillDTO) {
|
||||
// 根据参数查找运费模板 调用findCarriage方法
|
||||
CarriageEntity carriage = findCarriage(waybillDTO);
|
||||
|
||||
// 计算重量,最小重量为1KG,调用getComputedWeight方法
|
||||
double computeWeight = getComputeWeight(waybillDTO, carriage);
|
||||
|
||||
// 计算运费 运费=首重价格 + (实际重量 - 1) * 续重加格
|
||||
double price = carriage.getFirstWeight() + (computeWeight - 1) * carriage.getContinuousWeight();
|
||||
|
||||
// 结果保留一位小数
|
||||
BigDecimal expense = NumberUtil.round(price, 1);
|
||||
|
||||
// 封装运费和计算重量到CarriageDTO,并返回
|
||||
CarriageDTO carriageDTO = CarriageUtils.toDTO(carriage);
|
||||
carriageDTO.setExpense(expense.doubleValue());
|
||||
carriageDTO.setComputeWeight(computeWeight);
|
||||
|
||||
return carriageDTO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算重量
|
||||
* @param waybillDTO
|
||||
* @param carriage
|
||||
* @return
|
||||
*/
|
||||
private double getComputeWeight(WaybillDTO waybillDTO, CarriageEntity carriage) {
|
||||
// 计算体积,如果传入体积则不需要计算
|
||||
Integer volume = waybillDTO.getVolume();
|
||||
if (ObjectUtil.isEmpty(volume)) {
|
||||
try {
|
||||
volume = waybillDTO.getMeasureHigh() * waybillDTO.getMeasureLong() * waybillDTO.getMeasureWidth();
|
||||
} catch (Exception e) {
|
||||
volume = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 计算体积重量 = 体积 / 轻抛系数 tips:使用NumberUtil工具类计算 保留一位小数
|
||||
BigDecimal volumeWeight = NumberUtil.div(volume, carriage.getLightThrowingCoefficient(), 1);
|
||||
|
||||
// 重量取最大值 = 体积重量和实际重量 tips:使用NumberUtil工具类计算 保留一位小数
|
||||
double computeWeight = NumberUtil.max(volumeWeight, NumberUtil.round(waybillDTO.getWeight(), 1)).doubleValue();
|
||||
|
||||
// 计算续重,规则:不满1kg,按1kg计费
|
||||
if (computeWeight <= 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 10KG一下续重以0.1kg计量保留1位小数
|
||||
if (computeWeight <= 10) {
|
||||
return computeWeight;
|
||||
}
|
||||
|
||||
// 100KG 以上四舍五入取整,举例108.4kg按照108收费 108.5kg 按照109KG收费
|
||||
// tips:使用NumberUtil工具类计算
|
||||
if (computeWeight >= 100) {
|
||||
return NumberUtil.round(computeWeight, 0).doubleValue();
|
||||
}
|
||||
|
||||
// 10-100kg续重以0.5kg计量保留1位小数
|
||||
int intValue = NumberUtil.round(computeWeight, 0, RoundingMode.DOWN).intValue();
|
||||
|
||||
// 0.5为一个计量单位,举例:18.8kg按照19收费,18.4kg按照18.5收费,18.1kg按照18.5kg收费
|
||||
double sub = NumberUtil.sub(computeWeight, intValue);
|
||||
if (sub == 0) {
|
||||
return intValue;
|
||||
}
|
||||
if (sub < 0.5) {
|
||||
return NumberUtil.add(intValue, 0.5);
|
||||
}
|
||||
return NumberUtil.add(intValue, 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参数查找运费模板
|
||||
* @param waybillDTO
|
||||
* @return
|
||||
*/
|
||||
private CarriageEntity findCarriage(WaybillDTO waybillDTO) {
|
||||
Long senderCityId = waybillDTO.getSenderCityId();
|
||||
Long receiverCityId = waybillDTO.getReceiverCityId();
|
||||
|
||||
// 如果 发件的城市id 和 收件的城市id相同,查询同城模板 调用findByTemplateType方法
|
||||
if (ObjectUtil.equal(senderCityId, receiverCityId)) {
|
||||
CarriageEntity carriageEntity = findByTemplateType(CarriageConstant.SAME_CITY);
|
||||
if (ObjectUtil.isNotEmpty(carriageEntity)) {
|
||||
return carriageEntity;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有查到或不是同城,则获取收寄地址同省id,使用AreaFeign结构查询
|
||||
Long senderProvinceId = areaFeign.get(senderCityId).getParentId();
|
||||
Long receiverProvinceId = areaFeign.get(receiverCityId).getParentId();
|
||||
|
||||
// 如果 收发件的省份id相同,查询同省的模板,调用findByTemplate方法
|
||||
if (ObjectUtil.equal(senderProvinceId, receiverProvinceId)) {
|
||||
CarriageEntity carriageEntity = findByTemplateType(CarriageConstant.SAME_PROVINCE);
|
||||
if (ObjectUtil.isNotEmpty(carriageEntity)) {
|
||||
return carriageEntity;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有查到或不是同省,则查询是否为经济区互寄 调用findEconomicCarriage方法查询
|
||||
CarriageEntity carriageEntity = findEconomicCarriage(senderProvinceId, receiverProvinceId);
|
||||
if (ObjectUtil.isNotEmpty(carriageEntity)) {
|
||||
return carriageEntity;
|
||||
}
|
||||
|
||||
// 如果没有查到或不是经济区互寄,直接查跨省运费模板
|
||||
carriageEntity = findByTemplateType(CarriageConstant.TRANS_PROVINCE);
|
||||
if (ObjectUtil.isNotEmpty(carriageEntity)) {
|
||||
return carriageEntity;
|
||||
}
|
||||
|
||||
// 如果最后没有查到,直接抛自定义异常,提示模板未找到
|
||||
throw new SLException(CarriageExceptionEnum.NOT_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询是否为经济区互寄
|
||||
* @param senderProvinceId
|
||||
* @param receiverProvinceId
|
||||
* @return
|
||||
*/
|
||||
private CarriageEntity findEconomicCarriage(Long senderProvinceId, Long receiverProvinceId) {
|
||||
// 通过工具类EnumUtil 获取经济区城市配置枚举
|
||||
LinkedHashMap<String, EconomicRegionEnum> enumMap = EnumUtil.getEnumMap(EconomicRegionEnum.class);
|
||||
|
||||
// 遍历所有经济区枚举值
|
||||
EconomicRegionEnum economicRegionEnum = null;
|
||||
for (EconomicRegionEnum regionEnum : enumMap.values()) {
|
||||
// 通过ArrayUtil工具类 判断发件网点 和 收件网点是否在同一经济区
|
||||
boolean containsAll = ArrayUtil.containsAll(regionEnum.getValue(), receiverProvinceId, senderProvinceId);
|
||||
|
||||
// 如果在得到对应经济区枚举
|
||||
if (containsAll) {
|
||||
economicRegionEnum = regionEnum;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 循环遍历未发现所属经济区,方法直接返回null
|
||||
if (ObjectUtil.isNull(economicRegionEnum)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 如果有经济区 根据 模板类型=经济区,运输类型=普快 关联城市=枚举的code值 查询
|
||||
LambdaQueryWrapper<CarriageEntity> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.eq(CarriageEntity::getTemplateType, CarriageConstant.ECONOMIC_ZONE);
|
||||
queryWrapper.eq(CarriageEntity::getTransportType, economicRegionEnum.getCode());
|
||||
return super.getOne(queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据模板类型查询模板,经济区互寄不通过该方法查询模板
|
||||
*
|
||||
* @param templateType 模板类型:1-同城寄,2-省内寄,4-跨省
|
||||
* @return 运费模板
|
||||
*/
|
||||
@Override
|
||||
public CarriageEntity findByTemplateType(Integer templateType) {
|
||||
// 根据模板类型,及运输类型 = CarriageConst.REGULAR_FAST查询模板
|
||||
LambdaQueryWrapper<CarriageEntity> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.eq(CarriageEntity::getTemplateType, templateType);
|
||||
queryWrapper.eq(CarriageEntity::getTransportType, CarriageConstant.REGULAR_FAST);
|
||||
return super.getOne(queryWrapper);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.sl.ms.carriage.service.impl;
|
||||
|
||||
import com.sl.ms.carriage.domain.dto.CarriageDTO;
|
||||
import com.sl.ms.carriage.domain.dto.WaybillDTO;
|
||||
import com.sl.ms.carriage.service.CarriageService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@SpringBootTest
|
||||
class CarriageServiceImplTest {
|
||||
|
||||
@Resource
|
||||
private CarriageService carriageService;
|
||||
|
||||
@Test
|
||||
void saveOrUpdate() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void findAll() {
|
||||
List<CarriageDTO> all = carriageService.findAll();
|
||||
all.forEach(System.out::println);
|
||||
}
|
||||
|
||||
@Test
|
||||
void compute() {
|
||||
WaybillDTO waybillDTO = new WaybillDTO();
|
||||
waybillDTO.setReceiverCityId(161793L); //上海
|
||||
waybillDTO.setSenderCityId(2L); //北京
|
||||
waybillDTO.setWeight(0.8); //重量
|
||||
waybillDTO.setVolume(1); //体积
|
||||
|
||||
CarriageDTO compute = this.carriageService.compute(waybillDTO);
|
||||
System.out.println(compute);
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByTemplateType() {
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user