新增流程列表编辑功能

This commit is contained in:
wkc
2026-05-25 16:04:23 +08:00
parent cc6836804e
commit 998f0b3c48
14 changed files with 746 additions and 50 deletions

View File

@@ -69,6 +69,46 @@ public class LoanPricingWorkflowController extends BaseController
return success(result);
}
/**
* 查询利率定价流程编辑数据
*/
@Operation(summary = "查询利率定价流程编辑数据")
@GetMapping("/{serialNum}/edit")
public AjaxResult getEditInfo(
@Parameter(description = "业务方流水号")
@PathVariable("serialNum") String serialNum)
{
return success(loanPricingWorkflowService.selectEditableLoanPricingBySerialNum(serialNum));
}
/**
* 编辑个人客户利率定价流程
*/
@Operation(summary = "编辑个人客户利率定价流程")
@Log(title = "个人客户利率定价流程", businessType = BusinessType.UPDATE)
@PutMapping("/{serialNum}/personal")
public AjaxResult updatePersonal(
@Parameter(description = "业务方流水号")
@PathVariable("serialNum") String serialNum,
@Validated @RequestBody PersonalLoanPricingCreateDTO dto)
{
return success(loanPricingWorkflowService.updatePersonalLoanPricing(serialNum, dto));
}
/**
* 编辑企业客户利率定价流程
*/
@Operation(summary = "编辑企业客户利率定价流程")
@Log(title = "企业客户利率定价流程", businessType = BusinessType.UPDATE)
@PutMapping("/{serialNum}/corporate")
public AjaxResult updateCorporate(
@Parameter(description = "业务方流水号")
@PathVariable("serialNum") String serialNum,
@Validated @RequestBody CorporateLoanPricingCreateDTO dto)
{
return success(loanPricingWorkflowService.updateCorporateLoanPricing(serialNum, dto));
}
/**
* 查询个人客户号映射
*/

View File

