package jnpf.elnService.impl; import jnpf.elnService.ElnRecordFillTicketService; import jnpf.elnEntity.runtime.ElnRecordEntity; import jnpf.elnEntity.runtime.ElnRecordFieldValueEntity; import jnpf.elnEntity.runtime.ElnRecordRevisionEntity; import jnpf.elnEntity.runtime.ElnRecordRepeatRowEntity; import jnpf.elnEntity.runtime.ElnRecordRepeatValueEntity; import jnpf.elnEntity.field.ElnFieldVersionEntity; import jnpf.elnEntity.template.ElnTemplateBindingEntity; import jnpf.elnEntity.template.ElnTemplateVos; import jnpf.elnMapper.ElnFieldVersionMapper; import jnpf.elnMapper.ElnRecordFieldValueMapper; import jnpf.elnMapper.ElnRecordMapper; import jnpf.elnMapper.ElnRecordRevisionMapper; import jnpf.elnMapper.ElnRecordRepeatRowMapper; import jnpf.elnMapper.ElnRecordRepeatValueMapper; import jnpf.elnMapper.ElnTemplateBindingMapper; import jnpf.elnService.template.ElnTemplateCheckboxGroupService; import jnpf.elnService.template.ElnTemplateRepeatGroupService; import jnpf.elnService.template.ElnTemplateStepService; import jnpf.elnService.field.ElnTestResultFields; import jnpf.util.JsonUtil; import org.junit.Test; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.Arrays; import java.util.List; import java.lang.reflect.Proxy; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.fail; public class ElnRecordFillDataServiceImplTest { @Test public void preservesConfiguredBooleanNullFalseAndTrueAsReadonlySourceValues() { for (String text : new String[]{null, "false", "true"}) { ElnRecordEntity record = new ElnRecordEntity(); record.setId("record-a"); record.setMubanId("template-a"); record.setDangqianXiudingId("revision-a"); ElnRecordRevisionEntity revision = new ElnRecordRevisionEntity(); revision.setId("revision-a"); ElnRecordFieldValueEntity value = new ElnRecordFieldValueEntity(); value.setZiduanBianma("configured_bool"); value.setZiduanBanbenId("version-bool"); value.setZhiLaiyuan("LIMS_TASK"); value.setYuanShuxingBanben(1); value.setZhiWenben(text); ElnFieldVersionEntity version = new ElnFieldVersionEntity(); version.setShujuLeixing("CHECKBOX"); ElnRecordFillDataServiceImpl service = new ElnRecordFillDataServiceImpl( mapper(ElnRecordMapper.class, method -> "selectOne".equals(method) ? record : null), mapper(ElnRecordRevisionMapper.class, method -> "selectOne".equals(method) ? revision : null), mapper(ElnRecordFieldValueMapper.class, method -> "selectList".equals(method) ? Collections.singletonList(value) : null), mapper(ElnFieldVersionMapper.class, method -> "selectOne".equals(method) ? version : null), new ElnRecordFillDataServiceImpl.TenantRoute() { @Override public void switchTo(String tenantId) { } @Override public void clear() { } }); Map field = (Map) service.fields(recordTicket()).get("eln.field.configured_bool"); assertEquals(text == null ? null : Boolean.valueOf(text), field.get("value")); assertEquals(Boolean.TRUE, field.get("readOnly")); assertEquals("LIMS_TASK", field.get("valueSource")); } } @Test public void returnsRequiredAndFormulaMetadataForScalarFields() { ElnRecordEntity record = new ElnRecordEntity(); record.setId("record-a"); record.setMubanId("template-a"); record.setDangqianXiudingId("revision-a"); ElnRecordRevisionEntity revision = new ElnRecordRevisionEntity(); revision.setId("revision-a"); ElnRecordFieldValueEntity value = new ElnRecordFieldValueEntity(); value.setZiduanBianma(ElnTestResultFields.RESULT); value.setZiduanBanbenId("version-result"); value.setZhiWenben("4"); value.setZhiLaiyuan("CROSS_TEMPLATE"); value.setJisuanZhuangtai("SUCCESS"); value.setJisuanXiaoxi("计算完成"); ElnFieldVersionEntity version = new ElnFieldVersionEntity(); version.setShujuLeixing("TEXT"); version.setShifouBitian(1); ElnRecordFillDataServiceImpl service = new ElnRecordFillDataServiceImpl( mapper(ElnRecordMapper.class, method -> "selectOne".equals(method) ? record : null), mapper(ElnRecordRevisionMapper.class, method -> "selectOne".equals(method) ? revision : null), mapper(ElnRecordFieldValueMapper.class, method -> "selectList".equals(method) ? Collections.singletonList(value) : null), mapper(ElnFieldVersionMapper.class, method -> "selectOne".equals(method) ? version : null), new ElnRecordFillDataServiceImpl.TenantRoute() { @Override public void switchTo(String tenantId) { } @Override public void clear() { } }); Map fields = service.fields(recordTicket()); Map field = (Map) fields.get("eln.field.jianyan_jieguo_7d4c1a"); assertEquals(Boolean.TRUE, field.get("required")); assertEquals(Boolean.TRUE, field.get("readOnly")); assertEquals("CROSS_TEMPLATE", field.get("valueSource")); assertEquals("SUCCESS", field.get("formulaStatus")); assertEquals("计算完成", field.get("formulaMessage")); assertEquals(field, fields.get("eln.field.jianyan_jieguo")); assertEquals(field, fields.get("eln.field.test.result")); } @Test public void returnsRepeatGroupLimitsAndPendingDeleteRowsForReopen() { ElnRecordEntity record = new ElnRecordEntity(); record.setId("record-a"); record.setMubanId("template-a"); record.setDangqianXiudingId("revision-a"); ElnRecordRevisionEntity revision = new ElnRecordRevisionEntity(); revision.setId("revision-a"); ElnRecordRepeatRowEntity active = repeatRow("row-1", "ACTIVE"); ElnRecordRepeatRowEntity pending = repeatRow("row-2", "DELETE_PREPARED"); pending.setDeleteOperationCode("delete-2"); pending.setDeleteReason("录入错误"); ElnRecordRepeatValueEntity activeValue = repeatValue("row-1", "合格"); ElnRecordRepeatValueEntity pendingValue = repeatValue("row-2", "待恢复"); pendingValue.setJisuanZhuangtai("ERROR"); pendingValue.setJisuanXiaoxi("除数不能为零"); ElnFieldVersionEntity version = new ElnFieldVersionEntity(); version.setShujuLeixing("TEXT"); version.setShifouBitian(1); ElnTemplateVos.RepeatGroup group = new ElnTemplateVos.RepeatGroup(); group.setGroupCode("samples"); group.setMinRows(1); group.setMaxRows(3); group.setStepId("step-repeat"); ElnTemplateVos.StepFillStructure structure = new ElnTemplateVos.StepFillStructure(); ElnTemplateVos.StepConfiguration configuration = new ElnTemplateVos.StepConfiguration(); configuration.setSingleStep(false); structure.setConfiguration(configuration); ElnRecordFillDataServiceImpl service = new ElnRecordFillDataServiceImpl( mapper(ElnRecordMapper.class, method -> "selectOne".equals(method) ? record : null), mapper(ElnRecordRevisionMapper.class, method -> "selectOne".equals(method) ? revision : null), mapper(ElnRecordFieldValueMapper.class, method -> "selectList".equals(method) ? Collections.emptyList() : null), mapper(ElnFieldVersionMapper.class, method -> "selectOne".equals(method) ? version : null), mapper(ElnRecordRepeatRowMapper.class, method -> "selectList".equals(method) ? Arrays.asList(active, pending) : null), mapper(ElnRecordRepeatValueMapper.class, method -> "selectList".equals(method) ? Arrays.asList(activeValue, pendingValue) : null), mapper(ElnTemplateRepeatGroupService.class, method -> "list".equals(method) ? Collections.singletonList(group) : null), mapper(ElnTemplateStepService.class, method -> "fillStructure".equals(method) ? structure : null), new ElnRecordFillDataServiceImpl.TenantRoute() { @Override public void switchTo(String tenantId) { } @Override public void clear() { } }); Map data = service.data(recordTicket()); Map fields = (Map) data.get("fields"); List groups = (List) data.get("repeatGroups"); Map restored = (Map) fields.get("eln.repeat.samples.row-2.result"); Map metadata = (Map) groups.get(0); List rows = (List) metadata.get("rows"); Map pendingMetadata = (Map) rows.get(1); assertEquals("待恢复", restored.get("value")); assertEquals(Boolean.TRUE, restored.get("required")); assertEquals("ERROR", restored.get("formulaStatus")); assertEquals("除数不能为零", restored.get("formulaMessage")); assertEquals(1, metadata.get("minRows")); assertEquals(3, metadata.get("maxRows")); assertEquals("step-repeat", metadata.get("stepId")); assertEquals(structure, data.get("stepStructure")); assertEquals(2, metadata.get("activeRowCount")); assertEquals("DELETE_PREPARED", pendingMetadata.get("status")); assertEquals("delete-2", pendingMetadata.get("deleteOperationCode")); assertEquals("录入错误", pendingMetadata.get("deleteReason")); } @Test public void readsRecordFieldsInsideTicketTenantAndAlwaysClearsTheRoute() { AtomicReference tenant = new AtomicReference<>(); AtomicInteger cleared = new AtomicInteger(); ElnRecordEntity record = new ElnRecordEntity(); record.setId("record-a"); record.setDangqianXiudingId("revision-a"); ElnRecordRevisionEntity revision = new ElnRecordRevisionEntity(); revision.setId("revision-a"); ElnRecordMapper records = mapper(ElnRecordMapper.class, method -> { if (!"selectOne".equals(method)) return null; assertEquals("tenant-a", tenant.get()); return record; }); ElnRecordRevisionMapper revisions = mapper(ElnRecordRevisionMapper.class, method -> "selectOne".equals(method) ? revision : null); ElnRecordFieldValueMapper values = mapper(ElnRecordFieldValueMapper.class, method -> "selectList".equals(method) ? Collections.emptyList() : null); ElnRecordFillDataServiceImpl service = service(records, revisions, values, new ElnRecordFillDataServiceImpl.TenantRoute() { @Override public void switchTo(String tenantId) { tenant.set(tenantId); } @Override public void clear() { cleared.incrementAndGet(); } }); assertEquals(Collections.emptyMap(), service.fields(recordTicket())); assertEquals("tenant-a", tenant.get()); assertEquals(1, cleared.get()); } @Test public void clearsTenantRouteWhenRecordLookupFails() { AtomicInteger cleared = new AtomicInteger(); ElnRecordMapper records = mapper(ElnRecordMapper.class, method -> { if ("selectOne".equals(method)) throw new IllegalStateException("database unavailable"); return null; }); ElnRecordRevisionMapper revisions = mapper(ElnRecordRevisionMapper.class, method -> null); ElnRecordFieldValueMapper values = mapper(ElnRecordFieldValueMapper.class, method -> null); ElnRecordFillDataServiceImpl service = service(records, revisions, values, new ElnRecordFillDataServiceImpl.TenantRoute() { @Override public void switchTo(String tenantId) { } @Override public void clear() { cleared.incrementAndGet(); } }); try { service.fields(recordTicket()); fail("record lookup failure must propagate"); } catch (IllegalStateException expected) { assertEquals("database unavailable", expected.getMessage()); } assertEquals(1, cleared.get()); } @Test public void restoresActiveRepeatValuesWithStableRuntimeTags() { ElnRecordEntity record = new ElnRecordEntity(); record.setId("record-a"); record.setMubanId("template-a"); record.setDangqianXiudingId("revision-a"); ElnRecordRevisionEntity revision = new ElnRecordRevisionEntity(); revision.setId("revision-a"); ElnRecordRepeatRowEntity row = new ElnRecordRepeatRowEntity(); row.setRowId("row-1"); row.setRowOrder(1); row.setMubanId("template-a"); row.setRepeatGroupCode("samples"); row.setOperationStatus("ACTIVE"); ElnRecordRepeatValueEntity value = new ElnRecordRepeatValueEntity(); value.setRepeatRowId("row-1"); value.setRepeatGroupCode("samples"); value.setMubanId("template-a"); value.setZiduanBianma("result"); value.setZiduanBanbenId("version-result"); value.setZhiWenben("合格"); ElnFieldVersionEntity version = new ElnFieldVersionEntity(); version.setShujuLeixing("TEXT"); ElnRecordFillDataServiceImpl service = new ElnRecordFillDataServiceImpl( mapper(ElnRecordMapper.class, method -> "selectOne".equals(method) ? record : null), mapper(ElnRecordRevisionMapper.class, method -> "selectOne".equals(method) ? revision : null), mapper(ElnRecordFieldValueMapper.class, method -> "selectList".equals(method) ? Collections.emptyList() : null), mapper(ElnFieldVersionMapper.class, method -> "selectOne".equals(method) ? version : null), mapper(ElnRecordRepeatRowMapper.class, method -> "selectList".equals(method) ? Collections.singletonList(row) : null), mapper(ElnRecordRepeatValueMapper.class, method -> "selectList".equals(method) ? Collections.singletonList(value) : null), new ElnRecordFillDataServiceImpl.TenantRoute() { @Override public void switchTo(String tenantId) { } @Override public void clear() { } }); Map fields = service.fields(recordTicket()); Map restored = (Map) fields.get("eln.repeat.samples.row-1.result"); assertEquals("text", restored.get("type")); assertEquals("合格", restored.get("value")); } @Test public void exposesCheckboxGroupsOnlyForEditablePrimaryAndRepeatCheckboxes() { ElnRecordEntity record = new ElnRecordEntity(); record.setId("record-a"); record.setMubanId("template-a"); record.setDangqianXiudingId("revision-a"); ElnRecordRevisionEntity revision = new ElnRecordRevisionEntity(); revision.setId("revision-a"); ElnRecordFieldValueEntity grouped = fieldValue("passed", "binding-passed", null); ElnRecordFieldValueEntity ungrouped = fieldValue("comment", "binding-comment", null); ElnRecordFieldValueEntity readOnly = fieldValue( "source_result", "binding-source", "CROSS_TEMPLATE"); ElnRecordFieldValueEntity reference = fieldValue("copied", "binding-reference", null); ElnRecordFieldValueEntity legacy = fieldValue("legacy", "binding-legacy", null); ElnRecordRepeatRowEntity row = repeatRow("row-1", "ACTIVE"); ElnRecordRepeatValueEntity repeat = repeatValue("row-1", "true"); repeat.setMubanBangdingId("binding-repeat"); repeat.setZiduanBianma("qualified"); ElnFieldVersionEntity checkboxVersion = new ElnFieldVersionEntity(); checkboxVersion.setShujuLeixing("CHECKBOX"); ElnTemplateBindingEntity repeatBinding = binding( "binding-repeat", "REPEAT", "CHECKBOX", "row_result"); repeatBinding.setRepeatGroupCode("samples"); repeatBinding.setZiduanBianma("qualified"); ElnTemplateVos.CheckboxGroup primaryRule = checkboxGroup("test_result", 1, 2); ElnTemplateVos.CheckboxGroup repeatRule = checkboxGroup("row_result", 0, null); ElnRecordFillDataServiceImpl service = new ElnRecordFillDataServiceImpl( mapper(ElnRecordMapper.class, method -> "selectOne".equals(method) ? record : null), mapper(ElnRecordRevisionMapper.class, method -> "selectOne".equals(method) ? revision : null), mapper(ElnRecordFieldValueMapper.class, method -> "selectList".equals(method) ? Arrays.asList(grouped, ungrouped, readOnly, reference, legacy) : null), mapper(ElnFieldVersionMapper.class, method -> "selectOne".equals(method) ? checkboxVersion : null), mapper(ElnTemplateBindingMapper.class, method -> "selectList".equals(method) ? Arrays.asList( binding("binding-passed", "PRIMARY", "CHECKBOX", "test_result"), binding("binding-comment", "PRIMARY", "CHECKBOX", null), binding("binding-source", "PRIMARY", "CHECKBOX", "test_result"), binding("binding-reference", "REFERENCE", "CHECKBOX", "test_result"), binding("binding-legacy", "PRIMARY", "CHECKBOX", "legacy_result"), repeatBinding) : null), mapper(ElnRecordRepeatRowMapper.class, method -> "selectList".equals(method) ? Collections.singletonList(row) : null), mapper(ElnRecordRepeatValueMapper.class, method -> "selectList".equals(method) ? Collections.singletonList(repeat) : null), null, mapper(ElnTemplateCheckboxGroupService.class, method -> "list".equals(method) ? Arrays.asList(primaryRule, repeatRule) : null), null, new ElnRecordFillDataServiceImpl.TenantRoute() { @Override public void switchTo(String tenantId) { } @Override public void clear() { } }); Map data = service.data(recordTicket()); @SuppressWarnings("unchecked") Map fields = (Map) data.get("fields"); assertEquals("test_result", field(fields, "eln.field.passed") .get("checkboxGroupCode")); assertEquals(1, field(fields, "eln.field.passed") .get("checkboxGroupMinSelected")); assertEquals(2, field(fields, "eln.field.passed") .get("checkboxGroupMaxSelected")); assertEquals("row_result", field(fields, "eln.repeat.samples.row-1.qualified") .get("checkboxGroupCode")); assertEquals(0, field(fields, "eln.repeat.samples.row-1.qualified") .get("checkboxGroupMinSelected")); assertEquals(null, field(fields, "eln.repeat.samples.row-1.qualified") .get("checkboxGroupMaxSelected")); assertEquals("legacy_result", field(fields, "eln.field.legacy") .get("checkboxGroupCode")); assertEquals(0, field(fields, "eln.field.legacy") .get("checkboxGroupMinSelected")); assertEquals(1, field(fields, "eln.field.legacy") .get("checkboxGroupMaxSelected")); @SuppressWarnings("unchecked") List> repeatGroups = (List>) data.get("repeatGroups"); assertEquals(Collections.singletonMap("qualified", "row_result"), repeatGroups.get(0).get("checkboxGroups")); assertFalse(field(fields, "eln.field.comment").containsKey("checkboxGroupCode")); assertFalse(field(fields, "eln.field.source_result").containsKey("checkboxGroupCode")); assertFalse(field(fields, "eln.field.copied").containsKey("checkboxGroupCode")); } private static ElnRecordFillDataServiceImpl service(ElnRecordMapper records, ElnRecordRevisionMapper revisions, ElnRecordFieldValueMapper values, ElnRecordFillDataServiceImpl.TenantRoute route) { return new ElnRecordFillDataServiceImpl(records, revisions, values, mapper(ElnFieldVersionMapper.class, method -> null), route); } private static ElnRecordRepeatRowEntity repeatRow(String rowId, String status) { ElnRecordRepeatRowEntity row = new ElnRecordRepeatRowEntity(); row.setRowId(rowId); row.setRowOrder("row-1".equals(rowId) ? 1 : 2); row.setMubanId("template-a"); row.setRepeatGroupCode("samples"); row.setOperationStatus(status); return row; } private static ElnRecordRepeatValueEntity repeatValue(String rowId, String text) { ElnRecordRepeatValueEntity value = new ElnRecordRepeatValueEntity(); value.setRepeatRowId(rowId); value.setRepeatGroupCode("samples"); value.setMubanId("template-a"); value.setZiduanBianma("result"); value.setZiduanBanbenId("version-result"); value.setZhiWenben(text); return value; } private static ElnRecordFieldValueEntity fieldValue( String fieldCode, String bindingId, String valueSource) { ElnRecordFieldValueEntity value = new ElnRecordFieldValueEntity(); value.setZiduanBianma(fieldCode); value.setZiduanBanbenId("checkbox-version"); value.setMubanBangdingId(bindingId); value.setZhiWenben("false"); value.setZhiLaiyuan(valueSource); return value; } private static ElnTemplateBindingEntity binding( String id, String role, String type, String checkboxGroupCode) { ElnTemplateBindingEntity binding = new ElnTemplateBindingEntity(); binding.setId(id); binding.setMubanId("template-a"); binding.setKongjianJuese(role); binding.setKongjianLeixing(type); binding.setBangdingZhuangtai("ACTIVE"); binding.setCheckboxGroupCode(checkboxGroupCode); return binding; } private static ElnTemplateVos.CheckboxGroup checkboxGroup( String groupCode, Integer minSelected, Integer maxSelected) { ElnTemplateVos.CheckboxGroup group = new ElnTemplateVos.CheckboxGroup(); group.setGroupCode(groupCode); group.setMinSelected(minSelected); group.setMaxSelected(maxSelected); group.setVersion(0); return group; } @SuppressWarnings("unchecked") private static Map field(Map fields, String tag) { return (Map) fields.get(tag); } private static ElnRecordFillTicketService.FillTicketContext recordTicket() { Map payload = new LinkedHashMap<>(); payload.put("scope", ElnRecordFillTicketService.SCOPE); payload.put("tenantId", "tenant-a"); payload.put("userId", "user-a"); payload.put("fileId", "file-a"); payload.put("bizDataId", "record-a"); payload.put("bizModule", ElnRecordFillTicketService.BIZ_MODULE); payload.put("bizScene", ElnRecordFillTicketService.BIZ_SCENE); payload.put("pluginGuid", "asc.{7F4E8F35-5D66-47F8-A5B4-6AB3FAACF565}"); return new ElnRecordFillTicketService(ticket -> JsonUtil.getObjectToString(payload)).parse("ticket-a"); } @SuppressWarnings("unchecked") private static T mapper(Class type, MapperMethod handler) { return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, (proxy, method, args) -> handler.invoke(method.getName())); } @FunctionalInterface private interface MapperMethod { Object invoke(String method); } }