1186 lines
56 KiB
Markdown
1186 lines
56 KiB
Markdown
# Shopee Outbound API WES Mapping 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:** Implement Shopee Automation outbound interfaces plus protocol sections `4.1`-`5.8`, with `edi-shopee` as the external Shopee-facing entry and WES `ShopeeInboundApiHandler` as the internal business handler.
|
||
|
||
**Architecture:** Shopee calls `C:\work\gitlab\shopee\edi-shopee`; `edi-shopee` owns Shopee URL paths, JWT validation/generation, protocol response shape, EDI logging, and forwarding to WES. WES business handling stays in `wes-loghub/wms-api/src/main/groovy/com/ittx/wms/api/service/platform/ShopeeInboundApiHandler.groovy`, reached by `edi-shopee` through the existing WES sync API with `api=shopee...`.
|
||
|
||
**Tech Stack:** Groovy, Spring Boot, CBT `ResponseMessage`, WES `SyncApiController`/`ApiService` platform dispatch, MySQL/Flyway, `edi-shopee` HTTP/JWT integration.
|
||
|
||
---
|
||
|
||
## Scope
|
||
|
||
This plan covers the outbound module, inventory/rack-transfer module, and basic-data module interfaces present in this protocol file, based on:
|
||
|
||
- `出库单接口文档/Shopee_Automation_Vendor_接入协议手册_出库模块映射WES字段_V1.2.md`
|
||
- `wes-loghub/wms-api/src/main/groovy/com/ittx/wms/api/service/platform/ShopeeInboundApiHandler.groovy`
|
||
- `C:\work\gitlab\shopee\edi-shopee`
|
||
|
||
Do not implement inbound module interfaces in this plan. Include all concrete interfaces from `3.1`-`3.4`, `4.1`-`4.7`, and `5.1`-`5.8`.
|
||
|
||
## Current State
|
||
|
||
- `SyncApiController` already receives standard platform calls and delegates through `ApiService`; this remains the internal WES target called by `edi-shopee`.
|
||
- `ApiService` already delegates `ess.*` and `shopee.*` APIs to `PlatformInboundApiService`.
|
||
- `ShopeeInboundApiHandler` exists but has no outbound cases implemented.
|
||
- Confirmed: `4.2`-`4.5` Vendor-to-WES inventory/rack-transfer interfaces all enter WES through `ShopeeInboundApiHandler`; the handler then reuses existing `wms-transfer` and `wms-inventory` services.
|
||
- Confirmed: WES-to-Vendor basic-data interfaces in `5.2`-`5.8` are driven by scheduled jobs using a three-step `.confirm` -> `.get` -> `.uploadStatus` flow. Protocol `5.5` remains Vendor-to-WES and is not part of that scheduled outbound flow.
|
||
- Confirmed: Shopee extension fields are persisted through the dictionary mechanism only. Do not add WES entity columns for Shopee-only fields; use different dictionary group types for different usage locations.
|
||
- Confirmed: All 50 concrete interfaces in this plan must be implemented in this delivery. New Shopee-specific implementation classes must live under a `shopee` subpackage; keep only the existing platform entry handler in `service/platform`.
|
||
- `ShipmentHeader` already contains key Shopee fields: `cutOffTime`, `purchaseTime`, `orderTime`, `shopeeWave`, `waveRule`, `kickOutWave`, `ticketType`, `pickType`, `orderStructure`, `groupKey`.
|
||
- `ShopeeWaveService` has low-water scheduling and persistence, but the actual upstream wave-number request is still a placeholder.
|
||
- `WaveRuleMatchService` has Shopee wave binding placeholders and local binding/rollback logic.
|
||
- `wms-transfer` already contains transfer order services; use those existing transfer entities/services for rack-transfer data extraction before adding any new persistence.
|
||
- `edi-shopee` already owns outbound HTTP/token patterns and is the Shopee-facing entry for both inbound calls from Shopee and outbound calls to Shopee.
|
||
|
||
## File Structure
|
||
|
||
### wes-loghub
|
||
|
||
- Modify: `wms-api/src/main/groovy/com/ittx/wms/api/config/domain/PlatformApiConstants.groovy`
|
||
- Add Shopee outbound API names.
|
||
- Modify: `wms-api/src/main/groovy/com/ittx/wms/api/service/platform/ShopeeInboundApiHandler.groovy`
|
||
- Keep as the existing platform dispatch entry; add switch cases for all 50 concrete APIs and delegate to services in the `shopee` subpackage.
|
||
- Create: `wms-api/src/main/groovy/com/ittx/wms/api/domain/platform/shopee/ShopeeOutboundApiCmds.groovy`
|
||
- Store request DTOs for all 50 Shopee protocol APIs.
|
||
- Create: `wms-api/src/main/groovy/com/ittx/wms/api/domain/platform/shopee/ShopeeOutboundApiResults.groovy`
|
||
- Store response DTOs when a list result is required.
|
||
- Create: `wms-api/src/main/groovy/com/ittx/wms/api/service/platform/shopee/ShopeeOutboundShipmentMappingService.groovy`
|
||
- Convert Shopee request fields into existing WES entities and dictionaries.
|
||
- Modify: `wms-wave/src/main/groovy/com/ittx/wms/wave/service/hairo/ShopeeWaveService.groovy`
|
||
- Replace `requestShopeeWaveNumbers` placeholder with a call to `edi-shopee`.
|
||
- Modify: `wms-wave/src/main/groovy/com/ittx/wms/wave/service/hairo/WaveRuleMatchService.groovy`
|
||
- Replace Shopee wave bind placeholder with a call to `edi-shopee` and parse failed shipment IDs.
|
||
- Do not modify WES transfer-order business hooks for `4.1` in this phase.
|
||
- Only implement the `4.1`, `4.6`, and `4.7` interface surfaces and `edi-shopee` forwarding paths; the real移库业务触发点 remains explicitly out of scope.
|
||
- Create only if no existing transfer service method is suitable: `wms-api/src/main/groovy/com/ittx/wms/api/service/platform/shopee/ShopeeRackTransferMappingService.groovy`
|
||
- Define `4.1`, `4.6`, and `4.7` request contracts and response normalization only; do not read `TransferOrderHeader`/detail data until the business trigger is confirmed later.
|
||
- Modify: `src/main/resources/application.yml` and profile-specific config only if no existing system-parameter path is available.
|
||
- Add internal `edi-shopee` endpoint only if it cannot be represented by existing API/customer config.
|
||
|
||
### edi-shopee
|
||
|
||
- Create or modify: `src/main/groovy/com/ittx/edi/erp/service/ShopeeJwtService.groovy`
|
||
- Generate and verify HS256 JWT per Shopee protocol.
|
||
- Create or modify: `src/main/groovy/com/ittx/edi/erp/service/ShopeeAutomationVendorService.groovy`
|
||
- Validate Shopee inbound requests, forward to WES, build Shopee outbound URLs, set headers, call Shopee Automation Vendor APIs, normalize responses.
|
||
- Create or modify: `src/main/groovy/com/ittx/edi/erp/controller/ShopeeAutomationController.groovy`
|
||
- External endpoints called by Shopee plus internal endpoints consumed by `wes-loghub` for wave-number request and wave binding.
|
||
- Modify: `src/main/resources/application-zzw.yml`.
|
||
- Read Shopee JWT/account/host settings from `customerMap.shopee`; do not introduce a second config path in `application-dev.yml` or `application-k8s.yml` for this phase.
|
||
|
||
## Interface Inventory
|
||
|
||
Protocol alignment from `出库单接口文档/Shopee_Automation_Vendor_接入协议手册_出库模块映射WES字段_V1.2.md`:
|
||
|
||
- Outbound module title count: 45 entries under `3.1` to `3.4`.
|
||
- Outbound module URL count: 35 concrete, unique `/api/v2/automation/.../outbound/...` APIs.
|
||
- Reused/deprecated/explanation count: 10 title entries.
|
||
- Inventory/rack-transfer URL count: 7 concrete APIs under `4.1` to `4.7`.
|
||
- Basic-data URL count: 8 concrete APIs under `5.1` to `5.8`.
|
||
- Total implemented protocol API inventory in this plan: 50 concrete APIs.
|
||
|
||
### Concrete Outbound APIs
|
||
|
||
| No. | Section | Direction | Shopee/edi-shopee path | WES api constant | Implementation note |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| 1 | 3.1.1 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/salesorder/create_sub_picking_task` | `shopee.outbound.salesorder.createSubPickingTask` | WES 下发销售 SubPickingTask |
|
||
| 2 | 3.1.2 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/salesorder/cancel_sub_picking_task` | `shopee.outbound.salesorder.cancelSubPickingTask` | WES 取消销售 SubPickingTask |
|
||
| 3 | 3.1.3 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/salesorder/update_task_flag` | `shopee.outbound.salesorder.updateTaskFlag` | 更新 urgent flag |
|
||
| 4 | 3.1.5 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/start_picking_task` | `shopee.outbound.salesorder.startPickingTask` | Vendor 开始拣货任务 |
|
||
| 5 | 3.1.6 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/bind_picking_task` | `shopee.outbound.salesorder.bindPickingTask` | Vendor 实绑拣货任务 |
|
||
| 6 | 3.1.7 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/sync_picking_detail` | `shopee.outbound.salesorder.syncPickingDetail` | 增量拣货明细 |
|
||
| 7 | 3.1.8 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/change_picking_device` | `shopee.outbound.salesorder.changePickingDevice` | SubPickingTask 换箱,不产生新任务 |
|
||
| 8 | 3.1.9 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/complete_picking_task` | `shopee.outbound.salesorder.completePickingTask` | 完成拣货任务 |
|
||
| 9 | 3.1.10 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/search_picking_process_guide` | `shopee.outbound.salesorder.searchPickingProcessGuide` | 查询流程指引 |
|
||
| 10 | 3.1.11 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/salesorder/query_picking_detail` | `shopee.outbound.salesorder.queryPickingDetail` | 查询 Vendor 拣货任务列表 |
|
||
| 11 | 3.2.1 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/salesorder/create_order` | `shopee.outbound.salesorder.createOrder` | WMS 给 Vendor 下销售订单 |
|
||
| 12 | 3.2.2 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/salesorder/cancel_order` | `shopee.outbound.salesorder.cancelOrderToVendor` | WMS 向 Vendor 撤回订单,协议标题为“捞单” |
|
||
| 13 | 3.2.3 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/cancel_order` | `shopee.outbound.salesorder.vendorCancelOrder` | Vendor 向 WMS 撤单 |
|
||
| 14 | 3.2.4 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/salesorder/lock_unlock_order` | `shopee.outbound.salesorder.lockUnlockOrder` | WMS 下发锁单/解锁 |
|
||
| 15 | 3.2.5 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/cache_task_number` | `shopee.outbound.salesorder.cacheTaskNumber` | 获取号段缓存 |
|
||
| 16 | 3.2.7 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/create_picking_task` | `shopee.outbound.salesorder.createPickingTask` | 创建 picking task |
|
||
| 17 | 3.2.8 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/append_order` | `shopee.outbound.salesorder.appendOrder` | 追加订单明细 |
|
||
| 18 | 3.2.9 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/change_device` | `shopee.outbound.salesorder.changeDevice` | Flow Pick 换箱,产生新任务 |
|
||
| 19 | 3.2.10 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/salesorder/vendor_complete_task` | `shopee.outbound.salesorder.vendorCompleteTask` | Vendor 完成 task |
|
||
| 20 | 3.2.11 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/salesorder/search_lock_order_list` | `shopee.outbound.salesorder.searchLockOrderList` | 查询冻结状态订单列表 |
|
||
| 21 | 3.3.1 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/rtsmto/create_require` | `shopee.outbound.rtsmto.createRequire` | RTS/MTO 需求下发 |
|
||
| 22 | 3.3.2 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/rtsmto/cancel_require` | `shopee.outbound.rtsmto.cancelRequire` | RTS/MTO 需求取消 |
|
||
| 23 | 3.3.3 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/rtsmto/sync_occupied_require` | `shopee.outbound.rtsmto.syncOccupiedRequire` | 同步占用信息 |
|
||
| 24 | 3.3.6 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/rtsmto/create_picking_task` | `shopee.outbound.rtsmto.createPickingTask` | RTS/MTO 创建 picking task |
|
||
| 25 | 3.3.7 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/rtsmto/bind_picking_task` | `shopee.outbound.rtsmto.bindPickingTask` | RTS/MTO 实绑任务 |
|
||
| 26 | 3.3.8 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/rtsmto/append_order` | `shopee.outbound.rtsmto.appendOrder` | RTS/MTO 追加 |
|
||
| 27 | 3.3.9 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/rtsmto/sync_picking_detail` | `shopee.outbound.rtsmto.syncPickingDetail` | RTS/MTO 增量拣货明细 |
|
||
| 28 | 3.3.10 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/rtsmto/complete_task` | `shopee.outbound.rtsmto.completeTask` | RTS/MTO 完成 task |
|
||
| 29 | 3.3.11 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/rtsmto/change_picking_device` | `shopee.outbound.rtsmto.changePickingDevice` | RTS/MTO 换箱;协议原文 URL 有多余空格,实施时按无空格路径 |
|
||
| 30 | 3.4.1 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/mto/create_picking_task` | `shopee.outbound.mto.createPickingTask` | MTO 拣货任务下发 |
|
||
| 31 | 3.4.2 | WMS -> Vendor | `/api/v2/automation/tovendor/outbound/mto/cancel_picking_task` | `shopee.outbound.mto.cancelPickingTask` | MTO 取消拣货任务 |
|
||
| 32 | 3.4.5 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/mto/start_picking_task` | `shopee.outbound.mto.startPickingTask` | MTO 开始拣货 |
|
||
| 33 | 3.4.6 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/mto/bind_picking_task` | `shopee.outbound.mto.bindPickingTask` | MTO 真实绑定 |
|
||
| 34 | 3.4.7 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/mto/sync_picking_detail` | `shopee.outbound.mto.syncPickingDetail` | MTO 增量拣货明细 |
|
||
| 35 | 3.4.8 | Vendor -> WMS | `/api/v2/automation/toshopee/outbound/mto/complete_picking_task` | `shopee.outbound.mto.completePickingTask` | MTO 完成拣货任务 |
|
||
|
||
### Concrete Inventory and Basic APIs
|
||
|
||
| No. | Section | Direction | Shopee/edi-shopee path | WES api constant | Implementation note |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| 36 | 4.1 | WMS -> Vendor | `/api/v2/automation/tovendor/inventory/racktransfer/create_rt_order` | `shopee.inventory.racktransfer.createRtOrder` | WES 给 Vendor 同步移库占用库存 |
|
||
| 37 | 4.2 | Vendor -> WMS | `/api/v2/automation/toshopee/inventory/racktransfer/occupy_device` | `shopee.inventory.racktransfer.occupyDevice` | Vendor 占用或释放 PickingDevice |
|
||
| 38 | 4.3 | Vendor -> WMS | `/api/v2/automation/toshopee/inventory/racktransfer/submit_picking_sku_list` | `shopee.inventory.racktransfer.submitPickingSkuList` | Vendor 整箱同步移库拣货明细 |
|
||
| 39 | 4.4 | Vendor -> WMS | `/api/v2/automation/toshopee/inventory/racktransfer/sync_picking_sku_list` | `shopee.inventory.racktransfer.syncPickingSkuList` | Vendor 定时回传 WMS 创建移库单拣货明细 |
|
||
| 40 | 4.5 | Vendor -> WMS | `/api/v2/automation/toshopee/inventory/racktransfer/handle_diff_stock` | `shopee.inventory.racktransfer.handleDiffStock` | Vendor 盘点差异调减同步给 WMS |
|
||
| 41 | 4.6 | WMS -> Vendor | `/api/v2/automation/tovendor/inventory/racktransfer/query_picking_list` | `shopee.inventory.racktransfer.queryPickingList` | WES 查询 Vendor 移库拣货明细用于对账 |
|
||
| 42 | 4.7 | WMS -> Vendor | `/api/v2/automation/tovendor/inventory/racktransfer/update_rt_order` | `shopee.inventory.racktransfer.updateRtOrder` | WES 更新移库单优先级或取消状态 |
|
||
| 43 | 5.1 | Vendor -> WMS | `/api/v2/automation/toshopee/basic/user/query_user_exist` | `shopee.basic.user.queryUserExist` | Vendor 查询 WES 用户是否存在 |
|
||
| 44 | 5.2 | WMS -> Vendor | `/api/v2/automation/tovendor/basic/inventory/batch_status_update` | `shopee.basic.inventory.batchStatusUpdate` | WES 同步批次状态给 Vendor |
|
||
| 45 | 5.3 | WMS -> Vendor | `/api/v2/automation/tovendor/basic/inventory/query_sku_batch_inventory` | `shopee.basic.inventory.querySkuBatchInventory` | WES 查询 Vendor 批次库存信息 |
|
||
| 46 | 5.4 | WMS -> Vendor | `/api/v2/automation/tovendor/basic/inventory/sync_reconciliation_result` | `shopee.basic.inventory.syncReconciliationResult` | WES 同步库存对账结果给 Vendor |
|
||
| 47 | 5.5 | Vendor -> WMS | `/api/v2/automation/toshopee/basic/sku/query_sku_detail` | `shopee.basic.sku.querySkuDetail` | Vendor 查询 WES SKU 信息 |
|
||
| 48 | 5.6 | WMS -> Vendor | `/api/v2/automation/tovendor/basic/sku/sync_sku_info` | `shopee.basic.sku.syncSkuInfo` | WES 同步 SKU 信息给 Vendor |
|
||
| 49 | 5.7 | WMS -> Vendor | `/api/v2/automation/tovendor/basic/robot/query_agv_status` | `shopee.basic.robot.queryAgvStatus` | WES 查询 Vendor AGV 设备信息 |
|
||
| 50 | 5.8 | WMS -> Vendor | `/api/v2/automation/tovendor/basic/inventory/query_vendor_unit_list` | `shopee.basic.inventory.queryVendorUnitList` | WES 查询 Vendor Unit 信息 |
|
||
|
||
### Reused or Deprecated Title Entries
|
||
|
||
| Section | Title | Handling |
|
||
| --- | --- | --- |
|
||
| 3.1.4 | Vendor绑定/解绑device(空占)【复用basic接口】废弃 | 不新增出库接口 |
|
||
| 3.2.6 | Vendor绑定解绑设备【复用basic接口】废弃 | 不新增出库接口 |
|
||
| 3.2.12 | 复用接口列表 | 说明项,不新增接口 |
|
||
| 3.3.4 | Vendor绑定/解绑device【废弃】 | 不新增出库接口 |
|
||
| 3.3.5 | Vendor向wms获取号段缓存【复用】 | 复用 3.2.5 |
|
||
| 3.3.12 | 查询Vendor拣货任务列表【复用】 | 复用 3.1.11 |
|
||
| 3.3.13 | 更新需求的urgent_flag【复用】 | 复用 3.1.3 |
|
||
| 3.4.3 | WMS向Vendor更新task的urgent flag【复用3.1.3】 | 复用 3.1.3 |
|
||
| 3.4.4 | Vendor绑定/解绑device【复用basic接口】废弃 | 不新增出库接口 |
|
||
| 3.4.9 | 查询Vendor拣货任务列表【复用】 | 复用 3.1.11 |
|
||
|
||
## Interface Names
|
||
|
||
Add constants for all 50 concrete APIs above. All 50 must be implemented in this delivery; the constant inventory must stay aligned to the table and to Task 1 Step 1.
|
||
|
||
Two `cancel_order` protocol paths exist with different directions, so they use separate WES API identifiers: `cancelOrderToVendor` for `tovendor` and `vendorCancelOrder` for `toshopee`.
|
||
|
||
Use these names as WES internal API identifiers. Shopee does not call WES directly; Shopee calls `edi-shopee`, and `edi-shopee` forwards to WES `SyncApiController` with `/api/wms/api/sync/in?api=<constant>&format=json`.
|
||
|
||
---
|
||
|
||
### Task 1: Add Shopee Constants and DTOs
|
||
|
||
**Files:**
|
||
- Modify: `C:\work\gitlab\shopee\wes-loghub\wms-api\src\main\groovy\com\ittx\wms\api\config\domain\PlatformApiConstants.groovy`
|
||
- Create: `C:\work\gitlab\shopee\wes-loghub\wms-api\src\main\groovy\com\ittx\wms\api\domain\platform\shopee\ShopeeOutboundApiCmds.groovy`
|
||
- Create: `C:\work\gitlab\shopee\wes-loghub\wms-api\src\main\groovy\com\ittx\wms\api\domain\platform\shopee\ShopeeOutboundApiResults.groovy`
|
||
|
||
- [ ] **Step 1: Add constants**
|
||
|
||
Add the full 50-interface constant set under `PlatformApiConstants.ShopeeInterfaceType`. Do not leave any of these 50 constants as `ApiMessages.MSG_INTF_0005` in the final implementation:
|
||
|
||
```groovy
|
||
static final String SALES_CREATE_SUB_PICKING_TASK = 'shopee.outbound.salesorder.createSubPickingTask'
|
||
static final String SALES_CANCEL_SUB_PICKING_TASK = 'shopee.outbound.salesorder.cancelSubPickingTask'
|
||
static final String SALES_UPDATE_TASK_FLAG = 'shopee.outbound.salesorder.updateTaskFlag'
|
||
static final String SALES_ORDER_CREATE = 'shopee.outbound.salesorder.createOrder'
|
||
static final String SALES_CANCEL_ORDER_TO_VENDOR = 'shopee.outbound.salesorder.cancelOrderToVendor'
|
||
static final String SALES_SEARCH_LOCK_ORDER_LIST = 'shopee.outbound.salesorder.searchLockOrderList'
|
||
static final String SALES_VENDOR_CANCEL_ORDER = 'shopee.outbound.salesorder.vendorCancelOrder'
|
||
static final String SALES_LOCK_UNLOCK_ORDER = 'shopee.outbound.salesorder.lockUnlockOrder'
|
||
static final String SALES_CACHE_TASK_NUMBER = 'shopee.outbound.salesorder.cacheTaskNumber'
|
||
static final String SALES_START_PICKING_TASK = 'shopee.outbound.salesorder.startPickingTask'
|
||
static final String SALES_BIND_PICKING_TASK = 'shopee.outbound.salesorder.bindPickingTask'
|
||
static final String SALES_SYNC_PICKING_DETAIL = 'shopee.outbound.salesorder.syncPickingDetail'
|
||
static final String SALES_CHANGE_PICKING_DEVICE = 'shopee.outbound.salesorder.changePickingDevice'
|
||
static final String SALES_COMPLETE_PICKING_TASK = 'shopee.outbound.salesorder.completePickingTask'
|
||
static final String SALES_SEARCH_PICKING_PROCESS_GUIDE = 'shopee.outbound.salesorder.searchPickingProcessGuide'
|
||
static final String SALES_QUERY_PICKING_DETAIL = 'shopee.outbound.salesorder.queryPickingDetail'
|
||
static final String SALES_CREATE_PICKING_TASK = 'shopee.outbound.salesorder.createPickingTask'
|
||
static final String SALES_APPEND_ORDER = 'shopee.outbound.salesorder.appendOrder'
|
||
static final String SALES_CHANGE_DEVICE = 'shopee.outbound.salesorder.changeDevice'
|
||
static final String SALES_VENDOR_COMPLETE_TASK = 'shopee.outbound.salesorder.vendorCompleteTask'
|
||
static final String RTSMTO_CREATE_REQUIRE = 'shopee.outbound.rtsmto.createRequire'
|
||
static final String RTSMTO_CANCEL_REQUIRE = 'shopee.outbound.rtsmto.cancelRequire'
|
||
static final String RTSMTO_SYNC_OCCUPIED_REQUIRE = 'shopee.outbound.rtsmto.syncOccupiedRequire'
|
||
static final String RTSMTO_CREATE_PICKING_TASK = 'shopee.outbound.rtsmto.createPickingTask'
|
||
static final String RTSMTO_BIND_PICKING_TASK = 'shopee.outbound.rtsmto.bindPickingTask'
|
||
static final String RTSMTO_APPEND_ORDER = 'shopee.outbound.rtsmto.appendOrder'
|
||
static final String RTSMTO_SYNC_PICKING_DETAIL = 'shopee.outbound.rtsmto.syncPickingDetail'
|
||
static final String RTSMTO_COMPLETE_TASK = 'shopee.outbound.rtsmto.completeTask'
|
||
static final String RTSMTO_CHANGE_PICKING_DEVICE = 'shopee.outbound.rtsmto.changePickingDevice'
|
||
static final String MTO_CREATE_PICKING_TASK = 'shopee.outbound.mto.createPickingTask'
|
||
static final String MTO_CANCEL_PICKING_TASK = 'shopee.outbound.mto.cancelPickingTask'
|
||
static final String MTO_START_PICKING_TASK = 'shopee.outbound.mto.startPickingTask'
|
||
static final String MTO_BIND_PICKING_TASK = 'shopee.outbound.mto.bindPickingTask'
|
||
static final String MTO_SYNC_PICKING_DETAIL = 'shopee.outbound.mto.syncPickingDetail'
|
||
static final String MTO_COMPLETE_PICKING_TASK = 'shopee.outbound.mto.completePickingTask'
|
||
static final String RACK_TRANSFER_CREATE_RT_ORDER = 'shopee.inventory.racktransfer.createRtOrder'
|
||
static final String RACK_TRANSFER_OCCUPY_DEVICE = 'shopee.inventory.racktransfer.occupyDevice'
|
||
static final String RACK_TRANSFER_SUBMIT_PICKING_SKU_LIST = 'shopee.inventory.racktransfer.submitPickingSkuList'
|
||
static final String RACK_TRANSFER_SYNC_PICKING_SKU_LIST = 'shopee.inventory.racktransfer.syncPickingSkuList'
|
||
static final String RACK_TRANSFER_HANDLE_DIFF_STOCK = 'shopee.inventory.racktransfer.handleDiffStock'
|
||
static final String RACK_TRANSFER_QUERY_PICKING_LIST = 'shopee.inventory.racktransfer.queryPickingList'
|
||
static final String RACK_TRANSFER_UPDATE_RT_ORDER = 'shopee.inventory.racktransfer.updateRtOrder'
|
||
static final String BASIC_USER_QUERY_USER_EXIST = 'shopee.basic.user.queryUserExist'
|
||
static final String BASIC_INVENTORY_BATCH_STATUS_UPDATE = 'shopee.basic.inventory.batchStatusUpdate'
|
||
static final String BASIC_INVENTORY_QUERY_SKU_BATCH_INVENTORY = 'shopee.basic.inventory.querySkuBatchInventory'
|
||
static final String BASIC_INVENTORY_SYNC_RECONCILIATION_RESULT = 'shopee.basic.inventory.syncReconciliationResult'
|
||
static final String BASIC_SKU_QUERY_SKU_DETAIL = 'shopee.basic.sku.querySkuDetail'
|
||
static final String BASIC_SKU_SYNC_SKU_INFO = 'shopee.basic.sku.syncSkuInfo'
|
||
static final String BASIC_ROBOT_QUERY_AGV_STATUS = 'shopee.basic.robot.queryAgvStatus'
|
||
static final String BASIC_INVENTORY_QUERY_VENDOR_UNIT_LIST = 'shopee.basic.inventory.queryVendorUnitList'
|
||
```
|
||
|
||
- [ ] **Step 2: Add DTO shells**
|
||
|
||
Create DTOs with only fields present in the protocol tables and mapped to WES fields. Use Groovy classes, no Lombok, no new validation framework.
|
||
|
||
Minimum classes:
|
||
|
||
```groovy
|
||
package com.ittx.wms.api.domain.platform.shopee
|
||
|
||
import java.io.Serializable
|
||
|
||
class ShopeeCreateSubPickingTaskCmd implements Serializable {
|
||
String whs_id
|
||
String sub_pickup_id
|
||
Integer urgent_flag
|
||
Long cut_off_time
|
||
Long ship_by_date
|
||
Long purchase_time
|
||
Long order_time
|
||
Long ctime
|
||
Integer can_group_picking
|
||
String group_key
|
||
List<ShopeeSkuInfoCmd> sku_info_list = []
|
||
List<ShopeeSingleAttrCmd> single_attr_list = []
|
||
List<ShopeeMultiAttrCmd> multi_attr_list = []
|
||
Integer ticket_type
|
||
}
|
||
|
||
class ShopeeSkuInfoCmd implements Serializable {
|
||
String sku_id
|
||
BigDecimal qty
|
||
Integer block_type
|
||
Integer quality
|
||
}
|
||
|
||
class ShopeeSingleAttrCmd implements Serializable {
|
||
String attr_key
|
||
String attr_value_id
|
||
String attr_value_type
|
||
String attr_value_name
|
||
}
|
||
|
||
class ShopeeMultiAttrCmd implements Serializable {
|
||
String attr_key
|
||
List<ShopeeAttrCmd> attr_value_list = []
|
||
}
|
||
|
||
class ShopeeAttrCmd implements Serializable {
|
||
String attr_value_id
|
||
String attr_value_type
|
||
String attr_value_name
|
||
}
|
||
|
||
class ShopeeCancelSubPickingTaskCmd implements Serializable {
|
||
String whs_id
|
||
String sub_pickup_id
|
||
}
|
||
|
||
class ShopeeCreateRtOrderCmd implements Serializable {
|
||
String whs_id
|
||
String rt_order_id
|
||
List<ShopeeRtAttrCmd> attr_list = []
|
||
Long ctime
|
||
String operator
|
||
Integer ticket_type
|
||
List<ShopeeRtSkuInfoCmd> sku_info_list = []
|
||
}
|
||
|
||
class ShopeeRtAttrCmd implements Serializable {
|
||
String attr_key
|
||
String attr_value_id
|
||
String attr_value_name
|
||
}
|
||
|
||
class ShopeeRtSkuInfoCmd implements Serializable {
|
||
String sku_id
|
||
Integer block_type
|
||
BigDecimal qty
|
||
Integer sku_quality
|
||
}
|
||
|
||
class ShopeeUpdateTaskFlagCmd implements Serializable {
|
||
String whs_id
|
||
Integer biz_type
|
||
Integer ticket_type
|
||
List<String> ticket_number_list = []
|
||
Integer urgent_flag
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: Compile-check DTO syntax**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\wes-loghub
|
||
.\gradlew :wms-api:compileGroovy --no-problems-report
|
||
```
|
||
|
||
Expected: Groovy compile succeeds, or dependency resolution fails due local Nexus credentials. If Nexus fails, record the exact failure.
|
||
|
||
### Task 2: Wire ShopeeInboundApiHandler
|
||
|
||
**Files:**
|
||
- Modify: `C:\work\gitlab\shopee\wes-loghub\wms-api\src\main\groovy\com\ittx\wms\api\service\platform\ShopeeInboundApiHandler.groovy`
|
||
- Create: `C:\work\gitlab\shopee\wes-loghub\wms-api\src\main\groovy\com\ittx\wms\api\service\platform\shopee\ShopeeOutboundShipmentMappingService.groovy`
|
||
|
||
- [ ] **Step 1: Inject the mapping service**
|
||
|
||
Add:
|
||
|
||
```groovy
|
||
@Autowired
|
||
ShopeeOutboundShipmentMappingService shopeeOutboundShipmentMappingSvc
|
||
```
|
||
|
||
- [ ] **Step 2: Add switch cases**
|
||
|
||
Use the constants from Task 1. Add switch cases for all 50 concrete APIs and delegate to focused services under `com.ittx.wms.api.service.platform.shopee`.
|
||
|
||
```groovy
|
||
case PlatformApiConstants.ShopeeInterfaceType.SALES_CREATE_SUB_PICKING_TASK:
|
||
return createSubPickingTask(session, data)
|
||
case PlatformApiConstants.ShopeeInterfaceType.SALES_CANCEL_SUB_PICKING_TASK:
|
||
return cancelSubPickingTask(session, data)
|
||
case PlatformApiConstants.ShopeeInterfaceType.SALES_UPDATE_TASK_FLAG:
|
||
return updateTaskFlag(session, data)
|
||
case PlatformApiConstants.ShopeeInterfaceType.RACK_TRANSFER_OCCUPY_DEVICE:
|
||
return shopeeRackTransferSvc.occupyDevice(session, data)
|
||
case PlatformApiConstants.ShopeeInterfaceType.BASIC_SKU_QUERY_SKU_DETAIL:
|
||
return shopeeBasicDataSvc.querySkuDetail(session, data)
|
||
```
|
||
|
||
Final implementation must not return `ApiMessages.MSG_INTF_0005` for any of the 50 concrete APIs in the inventory.
|
||
|
||
- [ ] **Step 3: Add parse/validate methods**
|
||
|
||
Implement each method with the same pattern as `EssInboundApiHandler`: parse, validate required fields, set `CURRENT_WAREHOUSE`, call service.
|
||
|
||
Example:
|
||
|
||
```groovy
|
||
private ResponseMessage createSubPickingTask(TtxSession session, String data) {
|
||
ShopeeCreateSubPickingTaskCmd cmd
|
||
try {
|
||
cmd = convertValue(data, ShopeeCreateSubPickingTaskCmd.class)
|
||
} catch (Throwable ignored) {
|
||
return ResponseMessageFactory.error(ApiMessages.MSG_INTF_0003)
|
||
}
|
||
ResponseMessage validateRsp = validateCreateSubPickingTask(cmd)
|
||
if (validateRsp.hasError()) return validateRsp
|
||
session.params[WmsConstants.CURRENT_WAREHOUSE] = cmd.whs_id
|
||
return shopeeOutboundShipmentMappingSvc.createSubPickingTask(session, cmd)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 4: Compile**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\wes-loghub
|
||
.\gradlew :wms-api:compileGroovy --no-problems-report
|
||
```
|
||
|
||
Expected: Compile succeeds or reports only external dependency credential issues.
|
||
|
||
### Task 3: Implement Sales SubPickingTask Mapping
|
||
|
||
**Files:**
|
||
- Modify: `C:\work\gitlab\shopee\wes-loghub\wms-api\src\main\groovy\com\ittx\wms\api\service\platform\shopee\ShopeeOutboundShipmentMappingService.groovy`
|
||
- Reuse: `ShipmentHeaderService`, `ShipmentDetailService`, existing config/dictionary service if available
|
||
|
||
- [ ] **Step 1: Implement `createSubPickingTask`**
|
||
|
||
Map fields:
|
||
|
||
| Shopee field | WES field |
|
||
| --- | --- |
|
||
| `whs_id` | `shipment_header.warehouseCode` |
|
||
| `sub_pickup_id` | `shipment_header.erpOrderCode` and `shipment_header.shopeeWave` |
|
||
| `urgent_flag` | `shipment_header.priority` |
|
||
| `cut_off_time` | `shipment_header.cutOffTime` |
|
||
| `ship_by_date` | `shipment_header.scheduledShipDate` |
|
||
| `purchase_time` | `shipment_header.purchaseTime` |
|
||
| `order_time` | `shipment_header.orderTime` |
|
||
| `ctime` | dictionary only if business needs query/display; otherwise request log only |
|
||
| `can_group_picking` | dictionary only |
|
||
| `group_key` | `shipment_header.groupKey` |
|
||
| `ticket_type` | `shipment_header.ticketType`; `shipmentType` defaults to `XSCK` |
|
||
| `max_order_size` attr | dictionary only |
|
||
| `channel_id` attr | dictionary only |
|
||
| `fulfillment_chain_id` attr | dictionary only |
|
||
|
||
Use WES entity fields only for existing core business facts already present in the domain. All Shopee-only extension attributes go through the dictionary mechanism, not new columns.
|
||
|
||
- [ ] **Step 2: Implement idempotency**
|
||
|
||
Use `warehouseCode + erpOrderCode`:
|
||
|
||
```sql
|
||
select id from shipment_header where warehouseCode = ? and erpOrderCode = ? and processType = 'NORMAL'
|
||
```
|
||
|
||
If found, update mutable Shopee fields and replace details only if the task is still in pool. If task has started, return a non-retryable parameter/business error.
|
||
|
||
- [ ] **Step 3: Create details**
|
||
|
||
For each `sku_info_list` row:
|
||
|
||
| Shopee field | WES field |
|
||
| --- | --- |
|
||
| `sku_id` | `shipment_detail.itemCode` |
|
||
| `qty` | `shipment_detail.requestQty` |
|
||
| `block_type` | `shipment_detail.shelfLifeSts` |
|
||
| `quality` | `shipment_detail.inventorySts` |
|
||
|
||
Validate SKU existence by reusing existing item/detail service behavior. Do not hand-roll item master queries if a service already validates item code.
|
||
|
||
- [ ] **Step 4: Map all Shopee extension attributes to dictionary**
|
||
|
||
For `single_attr_list`, `multi_attr_list`, and Shopee-only scalar fields, write values to the existing field dictionary mechanism. Different usage locations must use different dictionary group types so downstream logic can distinguish meaning.
|
||
|
||
Minimum group type split:
|
||
|
||
| Usage location | Dictionary group type |
|
||
| --- | --- |
|
||
| Outbound sales/sub-picking task header attrs | `SHOPEE_OUTBOUND_TASK_HEADER` |
|
||
| Outbound order attrs | `SHOPEE_OUTBOUND_ORDER_HEADER` |
|
||
| RTS/MTO demand attrs | `SHOPEE_RTSMTO_DEMAND_HEADER` |
|
||
| MTO picking task attrs | `SHOPEE_MTO_TASK_HEADER` |
|
||
| Inventory/rack-transfer attrs | `SHOPEE_RACK_TRANSFER_HEADER` |
|
||
| Basic-data sync attrs | `SHOPEE_BASIC_DATA` |
|
||
|
||
If no compatible dictionary table/service exists in the current branch, add a separate dictionary task before implementation; do not add Shopee-only fields to WES domain entities:
|
||
|
||
```powershell
|
||
rg -n "shopee_field_dictionary|FieldDictionary|field_dictionary" C:\work\gitlab\shopee\wes-loghub
|
||
```
|
||
|
||
If absent, add a later task before implementation; do not create it inside this task ad hoc.
|
||
|
||
- [ ] **Step 5: Compile**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\wes-loghub
|
||
.\gradlew :wms-api:compileGroovy :wms-shipping:compileGroovy --no-problems-report
|
||
```
|
||
|
||
### Task 4: Implement Cancel and Urgent Flag Update
|
||
|
||
**Files:**
|
||
- Modify: `C:\work\gitlab\shopee\wes-loghub\wms-api\src\main\groovy\com\ittx\wms\api\service\platform\shopee\ShopeeOutboundShipmentMappingService.groovy`
|
||
|
||
- [ ] **Step 1: Implement cancel**
|
||
|
||
Input: `ShopeeCancelSubPickingTaskCmd`.
|
||
|
||
Behavior:
|
||
|
||
- Find by `warehouseCode = whs_id`, `erpOrderCode = sub_pickup_id`.
|
||
- If not found, return non-retryable business error.
|
||
- If already picked/closed, return non-retryable business error.
|
||
- Otherwise reuse existing cancellation/status-flow service. If no exact cancel service applies, mark `processType`/status via the same base cancel path used by manual shipment cancel, not a raw SQL-only status mutation.
|
||
- Ensure wave matching excludes canceled shipments.
|
||
|
||
- [ ] **Step 2: Implement urgent flag update**
|
||
|
||
Input: `ShopeeUpdateTaskFlagCmd`.
|
||
|
||
Behavior:
|
||
|
||
- Batch update `shipment_header.priority` by `erpOrderCode in ticket_number_list`.
|
||
- Return `success_list`, `fail_list`, and `not_exist_list`.
|
||
- Do not fail the entire request because one order is missing.
|
||
|
||
Return shape:
|
||
|
||
```groovy
|
||
[
|
||
success_list: successCodes,
|
||
fail_list: failCodes,
|
||
not_exist_list: notExistCodes
|
||
]
|
||
```
|
||
|
||
- [ ] **Step 3: Compile**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\wes-loghub
|
||
.\gradlew :wms-api:compileGroovy :wms-shipping:compileGroovy --no-problems-report
|
||
```
|
||
|
||
### Task 5: Implement edi-shopee JWT Service
|
||
|
||
**Files:**
|
||
- Create: `C:\work\gitlab\shopee\edi-shopee\src\main\groovy\com\ittx\edi\erp\service\ShopeeJwtService.groovy`
|
||
- Modify: `C:\work\gitlab\shopee\edi-shopee\src\main\resources\application-zzw.yml`
|
||
|
||
- [ ] **Step 1: Add JWT generation**
|
||
|
||
Implement HS256 with Base64 URL encoding:
|
||
|
||
```groovy
|
||
String generateToken(String account, String secret, Long timestampSeconds = System.currentTimeMillis().intdiv(1000L)) {
|
||
Map header = [alg: 'HS256', typ: 'JWT']
|
||
Map payload = [timestamp: timestampSeconds, account: account]
|
||
String signingInput = base64UrlJson(header) + '.' + base64UrlJson(payload)
|
||
String signature = hmacSha256Base64Url(signingInput, secret)
|
||
return signingInput + '.' + signature
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Add token validation**
|
||
|
||
Validation must:
|
||
|
||
- Split token into 3 segments.
|
||
- Verify signature using configured secret.
|
||
- Parse payload timestamp.
|
||
- Reject if absolute clock drift is greater than 300 seconds.
|
||
- Reject if account does not match configured account.
|
||
|
||
- [ ] **Step 3: Read config from `customerMap.shopee`**
|
||
|
||
JWT and Shopee host configuration live in `application-zzw.yml` under `customerMap.shopee`:
|
||
|
||
```yaml
|
||
customerMap:
|
||
shopee:
|
||
account: xxx
|
||
secret: xxx
|
||
env: uat
|
||
cid: cn
|
||
connectTimeoutMillis: 3000
|
||
readTimeoutMillis: 10000
|
||
```
|
||
|
||
`ShopeeJwtService` and `ShopeeAutomationVendorService` must read `account`, `secret`, host environment, country id, and timeout values from `customerMap.shopee`. Do not hard-code secrets in code and do not add duplicate Shopee JWT config under another profile file in this phase.
|
||
|
||
- [ ] **Step 4: Compile edi-shopee**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\edi-shopee
|
||
.\gradlew compileGroovy
|
||
```
|
||
|
||
### Task 6: Implement edi-shopee Shopee Automation Gateway
|
||
|
||
**Files:**
|
||
- Create: `C:\work\gitlab\shopee\edi-shopee\src\main\groovy\com\ittx\edi\erp\service\ShopeeAutomationVendorService.groovy`
|
||
- Create: `C:\work\gitlab\shopee\edi-shopee\src\main\groovy\com\ittx\edi\erp\controller\ShopeeAutomationController.groovy`
|
||
|
||
- [ ] **Step 1: Add Shopee inbound controller methods**
|
||
|
||
Expose Shopee-facing POST endpoints in `edi-shopee`, not in WES:
|
||
|
||
```groovy
|
||
@PostMapping('/api/v2/automation/toshopee/outbound/salesorder/create_sub_picking_task')
|
||
Object createSubPickingTask(@RequestHeader('Authorization') String authorization,
|
||
@RequestBody Map body) {
|
||
return shopeeAutomationVendorSvc.forwardShopeeInbound(
|
||
authorization,
|
||
'shopee.outbound.salesorder.createSubPickingTask',
|
||
body)
|
||
}
|
||
```
|
||
|
||
Add the same pattern for implemented Shopee inbound interfaces:
|
||
|
||
- `/api/v2/automation/toshopee/outbound/salesorder/cancel_sub_picking_task`
|
||
- `/api/v2/automation/toshopee/outbound/salesorder/update_task_flag`
|
||
- sales order and demand pool paths when their WES handlers are implemented.
|
||
|
||
- [ ] **Step 2: Validate JWT before forwarding to WES**
|
||
|
||
For every Shopee inbound request:
|
||
|
||
- Read `Authorization`.
|
||
- Validate JWT using `ShopeeJwtService`.
|
||
- Reject invalid account, signature, or timestamp over 5 minutes.
|
||
- Return Shopee response shape directly:
|
||
|
||
```groovy
|
||
[retcode: -10000000, message: 'auth failed', data: [:]]
|
||
```
|
||
|
||
- [ ] **Step 3: Forward valid Shopee inbound requests to WES**
|
||
|
||
Call WES existing sync API from `edi-shopee`:
|
||
|
||
```text
|
||
POST {wesBaseUrl}/api/wms/api/sync/in?api={apiName}&format=json
|
||
Content-Type: application/json
|
||
Body: original Shopee body
|
||
```
|
||
|
||
Convert WES `ResponseMessage` back to Shopee response shape:
|
||
|
||
```groovy
|
||
[retcode: 0, message: 'success', data: rsp.data ?: [:]]
|
||
```
|
||
|
||
On WES business error, do not implement final Shopee `retcode` mapping yet. Return a generic Shopee failure shape, keep the WES message sanitized, and log the original WES error for later mapping design. Do not expose WES stack traces.
|
||
|
||
- [ ] **Step 4: Add outbound call method**
|
||
|
||
Implement:
|
||
|
||
```groovy
|
||
ResponseMessage postToShopee(String module, String subModule, String interfaceName, Map body)
|
||
```
|
||
|
||
Build URL:
|
||
|
||
```text
|
||
https://wms-automation.ssc.{env}.shopee.{cid}/api/v2/automation/{direction}/{module}/{sub_module}/{interface_name}
|
||
```
|
||
|
||
For production, omit `{env}` according to the protocol.
|
||
|
||
- [ ] **Step 5: Add headers for edi-shopee outbound calls to Shopee**
|
||
|
||
Headers:
|
||
|
||
```groovy
|
||
[
|
||
'Content-Type': 'application/json',
|
||
'Authorization': shopeeJwtSvc.generateToken(account, secret)
|
||
]
|
||
```
|
||
|
||
- [ ] **Step 6: Normalize response from Shopee outbound calls**
|
||
|
||
Shopee response:
|
||
|
||
```json
|
||
{"retcode":0,"message":"success","data":{}}
|
||
```
|
||
|
||
Convert to CBT:
|
||
|
||
- `retcode == 0` -> `ResponseMessageFactory.success(data)`
|
||
- otherwise -> `ResponseMessageFactory.error(message)` and include retcode in data or parameters
|
||
|
||
- [ ] **Step 7: Add internal endpoints for WES-to-Shopee calls**
|
||
|
||
Internal controller methods:
|
||
|
||
- `POST /internal/shopee/automation/waveNumbers`
|
||
- `POST /internal/shopee/automation/bindWave`
|
||
- `POST /internal/shopee/automation/cancelOrder`
|
||
- `POST /internal/shopee/automation/flowPickChangeBox`
|
||
- `POST /internal/shopee/automation/rackTransfer/createRtOrder`
|
||
|
||
Keep these endpoints internal. They are for `wes-loghub` to call `edi-shopee`; Shopee-facing inbound endpoints are the `/api/v2/automation/toshopee/...` methods above, while WES-to-Vendor calls use `tovendor` paths built by `edi-shopee`.
|
||
|
||
- [ ] **Step 8: Compile**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\edi-shopee
|
||
.\gradlew compileGroovy
|
||
```
|
||
|
||
### Task 7: Replace WES ShopeeWaveService Placeholder
|
||
|
||
**Files:**
|
||
- Modify: `C:\work\gitlab\shopee\wes-loghub\wms-wave\src\main\groovy\com\ittx\wms\wave\service\hairo\ShopeeWaveService.groovy`
|
||
|
||
- [ ] **Step 1: Add an internal edi-shopee client method**
|
||
|
||
Prefer a small private method in `ShopeeWaveService` or a focused bean if an existing HTTP utility is available.
|
||
|
||
Request:
|
||
|
||
```groovy
|
||
[
|
||
warehouseCode: warehouseCode,
|
||
waveType: waveType,
|
||
needQty: needQty
|
||
]
|
||
```
|
||
|
||
Response data should be a list of wave codes:
|
||
|
||
```groovy
|
||
[
|
||
[code: 'SW202606040001', waveType: '1'],
|
||
[code: 'SW202606040002', waveType: '1']
|
||
]
|
||
```
|
||
|
||
- [ ] **Step 2: Implement `requestShopeeWaveNumbers`**
|
||
|
||
Replace the placeholder log-only method with:
|
||
|
||
- Call `edi-shopee` internal endpoint.
|
||
- Convert returned codes to `ShopeeWave`.
|
||
- Return empty list on call failure and log a process history error.
|
||
- Do not generate fake local wave numbers.
|
||
|
||
- [ ] **Step 3: Verify low-water scheduler**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\wes-loghub
|
||
.\gradlew :wms-wave:compileGroovy --no-problems-report
|
||
```
|
||
|
||
### Task 8: Replace WES Wave Binding Placeholder
|
||
|
||
**Files:**
|
||
- Modify: `C:\work\gitlab\shopee\wes-loghub\wms-wave\src\main\groovy\com\ittx\wms\wave\service\hairo\WaveRuleMatchService.groovy`
|
||
|
||
- [ ] **Step 1: Implement `requestShopeeWaveBind` via edi-shopee**
|
||
|
||
Request:
|
||
|
||
```groovy
|
||
[
|
||
warehouseCode: warehouseCode,
|
||
shopeeWaveCode: shopeeWaveCode,
|
||
shipmentIds: shipmentIds
|
||
]
|
||
```
|
||
|
||
Response:
|
||
|
||
```groovy
|
||
[
|
||
success_list: [1L, 2L],
|
||
fail_list: [3L]
|
||
]
|
||
```
|
||
|
||
- [ ] **Step 2: Parse partial failure**
|
||
|
||
Current code treats bind failure as whole batch failure. Change only if Shopee returns per-order failure. If partial failure exists:
|
||
|
||
- Mark failed shipments with `kickOutWave`.
|
||
- Continue binding successful shipment IDs.
|
||
- Return success if at least one shipment bound.
|
||
|
||
If Shopee returns whole request failure, keep existing whole-batch behavior.
|
||
|
||
- [ ] **Step 3: Keep lock and rollback semantics**
|
||
|
||
Do not remove:
|
||
|
||
- `buildShopeeWaveBindLockKey`
|
||
- `isShopeeWaveCodeAvailable`
|
||
- `rollbackShipmentShopeeWave`
|
||
- `rollbackWaveShipments`
|
||
|
||
These protect local WES consistency around external calls.
|
||
|
||
- [ ] **Step 4: Compile**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\wes-loghub
|
||
.\gradlew :wms-wave:compileGroovy --no-problems-report
|
||
```
|
||
|
||
### Task 9A: Implement Inventory and Basic Interface Surfaces 4.1-5.8
|
||
|
||
**Files:**
|
||
- Do not modify: `C:\work\gitlab\shopee\wes-loghub\wms-transfer\src\main\groovy\com\ittx\wms\transfer\service\TransferOrderHeaderService.groovy`
|
||
- Do not modify: `C:\work\gitlab\shopee\wes-loghub\wms-transfer\src\main\groovy\com\ittx\wms\transfer\service\TransferOrderDetailService.groovy`
|
||
- Create only if needed: `C:\work\gitlab\shopee\wes-loghub\wms-api\src\main\groovy\com\ittx\wms\api\service\platform\shopee\ShopeeRackTransferMappingService.groovy`
|
||
|
||
- [ ] **Step 1: Keep 4.1 business trigger out of scope**
|
||
|
||
Do not search for or wire the WES移库单创建、定位、锁定、占用完成事件 in this phase.
|
||
|
||
Implementation target for `4.1` is limited to:
|
||
|
||
- `edi-shopee` internal endpoint: `POST /internal/shopee/automation/rackTransfer/createRtOrder`
|
||
- Shopee outbound call: `POST /api/v2/automation/tovendor/inventory/racktransfer/create_rt_order`
|
||
- Request validation, JWT header generation, response normalization, logging, and retry classification.
|
||
|
||
- [ ] **Step 2: Define the 4.1 request contract without wiring WES transfer data**
|
||
|
||
Endpoint request shape accepted by `edi-shopee`:
|
||
|
||
```groovy
|
||
[
|
||
whs_id: request.whs_id,
|
||
rt_order_id: request.rt_order_id,
|
||
attr_list: [
|
||
[attr_key: 'urgent_flag', attr_value_id: '1', attr_value_name: '1'],
|
||
[attr_key: 'oos_order_qty', attr_value_id: '0', attr_value_name: '0']
|
||
].findAll { it.attr_value_id != null },
|
||
ctime: request.ctime,
|
||
operator: request.operator,
|
||
ticket_type: 6,
|
||
sku_info_list: request.sku_info_list.collect {
|
||
[
|
||
sku_id: it.sku_id,
|
||
block_type: it.block_type,
|
||
qty: it.qty,
|
||
sku_quality: it.sku_quality
|
||
]
|
||
}
|
||
]
|
||
```
|
||
|
||
Keep `ticket_type = 6` fixed for Rack Transfer. The later WES business trigger will be responsible for building this body from real transfer entities.
|
||
|
||
- [ ] **Step 3: Add 4.2-4.5 Vendor-to-WES rack-transfer handlers**
|
||
|
||
Expose these Shopee-facing `edi-shopee` endpoints and forward them to WES sync API with the WES api name below. WES dispatch must be:
|
||
|
||
```text
|
||
edi-shopee -> /api/wms/api/sync/in?api=<WES api>&format=json -> PlatformInboundApiService -> ShopeeInboundApiHandler
|
||
```
|
||
|
||
| Section | Path | WES api |
|
||
| --- | --- | --- |
|
||
| 4.2 | `/api/v2/automation/toshopee/inventory/racktransfer/occupy_device` | `shopee.inventory.racktransfer.occupyDevice` |
|
||
| 4.3 | `/api/v2/automation/toshopee/inventory/racktransfer/submit_picking_sku_list` | `shopee.inventory.racktransfer.submitPickingSkuList` |
|
||
| 4.4 | `/api/v2/automation/toshopee/inventory/racktransfer/sync_picking_sku_list` | `shopee.inventory.racktransfer.syncPickingSkuList` |
|
||
| 4.5 | `/api/v2/automation/toshopee/inventory/racktransfer/handle_diff_stock` | `shopee.inventory.racktransfer.handleDiffStock` |
|
||
|
||
Inside `ShopeeInboundApiHandler`, route to existing `wms-transfer` / `wms-inventory` services first. Do not add a separate WES controller for these four endpoints. Add new service methods only when existing transfer/inventory APIs cannot express the protocol action.
|
||
|
||
- [ ] **Step 4: Add 4.6-4.7 WMS-to-Vendor rack-transfer interface endpoints only**
|
||
|
||
Use internal `edi-shopee` endpoints for:
|
||
|
||
| Section | Internal endpoint | Shopee path |
|
||
| --- | --- | --- |
|
||
| 4.6 | `/internal/shopee/automation/rackTransfer/queryPickingList` | `/api/v2/automation/tovendor/inventory/racktransfer/query_picking_list` |
|
||
| 4.7 | `/internal/shopee/automation/rackTransfer/updateRtOrder` | `/api/v2/automation/tovendor/inventory/racktransfer/update_rt_order` |
|
||
|
||
Do not bind these endpoints to WES对账任务、移库取消、优先级更新、人工操作 or any other business trigger in this phase.
|
||
|
||
Keep the `4.1` internal endpoint:
|
||
|
||
Use the same internal client pattern as wave-number and wave-bind calls:
|
||
|
||
```text
|
||
POST {ediShopeeBaseUrl}/internal/shopee/automation/rackTransfer/createRtOrder
|
||
```
|
||
|
||
`edi-shopee` then calls Shopee:
|
||
|
||
```text
|
||
POST /api/v2/automation/tovendor/inventory/racktransfer/create_rt_order
|
||
```
|
||
|
||
Failure handling:
|
||
|
||
- Preserve Shopee `retcode` and message in the EDI call log.
|
||
- Do not finalize retry/non-retry mapping in this phase.
|
||
- Use existing transport failure handling for timeout/network errors only.
|
||
|
||
- [ ] **Step 5: Add 5.1 and 5.5 Vendor-to-WES basic handlers**
|
||
|
||
Expose Shopee-facing `edi-shopee` endpoints and forward to WES:
|
||
|
||
| Section | Path | WES api |
|
||
| --- | --- | --- |
|
||
| 5.1 | `/api/v2/automation/toshopee/basic/user/query_user_exist` | `shopee.basic.user.queryUserExist` |
|
||
| 5.5 | `/api/v2/automation/toshopee/basic/sku/query_sku_detail` | `shopee.basic.sku.querySkuDetail` |
|
||
|
||
Reuse existing WES user and SKU services. Do not create duplicate user/SKU lookup SQL if a service already exists.
|
||
|
||
- [ ] **Step 6: Add 5.2-5.4 and 5.6-5.8 scheduled WMS-to-Vendor basic calls**
|
||
|
||
Confirmed trigger source: scheduled jobs. Each WES-to-Vendor basic-data sync uses this three-step internal flow:
|
||
|
||
```text
|
||
<basic api>.confirm -> <basic api>.get -> <basic api>.uploadStatus
|
||
```
|
||
|
||
Use this pattern for the WES-to-Vendor basic-data interfaces. `5.5` remains a Vendor-to-WES query handled in Step 5.
|
||
|
||
| Section | Step | Internal endpoint | Shopee path |
|
||
| --- | --- | --- | --- |
|
||
| 5.2 | `.confirm` | `/internal/shopee/automation/basic/inventory/batchStatusUpdate.confirm` | `/api/v2/automation/tovendor/basic/inventory/batch_status_update` |
|
||
| 5.2 | `.get` | `/internal/shopee/automation/basic/inventory/batchStatusUpdate.get` | `/api/v2/automation/tovendor/basic/inventory/batch_status_update` |
|
||
| 5.2 | `.uploadStatus` | `/internal/shopee/automation/basic/inventory/batchStatusUpdate.uploadStatus` | `/api/v2/automation/tovendor/basic/inventory/batch_status_update` |
|
||
| 5.3 | `.confirm` | `/internal/shopee/automation/basic/inventory/querySkuBatchInventory.confirm` | `/api/v2/automation/tovendor/basic/inventory/query_sku_batch_inventory` |
|
||
| 5.3 | `.get` | `/internal/shopee/automation/basic/inventory/querySkuBatchInventory.get` | `/api/v2/automation/tovendor/basic/inventory/query_sku_batch_inventory` |
|
||
| 5.3 | `.uploadStatus` | `/internal/shopee/automation/basic/inventory/querySkuBatchInventory.uploadStatus` | `/api/v2/automation/tovendor/basic/inventory/query_sku_batch_inventory` |
|
||
| 5.4 | `.confirm` | `/internal/shopee/automation/basic/inventory/syncReconciliationResult.confirm` | `/api/v2/automation/tovendor/basic/inventory/sync_reconciliation_result` |
|
||
| 5.4 | `.get` | `/internal/shopee/automation/basic/inventory/syncReconciliationResult.get` | `/api/v2/automation/tovendor/basic/inventory/sync_reconciliation_result` |
|
||
| 5.4 | `.uploadStatus` | `/internal/shopee/automation/basic/inventory/syncReconciliationResult.uploadStatus` | `/api/v2/automation/tovendor/basic/inventory/sync_reconciliation_result` |
|
||
| 5.6 | `.confirm` | `/internal/shopee/automation/basic/sku/syncSkuInfo.confirm` | `/api/v2/automation/tovendor/basic/sku/sync_sku_info` |
|
||
| 5.6 | `.get` | `/internal/shopee/automation/basic/sku/syncSkuInfo.get` | `/api/v2/automation/tovendor/basic/sku/sync_sku_info` |
|
||
| 5.6 | `.uploadStatus` | `/internal/shopee/automation/basic/sku/syncSkuInfo.uploadStatus` | `/api/v2/automation/tovendor/basic/sku/sync_sku_info` |
|
||
| 5.7 | `.confirm` | `/internal/shopee/automation/basic/robot/queryAgvStatus.confirm` | `/api/v2/automation/tovendor/basic/robot/query_agv_status` |
|
||
| 5.7 | `.get` | `/internal/shopee/automation/basic/robot/queryAgvStatus.get` | `/api/v2/automation/tovendor/basic/robot/query_agv_status` |
|
||
| 5.7 | `.uploadStatus` | `/internal/shopee/automation/basic/robot/queryAgvStatus.uploadStatus` | `/api/v2/automation/tovendor/basic/robot/query_agv_status` |
|
||
| 5.8 | `.confirm` | `/internal/shopee/automation/basic/inventory/queryVendorUnitList.confirm` | `/api/v2/automation/tovendor/basic/inventory/query_vendor_unit_list` |
|
||
| 5.8 | `.get` | `/internal/shopee/automation/basic/inventory/queryVendorUnitList.get` | `/api/v2/automation/tovendor/basic/inventory/query_vendor_unit_list` |
|
||
| 5.8 | `.uploadStatus` | `/internal/shopee/automation/basic/inventory/queryVendorUnitList.uploadStatus` | `/api/v2/automation/tovendor/basic/inventory/query_vendor_unit_list` |
|
||
|
||
The previous one-call internal endpoint names are retained only as conceptual API names, not as the scheduled-job contract:
|
||
|
||
| Section | Internal endpoint | Shopee path |
|
||
| --- | --- | --- |
|
||
| 5.2 | `/internal/shopee/automation/basic/inventory/batchStatusUpdate` | `/api/v2/automation/tovendor/basic/inventory/batch_status_update` |
|
||
| 5.3 | `/internal/shopee/automation/basic/inventory/querySkuBatchInventory` | `/api/v2/automation/tovendor/basic/inventory/query_sku_batch_inventory` |
|
||
| 5.4 | `/internal/shopee/automation/basic/inventory/syncReconciliationResult` | `/api/v2/automation/tovendor/basic/inventory/sync_reconciliation_result` |
|
||
| 5.6 | `/internal/shopee/automation/basic/sku/syncSkuInfo` | `/api/v2/automation/tovendor/basic/sku/sync_sku_info` |
|
||
| 5.7 | `/internal/shopee/automation/basic/robot/queryAgvStatus` | `/api/v2/automation/tovendor/basic/robot/query_agv_status` |
|
||
| 5.8 | `/internal/shopee/automation/basic/inventory/queryVendorUnitList` | `/api/v2/automation/tovendor/basic/inventory/query_vendor_unit_list` |
|
||
|
||
These calls stay in `edi-shopee`. Scheduled jobs call `.confirm`, `.get`, then `.uploadStatus`; do not bind them to ad hoc WES business events in this phase.
|
||
|
||
- [ ] **Step 7: Compile transfer, API, inventory, and edi-shopee modules**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\wes-loghub
|
||
.\gradlew :wms-transfer:compileGroovy :wms-api:compileGroovy --no-problems-report
|
||
cd C:\work\gitlab\shopee\edi-shopee
|
||
.\gradlew compileGroovy
|
||
```
|
||
|
||
### Task 9: Add Sales Order and Demand Pool Interfaces
|
||
|
||
**Files:**
|
||
- Modify DTO file from Task 1.
|
||
- Modify `ShopeeInboundApiHandler.groovy`.
|
||
- Modify `C:\work\gitlab\shopee\wes-loghub\wms-api\src\main\groovy\com\ittx\wms\api\service\platform\shopee\ShopeeOutboundShipmentMappingService.groovy`.
|
||
|
||
- [ ] **Step 1: Implement sales order create/pull/revoke/lock**
|
||
|
||
Use the same handler pattern as Tasks 2-4.
|
||
|
||
Minimum mappings:
|
||
|
||
- Sales order create maps to `shipment_header` and `shipment_detail`, with `ticketType = 2`.
|
||
- Pull order queries eligible WES orders by Shopee identifiers and current state.
|
||
- Revoke order cancels or marks excluded, using existing shipment cancel/status services.
|
||
- Lock/unlock writes existing lock fields if present; otherwise reuse standard lock service.
|
||
|
||
- [ ] **Step 2: Implement RTS/MTO demand create/cancel/sync occupy**
|
||
|
||
Minimum mappings:
|
||
|
||
- RTS demand -> `shipmentType = RTS`, `ticketType = 3`.
|
||
- MTO demand -> `shipmentType = MTO`, `ticketType = 4`.
|
||
- MTO task -> `ticketType = 5`.
|
||
- RT -> `ticketType = 6`, does not use Shopee wave number.
|
||
|
||
- [ ] **Step 3: Guard one-wave-one-order types**
|
||
|
||
Ensure `WaveRuleMatchService` one-wave-one-order logic keeps:
|
||
|
||
- `ticketType = 1`
|
||
- `ticketType = 5`
|
||
- `ticketType = 6`
|
||
|
||
- [ ] **Step 4: Compile**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\wes-loghub
|
||
.\gradlew :wms-api:compileGroovy :wms-wave:compileGroovy --no-problems-report
|
||
```
|
||
|
||
### Task 10: Error Code and Response Contract Placeholder
|
||
|
||
**Files:**
|
||
- Modify: `ShopeeInboundApiHandler.groovy`
|
||
- Modify: `C:\work\gitlab\shopee\wes-loghub\wms-api\src\main\groovy\com\ittx\wms\api\service\platform\shopee\ShopeeOutboundShipmentMappingService.groovy`
|
||
|
||
- [ ] **Step 1: Keep retcode mapping as a placeholder**
|
||
|
||
WES standard `ResponseMessage` is acceptable inside current sync API. Final mapping from WES errors to Shopee protocol `retcode` is not decided yet and must not be implemented in this phase.
|
||
|
||
Boundary adapter behavior for now:
|
||
|
||
```groovy
|
||
[
|
||
retcode: rsp.hasError() ? -1 : 0,
|
||
message: rsp.hasError() ? sanitize(rsp.message) : 'success',
|
||
data: rsp.data ?: [:]
|
||
]
|
||
```
|
||
|
||
Keep original WES error code/message in logs for later retcode mapping. Do not change `ResponseMessage` globally.
|
||
|
||
- [ ] **Step 2: Defer retry mapping**
|
||
|
||
Do not create a retry table or classify business `retcode` values yet.
|
||
|
||
Only transport-level failures such as timeout, connection refused, and upstream unavailable use existing retry behavior. Business retcode retry rules stay pending until the final error-code mapping is confirmed.
|
||
|
||
### Task 11: Verification and Documentation
|
||
|
||
**Files:**
|
||
- Modify: `C:\work\gitlab\shopee\docs\统一汇总.md`
|
||
- Modify or create: focused API implementation note under `C:\work\gitlab\shopee\docs\`
|
||
|
||
- [ ] **Step 1: Run WES compile**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\wes-loghub
|
||
.\gradlew :wms-api:compileGroovy :wms-wave:compileGroovy :wms-shipping:compileGroovy --no-problems-report
|
||
```
|
||
|
||
- [ ] **Step 2: Run edi-shopee compile**
|
||
|
||
Run:
|
||
|
||
```powershell
|
||
cd C:\work\gitlab\shopee\edi-shopee
|
||
.\gradlew compileGroovy
|
||
```
|
||
|
||
- [ ] **Step 3: Manual Shopee-facing smoke tests**
|
||
|
||
Use one JSON body per implemented interface through `edi-shopee`, which then forwards to WES:
|
||
|
||
```powershell
|
||
Invoke-RestMethod `
|
||
-Method Post `
|
||
-Uri 'http://localhost:9210/api/v2/automation/toshopee/outbound/salesorder/create_sub_picking_task' `
|
||
-ContentType 'application/json' `
|
||
-Headers @{ Authorization = '<valid-shopee-jwt>' } `
|
||
-Body '<json body from protocol>'
|
||
```
|
||
|
||
Expected:
|
||
|
||
- Response is Shopee shape with `retcode = 0`.
|
||
- `shipment_header` has Shopee fields.
|
||
- `shipment_detail` rows exist.
|
||
- Duplicate request is idempotent.
|
||
|
||
- [ ] **Step 4: Manual 4.1-5.8 smoke tests**
|
||
|
||
Trigger or post representative `edi-shopee` endpoints from each added module.
|
||
|
||
4.1 WMS-to-Vendor rack-transfer body:
|
||
|
||
```powershell
|
||
Invoke-RestMethod `
|
||
-Method Post `
|
||
-Uri 'http://localhost:9210/internal/shopee/automation/rackTransfer/createRtOrder' `
|
||
-ContentType 'application/json' `
|
||
-Body '{
|
||
"whs_id":"SGL",
|
||
"rt_order_id":"RTSGL00020250102001",
|
||
"attr_list":[{"attr_key":"urgent_flag","attr_value_id":"1","attr_value_name":"1"}],
|
||
"ctime":1780000000,
|
||
"operator":"xxx@shopee.com",
|
||
"ticket_type":6,
|
||
"sku_info_list":[{"sku_id":"18377383_9999","block_type":0,"qty":2,"sku_quality":0}]
|
||
}'
|
||
```
|
||
|
||
Expected:
|
||
|
||
- `edi-shopee` calls `/api/v2/automation/tovendor/inventory/racktransfer/create_rt_order`.
|
||
- JWT header is present.
|
||
- Shopee success maps to CBT success.
|
||
- Retryable `-10013099` remains retryable.
|
||
|
||
Vendor-to-WES samples:
|
||
|
||
```powershell
|
||
Invoke-RestMethod `
|
||
-Method Post `
|
||
-Uri 'http://localhost:9210/api/v2/automation/toshopee/inventory/racktransfer/occupy_device' `
|
||
-ContentType 'application/json' `
|
||
-Headers @{ Authorization = '<valid-shopee-jwt>' } `
|
||
-Body '<4.2 json body from protocol>'
|
||
|
||
Invoke-RestMethod `
|
||
-Method Post `
|
||
-Uri 'http://localhost:9210/api/v2/automation/toshopee/basic/user/query_user_exist' `
|
||
-ContentType 'application/json' `
|
||
-Headers @{ Authorization = '<valid-shopee-jwt>' } `
|
||
-Body '<5.1 json body from protocol>'
|
||
```
|
||
|
||
WMS-to-Vendor basic-data samples:
|
||
|
||
```powershell
|
||
Invoke-RestMethod `
|
||
-Method Post `
|
||
-Uri 'http://localhost:9210/internal/shopee/automation/basic/sku/syncSkuInfo.confirm' `
|
||
-ContentType 'application/json' `
|
||
-Body '<5.6 confirm json body>'
|
||
|
||
Invoke-RestMethod `
|
||
-Method Post `
|
||
-Uri 'http://localhost:9210/internal/shopee/automation/basic/sku/syncSkuInfo.get' `
|
||
-ContentType 'application/json' `
|
||
-Body '<5.6 get json body from protocol>'
|
||
|
||
Invoke-RestMethod `
|
||
-Method Post `
|
||
-Uri 'http://localhost:9210/internal/shopee/automation/basic/sku/syncSkuInfo.uploadStatus' `
|
||
-ContentType 'application/json' `
|
||
-Body '<5.6 uploadStatus json body>'
|
||
```
|
||
|
||
- [ ] **Step 5: Manual internal WES smoke tests**
|
||
|
||
Use the WES sync API only as an internal verification target:
|
||
|
||
```powershell
|
||
Invoke-RestMethod `
|
||
-Method Post `
|
||
-Uri 'http://localhost:9001/api/wms/api/sync/in?api=shopee.outbound.salesorder.createSubPickingTask&format=json' `
|
||
-ContentType 'application/json' `
|
||
-Body '<json body from protocol>'
|
||
```
|
||
|
||
- [ ] **Step 6: Manual wave tests**
|
||
|
||
Check:
|
||
|
||
- Low-water scheduler calls `edi-shopee` and saves `shopee_wave`.
|
||
- Wave binding calls `edi-shopee`.
|
||
- Failed bind marks `kickOutWave`.
|
||
- Successful bind writes `shipment_header.shopeeWave`.
|
||
|
||
- [ ] **Step 7: Update docs**
|
||
|
||
Update:
|
||
|
||
- `docs/统一汇总.md`: move implemented items from "待实现" to "已落地".
|
||
- Add a concise implementation note linking `ShopeeInboundApiHandler`, `ShopeeWaveService`, `WaveRuleMatchService`, and `edi-shopee` JWT service.
|
||
|
||
## Self-Review
|
||
|
||
- Spec coverage: Covers `edi-shopee` as Shopee-facing entry, WES field mapping, wave number request, wave binding, all concrete interfaces from `3.1`-`3.4`, `4.1`-`4.7`, and `5.1`-`5.8`, JWT ownership in `edi-shopee`, and verification.
|
||
- Scope control: Excludes inbound module interfaces; includes outbound, inventory/rack-transfer, and basic-data interfaces from this protocol file; Shopee extension fields do not add WES entity columns and are persisted through dictionary group types.
|
||
- Type consistency: DTO names and handler method names match task references.
|
||
- Confirmed entry contract: Shopee 调 `edi-shopee`,`edi-shopee` 再转发到 WES `/api/wms/api/sync/in?api=shopee...`,WES 不直接作为 Shopee 外部入口。
|