jueves, 18 de abril de 2024

78 - Crear hojas a partir de una Plantilla, para lista de destinatarios.

 Si tenemos nuestra documentación en forma de base de datos (facturación, cobranzas, documentos emitidos, etc), en algún momento necesitaremos enviar esa documentación a los destinatarios. O necesitaremos guardar en hojas separadas esa información.

En este ejemplo, parto de una lista de facturas emitidas y la idea es guardar esa información en formato de documento, por cada cliente de la lista.

Ejemplo 1: la lista no se encuentra filtrada. Se controla si el registro tiene saldo a facturar.




Sub facturando()

Dim hoC As Worksheet, hoF As Worksheet

 

'se declaran las 2 hojas del proceso

Set hoC = Sheets("Clientes")

Set hoF = Sheets("Formato")

 

'recorrer el rango a facturar

With hoC

    For i = 4 To Range("B" & Rows.Count).End(xlUp).Row

        'comprobar si tiene saldo <> 0

        If .Range("X" & i) = 0 Then GoTo sigueOtro

       

        'crear copia de la hoja Formato agregándola al final

        hoF.Copy After:=Sheets(Sheets.Count)

        On Error Resume Next

        ActiveSheet.Name = .Range("D" & i).Text

        If Err.Number > 0 Then GoTo existeHoja

sigo:

        On Error GoTo 0

        Set hoX = ActiveSheet

        'pasar los datos a la nueva hoja

        hoX.[D2] = .Range("D" & i)      'nbre clie

        hoX.[D3] = .Range("C" & i)      'cod clie

        hoX.[D4] = .Range("E" & i)      'domicilio clie

        hoX.[B6] = .Range("F" & i)      'nro fact

        hoX.[E6] = .Range("B" & i)      'fecha

       

        'evluar si hay valores en H o en I

        If .Range("H" & i) = 0 Then

            hoX.[E15] = .Range("I" & i)

        Else

            hoX.[E15] = .Range("H" & i)

        End If

       

        'concatenar col AA + AB

        hoX.[A10] = .Range("AA" & i) & " " & .Range("AB" & i)

       

        hoX.[E16] = .Range("M" & i)    'iva

        hoX.[E17] = .Range("W" & i)     'retencion

'se pasa a la fila siguiente de la hoja base

sigueOtro:

    Next i

   

End With

 

MsgBox "Fin del proceso.", , "Información"

Exit Sub

 

existeHoja:

MsgBox "Ya existe una hoja de nombre " & hoC.Range("D" & i).Text & Chr(10) & _

"El formato se guardará con nombre de hoja " & ActiveSheet.Name & ".", vbCritical

GoTo sigo

End Sub



Ejemplo 2: Se aplicará filtro a la lista. Se recorre el rango rellenando el formato solo con datos de filas filtradas. Se controla si el registro tiene saldo a facturar.

Sub facturando_Filtrado()

 

'se declaran las 2 hojas del proceso

Set hoC = Sheets("Clientes")

Set hoF = Sheets("Formato")

 

'controles previos a la salida del formato (si se aplicó filtro => si hay filas filtradas)

x = hoC.Range("B" & Rows.Count).End(xlUp).Row

If x < 4 Then

    MsgBox "No hay datos para facturar.", , "Atención"

    Exit Sub

End If

 

'recorrer el rango a facturar

With hoC

    For Each celdita In .Range("B4:B" & x).SpecialCells(xlCellTypeVisible)

        'fila de la celda visible

        i = celdita.Row

        'comprobar si tiene saldo <> 0

        If .Range("X" & i) = 0 Then GoTo sigueOtro   

        'crear copia de la hoja Formato agregándola al final

        hoF.Copy After:=Sheets(Sheets.Count)

        On Error Resume Next

        ActiveSheet.Name = .Range("D" & i).Text

        If Err.Number > 0 Then GoTo existeHoja

