package jnpf.limsService.impl;
|
|
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
|
import jnpf.lims.api.model.TestWorkItemSnapshotBatch;
|
import jnpf.lims.api.model.TestWorkItemSnapshot;
|
import jnpf.lims.api.model.TestWorkItemSnapshotProperty;
|
import jnpf.lims.api.model.TestWorkItemSnapshotRequest;
|
import jnpf.limsEntity.LimsJianyanXiangEntity;
|
import jnpf.limsMapper.LimsJianyanXiangMapper;
|
import org.apache.ibatis.annotations.Select;
|
import org.junit.Test;
|
|
import java.lang.reflect.Method;
|
import java.util.Arrays;
|
import java.util.Calendar;
|
import java.util.Collections;
|
import java.util.Date;
|
import java.util.List;
|
|
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertTrue;
|
|
public class LimsTestWorkItemSnapshotServiceImplTest {
|
|
@Test
|
public void taskLookupFiltersDeletedTasksButResolvesSoftDeletedProjectHistory() throws Exception {
|
Method method = LimsJianyanXiangMapper.class.getMethod(
|
"selectSnapshotTasks", String.class, List.class);
|
|
assertArrayEquals(new String[]{"Ilg@true"},
|
method.getAnnotation(InterceptorIgnore.class).others());
|
String sql = String.join(" ", method.getAnnotation(Select.class).value());
|
assertTrue(sql.contains("f_tenant_id = #{tenantId}"));
|
assertTrue(sql.contains("task.f_delete_mark IS NULL OR task.f_delete_mark = 0"));
|
assertTrue(sql.contains("LEFT JOIN lims_qingyandan"));
|
assertTrue(sql.contains("LEFT JOIN zhiliang_biaozhun_guanli_zixiang"));
|
assertTrue(sql.contains("quality_standard.gongyang_danwei AS qualityStandardSource"));
|
assertTrue(sql.contains("FROM jianyan_xiangmu_guanli"));
|
assertTrue(sql.contains("FROM jianyan_xiangmu_guanli GROUP BY f_tenant_id, bianma"));
|
assertTrue(sql.contains("GROUP BY f_tenant_id, bianma"));
|
assertTrue(sql.contains("project.f_tenant_id = task.f_tenant_id"));
|
assertTrue(sql.contains("project.bianma = task.jianyan_xiangmu_bianma"));
|
assertTrue(sql.contains("project.match_count AS testDefinitionMatchCount"));
|
assertTrue(sql.contains("task.qingyandan_id AS qingyandanId"));
|
}
|
|
@Test
|
public void returnsFrozenBasisForNormalExternalAndWaterTestWorkItems() {
|
LimsTestWorkItemSnapshotServiceImpl service = new LimsTestWorkItemSnapshotServiceImpl(
|
(tenantId, ids) -> Arrays.asList(
|
task("normal", tenantId, "pending_test", "user-a", null, "普通依据"),
|
task("external", tenantId, "pending_test", null, "user-a", "外检依据"),
|
task("water", tenantId, "pending_test", "user-a", null, "水系统冻结依据")));
|
|
TestWorkItemSnapshotBatch result = service.resolve(request("normal", "external", "water"), "0", "user-a");
|
|
assertEquals(3, result.getItems().size());
|
assertSnapshot(result.getItems().get(0), "normal", "普通依据");
|
assertSnapshot(result.getItems().get(1), "external", "外检依据");
|
assertSnapshot(result.getItems().get(2), "water", "水系统冻结依据");
|
}
|
|
@Test
|
public void returnsResolvedTestDefinitionReferenceInsteadOfQualityStandardItemId() {
|
LimsJianyanXiangEntity task = task(
|
"normal", "0", "pending_test", "user-a", null, "普通依据");
|
LimsTestWorkItemSnapshotServiceImpl service = new LimsTestWorkItemSnapshotServiceImpl(
|
(tenantId, ids) -> Collections.singletonList(task));
|
|
TestWorkItemSnapshot item = service.resolve(
|
request("normal"), "0", "user-a").getItems().get(0);
|
|
assertEquals("test-definition-normal", item.getTestDefinitionId());
|
assertEquals("CODE-normal", item.getTestDefinitionCode());
|
assertEquals("项目-normal", item.getTestDefinitionName());
|
}
|
|
@Test
|
public void exposesTheFrozenTestRequestIdentityOnEachReadableSnapshot() {
|
LimsJianyanXiangEntity task = task(
|
"normal", "0", "pending_test", "user-a", null, "依据");
|
task.setQingyandanId("request-20260901");
|
LimsTestWorkItemSnapshotServiceImpl service = new LimsTestWorkItemSnapshotServiceImpl(
|
(tenantId, ids) -> Collections.singletonList(task));
|
|
TestWorkItemSnapshot item = service.resolve(
|
request("normal"), "0", "user-a").getItems().get(0);
|
|
assertEquals("SUCCESS", item.getOutcomeCode());
|
assertEquals("request-20260901", item.getTestRequestId());
|
}
|
|
@Test
|
public void rejectsSnapshotsWithoutTheFrozenTestRequestIdentity() {
|
LimsJianyanXiangEntity task = task(
|
"normal", "0", "pending_test", "user-a", null, "依据");
|
task.setQingyandanId(null);
|
LimsTestWorkItemSnapshotServiceImpl service = new LimsTestWorkItemSnapshotServiceImpl(
|
(tenantId, ids) -> Collections.singletonList(task));
|
|
TestWorkItemSnapshot item = service.resolve(
|
request("normal"), "0", "user-a").getItems().get(0);
|
|
assertEquals("TEST_REQUEST_INVALID", item.getOutcomeCode());
|
assertEquals("检验项缺少请验单身份", item.getReason());
|
assertNull(item.getTestRequestId());
|
}
|
|
@Test
|
public void rejectsMissingOrAmbiguousTestDefinitionReference() {
|
LimsJianyanXiangEntity missingCode = task(
|
"missing-code", "0", "pending_test", "user-a", null, "依据");
|
missingCode.setJianyanXiangmuBianma(null);
|
LimsJianyanXiangEntity unresolved = task(
|
"unresolved", "0", "pending_test", "user-a", null, "依据");
|
unresolved.setTestDefinitionId(null);
|
unresolved.setTestDefinitionMatchCount(0L);
|
LimsJianyanXiangEntity ambiguous = task(
|
"ambiguous", "0", "pending_test", "user-a", null, "依据");
|
ambiguous.setTestDefinitionMatchCount(2L);
|
LimsTestWorkItemSnapshotServiceImpl service = new LimsTestWorkItemSnapshotServiceImpl(
|
(tenantId, ids) -> Arrays.asList(missingCode, unresolved, ambiguous));
|
|
TestWorkItemSnapshotBatch result = service.resolve(
|
request("missing-code", "unresolved", "ambiguous"), "0", "user-a");
|
|
for (TestWorkItemSnapshot item : result.getItems()) {
|
assertEquals("TEST_DEFINITION_INVALID", item.getOutcomeCode());
|
assertNull(item.getTestDefinitionId());
|
assertNull(item.getTestDefinitionCode());
|
assertNull(item.getTestDefinitionName());
|
assertEquals("NOT_AVAILABLE", item.getProperties().get(0).getOutcomeCode());
|
}
|
}
|
|
@Test
|
public void reportsEachRejectedOrMissingValueWithoutDroppingTheBatch() {
|
LimsJianyanXiangEntity forbidden = task("forbidden", "0", "pending_test", "other-user", null, "依据");
|
LimsJianyanXiangEntity created = task("created", "0", "created", "user-a", null, "依据");
|
LimsJianyanXiangEntity pendingAssign = task("pending-assign", "0", "pending_assign", "user-a", null, "依据");
|
LimsJianyanXiangEntity deleted = task("deleted", "0", "pending_test", "user-a", null, "依据");
|
deleted.setDeleteMark(1);
|
LimsJianyanXiangEntity missing = task("missing", "0", "pending_test", "user-a", null, null);
|
LimsJianyanXiangEntity otherTenant = task("other-tenant", "other", "pending_test", "user-a", null, "依据");
|
LimsTestWorkItemSnapshotServiceImpl service = new LimsTestWorkItemSnapshotServiceImpl(
|
(tenantId, ids) -> Arrays.asList(forbidden, created, pendingAssign, deleted, missing, otherTenant));
|
|
TestWorkItemSnapshotBatch result = service.resolve(request(
|
"forbidden", "created", "pending-assign", "deleted", "missing", "other-tenant"), "0", "user-a");
|
|
assertEquals(6, result.getItems().size());
|
assertEquals("FORBIDDEN", result.getItems().get(0).getOutcomeCode());
|
assertEquals("STATE_NOT_ALLOWED", result.getItems().get(1).getOutcomeCode());
|
assertEquals("STATE_NOT_ALLOWED", result.getItems().get(2).getOutcomeCode());
|
assertEquals("DELETED", result.getItems().get(3).getOutcomeCode());
|
assertEquals("SUCCESS", result.getItems().get(4).getOutcomeCode());
|
assertEquals("MISSING", result.getItems().get(4).getProperties().get(0).getOutcomeCode());
|
assertNull(result.getItems().get(4).getProperties().get(0).getValue());
|
assertEquals("NOT_FOUND", result.getItems().get(5).getOutcomeCode());
|
assertEquals("NOT_AVAILABLE", result.getItems().get(0).getProperties().get(0).getOutcomeCode());
|
assertNull(result.getItems().get(0).getProperties().get(0).getValue());
|
}
|
|
@Test
|
public void rejectsUnknownPropertyForEveryTestWorkItem() {
|
LimsTestWorkItemSnapshotServiceImpl service = new LimsTestWorkItemSnapshotServiceImpl(
|
(tenantId, ids) -> Collections.singletonList(task(
|
"normal", tenantId, "pending_test", "user-a", null, "依据")));
|
TestWorkItemSnapshotRequest request = new TestWorkItemSnapshotRequest();
|
request.setTestWorkItemIds(Arrays.asList("normal", "not-found"));
|
request.setProperties(Collections.singletonList("sample.code"));
|
|
TestWorkItemSnapshotBatch result = service.resolve(request, "0", "user-a");
|
|
assertEquals(2, result.getItems().size());
|
for (TestWorkItemSnapshot item : result.getItems()) {
|
TestWorkItemSnapshotProperty property = item.getProperties().get(0);
|
assertEquals("sample.code", property.getProperty());
|
assertEquals("UNSUPPORTED_PROPERTY", property.getOutcomeCode());
|
}
|
}
|
|
@Test
|
public void returnsSampleAndTestPropertiesFromOneWorkItemSnapshot() {
|
LimsJianyanXiangEntity task = task("normal", "0", "pending_test", "user-a", null, "依据");
|
task.setChanpinMingcheng("阿司匹林片");
|
task.setPihao("B20260827");
|
task.setGuige("100mg");
|
task.setShengchanRiqi(date(2026, Calendar.AUGUST, 1));
|
task.setQualityStandardSource("企业标准");
|
task.setJianyanLeixing("初试");
|
LimsTestWorkItemSnapshotServiceImpl service = new LimsTestWorkItemSnapshotServiceImpl(
|
(tenantId, ids) -> Collections.singletonList(task));
|
TestWorkItemSnapshotRequest request = new TestWorkItemSnapshotRequest();
|
request.setTestWorkItemIds(Collections.singletonList("normal"));
|
request.setProperties(Arrays.asList("sample.name", "sample.batch_no", "sample.production_date",
|
"quality_standard.source", "sample.specification", "test.type"));
|
|
TestWorkItemSnapshot item = service.resolve(request, "0", "user-a").getItems().get(0);
|
|
assertEquals("SUCCESS", item.getOutcomeCode());
|
assertProperty(item, "sample.name", "TEXT", "阿司匹林片");
|
assertProperty(item, "sample.batch_no", "TEXT", "B20260827");
|
assertProperty(item, "sample.production_date", "DATE", "2026-08-01");
|
assertProperty(item, "quality_standard.source", "TEXT", "企业标准");
|
assertProperty(item, "sample.specification", "TEXT", "100mg");
|
assertProperty(item, "test.type", "TEXT", "初试");
|
}
|
|
@Test
|
public void reportsMissingForBlankOptionalRelatedProperties() {
|
LimsTestWorkItemSnapshotServiceImpl service = new LimsTestWorkItemSnapshotServiceImpl(
|
(tenantId, ids) -> Collections.singletonList(task(
|
"normal", tenantId, "pending_test", "user-a", null, "依据")));
|
TestWorkItemSnapshotRequest request = new TestWorkItemSnapshotRequest();
|
request.setTestWorkItemIds(Collections.singletonList("normal"));
|
request.setProperties(Arrays.asList("sample.production_date", "quality_standard.source", "test.type"));
|
|
TestWorkItemSnapshot item = service.resolve(request, "0", "user-a").getItems().get(0);
|
|
for (TestWorkItemSnapshotProperty property : item.getProperties()) {
|
assertEquals("MISSING", property.getOutcomeCode());
|
assertNull(property.getValue());
|
}
|
}
|
|
@Test
|
public void readsLegacyInspectionAliasesForExistingElnBindings() {
|
LimsJianyanXiangEntity legacyTask = task(
|
"normal", "0", "pending_test", "user-a", null, "历史依据");
|
legacyTask.setJianyanLeixing("初试");
|
LimsTestWorkItemSnapshotServiceImpl service = new LimsTestWorkItemSnapshotServiceImpl(
|
(tenantId, ids) -> Collections.singletonList(legacyTask));
|
TestWorkItemSnapshotRequest request = new TestWorkItemSnapshotRequest();
|
request.setTestWorkItemIds(Collections.singletonList("normal"));
|
request.setProperties(Arrays.asList("inspection.basis", "inspection.type"));
|
|
List<TestWorkItemSnapshotProperty> properties = service.resolve(request, "0", "user-a")
|
.getItems().get(0).getProperties();
|
|
assertEquals("inspection.basis", properties.get(0).getProperty());
|
assertEquals("SUCCESS", properties.get(0).getOutcomeCode());
|
assertEquals("历史依据", properties.get(0).getValue());
|
assertEquals("inspection.type", properties.get(1).getProperty());
|
assertEquals("SUCCESS", properties.get(1).getOutcomeCode());
|
assertEquals("初试", properties.get(1).getValue());
|
}
|
|
private static TestWorkItemSnapshotRequest request(String... ids) {
|
TestWorkItemSnapshotRequest request = new TestWorkItemSnapshotRequest();
|
request.setTestWorkItemIds(Arrays.asList(ids));
|
request.setProperties(Collections.singletonList("test.basis"));
|
return request;
|
}
|
|
private static LimsJianyanXiangEntity task(String id, String tenantId, String status,
|
String jianchaRen, String waijianLururen, String basis) {
|
LimsJianyanXiangEntity task = new LimsJianyanXiangEntity();
|
task.setId(id);
|
task.setQingyandanId("request-" + id);
|
task.setForeignId("quality-standard-item-" + id);
|
task.setTestDefinitionId("test-definition-" + id);
|
task.setTestDefinitionMatchCount(1L);
|
task.setJianyanXiangmuBianma("CODE-" + id);
|
task.setJianyanXiangmuMingcheng("项目-" + id);
|
task.setTenantId(tenantId);
|
task.setJianyanZhuangtai(status);
|
task.setJianchaRen(jianchaRen);
|
task.setWaijianLururen(waijianLururen);
|
task.setShifouWaijian(waijianLururen == null ? "no" : "yes");
|
task.setBiaozhunGuiding(basis);
|
return task;
|
}
|
|
private static void assertSnapshot(TestWorkItemSnapshot item, String id, String basis) {
|
assertEquals(id, item.getTestWorkItemId());
|
assertEquals("test-definition-" + id, item.getTestDefinitionId());
|
assertEquals("CODE-" + id, item.getTestDefinitionCode());
|
assertEquals("项目-" + id, item.getTestDefinitionName());
|
assertEquals("SUCCESS", item.getOutcomeCode());
|
TestWorkItemSnapshotProperty property = item.getProperties().get(0);
|
assertEquals("test.basis", property.getProperty());
|
assertEquals("TEXT", property.getDataType());
|
assertEquals("LIMS_TASK", property.getSource());
|
assertEquals(id, property.getSourceRef());
|
assertEquals("SUCCESS", property.getOutcomeCode());
|
assertEquals(basis, property.getValue());
|
}
|
|
private static void assertProperty(TestWorkItemSnapshot item, String code, String type, String value) {
|
for (TestWorkItemSnapshotProperty property : item.getProperties()) {
|
if (code.equals(property.getProperty())) {
|
assertEquals(type, property.getDataType());
|
assertEquals("SUCCESS", property.getOutcomeCode());
|
assertEquals(value, property.getValue());
|
return;
|
}
|
}
|
throw new AssertionError("缺少属性:" + code);
|
}
|
|
private static Date date(int year, int month, int day) {
|
Calendar calendar = Calendar.getInstance();
|
calendar.clear();
|
calendar.set(year, month, day);
|
return calendar.getTime();
|
}
|
}
|