优化
This commit is contained in:
@@ -178,7 +178,7 @@ export async function run(context) {
|
||||
| 人工状态矩阵 | `manual-state-matrix.mjs` | `manual-state-matrix-contract.test.mjs`;验证装柜完成、报关和订舱相关状态组合 |
|
||||
| 海外业务 HTTP 生命周期 | `phase4-overseas-business.mjs` | `phase4-overseas-business-contract.test.mjs` |
|
||||
| 海外主数据 HTTP 生命周期 | `phase4-overseas-master-data.mjs` | `phase4-overseas-master-data-contract.test.mjs` |
|
||||
| 目的港码头拖车与船节点终态 | `phase5-terminal-drayage.mjs`(PDA 卸柜前复用 `ACTIVE + TRUCKING` 主数据完成选车队、预约和实际提柜,卸柜后完成实际还柜,并覆盖四命令幂等/历史)、`phase4-carrier-nodes.mjs`(PDA 前补录至 `PICKUP_READY`;拖车完成后只读核验 `PICKED_UP/EMPTY_RETURNED` 和停止语义) | `phase5-terminal-drayage-contract.test.mjs`、`phase4-carrier-nodes-contract.test.mjs`;不再由船节点脚本直接伪造提柜和还柜 |
|
||||
| 目的港码头拖车与船节点终态 | `phase5-terminal-drayage.mjs`(PDA 卸柜前复用 `ACTIVE + TRUCKING + truckingScope=OVERSEAS` 主数据完成选车队、预约和实际提柜,卸柜后完成实际还柜,并覆盖四命令幂等/历史)、`phase4-carrier-nodes.mjs`(PDA 前补录至 `PICKUP_READY`;拖车完成后只读核验 `PICKED_UP/EMPTY_RETURNED` 和停止语义) | `phase5-terminal-drayage-contract.test.mjs`、`phase4-carrier-nodes-contract.test.mjs`;不再由船节点脚本直接伪造提柜和还柜 |
|
||||
| 海外排车、出库、派送、异常与回访 HTTP 生命周期 | `phase5-overseas-fulfillment.mjs`(复用本轮海外仓已收货托盘和预排单,正式创建临时 PDA 操作员并在 `finally` 停用;覆盖排车编辑、按 FBA 目的仓转出库/拆分派送单、PDA 全量拣货/发车、逐单签收资料保存自动完成、头程入仓与订单跨区回推、客户回访、人工异常及派送退回) | `phase5-overseas-fulfillment-contract.test.mjs` |
|
||||
| 初始化基线(仅离线) | — | `initialization-baseline-contract.test.mjs` |
|
||||
|
||||
@@ -188,7 +188,7 @@ export async function run(context) {
|
||||
|
||||
节点全链定向入口为 `--modules phase4-overseas-pda`。依赖展开固定先为本轮 `LOADED` 柜次完成国内 `CUSTOMS_DECLARATION` 与 PDA 装柜证据,再确认国内出仓;离仓后才维护 `DESTINATION_CLEARANCE`、`DELIVERY_ORDER` 两类目的港文件,PU 使用柜级数字码而不是文件,随后核对自动创建的 `OUTBOUND_CONFIRM` 船节点任务、人工补录至实际 `PICKUP_READY`,最后验证海外 PDA 候选可见。资料模块只写本轮 marker 柜次,覆盖上传/完成重放、同键异载荷 `A0409`、冲突后零漂移和聚合回读;任一 fixture 或 Trace 缺失均为 deployment blocker。
|
||||
|
||||
尾程单公网控制与目的港码头拖车定向入口为 `--modules phase4-carrier-nodes`。依赖会在海外 PDA 前插入 `phase4-tail-order-controls`,先对本轮柜验证接柜仓变更/恢复、目的仓变更、合托标记、CSV 导出、订单费用、暂扣阻断、解除和八个人工节点,再通过柜级预览与确认自动生成逐票计划和实体托盘;PDA 必须消费这些计划托盘,不得临时另建脱离计划的托盘。货柜到达 `PICKUP_READY` 后先复用公共 `ACTIVE + TRUCKING` 供应商完成选车队、预约和实际提柜;PDA 卸柜完成后,有界等待跨区卸柜事件回写国内聚合为 `UNLOADED`,再确认实际还柜。最后的船节点模块仅回读两次业务动作同步生成的 `PICKED_UP/EMPTY_RETURNED`,不得直接补录这两个节点。
|
||||
尾程单公网控制与目的港码头拖车定向入口为 `--modules phase4-carrier-nodes`。依赖会在海外 PDA 前插入 `phase4-tail-order-controls`,先对本轮柜验证接柜仓变更/恢复、目的仓变更、合托标记、CSV 导出、订单费用、暂扣阻断、解除和八个人工节点,再通过柜级预览与确认自动生成逐票计划和实体托盘;PDA 必须消费这些计划托盘,不得临时另建脱离计划的托盘。货柜到达 `PICKUP_READY` 后先复用公共 `ACTIVE + TRUCKING + truckingScope=OVERSEAS` 供应商完成选车队、预约和实际提柜;PDA 卸柜完成后,有界等待跨区卸柜事件回写国内聚合为 `UNLOADED`,再确认实际还柜。最后的船节点模块仅回读两次业务动作同步生成的 `PICKED_UP/EMPTY_RETURNED`,不得直接补录这两个节点。
|
||||
|
||||
```powershell
|
||||
node --env-file="$env:USERPROFILE\.codex\chongchong-global-test-acceptance.env" scripts/admin-test-env-acceptance.mjs --modules phase4-carrier-nodes
|
||||
|
||||
@@ -37,6 +37,7 @@ export function buildSupplierBody(marker, category) {
|
||||
return {
|
||||
name: `财务验收供应商-${suffix}`,
|
||||
category,
|
||||
truckingScope: category === 'TRUCKING' ? 'DOMESTIC' : null,
|
||||
...(category === 'BOOKING' ? { carrierCodes: ['MATSON'] } : {}),
|
||||
region: '宁波', legalRepresentative: '财务验收法人', contactName: '财务验收联系人',
|
||||
phone: '13800000000', email: `finance-supplier-${suffix || 'fixture'}@example.com`,
|
||||
|
||||
@@ -120,9 +120,9 @@ function truckPayload(context, oceanBooking, carrier, index) {
|
||||
|
||||
async function createTruck(context, oceanBooking, index) {
|
||||
const carrierResponse = await context.request('GET',
|
||||
'/api/platform/v1/suppliers?tenantId=0&category=TRUCKING&status=ACTIVE&page=1&size=20')
|
||||
'/api/platform/v1/suppliers?tenantId=0&category=TRUCKING&status=ACTIVE&truckingScope=DOMESTIC&page=1&size=20')
|
||||
const carrierPage = context.apiSuccess(MODULE, `读取拖车状态样本 ${index} 的 ACTIVE 承运商`, carrierResponse, '', OPTIONS)
|
||||
const carrier = carrierPage?.records?.find?.((item) => item?.id && item?.name)
|
||||
const carrier = carrierPage?.records?.find?.((item) => item?.id && item?.name && item?.truckingScope === 'DOMESTIC')
|
||||
if (!carrier) throw new Error(`创建拖车样本 ${index} 缺少 ACTIVE 承运商`)
|
||||
const response = await context.request('POST', TRUCK_BASE, truckPayload(context, oceanBooking, carrier, index))
|
||||
const value = context.apiSuccess(MODULE, `创建拖车状态样本 ${index}`, response, '', OPTIONS)
|
||||
|
||||
@@ -32,7 +32,7 @@ test('three real command payloads mutate contract fields and preserve remarks an
|
||||
addStep(_module, name, _response, passed) { assert.ok(passed, name) },
|
||||
addCoverageGap() { assert.fail('unexpected missing fixture') },
|
||||
async request(method, path, body, _token, headers) {
|
||||
if (path.includes('/suppliers?')) return response({ records: [{ id: '9223372036854775804', name: 'Offline fleet', status: 'ACTIVE' }] })
|
||||
if (path.includes('/suppliers?')) return response({ records: [{ id: '9223372036854775804', name: 'Offline fleet', category: 'TRUCKING', truckingScope: 'OVERSEAS', status: 'ACTIVE' }] })
|
||||
if (method === 'GET') {
|
||||
if (path.endsWith('/history')) return response(history)
|
||||
if (path.includes('?containerBookingIds=')) return response([state])
|
||||
|
||||
@@ -77,10 +77,10 @@ export async function prepareTerminalDrayage(context, producer) {
|
||||
if (!success(initial.response) || !initial.data?.allowedActions?.includes('SELECT_FLEET')) return null
|
||||
|
||||
const suppliers = await api(context, 'GET', '查询ACTIVE码头拖车供应商',
|
||||
'/api/platform/v1/suppliers?tenantId=0&category=TRUCKING&status=ACTIVE&page=1&size=100')
|
||||
const fleet = suppliers.data?.records?.find((item) => id(item?.id) && item?.status === 'ACTIVE')
|
||||
'/api/platform/v1/suppliers?tenantId=0&category=TRUCKING&status=ACTIVE&truckingScope=OVERSEAS&page=1&size=100')
|
||||
const fleet = suppliers.data?.records?.find((item) => id(item?.id) && item?.status === 'ACTIVE' && item?.category === 'TRUCKING' && item?.truckingScope === 'OVERSEAS')
|
||||
if (!fleet) {
|
||||
blocker(context, '取得有效码头拖车供应商', '没有可复用的ACTIVE + TRUCKING公共供应商;脚本不临时创建主数据', suppliers.response)
|
||||
blocker(context, '取得有效码头拖车供应商', '没有可复用的ACTIVE + TRUCKING + OVERSEAS公共供应商;脚本不临时创建主数据', suppliers.response)
|
||||
return null
|
||||
}
|
||||
const selected = await command(context, target, '选择车队', 'fleet', {
|
||||
|
||||
@@ -75,9 +75,9 @@ export async function run(context) {
|
||||
id(booking?.id) === id(ocean.id) && booking?.status === 'RELEASED',
|
||||
`oceanBookingId=${id(booking?.id) || 'missing'}, status=${booking?.status || 'missing'}`, OPTIONS)
|
||||
const carrierResponse = await requestWithTransientRetry(context, 'GET',
|
||||
'/api/platform/v1/suppliers?tenantId=0&category=TRUCKING&status=ACTIVE&page=1&size=20')
|
||||
'/api/platform/v1/suppliers?tenantId=0&category=TRUCKING&status=ACTIVE&truckingScope=DOMESTIC&page=1&size=20')
|
||||
const carrierPage = context.apiSuccess(MODULE, '读取 ACTIVE TRUCKING 承运商事实源', carrierResponse, '', OPTIONS)
|
||||
const carrier = carrierPage?.records?.find?.((item) => item?.id && item?.name)
|
||||
const carrier = carrierPage?.records?.find?.((item) => item?.id && item?.name && item?.truckingScope === 'DOMESTIC')
|
||||
context.assert(MODULE, '跨服务拖车使用正式 ACTIVE TRUCKING 承运商', carrierResponse,
|
||||
Boolean(carrier?.id && carrier?.name), `carrierId=${id(carrier?.id) || 'missing'}`, OPTIONS)
|
||||
if (!carrier) return
|
||||
|
||||
@@ -79,13 +79,14 @@ export function truckAppointmentPayload(context, suffix, identity, version = 0,
|
||||
}
|
||||
|
||||
async function activeSupplier(context, category, suffix) {
|
||||
const carrierFilter = category === 'BOOKING' ? '&carrierCode=MATSON' : ''
|
||||
const carrierFilter = category === 'BOOKING' ? '&carrierCode=MATSON' : category === 'TRUCKING' ? '&truckingScope=DOMESTIC' : ''
|
||||
const list = await request(context, 'GET', `/api/platform/v1/suppliers?tenantId=0&category=${category}&status=ACTIVE${carrierFilter}&page=1&size=100`)
|
||||
const existing = records(data(list)).find((item) => item?.category === category && item?.status === 'ACTIVE'
|
||||
&& (category !== 'TRUCKING' || item?.truckingScope === 'DOMESTIC')
|
||||
&& (category !== 'BOOKING' || item?.carrierCodes?.includes?.('MATSON')))
|
||||
if (existing) return { supplierId: id(existing.id), supplierName: existing.name }
|
||||
const created = await request(context, 'POST', '/api/platform/v1/suppliers?tenantId=0', {
|
||||
name: `${category}-验收-${suffix}`, category, carrierCodes: category === 'BOOKING' ? ['MATSON'] : [],
|
||||
name: `${category}-验收-${suffix}`, category, truckingScope: category === 'TRUCKING' ? 'DOMESTIC' : null, carrierCodes: category === 'BOOKING' ? ['MATSON'] : [],
|
||||
region: '深圳', legalRepresentative: '验收法人', contactName: '验收联系人', phone: '13800000000',
|
||||
email: 'truck-acceptance@example.com', address: '深圳市验收地址', businessLicenseNo: `TRUCK-${suffix}`.slice(0, 64),
|
||||
licenseFileId: null, status: 'ACTIVE', settlementPeriod: 'MONTHLY_30', remark: context.marker,
|
||||
|
||||
Reference in New Issue
Block a user