package jnpf.elnService.formula.impl;
|
|
import cn.hutool.core.util.IdUtil;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import jnpf.audit.model.AuditEventDTO;
|
import jnpf.audit.sdk.AuditClient;
|
import jnpf.elnEntity.field.ElnFieldVersionEntity;
|
import jnpf.elnEntity.formula.ElnFormulaDefEntity;
|
import jnpf.elnEntity.formula.ElnFormulaForms;
|
import jnpf.elnEntity.formula.ElnFormulaParameterSlotEntity;
|
import jnpf.elnEntity.formula.ElnFormulaVersionEntity;
|
import jnpf.elnEntity.formula.ElnFormulaVos;
|
import jnpf.elnEntity.formula.ElnTemplateFormulaBindingEntity;
|
import jnpf.elnEntity.template.ElnTemplateBindingEntity;
|
import jnpf.elnEntity.template.ElnTemplateVersionEntity;
|
import jnpf.elnMapper.ElnTemplateMapper;
|
import jnpf.elnMapper.ElnFieldVersionMapper;
|
import jnpf.elnMapper.ElnFormulaDefMapper;
|
import jnpf.elnMapper.ElnFormulaParameterSlotMapper;
|
import jnpf.elnMapper.ElnFormulaVersionMapper;
|
import jnpf.elnMapper.ElnTemplateBindingMapper;
|
import jnpf.elnMapper.ElnTemplateCrossReferenceMapper;
|
import jnpf.elnMapper.ElnTemplateFormulaBindingMapper;
|
import jnpf.elnService.formula.ElnTemplateFormulaBindingService;
|
import jnpf.elnService.formula.FormulaDependencyGraph;
|
import jnpf.elnService.template.TemplateAnnotationAuthorization;
|
import jnpf.exception.DataException;
|
import jnpf.util.JsonUtil;
|
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.StringUtils;
|
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.Date;
|
import java.util.LinkedHashMap;
|
import java.util.LinkedHashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.Set;
|
import java.util.function.Consumer;
|
import java.util.function.Supplier;
|
|
@Service
|
@Transactional(rollbackFor = Exception.class)
|
public class ElnTemplateFormulaBindingServiceImpl
|
implements ElnTemplateFormulaBindingService {
|
|
private static final String ACTIVE = "ACTIVE";
|
private static final String PENDING = "PENDING";
|
private static final String CANCELLED = "CANCELLED";
|
private static final String REMOVED = "REMOVED";
|
private static final String PUBLISHED = "PUBLISHED";
|
private static final String PRE_RELEASE = "PRE_RELEASE";
|
|
private final Store store;
|
private final FormulaDependencyGraph graph;
|
private final Supplier<String> idSupplier;
|
private final Consumer<AuditEventDTO> auditRecorder;
|
private final long pendingTimeoutMinutes;
|
private final ResultBindingGuard resultBindingGuard;
|
|
@Autowired
|
public ElnTemplateFormulaBindingServiceImpl(ElnTemplateMapper templateMapper,
|
ElnFormulaDefMapper definitionMapper, ElnFormulaVersionMapper formulaVersionMapper,
|
ElnFormulaParameterSlotMapper slotMapper, ElnTemplateBindingMapper fieldBindingMapper,
|
ElnFieldVersionMapper fieldVersionMapper,
|
ElnTemplateFormulaBindingMapper formulaBindingMapper,
|
ElnTemplateCrossReferenceMapper crossReferenceMapper,
|
ObjectProvider<AuditClient> auditClientProvider,
|
@Value("${eln.template-formula-binding.pending-timeout-minutes:30}") long timeout) {
|
this(new MyBatisStore(templateMapper, definitionMapper, formulaVersionMapper, slotMapper,
|
fieldBindingMapper, fieldVersionMapper, formulaBindingMapper),
|
new FormulaDependencyGraph(), IdUtil::getSnowflakeNextIdStr, event -> {
|
AuditClient client = auditClientProvider.getIfAvailable();
|
if (client != null) client.record(event);
|
}, timeout, (tenantId, bindingId) -> crossReferenceMapper.selectCount(
|
Wrappers.<jnpf.elnEntity.template.ElnTemplateCrossReferenceEntity>lambdaQuery()
|
.eq(jnpf.elnEntity.template.ElnTemplateCrossReferenceEntity::getFTenantId, tenantId)
|
.eq(jnpf.elnEntity.template.ElnTemplateCrossReferenceEntity::getMubanBangdingId, bindingId)
|
.eq(jnpf.elnEntity.template.ElnTemplateCrossReferenceEntity::getFDeleteMark, 0)) > 0);
|
}
|
|
public ElnTemplateFormulaBindingServiceImpl(Store store, FormulaDependencyGraph graph,
|
Supplier<String> idSupplier, Consumer<AuditEventDTO> auditRecorder,
|
long pendingTimeoutMinutes) {
|
this(store, graph, idSupplier, auditRecorder, pendingTimeoutMinutes, (tenantId, bindingId) -> false);
|
}
|
|
ElnTemplateFormulaBindingServiceImpl(Store store, FormulaDependencyGraph graph,
|
Supplier<String> idSupplier, Consumer<AuditEventDTO> auditRecorder,
|
long pendingTimeoutMinutes, ResultBindingGuard resultBindingGuard) {
|
this.store = store;
|
this.graph = graph;
|
this.idSupplier = idSupplier;
|
this.auditRecorder = auditRecorder;
|
this.pendingTimeoutMinutes = pendingTimeoutMinutes;
|
this.resultBindingGuard = resultBindingGuard;
|
}
|
|
@Override
|
@Transactional(readOnly = true)
|
public List<ElnFormulaVos.TemplateBinding> list(TemplateAnnotationAuthorization authorization) {
|
requireAuthorization(authorization);
|
List<ElnFormulaVos.TemplateBinding> result = new ArrayList<>();
|
for (ElnTemplateFormulaBindingEntity item : store.listBindings(
|
authorization.getTenantId(), authorization.getTemplateId())) {
|
if (!REMOVED.equals(item.getBangdingZhuangtai())
|
&& !CANCELLED.equals(item.getBangdingZhuangtai())) result.add(toVo(item));
|
}
|
return result;
|
}
|
|
@Override
|
@Transactional(readOnly = true)
|
public ElnFormulaVos.TemplateMappingContext context(
|
TemplateAnnotationAuthorization authorization) {
|
requireAuthorization(authorization);
|
ElnFormulaVos.TemplateMappingContext result = new ElnFormulaVos.TemplateMappingContext();
|
List<ElnTemplateFormulaBindingEntity> bindings = store.listBindings(
|
authorization.getTenantId(), authorization.getTemplateId());
|
for (ElnTemplateFormulaBindingEntity item : bindings) {
|
if (!REMOVED.equals(item.getBangdingZhuangtai())
|
&& !CANCELLED.equals(item.getBangdingZhuangtai())) {
|
result.getBindings().add(toVo(item));
|
}
|
if (PENDING.equals(item.getBangdingZhuangtai())
|
&& StringUtils.hasText(item.getLaiyuanGongshiBangdingId())) {
|
result.getCopiedPendingBindingIds().add(item.getId());
|
}
|
}
|
if (!result.getCopiedPendingBindingIds().isEmpty()) {
|
ElnTemplateVersionEntity template = store.findTemplate(
|
authorization.getTenantId(), authorization.getTemplateId());
|
if (template != null) result.setUpgradeOperationCode(template.getShengbanCaozuoBianma());
|
}
|
addInheritedFormulaLockBindings(authorization, result);
|
|
Map<String, ElnFormulaDefEntity> definitions = new LinkedHashMap<>();
|
for (ElnFormulaDefEntity item : store.listFormulaDefinitions(authorization.getTenantId())) {
|
definitions.put(item.getId(), item);
|
}
|
for (ElnFormulaVersionEntity item : store.listFormulaVersions(authorization.getTenantId())) {
|
ElnFormulaDefEntity definition = definitions.get(item.getGongshiDingyiId());
|
if (definition == null || (!PRE_RELEASE.equals(item.getBizStatus())
|
&& !PUBLISHED.equals(item.getBizStatus()))) continue;
|
result.getVersions().add(toTemplateFormulaVersion(authorization.getTenantId(),
|
definition, item));
|
}
|
return result;
|
}
|
|
private void addInheritedFormulaLockBindings(TemplateAnnotationAuthorization authorization,
|
ElnFormulaVos.TemplateMappingContext context) {
|
ElnTemplateVersionEntity target = store.findTemplate(
|
authorization.getTenantId(), authorization.getTemplateId());
|
if (target == null || !StringUtils.hasText(target.getLaiyuanMubanId())) return;
|
Set<String> sourceResultBindingIds = new LinkedHashSet<>();
|
for (ElnTemplateFormulaBindingEntity formula : store.listBindings(
|
authorization.getTenantId(), target.getLaiyuanMubanId())) {
|
if (ACTIVE.equals(formula.getBangdingZhuangtai())) {
|
sourceResultBindingIds.add(formula.getJieguoBangdingId());
|
}
|
}
|
if (sourceResultBindingIds.isEmpty()) return;
|
List<ElnTemplateBindingEntity> targetBindings = store.listFieldBindings(
|
authorization.getTenantId(), authorization.getTemplateId());
|
Set<String> targetResultBindingIds = new LinkedHashSet<>();
|
for (ElnTemplateBindingEntity binding : targetBindings) {
|
if (PENDING.equals(binding.getBangdingZhuangtai())
|
&& "PRIMARY".equals(binding.getKongjianJuese())
|
&& sourceResultBindingIds.contains(binding.getLaiyuanBangdingId())) {
|
targetResultBindingIds.add(binding.getId());
|
}
|
}
|
List<String> inherited = new ArrayList<>();
|
for (ElnTemplateBindingEntity binding : targetBindings) {
|
if (!PENDING.equals(binding.getBangdingZhuangtai())) continue;
|
if (targetResultBindingIds.contains(binding.getId())
|
|| ("REFERENCE".equals(binding.getKongjianJuese())
|
&& targetResultBindingIds.contains(binding.getYinyongShiliId()))) {
|
inherited.add(binding.getId());
|
}
|
}
|
Collections.sort(inherited);
|
context.setInheritedFormulaLockBindingIds(inherited);
|
}
|
|
@Override
|
public ElnFormulaVos.TemplateBinding reserve(TemplateAnnotationAuthorization authorization,
|
ElnFormulaForms.TemplateBinding form) {
|
requireAuthorization(authorization);
|
String operation = normalizeOperation(form == null ? null : form.getOperationCode());
|
form.setOperationCode(operation);
|
ElnTemplateFormulaBindingEntity existing = store.findByOperation(authorization.getTenantId(),
|
authorization.getTemplateId(), operation);
|
if (existing != null) {
|
ElnFormulaVersionEntity requestedVersion = store.findFormulaVersion(
|
authorization.getTenantId(), trim(form.getFormulaVersionId()));
|
if (requestedVersion == null || !sameReserve(existing, authorization, form,
|
requestedVersion.getGongshiDingyiId(), operation))
|
throw new DataException("操作码已用于其他公式映射请求");
|
return toVo(existing);
|
}
|
ValidatedMapping validated = validateRequest(authorization, form, null);
|
requireOriginalResultLockSnapshot(authorization, form.getResultBindingId(),
|
form.getJieguoSuoKuaizhao());
|
ElnTemplateFormulaBindingEntity created = new ElnTemplateFormulaBindingEntity();
|
created.setId(idSupplier.get());
|
created.setFTenantId(authorization.getTenantId());
|
created.setMubanId(authorization.getTemplateId());
|
created.setGongshiDingyiId(validated.definition.getId());
|
created.setGongshiBanbenId(validated.version.getId());
|
created.setCanshuYingshe(new LinkedHashMap<>(form.getParameterBindings()));
|
created.setJieguoBangdingId(form.getResultBindingId().trim());
|
created.setBangdingZhuangtai(PENDING);
|
created.setCaozuoBianma(operation);
|
created.setJieguoSuoKuaizhao(copyControls(form.getJieguoSuoKuaizhao()));
|
created.setDaoqiShijian(new Date(System.currentTimeMillis() + pendingTimeoutMinutes * 60_000L));
|
created.setFVersion(1);
|
created.setFCreatorUserId(authorization.getUserId());
|
created.setFCreatorTime(new Date());
|
created.setFDeleteMark(0);
|
if (!store.insertIfAbsent(created)) {
|
ElnTemplateFormulaBindingEntity concurrent = store.findByOperation(
|
authorization.getTenantId(), authorization.getTemplateId(), operation);
|
if (concurrent == null || !sameReserve(concurrent, authorization, form,
|
validated.definition.getId(), operation))
|
throw new DataException("操作码已用于其他公式映射请求");
|
return toVo(concurrent);
|
}
|
audit("ELN_TEMPLATE_FORMULA_RESERVE", authorization, created, null, created, null);
|
return toVo(created);
|
}
|
|
@Override
|
public void activate(TemplateAnnotationAuthorization authorization, String formulaBindingId,
|
ElnFormulaForms.ActivateFormulaBinding form) {
|
lockTemplateGraph(authorization);
|
ElnTemplateFormulaBindingEntity binding = requireOwned(authorization, formulaBindingId);
|
String operation = form == null ? null : normalizeOperation(form.getOperationCode());
|
if (form != null) form.setOperationCode(operation);
|
if (form != null && ACTIVE.equals(binding.getBangdingZhuangtai())
|
&& alreadyApplied(binding, form.getExpectedVersion(), operation)) return;
|
requireMutation(binding, operation,
|
form == null ? null : form.getExpectedVersion(), PENDING);
|
validateRequest(authorization, request(binding), binding.getId());
|
requireResultLocked(authorization, binding.getJieguoBangdingId(), form.getControls());
|
ElnTemplateFormulaBindingEntity before = copy(binding);
|
if (!store.updateStatus(binding, form.getExpectedVersion(), ACTIVE, null))
|
throw new DataException("公式映射版本冲突");
|
FormulaDependencyGraph.Result result = validateGraph(
|
authorization.getTenantId(), authorization.getTemplateId());
|
if (!result.isValid()) throw new DataException("公式依赖存在循环: " + result.getCyclePath());
|
audit("ELN_TEMPLATE_FORMULA_ACTIVATE", authorization, binding, before, binding, null);
|
}
|
|
@Override
|
public void cancel(TemplateAnnotationAuthorization authorization, String formulaBindingId,
|
ElnFormulaForms.CancelFormulaBinding form) {
|
ElnTemplateFormulaBindingEntity binding = requireOwned(authorization, formulaBindingId);
|
String operation = form == null ? null : normalizeOperation(form.getOperationCode());
|
if (form != null) form.setOperationCode(operation);
|
if (form != null && CANCELLED.equals(binding.getBangdingZhuangtai())
|
&& alreadyApplied(binding, form.getExpectedVersion(), operation)) return;
|
requireMutation(binding, operation,
|
form == null ? null : form.getExpectedVersion(), PENDING);
|
ElnTemplateFormulaBindingEntity before = copy(binding);
|
if (!store.updateStatus(binding, form.getExpectedVersion(), CANCELLED,
|
trimToNull(form.getReason()))) throw new DataException("公式映射版本冲突");
|
audit("ELN_TEMPLATE_FORMULA_CANCEL", authorization, binding, before, binding,
|
trimToNull(form.getReason()));
|
}
|
|
@Override
|
public ElnFormulaVos.MappingCheck checkUpgrade(TemplateAnnotationAuthorization authorization,
|
String formulaBindingId, ElnFormulaForms.TemplateBinding target) {
|
ElnTemplateFormulaBindingEntity binding = requireOwned(authorization, formulaBindingId);
|
requireStatus(binding, ACTIVE);
|
String operation = requireAvailableOperation(
|
authorization, target == null ? null : target.getOperationCode(), binding.getId());
|
target.setOperationCode(operation);
|
validateRequest(authorization, target, binding.getId());
|
ElnFormulaVos.MappingCheck result = new ElnFormulaVos.MappingCheck();
|
result.setOperationCode(operation);
|
result.getExpectedVersions().put(binding.getId(), binding.getFVersion());
|
return result;
|
}
|
|
@Override
|
public void confirmUpgrade(TemplateAnnotationAuthorization authorization, String formulaBindingId,
|
ElnFormulaForms.UpgradeMappingConfirm form) {
|
lockTemplateGraph(authorization);
|
ElnTemplateFormulaBindingEntity binding = requireOwned(authorization, formulaBindingId);
|
if (form == null || form.getTarget() == null) throw new DataException("升级确认参数不能为空");
|
String operation = requireAvailableOperation(
|
authorization, form.getOperationCode(), binding.getId());
|
String targetOperation = requireAvailableOperation(
|
authorization, form.getTarget().getOperationCode(), binding.getId());
|
if (!operation.equals(targetOperation))
|
throw new DataException("升级操作码与目标映射不一致");
|
form.setOperationCode(operation);
|
form.getTarget().setOperationCode(targetOperation);
|
if (alreadyApplied(binding, form.getExpectedVersion(), operation)
|
&& sameRequest(binding, form.getTarget())) return;
|
requireStatus(binding, ACTIVE);
|
requireMutationVersion(binding, form.getExpectedVersion());
|
ValidatedMapping validated = validateRequest(authorization, form.getTarget(), binding.getId());
|
requireResultLocked(authorization, form.getTarget().getResultBindingId(), form.getControls());
|
ElnTemplateFormulaBindingEntity before = copy(binding);
|
binding.setGongshiDingyiId(validated.definition.getId());
|
binding.setGongshiBanbenId(validated.version.getId());
|
binding.setCanshuYingshe(new LinkedHashMap<>(form.getTarget().getParameterBindings()));
|
binding.setJieguoBangdingId(form.getTarget().getResultBindingId());
|
binding.setCaozuoBianma(operation);
|
if (!store.updateStatus(binding, form.getExpectedVersion(), ACTIVE, null))
|
throw new DataException("公式映射版本冲突");
|
FormulaDependencyGraph.Result result = validateGraph(authorization.getTenantId(), authorization.getTemplateId());
|
if (!result.isValid()) throw new DataException("公式依赖存在循环: " + result.getCyclePath());
|
audit("ELN_TEMPLATE_FORMULA_UPGRADE", authorization, binding, before, binding, null);
|
}
|
|
@Override
|
public ElnFormulaVos.MappingCheck checkRemove(TemplateAnnotationAuthorization authorization,
|
String formulaBindingId) {
|
ElnTemplateFormulaBindingEntity binding = requireOwned(authorization, formulaBindingId);
|
requireStatus(binding, ACTIVE);
|
ElnFormulaVos.MappingCheck result = new ElnFormulaVos.MappingCheck();
|
result.setOperationCode("remove:" + binding.getId() + ":" + binding.getFVersion());
|
result.getExpectedVersions().put(binding.getId(), binding.getFVersion());
|
for (ElnTemplateFormulaBindingEntity candidate : store.listBindings(
|
authorization.getTenantId(), authorization.getTemplateId())) {
|
if (ACTIVE.equals(candidate.getBangdingZhuangtai()) && candidate.getCanshuYingshe() != null
|
&& candidate.getCanshuYingshe().containsValue(binding.getJieguoBangdingId()))
|
result.getDownstreamFormulaBindingIds().add(candidate.getId());
|
}
|
return result;
|
}
|
|
@Override
|
public void confirmRemove(TemplateAnnotationAuthorization authorization, String formulaBindingId,
|
ElnFormulaForms.RemoveMappingConfirm form) {
|
ElnTemplateFormulaBindingEntity binding = requireOwned(authorization, formulaBindingId);
|
if (form == null) throw new DataException("移除确认参数不能为空");
|
String operation = normalizeOperation(form.getOperationCode());
|
form.setOperationCode(operation);
|
if (alreadyApplied(binding, form.getExpectedVersion(), operation)
|
&& REMOVED.equals(binding.getBangdingZhuangtai())) return;
|
requireMutationVersion(binding, form.getExpectedVersion());
|
ElnFormulaVos.MappingCheck checked = checkRemove(authorization, formulaBindingId);
|
if (!checked.getOperationCode().equals(operation))
|
throw new DataException("移除操作码与预检结果不一致");
|
if (!checked.getDownstreamFormulaBindingIds().isEmpty())
|
throw new DataException("公式结果仍被下游公式引用");
|
requireResultUnlocked(authorization, binding, form.getControls());
|
ElnTemplateFormulaBindingEntity before = copy(binding);
|
binding.setCaozuoBianma(operation);
|
if (!store.updateStatus(binding, form.getExpectedVersion(), REMOVED, null))
|
throw new DataException("公式映射版本冲突");
|
validateGraph(authorization.getTenantId(), authorization.getTemplateId());
|
audit("ELN_TEMPLATE_FORMULA_REMOVE", authorization, binding, before, binding, null);
|
}
|
|
@Override
|
public void confirmVersionCopy(TemplateAnnotationAuthorization authorization,
|
ElnFormulaForms.FormulaVersionCopyConfirm form) {
|
lockTemplateGraph(authorization);
|
String upgradeOperation = normalizeOperation(
|
form == null ? null : form.getUpgradeOperationCode());
|
form.setUpgradeOperationCode(upgradeOperation);
|
ElnTemplateVersionEntity template = store.findTemplate(
|
authorization.getTenantId(), authorization.getTemplateId());
|
if (template == null || !upgradeOperation.equals(
|
template.getShengbanCaozuoBianma()))
|
throw new DataException("版本复制确认与模板升版操作不匹配");
|
List<ElnTemplateFormulaBindingEntity> copied = new ArrayList<>();
|
List<ElnTemplateFormulaBindingEntity> activeCopied = new ArrayList<>();
|
for (ElnTemplateFormulaBindingEntity item : store.listBindings(
|
authorization.getTenantId(), authorization.getTemplateId())) {
|
if (item.getLaiyuanGongshiBangdingId() != null
|
&& (PENDING.equals(item.getBangdingZhuangtai())
|
|| ACTIVE.equals(item.getBangdingZhuangtai()))) {
|
String expectedOperation = upgradeOperation + ":"
|
+ item.getLaiyuanGongshiBangdingId();
|
if (!expectedOperation.equals(item.getCaozuoBianma()))
|
throw new DataException("版本复制公式映射操作码不匹配");
|
if (PENDING.equals(item.getBangdingZhuangtai())
|
&& item.getDaoqiShijian() != null)
|
throw new DataException("版本复制公式映射不能设置到期时间");
|
if (PENDING.equals(item.getBangdingZhuangtai())) copied.add(item);
|
else if (ACTIVE.equals(item.getBangdingZhuangtai())) activeCopied.add(item);
|
}
|
}
|
if (!copied.isEmpty() && !activeCopied.isEmpty())
|
throw new DataException("版本复制公式映射状态混合,不能部分确认");
|
if (copied.isEmpty() && form.getExpectedVersions().keySet().equals(ids(activeCopied))) {
|
boolean retry = true;
|
for (ElnTemplateFormulaBindingEntity item : activeCopied) {
|
Integer expected = form.getExpectedVersions().get(item.getId());
|
retry &= expected != null && item.getFVersion() != null
|
&& item.getFVersion() == expected + 1;
|
}
|
if (retry) return;
|
}
|
if (!form.getExpectedVersions().keySet().equals(ids(copied)))
|
throw new DataException("版本复制公式映射集合不完整");
|
for (ElnTemplateFormulaBindingEntity item : copied) {
|
Integer expected = form.getExpectedVersions().get(item.getId());
|
requireMutationVersion(item, expected);
|
}
|
requireResultsLocked(authorization, copied, form.getControls());
|
for (ElnTemplateFormulaBindingEntity item : copied) {
|
ElnTemplateFormulaBindingEntity before = copy(item);
|
if (!store.updateStatus(item, form.getExpectedVersions().get(item.getId()), ACTIVE, null))
|
throw new DataException("版本复制公式映射版本冲突");
|
audit("ELN_TEMPLATE_FORMULA_VERSION_COPY_CONFIRM", authorization, item, before, item, null);
|
}
|
FormulaDependencyGraph.Result result = validateGraph(authorization.getTenantId(), authorization.getTemplateId());
|
if (!result.isValid()) throw new DataException("公式依赖存在循环: " + result.getCyclePath());
|
}
|
|
@Override
|
public FormulaDependencyGraph.Result validateGraph(String tenantId, String templateId) {
|
List<ElnTemplateFormulaBindingEntity> active = new ArrayList<>();
|
for (ElnTemplateFormulaBindingEntity item : store.listBindings(tenantId, templateId))
|
if (ACTIVE.equals(item.getBangdingZhuangtai())) active.add(item);
|
FormulaDependencyGraph.Result result = graph.validate(active);
|
if (result.isValid()) {
|
for (int index = 0; index < result.getTopologicalOrder().size(); index++) {
|
String id = result.getTopologicalOrder().get(index);
|
for (ElnTemplateFormulaBindingEntity item : active)
|
if (id.equals(item.getId())) store.updateTopology(item, index);
|
}
|
}
|
return result;
|
}
|
|
private ValidatedMapping validateRequest(TemplateAnnotationAuthorization auth,
|
ElnFormulaForms.TemplateBinding form, String ignoredResultOwnerId) {
|
if (form == null || !StringUtils.hasText(form.getFormulaVersionId())
|
|| !StringUtils.hasText(form.getResultBindingId()))
|
throw new DataException("公式映射参数不完整");
|
ElnTemplateVersionEntity template = store.findTemplate(auth.getTenantId(), auth.getTemplateId());
|
if (template == null || !auth.getTemplateId().equals(template.getId()))
|
throw new DataException("模板不存在或跨租户");
|
ElnFormulaVersionEntity version = store.findFormulaVersion(auth.getTenantId(), form.getFormulaVersionId());
|
if (version == null) throw new DataException("公式版本不存在或跨租户");
|
ElnFormulaDefEntity definition = store.findFormulaDefinition(auth.getTenantId(), version.getGongshiDingyiId());
|
if (definition == null) throw new DataException("公式定义不存在或跨租户");
|
if (!"enabled".equals(definition.getBizEnabled())) throw new DataException("停用公式不能新增映射");
|
boolean currentPublished = PUBLISHED.equals(version.getBizStatus())
|
&& version.getId().equals(definition.getDangqianGongshiBanbenId());
|
if ("DRAFT".equals(template.getBizStatus())) {
|
if (!PRE_RELEASE.equals(version.getBizStatus()) && !currentPublished)
|
throw new DataException("历史已发布公式版本只允许模板升版继承");
|
} else if (!PUBLISHED.equals(version.getBizStatus())) {
|
throw new DataException("正式模板只能引用已发布公式版本");
|
}
|
List<ElnFormulaParameterSlotEntity> slots = store.listSlots(auth.getTenantId(), version.getId());
|
Map<String, String> parameters = form.getParameterBindings() == null
|
? Collections.emptyMap() : form.getParameterBindings();
|
Set<String> expectedKeys = new LinkedHashSet<>();
|
for (ElnFormulaParameterSlotEntity slot : slots) expectedKeys.add(slot.getCanshuBianma());
|
if (!expectedKeys.equals(parameters.keySet())) throw new DataException("参数映射必须与公式参数槽完全一致");
|
Map<String, ElnTemplateBindingEntity> parameterBindings = new LinkedHashMap<>();
|
for (ElnFormulaParameterSlotEntity slot : slots) {
|
ElnTemplateBindingEntity fieldBinding = requireFormulaField(
|
auth, parameters.get(slot.getCanshuBianma()));
|
ElnFieldVersionEntity fieldVersion = requireFieldVersion(auth, fieldBinding);
|
requireParameterCompatible(slot.getShujuLeixing(), fieldBinding,
|
fieldVersion.getShujuLeixing());
|
parameterBindings.put(slot.getCanshuBianma(), fieldBinding);
|
}
|
ElnTemplateBindingEntity resultBinding = requireFormulaField(auth, form.getResultBindingId());
|
if (StringUtils.hasText(resultBinding.getCheckboxGroupCode())) {
|
throw new DataException("选择组成员不能作为公式结果字段");
|
}
|
if (resultBindingGuard.isCrossTemplateTarget(auth.getTenantId(), resultBinding.getId())) {
|
throw new DataException("跨模板字段只能作为公式输入,不能作为公式结果");
|
}
|
if (parameters.containsValue(resultBinding.getId())) throw new DataException("结果字段不能作为公式自身参数");
|
ElnFieldVersionEntity resultVersion = requireFieldVersion(auth, resultBinding);
|
requireResultCompatible(version.getJieguoLeixing(), resultVersion.getShujuLeixing());
|
requireFormulaShape(slots, parameterBindings, resultBinding);
|
requireFormulaResult(resultVersion);
|
for (ElnTemplateFormulaBindingEntity item : store.listBindings(auth.getTenantId(), auth.getTemplateId())) {
|
if ((PENDING.equals(item.getBangdingZhuangtai()) || ACTIVE.equals(item.getBangdingZhuangtai()))
|
&& resultBinding.getId().equals(item.getJieguoBangdingId())
|
&& !item.getId().equals(ignoredResultOwnerId))
|
throw new DataException("结果字段只允许一个公式写入");
|
}
|
return new ValidatedMapping(definition, version);
|
}
|
|
private ElnTemplateBindingEntity requireFormulaField(
|
TemplateAnnotationAuthorization auth, String id) {
|
ElnTemplateBindingEntity binding = store.findFieldBinding(auth.getTenantId(), trim(id));
|
if (binding == null || !auth.getTemplateId().equals(binding.getMubanId())
|
|| !ACTIVE.equals(binding.getBangdingZhuangtai())
|
|| !("PRIMARY".equals(binding.getKongjianJuese())
|
|| "REPEAT".equals(binding.getKongjianJuese())))
|
throw new DataException("参数和结果必须引用当前模板 ACTIVE PRIMARY/REPEAT 字段绑定");
|
return binding;
|
}
|
|
private ElnFieldVersionEntity requireFieldVersion(TemplateAnnotationAuthorization auth,
|
ElnTemplateBindingEntity binding) {
|
ElnFieldVersionEntity version = store.findFieldVersion(auth.getTenantId(), binding.getZiduanBanbenId());
|
if (version == null || !Objects.equals(version.getId(), binding.getZiduanBanbenId())
|
|| !Objects.equals(version.getZiduanDingyiId(), binding.getZiduanDingyiId()))
|
throw new DataException("字段固定版本不存在或跨租户");
|
return version;
|
}
|
|
private static void requireParameterCompatible(String formulaType,
|
ElnTemplateBindingEntity binding, String fieldType) {
|
if ("DECIMAL_LIST".equals(formulaType)) {
|
if (!"REPEAT".equals(binding.getKongjianJuese()) || !"DECIMAL".equals(fieldType)) {
|
throw new DataException("DECIMAL_LIST 参数必须映射 DECIMAL 重复字段");
|
}
|
return;
|
}
|
requireCompatible(formulaType, fieldType);
|
}
|
|
private static void requireResultCompatible(String formulaType, String fieldType) {
|
if ("DECIMAL_LIST".equals(formulaType)) {
|
throw new DataException("UNSUPPORTED_COLLECTION_BINDING");
|
}
|
requireCompatible(formulaType, fieldType);
|
}
|
|
private static void requireCompatible(String formulaType, String fieldType) {
|
boolean compatible = "DECIMAL".equals(formulaType) && "DECIMAL".equals(fieldType)
|
|| "TEXT".equals(formulaType) && ("TEXT".equals(fieldType)
|
|| "TEXTAREA".equals(fieldType) || "SELECT".equals(fieldType))
|
|| "BOOLEAN".equals(formulaType) && "CHECKBOX".equals(fieldType);
|
if (!compatible) throw new DataException("公式参数或结果类型与字段类型不兼容");
|
}
|
|
interface ResultBindingGuard {
|
boolean isCrossTemplateTarget(String tenantId, String bindingId);
|
}
|
|
private static void requireFormulaShape(List<ElnFormulaParameterSlotEntity> slots,
|
Map<String, ElnTemplateBindingEntity> parameters,
|
ElnTemplateBindingEntity result) {
|
boolean rowFormula = "REPEAT".equals(result.getKongjianJuese());
|
for (ElnFormulaParameterSlotEntity slot : slots) {
|
ElnTemplateBindingEntity parameter = parameters.get(slot.getCanshuBianma());
|
boolean list = "DECIMAL_LIST".equals(slot.getShujuLeixing());
|
if (list && rowFormula) throw new DataException("逐行公式不支持 DECIMAL_LIST 参数");
|
if (rowFormula && !"REPEAT".equals(parameter.getKongjianJuese())) {
|
throw new DataException("逐行公式参数必须映射同组重复字段");
|
}
|
if (!list && !rowFormula && "REPEAT".equals(parameter.getKongjianJuese())) {
|
throw new DataException("聚合公式的重复字段必须映射 DECIMAL_LIST 参数");
|
}
|
if (rowFormula && "REPEAT".equals(parameter.getKongjianJuese())
|
&& !Objects.equals(result.getRepeatGroupCode(),
|
parameter.getRepeatGroupCode())) {
|
throw new DataException("逐行公式参数和结果必须属于同一重复组");
|
}
|
}
|
}
|
|
@SuppressWarnings("unchecked")
|
private static void requireFormulaResult(ElnFieldVersionEntity version) {
|
Map<String, Object> config = StringUtils.hasText(version.getBangdingPeizhi())
|
? JsonUtil.getJsonToBean(version.getBangdingPeizhi(), Map.class) : null;
|
Map<String, Object> read = config == null ? null : (Map<String, Object>) config.get("read");
|
Map<String, Object> write = config == null ? null : (Map<String, Object>) config.get("write");
|
if (read == null || write == null || !"NONE".equals(read.get("source"))
|
|| !"ELN_RECORD".equals(write.get("target"))
|
|| !"RECORD_PRIVATE".equals(version.getPiciMoshi()))
|
throw new DataException("结果字段必须为 NONE/ELN_RECORD/RECORD_PRIVATE");
|
}
|
|
private void requireResultLocked(TemplateAnnotationAuthorization auth,
|
String resultBindingId,
|
List<ElnFormulaForms.ControlSnapshot> controls) {
|
Set<String> expected = resultControlBindingIds(auth, resultBindingId);
|
requireControlsLocked(auth, expected, controls);
|
}
|
|
private void requireOriginalResultLockSnapshot(TemplateAnnotationAuthorization auth,
|
String resultBindingId, List<ElnFormulaForms.ControlSnapshot> controls) {
|
Set<String> expected = resultControlBindingIds(auth, resultBindingId);
|
Map<String, ElnFormulaForms.ControlSnapshot> actual = byBindingId(controls);
|
if (!actual.keySet().equals(expected) || controls == null || controls.size() != expected.size())
|
throw new DataException("FORMULA_RESULT_LOCK_MISMATCH");
|
for (String id : expected) {
|
ElnTemplateBindingEntity binding = store.findFieldBinding(auth.getTenantId(), id);
|
ElnFormulaForms.ControlSnapshot control = actual.get(id);
|
if (!Objects.equals(binding.getKongjianBiaoqian(), control.getControlTag())
|
|| !Objects.equals(binding.getKongjianJuese(), control.getControlRole())
|
|| !isOriginalLock(control.getLock()))
|
throw new DataException("FORMULA_RESULT_LOCK_MISMATCH");
|
}
|
}
|
|
private void requireResultsLocked(TemplateAnnotationAuthorization auth,
|
List<ElnTemplateFormulaBindingEntity> formulaBindings,
|
List<ElnFormulaForms.ControlSnapshot> controls) {
|
Set<String> expected = new LinkedHashSet<>();
|
for (ElnTemplateFormulaBindingEntity binding : formulaBindings) {
|
expected.addAll(resultControlBindingIds(auth, binding));
|
}
|
requireControlsLocked(auth, expected, controls);
|
}
|
|
private void requireControlsLocked(TemplateAnnotationAuthorization auth,
|
Set<String> expected, List<ElnFormulaForms.ControlSnapshot> controls) {
|
Map<String, ElnFormulaForms.ControlSnapshot> actual = byBindingId(controls);
|
if (!actual.keySet().equals(expected) || controls == null || controls.size() != expected.size())
|
throw new DataException("FORMULA_RESULT_LOCK_MISMATCH");
|
for (String id : expected) {
|
ElnTemplateBindingEntity binding = store.findFieldBinding(auth.getTenantId(), id);
|
ElnFormulaForms.ControlSnapshot control = actual.get(id);
|
if (!Objects.equals(binding.getKongjianBiaoqian(), control.getControlTag())
|
|| !Objects.equals(binding.getKongjianJuese(), control.getControlRole())
|
|| !"sdtContentLocked".equals(control.getLock()))
|
throw new DataException("FORMULA_RESULT_LOCK_MISMATCH");
|
}
|
}
|
|
private void requireResultUnlocked(TemplateAnnotationAuthorization auth,
|
ElnTemplateFormulaBindingEntity formulaBinding,
|
List<ElnFormulaForms.ControlSnapshot> controls) {
|
Set<String> expected = resultControlBindingIds(auth, formulaBinding);
|
Map<String, ElnFormulaForms.ControlSnapshot> actual = byBindingId(controls);
|
if (!actual.keySet().equals(expected) || controls == null || controls.size() != expected.size())
|
throw new DataException("FORMULA_RESULT_LOCK_MISMATCH");
|
for (String id : expected) {
|
ElnTemplateBindingEntity binding = store.findFieldBinding(auth.getTenantId(), id);
|
ElnFormulaForms.ControlSnapshot control = actual.get(id);
|
if (!Objects.equals(binding.getKongjianBiaoqian(), control.getControlTag())
|
|| !Objects.equals(binding.getKongjianJuese(), control.getControlRole())
|
|| StringUtils.hasText(control.getLock()))
|
throw new DataException("FORMULA_RESULT_LOCK_MISMATCH");
|
}
|
}
|
|
private Set<String> resultControlBindingIds(TemplateAnnotationAuthorization auth,
|
ElnTemplateFormulaBindingEntity formulaBinding) {
|
return resultControlBindingIds(auth, formulaBinding.getJieguoBangdingId());
|
}
|
|
private Set<String> resultControlBindingIds(TemplateAnnotationAuthorization auth,
|
String resultBindingId) {
|
Set<String> result = new LinkedHashSet<>();
|
result.add(resultBindingId);
|
for (ElnTemplateBindingEntity item : store.listFieldBindings(auth.getTenantId(), auth.getTemplateId()))
|
if (ACTIVE.equals(item.getBangdingZhuangtai()) && "REFERENCE".equals(item.getKongjianJuese())
|
&& resultBindingId.equals(item.getYinyongShiliId())) result.add(item.getId());
|
return result;
|
}
|
|
private static Map<String, ElnFormulaForms.ControlSnapshot> byBindingId(
|
List<ElnFormulaForms.ControlSnapshot> controls) {
|
Map<String, ElnFormulaForms.ControlSnapshot> result = new LinkedHashMap<>();
|
if (controls != null) for (ElnFormulaForms.ControlSnapshot item : controls)
|
if (item != null && StringUtils.hasText(item.getBindingId())) result.put(item.getBindingId(), item);
|
return result;
|
}
|
|
private static boolean isOriginalLock(String lock) {
|
return "".equals(lock) || "contentLocked".equals(lock)
|
|| "sdtContentLocked".equals(lock) || "unlocked".equals(lock);
|
}
|
|
private ElnTemplateFormulaBindingEntity requireOwned(TemplateAnnotationAuthorization auth, String id) {
|
requireAuthorization(auth);
|
ElnTemplateFormulaBindingEntity binding = store.findBinding(auth.getTenantId(), trim(id));
|
if (binding == null || !auth.getTemplateId().equals(binding.getMubanId()))
|
throw new DataException("公式映射不存在或不属于当前模板");
|
return binding;
|
}
|
|
private static void requireAuthorization(TemplateAnnotationAuthorization auth) {
|
if (auth == null || !StringUtils.hasText(auth.getTenantId())
|
|| !StringUtils.hasText(auth.getTemplateId())) throw new DataException("标注授权无效");
|
}
|
|
private void lockTemplateGraph(TemplateAnnotationAuthorization authorization) {
|
requireAuthorization(authorization);
|
if (store.lockTemplate(authorization.getTenantId(), authorization.getTemplateId()) == null)
|
throw new DataException("模板不存在或跨租户");
|
}
|
private static String normalizeOperation(String operation) {
|
String normalized = operation == null ? null : operation.trim();
|
if (!StringUtils.hasText(normalized)) throw new DataException("操作码不能为空");
|
if (normalized.length() > 160) throw new DataException("操作码长度不能超过160个字符");
|
return normalized;
|
}
|
private String requireAvailableOperation(TemplateAnnotationAuthorization auth,
|
String operation, String currentBindingId) {
|
String normalized = normalizeOperation(operation);
|
ElnTemplateFormulaBindingEntity owner = store.findByOperation(
|
auth.getTenantId(), auth.getTemplateId(), normalized);
|
if (owner != null && !Objects.equals(owner.getId(), currentBindingId))
|
throw new DataException("操作码已用于其他公式映射请求");
|
return normalized;
|
}
|
private static void requireMutation(ElnTemplateFormulaBindingEntity binding, String operation,
|
Integer version, String status) {
|
String normalized = normalizeOperation(operation);
|
if (!Objects.equals(binding.getCaozuoBianma(), normalized)) throw new DataException("操作码不匹配");
|
requireStatus(binding, status);
|
requireMutationVersion(binding, version);
|
}
|
private static void requireMutationVersion(ElnTemplateFormulaBindingEntity binding, Integer version) {
|
if (version == null || !version.equals(binding.getFVersion())) throw new DataException("公式映射版本冲突");
|
}
|
private static boolean alreadyApplied(ElnTemplateFormulaBindingEntity binding,
|
Integer expectedVersion, String operationCode) {
|
return expectedVersion != null && binding.getFVersion() != null
|
&& binding.getFVersion() == expectedVersion + 1
|
&& Objects.equals(operationCode, binding.getCaozuoBianma());
|
}
|
private static void requireStatus(ElnTemplateFormulaBindingEntity binding, String status) {
|
if (!status.equals(binding.getBangdingZhuangtai())) throw new DataException("公式映射状态无效");
|
}
|
private static boolean sameRequest(ElnTemplateFormulaBindingEntity item, ElnFormulaForms.TemplateBinding form) {
|
return Objects.equals(item.getGongshiBanbenId(), trim(form.getFormulaVersionId()))
|
&& Objects.equals(item.getJieguoBangdingId(), trim(form.getResultBindingId()))
|
&& Objects.equals(item.getCanshuYingshe(), form.getParameterBindings());
|
}
|
private static boolean sameReserve(ElnTemplateFormulaBindingEntity item,
|
TemplateAnnotationAuthorization authorization, ElnFormulaForms.TemplateBinding form,
|
String definitionId, String operation) {
|
return Objects.equals(item.getFTenantId(), authorization.getTenantId())
|
&& Objects.equals(item.getMubanId(), authorization.getTemplateId())
|
&& Objects.equals(item.getGongshiDingyiId(), definitionId)
|
&& Objects.equals(item.getGongshiBanbenId(), trim(form.getFormulaVersionId()))
|
&& Objects.equals(item.getCanshuYingshe(), form.getParameterBindings())
|
&& Objects.equals(item.getJieguoBangdingId(), trim(form.getResultBindingId()))
|
&& sameControls(item.getJieguoSuoKuaizhao(), form.getJieguoSuoKuaizhao())
|
&& Objects.equals(item.getCaozuoBianma(), operation)
|
&& item.getLaiyuanGongshiBangdingId() == null
|
&& item.getDaoqiShijian() != null
|
&& (PENDING.equals(item.getBangdingZhuangtai())
|
|| ACTIVE.equals(item.getBangdingZhuangtai()));
|
}
|
private static ElnFormulaForms.TemplateBinding request(ElnTemplateFormulaBindingEntity item) {
|
ElnFormulaForms.TemplateBinding form = new ElnFormulaForms.TemplateBinding();
|
form.setFormulaVersionId(item.getGongshiBanbenId());
|
form.setParameterBindings(item.getCanshuYingshe());
|
form.setResultBindingId(item.getJieguoBangdingId());
|
form.setOperationCode(item.getCaozuoBianma());
|
return form;
|
}
|
|
private static List<ElnFormulaForms.ControlSnapshot> copyControls(
|
List<ElnFormulaForms.ControlSnapshot> controls) {
|
List<ElnFormulaForms.ControlSnapshot> result = new ArrayList<>();
|
if (controls != null) for (ElnFormulaForms.ControlSnapshot item : controls) {
|
if (item == null) continue;
|
ElnFormulaForms.ControlSnapshot copied = new ElnFormulaForms.ControlSnapshot();
|
copied.setBindingId(item.getBindingId());
|
copied.setControlTag(item.getControlTag());
|
copied.setControlRole(item.getControlRole());
|
copied.setLock(item.getLock());
|
result.add(copied);
|
}
|
return result;
|
}
|
|
private static boolean sameControls(List<ElnFormulaForms.ControlSnapshot> left,
|
List<ElnFormulaForms.ControlSnapshot> right) {
|
return copyControls(left).equals(copyControls(right));
|
}
|
private static Set<String> ids(List<ElnTemplateFormulaBindingEntity> items) {
|
Set<String> result = new LinkedHashSet<>();
|
for (ElnTemplateFormulaBindingEntity item : items) result.add(item.getId());
|
return result;
|
}
|
private static String trim(String value) { return value == null ? null : value.trim(); }
|
private static String trimToNull(String value) { return StringUtils.hasText(value) ? value.trim() : null; }
|
|
private void audit(String action, TemplateAnnotationAuthorization auth,
|
ElnTemplateFormulaBindingEntity target, Object before, Object after, String reason) {
|
Map<String, Object> snapshot = new LinkedHashMap<>();
|
snapshot.put("templateId", target.getMubanId());
|
snapshot.put("formulaDefinitionId", target.getGongshiDingyiId());
|
snapshot.put("formulaVersionId", target.getGongshiBanbenId());
|
snapshot.put("parameterBindings", target.getCanshuYingshe());
|
snapshot.put("resultBindingId", target.getJieguoBangdingId());
|
snapshot.put("operationCode", target.getCaozuoBianma());
|
snapshot.put("reason", reason);
|
snapshot.put("before", before);
|
snapshot.put("after", after);
|
auditRecorder.accept(AuditEventDTO.builder().tenantId(auth.getTenantId()).operatorId(auth.getUserId())
|
.eventTime(new Date()).eventType("DATA_CHANGE").actionCode(action)
|
.actionLabel(action).bizModule("eln").bizType("eln_template_formula_binding")
|
.targetTable("eln_template_formula_binding").targetId(target.getId()).reason(reason)
|
.dataSnapshot(JsonUtil.getObjectToString(snapshot)).build());
|
}
|
|
private static ElnFormulaVos.TemplateBinding toVo(ElnTemplateFormulaBindingEntity item) {
|
ElnFormulaVos.TemplateBinding result = new ElnFormulaVos.TemplateBinding();
|
result.setId(item.getId()); result.setTemplateId(item.getMubanId());
|
result.setFormulaDefinitionId(item.getGongshiDingyiId());
|
result.setFormulaVersionId(item.getGongshiBanbenId());
|
result.setParameterBindings(item.getCanshuYingshe());
|
result.setResultBindingId(item.getJieguoBangdingId());
|
result.setStatus(item.getBangdingZhuangtai()); result.setTopologicalOrder(item.getTuopuXuhao());
|
result.setOperationCode(item.getCaozuoBianma()); result.setVersion(item.getFVersion());
|
result.setJieguoSuoKuaizhao(copyControls(item.getJieguoSuoKuaizhao()));
|
return result;
|
}
|
|
private ElnFormulaVos.TemplateFormulaVersion toTemplateFormulaVersion(String tenantId,
|
ElnFormulaDefEntity definition, ElnFormulaVersionEntity version) {
|
ElnFormulaVos.TemplateFormulaVersion result = new ElnFormulaVos.TemplateFormulaVersion();
|
result.setId(version.getId());
|
result.setFormulaCode(definition.getGongshiBianma());
|
result.setFormulaName(definition.getGongshiMingcheng());
|
result.setFormulaEnabled("enabled".equals(definition.getBizEnabled()));
|
result.setIsCurrent(version.getId().equals(definition.getDangqianGongshiBanbenId()));
|
result.setResultType(version.getJieguoLeixing());
|
result.setStatus(version.getBizStatus());
|
for (ElnFormulaParameterSlotEntity item : store.listSlots(tenantId, version.getId())) {
|
ElnFormulaVos.TemplateFormulaSlot slot = new ElnFormulaVos.TemplateFormulaSlot();
|
slot.setCode(item.getCanshuBianma());
|
slot.setName(item.getCanshuMingcheng());
|
slot.setRequired(Integer.valueOf(1).equals(item.getShifouBitian()));
|
slot.setType(item.getShujuLeixing());
|
result.getSlots().add(slot);
|
}
|
return result;
|
}
|
|
private static ElnTemplateFormulaBindingEntity copy(ElnTemplateFormulaBindingEntity item) {
|
return JsonUtil.getJsonToBean(JsonUtil.getObjectToString(item), ElnTemplateFormulaBindingEntity.class);
|
}
|
|
private static final class ValidatedMapping {
|
private final ElnFormulaDefEntity definition;
|
private final ElnFormulaVersionEntity version;
|
private ValidatedMapping(ElnFormulaDefEntity definition, ElnFormulaVersionEntity version) {
|
this.definition = definition; this.version = version;
|
}
|
}
|
|
public interface Store {
|
ElnTemplateVersionEntity findTemplate(String tenantId, String id);
|
ElnTemplateVersionEntity lockTemplate(String tenantId, String id);
|
ElnFormulaDefEntity findFormulaDefinition(String tenantId, String id);
|
default List<ElnFormulaDefEntity> listFormulaDefinitions(String tenantId) {
|
return Collections.emptyList();
|
}
|
ElnFormulaVersionEntity findFormulaVersion(String tenantId, String id);
|
default List<ElnFormulaVersionEntity> listFormulaVersions(String tenantId) {
|
return Collections.emptyList();
|
}
|
List<ElnFormulaParameterSlotEntity> listSlots(String tenantId, String versionId);
|
ElnTemplateBindingEntity findFieldBinding(String tenantId, String id);
|
default List<ElnTemplateBindingEntity> listFieldBindings(String tenantId, String templateId) {
|
return Collections.emptyList();
|
}
|
ElnFieldVersionEntity findFieldVersion(String tenantId, String id);
|
ElnTemplateFormulaBindingEntity findByOperation(String tenantId, String templateId, String operation);
|
ElnTemplateFormulaBindingEntity findBinding(String tenantId, String id);
|
List<ElnTemplateFormulaBindingEntity> listBindings(String tenantId, String templateId);
|
boolean insertIfAbsent(ElnTemplateFormulaBindingEntity binding);
|
boolean updateStatus(ElnTemplateFormulaBindingEntity binding, int expectedVersion, String status, String reason);
|
void updateTopology(ElnTemplateFormulaBindingEntity binding, int order);
|
}
|
|
private static final class MyBatisStore implements Store {
|
private final ElnTemplateMapper templates; private final ElnFormulaDefMapper definitions;
|
private final ElnFormulaVersionMapper formulaVersions; private final ElnFormulaParameterSlotMapper slots;
|
private final ElnTemplateBindingMapper fieldBindings; private final ElnFieldVersionMapper fieldVersions;
|
private final ElnTemplateFormulaBindingMapper formulaBindings;
|
private MyBatisStore(ElnTemplateMapper templates, ElnFormulaDefMapper definitions,
|
ElnFormulaVersionMapper formulaVersions, ElnFormulaParameterSlotMapper slots,
|
ElnTemplateBindingMapper fieldBindings, ElnFieldVersionMapper fieldVersions,
|
ElnTemplateFormulaBindingMapper formulaBindings) {
|
this.templates=templates; this.definitions=definitions; this.formulaVersions=formulaVersions;
|
this.slots=slots; this.fieldBindings=fieldBindings; this.fieldVersions=fieldVersions;
|
this.formulaBindings=formulaBindings;
|
}
|
@Override public ElnTemplateVersionEntity findTemplate(String t,String id){return templates.selectOne(Wrappers.<ElnTemplateVersionEntity>lambdaQuery().eq(ElnTemplateVersionEntity::getFTenantId,t).eq(ElnTemplateVersionEntity::getId,id).and(q->q.isNull(ElnTemplateVersionEntity::getFDeleteMark).or().eq(ElnTemplateVersionEntity::getFDeleteMark,0)));}
|
@Override public ElnTemplateVersionEntity lockTemplate(String t,String id){return templates.lockTemplateForUpdate(t,id);}
|
@Override public ElnFormulaDefEntity findFormulaDefinition(String t,String id){return definitions.selectOne(Wrappers.<ElnFormulaDefEntity>lambdaQuery().eq(ElnFormulaDefEntity::getFTenantId,t).eq(ElnFormulaDefEntity::getId,id).and(q->q.isNull(ElnFormulaDefEntity::getFDeleteMark).or().eq(ElnFormulaDefEntity::getFDeleteMark,0)));}
|
@Override public List<ElnFormulaDefEntity> listFormulaDefinitions(String t){return definitions.selectList(Wrappers.<ElnFormulaDefEntity>lambdaQuery().eq(ElnFormulaDefEntity::getFTenantId,t).and(q->q.isNull(ElnFormulaDefEntity::getFDeleteMark).or().eq(ElnFormulaDefEntity::getFDeleteMark,0)).orderByAsc(ElnFormulaDefEntity::getId));}
|
@Override public ElnFormulaVersionEntity findFormulaVersion(String t,String id){return formulaVersions.selectOne(Wrappers.<ElnFormulaVersionEntity>lambdaQuery().eq(ElnFormulaVersionEntity::getFTenantId,t).eq(ElnFormulaVersionEntity::getId,id).and(q->q.isNull(ElnFormulaVersionEntity::getFDeleteMark).or().eq(ElnFormulaVersionEntity::getFDeleteMark,0)));}
|
@Override public List<ElnFormulaVersionEntity> listFormulaVersions(String t){return formulaVersions.selectList(Wrappers.<ElnFormulaVersionEntity>lambdaQuery().eq(ElnFormulaVersionEntity::getFTenantId,t).and(q->q.isNull(ElnFormulaVersionEntity::getFDeleteMark).or().eq(ElnFormulaVersionEntity::getFDeleteMark,0)).orderByAsc(ElnFormulaVersionEntity::getGongshiDingyiId).orderByAsc(ElnFormulaVersionEntity::getBanbenHao));}
|
@Override public List<ElnFormulaParameterSlotEntity> listSlots(String t,String id){return slots.selectList(Wrappers.<ElnFormulaParameterSlotEntity>lambdaQuery().eq(ElnFormulaParameterSlotEntity::getFTenantId,t).eq(ElnFormulaParameterSlotEntity::getGongshiBanbenId,id).and(q->q.isNull(ElnFormulaParameterSlotEntity::getFDeleteMark).or().eq(ElnFormulaParameterSlotEntity::getFDeleteMark,0)).orderByAsc(ElnFormulaParameterSlotEntity::getPaixu));}
|
@Override public ElnTemplateBindingEntity findFieldBinding(String t,String id){return fieldBindings.selectOne(Wrappers.<ElnTemplateBindingEntity>lambdaQuery().eq(ElnTemplateBindingEntity::getFTenantId,t).eq(ElnTemplateBindingEntity::getId,id).and(q->q.isNull(ElnTemplateBindingEntity::getFDeleteMark).or().eq(ElnTemplateBindingEntity::getFDeleteMark,0)));}
|
@Override public List<ElnTemplateBindingEntity> listFieldBindings(String t,String m){return fieldBindings.selectList(Wrappers.<ElnTemplateBindingEntity>lambdaQuery().eq(ElnTemplateBindingEntity::getFTenantId,t).eq(ElnTemplateBindingEntity::getMubanId,m).and(q->q.isNull(ElnTemplateBindingEntity::getFDeleteMark).or().eq(ElnTemplateBindingEntity::getFDeleteMark,0)));}
|
@Override public ElnFieldVersionEntity findFieldVersion(String t,String id){return fieldVersions.selectOne(Wrappers.<ElnFieldVersionEntity>lambdaQuery().eq(ElnFieldVersionEntity::getFTenantId,t).eq(ElnFieldVersionEntity::getId,id).and(q->q.isNull(ElnFieldVersionEntity::getFDeleteMark).or().eq(ElnFieldVersionEntity::getFDeleteMark,0)));}
|
@Override public ElnTemplateFormulaBindingEntity findByOperation(String t,String m,String o){return formulaBindings.selectOne(Wrappers.<ElnTemplateFormulaBindingEntity>lambdaQuery().eq(ElnTemplateFormulaBindingEntity::getFTenantId,t).eq(ElnTemplateFormulaBindingEntity::getMubanId,m).eq(ElnTemplateFormulaBindingEntity::getCaozuoBianma,o).and(q->q.isNull(ElnTemplateFormulaBindingEntity::getFDeleteMark).or().eq(ElnTemplateFormulaBindingEntity::getFDeleteMark,0)));}
|
@Override public ElnTemplateFormulaBindingEntity findBinding(String t,String id){return formulaBindings.selectOne(Wrappers.<ElnTemplateFormulaBindingEntity>lambdaQuery().eq(ElnTemplateFormulaBindingEntity::getFTenantId,t).eq(ElnTemplateFormulaBindingEntity::getId,id).and(q->q.isNull(ElnTemplateFormulaBindingEntity::getFDeleteMark).or().eq(ElnTemplateFormulaBindingEntity::getFDeleteMark,0)));}
|
@Override public List<ElnTemplateFormulaBindingEntity> listBindings(String t,String m){return formulaBindings.selectList(Wrappers.<ElnTemplateFormulaBindingEntity>lambdaQuery().eq(ElnTemplateFormulaBindingEntity::getFTenantId,t).eq(ElnTemplateFormulaBindingEntity::getMubanId,m).and(q->q.isNull(ElnTemplateFormulaBindingEntity::getFDeleteMark).or().eq(ElnTemplateFormulaBindingEntity::getFDeleteMark,0)).orderByAsc(ElnTemplateFormulaBindingEntity::getId));}
|
@Override public boolean insertIfAbsent(ElnTemplateFormulaBindingEntity b){return formulaBindings.insertIfAbsent(b)==1;}
|
@Override public boolean updateStatus(ElnTemplateFormulaBindingEntity b,int v,String s,String r){int n=formulaBindings.updateStatus(b,v,s,r); if(n==1){b.setBangdingZhuangtai(s);b.setZhuangtaiYuanyin(r);b.setFVersion(v+1);} return n==1;}
|
@Override public void updateTopology(ElnTemplateFormulaBindingEntity b,int order){formulaBindings.update(null,Wrappers.<ElnTemplateFormulaBindingEntity>lambdaUpdate().eq(ElnTemplateFormulaBindingEntity::getFTenantId,b.getFTenantId()).eq(ElnTemplateFormulaBindingEntity::getId,b.getId()).eq(ElnTemplateFormulaBindingEntity::getBangdingZhuangtai,ACTIVE).set(ElnTemplateFormulaBindingEntity::getTuopuXuhao,order));b.setTuopuXuhao(order);}
|
}
|
}
|