package jnpf.dmsService.impl;
|
|
import jnpf.base.Pagination;
|
import jnpf.base.UserInfo;
|
import jnpf.dmsEntity.DmsWenjianBianhaoEntity;
|
import jnpf.dmsEntity.DmsWenjianBianhaoGuizeEntity;
|
import jnpf.dmsEntity.DmsWenjianBianhaoGuizeZixiangEntity;
|
import jnpf.dmsEntity.DmsWenjianBianhaoShenqingEntity;
|
import jnpf.dmsEntity.DmsWenjianMingchengBiangengShenqingEntity;
|
import jnpf.dmsEntity.wenjianbianhao.DmsFlowEventType;
|
import jnpf.dmsMapper.DmsWenjianBianhaoGuizeMapper;
|
import jnpf.dmsMapper.DmsWenjianBianhaoGuizeZixiangMapper;
|
import jnpf.dmsMapper.DmsWenjianBianhaoLiushuiJishuMapper;
|
import jnpf.dmsMapper.DmsWenjianBianhaoMapper;
|
import jnpf.dmsMapper.DmsWenjianBianhaoShenqingMapper;
|
import jnpf.dmsMapper.DmsWenjianMingchengBiangengShenqingMapper;
|
import jnpf.dmsPermission.DmsCurrentIdentity;
|
import jnpf.dmsService.DmsWenjianBianhaoPermissionService;
|
import jnpf.exception.DataException;
|
import jnpf.permission.UserApi;
|
import jnpf.permission.entity.UserEntity;
|
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.mockito.InjectMocks;
|
import org.mockito.Mock;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
|
import java.util.Arrays;
|
import java.util.Collections;
|
import java.util.Date;
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.Mockito.lenient;
|
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.when;
|
|
@ExtendWith(MockitoExtension.class)
|
class DmsWenjianBianhaoApplicationServiceImplTest {
|
|
private static final String TENANT_ID = "tenant-1";
|
private static final String FLOW_ID = "flow-1";
|
private static final String TASK_ID = "task-1";
|
|
@Mock private DmsCurrentIdentity identity;
|
@Mock private DmsWenjianBianhaoPermissionService permissionService;
|
@Mock private DmsWenjianBianhaoGuizeMapper ruleMapper;
|
@Mock private DmsWenjianBianhaoGuizeZixiangMapper partMapper;
|
@Mock private DmsWenjianBianhaoShenqingMapper applicationMapper;
|
@Mock private DmsWenjianBianhaoMapper numberMapper;
|
@Mock private DmsWenjianBianhaoLiushuiJishuMapper counterMapper;
|
@Mock private DmsWenjianMingchengBiangengShenqingMapper nameChangeMapper;
|
@Mock private UserApi userApi;
|
|
@InjectMocks
|
private DmsWenjianBianhaoApplicationServiceImpl service;
|
|
@BeforeEach
|
void setUpIdentity() {
|
UserInfo user = new UserInfo();
|
user.setUserId("operator-1");
|
user.setTenantId(TENANT_ID);
|
when(identity.requireUser()).thenReturn(user);
|
lenient().when(identity.tenantId(user)).thenReturn(TENANT_ID);
|
}
|
|
@Test
|
void enabledRulesArePermissionFilteredBeforePaging() throws DataException {
|
Pagination pagination = new Pagination();
|
pagination.setCurrentPage(1);
|
pagination.setPageSize(20);
|
DmsWenjianBianhaoGuizeEntity allowed = rule("rule-1", "QC-SOP规则");
|
allowed.setGuizeLeixing("SOP");
|
allowed.setWenjianMulu("/质量控制部QC/SOP");
|
DmsWenjianBianhaoGuizeEntity denied = rule("rule-2", "QA-SOP规则");
|
when(ruleMapper.selectEnabled(TENANT_ID)).thenReturn(Arrays.asList(allowed, denied));
|
when(permissionService.canApplyRule("operator-1", "rule-1")).thenReturn(true);
|
when(permissionService.canApplyRule("operator-1", "rule-2")).thenReturn(false);
|
when(ruleMapper.selectActiveById(TENANT_ID, "rule-1")).thenReturn(allowed);
|
when(partMapper.selectActiveByRule(TENANT_ID, "rule-1")).thenReturn(Arrays.asList(
|
part("1", "gudingzhi", "QC", "-"),
|
part("2", "liushuihao", "000", "")));
|
|
jnpf.dmsEntity.wenjianbianhao.vo.DmsWenjianBianhaoRuleVO result =
|
service.enabledRules(pagination, null, "SOP").get(0);
|
|
assertEquals("rule-1", result.getId());
|
assertEquals("QC-待审", result.getYulanBianhao());
|
assertEquals("QC-SOP规则 / QC-待审", result.getGuizeXianshi());
|
assertEquals(1, pagination.getTotal());
|
verify(permissionService).canApplyRule("operator-1", "rule-1");
|
verify(permissionService).canApplyRule("operator-1", "rule-2");
|
}
|
|
@Test
|
void rejectsEventUntilFormAndWorkflowStatesMatch() {
|
DmsWenjianBianhaoShenqingEntity application = application(1);
|
when(applicationMapper.selectByFlowForUpdate(TENANT_ID, FLOW_ID, TASK_ID))
|
.thenReturn(Collections.singletonList(application));
|
|
assertThrows(DataException.class, () -> service.syncApplicationFlow(
|
FLOW_ID, TASK_ID, 2, DmsFlowEventType.END));
|
|
verify(numberMapper, never()).selectByApplicationForUpdate(any(), any());
|
}
|
|
@Test
|
void startEventFreezesOrderedRuleSnapshotAndUsesApplicantPermission() {
|
DmsWenjianBianhaoShenqingEntity application = application(1);
|
application.setShenqingRenId("applicant-1");
|
DmsWenjianBianhaoEntity number = number("number-1", "rule-1", "设备清洁规程");
|
when(applicationMapper.selectByFlowForUpdate(TENANT_ID, FLOW_ID, TASK_ID))
|
.thenReturn(Collections.singletonList(application));
|
when(numberMapper.selectByApplicationForUpdate(TENANT_ID, application.getId()))
|
.thenReturn(Collections.singletonList(number));
|
when(permissionService.canApplyRule("applicant-1", "rule-1")).thenReturn(true);
|
when(ruleMapper.selectActiveById(TENANT_ID, "rule-1"))
|
.thenReturn(rule("rule-1", "QC-SOP规则"));
|
when(partMapper.selectActiveByRule(TENANT_ID, "rule-1")).thenReturn(Arrays.asList(
|
part("1", "gudingzhi", "QC", "-"),
|
part("2", "liushuihao", "000", "")));
|
when(numberMapper.updateById(number)).thenReturn(1);
|
|
service.syncApplicationFlow(FLOW_ID, TASK_ID, 1, DmsFlowEventType.START);
|
service.syncApplicationFlow(FLOW_ID, TASK_ID, 1, DmsFlowEventType.START);
|
|
assertEquals("pending_review", number.getBizStatus());
|
assertEquals("rule-1", number.getGuizeKuaizhaoId());
|
assertEquals("QC-{SERIAL:3}", number.getBianhaoMuban());
|
assertEquals("QC-待审", number.getYulanBianhao());
|
assertEquals("QC-待审", number.getShenqingBianhao());
|
assertEquals("设备清洁规程", number.getDangqianWenjianMingcheng());
|
assertEquals(1, number.getMingchengBanben());
|
verify(permissionService).canApplyRule("applicant-1", "rule-1");
|
verify(ruleMapper, times(1)).selectActiveById(TENANT_ID, "rule-1");
|
verify(partMapper, times(1)).selectActiveByRule(TENANT_ID, "rule-1");
|
verify(numberMapper, times(1)).updateById(number);
|
}
|
|
@Test
|
void repeatedPassedEventDoesNotConsumeAnotherSerial() {
|
DmsWenjianBianhaoShenqingEntity application = application(2);
|
DmsWenjianBianhaoEntity number = number("number-1", "rule-1", "设备清洁规程");
|
number.setGuizeKuaizhao("[{}]");
|
number.setGuizeKuaizhaoId("rule-1");
|
number.setBianhaoMuban("QC-{SERIAL:3}");
|
number.setBizStatus("pending_review");
|
when(applicationMapper.selectByFlowForUpdate(TENANT_ID, FLOW_ID, TASK_ID))
|
.thenReturn(Collections.singletonList(application));
|
when(numberMapper.selectByApplicationForUpdate(TENANT_ID, application.getId()))
|
.thenReturn(Collections.singletonList(number));
|
when(counterMapper.next(TENANT_ID, "rule-1", "QC-{SERIAL:3}")).thenReturn(7L);
|
when(numberMapper.updateById(number)).thenReturn(1);
|
|
service.syncApplicationFlow(FLOW_ID, TASK_ID, 2, DmsFlowEventType.END);
|
service.syncApplicationFlow(FLOW_ID, TASK_ID, 2, DmsFlowEventType.END);
|
|
assertEquals("QC-007", number.getWenjianBianhao());
|
assertEquals("QC-007", number.getShenqingBianhao());
|
assertEquals("007", number.getLiushuiHao());
|
assertEquals("using", number.getBizStatus());
|
org.junit.jupiter.api.Assertions.assertNotNull(number.getBianhaoFafangShijian());
|
verify(counterMapper, times(1)).next(TENANT_ID, "rule-1", "QC-{SERIAL:3}");
|
verify(numberMapper, times(1)).updateById(number);
|
}
|
|
@Test
|
void usingNumbersReturnsPopupFieldsFromTenantScopedQuery() throws DataException {
|
Pagination pagination = new Pagination();
|
pagination.setCurrentPage(1);
|
pagination.setPageSize(20);
|
DmsWenjianBianhaoEntity number = number("number-1", "rule-1", "原文件名称");
|
number.setWenjianBianhao("QC-001");
|
number.setDangqianWenjianMingcheng("当前文件名称");
|
number.setMingchengBanben(2);
|
number.setGuizeMingchengKuaizhao("QC-SOP规则");
|
number.setShiyongRenId("user-1");
|
number.setBianhaoFafangShijian(new Date());
|
when(numberMapper.selectUsing(TENANT_ID, "number-1", pagination))
|
.thenReturn(Collections.singletonList(number));
|
when(permissionService.canViewNumber("operator-1", "number-1")).thenReturn(true);
|
UserEntity user = new UserEntity();
|
user.setId("user-1");
|
user.setRealName("张三");
|
when(userApi.getUserName(Collections.singletonList("user-1")))
|
.thenReturn(Collections.singletonList(user));
|
|
jnpf.dmsEntity.wenjianbianhao.vo.DmsWenjianBianhaoOptionVO result =
|
service.usingNumbers(pagination, " number-1 ", "当前").get(0);
|
|
assertEquals("number-1", result.getId());
|
assertEquals("QC-001", result.getWenjianBianhao());
|
assertEquals("当前文件名称", result.getWenjianMingcheng());
|
assertEquals(2, result.getMingchengBanben());
|
assertEquals("张三", result.getShiyongRen());
|
assertEquals("QC-001 / 当前文件名称", result.getBianhaoXianshi());
|
assertEquals("当前", pagination.getKeyword());
|
verify(permissionService).canViewNumber("operator-1", "number-1");
|
verify(numberMapper).selectUsing(TENANT_ID, "number-1", pagination);
|
}
|
|
@Test
|
void usingNumbersExcludeRowsDeniedByPermissionService() throws DataException {
|
Pagination pagination = new Pagination();
|
pagination.setCurrentPage(1);
|
pagination.setPageSize(20);
|
DmsWenjianBianhaoEntity denied = number("number-1", "rule-1", "受限文件");
|
denied.setWenjianBianhao("QA-001");
|
when(numberMapper.selectUsing(TENANT_ID, "", pagination))
|
.thenReturn(Collections.singletonList(denied));
|
when(permissionService.canViewNumber("operator-1", "number-1")).thenReturn(false);
|
|
assertEquals(0, service.usingNumbers(pagination, null, null).size());
|
|
verify(permissionService).canViewNumber("operator-1", "number-1");
|
verify(userApi, never()).getUserName(any());
|
}
|
|
@Test
|
void recallOnlyRestoresUnissuedNumberToDraft() {
|
DmsWenjianBianhaoShenqingEntity application = application(9);
|
DmsWenjianBianhaoEntity pending = number("number-1", "rule-1", "文件一");
|
pending.setBizStatus("pending_review");
|
DmsWenjianBianhaoEntity issued = number("number-2", "rule-1", "文件二");
|
issued.setBizStatus("using");
|
issued.setWenjianBianhao("QC-001");
|
when(applicationMapper.selectByFlowForUpdate(TENANT_ID, FLOW_ID, TASK_ID))
|
.thenReturn(Collections.singletonList(application));
|
when(numberMapper.selectByApplicationForUpdate(TENANT_ID, application.getId()))
|
.thenReturn(Arrays.asList(pending, issued));
|
when(numberMapper.updateById(pending)).thenReturn(1);
|
|
service.syncApplicationFlow(FLOW_ID, TASK_ID, 9, DmsFlowEventType.RECALL);
|
|
assertEquals("draft", pending.getBizStatus());
|
assertEquals("using", issued.getBizStatus());
|
verify(numberMapper).updateById(pending);
|
verify(numberMapper, never()).updateById(issued);
|
}
|
|
@Test
|
void nameChangePassIsVersionCheckedAndIdempotent() {
|
DmsWenjianMingchengBiangengShenqingEntity change = new DmsWenjianMingchengBiangengShenqingEntity();
|
change.setId("change-1");
|
change.setTenantId(TENANT_ID);
|
change.setFlowId(FLOW_ID);
|
change.setFlowTaskId(TASK_ID);
|
change.setFlowState(1);
|
change.setBianhaoId("number-1");
|
change.setBiangengHouWenjianMingcheng("新文件名称");
|
DmsWenjianBianhaoEntity number = number("number-1", "rule-1", "原文件名称");
|
number.setBizStatus("using");
|
number.setWenjianBianhao("QC-001");
|
number.setDangqianWenjianMingcheng("原文件名称");
|
number.setMingchengBanben(3);
|
when(nameChangeMapper.selectByFlowForUpdate(TENANT_ID, FLOW_ID, TASK_ID))
|
.thenReturn(Collections.singletonList(change));
|
when(numberMapper.selectActiveByIdForUpdate(TENANT_ID, "number-1")).thenReturn(number);
|
when(nameChangeMapper.updateById(change)).thenReturn(1);
|
when(numberMapper.updateById(number)).thenReturn(1);
|
|
service.syncNameChangeFlow(FLOW_ID, TASK_ID, 1, DmsFlowEventType.START);
|
change.setFlowState(2);
|
service.syncNameChangeFlow(FLOW_ID, TASK_ID, 2, DmsFlowEventType.END);
|
service.syncNameChangeFlow(FLOW_ID, TASK_ID, 2, DmsFlowEventType.END);
|
|
assertEquals("原文件名称", change.getYuanWenjianMingcheng());
|
assertEquals(3, change.getYuanMingchengBanben());
|
assertEquals("新文件名称", number.getDangqianWenjianMingcheng());
|
assertEquals(4, number.getMingchengBanben());
|
verify(numberMapper, times(1)).updateById(number);
|
}
|
|
@Test
|
void nameChangeStartRejectsAnotherActiveApplicationForTheSameNumber() {
|
DmsWenjianMingchengBiangengShenqingEntity change =
|
new DmsWenjianMingchengBiangengShenqingEntity();
|
change.setId("change-2");
|
change.setTenantId(TENANT_ID);
|
change.setFlowId(FLOW_ID);
|
change.setFlowTaskId(TASK_ID);
|
change.setFlowState(1);
|
change.setBianhaoId("number-1");
|
change.setBiangengHouWenjianMingcheng("另一个新名称");
|
DmsWenjianBianhaoEntity number = number("number-1", "rule-1", "原文件名称");
|
number.setBizStatus("using");
|
number.setWenjianBianhao("QC-001");
|
when(nameChangeMapper.selectByFlowForUpdate(TENANT_ID, FLOW_ID, TASK_ID))
|
.thenReturn(Collections.singletonList(change));
|
when(numberMapper.selectActiveByIdForUpdate(TENANT_ID, "number-1")).thenReturn(number);
|
when(nameChangeMapper.countActiveByNumber(TENANT_ID, "number-1", "change-2"))
|
.thenReturn(1);
|
|
DataException exception = assertThrows(DataException.class,
|
() -> service.syncNameChangeFlow(FLOW_ID, TASK_ID, 1, DmsFlowEventType.START));
|
|
assertEquals("该文件编号已有进行中的名称变更申请,请勿重复提交", exception.getMessage());
|
verify(nameChangeMapper, never()).updateById(change);
|
}
|
|
private DmsWenjianBianhaoShenqingEntity application(int flowState) {
|
DmsWenjianBianhaoShenqingEntity application = new DmsWenjianBianhaoShenqingEntity();
|
application.setId("application-1");
|
application.setTenantId(TENANT_ID);
|
application.setFlowId(FLOW_ID);
|
application.setFlowTaskId(TASK_ID);
|
application.setFlowState(flowState);
|
return application;
|
}
|
|
private DmsWenjianBianhaoEntity number(String id, String ruleId, String name) {
|
DmsWenjianBianhaoEntity number = new DmsWenjianBianhaoEntity();
|
number.setId(id);
|
number.setForeignId("application-1");
|
number.setTenantId(TENANT_ID);
|
number.setGuizeId(ruleId);
|
number.setYuanWenjianMingcheng(name);
|
return number;
|
}
|
|
private DmsWenjianBianhaoGuizeEntity rule(String id, String name) {
|
DmsWenjianBianhaoGuizeEntity rule = new DmsWenjianBianhaoGuizeEntity();
|
rule.setId(id);
|
rule.setTenantId(TENANT_ID);
|
rule.setGuizeMingcheng(name);
|
rule.setBizEnabled("enabled");
|
return rule;
|
}
|
|
private DmsWenjianBianhaoGuizeZixiangEntity part(
|
String id, String type, String value, String separator) {
|
DmsWenjianBianhaoGuizeZixiangEntity part = new DmsWenjianBianhaoGuizeZixiangEntity();
|
part.setId(id);
|
part.setTenantId(TENANT_ID);
|
part.setForeignId("rule-1");
|
part.setBianhaoZuheLeixing(type);
|
part.setZhi(value);
|
part.setFengefu(separator);
|
return part;
|
}
|
}
|