Café y Código

8. Proyecto: Automatizar un Reporte

En este proyecto integrador:

  • Construirás una macro que lee una tabla de ventas y genera un resumen por categoría.
  • Usarás variables, bucles, condicionales, rangos y una función auxiliar.
  • Aplicarás buenas prácticas: ScreenUpdating, limpieza previa y estructura en Sub separadas.

Estructura del libro de trabajo

Crea un archivo .xlsm con dos hojas:

Vista tipo Excel: la primera fila muestra las letras de columna; la primera columna muestra los números de fila. En las celdas con fórmula (=...), cada referencia lleva un color distinto. Clic en la referencia: resalta solo esa celda. Clic en el resto de la celda (por ejemplo el = o los operadores): resalta todas las celdas citadas. Repetir el mismo gesto sobre lo ya resaltado lo oculta.

Estructura del libroResumen

Nombra las hojas exactamente 'Ventas' y 'Resumen' para que el código funcione sin modificaciones.

AB
1 Nombre de la hojaContenido
2VentasTabla de datos fuente (columnas: Fecha | Producto | Categoría | Monto)
3ResumenAquí la macro escribirá los totales por categoría

Datos de ejemplo para la hoja Ventas (copia desde la fila 1):

Vista tipo Excel: la primera fila muestra las letras de columna; la primera columna muestra los números de fila. En las celdas con fórmula (=...), cada referencia lleva un color distinto. Clic en la referencia: resalta solo esa celda. Clic en el resto de la celda (por ejemplo el = o los operadores): resalta todas las celdas citadas. Repetir el mismo gesto sobre lo ya resaltado lo oculta.

Tabla fuente: hoja VentasCatálogo / datos maestros

La categoría está en la columna C (índice 3). La macro agrupará los montos por ese valor.

ABCD
1 FechaProductoCategoríaMonto
22024-01-05Laptop ProElectrónica1200.00
32024-01-07TecladoElectrónica85.00
42024-01-08Silla ergonómicaMuebles340.00
52024-01-10Monitor 27"Electrónica450.00
62024-01-12EscritorioMuebles220.00
72024-01-14Mouse inalámbricoElectrónica45.00
82024-01-15Lámpara LEDMuebles60.00
92024-01-18AudífonosElectrónica130.00
102024-01-20EstanteMuebles95.00
112024-01-22Webcam HDElectrónica75.00

Función auxiliar: SumarPorCategoria

Primero creamos una función que suma todos los montos de una categoría dada:

Modulo1.bas — función auxiliar
VBA
1 Function SumarPorCategoria(ByVal categoria As String) As Double
2 Dim hVentas As Worksheet
3 Dim ultimaFila As Long
4 Dim i As Long
5 Dim total As Double
6
7 Set hVentas = ThisWorkbook.Sheets("Ventas")
8 ultimaFila = hVentas.Cells(hVentas.Rows.Count, 1).End(xlUp).Row
9 total = 0
10
11 For i = 2 To ultimaFila
12 If hVentas.Cells(i, 3).Value = categoria Then
13 total = total + hVentas.Cells(i, 4).Value
14 End If
15 Next i
16
17 SumarPorCategoria = total
18 End Function

Sub principal: GenerarReporte

Modulo1.bas — sub principal
VBA
1 Sub GenerarReporte()
2 Dim hResumen As Worksheet
3 Dim categorias(1 To 2) As String
4 Dim i As Integer
5
6 ' Configuración inicial
7 Application.ScreenUpdating = False
8 Set hResumen = ThisWorkbook.Sheets("Resumen")
9
10 ' Limpiar resultados anteriores
11 hResumen.Range("A1:B100").ClearContents
12
13 ' Escribir encabezados
14 hResumen.Range("A1").Value = "Categoría"
15 hResumen.Range("B1").Value = "Total Ventas"
16
17 ' Lista de categorías a resumir
18 categorias(1) = "Electrónica"
19 categorias(2) = "Muebles"
20
21 ' Escribir totales por categoría
22 For i = 1 To 2
23 hResumen.Cells(i + 1, 1).Value = categorias(i)
24 hResumen.Cells(i + 1, 2).Value = SumarPorCategoria(categorias(i))
25 Next i
26
27 ' Formatear encabezado
28 With hResumen.Range("A1:B1")
29 .Font.Bold = True
30 .Interior.Color = RGB(29, 107, 68)
31 .Font.Color = RGB(255, 255, 255)
32 End With
33
34 hResumen.Activate
35 Application.ScreenUpdating = True
36 MsgBox "¡Reporte generado correctamente!"
37 End Sub

