Files
baiyue-firstleg/lastleg-service/src/main/resources/openapi/self-operated-inventory-turnover-v1.yaml
T

244 lines
17 KiB
YAML
Raw 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.
openapi: 3.0.3
info:
title: 平台自营库存周转只读查询
version: 1.0.0
description: >-
仅PLATFORM、tenantId=0、非代登录及platform:self-operated-analytics:list权限。
仓库由服务端受控配置校验;不触发采集,不读取来源订单,不调用领星。
所选窗口为截至endDate的1~366个完整北京时间自然日,并提供7/15/30天辅助对比;当前库存独立固定版本。
每次请求使用REPEATABLE_READ,一致性读固定销量、当前库存及历史日版本映射。
snapshotContext保存签名压缩的准确版本清单与缺失日期,不作为授权凭据;后续页按准确ID校验
账号、仓库、范围及失效标记,不用墙钟时刻重新推导日头。服务重启、校正失效、规则变更要求整体刷新。
历史分母只使用FLOW_EOD_V1日末全品质实物库存,以完整流水及独立库存锚点还原;不与旧计划样本混算。
上下文有效期最多30分钟;客户端不能直接指定runId。SKU/关注分页不改变概览范围。
历史销量完整性不依赖当前库存新鲜度;缺日保持未知、不缩短周转分母。sampleReasonCodes包含流水或独立库存对账失败原因。dailySamples.dayVersionId表示历史日版本标识,非原始库存run。
security: [{bearerAuth: []}]
paths:
/api/platform/v1/last-leg/self-operated-analytics/inventory-turnover:
get:
operationId: inventoryTurnover
summary: 单仓SKU或货主三窗口库存周转
description: >-
customerCodes按所选货主集合限定列表、概览及图表,省略或空集合表示全部;sku、focus、turnoverStatus及hideZeroInventory只筛列表。
按完整候选计算依赖后排序分页,未知末尾,同值按SKU及货主或货主编码稳定排序。
OWNER不计算整体可售天数;销售事实完整即可展示货主实际出库,不受单SKU观察期影响。
SKU出库及无出库判断同样不受首次观察时间限制:可信完整覆盖的缺销量行可计零;实际异常单位或未覆盖日期保持未知。
当前可售天数仍要求有效库存和完整销量窗口;期间件数周转仍要求合格每日库存样本及商品观察证据。
首屏必须current=1且返回概览;后续携带snapshotContext,includeOverview=false省略概览。
不接受attention、salesWindowDays、版本ID或其他视图参数。
parameters:
- {name: sourceAccount, in: query, required: true, schema: {type: string, minLength: 1, maxLength: 64}}
- {name: warehouseCode, in: query, required: true, schema: {type: string, minLength: 1, maxLength: 64}}
- {name: endDate, in: query, description: '含截止日,默认北京时间昨天,不接受今日或未来', schema: {type: string, format: date}}
- {name: baseWindowDays, in: query, schema: {type: integer, minimum: 1, maximum: 366, default: 30}}
- {name: groupBy, in: query, schema: {type: string, enum: [SKU, OWNER], default: SKU}}
- {name: customerCodes, in: query, style: form, explode: true, description: '货主编码多选,重复键传输;同一编码不重复计数,最多100个', schema: {type: array, maxItems: 100, items: {type: string, minLength: 1, maxLength: 64}}}
- {name: sku, in: query, description: SKU分组的精确查询,OWNER禁止传入, schema: {type: string, minLength: 1, maxLength: 128}}
- {name: hideZeroInventory, in: query, description: 默认隐藏当前全品质实物件数明确为0的SKU或货主汇总行,保留未知;全量筛选后分页,不改变概览及图表, schema: {type: boolean, default: true}}
- name: focus
in: query
schema: {type: string, enum: [ALL, NO_OUTBOUND_IN_WINDOW, COVERAGE_GT, COVERAGE_LE, FROZEN, DEFECTIVE, UNASSESSABLE], default: ALL}
- {name: coverageDaysThreshold, in: query, description: 'GT/LE必填,其余可选;无默认业务阈值', schema: {type: integer, minimum: 1}}
- {name: turnoverStatus, in: query, schema: {type: string, enum: [INSUFFICIENT]}}
- name: sortBy
in: query
description: 'OWNER禁止COVERAGE_ASC/DESC及UNIT_VOLUME_ASC/DESC,SKU禁止NO_OUTBOUND_PHYSICAL_DESC。全量筛选后按正式未舍入值排序再分页,未知值始终末尾,同值按SKU及货主升序。AVERAGE_DAILY及OUTBOUND_VOLUME使用baseWindowDays指定的窗口;体积按正式值排序,不使用已知小计。'
schema: {type: string, default: PHYSICAL_DESC, enum: [PHYSICAL_ASC, PHYSICAL_DESC, AVAILABLE_ASC, AVAILABLE_DESC, OUTBOUND_7_ASC, OUTBOUND_7_DESC, OUTBOUND_15_ASC, OUTBOUND_15_DESC, OUTBOUND_30_ASC, OUTBOUND_30_DESC, AVERAGE_DAILY_ASC, AVERAGE_DAILY_DESC, COVERAGE_ASC, COVERAGE_DESC, TRANSIT_ASC, TRANSIT_DESC, FROZEN_ASC, FROZEN_DESC, DEFECTIVE_ASC, DEFECTIVE_DESC, AVERAGE_PHYSICAL_ASC, AVERAGE_PHYSICAL_DESC, TURNOVER_ASC, TURNOVER_DESC, INVENTORY_VOLUME_ASC, INVENTORY_VOLUME_DESC, OUTBOUND_VOLUME_ASC, OUTBOUND_VOLUME_DESC, UNIT_VOLUME_ASC, UNIT_VOLUME_DESC, NO_OUTBOUND_PHYSICAL_DESC]}
- {name: current, in: query, schema: {type: integer, minimum: 1, default: 1}}
- {name: size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
- {name: includeOverview, in: query, schema: {type: boolean, default: true}}
- {name: snapshotContext, in: query, description: 首屏返回的完整不可拆分上下文;翻页必填, schema: {type: string, minLength: 1, maxLength: 16384}}
responses:
'200':
description: 统一ApiResponse;参数或上下文业务错误沿现有异常响应,不伪装成空结果
content:
application/json:
schema:
type: object
properties:
code: {type: string}
message: {type: string}
data: {$ref: '#/components/schemas/Response'}
'400': {description: HTTP参数类型或日期格式不合法}
'401': {description: 无可信登录身份}
'403': {description: 非平台、代登录或缺少独立只读权限}
components:
securitySchemes:
bearerAuth: {type: http, scheme: bearer, bearerFormat: JWT}
schemas:
Quantity:
type: number
nullable: true
description: PCS件数或对应指标值;未知为null,派生值六位小数,不把未知当0
Reasons:
type: array
items: {type: string}
Total:
type: object
required: [value, knownSubtotal, unknownSkuCount, reasonCodes]
properties:
value: {$ref: '#/components/schemas/Quantity'}
knownSubtotal: {$ref: '#/components/schemas/Quantity'}
unknownSkuCount: {type: integer, minimum: 0}
reasonCodes: {$ref: '#/components/schemas/Reasons'}
Risk:
type: object
description: 命中为已确认小计;只有整个实物及风险判断完整、分母大于0时才提供件数比例。未设慢消化阈值则数量与比例均null。
required: [matchedSkuCount, knownPhysicalQuantity, unknownSkuCount, physicalQuantityRatio]
properties:
matchedSkuCount: {$ref: '#/components/schemas/Quantity'}
knownPhysicalQuantity: {$ref: '#/components/schemas/Quantity'}
unknownSkuCount: {type: integer, minimum: 0}
physicalQuantityRatio: {$ref: '#/components/schemas/Quantity'}
Volume:
type: object
description: >-
m³,按SKU先计算再汇总,不对分页行求和。优先完整有效的仓库实测尺寸,否则完整商品申报尺寸;不混搭长宽高。
支持mm/cm/m/in/ft,未知单位及非正尺寸无效。商品资料固定为queryAsOf之前最近完整已发布批次,按账号+货主+SKU关联。
库存按全品质实物件数,不计在途,不代表库位占用;历史出库按当前商品尺寸估算,不代表历史包裹实测体积。
数量已知为0可得0,无需尺寸;数量未知或正数量缺有效尺寸时正式值null,已知小计单独返回。
required: [value, knownSubtotal, missingDimensionQuantity, missingDimensionSkuCount, unknownQuantitySkuCount, declaredDimensionQuantity, reasonCodes]
properties:
value: {type: number, nullable: true, description: 全部数量和所需尺寸可确认时的体积,m³}
knownSubtotal: {type: number, nullable: true, description: 可计算部分的体积小计,m³,不冒充总量}
missingDimensionQuantity: {$ref: '#/components/schemas/Quantity'}
missingDimensionSkuCount: {type: integer, minimum: 0}
unknownQuantitySkuCount: {type: integer, minimum: 0}
declaredDimensionQuantity: {allOf: [{$ref: '#/components/schemas/Quantity'}], description: 使用商品申报尺寸估算的件数}
reasonCodes: {type: array, items: {type: string, enum: [DIMENSIONS_MISSING_OR_INVALID, QUANTITY_UNAVAILABLE, DECLARED_DIMENSIONS_ESTIMATE]}}
VolumeWindow:
type: object
required: [days, startDate, endDateExclusive, volume]
properties:
days: {type: integer, minimum: 1, maximum: 366}
startDate: {type: string, format: date}
endDateExclusive: {type: string, format: date}
volume: {$ref: '#/components/schemas/Volume'}
Window:
type: object
required: [days, startDate, endDateExclusive, outboundQuantity, observedQuantity, averageDailyOutboundQuantity, completeDayCount, partialDayCount, unknownDayCount, dataStatus, reasonCodes]
properties:
days: {type: integer, minimum: 1, maximum: 366}
startDate: {type: string, format: date}
endDateExclusive: {type: string, format: date}
outboundQuantity: {$ref: '#/components/schemas/Quantity'}
observedQuantity: {$ref: '#/components/schemas/Quantity'}
averageDailyOutboundQuantity: {$ref: '#/components/schemas/Quantity'}
completeDayCount: {type: integer, minimum: 0}
partialDayCount: {type: integer, minimum: 0}
unknownDayCount: {type: integer, minimum: 0}
dataStatus: {type: string, enum: [COMPLETE, PARTIAL, UNKNOWN]}
reasonCodes: {$ref: '#/components/schemas/Reasons'}
Context:
type: object
required: [snapshotContext, sourceAccount, warehouseCode, endDate, baseWindowDays, queryAsOf, queryExpiresAt, analyticsContext, inventoryObservedFrom, inventoryObservedUntil, sampleRuleVersion, dailySamples, missingSampleDates, accumulationStartedOn]
properties:
snapshotContext: {type: string}
sourceAccount: {type: string}
warehouseCode: {type: string}
endDate: {type: string, format: date}
baseWindowDays: {type: integer, minimum: 1, maximum: 366}
queryAsOf: {type: string, format: date-time}
queryExpiresAt: {type: string, format: date-time}
analyticsContext: {$ref: './self-operated-analytics-v1.yaml#/components/schemas/Context'}
inventoryObservedFrom: {type: string, format: date-time, nullable: true}
inventoryObservedUntil: {type: string, format: date-time, nullable: true}
sampleRuleVersion: {type: string, enum: [FLOW_EOD_V1]}
dailySamples:
type: array
minItems: 30
maxItems: 366
items:
type: object
required: [date, dayVersionId]
properties:
date: {type: string, format: date}
dayVersionId: {type: string, nullable: true, description: 内部版本证据,不作为用户可见编号}
missingSampleDates: {type: array, items: {type: string, format: date}}
accumulationStartedOn: {type: string, format: date, nullable: true}
Row:
type: object
required: [customerCode, customerName, sku, productName, physicalQuantity, availableQuantity, frozenQuantity, defectiveQuantity, transitQuantity, physicalSkuCount, windows, averageDailyOutboundQuantity, inventoryCoverageDays, coverageStatus, averagePhysicalQuantity, quantityTurnoverCount, turnoverStatus, qualifiedSampleDays, requiredSampleDays, missingSampleDates, sampleReasonCodes, lastObservedOutboundDate, attentionReasons, noOutboundInWindow, slowCoverage, unassessableSkuCount, unitVolumeM3, dimensionSource, inventoryVolumeM3, outboundVolumesM3]
properties:
customerCode: {type: string}
customerName: {type: string, nullable: true}
sku: {type: string, nullable: true}
productName: {type: string, nullable: true}
physicalQuantity: {$ref: '#/components/schemas/Total'}
availableQuantity: {$ref: '#/components/schemas/Total'}
frozenQuantity: {$ref: '#/components/schemas/Total'}
defectiveQuantity: {$ref: '#/components/schemas/Total'}
transitQuantity:
allOf: [{$ref: '#/components/schemas/Total'}]
description: 当前固定库存版本的全品质在途件数;独立展示,不计入实物、可售或周转分母;缺失、异常或过期保留未知。
physicalSkuCount: {$ref: '#/components/schemas/Quantity'}
windows: {type: array, minItems: 3, maxItems: 4, items: {$ref: '#/components/schemas/Window'}}
averageDailyOutboundQuantity: {$ref: '#/components/schemas/Quantity'}
inventoryCoverageDays: {$ref: '#/components/schemas/Quantity'}
coverageStatus: {type: string, enum: [VALID, NOT_APPLICABLE, INVENTORY_UNKNOWN_OR_STALE, NO_AVAILABLE_STOCK, UNASSESSABLE, NO_OUTBOUND_IN_WINDOW]}
averagePhysicalQuantity: {$ref: '#/components/schemas/Quantity'}
quantityTurnoverCount: {$ref: '#/components/schemas/Quantity'}
turnoverStatus: {type: string, enum: [VALID, INSUFFICIENT, ZERO_AVERAGE_STOCK, SALES_WINDOW_UNAVAILABLE]}
qualifiedSampleDays: {type: integer, minimum: 0, maximum: 30}
requiredSampleDays: {type: integer, minimum: 1, maximum: 366}
missingSampleDates: {type: array, items: {type: string, format: date}}
sampleReasonCodes: {$ref: '#/components/schemas/Reasons'}
lastObservedOutboundDate: {type: string, format: date, nullable: true}
attentionReasons: {$ref: '#/components/schemas/Reasons'}
noOutboundInWindow: {$ref: '#/components/schemas/Risk'}
slowCoverage: {$ref: '#/components/schemas/Risk'}
unassessableSkuCount: {type: integer, minimum: 0}
unitVolumeM3: {type: number, nullable: true, description: SKU单件体积m³,货主汇总不提供}
dimensionSource: {type: string, nullable: true, enum: [WAREHOUSE_MEASURED, PRODUCT_DECLARED, MISSING], description: SKU尺寸来源,货主汇总不提供}
inventoryVolumeM3: {$ref: '#/components/schemas/Volume'}
outboundVolumesM3: {type: array, minItems: 3, maxItems: 4, items: {$ref: '#/components/schemas/VolumeWindow'}}
Overview:
type: object
nullable: true
required: [physicalQuantity, availableQuantity, noOutboundSkuCount, unassessableSkuCount, inventoryVolumeM3, outboundVolumesM3]
properties:
physicalQuantity: {$ref: '#/components/schemas/Total'}
availableQuantity: {$ref: '#/components/schemas/Total'}
noOutboundSkuCount: {$ref: '#/components/schemas/Total'}
unassessableSkuCount: {$ref: '#/components/schemas/Total'}
inventoryVolumeM3: {$ref: '#/components/schemas/Volume'}
outboundVolumesM3: {type: array, minItems: 3, maxItems: 4, items: {$ref: '#/components/schemas/VolumeWindow'}}
Charts:
type: object
nullable: true
required: [ownerPhysicalTop, unknownOwnerCount, ownerVolumeTop, unknownVolumeOwnerCount, averageDaily]
properties:
ownerPhysicalTop:
type: array
maxItems: 10
items:
type: object
required: [customerCode, customerName, physicalQuantity]
properties:
customerCode: {type: string}
customerName: {type: string, nullable: true}
physicalQuantity: {$ref: '#/components/schemas/Quantity'}
unknownOwnerCount: {type: integer, minimum: 0}
ownerVolumeTop:
type: array
maxItems: 10
description: 当前库存正式体积降序,同体积按货主编码稳定排序;排除体积未知货主,不受列表筛选及分页影响。
items:
type: object
required: [customerCode, customerName, inventoryVolumeM3]
properties:
customerCode: {type: string}
customerName: {type: string, nullable: true}
inventoryVolumeM3: {$ref: '#/components/schemas/Volume'}
unknownVolumeOwnerCount: {type: integer, minimum: 0, description: 因缺尺寸或库存数量未知未参与体积排名的货主数}
averageDaily: {type: array, minItems: 3, maxItems: 4, items: {$ref: '#/components/schemas/Window'}}
Response:
type: object
required: [context, summary, charts, rows, total]
properties:
context: {$ref: '#/components/schemas/Context'}
summary: {$ref: '#/components/schemas/Overview'}
charts: {$ref: '#/components/schemas/Charts'}
rows: {type: array, maxItems: 100, items: {$ref: '#/components/schemas/Row'}}
total: {type: string, pattern: '^[0-9]+$', description: 服务统一将Long序列化为字符串}