Files
2026-10-21 15:10:44 +08:00

82 lines
4.3 KiB
JavaScript

function count(value) {
const number = Number(value)
return Number.isFinite(number) ? number : NaN
}
function currentMonth() {
return new Intl.DateTimeFormat('en-CA', {
timeZone: 'Asia/Shanghai', year: 'numeric', month: '2-digit',
}).format(new Date()).slice(0, 7)
}
function id(value) { return value == null ? '' : String(value) }
function listOf(value) {
if (Array.isArray(value)) return value
if (Array.isArray(value?.records)) return value.records
return null
}
export async function run(context) {
const module = 'sailing-calendar'
const base = '/api/platform/v1/sailings'
const month = currentMonth()
const calendarResponse = await context.request('GET', `${base}/calendar?month=${month}`)
const calendar = context.apiSuccess(module, '查询船期月历', calendarResponse)
const records = Array.isArray(calendar?.records) ? calendar.records : []
const summary = calendar?.summary
const filterOptions = calendar?.filterOptions
context.assert(module, '月历记录、汇总与筛选选项结构完整', calendarResponse,
records.every((row) => id(row.id) && id(row.sailingNo)
&& (row.etaAt == null || Number.isFinite(Date.parse(row.etaAt))))
&& summary && Number.isFinite(count(summary.sailingCount))
&& filterOptions && Array.isArray(filterOptions.warehouses) && Array.isArray(filterOptions.channels),
`month=${month},records=${records.length},sailingCount=${summary?.sailingCount ?? 'missing'}`)
context.assert(module, '月历容量汇总均为非负有限数', calendarResponse,
['actualReceivedCbm', 'catchableForecastCbm', 'riskUnmatchedCbm'].every((field) =>
Number.isFinite(count(summary?.[field])) && count(summary?.[field]) >= 0),
JSON.stringify(summary || {}).slice(0, 200))
const channelsResponse = await context.request('GET', '/api/platform/v1/sailing-channels')
const channels = context.apiSuccess(module, '查询船期渠道资源', channelsResponse)
const channelRows = listOf(channels) ?? []
context.assert(module, '渠道列表字段完整', channelsResponse,
channelRows.every((row) => id(row.id) && id(row.channelCode) && Number.isFinite(count(row.defaultCutoffDays))),
`count=${channelRows.length}`)
const templatesResponse = await context.request('GET', '/api/platform/v1/sailing-templates?page=1&size=200')
const templates = context.apiSuccess(module, '查询船期模板', templatesResponse)
const templateRows = listOf(templates) ?? []
context.assert(module, '模板列表字段完整', templatesResponse,
templateRows.every((row) => id(row.id) && id(row.channelId) && id(row.warehouseId) && Array.isArray(row.weekdays)),
`count=${templateRows.length}`)
const exceptionsResponse = await context.request('GET', '/api/platform/v1/sailing-assignments/exceptions?page=1&size=20')
const exceptions = context.apiSuccess(module, '查询船期异常分配', exceptionsResponse)
const exceptionRows = listOf(exceptions) ?? []
context.assert(module, '异常分配列表字段完整', exceptionsResponse,
exceptionRows.every((row) => id(row.assignmentId) && Number.isFinite(count(row.volumeCbm))),
`count=${exceptionRows.length},total=${exceptions?.total ?? 'array'}`)
if (records[0]) {
const detailResponse = await context.request('GET', `${base}/${encodeURIComponent(records[0].id)}`)
const detail = context.apiSuccess(module, '查询当前船期详情', detailResponse)
context.assert(module, '船期详情包含版本与货量摘要', detailResponse,
id(detail?.sailing?.id) === id(records[0].id)
&& Number.isFinite(count(detail?.sailing?.version))
&& detail?.sailing?.volumeSummary != null
&& Array.isArray(detail?.histories),
`id=${detail?.sailing?.id},version=${detail?.sailing?.version}`)
} else {
context.addCoverageGap(module, 'sailing-calendar', '船期详情与变更历史',
'当前月份没有船期记录;需先由订舱/模板生成本轮船期后重跑', 'not-implemented', { blocking: false })
}
const missingResponse = await context.request('GET', `${base}/999999999999999`)
context.assert(module, '不存在的船期详情被拒绝', missingResponse,
(missingResponse.http === 200 && ['A0403', 'A0404'].includes(String(missingResponse.body?.code)))
|| missingResponse.http === 404,
`HTTP=${missingResponse.http},code=${missingResponse.body?.code ?? 'missing'}`)
}