tim-connector: check if connector values are invalid and more

Better error handling:
* check if connector connection values are valid
* New ConnectorException
* New .zul file to show import/export failed/success information
* All files modified affected by these changes
This commit is contained in:
miciele Ghiorghis 2013-03-13 16:46:51 +01:00 committed by Manuel Rego Casasnovas
parent 9325470d3d
commit 3891048f00
17 changed files with 443 additions and 54 deletions

View file

@ -19,6 +19,8 @@
package org.libreplan.business.common.entities;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -118,4 +120,29 @@ public class Connector extends BaseEntity {
"Y");
}
/**
* Check if connector's connections values are valid
*
* @return true if connection values are valid
*/
public boolean areConnectionValuesValid() {
String serverUrl = getPropertiesAsMap().get(
PredefinedConnectorProperties.SERVER_URL);
try {
new URL(serverUrl);
} catch (MalformedURLException e) {
return false;
}
if (StringUtils.isBlank(getPropertiesAsMap().get(
PredefinedConnectorProperties.USERNAME))) {
return false;
}
if (StringUtils.isBlank(getPropertiesAsMap().get(
PredefinedConnectorProperties.PASSWORD))) {
return false;
}
return true;
}
}

View file

@ -0,0 +1,33 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2013 St. Antoniusziekenhuis
*
* 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.business.common.entities;
/**
* Exception to ecapsulate connector(values) exceptions
*
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
*/
public class ConnectorException extends Exception {
public ConnectorException(String message) {
super(message);
}
}

View file

@ -14,7 +14,7 @@
<property name="name" column="name" not-null="true" />
<list name="properties" table="connector_property">
<list name="properties" table="connector_property" lazy="false">
<key column="connector_id" />
<list-index column="connector_property_position" />

View file

@ -19,6 +19,9 @@
package org.libreplan.importers;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.libreplan.business.common.entities.ConnectorException;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.ApplicationContext;
@ -30,6 +33,8 @@ import org.springframework.scheduling.quartz.QuartzJobBean;
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
*/
public class ExportTimesheetToTimJob extends QuartzJobBean {
private static final Log LOG = LogFactory
.getLog(ExportTimesheetToTimJob.class);
@Override
protected void executeInternal(JobExecutionContext context)
@ -40,7 +45,14 @@ public class ExportTimesheetToTimJob extends QuartzJobBean {
IExportTimesheetsToTim exportTimesheetsToTim = (IExportTimesheetsToTim) applicationContext
.getBean("exportTimesheetsToTim");
exportTimesheetsToTim.exportTimesheets();
try {
exportTimesheetsToTim.exportTimesheets();
LOG.info("Export scuccessful: "
+ exportTimesheetsToTim.getExportProcessInfo()
.isSuccessful());
} catch (ConnectorException e) {
LOG.error("Export timesheet to Tim failed", e);
}
}
}

View file