sigo:

        On Error GoTo 0

        Set hoX = ActiveSheet

        'pasar los datos a la nueva hoja

        hoX.[D2] = .Range("D" & i)

        hoX.[D3] = .Range("C" & i)

        hoX.[D4] = .Range("E" & i)

        hoX.[B6] = .Range("F" & i)

        hoX.[E6] = .Range("B" & i)

        If .Range("E" & i) = 0 Then

            hoX.[E15] = .Range("H" & i)

        Else

            hoX.[E15] = .Range("I" & i)

        End If

        hoX.[A10] = .Range("AA" & i) & " " & .Range("AB" & i)

        hoX.[E15] = .Range("B" & i)

        hoX.[E16] = .Range("M" & i)

        hoX.[E17] = .Range("W" & i)   

sigueOtro:

Next celdita

End With

 

MsgBox "Fin del proceso.", , "Información"

Exit Sub

 

existeHoja:

MsgBox "Ya existe una hoja de nombre " & hoC.Range("D" & i).Text & Chr(10) & _

"El formato se guardará con nombre de hoja " & ActiveSheet.Name & ".", vbCritical

GoTo sigo

End Sub


Descargar libro con las macros desde aquí o solicitarlo al correo Gmail de: cibersoft.arg

Ver video Nº 78 desde aquí.

miércoles, 10 de abril de 2024

77 - Graficando sin Gráficos.

 Si tenemos que presentar Informes de planillas con gran cantidad de filas y columnas, podemos hacer uso de un par de herramientas para graficar resultados, sin necesidad de crear Gráficos.

Modelo Nº 1:

a- En el primer grupo de Totales aplicamos Gráfico de barras.  

    Desde menú Inicio, Formato Condicional, Barra de datos, y seleccionamos un estilo a gusto.


b- En el segundo grupo, desde el mismo menú Inicio, Formato condicional, aplicamos Escalas de color, simulando un semáforo.

Nota: En la primera imagen se superpuso una Escala de color sobre un gráfico de Barras.


Modelo Nº 2:


Aquí se intenta graficar la evolución de los resultados mensuales. Para ello, desde menú Insertar optamos por el grupo Minigráficos seleccionando un estilo. En el primer grupo de valores se optó por Columnas y en el segundo por Líneas.


Se puede llamar a esta herramienta con algún rango ya seleccionado. Por ejemplo, si seleccionamos el rango de celdas donde se va a ubicar el gráfico, se nos pedirá el ingreso del rango de Datos.

Nota: una vez insertado el Minigráfico, se activará una nueva barra de herramientas que nos permitirá darle formato a gusto: color de las barras o líneas, marcar el punto más alto y el más bajo y otras opciones más. En el ejemplo, además, se le dió color de fondo a las celdas y se colocó como título las iniciales de los meses para una mejor visualización.


Modelo Nº 3:

En este modelo, el objetivo es colocar un objeto junto a los valores máximo, mínimo y coincidente con el contenido de una celda.

Para ello primero insertaremos unos objetos gráficos como imágenes o iconos (en versión Excel 365). Y luego ejecutaremos una macro para ubicar esos objetos en el Informe.

Nota: para insertar Iconos en versiones Excel 365 los invito a buscar en este Blog, la entrada de Mayo 2023


En el Editor de macros, insertamos un módulo y allí colocaremos la macro que recorrerá esta tabla colocando los objetos en el lugar que les corresponda según los valores de la tabla.

Nota: En el video Nº 77 (Graficando sin Gráficos) de mi canal, alrededor del minuto 5:50 se explica cómo obtener los nombres de los objetos para ser utilizados desde la programación.

Sub graficando_tabla()

Dim maxi As Single, mini As Single, ideal As Single

Dim cd As Range

Dim rangoTabla

 

'guardar los valores máximos y mínimos del rango

rangoTabla = Range("Préstamo[[Saldo final]]").Address

maxi = Application.WorksheetFunction.Max(Range(rangoTabla))

mini = Application.WorksheetFunction.Min(Range(rangoTabla))

ideal = [K1]      'celda donde se encuentra el valor 'ideal'

 

'se recorre el rango buscando el valor maxi y mini

