83 lines
4.8 KiB
JavaScript
83 lines
4.8 KiB
JavaScript
function count(value) {
|
|||
|
|
const number = Number(value)
|
||
|
|
return Number.isFinite(number) ? number : NaN
|
||
|
|
}
|
||
|
|
|
||
|
|
function shanghaiDate(offsetDays) {
|
||
|
|
return new Intl.DateTimeFormat('en-CA', {
|
||
|
|
timeZone: 'Asia/Shanghai', year: 'numeric', month: '2-digit', day: '2-digit',
|
||
|
|
}).format(new Date(Date.now() + offsetDays * 86_400_000))
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function run(context) {
|
||
|
|
const module = 'appointment-work'
|
||
|
|
const base = '/api/platform/v1/last-leg/appointment-work'
|
||
|
|
const from = shanghaiDate(-7)
|
||
|
|
const to = shanghaiDate(7)
|
||
|
|
|
||
|
|
const calendarResponse = await context.request('GET', `${base}/calendar?from=${from}&to=${to}`)
|
||
|
|
const calendar = context.apiSuccess(module, '查询预约工作日历', calendarResponse)
|
||
|
|
const days = Array.isArray(calendar?.days) ? calendar.days : []
|
||
|
|
const dayTotal = days.reduce((sum, day) => sum + Number(day?.total || 0), 0)
|
||
|
|
context.assert(module, '日历区间、日汇总与总数守恒', calendarResponse,
|
||
|
|
calendar?.from === from && calendar?.to === to && count(calendar?.total) === dayTotal,
|
||
|
|
`from=${calendar?.from || 'missing'},to=${calendar?.to || 'missing'},total=${calendar?.total ?? 'missing'},dayTotal=${dayTotal}`)
|
||
|
|
for (const day of days.slice(0, 3)) {
|
||
|
|
const typeTotal = Object.values(day?.typeCounts || {}).reduce((sum, value) => sum + Number(value || 0), 0)
|
||
|
|
context.assert(module, `日历日 ${day?.date} 类型汇总不超过当日总数`, calendarResponse,
|
||
|
|
Number(day?.total || 0) >= typeTotal,
|
||
|
|
`date=${day?.date || 'missing'},total=${day?.total ?? 'missing'},typeTotal=${typeTotal}`)
|
||
|
|
}
|
||
|
|
|
||
|
|
const summaryResponse = await context.request('GET', `${base}/summary`)
|
||
|
|
const summary = context.apiSuccess(module, '查询预约工作汇总', summaryResponse)
|
||
|
|
const summaryFields = ['all', 'followToday', 'overdue', 'undated', 'review']
|
||
|
|
context.assert(module, '工作汇总五项计数完整', summaryResponse,
|
||
|
|
summaryFields.every((field) => Number.isFinite(Number(summary?.[field]))),
|
||
|
|
summaryFields.map((field) => `${field}=${summary?.[field] ?? 'missing'}`).join(','))
|
||
|
|
|
||
|
|
const pageResponse = await context.request('GET', `${base}/items?view=ALL&page=1&size=20`)
|
||
|
|
const page = context.apiSuccess(module, '查询预约工作事项首页', pageResponse)
|
||
|
|
const records = Array.isArray(page?.records) ? page.records : []
|
||
|
|
const total = count(page?.total)
|
||
|
|
context.assert(module, '工作事项分页完整且不截断', pageResponse,
|
||
|
|
count(page?.page) === 1 && count(page?.size) === 20 && Number.isFinite(total)
|
||
|
|
&& records.length === Math.min(20, total) && count(page?.pages) === Math.ceil(total / 20),
|
||
|
|
`page=${page?.page},size=${page?.size},total=${page?.total},records=${records.length},pages=${page?.pages}`)
|
||
|
|
|
||
|
|
const first = records[0]
|
||
|
|
if (!first) {
|
||
|
|
context.addCoverageGap(module, 'appointment-work', '预约工作项详情与命令',
|
||
|
|
'本轮主链未产生预约工作事项;需先完成订单、柜、船节点或排车链后重跑', 'not-implemented',
|
||
|
|
{ blocking: false })
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
const detailResponse = await context.request('GET', `${base}/items/${encodeURIComponent(first.workItemKey)}`)
|
||
|
|
const detail = context.apiSuccess(module, '查询当前工作事项详情', detailResponse)
|
||
|
|
context.assert(module, '工作详情包含身份、来源与可执行动作', detailResponse,
|
||
|
|
detail?.item?.workItemKey === first.workItemKey
|
||
|
|
&& ['ROUTE', 'PICKUP', 'WAREHOUSE_RECEIPT', 'DELIVERY', 'TRANSPORT', 'EMPTY_RETURN'].includes(detail?.item?.type)
|
||
|
|
&& ['UNKNOWN', 'TRANSFER', 'DIRECT'].includes(detail?.item?.flow)
|
||
|
|
&& Array.isArray(detail?.item?.containers) && detail.item.containers.length > 0
|
||
|
|
&& Array.isArray(detail?.item?.allowedActions) && Array.isArray(detail?.references)
|
||
|
|
&& Array.isArray(detail?.history),
|
||
|
|
`key=${detail?.item?.workItemKey},type=${detail?.item?.type},flow=${detail?.item?.flow},`
|
||
|
|
+ `actions=${detail?.item?.allowedActions?.length ?? 'missing'}`)
|
||
|
|
|
||
|
|
const invalidKey = 'FULL-ACCEPTANCE-MISSING-WORK-ITEM'
|
||
|
|
const invalidResponse = await context.request('POST', `${base}/items/${encodeURIComponent(invalidKey)}/commands`, {
|
||
|
|
command: 'SAVE_FOLLOWUP',
|
||
|
|
payload: { ownerId: '1', followupDate: to, note: `missing-${context.marker}` },
|
||
|
|
expectedVersion: 1,
|
||
|
|
idempotencyKey: `${context.marker}-missing-work`,
|
||
|
|
})
|
||
|
|
context.assert(module, '不存在的工作事项命令被拒绝', invalidResponse,
|
||
|
|
invalidResponse.http === 200 && ['A0403', 'A0404'].includes(String(invalidResponse.body?.code)),
|
||
|
|
`HTTP=${invalidResponse.http},code=${invalidResponse.body?.code ?? 'missing'}`)
|
||
|
|
|
||
|
|
context.addCoverageGap(module, 'appointment-work', '预约写命令正向链路',
|
||
|
|
'当前仅验证拒绝路径;SAVE_FOLLOWUP/CONFIRM_ROUTE/SAVE_REQUIREMENT 需要本轮可编辑工作项与操作人 ID,待下一批接入',
|
||
|
|
'not-implemented', { blocking: false })
|
||
|
|
}
|