新增征信维护上传与覆盖服务
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
package com.ruoyi.info.collection.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiCreditNegativeInfo;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiDebtsInfo;
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiCreditInfoQueryDTO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CreditInfoDetailVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CreditInfoListVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CreditInfoUploadResultVO;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 征信维护服务接口
|
||||||
|
*/
|
||||||
|
public interface ICcdiCreditInfoService {
|
||||||
|
|
||||||
|
CreditInfoUploadResultVO upload(List<MultipartFile> files);
|
||||||
|
|
||||||
|
Page<CreditInfoListVO> selectCreditInfoPage(Page<CreditInfoListVO> page, CcdiCreditInfoQueryDTO queryDTO);
|
||||||
|
|
||||||
|
CreditInfoDetailVO selectDetailByPersonId(String personId);
|
||||||
|
|
||||||
|
int deleteByPersonId(String personId);
|
||||||
|
|
||||||
|
void replaceEmployeeCredit(String personId, List<CcdiDebtsInfo> debts, CcdiCreditNegativeInfo negative, String userName);
|
||||||
|
}
|
||||||
@@ -0,0 +1,252 @@
|
|||||||
|
package com.ruoyi.info.collection.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiBaseStaff;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiCreditNegativeInfo;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiDebtsInfo;
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiCreditInfoQueryDTO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CreditInfoDetailVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CreditInfoListVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CreditInfoUploadFailureVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CreditInfoUploadResultVO;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiBaseStaffMapper;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiCreditInfoQueryMapper;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiCreditNegativeInfoMapper;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiDebtsInfoMapper;
|
||||||
|
import com.ruoyi.info.collection.service.ICcdiCreditInfoService;
|
||||||
|
import com.ruoyi.info.collection.service.support.CreditInfoPayloadAssembler;
|
||||||
|
import com.ruoyi.lsfx.client.CreditParseClient;
|
||||||
|
import com.ruoyi.lsfx.domain.response.CreditParsePayload;
|
||||||
|
import com.ruoyi.lsfx.domain.response.CreditParseResponse;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 征信维护服务实现
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class CcdiCreditInfoServiceImpl implements ICcdiCreditInfoService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CreditParseClient creditParseClient;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CreditInfoPayloadAssembler assembler;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CcdiBaseStaffMapper baseStaffMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CcdiDebtsInfoMapper debtsInfoMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CcdiCreditNegativeInfoMapper negativeInfoMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CcdiCreditInfoQueryMapper queryMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CreditInfoUploadResultVO upload(List<MultipartFile> files) {
|
||||||
|
CreditInfoUploadResultVO result = new CreditInfoUploadResultVO();
|
||||||
|
List<CreditInfoUploadFailureVO> failures = new ArrayList<>();
|
||||||
|
int totalCount = files == null ? 0 : files.size();
|
||||||
|
int successCount = 0;
|
||||||
|
String userName = currentUserName();
|
||||||
|
|
||||||
|
if (files == null || files.isEmpty()) {
|
||||||
|
result.setTotalCount(0);
|
||||||
|
result.setSuccessCount(0);
|
||||||
|
result.setFailureCount(0);
|
||||||
|
result.setFailures(failures);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (MultipartFile file : files) {
|
||||||
|
try {
|
||||||
|
validateHtmlFile(file);
|
||||||
|
handleSingleFile(file, userName);
|
||||||
|
successCount++;
|
||||||
|
} catch (Exception e) {
|
||||||
|
failures.add(buildFailure(file, null, null, e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setTotalCount(totalCount);
|
||||||
|
result.setSuccessCount(successCount);
|
||||||
|
result.setFailureCount(failures.size());
|
||||||
|
result.setFailures(failures);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<CreditInfoListVO> selectCreditInfoPage(Page<CreditInfoListVO> page, CcdiCreditInfoQueryDTO queryDTO) {
|
||||||
|
return queryMapper.selectCreditInfoPage(page, queryDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CreditInfoDetailVO selectDetailByPersonId(String personId) {
|
||||||
|
return queryMapper.selectCreditInfoDetailByPersonId(personId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteByPersonId(String personId) {
|
||||||
|
int debtCount = debtsInfoMapper.deleteByPersonId(personId);
|
||||||
|
int negativeCount = negativeInfoMapper.deleteByPersonId(personId);
|
||||||
|
return debtCount + negativeCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void replaceEmployeeCredit(String personId, List<CcdiDebtsInfo> debts, CcdiCreditNegativeInfo negative, String userName) {
|
||||||
|
debtsInfoMapper.deleteByPersonId(personId);
|
||||||
|
negativeInfoMapper.deleteByPersonId(personId);
|
||||||
|
if (debts != null && !debts.isEmpty()) {
|
||||||
|
debts.forEach(item -> {
|
||||||
|
item.setCreateBy(userName);
|
||||||
|
item.setUpdateBy(userName);
|
||||||
|
});
|
||||||
|
debtsInfoMapper.insertBatch(debts);
|
||||||
|
}
|
||||||
|
if (negative != null) {
|
||||||
|
negative.setCreateBy(userName);
|
||||||
|
negative.setUpdateBy(userName);
|
||||||
|
negativeInfoMapper.insert(negative);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSingleFile(MultipartFile multipartFile, String userName) throws IOException {
|
||||||
|
File tempFile = createTempFile(multipartFile);
|
||||||
|
try {
|
||||||
|
CreditParseResponse response = creditParseClient.parse("LXCUSTALL", "PERSON", tempFile);
|
||||||
|
CreditParsePayload payload = requireResponse(response).getPayload();
|
||||||
|
Map<String, Object> header = requireHeader(payload);
|
||||||
|
String personId = stringValue(header.get("query_cert_no"));
|
||||||
|
String personName = stringValue(header.get("query_cust_name"));
|
||||||
|
LocalDate queryDate = parseQueryDate(stringValue(header.get("report_time")));
|
||||||
|
ensureStaffExists(personId);
|
||||||
|
ensureLatestQueryDate(personId, queryDate);
|
||||||
|
|
||||||
|
List<CcdiDebtsInfo> debts = assembler.buildDebts(personId, personName, queryDate, payload);
|
||||||
|
CcdiCreditNegativeInfo negative = assembler.buildNegative(personId, personName, queryDate, payload);
|
||||||
|
replaceEmployeeCredit(personId, debts, negative, userName);
|
||||||
|
} finally {
|
||||||
|
if (tempFile.exists()) {
|
||||||
|
tempFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private File createTempFile(MultipartFile multipartFile) throws IOException {
|
||||||
|
String originalFilename = multipartFile.getOriginalFilename();
|
||||||
|
String suffix = ".html";
|
||||||
|
if (originalFilename != null && originalFilename.contains(".")) {
|
||||||
|
suffix = originalFilename.substring(originalFilename.lastIndexOf('.'));
|
||||||
|
}
|
||||||
|
File tempFile = File.createTempFile("credit-info-", suffix);
|
||||||
|
multipartFile.transferTo(tempFile);
|
||||||
|
return tempFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateHtmlFile(MultipartFile file) {
|
||||||
|
String originalFilename = file == null ? null : file.getOriginalFilename();
|
||||||
|
if (originalFilename == null) {
|
||||||
|
throw new RuntimeException("上传文件不能为空");
|
||||||
|
}
|
||||||
|
String lowerName = originalFilename.toLowerCase();
|
||||||
|
if (!lowerName.endsWith(".html") && !lowerName.endsWith(".htm")) {
|
||||||
|
throw new RuntimeException("仅支持上传.html或.htm征信文件");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CreditParseResponse requireResponse(CreditParseResponse response) {
|
||||||
|
if (response == null || response.getPayload() == null) {
|
||||||
|
throw new RuntimeException("征信解析结果为空");
|
||||||
|
}
|
||||||
|
if (!"0".equals(response.getStatusCode())) {
|
||||||
|
throw new RuntimeException(stringValue(response.getMessage(), "征信解析失败"));
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> requireHeader(CreditParsePayload payload) {
|
||||||
|
Map<String, Object> header = payload.getLxHeader();
|
||||||
|
if (header == null || header.isEmpty()) {
|
||||||
|
throw new RuntimeException("征信解析结果缺少头信息");
|
||||||
|
}
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureStaffExists(String personId) {
|
||||||
|
if (isBlank(personId)) {
|
||||||
|
throw new RuntimeException("征信解析结果缺少员工身份证号");
|
||||||
|
}
|
||||||
|
CcdiBaseStaff staff = baseStaffMapper.selectOne(new LambdaQueryWrapper<CcdiBaseStaff>()
|
||||||
|
.eq(CcdiBaseStaff::getIdCard, personId)
|
||||||
|
.last("LIMIT 1"));
|
||||||
|
if (staff == null) {
|
||||||
|
throw new RuntimeException("未找到对应员工信息");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureLatestQueryDate(String personId, LocalDate queryDate) {
|
||||||
|
LocalDate latestQueryDate = queryMapper.selectLatestQueryDate(personId);
|
||||||
|
if (latestQueryDate != null && queryDate.isBefore(latestQueryDate)) {
|
||||||
|
throw new RuntimeException("上传征信日期早于当前已维护最新记录");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalDate parseQueryDate(String reportTime) {
|
||||||
|
if (isBlank(reportTime)) {
|
||||||
|
throw new RuntimeException("征信解析结果缺少征信查询日期");
|
||||||
|
}
|
||||||
|
String normalized = reportTime.trim();
|
||||||
|
if (normalized.length() > 10) {
|
||||||
|
normalized = normalized.substring(0, 10);
|
||||||
|
}
|
||||||
|
return LocalDate.parse(normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CreditInfoUploadFailureVO buildFailure(MultipartFile file, String personId, String personName, String reason) {
|
||||||
|
CreditInfoUploadFailureVO failure = new CreditInfoUploadFailureVO();
|
||||||
|
failure.setFileName(file == null ? null : file.getOriginalFilename());
|
||||||
|
failure.setPersonId(personId);
|
||||||
|
failure.setPersonName(personName);
|
||||||
|
failure.setReason(reason);
|
||||||
|
return failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String stringValue(Object value) {
|
||||||
|
return stringValue(value, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String stringValue(Object value, String defaultValue) {
|
||||||
|
if (value == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
String text = value.toString().trim();
|
||||||
|
return text.isEmpty() ? defaultValue : text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlank(String text) {
|
||||||
|
return text == null || text.trim().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String currentUserName() {
|
||||||
|
try {
|
||||||
|
return SecurityUtils.getUsername();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "system";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,138 @@
|
|||||||
package com.ruoyi.info.collection.service;
|
package com.ruoyi.info.collection.service;
|
||||||
|
|
||||||
import com.ruoyi.info.collection.domain.dto.CcdiCreditInfoQueryDTO;
|
import com.ruoyi.info.collection.domain.CcdiBaseStaff;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiCreditNegativeInfo;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiDebtsInfo;
|
||||||
import com.ruoyi.info.collection.domain.vo.CreditInfoUploadResultVO;
|
import com.ruoyi.info.collection.domain.vo.CreditInfoUploadResultVO;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiBaseStaffMapper;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiCreditInfoQueryMapper;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiCreditNegativeInfoMapper;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiDebtsInfoMapper;
|
||||||
|
import com.ruoyi.info.collection.service.impl.CcdiCreditInfoServiceImpl;
|
||||||
|
import com.ruoyi.info.collection.service.support.CreditInfoPayloadAssembler;
|
||||||
|
import com.ruoyi.lsfx.client.CreditParseClient;
|
||||||
|
import com.ruoyi.lsfx.domain.response.CreditParsePayload;
|
||||||
|
import com.ruoyi.lsfx.domain.response.CreditParseResponse;
|
||||||
import org.junit.jupiter.api.Test;
|
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 org.springframework.mock.web.MockMultipartFile;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import java.io.File;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
class CcdiCreditInfoServiceImplTest {
|
class CcdiCreditInfoServiceImplTest {
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private CcdiCreditInfoServiceImpl service;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CreditParseClient creditParseClient;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CreditInfoPayloadAssembler assembler;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CcdiBaseStaffMapper baseStaffMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CcdiDebtsInfoMapper debtsInfoMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CcdiCreditNegativeInfoMapper negativeInfoMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CcdiCreditInfoQueryMapper queryMapper;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldCompileCreditInfoContracts() {
|
void uploadHtmlFiles_shouldIsolateFailuresPerEmployee() {
|
||||||
CcdiCreditInfoQueryDTO queryDTO = new CcdiCreditInfoQueryDTO();
|
MockMultipartFile successFile = new MockMultipartFile("files", "a.html", "text/html", "<html>a</html>".getBytes(StandardCharsets.UTF_8));
|
||||||
CreditInfoUploadResultVO resultVO = new CreditInfoUploadResultVO();
|
MockMultipartFile failFile = new MockMultipartFile("files", "b.html", "text/html", "<html>b</html>".getBytes(StandardCharsets.UTF_8));
|
||||||
assertNotNull(queryDTO);
|
|
||||||
assertNotNull(resultVO);
|
when(creditParseClient.parse(anyString(), anyString(), any(File.class)))
|
||||||
|
.thenReturn(successResponse("330101199001010011", "张三", "2026-03-03"))
|
||||||
|
.thenThrow(new RuntimeException("征信解析失败"));
|
||||||
|
when(baseStaffMapper.selectOne(any())).thenReturn(baseStaff("330101199001010011", "张三"));
|
||||||
|
when(assembler.buildDebts(anyString(), anyString(), any(LocalDate.class), any(CreditParsePayload.class)))
|
||||||
|
.thenReturn(List.of(buildDebt()));
|
||||||
|
when(assembler.buildNegative(anyString(), anyString(), any(LocalDate.class), any(CreditParsePayload.class)))
|
||||||
|
.thenReturn(buildNegative());
|
||||||
|
|
||||||
|
CreditInfoUploadResultVO result = service.upload(Arrays.asList(successFile, failFile));
|
||||||
|
|
||||||
|
assertEquals(1, result.getSuccessCount());
|
||||||
|
assertEquals(1, result.getFailureCount());
|
||||||
|
assertEquals("征信解析失败", result.getFailures().get(0).getReason());
|
||||||
|
verify(debtsInfoMapper).deleteByPersonId("330101199001010011");
|
||||||
|
verify(negativeInfoMapper).deleteByPersonId("330101199001010011");
|
||||||
|
verify(debtsInfoMapper).insertBatch(any());
|
||||||
|
verify(negativeInfoMapper).insert(any(CcdiCreditNegativeInfo.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void uploadHtmlFiles_shouldRejectOlderReportDate() {
|
||||||
|
MockMultipartFile file = new MockMultipartFile("files", "a.html", "text/html", "<html>a</html>".getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
when(creditParseClient.parse(anyString(), anyString(), any(File.class)))
|
||||||
|
.thenReturn(successResponse("330101199001010011", "张三", "2026-03-03"));
|
||||||
|
when(baseStaffMapper.selectOne(any())).thenReturn(baseStaff("330101199001010011", "张三"));
|
||||||
|
when(queryMapper.selectLatestQueryDate("330101199001010011"))
|
||||||
|
.thenReturn(LocalDate.parse("2026-03-05"));
|
||||||
|
|
||||||
|
CreditInfoUploadResultVO result = service.upload(List.of(file));
|
||||||
|
|
||||||
|
assertEquals(0, result.getSuccessCount());
|
||||||
|
assertEquals("上传征信日期早于当前已维护最新记录", result.getFailures().get(0).getReason());
|
||||||
|
}
|
||||||
|
|
||||||
|
private CreditParseResponse successResponse(String personId, String personName, String reportTime) {
|
||||||
|
CreditParsePayload payload = new CreditParsePayload();
|
||||||
|
Map<String, Object> header = new HashMap<>();
|
||||||
|
header.put("query_cert_no", personId);
|
||||||
|
header.put("query_cust_name", personName);
|
||||||
|
header.put("report_time", reportTime);
|
||||||
|
payload.setLxHeader(header);
|
||||||
|
payload.setLxDebt(Map.of("uncle_bank_house_bal", "1"));
|
||||||
|
payload.setLxPublictype(Map.of("civil_cnt", 1));
|
||||||
|
|
||||||
|
CreditParseResponse response = new CreditParseResponse();
|
||||||
|
response.setStatusCode("0");
|
||||||
|
response.setPayload(payload);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CcdiBaseStaff baseStaff(String idCard, String name) {
|
||||||
|
CcdiBaseStaff staff = new CcdiBaseStaff();
|
||||||
|
staff.setIdCard(idCard);
|
||||||
|
staff.setName(name);
|
||||||
|
return staff;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CcdiDebtsInfo buildDebt() {
|
||||||
|
CcdiDebtsInfo debt = new CcdiDebtsInfo();
|
||||||
|
debt.setPersonId("330101199001010011");
|
||||||
|
debt.setDebtTotalAmount(new BigDecimal("100"));
|
||||||
|
return debt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CcdiCreditNegativeInfo buildNegative() {
|
||||||
|
CcdiCreditNegativeInfo info = new CcdiCreditNegativeInfo();
|
||||||
|
info.setPersonId("330101199001010011");
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user