跳至主要內容

运费模板

起凡大约 3 分钟

运费模板

运费模板
运费模板

表设计

前端的输入表单可以看见是比较动态且复杂的,这种配置数据适合用json类型存储。configs字段用来存储运费配置。

valid字段标识全局唯一生效的运费模板。

create table carriage_template
(
    id           varchar(36)   not null
        primary key,
    created_time datetime(6)   not null,
    edited_time  datetime(6)   not null,
    creator_id   varchar(36)   not null,
    editor_id    varchar(36)   not null,
    name         varchar(255)  not null comment '模板名称',
    description  varchar(1000) not null comment '运费模板描述',
    configs      json          not null comment '运费配置',
    valid        tinyint(1)    not null comment '是否生效(全局只能存在一个生效)'
)
    comment '运费模板';

模板创建

java

运费模板实体类

configs字段在数据库是json类型,在Java中对应的类型是List<CarriageConfig>。使用@Serialized存入到数据库时会触发json序列化成字符串,读取时触发反序列化成List<CarriageConfig>

@GenEntity
@Entity
public interface CarriageTemplate extends BaseEntity {
    /**
     * 模板名称
     */
    @GenTextField(label = "模板名称", order = 1)
    String name();

    @GenTextAreaField(label = "模板描述", order = 2)
    String description();

    /**
     * 是否生效(全局只能存在一个生效)
     */
    @GenBooleanField
    boolean valid();

    /**
     * 运费配置
     */
    @Serialized
    List<CarriageConfig> configs();
}

@Data
public class CarriageConfig {
    /**
     * 省份
     */
    List<String> province;
    /**
     * 运费配置
     */
    List<PriceRange> priceRanges;

    @Data
    public static class PriceRange {
        /**
         * 订单最高价格
         */
        BigDecimal maxPrice;
        /**
         * 订单最低价格
         */
        BigDecimal minPrice;
        /**
         * 运费
         */
        BigDecimal carriage;
    }
}

运费计算

传入地址id和商品总价计算运费。

  • 根据省份匹配适合的模板
  • 根据商品总价匹配适合的价格区间
@Service
@Slf4j
@AllArgsConstructor
@Transactional
public class CarriageTemplateService {
    private final CarriageTemplateRepository carriageTemplateRepository;
    private final AddressRepository addressRepository;

    public BigDecimal calculate(String addressId, BigDecimal productAmount) {
        Optional<Address> userAddressOpt = addressRepository.findUserAddressById(addressId);
        if (userAddressOpt.isEmpty()) return BigDecimal.ZERO;
        Address address = userAddressOpt.get();
        return carriageTemplateRepository.findValid()
                .configs()
                .stream()
                .filter(config -> String.join(";", config.getProvince()).contains((address.province())))
                .findFirst()
                .orElseThrow(() -> new BusinessException("当前省份不支持发货请联系客服"))
                .getPriceRanges()
                .stream()
                .filter(priceRange -> productAmount.compareTo(priceRange.getMinPrice()) >= 0 &&
                                      productAmount.compareTo(priceRange.getMaxPrice()) <= 0)
                .findFirst()
                .orElseThrow(() -> new BusinessException("运费模板不适应与该订单,请联系客服"))
                .getCarriage();
    }

}