新建应付配置的附加费开关配置

This commit is contained in:
liuminghui
2026-11-05 16:05:01 +08:00
parent 116b3b74e4
commit fde53681d1
15 changed files with 1002 additions and 21 deletions
@@ -1,5 +1,6 @@
package com.bms.web.controller.price;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
@@ -24,6 +25,7 @@ import com.bms.common.exception.ServiceException;
import com.bms.common.utils.file.FileUtils;
import com.bms.common.utils.poi.ExcelUtil;
import com.bms.price.domain.ChannelProductMap;
import com.bms.price.domain.PayFeeRuleGroup;
import com.bms.price.domain.PayProduct;
import com.bms.price.domain.PayProductTerm;
import com.bms.price.domain.PaySaveCommand;
@@ -70,6 +72,35 @@ public class PayProductController extends BaseController
return toAjax(payProductService.updateTerm(term));
}
/** 勾选的应付产品各自带出附加费开关。productIds 用逗号分隔 */
@PreAuthorize("@ss.hasPermi('price:pay:query')")
@GetMapping("/feeRule/list")
public AjaxResult feeRuleList(@RequestParam String productIds)
{
List<Long> ids = new ArrayList<>();
if (productIds != null)
{
for (String part : productIds.split(","))
{
if (part != null && !part.isBlank())
{
ids.add(Long.valueOf(part.trim()));
}
}
}
return success(payProductService.listFeeRules(ids));
}
/** 按产品保存附加费开关。多个产品各写一份 */
@PreAuthorize("@ss.hasPermi('price:pay:edit')")
@Log(title = "应付附加费开关", businessType = BusinessType.UPDATE)
@PutMapping("/feeRule")
public AjaxResult saveFeeRule(@RequestBody List<PayFeeRuleGroup> products)
{
payProductService.saveFeeRules(products);
return success();
}
@PreAuthorize("@ss.hasPermi('price:pay:edit')")
@Log(title = "应付有效期", businessType = BusinessType.UPDATE)
@PutMapping("/term/status")
@@ -91,14 +91,36 @@ class PayWorkbookParserTest
{
PayPreview preview = parse("32、");
PayProduct ups = product(preview, "德国UPS");
assertEquals("Zone 1", ups.getWeightBands().get(0).getZoneName());
assertEquals("DE", ups.getWeightBands().get(0).getCountryCode());
assertTrue(decimal(ups.getWeightBands().get(0), "3.9"));
assertEquals("Zone 2", ups.getWeightBands().get(1).getZoneName());
assertTrue(ups.getWeightBands().get(1).getCountryCode().startsWith("BE,LU"));
assertTrue(decimal(ups.getWeightBands().get(1), "7.58"));
assertTrue(ups.getWeightBands().get(4).getZoneName().contains("Zone 5"));
assertTrue(decimal(ups.getWeightBands().get(4), "9.45"));
String[] codes = {
"DE",
"BE", "LU", "NL", "AT", "SI",
"CZ", "PL", "SK",
"DK", "FI", "FR", "SE", "ES", "IT", "PT", "HU",
"GR", "IE", "BG", "HR", "EE", "LT", "LV", "RO"
};
String[] zones = {
"Zone 1",
"Zone 2", "Zone 2", "Zone 2", "Zone 2", "Zone 2",
"Zone 3", "Zone 3", "Zone 3",
"Zone 4", "Zone 4", "Zone 4", "Zone 4", "Zone 4", "Zone 4", "Zone 4", "Zone 4",
"Zone 5", "Zone 5", "Zone 5", "Zone 5", "Zone 5", "Zone 5", "Zone 5", "Zone 5"
};
String[] prices = {
"3.9",
"7.58", "7.58", "7.58", "7.58", "7.58",
"7.72", "7.72", "7.72",
"8.41", "8.41", "8.41", "8.41", "8.41", "8.41", "8.41", "8.41",
"9.45", "9.45", "9.45", "9.45", "9.45", "9.45", "9.45", "9.45"
};
assertEquals(codes.length, ups.getWeightBands().size());
for (int i = 0; i < codes.length; i++)
{
PayWeightBand band = ups.getWeightBands().get(i);
assertEquals(zones[i], band.getZoneName(), codes[i]);
assertEquals(codes[i], band.getCountryCode());
assertEquals(codes[i], band.getCountryName());
assertTrue(decimal(band, prices[i]), codes[i] + " " + prices[i]);
}
assertTrue(ups.getSurcharges().stream().anyMatch(fee -> "报价说明".equals(fee.getFeeName())
&& fee.getChargeText().contains("不含管理费") && fee.getChargeText().contains("不含燃油")));
PaySurcharge handling = ups.getSurcharges().stream()
@@ -0,0 +1,18 @@
package com.bms.price.domain;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
/**
* 一个应付产品上的附加费开关。多个产品各自一组,互不影响。
*/
@Data
public class PayFeeRuleGroup
{
private Long productId;
private String productName;
private List<PayProductFeeRule> rules = new ArrayList<>();
}
@@ -0,0 +1,47 @@
package com.bms.price.domain;
import java.math.BigDecimal;
import com.bms.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 应付产品附加费开关。挂在根产品上,价格仍在价卡版本的附加费行里。
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class PayProductFeeRule extends BaseEntity
{
private static final long serialVersionUID = 1L;
private Long ruleId;
/** 根产品编号 */
private Long productId;
/** 附加费名称,用来到价卡版本里取价 */
private String feeName;
/** 1 参与计算,0 不参与 */
private String enabled;
/** SIZE 尺寸,VOLUME 体积,WEIGHT 重量,POSTCODE 邮编,ALWAYS 每票,RETURN 退件 */
private String triggerType;
private BigDecimal sideMaxCm;
private BigDecimal sumMaxCm;
private BigDecimal volumeMaxCm3;
private BigDecimal minLengthCm;
private BigDecimal minWidthCm;
private BigDecimal minHeightCm;
private BigDecimal weightMaxKg;
/** ANY 任一条超出就收,ALL 写了的条件都超出才收 */
private String joinMode;
}
@@ -0,0 +1,19 @@
package com.bms.price.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.bms.price.domain.PayProductFeeRule;
/**
* 应付产品附加费开关
*/
public interface PayProductFeeRuleMapper
{
List<PayProductFeeRule> selectByProductId(Long productId);
int deleteByProductId(Long productId);
int deleteByProductIds(@Param("productIds") List<Long> productIds);
int insertBatch(@Param("list") List<PayProductFeeRule> list);
}
@@ -2811,17 +2811,22 @@ public class PayWorkbookParser
{
continue;
}
PayWeightBand band = new PayWeightBand();
band.setSectionName("分区报价");
String country = countryRow < 0 ? "" : grid.text(countryRow, col);
band.setCountryName(country);
band.setCountryCode(zoneCodes(country));
band.setZoneName(grid.text(header, col));
band.setChargeName(charge);
band.setPrice(price);
band.setPriceUnit(unitOf(charge + " EUR"));
band.setSortNo(product.getWeightBands().size() + 1);
product.getWeightBands().add(band);
String zone = grid.text(header, col);
for (String piece : zoneCountryPieces(country))
{
PayWeightBand band = new PayWeightBand();
band.setSectionName("分区报价");
String code = zoneCodes(piece);
band.setCountryName(zoneCountryName(piece, code, country));
band.setCountryCode(code.contains(",") ? "" : code);
band.setZoneName(zone);
band.setChargeName(charge);
band.setPrice(price);
band.setPriceUnit(unitOf(charge + " EUR"));
band.setSortNo(product.getWeightBands().size() + 1);
product.getWeightBands().add(band);
}
}
return row + 1;
}
@@ -3268,19 +3273,103 @@ public class PayWorkbookParser
private static String zoneCodes(String text)
{
Matcher matcher = Pattern.compile("\\b([A-Z]{2})\\b").matcher(text == null ? "" : text);
StringBuilder codes = new StringBuilder();
while (matcher.find())
for (String code : zoneCodeList(text))
{
if (codes.length() > 0)
{
codes.append(',');
}
codes.append(matcher.group(1));
codes.append(code);
}
return codes.toString();
}
private static List<String> zoneCodeList(String text)
{
List<String> codes = new ArrayList<>();
Matcher matcher = Pattern.compile("\\b([A-Z]{2})\\b").matcher(text == null ? "" : text);
while (matcher.find())
{
codes.add(matcher.group(1));
}
return codes;
}
/**
* 德国 UPS 这类分区国家格把多个国家写在同一格,用顿号或换行接起来。
* 纯国家码列表按出现顺序拆开;没有国家码、只用顿号连接的国名同样拆开。
* 只有一个国家时保留原格,避免把说明文字拆碎。
*/
private static List<String> zoneCountryPieces(String text)
{
if (text == null || text.isBlank())
{
return List.of("");
}
String folded = text.replace('\r', '\n');
List<String> codes = zoneCodeList(folded);
if (codes.size() > 1 && isCountryCodeList(folded))
{
return codes;
}
if (!folded.contains("、"))
{
return List.of(text.trim());
}
List<String> pieces = new ArrayList<>();
for (String part : folded.split("、"))
{
String token = part.replace('\n', ' ').trim();
if (token.isEmpty())
{
continue;
}
List<String> tokenCodes = zoneCodeList(token);
if (tokenCodes.size() > 1 && isCountryCodeList(token))
{
pieces.addAll(tokenCodes);
}
else
{
pieces.add(token);
}
}
return pieces.size() > 1 ? pieces : List.of(text.trim());
}
private static boolean isCountryCodeList(String text)
{
String stripped = text.replaceAll("\\b[A-Z]{2}\\b", "");
return stripped.replaceAll("[、,,;;\\s]+", "").isEmpty();
}
/** 拆开后的一格如果就是国家码,名称也用这个码;没拆开的原格保持原文。 */
private static String zoneCountryName(String piece, String code, String original)
{
if (piece == null)
{
return "";
}
if (original != null && piece.equals(original.trim()))
{
return original.trim();
}
String trimmed = piece.trim();
if (code == null || code.isBlank() || code.contains(","))
{
return trimmed;
}
if (trimmed.equalsIgnoreCase(code))
{
return code;
}
String name = trimmed.replaceAll("(?i)\\b" + Pattern.quote(code) + "\\b", "")
.replaceAll("[()()]", " ")
.trim();
return name.isEmpty() ? code : name;
}
private static int currencyHits(String text)
{
if (text == null || text.isBlank())
@@ -3,6 +3,7 @@ package com.bms.price.service;
import java.io.OutputStream;
import java.util.List;
import java.util.Date;
import com.bms.price.domain.PayFeeRuleGroup;
import com.bms.price.domain.PayPreview;
import com.bms.price.domain.PayPriceCompare;
import com.bms.price.domain.PayProduct;
@@ -74,4 +75,10 @@ public interface IPayProductService
void writeSource(Long productId, OutputStream output);
int deletePayProducts(Long[] productIds);
/** 按根产品编号带出附加费开关。没有配置过的产品返回空列表 */
List<PayFeeRuleGroup> listFeeRules(List<Long> productIds);
/** 按产品整组替换附加费开关。每个产品一份,互不影响 */
void saveFeeRules(List<PayFeeRuleGroup> products);
}
@@ -3,11 +3,13 @@ package com.bms.price.service.impl;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -26,6 +28,8 @@ import com.bms.common.utils.file.OssStorage;
import com.bms.common.utils.uuid.IdUtils;
import com.bms.price.domain.ChannelProductMap;
import com.bms.price.domain.PayExtraLine;
import com.bms.price.domain.PayFeeRuleGroup;
import com.bms.price.domain.PayProductFeeRule;
import com.bms.price.domain.PayPreview;
import com.bms.price.domain.PayPriceCompare;
import com.bms.price.domain.PayPriceDiff;
@@ -35,6 +39,7 @@ import com.bms.price.domain.PaySaveCommand;
import com.bms.price.domain.PaySurcharge;
import com.bms.price.domain.PayWeightBand;
import com.bms.price.mapper.ChannelProductMapMapper;
import com.bms.price.mapper.PayProductFeeRuleMapper;
import com.bms.price.mapper.PayProductMapper;
import com.bms.price.mapper.PayProductTermMapper;
import com.bms.price.pay.PayWorkbookParser;
@@ -64,6 +69,11 @@ public class PayProductServiceImpl implements IPayProductService
@Autowired
private PayProductTermMapper payProductTermMapper;
@Autowired
private PayProductFeeRuleMapper payProductFeeRuleMapper;
private static final Set<String> FEE_TRIGGERS = Set.of("SIZE", "VOLUME", "WEIGHT", "POSTCODE", "ALWAYS", "RETURN");
@Autowired
private ISysDictTypeService dictTypeService;
@@ -670,6 +680,7 @@ public class PayProductServiceImpl implements IPayProductService
return 0;
}
payProductTermMapper.deleteByProductIds(ids);
payProductFeeRuleMapper.deleteByProductIds(ids);
payProductMapper.deleteWeightBands(ids);
payProductMapper.deleteSurcharges(ids);
payProductMapper.deleteExtraLines(ids);
@@ -1216,6 +1227,176 @@ public class PayProductServiceImpl implements IPayProductService
return rows == null ? 0 : rows.size();
}
@Override
public List<PayFeeRuleGroup> listFeeRules(List<Long> productIds)
{
List<PayFeeRuleGroup> groups = new ArrayList<>();
if (productIds == null)
{
return groups;
}
LinkedHashSet<Long> ordered = new LinkedHashSet<>();
for (Long productId : productIds)
{
if (productId != null)
{
ordered.add(productId);
}
}
for (Long productId : ordered)
{
PayProduct root = requireRoot(productId);
PayFeeRuleGroup group = new PayFeeRuleGroup();
group.setProductId(root.getProductId());
group.setProductName(root.getProductName());
List<PayProductFeeRule> rules = payProductFeeRuleMapper.selectByProductId(root.getProductId());
group.setRules(rules == null ? new ArrayList<>() : rules);
groups.add(group);
}
return groups;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void saveFeeRules(List<PayFeeRuleGroup> products)
{
if (products == null || products.isEmpty())
{
throw new ServiceException("请选择应付产品");
}
String operator = SecurityUtils.getUsername();
Date now = DateUtils.getNowDate();
for (PayFeeRuleGroup group : products)
{
if (group == null || group.getProductId() == null)
{
throw new ServiceException("请选择应付产品");
}
PayProduct root = requireRoot(group.getProductId());
List<PayProductFeeRule> rules = normalizeFeeRules(root, group.getRules(), operator, now);
payProductFeeRuleMapper.deleteByProductId(root.getProductId());
if (!rules.isEmpty())
{
payProductFeeRuleMapper.insertBatch(rules);
}
}
}
private PayProduct requireRoot(Long productId)
{
PayProduct product = payProductMapper.selectPayProductById(productId);
if (product == null)
{
throw new ServiceException("应付产品不存在");
}
if (product.getOriginId() != null)
{
product = payProductMapper.selectPayProductById(product.getOriginId());
if (product == null)
{
throw new ServiceException("应付产品不存在");
}
}
return product;
}
private List<PayProductFeeRule> normalizeFeeRules(PayProduct root, List<PayProductFeeRule> source, String operator, Date now)
{
List<PayProductFeeRule> rules = new ArrayList<>();
Set<String> names = new HashSet<>();
String productName = root.getProductName() == null ? String.valueOf(root.getProductId()) : root.getProductName();
if (source == null)
{
return rules;
}
for (PayProductFeeRule raw : source)
{
if (raw == null || isBlank(raw.getFeeName()))
{
if (raw != null && (feeRuleFilled(raw) || feeRuleChanged(raw)))
{
throw new ServiceException(productName + "有未选择名称的附加费");
}
continue;
}
String feeName = raw.getFeeName().trim();
if (feeName.length() > 100)
{
throw new ServiceException(productName + "的附加费名称过长");
}
if (!names.add(feeName))
{
throw new ServiceException(productName + "的附加费「" + feeName + "」重复了");
}
String trigger = isBlank(raw.getTriggerType()) ? "ALWAYS" : raw.getTriggerType().trim().toUpperCase(Locale.ROOT);
if (!FEE_TRIGGERS.contains(trigger))
{
throw new ServiceException(productName + "的触发类型不正确");
}
String joinMode = isBlank(raw.getJoinMode()) ? "ANY" : raw.getJoinMode().trim().toUpperCase(Locale.ROOT);
if (!"ANY".equals(joinMode) && !"ALL".equals(joinMode))
{
throw new ServiceException(productName + "的命中方式不正确");
}
String enabled = "1".equals(raw.getEnabled()) ? "1" : "0";
checkFeeNumber(raw.getSideMaxCm(), productName, "最长边");
checkFeeNumber(raw.getSumMaxCm(), productName, "长宽高之和");
checkFeeNumber(raw.getVolumeMaxCm3(), productName, "体积");
checkFeeNumber(raw.getMinLengthCm(), productName, "最小长度");
checkFeeNumber(raw.getMinWidthCm(), productName, "最小宽度");
checkFeeNumber(raw.getMinHeightCm(), productName, "最小高度");
checkFeeNumber(raw.getWeightMaxKg(), productName, "重量上限");
String remark = raw.getRemark() == null ? null : raw.getRemark().trim();
if (remark != null && remark.length() > 500)
{
throw new ServiceException(productName + "的说明过长");
}
PayProductFeeRule rule = new PayProductFeeRule();
rule.setProductId(root.getProductId());
rule.setFeeName(feeName);
rule.setEnabled(enabled);
rule.setTriggerType(trigger);
rule.setSideMaxCm(raw.getSideMaxCm());
rule.setSumMaxCm(raw.getSumMaxCm());
rule.setVolumeMaxCm3(raw.getVolumeMaxCm3());
rule.setMinLengthCm(raw.getMinLengthCm());
rule.setMinWidthCm(raw.getMinWidthCm());
rule.setMinHeightCm(raw.getMinHeightCm());
rule.setWeightMaxKg(raw.getWeightMaxKg());
rule.setJoinMode(joinMode);
rule.setRemark(isBlank(remark) ? null : remark);
rule.setCreateBy(operator);
rule.setCreateTime(now);
rule.setUpdateBy(operator);
rule.setUpdateTime(now);
rules.add(rule);
}
return rules;
}
private static boolean feeRuleChanged(PayProductFeeRule rule)
{
String trigger = rule.getTriggerType() == null ? "" : rule.getTriggerType().trim();
String joinMode = rule.getJoinMode() == null ? "" : rule.getJoinMode().trim();
return (!trigger.isEmpty() && !"ALWAYS".equalsIgnoreCase(trigger))
|| (!joinMode.isEmpty() && !"ANY".equalsIgnoreCase(joinMode));
}
private static boolean feeRuleFilled(PayProductFeeRule rule)
{
return rule.getSideMaxCm() != null || rule.getSumMaxCm() != null || rule.getVolumeMaxCm3() != null
|| rule.getMinLengthCm() != null || rule.getMinWidthCm() != null || rule.getMinHeightCm() != null
|| rule.getWeightMaxKg() != null || !isBlank(rule.getRemark()) || "1".equals(rule.getEnabled());
}
private static void checkFeeNumber(BigDecimal value, String productName, String label)
{
if (value != null && value.signum() < 0)
{
throw new ServiceException(productName + "的" + label + "不能小于0");
}
}
private static boolean isBlank(String value)
{
return value == null || value.trim().isEmpty();
@@ -0,0 +1,42 @@
<?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.bms.price.mapper.PayProductFeeRuleMapper">
<select id="selectByProductId" resultType="com.bms.price.domain.PayProductFeeRule">
select rule_id as ruleId, product_id as productId, fee_name as feeName, enabled,
trigger_type as triggerType, side_max_cm as sideMaxCm, sum_max_cm as sumMaxCm,
volume_max_cm3 as volumeMaxCm3, min_length_cm as minLengthCm, min_width_cm as minWidthCm,
min_height_cm as minHeightCm, weight_max_kg as weightMaxKg, join_mode as joinMode,
remark, created_by as createBy, create_time as createTime, updated_by as updateBy,
update_time as updateTime
from pay_product_fee_rule
where product_id = #{productId}
order by rule_id
</select>
<delete id="deleteByProductId">
delete from pay_product_fee_rule where product_id = #{productId}
</delete>
<delete id="deleteByProductIds">
delete from pay_product_fee_rule where product_id in
<foreach collection="productIds" item="id" open="(" separator="," close=")">#{id}</foreach>
</delete>
<insert id="insertBatch">
insert into pay_product_fee_rule (
product_id, fee_name, enabled, trigger_type, side_max_cm, sum_max_cm, volume_max_cm3,
min_length_cm, min_width_cm, min_height_cm, weight_max_kg, join_mode, remark,
created_by, create_time, updated_by, update_time
) values
<foreach collection="list" item="item" separator=",">
(#{item.productId}, #{item.feeName}, #{item.enabled}, #{item.triggerType},
#{item.sideMaxCm}, #{item.sumMaxCm}, #{item.volumeMaxCm3},
#{item.minLengthCm}, #{item.minWidthCm}, #{item.minHeightCm}, #{item.weightMaxKg},
#{item.joinMode}, #{item.remark}, #{item.createBy}, #{item.createTime},
#{item.updateBy}, #{item.updateTime})
</foreach>
</insert>
</mapper>
+162
View File
@@ -0,0 +1,162 @@
-- 应付附加费类型。名称来自 D:\应付供应商 全部价卡的附加费收费项,已去重。
-- 可重复执行。
SET NAMES utf8mb4;
INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark)
SELECT '附加费类型', 'bms_surcharge_type', '0', 'admin', sysdate(), '应付价卡附加费名称'
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_dict_type WHERE dict_type = 'bms_surcharge_type');
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
SELECT v.dict_sort, v.dict_label, v.dict_value, 'bms_surcharge_type', '', 'default', 'N', '0', 'admin', sysdate(), '应付价卡附加费'
FROM (
SELECT 1 AS dict_sort, '疫情附加费' AS dict_label, '疫情附加费' AS dict_value
UNION ALL SELECT 2, '燃油附加费', '燃油附加费'
UNION ALL SELECT 3, '地址及联系方式修正费', '地址及联系方式修正费'
UNION ALL SELECT 4, '城市邮编不匹配', '城市邮编不匹配'
UNION ALL SELECT 5, '分拣机不可操作费', '分拣机不可操作费'
UNION ALL SELECT 6, '超重超尺寸费', '超重超尺寸费'
UNION ALL SELECT 7, '脱碳附加费', '脱碳附加费'
UNION ALL SELECT 8, '非法国电话联系费', '非法国电话联系费'
UNION ALL SELECT 9, '换面单费', '换面单费'
UNION ALL SELECT 10, '交错仓罚金', '交错仓罚金'
UNION ALL SELECT 11, '乡村邮编单量占比过大罚金', '乡村邮编单量占比过大罚金'
UNION ALL SELECT 12, '仿牌侵权罚款', '仿牌侵权罚款'
UNION ALL SELECT 13, '危险品罚款', '危险品罚款'
UNION ALL SELECT 14, '燃油费', '燃油费'
UNION ALL SELECT 15, '重派费', '重派费'
UNION ALL SELECT 16, '退件仓库操作费', '退件仓库操作费'
UNION ALL SELECT 17, '重派仓库操作费', '重派仓库操作费'
UNION ALL SELECT 18, '旺季附加费', '旺季附加费'
UNION ALL SELECT 19, '高峰旺季附加费', '高峰旺季附加费'
UNION ALL SELECT 20, '超尺寸超重费', '超尺寸超重费'
UNION ALL SELECT 21, '路由码选择附加费', '路由码选择附加费'
UNION ALL SELECT 22, '未预报附加费', '未预报附加费'
UNION ALL SELECT 23, '托收附加费', '托收附加费'
UNION ALL SELECT 24, '提供虚假信息罚款费', '提供虚假信息罚款费'
UNION ALL SELECT 25, '零售网点路线', '零售网点路线'
UNION ALL SELECT 26, '退件费', '退件费'
UNION ALL SELECT 27, '退件重派费', '退件重派费'
UNION ALL SELECT 28, '退件操作费', '退件操作费'
UNION ALL SELECT 29, '重派操作费', '重派操作费'
UNION ALL SELECT 30, '道路通行费', '道路通行费'
UNION ALL SELECT 31, '重量信息修正附加费', '重量信息修正附加费'
UNION ALL SELECT 32, '高风险地区附加费', '高风险地区附加费'
UNION ALL SELECT 33, '取还服务', '取还服务'
UNION ALL SELECT 34, '取货发货服务', '取货发货服务'
UNION ALL SELECT 35, '现金服务', '现金服务'
UNION ALL SELECT 36, '灵活配送服务', '灵活配送服务'
UNION ALL SELECT 37, '安全费', '安全费'
UNION ALL SELECT 38, '危机燃油附加费', '危机燃油附加费'
UNION ALL SELECT 39, '能源附加费', '能源附加费'
UNION ALL SELECT 40, '异形费', '异形费'
UNION ALL SELECT 41, '漏预报或漏发货', '漏预报或漏发货'
UNION ALL SELECT 42, '标签费', '标签费'
UNION ALL SELECT 43, '无法派送费', '无法派送费'
UNION ALL SELECT 44, '变更服务费', '变更服务费'
UNION ALL SELECT 45, '二次派送费', '二次派送费'
UNION ALL SELECT 46, '签名费', '签名费'
UNION ALL SELECT 47, '危险货物费', '危险货物费'
UNION ALL SELECT 48, '特殊产品加收', '特殊产品加收'
UNION ALL SELECT 49, '岛屿附加费', '岛屿附加费'
UNION ALL SELECT 50, '陆运能源附加费', '陆运能源附加费'
UNION ALL SELECT 51, '空运能源附加费', '空运能源附加费'
UNION ALL SELECT 52, '带电附加费', '带电附加费'
UNION ALL SELECT 53, '特货费', '特货费'
UNION ALL SELECT 54, '偏远费', '偏远费'
UNION ALL SELECT 55, '偏远地区附加费', '偏远地区附加费'
UNION ALL SELECT 56, '超大附加费(包裹)', '超大附加费(包裹)'
UNION ALL SELECT 57, '超重附加费(包裹)', '超重附加费(包裹)'
UNION ALL SELECT 58, '重复单号', '重复单号'
UNION ALL SELECT 59, '未预报', '未预报'
UNION ALL SELECT 60, '无法投递或其他原因退件运费', '无法投递或其他原因退件运费'
UNION ALL SELECT 61, '航司可持续性附加费', '航司可持续性附加费'
UNION ALL SELECT 62, '退件处理费', '退件处理费'
UNION ALL SELECT 63, '超尺寸费', '超尺寸费'
UNION ALL SELECT 64, '周末服务费', '周末服务费'
UNION ALL SELECT 65, '空气清洁费', '空气清洁费'
UNION ALL SELECT 66, '拖车附加费', '拖车附加费'
UNION ALL SELECT 67, '派送附加费', '派送附加费'
UNION ALL SELECT 68, '自送海外仓运费', '自送海外仓运费'
UNION ALL SELECT 69, '操作费', '操作费'
UNION ALL SELECT 70, '仓库操作费', '仓库操作费'
UNION ALL SELECT 71, '重新包装费', '重新包装费'
UNION ALL SELECT 72, '换包装费', '换包装费'
UNION ALL SELECT 73, '去碳附加费', '去碳附加费'
UNION ALL SELECT 74, '超重费', '超重费'
UNION ALL SELECT 75, '地址修正费', '地址修正费'
UNION ALL SELECT 76, '邮编城市不对应费', '邮编城市不对应费'
UNION ALL SELECT 77, '邮箱和电话缺失费', '邮箱和电话缺失费'
UNION ALL SELECT 78, '人工处理费', '人工处理费'
UNION ALL SELECT 79, '海外省费', '海外省费'
UNION ALL SELECT 80, '错误送仓罚款', '错误送仓罚款'
UNION ALL SELECT 81, '更换面单费', '更换面单费'
UNION ALL SELECT 82, '乡村地区占比超标准罚款', '乡村地区占比超标准罚款'
UNION ALL SELECT 83, 'COD', 'COD'
UNION ALL SELECT 84, '重新贴标附加费', '重新贴标附加费'
UNION ALL SELECT 85, '重派运费', '重派运费'
UNION ALL SELECT 86, '短期能源附加费', '短期能源附加费'
UNION ALL SELECT 87, '旺季高峰期附加费', '旺季高峰期附加费'
UNION ALL SELECT 88, '面单错误附加费', '面单错误附加费'
UNION ALL SELECT 89, '零售网点自提费', '零售网点自提费'
UNION ALL SELECT 90, '异形件费', '异形件费'
UNION ALL SELECT 91, '重量差异附加费', '重量差异附加费'
UNION ALL SELECT 92, '换单费', '换单费'
UNION ALL SELECT 93, '无法投递处理费', '无法投递处理费'
UNION ALL SELECT 94, '无法投递处理费-陆运', '无法投递处理费-陆运'
UNION ALL SELECT 95, '无法投递处理费-空运', '无法投递处理费-空运'
UNION ALL SELECT 96, '战争附加费', '战争附加费'
UNION ALL SELECT 97, '超尺寸附加费', '超尺寸附加费'
UNION ALL SELECT 98, '偏远附加费', '偏远附加费'
UNION ALL SELECT 99, '空气减排费', '空气减排费'
UNION ALL SELECT 100, '面单无法识别费', '面单无法识别费'
UNION ALL SELECT 101, '无法派送或退件费', '无法派送或退件费'
UNION ALL SELECT 102, '超重附加费', '超重附加费'
UNION ALL SELECT 103, '重复单号费', '重复单号费'
UNION ALL SELECT 104, '使用取消单号发货费', '使用取消单号发货费'
UNION ALL SELECT 105, '面单不符费', '面单不符费'
UNION ALL SELECT 106, '面单粘贴不合规范', '面单粘贴不合规范'
UNION ALL SELECT 107, '未经允许乱交邮费', '未经允许乱交邮费'
UNION ALL SELECT 108, '异形件附加费', '异形件附加费'
UNION ALL SELECT 109, '退件费(陆运)', '退件费(陆运)'
UNION ALL SELECT 110, '退件费(空运)', '退件费(空运)'
UNION ALL SELECT 111, '邮编城市不对应', '邮编城市不对应'
UNION ALL SELECT 112, '收件人信息错误处理费', '收件人信息错误处理费'
UNION ALL SELECT 113, '无法过机操作费', '无法过机操作费'
UNION ALL SELECT 114, '不可达地址费', '不可达地址费'
UNION ALL SELECT 115, '销毁费', '销毁费'
UNION ALL SELECT 116, '仓储费', '仓储费'
UNION ALL SELECT 117, 'CO₂附加费', 'CO₂附加费'
UNION ALL SELECT 118, '退回件处理费', '退回件处理费'
UNION ALL SELECT 119, '异形件/超尺寸处理费', '异形件/超尺寸处理费'
UNION ALL SELECT 120, '重量申报错误操作费', '重量申报错误操作费'
UNION ALL SELECT 121, '垃圾处理费', '垃圾处理费'
UNION ALL SELECT 122, '绿色附加费', '绿色附加费'
UNION ALL SELECT 123, '无法投递费', '无法投递费'
UNION ALL SELECT 124, '额外处理费', '额外处理费'
UNION ALL SELECT 125, '超大件', '超大件'
UNION ALL SELECT 126, '超限制', '超限制'
UNION ALL SELECT 127, '地址更正', '地址更正'
UNION ALL SELECT 128, '扩展区域收货和送货服务', '扩展区域收货和送货服务'
UNION ALL SELECT 129, '偏远地区收货和送货服务', '偏远地区收货和送货服务'
UNION ALL SELECT 130, '私人地址派送费', '私人地址派送费'
UNION ALL SELECT 131, '包裹信息缺失', '包裹信息缺失'
UNION ALL SELECT 132, '高峰附加费', '高峰附加费'
UNION ALL SELECT 133, '更改地址费', '更改地址费'
UNION ALL SELECT 134, '空气减排附加费', '空气减排附加费'
UNION ALL SELECT 135, '异地取货费', '异地取货费'
UNION ALL SELECT 136, '包裹退件运费', '包裹退件运费'
UNION ALL SELECT 137, '退件入仓处理费', '退件入仓处理费'
UNION ALL SELECT 138, '退件重派操作费', '退件重派操作费'
UNION ALL SELECT 139, '退件重派运费', '退件重派运费'
UNION ALL SELECT 140, '退件销毁费', '退件销毁费'
UNION ALL SELECT 141, 'Bulky goods Fee', 'Bulky goods Fee'
UNION ALL SELECT 142, '地址校验费', '地址校验费'
UNION ALL SELECT 143, 'Labeling fee', 'Labeling fee'
UNION ALL SELECT 144, '瑞典和芬兰门到门派送费', '瑞典和芬兰门到门派送费'
UNION ALL SELECT 145, '特别旺季附加费', '特别旺季附加费'
UNION ALL SELECT 146, '脱欧手续费', '脱欧手续费'
) v
WHERE NOT EXISTS (
SELECT 1 FROM sys_dict_data d
WHERE d.dict_type = 'bms_surcharge_type' AND d.dict_value = v.dict_value
);
+23
View File
@@ -88,6 +88,29 @@ CREATE TABLE IF NOT EXISTS `pay_extra_line` (
KEY `idx_pay_extra_product` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应付产品上的邮编或其他配置原文';
CREATE TABLE IF NOT EXISTS `pay_product_fee_rule` (
`rule_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '规则ID',
`product_id` bigint(20) NOT NULL COMMENT '根产品编号,渠道应付绑定的产品,不是某一版导入的版本号',
`fee_name` varchar(100) NOT NULL COMMENT '附加费名称,对应价卡附加费行,用来取价',
`enabled` char(1) NOT NULL DEFAULT '0' COMMENT '1参与计算,0不参与',
`trigger_type` varchar(20) NOT NULL DEFAULT 'ALWAYS' COMMENT '触发类型:SIZE尺寸 VOLUME体积 WEIGHT重量 POSTCODE邮编 ALWAYS每票 RETURN退件',
`side_max_cm` decimal(10,2) DEFAULT NULL COMMENT '最长边上限,厘米,超出则命中',
`sum_max_cm` decimal(10,2) DEFAULT NULL COMMENT '长+宽+高上限,厘米,超出则命中',
`volume_max_cm3` decimal(14,2) DEFAULT NULL COMMENT '体积上限,立方厘米,长×宽×高超出则命中',
`min_length_cm` decimal(10,2) DEFAULT NULL COMMENT '最小长度,厘米,小于则命中',
`min_width_cm` decimal(10,2) DEFAULT NULL COMMENT '最小宽度,厘米,小于则命中',
`min_height_cm` decimal(10,2) DEFAULT NULL COMMENT '最小高度,厘米,小于则命中',
`weight_max_kg` decimal(10,3) DEFAULT NULL COMMENT '重量上限,千克,计费重超出则命中',
`join_mode` varchar(10) NOT NULL DEFAULT 'ANY' COMMENT 'ANY任一条超出就收,ALL写了的条件都超出才收',
`remark` varchar(500) DEFAULT NULL COMMENT '说明,不参与判断',
`created_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`updated_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`rule_id`),
UNIQUE KEY `uk_pay_fee_rule_product` (`product_id`, `fee_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应付产品附加费开关';
-- 菜单挂在价格基础下面
SET @parentId := (
SELECT menu_id FROM sys_menu
@@ -0,0 +1,25 @@
-- 应付产品附加费开关。挂在根产品上,同一产品同一费用名称一行。可重复执行。
SET NAMES utf8mb4;
CREATE TABLE IF NOT EXISTS `pay_product_fee_rule` (
`rule_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '规则ID',
`product_id` bigint(20) NOT NULL COMMENT '根产品编号,渠道应付绑定的产品,不是某一版导入的版本号',
`fee_name` varchar(100) NOT NULL COMMENT '附加费名称,对应价卡附加费行,用来取价',
`enabled` char(1) NOT NULL DEFAULT '0' COMMENT '1参与计算,0不参与',
`trigger_type` varchar(20) NOT NULL DEFAULT 'ALWAYS' COMMENT '触发类型:SIZE尺寸 VOLUME体积 WEIGHT重量 POSTCODE邮编 ALWAYS每票 RETURN退件',
`side_max_cm` decimal(10,2) DEFAULT NULL COMMENT '最长边上限,厘米,超出则命中',
`sum_max_cm` decimal(10,2) DEFAULT NULL COMMENT '长+宽+高上限,厘米,超出则命中',
`volume_max_cm3` decimal(14,2) DEFAULT NULL COMMENT '体积上限,立方厘米,长×宽×高超出则命中',
`min_length_cm` decimal(10,2) DEFAULT NULL COMMENT '最小长度,厘米,小于则命中',
`min_width_cm` decimal(10,2) DEFAULT NULL COMMENT '最小宽度,厘米,小于则命中',
`min_height_cm` decimal(10,2) DEFAULT NULL COMMENT '最小高度,厘米,小于则命中',
`weight_max_kg` decimal(10,3) DEFAULT NULL COMMENT '重量上限,千克,计费重超出则命中',
`join_mode` varchar(10) NOT NULL DEFAULT 'ANY' COMMENT 'ANY任一条超出就收,ALL写了的条件都超出才收',
`remark` varchar(500) DEFAULT NULL COMMENT '说明,不参与判断',
`created_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`updated_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`rule_id`),
UNIQUE KEY `uk_pay_fee_rule_product` (`product_id`, `fee_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应付产品附加费开关';