56 KiB
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.mdwes-loghub/wms-api/src/main/groovy/com/ittx/wms/api/service/platform/ShopeeInboundApiHandler.groovyC:\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
SyncApiControlleralready receives standard platform calls and delegates throughApiService; this remains the internal WES target called byedi-shopee.ApiServicealready delegatesess.*andshopee.*APIs toPlatformInboundApiService.ShopeeInboundApiHandlerexists but has no outbound cases implemented.- Confirmed:
4.2-4.5Vendor-to-WES inventory/rack-transfer interfaces all enter WES throughShopeeInboundApiHandler; the handler then reuses existingwms-transferandwms-inventoryservices. - Confirmed: WES-to-Vendor basic-data interfaces in
5.2-5.8are driven by scheduled jobs using a three-step.confirm->.get->.uploadStatusflow. Protocol5.5remains 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
shopeesubpackage; keep only the existing platform entry handler inservice/platform. ShipmentHeaderalready contains key Shopee fields:cutOffTime,purchaseTime,orderTime,shopeeWave,waveRule,kickOutWave,ticketType,pickType,orderStructure,groupKey.ShopeeWaveServicehas low-water scheduling and persistence, but the actual upstream wave-number request is still a placeholder.WaveRuleMatchServicehas Shopee wave binding placeholders and local binding/rollback logic.wms-transferalready contains transfer order services; use those existing transfer entities/services for rack-transfer data extraction before adding any new persistence.edi-shopeealready 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
shopeesubpackage.
- Keep as the existing platform dispatch entry; add switch cases for all 50 concrete APIs and delegate to services in the
- 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
requestShopeeWaveNumbersplaceholder with a call toedi-shopee.
- Replace
- Modify:
wms-wave/src/main/groovy/com/ittx/wms/wave/service/hairo/WaveRuleMatchService.groovy- Replace Shopee wave bind placeholder with a call to
edi-shopeeand parse failed shipment IDs.
- Replace Shopee wave bind placeholder with a call to
- Do not modify WES transfer-order business hooks for
4.1in this phase.- Only implement the
4.1,4.6, and4.7interface surfaces andedi-shopeeforwarding paths; the real移库业务触发点 remains explicitly out of scope.
- Only implement the
- 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, and4.7request contracts and response normalization only; do not readTransferOrderHeader/detail data until the business trigger is confirmed later.
- Define
- Modify:
src/main/resources/application.ymland profile-specific config only if no existing system-parameter path is available.- Add internal
edi-shopeeendpoint only if it cannot be represented by existing API/customer config.
- Add internal
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-loghubfor wave-number request and wave binding.
- External endpoints called by Shopee plus internal endpoints consumed by
- Modify:
src/main/resources/application-zzw.yml.- Read Shopee JWT/account/host settings from
customerMap.shopee; do not introduce a second config path inapplication-dev.ymlorapplication-k8s.ymlfor this phase.
- Read Shopee JWT/account/host settings from
Interface Inventory
Protocol alignment from 出库单接口文档/Shopee_Automation_Vendor_接入协议手册_出库模块映射WES字段_V1.2.md:
- Outbound module title count: 45 entries under
3.1to3.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.1to4.7. - Basic-data URL count: 8 concrete APIs under
5.1to5.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:
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:
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:
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:
@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.
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:
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:
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:
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:
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:
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.prioritybyerpOrderCode in ticket_number_list. - Return
success_list,fail_list, andnot_exist_list. - Do not fail the entire request because one order is missing.
Return shape:
[
success_list: successCodes,
fail_list: failCodes,
not_exist_list: notExistCodes
]
- Step 3: Compile
Run:
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:
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:
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:
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:
@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:
[retcode: -10000000, message: 'auth failed', data: [:]]
- Step 3: Forward valid Shopee inbound requests to WES
Call WES existing sync API from edi-shopee:
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:
[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:
ResponseMessage postToShopee(String module, String subModule, String interfaceName, Map body)
Build URL:
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:
[
'Content-Type': 'application/json',
'Authorization': shopeeJwtSvc.generateToken(account, secret)
]
- Step 6: Normalize response from Shopee outbound calls
Shopee response:
{"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/waveNumbersPOST /internal/shopee/automation/bindWavePOST /internal/shopee/automation/cancelOrderPOST /internal/shopee/automation/flowPickChangeBoxPOST /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:
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:
[
warehouseCode: warehouseCode,
waveType: waveType,
needQty: needQty
]
Response data should be a list of wave codes:
[
[code: 'SW202606040001', waveType: '1'],
[code: 'SW202606040002', waveType: '1']
]
- Step 2: Implement
requestShopeeWaveNumbers
Replace the placeholder log-only method with:
-
Call
edi-shopeeinternal 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:
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
requestShopeeWaveBindvia edi-shopee
Request:
[
warehouseCode: warehouseCode,
shopeeWaveCode: shopeeWaveCode,
shipmentIds: shipmentIds
]
Response:
[
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:
buildShopeeWaveBindLockKeyisShopeeWaveCodeAvailablerollbackShipmentShopeeWaverollbackWaveShipments
These protect local WES consistency around external calls.
- Step 4: Compile
Run:
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-shopeeinternal 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:
[
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:
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:
POST {ediShopeeBaseUrl}/internal/shopee/automation/rackTransfer/createRtOrder
edi-shopee then calls Shopee:
POST /api/v2/automation/tovendor/inventory/racktransfer/create_rt_order
Failure handling:
-
Preserve Shopee
retcodeand 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:
<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:
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_headerandshipment_detail, withticketType = 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:
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:
[
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:
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:
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:
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_headerhas Shopee fields. -
shipment_detailrows 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:
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-shopeecalls/api/v2/automation/tovendor/inventory/racktransfer/create_rt_order.- JWT header is present.
- Shopee success maps to CBT success.
- Retryable
-10013099remains retryable.
Vendor-to-WES samples:
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:
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:
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-shopeeand savesshopee_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, andedi-shopeeJWT service.
Self-Review
- Spec coverage: Covers
edi-shopeeas Shopee-facing entry, WES field mapping, wave number request, wave binding, all concrete interfaces from3.1-3.4,4.1-4.7, and5.1-5.8, JWT ownership inedi-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 外部入口。