完善客商模块

This commit is contained in:
2026-08-01 01:22:46 +08:00
parent e03b554473
commit 454ca91760
15 changed files with 280 additions and 41 deletions

View File

@@ -71,6 +71,12 @@ public class CustomerArchive extends TenantEntity {
@Schema(description = "注册/实际经营地址")
private String registeredAddress;
@Schema(description = "注册地址行政区划")
private String registeredRegionName;
@Schema(description = "注册地址详细地址")
private String registeredDetailAddress;
@Schema(description = "法人/负责人")
private String legalPerson;
@@ -80,6 +86,9 @@ public class CustomerArchive extends TenantEntity {
@Schema(description = "所属组织ID")
private Long deptId;
@Schema(description = "所属组织ID集合")
private String deptIds;
@Schema(description = "所属组织")
private String deptName;
@@ -116,7 +125,7 @@ public class CustomerArchive extends TenantEntity {
@Schema(description = "备注")
private String remark;
@Schema(description = "资质附件JSON")
@Schema(description = "客商材料JSON")
private String qualificationAttachments;
@Schema(description = "准入类型temporary/formal")

View File

@@ -59,6 +59,18 @@ public class CustomerContact extends TenantEntity {
@Schema(description = "邮箱")
private String email;
@Schema(description = "行政区划")
private String regionName;
@Schema(description = "详细地址")
private String detailAddress;
@Schema(description = "联系地址")
private String contactAddress;
@Schema(description = "所属分公司/事业部")
private String branchName;
@Schema(description = "职务")
private String positionName;

View File

@@ -68,6 +68,9 @@ public class CustomerCreditScore extends TenantEntity {
@Schema(description = "最终得分")
private BigDecimal finalScore;
@Schema(description = "得分率")
private BigDecimal scoreRate;
@Schema(description = "信用等级")
private String creditLevel;
@@ -77,6 +80,15 @@ public class CustomerCreditScore extends TenantEntity {
@Schema(description = "拟申请总资金使用额度(万元)")
private BigDecimal applyCreditLimit;
@Schema(description = "临时申请额度(万元)")
private BigDecimal tempApplyCreditLimit;
@Schema(description = "临时额度开始日期")
private LocalDate tempCreditStartDate;
@Schema(description = "临时额度结束日期")
private LocalDate tempCreditEndDate;
@Schema(description = "自评状态")
private String selfStatus;

View File

@@ -80,6 +80,9 @@ public class CustomerCreditScoreDetail extends TenantEntity {
@Schema(description = "得分说明")
private String scoreDescription;
@Schema(description = "评分项目配置最高得分")
private BigDecimal score;
@Schema(description = "自评得分")
private BigDecimal selfScore;

View File

@@ -68,6 +68,12 @@ public class CustomerInvoiceInfo extends TenantEntity {
@Schema(description = "注册地址")
private String registeredAddress;
@Schema(description = "注册地址行政区划")
private String registeredRegionName;
@Schema(description = "注册地址详细地址")
private String registeredDetailAddress;
@Schema(description = "邮箱")
private String email;
@@ -80,6 +86,12 @@ public class CustomerInvoiceInfo extends TenantEntity {
@Schema(description = "收件人地址")
private String receiverAddress;
@Schema(description = "收件人地址行政区划")
private String receiverRegionName;
@Schema(description = "收件人详细地址")
private String receiverDetailAddress;
@Schema(description = "是否默认")
private Integer isDefault;

View File

@@ -53,6 +53,9 @@ public class CustomerReceiptAccount extends TenantEntity {
@Schema(description = "收款方名称")
private String accountName;
@Schema(description = "开户人姓名")
private String accountHolderName;
@Schema(description = "开户行名称")
private String bankName;
@@ -71,4 +74,7 @@ public class CustomerReceiptAccount extends TenantEntity {
@Schema(description = "是否默认")
private Integer isDefault;
@Schema(description = "备注")
private String remark;
}

View File

@@ -49,4 +49,12 @@ public class CustomerCreditScoreVO extends CustomerCreditScore {
@Schema(description = "评分明细")
private List<CustomerCreditScoreDetailVO> details = new ArrayList<>();
@TableField(exist = false)
@Schema(description = "证明材料")
private Object attachments;
@TableField(exist = false)
@Schema(description = "评估标准")
private List<CreditRatingStandardVO> standards = new ArrayList<>();
}

View File

@@ -73,7 +73,7 @@ public class RailwayStationServiceImpl extends BaseServiceImpl<RailwayStationMap
private static final int STATUS_ENABLED = 1;
private static final int STATUS_DISABLED = 2;
private static final int CODE_MAX_LENGTH = 20;
private static final int NAME_MAX_LENGTH = 100;
private static final int NAME_MAX_LENGTH = 50;
private static final int RAILWAY_LINE_MAX_LENGTH = 100;
private static final int REGION_NAME_MAX_LENGTH = 128;
private static final int REGION_CODE_MAX_LENGTH = 32;
@@ -175,7 +175,7 @@ public class RailwayStationServiceImpl extends BaseServiceImpl<RailwayStationMap
try {
return new BigDecimal(trimValue);
} catch (NumberFormatException exception) {
throw new ServiceException(name + "格式不正确");
throw new ServiceException(name + "范围不正确");
}
}
@@ -216,16 +216,16 @@ public class RailwayStationServiceImpl extends BaseServiceImpl<RailwayStationMap
throw new ServiceException("TMIS国标编码为5位数字");
}
if (Func.isEmpty(railwayStation.getTelegraphCode())) {
throw new ServiceException("电报码不能为空");
throw new ServiceException("电报码格式不正确或已存在");
}
if (!TELEGRAPH_CODE_PATTERN.matcher(railwayStation.getTelegraphCode()).matches()) {
throw new ServiceException("电报码为3位大写字母");
throw new ServiceException("电报码格式不正确或已存在");
}
if (Func.isEmpty(railwayStation.getName())) {
throw new ServiceException("车站名称不能为空");
throw new ServiceException("请输入车站名称");
}
validateLength(railwayStation.getCode(), CODE_MAX_LENGTH, "编码不能超过20字");
validateLength(railwayStation.getName(), NAME_MAX_LENGTH, "车站名称不能超过100字");
validateLength(railwayStation.getName(), NAME_MAX_LENGTH, "请输入车站名称");
// validateLength(railwayStation.getRailwayLine(), RAILWAY_LINE_MAX_LENGTH, "所属铁路线路不能超过100字");
validateLength(railwayStation.getProvinceName(), REGION_NAME_MAX_LENGTH, "所属省份不能超过128字");
validateLength(railwayStation.getCityName(), REGION_NAME_MAX_LENGTH, "所属城市不能超过128字");
@@ -234,15 +234,21 @@ public class RailwayStationServiceImpl extends BaseServiceImpl<RailwayStationMap
validateLength(railwayStation.getRegionName(), REGION_NAME_MAX_LENGTH, "行政区划不能超过128字");
validateLength(railwayStation.getDetailAddress(), DETAIL_ADDRESS_MAX_LENGTH, "详细地址不能超过255字");
validateLength(railwayStation.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字");
if (Func.isEmpty(railwayStation.getProvinceCode()) || Func.isEmpty(railwayStation.getCityCode()) || Func.isEmpty(railwayStation.getDistrictCode())) {
throw new ServiceException("请选择省份、城市和区县");
if (Func.isEmpty(railwayStation.getProvinceCode())) {
throw new ServiceException("请选择所属省份");
}
if (Func.isEmpty(railwayStation.getCityCode())) {
throw new ServiceException("请选择所属城市");
}
if (Func.isEmpty(railwayStation.getDistrictCode())) {
throw new ServiceException("请选择所属区县");
}
validateCoordinate(railwayStation.getLongitude(), MIN_LONGITUDE, MAX_LONGITUDE, "经度");
validateCoordinate(railwayStation.getLatitude(), MIN_LATITUDE, MAX_LATITUDE, "纬度");
validateDataSource(railwayStation.getDataSource());
validateStatus(railwayStation.getStatus());
validateUnique(railwayStation, RailwayStation::getTmisCode, railwayStation.getTmisCode(), "该TMIS编码已存在");
validateUnique(railwayStation, RailwayStation::getTelegraphCode, railwayStation.getTelegraphCode(), "电报码已存在");
validateUnique(railwayStation, RailwayStation::getTelegraphCode, railwayStation.getTelegraphCode(), "电报码格式不正确或已存在");
validateUnique(railwayStation, RailwayStation::getCode, railwayStation.getCode(), "该编码已存在");
}
@@ -257,7 +263,7 @@ public class RailwayStationServiceImpl extends BaseServiceImpl<RailwayStationMap
.eq(Region::getName, railwayStation.getProvinceName()), false);
}
if (Func.isEmpty(province)) {
throw new ServiceException("请选择省份");
throw new ServiceException("请选择所属省份");
}
Region city = null;
@@ -270,7 +276,7 @@ public class RailwayStationServiceImpl extends BaseServiceImpl<RailwayStationMap
.eq(Region::getName, railwayStation.getCityName()), false);
}
if (Func.isEmpty(city)) {
throw new ServiceException("请选择城市");
throw new ServiceException("请选择所属城市");
}
if (!Objects.equals(city.getParentCode(), province.getCode())) {
throw new ServiceException("所属城市与所属省份不匹配");
@@ -290,7 +296,7 @@ public class RailwayStationServiceImpl extends BaseServiceImpl<RailwayStationMap
.eq(Region::getName, railwayStation.getDistrictName()), false);
}
if (Func.isEmpty(district)) {
throw new ServiceException("请选择区县");
throw new ServiceException("请选择所属区县");
}
if (!Objects.equals(district.getParentCode(), city.getCode())) {
throw new ServiceException("所属区县与所属城市不匹配");
@@ -306,7 +312,7 @@ public class RailwayStationServiceImpl extends BaseServiceImpl<RailwayStationMap
return;
}
if (value.compareTo(min) < 0 || value.compareTo(max) > 0) {
throw new ServiceException(name + ("经度".equals(name) ? "范围为 -180 到 180" : "范围为 -90 到 90"));
throw new ServiceException(name + "范围不正确");
}
}

View File

@@ -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

View File

@@ -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,

View File

@@ -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();
}

View File

@@ -12,10 +12,13 @@ CREATE TABLE `blade_customer_archive` (
`unified_credit_code` varchar(18) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '统一社会信用代码',
`customer_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客商类型',
`project_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属项目',
`registered_address` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册/实际经营地址',
`registered_address` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册/实际经营地址',
`registered_region_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址行政区划',
`registered_detail_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址详细地址',
`legal_person` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '法人/负责人',
`contact_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '联系电话',
`dept_id` bigint NULL DEFAULT NULL COMMENT '所属组织ID',
`dept_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属组织ID集合',
`dept_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所属组织',
`invoice_tax_rate` decimal(6,2) NULL DEFAULT NULL COMMENT '开票税点',
`business_scope` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '经营范围',
@@ -28,7 +31,7 @@ CREATE TABLE `blade_customer_archive` (
`max_credit_limit` decimal(18,2) NULL DEFAULT NULL COMMENT '最大资金使用额度(万元)',
`apply_credit_limit` decimal(18,2) NULL DEFAULT NULL COMMENT '申请总资金使用额度(万元)',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`qualification_attachments` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '资质附件JSON',
`qualification_attachments` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '客商材料JSON',
`access_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'temporary' COMMENT '准入类型temporary临时formal正式',
`approval_status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'draft' COMMENT '审批状态draft草稿reviewing审核中approved审核通过rejected审核不通过',
`current_node` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '当前节点',
@@ -59,6 +62,10 @@ CREATE TABLE `blade_customer_contact` (
`contact_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系人姓名',
`contact_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话',
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
`region_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '行政区划',
`detail_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '详细地址',
`contact_address` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系地址',
`branch_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属分公司/事业部',
`position_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '职务',
`is_default` int NULL DEFAULT 0 COMMENT '是否默认',
`remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
@@ -82,12 +89,14 @@ CREATE TABLE `blade_customer_receipt_account` (
`tenant_id` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '000000' COMMENT '租户ID',
`customer_id` bigint NOT NULL COMMENT '客商ID',
`account_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收款方名称',
`account_holder_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '开户人姓名',
`bank_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '开户行名称',
`bank_account` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '银行账号',
`registered_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册电话',
`registered_address` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址',
`tax_no` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '纳税人识别号',
`is_default` int NULL DEFAULT 0 COMMENT '是否默认',
`remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`create_user` bigint NULL DEFAULT NULL COMMENT '创建人',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
@@ -112,11 +121,15 @@ CREATE TABLE `blade_customer_invoice_info` (
`bank_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '开户行名称',
`registered_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册电话',
`bank_account` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '银行账号',
`registered_address` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址',
`registered_address` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址',
`registered_region_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址行政区划',
`registered_detail_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址详细地址',
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
`receiver_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人姓名',
`receiver_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人电话',
`receiver_address` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人地址',
`receiver_address` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人地址',
`receiver_region_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人地址行政区划',
`receiver_detail_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人详细地址',
`is_default` int NULL DEFAULT 0 COMMENT '是否默认',
`create_user` bigint NULL DEFAULT NULL COMMENT '创建人',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
@@ -142,9 +155,13 @@ CREATE TABLE `blade_customer_credit_score` (
`self_score` decimal(10,2) NULL DEFAULT NULL COMMENT '自评得分',
`review_score` decimal(10,2) NULL DEFAULT NULL COMMENT '复评得分',
`final_score` decimal(10,2) NULL DEFAULT NULL COMMENT '最终得分',
`score_rate` decimal(10,2) NULL DEFAULT NULL COMMENT '得分率',
`credit_level` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '信用等级',
`max_credit_limit` decimal(18,2) NULL DEFAULT NULL COMMENT '最大资金使用额度(万元)',
`apply_credit_limit` decimal(18,2) NULL DEFAULT NULL COMMENT '拟申请总资金使用额度(万元)',
`temp_apply_credit_limit` decimal(18,2) NULL DEFAULT NULL COMMENT '临时申请额度(万元)',
`temp_credit_start_date` date NULL DEFAULT NULL COMMENT '临时额度开始日期',
`temp_credit_end_date` date NULL DEFAULT NULL COMMENT '临时额度结束日期',
`self_status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '未完成' COMMENT '自评状态',
`review_status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '未完成' COMMENT '复评状态',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
@@ -178,6 +195,7 @@ CREATE TABLE `blade_customer_credit_score_detail` (
`options_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '选项JSON',
`selected_option` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '已选选项',
`score_description` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '得分说明',
`score` decimal(10,2) NULL DEFAULT NULL COMMENT '评分项目配置最高得分',
`self_score` decimal(10,2) NULL DEFAULT NULL COMMENT '自评得分',
`review_score` decimal(10,2) NULL DEFAULT NULL COMMENT '复评得分',
`sort` int NULL DEFAULT 0 COMMENT '排序',

View File

@@ -0,0 +1,26 @@
-- 客商档案:联系人地址与客商材料字段补丁
ALTER TABLE `blade_customer_contact`
ADD COLUMN `region_name` varchar(100) DEFAULT NULL COMMENT '行政区划' AFTER `email`,
ADD COLUMN `detail_address` varchar(255) DEFAULT NULL COMMENT '详细地址' AFTER `region_name`,
ADD COLUMN `contact_address` varchar(400) DEFAULT NULL COMMENT '联系地址' AFTER `detail_address`,
ADD COLUMN `branch_name` varchar(100) DEFAULT NULL COMMENT '所属分公司/事业部' AFTER `contact_address`;
ALTER TABLE `blade_customer_archive`
ADD COLUMN `registered_region_name` varchar(100) DEFAULT NULL COMMENT '注册地址行政区划' AFTER `registered_address`,
ADD COLUMN `registered_detail_address` varchar(255) DEFAULT NULL COMMENT '注册地址详细地址' AFTER `registered_region_name`,
ADD COLUMN `dept_ids` varchar(500) DEFAULT NULL COMMENT '所属组织ID集合' AFTER `dept_id`,
MODIFY COLUMN `registered_address` varchar(400) DEFAULT NULL COMMENT '注册/实际经营地址',
MODIFY COLUMN `qualification_attachments` text COMMENT '客商材料JSON';
ALTER TABLE `blade_customer_receipt_account`
ADD COLUMN `account_holder_name` varchar(50) DEFAULT NULL COMMENT '开户人姓名' AFTER `account_name`,
ADD COLUMN `remark` varchar(200) DEFAULT NULL COMMENT '备注' AFTER `is_default`;
ALTER TABLE `blade_customer_invoice_info`
ADD COLUMN `registered_region_name` varchar(100) DEFAULT NULL COMMENT '注册地址行政区划' AFTER `registered_address`,
ADD COLUMN `registered_detail_address` varchar(255) DEFAULT NULL COMMENT '注册地址详细地址' AFTER `registered_region_name`,
ADD COLUMN `receiver_region_name` varchar(100) DEFAULT NULL COMMENT '收件人地址行政区划' AFTER `receiver_address`,
ADD COLUMN `receiver_detail_address` varchar(255) DEFAULT NULL COMMENT '收件人详细地址' AFTER `receiver_region_name`,
MODIFY COLUMN `registered_address` varchar(400) DEFAULT NULL COMMENT '注册地址',
MODIFY COLUMN `receiver_address` varchar(400) DEFAULT NULL COMMENT '收件人地址';

View File

@@ -0,0 +1,6 @@
-- 客商评分记录:临时额度字段补丁
ALTER TABLE `blade_customer_credit_score`
ADD COLUMN `temp_apply_credit_limit` decimal(18,2) NULL DEFAULT NULL COMMENT '临时申请额度(万元)' AFTER `apply_credit_limit`,
ADD COLUMN `temp_credit_start_date` date NULL DEFAULT NULL COMMENT '临时额度开始日期' AFTER `temp_apply_credit_limit`,
ADD COLUMN `temp_credit_end_date` date NULL DEFAULT NULL COMMENT '临时额度结束日期' AFTER `temp_credit_start_date`;

View File

@@ -0,0 +1,7 @@
-- 客商评分记录保存字段补丁
ALTER TABLE `blade_customer_credit_score`
ADD COLUMN `score_rate` decimal(10,2) NULL DEFAULT NULL COMMENT '得分率' AFTER `final_score`;
ALTER TABLE `blade_customer_credit_score_detail`
ADD COLUMN `score` decimal(10,2) NULL DEFAULT NULL COMMENT '评分项目配置最高得分' AFTER `score_description`;