优化
This commit is contained in:
+4
-20
@@ -186,27 +186,11 @@ SELECT
|
|||||||
|
|
||||||
上述三个结果 `public_scope_violations`、`customer_scope_violations`、`parent_child_scope_mismatches` 必须都为 `0`。
|
上述三个结果 `public_scope_violations`、`customer_scope_violations`、`parent_child_scope_mismatches` 必须都为 `0`。
|
||||||
|
|
||||||
## 船司 FBA 价格公共作用域迁移
|
## 船司 FBA 价格公共作用域
|
||||||
|
|
||||||
- `fl_carrier_fba_rate` 的船司 FBA 价格固定归平台作用域 `tenant_id = 0`;客户计费规则仍按客户 `tenant_id > 0` 隔离。
|
- 当前测试环境 `fl_carrier_fba_rate` 为空表,不执行存量价格迁移。
|
||||||
- 固定入口会先检查存量价格的 `(rate_code, rate_version)` 重复,以及相同匹配维度的有效期重叠;发现冲突时通过 `SQLSTATE 45000` 中止,不会自动覆盖价格。
|
- 初始化表结构将船司 FBA 价格定义为平台公共价格,Firstleg 创建、查询和计费匹配固定使用 `tenant_id = 0`;客户计费规则仍按客户 `tenant_id > 0` 隔离。
|
||||||
- 无冲突时,固定入口才会把存量船司价格迁移到 `tenant_id = 0`,并在末尾验证不存在非平台价格作用域。迁移完成后再启动或重启 `firstleg-service`。
|
- 初始化或重建测试库后,再启动或重启 `firstleg-service`。
|
||||||
|
|
||||||
执行前可只读盘点:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
SELECT tenant_id, COUNT(*) AS total
|
|
||||||
FROM baiyue_firstleg.fl_carrier_fba_rate
|
|
||||||
GROUP BY tenant_id
|
|
||||||
ORDER BY tenant_id;
|
|
||||||
|
|
||||||
SELECT rate_code, rate_version, COUNT(*) AS total
|
|
||||||
FROM baiyue_firstleg.fl_carrier_fba_rate
|
|
||||||
GROUP BY rate_code, rate_version
|
|
||||||
HAVING COUNT(*) > 1;
|
|
||||||
```
|
|
||||||
|
|
||||||
如果固定入口因价格冲突中止,应先由业务确认保留版本、有效期和价格金额,再清理冲突后重新完整执行脚本;不要直接手工把冲突记录改为 `0`。
|
|
||||||
|
|
||||||
## 海外仓阶梯费用增量
|
## 海外仓阶梯费用增量
|
||||||
|
|
||||||
|
|||||||
@@ -3053,61 +3053,6 @@ PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
|||||||
|
|
||||||
DROP PROCEDURE IF EXISTS phase2_fba_add_column;
|
DROP PROCEDURE IF EXISTS phase2_fba_add_column;
|
||||||
|
|
||||||
-- 船司 FBA 价格是平台公共主数据;迁移前检查版本和有效期冲突,避免静默覆盖客户价格。
|
|
||||||
DROP PROCEDURE IF EXISTS phase2_fba_migrate_carrier_rate_scope;
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE PROCEDURE phase2_fba_migrate_carrier_rate_scope()
|
|
||||||
BEGIN
|
|
||||||
DECLARE v_conflicts INT DEFAULT 0;
|
|
||||||
|
|
||||||
SELECT COUNT(*) INTO v_conflicts
|
|
||||||
FROM (
|
|
||||||
SELECT rate_code, rate_version
|
|
||||||
FROM fl_carrier_fba_rate
|
|
||||||
GROUP BY rate_code, rate_version
|
|
||||||
HAVING COUNT(*) > 1
|
|
||||||
) AS duplicate_versions;
|
|
||||||
IF v_conflicts > 0 THEN
|
|
||||||
SIGNAL SQLSTATE '45000'
|
|
||||||
SET MESSAGE_TEXT = 'FBA价格迁移失败:不同客户存在重复价格编码版本,请先合并';
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
SELECT COUNT(*) INTO v_conflicts
|
|
||||||
FROM (
|
|
||||||
SELECT first_rate.id
|
|
||||||
FROM fl_carrier_fba_rate first_rate
|
|
||||||
JOIN fl_carrier_fba_rate second_rate
|
|
||||||
ON first_rate.id < second_rate.id
|
|
||||||
AND first_rate.status = 'ACTIVE'
|
|
||||||
AND second_rate.status = 'ACTIVE'
|
|
||||||
AND first_rate.origin_warehouse_id <=> second_rate.origin_warehouse_id
|
|
||||||
AND first_rate.business_type <=> second_rate.business_type
|
|
||||||
AND first_rate.channel_code <=> second_rate.channel_code
|
|
||||||
AND first_rate.carrier_id <=> second_rate.carrier_id
|
|
||||||
AND first_rate.destination_code <=> second_rate.destination_code
|
|
||||||
AND first_rate.charge_unit <=> second_rate.charge_unit
|
|
||||||
AND first_rate.effective_from < COALESCE(second_rate.effective_to, '9999-12-31 23:59:59.999')
|
|
||||||
AND second_rate.effective_from < COALESCE(first_rate.effective_to, '9999-12-31 23:59:59.999')
|
|
||||||
LIMIT 1
|
|
||||||
) AS overlapping_rates;
|
|
||||||
IF v_conflicts > 0 THEN
|
|
||||||
SIGNAL SQLSTATE '45000'
|
|
||||||
SET MESSAGE_TEXT = 'FBA价格迁移失败:公共匹配维度存在有效期重叠,请先合并';
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
UPDATE fl_carrier_fba_rate
|
|
||||||
SET tenant_id = 0
|
|
||||||
WHERE tenant_id <> 0;
|
|
||||||
|
|
||||||
IF EXISTS (SELECT 1 FROM fl_carrier_fba_rate WHERE tenant_id <> 0) THEN
|
|
||||||
SIGNAL SQLSTATE '45000'
|
|
||||||
SET MESSAGE_TEXT = 'FBA价格迁移失败:仍存在非平台价格作用域';
|
|
||||||
END IF;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
CALL phase2_fba_migrate_carrier_rate_scope();
|
|
||||||
DROP PROCEDURE IF EXISTS phase2_fba_migrate_carrier_rate_scope;
|
|
||||||
|
|
||||||
-- 旧索引可能缺少业务类型、船司和结束时间;用新索引名并存,避免破坏线上依赖。
|
-- 旧索引可能缺少业务类型、船司和结束时间;用新索引名并存,避免破坏线上依赖。
|
||||||
SET @idx_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS
|
SET @idx_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'fl_carrier_fba_rate' AND INDEX_NAME = 'idx_fba_rate_unique_match');
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'fl_carrier_fba_rate' AND INDEX_NAME = 'idx_fba_rate_unique_match');
|
||||||
|
|||||||
@@ -56,61 +56,6 @@ SET @sql = IF(@resource_tenant_needs_modify > 0,
|
|||||||
'SELECT 1');
|
'SELECT 1');
|
||||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
-- 船司 FBA 价格是平台公共主数据;迁移前检查版本和有效期冲突,避免静默覆盖客户价格。
|
|
||||||
DROP PROCEDURE IF EXISTS phase2_fba_migrate_carrier_rate_scope;
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE PROCEDURE phase2_fba_migrate_carrier_rate_scope()
|
|
||||||
BEGIN
|
|
||||||
DECLARE v_conflicts INT DEFAULT 0;
|
|
||||||
|
|
||||||
SELECT COUNT(*) INTO v_conflicts
|
|
||||||
FROM (
|
|
||||||
SELECT rate_code, rate_version
|
|
||||||
FROM fl_carrier_fba_rate
|
|
||||||
GROUP BY rate_code, rate_version
|
|
||||||
HAVING COUNT(*) > 1
|
|
||||||
) AS duplicate_versions;
|
|
||||||
IF v_conflicts > 0 THEN
|
|
||||||
SIGNAL SQLSTATE '45000'
|
|
||||||
SET MESSAGE_TEXT = 'FBA价格迁移失败:不同客户存在重复价格编码版本,请先合并';
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
SELECT COUNT(*) INTO v_conflicts
|
|
||||||
FROM (
|
|
||||||
SELECT first_rate.id
|
|
||||||
FROM fl_carrier_fba_rate first_rate
|
|
||||||
JOIN fl_carrier_fba_rate second_rate
|
|
||||||
ON first_rate.id < second_rate.id
|
|
||||||
AND first_rate.status = 'ACTIVE'
|
|
||||||
AND second_rate.status = 'ACTIVE'
|
|
||||||
AND first_rate.origin_warehouse_id <=> second_rate.origin_warehouse_id
|
|
||||||
AND first_rate.business_type <=> second_rate.business_type
|
|
||||||
AND first_rate.channel_code <=> second_rate.channel_code
|
|
||||||
AND first_rate.carrier_id <=> second_rate.carrier_id
|
|
||||||
AND first_rate.destination_code <=> second_rate.destination_code
|
|
||||||
AND first_rate.charge_unit <=> second_rate.charge_unit
|
|
||||||
AND first_rate.effective_from < COALESCE(second_rate.effective_to, '9999-12-31 23:59:59.999')
|
|
||||||
AND second_rate.effective_from < COALESCE(first_rate.effective_to, '9999-12-31 23:59:59.999')
|
|
||||||
LIMIT 1
|
|
||||||
) AS overlapping_rates;
|
|
||||||
IF v_conflicts > 0 THEN
|
|
||||||
SIGNAL SQLSTATE '45000'
|
|
||||||
SET MESSAGE_TEXT = 'FBA价格迁移失败:公共匹配维度存在有效期重叠,请先合并';
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
UPDATE fl_carrier_fba_rate
|
|
||||||
SET tenant_id = 0
|
|
||||||
WHERE tenant_id <> 0;
|
|
||||||
|
|
||||||
IF EXISTS (SELECT 1 FROM fl_carrier_fba_rate WHERE tenant_id <> 0) THEN
|
|
||||||
SIGNAL SQLSTATE '45000'
|
|
||||||
SET MESSAGE_TEXT = 'FBA价格迁移失败:仍存在非平台价格作用域';
|
|
||||||
END IF;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
CALL phase2_fba_migrate_carrier_rate_scope();
|
|
||||||
DROP PROCEDURE IF EXISTS phase2_fba_migrate_carrier_rate_scope;
|
|
||||||
|
|
||||||
DROP PROCEDURE IF EXISTS phase2_fba_add_column;
|
DROP PROCEDURE IF EXISTS phase2_fba_add_column;
|
||||||
|
|
||||||
-- 旧索引可能缺少业务类型、船司和结束时间;用新索引名并存,避免破坏线上依赖。
|
-- 旧索引可能缺少业务类型、船司和结束时间;用新索引名并存,避免破坏线上依赖。
|
||||||
|
|||||||
-14
@@ -38,18 +38,4 @@ class InboundWorkflowSqlContractTest {
|
|||||||
.contains("SET warehouse_resource_tenant_id = 0")
|
.contains("SET warehouse_resource_tenant_id = 0")
|
||||||
.contains("MODIFY COLUMN warehouse_resource_tenant_id BIGINT UNSIGNED NOT NULL");
|
.contains("MODIFY COLUMN warehouse_resource_tenant_id BIGINT UNSIGNED NOT NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("船司价格存量迁移固定到平台作用域并拒绝冲突")
|
|
||||||
void shouldMigrateCarrierRatesToPublicScopeWithoutOverwritingConflicts() throws Exception {
|
|
||||||
String migration = new ClassPathResource("db/phase2-fba-pricing-migration.sql")
|
|
||||||
.getContentAsString(StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
assertThat(migration)
|
|
||||||
.contains("phase2_fba_migrate_carrier_rate_scope")
|
|
||||||
.contains("GROUP BY rate_code, rate_version")
|
|
||||||
.contains("公共匹配维度存在有效期重叠")
|
|
||||||
.contains("SET tenant_id = 0")
|
|
||||||
.contains("WHERE tenant_id <> 0");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
"reportName": "二期测试环境 API 验收",
|
||||||
|
"scope": [
|
||||||
|
"头程下单",
|
||||||
|
"商户提交",
|
||||||
|
"平台审核",
|
||||||
|
"异步生成入库单",
|
||||||
|
"测量草稿",
|
||||||
|
"称重图片与结果",
|
||||||
|
"人工修正与确认",
|
||||||
|
"测量提交与审核",
|
||||||
|
"计费试算"
|
||||||
|
],
|
||||||
|
"excluded": [
|
||||||
|
"分柜",
|
||||||
|
"预装",
|
||||||
|
"PDA 拣货",
|
||||||
|
"装柜证据",
|
||||||
|
"装柜完成",
|
||||||
|
"派送"
|
||||||
|
],
|
||||||
|
"gateway": "http://8.163.30.128:9000",
|
||||||
|
"marker": "API-E2E-20260806180457",
|
||||||
|
"startedAt": "2026-08-06T18:04:57.0000000",
|
||||||
|
"finishedAt": "2026-08-06T18:04:59.2138202+08:00",
|
||||||
|
"success": false,
|
||||||
|
"passedCount": 4,
|
||||||
|
"failedCount": 1,
|
||||||
|
"ids": {
|
||||||
|
"carrierId": "2085306128758538241",
|
||||||
|
"orderId": null,
|
||||||
|
"inboundId": null,
|
||||||
|
"measurementId": null,
|
||||||
|
"weightResultId": null,
|
||||||
|
"fileId": null
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"inbound": null,
|
||||||
|
"measurement": null,
|
||||||
|
"weightResult": null
|
||||||
|
},
|
||||||
|
"fatal": "创建头程订单草稿 失败:HTTP=200 code=A0422 message=Validation failed",
|
||||||
|
"billingDefect": null,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "平台登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "商户登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Firstleg 服务健康检查",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建公共测试承运商",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建头程订单草稿",
|
||||||
|
"passed": false,
|
||||||
|
"http": 200,
|
||||||
|
"code": "A0422",
|
||||||
|
"message": "Validation failed",
|
||||||
|
"requestId": "347014a0-f9e9-466a-8cc2-ff947cf946d3",
|
||||||
|
"traceId": "946f25aaf3824d029c5228b1fd4b52f8",
|
||||||
|
"evidence": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"reportName": "二期测试环境 API 验收",
|
||||||
|
"scope": [
|
||||||
|
"头程下单",
|
||||||
|
"商户提交",
|
||||||
|
"平台审核",
|
||||||
|
"异步生成入库单",
|
||||||
|
"测量草稿",
|
||||||
|
"称重图片与结果",
|
||||||
|
"人工修正与确认",
|
||||||
|
"测量提交与审核",
|
||||||
|
"计费试算"
|
||||||
|
],
|
||||||
|
"excluded": [
|
||||||
|
"分柜",
|
||||||
|
"预装",
|
||||||
|
"PDA 拣货",
|
||||||
|
"装柜证据",
|
||||||
|
"装柜完成",
|
||||||
|
"派送"
|
||||||
|
],
|
||||||
|
"gateway": "http://8.163.30.128:9000",
|
||||||
|
"marker": "API-E2E-20260806180542",
|
||||||
|
"startedAt": "2026-08-06T18:05:42.0000000",
|
||||||
|
"finishedAt": "2026-08-06T18:05:42.1924377+08:00",
|
||||||
|
"success": false,
|
||||||
|
"passedCount": 0,
|
||||||
|
"failedCount": 1,
|
||||||
|
"ids": {
|
||||||
|
"carrierId": null,
|
||||||
|
"orderId": null,
|
||||||
|
"inboundId": null,
|
||||||
|
"measurementId": null,
|
||||||
|
"weightResultId": null,
|
||||||
|
"fileId": null
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"inbound": null,
|
||||||
|
"measurement": null,
|
||||||
|
"weightResult": null
|
||||||
|
},
|
||||||
|
"fatal": "平台登录 失败:HTTP=503 code= message=",
|
||||||
|
"billingDefect": null,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "平台登录",
|
||||||
|
"passed": false,
|
||||||
|
"http": 503,
|
||||||
|
"code": "",
|
||||||
|
"message": "",
|
||||||
|
"requestId": "93c3a0a1-684",
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"reportName": "二期测试环境 API 验收",
|
||||||
|
"scope": [
|
||||||
|
"头程下单",
|
||||||
|
"商户提交",
|
||||||
|
"平台审核",
|
||||||
|
"异步生成入库单",
|
||||||
|
"测量草稿",
|
||||||
|
"称重图片与结果",
|
||||||
|
"人工修正与确认",
|
||||||
|
"测量提交与审核",
|
||||||
|
"计费试算"
|
||||||
|
],
|
||||||
|
"excluded": [
|
||||||
|
"分柜",
|
||||||
|
"预装",
|
||||||
|
"PDA 拣货",
|
||||||
|
"装柜证据",
|
||||||
|
"装柜完成",
|
||||||
|
"派送"
|
||||||
|
],
|
||||||
|
"gateway": "http://8.163.30.128:9000",
|
||||||
|
"marker": "API-E2E-20260806180635",
|
||||||
|
"startedAt": "2026-08-06T18:06:35.0000000",
|
||||||
|
"finishedAt": "2026-08-06T18:06:37.8507638+08:00",
|
||||||
|
"success": false,
|
||||||
|
"passedCount": 0,
|
||||||
|
"failedCount": 0,
|
||||||
|
"ids": {
|
||||||
|
"carrierId": null,
|
||||||
|
"orderId": null,
|
||||||
|
"inboundId": null,
|
||||||
|
"measurementId": null,
|
||||||
|
"weightResultId": null,
|
||||||
|
"fileId": null
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"inbound": null,
|
||||||
|
"measurement": null,
|
||||||
|
"weightResult": null
|
||||||
|
},
|
||||||
|
"fatal": "由于目标计算机积极拒绝,无法连接。 (8.163.30.128:9000)",
|
||||||
|
"billingDefect": null,
|
||||||
|
"steps": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
{
|
||||||
|
"reportName": "二期测试环境 API 验收",
|
||||||
|
"scope": [
|
||||||
|
"头程下单",
|
||||||
|
"商户提交",
|
||||||
|
"平台审核",
|
||||||
|
"异步生成入库单",
|
||||||
|
"测量草稿",
|
||||||
|
"称重图片与结果",
|
||||||
|
"人工修正与确认",
|
||||||
|
"测量提交与审核",
|
||||||
|
"计费试算"
|
||||||
|
],
|
||||||
|
"excluded": [
|
||||||
|
"分柜",
|
||||||
|
"预装",
|
||||||
|
"PDA 拣货",
|
||||||
|
"装柜证据",
|
||||||
|
"装柜完成",
|
||||||
|
"派送"
|
||||||
|
],
|
||||||
|
"gateway": "http://8.163.30.128:9000",
|
||||||
|
"marker": "API-E2E-20260806180746",
|
||||||
|
"startedAt": "2026-08-06T18:07:46.0000000",
|
||||||
|
"finishedAt": "2026-08-06T18:07:49.7438673+08:00",
|
||||||
|
"success": false,
|
||||||
|
"passedCount": 4,
|
||||||
|
"failedCount": 1,
|
||||||
|
"ids": {
|
||||||
|
"carrierId": "2085306838682238977",
|
||||||
|
"orderId": null,
|
||||||
|
"inboundId": null,
|
||||||
|
"measurementId": null,
|
||||||
|
"weightResultId": null,
|
||||||
|
"fileId": null
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"inbound": null,
|
||||||
|
"measurement": null,
|
||||||
|
"weightResult": null
|
||||||
|
},
|
||||||
|
"fatal": "创建头程订单草稿 失败:HTTP=200 code=A0422 message=仓库未启用收货能力",
|
||||||
|
"billingDefect": null,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "平台登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "商户登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Firstleg 服务健康检查",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建公共测试承运商",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建头程订单草稿",
|
||||||
|
"passed": false,
|
||||||
|
"http": 200,
|
||||||
|
"code": "A0422",
|
||||||
|
"message": "仓库未启用收货能力",
|
||||||
|
"requestId": "879f056b-40c2-486b-b643-c6ff7ab1a224",
|
||||||
|
"traceId": "282c6a4652d649608deaa0989f1109f8",
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
{
|
||||||
|
"reportName": "二期测试环境 API 验收",
|
||||||
|
"scope": [
|
||||||
|
"头程下单",
|
||||||
|
"商户提交",
|
||||||
|
"平台审核",
|
||||||
|
"异步生成入库单",
|
||||||
|
"测量草稿",
|
||||||
|
"称重图片与结果",
|
||||||
|
"人工修正与确认",
|
||||||
|
"测量提交与审核",
|
||||||
|
"计费试算"
|
||||||
|
],
|
||||||
|
"excluded": [
|
||||||
|
"分柜",
|
||||||
|
"预装",
|
||||||
|
"PDA 拣货",
|
||||||
|
"装柜证据",
|
||||||
|
"装柜完成",
|
||||||
|
"派送"
|
||||||
|
],
|
||||||
|
"gateway": "http://8.163.30.128:9000",
|
||||||
|
"marker": "API-E2E-20260806180915",
|
||||||
|
"startedAt": "2026-08-06T18:09:15.0000000",
|
||||||
|
"finishedAt": "2026-08-06T18:09:18.4509682+08:00",
|
||||||
|
"success": false,
|
||||||
|
"passedCount": 13,
|
||||||
|
"failedCount": 1,
|
||||||
|
"ids": {
|
||||||
|
"warehouseId": "2085307213141311489",
|
||||||
|
"carrierId": "2085307212440862722",
|
||||||
|
"orderId": "2085307214373949442",
|
||||||
|
"inboundId": null,
|
||||||
|
"measurementId": null,
|
||||||
|
"weightResultId": null,
|
||||||
|
"fileId": null
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"inbound": null,
|
||||||
|
"measurement": null,
|
||||||
|
"weightResult": null
|
||||||
|
},
|
||||||
|
"fatal": "商户提交订单 失败:HTTP=200 code=A0403 message=All required enterprise qualifications must be approved",
|
||||||
|
"billingDefect": null,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "平台登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "商户登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Firstleg 服务健康检查",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建公共测试承运商",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建启用收货能力的公共测试仓",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建头程订单草稿",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "重放创建订单幂等请求",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建订单幂等结果一致",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "orderId=2085307214373949442",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "查询订单草稿",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "订单初始状态为 DRAFT",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "status=DRAFT",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "编辑头程订单草稿",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "回查编辑后的订单草稿",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "订单编辑内容已保存",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "customerRemark=API-E2E-20260806180915 编辑后草稿",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "商户提交订单",
|
||||||
|
"passed": false,
|
||||||
|
"http": 200,
|
||||||
|
"code": "A0403",
|
||||||
|
"message": "All required enterprise qualifications must be approved",
|
||||||
|
"requestId": "43731de1-a837-47ed-944e-74a52c778c0d",
|
||||||
|
"traceId": "d65dce17b1974c0e85987a1f5b7b38c0",
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"reportName": "二期测试环境 API 验收",
|
||||||
|
"scope": [
|
||||||
|
"头程下单",
|
||||||
|
"商户提交",
|
||||||
|
"平台审核",
|
||||||
|
"异步生成入库单",
|
||||||
|
"测量草稿",
|
||||||
|
"称重图片与结果",
|
||||||
|
"人工修正与确认",
|
||||||
|
"测量提交与审核",
|
||||||
|
"计费试算"
|
||||||
|
],
|
||||||
|
"excluded": [
|
||||||
|
"分柜",
|
||||||
|
"预装",
|
||||||
|
"PDA 拣货",
|
||||||
|
"装柜证据",
|
||||||
|
"装柜完成",
|
||||||
|
"派送"
|
||||||
|
],
|
||||||
|
"gateway": "http://8.163.30.128:9000",
|
||||||
|
"marker": "API-E2E-20260806181135",
|
||||||
|
"startedAt": "2026-08-06T18:11:35.0000000",
|
||||||
|
"finishedAt": "2026-08-06T18:11:36.8065276+08:00",
|
||||||
|
"success": false,
|
||||||
|
"passedCount": 4,
|
||||||
|
"failedCount": 0,
|
||||||
|
"ids": {
|
||||||
|
"qualificationReviewId": null,
|
||||||
|
"warehouseId": null,
|
||||||
|
"carrierId": null,
|
||||||
|
"orderId": null,
|
||||||
|
"inboundId": null,
|
||||||
|
"measurementId": null,
|
||||||
|
"weightResultId": null,
|
||||||
|
"fileId": null
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"inbound": null,
|
||||||
|
"measurement": null,
|
||||||
|
"weightResult": null
|
||||||
|
},
|
||||||
|
"fatal": "The process cannot access the file 'C:\\Users\\BY-OY\\Desktop\\code\\chongchong-global\\apps\\pda-uniapp\\static\\c7.png' because it is being used by another process.",
|
||||||
|
"billingDefect": null,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "平台登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "商户登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Firstleg 服务健康检查",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "查询商户必备资质",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
{
|
||||||
|
"reportName": "二期测试环境 API 验收",
|
||||||
|
"scope": [
|
||||||
|
"头程下单",
|
||||||
|
"商户提交",
|
||||||
|
"平台审核",
|
||||||
|
"异步生成入库单",
|
||||||
|
"测量草稿",
|
||||||
|
"称重图片与结果",
|
||||||
|
"人工修正与确认",
|
||||||
|
"测量提交与审核",
|
||||||
|
"计费试算"
|
||||||
|
],
|
||||||
|
"excluded": [
|
||||||
|
"分柜",
|
||||||
|
"预装",
|
||||||
|
"PDA 拣货",
|
||||||
|
"装柜证据",
|
||||||
|
"装柜完成",
|
||||||
|
"派送"
|
||||||
|
],
|
||||||
|
"gateway": "http://8.163.30.128:9000",
|
||||||
|
"marker": "API-E2E-20260806181211",
|
||||||
|
"startedAt": "2026-08-06T18:12:11.0000000",
|
||||||
|
"finishedAt": "2026-08-06T18:12:12.6225155+08:00",
|
||||||
|
"success": false,
|
||||||
|
"passedCount": 4,
|
||||||
|
"failedCount": 1,
|
||||||
|
"ids": {
|
||||||
|
"qualificationReviewId": null,
|
||||||
|
"warehouseId": null,
|
||||||
|
"carrierId": null,
|
||||||
|
"orderId": null,
|
||||||
|
"inboundId": null,
|
||||||
|
"measurementId": null,
|
||||||
|
"weightResultId": null,
|
||||||
|
"fileId": null
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"inbound": null,
|
||||||
|
"measurement": null,
|
||||||
|
"weightResult": null
|
||||||
|
},
|
||||||
|
"fatal": "补齐商户营业执照与法人身份证测试包 失败:HTTP=200 code=B0001 message=Only PDF, JPG and PNG files are supported / 仅支持 PDF、JPG、PNG 文件",
|
||||||
|
"billingDefect": null,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "平台登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "商户登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Firstleg 服务健康检查",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "查询商户必备资质",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "补齐商户营业执照与法人身份证测试包",
|
||||||
|
"passed": false,
|
||||||
|
"http": 200,
|
||||||
|
"code": "B0001",
|
||||||
|
"message": "Only PDF, JPG and PNG files are supported / 仅支持 PDF、JPG、PNG 文件",
|
||||||
|
"requestId": "a3322a13-862f-4176-b36a-7f5bf48dabbc",
|
||||||
|
"traceId": "158c6783070f4605b966a8bbb5fd624d",
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
{
|
||||||
|
"reportName": "二期测试环境 API 验收",
|
||||||
|
"scope": [
|
||||||
|
"头程下单",
|
||||||
|
"商户提交",
|
||||||
|
"平台审核",
|
||||||
|
"异步生成入库单",
|
||||||
|
"测量草稿",
|
||||||
|
"称重图片与结果",
|
||||||
|
"人工修正与确认",
|
||||||
|
"测量提交与审核",
|
||||||
|
"计费试算"
|
||||||
|
],
|
||||||
|
"excluded": [
|
||||||
|
"分柜",
|
||||||
|
"预装",
|
||||||
|
"PDA 拣货",
|
||||||
|
"装柜证据",
|
||||||
|
"装柜完成",
|
||||||
|
"派送"
|
||||||
|
],
|
||||||
|
"gateway": "http://8.163.30.128:9000",
|
||||||
|
"marker": "API-E2E-20260806181252",
|
||||||
|
"startedAt": "2026-08-06T18:12:52.0000000",
|
||||||
|
"finishedAt": "2026-08-06T18:12:53.8062380+08:00",
|
||||||
|
"success": false,
|
||||||
|
"passedCount": 4,
|
||||||
|
"failedCount": 1,
|
||||||
|
"ids": {
|
||||||
|
"qualificationReviewId": null,
|
||||||
|
"warehouseId": null,
|
||||||
|
"carrierId": null,
|
||||||
|
"orderId": null,
|
||||||
|
"inboundId": null,
|
||||||
|
"measurementId": null,
|
||||||
|
"weightResultId": null,
|
||||||
|
"fileId": null
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"inbound": null,
|
||||||
|
"measurement": null,
|
||||||
|
"weightResult": null
|
||||||
|
},
|
||||||
|
"fatal": "补齐商户营业执照与法人身份证测试包 失败:HTTP=200 code=A0409 message=Qualifications can only be uploaded before review / 仅待完善或已驳回客户可上传资质",
|
||||||
|
"billingDefect": null,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "平台登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "商户登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Firstleg 服务健康检查",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "查询商户必备资质",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "补齐商户营业执照与法人身份证测试包",
|
||||||
|
"passed": false,
|
||||||
|
"http": 200,
|
||||||
|
"code": "A0409",
|
||||||
|
"message": "Qualifications can only be uploaded before review / 仅待完善或已驳回客户可上传资质",
|
||||||
|
"requestId": "c3dcb898-0edd-4244-97a0-e3b399a334ed",
|
||||||
|
"traceId": "18334f1be9ca4ee8ae0a88f98724cc51",
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,390 @@
|
|||||||
|
{
|
||||||
|
"reportName": "二期测试环境 API 验收",
|
||||||
|
"scope": [
|
||||||
|
"头程下单",
|
||||||
|
"商户提交",
|
||||||
|
"平台审核",
|
||||||
|
"异步生成入库单",
|
||||||
|
"测量草稿",
|
||||||
|
"称重图片与结果",
|
||||||
|
"人工修正与确认",
|
||||||
|
"测量提交与审核",
|
||||||
|
"计费试算"
|
||||||
|
],
|
||||||
|
"excluded": [
|
||||||
|
"分柜",
|
||||||
|
"预装",
|
||||||
|
"PDA 拣货",
|
||||||
|
"装柜证据",
|
||||||
|
"装柜完成",
|
||||||
|
"派送"
|
||||||
|
],
|
||||||
|
"gateway": "http://8.163.30.128:9000",
|
||||||
|
"marker": "API-E2E-20260806181400",
|
||||||
|
"startedAt": "2026-08-06T18:14:00.0000000",
|
||||||
|
"finishedAt": "2026-08-06T18:14:07.3773798+08:00",
|
||||||
|
"success": false,
|
||||||
|
"passedCount": 30,
|
||||||
|
"failedCount": 1,
|
||||||
|
"ids": {
|
||||||
|
"tenantId": "2085308406756851714",
|
||||||
|
"qualificationReviewId": "2085308409122439169",
|
||||||
|
"warehouseId": "2085308410753515522",
|
||||||
|
"carrierId": "2085308410510245890",
|
||||||
|
"orderId": "2085308411180847106",
|
||||||
|
"inboundId": "2085308426690875393",
|
||||||
|
"measurementId": "2085308428624449538",
|
||||||
|
"weightResultId": null,
|
||||||
|
"fileId": null
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"inbound": 0,
|
||||||
|
"measurement": 0,
|
||||||
|
"weightResult": null
|
||||||
|
},
|
||||||
|
"fatal": "上传称重图片并触发 OCR 失败:HTTP=200 code=A0400 message=称重图片仅支持JPG、PNG、BMP",
|
||||||
|
"billingDefect": null,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "平台登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "商户登录",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Firstleg 服务健康检查",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "查询商户必备资质",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "注册隔离的 API E2E 测试企业",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "登录隔离的 API E2E 测试企业",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "补齐商户营业执照与法人身份证测试包",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "提交商户资质审核",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "查询平台待审核企业",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "平台审核通过商户资质",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建公共测试承运商",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建启用收货能力的公共测试仓",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建头程订单草稿",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "重放创建订单幂等请求",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "创建订单幂等结果一致",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "orderId=2085308411180847106",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "查询订单草稿",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "订单初始状态为 DRAFT",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "status=DRAFT",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "编辑头程订单草稿",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "回查编辑后的订单草稿",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "订单编辑内容已保存",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "customerRemark=API-E2E-20260806181400 编辑后草稿",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "商户提交订单",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "统一订单详情查询待审核状态",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "统一订单主状态为 PENDING_REVIEW",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "mainStatus=PENDING_REVIEW",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "平台指派承运商",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "平台审核通过订单",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "异步生成入库单",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "inboundId=2085308426690875393",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "查询入库单详情",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "入库单进入待测量状态",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "processStatus=WAIT_MEASURE, version=0",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "查询初始测量详情",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "保存测量草稿",
|
||||||
|
"passed": true,
|
||||||
|
"http": 200,
|
||||||
|
"code": "200",
|
||||||
|
"message": "success",
|
||||||
|
"requestId": null,
|
||||||
|
"traceId": null,
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "上传称重图片并触发 OCR",
|
||||||
|
"passed": false,
|
||||||
|
"http": 200,
|
||||||
|
"code": "A0400",
|
||||||
|
"message": "称重图片仅支持JPG、PNG、BMP",
|
||||||
|
"requestId": "b527475c-3624-4050-8cb1-13ec7ec48fa5",
|
||||||
|
"traceId": "81f92a40cd554334a987d4c2ff4a8679",
|
||||||
|
"evidence": "",
|
||||||
|
"details": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,431 @@
|
|||||||
|
param(
|
||||||
|
[string]$GatewayBaseUrl = 'http://8.163.30.128:9000',
|
||||||
|
[string]$PlatformUsername = 'platform_admin',
|
||||||
|
[string]$MerchantUsername = 'merchant_admin',
|
||||||
|
[string]$Password = 'ChangeMe123!',
|
||||||
|
[long]$TenantId = 10001,
|
||||||
|
[string]$OutputPath = ''
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$repoRoot = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||||
|
$stamp = Get-Date -Format 'yyyyMMddHHmmss'
|
||||||
|
$marker = "API-E2E-$stamp"
|
||||||
|
if ([string]::IsNullOrWhiteSpace($OutputPath)) {
|
||||||
|
$OutputPath = Join-Path $repoRoot "reports\二期测试环境API验收-$stamp.json"
|
||||||
|
}
|
||||||
|
|
||||||
|
$steps = [System.Collections.Generic.List[object]]::new()
|
||||||
|
$ids = [ordered]@{ tenantId = [string]$TenantId; qualificationReviewId = $null; warehouseId = $null; carrierId = $null; orderId = $null; inboundId = $null; measurementId = $null; weightResultId = $null; fileId = $null }
|
||||||
|
$versions = [ordered]@{ inbound = $null; measurement = $null; weightResult = $null }
|
||||||
|
$fatal = $null
|
||||||
|
$billingDefect = $null
|
||||||
|
|
||||||
|
function New-Key([string]$Action) {
|
||||||
|
return "$marker-$Action-$([guid]::NewGuid().ToString('N'))"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Api(
|
||||||
|
[string]$Method,
|
||||||
|
[string]$Path,
|
||||||
|
[string]$Token = '',
|
||||||
|
[object]$Body = $null,
|
||||||
|
[hashtable]$ExtraHeaders = @{}
|
||||||
|
) {
|
||||||
|
$headers = @{}
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($Token)) { $headers.Authorization = "Bearer $Token" }
|
||||||
|
foreach ($entry in $ExtraHeaders.GetEnumerator()) { $headers[$entry.Key] = $entry.Value }
|
||||||
|
$args = @{ Method = $Method; Uri = "$GatewayBaseUrl$Path"; Headers = $headers; TimeoutSec = 30; SkipHttpErrorCheck = $true }
|
||||||
|
if ($null -ne $Body) {
|
||||||
|
$args.ContentType = 'application/json; charset=utf-8'
|
||||||
|
$jsonText = $Body | ConvertTo-Json -Depth 20 -Compress
|
||||||
|
$args.Body = [Text.Encoding]::UTF8.GetBytes($jsonText)
|
||||||
|
}
|
||||||
|
$response = Invoke-WebRequest @args
|
||||||
|
$json = $null
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($response.Content)) {
|
||||||
|
try { $json = $response.Content | ConvertFrom-Json } catch { }
|
||||||
|
}
|
||||||
|
return [pscustomobject]@{
|
||||||
|
http = [int]$response.StatusCode
|
||||||
|
body = $json
|
||||||
|
raw = if ($null -eq $json) { $response.Content } else { $null }
|
||||||
|
requestId = if ($null -ne $json) { $json.requestId } else { $response.Headers['X-Request-Id'] }
|
||||||
|
traceId = if ($null -ne $json) { $json.traceId } else { $response.Headers['X-Trace-Id'] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Upload([string]$Path, [string]$Token, [string]$FilePath) {
|
||||||
|
$response = Invoke-WebRequest -Method POST -Uri "$GatewayBaseUrl$Path" `
|
||||||
|
-Headers @{ Authorization = "Bearer $Token" } -Form @{ file = Get-Item -LiteralPath $FilePath } `
|
||||||
|
-TimeoutSec 60 -SkipHttpErrorCheck
|
||||||
|
$json = $null
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($response.Content)) {
|
||||||
|
try { $json = $response.Content | ConvertFrom-Json } catch { }
|
||||||
|
}
|
||||||
|
return [pscustomobject]@{
|
||||||
|
http = [int]$response.StatusCode
|
||||||
|
body = $json
|
||||||
|
raw = if ($null -eq $json) { $response.Content } else { $null }
|
||||||
|
requestId = if ($null -ne $json) { $json.requestId } else { $response.Headers['X-Request-Id'] }
|
||||||
|
traceId = if ($null -ne $json) { $json.traceId } else { $response.Headers['X-Trace-Id'] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-RequiredQualificationUpload([string]$Token, [string]$FilePath, [string]$CreditCode) {
|
||||||
|
$query = "unifiedSocialCreditCode=$CreditCode&replaceBusinessLicense=true&replaceLegalPersonId=false"
|
||||||
|
$businessFile = Get-Item -LiteralPath $FilePath
|
||||||
|
$legalPersonFile = Get-Item -LiteralPath (Join-Path $businessFile.DirectoryName 'c8.png')
|
||||||
|
$content = & curl.exe -sS -X POST "$GatewayBaseUrl/api/merchant/v1/files/qualifications/required-package?$query" `
|
||||||
|
-H "Authorization: Bearer $Token" `
|
||||||
|
-F "businessLicense=@$($businessFile.FullName);type=image/png" `
|
||||||
|
-F "legalPersonId=@$($legalPersonFile.FullName);type=image/png"
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw '必备资质包上传发生传输错误' }
|
||||||
|
$json = $null
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($content)) {
|
||||||
|
try { $json = $content | ConvertFrom-Json } catch { }
|
||||||
|
}
|
||||||
|
return [pscustomobject]@{
|
||||||
|
http = 200
|
||||||
|
body = $json
|
||||||
|
raw = if ($null -eq $json) { [string]$content } else { $null }
|
||||||
|
requestId = if ($null -ne $json) { $json.requestId } else { $null }
|
||||||
|
traceId = if ($null -ne $json) { $json.traceId } else { $null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Add-Step([string]$Name, $Response, [bool]$Passed, [string]$Evidence = '') {
|
||||||
|
$code = if ($null -ne $Response.body) { [string]$Response.body.code } else { $null }
|
||||||
|
$message = if ($null -ne $Response.body) { [string]$Response.body.message } else { [string]$Response.raw }
|
||||||
|
$steps.Add([pscustomobject]@{
|
||||||
|
name = $Name
|
||||||
|
passed = $Passed
|
||||||
|
http = $Response.http
|
||||||
|
code = $code
|
||||||
|
message = $message
|
||||||
|
requestId = $Response.requestId
|
||||||
|
traceId = $Response.traceId
|
||||||
|
evidence = $Evidence
|
||||||
|
details = if ($Passed -or $null -eq $Response.body) { $null } else { $Response.body.data }
|
||||||
|
})
|
||||||
|
Write-Host "[$(if ($Passed) { '通过' } else { '失败' })] $Name HTTP=$($Response.http) code=$code $Evidence"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Require-Success([string]$Name, $Response, [string]$Evidence = '') {
|
||||||
|
$passed = $Response.http -eq 200 -and [string]$Response.body.code -eq '200'
|
||||||
|
Add-Step $Name $Response $passed $Evidence
|
||||||
|
if (-not $passed) { throw "$Name 失败:HTTP=$($Response.http) code=$($Response.body.code) message=$($Response.body.message)" }
|
||||||
|
return $Response.body.data
|
||||||
|
}
|
||||||
|
|
||||||
|
function Require-Condition([string]$Name, $Response, [bool]$Condition, [string]$Evidence) {
|
||||||
|
$passed = $Response.http -eq 200 -and [string]$Response.body.code -eq '200' -and $Condition
|
||||||
|
Add-Step $Name $Response $passed $Evidence
|
||||||
|
if (-not $passed) { throw "$Name 断言失败:$Evidence" }
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$platformLoginResponse = Invoke-Api POST '/api/auth/login' '' @{ username = $PlatformUsername; password = $Password }
|
||||||
|
$platformLogin = Require-Success '平台登录' $platformLoginResponse
|
||||||
|
$platformToken = $platformLogin.accessToken
|
||||||
|
|
||||||
|
$merchantLoginResponse = Invoke-Api POST '/api/auth/login' '' @{ username = $MerchantUsername; password = $Password }
|
||||||
|
$merchantLogin = Require-Success '商户登录' $merchantLoginResponse
|
||||||
|
$merchantToken = $merchantLogin.accessToken
|
||||||
|
|
||||||
|
$healthResponse = Invoke-Api GET '/api/platform/v1/first-leg/status' $platformToken
|
||||||
|
$null = Require-Success 'Firstleg 服务健康检查' $healthResponse
|
||||||
|
|
||||||
|
$qualificationsResponse = Invoke-Api GET '/api/merchant/v1/iam/tenant/qualifications' $merchantToken
|
||||||
|
$qualifications = @(Require-Success '查询商户必备资质' $qualificationsResponse)
|
||||||
|
$approvedTypes = @($qualifications | Where-Object { $_.status -eq 'APPROVED' } | ForEach-Object { $_.qualificationType })
|
||||||
|
if ('BUSINESS_LICENSE' -notin $approvedTypes -or 'LEGAL_PERSON_ID' -notin $approvedTypes) {
|
||||||
|
$e2eUsername = "api_e2e_$stamp"
|
||||||
|
$e2ePassword = 'ApiE2e123!'
|
||||||
|
$registerResponse = Invoke-Api POST '/api/auth/register' '' @{
|
||||||
|
username = $e2eUsername; password = $e2ePassword; displayName = 'API E2E Tester'
|
||||||
|
companyName = "API E2E 测试企业 $stamp"; legalPerson = 'API Tester'; legalPhone = '13800138000'
|
||||||
|
contactEmail = "api-e2e-$stamp@example.com"; countryCode = 'CN'; address = 'API E2E 测试地址'
|
||||||
|
}
|
||||||
|
$registration = Require-Success '注册隔离的 API E2E 测试企业' $registerResponse
|
||||||
|
$TenantId = [long]$registration.tenantId
|
||||||
|
$ids.tenantId = [string]$TenantId
|
||||||
|
|
||||||
|
$e2eLoginResponse = Invoke-Api POST '/api/auth/login' '' @{ username = $e2eUsername; password = $e2ePassword }
|
||||||
|
$e2eLogin = Require-Success '登录隔离的 API E2E 测试企业' $e2eLoginResponse
|
||||||
|
$merchantToken = $e2eLogin.accessToken
|
||||||
|
|
||||||
|
$qualificationImage = Join-Path (Split-Path -Parent $repoRoot) 'apps\pda-uniapp\static\c7.png'
|
||||||
|
$creditCode = "91${stamp}A1"
|
||||||
|
$qualificationUploadResponse = Invoke-RequiredQualificationUpload $merchantToken $qualificationImage $creditCode
|
||||||
|
$null = Require-Success '补齐商户营业执照与法人身份证测试包' $qualificationUploadResponse
|
||||||
|
|
||||||
|
$reviewSubmitResponse = Invoke-Api POST '/api/merchant/v1/iam/tenant/qualifications/submit-review' $merchantToken
|
||||||
|
$null = Require-Success '提交商户资质审核' $reviewSubmitResponse
|
||||||
|
$reviewsResponse = Invoke-Api GET '/api/platform/v1/iam/reviews' $platformToken
|
||||||
|
$reviews = @(Require-Success '查询平台待审核企业' $reviewsResponse)
|
||||||
|
$review = @($reviews | Where-Object { [string]$_.tenantId -eq [string]$TenantId } | Select-Object -First 1)
|
||||||
|
if ($review.Count -eq 0) { throw "未找到 tenantId=$TenantId 的资质审核单" }
|
||||||
|
$ids.qualificationReviewId = [string]$review[0].id
|
||||||
|
$reviewApproveResponse = Invoke-Api POST "/api/platform/v1/iam/reviews/$($ids.qualificationReviewId)/approve" $platformToken @{ comment = "$marker 测试环境验收补齐" }
|
||||||
|
$null = Require-Success '平台审核通过商户资质' $reviewApproveResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
$carrierPayload = [ordered]@{
|
||||||
|
partnerCode = "API-E2E-CARRIER-$stamp"
|
||||||
|
partnerName = "API E2E 测试承运商 $stamp"
|
||||||
|
partnerType = 'CARRIER'
|
||||||
|
types = @('CARRIER')
|
||||||
|
contactName = 'API Tester'
|
||||||
|
contactPhone = '13800138000'
|
||||||
|
contactEmail = 'api-e2e@example.com'
|
||||||
|
countryCode = 'CN'
|
||||||
|
province = '广东省'
|
||||||
|
city = '深圳市'
|
||||||
|
district = '南山区'
|
||||||
|
addressLine = 'API E2E 测试地址'
|
||||||
|
postalCode = '518000'
|
||||||
|
status = 'ACTIVE'
|
||||||
|
remark = $marker
|
||||||
|
}
|
||||||
|
$carrierResponse = Invoke-Api POST '/api/platform/v1/partners?tenantId=0' $platformToken $carrierPayload
|
||||||
|
$ids.carrierId = [string](Require-Success '创建公共测试承运商' $carrierResponse)
|
||||||
|
|
||||||
|
$warehousePayload = [ordered]@{
|
||||||
|
tenantId = 0
|
||||||
|
warehouseCode = "API-E2E-WH-$stamp"
|
||||||
|
warehouseName = "API E2E 收货仓 $stamp"
|
||||||
|
warehouseType = 'DOMESTIC'
|
||||||
|
countryCode = 'CN'
|
||||||
|
timezone = 'UTC+8'
|
||||||
|
contactName = 'API Tester'
|
||||||
|
contactPhone = '13800138000'
|
||||||
|
contactEmail = 'api-e2e@example.com'
|
||||||
|
status = 'ACTIVE'
|
||||||
|
remark = $marker
|
||||||
|
address = [ordered]@{
|
||||||
|
addressType = 'WAREHOUSE'; countryCode = 'CN'; stateProvince = '广东省'; city = '深圳市'
|
||||||
|
district = '南山区'; postalCode = '518000'; addressLine1 = 'API E2E 测试收货仓地址'
|
||||||
|
addressLine2 = $null; latitude = $null; longitude = $null
|
||||||
|
}
|
||||||
|
capabilities = @([ordered]@{
|
||||||
|
capabilityCode = 'RECEIVING'; capabilityName = '头程收货'; enabled = $true
|
||||||
|
cutoffTime = '16:00:00'; description = $marker
|
||||||
|
})
|
||||||
|
}
|
||||||
|
$warehouseResponse = Invoke-Api POST '/api/platform/v1/warehouse-admin' $platformToken $warehousePayload
|
||||||
|
$ids.warehouseId = [string](Require-Success '创建启用收货能力的公共测试仓' $warehouseResponse)
|
||||||
|
|
||||||
|
$sender = [ordered]@{
|
||||||
|
companyName = '深圳示例贸易有限公司'; contactName = 'API Tester'; phone = '13800138000'
|
||||||
|
email = 'api-e2e@example.com'; countryCode = 'CN'; province = '广东省'; city = '深圳市'
|
||||||
|
district = '南山区'; addressLine = 'API E2E 测试地址'; postalCode = '518000'
|
||||||
|
}
|
||||||
|
$orderPayload = [ordered]@{
|
||||||
|
customerId = '191000000000000001'
|
||||||
|
customerName = '深圳示例贸易有限公司'
|
||||||
|
transportMode = 'SEA'
|
||||||
|
tradeTerm = 'FOB'
|
||||||
|
destinationCountryCode = 'US'
|
||||||
|
destinationWarehouseId = '193000000000000001'
|
||||||
|
destinationWarehouseName = 'ABE2'
|
||||||
|
expectedShipDate = (Get-Date).AddDays(10).ToString('yyyy-MM-dd')
|
||||||
|
customerRemark = "$marker 初始草稿"
|
||||||
|
sender = $sender
|
||||||
|
receiver = $null
|
||||||
|
cargoes = @([ordered]@{
|
||||||
|
cargoName = 'API E2E 测试货物'; cargoNameEn = 'API E2E Test Cargo'; hsCode = '8518210000'
|
||||||
|
customsHsCode = '8518210000'; packageType = 'CARTON'; packageCount = 1
|
||||||
|
grossWeightKg = 10; netWeightKg = 9; volumeCbm = 0.06
|
||||||
|
lengthCm = 50; widthCm = 40; heightCm = 30; declaredValue = 100; unitDeclaredValue = 100
|
||||||
|
currency = 'USD'; dangerousGoods = $false; cargoRemark = $marker
|
||||||
|
skuNo = "SKU-$stamp"; upcNo = "UPC-$stamp"; unitsPerPackage = 1; totalQuantity = 1
|
||||||
|
material = '塑料'; usage = '测试'; model = 'E2E'; brand = 'API-E2E'
|
||||||
|
})
|
||||||
|
pickupMethod = 'PICKUP'
|
||||||
|
receivingWarehouseId = $ids.warehouseId
|
||||||
|
receivingWarehouseName = $warehousePayload.warehouseName
|
||||||
|
channelCode = 'API-E2E-SEA'
|
||||||
|
channelName = 'API E2E 海运渠道'
|
||||||
|
carrierId = $null
|
||||||
|
carrierName = $null
|
||||||
|
taxMode = 'BUY_DECLARATION'
|
||||||
|
containerMode = 'LCL'
|
||||||
|
customsInspection = $false
|
||||||
|
destinationType = 'FBA'
|
||||||
|
amazonWarehouseCode = 'ABE2'
|
||||||
|
shipmentId = "SHIP-$stamp"
|
||||||
|
referenceId = $marker
|
||||||
|
}
|
||||||
|
|
||||||
|
$createKey = New-Key 'order-create'
|
||||||
|
$createResponse = Invoke-Api POST '/api/merchant/v1/orders/first-leg' $merchantToken $orderPayload @{ 'Idempotency-Key' = $createKey }
|
||||||
|
$ids.orderId = [string](Require-Success '创建头程订单草稿' $createResponse)
|
||||||
|
|
||||||
|
$replayResponse = Invoke-Api POST '/api/merchant/v1/orders/first-leg' $merchantToken $orderPayload @{ 'Idempotency-Key' = $createKey }
|
||||||
|
$replayedOrderId = [string](Require-Success '重放创建订单幂等请求' $replayResponse)
|
||||||
|
Require-Condition '创建订单幂等结果一致' $replayResponse ($replayedOrderId -eq $ids.orderId) "orderId=$replayedOrderId"
|
||||||
|
|
||||||
|
$draftDetailResponse = Invoke-Api GET "/api/merchant/v1/orders/first-leg/$($ids.orderId)" $merchantToken
|
||||||
|
$draftDetail = Require-Success '查询订单草稿' $draftDetailResponse
|
||||||
|
Require-Condition '订单初始状态为 DRAFT' $draftDetailResponse ($draftDetail.order.status -eq 'DRAFT') "status=$($draftDetail.order.status)"
|
||||||
|
|
||||||
|
$orderPayload.customerRemark = "$marker 编辑后草稿"
|
||||||
|
$updateResponse = Invoke-Api PUT "/api/merchant/v1/orders/first-leg/$($ids.orderId)" $merchantToken $orderPayload
|
||||||
|
$null = Require-Success '编辑头程订单草稿' $updateResponse
|
||||||
|
$editedDetailResponse = Invoke-Api GET "/api/merchant/v1/orders/first-leg/$($ids.orderId)" $merchantToken
|
||||||
|
$editedDetail = Require-Success '回查编辑后的订单草稿' $editedDetailResponse
|
||||||
|
Require-Condition '订单编辑内容已保存' $editedDetailResponse ($editedDetail.order.customerRemark -eq $orderPayload.customerRemark) "customerRemark=$($editedDetail.order.customerRemark)"
|
||||||
|
|
||||||
|
$submitResponse = Invoke-Api POST "/api/merchant/v1/orders/first-leg/$($ids.orderId)/submit" $merchantToken $null @{ 'Idempotency-Key' = (New-Key 'order-submit') }
|
||||||
|
$null = Require-Success '商户提交订单' $submitResponse
|
||||||
|
|
||||||
|
$unifiedPendingResponse = Invoke-Api GET "/api/platform/v1/orders/$($ids.orderId)?tenantId=$TenantId" $platformToken
|
||||||
|
$unifiedPending = Require-Success '统一订单详情查询待审核状态' $unifiedPendingResponse
|
||||||
|
Require-Condition '统一订单主状态为 PENDING_REVIEW' $unifiedPendingResponse ($unifiedPending.summary.mainStatus -eq 'PENDING_REVIEW') "mainStatus=$($unifiedPending.summary.mainStatus)"
|
||||||
|
|
||||||
|
$carrierAssignResponse = Invoke-Api PUT "/api/platform/v1/orders/first-leg/$($ids.orderId)/carrier?tenantId=$TenantId" $platformToken @{ carrierId = $ids.carrierId }
|
||||||
|
$null = Require-Success '平台指派承运商' $carrierAssignResponse
|
||||||
|
|
||||||
|
$approveOrderResponse = Invoke-Api POST "/api/platform/v1/orders/first-leg/$($ids.orderId)/approve?tenantId=$TenantId" $platformToken
|
||||||
|
$null = Require-Success '平台审核通过订单' $approveOrderResponse
|
||||||
|
|
||||||
|
$unifiedApprovedResponse = $null
|
||||||
|
$unifiedApproved = $null
|
||||||
|
for ($attempt = 1; $attempt -le 20; $attempt++) {
|
||||||
|
$unifiedApprovedResponse = Invoke-Api GET "/api/platform/v1/orders/$($ids.orderId)?tenantId=$TenantId" $platformToken
|
||||||
|
if ($unifiedApprovedResponse.http -eq 200 -and [string]$unifiedApprovedResponse.body.code -eq '200' -and $null -ne $unifiedApprovedResponse.body.data.summary.inboundId) {
|
||||||
|
$unifiedApproved = $unifiedApprovedResponse.body.data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Start-Sleep -Seconds 3
|
||||||
|
}
|
||||||
|
$inboundReady = $null -ne $unifiedApproved -and $null -ne $unifiedApproved.summary.inboundId
|
||||||
|
Add-Step '异步生成入库单' $unifiedApprovedResponse $inboundReady $(if ($inboundReady) { "inboundId=$($unifiedApproved.summary.inboundId)" } else { '60 秒内未取得 inboundId' })
|
||||||
|
if (-not $inboundReady) { throw '订单审核后 60 秒内未异步生成入库单' }
|
||||||
|
$ids.inboundId = [string]$unifiedApproved.summary.inboundId
|
||||||
|
$versions.inbound = [int]$unifiedApproved.summary.inboundVersion
|
||||||
|
|
||||||
|
$inboundDetailResponse = Invoke-Api GET "/api/platform/inbounds/$($ids.inboundId)?tenantId=$TenantId" $platformToken
|
||||||
|
$inboundDetail = Require-Success '查询入库单详情' $inboundDetailResponse
|
||||||
|
$versions.inbound = [int]$inboundDetail.summary.version
|
||||||
|
Require-Condition '入库单进入待测量状态' $inboundDetailResponse ($inboundDetail.summary.processStatus -eq 'WAIT_MEASURE') "processStatus=$($inboundDetail.summary.processStatus), version=$($versions.inbound)"
|
||||||
|
|
||||||
|
$measurementDetailResponse = Invoke-Api GET "/api/platform/v1/first-leg/inbounds/$($ids.inboundId)/measurement?tenantId=$TenantId" $platformToken
|
||||||
|
$null = Require-Success '查询初始测量详情' $measurementDetailResponse
|
||||||
|
|
||||||
|
$draftPayload = [ordered]@{
|
||||||
|
measurementId = $null; version = 0; originalDocumentNo = $marker
|
||||||
|
originalGrossWeightKg = 10; originalVolumeCbm = 0.06; actualGoodsName = 'API E2E 测试货物'
|
||||||
|
items = @([ordered]@{
|
||||||
|
itemNo = 'ITEM-1'; boxSpecification = '50x40x30cm'; packageCount = 1
|
||||||
|
lengthCm = 50; widthCm = 40; heightCm = 30; unitWeightKg = 10
|
||||||
|
intelligentImageFileId = $null; overLimitWarning = $null
|
||||||
|
outerLengthCm = 50; outerWidthCm = 40; outerHeightCm = 30; remark = $marker
|
||||||
|
})
|
||||||
|
}
|
||||||
|
$saveDraftResponse = Invoke-Api PUT "/api/platform/v1/first-leg/inbounds/$($ids.inboundId)/measurement/draft?tenantId=$TenantId" $platformToken $draftPayload
|
||||||
|
$savedDraft = Require-Success '保存测量草稿' $saveDraftResponse
|
||||||
|
$ids.measurementId = [string]$savedDraft.measurementId
|
||||||
|
$versions.measurement = [int]$savedDraft.version
|
||||||
|
|
||||||
|
$imagePath = Join-Path (Split-Path -Parent $repoRoot) 'apps\pda-uniapp\static\c7.png'
|
||||||
|
if (-not (Test-Path -LiteralPath $imagePath)) { throw "找不到测试称重图片:$imagePath" }
|
||||||
|
$uploadResponse = Invoke-Upload "/api/platform/v1/files/measurements/$TenantId/$($ids.inboundId)" $platformToken $imagePath
|
||||||
|
$uploaded = Require-Success '上传称重图片并触发 OCR' $uploadResponse
|
||||||
|
$ids.fileId = [string]$uploaded.fileId
|
||||||
|
|
||||||
|
$weightPayload = [ordered]@{
|
||||||
|
fileId = $ids.fileId
|
||||||
|
ocrProvider = 'API_E2E_MANUAL'
|
||||||
|
ocrRawText = if ($uploaded.weightValue) { [string]$uploaded.weightValue } else { 'OCR unavailable; manual verification required' }
|
||||||
|
ocrWeightValue = $uploaded.weightValue
|
||||||
|
ocrWeightUnit = if ($uploaded.weightValue) { 'KG' } else { $null }
|
||||||
|
confidence = $uploaded.confidence
|
||||||
|
}
|
||||||
|
$weightCreateResponse = Invoke-Api POST "/api/platform/v1/first-leg/inbounds/$($ids.inboundId)/weight-results?tenantId=$TenantId" $platformToken $weightPayload
|
||||||
|
$weightResult = Require-Success '登记称重结果' $weightCreateResponse
|
||||||
|
$ids.weightResultId = [string]$weightResult.id
|
||||||
|
$versions.weightResult = [int]$weightResult.version
|
||||||
|
|
||||||
|
$correctResponse = Invoke-Api PUT "/api/platform/v1/first-leg/inbounds/$($ids.inboundId)/weight-results/$($ids.weightResultId)?tenantId=$TenantId" $platformToken @{
|
||||||
|
version = $versions.weightResult; adjustedWeightValue = 10; adjustedWeightUnit = 'KG'; adjustmentReason = "$marker 人工确认"
|
||||||
|
}
|
||||||
|
$corrected = Require-Success '人工修正称重结果' $correctResponse
|
||||||
|
$versions.weightResult = [int]$corrected.version
|
||||||
|
|
||||||
|
$confirmResponse = Invoke-Api POST "/api/platform/v1/first-leg/inbounds/$($ids.inboundId)/weight-results/$($ids.weightResultId)/confirm?tenantId=$TenantId" $platformToken @{
|
||||||
|
version = $versions.weightResult
|
||||||
|
}
|
||||||
|
$confirmed = Require-Success '确认称重结果' $confirmResponse
|
||||||
|
$versions.weightResult = [int]$confirmed.version
|
||||||
|
|
||||||
|
$measurementBeforeSubmitResponse = Invoke-Api GET "/api/platform/v1/first-leg/inbounds/$($ids.inboundId)/measurement?tenantId=$TenantId" $platformToken
|
||||||
|
$measurementBeforeSubmit = Require-Success '提交前回查测量详情' $measurementBeforeSubmitResponse
|
||||||
|
$versions.measurement = [int]$measurementBeforeSubmit.version
|
||||||
|
Require-Condition '确认重量汇总为 10KG' $measurementBeforeSubmitResponse ([decimal]$measurementBeforeSubmit.actualGrossWeightKg -eq 10) "actualGrossWeightKg=$($measurementBeforeSubmit.actualGrossWeightKg)"
|
||||||
|
|
||||||
|
$measurementSubmitResponse = Invoke-Api POST "/api/platform/v1/first-leg/inbounds/$($ids.inboundId)/measurement/submit?tenantId=$TenantId" $platformToken @{
|
||||||
|
measurementId = $ids.measurementId; version = $versions.measurement
|
||||||
|
}
|
||||||
|
$measurementSubmitted = Require-Success '提交测量审核' $measurementSubmitResponse
|
||||||
|
$versions.measurement = [int]$measurementSubmitted.version
|
||||||
|
Require-Condition '测量进入待审核状态' $measurementSubmitResponse ($measurementSubmitted.processStatus -eq 'MEASURE_PENDING' -and $measurementSubmitted.measureReviewStatus -eq 'PENDING') "processStatus=$($measurementSubmitted.processStatus), reviewStatus=$($measurementSubmitted.measureReviewStatus)"
|
||||||
|
|
||||||
|
$pendingInboundResponse = Invoke-Api GET "/api/platform/inbounds/$($ids.inboundId)?tenantId=$TenantId" $platformToken
|
||||||
|
$pendingInbound = Require-Success '审核前回查入库单版本' $pendingInboundResponse
|
||||||
|
$versions.inbound = [int]$pendingInbound.summary.version
|
||||||
|
|
||||||
|
$measurementApproveResponse = Invoke-Api POST "/api/platform/v1/inbounds/$($ids.inboundId)/measurements/approve?tenantId=$TenantId" $platformToken @{
|
||||||
|
measurementId = $ids.measurementId; expectedVersion = $versions.inbound; reason = $null
|
||||||
|
} @{ 'Idempotency-Key' = (New-Key 'measurement-approve') }
|
||||||
|
$null = Require-Success '平台审核通过测量' $measurementApproveResponse
|
||||||
|
|
||||||
|
$approvedInboundResponse = Invoke-Api GET "/api/platform/inbounds/$($ids.inboundId)?tenantId=$TenantId" $platformToken
|
||||||
|
$approvedInbound = Require-Success '审核后回查入库单' $approvedInboundResponse
|
||||||
|
$versions.inbound = [int]$approvedInbound.summary.version
|
||||||
|
Require-Condition '二期边界停在 WAIT_SPLIT' $approvedInboundResponse ($approvedInbound.summary.processStatus -eq 'WAIT_SPLIT' -and $approvedInbound.summary.measureReviewStatus -eq 'APPROVED') "processStatus=$($approvedInbound.summary.processStatus), reviewStatus=$($approvedInbound.summary.measureReviewStatus)"
|
||||||
|
|
||||||
|
$feeResponse = Invoke-Api POST "/api/platform/v1/inbounds/$($ids.inboundId)/fees/calculate?tenantId=$TenantId" $platformToken @{} @{ 'Idempotency-Key' = (New-Key 'fee-calculate') }
|
||||||
|
$feePassed = $feeResponse.http -eq 200 -and [string]$feeResponse.body.code -eq '200'
|
||||||
|
Add-Step '二期计费接口试算' $feeResponse $feePassed "inboundStatus=$($approvedInbound.summary.processStatus)"
|
||||||
|
if (-not $feePassed) {
|
||||||
|
$billingDefect = [ordered]@{
|
||||||
|
severity = 'P0'
|
||||||
|
summary = '测量审核后进入 WAIT_SPLIT,但计费接口不接受该状态,二期正常链路无法计费'
|
||||||
|
http = $feeResponse.http
|
||||||
|
code = [string]$feeResponse.body.code
|
||||||
|
message = [string]$feeResponse.body.message
|
||||||
|
requestId = $feeResponse.requestId
|
||||||
|
traceId = $feeResponse.traceId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$fatal = $_.Exception.Message
|
||||||
|
Write-Host "[中止] $fatal"
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$passedCount = @($steps | Where-Object passed).Count
|
||||||
|
$failedCount = @($steps | Where-Object { -not $_.passed }).Count
|
||||||
|
$report = [ordered]@{
|
||||||
|
reportName = '二期测试环境 API 验收'
|
||||||
|
scope = @('头程下单', '商户提交', '平台审核', '异步生成入库单', '测量草稿', '称重图片与结果', '人工修正与确认', '测量提交与审核', '计费试算')
|
||||||
|
excluded = @('分柜', '预装', 'PDA 拣货', '装柜证据', '装柜完成', '派送')
|
||||||
|
gateway = $GatewayBaseUrl
|
||||||
|
marker = $marker
|
||||||
|
startedAt = [datetime]::ParseExact($stamp, 'yyyyMMddHHmmss', $null).ToString('o')
|
||||||
|
finishedAt = (Get-Date).ToString('o')
|
||||||
|
success = $null -eq $fatal -and $null -eq $billingDefect -and $failedCount -eq 0
|
||||||
|
passedCount = $passedCount
|
||||||
|
failedCount = $failedCount
|
||||||
|
ids = $ids
|
||||||
|
versions = $versions
|
||||||
|
fatal = $fatal
|
||||||
|
billingDefect = $billingDefect
|
||||||
|
steps = $steps
|
||||||
|
}
|
||||||
|
$report | ConvertTo-Json -Depth 20 | Set-Content -LiteralPath $OutputPath -Encoding utf8
|
||||||
|
Write-Host "报告:$OutputPath"
|
||||||
|
$report | ConvertTo-Json -Depth 20
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user