Jira-integration: synchronize the timesheets with jira issues

An implementation of the interface IJiraTimesheetSynchronizer.
It synchronizes the timesheets of order-tasks of an existing order with jira issues.
Loops through all jira issues and creates or updates timesheets(WorkReports) for an
existing order. As a pre condition a WorkReportType with the name 'jira-connector'
must be created and configured properly prior to synchronization of timesheets.
This commit is contained in:
Miciele Ghiorghis 2012-10-24 12:05:22 +02:00 committed by Manuel Rego Casasnovas
parent 23aef762a5
commit 13b649fb93

View file

@ -0,0 +1,370 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2012 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.importers;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.NonUniqueResultException;
import org.libreplan.business.common.IAdHocTransactionService;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.costcategories.daos.ITypeOfWorkHoursDAO;
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.resources.daos.IWorkerDAO;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.business.workreports.daos.IWorkReportDAO;
import org.libreplan.business.workreports.daos.IWorkReportLineDAO;
import org.libreplan.business.workreports.daos.IWorkReportTypeDAO;
import org.libreplan.business.workreports.entities.WorkReport;
import org.libreplan.business.workreports.entities.WorkReportLine;
import org.libreplan.business.workreports.entities.WorkReportType;
import org.libreplan.business.workreports.valueobjects.DescriptionField;
import org.libreplan.business.workreports.valueobjects.DescriptionValue;
import org.libreplan.importers.jira.Issue;
import org.libreplan.importers.jira.WorkLog;
import org.libreplan.importers.jira.WorkLogItem;
import org.libreplan.web.workreports.IWorkReportModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class JiraTimesheetSynchronizer implements IJiraTimesheetSynchronizer {
private static String CODE_PREFIX = "JIRA-";
private JiraSyncInfo jiraSyncInfo;
private List<Worker> workers;
private WorkReportType workReportType;
private TypeOfWorkHours typeOfWorkHours;
@Autowired
private IWorkerDAO workerDAO;
@Autowired
private IWorkReportTypeDAO workReportTypeDAO;
@Autowired
private IWorkReportDAO workReportDAO;
@Autowired
private IWorkReportLineDAO workReportLineDAO;
@Autowired
private IWorkReportModel workReportModel;
@Autowired
private ITypeOfWorkHoursDAO typeOfWorkHoursDAO;
@Autowired
private IAdHocTransactionService adHocTransactionService;
@Override
@Transactional
public void syncJiraTimesheetWithJiraIssues(List<Issue> issues, Order order) {
startSync(issues, order);
}
/**
* Start synchronization of timesheets
*
* @param issues
* the jira issues
* @param order
* an existing order
*/
private void startSync(List<Issue> issues, Order order) {
jiraSyncInfo = new JiraSyncInfo();
workReportType = findWorkReportType("Jira-connector");
if (workReportType == null) {
return;
}
typeOfWorkHours = findTypeOfWorkHours("Default");
if (typeOfWorkHours == null) {
return;
}
workers = getWorkers();
if (workers == null && workers.isEmpty()) {
jiraSyncInfo.addSyncFailedReason("No workers found");
return;
}
String code = order.getCode() + " " + order.getImportedLabel();
WorkReport workReport = updateOrCreateWorkReport(code);
for (Issue issue : issues) {
WorkLog worklog = issue.getFields().getWorklog();
if (worklog == null) {
jiraSyncInfo.addSyncFailedReason("No worklogs found for '"
+ issue.getKey() + "'");
} else {
List<WorkLogItem> workLogItems = worklog.getWorklogs();
if (workLogItems == null || workLogItems.isEmpty()) {
jiraSyncInfo
.addSyncFailedReason("No worklog items found for '"
+ issue.getKey() + "' issue");
} else {
String codeOrderElement = CODE_PREFIX + order.getCode() + "-"
+ issue.getKey();
OrderElement orderElement = order.getOrderElement(codeOrderElement);
if (orderElement == null) {
jiraSyncInfo.addSyncFailedReason("Order element("
+ code + ") not found");
} else {
updateOrCreateWorkReportLineAndAddToWorkReport(workReport, orderElement,
workLogItems);
}
}
}
}
if (workReportModel.getWorkReport().getWorkReportLines().size() > 0) {
workReportModel.confirmSave();
}
}
/**
* Updates {@link WorkReport} if exist, if not creates new one
*
* @param code
* search criteria for workReport
* @return the workReport
*/
private WorkReport updateOrCreateWorkReport(String code) {
WorkReport workReport = findWorkReport(code);
if (workReport == null) {
workReportModel.initCreate(workReportType);
} else {
workReportModel.initEdit(workReport);
}
workReportModel.setCodeAutogenerated(false);
workReport = workReportModel.getWorkReport();
workReport.setCode(code);
return workReport;
}
/**
* Updates {@link WorkReportLine} if exist. If not creates new one and adds
* to <code>workReport</code>
*
* @param workReport
* an existing or new created workReport
* @param orderElement
* the orderElement
* @param workLogItems
* jira's workLog items to be added to workReportLine
*/
private void updateOrCreateWorkReportLineAndAddToWorkReport(WorkReport workReport,
OrderElement orderElement,
List<WorkLogItem> workLogItems) {
for (WorkLogItem workLogItem : workLogItems) {
WorkReportLine workReportLine;
try {
workReportLine = workReport
.getWorkReportLineByCode(orderElement.getCode() + "-"
+ workLogItem.getId());
} catch (InstanceNotFoundException e) {
workReportLine = WorkReportLine.create(workReport);
}
Resource resource = getWorker(workLogItem.getAuthor().getName());
if (resource != null) {
updateWorkReportLine(workReportLine, orderElement,
workLogItem, resource);
if (workReportLine.isNewObject()) {
workReport.addWorkReportLine(workReportLine);
}
}
}
}
/**
* Updates {@link WorkReportLine} with <code>workLogItem</code>
*
* @param workReportLine
* workReportLine to be updated
* @param orderElement
* the orderElement
* @param workLogItem
* workLogItem to update the workReportLine
* @param resource
* the resource
*/
private void updateWorkReportLine(WorkReportLine workReportLine,
OrderElement orderElement, WorkLogItem workLogItem,
Resource resource) {
String code = orderElement.getCode() + "-" + workLogItem.getId();
int timeSpent = workLogItem.getTimeSpentSeconds().intValue();
workReportLine.setCode(code);
workReportLine.setDate(workLogItem.getStarted());
workReportLine.setResource(resource);
workReportLine.setOrderElement(orderElement);
workReportLine.setEffort(EffortDuration
.hours(EffortDuration.Granularity.HOURS
.convertFromSeconds(timeSpent)));
workReportLine.setTypeOfWorkHours(typeOfWorkHours);
updateOrCreateDescriptionValuesAndAddToWorkReportLine(workReportLine,
workLogItem.getComment());
}
/**
* Updates {@link DescriptionValue} if exist. if not creates new one and
* adds to <code>workReportLine</code>
*
* @param workReportLine
* workReprtLinew where descriptionvalues to be added to
* @param comment
* the description value
*/
private void updateOrCreateDescriptionValuesAndAddToWorkReportLine(WorkReportLine workReportLine,
String comment) {
Set<DescriptionValue> descriptionValues = new HashSet<DescriptionValue>();
for (DescriptionField descriptionField : workReportType.getLineFields()) {
DescriptionValue descriptionValue;
try {
descriptionValue = workReportLine
.getDescriptionValueByFieldName(descriptionField
.getFieldName());
descriptionValue.setValue(comment.substring(0,
Math.min(comment.length(), 254)));
} catch (InstanceNotFoundException e) {
descriptionValue = DescriptionValue.create(
descriptionField.getFieldName(), comment);
}
descriptionValues.add(descriptionValue);
}
workReportLine.setDescriptionValues(descriptionValues);
}
/**
* Searches for {@link WorkReportType} for the specified parameter
* <code>name</code>
*
* @param name
* unique name
* @return WorkReportType if found, null otherwise
*/
private WorkReportType findWorkReportType(String name) {
try {
return workReportTypeDAO.findUniqueByName(name);
} catch (NonUniqueResultException e) {
jiraSyncInfo
.addSyncFailedReason("Work report type 'Jira-connector' is not unique");
} catch (InstanceNotFoundException e) {
jiraSyncInfo
.addSyncFailedReason("Work report type 'Jira-connector' not found");
}
return null;
}
/**
* Searches for {@link TypeOfWorkHours} for the specified parameter
* <code>name</code>
*
* @param name
* unique name
* @return TypeOfWorkHours if found, null otherwise
*/
private TypeOfWorkHours findTypeOfWorkHours(String name) {
try {
return typeOfWorkHoursDAO.findUniqueByName(name);
} catch (InstanceNotFoundException e) {
jiraSyncInfo.addSyncFailedReason("Type of workhours '" + name
+ "' not found");
}
return null;
}
/**
* Searches for {@link WorkReport} for the specified parameter
* <code>code</code>
*
* @param code
* unique code
* @return workReportType if found, null otherwise
*/
private WorkReport findWorkReport(String code) {
try {
return workReportDAO.findByCodeAnotherTransaction(code);
} catch (InstanceNotFoundException e) {
}
return null;
}
/**
* Gets all libreplan workers
*
* @return list of workers
*/
private List<Worker> getWorkers() {
return workerDAO.findAll();
}
/**
* Searches for {@link Worker} for the specified parameter <code>nif</code>
*
* @param nif
* unique id
* @return worker if found, null otherwise
*/
private Worker getWorker(String nif) {
for (Worker worker : workers) {
if (worker.getNif().equals(nif)) {
return worker;
}
}
jiraSyncInfo.addSyncFailedReason("Worker('" + nif + "') not found");
return null;
}
@Override
public JiraSyncInfo getJiraSyncInfo() {
return jiraSyncInfo;
}
}