¿Cómo gestionar bolsa de horas en Jira? Aquí te explicamos cómo controlar las horas invertidas por proyecto, en un portafolio de proyectos grande; en nuestro caso el servicio especializado en herramientas Atlassian que ofrecemos en Deiser a grandes empresas en España. Sigue leyendo!
La gestión de servicios puede ser abrumadora, por eso es importante utilizar las herramientas adecuadas. En Deiser gestionamos bolsa de horas en Jira, añadiendo Projectrak (antes Profields) y ScriptRunner for Jira a la ecuación. Estas dos apps disponibles en el Marketplace de Atlassian nos han permitido obtener el máximo provecho de Jira, y por defecto, el valor que entregamos a nuestros clientes a través de nuestro servicio.
En Jira gestionamos bolsas de horas con la ayuda de Projectrak, una app para el seguimiento de proyectos que nos permite almacenar, personalizar, visualizar y centralizar información específica de distintos proyectos, y ScriptRunner for Jira nos permite personalizar y automatizar la herramienta.
Un servicio especializado en Atlassian que ofrecemos en Deiser con el que gestionamos el total de horas contratadas por nuestros clientes, productos soportados en este servicio, comentarios de facturación, usuarios implicados por parte del cliente, fecha de finalización de la bolsa, etc., una importante capacidad de gestión prácticamente personalizada.
En esta publicación de blog, contamos cómo automatizamos el control de las peticiones que han entrado en bolsas que no tienen horas o que han caducado, y la evolución que han alcanzado gracias a nuevas incorporaciones en el equipo y el proceso constante de transformación empresarial de Deiser.
Ten en cuenta lo siguiente antes de empezar
Para identificar las peticiones en bolsas caducadas o sin horas, además de Projectrak y el propio Jira necesitamos hacer uso de Script Runner for Jira, actualmente las versiones que nosotros tenemos instaladas son las siguientes:
Hasta ahora el control que hacíamos era muy manual con los campos personalizados de Projectrak y un gadget que posteriormente puede ser insertado en un dashboard de Jira. Los campos que necesitamos son:
Para controlar las horas restantes por proyecto, creamos un dashboard en Jira donde visualizamos el cálculo automático que hace la herramienta de los días restantes por proyecto, utilizando un gadget de Projectrak llamado "Project Time Sheet Report":
Para controlar la expiración de cada proyecto disponíamos de un campo de Projectrak de tipo Script en el que se podía ver en cada proyecto si está expirado o no:
Para agilizar la gestión y que fuese mucho más fácil su seguimiento, en Projectrak creamos un campo personalizado de tipo Script llamado "Support Pack Info".
En la configuración de Script Runner el campo tiene el siguiente script:import com.atlassian.jira.bc.issue.worklog.TimeTrackingConfiguration
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.project.Project
import com.atlassian.jira.util.JiraDurationUtils
import com.deiser.jira.profields.api.field.DatetimeField
import com.deiser.jira.profields.api.field.FieldService
import com.deiser.jira.profields.api.field.OriginalEstimateField
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import java.text.SimpleDateFormat
@WithPlugin("com.deiser.jira.profields")
@PluginModule
FieldService fieldService
def SUPPORT_PACK_EXPIRATION_DATE_ID = 10
def SUPPORT_PACK_SIZE_ID = 1
Calendar getCalendarWithoutTime(Date date) {
Calendar calendar = new GregorianCalendar()
calendar.setTime(date)
calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0)
calendar.set(Calendar.MILLISECOND, 0)
return calendar;
}
String isExpired(Date expirationDate) {
if (expirationDate == null) {
return false
}
def expiration = getCalendarWithoutTime(expirationDate)
def actual = getCalendarWithoutTime(new Date())
if (actual.compareTo(expiration) > 0) {
def simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy")
return String.format('''
<p>Expired.</p>
<blockquote>Expiration date: %s</blockquote>
'''
, simpleDateFormat.format(expirationDate))
}
return null
}
String hasRemaining(Project project, Long total) {
def issueManager = ComponentAccessor.issueManager
def timeTrackingConfiguration = ComponentAccessor.getOSGiComponentInstanceOfType(TimeTrackingConfiguration.class)
def jiraAuthenticationContext = ComponentAccessor.jiraAuthenticationContext
def prettyDurationFormatter = new JiraDurationUtils.PrettyDurationFormatter(
timeTrackingConfiguration.hoursPerDay,
timeTrackingConfiguration.daysPerWeek,
jiraAuthenticationContext.i18nHelper)
Long timeSpent = (Long)issueManager.getIssueIdsForProject(project.id).sum { issueManager.getIssueObject((Long)it).timeSpent ?: 0L }
total = total ? (Long)(total / 1000L) : 0L
timeSpent = timeSpent ?: 0L
if (total <= timeSpent) {
return String.format('''
<p>No available hours</p>
<blockquote>
Total hours: %s</br>
Time spent: %s
</blockquote>
'''
, prettyDurationFormatter.format(total, jiraAuthenticationContext.locale)
, prettyDurationFormatter.format(timeSpent, jiraAuthenticationContext.locale))
}
return null
}
try{
Issue currentIssue = issue
def supportPackExpirationDateField = (DatetimeField) fieldService.get(SUPPORT_PACK_EXPIRATION_DATE_ID)
def supportPackSizeField = (OriginalEstimateField) fieldService.get(SUPPORT_PACK_SIZE_ID)
def supportPackExpirationDate = supportPackExpirationDateField.getValueInProject(currentIssue.projectObject)
def supportPackSize = supportPackSizeField.getValueInProject(currentIssue.projectObject)
def expired = isExpired(supportPackExpirationDate)
def hasHours = hasRemaining(currentIssue.projectObject, supportPackSize)
def message = '''
<div class="aui-message aui-message-warning">
<p class="title"><strong>%s!</strong></p>
%s
</div>
'''
if (expired && !hasHours) {
return String.format(message, "Warning!", expired)
} else if (!expired && hasHours) {
return String.format(message, "Warning!", hasHours)
} else if (expired && hasHours) {
return String.format(message, "Warning!", expired + hasHours)
} else {
return null
}
} catch(def e){
log.error("Error while calculating support pack info: " + e.getClass().getName())
}
Las variables SUPPORT_PACK_EXPIRATION_DATE_ID y SUPPORT_PACK_SIZE_ID tienen el ID de los campos de control.
Para extraer los IDs de los campos de Projectrak al igual que con Jira, es necesario verificar la URL.
Aquí está el quid de la cuestión, al tener esta nueva configuración cada vez que un cliente nos hace una petición del servicio de bolsa de horas, si bien está caducada o no tiene horas el sistema, el sistema nos devolverá un mensaje de forma automática tal como podemos ver a continuación:
La acción de incluir Projectrak y ScriptRunner nos evita la tarea "manual" de monitorizar las Bolsas de Horas de forma periódica.
Con esta configuración es posible incentivar la transparencia de cara al cliente ya que si bien es posible que el equipo pueda conocer el estado de la Bolsa de Horas ha caducado o si no le quedan horas el cliente también podrá estar al tanto de esta información.
Éste es sólo un ejemplo de cómo Jira hace más fácil nuestro día a día, mejorando la comunicación interna y de cara al cliente.
Si en tu caso tienes claro todo que te gustaría hacer con tu instancia de Jira pero no tienes el tiempo suficiente para hacerlo por ti mismo, cuenta con nosotros, somos Atlassian Platinum Solution Partner Enterprise y Atlassian Marketplace Platinum Partners en España y tenemos la experiencia y capacidad de adaptar Jira o cualquier producto Atlassian a las necesidades específicas de tu equipo y empresa para que puedas alcanzar los objetivos plateados.
En Deiser tenemos nuestra propia forma de gestionar proyectos, y te podemos ayudar a gestionar los tuyos. Nos adaptamos a los procesos que deba enfrentar cada flujo de trabajo, utilizando las herramientas de Atlassian.
Conoce en detalle los servicios que ofrecemos y descubre cómo te podemos ayudar haciendo clic en el botón a continuación:
These Stories on Projectrak para Jira
No Comments Yet
Let us know what you think