test: align full acceptance contracts
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
- 正式上线前的数据库变更直接维护该文件中的当前基线、存量兼容处理和最终校验,不再创建按日期拆分的发布 SQL;正式上线后的迁移策略在生产发布规范中另行冻结。
|
||||
- 当前测试环境尚未上线,船期价格表相关表、字段和索引只维护在现有初始化建表定义及本固定入口中,不向 `phase1-order-extension.sql`、`phase2-fba-pricing-migration.sql` 或新的增量脚本追加同一结构。
|
||||
- 模块 `src/main/resources/db/` 下的 SQL 用于开发溯源;`deploy/sql/` 下已有日期文件全部冻结为历史记录,不再单独部署,也不得与固定入口重复执行。
|
||||
- 固定入口不包含 `auth/phase1-admin-accounts.sql` 和 `warehouse/warehouse-seed.sql`,不会写入固定密码账号、演示仓库、演示快递公司或演示订单;正式平台公共仓库主数据已内联到固定入口。
|
||||
- 固定入口不包含 `auth/phase1-admin-accounts.sql` 和 `warehouse/warehouse-seed.sql`;仅在开发/测试基线账号缺失时创建最小登录账号,重复执行不覆盖现有密码。脚本不写入演示订单;正式平台公共仓库主数据已内联到固定入口。
|
||||
- `warehouse/phase2-pallet-location-schema-migration.sql` 的有效结构已被当前 `phase2-pallet-location-schema.sql` 和后续共享溢出位迁移完整覆盖,因此不重复内联,避免每次部署无条件删除并重建同名唯一索引。
|
||||
- 脚本会创建 9 个独立数据库:`baiyue_auth`、`baiyue_iam`、`baiyue_order`、`baiyue_warehouse`、`baiyue_firstleg`、`baiyue_file`、`baiyue_audit`、`baiyue_event_bridge`、`baiyue_finance`。Gateway、Print、Integration Service 无数据库。
|
||||
- IAM 消息中心基线已内联到固定入口,包括 5 张 `iam_notification_*` 表、任务/事件幂等约束、平台消息管理权限、企业成员收件箱权限及默认角色授权;模块溯源脚本为 `iam/src/main/resources/db/notification-center.sql`。
|
||||
|
||||
@@ -244,7 +244,7 @@ EXECUTE auth_password_change_required_stmt;
|
||||
DEALLOCATE PREPARE auth_password_change_required_stmt;
|
||||
|
||||
-- 开发/测试环境最小登录基线:一个平台系统管理员和一个 IT 测试客户管理员。
|
||||
-- 初始密码统一为 ChangeMe123!;只保存 BCrypt 哈希,不写入明文。
|
||||
-- 缺失账号首次创建时写入开发基线 BCrypt 哈希;重复执行统一增量绝不覆盖现有密码。
|
||||
INSERT INTO auth_account (
|
||||
id, username, password_hash, display_name, account_status,
|
||||
failed_login_count, token_version, password_change_required, default_tenant_id,
|
||||
@@ -255,7 +255,6 @@ INSERT INTO auth_account (
|
||||
(1000002, 'merchant_admin', '$2a$12$AMZJjd88leYPLI9uKvjZiew2CTQXI32BXoHFX.FrCi28/IeZ7mZ96',
|
||||
'IT 测试客户管理员', 'ACTIVE', 0, 1, 0, 10001, 10001, 3000002, 'MERCHANT', 0)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
password_hash = VALUES(password_hash),
|
||||
display_name = VALUES(display_name),
|
||||
account_status = 'ACTIVE',
|
||||
failed_login_count = 0,
|
||||
|
||||
@@ -58,7 +58,7 @@ test('客户详情经营统计模块登记三项独立正式接口与精度字
|
||||
test('后端统计契约测试覆盖客户详情已确认边界口径', () => {
|
||||
for (const marker of ["order_role = 'master'", 'submitted_at is not null', 'monthstart', 'nextmonthstart', 'doesNotContain\\\("status ="\\\)']) assert.match(orderStatisticsTest, new RegExp(marker, 'i'))
|
||||
for (const marker of ['VOIDED', 'totalReceivable', 'receivedAmount', 'outstandingReceivable']) assert.match(financeStatisticsTest, new RegExp(marker, 'i'))
|
||||
for (const marker of ['actual_sailing_at', 'actual_warehouse_arrival_at', 'CANCELLED', 'FAILED', '20\\*=1', '40\\*=2', '45\\*=2.25', '2.25', 'unknown']) assert.match(transitStatisticsTest, new RegExp(marker, 'i'))
|
||||
for (const marker of ['actual_sailing_at', 'actual_warehouse_arrival_at', 'CANCELLED', 'NOT EXISTS', '20\\*=1', '40\\*=2', '45\\*=2.25', '2.25', 'unknown']) assert.match(transitStatisticsTest, new RegExp(marker, 'i'))
|
||||
assert.match(orderStatisticsTest, /tenant_id|tenantSubmittedStatistics/)
|
||||
assert.match(financeStatisticsTest, /customerId|customer_id/)
|
||||
assert.match(transitStatisticsTest, /customerId|customer_id/)
|
||||
|
||||
@@ -16,7 +16,8 @@ test('国内整柜模块仅由总编排注入 context 后执行', () => {
|
||||
})
|
||||
|
||||
test('正式全量验收默认注册国内整柜模块', () => {
|
||||
assert.match(acceptance, /DEFAULT_MODULES\s*=\s*\[[^\]]*['"]domestic-container['"]/s)
|
||||
assert.match(acceptance, /CONFIGURED_MODULES\s*=\s*\[[^\]]*['"]domestic-container['"]/s)
|
||||
assert.match(acceptance, /DEFAULT_MODULES\s*=\s*normalizeModuleOrder\(CONFIGURED_MODULES\)/)
|
||||
})
|
||||
|
||||
test('覆盖国内仓、待单、完成入库、部分和全部出库及列表详情流水', () => {
|
||||
|
||||
@@ -9,7 +9,8 @@ const acceptance = fs.readFileSync(path.join(here, '..', 'admin-test-env-accepta
|
||||
const finance = fs.readFileSync(path.join(here, 'finance.mjs'), 'utf8')
|
||||
|
||||
test('正式全量验收默认包含 Finance 模块', () => {
|
||||
assert.match(acceptance, /DEFAULT_MODULES\s*=\s*\[[\s\S]*['"]finance['"]/)
|
||||
assert.match(acceptance, /CONFIGURED_MODULES\s*=\s*\[[\s\S]*['"]finance['"]/)
|
||||
assert.match(acceptance, /DEFAULT_MODULES\s*=\s*normalizeModuleOrder\(CONFIGURED_MODULES\)/)
|
||||
})
|
||||
|
||||
test('验收请求器支持并透传额外请求头', () => {
|
||||
|
||||
@@ -46,7 +46,8 @@ test('writes carry marker idempotency and include replay and stale-version confl
|
||||
assert.match(source, /错误 sourceVersion 调整产生并发版本冲突/)
|
||||
})
|
||||
|
||||
test('uses existing ACTIVE Warehouse supplier and never creates one', () => {
|
||||
assert.match(source, /\/api\/platform\/v1\/suppliers\?page=1&size=200&status=ACTIVE&category=BOOKING/)
|
||||
test('uses the fee item supplier category to select an existing ACTIVE supplier and never creates one', () => {
|
||||
assert.match(source, /\/api\/platform\/v1\/suppliers\?page=1&size=200&status=ACTIVE\$\{suffix\}/)
|
||||
assert.match(source, /const supplier = await loadActiveSupplier\(context, payableItem\?\.supplierCategory \|\| null\)/)
|
||||
assert.doesNotMatch(source, /\/api\/platform\/v1\/partners/)
|
||||
})
|
||||
|
||||
@@ -12,6 +12,10 @@ test('统一初始化 SQL 保留最小登录与客户主体', () => {
|
||||
assert.equal((sql.match(/'platform_admin'/g) || []).length, 1)
|
||||
assert.equal((sql.match(/'merchant_admin'/g) || []).length, 1)
|
||||
assert.match(sql, /\(10001, 'IT_TEST', 'IT 测试客户'/)
|
||||
const accountSeed = sql.match(/INSERT INTO auth_account \([\s\S]*?deleted = 0;/)?.[0]
|
||||
assert.ok(accountSeed, 'missing auth account seed')
|
||||
assert.doesNotMatch(accountSeed, /ON DUPLICATE KEY UPDATE[\s\S]*?password_hash\s*=/,
|
||||
're-running the unified SQL must not reset an existing account password')
|
||||
})
|
||||
|
||||
test('IT 测试客户初始化后具备已审核的必填资质和下单资格', () => {
|
||||
@@ -34,25 +38,22 @@ test('统一初始化 SQL 提供人工验收所需公共仓储主数据', () =>
|
||||
assert.doesNotMatch(palletSeed, /\bstatus\b|'AVAILABLE'/)
|
||||
})
|
||||
|
||||
test('三期权限迁移允许脚本历史版本写入的旧权限并在随后收敛', () => {
|
||||
test('三期权限迁移删除退役权限并只保留 canonical 权限', () => {
|
||||
for (const source of [sql, oceanBookingSchema]) {
|
||||
assert.match(source, /id = 5102141[\s\S]*?ocean-booking:view/)
|
||||
assert.match(source, /id = 5102147[\s\S]*?ocean-booking:cancel[\s\S]*?ocean-booking:edit/)
|
||||
assert.match(source, /id = 5102148[\s\S]*?ocean-booking:change[\s\S]*?ocean-booking:delete/)
|
||||
assert.match(source, /SET permission_code='platform:firstleg:ocean-booking:view',status='INACTIVE',deleted=1/)
|
||||
assert.match(source, /UPDATE iam_permission SET status='INACTIVE',deleted=1 WHERE id=5102141/)
|
||||
assert.match(source, /DELETE FROM iam_permission WHERE id IN \(5102143,5102144,5102145\)/)
|
||||
assert.match(source, /DELETE FROM iam_permission WHERE id IN \(5102141,5102143,5102144,5102145\)/)
|
||||
assert.match(source, /5102147[\s\S]*?platform:firstleg:ocean-booking:edit/)
|
||||
assert.match(source, /5102148[\s\S]*?platform:firstleg:ocean-booking:delete/)
|
||||
assert.doesNotMatch(source, /platform:firstleg:ocean-booking:(view|cancel|change)/)
|
||||
assert.ok(
|
||||
source.indexOf('DELETE FROM iam_permission WHERE id IN (5102143,5102144,5102145)') <
|
||||
source.indexOf('DELETE FROM iam_permission WHERE id IN (5102141,5102143,5102144,5102145)') <
|
||||
source.indexOf('(5102147,0,\'PLATFORM\',\'BUTTON\',5102140,\'platform:firstleg:ocean-booking:edit\''),
|
||||
'legacy ocean-booking edit permission must be removed before assigning the code to 5102147',
|
||||
)
|
||||
}
|
||||
|
||||
for (const source of [sql, truckAppointmentSchema]) {
|
||||
assert.match(source, /id = 5102151[\s\S]*?truck-appointment:view/)
|
||||
assert.match(source, /SET permission_code='platform:firstleg:truck-appointment:view',status='INACTIVE',deleted=1/)
|
||||
assert.match(source, /UPDATE iam_permission SET status='INACTIVE',deleted=1 WHERE id=5102151/)
|
||||
assert.match(source, /DELETE FROM iam_permission WHERE id=5102151/)
|
||||
assert.doesNotMatch(source, /platform:firstleg:truck-appointment:view[',]/)
|
||||
}
|
||||
|
||||
assert.match(sql, /status='ACTIVE' AND deleted=0[\s\S]*?id BETWEEN 5102140 AND 5102149/)
|
||||
|
||||
@@ -35,9 +35,9 @@ test('focused splitting and manual groups resolve producers before consumers wit
|
||||
'merchant-qualification-fixture',
|
||||
'phase3-container-loading',
|
||||
'phase3-loading',
|
||||
'phase3-order-splitting',
|
||||
'ocean-bookings',
|
||||
'phase3-loading-finalize',
|
||||
'phase3-order-splitting',
|
||||
'phase3-customs',
|
||||
'manual-state-matrix',
|
||||
]
|
||||
|
||||
@@ -6,9 +6,10 @@ const acceptance = readFileSync(new URL('../admin-test-env-acceptance.mjs', impo
|
||||
const fixture = readFileSync(new URL('./merchant-qualification-fixture.mjs', import.meta.url), 'utf8')
|
||||
|
||||
test('默认全量验收先准备已审核商户再运行订单链路', () => {
|
||||
const modules = acceptance.match(/const DEFAULT_MODULES = \[([^\n]+)\]/)?.[1] || ''
|
||||
const modules = acceptance.match(/const CONFIGURED_MODULES = \[([^\n]+)\]/)?.[1] || ''
|
||||
assert.match(modules, /^'merchant-qualification-fixture', 'customers'/)
|
||||
assert.ok(modules.indexOf("'merchant-qualification-fixture'") < modules.indexOf("'orders'"))
|
||||
assert.match(acceptance, /DEFAULT_MODULES\s*=\s*normalizeModuleOrder\(CONFIGURED_MODULES\)/)
|
||||
})
|
||||
|
||||
test('商户夹具通过正式 File 和 IAM 审核流程建立下单资格', () => {
|
||||
|
||||
@@ -41,7 +41,7 @@ test('OpenAPI freezes LOADING incremental plan capabilities and optimistic versi
|
||||
})
|
||||
|
||||
test('default fixture publishes a second marker-owned inbound for the same-plan increment', () => {
|
||||
assert.match(entry, /const incrementalMarker = `\$\{originalMarker\}-LOAD-INC`/)
|
||||
assert.match(entry, /const incrementalMarker = `\$\{originalMarker\}-LOAD\$\{suffix\}-INC`/)
|
||||
assert.match(entry, /orders-phase3-loading-incremental-fixture/)
|
||||
assert.match(entry, /inbound-measurement-phase3-loading-incremental-fixture/)
|
||||
assert.match(entry, /phase3LoadingIncrementalPackageCount = 2/)
|
||||
|
||||
Reference in New Issue
Block a user