@@ -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 ( ) , 2 00, " 地址 最多2 00个字符" ) ;
validateLength ( customer . getRegisteredRegionName ( ) , 1 00, " 省市区 最多1 00个字符" ) ;
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 ( ) ;
}