CR + Tooltips + Promedios
This commit is contained in:
+76
-10
@@ -24,6 +24,11 @@ const config = {
|
||||
qaTotalTimeQa: 'customfield_10825',
|
||||
qaLastDurQa: 'customfield_10826',
|
||||
timesReturned: 'customfield_11217',
|
||||
spFinalReal: 'customfield_11216',
|
||||
crEntry: 'customfield_10818',
|
||||
crTotalTime: 'customfield_10819',
|
||||
enCursoEntry: 'customfield_10815',
|
||||
enCursoTotalTime: 'customfield_10816',
|
||||
},
|
||||
jql: process.env.JIRA_JQL || 'project = ${PROJECT} AND ${FIELD_SP_ESTIMATE} is not EMPTY ORDER BY updated DESC',
|
||||
api: {
|
||||
@@ -99,7 +104,9 @@ function buildFieldsList() {
|
||||
config.fields.spEstimate, config.fields.spFinal, config.fields.developer,
|
||||
config.fields.qaAssignee, config.fields.qaEntryRtqa, config.fields.qaTotalTimeRtqa,
|
||||
config.fields.qaLastDurRtqa, config.fields.qaEntryQa, config.fields.qaTotalTimeQa,
|
||||
config.fields.qaLastDurQa, config.fields.timesReturned,
|
||||
config.fields.qaLastDurQa, config.fields.timesReturned, config.fields.spFinalReal,
|
||||
config.fields.crEntry, config.fields.crTotalTime, config.fields.enCursoEntry,
|
||||
config.fields.enCursoTotalTime,
|
||||
].join(',');
|
||||
}
|
||||
|
||||
@@ -116,15 +123,17 @@ function processIssues(issues) {
|
||||
const now = new Date();
|
||||
|
||||
const qaData = {
|
||||
tickets: 0,
|
||||
ticketsReturned: 0,
|
||||
totalTimeQa: 0,
|
||||
totalTimeRtqa: 0,
|
||||
monthlyTotalQa: {},
|
||||
monthlyCountQa: {},
|
||||
monthlyTotalRtqa: {},
|
||||
monthlyCountRtqa: {},
|
||||
issues: [],
|
||||
tickets: 0, ticketsReturned: 0, totalTimeQa: 0, totalTimeRtqa: 0,
|
||||
monthlyTotalQa: {}, monthlyCountQa: {}, monthlyTotalRtqa: {}, monthlyCountRtqa: {}, issues: [],
|
||||
};
|
||||
|
||||
const deliveryData = {
|
||||
totalLeadTimeDays: 0, totalCycleTimeDays: 0, doneTicketsLead: 0, doneTicketsCycle: 0,
|
||||
doneSpOriginal: 0, doneSpFinal: 0
|
||||
};
|
||||
|
||||
const crData = {
|
||||
tickets: 0, totalTimeCr: 0, issues: [], monthlyTotalCr: {}, monthlyCountCr: {}, stalledIssues: []
|
||||
};
|
||||
|
||||
for (const issue of issues) {
|
||||
@@ -138,6 +147,10 @@ function processIssues(issues) {
|
||||
} else {
|
||||
devs = ['Sin asignar'];
|
||||
}
|
||||
|
||||
const INACTIVE_DEVS = ['Felipe Esposito', 'heiner', 'Ciro Bruno'];
|
||||
devs = devs.filter(d => !INACTIVE_DEVS.includes(d));
|
||||
if (devs.length === 0) continue;
|
||||
|
||||
const sp = (f[config.fields.spFinal] != null ? f[config.fields.spFinal] : f[config.fields.spEstimate]) ?? 0;
|
||||
const statusKey = f.status?.statusCategory?.key ?? 'new';
|
||||
@@ -167,6 +180,26 @@ function processIssues(issues) {
|
||||
monthlyDone[month][dev] = (monthlyDone[month][dev] ?? 0) + sp;
|
||||
}
|
||||
}
|
||||
|
||||
// Delivery Metrics
|
||||
const createdDate = f.created ? new Date(f.created) : null;
|
||||
const resolvedDate = f.resolutiondate ? new Date(f.resolutiondate) : null;
|
||||
const enCursoDate = f[config.fields.enCursoEntry] ? new Date(f[config.fields.enCursoEntry]) : null;
|
||||
const spOriginal = f[config.fields.spEstimate] || 0;
|
||||
const spReal = f[config.fields.spFinalReal] != null ? f[config.fields.spFinalReal] : spOriginal;
|
||||
|
||||
if (resolvedDate) {
|
||||
if (createdDate) {
|
||||
deliveryData.totalLeadTimeDays += (resolvedDate - createdDate) / (1000 * 60 * 60 * 24);
|
||||
deliveryData.doneTicketsLead++;
|
||||
}
|
||||
if (enCursoDate) {
|
||||
deliveryData.totalCycleTimeDays += (resolvedDate - enCursoDate) / (1000 * 60 * 60 * 24);
|
||||
deliveryData.doneTicketsCycle++;
|
||||
}
|
||||
deliveryData.doneSpOriginal += spOriginal;
|
||||
deliveryData.doneSpFinal += spReal;
|
||||
}
|
||||
}
|
||||
|
||||
issuesList.push({ id: issue.id, key: issue.key, summary: f.summary, status: statusKey, sp, devs, creMonth });
|
||||
@@ -195,6 +228,25 @@ function processIssues(issues) {
|
||||
qaData.monthlyTotalRtqa[qaMonth] = (qaData.monthlyTotalRtqa[qaMonth] || 0) + timeRtqaMin;
|
||||
qaData.monthlyCountRtqa[qaMonth] = (qaData.monthlyCountRtqa[qaMonth] || 0) + 1;
|
||||
}
|
||||
|
||||
const timeCrMin = f[config.fields.crTotalTime] ?? 0;
|
||||
if (timeCrMin > 0) {
|
||||
crData.tickets++;
|
||||
crData.totalTimeCr += timeCrMin;
|
||||
if (qaMonth) {
|
||||
crData.monthlyTotalCr[qaMonth] = (crData.monthlyTotalCr[qaMonth] || 0) + timeCrMin;
|
||||
crData.monthlyCountCr[qaMonth] = (crData.monthlyCountCr[qaMonth] || 0) + 1;
|
||||
}
|
||||
crData.issues.push({ key: issue.key, summary: f.summary, timeCr: minsToHrs(timeCrMin), status: statusKey });
|
||||
}
|
||||
|
||||
const crEntryDate = f[config.fields.crEntry];
|
||||
if (crEntryDate && !isDone && !f[config.fields.qaEntryRtqa]) {
|
||||
const daysInCr = (now - new Date(crEntryDate)) / (1000 * 60 * 60 * 24);
|
||||
if (daysInCr > 2) {
|
||||
crData.stalledIssues.push({ key: issue.key, summary: f.summary, days: Math.round(daysInCr * 10)/10 });
|
||||
}
|
||||
}
|
||||
|
||||
if (isInProgress && f.updated) {
|
||||
const days = (now - new Date(f.updated)) / (1000 * 60 * 60 * 24);
|
||||
@@ -221,9 +273,23 @@ function processIssues(issues) {
|
||||
}
|
||||
}
|
||||
|
||||
const monthlyAvgCr = {};
|
||||
for (const m of Object.keys(crData.monthlyTotalCr)) monthlyAvgCr[m] = minsToHrs(crData.monthlyTotalCr[m] / crData.monthlyCountCr[m]);
|
||||
|
||||
return {
|
||||
lastUpdated: new Date().toISOString(),
|
||||
assigneeData, monthlyDone, issuesList, warnings,
|
||||
deliveryData: {
|
||||
avgLeadTime: deliveryData.doneTicketsLead > 0 ? Math.round(deliveryData.totalLeadTimeDays / deliveryData.doneTicketsLead) : 0,
|
||||
avgCycleTime: deliveryData.doneTicketsCycle > 0 ? Math.round(deliveryData.totalCycleTimeDays / deliveryData.doneTicketsCycle) : 0,
|
||||
spOriginal: deliveryData.doneSpOriginal,
|
||||
spFinal: deliveryData.doneSpFinal,
|
||||
spDeviationPct: deliveryData.doneSpOriginal > 0 ? ((deliveryData.doneSpFinal - deliveryData.doneSpOriginal) / deliveryData.doneSpOriginal * 100).toFixed(1) : 0
|
||||
},
|
||||
crData: {
|
||||
...crData, monthlyAvgCr,
|
||||
avgTimeCr: crData.tickets > 0 ? minsToHrs(crData.totalTimeCr / crData.tickets) : 0
|
||||
},
|
||||
qaData: {
|
||||
...qaData, monthlyAvgQa, monthlyAvgRtqa,
|
||||
avgTimeQa: qaData.tickets > 0 ? minsToHrs(qaData.totalTimeQa / qaData.tickets) : 0,
|
||||
|
||||
Reference in New Issue
Block a user