完善客商模块
This commit is contained in:
@@ -110,8 +110,8 @@
|
||||
id AS source_id,
|
||||
code AS site_code,
|
||||
name AS address_name,
|
||||
CONCAT_WS('', country, city) AS region_name,
|
||||
region_code,
|
||||
CONCAT_WS('', country, city, district_name) AS region_name,
|
||||
district_code AS region_code,
|
||||
detail_address,
|
||||
longitude,
|
||||
latitude
|
||||
@@ -154,8 +154,8 @@
|
||||
id AS source_id,
|
||||
code AS site_code,
|
||||
name AS address_name,
|
||||
CONCAT_WS('', country, city) AS region_name,
|
||||
region_code,
|
||||
CONCAT_WS('', country, city, district_name) AS region_name,
|
||||
district_code AS region_code,
|
||||
detail_address,
|
||||
longitude,
|
||||
latitude
|
||||
|
||||
@@ -20,9 +20,12 @@
|
||||
<result column="customer_type" property="customerType"/>
|
||||
<result column="project_name" property="projectName"/>
|
||||
<result column="registered_address" property="registeredAddress"/>
|
||||
<result column="registered_region_name" property="registeredRegionName"/>
|
||||
<result column="registered_detail_address" property="registeredDetailAddress"/>
|
||||
<result column="legal_person" property="legalPerson"/>
|
||||
<result column="contact_phone" property="contactPhone"/>
|
||||
<result column="dept_id" property="deptId"/>
|
||||
<result column="dept_ids" property="deptIds"/>
|
||||
<result column="dept_name" property="deptName"/>
|
||||
<result column="invoice_tax_rate" property="invoiceTaxRate"/>
|
||||
<result column="business_scope" property="businessScope"/>
|
||||
@@ -62,9 +65,12 @@
|
||||
customer_type,
|
||||
project_name,
|
||||
registered_address,
|
||||
registered_region_name,
|
||||
registered_detail_address,
|
||||
legal_person,
|
||||
contact_phone,
|
||||
dept_id,
|
||||
dept_ids,
|
||||
dept_name,
|
||||
invoice_tax_rate,
|
||||
business_scope,
|
||||
|
||||
@@ -63,6 +63,7 @@ import org.springblade.transport.pojo.vo.CustomerChangeRecordVO;
|
||||
import org.springblade.transport.pojo.vo.CustomerContactVO;
|
||||
import org.springblade.transport.pojo.vo.CustomerCreditScoreDetailVO;
|
||||
import org.springblade.transport.pojo.vo.CustomerCreditScoreVO;
|
||||
import org.springblade.transport.pojo.vo.CreditRatingStandardVO;
|
||||
import org.springblade.transport.pojo.vo.CustomerInvoiceInfoVO;
|
||||
import org.springblade.transport.pojo.vo.CustomerReceiptAccountVO;
|
||||
import org.springblade.transport.service.ICustomerArchiveService;
|
||||
@@ -73,14 +74,12 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -101,8 +100,6 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
private static final String APPROVAL_APPROVED = "approved";
|
||||
private static final String APPROVAL_REJECTED = "rejected";
|
||||
private static final String CUSTOMER_CODE_PREFIX = "KS";
|
||||
private static final Set<String> CUSTOMER_NATURES = Set.of("有限公司", "个体工商户");
|
||||
private static final Set<String> CUSTOMER_TYPES = Set.of("客户", "承运商");
|
||||
|
||||
private final CustomerContactMapper contactMapper;
|
||||
private final CustomerReceiptAccountMapper receiptAccountMapper;
|
||||
@@ -258,8 +255,13 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
customer.setCustomerNature(trimToEmpty(customer.getCustomerNature()));
|
||||
customer.setUnifiedCreditCode(trimToEmpty(customer.getUnifiedCreditCode()));
|
||||
customer.setCustomerType(trimToEmpty(customer.getCustomerType()));
|
||||
customer.setBusinessScope(trimToNull(customer.getBusinessScope()));
|
||||
customer.setRegisteredRegionName(trimToNull(customer.getRegisteredRegionName()));
|
||||
customer.setRegisteredDetailAddress(trimToNull(customer.getRegisteredDetailAddress()));
|
||||
customer.setRegisteredAddress(buildRegisteredAddress(customer));
|
||||
customer.setLegalPerson(trimToEmpty(customer.getLegalPerson()));
|
||||
customer.setContactPhone(trimToEmpty(customer.getContactPhone()));
|
||||
customer.setDeptIds(trimToNull(customer.getDeptIds()));
|
||||
customer.setDeptName(trimToEmpty(customer.getDeptName()));
|
||||
customer.setAccessType(Func.isEmpty(customer.getAccessType()) ? ACCESS_TEMPORARY : customer.getAccessType());
|
||||
customer.setApprovalStatus(Func.isEmpty(customer.getApprovalStatus()) ? APPROVAL_DRAFT : customer.getApprovalStatus());
|
||||
@@ -279,9 +281,6 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
if (Func.isEmpty(customer.getCustomerNature())) {
|
||||
throw new ServiceException("客商性质不能为空");
|
||||
}
|
||||
if (!CUSTOMER_NATURES.contains(customer.getCustomerNature())) {
|
||||
throw new ServiceException("客商性质只能选择有限公司或个体工商户");
|
||||
}
|
||||
if (Func.isEmpty(customer.getUnifiedCreditCode())) {
|
||||
throw new ServiceException("统一社会信用代码不能为空");
|
||||
}
|
||||
@@ -311,10 +310,13 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
validateLength(customer.getFullName(), 100, "客商全称最多100个字符");
|
||||
validateLength(customer.getLegalPerson(), 10, "法人/负责人最多10个汉字");
|
||||
validateLength(customer.getContactPhone(), 11, "联系电话必须为11位手机号");
|
||||
validateLength(customer.getRegisteredAddress(), 200, "地址最多200个字符");
|
||||
validateLength(customer.getRegisteredRegionName(), 100, "省市区最多100个字符");
|
||||
validateLength(customer.getRegisteredDetailAddress(), 255, "详细地址最多255个字符");
|
||||
validateLength(customer.getRegisteredAddress(), 400, "地址最多400个字符");
|
||||
validateLength(customer.getBusinessScope(), 500, "经营范围最多500个字符");
|
||||
validateLength(customer.getRemark(), 500, "备注最多500个字符");
|
||||
validateNonNegative(customer.getInvoiceTaxRate(), "开票税点不能小于0");
|
||||
validateMax(customer.getInvoiceTaxRate(), new BigDecimal("13"), "开票税点必须在0到13之间");
|
||||
validateNonNegative(customer.getRegisteredCapital(), "注册资金不能小于0");
|
||||
validateNonNegative(customer.getMaxCreditLimit(), "最大资金使用额度不能小于0");
|
||||
validateNonNegative(customer.getApplyCreditLimit(), "申请总资金使用额度不能小于0");
|
||||
@@ -322,24 +324,20 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
}
|
||||
|
||||
private void validateCustomerType(String customerType) {
|
||||
List<String> typeList = Arrays.stream(customerType.replace(",", ",").split(","))
|
||||
List<String> typeList = Func.toStrList(customerType.replace(",", ","))
|
||||
.stream()
|
||||
.map(String::trim)
|
||||
.filter(Func::isNotEmpty)
|
||||
.toList();
|
||||
if (Func.isEmpty(typeList)) {
|
||||
throw new ServiceException("客商类型不能为空");
|
||||
}
|
||||
for (String type : typeList) {
|
||||
if (!CUSTOMER_TYPES.contains(type)) {
|
||||
throw new ServiceException("客商类型只能选择客户或承运商");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateApproval(CustomerArchiveVO customer) {
|
||||
if (Objects.equals(customer.getAccessType(), ACCESS_FORMAL)) {
|
||||
if (Func.isEmpty(customer.getQualificationAttachments())) {
|
||||
throw new ServiceException("正式客商提交审核前必须上传资质附件");
|
||||
throw new ServiceException("正式客商提交审核前必须上传客商材料");
|
||||
}
|
||||
boolean hasCompletedScore = customer.getScores().stream()
|
||||
.anyMatch(score -> "已完成".equals(score.getSelfStatus()) || "已完成".equals(score.getReviewStatus()) || Func.isNotEmpty(score.getFinalScore()));
|
||||
@@ -403,6 +401,8 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
if (Func.isEmpty(invoiceVO.getInvoiceTitle()) && Func.isEmpty(invoiceVO.getTaxNo())) {
|
||||
continue;
|
||||
}
|
||||
invoiceVO.setRegisteredAddress(buildAddress(invoiceVO.getRegisteredRegionName(), invoiceVO.getRegisteredDetailAddress(), invoiceVO.getRegisteredAddress()));
|
||||
invoiceVO.setReceiverAddress(buildAddress(invoiceVO.getReceiverRegionName(), invoiceVO.getReceiverDetailAddress(), invoiceVO.getReceiverAddress()));
|
||||
CustomerInvoiceInfo invoice = Objects.requireNonNull(BeanUtil.copyProperties(invoiceVO, CustomerInvoiceInfo.class));
|
||||
invoice.setId(IdWorker.getId());
|
||||
invoice.setCustomerId(customerId);
|
||||
@@ -417,6 +417,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
continue;
|
||||
}
|
||||
Long scoreId = IdWorker.getId();
|
||||
scoreVO.setProofAttachments(normalizeScoreProofAttachments(scoreVO));
|
||||
CustomerCreditScore score = Objects.requireNonNull(BeanUtil.copyProperties(scoreVO, CustomerCreditScore.class));
|
||||
score.setId(scoreId);
|
||||
score.setCustomerId(customerId);
|
||||
@@ -424,7 +425,11 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
creditScoreMapper.insert(score);
|
||||
List<CustomerCreditScoreDetailVO> details = scoreVO.getDetails() == null ? new ArrayList<>() : scoreVO.getDetails();
|
||||
for (int detailIndex = 0; detailIndex < details.size(); detailIndex++) {
|
||||
CustomerCreditScoreDetail detail = Objects.requireNonNull(BeanUtil.copyProperties(details.get(detailIndex), CustomerCreditScoreDetail.class));
|
||||
CustomerCreditScoreDetailVO detailVO = details.get(detailIndex);
|
||||
if (Func.isEmpty(detailVO.getScore())) {
|
||||
detailVO.setScore(resolveFullScore(detailVO.getOptionsJson()));
|
||||
}
|
||||
CustomerCreditScoreDetail detail = Objects.requireNonNull(BeanUtil.copyProperties(detailVO, CustomerCreditScoreDetail.class));
|
||||
detail.setId(IdWorker.getId());
|
||||
detail.setScoreId(scoreId);
|
||||
detail.setQuantificationId(score.getQuantificationId());
|
||||
@@ -477,7 +482,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
private List<CustomerCreditScoreVO> loadScores(Long customerId) {
|
||||
List<CustomerCreditScore> scores = creditScoreMapper.selectList(Wrappers.<CustomerCreditScore>lambdaQuery()
|
||||
.eq(CustomerCreditScore::getCustomerId, customerId)
|
||||
.eq(CustomerCreditScore::getIsDeleted, 0)
|
||||
.and(wrapper -> wrapper.eq(CustomerCreditScore::getIsDeleted, 0).or().isNull(CustomerCreditScore::getIsDeleted))
|
||||
.orderByDesc(CustomerCreditScore::getScoreDate)
|
||||
.orderByDesc(CustomerCreditScore::getCreateTime));
|
||||
if (Func.isEmpty(scores)) {
|
||||
@@ -486,18 +491,45 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
List<Long> scoreIds = scores.stream().map(CustomerCreditScore::getId).toList();
|
||||
Map<Long, List<CustomerCreditScoreDetailVO>> detailMap = creditScoreDetailMapper.selectList(Wrappers.<CustomerCreditScoreDetail>lambdaQuery()
|
||||
.in(CustomerCreditScoreDetail::getScoreId, scoreIds)
|
||||
.eq(CustomerCreditScoreDetail::getIsDeleted, 0)
|
||||
.and(wrapper -> wrapper.eq(CustomerCreditScoreDetail::getIsDeleted, 0).or().isNull(CustomerCreditScoreDetail::getIsDeleted))
|
||||
.orderByAsc(CustomerCreditScoreDetail::getSort))
|
||||
.stream()
|
||||
.map(detail -> Objects.requireNonNull(BeanUtil.copyProperties(detail, CustomerCreditScoreDetailVO.class)))
|
||||
.collect(Collectors.groupingBy(CustomerCreditScoreDetailVO::getScoreId));
|
||||
return scores.stream().map(score -> {
|
||||
CustomerCreditScoreVO scoreVO = Objects.requireNonNull(BeanUtil.copyProperties(score, CustomerCreditScoreVO.class));
|
||||
scoreVO.setAttachments(parseScoreAttachments(score.getProofAttachments()));
|
||||
scoreVO.setDetails(detailMap.getOrDefault(score.getId(), new ArrayList<>()));
|
||||
scoreVO.setStandards(loadStandards(score.getQuantificationId()));
|
||||
return scoreVO;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private String normalizeScoreProofAttachments(CustomerCreditScoreVO scoreVO) {
|
||||
if (Func.isNotEmpty(scoreVO.getProofAttachments())) {
|
||||
return trimToNull(scoreVO.getProofAttachments());
|
||||
}
|
||||
Object attachments = scoreVO.getAttachments();
|
||||
if (Func.isEmpty(attachments)) {
|
||||
return null;
|
||||
}
|
||||
if (attachments instanceof String attachmentText) {
|
||||
return trimToNull(attachmentText);
|
||||
}
|
||||
return JsonUtil.toJson(attachments);
|
||||
}
|
||||
|
||||
private Object parseScoreAttachments(String value) {
|
||||
if (Func.isEmpty(value)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
try {
|
||||
return JsonUtil.parse(value, List.class);
|
||||
} catch (Exception exception) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private List<CustomerChangeRecordVO> loadChangeRecords(Long customerId) {
|
||||
return changeRecordMapper.selectList(Wrappers.<CustomerChangeRecord>lambdaQuery()
|
||||
.eq(CustomerChangeRecord::getCustomerId, customerId)
|
||||
@@ -549,7 +581,9 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
detail.setItemName(item.getItemName());
|
||||
detail.setOptionDescription(item.getOptionDescription());
|
||||
detail.setScoreDescription(item.getScoreDescription());
|
||||
detail.setOptionsJson(buildOptionsJson(optionMap.getOrDefault(item.getId(), new ArrayList<>())));
|
||||
List<CreditScoreItemOption> itemOptions = optionMap.getOrDefault(item.getId(), new ArrayList<>());
|
||||
detail.setScore(resolveFullScore(itemOptions));
|
||||
detail.setOptionsJson(buildOptionsJson(itemOptions));
|
||||
detail.setSelfScore(BigDecimal.ZERO);
|
||||
detail.setReviewScore(BigDecimal.ZERO);
|
||||
details.add(detail);
|
||||
@@ -570,6 +604,61 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
return JsonUtil.toJson(optionList);
|
||||
}
|
||||
|
||||
private List<CreditRatingStandardVO> loadStandards(Long quantificationId) {
|
||||
if (Func.isEmpty(quantificationId)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return standardMapper.selectList(Wrappers.<CreditRatingStandard>lambdaQuery()
|
||||
.eq(CreditRatingStandard::getQuantificationId, quantificationId)
|
||||
.eq(CreditRatingStandard::getIsDeleted, 0)
|
||||
.orderByAsc(CreditRatingStandard::getSort))
|
||||
.stream()
|
||||
.map(standard -> Objects.requireNonNull(BeanUtil.copyProperties(standard, CreditRatingStandardVO.class)))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private BigDecimal resolveFullScore(List<CreditScoreItemOption> options) {
|
||||
return options.stream()
|
||||
.map(CreditScoreItemOption::getScore)
|
||||
.filter(Objects::nonNull)
|
||||
.max(BigDecimal::compareTo)
|
||||
.orElse(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
private BigDecimal resolveFullScore(String optionsJson) {
|
||||
if (Func.isEmpty(optionsJson)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
try {
|
||||
Object value = JsonUtil.parse(optionsJson, List.class);
|
||||
if (!(value instanceof List<?> options)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return options.stream()
|
||||
.map(this::resolveOptionScore)
|
||||
.filter(Objects::nonNull)
|
||||
.max(BigDecimal::compareTo)
|
||||
.orElse(BigDecimal.ZERO);
|
||||
} catch (Exception exception) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
private BigDecimal resolveOptionScore(Object option) {
|
||||
if (!(option instanceof Map<?, ?> optionMap)) {
|
||||
return null;
|
||||
}
|
||||
Object score = optionMap.get("score");
|
||||
if (score == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new BigDecimal(String.valueOf(score));
|
||||
} catch (NumberFormatException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String nextCustomerCode() {
|
||||
CustomerArchive latest = list(Wrappers.<CustomerArchive>lambdaQuery()
|
||||
.likeRight(CustomerArchive::getCustomerCode, CUSTOMER_CODE_PREFIX)
|
||||
@@ -650,6 +739,25 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMax(BigDecimal value, BigDecimal max, String message) {
|
||||
if (Func.isNotEmpty(value) && value.compareTo(max) > 0) {
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
private String buildRegisteredAddress(CustomerArchiveVO customer) {
|
||||
return buildAddress(customer.getRegisteredRegionName(), customer.getRegisteredDetailAddress(), customer.getRegisteredAddress());
|
||||
}
|
||||
|
||||
private String buildAddress(String regionNameValue, String detailAddressValue, String fallbackAddress) {
|
||||
String regionName = trimToEmpty(regionNameValue);
|
||||
String detailAddress = trimToEmpty(detailAddressValue);
|
||||
if (Func.isNotEmpty(regionName) || Func.isNotEmpty(detailAddress)) {
|
||||
return regionName + detailAddress;
|
||||
}
|
||||
return trimToNull(fallbackAddress);
|
||||
}
|
||||
|
||||
private String trimToEmpty(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user