For Each cd In Range(rangoTabla)

 

    'si la celda contiene el valor 'maxi' se coloca el gráfico 4 en el tope y margen izquierdo de esa celda

    If cd.Value = maxi Then

        ActiveSheet.Shapes.Range(Array("Gráfico 4")).Top = cd.Top

        ActiveSheet.Shapes.Range(Array("Gráfico 4")).Left = cd.Offset(0, 1).Left + 20

       

    ElseIf cd.Value = mini Then

        'si la celda contiene el valor 'mini' se coloca el gráfico 2 en el tope y margen izquierdo de esa celda

         ActiveSheet.Shapes.Range(Array("Gráfico 2")).Top = cd.Top

         ActiveSheet.Shapes.Range(Array("Gráfico 2")).Left = cd.Offset(0, 1).Left + 20

 

    ElseIf cd.Value = ideal Then

        'si la celda contiene el valor 'mini' se coloca la imagen en el tope y margen izquierdo de esa celda

         ActiveSheet.Shapes.Range(Array("Group 17")).Top = cd.Top

         ActiveSheet.Shapes.Range(Array("Group 17")).Left = cd.Offset(0, 1).Left + 20

    End If

Next cd

End Sub

 


Nota: En el libro que se puede descargar desde este enlace o solicitarlo al correo Gmail: cibersoft.arg encontrarán otra macro que recorre un rango común (no Tabla).

Ver video Nº 77 desde aquí.


domingo, 24 de marzo de 2024

76 - Diferencias entre Notas y Comentarios. Cómo agregarlos mediante VBA.

En entradas anteriores (Nov.2018 y Abr.2019) vimos diferentes modelos de Comentarios. Cómo formatearlos (formas, colores e imágenes) y además cómo programar en VBA el agregado o modificación de estos objetos. 

Estos temas fueron mostrados en mi canal Soluciones Excel, en los siguientes videos:

Nº 17: Agregar COMENTARIOS en hoja Excel   (no apto para versiones Excel 365)

Nº 24: Comentarios en Excel mediante programación VBA    (no apto para versiones Excel 365)

Ahora, con la llegada de la versión Excel 365, los antiguos 'comentarios' pasaron a llamarse 'Notas'. Estos objetos Notas todavía conservan la posibilidad de cambios en sus formatos (colores, formas e imagen). Y en VBA siguen llamándose Comment.

Los nuevos Comentarios en cambiono permiten el cambio de formato. Pero sí permiten el agregado de respuestas en dicho cuadro.

En esta nueva versión 365, al seleccionar una celda con comentario, se abrirá un panel lateral a la derecha mostrando el texto original y la posibilidad de agregar una respuesta que se publicará al presionar el botón verde. Y así se irán viendo los autores, fecha y texto de las diferentes respuestas.


Y en VBA, el término 'Comment' pasa ahora a llamarse CommentThreaded.

Veamos un ejemplo de cómo agregar comentarios y respuestas en VBA, ya sea en las versiones clásicas de Excel y en versión 365:

A continuación evaluaremos el cambio en las celdas de dos columnas.  

Si se trata de la columna C agregaremos una NOTA. Si la celda ya presenta una NOTA se sobrescribirá. Y si se borra la celda, también se borrará la NOTA.

En cambio si se trata de la columna I agregaremos COMENTARIOS. Si se borra la celda, se mostrará el cambio como un nuevo comentario.

 Private Sub Worksheet_Change(ByVal Target As Range)

'no se evalúan los cambios en fila 1 ni tampoco si se han seleccionado varias celdas

If Target.Count > 1 Or Target.Row = 1 Then Exit Sub


'si el cambio se da en col 3 (C) se deja solo una NOTA

If Target.Column = 3 Then


    Target.ClearComments    'otra opción: evaluar si hay una nota o no.

    Target.AddComment "Compartir este evento con Jose Luis."


    

'si el cambio se da en col I de la tabla de costos se agrega como Comentarios el nombre del usuario y el importe ingresado. 

