Browse Source
新增 ValueMethodEnum 与 SplitMergeStrategyEnum 承载字段可选值,消除魔法值, 并为二者补充 parse/validOptions 方法供保存校验使用。 保存入口(addAll/editAll)统一增加 validateBeforeSave 前置校验, 校验不通过抛 MyRuntimeException 阻止保存,且早于任何写库操作,避免脏数据。 - 取值方式:为空或未知时阻止保存,错误信息定位到分录行号、源字段、 目标字段、非法值、合法选项及分录id - 分单策略:未配置按默认「一对一」放行;非法值阻止保存;选择「按规则分组合并」 但未配置分单字段时阻止保存 - 事务:addAll/editAll 涉及主表与分录的多次独立写库(editAll 为先删后插), 此前无事务边界,中途失败会造成主表已改、分录残缺或产生无分录的空规则。 现补充 @Transactional(rollbackFor = Exception.class),removeChild 一并补充 files: common/common-botp/src/main/java/apelet/common/botp/model/constant/ValueMethodEnum.java common/common-botp/src/main/java/apelet/common/botp/model/constant/SplitMergeStrategyEnum.java common/common-botp/src/main/java/apelet/common/botp/service/impl/ConvertRuleServiceImpl.javadev-lml
3 changed files with 310 additions and 1 deletions
@ -0,0 +1,99 @@
@@ -0,0 +1,99 @@
|
||||
package apelet.common.botp.model.constant; |
||||
|
||||
import lombok.Getter; |
||||
import org.apache.commons.lang3.StringUtils; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Map; |
||||
import java.util.Optional; |
||||
import java.util.stream.Collectors; |
||||
|
||||
/** |
||||
* 分单/合并策略枚举。 |
||||
* |
||||
* <p>对应 convert_rule.split_merge_strategy,落库为 varchar 的 "1"/"2"/"3",默认按「一对一」处理。</p> |
||||
* |
||||
* @author admin |
||||
* @since 2024-01-18 |
||||
*/ |
||||
public enum SplitMergeStrategyEnum { |
||||
|
||||
/** |
||||
* 一对一:一条源单对应一条目标单。 |
||||
*/ |
||||
ONE_TO_ONE("1", "一对一"), |
||||
|
||||
/** |
||||
* 多对一:多条源单合并为一条目标单。 |
||||
*/ |
||||
MANY_TO_ONE("2", "多对一"), |
||||
|
||||
/** |
||||
* 按规则分组合并:按分单字段分组后分别合并。 |
||||
*/ |
||||
GROUP_BY_RULE("3", "按规则分组合并"); |
||||
|
||||
@Getter |
||||
private final String code; |
||||
|
||||
@Getter |
||||
private final String description; |
||||
|
||||
private static final Map<String, SplitMergeStrategyEnum> ENUM_MAP; |
||||
|
||||
SplitMergeStrategyEnum(String code, String description) { |
||||
this.code = code; |
||||
this.description = description; |
||||
} |
||||
|
||||
static { |
||||
ENUM_MAP = Arrays.stream(values()).collect(Collectors.toMap(SplitMergeStrategyEnum::getCode, e -> e)); |
||||
} |
||||
|
||||
/** |
||||
* 根据 code 获取枚举对象。 |
||||
* |
||||
* @param code 分单策略编码。 |
||||
* @return 枚举对象。 |
||||
*/ |
||||
public static SplitMergeStrategyEnum of(String code) { |
||||
return Optional.ofNullable(ENUM_MAP.get(code)) |
||||
.orElseThrow(() -> new IllegalArgumentException("无法根据 code 获取分单策略:" + code)); |
||||
} |
||||
|
||||
/** |
||||
* 根据 code 获取枚举对象,空值按「一对一」处理(与字段默认值一致)。 |
||||
* |
||||
* @param code 分单策略编码。 |
||||
* @return 枚举对象。 |
||||
*/ |
||||
public static SplitMergeStrategyEnum ofNullable(String code) { |
||||
if (StringUtils.isBlank(code)) { |
||||
return ONE_TO_ONE; |
||||
} |
||||
return of(code.trim()); |
||||
} |
||||
|
||||
/** |
||||
* 根据 code 获取枚举对象,空值或未知 code 均返回 null(不兜底、不抛异常)。 |
||||
* |
||||
* <p>供保存校验等场景使用:需要区分「未配置」与「配置了非法值」时,用本方法。</p> |
||||
* |
||||
* @param code 分单策略编码。 |
||||
* @return 枚举对象;不是已知编码时返回 null。 |
||||
*/ |
||||
public static SplitMergeStrategyEnum parse(String code) { |
||||
return StringUtils.isBlank(code) ? null : ENUM_MAP.get(code.trim()); |
||||
} |
||||
|
||||
/** |
||||
* 生成可选值说明,用于错误提示。 |
||||
* |
||||
* @return 形如「1-一对一 2-多对一 3-按规则分组合并」。 |
||||
*/ |
||||
public static String validOptions() { |
||||
return Arrays.stream(values()) |
||||
.map(e -> e.getCode() + "-" + e.getDescription()) |
||||
.collect(Collectors.joining(" ")); |
||||
} |
||||
} |
||||
@ -0,0 +1,105 @@
@@ -0,0 +1,105 @@
|
||||
package apelet.common.botp.model.constant; |
||||
|
||||
import lombok.Getter; |
||||
import org.apache.commons.lang3.StringUtils; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Map; |
||||
import java.util.Optional; |
||||
import java.util.stream.Collectors; |
||||
|
||||
/** |
||||
* 字段取值方式枚举。 |
||||
* |
||||
* <p>对应 convert_fieldmapping_entry.value_method,落库为 varchar 的 "1"/"2"/"3"/"4"。</p> |
||||
* |
||||
* @author admin |
||||
* @since 2024-01-18 |
||||
*/ |
||||
public enum ValueMethodEnum { |
||||
|
||||
/** |
||||
* 映射:取源单同名字段的值。 |
||||
*/ |
||||
MAPPING("1", "映射"), |
||||
|
||||
/** |
||||
* 常量:直接使用配置的固定值。 |
||||
*/ |
||||
CONSTANT("2", "常量"), |
||||
|
||||
/** |
||||
* 计算公式:按配置的公式表达式计算。 |
||||
*/ |
||||
EXPRESSION("3", "计算公式"), |
||||
|
||||
/** |
||||
* 按条件取值 |
||||
*/ |
||||
CONDITION("4", "按条件取值") |
||||
; |
||||
|
||||
@Getter |
||||
private final String code; |
||||
|
||||
@Getter |
||||
private final String description; |
||||
|
||||
private static final Map<String, ValueMethodEnum> ENUM_MAP; |
||||
|
||||
ValueMethodEnum(String code, String description) { |
||||
this.code = code; |
||||
this.description = description; |
||||
} |
||||
|
||||
static { |
||||
ENUM_MAP = Arrays.stream(values()).collect(Collectors.toMap(ValueMethodEnum::getCode, e -> e)); |
||||
} |
||||
|
||||
/** |
||||
* 根据 code 获取枚举对象。 |
||||
* |
||||
* @param code 取值方式编码。 |
||||
* @return 枚举对象。 |
||||
*/ |
||||
public static ValueMethodEnum of(String code) { |
||||
return Optional.ofNullable(ENUM_MAP.get(code)) |
||||
.orElseThrow(() -> new IllegalArgumentException("无法根据 code 获取字段取值方式:" + code)); |
||||
} |
||||
|
||||
/** |
||||
* 根据 code 获取枚举对象,空值按「映射」处理(与字段默认值一致)。 |
||||
* |
||||
* @param code 取值方式编码。 |
||||
* @return 枚举对象。 |
||||
*/ |
||||
public static ValueMethodEnum ofNullable(String code) { |
||||
if (StringUtils.isBlank(code)) { |
||||
return MAPPING; |
||||
} |
||||
return of(code.trim()); |
||||
} |
||||
|
||||
/** |
||||
* 根据 code 获取枚举对象,空值或未知 code 均返回 null(不兜底、不抛异常)。 |
||||
* |
||||
* <p>供保存校验等场景使用:需要区分「未配置」与「配置了非法值」时,用本方法。</p> |
||||
* |
||||
* @param code 取值方式编码。 |
||||
* @return 枚举对象;不是已知编码时返回 null。 |
||||
*/ |
||||
public static ValueMethodEnum parse(String code) { |
||||
return StringUtils.isBlank(code) ? null : ENUM_MAP.get(code.trim()); |
||||
} |
||||
|
||||
/** |
||||
* 生成可选值说明,用于错误提示。 |
||||
* |
||||
* @return 形如「1-映射 2-常量 3-计算公式 4-按条件取值」。 |
||||
*/ |
||||
public static String validOptions() { |
||||
return Arrays.stream(values()) |
||||
.map(e -> e.getCode() + "-" + e.getDescription()) |
||||
.collect(Collectors.joining(" ")); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue