Observando el rechazo masivo a usar Project para programar obras surgió esta macro.
Las entradas son las tareas, su comienzo, su duración y su costo tanto programado como real.
La salida automática es la integración del diagrama de gantt con sus barras, la curva de inversión, la curva de avance y la interposición de los recursos en la escala del tiempo en la parte superior, y por supuesto la fecha de hoy transversal a toda la información gráfica. Todo en la misma pantalla y en simultáneo.
Una vez escritas las actividades, y las fechas de inicio y de fin de cada una vamos a necesitar un auxiliar llamado
que arme por nosotros el calendario hacia la derecha con un formato que sea entendible a simple vista, claro que para esto entiendo que la fecha de partida será la fecha más pequeña del programa y la máxima la fecha más lejana de todo el programa.
nos ayudará a crear dentro de este calendario las barras correspondientes a las tareas pero, teniendo en cuenta que a cada tarea será asignada un recurso, al mismo tiempo en la parte superior aparecerá la gráfica de quién será el responsable de esa tarea ocupando la franja en la línea de tiempo.
Pero si pienso que también quiero una curva de avance y que no pueden convivir dos informaciones en la misma celda, la solución está en crear por medio de la macro las barras como shapes contenidas en las celdas a las que corresponda y al mismo tiempo escribir dentro de la celda el valor que le corresponda. En resumen digo que solo vamos a ver la barra, pero que está en su interior esconde el avance fraccionado.
Pero como fraccionamos ese porcentaje? Aca voy a buscar suplantar una gran mentira por mentiritas más pequeñas con alguna certezas. Es decir que en vez de dividir el precio calculado en el plazo propuesto lo que sería un avance lineal voy a proponer que puede o no haber anticipo financiero, que puedo o no haber una retención para el final de la tarea y que todo lo que ocurra post anticipo y antes de la devolución de la retención será planeado con algún criterio de rendimiento. Y es aquí donde traigo algunas variantes con el solo objetivo de intentar acercarme un poquito más a la realidad.
Option Explicit
Dim Bcle As Long
Private Sub Worksheet_Change(ByVal Target As Range)
Inicio:
Dim Hoja As String: Hoja = "Gantt"
Dim Barra_Name As String
Dim Fecha_I As Date
Dim Fecha_F As Date
Dim Dias As Long
Dim barra As Shape
Dim Min_Fecha As Date
Dim Temp_Fecha As Date
Dim C_Ini As Long: Dim C_Fi As Long
Dim L_Barra As Double
Dim P_Recurso As String
'Defino columnas
Dim Colum_P_I As Long: Colum_P_I = 11
Dim Colum_P_D As Long: Colum_P_D = 12
Dim Colum_P_F As Long: Colum_P_F = 13
Dim Colum_R_I As Long: Colum_R_I = 14
Dim Colum_R_D As Long: Colum_R_D = 15
Dim Colum_R_F As Long: Colum_R_F = 16
Dim Colum_Inicio_Gantt As Long: Colum_Inicio_Gantt = 22
'Defino datos comunes
Min_Fecha = Sheets(Hoja).Cells(4, 8)
Ctrl_G.Obtener_Rango Hoja, Target.Row, 1, Barra_Name
Select Case Target.Column
Case Colum_P_I To Colum_P_F
Barra_Name = "P_" & Barra_Name
P_Recurso = "T_" & Excel.Sheets(Hoja).Cells(Target.Row, 1)
Fecha_I = Sheets(Hoja).Cells(Target.Row, Colum_P_I)
Dias = Sheets(Hoja).Cells(Target.Row, Colum_P_D)
Fecha_F = Sheets(Hoja).Cells(Target.Row, Colum_P_F): Fecha_F = Fecha_I + Dias
If Target.Column = Colum_P_I Then
If Not Sheets(Hoja).Cells(Target.Row, Colum_P_F) = Fecha_F Then Sheets(Hoja).Cells(Target.Row, Colum_P_F) = Fecha_F
Sheets(Hoja).Cells(Target.Row, Colum_P_D) = Dias
End If
If Target.Column = Colum_P_F Then
Dias = Fecha_F - Fecha_I
If Not Sheets(Hoja).Cells(Target.Row, Colum_P_D) = Dias Then Sheets(Hoja).Cells(Target.Row, Colum_P_D) = Dias
End If
If Target.Column = Colum_P_D Then
If Not Sheets(Hoja).Cells(Target.Row, Colum_P_F) = Fecha_F Then Sheets(Hoja).Cells(Target.Row, Colum_P_F) = Fecha_F
For Each barra In Sheets(Hoja).Shapes
If barra.Name = Barra_Name Then: barra.Delete: Exit For
Next
'Borro la barra del recurso
For Each barra In Sheets(Hoja).Shapes
If barra.Name = P_Recurso Then: barra.Delete: Exit For
Next
If Sheets(Hoja).Cells(Target.Row, Colum_P_I) = 0 Or Sheets(Hoja).Cells(Target.Row, Colum_P_F) = 0 Then Exit Sub
Temp_Fecha = Sheets(Hoja).Cells(Target.Row, Colum_P_F)
C_Ini = Colum_Inicio_Gantt + (Fecha_I - Min_Fecha): C_Fi = C_Ini + Dias
L_Barra = Sheets(Hoja).Range(Cells(Target.Row, C_Ini), Cells(Target.Row, C_Fi)).Width
C_Fi = L_Barra
C_Ini = Val(Excel.Sheets(Hoja).Cells(Target.Row, C_Ini).Left)
'Ctrl_G.Barras_Gantt Val(C_Ini), Target.Top + Target.Height / 6, Val(C_Fi), Target.Height / 1.5, Excel.Sheets(Hoja).Cells(Target.Row, 2), Barra_Name
Dim Cel_I, Cel_F As Long
' modifico costos en gantt
Display_Excel.Proteger_Hoja Excel.ThisWorkbook.Name, "Gantt", False
Sheets("Gantt").Range(Cells(Target.Row, Colum_Inicio_Gantt), Cells(Target.Row, 365)).Clear
Display_Excel.Proteger_Hoja Excel.ThisWorkbook.Name, "Gantt", False
Cel_I = Colum_Inicio_Gantt + (Fecha_I - Min_Fecha)
Cel_F = Cel_I + Dias
For Bcle = Cel_I To Cel_F
Display_Excel.Proteger_Hoja Excel.ThisWorkbook.Name, "Gantt", False
Cells(Target.Row, Bcle) = Cells(Target.Row, 6) / (Cel_F - Cel_I + 1)
Next
Formato.Format_H_Text Excel.ActiveWorkbook.Name, Hoja, Cells(Target.Row, Cel_I), Cells(Target.Row, Cel_F), 4
'Escribo el recurso
If Len(Excel.Sheets(Hoja).Cells(Target.Row, 8)) > 0 Then
Cel_I = Colum_Inicio_Gantt + (Fecha_I - Min_Fecha)
Cel_F = Cel_I + Dias
'Verifico de no pisarlo
Dim H_Recursos As Double: H_Recursos = Excel.Sheets("Gantt").Range(Cells(1, 1), Cells(4, 1)).Height
Dim Cant_Max_Rec As Double: Cant_Max_Rec = 0 'se obtiene de fila 1
For Bcle = Cel_I To Cel_F
If Excel.Sheets(Hoja).Cells(1, Bcle) > Cant_Max_Rec Then Cant_Max_Rec = Val(Excel.Sheets(Hoja).Cells(1, Bcle))
Next
Dim barra_Altura As Long: barra_Altura = H_Recursos / Cant_Max_Rec
Dim Recurso_Y As Double: Recurso_Y = 0
Dim Recurso_Y_min As Double: Recurso_Y_min = H_Recursos - barra_Altura
For Each barra In Sheets(Hoja).Shapes
If Left(barra.Name, 1) = "T" Then
If barra.Left > C_Ini And barra.Left < (C_Ini + C_Fi) Or barra.Left + barra.Width > C_Ini And barra.Left + barra.Width < (C_Ini + C_Fi) Then
barra.Height = barra_Altura
If barra.Height + barra.Top >= Recurso_Y Then Recurso_Y = barra.Height + barra.Top
If barra.Height < Recurso_Y_min Then Recurso_Y_min = barra.Height
End If
End If
Next
MsgBox Recurso_Y_min & "-" & Recurso_Y
Display_Excel.Proteger_Hoja Excel.ThisWorkbook.Name, "Gantt", False
'Ctrl_G.Barras_Gantt Val(C_Ini), ((Temp_N - 1) * barra_Altura), Val(C_Fi), Val(barra_Altura), Excel.Sheets(Hoja).Cells(Target.Row, 8), P_Recurso
'Ctrl_G.Barras_Gantt Val(C_Ini), Recurso_Y, Val(C_Fi), Val(barra_Altura), Excel.Sheets(Hoja).Cells(Target.Row, 8), P_Recurso
End If
End If
Case Colum_R_I To Colum_R_F
Barra_Name = "R_" & Barra_Name
Fecha_I = Sheets(Hoja).Cells(Target.Row, Colum_R_I)
Dias = Sheets(Hoja).Cells(Target.Row, Colum_R_D)
Fecha_F = Sheets(Hoja).Cells(Target.Row, Colum_R_F): Fecha_F = Fecha_I + Dias
If Target.Column = Colum_R_I Then
If Not Sheets(Hoja).Cells(Target.Row, Colum_R_F) = Fecha_F Then Sheets(Hoja).Cells(Target.Row, Colum_R_F) = Fecha_F
Sheets(Hoja).Cells(Target.Row, Colum_R_D) = Dias
End If
If Target.Column = Colum_R_F Then
Dias = Fecha_F - Fecha_I
If Not Sheets(Hoja).Cells(Target.Row, Colum_R_D) = Dias Then Sheets(Hoja).Cells(Target.Row, Colum_R_D) = Dias
End If
If Target.Column = Colum_R_D Then
If Not Sheets(Hoja).Cells(Target.Row, Colum_R_F) = Fecha_F Then Sheets(Hoja).Cells(Target.Row, Colum_R_F) = Fecha_F
For Each barra In Sheets(Hoja).Shapes
If barra.Name = Barra_Name Then: barra.Delete: Exit For
Next
If Sheets(Hoja).Cells(Target.Row, Colum_R_I) = 0 Or Sheets(Hoja).Cells(Target.Row, Colum_R_F) = 0 Then Exit Sub
Temp_Fecha = Sheets(Hoja).Cells(Target.Row, Colum_R_F)
C_Ini = Colum_Inicio_Gantt + (Fecha_I - Min_Fecha): C_Fi = C_Ini + Dias
L_Barra = Sheets(Hoja).Range(Cells(Target.Row, C_Ini), Cells(Target.Row, C_Fi)).Width
C_Fi = L_Barra
C_Ini = Val(Excel.Sheets(Hoja).Cells(Target.Row, C_Ini).Left)
'Ctrl_G.Barras_Gantt Val(C_Ini), Target.Top + Target.Height / 4, Val(C_Fi), Target.Height / 2, Excel.Sheets(Hoja).Cells(Target.Row, 2), Barra_Name
End If
End Select
End Sub
Public Sub Ubicar_Avance()
Display_Excel.Proteger_Hoja Excel.ThisWorkbook.Name, "Gantt", False
Dim Grafico As Shape
'Dim Titulo As Range
Dim T As Double
Dim L As Double
Dim H As Double
Dim W As Double
For Each Grafico In Excel.Sheets("Gantt").Shapes
With Excel.Sheets("Gantt")
Select Case Grafico.Name
Case "G_Desagregado": T = .Cells(5, 1).Top
L = .Cells(5, 1).Left
H = .Cells(6, 3).Top - Grafico.Top
W = .Cells(6, 3).Left - Grafico.Left
Grafico.Locked = True
Case "G_Separador": T = .Cells(1, 21).Top
L = .Cells(1, 21).Left
H = .Cells(43, 22).Top - Grafico.Top
W = .Cells(43, 22).Left - Grafico.Left
Grafico.Locked = True
Case "G_Licitacion": T = .Cells(5, 3).Top
L = .Cells(5, 3).Left
H = .Cells(6, 8).Top - Grafico.Top
W = .Cells(6, 8).Left - Grafico.Left
Grafico.Locked = True
Case "G_Titulo": T = .Cells(1, 1).Top
L = .Cells(1, 1).Left
H = .Cells(3, 21).Top - Grafico.Top
W = .Cells(3, 21).Left - Grafico.Left
Grafico.Locked = True
Case "G_Prog": T = .Cells(5, 8).Top
L = .Cells(5, 8).Left
H = .Cells(6, 14).Top - Grafico.Top
W = .Cells(6, 14).Left - Grafico.Left
Grafico.Locked = True
Case "G_Real": T = .Cells(5, 14).Top
L = .Cells(5, 14).Left
H = .Cells(6, 21).Top - Grafico.Top
W = .Cells(6, 21).Left - Grafico.Left
Grafico.Locked = True
End Select
End With
If Grafico.Name = "Deagregado" Then
Grafico.Top = Excel.Sheets("Gantt").Cells(5, 1).Top
Grafico.Left = Excel.Sheets("Gantt").Cells(5, 1).Left
Grafico.Height = Excel.Sheets("Gantt").Cells(6, 1).Top - Grafico.Top
Grafico.Width = Excel.Sheets("Gantt").Cells(6, 3).Left - Grafico.Left
Grafico.Locked = False
End If
If Grafico.Name = "G_Titulo_Gantt" Then
Grafico.Top = Excel.Sheets("Gantt").Cells(1, 1).Top
Grafico.Left = Excel.Sheets("Gantt").Cells(6, 22).Left
Grafico.Height = Excel.Sheets("Gantt").Cells(5, 1).Top - Grafico.Top
Grafico.Width = Excel.Sheets("Gantt").Cells(43, 182).Left - Grafico.Left
Grafico.Locked = True
End If
If Grafico.Name = "G_Avances" Then
Grafico.Top = Excel.Sheets("Gantt").Cells(6, 1).Top
Grafico.Left = Excel.Sheets("Gantt").Cells(6, 22).Left
Grafico.Height = Excel.Sheets("Gantt").Cells(43, 1).Top - Grafico.Top
Grafico.Width = Excel.Sheets("Gantt").Cells(43, 182).Left - Grafico.Left
Grafico.Locked = True
End If
Next
Display_Excel.Proteger_Hoja Excel.ThisWorkbook.Name, "Gantt", True
End Sub
Public Function Obtener_Max_Min_Date_Partes()
Dim Temp_Range As Variant
Dim Bcle As Long
Dim Min_Date As Date
Dim Max_Dateb As Date
Dim Max_Row As Long
Ctrl_G.Obtener_Ultima_fila "Partes $", Max_Row
Ctrl_G.Capturar_Mtz_Total "Partes $", Temp_Range, 2, 2, 2, Max_Row
For Bcle = 1 To UBound(Temp_Range)
If Bcle = 1 Then Max_Dateb = Temp_Range(Bcle, 1)
If Bcle = 1 Then Min_Date = Temp_Range(Bcle, 1)
If Temp_Range(Bcle, 1) > Max_Dateb Then: Max_Dateb = Temp_Range(Bcle, 1)
If Temp_Range(Bcle, 1) < Min_Date And Temp_Range(Bcle, 1) > 0 Then: Min_Date = Temp_Range(Bcle, 1)
Next
Ctrl_G.Obtener_Ultima_fila "Gantt", Max_Row
Ctrl_G.Capturar_Mtz_Total "Gantt", Temp_Range, 6, 6, 5, Max_Row
For Bcle = 1 To UBound(Temp_Range)
If Temp_Range(Bcle, 1) < Min_Date And Temp_Range(Bcle, 1) > 0 Then: Min_Date = Temp_Range(Bcle, 1)
Next
Ctrl_G.Capturar_Mtz_Total "Gantt", Temp_Range, 8, 8, 5, Max_Row
For Bcle = 1 To UBound(Temp_Range)
If Temp_Range(Bcle, 1) > Max_Dateb Then: Max_Dateb = Temp_Range(Bcle, 1)
Next
Ctrl_G.Capturar_Mtz_Total "Gantt", Temp_Range, 9, 9, 5, Max_Row
For Bcle = 1 To UBound(Temp_Range)
If Temp_Range(Bcle, 1) < Min_Date And Temp_Range(Bcle, 1) > 0 Then: Min_Date = Temp_Range(Bcle, 1)
Next
Ctrl_G.Capturar_Mtz_Total "Gantt", Temp_Range, 11, 11, 5, Max_Row
For Bcle = 1 To UBound(Temp_Range)
If Temp_Range(Bcle, 1) > Max_Dateb Then: Max_Dateb = Temp_Range(Bcle, 1)
Next
Sheets("Gantt").Cells(1, 5) = Min_Date
Sheets("Gantt").Cells(2, 5) = Max_Dateb
Armar_Calendario
End Function
Si te interesa dale al boton G+, comenta, participa...
Y escribime para enviarte el ejemplo!