ElseIf Target.Column = 9 Then


    'evaluar si la celda no tiene aún comentario, o sea es el primero a registrar

    If Target.CommentThreaded Is Nothing Then

        Target.AddCommentThreaded Application.UserName & "_" & Target.Value

    Else

        'si ya tiene algún comentario se agrega una 'respuesta'

        Target.CommentThreaded.AddReply Application.UserName & "_" & Target.Value

    End If

End If

End Sub



NOTA: Si utilizamos el mismo libro en diferentes versiones, los comentarios creados en versión Excel clásico se verán en Excel 365 tal como fueron creados, solo que ahora estarán en el menú 'Notas'.
En cambio los nuevos comentarios creados desde Excel 365, al pasarlos a la versión Excel clásico se verán como los de siempre (con formato) y con un aviso de parte de Microsoft, donde se informa de que los cambios realizados aquí ya no se verán como 'Respuestas' en la versión 365.



Ver video N° 76 desde aquí.


martes, 12 de marzo de 2024

75 - Ejecutar macros dinámicamente

 Las macros en Excel pueden ejecutarse de varias maneras:

- al clic de un botón ActiveX, un botón de la barra Formulario o algún control dentro de un Userform.

- al clic en algún objeto incrustado en la hoja.

- con la instrucción Call nombre_de_macro . De esta manera las llamamos desde cualquier otro proceso. Por ejemplo: al abrir un Userform deseamos primeramente ordenar una lista para rellenar algún control ComboBox o ListBox, tendremos una instrucción del tipo: Call ordena_Clientes

- desde algún evento de Libro o de Hojas.

- de modo dinámico. Es decir, que sin invocar su nombre, podremos llamar a la macro por el contenido de alguna celda o selección dentro de un desplegable.

Las macros ya estarán ubicadas en un módulo. El nombre de cada macro tendrá que coincidir con el contenido de las celdas o con los elementos de una lista desplegable si fuera el caso.

Ejemplo Nº 1:  al doble clic en celdas de meses o conceptos de Caja, se llamará a la macro según el contenido de la celda: En la hoja de Caja, se colocará el siguiente código:

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

'controla posible error al seleccionar una celda sin macro asociada.

On Error Resume Next                

'ejecuta la macro cuyo nombre coincida con el contenido de la celda activa 

Application.Run (Target.Value) 

'coloca el foco en otra celda. Aquí, 1 fila hacia abajo en la misma columna. 

Target.Offset(1, 0).Select

 

End Sub

                    


 

Ejemplo Nº 2:  al seleccionar algún elemento del desplegable, se ejecutará la macro cuyo nombre coincida con el elemento seleccionado. El código ubicado en el Userform será:

Private Sub ComboBox2_Click()
On Error Resume Next
Application.Run (ComboBox2.Text)
End Sub


                
            En uno o varios módulos tendremos las macros:

Sub INGRESOS()

MsgBox "Estoy ejecutanto la macro de INGRESOS!"

End Sub 

Sub EGRESOS()

MsgBox "Estoy ejecutanto la macro de EGRESOS!"

End Sub


Sub ENERO()

MsgBox "Estoy ejecutanto la macro de ENERO!"

End Sub

Sub FEBRERO()

MsgBox "Estoy ejecutanto la macro de FEBRERO!"

End Sub


Sub TALLER_CORTE()

MsgBox "Estoy ejecutanto la macro de TALLER_CORTE!"

End Sub

Sub TALLER_COSTURA()

MsgBox "Estoy ejecutanto la macro de TALLER_COSTURA!"

End Sub

NOTA: En caso de tener otras hojas donde los nombres, por ejemplo de Meses, aparecen en minúscula se antepondrá la función UCASE al valor de la celda.

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

Dim nbreHoja As String

If Target.Column = 3 And Target.Row > 2 Then

    nbreHoja = UCase(Target.Value)      'convertir texto en mayúsculas

    Application.Run (nbreHoja)

    Target.Offset(1, 0).Select

End If

End Sub

 


 

                    Ver video Nº 75 desde aquí.