@@ -34,6 +34,32 @@ public interface ILoanPricingWorkflowService
*/
public LoanPricingWorkflow createCorporateLoanPricing(CorporateLoanPricingCreateDTO dto);
/**
* 查询利率定价流程编辑数据
*
* @param serialNum 业务方流水号
* @return 编辑用流程数据
*/
public LoanPricingWorkflow selectEditableLoanPricingBySerialNum(String serialNum);
/**
* 编辑个人客户利率定价流程
*
* @param serialNum 业务方流水号
* @param dto 个人客户编辑DTO
* @return 更新后的流程数据
*/
public LoanPricingWorkflow updatePersonalLoanPricing(String serialNum, PersonalLoanPricingCreateDTO dto);
/**
* 编辑企业客户利率定价流程
*
* @param serialNum 业务方流水号
* @param dto 企业客户编辑DTO
* @return 更新后的流程数据
*/
public LoanPricingWorkflow updateCorporateLoanPricing(String serialNum, CorporateLoanPricingCreateDTO dto);
/**
* 查询利率定价流程列表
*

View File

@@ -40,6 +40,14 @@ public class LoanPricingModelService {
private SensitiveFieldCryptoService sensitiveFieldCryptoService;
public void invokeModelAsync(Long workflowId) {
invokeModelAndSave(workflowId, false);
}
public void reinvokeModelAndOverwrite(Long workflowId) {
invokeModelAndSave(workflowId, true);
}
private void invokeModelAndSave(Long workflowId, boolean overwriteModelOutput) {
LoanPricingWorkflow loanPricingWorkflow = loanPricingWorkflowMapper.selectById(workflowId);
if (Objects.isNull(loanPricingWorkflow)){
log.error("未找到对应的流程信息,未调用模型服务");
@@ -68,26 +76,43 @@ public class LoanPricingModelService {
if (loanPricingWorkflow.getCustType().equals("个人")){
// 个人模型
ModelRetailOutputFields modelRetailOutputFields = modelService.invokePersonalModel(modelInvokeDTO);
modelRetailOutputFieldsMapper.insert(modelRetailOutputFields);
if (overwriteModelOutput && Objects.nonNull(loanPricingWorkflow.getModelOutputId()))
{
modelRetailOutputFields.setId(loanPricingWorkflow.getModelOutputId());
modelRetailOutputFieldsMapper.updateById(modelRetailOutputFields);
}
else
{
modelRetailOutputFieldsMapper.insert(modelRetailOutputFields);
}
log.info("个人模型调用成功");
LoanPricingWorkflow workflowToUpdate = new LoanPricingWorkflow();
workflowToUpdate.setId(loanPricingWorkflow.getId());
workflowToUpdate.setModelOutputId(modelRetailOutputFields.getId());
loanPricingWorkflowMapper.updateById(workflowToUpdate);
log.info("更新流程信息成功");
updateWorkflowModelOutputId(loanPricingWorkflow, modelRetailOutputFields.getId());
}else if (loanPricingWorkflow.getCustType().equals("企业")){
// 企业模型
ModelCorpOutputFields modelCorpOutputFields = modelService.invokeCorporateModel(modelInvokeDTO);
modelCorpOutputFieldsMapper.insert(modelCorpOutputFields);
if (overwriteModelOutput && Objects.nonNull(loanPricingWorkflow.getModelOutputId()))
{
modelCorpOutputFields.setId(loanPricingWorkflow.getModelOutputId());
modelCorpOutputFieldsMapper.updateById(modelCorpOutputFields);
}
else
{
modelCorpOutputFieldsMapper.insert(modelCorpOutputFields);
}
log.info("企业模型调用成功");
LoanPricingWorkflow workflowToUpdate = new LoanPricingWorkflow();
workflowToUpdate.setId(loanPricingWorkflow.getId());
workflowToUpdate.setModelOutputId(modelCorpOutputFields.getId());
loanPricingWorkflowMapper.updateById(workflowToUpdate);
log.info("更新流程信息成功");
updateWorkflowModelOutputId(loanPricingWorkflow, modelCorpOutputFields.getId());
}
}
private void updateWorkflowModelOutputId(LoanPricingWorkflow loanPricingWorkflow, Long modelOutputId)
{
LoanPricingWorkflow workflowToUpdate = new LoanPricingWorkflow();
workflowToUpdate.setId(loanPricingWorkflow.getId());
workflowToUpdate.setModelOutputId(modelOutputId);
loanPricingWorkflowMapper.updateById(workflowToUpdate);
log.info("更新流程信息成功");
}
private void normalizePersonalModelInvokeDTO(ModelInvokeDTO modelInvokeDTO)
{
modelInvokeDTO.setBizProof(toZeroOne(modelInvokeDTO.getBizProof()));
@@ -98,6 +123,7 @@ public class LoanPricingModelService {
private void normalizeCorporateModelInvokeDTO(ModelInvokeDTO modelInvokeDTO)
{
modelInvokeDTO.setCollThirdParty(toZeroOne(modelInvokeDTO.getCollThirdParty()));
modelInvokeDTO.setResCover(toZeroOne(modelInvokeDTO.getResCover()));
modelInvokeDTO.setIsGreenLoan(toZeroOne(modelInvokeDTO.getIsGreenLoan()));
modelInvokeDTO.setIsTradeBuildEnt(toZeroOne(modelInvokeDTO.getIsTradeBuildEnt()));
}

View File

@@ -1,6 +1,7 @@
package com.ruoyi.loanpricing.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.UserConstants;
@@ -47,6 +48,10 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
private static final String WORKFLOW_ADMIN_ROLE_KEY = "headAdmin";
private static final String WORKFLOW_BRANCH_ADMIN_ROLE_NAME = "支行管理员";
private static final String WORKFLOW_BRANCH_ADMIN_ROLE_KEY = "branchAdmin";
@Resource
private LoanPricingWorkflowMapper loanPricingWorkflowMapper;
@@ -93,6 +98,7 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
loanPricingWorkflow.setRunType("1");
}
loanPricingWorkflow.setDeptId(SecurityUtils.getDeptId());
loanPricingWorkflow.setCustName(sensitiveFieldCryptoService.encrypt(loanPricingWorkflow.getCustName()));
loanPricingWorkflow.setIdNum(sensitiveFieldCryptoService.encrypt(loanPricingWorkflow.getIdNum()));
loanPricingWorkflowMapper.insert(loanPricingWorkflow);
@@ -193,6 +199,97 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
return createLoanPricing(entity);
}
@Override
public LoanPricingWorkflow selectEditableLoanPricingBySerialNum(String serialNum)
{
LoanPricingWorkflow workflow = selectWorkflowBySerialNum(serialNum);
assertCurrentUserIsCreator(workflow);
workflow.setCustName(sensitiveFieldCryptoService.decrypt(workflow.getCustName()));
workflow.setIdNum(sensitiveFieldCryptoService.decrypt(workflow.getIdNum()));
return workflow;
}
@Override
@Transactional(rollbackFor = Exception.class)
public LoanPricingWorkflow updatePersonalLoanPricing(String serialNum, PersonalLoanPricingCreateDTO dto)
{
LoanPricingWorkflow editingWorkflow = LoanPricingConverter.toEntity(dto);
return updateLoanPricing(serialNum, editingWorkflow, "个人");
}
@Override
@Transactional(rollbackFor = Exception.class)
public LoanPricingWorkflow updateCorporateLoanPricing(String serialNum, CorporateLoanPricingCreateDTO dto)
{
LoanPricingWorkflow editingWorkflow = LoanPricingConverter.toEntity(dto);
return updateLoanPricing(serialNum, editingWorkflow, "企业");
}
private LoanPricingWorkflow updateLoanPricing(String serialNum, LoanPricingWorkflow editingWorkflow, String expectedCustType)
{
LoanPricingWorkflow existingWorkflow = selectWorkflowBySerialNum(serialNum);
assertCurrentUserIsCreator(existingWorkflow);
if (!expectedCustType.equals(existingWorkflow.getCustType()))
{
throw new ServiceException("客户类型不匹配,不能编辑该流程");
}
editingWorkflow.setId(existingWorkflow.getId());
editingWorkflow.setSerialNum(existingWorkflow.getSerialNum());
editingWorkflow.setCustType(existingWorkflow.getCustType());
editingWorkflow.setModelOutputId(existingWorkflow.getModelOutputId());
validateBusinessTypeAndHistoryRate(editingWorkflow);
validateCollateralTypeAndCouponRate(editingWorkflow);
String encryptedCustName = sensitiveFieldCryptoService.encrypt(editingWorkflow.getCustName());
String encryptedIdNum = sensitiveFieldCryptoService.encrypt(editingWorkflow.getIdNum());
LambdaUpdateWrapper<LoanPricingWorkflow> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(LoanPricingWorkflow::getId, existingWorkflow.getId())
.set(LoanPricingWorkflow::getCustIsn, editingWorkflow.getCustIsn())
.set(LoanPricingWorkflow::getCustName, encryptedCustName)
.set(LoanPricingWorkflow::getIdType, editingWorkflow.getIdType())
.set(LoanPricingWorkflow::getIdNum, encryptedIdNum)
.set(LoanPricingWorkflow::getGuarType, editingWorkflow.getGuarType())
.set(LoanPricingWorkflow::getApplyAmt, editingWorkflow.getApplyAmt())
.set(LoanPricingWorkflow::getBusinessType, editingWorkflow.getBusinessType())
.set(LoanPricingWorkflow::getLoanRateHistory, editingWorkflow.getLoanRateHistory())
.set(LoanPricingWorkflow::getCouponRate, editingWorkflow.getCouponRate())
.set(LoanPricingWorkflow::getLoanTerm, editingWorkflow.getLoanTerm())
.set(LoanPricingWorkflow::getCollType, editingWorkflow.getCollType())
.set(LoanPricingWorkflow::getCollThirdParty, editingWorkflow.getCollThirdParty())
.set(LoanPricingWorkflow::getLoanLoop, editingWorkflow.getLoanLoop())
.set(LoanPricingWorkflow::getResCover, editingWorkflow.getResCover())
.set(LoanPricingWorkflow::getRepayMethod, editingWorkflow.getRepayMethod())
.set(LoanPricingWorkflow::getIsGreenLoan, editingWorkflow.getIsGreenLoan())
.set(LoanPricingWorkflow::getIsTradeBuildEnt, editingWorkflow.getIsTradeBuildEnt())
.set(LoanPricingWorkflow::getUpdateBy, buildCurrentCreateBy(SecurityUtils.getLoginUser()))
.set(LoanPricingWorkflow::getUpdateTime, new Date());
loanPricingWorkflowMapper.update(null, updateWrapper);
loanPricingModelService.reinvokeModelAndOverwrite(existingWorkflow.getId());
return selectEditableLoanPricingBySerialNum(serialNum);
}
private LoanPricingWorkflow selectWorkflowBySerialNum(String serialNum)
{
LambdaQueryWrapper<LoanPricingWorkflow> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(LoanPricingWorkflow::getSerialNum, serialNum);
LoanPricingWorkflow workflow = loanPricingWorkflowMapper.selectOne(wrapper);
if (workflow == null)
{
throw new ServiceException("记录不存在");
}
return workflow;
}
private void assertCurrentUserIsCreator(LoanPricingWorkflow workflow)
{
String currentCreateBy = buildCurrentCreateBy(SecurityUtils.getLoginUser());
if (!currentCreateBy.equals(workflow.getCreateBy()))
{
throw new ServiceException("只有创建者可以编辑该流程");
}
}
/**
* 查询利率定价流程列表
*
@@ -306,7 +403,15 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
{
LoanPricingWorkflow scopedQuery = query == null ? new LoanPricingWorkflow() : query;
LoginUser loginUser = SecurityUtils.getLoginUser();
if (!canViewAllWorkflows(loginUser))
if (canViewAllWorkflows(loginUser))
{
return scopedQuery;
}
if (canViewBranchWorkflows(loginUser))
{
scopedQuery.setDataScopeDeptId(loginUser.getDeptId() == null ? -1L : loginUser.getDeptId());
}
else
{
scopedQuery.setDataScopeCreateBy(buildCurrentCreateBy(loginUser));
}
@@ -331,6 +436,19 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
|| WORKFLOW_ADMIN_ROLE_KEY.equals(role.getRoleKey())));
}
private boolean canViewBranchWorkflows(LoginUser loginUser)
{
List<SysRole> roles = loginUser.getUser().getRoles();
if (roles == null)
{
return false;
}
return roles.stream().anyMatch(role -> role != null
&& UserConstants.ROLE_NORMAL.equals(role.getStatus())
&& (WORKFLOW_BRANCH_ADMIN_ROLE_NAME.equals(role.getRoleName())
|| WORKFLOW_BRANCH_ADMIN_ROLE_KEY.equals(role.getRoleKey())));
}
private String buildCurrentCreateBy(LoginUser loginUser)
{
SysUser user = loginUser.getUser();

View File

@@ -57,6 +57,7 @@ class LoanPricingModelServiceTest
workflow.setCustName("cipher-name");
workflow.setIdNum("cipher-id");
workflow.setRepayMethod("分期");
workflow.setResCover("true");
workflow.setIsGreenLoan("true");
workflow.setIsTradeBuildEnt("false");
workflow.setCollThirdParty("true");
@@ -67,6 +68,7 @@ class LoanPricingModelServiceTest
ModelInvokeDTO request = context.modelService.corporateRequest;
assertEquals("分期", request.getRepayMethod());
assertEquals("1", request.getResCover());
assertEquals("1", request.getIsGreenLoan());
assertEquals("0", request.getIsTradeBuildEnt());
assertEquals("1", request.getCollThirdParty());
@@ -77,6 +79,24 @@ class LoanPricingModelServiceTest
assertEquals(1, context.corpInsertCount.get());
}
@Test
void shouldOverwriteExistingCorporateModelOutputWhenReinvokingModel() throws Exception
{
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
workflow.setId(4L);
workflow.setModelOutputId(88L);
workflow.setCustType("企业");
workflow.setCustName("cipher-name");
workflow.setIdNum("cipher-id");
TestContext context = createContext(workflow);
context.service.reinvokeModelAndOverwrite(4L);
assertEquals(1, context.modelService.corporateCalls.get());
assertEquals(0, context.corpInsertCount.get());
assertEquals(1, context.corpUpdateCount.get());
}
private static LoanPricingWorkflow personalWorkflow(Long id)
{
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
@@ -96,15 +116,17 @@ class LoanPricingModelServiceTest
context.workflow = workflow;
context.updatedWorkflow = new AtomicReference<>();
context.retailInsertCount = new AtomicInteger();
context.retailUpdateCount = new AtomicInteger();
context.corpInsertCount = new AtomicInteger();
context.corpUpdateCount = new AtomicInteger();
setField(context.service, "modelService", context.modelService);
setField(context.service, "loanPricingWorkflowMapper",
workflowMapper(context.workflow, context.updatedWorkflow));
setField(context.service, "modelRetailOutputFieldsMapper",
insertCountingMapper(ModelRetailOutputFieldsMapper.class, context.retailInsertCount));
savingMapper(ModelRetailOutputFieldsMapper.class, context.retailInsertCount, context.retailUpdateCount));
setField(context.service, "modelCorpOutputFieldsMapper",
insertCountingMapper(ModelCorpOutputFieldsMapper.class, context.corpInsertCount));
savingMapper(ModelCorpOutputFieldsMapper.class, context.corpInsertCount, context.corpUpdateCount));
setField(context.service, "sensitiveFieldCryptoService", new TestSensitiveFieldCryptoService());
return context;
}
@@ -126,7 +148,7 @@ class LoanPricingModelServiceTest
});
}
private static <T> T insertCountingMapper(Class<T> mapperClass, AtomicInteger insertCount)
private static <T> T savingMapper(Class<T> mapperClass, AtomicInteger insertCount, AtomicInteger updateCount)
{
return proxy(mapperClass, (proxy, method, args) -> {
if ("insert".equals(method.getName()))
@@ -134,6 +156,11 @@ class LoanPricingModelServiceTest
insertCount.incrementAndGet();
return 1;
}
if ("updateById".equals(method.getName()))
{
updateCount.incrementAndGet();
return 1;
}
return defaultValue(method);
});
}
@@ -172,7 +199,9 @@ class LoanPricingModelServiceTest
private LoanPricingWorkflow workflow;
private AtomicReference<LoanPricingWorkflow> updatedWorkflow;
private AtomicInteger retailInsertCount;
private AtomicInteger retailUpdateCount;
private AtomicInteger corpInsertCount;
private AtomicInteger corpUpdateCount;
}
private static class CapturingModelService extends ModelService

View File

@@ -11,6 +11,7 @@ import static org.mockito.Mockito.when;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -100,6 +101,7 @@ class LoanPricingWorkflowServiceImplTest
verify(loanPricingWorkflowMapper).insert(argThat((LoanPricingWorkflow entity) ->
Objects.equals("cipher-name", entity.getCustName())
&& Objects.equals("cipher-id", entity.getIdNum())
&& Objects.equals(100L, entity.getDeptId())
&& Objects.equals("CUST001", entity.getCustIsn())));
}
@@ -148,6 +150,7 @@ class LoanPricingWorkflowServiceImplTest
verify(loanPricingWorkflowMapper).selectWorkflowPageWithRates(any(), queryCaptor.capture());
assertNull(queryCaptor.getValue().getDataScopeCreateBy());
assertNull(queryCaptor.getValue().getDataScopeDeptId());
}
@Test
@@ -162,6 +165,40 @@ class LoanPricingWorkflowServiceImplTest
verify(loanPricingWorkflowMapper).selectWorkflowPageWithRates(any(), queryCaptor.capture());
assertNull(queryCaptor.getValue().getDataScopeCreateBy());
assertNull(queryCaptor.getValue().getDataScopeDeptId());
}
@Test
void shouldSetCurrentDeptForBranchAdminWhenReturningPagedWorkflowList()
{
setLoginUser(102L, 101L, "8920100", "测试支行管理员", role(102L, "支行管理员", "branchAdmin"));
when(loanPricingWorkflowMapper.selectWorkflowPageWithRates(any(), any())).thenReturn(emptyPageResult());
loanPricingWorkflowService.selectLoanPricingPage(new Page<>(1, 10), new LoanPricingWorkflow());
ArgumentCaptor<LoanPricingWorkflow> queryCaptor = ArgumentCaptor.forClass(LoanPricingWorkflow.class);
verify(loanPricingWorkflowMapper).selectWorkflowPageWithRates(any(), queryCaptor.capture());
assertEquals(101L, queryCaptor.getValue().getDataScopeDeptId());
assertNull(queryCaptor.getValue().getDataScopeCreateBy());
}
@Test
void shouldKeepBranchAdminWithinDeptDataScopeWhenCreateByQueryIsProvided()
{
setLoginUser(102L, 101L, "8920100", "测试支行管理员", role(102L, "支行管理员", "branchAdmin"));
LoanPricingWorkflow query = new LoanPricingWorkflow();
query.setCreateBy("8920001");
when(loanPricingWorkflowMapper.selectWorkflowPageWithRates(any(), any())).thenReturn(emptyPageResult());
loanPricingWorkflowService.selectLoanPricingPage(new Page<>(1, 10), query);
ArgumentCaptor<LoanPricingWorkflow> queryCaptor = ArgumentCaptor.forClass(LoanPricingWorkflow.class);
verify(loanPricingWorkflowMapper).selectWorkflowPageWithRates(any(), queryCaptor.capture());
assertEquals("8920001", queryCaptor.getValue().getCreateBy());
assertEquals(101L, queryCaptor.getValue().getDataScopeDeptId());
assertNull(queryCaptor.getValue().getDataScopeCreateBy());
}
@Test
@@ -193,6 +230,7 @@ class LoanPricingWorkflowServiceImplTest
assertEquals("若依-admin", queryCaptor.getValue().getCreateBy());
assertEquals("测试客户经理-8920001", queryCaptor.getValue().getDataScopeCreateBy());
assertNull(queryCaptor.getValue().getDataScopeDeptId());
}
@Test
@@ -336,15 +374,151 @@ class LoanPricingWorkflowServiceImplTest
dto.setLoanTerm("3");
dto.setCollType("存单质押");
dto.setCouponRate("2.35");
dto.setResCover("1");
loanPricingWorkflowService.createCorporateLoanPricing(dto);
verify(loanPricingWorkflowMapper).insert(argThat((LoanPricingWorkflow entity) ->
Objects.equals("企业", entity.getCustType())
&& Objects.equals("新增", entity.getBusinessType())
&& Objects.equals("1", entity.getResCover())
&& Objects.equals("2.35", entity.getCouponRate())));
}
@Test
void shouldReturnEditableWorkflowWithPlainSensitiveFieldsForCreator()
{
LoanPricingWorkflow workflow = editableWorkflow("个人", "若依-admin");
workflow.setCustName("cipher-name");
workflow.setIdNum("cipher-id");
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("张三");
when(sensitiveFieldCryptoService.decrypt("cipher-id")).thenReturn("110101199001011234");
LoanPricingWorkflow result = loanPricingWorkflowService.selectEditableLoanPricingBySerialNum("P20260525001");
assertEquals("张三", result.getCustName());
assertEquals("110101199001011234", result.getIdNum());
}
@Test
void shouldRejectEditableWorkflowWhenCurrentUserIsNotCreator()
{
LoanPricingWorkflow workflow = editableWorkflow("个人", "其他用户-8920001");
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
ServiceException exception = assertThrows(ServiceException.class,
() -> loanPricingWorkflowService.selectEditableLoanPricingBySerialNum("P20260525001"));
assertEquals("只有创建者可以编辑该流程", exception.getMessage());
}
@Test
void shouldUpdatePersonalWorkflowAndReinvokeModelForCreator()
{
LoanPricingWorkflow workflow = editableWorkflow("个人", "若依-admin");
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
when(sensitiveFieldCryptoService.encrypt("张三")).thenReturn("cipher-name-new");
when(sensitiveFieldCryptoService.encrypt("110101199001019999")).thenReturn("cipher-id-new");
when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("张三");
when(sensitiveFieldCryptoService.decrypt("cipher-id")).thenReturn("110101199001019999");
PersonalLoanPricingCreateDTO dto = new PersonalLoanPricingCreateDTO();
dto.setCustIsn("CUST001");
dto.setCustName("张三");
dto.setIdType("身份证");
dto.setIdNum("110101199001019999");
dto.setGuarType("信用");
dto.setApplyAmt("200000");
dto.setBusinessType("新增");
dto.setLoanTerm("3");
dto.setLoanLoop("1");
loanPricingWorkflowService.updatePersonalLoanPricing("P20260525001", dto);
ArgumentCaptor<LambdaUpdateWrapper> updateWrapperCaptor = ArgumentCaptor.forClass(LambdaUpdateWrapper.class);
verify(loanPricingWorkflowMapper).update(any(), updateWrapperCaptor.capture());
assertTrue(updateWrapperCaptor.getValue().getSqlSet().contains("apply_amt"));
verify(loanPricingModelService).reinvokeModelAndOverwrite(101L);
}
@Test
void shouldUpdateCorporateWorkflowAndReinvokeModelForCreator()
{
LoanPricingWorkflow workflow = editableWorkflow("企业", "若依-admin");
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
when(sensitiveFieldCryptoService.encrypt("测试科技有限公司")).thenReturn("cipher-corp-name");
when(sensitiveFieldCryptoService.encrypt("91110000100000000X")).thenReturn("cipher-corp-id");
when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("测试科技有限公司");
when(sensitiveFieldCryptoService.decrypt("cipher-id")).thenReturn("91110000100000000X");
CorporateLoanPricingCreateDTO dto = new CorporateLoanPricingCreateDTO();
dto.setCustIsn("CORP001");
dto.setCustName("测试科技有限公司");
dto.setIdType("统一社会信用代码");
dto.setIdNum("91110000100000000X");
dto.setGuarType("质押");
dto.setApplyAmt("300000");
dto.setBusinessType("新增");
dto.setLoanTerm("5");
dto.setCollType("存单质押");
dto.setCollThirdParty("1");
dto.setCouponRate("2.35");
dto.setResCover("1");
dto.setIsGreenLoan("1");
dto.setIsTradeBuildEnt("0");
loanPricingWorkflowService.updateCorporateLoanPricing("C20260525001", dto);
ArgumentCaptor<LambdaUpdateWrapper> updateWrapperCaptor = ArgumentCaptor.forClass(LambdaUpdateWrapper.class);
verify(loanPricingWorkflowMapper).update(any(), updateWrapperCaptor.capture());
String sqlSet = updateWrapperCaptor.getValue().getSqlSet();
assertTrue(sqlSet.contains("res_cover"), sqlSet);
assertTrue(sqlSet.contains("is_green_loan"), sqlSet);
assertTrue(sqlSet.contains("is_trade_construction"), sqlSet);
assertTrue(sqlSet.contains("coll_third_party"), sqlSet);
verify(loanPricingModelService).reinvokeModelAndOverwrite(101L);
}
@Test
void shouldRejectUpdateWhenCustomerTypeDoesNotMatch()
{
LoanPricingWorkflow workflow = editableWorkflow("个人", "若依-admin");
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
CorporateLoanPricingCreateDTO dto = new CorporateLoanPricingCreateDTO();
dto.setCustIsn("CORP001");
dto.setGuarType("信用");
dto.setApplyAmt("300000");
dto.setBusinessType("新增");
dto.setLoanTerm("5");
ServiceException exception = assertThrows(ServiceException.class,
() -> loanPricingWorkflowService.updateCorporateLoanPricing("P20260525001", dto));
assertEquals("客户类型不匹配,不能编辑该流程", exception.getMessage());
}
@Test
void shouldRejectUpdateWhenCurrentUserIsNotCreator()
{
LoanPricingWorkflow workflow = editableWorkflow("个人", "其他用户-8920001");
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
PersonalLoanPricingCreateDTO dto = new PersonalLoanPricingCreateDTO();
dto.setCustIsn("CUST001");
dto.setGuarType("信用");
dto.setApplyAmt("200000");
dto.setBusinessType("新增");
dto.setLoanTerm("3");
ServiceException exception = assertThrows(ServiceException.class,
() -> loanPricingWorkflowService.updatePersonalLoanPricing("P20260525001", dto));
assertEquals("只有创建者可以编辑该流程", exception.getMessage());
}
@Test
void shouldUseRetailModelOutputFinalCalculateRateForWorkflowDetail()
{
@@ -479,6 +653,25 @@ class LoanPricingWorkflowServiceImplTest
return workflow;
}
private LoanPricingWorkflow editableWorkflow(String custType, String createBy)
{
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
workflow.setId(101L);
workflow.setSerialNum("个人".equals(custType) ? "P20260525001" : "C20260525001");
workflow.setModelOutputId(201L);
workflow.setCustIsn("CUST001");
workflow.setCustType(custType);
workflow.setCustName("cipher-name");
workflow.setIdType("身份证");
workflow.setIdNum("cipher-id");
workflow.setGuarType("信用");
workflow.setApplyAmt("100000");
workflow.setBusinessType("新增");
workflow.setLoanTerm("3");
workflow.setCreateBy(createBy);
return workflow;
}
private Page<LoanPricingWorkflowListVO> emptyPageResult()
{
Page<LoanPricingWorkflowListVO> pageResult = new Page<>(1, 10);
@@ -487,13 +680,19 @@ class LoanPricingWorkflowServiceImplTest
}
private void setLoginUser(Long userId, String username, String nickName, SysRole... roles)
{
setLoginUser(userId, 100L, username, nickName, roles);
}
private void setLoginUser(Long userId, Long deptId, String username, String nickName, SysRole... roles)
{
SysUser user = new SysUser();
user.setUserId(userId);
user.setDeptId(deptId);
user.setUserName(username);
user.setNickName(nickName);
user.setRoles(java.util.Arrays.asList(roles));
LoginUser loginUser = new LoginUser(userId, 100L, user, Collections.emptySet());
LoginUser loginUser = new LoginUser(userId, deptId, user, Collections.emptySet());
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(loginUser, null, Collections.emptyList());
SecurityContextHolder.getContext().setAuthentication(authentication);