diff --git a/sql/06-approval-settlement.sql b/sql/06-approval-settlement.sql
new file mode 100644
index 0000000..40fbf9c
--- /dev/null
+++ b/sql/06-approval-settlement.sql
@@ -0,0 +1,39 @@
+-- 结算单业务表与明细子表(可重复执行)
+-- 目标库:db_gxtyzx(master)
+-- 执行顺序:01-approval.sql -> 02-approval_menu.sql -> 03-approval_orgs_roles.sql
+-- -> 04-approval_role_grants.sql -> 05-approval_phase2.sql -> 06-approval-settlement.sql
+--
+-- 覆盖 ADR 0011(结算单):三部门会签、明细行(金额服务端重算、合计不落库)、
+-- 外单位盖章件(SIGNED)必传。业务表 1:1 实例,明细子表按 instance_id + line_no 唯一。
+
+CREATE TABLE IF NOT EXISTS approval_settlement_form (
+ id BIGINT NOT NULL AUTO_INCREMENT,
+ tenant_id INT NOT NULL DEFAULT 10150,
+ instance_id BIGINT NOT NULL,
+ settlement_reason VARCHAR(500) NOT NULL COMMENT '结算事由',
+ settlement_period VARCHAR(100) DEFAULT NULL COMMENT '结算期间',
+ counterparty_name VARCHAR(200) NOT NULL COMMENT '结算对象名称',
+ contract_no VARCHAR(100) DEFAULT NULL COMMENT '合同/项目编号',
+ create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (id),
+ UNIQUE KEY uk_instance (instance_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='结算单';
+
+CREATE TABLE IF NOT EXISTS approval_settlement_item (
+ id BIGINT NOT NULL AUTO_INCREMENT,
+ tenant_id INT NOT NULL DEFAULT 10150,
+ instance_id BIGINT NOT NULL,
+ line_no INT NOT NULL COMMENT '行号,按提交顺序重排为 1..N',
+ item_name VARCHAR(200) NOT NULL COMMENT '项目名称',
+ spec VARCHAR(200) DEFAULT NULL COMMENT '规格说明',
+ quantity DECIMAL(12,3) NOT NULL COMMENT '数量',
+ unit VARCHAR(20) NOT NULL COMMENT '单位',
+ unit_price DECIMAL(12,2) NOT NULL COMMENT '单价',
+ amount DECIMAL(12,2) NOT NULL COMMENT '金额,服务端按数量×单价重算',
+ remark VARCHAR(200) DEFAULT NULL COMMENT '备注',
+ create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (id),
+ UNIQUE KEY uk_instance_line (instance_id, line_no)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='结算单明细';
diff --git a/src/main/java/com/gxwebsoft/approval/doc/settlement/ApprovalSettlementForm.java b/src/main/java/com/gxwebsoft/approval/doc/settlement/ApprovalSettlementForm.java
new file mode 100644
index 0000000..57a8f52
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/approval/doc/settlement/ApprovalSettlementForm.java
@@ -0,0 +1,45 @@
+package com.gxwebsoft.approval.doc.settlement;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 结算单(ADR 0011):与外单位结算的业务字段,1:1 对应审批实例。
+ *
+ *
不设币种:客户业务全为人民币,多币种要配套汇率与折算。
+ */
+@Data
+@ApiModel(description = "结算单")
+@TableName("approval_settlement_form")
+public class ApprovalSettlementForm implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ private Integer tenantId;
+
+ private Long instanceId;
+
+ /** 结算事由。 */
+ private String settlementReason;
+
+ /** 结算期间。 */
+ private String settlementPeriod;
+
+ /** 结算对象名称。 */
+ private String counterpartyName;
+
+ /** 合同/项目编号。 */
+ private String contractNo;
+
+ private LocalDateTime createTime;
+
+ private LocalDateTime updateTime;
+}
diff --git a/src/main/java/com/gxwebsoft/approval/doc/settlement/ApprovalSettlementItem.java b/src/main/java/com/gxwebsoft/approval/doc/settlement/ApprovalSettlementItem.java
new file mode 100644
index 0000000..3de291a
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/approval/doc/settlement/ApprovalSettlementItem.java
@@ -0,0 +1,51 @@
+package com.gxwebsoft.approval.doc.settlement;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 结算单明细行(ADR 0011 / 0004):金额由服务端按数量 × 单价重算,合计不落库。
+ */
+@Data
+@ApiModel(description = "结算单明细")
+@TableName("approval_settlement_item")
+public class ApprovalSettlementItem implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ private Integer tenantId;
+
+ private Long instanceId;
+
+ /** 行号:按提交顺序重排为 1..N。 */
+ private Integer lineNo;
+
+ private String itemName;
+
+ private String spec;
+
+ /** 数量,3 位小数(租用时长常带小数)。 */
+ private BigDecimal quantity;
+
+ private String unit;
+
+ private BigDecimal unitPrice;
+
+ /** 金额:服务端按 quantity × unitPrice 重算,不信任客户端值。 */
+ private BigDecimal amount;
+
+ private String remark;
+
+ private LocalDateTime createTime;
+
+ private LocalDateTime updateTime;
+}
diff --git a/src/main/java/com/gxwebsoft/approval/doc/settlement/ApprovalSettlementParam.java b/src/main/java/com/gxwebsoft/approval/doc/settlement/ApprovalSettlementParam.java
new file mode 100644
index 0000000..3e71dbf
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/approval/doc/settlement/ApprovalSettlementParam.java
@@ -0,0 +1,29 @@
+package com.gxwebsoft.approval.doc.settlement;
+
+import com.gxwebsoft.approval.document.ApprovalDocumentParam;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 结算单草稿参数;id 为审批实例id,更新草稿时传入,明细行走基类 lines。
+ *
+ * 报送部门与报送人由服务端按登录态带出,不在参数中接收。
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ApprovalSettlementParam extends ApprovalDocumentParam {
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("结算事由,必填")
+ private String settlementReason;
+
+ @ApiModelProperty("结算期间,选填")
+ private String settlementPeriod;
+
+ @ApiModelProperty("结算对象名称,必填")
+ private String counterpartyName;
+
+ @ApiModelProperty("合同/项目编号,选填")
+ private String contractNo;
+}
diff --git a/src/main/java/com/gxwebsoft/approval/doc/settlement/SettlementDocumentType.java b/src/main/java/com/gxwebsoft/approval/doc/settlement/SettlementDocumentType.java
new file mode 100644
index 0000000..38d66cb
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/approval/doc/settlement/SettlementDocumentType.java
@@ -0,0 +1,250 @@
+package com.gxwebsoft.approval.doc.settlement;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.gxwebsoft.approval.constant.ApprovalConstants;
+import com.gxwebsoft.approval.document.AbstractApprovalDocumentType;
+import com.gxwebsoft.approval.document.ApprovalDocumentParam;
+import com.gxwebsoft.approval.document.ApprovalLineSupport;
+import com.gxwebsoft.approval.entity.ApprovalInstance;
+import com.gxwebsoft.approval.mapper.ApprovalSettlementFormMapper;
+import com.gxwebsoft.approval.mapper.ApprovalSettlementItemMapper;
+import com.gxwebsoft.approval.support.ApprovalLineSpec;
+import com.gxwebsoft.approval.vo.ApprovalDetail;
+import com.gxwebsoft.common.core.exception.BusinessException;
+import com.gxwebsoft.common.system.entity.User;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 结算单(ADR 0011):报送部门负责人 → 三部门会签(场馆部/安全运保部/财务部)→
+ * 报送部门分管领导 → 报送人存档 → 归档。
+ *
+ * 吃掉引擎三项能力:会签(组声明固定)、明细行(金额服务端重算、合计不落库)、
+ * 附件分类(外单位盖章件 SIGNED 必传)。
+ */
+@Component
+public class SettlementDocumentType extends AbstractApprovalDocumentType {
+
+ /** 节点链:报送人提交后从报送部门负责人开始。 */
+ static final String NODES_JSON = "["
+ + "{\"key\":\"reportLeader\",\"type\":\"APPROVE\",\"resolver\":\"reporterOrgLeader\",\"name\":\"报送部门负责人\"},"
+ + "{\"key\":\"countersign\",\"type\":\"COUNTERSIGN\",\"name\":\"三部门会签\",\"groups\":["
+ + "{\"key\":\"venue\",\"name\":\"场馆部\",\"resolver\":\"orgLeaderByCode\",\"orgCode\":\"APPROVAL_VENUE\"},"
+ + "{\"key\":\"safety\",\"name\":\"安全运保部\",\"resolver\":\"orgLeaderByCode\",\"orgCode\":\"APPROVAL_SAFETY\"},"
+ + "{\"key\":\"finance\",\"name\":\"财务部\",\"resolver\":\"orgLeaderByCode\",\"orgCode\":\"APPROVAL_FINANCE\"}"
+ + "]},"
+ + "{\"key\":\"deputy\",\"type\":\"APPROVE\",\"resolver\":\"reporterOrgDeputy\",\"name\":\"分管领导\"},"
+ + "{\"key\":\"confirm\",\"type\":\"CONFIRM\",\"resolver\":\"reporter\",\"name\":\"存档\"},"
+ + "{\"key\":\"archive\",\"type\":\"ARCHIVE\",\"resolver\":\"archivist\",\"name\":\"归档\"}"
+ + "]";
+
+ /** 明细列(ADR 0004 / 0011):列结构随表结构走。 */
+ private static final List LINE_COLUMNS = Collections.unmodifiableList(
+ List.of(
+ ApprovalLineSpec.text("itemName", "项目名称", true, 200),
+ ApprovalLineSpec.text("spec", "规格说明", false, 200),
+ ApprovalLineSpec.decimal("quantity", "数量", true, 3),
+ ApprovalLineSpec.text("unit", "单位", true, 20),
+ ApprovalLineSpec.decimal("unitPrice", "单价", true, 2),
+ // 金额由服务端重算:客户端可不传,传了就必须与数量×单价一致
+ ApprovalLineSpec.decimal("amount", "金额", false, 2).asMoney(),
+ ApprovalLineSpec.text("remark", "备注", false, 200)
+ ));
+
+ @Resource
+ private ApprovalSettlementFormMapper settlementFormMapper;
+ @Resource
+ private ApprovalSettlementItemMapper settlementItemMapper;
+
+ @Override
+ public String flowCode() {
+ return ApprovalConstants.FLOW_SETTLEMENT;
+ }
+
+ @Override
+ public String docType() {
+ return ApprovalConstants.FLOW_SETTLEMENT;
+ }
+
+ @Override
+ public String flowName() {
+ return "结算单";
+ }
+
+ @Override
+ public String nodesJson() {
+ return NODES_JSON;
+ }
+
+ @Override
+ public String noPrefix() {
+ return ApprovalConstants.NO_PREFIX_SETTLEMENT;
+ }
+
+ @Override
+ public List lineColumns() {
+ return LINE_COLUMNS;
+ }
+
+ /** 外单位盖章件(签字件)至少一张:只要求整单有附件会让报价单顶替掉盖章件(ADR 0005)。 */
+ @Override
+ public String requiredAttachmentCategory() {
+ return ApprovalConstants.CATEGORY_SIGNED;
+ }
+
+ @Override
+ public Class extends ApprovalDocumentParam> paramClass() {
+ return ApprovalSettlementParam.class;
+ }
+
+ @Override
+ public void validate(ApprovalDocumentParam param, User user) {
+ ApprovalSettlementParam settlement = cast(param);
+ requireText("结算事由", settlement.getSettlementReason(), 500);
+ requireText("结算对象", settlement.getCounterpartyName(), 200);
+ optionalText("结算期间", settlement.getSettlementPeriod(), 100);
+ optionalText("合同号", settlement.getContractNo(), 100);
+ // 明细在持久化前统一校验;这里先做结构校验,避免先落业务主表再报错
+ ApprovalLineSupport.normalize(settlement.getLines(), LINE_COLUMNS);
+ }
+
+ /**
+ * 写业务表:明细整表替换(先删后插),line_no 由校验器重排为 1..N。
+ *
+ * 调用方(ApprovalDocumentService)已在外层事务内调用,跨库解析不在这里做。
+ */
+ @Override
+ public Long persist(Long instanceId, Long bizId, ApprovalDocumentParam param, User user) {
+ ApprovalSettlementParam settlement = cast(param);
+ List