Reporte Sprints


In [ ]:
from IPython.display import HTML
from IPython.display import display        

HTML('''<script>
code_show=true; 
function code_toggle() {
 if (code_show){
 $('div.input').hide();
 } else {
 $('div.input').show();
 }
 code_show = !code_show
} 
$( document ).ready(code_toggle);
</script>
<form action="javascript:code_toggle()"><input type="submit" value="Click aquí para ver el código"></form>''')

In [ ]:
## CONFIGURACION
SPRINT_ACTUAL = "export9.csv"  
SPRINT_ANTERIOR = "export8.csv"  
#DATE_START = "20170515"  
#DATE_END = "20170526"  
#DATES_HOLIDAYS = []  
print("CONFIGURACIÓN")
print("SPRINT ACTUAL: "+SPRINT_ACTUAL)
print("SPRINT ANTERIOR: "+SPRINT_ANTERIOR)

In [ ]:
## IMPORT AND LOADING

import pandas as pd
import math

col_names = ["#","Estado","Proyecto","Tipo","% Realizado","Tiempo estimado","Tarjeta","Versión prevista"]
new_col_names = ["Issue","Estado","Proyecto","Tipo","Porcentaje","Tiempo","Tarjeta","Version"]
col_names2 = ["#","Estado","Proyecto","Tipo","% Realizado","Tiempo estimado","Versión prevista"]
new_col_names2 = ["Issue","Estado","Proyecto","Tipo","Porcentaje","Tiempo","Version"]

grupos_tarjetas = {"SVV":"SVV",
                   "TC":"TC",
                   "MON":"SVE",
                   "SVD":"SVE",
                   "PC":"PC"}


finished_states = ["Pte Validacion","Corregida","Resuelta"]
blocked_states = ["Bloqueada"]
special_types = ["Soporte","Unexpected"]


dat = pd.read_csv(SPRINT_ACTUAL,sep=";",header=0,usecols=col_names,encoding="iso-8859-15",decimal=",")
dat = dat.rename(columns=dict(zip(col_names,new_col_names)))
datPrev = pd.read_csv(SPRINT_ANTERIOR,sep=";",header=0,usecols=col_names2,encoding="iso-8859-15",decimal=",")
datPrev = datPrev.rename(columns=dict(zip(col_names2,new_col_names2)))

dat.loc[dat["Issue"] == 14169]

Peticiones con errores

Tiempo de la tarea


In [ ]:
def check_bad_time(DF):
    if pd.isnull(DF["Tiempo"]).any() | (DF["Tiempo"] == 0).any():
        display("Lista de peticiones con tiempo inválido o 0 (eliminadas de la lista a partir de ahora)")
        index = DF.loc[(pd.isnull(dat["Tiempo"])) | (DF["Tiempo"] == 0),:].index
        display(DF.loc[index,:])
        DF.drop(index,inplace=True)
    else:
        display("Todas las peticiones tienen tiempos correctos")

print("Sprint Actual: "+SPRINT_ACTUAL)
check_bad_time(dat)
print("Sprint Anterior: "+SPRINT_ANTERIOR)
check_bad_time(datPrev)

Inconsistencias Estado/Porcentaje


In [ ]:
def check_inconsistent_state(DF):
    inconsistent = DF[(DF["Estado"].isin(finished_states)) & (DF["Porcentaje"] < 100)]
    if inconsistent.empty:
        print("Todas las peticiones tienen estado/porcentaje consistente")
    else:
        print("Lista de peticiones con inconsistencias en Estado/Porcentaje (se eliminan)")
        display(inconsistent)
        DF.drop(inconsistent.index,inplace=True)

print("Sprint Actual: "+SPRINT_ACTUAL)
check_inconsistent_state(dat)
print("Sprint Anterior: "+SPRINT_ANTERIOR)
check_inconsistent_state(datPrev)

Inconsistencias Tipo Soporte / Sprint Soporte


In [ ]:
def check_soporte(DF):
    soporte = DF[(DF["Tipo"] == "Soporte") & (~DF["Version"].str.contains("Soporte"))]
    if soporte.empty:
        print("Todas las tareas de soporte están en la sprint correcta")
    else:
        print("Lista de tareas de tipo soporte en sprint incorrecta (se mantienen)")
        display(soporte)

