112 lines
6.1 KiB
Java
112 lines
6.1 KiB
Java
package com.baiyue.finance;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.regex.Pattern;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
|
|
class FinanceSqlCommentContractTest {
|
|
private static final Pattern TABLE = Pattern.compile("CREATE TABLE IF NOT EXISTS (fin_[a-z0-9_]+) ");
|
|
private static final Pattern COLUMN = Pattern.compile("^\\s{2}([a-z][a-z0-9_]*)\\s+(?:BIGINT|INT|VARCHAR|CHAR|DECIMAL|DATETIME|DATE|JSON|TINYINT)\\b", Pattern.CASE_INSENSITIVE);
|
|
private static final Pattern CHINESE = Pattern.compile("[\\p{IsHan}]");
|
|
|
|
@Test
|
|
void everyFinanceBaselineColumnHasMeaningfulChineseComment() throws Exception {
|
|
List<String> lines = Files.readAllLines(Path.of("src/main/resources/db/finance.sql"), StandardCharsets.UTF_8);
|
|
int tableCount = 0;
|
|
int columnCount = 0;
|
|
String currentTable = null;
|
|
List<String> missing = new ArrayList<>();
|
|
for (String line : lines) {
|
|
var table = TABLE.matcher(line);
|
|
if (table.find()) {
|
|
currentTable = table.group(1);
|
|
tableCount++;
|
|
continue;
|
|
}
|
|
if (currentTable == null) continue;
|
|
if (line.startsWith(") ENGINE=")) {
|
|
currentTable = null;
|
|
continue;
|
|
}
|
|
var column = COLUMN.matcher(line);
|
|
if (!column.find()) continue;
|
|
columnCount++;
|
|
int comment = line.indexOf("COMMENT '");
|
|
if (comment < 0 || !CHINESE.matcher(line.substring(comment)).find()) {
|
|
missing.add(currentTable + "." + column.group(1));
|
|
}
|
|
}
|
|
assertThat(tableCount).isEqualTo(23);
|
|
assertThat(columnCount).isEqualTo(353);
|
|
assertThat(missing).as("缺少中文业务注释的Finance字段").isEmpty();
|
|
}
|
|
|
|
@Test
|
|
void keyIsolationStatusSnapshotAndIdempotencyCommentsUseFrozenMeaning() throws Exception {
|
|
String sql = Files.readString(Path.of("src/main/resources/db/finance.sql"), StandardCharsets.UTF_8);
|
|
assertThat(sql).contains("tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键'");
|
|
assertThat(sql).contains("AVAILABLE可结算、SETTLED资金账户已结清、SUPERSEDED已被新版本替代、VOIDED已作废");
|
|
assertThat(sql).contains("RECEIVED已接收、PROCESSED已完成、FAILED处理失败");
|
|
assertThat(sql).contains("Firstleg费用来源完整不可变JSON快照");
|
|
assertThat(sql).contains("ON_ACCOUNT账期应付、DIRECT_PAID业务已付");
|
|
assertThat(sql).contains("来源直接已付且CONFIRMED计入已线下支付供应商款");
|
|
assertThat(sql).contains("RECEIVABLE计待收,PAYABLE与未制单ON_ACCOUNT来源共同计待付");
|
|
assertThat(sql).contains("规范化完整请求的SHA-256十六进制哈希");
|
|
}
|
|
|
|
@Test
|
|
void unifiedInitializationDefinesBillLineAdjustmentReasonDirectly() throws Exception {
|
|
Path direct = Path.of("deploy", "sql", "头程数据库统一增量-MySQL8.sql");
|
|
Path unified = Files.exists(direct) ? direct : Path.of("..", "deploy", "sql", "头程数据库统一增量-MySQL8.sql");
|
|
String sql = Files.readString(unified, StandardCharsets.UTF_8);
|
|
|
|
assertThat(sql)
|
|
.contains("adjustment_reason varchar(500) DEFAULT NULL COMMENT '最近一次账单调整行原因;完整历史保存在修订与审计记录'")
|
|
.doesNotContain("ALTER TABLE baiyue_finance.fin_bill_line", "queue_column_comment");
|
|
}
|
|
|
|
@Test
|
|
void operatingFundAggregatesHaveDedicatedBaselineIndexes() throws Exception {
|
|
String sql = Files.readString(Path.of("src/main/resources/db/finance.sql"), StandardCharsets.UTF_8);
|
|
assertThat(sql)
|
|
.contains("KEY idx_fin_fee_source_customer_fund (customer_id, direction, settlement_mode, review_status, status, currency_code, id)")
|
|
.contains("KEY idx_fin_cost_customer_origin_status (tenant_id, cost_origin, status)")
|
|
.contains("KEY idx_fin_settlement_customer_direction_status (tenant_id, direction, status)")
|
|
.contains("KEY idx_fin_settlement_line_source (fee_source_id)")
|
|
.contains("KEY idx_fin_settlement_payment_customer_type_time (tenant_id, transaction_type, created_at, settlement_id)");
|
|
}
|
|
|
|
@Test
|
|
void financeLedgerSourcesPersistOperatorNameSnapshotsInBaselineAndUnifiedSql() throws Exception {
|
|
String baseline = Files.readString(Path.of("src/main/resources/db/finance.sql"), StandardCharsets.UTF_8);
|
|
Path direct = Path.of("deploy", "sql", "头程数据库统一增量-MySQL8.sql");
|
|
Path unifiedPath = Files.exists(direct) ? direct : Path.of("..", "deploy", "sql", "头程数据库统一增量-MySQL8.sql");
|
|
String unified = Files.readString(unifiedPath, StandardCharsets.UTF_8);
|
|
|
|
assertThat(baseline.split("created_by_name VARCHAR\\(128\\) NULL COMMENT '创建操作人名称快照'", -1))
|
|
.hasSize(4);
|
|
assertThat(baseline)
|
|
.contains("updated_by_name VARCHAR(128) NULL COMMENT '最后修改操作人名称快照'")
|
|
.contains("created_by_name VARCHAR(128) NULL COMMENT '登记操作人名称快照'");
|
|
assertThat(tableBlock(unified, "fin_bill")).contains("created_by_name", "updated_by_name");
|
|
assertThat(tableBlock(unified, "fin_receipt")).contains("created_by_name");
|
|
assertThat(tableBlock(unified, "fin_cost")).contains("created_by_name");
|
|
assertThat(tableBlock(unified, "fin_settlement_payment")).contains("created_by_name");
|
|
assertThat(tableBlock(unified, "fin_bill_revision")).contains("created_by_name");
|
|
assertThat(unified).doesNotContain("finance_add_operator_snapshot_column");
|
|
}
|
|
|
|
private static String tableBlock(String sql, String table) {
|
|
int start = sql.indexOf("CREATE TABLE " + table + " (");
|
|
int end = sql.indexOf(';', start);
|
|
return start < 0 || end < 0 ? "" : sql.substring(start, end);
|
|
}
|
|
}
|