fix(pda): ignore empty identifiers when checking half-tray jobs
This commit is contained in:
@@ -85,10 +85,20 @@ public class PdaServiceImp implements PdaService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AjaxResult halfTrayOut(TrayCodeMsg trayCodeMsg) {
|
public AjaxResult halfTrayOut(TrayCodeMsg trayCodeMsg) {
|
||||||
|
if (!"1".equals(trayCodeMsg.getExitId()) && !"2".equals(trayCodeMsg.getExitId())) {
|
||||||
|
return AjaxResult.error("请选择有效的出库出口(出口1或出口2)。");
|
||||||
|
}
|
||||||
InStockinDetail inStockinDetail = inStockinDetailService.selectInStockinDetailByStockinDetailId(trayCodeMsg.getStockinDetailId());
|
InStockinDetail inStockinDetail = inStockinDetailService.selectInStockinDetailByStockinDetailId(trayCodeMsg.getStockinDetailId());
|
||||||
// InStockin inStockin = inStockinService.selectInStockinByStockinId(inStockinDetail.getStockinId());
|
if (inStockinDetail == null) {
|
||||||
// inStockinDetail.setSpare4(inStockin.getDepartmentNo());
|
return AjaxResult.error("未查询到入库明细,请核对条码后重试。");
|
||||||
|
}
|
||||||
|
if (mapper.selectBySpare4OrCargo(inStockinDetail) > 0) {
|
||||||
|
return AjaxResult.error("该项目或匹配编码已有半盘出库作业,请完成后再操作。");
|
||||||
|
}
|
||||||
List<BasStock> hasHalfTray = basStockMapper.selectHasHalfTray(inStockinDetail);
|
List<BasStock> hasHalfTray = basStockMapper.selectHasHalfTray(inStockinDetail);
|
||||||
|
if (CollUtil.isEmpty(hasHalfTray)) {
|
||||||
|
return AjaxResult.error("未找到可出库的未满托盘,请刷新后重试。");
|
||||||
|
}
|
||||||
HashMap<String, Object> map = new HashMap<>();
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
map.put("v_tray_code", hasHalfTray.get(0).getTrayCode());
|
map.put("v_tray_code", hasHalfTray.get(0).getTrayCode());
|
||||||
map.put("v_exit_id", trayCodeMsg.getExitId());
|
map.put("v_exit_id", trayCodeMsg.getExitId());
|
||||||
|
|||||||
@@ -298,7 +298,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
|
|
||||||
|
|
||||||
<select id="selectBySpare4OrCargo" parameterType="InStockinDetail" resultType="java.lang.Integer">
|
<select id="selectBySpare4OrCargo" parameterType="InStockinDetail" resultType="java.lang.Integer">
|
||||||
select count(1) from mydo_job where job_id in (select job_id from mydo_job_detail where spare4=#{spare4} or exit_id =#{cargoNo}) and in_or_out='26'
|
select count(1) from mydo_job
|
||||||
|
where in_or_out='26' and job_id in (
|
||||||
|
select job_id from mydo_job_detail
|
||||||
|
where 1=0
|
||||||
|
<if test="spare4 != null and spare4.trim() != ''">
|
||||||
|
or spare4=#{spare4}
|
||||||
|
</if>
|
||||||
|
<if test="cargoNo != null and cargoNo.trim() != ''">
|
||||||
|
or exit_id=#{cargoNo}
|
||||||
|
</if>
|
||||||
|
)
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package com.ruoyi.pda.service;
|
||||||
|
|
||||||
|
import com.ruoyi.in.stockindetail.domain.InStockinDetail;
|
||||||
|
import com.ruoyi.in.stockindetail.service.IInStockinDetailService;
|
||||||
|
import com.ruoyi.job.mydojob.domain.MydoJob;
|
||||||
|
import com.ruoyi.job.mydojob.mapper.MydoJobMapper;
|
||||||
|
import com.ruoyi.stock.stock.domain.BasStock;
|
||||||
|
import com.ruoyi.stock.stock.mapper.BasStockMapper;
|
||||||
|
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
|
||||||
|
import org.apache.ibatis.mapping.Environment;
|
||||||
|
import org.apache.ibatis.session.Configuration;
|
||||||
|
import org.apache.ibatis.session.SqlSession;
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
|
||||||
|
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
|
||||||
|
import org.h2.jdbcx.JdbcDataSource;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.NullAndEmptySource;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
class HalfTrayEligibilityTest {
|
||||||
|
private JdbcTemplate jdbc;
|
||||||
|
private SqlSessionFactory sessions;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() throws Exception {
|
||||||
|
JdbcDataSource dataSource = new JdbcDataSource();
|
||||||
|
dataSource.setURL("jdbc:h2:mem:" + UUID.randomUUID() + ";MODE=MSSQLServer;DB_CLOSE_DELAY=-1");
|
||||||
|
jdbc = new JdbcTemplate(dataSource);
|
||||||
|
jdbc.execute("create table mydo_job(job_id varchar(80), in_or_out varchar(20))");
|
||||||
|
jdbc.execute("create table mydo_job_detail(job_id varchar(80), spare4 varchar(80), exit_id varchar(80))");
|
||||||
|
Configuration configuration = new Configuration(new Environment("test", new JdbcTransactionFactory(), dataSource));
|
||||||
|
configuration.getTypeAliasRegistry().registerAlias("MydoJob", MydoJob.class);
|
||||||
|
configuration.getTypeAliasRegistry().registerAlias("InStockinDetail", InStockinDetail.class);
|
||||||
|
try (var stream = getClass().getClassLoader().getResourceAsStream("mapper/job/MydoJobMapper.xml")) {
|
||||||
|
new XMLMapperBuilder(stream, configuration, "mapper/job/MydoJobMapper.xml", configuration.getSqlFragments()).parse();
|
||||||
|
}
|
||||||
|
sessions = new SqlSessionFactoryBuilder().build(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void close() {
|
||||||
|
jdbc.execute("shutdown");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@NullAndEmptySource
|
||||||
|
@ValueSource(strings = {" "})
|
||||||
|
void blankCodeDoesNotHideCandidatesForAnUnrelatedProject(String cargoNo) {
|
||||||
|
job("HPC202609070029", "26", "AD.A-00002.01.26", cargoNo);
|
||||||
|
InStockinDetail detail = incoming("AD.A-00002.01.32", cargoNo);
|
||||||
|
IInStockinDetailService inbound = mock(IInStockinDetailService.class);
|
||||||
|
BasStockMapper stocks = mock(BasStockMapper.class);
|
||||||
|
when(inbound.selectInStockinDetailByStockinDetailId("5673093")).thenReturn(detail);
|
||||||
|
BasStock tray333 = new BasStock();
|
||||||
|
tray333.setTrayCode("T0000333");
|
||||||
|
BasStock tray343 = new BasStock();
|
||||||
|
tray343.setTrayCode("T0000343");
|
||||||
|
when(stocks.selectHasHalfTray(detail)).thenReturn(List.of(tray333, tray343));
|
||||||
|
|
||||||
|
try (SqlSession session = sessions.openSession()) {
|
||||||
|
PdaServiceImp service = new PdaServiceImp();
|
||||||
|
ReflectionTestUtils.setField(service, "inStockinDetailService", inbound);
|
||||||
|
ReflectionTestUtils.setField(service, "basStockMapper", stocks);
|
||||||
|
ReflectionTestUtils.setField(service, "mapper", session.getMapper(MydoJobMapper.class));
|
||||||
|
|
||||||
|
assertThat(service.selectHasHalfTray("5673093"))
|
||||||
|
.extracting(BasStock::getTrayCode).containsExactly("T0000333", "T0000343");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@NullAndEmptySource
|
||||||
|
@ValueSource(strings = {" "})
|
||||||
|
void sameProjectRemainsBlockedEvenWhenCodeIsBlank(String cargoNo) {
|
||||||
|
job("SAME-PROJECT", "26", "PROJECT", "OTHER-CODE");
|
||||||
|
assertThat(count(incoming("PROJECT", cargoNo))).isEqualTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void sameNonemptyCodeStillBlocksAcrossProjectsAndCountsAJobOnlyOnce() {
|
||||||
|
job("SAME-CODE", "26", "OTHER-PROJECT", "020210100000249");
|
||||||
|
jdbc.update("insert into mydo_job_detail values(?,?,?)", "SAME-CODE", "OTHER-PROJECT", "020210100000249");
|
||||||
|
assertThat(count(incoming("PROJECT", "020210100000249"))).isEqualTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void differentNonemptyCodeDoesNotBlock() {
|
||||||
|
job("UNRELATED", "26", "OTHER-PROJECT", "OTHER-CODE");
|
||||||
|
assertThat(count(incoming("PROJECT", "CODE"))).isZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void nonHalfTrayJobsAndOrphanDetailsDoNotBlock() {
|
||||||
|
job("NORMAL-OUT", "21", "PROJECT", "CODE");
|
||||||
|
jdbc.update("insert into mydo_job_detail values(?,?,?)", "COMPLETED-JOB", "PROJECT", "CODE");
|
||||||
|
assertThat(count(incoming("PROJECT", "CODE"))).isZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void blankProjectDoesNotCreateAnotherEmptyIdentityMatch() {
|
||||||
|
job("NO-PROJECT", "26", "", "OTHER-CODE");
|
||||||
|
assertThat(count(incoming("", "CODE"))).isZero();
|
||||||
|
assertThat(count(incoming("", ""))).isZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int count(InStockinDetail detail) {
|
||||||
|
try (SqlSession session = sessions.openSession()) {
|
||||||
|
return session.getMapper(MydoJobMapper.class).selectBySpare4OrCargo(detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void job(String id, String type, String project, String code) {
|
||||||
|
jdbc.update("insert into mydo_job values(?,?)", id, type);
|
||||||
|
jdbc.update("insert into mydo_job_detail values(?,?,?)", id, project, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
private InStockinDetail incoming(String project, String code) {
|
||||||
|
InStockinDetail detail = new InStockinDetail();
|
||||||
|
detail.setSpare4(project);
|
||||||
|
detail.setCargoNo(code);
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package com.ruoyi.pda.service;
|
||||||
|
|
||||||
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
import com.ruoyi.in.stockindetail.domain.InStockinDetail;
|
||||||
|
import com.ruoyi.in.stockindetail.service.IInStockinDetailService;
|
||||||
|
import com.ruoyi.job.mydojob.mapper.MydoJobMapper;
|
||||||
|
import com.ruoyi.pda.domain.TrayCodeMsg;
|
||||||
|
import com.ruoyi.pda.mapper.PdaMapper;
|
||||||
|
import com.ruoyi.stock.stock.domain.BasStock;
|
||||||
|
import com.ruoyi.stock.stock.mapper.BasStockMapper;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
class PdaHalfTrayOutTest {
|
||||||
|
private final PdaServiceImp service = new PdaServiceImp();
|
||||||
|
private final IInStockinDetailService inbound = mock(IInStockinDetailService.class);
|
||||||
|
private final BasStockMapper stocks = mock(BasStockMapper.class);
|
||||||
|
private final MydoJobMapper jobs = mock(MydoJobMapper.class);
|
||||||
|
private final PdaMapper procedures = mock(PdaMapper.class);
|
||||||
|
private final InStockinDetail detail = new InStockinDetail();
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
ReflectionTestUtils.setField(service, "inStockinDetailService", inbound);
|
||||||
|
ReflectionTestUtils.setField(service, "basStockMapper", stocks);
|
||||||
|
ReflectionTestUtils.setField(service, "mapper", jobs);
|
||||||
|
ReflectionTestUtils.setField(service, "pdaMapper", procedures);
|
||||||
|
when(inbound.selectInStockinDetailByStockinDetailId("5673093")).thenReturn(detail);
|
||||||
|
BasStock tray = new BasStock();
|
||||||
|
tray.setTrayCode("T0000343");
|
||||||
|
when(stocks.selectHasHalfTray(detail)).thenReturn(List.of(tray));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void candidatesDisappearingBetweenLookupAndSubmitReturnBusinessError() {
|
||||||
|
when(stocks.selectHasHalfTray(detail)).thenReturn(Collections.emptyList());
|
||||||
|
AjaxResult result = service.halfTrayOut(request());
|
||||||
|
assertThat(result.isError()).isTrue();
|
||||||
|
assertThat(result.get("msg").toString()).contains("未找到", "刷新");
|
||||||
|
verifyNoInteractions(procedures);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void newlyCreatedMatchingJobBlocksSubmissionWithAnExplanation() {
|
||||||
|
when(jobs.selectBySpare4OrCargo(detail)).thenReturn(1);
|
||||||
|
AjaxResult result = service.halfTrayOut(request());
|
||||||
|
assertThat(result.isError()).isTrue();
|
||||||
|
assertThat(result.get("msg").toString()).contains("已有", "半盘出库作业");
|
||||||
|
verifyNoInteractions(procedures);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void missingInboundDetailReturnsBusinessError() {
|
||||||
|
when(inbound.selectInStockinDetailByStockinDetailId("5673093")).thenReturn(null);
|
||||||
|
AjaxResult result = service.halfTrayOut(request());
|
||||||
|
assertThat(result.isError()).isTrue();
|
||||||
|
assertThat(result.get("msg").toString()).contains("入库明细", "条码");
|
||||||
|
verifyNoInteractions(procedures);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void invalidExitIsRejectedBeforeCreatingAJob() {
|
||||||
|
TrayCodeMsg request = request();
|
||||||
|
request.setExitId("TD1008");
|
||||||
|
AjaxResult result = service.halfTrayOut(request);
|
||||||
|
assertThat(result.isError()).isTrue();
|
||||||
|
assertThat(result.get("msg").toString()).contains("出口");
|
||||||
|
verifyNoInteractions(procedures);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void successfulSubmissionKeepsExistingTrayAndExitArguments() {
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
HashMap<String, Object> args = invocation.getArgument(0);
|
||||||
|
assertThat(args).containsEntry("v_tray_code", "T0000343").containsEntry("v_exit_id", "2");
|
||||||
|
args.put("v_result", 10);
|
||||||
|
return null;
|
||||||
|
}).when(procedures).halfTrayOut(any());
|
||||||
|
assertThat(service.halfTrayOut(request()).isSuccess()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void procedureRejectionKeepsItsBusinessMessage() {
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
HashMap<String, Object> args = invocation.getArgument(0);
|
||||||
|
args.put("v_result", 4);
|
||||||
|
args.put("v_resultmsg", "该库存已被分配生成作业");
|
||||||
|
return null;
|
||||||
|
}).when(procedures).halfTrayOut(any());
|
||||||
|
AjaxResult result = service.halfTrayOut(request());
|
||||||
|
assertThat(result.isError()).isTrue();
|
||||||
|
assertThat(result.get("msg")).isEqualTo("该库存已被分配生成作业");
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrayCodeMsg request() {
|
||||||
|
TrayCodeMsg request = new TrayCodeMsg();
|
||||||
|
request.setStockinDetailId("5673093");
|
||||||
|
request.setExitId("2");
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user