项目、合同修复

This commit is contained in:
2026-08-06 17:58:27 +08:00
parent 28eb484a68
commit a1eea5075b
15 changed files with 245 additions and 50 deletions

View File

@@ -22,6 +22,8 @@
*/ */
package org.springblade.transport.pojo.entity; package org.springblade.transport.pojo.entity;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@@ -107,9 +109,11 @@ public class ContractManage extends TenantEntity {
private Integer legalSealFlag; private Integer legalSealFlag;
@Schema(description = "一式份数") @Schema(description = "一式份数")
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private Integer copyCount; private Integer copyCount;
@Schema(description = "回款账期(天)") @Schema(description = "回款账期(天)")
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private Integer paymentDays; private Integer paymentDays;
@Schema(description = "合同阶段") @Schema(description = "合同阶段")

View File

@@ -22,6 +22,8 @@
*/ */
package org.springblade.transport.pojo.entity; package org.springblade.transport.pojo.entity;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@@ -93,6 +95,7 @@ public class CustomerArchive extends TenantEntity {
private String deptName; private String deptName;
@Schema(description = "开票税点") @Schema(description = "开票税点")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private BigDecimal invoiceTaxRate; private BigDecimal invoiceTaxRate;
@Schema(description = "经营范围") @Schema(description = "经营范围")
@@ -102,9 +105,11 @@ public class CustomerArchive extends TenantEntity {
private String businessTermType; private String businessTermType;
@Schema(description = "营业期限截止日") @Schema(description = "营业期限截止日")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDate businessEndDate; private LocalDate businessEndDate;
@Schema(description = "注册资金(万元)") @Schema(description = "注册资金(万元)")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private BigDecimal registeredCapital; private BigDecimal registeredCapital;
@Schema(description = "客商负责人") @Schema(description = "客商负责人")

View File

@@ -55,6 +55,10 @@ public class ContractManageVO extends ContractManage {
@Schema(description = "到期快捷筛选") @Schema(description = "到期快捷筛选")
private String expireScope; private String expireScope;
@TableField(exist = false)
@Schema(description = "生效类型筛选")
private String effectiveType;
@TableField(exist = false) @TableField(exist = false)
@Schema(description = "创建人姓名") @Schema(description = "创建人姓名")
private String createUserName; private String createUserName;

View File

@@ -71,4 +71,8 @@ public class ProjectApplyVO extends ProjectApply {
@Schema(description = "变更类型") @Schema(description = "变更类型")
private String changeType; private String changeType;
@TableField(exist = false)
@Schema(description = "是否仅查询可用于临时额度申请的项目")
private Boolean temporaryCreditLimitSelectable;
} }

View File

@@ -56,41 +56,41 @@ public class AirportMasterExcel implements Serializable {
@ExcelProperty("编码") @ExcelProperty("编码")
private String code; private String code;
@ExcelProperty("IATA编码") @ExcelProperty("IATA编码*")
private String iataCode; private String iataCode;
@ExcelProperty("ICAO代码") @ExcelProperty("ICAO代码*")
private String icaoCode; private String icaoCode;
@ExcelProperty("机场标准名称") @ExcelProperty("机场标准名称*")
private String name; private String name;
@ExcelProperty("机场简称") @ExcelProperty("机场简称")
private String shortName; private String shortName;
@ExcelProperty("所属省份") @ExcelProperty("所属省份*")
private String provinceName; private String provinceName;
@ExcelProperty("所属城市") @ExcelProperty("所属城市*")
private String cityName; private String cityName;
@ExcelProperty("所属区县") @ExcelProperty("所属区县*")
private String districtName; private String districtName;
@ExcelProperty("行政区划")
private String regionName;
@ExcelProperty("详细地址") @ExcelProperty("详细地址")
private String detailAddress; private String detailAddress;
@ExcelProperty("经度") @ExcelProperty("经度*")
@NumberFormat("0.000000") @NumberFormat("0.000000")
private BigDecimal longitude; private BigDecimal longitude;
@ExcelProperty("纬度") @ExcelProperty("纬度*")
@NumberFormat("0.000000") @NumberFormat("0.000000")
private BigDecimal latitude; private BigDecimal latitude;
@ExcelProperty("行政区划编号")
private String regionCode;
@ExcelProperty("数据来源") @ExcelProperty("数据来源")
private String dataSource; private String dataSource;

View File

@@ -54,30 +54,27 @@ public class RailwayStationExcel implements Serializable {
@ExcelProperty("编码") @ExcelProperty("编码")
private String code; private String code;
@ExcelProperty("TMIS国标编码") @ExcelProperty("TMIS国标编码*")
private String tmisCode; private String tmisCode;
@ExcelProperty("电报码") @ExcelProperty("电报码*")
private String telegraphCode; private String telegraphCode;
@ExcelProperty("车站名称") @ExcelProperty("车站名称*")
private String name; private String name;
// @ExcelProperty("所属铁路线路") // @ExcelProperty("所属铁路线路")
// private String railwayLine; // private String railwayLine;
@ExcelProperty("所属省份") @ExcelProperty("所属省份*")
private String provinceName; private String provinceName;
@ExcelProperty("所属城市") @ExcelProperty("所属城市*")
private String cityName; private String cityName;
@ExcelProperty("所属区县") @ExcelProperty("所属区县*")
private String districtName; private String districtName;
@ExcelProperty("行政区划")
private String regionName;
@ExcelProperty("详细地址") @ExcelProperty("详细地址")
private String detailAddress; private String detailAddress;
@@ -87,6 +84,9 @@ public class RailwayStationExcel implements Serializable {
@ExcelProperty("纬度") @ExcelProperty("纬度")
private String latitude; private String latitude;
@ExcelProperty("行政区划编号")
private String regionCode;
@ExcelProperty("数据来源") @ExcelProperty("数据来源")
private String dataSource; private String dataSource;

View File

@@ -8,6 +8,8 @@
<result column="create_dept" property="createDept"/> <result column="create_dept" property="createDept"/>
<result column="create_time" property="createTime"/> <result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/> <result column="update_user" property="updateUser"/>
<result column="create_dept_name" property="createDeptName"/>
<result column="update_user_name" property="updateUserName"/>
<result column="update_time" property="updateTime"/> <result column="update_time" property="updateTime"/>
<result column="status" property="status"/> <result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/> <result column="is_deleted" property="isDeleted"/>
@@ -18,29 +20,33 @@
<select id="selectFeeItemPage" resultMap="feeItemResultMap"> <select id="selectFeeItemPage" resultMap="feeItemResultMap">
SELECT SELECT
* bfi.*,
bd.dept_name AS create_dept_name,
bu.real_name AS update_user_name
FROM FROM
blade_fee_item blade_fee_item bfi
LEFT JOIN blade_dept bd ON bd.id = bfi.create_dept
LEFT JOIN blade_user bu ON bu.id = bfi.update_user
WHERE WHERE
is_deleted = 0 bfi.is_deleted = 0
<if test="feeItem.feeCategory != null and feeItem.feeCategory != ''"> <if test="feeItem.feeCategory != null and feeItem.feeCategory != ''">
AND fee_category = #{feeItem.feeCategory} AND bfi.fee_category = #{feeItem.feeCategory}
</if> </if>
<if test="feeItem.name != null and feeItem.name != ''"> <if test="feeItem.name != null and feeItem.name != ''">
<bind name="nameLike" value="'%' + feeItem.name + '%'"/> <bind name="nameLike" value="'%' + feeItem.name + '%'"/>
AND name LIKE #{nameLike} AND bfi.name LIKE #{nameLike}
</if> </if>
<if test="feeItem.englishName != null and feeItem.englishName != ''"> <if test="feeItem.englishName != null and feeItem.englishName != ''">
<bind name="englishNameLike" value="'%' + feeItem.englishName + '%'"/> <bind name="englishNameLike" value="'%' + feeItem.englishName + '%'"/>
AND english_name LIKE #{englishNameLike} AND bfi.english_name LIKE #{englishNameLike}
</if> </if>
<if test="feeItem.status != null"> <if test="feeItem.status != null">
AND status = #{feeItem.status} AND bfi.status = #{feeItem.status}
</if> </if>
<if test="feeItem.createDept != null"> <if test="feeItem.createDept != null">
AND create_dept = #{feeItem.createDept} AND bfi.create_dept = #{feeItem.createDept}
</if> </if>
ORDER BY create_time DESC ORDER BY bfi.create_time DESC
</select> </select>
</mapper> </mapper>

View File

@@ -71,6 +71,9 @@
<if test="param2.name!=null and param2.name!=''"> <if test="param2.name!=null and param2.name!=''">
and region.name like concat(concat('%', #{param2.name}),'%') and region.name like concat(concat('%', #{param2.name}),'%')
</if> </if>
<if test="param2.regionLevel!=null">
and region.level = #{param2.regionLevel}
</if>
</where> </where>
ORDER BY region.sort ASC, region.code ASC ORDER BY region.sort ASC, region.code ASC
</select> </select>
@@ -95,6 +98,9 @@
<if test="param2.name!=null and param2.name!=''"> <if test="param2.name!=null and param2.name!=''">
and region.name like concat(concat('%', #{param2.name}),'%') and region.name like concat(concat('%', #{param2.name}),'%')
</if> </if>
<if test="param2.regionLevel!=null">
and region.level = #{param2.regionLevel}
</if>
</where> </where>
ORDER BY region.sort ASC, region.code ASC ORDER BY region.sort ASC, region.code ASC
</select> </select>

View File

@@ -143,29 +143,36 @@ public class ContractManageController extends BladeController {
return R.status(contractManageService.terminate(id, reason)); return R.status(contractManageService.terminate(id, reason));
} }
@PostMapping("/copy") @PostMapping("/update-attachments")
@ApiOperationSupport(order = 12) @ApiOperationSupport(order = 12)
@Operation(summary = "更新合同附件", description = "传入合同id及附件信息")
public R updateAttachments(@RequestBody ContractManage contractManage) {
return R.status(contractManageService.updateAttachments(contractManage));
}
@PostMapping("/copy")
@ApiOperationSupport(order = 13)
@Operation(summary = "复制合同", description = "传入id") @Operation(summary = "复制合同", description = "传入id")
public R<ContractManageVO> copy(@Parameter(description = "主键", required = true) @RequestParam Long id) { public R<ContractManageVO> copy(@Parameter(description = "主键", required = true) @RequestParam Long id) {
return R.data(contractManageService.copy(id)); return R.data(contractManageService.copy(id));
} }
@PostMapping("/remove") @PostMapping("/remove")
@ApiOperationSupport(order = 13) @ApiOperationSupport(order = 14)
@Operation(summary = "逻辑删除", description = "传入ids") @Operation(summary = "逻辑删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) { public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(contractManageService.removeDraft(ids)); return R.status(contractManageService.removeDraft(ids));
} }
@GetMapping("/expire-stats") @GetMapping("/expire-stats")
@ApiOperationSupport(order = 14) @ApiOperationSupport(order = 15)
@Operation(summary = "到期统计", description = "传入contractManage") @Operation(summary = "到期统计", description = "传入contractManage")
public R<Map<String, Long>> expireStats(ContractManageVO contractManage) { public R<Map<String, Long>> expireStats(ContractManageVO contractManage) {
return R.data(contractManageService.expireStats(contractManage)); return R.data(contractManageService.expireStats(contractManage));
} }
@GetMapping("/export-contract-manage") @GetMapping("/export-contract-manage")
@ApiOperationSupport(order = 15) @ApiOperationSupport(order = 16)
@Operation(summary = "导出合同管理") @Operation(summary = "导出合同管理")
public void exportContractManage(ContractManageVO contractManage, @RequestParam(required = false) String ids, HttpServletResponse response) { public void exportContractManage(ContractManageVO contractManage, @RequestParam(required = false) String ids, HttpServletResponse response) {
List<ContractManageExcel> list = contractManageService.exportContractManage(contractManage, ids); List<ContractManageExcel> list = contractManageService.exportContractManage(contractManage, ids);

View File

@@ -48,6 +48,7 @@ public interface IContractManageService extends BaseService<ContractManage> {
boolean reject(Long id); boolean reject(Long id);
boolean withdraw(Long id); boolean withdraw(Long id);
boolean startChange(Long id, String changeContent, String changeReason); boolean startChange(Long id, String changeContent, String changeReason);
boolean updateAttachments(ContractManage contractManage);
boolean terminate(Long id, String reason); boolean terminate(Long id, String reason);
boolean removeDraft(String ids); boolean removeDraft(String ids);
ContractManageVO copy(Long id); ContractManageVO copy(Long id);

View File

@@ -49,7 +49,6 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors;
/** /**
* 合同管理 服务实现类 * 合同管理 服务实现类
@@ -193,7 +192,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public boolean startChange(Long id, String changeContent, String changeReason) { public boolean startChange(Long id, String changeContent, String changeReason) {
ContractManage contractManage = loadExists(id); ContractManage contractManage = loadExists(id);
if (!Objects.equals(contractManage.getApprovalStatus(), STATUS_APPROVED) || !Objects.equals(contractManage.getContractStage(), STAGE_FORMAL)) { if (!Objects.equals(contractManage.getContractStage(), STAGE_FORMAL)
|| !List.of(STATUS_APPROVED, STATUS_CHANGE_APPROVED, STATUS_CHANGE_REJECTED).contains(contractManage.getApprovalStatus())) {
throw new ServiceException("仅正式合同允许发起变更"); throw new ServiceException("仅正式合同允许发起变更");
} }
contractManage.setApprovalStatus(STATUS_CHANGE_REVIEWING); contractManage.setApprovalStatus(STATUS_CHANGE_REVIEWING);
@@ -205,6 +205,19 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
return updateById(contractManage); return updateById(contractManage);
} }
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateAttachments(ContractManage contractManage) {
ContractManage source = loadExists(contractManage.getId());
if (!Objects.equals(source.getContractStage(), STAGE_FORMAL)
|| !List.of(STATUS_APPROVED, STATUS_CHANGE_APPROVED).contains(source.getApprovalStatus())) {
throw new ServiceException("仅审批通过的正式合同允许上传附件");
}
source.setContractFileJson(TransportBusinessSupport.trimToNull(contractManage.getContractFileJson()));
source.setAttachmentsJson(TransportBusinessSupport.trimToNull(contractManage.getAttachmentsJson()));
return updateById(source);
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public boolean terminate(Long id, String reason) { public boolean terminate(Long id, String reason) {
@@ -258,9 +271,17 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
@Override @Override
public Map<String, Long> expireStats(ContractManageVO contractManage) { public Map<String, Long> expireStats(ContractManageVO contractManage) {
List<ContractManage> contracts = list(buildQuery(contractManage)); List<ContractManage> contracts = list(buildQuery(contractManage));
return contracts.stream() Map<String, Long> stats = new LinkedHashMap<>();
stats.put("all", (long) contracts.size());
stats.put("within30", 0L);
stats.put("within90", 0L);
stats.put("over90", 0L);
stats.put("expired", 0L);
contracts.stream()
.filter(item -> item.getEndDate() != null) .filter(item -> item.getEndDate() != null)
.collect(Collectors.groupingBy(item -> expireScope(item.getEndDate()), Collectors.counting())); .map(item -> expireScope(item.getEndDate()))
.forEach(scope -> stats.computeIfPresent(scope, (key, count) -> count + 1));
return stats;
} }
@Override @Override
@@ -298,9 +319,58 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
.eq(Func.isNotEmpty(contractManage.getApprovalStatus()), ContractManage::getApprovalStatus, contractManage.getApprovalStatus()) .eq(Func.isNotEmpty(contractManage.getApprovalStatus()), ContractManage::getApprovalStatus, contractManage.getApprovalStatus())
.eq(Func.isNotEmpty(contractManage.getContractStage()), ContractManage::getContractStage, contractManage.getContractStage()) .eq(Func.isNotEmpty(contractManage.getContractStage()), ContractManage::getContractStage, contractManage.getContractStage())
.orderByDesc(ContractManage::getCreateTime); .orderByDesc(ContractManage::getCreateTime);
applyEffectiveType(queryWrapper, contractManage.getEffectiveType());
applyExpireScope(queryWrapper, contractManage.getExpireScope());
return queryWrapper; return queryWrapper;
} }
private void applyEffectiveType(LambdaQueryWrapper<ContractManage> queryWrapper, String effectiveType) {
if (Func.isEmpty(effectiveType)) {
return;
}
LocalDate today = LocalDate.now();
switch (effectiveType) {
case "not_effective" -> queryWrapper.and(wrapper -> wrapper
.notIn(ContractManage::getApprovalStatus, STATUS_APPROVED, STATUS_CHANGE_APPROVED)
.or(item -> item.eq(ContractManage::getContractStage, STAGE_TEMPORARY)
.gt(ContractManage::getTemporaryStartDate, today))
.or(item -> item.ne(ContractManage::getContractStage, STAGE_TEMPORARY)
.gt(ContractManage::getStartDate, today)));
case "temporary_effective" -> queryWrapper.eq(ContractManage::getContractStage, STAGE_TEMPORARY)
.in(ContractManage::getApprovalStatus, STATUS_APPROVED, STATUS_CHANGE_APPROVED)
.and(wrapper -> wrapper.isNull(ContractManage::getTemporaryStartDate)
.or().le(ContractManage::getTemporaryStartDate, today))
.and(wrapper -> wrapper.isNull(ContractManage::getTemporaryEndDate)
.or().ge(ContractManage::getTemporaryEndDate, today));
case "formal_effective" -> queryWrapper.eq(ContractManage::getContractStage, STAGE_FORMAL)
.in(ContractManage::getApprovalStatus, STATUS_APPROVED, STATUS_CHANGE_APPROVED)
.and(wrapper -> wrapper.isNull(ContractManage::getStartDate)
.or().le(ContractManage::getStartDate, today))
.and(wrapper -> wrapper.isNull(ContractManage::getEndDate)
.or().ge(ContractManage::getEndDate, today));
case "expired" -> queryWrapper.in(ContractManage::getApprovalStatus, STATUS_APPROVED, STATUS_CHANGE_APPROVED)
.and(wrapper -> wrapper.eq(ContractManage::getContractStage, STAGE_TEMPORARY)
.lt(ContractManage::getTemporaryEndDate, today)
.or(wrapper2 -> wrapper2.ne(ContractManage::getContractStage, STAGE_TEMPORARY)
.lt(ContractManage::getEndDate, today)));
default -> throw new ServiceException("无效的生效类型筛选条件");
}
}
private void applyExpireScope(LambdaQueryWrapper<ContractManage> queryWrapper, String expireScope) {
if (Func.isEmpty(expireScope)) {
return;
}
LocalDate today = LocalDate.now();
switch (expireScope) {
case "within30" -> queryWrapper.ge(ContractManage::getEndDate, today).le(ContractManage::getEndDate, today.plusDays(30));
case "within90" -> queryWrapper.gt(ContractManage::getEndDate, today.plusDays(30)).le(ContractManage::getEndDate, today.plusDays(90));
case "over90" -> queryWrapper.gt(ContractManage::getEndDate, today.plusDays(90));
case "expired" -> queryWrapper.lt(ContractManage::getEndDate, today);
default -> throw new ServiceException("无效的到期筛选条件");
}
}
private void prepareCreateOrUpdate(ContractManage contractManage) { private void prepareCreateOrUpdate(ContractManage contractManage) {
if (Func.isEmpty(contractManage.getId())) { if (Func.isEmpty(contractManage.getId())) {
if (Func.isEmpty(contractManage.getContractNo())) { if (Func.isEmpty(contractManage.getContractNo())) {
@@ -346,14 +416,35 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
contractManage.setSettlementRuleJson(TransportBusinessSupport.trimToNull(contractManage.getSettlementRuleJson())); contractManage.setSettlementRuleJson(TransportBusinessSupport.trimToNull(contractManage.getSettlementRuleJson()));
contractManage.setReconciliationJson(TransportBusinessSupport.trimToNull(contractManage.getReconciliationJson())); contractManage.setReconciliationJson(TransportBusinessSupport.trimToNull(contractManage.getReconciliationJson()));
contractManage.setChangeRecordJson(TransportBusinessSupport.trimToNull(contractManage.getChangeRecordJson())); contractManage.setChangeRecordJson(TransportBusinessSupport.trimToNull(contractManage.getChangeRecordJson()));
normalizeOptionalIntegerFields(contractManage);
}
private void normalizeOptionalIntegerFields(ContractManage contractManage) {
if (contractManage.getCopyCount() != null && contractManage.getCopyCount() < 0) {
contractManage.setCopyCount(null);
}
if (contractManage.getPaymentDays() != null && contractManage.getPaymentDays() < 0) {
contractManage.setPaymentDays(null);
}
} }
private void validateDraft(ContractManage contractManage) { private void validateDraft(ContractManage contractManage) {
TransportBusinessSupport.validateRequired(contractManage.getContractName(), "请输入合同名称"); TransportBusinessSupport.validateRequired(contractManage.getContractName(), "请输入合同名称");
TransportBusinessSupport.validateRequired(contractManage.getContractCategory(), "请选择合同类别"); TransportBusinessSupport.validateRequired(contractManage.getContractCategory(), "请选择合同类别");
validateContractNameUnique(contractManage);
TransportBusinessSupport.validateLength(contractManage.getRemark(), 2000, "备注不能超过2000字"); TransportBusinessSupport.validateLength(contractManage.getRemark(), 2000, "备注不能超过2000字");
} }
private void validateContractNameUnique(ContractManage contractManage) {
Long count = count(Wrappers.<ContractManage>lambdaQuery()
.eq(ContractManage::getIsDeleted, 0)
.eq(ContractManage::getContractName, contractManage.getContractName())
.ne(Func.isNotEmpty(contractManage.getId()), ContractManage::getId, contractManage.getId()));
if (count > 0) {
throw new ServiceException("合同名称已存在");
}
}
private void validateTemporary(ContractManage contractManage) { private void validateTemporary(ContractManage contractManage) {
TransportBusinessSupport.validateRequired(contractManage.getSignType(), "请选择签约类型"); TransportBusinessSupport.validateRequired(contractManage.getSignType(), "请选择签约类型");
} }
@@ -447,18 +538,19 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
private String expireScope(LocalDate endDate) { private String expireScope(LocalDate endDate) {
long days = java.time.temporal.ChronoUnit.DAYS.between(LocalDate.now(), endDate); long days = java.time.temporal.ChronoUnit.DAYS.between(LocalDate.now(), endDate);
if (days < 0) { if (days < 0) {
return "已到期"; return "expired";
} }
if (days <= 30) { if (days <= 30) {
return "30天内到期"; return "within30";
} }
if (days <= 90) { if (days <= 90) {
return "90天内到期"; return "within90";
} }
return "90天以上"; return "over90";
} }
private void fillReadonly(ContractManageVO contractManageVO) { private void fillReadonly(ContractManageVO contractManageVO) {
normalizeOptionalIntegerFields(contractManageVO);
contractManageVO.setReadonly(!canOperateInCurrentScope(contractManageVO)); contractManageVO.setReadonly(!canOperateInCurrentScope(contractManageVO));
} }

View File

@@ -276,6 +276,8 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
customer.setUnifiedCreditCode(trimToEmpty(customer.getUnifiedCreditCode())); customer.setUnifiedCreditCode(trimToEmpty(customer.getUnifiedCreditCode()));
customer.setCustomerType(trimToEmpty(customer.getCustomerType())); customer.setCustomerType(trimToEmpty(customer.getCustomerType()));
customer.setBusinessScope(trimToNull(customer.getBusinessScope())); customer.setBusinessScope(trimToNull(customer.getBusinessScope()));
customer.setInvoiceTaxRate(normalizeSentinelAmount(customer.getInvoiceTaxRate()));
customer.setRegisteredCapital(normalizeSentinelAmount(customer.getRegisteredCapital()));
customer.setRegisteredRegionName(trimToNull(customer.getRegisteredRegionName())); customer.setRegisteredRegionName(trimToNull(customer.getRegisteredRegionName()));
customer.setRegisteredDetailAddress(trimToNull(customer.getRegisteredDetailAddress())); customer.setRegisteredDetailAddress(trimToNull(customer.getRegisteredDetailAddress()));
customer.setRegisteredAddress(buildRegisteredAddress(customer)); customer.setRegisteredAddress(buildRegisteredAddress(customer));
@@ -383,11 +385,14 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
} }
private void replaceDetail(Long customerId, CustomerArchiveVO customer) { private void replaceDetail(Long customerId, CustomerArchiveVO customer) {
deleteDetail(List.of(customerId)); deleteDetail(List.of(customerId), false);
insertContacts(customerId, customer.getContacts()); insertContacts(customerId, customer.getContacts());
insertReceiptAccounts(customerId, customer.getReceiptAccounts()); insertReceiptAccounts(customerId, customer.getReceiptAccounts());
insertInvoices(customerId, customer.getInvoices()); insertInvoices(customerId, customer.getInvoices());
insertScores(customerId, customer.getScores()); if (Func.isNotEmpty(customer.getScores())) {
deleteScores(List.of(customerId));
insertScores(customerId, customer.getScores());
}
} }
private void insertContacts(Long customerId, List<CustomerContactVO> contacts) { private void insertContacts(Long customerId, List<CustomerContactVO> contacts) {
@@ -437,11 +442,14 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
continue; continue;
} }
Long scoreId = IdWorker.getId(); Long scoreId = IdWorker.getId();
scoreVO.setTempApplyCreditLimit(normalizeOptionalScoreAmount(scoreVO.getTempApplyCreditLimit()));
scoreVO.setProofAttachments(normalizeScoreProofAttachments(scoreVO)); scoreVO.setProofAttachments(normalizeScoreProofAttachments(scoreVO));
CustomerCreditScore score = Objects.requireNonNull(BeanUtil.copyProperties(scoreVO, CustomerCreditScore.class)); CustomerCreditScore score = Objects.requireNonNull(BeanUtil.copyProperties(scoreVO, CustomerCreditScore.class));
score.setId(scoreId); score.setId(scoreId);
score.setCustomerId(customerId); score.setCustomerId(customerId);
score.setTenantId(AuthUtil.getTenantId());
score.setStatus(STATUS_ENABLED); score.setStatus(STATUS_ENABLED);
score.setIsDeleted(0);
creditScoreMapper.insert(score); creditScoreMapper.insert(score);
List<CustomerCreditScoreDetailVO> details = scoreVO.getDetails() == null ? new ArrayList<>() : scoreVO.getDetails(); List<CustomerCreditScoreDetailVO> details = scoreVO.getDetails() == null ? new ArrayList<>() : scoreVO.getDetails();
for (int detailIndex = 0; detailIndex < details.size(); detailIndex++) { for (int detailIndex = 0; detailIndex < details.size(); detailIndex++) {
@@ -455,16 +463,29 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
detail.setQuantificationId(score.getQuantificationId()); detail.setQuantificationId(score.getQuantificationId());
detail.setSort(detailIndex + 1); detail.setSort(detailIndex + 1);
detail.setStatus(STATUS_ENABLED); detail.setStatus(STATUS_ENABLED);
detail.setIsDeleted(0);
creditScoreDetailMapper.insert(detail); creditScoreDetailMapper.insert(detail);
} }
} }
} }
private void deleteDetail(List<Long> customerIds) { private void deleteDetail(List<Long> customerIds) {
deleteDetail(customerIds, true);
}
private void deleteDetail(List<Long> customerIds, boolean deleteScores) {
contactMapper.update(null, Wrappers.<CustomerContact>lambdaUpdate().in(CustomerContact::getCustomerId, customerIds).set(CustomerContact::getIsDeleted, 1)); contactMapper.update(null, Wrappers.<CustomerContact>lambdaUpdate().in(CustomerContact::getCustomerId, customerIds).set(CustomerContact::getIsDeleted, 1));
receiptAccountMapper.update(null, Wrappers.<CustomerReceiptAccount>lambdaUpdate().in(CustomerReceiptAccount::getCustomerId, customerIds).set(CustomerReceiptAccount::getIsDeleted, 1)); receiptAccountMapper.update(null, Wrappers.<CustomerReceiptAccount>lambdaUpdate().in(CustomerReceiptAccount::getCustomerId, customerIds).set(CustomerReceiptAccount::getIsDeleted, 1));
invoiceInfoMapper.update(null, Wrappers.<CustomerInvoiceInfo>lambdaUpdate().in(CustomerInvoiceInfo::getCustomerId, customerIds).set(CustomerInvoiceInfo::getIsDeleted, 1)); invoiceInfoMapper.update(null, Wrappers.<CustomerInvoiceInfo>lambdaUpdate().in(CustomerInvoiceInfo::getCustomerId, customerIds).set(CustomerInvoiceInfo::getIsDeleted, 1));
List<CustomerCreditScore> scores = creditScoreMapper.selectList(Wrappers.<CustomerCreditScore>lambdaQuery().in(CustomerCreditScore::getCustomerId, customerIds).eq(CustomerCreditScore::getIsDeleted, 0)); if (deleteScores) {
deleteScores(customerIds);
}
}
private void deleteScores(List<Long> customerIds) {
List<CustomerCreditScore> scores = creditScoreMapper.selectList(Wrappers.<CustomerCreditScore>lambdaQuery()
.in(CustomerCreditScore::getCustomerId, customerIds)
.and(wrapper -> wrapper.ne(CustomerCreditScore::getIsDeleted, 1).or().isNull(CustomerCreditScore::getIsDeleted)));
if (Func.isNotEmpty(scores)) { if (Func.isNotEmpty(scores)) {
List<Long> scoreIds = scores.stream().map(CustomerCreditScore::getId).toList(); List<Long> scoreIds = scores.stream().map(CustomerCreditScore::getId).toList();
creditScoreDetailMapper.update(null, Wrappers.<CustomerCreditScoreDetail>lambdaUpdate().in(CustomerCreditScoreDetail::getScoreId, scoreIds).set(CustomerCreditScoreDetail::getIsDeleted, 1)); creditScoreDetailMapper.update(null, Wrappers.<CustomerCreditScoreDetail>lambdaUpdate().in(CustomerCreditScoreDetail::getScoreId, scoreIds).set(CustomerCreditScoreDetail::getIsDeleted, 1));
@@ -502,7 +523,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
private List<CustomerCreditScoreVO> loadScores(Long customerId) { private List<CustomerCreditScoreVO> loadScores(Long customerId) {
List<CustomerCreditScore> scores = creditScoreMapper.selectList(Wrappers.<CustomerCreditScore>lambdaQuery() List<CustomerCreditScore> scores = creditScoreMapper.selectList(Wrappers.<CustomerCreditScore>lambdaQuery()
.eq(CustomerCreditScore::getCustomerId, customerId) .eq(CustomerCreditScore::getCustomerId, customerId)
.and(wrapper -> wrapper.eq(CustomerCreditScore::getIsDeleted, 0).or().isNull(CustomerCreditScore::getIsDeleted)) .and(wrapper -> wrapper.ne(CustomerCreditScore::getIsDeleted, 1).or().isNull(CustomerCreditScore::getIsDeleted))
.orderByDesc(CustomerCreditScore::getScoreDate) .orderByDesc(CustomerCreditScore::getScoreDate)
.orderByDesc(CustomerCreditScore::getCreateTime)); .orderByDesc(CustomerCreditScore::getCreateTime));
if (Func.isEmpty(scores)) { if (Func.isEmpty(scores)) {
@@ -511,7 +532,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
List<Long> scoreIds = scores.stream().map(CustomerCreditScore::getId).toList(); List<Long> scoreIds = scores.stream().map(CustomerCreditScore::getId).toList();
Map<Long, List<CustomerCreditScoreDetailVO>> detailMap = creditScoreDetailMapper.selectList(Wrappers.<CustomerCreditScoreDetail>lambdaQuery() Map<Long, List<CustomerCreditScoreDetailVO>> detailMap = creditScoreDetailMapper.selectList(Wrappers.<CustomerCreditScoreDetail>lambdaQuery()
.in(CustomerCreditScoreDetail::getScoreId, scoreIds) .in(CustomerCreditScoreDetail::getScoreId, scoreIds)
.and(wrapper -> wrapper.eq(CustomerCreditScoreDetail::getIsDeleted, 0).or().isNull(CustomerCreditScoreDetail::getIsDeleted)) .and(wrapper -> wrapper.ne(CustomerCreditScoreDetail::getIsDeleted, 1).or().isNull(CustomerCreditScoreDetail::getIsDeleted))
.orderByAsc(CustomerCreditScoreDetail::getSort)) .orderByAsc(CustomerCreditScoreDetail::getSort))
.stream() .stream()
.map(detail -> Objects.requireNonNull(BeanUtil.copyProperties(detail, CustomerCreditScoreDetailVO.class))) .map(detail -> Objects.requireNonNull(BeanUtil.copyProperties(detail, CustomerCreditScoreDetailVO.class)))
@@ -539,6 +560,14 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
return JsonUtil.toJson(attachments); return JsonUtil.toJson(attachments);
} }
private BigDecimal normalizeOptionalScoreAmount(BigDecimal value) {
return value != null && value.compareTo(BigDecimal.ZERO) < 0 ? null : value;
}
private BigDecimal normalizeSentinelAmount(BigDecimal value) {
return value != null && value.compareTo(BigDecimal.ONE.negate()) == 0 ? null : value;
}
private Object parseScoreAttachments(String value) { private Object parseScoreAttachments(String value) {
if (Func.isEmpty(value)) { if (Func.isEmpty(value)) {
return new ArrayList<>(); return new ArrayList<>();

View File

@@ -83,6 +83,7 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
@Override @Override
public ProjectApplyVO detail(Long id) { public ProjectApplyVO detail(Long id) {
ProjectApplyVO projectApplyVO = ProjectApplyWrapper.build().entityVO(loadExists(id)); ProjectApplyVO projectApplyVO = ProjectApplyWrapper.build().entityVO(loadExists(id));
normalizeOptionalAmounts(projectApplyVO);
fillReadonly(projectApplyVO); fillReadonly(projectApplyVO);
return projectApplyVO; return projectApplyVO;
} }
@@ -91,7 +92,6 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public boolean saveDraft(ProjectApply projectApply) { public boolean saveDraft(ProjectApply projectApply) {
prepare(projectApply); prepare(projectApply);
validateDraft(projectApply);
if (Func.isNotEmpty(projectApply.getId())) { if (Func.isNotEmpty(projectApply.getId())) {
loadEditable(projectApply.getId(), true); loadEditable(projectApply.getId(), true);
} }
@@ -109,9 +109,9 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
loadEditable(projectApply.getId(), true); loadEditable(projectApply.getId(), true);
} }
prepareCreateOrUpdate(projectApply); prepareCreateOrUpdate(projectApply);
if (Func.isEmpty(projectApply.getApprovalStatus())) { projectApply.setApprovalStatus(STATUS_REVIEWING);
projectApply.setApprovalStatus(STATUS_DRAFT); projectApply.setCurrentNode(resolveApprovalNode(projectApply));
} projectApply.setCurrentProcessor("待处理");
return saveOrUpdate(projectApply); return saveOrUpdate(projectApply);
} }
@@ -279,6 +279,10 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
.eq(Func.isNotEmpty(projectApply.getApprovalStatus()), ProjectApply::getApprovalStatus, projectApply.getApprovalStatus()) .eq(Func.isNotEmpty(projectApply.getApprovalStatus()), ProjectApply::getApprovalStatus, projectApply.getApprovalStatus())
.eq(Func.isNotEmpty(projectApply.getEffectiveType()), ProjectApply::getEffectiveType, projectApply.getEffectiveType()) .eq(Func.isNotEmpty(projectApply.getEffectiveType()), ProjectApply::getEffectiveType, projectApply.getEffectiveType())
.orderByDesc(ProjectApply::getCreateTime); .orderByDesc(ProjectApply::getCreateTime);
if (Boolean.TRUE.equals(projectApply.getTemporaryCreditLimitSelectable())) {
queryWrapper.eq(ProjectApply::getEffectiveType, EFFECTIVE_FORMAL)
.in(ProjectApply::getApprovalStatus, STATUS_APPROVED, "change_approved");
}
return queryWrapper; return queryWrapper;
} }
@@ -332,6 +336,7 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
projectApply.setTransportRoute(TransportBusinessSupport.trimToNull(projectApply.getTransportRoute())); projectApply.setTransportRoute(TransportBusinessSupport.trimToNull(projectApply.getTransportRoute()));
projectApply.setTransportType(TransportBusinessSupport.trimToNull(projectApply.getTransportType())); projectApply.setTransportType(TransportBusinessSupport.trimToNull(projectApply.getTransportType()));
projectApply.setBusinessType(TransportBusinessSupport.trimToNull(projectApply.getBusinessType())); projectApply.setBusinessType(TransportBusinessSupport.trimToNull(projectApply.getBusinessType()));
normalizeOptionalAmounts(projectApply);
projectApply.setSettlementMode(TransportBusinessSupport.trimToNull(projectApply.getSettlementMode())); projectApply.setSettlementMode(TransportBusinessSupport.trimToNull(projectApply.getSettlementMode()));
projectApply.setHandlerUserName(TransportBusinessSupport.trimToNull(projectApply.getHandlerUserName())); projectApply.setHandlerUserName(TransportBusinessSupport.trimToNull(projectApply.getHandlerUserName()));
projectApply.setPrincipalUserName(TransportBusinessSupport.trimToNull(projectApply.getPrincipalUserName())); projectApply.setPrincipalUserName(TransportBusinessSupport.trimToNull(projectApply.getPrincipalUserName()));
@@ -340,6 +345,18 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
projectApply.setSituationRemark(TransportBusinessSupport.trimToNull(projectApply.getSituationRemark())); projectApply.setSituationRemark(TransportBusinessSupport.trimToNull(projectApply.getSituationRemark()));
} }
private void normalizeOptionalAmounts(ProjectApply projectApply) {
if (projectApply.getProjectScale() != null && projectApply.getProjectScale().signum() < 0) {
projectApply.setProjectScale(null);
}
if (projectApply.getEstimatedProfit() != null && projectApply.getEstimatedProfit().signum() < 0) {
projectApply.setEstimatedProfit(null);
}
if (projectApply.getFundDemand() != null && projectApply.getFundDemand().signum() < 0) {
projectApply.setFundDemand(null);
}
}
private void copyChangeFields(ProjectApply target, ProjectApply source) { private void copyChangeFields(ProjectApply target, ProjectApply source) {
target.setFundLimit(source.getFundLimit()); target.setFundLimit(source.getFundLimit());
target.setReceivableLimit(source.getReceivableLimit()); target.setReceivableLimit(source.getReceivableLimit());

View File

@@ -101,6 +101,9 @@ public class TemporaryCreditLimitServiceImpl extends BaseServiceImpl<TemporaryCr
loadEditable(temporaryCreditLimit.getId()); loadEditable(temporaryCreditLimit.getId());
} }
prepareCreateOrUpdate(temporaryCreditLimit); prepareCreateOrUpdate(temporaryCreditLimit);
temporaryCreditLimit.setApprovalStatus(STATUS_REVIEWING);
temporaryCreditLimit.setCurrentNode("临时额度审批");
temporaryCreditLimit.setCurrentProcessor("待处理");
return saveOrUpdate(temporaryCreditLimit); return saveOrUpdate(temporaryCreditLimit);
} }

View File

@@ -0,0 +1,17 @@
-- 客商评分记录逻辑删除字段修复
-- 将历史默认值 -1 统一为正常未删除状态 0避免评分记录被查询过滤。
ALTER TABLE `blade_customer_credit_score`
MODIFY COLUMN `is_deleted` int NULL DEFAULT 0 COMMENT '是否已删除';
ALTER TABLE `blade_customer_credit_score_detail`
MODIFY COLUMN `is_deleted` int NULL DEFAULT 0 COMMENT '是否已删除';
-- 修复历史记录:-1 并非逻辑删除标识,应作为未删除数据保留。
UPDATE `blade_customer_credit_score`
SET `is_deleted` = 0
WHERE `is_deleted` = -1;
UPDATE `blade_customer_credit_score_detail`
SET `is_deleted` = 0
WHERE `is_deleted` = -1;