diff --git a/deploy/sql/头程数据库统一增量-MySQL8.sql b/deploy/sql/头程数据库统一增量-MySQL8.sql index f6f9122a8..59184ea9c 100644 --- a/deploy/sql/头程数据库统一增量-MySQL8.sql +++ b/deploy/sql/头程数据库统一增量-MySQL8.sql @@ -6529,6 +6529,130 @@ USE baiyue_firstleg; CALL assert_phase3_smart_loading_schema(); DROP PROCEDURE IF EXISTS assert_phase3_smart_loading_schema; +-- ============================================================================ +-- 三期正式范围:海运订舱与拖车预约 IAM 权限 +-- 来源:firstleg/src/main/resources/db/phase3-ocean-booking-schema.sql +-- firstleg/src/main/resources/db/phase3-truck-appointment-schema.sql +-- ============================================================================ +USE baiyue_iam; +DROP PROCEDURE IF EXISTS assert_phase3_booking_truck_permission_ids_available; +DELIMITER $$ +CREATE PROCEDURE assert_phase3_booking_truck_permission_ids_available() +BEGIN + IF EXISTS ( + SELECT 1 FROM iam_permission + WHERE (id BETWEEN 5102140 AND 5102154 + AND permission_code <> CASE id + WHEN 5102140 THEN 'platform:firstleg:ocean-booking:list' + WHEN 5102141 THEN 'platform:firstleg:ocean-booking:view' + WHEN 5102142 THEN 'platform:firstleg:ocean-booking:create' + WHEN 5102143 THEN 'platform:firstleg:ocean-booking:edit' + WHEN 5102144 THEN 'platform:firstleg:ocean-booking:submit' + WHEN 5102145 THEN 'platform:firstleg:ocean-booking:confirm' + WHEN 5102146 THEN 'platform:firstleg:ocean-booking:release' + WHEN 5102147 THEN 'platform:firstleg:ocean-booking:cancel' + WHEN 5102148 THEN 'platform:firstleg:ocean-booking:change' + WHEN 5102149 THEN 'platform:firstleg:ocean-booking:allocate' + WHEN 5102150 THEN 'platform:firstleg:truck-appointment:list' + WHEN 5102151 THEN 'platform:firstleg:truck-appointment:view' + WHEN 5102152 THEN 'platform:firstleg:truck-appointment:create' + WHEN 5102153 THEN 'platform:firstleg:truck-appointment:edit' + WHEN 5102154 THEN 'platform:firstleg:truck-appointment:operate' + END) + OR (permission_code IN ( + 'platform:firstleg:ocean-booking:list', 'platform:firstleg:ocean-booking:view', + 'platform:firstleg:ocean-booking:create', 'platform:firstleg:ocean-booking:edit', + 'platform:firstleg:ocean-booking:submit', 'platform:firstleg:ocean-booking:confirm', + 'platform:firstleg:ocean-booking:release', 'platform:firstleg:ocean-booking:cancel', + 'platform:firstleg:ocean-booking:change', 'platform:firstleg:ocean-booking:allocate', + 'platform:firstleg:truck-appointment:list', 'platform:firstleg:truck-appointment:view', + 'platform:firstleg:truck-appointment:create', 'platform:firstleg:truck-appointment:edit', + 'platform:firstleg:truck-appointment:operate') + AND (tenant_id <> 0 OR app_code <> 'PLATFORM' OR id NOT BETWEEN 5102140 AND 5102154)) + ) THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '三期订舱/拖车权限迁移失败:5102140-5102154 ID 或权限码被其他语义占用'; + END IF; +END$$ +DELIMITER ; +CALL assert_phase3_booking_truck_permission_ids_available(); +DROP PROCEDURE IF EXISTS assert_phase3_booking_truck_permission_ids_available; + +INSERT INTO iam_permission + (id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name, + route_path,http_method,sort_no,status,built_in,deleted) +VALUES + (5102140,0,'PLATFORM','MENU',5102000,'platform:firstleg:ocean-booking:list','订舱管理','/first-leg/ocean-bookings','GET',80,'ACTIVE',1,0), + (5102141,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:view','查看订舱',NULL,'GET',10,'ACTIVE',1,0), + (5102142,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:create','创建订舱',NULL,'POST',20,'ACTIVE',1,0), + (5102143,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:edit','编辑订舱',NULL,'PUT',30,'ACTIVE',1,0), + (5102144,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:submit','提交订舱',NULL,'POST',40,'ACTIVE',1,0), + (5102145,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:confirm','确认订舱',NULL,'POST',50,'ACTIVE',1,0), + (5102146,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:release','确认放舱',NULL,'POST',60,'ACTIVE',1,0), + (5102147,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:cancel','取消订舱',NULL,'POST',70,'ACTIVE',1,0), + (5102148,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:change','变更船期',NULL,'POST',80,'ACTIVE',1,0), + (5102149,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:allocate','分配柜次',NULL,'POST',90,'ACTIVE',1,0), + (5102150,0,'PLATFORM','MENU',5102000,'platform:firstleg:truck-appointment:list','拖车预约','/first-leg/truck-appointments','GET',90,'ACTIVE',1,0), + (5102151,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:view','查看拖车预约',NULL,'GET',10,'ACTIVE',1,0), + (5102152,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:create','创建拖车预约',NULL,'POST',20,'ACTIVE',1,0), + (5102153,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:edit','编辑拖车预约',NULL,'PUT',30,'ACTIVE',1,0), + (5102154,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:operate','操作拖车预约',NULL,'POST',40,'ACTIVE',1,0) +ON DUPLICATE KEY UPDATE tenant_id=0,app_code='PLATFORM',permission_type=VALUES(permission_type), + permission_code=VALUES(permission_code),permission_name=VALUES(permission_name),parent_id=VALUES(parent_id), + route_path=VALUES(route_path),http_method=VALUES(http_method),sort_no=VALUES(sort_no),status='ACTIVE',built_in=1,deleted=0; + +INSERT IGNORE INTO iam_role_permission(role_id,permission_id,tenant_id) +SELECT role.id,permission.id,0 FROM iam_role role JOIN iam_permission permission + ON permission.tenant_id=0 AND permission.app_code='PLATFORM' + AND (permission.permission_code LIKE 'platform:firstleg:ocean-booking:%' + OR permission.permission_code LIKE 'platform:firstleg:truck-appointment:%') +WHERE role.tenant_id=0 AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR'); + +DROP PROCEDURE IF EXISTS assert_phase3_booking_truck_permissions; +DELIMITER $$ +CREATE PROCEDURE assert_phase3_booking_truck_permissions() +BEGIN + IF (SELECT COUNT(*) FROM iam_permission + WHERE tenant_id=0 AND app_code='PLATFORM' AND status='ACTIVE' AND deleted=0 + AND ((id=5102140 AND permission_code='platform:firstleg:ocean-booking:list' AND parent_id=5102000 AND route_path='/first-leg/ocean-bookings' AND http_method='GET') + OR (id=5102141 AND permission_code='platform:firstleg:ocean-booking:view' AND parent_id=5102140 AND http_method='GET') + OR (id=5102142 AND permission_code='platform:firstleg:ocean-booking:create' AND parent_id=5102140 AND http_method='POST') + OR (id=5102143 AND permission_code='platform:firstleg:ocean-booking:edit' AND parent_id=5102140 AND http_method='PUT') + OR (id=5102144 AND permission_code='platform:firstleg:ocean-booking:submit' AND parent_id=5102140 AND http_method='POST') + OR (id=5102145 AND permission_code='platform:firstleg:ocean-booking:confirm' AND parent_id=5102140 AND http_method='POST') + OR (id=5102146 AND permission_code='platform:firstleg:ocean-booking:release' AND parent_id=5102140 AND http_method='POST') + OR (id=5102147 AND permission_code='platform:firstleg:ocean-booking:cancel' AND parent_id=5102140 AND http_method='POST') + OR (id=5102148 AND permission_code='platform:firstleg:ocean-booking:change' AND parent_id=5102140 AND http_method='POST') + OR (id=5102149 AND permission_code='platform:firstleg:ocean-booking:allocate' AND parent_id=5102140 AND http_method='POST') + OR (id=5102150 AND permission_code='platform:firstleg:truck-appointment:list' AND parent_id=5102000 AND route_path='/first-leg/truck-appointments' AND http_method='GET') + OR (id=5102151 AND permission_code='platform:firstleg:truck-appointment:view' AND parent_id=5102150 AND http_method='GET') + OR (id=5102152 AND permission_code='platform:firstleg:truck-appointment:create' AND parent_id=5102150 AND http_method='POST') + OR (id=5102153 AND permission_code='platform:firstleg:truck-appointment:edit' AND parent_id=5102150 AND http_method='PUT') + OR (id=5102154 AND permission_code='platform:firstleg:truck-appointment:operate' AND parent_id=5102150 AND http_method='POST'))) <> 15 THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '统一迁移失败:三期订舱/拖车 15 项权限映射不完整'; + END IF; + IF EXISTS ( + SELECT 1 FROM iam_role role + WHERE role.tenant_id=0 AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR') + AND EXISTS ( + SELECT 1 FROM iam_permission permission + WHERE permission.tenant_id=0 AND permission.app_code='PLATFORM' + AND permission.id BETWEEN 5102140 AND 5102154 + AND NOT EXISTS ( + SELECT 1 FROM iam_role_permission grant_row + WHERE grant_row.role_id=role.id AND grant_row.permission_id=permission.id + AND grant_row.tenant_id=0)) + ) THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '统一迁移失败:三期订舱/拖车角色授权不完整'; + END IF; +END$$ +DELIMITER ; +CALL assert_phase3_booking_truck_permissions(); +DROP PROCEDURE IF EXISTS assert_phase3_booking_truck_permissions; +USE baiyue_firstleg; + -- 兼容已经执行过旧单行配置模型的开发/测试库。仅精确识别旧结构时丢弃旧值并重建; -- 已是四箱规结构时不做 DDL,避免破坏 Admin 已编辑的数据。 DROP PROCEDURE IF EXISTS unified_upgrade_legacy_customer_dimension_config; diff --git a/firstleg/src/main/resources/db/phase3-ocean-booking-schema.sql b/firstleg/src/main/resources/db/phase3-ocean-booking-schema.sql index e62d33268..9f9aed850 100644 --- a/firstleg/src/main/resources/db/phase3-ocean-booking-schema.sql +++ b/firstleg/src/main/resources/db/phase3-ocean-booking-schema.sql @@ -197,6 +197,36 @@ BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='订舱状态历史不可删除'; DELIMITER ; USE baiyue_iam; +DROP PROCEDURE IF EXISTS assert_ocean_booking_permission_ids_available; +DELIMITER $$ +CREATE PROCEDURE assert_ocean_booking_permission_ids_available() +BEGIN + IF EXISTS ( + SELECT 1 FROM iam_permission + WHERE (id BETWEEN 5102140 AND 5102149 + AND permission_code <> CASE id + WHEN 5102140 THEN 'platform:firstleg:ocean-booking:list' + WHEN 5102141 THEN 'platform:firstleg:ocean-booking:view' + WHEN 5102142 THEN 'platform:firstleg:ocean-booking:create' + WHEN 5102143 THEN 'platform:firstleg:ocean-booking:edit' + WHEN 5102144 THEN 'platform:firstleg:ocean-booking:submit' + WHEN 5102145 THEN 'platform:firstleg:ocean-booking:confirm' + WHEN 5102146 THEN 'platform:firstleg:ocean-booking:release' + WHEN 5102147 THEN 'platform:firstleg:ocean-booking:cancel' + WHEN 5102148 THEN 'platform:firstleg:ocean-booking:change' + WHEN 5102149 THEN 'platform:firstleg:ocean-booking:allocate' + END) + OR (permission_code LIKE 'platform:firstleg:ocean-booking:%' + AND (tenant_id <> 0 OR app_code <> 'PLATFORM' OR id NOT BETWEEN 5102140 AND 5102149)) + ) THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '三期订舱权限迁移失败:5102140-5102149 ID 或权限码被其他语义占用'; + END IF; +END$$ +DELIMITER ; +CALL assert_ocean_booking_permission_ids_available(); +DROP PROCEDURE IF EXISTS assert_ocean_booking_permission_ids_available; + INSERT INTO iam_permission (id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name, route_path,http_method,sort_no,status,built_in,deleted) @@ -211,7 +241,8 @@ VALUES (5102147,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:cancel','取消订舱',NULL,'POST',70,'ACTIVE',1,0), (5102148,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:change','变更船期',NULL,'POST',80,'ACTIVE',1,0), (5102149,0,'PLATFORM','BUTTON',5102140,'platform:firstleg:ocean-booking:allocate','分配柜次',NULL,'POST',90,'ACTIVE',1,0) -ON DUPLICATE KEY UPDATE permission_name=VALUES(permission_name),parent_id=VALUES(parent_id), +ON DUPLICATE KEY UPDATE tenant_id=0,app_code='PLATFORM',permission_type=VALUES(permission_type), + permission_code=VALUES(permission_code),permission_name=VALUES(permission_name),parent_id=VALUES(parent_id), route_path=VALUES(route_path),http_method=VALUES(http_method),sort_no=VALUES(sort_no),status='ACTIVE',built_in=1,deleted=0; INSERT IGNORE INTO iam_role_permission(role_id,permission_id,tenant_id) diff --git a/firstleg/src/main/resources/db/phase3-truck-appointment-schema.sql b/firstleg/src/main/resources/db/phase3-truck-appointment-schema.sql index 408c31bb5..d53c27f9b 100644 --- a/firstleg/src/main/resources/db/phase3-truck-appointment-schema.sql +++ b/firstleg/src/main/resources/db/phase3-truck-appointment-schema.sql @@ -29,3 +29,70 @@ CREATE TABLE IF NOT EXISTS fl_truck_appointment_operation ( id BIGINT UNSIGNED NOT NULL, appointment_id BIGINT UNSIGNED NOT NULL, idempotency_key VARCHAR(128) NOT NULL, request_hash CHAR(64) NOT NULL, action VARCHAR(32) NOT NULL, response_snapshot JSON NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY(id), UNIQUE KEY uk_truck_operation(idempotency_key), KEY idx_truck_operation_appointment(appointment_id) ) ENGINE=InnoDB COMMENT='拖车操作幂等记录'; + +USE baiyue_iam; +DROP PROCEDURE IF EXISTS assert_truck_appointment_permission_ids_available; +DELIMITER $$ +CREATE PROCEDURE assert_truck_appointment_permission_ids_available() +BEGIN + IF EXISTS ( + SELECT 1 FROM iam_permission + WHERE (id BETWEEN 5102150 AND 5102154 + AND permission_code <> CASE id + WHEN 5102150 THEN 'platform:firstleg:truck-appointment:list' + WHEN 5102151 THEN 'platform:firstleg:truck-appointment:view' + WHEN 5102152 THEN 'platform:firstleg:truck-appointment:create' + WHEN 5102153 THEN 'platform:firstleg:truck-appointment:edit' + WHEN 5102154 THEN 'platform:firstleg:truck-appointment:operate' + END) + OR (permission_code LIKE 'platform:firstleg:truck-appointment:%' + AND (tenant_id <> 0 OR app_code <> 'PLATFORM' OR id NOT BETWEEN 5102150 AND 5102154)) + ) THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '三期拖车权限迁移失败:5102150-5102154 ID 或权限码被其他语义占用'; + END IF; +END$$ +DELIMITER ; +CALL assert_truck_appointment_permission_ids_available(); +DROP PROCEDURE IF EXISTS assert_truck_appointment_permission_ids_available; + +INSERT INTO iam_permission + (id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name, + route_path,http_method,sort_no,status,built_in,deleted) +VALUES + (5102150,0,'PLATFORM','MENU',5102000,'platform:firstleg:truck-appointment:list','拖车预约','/first-leg/truck-appointments','GET',90,'ACTIVE',1,0), + (5102151,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:view','查看拖车预约',NULL,'GET',10,'ACTIVE',1,0), + (5102152,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:create','创建拖车预约',NULL,'POST',20,'ACTIVE',1,0), + (5102153,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:edit','编辑拖车预约',NULL,'PUT',30,'ACTIVE',1,0), + (5102154,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:operate','操作拖车预约',NULL,'POST',40,'ACTIVE',1,0) +ON DUPLICATE KEY UPDATE tenant_id=0,app_code='PLATFORM',permission_type=VALUES(permission_type), + permission_code=VALUES(permission_code),permission_name=VALUES(permission_name),parent_id=VALUES(parent_id), + route_path=VALUES(route_path),http_method=VALUES(http_method),sort_no=VALUES(sort_no),status='ACTIVE',built_in=1,deleted=0; + +INSERT IGNORE INTO iam_role_permission(role_id,permission_id,tenant_id) +SELECT role.id,permission.id,0 FROM iam_role role JOIN iam_permission permission + ON permission.tenant_id=0 AND permission.app_code='PLATFORM' + AND permission.permission_code LIKE 'platform:firstleg:truck-appointment:%' +WHERE role.tenant_id=0 AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR'); + +USE baiyue_firstleg; + +USE baiyue_iam; +INSERT INTO iam_permission + (id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name, + route_path,http_method,sort_no,status,built_in,deleted) +VALUES + (5102150,0,'PLATFORM','MENU',5102000,'platform:firstleg:truck-appointment:list','拖车预约','/trucking','GET',90,'ACTIVE',1,0), + (5102151,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:view','查看拖车预约',NULL,'GET',10,'ACTIVE',1,0), + (5102152,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:create','创建拖车预约',NULL,'POST',20,'ACTIVE',1,0), + (5102153,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:edit','编辑拖车预约',NULL,'PUT',30,'ACTIVE',1,0), + (5102154,0,'PLATFORM','BUTTON',5102150,'platform:firstleg:truck-appointment:operate','操作拖车状态',NULL,'POST',40,'ACTIVE',1,0) +ON DUPLICATE KEY UPDATE permission_name=VALUES(permission_name),parent_id=VALUES(parent_id), + route_path=VALUES(route_path),http_method=VALUES(http_method),sort_no=VALUES(sort_no),status='ACTIVE',built_in=1,deleted=0; + +INSERT IGNORE INTO iam_role_permission(role_id,permission_id,tenant_id) +SELECT role.id,permission.id,0 FROM iam_role role JOIN iam_permission permission + ON permission.tenant_id=0 AND permission.permission_code LIKE 'platform:firstleg:truck-appointment:%' +WHERE role.tenant_id=0 AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR'); + +USE baiyue_firstleg; diff --git a/firstleg/src/test/java/com/baiyue/firstleg/controller/TruckAppointmentControllerContractTest.java b/firstleg/src/test/java/com/baiyue/firstleg/controller/TruckAppointmentControllerContractTest.java index f422dfc98..0ce0c6f5e 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/controller/TruckAppointmentControllerContractTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/controller/TruckAppointmentControllerContractTest.java @@ -1,6 +1,31 @@ package com.baiyue.firstleg.controller; -import org.junit.jupiter.api.Test; import org.springframework.core.io.ClassPathResource; import org.springframework.security.access.prepost.PreAuthorize; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import static org.assertj.core.api.Assertions.assertThat; + +import com.baiyue.common.security.AuthenticatedUser; +import com.baiyue.firstleg.dto.TruckAppointmentDtos.ActionRequest; +import org.junit.jupiter.api.Test; +import org.springframework.core.io.ClassPathResource; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.RequestHeader; + +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + class TruckAppointmentControllerContractTest { @Test void exposesDedicatedEndpointAndPermissions() {String p=PlatformTruckAppointmentController.class.getAnnotation(org.springframework.web.bind.annotation.RequestMapping.class).value()[0];assertThat(p).isEqualTo("/api/platform/v1/truck-appointments"); for(String n:new String[]{"page","detail","create","edit","action","reschedule"}) assertThat(java.util.Arrays.stream(PlatformTruckAppointmentController.class.getDeclaredMethods()).anyMatch(m->m.getName().equals(n))).isTrue();} @Test void schemaHasAggregateTablesAndStates() throws Exception {String s=new ClassPathResource("db/phase3-truck-appointment-schema.sql").getContentAsString(StandardCharsets.UTF_8);assertThat(s).contains("fl_truck_appointment","fl_truck_appointment_history","fl_truck_appointment_attachment","fl_truck_appointment_operation","PENDING_DISPATCH","PICKUP_IN_PROGRESS","ARRIVED_WAREHOUSE","RESCHEDULED");} + @Test void methodsHavePlatformPermissionsAndAuthenticatedScope() { + Map expected=Map.of("page","platform:firstleg:truck-appointment:list","detail","platform:firstleg:truck-appointment:view","create","platform:firstleg:truck-appointment:create","edit","platform:firstleg:truck-appointment:edit","action","platform:firstleg:truck-appointment:operate","reschedule","platform:firstleg:truck-appointment:operate"); + for (Method m: PlatformTruckAppointmentController.class.getDeclaredMethods()) { if (!expected.containsKey(m.getName())) continue; assertThat(m.getAnnotation(PreAuthorize.class).value()).isEqualTo("hasAuthority('"+expected.get(m.getName())+"')"); assertThat(java.util.Arrays.stream(m.getParameterAnnotations()).anyMatch(a -> java.util.Arrays.stream(a).anyMatch(x -> x.annotationType()==AuthenticationPrincipal.class))).isTrue(); } + } + @Test void actionKeepsOptionalIdempotencyHeaders() throws Exception { + Method action=PlatformTruckAppointmentController.class.getDeclaredMethod("action", AuthenticatedUser.class,long.class,String.class,String.class,String.class,ActionRequest.class); + RequestHeader[] headers=java.util.Arrays.stream(action.getParameterAnnotations()).flatMap(java.util.Arrays::stream).filter(a -> a instanceof RequestHeader).map(a -> (RequestHeader)a).toArray(RequestHeader[]::new); + assertThat(java.util.Arrays.stream(headers).map(RequestHeader::value)).contains("Idempotency-Key","X-Request-Hash"); assertThat(java.util.Arrays.stream(headers).allMatch(h -> !h.required())).isTrue(); + assertThat(PlatformTruckAppointmentController.class.getDeclaredMethod("reschedule", AuthenticatedUser.class,long.class,LocalDateTime.class,ActionRequest.class)).isNotNull(); + } } diff --git a/firstleg/src/test/java/com/baiyue/firstleg/repository/TruckAppointmentMapperContractTest.java b/firstleg/src/test/java/com/baiyue/firstleg/repository/TruckAppointmentMapperContractTest.java index b5d8b1c0c..97144d19d 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/repository/TruckAppointmentMapperContractTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/repository/TruckAppointmentMapperContractTest.java @@ -14,11 +14,11 @@ class TruckAppointmentMapperContractTest { assertThat(TruckAppointmentEntity.class.getAnnotation(TableName.class).value()).isEqualTo("fl_truck_appointment"); String page = TruckAppointmentMapper.class.getMethod("page", com.baomidou.mybatisplus.extension.plugins.pagination.Page.class, com.baiyue.firstleg.dto.TruckAppointmentDtos.Query.class).getAnnotation(Select.class).value()[0]; assertThat(page).contains("fl_truck_appointment", "appointment_no", "vehicle_no", "status=#{q.status}", "container_booking_id=#{q.containerBookingId}"); - String transition = TruckAppointmentMapper.class.getMethod("transition", long.class, String.class, String.class, int.class).getAnnotation(Update.class).value(); + String transition = TruckAppointmentMapper.class.getMethod("transition", long.class, String.class, String.class, int.class).getAnnotation(Update.class).value()[0]; assertThat(transition).contains("status=#{toStatus}", "status=#{fromStatus}", "version=#{version}", "revision=revision+1", "version=version+1"); - String reschedule = TruckAppointmentMapper.class.getMethod("reschedule", long.class, java.time.LocalDateTime.class, String.class, int.class).getAnnotation(Update.class).value(); + String reschedule = TruckAppointmentMapper.class.getMethod("reschedule", long.class, java.time.LocalDateTime.class, String.class, int.class).getAnnotation(Update.class).value()[0]; assertThat(reschedule).contains("status='RESCHEDULED'", "version=#{version}", "revision=revision+1"); - String edit = TruckAppointmentMapper.class.getMethod("updateEdit", TruckAppointmentEntity.class, int.class).getAnnotation(Update.class).value(); + String edit = TruckAppointmentMapper.class.getMethod("updateEdit", TruckAppointmentEntity.class, int.class).getAnnotation(Update.class).value()[0]; assertThat(edit).contains("WHERE id=#{e.id} AND version=#{version}", "version=version+1", "revision=revision+1"); } } diff --git a/reports/client-phase2-test-env-20260808061916-a8e93e65.json b/reports/client-phase2-test-env-20260808061916-a8e93e65.json new file mode 100644 index 000000000..9c4b1853c --- /dev/null +++ b/reports/client-phase2-test-env-20260808061916-a8e93e65.json @@ -0,0 +1,52 @@ +{ + "marker": "20260808061916-a8e93e65", + "gateway": "http://8.163.30.128:9000", + "generatedAt": "2026-08-08T06:19:16.413Z", + "completedAt": "2026-08-08T06:19:17.127Z", + "success": false, + "fatal": { + "name": "Error", + "message": "business code: expected=\"200\" actual=\"S0503\"" + }, + "testAccount": { + "username": "merchant_admin" + }, + "expectedTerminalState": { + "processStatus": "WAIT_SPLIT", + "measureReviewStatus": "APPROVED", + "feeStatus": "CONFIRMED" + }, + "resources": { + "tenantId": null, + "terminalInboundId": null, + "terminalOrderId": null, + "terminalInboundCode": null, + "terminalMeasurementId": null, + "pendingOrderId": null, + "foreignOrderId": null, + "measurementImageFileIds": [], + "weightImageFileIds": [] + }, + "steps": [ + { + "module": "phase2-session", + "name": "client login", + "passed": false, + "skipped": false, + "startedAt": "2026-08-08T06:19:16.414Z", + "durationMs": 712, + "http": 200, + "code": "S0503", + "message": "IAM 权限服务暂时不可用", + "requestId": "client-phase2-899a7f01-b4cb-42b3-b4cd-6628a3bff7ec, client-phase2-899a7f01-b4cb-42b3-b4cd-6628a3bff7ec", + "traceId": "58151ea8e6f946debc1050bafd97dcaa", + "evidence": { + "username": "merchant_admin" + }, + "error": { + "name": "Error", + "message": "business code: expected=\"200\" actual=\"S0503\"" + } + } + ] +}