print("Sprint Actual: "+SPRINT_ACTUAL)
check_soporte(dat)
print("Sprint Anterior: "+SPRINT_ANTERIOR)
check_soporte(datPrev)

Inconsistencias en Tarjeta


In [ ]:
def check_tarjeta(DF):
    tarjetaNaN = DF.loc[pd.isnull(DF["Tarjeta"])]
    if tarjetaNaN.empty:
        print("Todas las peticiones tienen la tarjeta asignada")
    else:
        print("Lista de peticiones con la tarjeta no asignada (se mantienen)")
        display(tarjetaNaN)
        
print("Sprint Actual: "+SPRINT_ACTUAL)
check_tarjeta(dat)

Estadísticas por proyecto

Se calculan las horas totales del proyecto, eliminando las tareas de tipo Soporte o Unexpected.

TiempoFinalizado es el tiempo calculado a partir del porcentaje.
TiempoPendiente es la diferencia entre el tiempo real y el finalizado.


In [ ]:
#dat.groupby("Proyecto").loc["Tiempo","TiempoReal"].sum().reset_index()
# for proy in dat.Proyecto.unique():
#     print("Proyecto {:>20s} ==> {:>6.1f} horas".format(proy,dat.loc[dat["Proyecto"] == proy,"Tiempo"].sum()))

dat["TiempoFinalizado"] = dat["Tiempo"]*dat["Porcentaje"]/100;
dat["TiempoPendiente"] =dat["Tiempo"]*(100-dat["Porcentaje"])/100
datPrev["TiempoFinalizado"] = datPrev["Tiempo"]*datPrev["Porcentaje"]/100;
datPrev["TiempoPendiente"] = datPrev["Tiempo"]*(100-datPrev["Porcentaje"])/100

# Se asigna la tarjeta correcta
dat["Tarjeta"] = dat["Tarjeta"].map(grupos_tarjetas).fillna("UNK").astype(str)
#display(dat)

display(dat.groupby(["Proyecto","Version","Tarjeta"])["Tiempo","TiempoFinalizado","TiempoPendiente"].sum())

Suma de horas pendientes por Proyecto

Se suman todos los tiempos pendientes de las distintas versiones (Backlog y Sprint). No se han quitado las tareas de soporte, pero estas deberían tener como TiempoPendiente 0 por lo que no afectarían al resultado.


In [ ]:
display(dat.groupby(["Proyecto"])["Tiempo","TiempoPendiente"].sum())

Suma de horas de Soporte


In [ ]:
dat.loc[dat["Tipo"] == "Soporte",["Tiempo","TiempoFinalizado"]].sum()

Sprint Actual

Los datos siguientes se refieren al sprint actual. Horas realizadas, teniendo en cuenta las horas realizadas hasta el sprint anterior.


In [ ]:
#Extraemos solo el proyecto y los tiempos de las tareas que no están en Backlog ni Soporte
dat["TiempoSprintAnterior"] = dat["Issue"].map(datPrev.set_index("Issue")["TiempoFinalizado"]).fillna(0).astype(int)
sprint=dat[~dat["Version"].str.contains('BackLog|Soporte|Backlog')]
sprintT=sprint.groupby("Proyecto")["Tiempo","TiempoFinalizado","TiempoSprintAnterior"].sum()
sprintT["TiempoFinalizadoReal"] = sprintT["TiempoFinalizado"]-sprintT["TiempoSprintAnterior"]
display(sprintT)
display("Tiempos Totales:")
display(sprintT.sum(numeric_only=True))

Resumen Sprint


In [ ]:
print("Tiempo total realizado en este sprint:")
print("Tiempo tareas del Sprint: ")
tSprint = sprintT.sum(numeric_only=True)["TiempoFinalizadoReal"]
display(tSprint)
print("Tiempo tareas Soporte: ")
tSoporte = dat.loc[dat["Tipo"] == "Soporte",["Tiempo","TiempoFinalizado"]].sum()["TiempoFinalizado"]
display(tSoporte)
print("Tiempo Total: ")
display(tSprint+tSoporte)