Files

103 lines
8.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Integration 本地领星 WMS 查询
本入口用于在现有 Java 服务内验证 WMS 只读调用。仅返回单页出库摘要,不启动月度采集、库存全量同步、定时任务或数据库写入。业务方案见[领星一件代发数据统计一期方案](../../docs/自营业务/领星一件代发数据统计一期方案.md)。
后续开发交接见[接口联调手册](../../docs/自营业务/领星WMS接口联调手册.md):已另行用只读 HTTP 验证仓库发现、一件代发详情和按仓产品库存全分页。此处现有 Java 接口仍只有出库摘要;库存内部接口、分仓任务和持久化尚待开发,不能以外部直连成功推定 Java 功能已经具备。
## 凭据与开关
从 WMS 管理后台的“个人中心 → API 信息 → 自研系统”获取 `appKey` 和 `appSecret`,填写本目录 Git 忽略的 `.env.local`,格式参考 [.env.example](.env.example)。这两个值分别加载为 `LINGXING_OMS_APP_KEY` 和 `LINGXING_OMS_APP_SECRET` 进程环境变量,不提交真实值。Spring 本身不会自动读取 `.env.local`,应在启动 Java 的同一终端加载。该凭据属于 OMP 服务商内部系统对接,不使用 OMS 货主或 WMS 智能设备协议。
正式应用配置默认 `LINGXING_WMS_ENABLED=false`。下面的本地命令显式启用适配器,为该本地实例生成内部调用令牌。不要复用共享环境令牌。
测试部署通过 `deploy/docker-compose.yml` 将 `LINGXING_OMS_APP_KEY`、`LINGXING_OMS_APP_SECRET` 传入 Integration 容器。现有 Jenkins 下游部署任务读取 `firstleg-test-env` Secret File;可将这两项加入该文件,或在实际执行部署的下游服务任务中以凭据绑定注入同名环境变量。只在上游总控任务设置变量不会自动传给下游任务。变量命名采用用户指定的 `OMS`,接口协议仍为当前 WMS 自研系统(OMP);真实凭据是否有该接口权限仍待联调核验。不要将密钥作为普通构建参数或打印完整 Compose 配置。
2026-10-12 用户确认唯一账号、所有源时间按北京时间、数量按 SKU 件数。Lastleg 应用配置使用 `source-account=lingxing-primary`(内部稳定标识,不是 appKey)、`source-query-timezone=Asia/Shanghai`、`quantity-unit=PCS`,分仓配置的源时区默认 `Asia/Shanghai`;数量仍保留十进制精度。仓库编码须在获得真实仓库目录后配置到 `baiyue.self-operated-analytics.warehouses`,不预填虚构仓库。`SELFOP_EXECUTION_ENABLED` 和 `SELFOP_SALES_PUBLICATION_ENABLED` 均默认关闭。
## 本地启动
先在后端仓库根目录执行构建,包含相关模块的编译与测试:
```powershell
mvn -pl integration-service -am package
```
然后在同一目录的 PowerShell 中执行。只加载明确允许的两个名称,不执行环境文件内的代码:
```powershell
$credentialNames = @('LINGXING_OMS_APP_KEY', 'LINGXING_OMS_APP_SECRET')
foreach ($line in [IO.File]::ReadAllLines((Join-Path (Get-Location) 'integration-service/.env.local'))) {
if ($line -match '^\s*(LINGXING_OMS_APP_KEY|LINGXING_OMS_APP_SECRET)\s*=(.*)$') {
$credentialName = $matches[1]
$credentialValue = $matches[2].Trim()
if ($credentialValue.Length -ge 2 -and
(($credentialValue.StartsWith('"') -and $credentialValue.EndsWith('"')) -or
($credentialValue.StartsWith("'") -and $credentialValue.EndsWith("'")))) {
$credentialValue = $credentialValue.Substring(1, $credentialValue.Length - 2)
}
[Environment]::SetEnvironmentVariable($credentialName, $credentialValue, 'Process')
}
}
foreach ($credentialName in $credentialNames) {
if ([string]::IsNullOrWhiteSpace([Environment]::GetEnvironmentVariable($credentialName, 'Process'))) {
throw "Missing credential: $credentialName"
}
}
$env:INTERNAL_SERVICE_TOKEN = [guid]::NewGuid().ToString()
$localInternalToken = $env:INTERNAL_SERVICE_TOKEN
$env:INTEGRATION_LOCAL_PORT = '19210'
$buildJar = (Resolve-Path 'integration-service/target/integration-service-1.0.0-SNAPSHOT.jar').Path
$localJava = Start-Process -FilePath (Get-Command java).Source -WindowStyle Hidden -PassThru `
-ArgumentList @('-jar', ('"' + $buildJar + '"'),
'--spring.config.location=classpath:/application-lingxing-local.yml',
'--baiyue.integration.lingxing-wms.enabled=true') `
-RedirectStandardOutput 'integration-service/target/lingxing-local.stdout.log' `
-RedirectStandardError 'integration-service/target/lingxing-local.stderr.log'
```
该配置仅监听 `127.0.0.1`,关闭 Nacos Config、Discovery、服务注册及 Spring 定时任务,不导入共享环境配置。若端口占用,选择其他本地端口并同步替换后续 URL,不停止未知进程。确认 `http://127.0.0.1:19210/actuator/health` 返回 `UP` 后再查询。
## 读取一条出库单
在保留上述变量的同一 PowerShell 中执行一次:
```powershell
$businessZone = [TimeZoneInfo]::FindSystemTimeZoneById('China Standard Time')
$queryEnd = [TimeZoneInfo]::ConvertTimeFromUtc([DateTime]::UtcNow, $businessZone)
$query = @{
startTime = $queryEnd.AddMonths(-1).ToString('yyyy-MM-ddTHH:mm:ss')
endTime = $queryEnd.ToString('yyyy-MM-ddTHH:mm:ss')
current = 1
size = 1
} | ConvertTo-Json -Compress
$result = Invoke-RestMethod -Method Post `
-Uri 'http://127.0.0.1:19210/internal/integrations/lingxing/wms/outbound-orders/query' `
-Headers @{'X-Internal-Service-Token' = $localInternalToken} `
-ContentType 'application/json' -Body $query
$result | ConvertTo-Json -Depth 6
```
返回摘要只包含出库单号、来源单号、货主编码、仓库编码、状态、创建时间和出库时间,不返回收件人或地址。业务 `code="200"` 且 `records` 包含一条才表示已读到样本;空页表示调用成功但未取得样本;`B0001`/`S0503` 表示明确失败,保留 `errorCode`、来源数值错误码及请求标识排查,不能当作零销量。
当前调用 OMP `POST /openapi/v2/order/delivery/page`,固定 `timeType=outboundTime`、`status=100` 已出库,窗口最多向前一个自然月。该本地保护不代表供应商历史上限;单页样本也不代表整月采集完成。订单详情、全量库存、增量任务和统计落库仍按业务方案后续实现。
测试完毕,在同一终端停止本次启动的进程,并清理当前终端注入的变量:
```powershell
if (-not $localJava.HasExited) { Stop-Process -Id $localJava.Id }
foreach ($credentialName in @('LINGXING_OMS_APP_KEY', 'LINGXING_OMS_APP_SECRET', 'INTERNAL_SERVICE_TOKEN')) {
[Environment]::SetEnvironmentVariable($credentialName, $null, 'Process')
}
$localInternalToken = $null
$credentialValue = $null
```
## 接口与验证
- 2026-10-12 已通过本地 Java 实例调用 OMP WMS 出库分页,按最近 1 个月、`current=1`、`size=1` 成功返回 1 条已出库摘要;无内部令牌请求被拒绝。验证后本地进程已停止。该结果仅证明当前只读链路可用,不代表全量采集或库存同步完成。
- 实测成功响应为数值 `code=200`,但缺少官方示例及 Schema 中的 `success`。客户端以成功码和有效分页结构共同判定;`success` 出现时仍须为布尔 `true`。此差异已加入回归测试,失败响应不转换为空页。
- 内部前缀为 `POST /internal/integrations/lingxing/wms`,提供 `/outbound-orders/query`、`/outbound-orders/locate`、`/outbound-orders/detail`、`/warehouses/query`、`/product-inventory/query`;仅接受 `X-Internal-Service-Token`,不经公网 Gateway。各请求只返回一页或一单,多页与业务版本归 Lastleg 编排。定位不传时间/状态;产品库存必须指定仓库、保留全部品质和零库存。源时间原值与 BigDecimal 数量未知值保留,不推断时区或单位。
- [OpenAPI](src/main/resources/openapi/lingxing-wms-v1.yaml)定义输入、分页摘要和失败结构。
- 从后端根执行 `mvn -pl integration-service -am test` 与 `node --test scripts/gateway-route-contract.test.mjs`。
- 本地模拟 HTTP 单测验证签名、请求体、敏感信息隔离和错误处理;不能代替真实领星样本验证。官方入口为[服务商内部系统对接](https://apidoc-omp.xlwms.com/)与[一件代发出库单 WMS 分页查询](https://apidoc-omp.xlwms.com/reference/post_openapi-v2-order-delivery-page-1)。