feat(self-operated): unify completed-day ranges and analytics sorting
This commit is contained in:
@@ -13,7 +13,7 @@ const button = defineComponent({ emits: ['click'], setup(_, { slots, emit }) { r
|
||||
const shell = defineComponent({ setup(_, { slots }) { return () => h('div', slots.default?.()) } })
|
||||
const total = { value: 100, knownSubtotal: 100, unknownSkuCount: 0, reasonCodes: [] }
|
||||
const risk = { matchedSkuCount: 0, knownPhysicalQuantity: 0, unknownSkuCount: 0, physicalQuantityRatio: 0 }
|
||||
const row: TurnoverRow = { customerCode: 'OWNER-A', customerName: null, sku: 'SAME', productName: '商品', physicalQuantity: total, availableQuantity: total, frozenQuantity: total, defectiveQuantity: total, physicalSkuCount: 1, windows: [7, 15, 30].map(days => ({ days: days as 7 | 15 | 30, startDate: '2026-09-13', endDateExclusive: '2026-10-13', outboundQuantity: 300, observedQuantity: 300, averageDailyOutboundQuantity: 10, completeDayCount: days, partialDayCount: 0, unknownDayCount: 0, dataStatus: 'COMPLETE', reasonCodes: [] })), averageDailyOutboundQuantity: 10, inventoryCoverageDays: 10, coverageStatus: 'VALID', averagePhysicalQuantity: null, quantityTurnoverCount: null, turnoverStatus: 'INSUFFICIENT', qualifiedSampleDays: 0, requiredSampleDays: 30, missingSampleDates: ['2026-10-12'], sampleReasonCodes: [], lastObservedOutboundDate: null, attentionReasons: [], noOutbound30d: risk, slowCoverage: risk, unassessableSkuCount: 0 }
|
||||
const row: TurnoverRow = { customerCode: 'OWNER-A', customerName: null, sku: 'SAME', productName: '商品', physicalQuantity: total, availableQuantity: total, frozenQuantity: total, defectiveQuantity: total, physicalSkuCount: 1, windows: [7, 15, 30].map(days => ({ days: days as 7 | 15 | 30, startDate: '2026-09-13', endDateExclusive: '2026-10-13', outboundQuantity: 300, observedQuantity: 300, averageDailyOutboundQuantity: 10, completeDayCount: days, partialDayCount: 0, unknownDayCount: 0, dataStatus: 'COMPLETE', reasonCodes: [] })), averageDailyOutboundQuantity: 10, inventoryCoverageDays: 10, coverageStatus: 'VALID', averagePhysicalQuantity: null, quantityTurnoverCount: null, turnoverStatus: 'INSUFFICIENT', qualifiedSampleDays: 0, requiredSampleDays: 30, missingSampleDates: ['2026-10-12'], sampleReasonCodes: [], lastObservedOutboundDate: null, attentionReasons: [], noOutboundInWindow: risk, slowCoverage: risk, unassessableSkuCount: 0 }
|
||||
function response(q: TurnoverQuery): TurnoverResponse {
|
||||
return { context: { snapshotContext: q.snapshotContext || `token-${q.warehouseCode}`, sourceAccount: q.sourceAccount, warehouseCode: q.warehouseCode, endDate: q.endDate, baseWindowDays: q.baseWindowDays, queryAsOf: '2026-10-13T00:00:00Z', queryExpiresAt: '2099-10-13T00:30:00Z', inventoryObservedFrom: null, inventoryObservedUntil: null, sampleRuleVersion: 'DAILY_SCHEDULED_FIRST_V1', dailySamples: [], missingSampleDates: ['2026-10-12'], accumulationStartedOn: null, analyticsContext: { salesRunId: '11', inventoryRunId: '22', salesScopeHash: 'a', inventoryScopeHash: 'b', queryAsOf: '2026-10-13T00:00:00Z', queryExpiresAt: '2099-10-13T00:30:00Z', businessTimezone: 'Asia/Shanghai', anchorDate: '2026-10-13' } }, summary: q.includeOverview ? { physicalQuantity: total, availableQuantity: total, noOutboundSkuCount: total, unassessableSkuCount: total } : null, charts: q.includeOverview ? { ownerPhysicalTop: [], unknownOwnerCount: 0, averageDaily: row.windows } : null, rows: [{ ...row, sku: q.groupBy === 'OWNER' ? null : row.sku }], total: 40 }
|
||||
}
|
||||
@@ -42,7 +42,7 @@ describe('inventory turnover page fixed snapshot behavior', () => {
|
||||
expect(header.attributes('aria-label')).toContain(direction === 'ASC' ? '当前升序' : '当前降序')
|
||||
}
|
||||
}
|
||||
await change(w, { baseWindowDays: 7 })
|
||||
await change(w, { rangePreset: 'LAST_7_DAYS' })
|
||||
expect(w.get('button[data-column="averageDailyOutboundQuantity"]').text()).toContain('7日日均')
|
||||
await w.get('button[data-column="averageDailyOutboundQuantity"]').trigger('click'); await flushPromises()
|
||||
expect(mocks.turnover.mock.calls.at(-1)![0]).toMatchObject({ baseWindowDays: 7, sortBy: 'AVERAGE_DAILY_DESC' })
|
||||
@@ -109,7 +109,7 @@ describe('inventory turnover page fixed snapshot behavior', () => {
|
||||
it('queries the remaining focus tabs and uses owner-compatible sorting', async () => {
|
||||
const w = page(); await flushPromises()
|
||||
await change(w, { groupBy: 'OWNER' })
|
||||
for (const [label, focus, sortBy] of [['近30日无出库', 'NO_OUTBOUND_30D', 'NO_OUTBOUND_PHYSICAL_DESC'], ['待评估', 'UNASSESSABLE', 'PHYSICAL_DESC'], ['消化较慢', 'COVERAGE_GT', 'PHYSICAL_DESC'], ['消化较快', 'COVERAGE_LE', 'PHYSICAL_DESC'], ['全部', 'ALL', 'PHYSICAL_DESC']]) {
|
||||
for (const [label, focus, sortBy] of [['所选时段无出库', 'NO_OUTBOUND_IN_WINDOW', 'NO_OUTBOUND_PHYSICAL_DESC'], ['待评估', 'UNASSESSABLE', 'PHYSICAL_DESC'], ['消化较慢', 'COVERAGE_GT', 'PHYSICAL_DESC'], ['消化较快', 'COVERAGE_LE', 'PHYSICAL_DESC'], ['全部', 'ALL', 'PHYSICAL_DESC']]) {
|
||||
await w.findAll('.turnover-focus button').find(b => b.text() === label)!.trigger('click'); await flushPromises()
|
||||
expect(mocks.turnover.mock.calls.at(-1)![0]).toMatchObject({ groupBy: 'OWNER', focus, sortBy, current: 1 })
|
||||
}
|
||||
@@ -210,6 +210,9 @@ describe('inventory turnover page fixed snapshot behavior', () => {
|
||||
await w.findAll('button').find(b => b.text() === '返回货主汇总')!.trigger('click'); await flushPromises()
|
||||
expect(w.findComponent(table).props('page')).toBe(2)
|
||||
expect(w.findComponent(toolbar).props('modelValue').groupBy).toBe('OWNER')
|
||||
expect(w.findComponent(toolbar).props('modelValue')).toMatchObject({ rangePreset: 'CUSTOM', customRange: ['2026-09-13', '2026-10-12'] })
|
||||
w.findComponent(table).vm.$emit('update:page', 1); await flushPromises()
|
||||
expect(mocks.turnover.mock.calls.at(-1)![0]).toMatchObject({ endDate: '2026-10-12', baseWindowDays: 30, snapshotContext: 'token-A' })
|
||||
})
|
||||
it('blocks invalid thresholds and preserves known data on same-scope refresh failure', async () => {
|
||||
const w = page(); await flushPromises()
|
||||
|
||||
Reference in New Issue
Block a user