#49 feat: graficos de provenance en columnas por nivel y aristas deduplicadas

This commit is contained in:
2026-08-16 02:21:41 -05:00
parent 2967ea4f4d
commit 5c91e66429
6 changed files with 166 additions and 25 deletions

View File

@@ -87,6 +87,26 @@ describe('hasAnyTerritory', () => {
const noSuppliers = [{ product: { id: 1, name: 'Panela' }, suppliers: [] }]
expect(hasAnyTerritory(noSuppliers)).toBe(false)
})
it('es true cuando hay municipio aunque el país venga null', () => {
const data = [
{
product: { id: 1, name: 'Panela' },
suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, municipality: { id: 7, name: 'Santa Bárbara' }, department: null, country: null }],
},
]
expect(hasAnyTerritory(data)).toBe(true)
})
it('es false cuando solo hay país', () => {
const data = [
{
product: { id: 1, name: 'Panela' },
suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, municipality: null, department: null, country: { id: 1, name: 'Colombia' } }],
},
]
expect(hasAnyTerritory(data)).toBe(false)
})
})
describe('buildSupplierOrganizationGraph', () => {
@@ -146,7 +166,7 @@ describe('buildSupplierOrganizationGraph', () => {
expect(graph.edges).toEqual([{ from: 'product:1', to: 'supplier:5', certain: true }])
})
it('no duplica nodos que se repiten entre productos', () => {
it('no duplica nodos ni aristas cuando se repiten entre productos', () => {
const data = [
{ product: { id: 1, name: 'Panela' }, suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, organization: { id: 3, name: 'Red' } }] },
{ product: { id: 2, name: 'Arroz' }, suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, organization: { id: 3, name: 'Red' } }] },
@@ -155,7 +175,19 @@ describe('buildSupplierOrganizationGraph', () => {
expect(graph.nodes.filter(n => n.id === 'supplier:5')).toHaveLength(1)
expect(graph.nodes.filter(n => n.id === 'organization:3')).toHaveLength(1)
expect(graph.edges).toHaveLength(4)
expect(graph.edges.filter(e => e.from === 'supplier:5' && e.to === 'organization:3')).toHaveLength(1)
expect(graph.edges).toHaveLength(3)
})
it('si el mismo par de nodos repite con distinta certeza, gana la duda', () => {
const data = [
{ product: { id: 1, name: 'Panela' }, suppliers: [{ supplier: { id: 5, name: 'A' }, organization: { id: 3, name: 'Red' } }] },
{ product: { id: 2, name: 'Arroz' }, suppliers: [{ supplier: { id: 5, name: 'A' }, organization: { id: 3, name: 'Red' } }, { supplier: { id: 6, name: 'B' }, organization: { id: 4, name: 'Coop' } }] },
]
const graph = buildSupplierOrganizationGraph(data)
expect(graph.edges.filter(e => e.from === 'supplier:5' && e.to === 'organization:3')).toHaveLength(1)
expect(edgeOf(graph, 'supplier:5', 'organization:3').certain).toBe(false)
})
it('no incluye posiciones de layout', () => {
@@ -181,7 +213,25 @@ describe('buildTerritoryGraph', () => {
expect(edgeOf(graph, 'product:1', 'supplier:5')).toEqual({ from: 'product:1', to: 'supplier:5', certain: true })
expect(edgeOf(graph, 'supplier:5', 'municipality:7')).toEqual({ from: 'supplier:5', to: 'municipality:7', certain: true })
expect(edgeOf(graph, 'municipality:7', 'department:2')).toEqual({ from: 'municipality:7', to: 'department:2', certain: true })
expect(edgeOf(graph, 'department:2', 'country:1')).toEqual({ from: 'department:2', to: 'country:1', certain: true })
})
it('no incluye nodos ni aristas de país', () => {
const graph = buildTerritoryGraph(singleSupplier)
expect(graph.nodes.map(n => n.id)).not.toContain('country:1')
expect(graph.edges.some(edge => edge.from.startsWith('country:') || edge.to.startsWith('country:'))).toBe(false)
})
it('con varios productos del mismo proveedor solo traza una línea hacia el municipio', () => {
const data = [
{ product: { id: 1, name: 'Panela' }, suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, municipality: { id: 7, name: 'Santa Bárbara' }, department: { id: 2, name: 'Antioquia' } }] },
{ product: { id: 2, name: 'Arroz' }, suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, municipality: { id: 7, name: 'Santa Bárbara' }, department: { id: 2, name: 'Antioquia' } }] },
{ product: { id: 3, name: 'Queso' }, suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, municipality: { id: 7, name: 'Santa Bárbara' }, department: { id: 2, name: 'Antioquia' } }] },
]
const graph = buildTerritoryGraph(data)
expect(graph.edges.filter(e => e.from === 'supplier:5' && e.to === 'municipality:7')).toHaveLength(1)
expect(graph.nodes.filter(n => n.id === 'municipality:7')).toHaveLength(1)
})
it('cuando los proveedores comparten municipio, el territorio es cierto desde allí', () => {
@@ -194,7 +244,6 @@ describe('buildTerritoryGraph', () => {
expect(edgeOf(graph, 'supplier:5', 'municipality:7')).toEqual({ from: 'supplier:5', to: 'municipality:7', certain: true })
expect(edgeOf(graph, 'supplier:6', 'municipality:7')).toEqual({ from: 'supplier:6', to: 'municipality:7', certain: true })
expect(edgeOf(graph, 'municipality:7', 'department:2').certain).toBe(true)
expect(edgeOf(graph, 'department:2', 'country:1').certain).toBe(true)
})
it('municipios distintos pero mismo departamento: dudoso hasta el municipio y cierto desde el departamento', () => {
@@ -206,18 +255,15 @@ describe('buildTerritoryGraph', () => {
expect(edgeOf(graph, 'supplier:6', 'municipality:8').certain).toBe(false)
expect(edgeOf(graph, 'municipality:7', 'department:2')).toEqual({ from: 'municipality:7', to: 'department:2', certain: true })
expect(edgeOf(graph, 'municipality:8', 'department:2')).toEqual({ from: 'municipality:8', to: 'department:2', certain: true })
expect(edgeOf(graph, 'department:2', 'country:1').certain).toBe(true)
})
it('municipios y departamentos distintos mantienen la duda, y el país común es cierto', () => {
it('municipios y departamentos distintos mantienen la duda', () => {
const graph = buildTerritoryGraph(twoSuppliers())
expect(edgeOf(graph, 'supplier:5', 'municipality:7').certain).toBe(false)
expect(edgeOf(graph, 'municipality:7', 'department:2').certain).toBe(false)
expect(edgeOf(graph, 'supplier:6', 'municipality:8').certain).toBe(false)
expect(edgeOf(graph, 'municipality:8', 'department:3').certain).toBe(false)
expect(edgeOf(graph, 'department:2', 'country:1')).toEqual({ from: 'department:2', to: 'country:1', certain: true })
expect(edgeOf(graph, 'department:3', 'country:1')).toEqual({ from: 'department:3', to: 'country:1', certain: true })
})
it('no crea nodos de territorio cuando el proveedor no tiene municipio', () => {