feat(self-operated): support selected-day analytics and global quantity sorting

This commit is contained in:
2026-10-14 12:44:15 +08:00
parent 287edcf32b
commit bc9c78122b
31 changed files with 329 additions and 144 deletions
@@ -5,10 +5,10 @@ info:
description: >-
仅PLATFORM、tenantId=0、非代登录及platform:self-operated-analytics:list权限。
仓库由服务端受控配置校验;不触发采集,不读取来源订单,不调用领星。
三窗为截至endDate的7/15/30个完整北京时间自然日;当前库存独立固定版本。
所选窗口为截至endDate的1~366个完整北京时间自然日,并提供7/15/30天辅助对比;当前库存独立固定版本。
每次请求使用REPEATABLE_READ。snapshotContext为服务端重建验证的版本与日代表证据,
不作为授权凭据;账号、仓库、截止日、基准、queryAsOf、版本对、范围摘要、
重建状态及全部30日映射(含缺失日期)逐项重建比较;无效或过期要求整体刷新。
重建状态及全部max(30,baseWindowDays)日映射(含缺失日期)逐项重建比较;无效或过期要求整体刷新。
历史代表须同范围、正式计划采集、已发布且DAILY_SCHEDULED_FIRST_V1合格标记。
上下文有效期最多30分钟;客户端不能直接指定runId。SKU/关注分页不改变概览范围。
历史销量完整性不依赖当前库存新鲜度;缺样本不补零、不缩短周转分母。
@@ -28,13 +28,13 @@ paths:
- {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, enum: [7, 15, 30], default: 30}}
- {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: customerCode, in: query, schema: {type: string, minLength: 1, maxLength: 64}}
- {name: sku, in: query, description: SKU分组的精确查询,OWNER禁止传入, schema: {type: string, minLength: 1, maxLength: 128}}
- name: focus
in: query
schema: {type: string, enum: [ALL, NO_OUTBOUND_30D, COVERAGE_GT, COVERAGE_LE, FROZEN, DEFECTIVE, UNASSESSABLE], default: ALL}
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
@@ -91,7 +91,7 @@ components:
type: object
required: [days, startDate, endDateExclusive, outboundQuantity, observedQuantity, averageDailyOutboundQuantity, completeDayCount, partialDayCount, unknownDayCount, dataStatus, reasonCodes]
properties:
days: {type: integer, enum: [7, 15, 30]}
days: {type: integer, minimum: 1, maximum: 366}
startDate: {type: string, format: date}
endDateExclusive: {type: string, format: date}
outboundQuantity: {$ref: '#/components/schemas/Quantity'}
@@ -110,7 +110,7 @@ components:
sourceAccount: {type: string}
warehouseCode: {type: string}
endDate: {type: string, format: date}
baseWindowDays: {type: integer, enum: [7, 15, 30]}
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'}
@@ -120,7 +120,7 @@ components:
dailySamples:
type: array
minItems: 30
maxItems: 30
maxItems: 366
items:
type: object
required: [date, runId]
@@ -131,7 +131,7 @@ components:
accumulationStartedOn: {type: string, format: date, nullable: true}
Row:
type: object
required: [customerCode, customerName, sku, productName, physicalQuantity, availableQuantity, frozenQuantity, defectiveQuantity, physicalSkuCount, windows, averageDailyOutboundQuantity, inventoryCoverageDays, coverageStatus, averagePhysicalQuantity, quantityTurnoverCount, turnoverStatus, qualifiedSampleDays, requiredSampleDays, missingSampleDates, sampleReasonCodes, lastObservedOutboundDate, attentionReasons, noOutbound30d, slowCoverage, unassessableSkuCount]
required: [customerCode, customerName, sku, productName, physicalQuantity, availableQuantity, frozenQuantity, defectiveQuantity, physicalSkuCount, windows, averageDailyOutboundQuantity, inventoryCoverageDays, coverageStatus, averagePhysicalQuantity, quantityTurnoverCount, turnoverStatus, qualifiedSampleDays, requiredSampleDays, missingSampleDates, sampleReasonCodes, lastObservedOutboundDate, attentionReasons, noOutboundInWindow, slowCoverage, unassessableSkuCount]
properties:
customerCode: {type: string}
customerName: {type: string, nullable: true}
@@ -142,7 +142,7 @@ components:
frozenQuantity: {$ref: '#/components/schemas/Total'}
defectiveQuantity: {$ref: '#/components/schemas/Total'}
physicalSkuCount: {$ref: '#/components/schemas/Quantity'}
windows: {type: array, minItems: 3, maxItems: 3, items: {$ref: '#/components/schemas/Window'}}
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]}
@@ -150,12 +150,12 @@ components:
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, enum: [7, 15, 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'}
noOutbound30d: {$ref: '#/components/schemas/Risk'}
noOutboundInWindow: {$ref: '#/components/schemas/Risk'}
slowCoverage: {$ref: '#/components/schemas/Risk'}
unassessableSkuCount: {type: integer, minimum: 0}
Overview:
@@ -183,7 +183,7 @@ components:
customerName: {type: string, nullable: true}
physicalQuantity: {$ref: '#/components/schemas/Quantity'}
unknownOwnerCount: {type: integer, minimum: 0}
averageDaily: {type: array, minItems: 3, maxItems: 3, items: {$ref: '#/components/schemas/Window'}}
averageDaily: {type: array, minItems: 3, maxItems: 4, items: {$ref: '#/components/schemas/Window'}}
Response:
type: object
required: [context, summary, charts, rows, total]