🐛 审核未命中目标档案时整体回滚,不再静默置为已通过
审核通过时对司机/车辆档案的 updateById 命中 0 行只返回 false、不抛异常,而这个返回值原先被丢弃,于是「认证记录已通过、档案一个字没变」能静默成立:生效快照指针没写进去,对象下次接单仍被判未认证,审核页却显示已通过。现在命中 0 行即抛异常并回滚整次审核,宁可报错也不留下状态与档案互相矛盾的数据。
This commit is contained in:
+21
-2
@@ -206,7 +206,7 @@ public class CertAuditServiceImpl implements ICertAuditService {
|
||||
// 与指针合并成同一次 UPDATE,不额外多写一次同一行。
|
||||
applySnapshotToVehicle(vehicle, record.getSnapshotJson());
|
||||
}
|
||||
transportVehicleService.updateById(vehicle);
|
||||
requireTargetUpdated(transportVehicleService.updateById(vehicle), "车辆", record.getBizId());
|
||||
return;
|
||||
}
|
||||
Driver driver = new Driver();
|
||||
@@ -225,7 +225,26 @@ public class CertAuditServiceImpl implements ICertAuditService {
|
||||
// 与指针合并成同一次 UPDATE,不额外多写一次同一行。
|
||||
applySnapshotToDriver(driver, record.getSnapshotJson());
|
||||
}
|
||||
driverService.updateById(driver);
|
||||
requireTargetUpdated(driverService.updateById(driver), "司机", record.getBizId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 目标对象的写入必须命中一行,否则整体失败
|
||||
* <p>
|
||||
* {@code updateById} 命中 0 行时**不抛异常、只返回 false**。原先丢弃这个返回值,
|
||||
* 于是「审核记录已通过、司机/车辆档案一个字没变」能静默成立:生效快照指针没写进去,
|
||||
* 对象下次接单仍被判未认证,而审核页显示的是已通过。此处让事务整体回滚,
|
||||
* 宁可报错也不留下状态与档案互相矛盾的数据。
|
||||
*
|
||||
* @param updated 更新结果
|
||||
* @param target 对象名称,用于提示
|
||||
* @param id 对象主键
|
||||
*/
|
||||
private void requireTargetUpdated(boolean updated, String target, Long id) {
|
||||
if (!updated) {
|
||||
throw new ServiceException("未能更新" + target + "档案(ID:" + id
|
||||
+ "),本次审核已回滚、未生效;请核对该对象是否存在、未被删除,且与认证记录属于同一租户");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+26
@@ -50,6 +50,9 @@ class CertAuditServiceImplTest {
|
||||
transportVehicleService = mock(ITransportVehicleService.class);
|
||||
driverService = mock(IDriverService.class);
|
||||
service = new CertAuditServiceImpl(certRecordService, certRecordMapper, transportVehicleService, driverService);
|
||||
// 目标对象的写入默认成功;「写入一行都没命中」由专门的用例覆盖
|
||||
when(transportVehicleService.updateById(any(TransportVehicle.class))).thenReturn(true);
|
||||
when(driverService.updateById(any(Driver.class))).thenReturn(true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ 通过
|
||||
@@ -174,6 +177,29 @@ class CertAuditServiceImplTest {
|
||||
"审核通过不得把司机的车辆绑定清空");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("通过:目标对象一行都没命中时必须整体失败,不得「记录已通过、档案没变」")
|
||||
void approveFailsWhenVehicleNotUpdated() {
|
||||
when(certRecordService.getById(RECORD_ID)).thenReturn(vehicleRecord(TransportCertRecord.STATUS_PENDING));
|
||||
when(transportVehicleService.updateById(any(TransportVehicle.class))).thenReturn(false);
|
||||
|
||||
ServiceException exception = assertThrows(ServiceException.class,
|
||||
() -> service.audit(RECORD_ID, true, null));
|
||||
assertTrue(exception.getMessage().contains("未生效"), exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("通过司机认证:司机档案没命中时同样必须整体失败,不得静默放行")
|
||||
void approveFailsWhenDriverNotUpdated() {
|
||||
when(certRecordService.getById(RECORD_ID)).thenReturn(driverRecord(TransportCertRecord.STATUS_PENDING));
|
||||
when(driverService.getById(DRIVER_ID)).thenReturn(driver(null));
|
||||
when(driverService.updateById(any(Driver.class))).thenReturn(false);
|
||||
|
||||
ServiceException exception = assertThrows(ServiceException.class,
|
||||
() -> service.audit(RECORD_ID, true, null));
|
||||
assertTrue(exception.getMessage().contains("司机"), exception.getMessage());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ 驳回
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user