@ -33,6 +33,7 @@ import org.libreplan.business.common.IOnTransaction;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.daos.IConnectorDAO;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
import org.libreplan.business.common.entities.PredefinedConnectors;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
@ -91,47 +92,67 @@ public class ExportTimesheetsToTim implements IExportTimesheetsToTim {
@Autowired
private IOrderDAO orderDAO;
private TimImpExpInfo timImpExpInfo;
/**
* Action name
*/
private static final String EXPORT = "Export";
@Override
@Transactional(readOnly = true)
public void exportTimesheets() {
String name = PredefinedConnectors.TIM.getName();
Connector connector = connectorDAO.findUniqueByName(name);
public void exportTimesheets() throws ConnectorException {
Connector connector = getTimConnector();
if (connector == null) {
return;
throw new ConnectorException("Tim connector not found");
}
if (!connector.areConnectionValuesValid()) {
throw new ConnectorException(
"Connection values of Tim connector are invalid");
}
timImpExpInfo = new TimImpExpInfo(EXPORT);
List<Order> orders = orderDAO.getOrders();
for (Order order : orders) {
OrderSyncInfo orderSyncInfo = orderSyncInfoDAO
.findLastSynchronizedInfoByOrderAndConnectorId(order,
name);
OrderSyncInfo orderSyncInfo = getOrderLastSyncInfo(order);
if (orderSyncInfo == null) {
LOG.warn("Order '" + order.getName()
+ "' is not yet synchronized");
timImpExpInfo.addFailedReason("Order '" + order.getName()
+ "' is not yet synchronized");
} else {
boolean result = exportTimesheets(orderSyncInfo.getKey(),
LOG.info("Exporting '" + order.getName() + "'");
exportTimesheets(orderSyncInfo.getKey(),
orderSyncInfo.getOrder(), connector);
LOG.info("Export successful: " + result);
}
}
}
@Override
@Transactional(readOnly = true)
public boolean exportTimesheets(String productCode, Order order) {
public void exportTimesheets(String productCode, Order order)
throws ConnectorException {
if (productCode == null || productCode.isEmpty()) {
throw new RuntimeException("Product code should not be empty");
}
if (order == null) {
throw new RuntimeException("Order should not be empty");
}
Connector connector = connectorDAO
.findUniqueByName(PredefinedConnectors.TIM.getName());
Connector connector = getTimConnector();
if (connector == null) {
throw new RuntimeException("Tim connector not found");
throw new ConnectorException("Tim connector not found");
}
return exportTimesheets(productCode, order, connector);
if (!connector.areConnectionValuesValid()) {
throw new ConnectorException(
"Connection values of Tim connector are invalid");
}
timImpExpInfo = new TimImpExpInfo(EXPORT);
exportTimesheets(productCode, order, connector);
}
/**
@ -146,7 +167,7 @@ public class ExportTimesheetsToTim implements IExportTimesheetsToTim {
*
* @return true if export is succeeded, false otherwise
*/
private boolean exportTimesheets(String productCode, Order order,
private void exportTimesheets(String productCode, Order order,
Connector connector) {
Map<String, String> properties = connector.getPropertiesAsMap();
@ -165,8 +186,12 @@ public class ExportTimesheetsToTim implements IExportTimesheetsToTim {
dateNrOfDaysBack.toDateTimeAtStartOfDay().toDate(), new Date(),
true);
if (workReportLines == null || workReportLines.isEmpty()) {
LOG.warn("No work reportlines are found");
return false;
LOG.warn("No work reportlines are found for order: '"
+ order.getName() + "'");
timImpExpInfo
.addFailedReason("No work reportlines are found for order: '"
+ order.getName() + "'");
return;
}
List<TimeRegistrationDTO> timeRegistrationDTOs = new ArrayList<TimeRegistrationDTO>();
@ -181,7 +206,9 @@ public class ExportTimesheetsToTim implements IExportTimesheetsToTim {
if (timeRegistrationDTOs.isEmpty()) {
LOG.warn("Unable to crate timeregistration for request");
return false;
timImpExpInfo
.addFailedReason("Unable to crate timeregistration for request");
return;
}
TimeRegistrationRequestDTO timeRegistrationRequestDTO = new TimeRegistrationRequestDTO();
@ -191,12 +218,20 @@ public class ExportTimesheetsToTim implements IExportTimesheetsToTim {
.sendRequestReceiveResponse(url, userName, password,
timeRegistrationRequestDTO, TimeRegistrationResponseDTO.class);
if (timeRegistrationResponseDTO == null) {
LOG.error("No response or exception in response");
timImpExpInfo
.addFailedReason("No response or exception in response");
return;
}
if (isRefsListEmpty(timeRegistrationResponseDTO.getRefs())) {
LOG.warn("Registration response with empty refs");
return false;
timImpExpInfo
.addFailedReason("Registration response with empty refs");
return;
}
saveSyncInfoOnAnotherTransaction(productCode, order);
return true;
}
/**
@ -254,6 +289,8 @@ public class ExportTimesheetsToTim implements IExportTimesheetsToTim {
worker = workerDAO.findByCode(workerCode);
} catch (InstanceNotFoundException e) {
LOG.warn("Worker \"" + workerCode + "\" not found!");
timImpExpInfo.addFailedReason("Worker \"" + workerCode
+ "\" not found!");
return null;
}
@ -289,4 +326,17 @@ public class ExportTimesheetsToTim implements IExportTimesheetsToTim {
order, PredefinedConnectors.TIM.getName());
}
/**
* finds and returns a Tim connector
*/
private Connector getTimConnector() {
return connectorDAO
.findUniqueByName(PredefinedConnectors.TIM.getName());
}
@Override
public TimImpExpInfo getExportProcessInfo() {
return timImpExpInfo;
}
}

View file

@ -20,6 +20,7 @@
package org.libreplan.importers;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderSyncInfo;
@ -43,15 +44,20 @@ public interface IExportTimesheetsToTim {
* the Tim's productCode
* @param order
* an existing order
* @throws ConnectorException
* if connector is not valid
*/
boolean exportTimesheets(String productCode, Order order);
void exportTimesheets(String productCode, Order order) throws ConnectorException;
/**
* Loops through all existing {@link Order}s and searches for last
* synchronized order. if found, start exporting the time sheets of that
* order to Tim SOAP server. if not found write info to the log file.
*
* @throws ConnectorException
* if connector is not valid
*/
void exportTimesheets();
void exportTimesheets() throws ConnectorException;
/**
* Gets the most recent synchronized time sheet info
@ -62,4 +68,9 @@ public interface IExportTimesheetsToTim {
*/
OrderSyncInfo getOrderLastSyncInfo(Order order);
/**
* Returns export process info, success of fail info
*/
TimImpExpInfo getExportProcessInfo();
}

View file

@ -21,6 +21,7 @@ package org.libreplan.importers;
import org.libreplan.business.calendars.entities.CalendarException;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorException;
/**
* Import Rosters from Tim SOAP server using {@link TimSoapClient} and updates
@ -38,6 +39,14 @@ public interface IImportRosterFromTim {
*
* If worker calendar exception already exists it will be removed and added
* new one, in other cases a new calendar exception will be created
*
* @throws ConnectorException
* if connector is not valid
*/
void importRosters();
void importRosters() throws ConnectorException;
/**
* Returns import process info, success of fail info
*/
TimImpExpInfo getImportProcessInfo();
}

View file

@ -41,6 +41,7 @@ import org.libreplan.business.common.IOnTransaction;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.daos.IConnectorDAO;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
import org.libreplan.business.common.entities.PredefinedConnectors;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
@ -103,6 +104,13 @@ public class ImportRosterFromTim implements IImportRosterFromTim {
@Qualifier("subclass")
private IBaseCalendarModel baseCalendarModel;
private TimImpExpInfo timImpExpInfo;
/**
* Action name
*/
private static final String IMPORT = "Import";
/**
* Search criteria for roster exception days in RESPONSE message
* {@link RosterDTO}
@ -124,18 +132,24 @@ public class ImportRosterFromTim implements IImportRosterFromTim {
@Override
@Transactional
public void importRosters() {
public void importRosters() throws ConnectorException {
Connector connector = connectorDAO
.findUniqueByName(
PredefinedConnectors.TIM.getName());
.findUniqueByName(PredefinedConnectors.TIM.getName());
if (connector == null) {
return;
throw new ConnectorException("Tim Connector not found");
}
if (!connector.areConnectionValuesValid()) {
throw new ConnectorException(
"Connection values of Tim connector are invalid");
}
Map<String, String> properties = connector.getPropertiesAsMap();
String url = properties.get(PredefinedConnectorProperties.SERVER_URL);
String userName = properties
.get(PredefinedConnectorProperties.USERNAME);
String password = properties
.get(PredefinedConnectorProperties.PASSWORD);
@ -149,14 +163,16 @@ public class ImportRosterFromTim implements IImportRosterFromTim {
String departmentIds = properties
.get(PredefinedConnectorProperties.TIM_DEPARTAMENTS_IMPORT_ROSTER);
if (StringUtils.isEmpty(departmentIds)) {
if (StringUtils.isBlank(departmentIds)) {
LOG.warn("No departments configured");
return;
throw new ConnectorException("No departments configured");
}
String[] departmentIdsArray = StringUtils.stripAll(StringUtils.split(
departmentIds, ","));
timImpExpInfo = new TimImpExpInfo(IMPORT);
for (String department : departmentIdsArray) {
LOG.info("Department: " + department);
RosterRequestDTO rosterRequestDTO = createRosterRequest(department,
@ -165,12 +181,18 @@ public class ImportRosterFromTim implements IImportRosterFromTim {
.sendRequestReceiveResponse(url, userName, password,
rosterRequestDTO, RosterResponseDTO.class);
updateWorkersCalendarException(rosterResponseDTO,
productivityFactor);
if (rosterResponseDTO != null) {
updateWorkersCalendarException(rosterResponseDTO,
productivityFactor);
} else {
LOG.error("No valid response for department " + department);
timImpExpInfo
.addFailedReason("No valid response for department "
+ department);
}
}
}
/**
* updates workers Exception calendar
*
@ -190,6 +212,8 @@ public class ImportRosterFromTim implements IImportRosterFromTim {
updateCalendarException(rosterExceptions);
} else {
LOG.info("No roster-exceptions found in the response");
timImpExpInfo
.addFailedReason("No roster-exceptions found in the response");
}
return null;
}
@ -217,6 +241,8 @@ public class ImportRosterFromTim implements IImportRosterFromTim {
worker = workerDAO.findUniqueByNif(workerCode);
} catch (InstanceNotFoundException e) {
LOG.warn("Worker \"" + workerCode + "\" not found!");
timImpExpInfo.addFailedReason("Worker \"" + workerCode
+ "\" not found!");
}
if (worker != null) {
List<RosterDTO> list = entry.getValue();
@ -331,6 +357,7 @@ public class ImportRosterFromTim implements IImportRosterFromTim {
private CalendarExceptionType getCalendarExceptionType(String name) {
if (name == null || name.isEmpty()) {
LOG.error("Exception name should not be empty");
timImpExpInfo.addFailedReason("Exception name should not be empty");
return null;
}
try {
@ -345,6 +372,7 @@ public class ImportRosterFromTim implements IImportRosterFromTim {
return calendarExceptionTypeDAO.findUniqueByName(nameToSearch);
} catch (InstanceNotFoundException e) {
LOG.error("Calendar exceptionType not found", e);
timImpExpInfo.addFailedReason("Calendar exceptionType not found");
}
return null;
}
@ -437,4 +465,9 @@ public class ImportRosterFromTim implements IImportRosterFromTim {
rosterDTO.setConcept(false);
return rosterDTO;
}
@Override
public TimImpExpInfo getImportProcessInfo() {
return timImpExpInfo;
}
}

View file

@ -19,6 +19,9 @@
package org.libreplan.importers;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.libreplan.business.common.entities.ConnectorException;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.config.BeanDefinition;
@ -35,6 +38,8 @@ import org.springframework.stereotype.Component;
@Component
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class ImportRosterFromTimJob extends QuartzJobBean {
private static final Log LOG = LogFactory
.getLog(ImportRosterFromTimJob.class);
@Override
protected void executeInternal(JobExecutionContext context)
@ -45,7 +50,13 @@ public class ImportRosterFromTimJob extends QuartzJobBean {
IImportRosterFromTim importRosterFromTim = (IImportRosterFromTim) applicationContext
.getBean("importRosterFromTim");
importRosterFromTim.importRosters();
try {
importRosterFromTim.importRosters();
LOG.info("Import scuccessful: "
+ importRosterFromTim.getImportProcessInfo().isSuccessful());
} catch (ConnectorException e) {
LOG.error("Import roster from Tim failed", e);
}
}

View file

@ -0,0 +1,79 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2013 St. Antoniusziekenhuis
*
* 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.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Keeps track the success/failure of Tim's import and/or export process
*
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
*/
public class TimImpExpInfo {
/**
* action, import or export process
*/
private String action;
/**
* Holds failed reasons
*/
private List<String> failedReasons = new ArrayList<String>();
public TimImpExpInfo(String action) {
this.action = action;
}
/**
* Returns the action
*/
public String getAction() {
return action;
}
/**
* Adds the specified <code>reason</code> to <code>failedReasons<code> list
*
* @param reason
* reason why import/export failed
*/
public void addFailedReason(String reason) {
failedReasons.add(reason);
}
/**
* Is import or export succeeded
*
* @return true if <code>failedReasons</code> is empty
*/
public boolean isSuccessful() {
return failedReasons.isEmpty();
}
/**
* returns reasons why import or export failed
*/
public List<String> getFailedReasons() {
return Collections.unmodifiableList(failedReasons);
}
}

View file

@ -22,9 +22,11 @@ package org.libreplan.web.common;
import java.util.List;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.importers.TimImpExpInfo;
/**
* Contract for {@link JobSchedulerModel}.
@ -55,9 +57,16 @@ public interface IJobSchedulerModel {
*
* @param jobSchedulerConfiguration
* the job configuration
* @throws ConnectorException
* if connector is not valid
*/
void doManual(JobSchedulerConfiguration jobSchedulerConfiguration);
void doManual(JobSchedulerConfiguration jobSchedulerConfiguration)
throws ConnectorException;
/**
* Returns import/export info. Failure or success info
*/
TimImpExpInfo getImportExportInfo();
/**
* Prepares for create a new {@link JobSchedulerConfiguration}.

View file

@ -23,18 +23,24 @@ import static org.libreplan.web.I18nHelper._;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.common.entities.JobClassNameEnum;
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.importers.TimImpExpInfo;
import org.quartz.CronExpression;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.SuspendNotAllowedException;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
@ -46,7 +52,9 @@ import org.zkoss.zul.Label;
import org.zkoss.zul.Popup;
import org.zkoss.zul.Row;
import org.zkoss.zul.RowRenderer;
import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.api.Textbox;
import org.zkoss.zul.api.Window;
/**
* Controller for job scheduler manager
@ -174,7 +182,13 @@ public class JobSchedulerController extends
@Override
public void onEvent(Event event) throws Exception {
jobSchedulerModel.doManual(jobSchedulerConfiguration);
try {
jobSchedulerModel.doManual(jobSchedulerConfiguration);
shwoImpExpInfo();
} catch (ConnectorException e) {
messagesForUser.showMessage(Level.ERROR,
_(e.getMessage()));
}
}
}));
hbox.appendChild(Util.createEditButton(new EventListener() {
@ -195,6 +209,27 @@ public class JobSchedulerController extends
};
}
private void shwoImpExpInfo() {
Map<String, Object> args = new HashMap<String, Object>();
TimImpExpInfo timImpExpInfo = jobSchedulerModel.getImportExportInfo();
args.put("action", _(timImpExpInfo.getAction()));
args.put("showSuccess", timImpExpInfo.isSuccessful());
args.put("failedReasons",
new SimpleListModel(timImpExpInfo.getFailedReasons()));
Window timImpExpInfoWindow = (Window) Executions.createComponents(
"/orders/_timImpExpInfo.zul", null, args);
try {
timImpExpInfoWindow.doModal();
} catch (SuspendNotAllowedException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
/**
* returns the next fire time for the specified job in
* {@link JobSchedulerConfiguration}

View file

@ -24,6 +24,7 @@ import java.util.List;
import org.libreplan.business.common.daos.IConnectorDAO;
import org.libreplan.business.common.daos.IJobSchedulerConfigurationDAO;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.common.entities.JobClassNameEnum;
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
@ -31,6 +32,7 @@ import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.importers.IExportTimesheetsToTim;
import org.libreplan.importers.IImportRosterFromTim;
import org.libreplan.importers.ISchedulerManager;
import org.libreplan.importers.TimImpExpInfo;
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
@ -67,6 +69,8 @@ public class JobSchedulerModel implements IJobSchedulerModel {
@Autowired
private IExportTimesheetsToTim exportTimesheetsToTim;
private TimImpExpInfo timImpExpInfo;
@Override
@Transactional(readOnly = true)
public List<JobSchedulerConfiguration> getJobSchedulerConfigurations() {
@ -80,18 +84,26 @@ public class JobSchedulerModel implements IJobSchedulerModel {
}
@Override
public void doManual(JobSchedulerConfiguration jobSchedulerConfiguration) {
public void doManual(JobSchedulerConfiguration jobSchedulerConfiguration)
throws ConnectorException {
String name = jobSchedulerConfiguration.getJobClassName().getName();
if (name.equals(JobClassNameEnum.IMPORT_ROSTER_FROM_TIM_JOB.getName())) {
importRosterFromTim.importRosters();
timImpExpInfo = importRosterFromTim.getImportProcessInfo();
return;
}
if (name.equals(JobClassNameEnum.EXPORT_TIMESHEET_TO_TIM_JOB.getName())) {
exportTimesheetsToTim.exportTimesheets();
timImpExpInfo = exportTimesheetsToTim.getExportProcessInfo();
return;
}
}
@Override
public TimImpExpInfo getImportExportInfo() {
return timImpExpInfo;
}
@Override
public void initCreate() {
this.jobSchedulerConfiguration = JobSchedulerConfiguration.create();

View file

@ -21,21 +21,30 @@ package org.libreplan.web.orders;
import static org.libreplan.web.I18nHelper._;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.LogFactory;
import org.libreplan.business.common.daos.IConnectorDAO;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.common.entities.PredefinedConnectors;
import org.libreplan.business.orders.entities.OrderSyncInfo;
import org.libreplan.importers.IExportTimesheetsToTim;
import org.libreplan.importers.TimImpExpInfo;
import org.libreplan.web.common.IMessagesForUser;
import org.libreplan.web.common.Level;
import org.libreplan.web.common.MessagesForUser;
import org.libreplan.web.common.Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.SuspendNotAllowedException;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Label;
import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.api.Window;
/**
* Controller for Tim synchronization
@ -76,15 +85,18 @@ public class TimSynchronizationController extends GenericForwardComposer {
public void startExportToTim() {
LOG.info("startExportToTim(): " + orderController.getOrder().getName());
txtProductCode.setConstraint("no empty:" + _("cannot be empty"));
if (exportTimesheetsToTim.exportTimesheets(txtProductCode.getValue(),
orderController.getOrder())) {
messagesForUser.showMessage(Level.INFO,
"Exporting timesheets to Tim is completed successfully");
} else {
try {
exportTimesheetsToTim.exportTimesheets(txtProductCode.getValue(),
orderController.getOrder());
updateOrderLastSyncInfoScreen();
shwoImpExpInfo();
} catch (ConnectorException e) {
messagesForUser.showMessage(Level.ERROR,
_("Exporting timesheets to Tim failed"));
_("Exporting timesheets to Tim failed. Check the Tim connector"));
}
updateOrderLastSyncInfoScreen();
}
private void updateOrderLastSyncInfoScreen() {
@ -109,4 +121,26 @@ public class TimSynchronizationController extends GenericForwardComposer {
}
return connector.isActivated();
}
private void shwoImpExpInfo() {
Map<String, Object> args = new HashMap<String, Object>();
TimImpExpInfo timImpExpInfo = exportTimesheetsToTim.getExportProcessInfo();
args.put("action", _(timImpExpInfo.getAction()));
args.put("showSuccess", timImpExpInfo.isSuccessful());
args.put("failedReasons",
new SimpleListModel(timImpExpInfo.getFailedReasons()));
Window timImpExpInfoWindow = (Window) Executions.createComponents(
"/orders/_timImpExpInfo.zul", null, args);
try {
timImpExpInfoWindow.doModal();
} catch (SuspendNotAllowedException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -0,0 +1,31 @@
<!--
This file is part of LibrePlan
Copyright (C) 2013 St. Antoniusziekenhuis
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/>.
-->
<window id="winTimImpExpInfo" title="${i18n:_('LibrePlan: Tim import export info')}"
width="500px" border="normal" mode="modal">
<div>
<vbox>
<label value="${arg.action} ${i18n:_('was successful')}" sclass="remarked" if="${arg.showSuccess}"/>
<label value="${arg.action} ${i18n:_('is not completed for the following reasons:')}" sclass="remarked" if="${not arg.showSuccess}"/>
<listbox model="${arg.failedReasons}"/>
</vbox>
</div>
<button id="closeBtn" label="${i18n:_('Close')}" onClick="winTimImpExpInfo.detach()"
sclass="cancel-button global-action"/>
</window>

View file

@ -44,14 +44,13 @@ import org.libreplan.business.IDataBootstrap;
import org.libreplan.business.common.IAdHocTransactionService;
import org.libreplan.business.common.IOnTransaction;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.orders.daos.IOrderDAO;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.scenarios.IScenarioManager;
import org.libreplan.business.scenarios.entities.OrderVersion;
import org.libreplan.business.scenarios.entities.Scenario;
import org.libreplan.importers.ExportTimesheetsToTim;
import org.libreplan.importers.IExportTimesheetsToTim;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ -160,9 +159,12 @@ public class ExportTimesheetsToTimTest {
@Test
@Ignore("Only working if you have a Tim server configured")
public void testExportTimesheetsToTimWithValidCodeAndOrder() {
public void testExportTimesheetsToTimWithValidCodeAndOrder()
throws ConnectorException {
Order order = givenOrder();
boolean result = exportTimesheetsToTim.exportTimesheets("5160", order);
exportTimesheetsToTim.exportTimesheets("5160", order);
boolean result = exportTimesheetsToTim.getExportProcessInfo()
.isSuccessful();
if (!result) {
fail("Export timesheets to tim failed");
}
@ -170,13 +172,15 @@ public class ExportTimesheetsToTimTest {
}
@Test(expected = RuntimeException.class)
public void testExportTimesheetsToTimWithInvalidCode() {
public void testExportTimesheetsToTimWithInvalidCode()
throws ConnectorException {
Order order = givenOrder();
exportTimesheetsToTim.exportTimesheets("", order);
}
@Test(expected = RuntimeException.class)
public void testExportTimesheetsToTimWithOrderNull() {
public void testExportTimesheetsToTimWithOrderNull()
throws ConnectorException {
exportTimesheetsToTim.exportTimesheets("5160", null);
}
}

View file

@ -35,8 +35,7 @@ import org.junit.runner.RunWith;
import org.libreplan.business.IDataBootstrap;
import org.libreplan.business.common.IAdHocTransactionService;
import org.libreplan.business.common.IOnTransaction;
import org.libreplan.importers.IImportRosterFromTim;
import org.libreplan.importers.ImportRosterFromTim;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.web.calendars.IBaseCalendarModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@ -93,7 +92,7 @@ public class ImportRosterFromTimTest {
@Test
@Ignore("Only working if you have a Tim server configured")
public void testImportRosters() {
public void testImportRosters() throws ConnectorException {
importRosterFromTim.importRosters();
assertTrue(baseCalendarModel.getCalendarExceptionType() != null);
}