Application.ScreenUpdating = False oculta los cambios visuales mientras la macro corre, acelerando la ejecución. Siempre restáuralo a True al terminar.

Practica en Excel

Abre Excel (o copia los datos con el botón de la tabla), sigue los pasos y comprueba el resultado en tu hoja.

  1. Crea el archivo .xlsm con las hojas "Ventas" y "Resumen".
  2. Copia la tabla de datos de ejemplo en la hoja Ventas (desde A1).
  3. Abre el editor VBA (Alt+F11), inserta un módulo y pega ambos procedimientos.
  4. Ejecuta GenerarReporte() desde Alt+F8 → GenerarReporte.
  5. Verifica que la hoja Resumen muestra los totales de Electrónica y Muebles con encabezado verde.
  6. Agrega 3 filas más a Ventas con una nueva categoría "Papelería", añádela al array y al bucle.
  7. Vuelve a ejecutar y confirma que el resumen incluye Papelería.

Ejercicios prácticos

15 ejercicios para ampliar y personalizar el proyecto de automatización de reportes.

Básico

1. Ejecutar y verificar

Crea el libro con las hojas "Ventas" y "Resumen", copia los datos de ejemplo y ejecuta GenerarReporte. Verifica que Electrónica suma 1985 y Muebles suma 715.

Ver solución

Electrónica: 1200 + 85 + 450 + 45 + 130 + 75 = 1985
Muebles: 340 + 220 + 60 + 95 = 715

Si los números coinciden, la macro funciona correctamente.

2. Agregar categoría Papelería

Añade 3 filas con categoría "Papelería" (montos: 30, 55, 80) a la hoja Ventas. Modifica el array categorias y el bucle para incluir esta nueva categoría en el reporte.

Ver solución
GenerarReporte — array ampliado
VBA
1 Dim categorias(1 To 3) As String
2 categorias(1) = "Electrónica"
3 categorias(2) = "Muebles"
4 categorias(3) = "Papelería"
5 ' El bucle For i = 1 To 3 ya lo cubre automáticamente

3. Cambiar color del encabezado

Modifica el bloque With hResumen.Range("A1:B1") para que el encabezado tenga fondo azul marino (RGB(0, 32, 96)) con texto blanco.

Ver solución
Fragmento de GenerarReporte
VBA
1 With hResumen.Range("A1:B1")
2 .Font.Bold = True
3 .Interior.Color = RGB(0, 32, 96)
4 .Font.Color = RGB(255, 255, 255)
5 End With

4. Mostrar total general

Después de escribir los totales por categoría, agrega una fila de Total General que sume todos los montos de la columna B en la hoja Resumen.

Ver solución
Al final de GenerarReporte
VBA
1 Dim filaTotal As Long
2 filaTotal = 2 + UBound(categorias)
3 hResumen.Cells(filaTotal, 1).Value = "TOTAL"
4 hResumen.Cells(filaTotal, 2).Formula = "=SUM(B2:B" & (filaTotal - 1) & ")"
5 hResumen.Cells(filaTotal, 1).Font.Bold = True
6 hResumen.Cells(filaTotal, 2).Font.Bold = True

5. Ancho de columnas automático

Al final de GenerarReporte, ajusta automáticamente el ancho de las columnas A y B de la hoja Resumen con AutoFit.

Ver solución
Final de GenerarReporte
VBA
1 hResumen.Columns("A:B").AutoFit

Intermedio

6. Categorías dinámicas

En lugar de declarar el array con categorías fijas, reescribe la lógica para que la macro detecte automáticamente todas las categorías únicas de la columna C y las use en el reporte.

