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