Merge branch 'feat/pending-return-confirm' into feat/rc-08
This commit is contained in:
+14
-2
@@ -1068,10 +1068,11 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
|||||||
waybill.setMasterNo(null);
|
waybill.setMasterNo(null);
|
||||||
waybill.setMileageRemark(null);
|
waybill.setMileageRemark(null);
|
||||||
}
|
}
|
||||||
// 新建若已带业务状态(如复制提交已完成)则在过程校正后回写,保证与原运单一致
|
// 新建若已带业务状态(如复制提交已完成)则在过程校正后回写,保证与原运单一致;
|
||||||
|
// 编辑保存只改资料,business_status 以库里的值为准,请求体里的值不回写
|
||||||
String preservedBusinessStatus = created
|
String preservedBusinessStatus = created
|
||||||
? TransportBusinessSupport.trimToNull(waybill.getBusinessStatus())
|
? TransportBusinessSupport.trimToNull(waybill.getBusinessStatus())
|
||||||
: null;
|
: editPreservedBusinessStatus(oldRecord);
|
||||||
if (isCompletedBusinessStatus(preservedBusinessStatus)) {
|
if (isCompletedBusinessStatus(preservedBusinessStatus)) {
|
||||||
preservedBusinessStatus = "completed";
|
preservedBusinessStatus = "completed";
|
||||||
}
|
}
|
||||||
@@ -1093,6 +1094,17 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑保存要回写的业务状态:取库里的值。
|
||||||
|
* 草稿返回 null —— submit 即正式提交,草稿须由过程校正提升为待执行 / 进行中。
|
||||||
|
*/
|
||||||
|
private String editPreservedBusinessStatus(Waybill oldRecord) {
|
||||||
|
String currentStatus = oldRecord == null
|
||||||
|
? null
|
||||||
|
: TransportBusinessSupport.trimToNull(oldRecord.getBusinessStatus());
|
||||||
|
return STATUS_DRAFT.equals(currentStatus) ? null : currentStatus;
|
||||||
|
}
|
||||||
|
|
||||||
private void fillCustomerName(Waybill waybill) {
|
private void fillCustomerName(Waybill waybill) {
|
||||||
if (Func.isNotEmpty(waybill.getContractId())) {
|
if (Func.isNotEmpty(waybill.getContractId())) {
|
||||||
ContractManage contract = contractManageService.getById(waybill.getContractId());
|
ContractManage contract = contractManageService.getById(waybill.getContractId());
|
||||||
|
|||||||
+198
@@ -0,0 +1,198 @@
|
|||||||
|
package org.springblade.transport.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||||
|
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
|
import org.springblade.transport.mapper.WaybillMapper;
|
||||||
|
import org.springblade.transport.pojo.entity.Waybill;
|
||||||
|
import org.springblade.transport.support.WaybillProcessSupport;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.mockStatic;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运单编辑保存的业务状态来源测试。
|
||||||
|
* <p>
|
||||||
|
* 编辑保存只改运单资料,business_status 一律以库里的值为准:请求体不回传(null / 空串)
|
||||||
|
* 不得把库里的待执行、进行中、已完成改写成别的状态,回传陈旧值也不得覆盖。
|
||||||
|
* 唯一例外是草稿——submit 即正式提交,草稿须按过程配置提升为待执行 / 进行中。
|
||||||
|
* <p>
|
||||||
|
* 过程配置用「无需确认接单」的快照({@code []}):无过程校正时待执行会被提升为进行中,
|
||||||
|
* 正是编辑保存最容易把库里状态写坏的场景。
|
||||||
|
*/
|
||||||
|
class WaybillEditSaveBusinessStatusTest {
|
||||||
|
|
||||||
|
private static final Long WAYBILL_ID = 7001L;
|
||||||
|
private static final Long DEPT_ID = 100L;
|
||||||
|
/** 无接单节点的过程配置:normalizeBusinessStatus 会把空 / pending 提升为 running */
|
||||||
|
private static final String PROCESS_JSON_NO_ACCEPT = "[]";
|
||||||
|
|
||||||
|
private WaybillMapper waybillMapper;
|
||||||
|
private WaybillServiceImpl service;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void initTableInfo() {
|
||||||
|
// saveOrUpdate 判主键需要 MyBatis-Plus 的实体元数据缓存
|
||||||
|
MybatisConfiguration configuration = new MybatisConfiguration();
|
||||||
|
MapperBuilderAssistant assistant = new MapperBuilderAssistant(configuration, "");
|
||||||
|
assistant.setCurrentNamespace("test");
|
||||||
|
TableInfoHelper.initTableInfo(assistant, Waybill.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() throws Exception {
|
||||||
|
waybillMapper = mock(WaybillMapper.class);
|
||||||
|
service = new WaybillServiceImpl();
|
||||||
|
inject("baseMapper", waybillMapper);
|
||||||
|
when(waybillMapper.updateById(any(Waybill.class))).thenReturn(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------ 编辑保存:以库里的状态为准
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("编辑保存:请求体不回传业务状态,库里的待执行不得被提升为进行中")
|
||||||
|
void editSaveKeepsPendingWhenRequestBodyOmitsStatus() {
|
||||||
|
Waybill request = editableRequest();
|
||||||
|
|
||||||
|
submit(request, "pending");
|
||||||
|
|
||||||
|
assertEquals("pending", request.getBusinessStatus(),
|
||||||
|
"编辑保存时请求体没有 business_status,不得按过程配置把库里的待执行改写成进行中");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("编辑保存:请求体不回传业务状态,库里的进行中不得被改写")
|
||||||
|
void editSaveKeepsRunningWhenRequestBodyOmitsStatus() {
|
||||||
|
Waybill request = editableRequest();
|
||||||
|
|
||||||
|
submit(request, "running");
|
||||||
|
|
||||||
|
assertEquals("running", request.getBusinessStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("编辑保存:请求体不回传业务状态,库里的已完成不得被改写")
|
||||||
|
void editSaveKeepsCompletedWhenRequestBodyOmitsStatus() {
|
||||||
|
Waybill request = editableRequest();
|
||||||
|
|
||||||
|
submit(request, "completed");
|
||||||
|
|
||||||
|
assertEquals("completed", request.getBusinessStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("编辑保存:请求体回传陈旧状态,仍以库里的值为准")
|
||||||
|
void editSaveKeepsDatabaseStatusWhenRequestBodyCarriesStaleValue() {
|
||||||
|
Waybill request = editableRequest();
|
||||||
|
request.setBusinessStatus("running");
|
||||||
|
|
||||||
|
submit(request, "completed");
|
||||||
|
|
||||||
|
assertEquals("completed", request.getBusinessStatus(),
|
||||||
|
"库里已完成,请求体带的是打开表单时的旧值,不得据此回退状态");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("编辑保存:请求体回传空串,库里的状态不得被清空")
|
||||||
|
void editSaveKeepsDatabaseStatusWhenRequestBodyIsBlank() {
|
||||||
|
Waybill request = editableRequest();
|
||||||
|
request.setBusinessStatus("");
|
||||||
|
|
||||||
|
submit(request, "running");
|
||||||
|
|
||||||
|
assertEquals("running", request.getBusinessStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------ 新增状态
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("编辑保存:待回单确认的运单不得被编辑保存改成进行中")
|
||||||
|
void editSaveKeepsPendingReturnConfirm() {
|
||||||
|
Waybill request = editableRequest();
|
||||||
|
|
||||||
|
submit(request, WaybillProcessSupport.STATUS_PENDING_RETURN_CONFIRM);
|
||||||
|
|
||||||
|
assertEquals(WaybillProcessSupport.STATUS_PENDING_RETURN_CONFIRM, request.getBusinessStatus(),
|
||||||
|
"司机已打完末位卡,编辑一次运单资料不得把它退回进行中");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------ 草稿例外
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("提交草稿:草稿仍按过程配置提升为进行中")
|
||||||
|
void submitDraftStillPromotesToRunning() {
|
||||||
|
Waybill request = editableRequest();
|
||||||
|
|
||||||
|
submit(request, "draft");
|
||||||
|
|
||||||
|
assertEquals("running", request.getBusinessStatus(),
|
||||||
|
"submit 即正式提交,草稿必须脱离 draft,不能被「以库里的值为准」锁死");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------ 夹具
|
||||||
|
|
||||||
|
private Waybill editableRequest() {
|
||||||
|
Waybill waybill = new Waybill();
|
||||||
|
waybill.setId(WAYBILL_ID);
|
||||||
|
waybill.setProjectName("项目A");
|
||||||
|
waybill.setContractName("客户合同A");
|
||||||
|
waybill.setCustomerName("客户A");
|
||||||
|
waybill.setTransportType("公路运输");
|
||||||
|
waybill.setCargoName("钢材");
|
||||||
|
waybill.setCargoType("普货");
|
||||||
|
waybill.setQuantityUnit("吨");
|
||||||
|
waybill.setCarrierType("自运");
|
||||||
|
waybill.setVehicleNo("桂A12345");
|
||||||
|
waybill.setDriverName("张三");
|
||||||
|
waybill.setCarrierJson("{}");
|
||||||
|
waybill.setQuantity(BigDecimal.TEN);
|
||||||
|
waybill.setProcessJson(PROCESS_JSON_NO_ACCEPT);
|
||||||
|
return waybill;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 让库里的同一条运单处于 {@code databaseStatus},再走一次编辑保存(submit)。
|
||||||
|
* 司机与车牌保持一致,避免接单记录被判定为「换了司机」而清空。
|
||||||
|
*/
|
||||||
|
private void submit(Waybill request, String databaseStatus) {
|
||||||
|
Waybill oldRecord = editableRequest();
|
||||||
|
oldRecord.setBusinessStatus(databaseStatus);
|
||||||
|
oldRecord.setDeptId(DEPT_ID);
|
||||||
|
oldRecord.setDeptName("测试组织");
|
||||||
|
when(waybillMapper.selectById(WAYBILL_ID)).thenReturn(oldRecord);
|
||||||
|
|
||||||
|
try (MockedStatic<AuthUtil> authUtil = mockStatic(AuthUtil.class)) {
|
||||||
|
authUtil.when(AuthUtil::getDeptId).thenReturn(DEPT_ID);
|
||||||
|
assertTrue(service.submit(request));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void inject(String field, Object value) throws Exception {
|
||||||
|
Class<?> type = service.getClass();
|
||||||
|
while (type != null) {
|
||||||
|
try {
|
||||||
|
Field declared = type.getDeclaredField(field);
|
||||||
|
declared.setAccessible(true);
|
||||||
|
declared.set(service, value);
|
||||||
|
return;
|
||||||
|
} catch (NoSuchFieldException ignored) {
|
||||||
|
type = type.getSuperclass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("未找到字段:" + field);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user