Ver solución
Modulo1 — categorías dinámicas
VBA
1 Sub GenerarReporteDinamico()
2 Dim hVentas As Worksheet, hResumen As Worksheet
3 Dim ultimaFila As Long, i As Long, j As Long
4 Dim categorias() As String
5 Dim numCats As Integer
6 Dim catActual As String, yaExiste As Boolean
7
8 Set hVentas = ThisWorkbook.Sheets("Ventas")
9 Set hResumen = ThisWorkbook.Sheets("Resumen")
10 Application.ScreenUpdating = False
11 hResumen.Range("A1:B200").ClearContents
12
13 ultimaFila = hVentas.Cells(hVentas.Rows.Count, 1).End(xlUp).Row
14 numCats = 0
15 ReDim categorias(1 To 1)
16
17 For i = 2 To ultimaFila
18 catActual = hVentas.Cells(i, 3).Value
19 yaExiste = False
20 For j = 1 To numCats
21 If categorias(j) = catActual Then yaExiste = True: Exit For
22 Next j
23 If Not yaExiste Then
24 numCats = numCats + 1
25 ReDim Preserve categorias(1 To numCats)
26 categorias(numCats) = catActual
27 End If
28 Next i
29
30 hResumen.Range("A1").Value = "Categoría"
31 hResumen.Range("B1").Value = "Total"
32 For i = 1 To numCats
33 hResumen.Cells(i + 1, 1).Value = categorias(i)
34 hResumen.Cells(i + 1, 2).Value = SumarPorCategoria(categorias(i))
35 Next i
36
37 hResumen.Columns("A:B").AutoFit
38 Application.ScreenUpdating = True
39 MsgBox "Reporte con " & numCats & " categorías generado."
40 End Sub

7. Filtrar por mes

Agrega un parámetro mesFiltro As Integer a SumarPorCategoria para que solo sume ventas del mes indicado (usa Month(Cells(i,1).Value)).

Ver solución
Modulo1
VBA
1 Function SumarPorCategoriaYMes(ByVal categoria As String, ByVal mesFiltro As Integer) As Double
2 Dim hVentas As Worksheet
3 Dim ultimaFila As Long, i As Long, total As Double
4 Set hVentas = ThisWorkbook.Sheets("Ventas")
5 ultimaFila = hVentas.Cells(hVentas.Rows.Count, 1).End(xlUp).Row
6 total = 0
7 For i = 2 To ultimaFila
8 If hVentas.Cells(i, 3).Value = categoria Then
9 If Month(hVentas.Cells(i, 1).Value) = mesFiltro Then
10 total = total + hVentas.Cells(i, 4).Value
11 End If
12 End If
13 Next i
14 SumarPorCategoriaYMes = total
15 End Function

8. Contar ventas por categoría

Agrega una columna C "Cantidad" al reporte que muestre cuántas ventas (filas) tiene cada categoría, no el monto total.

Ver solución
Función auxiliar
VBA
1 Function ContarPorCategoria(ByVal categoria As String) As Long
2 Dim hVentas As Worksheet
3 Dim ultimaFila As Long, i As Long, cuenta As Long
4 Set hVentas = ThisWorkbook.Sheets("Ventas")
5 ultimaFila = hVentas.Cells(hVentas.Rows.Count, 1).End(xlUp).Row
6 cuenta = 0
7 For i = 2 To ultimaFila
8 If hVentas.Cells(i, 3).Value = categoria Then cuenta = cuenta + 1
9 Next i
10 ContarPorCategoria = cuenta
11 End Function

En GenerarReporte, agrega hResumen.Range("C1").Value = "Cantidad" y hResumen.Cells(i+1, 3).Value = ContarPorCategoria(categorias(i)).

9. Ordenar el reporte por total descendente

Después de escribir todos los datos en la hoja Resumen, ordena el rango de datos (sin encabezado) por la columna B de mayor a menor usando el método Sort.

Ver solución
Al final de GenerarReporte
VBA
1 Dim rngDatos As Range
2 Dim filaFin As Long
3 filaFin = 1 + UBound(categorias)
4 Set rngDatos = hResumen.Range("A2:B" & filaFin)
5 rngDatos.Sort Key1:=hResumen.Range("B2"), Order1:=xlDescending, Header:=xlNo

10. Botón para ejecutar la macro

En la hoja Resumen, inserta una forma (rectángulo redondeado) con el texto "Generar Reporte" y asígnale la macro GenerarReporte. Indica los pasos en el editor VBA y en Excel.

Ver solución

Pasos:

  1. En la hoja Resumen, ve a Insertar → Formas → Rectángulo redondeado.
  2. Dibuja la forma y escribe el texto "Generar Reporte".
  3. Haz clic derecho sobre la forma → Asignar macro.
  4. Selecciona GenerarReporte y acepta.

También puedes hacer esto desde VBA:

Crear botón por código
VBA
1 Sub AgregarBoton()
2 Dim ws As Worksheet
3 Dim btn As Shape
4 Set ws = ThisWorkbook.Sheets("Resumen")
5 Set btn = ws.Shapes.AddShape(msoShapeRoundedRectangle, 10, 10, 150, 40)
6 btn.TextFrame.Characters.Text = "Generar Reporte"
7 btn.OnAction = "GenerarReporte"
8 End Sub

Avanzado

11. Calcular ticket promedio

