From c07af65c3baf36c5916aa0d3125ed76c27204dbc Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sat, 15 Aug 2026 09:49:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../phase3-evidence-gate.mjs | 43 +++++++++++++++++-- .../PlatformSupplierController.java | 3 +- .../warehouse/service/SupplierService.java | 6 +-- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/scripts/admin-test-env-modules/phase3-evidence-gate.mjs b/scripts/admin-test-env-modules/phase3-evidence-gate.mjs index 56b99c3f7..7a8e52f99 100644 --- a/scripts/admin-test-env-modules/phase3-evidence-gate.mjs +++ b/scripts/admin-test-env-modules/phase3-evidence-gate.mjs @@ -2,15 +2,52 @@ const MODULE = 'phase3-evidence-gate' const OPTIONS = { scenario: 'loading-evidence-gate', deploymentBlocker: true } function id(value) { return value == null ? '' : String(value) } +function successful(response) { return response?.http === 200 && String(response?.body?.code ?? '') === '200' } export async function run(context) { const fixture = context.createdResources?.phase3Loading - if (!fixture?.tenantId || !fixture?.inboundId || fixture.marker !== context.marker) { + const tenantId = id(fixture?.tenantId) + const inboundId = id(fixture?.inboundId) + const taskId = id(fixture?.canonicalPdaTaskId || fixture?.pickingTaskId) + const loadingPlanId = id(fixture?.loadingPlanId) + const containerBookingId = id(fixture?.containerBookingId) + const warehouseId = id(fixture?.warehouseId) + if (!tenantId || !inboundId || !taskId || !loadingPlanId || !containerBookingId || !warehouseId + || fixture.marker !== context.marker) { context.addCoverageGap(MODULE, OPTIONS.scenario, '五类证据多图追加、作废审计和有效证据门禁', - '本轮未取得 phase3-loading 的 marker 隔离证据 fixture,未使用历史资源', 'fixture') + '本轮未取得带 taskId/inboundId/loadingPlanId/containerBookingId 的 phase3-loading marker 隔离证据 fixture,未使用历史资源', 'fixture') return } - const path = `/api/platform/v1/inbounds/${fixture.inboundId}/loading/evidence?tenantId=${encodeURIComponent(fixture.tenantId)}` + + // AWAITING_REVIEW is a PDA workflow state, not evidence permission. Evidence is + // opened only after the server-side inbound aggregate has entered LOADING. + const taskResponse = await context.request('GET', + `/api/platform/v1/first-leg/pda-loading/tasks?loadingPlanId=${encodeURIComponent(loadingPlanId)}&warehouseId=${encodeURIComponent(warehouseId)}`) + const task = successful(taskResponse) ? taskResponse.body?.data : null + const taskItem = task?.items?.find?.((item) => id(item?.inboundId) === inboundId) + const taskIdentityValid = id(task?.id) === taskId + && id(task?.loadingPlanId) === loadingPlanId + && id(task?.containerBookingId) === containerBookingId + && Boolean(taskItem) && id(taskItem?.inboundId) === inboundId + context.assert(MODULE, '证据前置任务身份使用本轮四元稳定关联', taskResponse, + taskIdentityValid, + `taskId=${id(task?.id) || 'missing'}, inboundId=${id(taskItem?.inboundId) || 'missing'}, loadingPlanId=${id(task?.loadingPlanId) || 'missing'}, containerBookingId=${id(task?.containerBookingId) || 'missing'}`, OPTIONS) + if (!taskIdentityValid) return + + const inboundResponse = await context.request('GET', + `/api/platform/inbounds/${encodeURIComponent(inboundId)}?tenantId=${encodeURIComponent(tenantId)}`) + const inbound = successful(inboundResponse) ? inboundResponse.body?.data : null + const serverLoading = inbound?.summary?.processStatus === 'LOADING' + context.assert(MODULE, '服务端入库进入 LOADING 后才开放装柜证据', inboundResponse, + serverLoading, + `processStatus=${inbound?.summary?.processStatus || 'missing'}, taskWorkflow=${task?.workflowStatus || 'missing'}`, OPTIONS) + if (!serverLoading) { + context.addCoverageGap(MODULE, OPTIONS.scenario, '服务端装柜阶段前不请求证据', + `taskId=${taskId}, inboundId=${inboundId}, loadingPlanId=${loadingPlanId}, containerBookingId=${containerBookingId}, processStatus=${inbound?.summary?.processStatus || 'missing'};AWAITING_REVIEW 不作为证据开放条件`, 'deployment-blocker') + return + } + + const path = `/api/platform/v1/inbounds/${inboundId}/loading/evidence?tenantId=${encodeURIComponent(tenantId)}` const response = await context.request('GET', path) const data = context.apiSuccess(MODULE, '复核本轮装柜证据聚合', response, `inboundId=${fixture.inboundId}`, OPTIONS) const evidences = Array.isArray(data?.evidences) ? data.evidences : [] diff --git a/warehouse/src/main/java/com/baiyue/warehouse/controller/PlatformSupplierController.java b/warehouse/src/main/java/com/baiyue/warehouse/controller/PlatformSupplierController.java index 3494a0768..302e94de8 100644 --- a/warehouse/src/main/java/com/baiyue/warehouse/controller/PlatformSupplierController.java +++ b/warehouse/src/main/java/com/baiyue/warehouse/controller/PlatformSupplierController.java @@ -8,6 +8,7 @@ import com.baiyue.common.security.AuthenticatedUser; import com.baiyue.warehouse.dto.SupplierDtos.*; import com.baiyue.warehouse.entity.SupplierEntity; import com.baiyue.warehouse.service.SupplierService; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; @@ -33,7 +34,7 @@ public class PlatformSupplierController { @GetMapping("/{id}") @PreAuthorize("hasAuthority('platform:supplier:list')") public ApiResponse detail(@AuthenticationPrincipal AuthenticatedUser user, @RequestParam @Min(0) long tenantId, @PathVariable long id) { requirePlatform(user); requireScope(tenantId); return ApiResponse.success(service.detail(id)); } @PostMapping @PreAuthorize("hasAuthority('platform:supplier:create')") - public ApiResponse create(@AuthenticationPrincipal AuthenticatedUser user, @RequestParam @Min(0) long tenantId, @Valid @RequestBody SaveRequest request) { requirePlatform(user); requireScope(tenantId); return ApiResponse.success(service.create(request)); } + public ApiResponse create(@AuthenticationPrincipal AuthenticatedUser user, @RequestParam @Min(0) long tenantId, @Valid @RequestBody SaveRequest request) { requirePlatform(user); requireScope(tenantId); long id = IdWorker.getId(); return ApiResponse.success(service.create(id, request)); } @PutMapping("/{id}") @PreAuthorize("hasAuthority('platform:supplier:edit')") public ApiResponse update(@AuthenticationPrincipal AuthenticatedUser user, @RequestParam @Min(0) long tenantId, @PathVariable long id, @Valid @RequestBody SaveRequest request) { requirePlatform(user); requireScope(tenantId); service.update(id, request); return ApiResponse.success(null); } @PatchMapping("/{id}/status") @PreAuthorize("hasAuthority('platform:supplier:status')") diff --git a/warehouse/src/main/java/com/baiyue/warehouse/service/SupplierService.java b/warehouse/src/main/java/com/baiyue/warehouse/service/SupplierService.java index 0403580c7..1cf0c6f14 100644 --- a/warehouse/src/main/java/com/baiyue/warehouse/service/SupplierService.java +++ b/warehouse/src/main/java/com/baiyue/warehouse/service/SupplierService.java @@ -26,11 +26,11 @@ public class SupplierService { public Stats stats() { return new Stats(repository.count(0, "BOOKING"), repository.count(0, "CUSTOMS"), repository.count(0, "TRUCKING"), repository.count(0, "CERTIFICATE")); } @Transactional - @BusinessAudit(event = "SUPPLIER_CREATE", resourceType = "SUPPLIER", resourceId = "#request.name", description = "新增供应商", captureBefore = false) - public Long create(SaveRequest request) { + @BusinessAudit(event = "SUPPLIER_CREATE", resourceType = "SUPPLIER", resourceId = "#id", description = "新增供应商", captureBefore = false) + public Long create(long id, SaveRequest request) { validateScope(request); ensureName(request.name(), null); - SupplierEntity entity = new SupplierEntity(); entity.setTenantId(0L); copy(entity, request); + SupplierEntity entity = new SupplierEntity(); entity.setId(id); entity.setTenantId(0L); copy(entity, request); try { repository.insert(entity); } catch (DataIntegrityViolationException e) { throw new BizException(ResultCode.CONFLICT, "供应商名称已存在"); } return entity.getId(); }