Merge branch 't3code/investigate-unmapped-details'
This commit is contained in:
@@ -719,6 +719,138 @@ describe('financial taxonomy internals', () => {
|
|||||||
expect(standardizedRows.some((row) => row.key.includes('BusinessAcquisitionsProFormaNetIncomeLoss'))).toBe(true);
|
expect(standardizedRows.some((row) => row.key.includes('BusinessAcquisitionsProFormaNetIncomeLoss'))).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('merges detail rows across taxonomy-version concept drift for Microsoft residuals', () => {
|
||||||
|
const aggregated = __financialTaxonomyInternals.aggregateDetailRows({
|
||||||
|
statement: 'income',
|
||||||
|
selectedPeriodIds: new Set(['2024-fy', '2025-fy']),
|
||||||
|
snapshots: [
|
||||||
|
{
|
||||||
|
...createSnapshot({
|
||||||
|
filingId: 90,
|
||||||
|
filingType: '10-K',
|
||||||
|
filingDate: '2024-07-30',
|
||||||
|
statement: 'income',
|
||||||
|
periods: [{
|
||||||
|
id: '2024-fy',
|
||||||
|
periodStart: '2023-07-01',
|
||||||
|
periodEnd: '2024-06-30',
|
||||||
|
periodLabel: 'FY24'
|
||||||
|
}]
|
||||||
|
}),
|
||||||
|
detail_rows: {
|
||||||
|
income: {
|
||||||
|
unmapped: [
|
||||||
|
{
|
||||||
|
key: 'http://fasb.org/us-gaap/2024#AdvertisingExpense',
|
||||||
|
parentSurfaceKey: 'unmapped',
|
||||||
|
label: 'Advertising Expense',
|
||||||
|
conceptKey: 'http://fasb.org/us-gaap/2024#AdvertisingExpense',
|
||||||
|
qname: 'us-gaap:AdvertisingExpense',
|
||||||
|
namespaceUri: 'http://fasb.org/us-gaap/2024',
|
||||||
|
localName: 'AdvertisingExpense',
|
||||||
|
unit: 'iso4217:USD',
|
||||||
|
values: { '2024-fy': 1_500_000_000 },
|
||||||
|
sourceFactIds: [101],
|
||||||
|
isExtension: false,
|
||||||
|
dimensionsSummary: [],
|
||||||
|
residualFlag: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'https://xbrl.microsoft.com/2024#BusinessAcquisitionsProFormaRevenue',
|
||||||
|
parentSurfaceKey: 'unmapped',
|
||||||
|
label: 'Business Acquisitions Pro Forma Revenue',
|
||||||
|
conceptKey: 'https://xbrl.microsoft.com/2024#BusinessAcquisitionsProFormaRevenue',
|
||||||
|
qname: 'msft:BusinessAcquisitionsProFormaRevenue',
|
||||||
|
namespaceUri: 'https://xbrl.microsoft.com/2024',
|
||||||
|
localName: 'BusinessAcquisitionsProFormaRevenue',
|
||||||
|
unit: 'iso4217:USD',
|
||||||
|
values: { '2024-fy': 247_442_000_000 },
|
||||||
|
sourceFactIds: [102],
|
||||||
|
isExtension: true,
|
||||||
|
dimensionsSummary: [],
|
||||||
|
residualFlag: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
balance: {},
|
||||||
|
cash_flow: {},
|
||||||
|
equity: {},
|
||||||
|
comprehensive_income: {}
|
||||||
|
}
|
||||||
|
} satisfies FilingTaxonomySnapshotRecord,
|
||||||
|
{
|
||||||
|
...createSnapshot({
|
||||||
|
filingId: 91,
|
||||||
|
filingType: '10-K',
|
||||||
|
filingDate: '2025-07-30',
|
||||||
|
statement: 'income',
|
||||||
|
periods: [{
|
||||||
|
id: '2025-fy',
|
||||||
|
periodStart: '2024-07-01',
|
||||||
|
periodEnd: '2025-06-30',
|
||||||
|
periodLabel: 'FY25'
|
||||||
|
}]
|
||||||
|
}),
|
||||||
|
detail_rows: {
|
||||||
|
income: {
|
||||||
|
unmapped: [
|
||||||
|
{
|
||||||
|
key: 'http://fasb.org/us-gaap/2025#AdvertisingExpense',
|
||||||
|
parentSurfaceKey: 'unmapped',
|
||||||
|
label: 'Advertising Expense',
|
||||||
|
conceptKey: 'http://fasb.org/us-gaap/2025#AdvertisingExpense',
|
||||||
|
qname: 'us-gaap:AdvertisingExpense',
|
||||||
|
namespaceUri: 'http://fasb.org/us-gaap/2025',
|
||||||
|
localName: 'AdvertisingExpense',
|
||||||
|
unit: 'iso4217:USD',
|
||||||
|
values: { '2025-fy': 1_700_000_000 },
|
||||||
|
sourceFactIds: [201],
|
||||||
|
isExtension: false,
|
||||||
|
dimensionsSummary: [],
|
||||||
|
residualFlag: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'https://xbrl.microsoft.com/2025#BusinessAcquisitionsProFormaRevenue',
|
||||||
|
parentSurfaceKey: 'unmapped',
|
||||||
|
label: 'Business Acquisitions Pro Forma Revenue',
|
||||||
|
conceptKey: 'https://xbrl.microsoft.com/2025#BusinessAcquisitionsProFormaRevenue',
|
||||||
|
qname: 'msft:BusinessAcquisitionsProFormaRevenue',
|
||||||
|
namespaceUri: 'https://xbrl.microsoft.com/2025',
|
||||||
|
localName: 'BusinessAcquisitionsProFormaRevenue',
|
||||||
|
unit: 'iso4217:USD',
|
||||||
|
values: { '2025-fy': 219_790_000_000 },
|
||||||
|
sourceFactIds: [202],
|
||||||
|
isExtension: true,
|
||||||
|
dimensionsSummary: [],
|
||||||
|
residualFlag: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
balance: {},
|
||||||
|
cash_flow: {},
|
||||||
|
equity: {},
|
||||||
|
comprehensive_income: {}
|
||||||
|
}
|
||||||
|
} satisfies FilingTaxonomySnapshotRecord
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const unmapped = aggregated.unmapped ?? [];
|
||||||
|
expect(unmapped).toHaveLength(2);
|
||||||
|
|
||||||
|
const advertising = unmapped.find((row) => row.label === 'Advertising Expense');
|
||||||
|
expect(advertising?.values).toEqual({
|
||||||
|
'2024-fy': 1_500_000_000,
|
||||||
|
'2025-fy': 1_700_000_000
|
||||||
|
});
|
||||||
|
|
||||||
|
const proFormaRevenue = unmapped.find((row) => row.label === 'Business Acquisitions Pro Forma Revenue');
|
||||||
|
expect(proFormaRevenue?.values).toEqual({
|
||||||
|
'2024-fy': 247_442_000_000,
|
||||||
|
'2025-fy': 219_790_000_000
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('resolves CASY-style income gaps with ordered fallbacks and tighter interest income exclusions', () => {
|
it('resolves CASY-style income gaps with ordered fallbacks and tighter interest income exclusions', () => {
|
||||||
const period = createPeriod({
|
const period = createPeriod({
|
||||||
id: '2025-fy',
|
id: '2025-fy',
|
||||||
|
|||||||
@@ -315,6 +315,54 @@ function rowHasValues(values: Record<string, number | null>) {
|
|||||||
return Object.values(values).some((value) => value !== null);
|
return Object.values(values).some((value) => value !== null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function detailConceptIdentity(row: DetailFinancialRow) {
|
||||||
|
const localName = row.localName.trim().toLowerCase();
|
||||||
|
if (localName.length > 0) {
|
||||||
|
if (row.isExtension) {
|
||||||
|
return `extension:${localName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.namespaceUri.includes('us-gaap')) {
|
||||||
|
return `us-gaap:${localName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.namespaceUri.includes('ifrs')) {
|
||||||
|
return `ifrs:${localName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefix = row.qname.split(':')[0]?.trim().toLowerCase();
|
||||||
|
if (prefix) {
|
||||||
|
return `${prefix}:${localName}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedQName = row.qname.trim().toLowerCase();
|
||||||
|
if (normalizedQName.length > 0) {
|
||||||
|
return normalizedQName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedConceptKey = row.conceptKey.trim().toLowerCase();
|
||||||
|
if (normalizedConceptKey.length > 0) {
|
||||||
|
return normalizedConceptKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return row.key.trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function detailMergeKey(row: DetailFinancialRow) {
|
||||||
|
const dimensionsKey = [...row.dimensionsSummary]
|
||||||
|
.map((value) => value.trim().toLowerCase())
|
||||||
|
.filter((value) => value.length > 0)
|
||||||
|
.sort((left, right) => left.localeCompare(right))
|
||||||
|
.join('|') || 'no-dimensions';
|
||||||
|
|
||||||
|
return [
|
||||||
|
detailConceptIdentity(row),
|
||||||
|
row.unit ?? 'no-unit',
|
||||||
|
dimensionsKey
|
||||||
|
].join('::');
|
||||||
|
}
|
||||||
|
|
||||||
const PINNED_INCOME_SURFACE_ROWS = new Set([
|
const PINNED_INCOME_SURFACE_ROWS = new Set([
|
||||||
'revenue',
|
'revenue',
|
||||||
'gross_profit',
|
'gross_profit',
|
||||||
@@ -440,9 +488,10 @@ function aggregateDetailRows(input: {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const existing = bucket.get(row.key);
|
const mergeKey = detailMergeKey(row);
|
||||||
|
const existing = bucket.get(mergeKey);
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
bucket.set(row.key, {
|
bucket.set(mergeKey, {
|
||||||
...row,
|
...row,
|
||||||
values: filteredValues,
|
values: filteredValues,
|
||||||
sourceFactIds: [...sourceFactIds],
|
sourceFactIds: [...sourceFactIds],
|
||||||
@@ -1216,6 +1265,7 @@ export const __financialTaxonomyInternals = {
|
|||||||
buildDimensionBreakdown,
|
buildDimensionBreakdown,
|
||||||
buildNormalizationMetadata,
|
buildNormalizationMetadata,
|
||||||
aggregateSurfaceRows,
|
aggregateSurfaceRows,
|
||||||
|
aggregateDetailRows,
|
||||||
mergeStructuredKpiRowsByPriority,
|
mergeStructuredKpiRowsByPriority,
|
||||||
periodSorter,
|
periodSorter,
|
||||||
selectPrimaryPeriodsByCadence,
|
selectPrimaryPeriodsByCadence,
|
||||||
|
|||||||
Reference in New Issue
Block a user