From 3ac7305724428ab7c7261247936aef2f340df0a2 Mon Sep 17 00:00:00 2001 From: zgw <13623675548@163.com> Date: Thu, 16 Jul 2026 09:30:01 +0800 Subject: [PATCH] docs: plan dense outbound relocation dispatch --- ...7-16-dense-outbound-relocation-dispatch.md | 443 ++++++++++++++++++ 1 file changed, 443 insertions(+) create mode 100644 docs/superpowers/plans/2026-07-16-dense-outbound-relocation-dispatch.md diff --git a/docs/superpowers/plans/2026-07-16-dense-outbound-relocation-dispatch.md b/docs/superpowers/plans/2026-07-16-dense-outbound-relocation-dispatch.md new file mode 100644 index 0000000..5fffa9b --- /dev/null +++ b/docs/superpowers/plans/2026-07-16-dense-outbound-relocation-dispatch.md @@ -0,0 +1,443 @@ +# Dense Outbound Relocation And Dispatch Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add durable WCS outbound retry compensation, dense-lane outermost enforcement, automatic/manual same-floor relocation, and dense-lane outbound workflows without changing existing inbound or non-dense outbound behavior. + +**Architecture:** Keep `mydo_job` as the business record and add a one-to-one `wcs_job_dispatch` outbox record. Route every outbound push through a single dispatch service that atomically claims attempts and calls a dense-lane eligibility service before selecting a type-specific WCS endpoint. Build relocation and lane-outbound workflows on shared dense-lane queries so automatic allocation, scheduled retry, manual push, location outbound, KPI relocation, and lane outbound enforce the same rules. + +**Tech Stack:** Java 17, Spring Boot, MyBatis XML, SQL Server, Quartz through RuoYi `sys_job`, JUnit 5/Mockito/AssertJ, Vue 2, Element UI, Maven 3.9.11, npm. + +## Global Constraints + +- Preserve current RuoYi controller/domain/mapper/service/service.impl layering and naming style. +- Do not alter the existing inbound WCS pull flow or non-03 warehouse outbound allocation semantics. +- Apply dense-lane rules only to warehouse `03` cargo spaces with non-empty `group_coding`. +- `in_or_out=23` is relocation and uses `util_serial_task '23'`. +- Automatic WCS retries run at most five times after the initial failed call. +- Relocation source and destination must be in the same warehouse and same floor, but different channel groups. +- All WCS dispatch entry points must enforce current outermost eligibility immediately before the HTTP call. +- Use `D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd` for Maven commands. +- Use repeatable SQL Server migration statements; do not delete existing business data. + +--- + +### Task 1: Dispatch Outbox Schema And Persistence + +**Files:** +- Create: `sql/20260716_dense_outbound_relocation_dispatch.sql` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/domain/WcsJobDispatch.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapper.java` +- Create: `ruoyi-admin/src/main/resources/mapper/out/WcsJobDispatchMapper.xml` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapperSqlTest.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/in/job/domain/MydoJob.java` +- Modify: `ruoyi-admin/src/main/resources/mapper/in/MydoJobMapper.xml` + +**Interfaces:** +- Produces: `WcsJobDispatchMapper.insertIfAbsent(String jobId)`, `selectByJobId(String jobId)`, `selectRetryCandidates(Date now, int limit)`, `claimForSend(Map)`, `markBlocked(Map)`, `markRetryWait(Map)`, `markSuccess(Map)`, and `markExhausted(Map)`. +- Produces: non-persistent `MydoJob.dispatchStatus`, `autoRetryCount`, `manualRetryCount`, and `lastDispatchError` populated by list/detail queries. + +- [ ] **Step 1: Write the failing mapper structure test** + +Create a JUnit test that reads the mapper XML and migration and asserts the six statuses, the retry-count predicate, atomic `SENDING` claim, dispatch join aliases, ID `23` seed, Quartz invocation, menu permissions, and repeatable `IF NOT EXISTS` guards. + +```java +assertThat(mapperXml) + .contains("dispatch_status = 'SENDING'") + .contains("auto_retry_count < 5") + .contains("last_dispatch_error"); +assertThat(migration) + .contains("wcs_job_dispatch") + .contains("wcsOutboundRetryTask.retryFailedJobs") + .contains("out:denseLaneOutbound:generate"); +``` + +- [ ] **Step 2: Run the focused test and verify RED** + +Run: + +```powershell +& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=WcsJobDispatchMapperSqlTest test +``` + +Expected: FAIL because the mapper and migration do not exist. + +- [ ] **Step 3: Implement the migration, domain, mapper, XML, and job query join** + +Use exact dispatch constants `PENDING`, `SENDING`, `BLOCKED`, `RETRY_WAIT`, `SUCCESS`, `EXHAUSTED`. The migration creates the table and indexes, inserts task type `23` only when absent, inserts the non-concurrent one-minute Quartz row, and inserts/updates the lane-outbound menu and three permissions. `claimForSend` must update exactly one eligible row and increment either `auto_retry_count` or `manual_retry_count` based on a parameter. + +- [ ] **Step 4: Run the focused test and verify GREEN** + +Run the command from Step 2. Expected: PASS. + +- [ ] **Step 5: Commit** + +```powershell +git add sql/20260716_dense_outbound_relocation_dispatch.sql ruoyi-admin/src/main/java/com/ruoyi/out/dispatch ruoyi-admin/src/main/resources/mapper/out/WcsJobDispatchMapper.xml ruoyi-admin/src/main/java/com/ruoyi/in/job/domain/MydoJob.java ruoyi-admin/src/main/resources/mapper/in/MydoJobMapper.xml ruoyi-admin/src/test/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapperSqlTest.java +git commit -m "feat: add WCS dispatch outbox" +``` + +### Task 2: WCS Routing And Durable Dispatch Service + +**Files:** +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/service/IOutboundDispatchService.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/service/impl/OutboundDispatchServiceImpl.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/domain/DispatchTrigger.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/task/WcsOutboundRetryTask.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DispatchEligibility.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/mapper/DenseLaneMapper.java` +- Create: `ruoyi-admin/src/main/resources/mapper/out/DenseLaneMapper.xml` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/IDenseLaneService.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/impl/DenseLaneServiceImpl.java` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/out/dispatch/service/impl/OutboundDispatchServiceImplTest.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/api/client/WcsClient.java` +- Modify: `ruoyi-admin/src/main/resources/application.yml` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/in/job/service/IMydoJobService.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/in/job/service/impl/MydoJobServiceImpl.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/out/job/controller/OutMydoJobController.java` + +**Interfaces:** +- Produces: `AjaxResult dispatch(String jobId, DispatchTrigger trigger)` where trigger is `INITIAL`, `AUTO_RETRY`, or `MANUAL`. +- Produces: `int retryFailedJobs()` for Quartz. +- Produces: `WcsClient.sendOutboundTask(MydoJob)`, `sendLocationOutboundTask(MydoJob)`, and `sendRelocationTask(MydoJob)`. + +- [ ] **Step 1: Write failing service tests** + +Cover initial failure with count 0, five auto retries then exhausted, manual send past exhaustion, successful status/phase update, atomic claim rejection, and route selection for types 20, 21, and 23. Mock only mapper and WCS boundaries; assert real service decisions. + +```java +assertThat(service.dispatch("CK1", DispatchTrigger.INITIAL).isSuccess()).isTrue(); +verify(dispatchMapper).markRetryWait(argThat(m -> Integer.valueOf(0).equals(m.get("autoRetryCount")))); +verify(wcsClient).sendRelocationTask(jobOfType(23L)); +``` + +- [ ] **Step 2: Run the tests and verify RED** + +```powershell +& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=OutboundDispatchServiceImplTest test +``` + +Expected: FAIL because the dispatch API and WCS methods do not exist. + +- [ ] **Step 3: Implement dispatch state transitions, the minimal dense eligibility guard, and WCS routes** + +The service creates the outbox row if absent, delegates dense eligibility to `IDenseLaneService`, claims `SENDING`, calls the type route, records failures without throwing away the business job, and updates `mydo_job.status='3'`, `execution_phase='1'`, `start_time` only after success. The minimal dense mapper answers whether the job source is the current outermost occupied cargo position; non-03 or non-dense jobs are immediately eligible. Add `PUT /out/job/pushWcs/{jobId}` as the manual trigger backed by this service. Configure: + +```yaml +sendRetrieveTask: ${WCS_OUTBOUND_PATH:/wcs/api/receiveWmsOutJob} +sendLocationOutboundTask: ${WCS_LOCATION_OUTBOUND_PATH:/wcs/api/receiveWmsLocationOutJob} +sendRelocationTask: ${WCS_RELOCATION_PATH:/wcs/api/receiveWmsMoveJob} +``` + +- [ ] **Step 4: Run the tests and verify GREEN** + +Run Step 2. Expected: PASS. + +- [ ] **Step 5: Commit** + +```powershell +git add ruoyi-admin/src/main/java/com/ruoyi/out/dispatch ruoyi-admin/src/main/java/com/ruoyi/api/client/WcsClient.java ruoyi-admin/src/main/resources/application.yml ruoyi-admin/src/main/java/com/ruoyi/in/job ruoyi-admin/src/main/java/com/ruoyi/out/job/controller/OutMydoJobController.java ruoyi-admin/src/test/java/com/ruoyi/out/dispatch/service/impl/OutboundDispatchServiceImplTest.java +git commit -m "feat: add outbound WCS retry dispatch" +``` + +### Task 3: Dense Lane Geometry And Eligibility + +**Files:** +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLanePosition.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseRelocationCandidate.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/mapper/DenseLaneMapper.java` +- Modify: `ruoyi-admin/src/main/resources/mapper/out/DenseLaneMapper.xml` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/IDenseLaneService.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/impl/DenseLaneServiceImpl.java` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/out/dense/service/impl/DenseLaneServiceImplTest.java` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/out/dense/mapper/DenseLaneMapperSqlTest.java` + +**Interfaces:** +- Produces: `DispatchEligibility checkDispatchEligibility(MydoJob job)`. +- Produces: `List selectBlockersForUpdate(String cargoSpaceId)` ordered outer-to-inner. +- Produces: `BasCargoSpace selectRelocationTargetForUpdate(RelocationTargetQuery query)`. +- Produces: lane summary, tray preview, and inventory detail queries consumed by Tasks 6 and 7. + +- [ ] **Step 1: Write failing direction and SQL tests** + +Assert direction 1 treats the maximum occupied column as outermost, direction 2 treats the minimum as outermost, direction 3 uses nearest boundary, non-03 jobs bypass the rule, blockers exclude trays already covered by active outbound jobs, and destination SQL enforces same floor and different `group_coding`. + +- [ ] **Step 2: Run focused tests and verify RED** + +```powershell +& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=DenseLaneServiceImplTest,DenseLaneMapperSqlTest test +``` + +Expected: FAIL because dense-lane classes do not exist. + +- [ ] **Step 3: Implement pure ordering helpers and locked mapper queries** + +Centralize direction ordering in one service. SQL uses `UPDLOCK,HOLDLOCK` for blocker/destination selection, treats cargo statuses 2/3/4 with tray codes as occupied, excludes active jobs for destination reservations, and joins stock profiles used by current inbound rules. + +- [ ] **Step 4: Run tests and verify GREEN** + +Run Step 2. Expected: PASS. + +- [ ] **Step 5: Commit** + +```powershell +git add ruoyi-admin/src/main/java/com/ruoyi/out/dense ruoyi-admin/src/main/resources/mapper/out/DenseLaneMapper.xml ruoyi-admin/src/test/java/com/ruoyi/out/dense +git commit -m "feat: enforce dense lane outermost order" +``` + +### Task 4: Relocation Job Generation And Completion + +**Files:** +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/relocation/domain/RelocationGenerateRequest.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/relocation/domain/RelocationPreview.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/relocation/mapper/RelocationJobMapper.java` +- Create: `ruoyi-admin/src/main/resources/mapper/out/RelocationJobMapper.xml` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/relocation/service/IRelocationJobService.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/relocation/service/impl/RelocationJobServiceImpl.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/relocation/controller/RelocationJobController.java` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/out/relocation/service/impl/RelocationJobServiceImplTest.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/api/controller/ExternalApiController.java` + +**Interfaces:** +- Produces: `List createBlockerRelocations(String blockedJobId)`. +- Produces: `RelocationPreview preview(RelocationGenerateRequest request)` and `List generate(RelocationGenerateRequest request)`. +- Produces: `AjaxResult completeFromWcs(String jobId)`. + +- [ ] **Step 1: Write failing relocation tests** + +Cover type 23/task sequence, one main job per tray, one detail per stock detail, same-floor/different-lane rejection, source status 4/target status 3 reservation, all-or-nothing capacity validation, completion inventory move, cargo status swap, archive, duplicate callback, and dispatch wake-up after commit. + +- [ ] **Step 2: Run test and verify RED** + +```powershell +& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=RelocationJobServiceImplTest test +``` + +Expected: FAIL because relocation service does not exist. + +- [ ] **Step 3: Implement transactional generation and completion** + +Use `@Transactional(rollbackFor = Exception.class)`. Generate blockers outer-to-inner, reserve all destinations before inserting jobs, copy stock trace fields into job details, and create dispatch rows. On completion, lock and validate active type 23, update every `bas_stock` row for the tray, switch cargo statuses, archive job/detail with explicit column lists, delete active rows, then dispatch the next eligible source-lane job after commit. + +- [ ] **Step 4: Route WCS completion by type** + +In `ExternalApiController.completeOutbound`, type 23 calls `relocationJobService.completeFromWcs`; all other outbound types keep current phase-5/PDA behavior. + +- [ ] **Step 5: Run tests and verify GREEN** + +Run Step 2. Expected: PASS. + +- [ ] **Step 6: Commit** + +```powershell +git add ruoyi-admin/src/main/java/com/ruoyi/out/relocation ruoyi-admin/src/main/resources/mapper/out/RelocationJobMapper.xml ruoyi-admin/src/main/java/com/ruoyi/api/controller/ExternalApiController.java ruoyi-admin/src/test/java/com/ruoyi/out/relocation +git commit -m "feat: add dense warehouse relocation jobs" +``` + +### Task 5: Integrate Existing Outbound Allocation And Location Outbound + +**Files:** +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/out/stockout/service/impl/OutStockoutServiceImpl.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/out/location/service/impl/LocationOutboundServiceImpl.java` +- Modify: `ruoyi-admin/src/test/java/com/ruoyi/out/stockout/service/impl/OutStockoutServiceImplTest.java` +- Modify: `ruoyi-admin/src/test/java/com/ruoyi/out/location/service/impl/LocationOutboundServiceImplTest.java` + +**Interfaces:** +- Consumes: relocation blocker generation and unified dispatch from Tasks 2 and 4. +- Produces: allocation responses that distinguish dispatched, queued-for-retry, and blocked-by-relocation jobs. + +- [ ] **Step 1: Add failing integration-unit tests** + +Assert auto/manual allocation no longer calls `MydoJobService.pushOutJobToWcs`, specified stock allocation creates blocker relocations before dispatch, normal non-03 allocation dispatches directly, location outbound creates relocations for non-outbound full blockers, and WCS failure returns business success with compensation message. + +- [ ] **Step 2: Run tests and verify RED** + +```powershell +& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=OutStockoutServiceImplTest,LocationOutboundServiceImplTest test +``` + +- [ ] **Step 3: Replace direct push calls with prepare-and-dispatch orchestration** + +After each successful database allocation, call blocker generation for the selected job, create dispatch rows for every new job, and dispatch only currently eligible jobs. Keep existing non-dense procedure behavior and stock-status filters unchanged. + +- [ ] **Step 4: Run tests and verify GREEN** + +Run Step 2. Expected: PASS. + +- [ ] **Step 5: Commit** + +```powershell +git add ruoyi-admin/src/main/java/com/ruoyi/out/stockout/service/impl/OutStockoutServiceImpl.java ruoyi-admin/src/main/java/com/ruoyi/out/location/service/impl/LocationOutboundServiceImpl.java ruoyi-admin/src/test/java/com/ruoyi/out/stockout ruoyi-admin/src/test/java/com/ruoyi/out/location +git commit -m "feat: prepare dense blockers during outbound allocation" +``` + +### Task 6: KPI Dense Plan Manual Relocation + +**Files:** +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/kpi/controller/KpiController.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/kpi/service/KpiService.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/kpi/service/impl/KpiServiceImpl.java` +- Modify: `ruoyi-ui/src/api/kpi/kpi.js` +- Modify: `ruoyi-ui/src/views/kpi/plan/index.vue` +- Modify: `ruoyi-ui/src/views/kpi/plan/components/DenseCargoSpaceMap.vue` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/kpi/service/impl/KpiDenseRelocationServiceTest.java` + +**Interfaces:** +- Produces: `GET /kpi/denseRelocation/options`, `POST /kpi/denseRelocation/preview`, and `POST /kpi/denseRelocation/generate`. + +- [ ] **Step 1: Write failing controller/service tests** + +Assert only warehouse 03 is accepted, target lane floor equals source/current floor, options require sufficient compatible capacity, preview returns exact outer trays and inventory totals, and generate revalidates state. + +- [ ] **Step 2: Run Java tests and verify RED** + +```powershell +& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=KpiDenseRelocationServiceTest test +``` + +- [ ] **Step 3: Implement backend endpoints and existing-style UI** + +Add a compact “指定移库” button to the dense toolbar. Use an Element UI dialog with source lane, numeric tray count, target lane, and a fixed-height preview table. Do not add decorative cards or alter map dimensions. Refresh map data after successful generation. + +- [ ] **Step 4: Run Java tests and production UI build** + +```powershell +& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=KpiDenseRelocationServiceTest test +Set-Location ruoyi-ui +npm run build:prod +``` + +Expected: tests PASS and Vue build exits 0. + +- [ ] **Step 5: Commit** + +```powershell +git add ruoyi-admin/src/main/java/com/ruoyi/kpi ruoyi-admin/src/test/java/com/ruoyi/kpi ruoyi-ui/src/api/kpi/kpi.js ruoyi-ui/src/views/kpi/plan +git commit -m "feat: add KPI dense lane relocation" +``` + +### Task 7: Dense Lane Outbound Menu And Workflow + +**Files:** +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/controller/DenseLaneOutboundController.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLaneOutboundQuery.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLaneOutboundRequest.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLaneSummary.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/IDenseLaneOutboundService.java` +- Create: `ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/impl/DenseLaneOutboundServiceImpl.java` +- Create: `ruoyi-ui/src/api/out/denseLaneOutbound.js` +- Create: `ruoyi-ui/src/views/out/denseLaneOutbound/index.vue` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/out/dense/service/impl/DenseLaneOutboundServiceImplTest.java` + +**Interfaces:** +- Produces: `GET /out/denseLaneOutbound/list`, `GET /out/denseLaneOutbound/preview`, and `POST /out/denseLaneOutbound/generate`. + +- [ ] **Step 1: Write failing service tests** + +Assert list groups only full 03 dense lanes, totals all stock details per tray, preview selects exactly outermost N unreserved trays, quantity over capacity fails, stale preview fails generation, exit compatibility is validated, and every generated type-20 job contains the selected tray's complete inventory details. + +- [ ] **Step 2: Run tests and verify RED** + +```powershell +& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=DenseLaneOutboundServiceImplTest test +``` + +- [ ] **Step 3: Implement backend and menu page** + +Use the migration permissions from Task 1. The page displays group code, area, row, floor, full/available tray counts, total stock, current outer tray, and expandable inventory details. Generation dialog uses an integer stepper, exit selector, and preview table showing exact trays and quantities. + +- [ ] **Step 4: Verify tests and UI build** + +Run Task 6 Step 4 with `DenseLaneOutboundServiceImplTest`. Expected: PASS and build exit 0. + +- [ ] **Step 5: Commit** + +```powershell +git add ruoyi-admin/src/main/java/com/ruoyi/out/dense ruoyi-admin/src/test/java/com/ruoyi/out/dense ruoyi-ui/src/api/out/denseLaneOutbound.js ruoyi-ui/src/views/out/denseLaneOutbound sql/20260716_dense_outbound_relocation_dispatch.sql +git commit -m "feat: add dense lane outbound workflow" +``` + +### Task 8: Outbound Job Management Dispatch UI + +**Files:** +- Modify: `ruoyi-ui/src/api/out/job.js` +- Modify: `ruoyi-ui/src/views/out/job/index.vue` +- Modify: `sql/20260716_dense_outbound_relocation_dispatch.sql` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/out/job/controller/OutMydoJobDispatchControllerTest.java` + +**Interfaces:** +- Consumes: dispatch fields and `PUT /out/job/pushWcs/{jobId}`. + +- [ ] **Step 1: Write failing controller permission/state test** + +Assert the endpoint requires `out:job:pushWcs`, delegates with `MANUAL`, rejects completed jobs, and returns blocked reason without calling WCS when a dense job is not outermost. + +- [ ] **Step 2: Run test and verify RED** + +```powershell +& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=OutMydoJobDispatchControllerTest test +``` + +- [ ] **Step 3: Implement UI columns and manual action** + +Add WCS status, automatic retry count, and last-error tooltip columns. Use the existing send icon button with tooltip “手动下发 WCS”, permission `out:job:pushWcs`, and a confirmation message containing attempts and last error. Show it for pending, retry-wait, exhausted, and blocked active jobs; backend remains authoritative. + +- [ ] **Step 4: Verify controller and UI build** + +Run Step 2 and `npm run build:prod`. Expected: PASS and build exit 0. + +- [ ] **Step 5: Commit** + +```powershell +git add ruoyi-admin/src/test/java/com/ruoyi/out/job ruoyi-ui/src/api/out/job.js ruoyi-ui/src/views/out/job/index.vue sql/20260716_dense_outbound_relocation_dispatch.sql +git commit -m "feat: add manual WCS dispatch action" +``` + +### Task 9: Full Regression, Migration, And Runtime Scenarios + +**Files:** +- Create: `docs/testing/2026-07-16-dense-outbound-relocation-dispatch-report.md` + +**Interfaces:** +- Verifies all interfaces produced above as one workflow. + +- [ ] **Step 1: Run all backend tests** + +```powershell +& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -am test +``` + +Expected: BUILD SUCCESS with zero test failures. + +- [ ] **Step 2: Run backend package and frontend production build** + +```powershell +& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' clean package -DskipTests +Set-Location ruoyi-ui +npm run build:prod +``` + +Expected: both commands exit 0. + +- [ ] **Step 3: Apply migration to the configured disposable/local database** + +Execute `sql/20260716_dense_outbound_relocation_dispatch.sql` twice. Expected: both runs succeed, one task type 23 row, one Quartz task, one menu, three button permissions, and no duplicate indexes. + +- [ ] **Step 4: Run runtime integration scenarios** + +Verify with controlled WCS mock responses: initial failure plus five retries reaches exhausted; manual recovery succeeds; direction-1 and direction-2 lanes reject inner jobs; blocker relocation completes source/target inventory atomically; location outbound creates blockers; KPI manual relocation stays same-floor; lane outbound selects exactly outer N; non-03 outbound remains direct. + +- [ ] **Step 5: Verify UI with Playwright screenshots** + +Check outbound job management, KPI relocation dialog, and dense lane outbound page at desktop and mobile/narrow viewports. Verify no overlap, clipped button text, blank table, or broken dialog sizing. + +- [ ] **Step 6: Write the report and run requirement audit** + +Record commands, counts, screenshots, created job IDs, retry transitions, relocation source/target IDs, lane outbound selections, and residual risks. Map each of the six user requirements to direct evidence. + +- [ ] **Step 7: Commit the verification report** + +```powershell +git add docs/testing/2026-07-16-dense-outbound-relocation-dispatch-report.md +git commit -m "test: verify dense outbound dispatch workflows" +```