✨ 新增项目预付核销,并修复平台公司多选、常用线路组织过滤与登录 IP 连坐锁
结算附件支持项目预付核销并扣减可付款金额;加固项目平台公司多选字段扩容脚本;常用线路新增归属组织与列表筛选对齐;登录失败仅按账号锁定,取消 IP 级连坐。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+8
-7
@@ -84,16 +84,11 @@ public class BladeAuthorizationHandler extends AbstractAuthorizationHandler {
|
||||
if (bladeProperties.isProd() && isWeakPassword(request.getPassword())) {
|
||||
return buildValidationFailure(ExceptionCode.INVALID_USER_PASSWORD);
|
||||
}
|
||||
// 判断账号是否锁定
|
||||
// 仅按账号锁定;不做 IP 锁定,避免同出口/网关 IP 下一人失败牵连全部未登录用户
|
||||
OAuth2Validation accountValidation = lockHandler.validateAccountLock(request.getTenantId(), request.getUsername());
|
||||
if (!accountValidation.isSuccess()) {
|
||||
return accountValidation;
|
||||
}
|
||||
// 判断IP是否锁定
|
||||
OAuth2Validation ipValidation = lockHandler.validateIpLock(request.getTenantId());
|
||||
if (!ipValidation.isSuccess()) {
|
||||
return ipValidation;
|
||||
}
|
||||
}
|
||||
return super.preValidation(request);
|
||||
}
|
||||
@@ -105,7 +100,13 @@ public class BladeAuthorizationHandler extends AbstractAuthorizationHandler {
|
||||
*/
|
||||
@Override
|
||||
public void preFailure(OAuth2Request request, OAuth2Validation validation) {
|
||||
// 处理认证失败,增加错误次数
|
||||
// 已因锁定失败时不再累加失败次数,避免其他账号重试时被误计并连带锁定
|
||||
if (validation != null && !validation.isSuccess()
|
||||
&& ExceptionCode.USER_TOO_MANY_FAILS.getCode() == validation.getCode()) {
|
||||
log.error("用户:{},认证失败,失败原因:{}", request.getUsername(), validation.getMessage());
|
||||
return;
|
||||
}
|
||||
// 处理认证失败,增加错误次数(仅账号维度)
|
||||
lockHandler.handleAuthFailure(request.getTenantId(), request.getUsername());
|
||||
|
||||
log.error("用户:{},认证失败,失败原因:{}", request.getUsername(), validation.getMessage());
|
||||
|
||||
@@ -90,7 +90,7 @@ public class BladeLockHandler {
|
||||
|
||||
/**
|
||||
* 处理认证失败
|
||||
* 同时增加账号和IP错误次数
|
||||
* 仅增加账号错误次数;不再累计 IP 失败次数,避免共享出口 IP 误伤其他用户。
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
* @param account 账号
|
||||
@@ -102,7 +102,6 @@ public class BladeLockHandler {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
authLockClient.addAccountFailCount(tenantId, account, userId, ip, userAgent);
|
||||
authLockClient.addIpFailCount(tenantId, ip, userAgent);
|
||||
} catch (Exception e) {
|
||||
log.warn("认证失败计数异常: {}", e.getMessage());
|
||||
}
|
||||
|
||||
+2
@@ -32,6 +32,8 @@ public class FormalSettlementSaveRequest implements Serializable {
|
||||
private String remark;
|
||||
private List<SummaryFee> summaryFees;
|
||||
private List<Invoice> invoices;
|
||||
/** 项目预付核销 */
|
||||
private List<SettlementProjectAdvanceWriteOffRequest> projectAdvanceWriteOffs;
|
||||
|
||||
@Data
|
||||
public static class DetailAdjustment implements Serializable {
|
||||
|
||||
+3
@@ -76,6 +76,9 @@ public class PreSettlementSaveRequest implements Serializable {
|
||||
@Schema(description = "结算合计费用")
|
||||
private List<SummaryFee> summaryFees;
|
||||
|
||||
@Schema(description = "项目预付核销")
|
||||
private List<SettlementProjectAdvanceWriteOffRequest> projectAdvanceWriteOffs;
|
||||
|
||||
@Data
|
||||
@Schema(description = "结算合计费用")
|
||||
public static class SummaryFee implements Serializable {
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.pojo.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 结算单项目预付核销保存行
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "结算单项目预付核销保存行")
|
||||
public class SettlementProjectAdvanceWriteOffRequest implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "项目预付付款申请ID")
|
||||
private Long paymentApplicationId;
|
||||
|
||||
@Schema(description = "本次核销金额")
|
||||
private BigDecimal writeOffAmount;
|
||||
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springblade.core.tenant.mp.TenantEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 结算单项目预付核销实体类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("blade_settlement_project_advance_write_off")
|
||||
@Schema(description = "结算单项目预付核销")
|
||||
public class SettlementProjectAdvanceWriteOff extends TenantEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "结算单类型:pre/formal")
|
||||
private String settlementType;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "预结算/正式结算单ID")
|
||||
private Long settlementId;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "项目预付付款申请ID")
|
||||
private Long paymentApplicationId;
|
||||
|
||||
@Schema(description = "预付单号")
|
||||
private String paymentNo;
|
||||
|
||||
@Schema(description = "项目预付金额")
|
||||
private BigDecimal projectAdvanceAmount;
|
||||
|
||||
@Schema(description = "本次核销金额")
|
||||
private BigDecimal writeOffAmount;
|
||||
|
||||
@Schema(description = "金蝶预付单号")
|
||||
private String kingdeeBillNo;
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "可核销金额(动态计算)")
|
||||
private BigDecimal availableWriteOffAmount;
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "预付单创建人姓名")
|
||||
private String createUserName;
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "预付单创建时间(展示用)")
|
||||
private Date paymentCreateTime;
|
||||
|
||||
}
|
||||
+3
@@ -20,6 +20,7 @@ import org.springblade.transport.pojo.entity.FormalSettlementSource;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementPayment;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementSummaryFee;
|
||||
import org.springblade.transport.pojo.entity.InvoiceApplicationInvoice;
|
||||
import org.springblade.transport.pojo.entity.SettlementProjectAdvanceWriteOff;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
@@ -64,6 +65,8 @@ public class FormalSettlementVO extends FormalSettlement implements KingdeeUnloc
|
||||
@TableField(exist = false) private List<FormalSettlementSummaryFee> summaryFees;
|
||||
@TableField(exist = false) private List<FormalSettlementPayment> payments;
|
||||
@TableField(exist = false) private List<FormalSettlementInvoice> invoices;
|
||||
@TableField(exist = false) @Schema(description = "项目预付核销")
|
||||
private List<SettlementProjectAdvanceWriteOff> projectAdvanceWriteOffs;
|
||||
@TableField(exist = false) @Schema(description = "开票申请经金蝶回写的发票结果(含文件地址,只读展示)")
|
||||
private List<InvoiceApplicationInvoice> issuedInvoices;
|
||||
@TableField(exist = false) private List<PaymentApplicationVO> paymentApplications;
|
||||
|
||||
+5
@@ -35,6 +35,7 @@ import org.springblade.transport.pojo.entity.PreSettlementChangeRecord;
|
||||
import org.springblade.transport.pojo.entity.PreSettlementDetail;
|
||||
import org.springblade.transport.pojo.entity.PreSettlementDetailFee;
|
||||
import org.springblade.transport.pojo.entity.PreSettlementSummaryFee;
|
||||
import org.springblade.transport.pojo.entity.SettlementProjectAdvanceWriteOff;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
@@ -100,6 +101,10 @@ public class PreSettlementVO extends PreSettlement {
|
||||
@Schema(description = "预付信息")
|
||||
private List<PreSettlementAdvance> advances;
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "项目预付核销")
|
||||
private List<SettlementProjectAdvanceWriteOff> projectAdvanceWriteOffs;
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "变更记录")
|
||||
private List<PreSettlementChangeRecord> changeRecords;
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 可选项目预付核销选项
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "可选项目预付核销选项")
|
||||
public class ProjectAdvanceWriteOffOptionVO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "付款申请ID")
|
||||
private Long paymentApplicationId;
|
||||
|
||||
@Schema(description = "预付单号")
|
||||
private String paymentNo;
|
||||
|
||||
@Schema(description = "项目预付金额")
|
||||
private BigDecimal projectAdvanceAmount;
|
||||
|
||||
@Schema(description = "可核销金额")
|
||||
private BigDecimal availableWriteOffAmount;
|
||||
|
||||
@Schema(description = "金蝶预付单号")
|
||||
private String kingdeeBillNo;
|
||||
|
||||
@Schema(description = "创建人姓名")
|
||||
private String createUserName;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
}
|
||||
+12
@@ -31,9 +31,21 @@ package org.springblade.transport.constant;
|
||||
*/
|
||||
public final class TransportBusiConstant {
|
||||
|
||||
/** 付款类型:项目预付。 */
|
||||
public static final String PAYMENT_TYPE_PROJECT_ADVANCE = "project_advance";
|
||||
|
||||
/** 付款类型:进度预付。 */
|
||||
public static final String PAYMENT_TYPE_PROGRESS_ADVANCE = "progress_advance";
|
||||
|
||||
/** 付款类型:结算付款(关联正式结算单的正式付款)。 */
|
||||
public static final String PAYMENT_TYPE_SETTLEMENT = "settlement_payment";
|
||||
|
||||
/** 结算单类型:预结算。 */
|
||||
public static final String SETTLEMENT_BILL_PRE = "pre";
|
||||
|
||||
/** 结算单类型:正式结算。 */
|
||||
public static final String SETTLEMENT_BILL_FORMAL = "formal";
|
||||
|
||||
/** 审批状态:草稿(允许编辑、删除)。 */
|
||||
public static final String DRAFT = "draft";
|
||||
|
||||
|
||||
+12
@@ -34,6 +34,7 @@ import org.springblade.transport.pojo.dto.PaymentApplicationSaveRequest;
|
||||
import org.springblade.transport.pojo.dto.PaymentApplicationStatusRequest;
|
||||
import org.springblade.transport.pojo.vo.PaymentApplicationReferenceAmountVO;
|
||||
import org.springblade.transport.pojo.vo.PaymentApplicationVO;
|
||||
import org.springblade.transport.pojo.vo.ProjectAdvanceWriteOffOptionVO;
|
||||
import org.springblade.transport.service.IPaymentApplicationService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -67,6 +68,17 @@ public class PaymentApplicationController extends BladeController {
|
||||
@RequestParam Long referenceId, @RequestParam(required = false) Long excludeId) {
|
||||
return R.data(paymentApplicationService.referenceAmount(paymentType, referenceId, excludeId));
|
||||
}
|
||||
|
||||
@GetMapping("/project-advance-write-off-options")
|
||||
@ApiOperationSupport(order = 3)
|
||||
@Operation(summary = "按合同查询可选项目预付核销列表")
|
||||
public R<List<ProjectAdvanceWriteOffOptionVO>> projectAdvanceWriteOffOptions(
|
||||
@RequestParam Long contractId,
|
||||
@RequestParam(required = false) String excludeSettlementType,
|
||||
@RequestParam(required = false) Long excludeSettlementId) {
|
||||
return R.data(paymentApplicationService.projectAdvanceWriteOffOptions(
|
||||
contractId, excludeSettlementType, excludeSettlementId));
|
||||
}
|
||||
@PostMapping("/save")
|
||||
@ApiOperationSupport(order = 4)
|
||||
@Operation(summary = "保存付款申请")
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springblade.transport.pojo.entity.SettlementProjectAdvanceWriteOff;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 结算单项目预付核销 Mapper
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Mapper
|
||||
public interface SettlementProjectAdvanceWriteOffMapper extends BaseMapper<SettlementProjectAdvanceWriteOff> {
|
||||
|
||||
/**
|
||||
* 统计项目预付已核销金额(排除作废结算单,可排除当前结算单)。
|
||||
*/
|
||||
BigDecimal sumWriteOffByPaymentApplication(@Param("paymentApplicationId") Long paymentApplicationId,
|
||||
@Param("excludeSettlementType") String excludeSettlementType,
|
||||
@Param("excludeSettlementId") Long excludeSettlementId);
|
||||
|
||||
/**
|
||||
* 统计结算单核销合计。
|
||||
*/
|
||||
BigDecimal sumWriteOffBySettlement(@Param("settlementType") String settlementType,
|
||||
@Param("settlementId") Long settlementId);
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.springblade.transport.mapper.SettlementProjectAdvanceWriteOffMapper">
|
||||
|
||||
<select id="sumWriteOffByPaymentApplication" resultType="java.math.BigDecimal">
|
||||
SELECT COALESCE(SUM(w.write_off_amount), 0)
|
||||
FROM blade_settlement_project_advance_write_off w
|
||||
LEFT JOIN blade_pre_settlement p
|
||||
ON w.settlement_type = 'pre'
|
||||
AND w.settlement_id = p.id
|
||||
AND p.is_deleted = 0
|
||||
LEFT JOIN blade_formal_settlement f
|
||||
ON w.settlement_type = 'formal'
|
||||
AND w.settlement_id = f.id
|
||||
AND f.is_deleted = 0
|
||||
WHERE w.is_deleted = 0
|
||||
AND w.payment_application_id = #{paymentApplicationId}
|
||||
AND (
|
||||
(w.settlement_type = 'pre' AND p.id IS NOT NULL AND IFNULL(p.approval_status, '') <> 'voided')
|
||||
OR (w.settlement_type = 'formal' AND f.id IS NOT NULL AND IFNULL(f.approval_status, '') <> 'voided')
|
||||
)
|
||||
<if test="excludeSettlementType != null and excludeSettlementId != null">
|
||||
AND NOT (w.settlement_type = #{excludeSettlementType} AND w.settlement_id = #{excludeSettlementId})
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="sumWriteOffBySettlement" resultType="java.math.BigDecimal">
|
||||
SELECT COALESCE(SUM(write_off_amount), 0)
|
||||
FROM blade_settlement_project_advance_write_off
|
||||
WHERE is_deleted = 0
|
||||
AND settlement_type = #{settlementType}
|
||||
AND settlement_id = #{settlementId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
+6
@@ -28,6 +28,7 @@ import org.springblade.transport.pojo.dto.PaymentApplicationStatusRequest;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplication;
|
||||
import org.springblade.transport.pojo.vo.PaymentApplicationReferenceAmountVO;
|
||||
import org.springblade.transport.pojo.vo.PaymentApplicationVO;
|
||||
import org.springblade.transport.pojo.vo.ProjectAdvanceWriteOffOptionVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -36,6 +37,11 @@ public interface IPaymentApplicationService extends BaseService<PaymentApplicati
|
||||
IPage<PaymentApplicationVO> selectPage(IPage<PaymentApplication> page, PaymentApplicationVO query);
|
||||
PaymentApplicationVO detail(Long id);
|
||||
PaymentApplicationReferenceAmountVO referenceAmount(String paymentType, Long referenceId, Long excludeId);
|
||||
|
||||
/** 按合同查询可选项目预付核销列表。 */
|
||||
List<ProjectAdvanceWriteOffOptionVO> projectAdvanceWriteOffOptions(Long contractId,
|
||||
String excludeSettlementType,
|
||||
Long excludeSettlementId);
|
||||
Long saveDraft(PaymentApplicationSaveRequest request);
|
||||
void removeDraft(Long id);
|
||||
void submit(PaymentApplicationStatusRequest request);
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.service;
|
||||
|
||||
import org.springblade.transport.pojo.dto.SettlementProjectAdvanceWriteOffRequest;
|
||||
import org.springblade.transport.pojo.entity.SettlementProjectAdvanceWriteOff;
|
||||
import org.springblade.transport.pojo.vo.ProjectAdvanceWriteOffOptionVO;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 结算单项目预付核销服务
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface ISettlementProjectAdvanceWriteOffService {
|
||||
|
||||
/**
|
||||
* 按合同查询可选项目预付(审批通过且仍有可核销余额)。
|
||||
*/
|
||||
List<ProjectAdvanceWriteOffOptionVO> listOptions(Long contractId, String excludeSettlementType,
|
||||
Long excludeSettlementId);
|
||||
|
||||
/**
|
||||
* 查询结算单已保存的核销明细(含动态可核销金额)。
|
||||
*/
|
||||
List<SettlementProjectAdvanceWriteOff> listBySettlement(String settlementType, Long settlementId);
|
||||
|
||||
/**
|
||||
* 结算单核销金额合计。
|
||||
*/
|
||||
BigDecimal sumBySettlement(String settlementType, Long settlementId);
|
||||
|
||||
/**
|
||||
* 覆盖保存核销明细,并校验不超过可核销金额与结算单金额。
|
||||
*/
|
||||
void replaceWriteOffs(String settlementType, Long settlementId, Long contractId,
|
||||
BigDecimal settlementAmount, List<SettlementProjectAdvanceWriteOffRequest> writeOffs);
|
||||
|
||||
/**
|
||||
* 物理清理结算单核销明细(草稿删除时)。
|
||||
*/
|
||||
void deleteBySettlement(String settlementType, Long settlementId);
|
||||
|
||||
}
|
||||
+23
-2
@@ -30,6 +30,7 @@ import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||
import org.springblade.core.tool.utils.BeanUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.system.cache.SysCache;
|
||||
import org.springblade.system.cache.UserCache;
|
||||
import org.springblade.system.pojo.entity.Dept;
|
||||
import org.springblade.transport.excel.CommonRouteExportExcel;
|
||||
@@ -217,12 +218,32 @@ public class CommonRouteServiceImpl extends BaseServiceImpl<CommonRouteMapper, C
|
||||
commonRoute.setArrivalPhone(TransportBusinessSupport.trimToNull(commonRoute.getArrivalPhone()));
|
||||
commonRoute.setDeptName(TransportBusinessSupport.trimToNull(commonRoute.getDeptName()));
|
||||
commonRoute.setRemark(TransportBusinessSupport.trimToNull(commonRoute.getRemark()));
|
||||
if (Func.isEmpty(commonRoute.getDeptId())) {
|
||||
// 仅新增时绑定组织;编辑沿用原组织(submit 中已从旧记录写回)。
|
||||
if (Func.isEmpty(commonRoute.getId())) {
|
||||
bindDeptOnCreate(commonRoute);
|
||||
}
|
||||
if (commonRoute.getStatus() == null) { commonRoute.setStatus(1); }
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增绑定所属组织:普通用户始终落当前组织;超管可按入参组织保存,未传时回落当前组织。
|
||||
*/
|
||||
private void bindDeptOnCreate(CommonRoute commonRoute) {
|
||||
if (commonRoute == null) {
|
||||
return;
|
||||
}
|
||||
boolean administrator = TransportBusinessSupport.isAdministrator();
|
||||
if (!administrator || Func.isEmpty(commonRoute.getDeptId()) || commonRoute.getDeptId() <= 0) {
|
||||
Dept dept = TransportBusinessSupport.currentDept("常用线路");
|
||||
commonRoute.setDeptId(dept.getId());
|
||||
commonRoute.setDeptName(dept.getDeptName());
|
||||
return;
|
||||
}
|
||||
if (commonRoute.getStatus() == null) { commonRoute.setStatus(1); }
|
||||
Dept dept = SysCache.getDept(commonRoute.getDeptId());
|
||||
if (Func.isEmpty(dept)) {
|
||||
throw new ServiceException("所属组织不存在或已删除");
|
||||
}
|
||||
commonRoute.setDeptName(TransportBusinessSupport.trimToNull(dept.getDeptName()));
|
||||
}
|
||||
|
||||
private void validate(CommonRoute commonRoute) {
|
||||
|
||||
+11
@@ -88,6 +88,7 @@ import org.springblade.transport.service.IInvoiceReceiptService;
|
||||
import org.springblade.transport.service.IKingdeeBillLockService;
|
||||
import org.springblade.transport.service.IContractManageService;
|
||||
import org.springblade.transport.service.IPreSettlementService;
|
||||
import org.springblade.transport.service.ISettlementProjectAdvanceWriteOffService;
|
||||
import org.springblade.transport.service.IWaybillService;
|
||||
import org.springblade.transport.service.KingdeeSyncContext;
|
||||
import org.springblade.transport.support.KingdeeApBillSyncSupport;
|
||||
@@ -170,6 +171,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
private final SettlementAdjustmentMapper settlementAdjustmentMapper;
|
||||
private final IContractManageService contractManageService;
|
||||
private final IPreSettlementService preSettlementService;
|
||||
private final ISettlementProjectAdvanceWriteOffService projectAdvanceWriteOffService;
|
||||
private final IWaybillService waybillService;
|
||||
private final KingdeeApBillSyncSupport kingdeeApBillSyncSupport;
|
||||
private final KingdeeArBillSyncSupport kingdeeArBillSyncSupport;
|
||||
@@ -318,6 +320,8 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
.eq(FormalSettlementPayment::getFormalSettlementId, id).orderByDesc(FormalSettlementPayment::getCreateTime)));
|
||||
vo.setInvoices(listInvoices(settlement));
|
||||
vo.setIssuedInvoices(listIssuedInvoices(id));
|
||||
vo.setProjectAdvanceWriteOffs(projectAdvanceWriteOffService.listBySettlement(
|
||||
TransportBusiConstant.SETTLEMENT_BILL_FORMAL, id));
|
||||
Set<Long> relationApplicationIds = paymentApplicationSettlementMapper.selectList(
|
||||
Wrappers.<PaymentApplicationSettlement>lambdaQuery()
|
||||
.select(PaymentApplicationSettlement::getPaymentApplicationId)
|
||||
@@ -541,6 +545,12 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
applySummaryRequest(settlement.getId(), request.getSummaryFees());
|
||||
refreshSettlementAmount(settlement);
|
||||
rebuildInvoices(settlement, request.getInvoices());
|
||||
projectAdvanceWriteOffService.replaceWriteOffs(
|
||||
TransportBusiConstant.SETTLEMENT_BILL_FORMAL,
|
||||
settlement.getId(),
|
||||
settlement.getContractId(),
|
||||
settlement.getSettlementAmount(),
|
||||
request.getProjectAdvanceWriteOffs());
|
||||
if (!creating && !restoring) {
|
||||
saveChange(settlement.getId(), "结算单基本信息", null, "调整",
|
||||
"保存正式结算单" + settlement.getFormalSettlementNo(), request.getRemark());
|
||||
@@ -562,6 +572,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
.eq(FormalSettlementSummaryFee::getFormalSettlementId, id));
|
||||
invoiceMapper.delete(Wrappers.<FormalSettlementInvoice>lambdaQuery()
|
||||
.eq(FormalSettlementInvoice::getFormalSettlementId, id));
|
||||
projectAdvanceWriteOffService.deleteBySettlement(TransportBusiConstant.SETTLEMENT_BILL_FORMAL, id);
|
||||
changeRecordMapper.delete(Wrappers.<FormalSettlementChangeRecord>lambdaQuery()
|
||||
.eq(FormalSettlementChangeRecord::getFormalSettlementId, id));
|
||||
removeById(id);
|
||||
|
||||
+40
-9
@@ -98,7 +98,9 @@ import org.springblade.transport.pojo.vo.PaymentApplicationVO;
|
||||
import org.springblade.transport.service.IFormalSettlementService;
|
||||
import org.springblade.transport.service.IKingdeeBillLockService;
|
||||
import org.springblade.transport.service.IPaymentApplicationService;
|
||||
import org.springblade.transport.service.ISettlementProjectAdvanceWriteOffService;
|
||||
import org.springblade.transport.service.KingdeeSyncContext;
|
||||
import org.springblade.transport.pojo.vo.ProjectAdvanceWriteOffOptionVO;
|
||||
import org.springblade.transport.support.KingdeeApBillSyncSupport;
|
||||
import org.springblade.transport.support.KingdeeAttachmentSyncSupport;
|
||||
import org.springblade.transport.support.KingdeeSyncLockSupport;
|
||||
@@ -159,6 +161,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
private final BillLedgerUsageMapper billLedgerUsageMapper;
|
||||
private final TemporaryCreditLimitMapper temporaryCreditLimitMapper;
|
||||
private final IFormalSettlementService formalSettlementService;
|
||||
private final ISettlementProjectAdvanceWriteOffService projectAdvanceWriteOffService;
|
||||
private final IKingdeeBillLockService kingdeeBillLockService;
|
||||
private final IBfiService bfiService;
|
||||
private final KingdeeApBillSyncSupport kingdeeApBillSyncSupport;
|
||||
@@ -301,13 +304,24 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
BigDecimal cumulativeAppliedAmount = preSettlementReference
|
||||
? cumulativePreSettlementApplied(referenceId, excludeId)
|
||||
: cumulativeFormalSettlementApplied(referenceId, excludeId);
|
||||
BigDecimal writeOffAmount = preSettlementReference
|
||||
? projectAdvanceWriteOffService.sumBySettlement(TransportBusiConstant.SETTLEMENT_BILL_PRE, referenceId)
|
||||
: projectAdvanceWriteOffService.sumBySettlement(TransportBusiConstant.SETTLEMENT_BILL_FORMAL, referenceId);
|
||||
PaymentApplicationReferenceAmountVO amount = new PaymentApplicationReferenceAmountVO();
|
||||
amount.setSettlementAmount(settlementAmount);
|
||||
amount.setCumulativeAppliedAmount(cumulativeAppliedAmount);
|
||||
amount.setPayableAmount(settlementAmount.subtract(cumulativeAppliedAmount));
|
||||
amount.setCumulativeAppliedAmount(cumulativeAppliedAmount.add(writeOffAmount));
|
||||
amount.setPayableAmount(settlementAmount.subtract(cumulativeAppliedAmount).subtract(writeOffAmount)
|
||||
.max(BigDecimal.ZERO));
|
||||
return amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProjectAdvanceWriteOffOptionVO> projectAdvanceWriteOffOptions(Long contractId,
|
||||
String excludeSettlementType,
|
||||
Long excludeSettlementId) {
|
||||
return projectAdvanceWriteOffService.listOptions(contractId, excludeSettlementType, excludeSettlementId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long saveDraft(PaymentApplicationSaveRequest request) {
|
||||
@@ -1741,12 +1755,12 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
if (source == null) throw new ServiceException("正式结算单不存在");
|
||||
if (!TransportBusiConstant.APPROVED.equals(source.getApprovalStatus())) throw new ServiceException("只能选择审批通过、未作废的正式结算单");
|
||||
entity.setSettlementId(source.getId()); entity.setSettlementNo(source.getFormalSettlementNo()); entity.setPreSettlementId(null); entity.setPreSettlementNo(null);
|
||||
entity.setProjectId(source.getProjectId()); entity.setProjectName(source.getProjectName()); entity.setDeptId(source.getDeptId()); entity.setDeptName(source.getDeptName()); entity.setContractId(source.getContractId()); entity.setContractNo(source.getContractNo()); entity.setContractName(source.getContractName()); entity.setPayerName(source.getPayerName()); entity.setPayeeName(source.getPayeeName()); entity.setSettlementAmount(source.getSettlementAmount()); entity.setPayableAmount(money(source.getSettlementAmount()).subtract(cumulativeFormalSettlementApplied(source.getId(), entity.getId()))); entity.setBillType("正式结算单");
|
||||
entity.setProjectId(source.getProjectId()); entity.setProjectName(source.getProjectName()); entity.setDeptId(source.getDeptId()); entity.setDeptName(source.getDeptName()); entity.setContractId(source.getContractId()); entity.setContractNo(source.getContractNo()); entity.setContractName(source.getContractName()); entity.setPayerName(source.getPayerName()); entity.setPayeeName(source.getPayeeName()); entity.setSettlementAmount(source.getSettlementAmount()); entity.setPayableAmount(payableOfFormalSettlement(source.getId(), source.getSettlementAmount(), entity.getId())); entity.setBillType("正式结算单");
|
||||
} else if (request.getPreSettlementId() != null) {
|
||||
PreSettlement source = preSettlementMapper.selectById(request.getPreSettlementId());
|
||||
if (source == null) throw new ServiceException("预结算单不存在");
|
||||
if (!TransportBusiConstant.APPROVED.equals(source.getApprovalStatus())) throw new ServiceException("只能选择审批通过、未作废的预结算单");
|
||||
entity.setPreSettlementId(source.getId()); entity.setPreSettlementNo(source.getPreSettlementNo()); entity.setSettlementId(null); entity.setSettlementNo(null); entity.setProjectId(source.getProjectId()); entity.setProjectName(source.getProjectName()); entity.setDeptId(source.getDeptId()); entity.setDeptName(source.getDeptName()); entity.setContractId(source.getContractId()); entity.setContractNo(source.getContractNo()); entity.setContractName(source.getContractName()); entity.setPayerName(source.getPayerName()); entity.setPayeeName(source.getPayeeName()); entity.setSettlementAmount(source.getSettlementAmount()); entity.setPayableAmount(money(source.getSettlementAmount()).subtract(cumulativePreSettlementApplied(source.getId(), entity.getId()))); entity.setBillType("预结算单");
|
||||
entity.setPreSettlementId(source.getId()); entity.setPreSettlementNo(source.getPreSettlementNo()); entity.setSettlementId(null); entity.setSettlementNo(null); entity.setProjectId(source.getProjectId()); entity.setProjectName(source.getProjectName()); entity.setDeptId(source.getDeptId()); entity.setDeptName(source.getDeptName()); entity.setContractId(source.getContractId()); entity.setContractNo(source.getContractNo()); entity.setContractName(source.getContractName()); entity.setPayerName(source.getPayerName()); entity.setPayeeName(source.getPayeeName()); entity.setSettlementAmount(source.getSettlementAmount()); entity.setPayableAmount(payableOfPreSettlement(source.getId(), source.getSettlementAmount(), entity.getId())); entity.setBillType("预结算单");
|
||||
} else {
|
||||
entity.setProjectId(request.getProjectId()); entity.setProjectName(request.getProjectName()); entity.setDeptId(request.getDeptId()); entity.setDeptName(request.getDeptName()); entity.setContractId(request.getContractId()); entity.setContractNo(request.getContractNo()); entity.setContractName(request.getContractName()); entity.setPayerName(request.getPayerName()); entity.setPayeeName(request.getPayeeName()); entity.setSettlementAmount(request.getSettlementAmount()); entity.setPayableAmount(request.getPayableAmount()); entity.setBillType(request.getBillType());
|
||||
}
|
||||
@@ -1782,7 +1796,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
BigDecimal settlementAmount = settlements.stream().map(FormalSettlement::getSettlementAmount)
|
||||
.map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
BigDecimal payableAmount = settlements.stream()
|
||||
.map(item -> money(item.getSettlementAmount()).subtract(cumulativeFormalSettlementApplied(item.getId(), entity.getId())).max(BigDecimal.ZERO))
|
||||
.map(item -> payableOfFormalSettlement(item.getId(), item.getSettlementAmount(), entity.getId()))
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
if (money(entity.getAppliedAmount()).compareTo(payableAmount) > 0) throw new ServiceException("申请付款金额不能超过所选结算单可付款金额合计");
|
||||
FormalSettlement first = settlements.get(0);
|
||||
@@ -1796,15 +1810,14 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
if (settlements.isEmpty()) return;
|
||||
settlementRelationMapper.delete(Wrappers.<PaymentApplicationSettlement>lambdaQuery()
|
||||
.eq(PaymentApplicationSettlement::getPaymentApplicationId, entity.getId()));
|
||||
BigDecimal totalBase = settlements.stream().map(item -> money(item.getSettlementAmount()).subtract(
|
||||
cumulativeFormalSettlementApplied(item.getId(), entity.getId())).max(BigDecimal.ZERO))
|
||||
BigDecimal totalBase = settlements.stream()
|
||||
.map(item -> payableOfFormalSettlement(item.getId(), item.getSettlementAmount(), entity.getId()))
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
BigDecimal remainingApplied = money(entity.getAppliedAmount());
|
||||
BigDecimal remainingPaid = money(entity.getPaidAmount());
|
||||
for (int index = 0; index < settlements.size(); index++) {
|
||||
FormalSettlement settlement = settlements.get(index);
|
||||
BigDecimal base = money(settlement.getSettlementAmount()).subtract(
|
||||
cumulativeFormalSettlementApplied(settlement.getId(), entity.getId())).max(BigDecimal.ZERO);
|
||||
BigDecimal base = payableOfFormalSettlement(settlement.getId(), settlement.getSettlementAmount(), entity.getId());
|
||||
BigDecimal applied = index == settlements.size() - 1 ? remainingApplied
|
||||
: money(entity.getAppliedAmount()).multiply(base).divide(totalBase, 2, RoundingMode.DOWN);
|
||||
BigDecimal paid = index == settlements.size() - 1 ? remainingPaid
|
||||
@@ -1881,6 +1894,24 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
.ne(excludeId != null, PaymentApplication::getId, excludeId));
|
||||
}
|
||||
|
||||
/** 正式结算可付款 = 结算金额 − 已申请付款 − 项目预付核销 */
|
||||
private BigDecimal payableOfFormalSettlement(Long settlementId, BigDecimal settlementAmount, Long excludeId) {
|
||||
return money(settlementAmount)
|
||||
.subtract(cumulativeFormalSettlementApplied(settlementId, excludeId))
|
||||
.subtract(projectAdvanceWriteOffService.sumBySettlement(
|
||||
TransportBusiConstant.SETTLEMENT_BILL_FORMAL, settlementId))
|
||||
.max(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
/** 预结算可付款 = 结算金额 − 已申请付款 − 项目预付核销 */
|
||||
private BigDecimal payableOfPreSettlement(Long preSettlementId, BigDecimal settlementAmount, Long excludeId) {
|
||||
return money(settlementAmount)
|
||||
.subtract(cumulativePreSettlementApplied(preSettlementId, excludeId))
|
||||
.subtract(projectAdvanceWriteOffService.sumBySettlement(
|
||||
TransportBusiConstant.SETTLEMENT_BILL_PRE, preSettlementId))
|
||||
.max(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
private void fillBillLedger(PaymentApplication entity, PaymentApplicationSaveRequest request) {
|
||||
if (!isBillPayment(request.getPaymentMethod())) {
|
||||
entity.setBillLedgerId(null);
|
||||
|
||||
+12
@@ -36,6 +36,7 @@ import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.jackson.JsonUtil;
|
||||
import org.springblade.core.tool.utils.BeanUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.transport.constant.TransportBusiConstant;
|
||||
import org.springblade.transport.mapper.PreSettlementAdvanceMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementChangeRecordMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementDetailFeeMapper;
|
||||
@@ -67,6 +68,7 @@ import org.springblade.transport.service.IContractManageService;
|
||||
import org.springblade.transport.service.ICustomerArchiveService;
|
||||
import org.springblade.transport.service.IPreSettlementService;
|
||||
import org.springblade.transport.service.IProjectApplyService;
|
||||
import org.springblade.transport.service.ISettlementProjectAdvanceWriteOffService;
|
||||
import org.springblade.transport.service.IWaybillService;
|
||||
import org.springblade.transport.wrapper.PreSettlementWrapper;
|
||||
import org.springblade.system.cache.UserCache;
|
||||
@@ -124,6 +126,7 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
|
||||
private final ICustomerArchiveService customerArchiveService;
|
||||
private final IWaybillService waybillService;
|
||||
private final ISysClient sysClient;
|
||||
private final ISettlementProjectAdvanceWriteOffService projectAdvanceWriteOffService;
|
||||
|
||||
@Override
|
||||
public IPage<PreSettlementVO> selectPage(IPage<PreSettlement> page, PreSettlementVO query) {
|
||||
@@ -198,6 +201,8 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
|
||||
List<PreSettlementAdvance> advances = listAdvances(id);
|
||||
advances.forEach(advance -> advance.setCreateUserName(UserCache.getUserRealName(advance.getCreateUser())));
|
||||
vo.setAdvances(advances);
|
||||
vo.setProjectAdvanceWriteOffs(projectAdvanceWriteOffService.listBySettlement(
|
||||
TransportBusiConstant.SETTLEMENT_BILL_PRE, id));
|
||||
vo.setChangeRecords(changeRecordMapper.selectList(Wrappers.<PreSettlementChangeRecord>lambdaQuery()
|
||||
.eq(PreSettlementChangeRecord::getPreSettlementId, id)
|
||||
.eq(PreSettlementChangeRecord::getIsDeleted, 0)
|
||||
@@ -346,6 +351,12 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
|
||||
rebuildSummaryFees(settlement.getId(), true);
|
||||
applySummaryRequest(settlement.getId(), contractChanged ? List.of() : request.getSummaryFees());
|
||||
refreshSettlementAmount(settlement);
|
||||
projectAdvanceWriteOffService.replaceWriteOffs(
|
||||
TransportBusiConstant.SETTLEMENT_BILL_PRE,
|
||||
settlement.getId(),
|
||||
settlement.getContractId(),
|
||||
settlement.getSettlementAmount(),
|
||||
request.getProjectAdvanceWriteOffs());
|
||||
if (created) {
|
||||
saveChange(settlement.getId(), "结算单基本信息", null, "新增",
|
||||
"新增预结算单" + settlement.getPreSettlementNo(), "");
|
||||
@@ -362,6 +373,7 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
|
||||
}
|
||||
releaseSourceDetails(settlement, listDetails(id));
|
||||
deleteChildren(id);
|
||||
projectAdvanceWriteOffService.deleteBySettlement(TransportBusiConstant.SETTLEMENT_BILL_PRE, id);
|
||||
deleteLogic(List.of(id));
|
||||
}
|
||||
|
||||
|
||||
+35
-2
@@ -166,7 +166,7 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
|
||||
appendProjectChangeRecord(projectApply, CHANGE_TYPE_DRAFT, null, STATUS_DRAFT, "草稿",
|
||||
buildProjectChangeSnapshot(beforeRecord), buildProjectChangeSnapshot(projectApply));
|
||||
}
|
||||
return saveOrUpdate(projectApply);
|
||||
return persistProjectApply(projectApply);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -185,7 +185,7 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
|
||||
projectApply.setApprovalStatus(STATUS_REVIEWING);
|
||||
projectApply.setCurrentNode(resolveApprovalNode(projectApply));
|
||||
projectApply.setCurrentProcessor("待处理");
|
||||
return saveOrUpdate(projectApply);
|
||||
return persistProjectApply(projectApply);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -772,6 +772,8 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
|
||||
private void validateLength(ProjectApply projectApply) {
|
||||
TransportBusinessSupport.validateLength(projectApply.getProjectName(), 50, "项目名称不能超过50个字");
|
||||
TransportBusinessSupport.validateLength(projectApply.getProjectShortName(), 20, "项目简称不能超过20个字");
|
||||
TransportBusinessSupport.validateLength(projectApply.getUndertakeDeptId(), 500, "平台公司选择过多,请减少后再提交");
|
||||
TransportBusinessSupport.validateLength(projectApply.getUndertakeDeptName(), 500, "平台公司名称过长,请减少选择后再提交");
|
||||
TransportBusinessSupport.validateLength(projectApply.getSourceRemark(), 300, "项目由来说明不能超过300个字");
|
||||
TransportBusinessSupport.validateLength(projectApply.getCargoQuantity(), 100, "预估货物数量不能超过100个字");
|
||||
TransportBusinessSupport.validateLength(projectApply.getTransportRoute(), 100, "运输线路不能超过100个字");
|
||||
@@ -1023,6 +1025,37 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
|
||||
});
|
||||
}
|
||||
|
||||
private boolean persistProjectApply(ProjectApply projectApply) {
|
||||
try {
|
||||
return saveOrUpdate(projectApply);
|
||||
} catch (RuntimeException exception) {
|
||||
throw translateUndertakeDeptPersistError(exception, projectApply);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 多选平台公司写入失败时,提示执行字段扩容脚本(原列为 bigint / varchar(100))。
|
||||
*/
|
||||
private RuntimeException translateUndertakeDeptPersistError(RuntimeException exception, ProjectApply projectApply) {
|
||||
String message = Func.toStr(exception.getMessage());
|
||||
Throwable cause = exception.getCause();
|
||||
while (cause != null) {
|
||||
message = message + " " + Func.toStr(cause.getMessage());
|
||||
cause = cause.getCause();
|
||||
}
|
||||
String lowerMessage = message.toLowerCase();
|
||||
boolean multiUndertake = Func.isNotEmpty(projectApply.getUndertakeDeptId())
|
||||
&& (projectApply.getUndertakeDeptId().contains(",") || projectApply.getUndertakeDeptId().contains(","));
|
||||
boolean columnHint = lowerMessage.contains("undertake_dept")
|
||||
|| lowerMessage.contains("incorrect integer")
|
||||
|| lowerMessage.contains("data truncation")
|
||||
|| lowerMessage.contains("data too long");
|
||||
if (multiUndertake && columnHint) {
|
||||
return new ServiceException("平台公司多选保存失败,请先执行脚本 blade_project_apply_undertake_dept_multi_20261014.sql 扩容字段后重试");
|
||||
}
|
||||
return exception;
|
||||
}
|
||||
|
||||
private void normalizeUndertakeDept(ProjectApply projectApply) {
|
||||
if (projectApply == null) {
|
||||
return;
|
||||
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.system.cache.UserCache;
|
||||
import org.springblade.transport.constant.TransportBusiConstant;
|
||||
import org.springblade.transport.mapper.PaymentApplicationMapper;
|
||||
import org.springblade.transport.mapper.SettlementProjectAdvanceWriteOffMapper;
|
||||
import org.springblade.transport.pojo.dto.SettlementProjectAdvanceWriteOffRequest;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplication;
|
||||
import org.springblade.transport.pojo.entity.SettlementProjectAdvanceWriteOff;
|
||||
import org.springblade.transport.pojo.vo.ProjectAdvanceWriteOffOptionVO;
|
||||
import org.springblade.transport.service.ISettlementProjectAdvanceWriteOffService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 结算单项目预付核销服务实现
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SettlementProjectAdvanceWriteOffServiceImpl implements ISettlementProjectAdvanceWriteOffService {
|
||||
|
||||
private final SettlementProjectAdvanceWriteOffMapper writeOffMapper;
|
||||
private final PaymentApplicationMapper paymentApplicationMapper;
|
||||
|
||||
@Override
|
||||
public List<ProjectAdvanceWriteOffOptionVO> listOptions(Long contractId, String excludeSettlementType,
|
||||
Long excludeSettlementId) {
|
||||
if (contractId == null) {
|
||||
throw new ServiceException("请先选择合同");
|
||||
}
|
||||
List<PaymentApplication> applications = paymentApplicationMapper.selectList(
|
||||
Wrappers.<PaymentApplication>lambdaQuery()
|
||||
.eq(PaymentApplication::getContractId, contractId)
|
||||
.eq(PaymentApplication::getPaymentType, TransportBusiConstant.PAYMENT_TYPE_PROJECT_ADVANCE)
|
||||
.eq(PaymentApplication::getApprovalStatus, TransportBusiConstant.APPROVED)
|
||||
.eq(PaymentApplication::getIsDeleted, 0)
|
||||
.orderByDesc(PaymentApplication::getCreateTime));
|
||||
List<ProjectAdvanceWriteOffOptionVO> options = new ArrayList<>();
|
||||
for (PaymentApplication application : applications) {
|
||||
BigDecimal projectAdvanceAmount = money(application.getAppliedAmount());
|
||||
BigDecimal usedAmount = money(writeOffMapper.sumWriteOffByPaymentApplication(
|
||||
application.getId(), excludeSettlementType, excludeSettlementId));
|
||||
BigDecimal availableAmount = projectAdvanceAmount.subtract(usedAmount).max(BigDecimal.ZERO);
|
||||
if (availableAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
continue;
|
||||
}
|
||||
ProjectAdvanceWriteOffOptionVO option = new ProjectAdvanceWriteOffOptionVO();
|
||||
option.setPaymentApplicationId(application.getId());
|
||||
option.setPaymentNo(application.getPaymentNo());
|
||||
option.setProjectAdvanceAmount(projectAdvanceAmount);
|
||||
option.setAvailableWriteOffAmount(availableAmount);
|
||||
option.setKingdeeBillNo(application.getKingdeeBillNo());
|
||||
option.setCreateUserName(UserCache.getUserRealName(application.getCreateUser()));
|
||||
option.setCreateTime(application.getCreateTime());
|
||||
options.add(option);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SettlementProjectAdvanceWriteOff> listBySettlement(String settlementType, Long settlementId) {
|
||||
if (Func.isEmpty(settlementType) || settlementId == null) {
|
||||
return List.of();
|
||||
}
|
||||
List<SettlementProjectAdvanceWriteOff> rows = writeOffMapper.selectList(
|
||||
Wrappers.<SettlementProjectAdvanceWriteOff>lambdaQuery()
|
||||
.eq(SettlementProjectAdvanceWriteOff::getSettlementType, settlementType)
|
||||
.eq(SettlementProjectAdvanceWriteOff::getSettlementId, settlementId)
|
||||
.eq(SettlementProjectAdvanceWriteOff::getIsDeleted, 0)
|
||||
.orderByAsc(SettlementProjectAdvanceWriteOff::getCreateTime)
|
||||
.orderByAsc(SettlementProjectAdvanceWriteOff::getId));
|
||||
for (SettlementProjectAdvanceWriteOff row : rows) {
|
||||
PaymentApplication application = paymentApplicationMapper.selectById(row.getPaymentApplicationId());
|
||||
BigDecimal projectAdvanceAmount = application == null
|
||||
? money(row.getProjectAdvanceAmount()) : money(application.getAppliedAmount());
|
||||
BigDecimal usedAmount = money(writeOffMapper.sumWriteOffByPaymentApplication(
|
||||
row.getPaymentApplicationId(), settlementType, settlementId));
|
||||
row.setProjectAdvanceAmount(projectAdvanceAmount);
|
||||
row.setAvailableWriteOffAmount(projectAdvanceAmount.subtract(usedAmount).max(BigDecimal.ZERO));
|
||||
if (application != null) {
|
||||
row.setPaymentNo(application.getPaymentNo());
|
||||
row.setKingdeeBillNo(application.getKingdeeBillNo());
|
||||
row.setCreateUserName(UserCache.getUserRealName(application.getCreateUser()));
|
||||
row.setPaymentCreateTime(application.getCreateTime());
|
||||
} else {
|
||||
row.setCreateUserName(UserCache.getUserRealName(row.getCreateUser()));
|
||||
row.setPaymentCreateTime(row.getCreateTime());
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal sumBySettlement(String settlementType, Long settlementId) {
|
||||
if (Func.isEmpty(settlementType) || settlementId == null) {
|
||||
return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
return money(writeOffMapper.sumWriteOffBySettlement(settlementType, settlementId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void replaceWriteOffs(String settlementType, Long settlementId, Long contractId,
|
||||
BigDecimal settlementAmount, List<SettlementProjectAdvanceWriteOffRequest> writeOffs) {
|
||||
if (Func.isEmpty(settlementType) || settlementId == null) {
|
||||
throw new ServiceException("结算单不能为空");
|
||||
}
|
||||
if (contractId == null) {
|
||||
throw new ServiceException("合同不能为空");
|
||||
}
|
||||
List<SettlementProjectAdvanceWriteOffRequest> requestRows = writeOffs == null ? List.of() : writeOffs;
|
||||
BigDecimal settlementLimit = money(settlementAmount);
|
||||
BigDecimal totalWriteOff = BigDecimal.ZERO;
|
||||
Set<Long> paymentIds = new HashSet<>();
|
||||
List<SettlementProjectAdvanceWriteOff> entities = new ArrayList<>();
|
||||
for (SettlementProjectAdvanceWriteOffRequest request : requestRows) {
|
||||
if (request == null || request.getPaymentApplicationId() == null) {
|
||||
throw new ServiceException("请选择项目预付单");
|
||||
}
|
||||
if (!paymentIds.add(request.getPaymentApplicationId())) {
|
||||
throw new ServiceException("同一项目预付单不可重复核销");
|
||||
}
|
||||
BigDecimal writeOffAmount = money(request.getWriteOffAmount());
|
||||
if (writeOffAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new ServiceException("本次核销金额必须大于0");
|
||||
}
|
||||
PaymentApplication application = paymentApplicationMapper.selectById(request.getPaymentApplicationId());
|
||||
if (application == null || Objects.equals(application.getIsDeleted(), 1)) {
|
||||
throw new ServiceException("项目预付单不存在");
|
||||
}
|
||||
if (!TransportBusiConstant.PAYMENT_TYPE_PROJECT_ADVANCE.equals(application.getPaymentType())) {
|
||||
throw new ServiceException("仅可核销项目预付单");
|
||||
}
|
||||
if (!TransportBusiConstant.APPROVED.equals(application.getApprovalStatus())) {
|
||||
throw new ServiceException("仅可选择审核通过的项目预付单");
|
||||
}
|
||||
if (!Objects.equals(contractId, application.getContractId())) {
|
||||
throw new ServiceException("项目预付单与结算单合同不一致");
|
||||
}
|
||||
BigDecimal projectAdvanceAmount = money(application.getAppliedAmount());
|
||||
BigDecimal usedAmount = money(writeOffMapper.sumWriteOffByPaymentApplication(
|
||||
application.getId(), settlementType, settlementId));
|
||||
BigDecimal availableAmount = projectAdvanceAmount.subtract(usedAmount).max(BigDecimal.ZERO);
|
||||
if (writeOffAmount.compareTo(availableAmount) > 0) {
|
||||
throw new ServiceException("预付单" + Func.toStr(application.getPaymentNo(), "")
|
||||
+ "本次核销金额不能超过可核销金额");
|
||||
}
|
||||
totalWriteOff = totalWriteOff.add(writeOffAmount);
|
||||
SettlementProjectAdvanceWriteOff entity = new SettlementProjectAdvanceWriteOff();
|
||||
entity.setSettlementType(settlementType);
|
||||
entity.setSettlementId(settlementId);
|
||||
entity.setPaymentApplicationId(application.getId());
|
||||
entity.setPaymentNo(application.getPaymentNo());
|
||||
entity.setProjectAdvanceAmount(projectAdvanceAmount);
|
||||
entity.setWriteOffAmount(writeOffAmount);
|
||||
entity.setKingdeeBillNo(application.getKingdeeBillNo());
|
||||
entity.setStatus(1);
|
||||
entity.setIsDeleted(0);
|
||||
entities.add(entity);
|
||||
}
|
||||
if (totalWriteOff.compareTo(settlementLimit) > 0) {
|
||||
throw new ServiceException("项目预付核销合计不能超过结算单金额");
|
||||
}
|
||||
writeOffMapper.delete(Wrappers.<SettlementProjectAdvanceWriteOff>lambdaQuery()
|
||||
.eq(SettlementProjectAdvanceWriteOff::getSettlementType, settlementType)
|
||||
.eq(SettlementProjectAdvanceWriteOff::getSettlementId, settlementId));
|
||||
for (SettlementProjectAdvanceWriteOff entity : entities) {
|
||||
writeOffMapper.insert(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteBySettlement(String settlementType, Long settlementId) {
|
||||
if (Func.isEmpty(settlementType) || settlementId == null) {
|
||||
return;
|
||||
}
|
||||
writeOffMapper.delete(Wrappers.<SettlementProjectAdvanceWriteOff>lambdaQuery()
|
||||
.eq(SettlementProjectAdvanceWriteOff::getSettlementType, settlementType)
|
||||
.eq(SettlementProjectAdvanceWriteOff::getSettlementId, settlementId));
|
||||
}
|
||||
|
||||
private BigDecimal money(BigDecimal value) {
|
||||
return value == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)
|
||||
: value.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,64 @@
|
||||
-- 平台公司支持多选:ID 逗号分隔,名称顿号分隔
|
||||
ALTER TABLE `blade_project_apply`
|
||||
MODIFY COLUMN `undertake_dept_id` varchar(500) DEFAULT NULL COMMENT '平台公司ID,多个逗号分隔',
|
||||
MODIFY COLUMN `undertake_dept_name` varchar(500) DEFAULT NULL COMMENT '平台公司,多个顿号分隔';
|
||||
-- 项目立项平台公司多选:ID 逗号分隔,名称顿号分隔
|
||||
-- 原字段:undertake_dept_id bigint、undertake_dept_name varchar(100)
|
||||
-- 选择 2 个及以上平台公司时,若未扩容会报 Incorrect integer value / Data truncation
|
||||
-- 整列索引挂在 varchar(500) 上可能因键长超限导致 ALTER 失败,故先删索引再改前缀索引
|
||||
|
||||
DELIMITER $$
|
||||
|
||||
DROP PROCEDURE IF EXISTS `upgrade_project_apply_undertake_dept_multi_20261014`$$
|
||||
CREATE PROCEDURE `upgrade_project_apply_undertake_dept_multi_20261014`()
|
||||
BEGIN
|
||||
DECLARE db_name varchar(128);
|
||||
DECLARE need_modify tinyint DEFAULT 0;
|
||||
SET db_name = DATABASE();
|
||||
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = db_name
|
||||
AND table_name = 'blade_project_apply'
|
||||
AND column_name = 'undertake_dept_id'
|
||||
AND (
|
||||
data_type IN ('bigint', 'int', 'integer')
|
||||
OR (data_type IN ('varchar', 'char') AND IFNULL(character_maximum_length, 0) < 500)
|
||||
)
|
||||
) OR EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = db_name
|
||||
AND table_name = 'blade_project_apply'
|
||||
AND column_name = 'undertake_dept_name'
|
||||
AND data_type IN ('varchar', 'char')
|
||||
AND IFNULL(character_maximum_length, 0) < 500
|
||||
) THEN
|
||||
SET need_modify = 1;
|
||||
END IF;
|
||||
|
||||
IF need_modify = 1 THEN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.statistics
|
||||
WHERE table_schema = db_name
|
||||
AND table_name = 'blade_project_apply'
|
||||
AND index_name = 'idx_project_apply_dept'
|
||||
) THEN
|
||||
ALTER TABLE `blade_project_apply` DROP INDEX `idx_project_apply_dept`;
|
||||
END IF;
|
||||
|
||||
ALTER TABLE `blade_project_apply`
|
||||
MODIFY COLUMN `undertake_dept_id` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '平台公司ID,多个逗号分隔',
|
||||
MODIFY COLUMN `undertake_dept_name` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '平台公司,多个顿号分隔';
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.statistics
|
||||
WHERE table_schema = db_name
|
||||
AND table_name = 'blade_project_apply'
|
||||
AND index_name = 'idx_project_apply_dept'
|
||||
) THEN
|
||||
ALTER TABLE `blade_project_apply`
|
||||
ADD INDEX `idx_project_apply_dept` (`undertake_dept_id`(191)) USING BTREE;
|
||||
END IF;
|
||||
END$$
|
||||
|
||||
CALL `upgrade_project_apply_undertake_dept_multi_20261014`()$$
|
||||
DROP PROCEDURE `upgrade_project_apply_undertake_dept_multi_20261014`$$
|
||||
|
||||
DELIMITER ;
|
||||
|
||||
@@ -60,7 +60,7 @@ CREATE TABLE `blade_project_apply` (
|
||||
`void_reason` varchar(500) DEFAULT NULL COMMENT '作废原因',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_project_apply_name` (`project_name`, `is_deleted`) USING BTREE,
|
||||
KEY `idx_project_apply_dept` (`undertake_dept_id`) USING BTREE,
|
||||
KEY `idx_project_apply_dept` (`undertake_dept_id`(191)) USING BTREE,
|
||||
KEY `idx_project_apply_status` (`approval_status`) USING BTREE,
|
||||
KEY `idx_project_apply_create_time` (`create_time`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目立项';
|
||||
@@ -80,8 +80,8 @@ CREATE TABLE `blade_temporary_credit_limit` (
|
||||
`project_id` bigint(20) DEFAULT NULL COMMENT '项目ID',
|
||||
`project_code` varchar(100) DEFAULT NULL COMMENT '项目编号',
|
||||
`project_name` varchar(100) DEFAULT NULL COMMENT '项目名称',
|
||||
`undertake_dept_id` varchar(500) DEFAULT NULL COMMENT '平台公司ID,多个逗号分隔',
|
||||
`undertake_dept_name` varchar(500) DEFAULT NULL COMMENT '平台公司,多个顿号分隔',
|
||||
`undertake_dept_id` bigint(20) DEFAULT NULL COMMENT '承办部门ID',
|
||||
`undertake_dept_name` varchar(100) DEFAULT NULL COMMENT '承办部门',
|
||||
`project_fund_limit` decimal(18,2) DEFAULT NULL COMMENT '项目资金使用额度(万元)',
|
||||
`used_fund_limit` decimal(18,2) DEFAULT NULL COMMENT '已使用项目资金额度(万元)',
|
||||
`remaining_fund_limit` decimal(18,2) DEFAULT NULL COMMENT '剩余项目资金使用额度(万元)',
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
-- 结算单项目预付核销明细
|
||||
CREATE TABLE IF NOT EXISTS `blade_settlement_project_advance_write_off` (
|
||||
`id` bigint NOT NULL COMMENT '主键',
|
||||
`tenant_id` varchar(12) NOT NULL DEFAULT '000000' COMMENT '租户ID',
|
||||
`settlement_type` varchar(20) NOT NULL COMMENT '结算单类型 pre/formal',
|
||||
`settlement_id` bigint NOT NULL COMMENT '预结算/正式结算单ID',
|
||||
`payment_application_id` bigint NOT NULL COMMENT '项目预付付款申请ID',
|
||||
`payment_no` varchar(64) DEFAULT NULL COMMENT '预付单号',
|
||||
`project_advance_amount` decimal(18,2) DEFAULT 0.00 COMMENT '项目预付金额',
|
||||
`write_off_amount` decimal(18,2) NOT NULL DEFAULT 0.00 COMMENT '本次核销金额',
|
||||
`kingdee_bill_no` varchar(100) DEFAULT NULL COMMENT '金蝶预付单号',
|
||||
`create_user` bigint DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_user` bigint DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`status` int DEFAULT 1 COMMENT '业务状态',
|
||||
`is_deleted` int DEFAULT 0 COMMENT '是否已删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_spa_write_off_settlement` (`settlement_type`,`settlement_id`),
|
||||
KEY `idx_spa_write_off_payment` (`payment_application_id`),
|
||||
KEY `idx_spa_write_off_create_time` (`create_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='结算单项目预付核销';
|
||||
Reference in New Issue
Block a user