diff --git a/libreplan-webapp/src/main/java/org/libreplan/importers/ExportTimesheetsToTim.java b/libreplan-webapp/src/main/java/org/libreplan/importers/ExportTimesheetsToTim.java
new file mode 100644
index 000000000..0909538e0
--- /dev/null
+++ b/libreplan-webapp/src/main/java/org/libreplan/importers/ExportTimesheetsToTim.java
@@ -0,0 +1,291 @@
+/*
+ * 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 .
+ */
+
+package org.libreplan.importers;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.libreplan.business.common.IAdHocTransactionService;
+import org.libreplan.business.common.IOnTransaction;
+import org.libreplan.business.common.daos.IAppPropertiesDAO;
+import org.libreplan.business.common.daos.IConfigurationDAO;
+import org.libreplan.business.orders.daos.IOrderDAO;
+import org.libreplan.business.orders.daos.IOrderSyncInfoDAO;
+import org.libreplan.business.orders.entities.Order;
+import org.libreplan.business.orders.entities.OrderSyncInfo;
+import org.libreplan.business.resources.daos.IWorkerDAO;
+import org.libreplan.business.resources.entities.Worker;
+import org.libreplan.business.workreports.daos.IWorkReportLineDAO;
+import org.libreplan.business.workreports.entities.WorkReportLine;
+import org.libreplan.importers.tim.Duration;
+import org.libreplan.importers.tim.Person;
+import org.libreplan.importers.tim.Product;
+import org.libreplan.importers.tim.RegistrationDate;
+import org.libreplan.importers.tim.TimOptions;
+import org.libreplan.importers.tim.TimeRegistration;
+import org.libreplan.importers.tim.TimeRegistrationRequest;
+import org.libreplan.importers.tim.TimeRegistrationResponse;
+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 ExportTimesheetsToTim implements IExportTimesheetsToTim {
+
+ private static final Log LOG = LogFactory
+ .getLog(ExportTimesheetsToTim.class);
+
+ @Autowired
+ private IWorkerDAO workerDAO;
+
+ @Autowired
+ private IWorkReportLineDAO workReportLineDAO;
+
+ @Autowired
+ private IConfigurationDAO configurationDAO;
+
+ @Autowired
+ IOrderSyncInfoDAO orderSyncInfoDAO;
+
+ @Autowired
+ private IAdHocTransactionService adHocTransactionService;
+
+ private List workers;
+
+ @Autowired
+ private IAppPropertiesDAO appPropertiesDAO;
+
+ @Autowired
+ private IOrderDAO orderDAO;
+
+ @Override
+ @Transactional(readOnly = true)
+ public void exportTimesheets() {
+ Map prop = appPropertiesDAO.findByMajorId("Tim");
+ List orders = orderDAO.getOrders();
+ for (Order order : orders) {
+ OrderSyncInfo orderSyncInfo = orderSyncInfoDAO
+ .findByOrderLastSynchronizedInfo(order);
+ if (orderSyncInfo == null) {
+ LOG.warn("Order '" + order.getName()
+ + "' is not yet synchronized");
+ } else {
+ boolean result = exportTimesheets(orderSyncInfo.getCode(),
+ orderSyncInfo.getOrder(), prop);
+ LOG.info("Export successful: " + result);
+ }
+ }
+ }
+
+ @Override
+ @Transactional(readOnly = true)
+ public boolean exportTimesheets(String productCode, Order order) {
+ 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");
+ }
+
+ Map prop = appPropertiesDAO.findByMajorId("Tim");
+ return exportTimesheets(productCode, order, prop);
+
+ }
+
+ /**
+ * exports time sheets to Tim
+ *
+ * @param productCode
+ * the product code
+ * @param order
+ * the order
+ * @param appProperties
+ * the app properties
+ *
+ * @return true if export is succeeded, false otherwise
+ */
+ private boolean exportTimesheets(String productCode, Order order,
+ Map appProperties) {
+
+ workers = workerDAO.findAll();
+ LOG.info("workers.findAll(): " + workers.size());
+ if (workers == null && workers.isEmpty()) {
+ LOG.warn("No workers found!");
+ return false;
+ }
+
+ String url = appProperties.get("Server");
+ String userName = appProperties.get("Username");
+ String password = appProperties.get("Password");
+ int nrDaysTimesheetToTim = Integer.parseInt(appProperties
+ .get("NrDaysTimesheetToTim"));
+
+ Calendar dateNrOfDaysBack = Calendar.getInstance();
+ dateNrOfDaysBack.add(Calendar.DAY_OF_MONTH, -nrDaysTimesheetToTim);
+
+ List workReportLines = order.getWorkReportLines(
+ new Date(dateNrOfDaysBack.getTimeInMillis()), new Date(), true);
+ if (workReportLines == null || workReportLines.isEmpty()) {
+ LOG.warn("No work reportlines are found");
+ return false;
+ }
+
+ List timeRegistrations = new ArrayList();
+
+ for (WorkReportLine workReportLine : workReportLines) {
+ TimeRegistration timeRegistration = createExportTimeRegistration(
+ productCode, workReportLine);
+ if (timeRegistration != null) {
+ timeRegistrations.add(timeRegistration);
+ }
+ }
+
+ if (timeRegistrations.isEmpty()) {
+ LOG.warn("Unable to crate timeregistration request");
+ return false;
+ }
+
+ TimeRegistrationRequest timeRegistrationRequest = new TimeRegistrationRequest();
+ timeRegistrationRequest.setTimeRegistrations(timeRegistrations);
+
+ TimeRegistrationResponse timeRegistrationResponse = TimSoapClient
+ .sendRequestReceiveResponse(url, userName, password,
+ timeRegistrationRequest, TimeRegistrationResponse.class);
+
+ if (isRefsListEmpty(timeRegistrationResponse.getRefs())) {
+ LOG.warn("Registration response empty refs");
+ return false;
+ }
+ saveSyncInfoOnAnotherTransaction(productCode, order);
+ return true;
+ }
+
+ /**
+ * checks if list of refs is empty
+ *
+ * @param refs
+ * the list of refs
+ * @return true if list is empty otherwise false
+ */
+ private boolean isRefsListEmpty(List refs) {
+ if (refs == null) {
+ return true;
+ }
+ refs.removeAll(Collections.singleton(0));
+ return refs.isEmpty();
+ }
+
+ /**
+ * Saves synchronization info
+ *
+ * @param productCode
+ * the productcode
+ * @param order
+ * the order
+ */
+ private void saveSyncInfoOnAnotherTransaction(final String productCode,
+ final Order order) {
+ adHocTransactionService
+ .runOnAnotherTransaction(new IOnTransaction() {
+ @Override
+ public Void execute() {
+ OrderSyncInfo orderSyncInfo = OrderSyncInfo
+ .create(order);
+ orderSyncInfo.setCode(productCode);
+ orderSyncInfoDAO.save(orderSyncInfo);
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Creates export time registration
+ *
+ * @param productCode
+ * the product code
+ * @param workReportLine
+ * the workreportLine
+ * @return timeRegistration
+ */
+ private TimeRegistration createExportTimeRegistration(String productCode,
+ WorkReportLine workReportLine) {
+ Worker worker = getWorker(workReportLine.getResource().getCode());
+ if (worker == null) {
+ LOG.warn("Worker not found!");
+ return null;
+ }
+
+ Person person = new Person();
+ person.setName(worker.getName());
+ // person.setNetworkName(worker.getNif());
+ person.setOptions(TimOptions.UPDATE_OR_INSERT);
+
+ Product product = new Product();
+ product.setOptions(TimOptions.UPDATE_OR_INSERT);
+ product.setCode(productCode);
+
+ RegistrationDate date = new RegistrationDate();
+ date.setOptions(TimOptions.UPDATE_OR_INSERT);
+ date.setDate(workReportLine.getLocalDate());
+
+ Duration duration = new Duration();
+ duration.setOptions(TimOptions.DECIMAL);
+ duration.setDuration(workReportLine.getEffort()
+ .toHoursAsDecimalWithScale(2).doubleValue());
+
+ TimeRegistration timeRegistration = new TimeRegistration();
+ timeRegistration.setPerson(person);
+ timeRegistration.setProduct(product);
+ timeRegistration.setRegistrationDate(date);
+ timeRegistration.setDuration(duration);
+ return timeRegistration;
+ }
+
+ /**
+ * get worker based on the specified code
+ *
+ * @param code
+ * @return worker
+ */
+ private Worker getWorker(String code) {
+ for (Worker worker : workers) {
+ if (worker.getCode().equals(code)) {
+ return worker;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ @Transactional(readOnly = true)
+ public OrderSyncInfo getOrderLastSyncInfo(Order order) {
+ return orderSyncInfoDAO.findByOrderLastSynchronizedInfo(order);
+ }
+
+}