Agrega una columna D "Promedio" al reporte que muestre el monto promedio por venta de cada categoría (total / cantidad). Formatea las celdas con 2 decimales.

Ver solución
En GenerarReporte
VBA
1 ' Encabezado
2 hResumen.Range("D1").Value = "Promedio"
3 ' Dentro del bucle For i = 1 To numCats:
4 Dim total As Double, cantidad As Long
5 total = SumarPorCategoria(categorias(i))
6 cantidad = ContarPorCategoria(categorias(i))
7 If cantidad > 0 Then
8 hResumen.Cells(i + 1, 4).Value = total / cantidad
9 Else
10 hResumen.Cells(i + 1, 4).Value = 0
11 End If
12 hResumen.Cells(i + 1, 4).NumberFormat = "0.00"

12. Exportar resumen a hoja nueva

Al final de GenerarReporte, copia el rango de la hoja Resumen a una hoja nueva llamada "Reporte_YYYYMMDD" (con la fecha de hoy en el nombre) para conservar un histórico.

Ver solución
Final de GenerarReporte
VBA
1 Dim nombreHoja As String
2 Dim wsHistorico As Worksheet
3 nombreHoja = "Reporte_" & Format(Date, "YYYYMMDD")
4
5 ' Eliminar hoja previa del mismo día si existe
6 On Error Resume Next
7 Application.DisplayAlerts = False
8 ThisWorkbook.Sheets(nombreHoja).Delete
9 Application.DisplayAlerts = True
10 On Error GoTo 0
11
12 Set wsHistorico = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
13 wsHistorico.Name = nombreHoja
14 hResumen.UsedRange.Copy wsHistorico.Range("A1")
15 MsgBox "Histórico guardado en hoja: " & nombreHoja

13. Insertar gráfico de barras

Después de generar el resumen, crea un gráfico de barras (xlBarClustered) en la hoja Resumen que muestre las categorías y sus totales.

Ver solución
Agregar gráfico al reporte
VBA
1 Sub AgregarGrafico()
2 Dim hResumen As Worksheet
3 Dim cht As ChartObject
4 Dim filaFin As Long
5
6 Set hResumen = ThisWorkbook.Sheets("Resumen")
7 filaFin = hResumen.Cells(hResumen.Rows.Count, 1).End(xlUp).Row
8
9 ' Eliminar gráfico previo si existe
10 Dim co As ChartObject
11 For Each co In hResumen.ChartObjects
12 co.Delete
13 Next co
14
15 Set cht = hResumen.ChartObjects.Add(Left:=200, Top:=10, Width:=350, Height:=220)
16 With cht.Chart
17 .SetSourceData hResumen.Range("A1:B" & filaFin)
18 .ChartType = xlBarClustered
19 .HasTitle = True
20 .ChartTitle.Text = "Ventas por Categoría"
21 .SeriesCollection(1).Name = "Total"
22 End With
23 End Sub

14. Progreso con barra de estado

Cuando la macro procese muchas categorías, muestra el progreso en la barra de estado de Excel (Application.StatusBar) con el formato "Procesando: Electrónica (1/5)…". Al terminar, restaura Application.StatusBar = False.

Ver solución
Dentro del bucle For i
VBA
1 Application.StatusBar = "Procesando: " & categorias(i) & " (" & i & "/" & numCats & ")..."
2 ' ... resto del código del bucle
3
4 ' Al salir del bucle:
5 Application.StatusBar = False

15. Reporte con evento automático

Combina todo: usa un evento Worksheet_Change en la hoja Ventas para que, cada vez que se agregue un valor en la columna D (Monto), se ejecute automáticamente GenerarReporteDinamico y actualice el resumen en tiempo real.

Ver solución
Módulo de hoja Ventas
VBA
1 Private Sub Worksheet_Change(ByVal Target As Range)
2 ' Solo reaccionar si se edita la columna D (Monto)
3 If Target.Column = 4 Then
4 Application.EnableEvents = False
5 Application.ScreenUpdating = False
6 Call GenerarReporteDinamico
7 Application.ScreenUpdating = True
8 Application.EnableEvents = True
9 End If
10 End Sub

Nota: asegúrate de que GenerarReporteDinamico también tenga ScreenUpdating y EnableEvents desactivados internamente, o usa la versión simplificada sin esos controles para evitar conflictos.

Pon a prueba tus conocimientos

Ko-fi
Donaciones
Apoyá cafeycodigo con un café en Ko-fi. Colaboradores: insignia, muro y zona exclusiva.