diff --git a/appointment-import/src/main/java/smash/appointment/parse/AppointmentDao.java b/appointment-import/src/main/java/smash/appointment/parse/AppointmentDao.java
index fa9a57f9a3fc80456e4bfa307da2375548751569..cb965abff90d22aecbb62626c0d27731314c7d3f 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/AppointmentDao.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/AppointmentDao.java
@@ -1,6 +1,9 @@
 package smash.appointment.parse;
 
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -36,7 +39,7 @@ public class AppointmentDao {
 		this.appointments = appointments;
 	}
 
-	public List<Visit> getVisits() {
+	public List<Visit> getVisits() throws ParseException {
 		List<Visit> result = new ArrayList<>();
 		Map<Subject, List<AppointmentEntry>> subjectAppointments = new HashMap<>();
 		for (AppointmentEntry entry : appointments) {
@@ -51,7 +54,7 @@ public class AppointmentDao {
 		return result;
 	}
 
-	private List<Visit> getVisitsForSubject(Subject subject, List<AppointmentEntry> list) {
+	private List<Visit> getVisitsForSubject(Subject subject, List<AppointmentEntry> list) throws ParseException {
 		Comparator<AppointmentEntry> comparator = new Comparator<AppointmentEntry>() {
 
 			@Override
@@ -87,7 +90,7 @@ public class AppointmentDao {
 				String date = currentVisit.getLastAppointmentDate();
 				if (date.equals(appointmentEntry.getDay().substring(0, 10))) {
 					currentVisit.getLastAppointment().addTypes(appointmentEntry.getTypes());
-					String source = appointmentEntry.getSource() + "\n"+currentVisit.getLastAppointment().getSource();
+					String source = appointmentEntry.getSource() + "\n" + currentVisit.getLastAppointment().getSource();
 					currentVisit.getLastAppointment().setSource(source);
 				} else {
 					currentVisit.addAppointment(appointmentEntry);
@@ -97,9 +100,34 @@ public class AppointmentDao {
 		if (currentVisit.getAppointments().size() > 0) {
 			result.add(currentVisit);
 		}
+		if (shouldBeFinished(currentVisit.getEndDate())) {
+			result.add(createNextVisit(currentVisit));
+		}
 		return result;
 	}
 
+	protected Visit createNextVisit(Visit currentVisit) throws ParseException {
+		Visit visit = new Visit(currentVisit.getSubject());
+		Calendar date = Calendar.getInstance();
+		String dateStr =currentVisit.getStartDate(); 
+		date.setTime(DATE_FORMATTER.parse(dateStr));
+		if (currentVisit.getSubject().getType().equals(SubjectType.CONTROL)) {
+			date.add(Calendar.YEAR, 4);
+		} else {
+			date.add(Calendar.YEAR, 1);
+		}
+		visit.setStartDate(DATE_FORMATTER.format(date.getTime()));
+		return visit;
+	}
+
+	private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
+
+	protected boolean shouldBeFinished(String endDate) {
+		Calendar today_minus_two_months = Calendar.getInstance();
+		today_minus_two_months.add(Calendar.MONTH, -2);
+		return DATE_FORMATTER.format(today_minus_two_months.getTime()).compareTo(endDate) > 0;
+	}
+
 	public void addAppointment(AppointmentEntry appointment) {
 		appointments.add(appointment);
 
diff --git a/appointment-import/src/main/java/smash/appointment/parse/AppointmentEntry.java b/appointment-import/src/main/java/smash/appointment/parse/AppointmentEntry.java
index b4faf7c678c40b3daa3f6429d2314ce8d11e87ce..4b8001727ff44fdd7e46e3a9fa5f35695d0e02e7 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/AppointmentEntry.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/AppointmentEntry.java
@@ -12,6 +12,8 @@ public class AppointmentEntry {
 	private Subject								subject;
 	private Set<AppointmentType>	types	= new HashSet<>();
 	private String								source;
+	private String								location;
+	
 
 	/**
 	 * @return the time
@@ -144,4 +146,20 @@ public class AppointmentEntry {
 		}
 
 	}
+
+	/**
+	 * @return the location
+	 * @see #location
+	 */
+	public String getLocation() {
+		return location;
+	}
+
+	/**
+	 * @param location the location to set
+	 * @see #location
+	 */
+	public void setLocation(String location) {
+		this.location = location;
+	}
 }
diff --git a/appointment-import/src/main/java/smash/appointment/parse/AppointmentSqlExporter.java b/appointment-import/src/main/java/smash/appointment/parse/AppointmentSqlExporter.java
index 6966c9ec3dcea9a0d39f302eb625c6aeb923005a..4c669334a76b25c7a1ebe5959bbb4e771df61346 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/AppointmentSqlExporter.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/AppointmentSqlExporter.java
@@ -1,33 +1,53 @@
 package smash.appointment.parse;
 
+import java.util.Calendar;
+
 public class AppointmentSqlExporter extends SqlExporter {
 
-	public String toSql(AppointmentEntry appointment, boolean isFinished) {
+	public String toSql(AppointmentEntry appointment) {
 		StringBuilder result = new StringBuilder("");
 
 		result.append("insert into web_appointment (");
 		result.append("datetime_when, ");
 		result.append("length, ");
-		result.append("is_finished, ");
+		result.append("status, ");
 		result.append("comment, ");
+		result.append("location_id, ");
 		result.append("visit_id) ");
 
 		result.append("values (");
-		result.append(getStringVal(appointment.getDay() + " " + appointment.getTime()+"+00") + ",");
+		result.append(getStringVal(appointment.getDay() + " " + appointment.getTime() + "+00") + ",");
 		result.append(getStringVal(appointment.getDuration()) + ",");
-		result.append(isFinished + ",");
+		if (isBefore(appointment, Calendar.getInstance())) {
+			result.append("'FINISHED',");
+		} else {
+			result.append("'SCHEDULED',");
+		}
 		result.append(getStringVal(appointment.getSource()) + ",");
+		switch (appointment.getLocation().substring(0, 1)) {
+			case ("L"):
+				result.append("(select id from web_location where name = 'LIH'),");
+				break;
+			case ("F"):
+				result.append("(select id from web_location where name = 'Flying Team'),");
+				break;
+			case ("P"):
+				result.append("(select id from web_location where name = 'PRC'),");
+				break;
+			default:
+				throw new RuntimeException("Unknown location: " + appointment.getLocation());
+		}
 		result.append("(select max(id) from web_visit)");
-		result.append(");");
+		result.append(");\n");
 
 		for (AppointmentType type : appointment.getTypes()) {
-			result.append("insert into web_appointment_appointment_types (");
+			result.append("\tinsert into web_appointment_appointment_types (");
 			result.append("appointment_id, ");
 			result.append("appointmenttype_id) ");
 			result.append("values (");
 			result.append("(select max(id) from web_appointment),");
 			result.append("(select id from web_appointmenttype where code=" + getStringVal(type.getAbbreviation()) + ") ");
-			result.append(");");
+			result.append(");\n");
 		}
 
 		return result.toString();
diff --git a/appointment-import/src/main/java/smash/appointment/parse/AppointmentTypeCollection.java b/appointment-import/src/main/java/smash/appointment/parse/AppointmentTypeCollection.java
index c4fdcc15a17c91f517da687112ce87bff8298940..63797a4d2e20e4276b351e7a724e4fd992e64d7a 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/AppointmentTypeCollection.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/AppointmentTypeCollection.java
@@ -48,7 +48,7 @@ public enum AppointmentTypeCollection {
 			new String[] { "evel B" }), //
 	LEVEL_B_M_POWER(new AppointmentType[] { AppointmentType.LEVEL_B_M_POWER }, //
 			new String[] { "mPower" }), //
-	OTHER(new AppointmentType[] {}, //
+	OTHER(new AppointmentType[] {AppointmentType.OTHER}, //
 			new String[] {}), //
 	;
 	private String[]					queryStrings;
diff --git a/appointment-import/src/main/java/smash/appointment/parse/CellParser.java b/appointment-import/src/main/java/smash/appointment/parse/CellParser.java
index 3780a8006712edf884e6e5d1ad6f1a5ecd34ca0b..bfd6940fcf13b38ed6c8e2279e953bc515f70192 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/CellParser.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/CellParser.java
@@ -42,6 +42,11 @@ public class CellParser {
 
 		Subject subject = extractSubject(query);
 		result.setSubject(subject);
+		if (subject!=null) {
+			result.setLocation(subject.getToBeSeenAt());
+		} else {
+			result.setLocation("PRC");
+		}
 
 		AppointmentTypeCollection type = extractType(query);
 		if (type == null) {
@@ -54,7 +59,7 @@ public class CellParser {
 		return result;
 	}
 
-	private AppointmentTypeCollection extractType(String query) {
+	public AppointmentTypeCollection extractType(String query) {
 		
 		String simplifiedQuery = Utils.simplifyString(query);
 
diff --git a/appointment-import/src/main/java/smash/appointment/parse/PrcControlParser.java b/appointment-import/src/main/java/smash/appointment/parse/PrcControlParser.java
index e0c6e4f5407e09e29609ac6ae55c76a9a14ecdb4..e5802c237d7caf2c35655f27037bcafdbd151e87 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/PrcControlParser.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/PrcControlParser.java
@@ -11,7 +11,7 @@ public class PrcControlParser extends SubjectParser {
 
 	@Override
 	protected String parseScreeningNumber(Row row) {
-		String number = getString(row.getCell(16));
+		String number = getString(row.getCell(13));
 		if (number.trim().isEmpty()) {
 			return "";
 		} else {
@@ -36,7 +36,7 @@ public class PrcControlParser extends SubjectParser {
 
 	@Override
 	protected String parseNdNumber(Row row) {
-		return getString(row.getCell(14));
+		return getString(row.getCell(12));
 	}
 
 	@Override
@@ -51,7 +51,7 @@ public class PrcControlParser extends SubjectParser {
 
 	@Override
 	protected String parseBirthDate(Row row) {
-		return "";
+		return parseDateOfBirth(row.getCell(11));
 	}
 
 	@Override
@@ -61,7 +61,7 @@ public class PrcControlParser extends SubjectParser {
 
 	@Override
 	protected String parseAddDate(Row row) {
-		return getDate(row.getCell(8), Calendar.getInstance());
+		return getDate(row.getCell(9), Calendar.getInstance());
 	}
 
 	@Override
@@ -76,60 +76,37 @@ public class PrcControlParser extends SubjectParser {
 
 	@Override
 	protected String parseMail(Row row) {
-		return getString(row.getCell(5));
+		return getString(row.getCell(8));
 	}
 
 	@Override
 	protected String parsePhone3(Row row) {
-		String phones[] = getPhones(row);
-		if (phones.length > 2) {
-			return phones[2].trim();
-		}
 		return "";
 	}
 
-	private String[] getPhones(Row row) {
-		return getString(row.getCell(4)).split("/");
-	}
-
 	@Override
 	protected String parsePhone2(Row row) {
-		String phones[] = getPhones(row);
-		if (phones.length > 1) {
-			return phones[1].trim();
-		}
-		return "";
+		return getString(row.getCell(7));
 	}
 
 	@Override
 	protected String parsePhone1(Row row) {
-		String phones[] = getPhones(row);
-		return phones[0].trim();
+		return getString(row.getCell(6));
 	}
 
 	@Override
 	protected String parseCity(Row row) {
-		String string = getString(row.getCell(3));
-		int spaceIndex = string.indexOf(" ");
-		if (spaceIndex > 0) {
-			return string.substring(spaceIndex).trim();
-		}
-		return string;
+		return getString(row.getCell(4));
 	}
 
 	@Override
 	protected String parseCountry(Row row) {
-		return "";
+		return getString(row.getCell(5));
 	}
 
 	@Override
 	protected String parseZipCode(Row row) {
-		String string = getString(row.getCell(3));
-		int spaceIndex = string.indexOf(" ");
-		if (spaceIndex > 0) {
-			return string.substring(0,spaceIndex);
-		}
-		return "";
+		return getString(row.getCell(3));
 	}
 
 	@Override
@@ -139,7 +116,7 @@ public class PrcControlParser extends SubjectParser {
 
 	@Override
 	protected String parseRemarks(Row row) {
-		String remark1 = getString(row.getCell(9));
+		String remark1 = getString(row.getCell(10));
 		String remark2 = "";
 
 		String result = "";
@@ -180,5 +157,4 @@ public class PrcControlParser extends SubjectParser {
 	protected boolean parseResigned(Row row) {
 		return false;
 	}
-
 }
diff --git a/appointment-import/src/main/java/smash/appointment/parse/PrcFlyingParser.java b/appointment-import/src/main/java/smash/appointment/parse/PrcFlyingParser.java
index efb92ca21c1289dc67732144365ba7e10fc08b65..9fa28ec25ce3e1c698d6527ee261d76ae4d1c525 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/PrcFlyingParser.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/PrcFlyingParser.java
@@ -11,7 +11,7 @@ public class PrcFlyingParser extends SubjectParser {
 
 	@Override
 	protected String parseScreeningNumber(Row row) {
-		String number = getString(row.getCell(25));
+		String number = getString(row.getCell(21));
 		if (number.trim().isEmpty()) {
 			return "";
 		} else {
@@ -20,13 +20,13 @@ public class PrcFlyingParser extends SubjectParser {
 			} else if (number.length() == 2) {
 				number = "0" + number;
 			}
-			return "P-" + number;
+			return "F-" + number;
 		}
 	}
 
 	@Override
 	protected String parseName(Row row) {
-		return "";
+		return getString(row.getCell(1));
 	}
 
 	@Override
@@ -36,7 +36,7 @@ public class PrcFlyingParser extends SubjectParser {
 
 	@Override
 	protected String parseNdNumber(Row row) {
-		return getString(row.getCell(23));
+		return getString(row.getCell(20));
 	}
 
 	@Override
@@ -51,7 +51,7 @@ public class PrcFlyingParser extends SubjectParser {
 
 	@Override
 	protected String parseBirthDate(Row row) {
-		return parseDateOfBirth(row.getCell(27));
+		return parseDateOfBirth(row.getCell(22));
 	}
 
 	@Override
@@ -61,75 +61,62 @@ public class PrcFlyingParser extends SubjectParser {
 
 	@Override
 	protected String parseAddDate(Row row) {
-		return getDate(row.getCell(11),Calendar.getInstance());
+		return getDate(row.getCell(12),Calendar.getInstance());
 	}
 
 	@Override
 	protected String parseReferal(Row row) {
-		return getString(row.getCell(10));
+		return getString(row.getCell(11));
 	}
 
 	@Override
 	protected String parseDiagnosisYear(Row row) {
-		return getString(row.getCell(8));
+		return "";
 	}
 
 	@Override
 	protected String parseMail(Row row) {
-		return getString(row.getCell(6));
+		return getString(row.getCell(8));
 	}
 
 	@Override
 	protected String parsePhone3(Row row) {
-		String phones[] = getPhones(row);
-		if (phones.length > 2) {
-			return phones[2].trim();
-		}
 		return "";
 	}
 
-	private String[] getPhones(Row row) {
-		return getString(row.getCell(5)).split("/");
-	}
-
 	@Override
 	protected String parsePhone2(Row row) {
-		String phones[] = getPhones(row);
-		if (phones.length > 1) {
-			return phones[1].trim();
-		}
-		return "";
+		return getString(row.getCell(7));
 	}
 
 	@Override
 	protected String parsePhone1(Row row) {
-		String phones[] = getPhones(row);
-		return phones[0].trim();
+		return getString(row.getCell(6));
 	}
 
 	@Override
 	protected String parseCity(Row row) {
-		return getString(row.getCell(3));
+		return getString(row.getCell(4));
 	}
 
 	@Override
 	protected String parseCountry(Row row) {
-		return getString(row.getCell(4));
+		return getString(row.getCell(5));
 	}
 
 	@Override
 	protected String parseZipCode(Row row) {
-		return getString(row.getCell(2));
+		return getString(row.getCell(3));
 	}
 
 	@Override
 	protected String parseAddress(Row row) {
-		return getString(row.getCell(1));
+		return getString(row.getCell(2));
 	}
 
 	@Override
 	protected String parseRemarks(Row row) {
-		String remark1 = getString(row.getCell(7));
+		String remark1 = getString(row.getCell(9));
 		String remark2 = getString(row.getCell(18));
 
 		String result = "";
@@ -144,7 +131,7 @@ public class PrcFlyingParser extends SubjectParser {
 
 	@Override
 	protected String parseDiagnosis(Row row) {
-		return getString(row.getCell(9));
+		return getString(row.getCell(10));
 	}
 
 	@Override
diff --git a/appointment-import/src/main/java/smash/appointment/parse/PrcSubjectsParser.java b/appointment-import/src/main/java/smash/appointment/parse/PrcSubjectsParser.java
index b24a61be5c22d4b6af45cc8a0347a598a9fe2108..a06e088395e0e174ea3625507faf7affb26e1b3a 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/PrcSubjectsParser.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/PrcSubjectsParser.java
@@ -4,8 +4,11 @@ import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.List;
 
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.usermodel.Color;
 import org.apache.poi.ss.usermodel.IndexedColors;
 import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.xssf.usermodel.XSSFColor;
 
 public class PrcSubjectsParser extends SubjectParser {
 
@@ -151,9 +154,21 @@ public class PrcSubjectsParser extends SubjectParser {
 
 	@Override
 	protected boolean parseDead(Row row) {
-		if (row.getCell(0).getCellStyle().getFillBackgroundColorColor() != null) {
+		Color color = row.getCell(0).getCellStyle().getFillForegroundColorColor();
+		if (color == null) {
+			return false;
+		}
+		if (color instanceof XSSFColor) {
 			return true;
 		}
+		if (color instanceof HSSFColor) {
+			HSSFColor hssfColor = (HSSFColor) color;
+			if (hssfColor.getHexString().equalsIgnoreCase("0:0:0")) {
+				return false;
+			} else {
+				return true;
+			}
+		}
 		return false;
 	}
 
@@ -161,7 +176,7 @@ public class PrcSubjectsParser extends SubjectParser {
 	protected boolean parseResigned(Row row) {
 		try {
 			int colorId = row.getSheet().getWorkbook().getFontAt(row.getCell(0).getCellStyle().getFontIndex()).getColor();
-			//special case for black
+			// special case for black
 			if (colorId == 32767) {
 				return false;
 			}
@@ -186,7 +201,7 @@ public class PrcSubjectsParser extends SubjectParser {
 					return false;
 			}
 		} catch (Exception e) {
-			logger.error("Problem with parsing color for subject: " + parseName(row)+" "+parseSurname(row), e);
+			logger.error("Problem with parsing color for subject: " + parseName(row) + " " + parseSurname(row), e);
 			return false;
 		}
 	}
diff --git a/appointment-import/src/main/java/smash/appointment/parse/RedcapCalendarParser.java b/appointment-import/src/main/java/smash/appointment/parse/RedcapCalendarParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..41a5d791d53a07ad39a1fc3c35db84bb9d3ebd1d
--- /dev/null
+++ b/appointment-import/src/main/java/smash/appointment/parse/RedcapCalendarParser.java
@@ -0,0 +1,149 @@
+package smash.appointment.parse;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+public class RedcapCalendarParser {
+	Logger						 logger				 = Logger.getLogger(RedcapCalendarParser.class);
+
+	private SubjectDao subjectDao;
+
+	DateTimeFormatter	 formatter		 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+	SimpleDateFormat	 dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
+
+	public List<AppointmentEntry> parse(String filename, Calendar minDate) throws FileNotFoundException, IOException {
+		List<AppointmentEntry> result = new ArrayList<>();
+		try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
+			String line;
+			while ((line = br.readLine()) != null) {
+				if (!line.startsWith("INSERT INTO")) {
+					continue;
+				}
+				String tmp[] = line.substring(line.indexOf("(")).split("\\),\\(", -1);
+				for (String string : tmp) {
+					AppointmentEntry entry = processEntry(string, minDate);
+					if (entry != null) {
+						result.add(entry);
+					}
+				}
+			}
+		}
+		return result;
+	}
+
+	private AppointmentEntry processEntry(String string, Calendar minDate) {
+		AppointmentEntry result = new AppointmentEntry();
+		if (string.startsWith("(")) {
+			string = string.substring(1);
+		}
+		if (string.endsWith(")")) {
+			string = string.substring(0, string.length() - 1);
+		}
+		string = string.replaceAll("\\\\'", "__quota__");
+		string = string.replaceAll("'", "\"");
+		string = string.replaceAll("__quota__", "'");
+		String fields[] = string.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);
+		String ndNumber = fields[1].replaceAll("\"", "");
+		String day = fields[6].replaceAll("\"", "");
+		String time = fields[7].replaceAll("\"", "");
+
+		String query = fields[10].replaceAll("\"", "");
+
+		if (query.equals("") || query.equals("NULL")) {
+			return null;
+		}
+
+		if (minDate != null) {
+			if (day.compareTo(dateFormatter.format(minDate.getTime())) < 0) {
+				return null;
+			}
+		}
+		if (ndNumber.equals("NDtest_internal") || ndNumber.equals("NDtest_external")) {
+			return null;
+		}
+
+		Subject subject = null;
+		if (!ndNumber.equalsIgnoreCase("NULL")) {
+			subject = subjectDao.getByNdNumber(ndNumber);
+			if (subject == null) {
+				logger.warn("Cannot find subject with nd number: " + ndNumber);
+			}
+		}
+		if (subject == null) {
+			subject = findSubject(query);
+		}
+		if (subject != null && !subject.getToBeSeenAt().equalsIgnoreCase("LIH")) {
+			return null;
+		}
+		result.setLocation("LIH");
+		result.setDay(day);
+		result.setTime(time);
+		result.setSource("From redcap: " + query);
+		result.setSubject(subject);
+		result.addTypes(getTypes(query));
+		if (result.getTypes().contains(AppointmentType.OTHER)) {
+			logger.warn("Cannot find types for: " + query);
+		}
+		return result;
+	}
+
+	CellParser cellParser = new CellParser();
+
+	private List<AppointmentType> getTypes(String query) {
+		List<AppointmentType> result = new ArrayList<>();
+		AppointmentTypeCollection collection = cellParser.extractType(query);
+		if (collection == null) {
+			int index = query.indexOf("_");
+			if (index >= 0) {
+				query = query.substring(index);
+				if (query.startsWith("_lev a_")) {
+					collection = AppointmentTypeCollection.LEVEL_A;
+				}
+			}
+			if (collection == null) {
+				collection = AppointmentTypeCollection.OTHER;
+			}
+		}
+		for (AppointmentType appointmentType : collection.getTypes()) {
+			result.add(appointmentType);
+		}
+
+		return result;
+	}
+
+	private Subject findSubject(String query) {
+		String id = query.split("_")[0];
+		id = "L-" + id;
+		Subject result = subjectDao.getByScreeningNumber(id);
+		if (result == null) {
+			logger.warn("Cannot find subject for query: " + query);
+		}
+		return result;
+	}
+
+	/**
+	 * @return the subjectDao
+	 * @see #subjectDao
+	 */
+	public SubjectDao getSubjectDao() {
+		return subjectDao;
+	}
+
+	/**
+	 * @param subjectDao
+	 *          the subjectDao to set
+	 * @see #subjectDao
+	 */
+	public void setSubjectDao(SubjectDao subjectDao) {
+		this.subjectDao = subjectDao;
+	}
+}
diff --git a/appointment-import/src/main/java/smash/appointment/parse/RedcapParser.java b/appointment-import/src/main/java/smash/appointment/parse/RedcapParser.java
index 8ba9e39616c177ea8487d95bd2a959f3964e09de..2f4615a2f9bf9e82ebd980a1a31301119dd70e17 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/RedcapParser.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/RedcapParser.java
@@ -92,6 +92,7 @@ public class RedcapParser {
 		entry.setSubject(subject);
 		entry.setSource("Imported from RedCap");
 		entry.addType(AppointmentType.LEVEL_B_M_POWER);
+		entry.setLocation(subject.getToBeSeenAt());
 		return entry;
 	}
 
@@ -102,6 +103,7 @@ public class RedcapParser {
 		entry.setSubject(subject);
 		entry.setSource("Imported from RedCap");
 		entry.addType(AppointmentType.LEVEL_SB);
+		entry.setLocation(subject.getToBeSeenAt());
 		return entry;
 	}
 
@@ -116,6 +118,7 @@ public class RedcapParser {
 		entry.setSubject(subject);
 		entry.setSource("Imported from RedCap");
 		entry.addType(AppointmentType.LEVEL_BV);
+		entry.setLocation(subject.getToBeSeenAt());
 		return entry;
 	}
 
@@ -130,6 +133,7 @@ public class RedcapParser {
 		entry.setSubject(subject);
 		entry.setSource("Imported from RedCap");
 		entry.addType(AppointmentType.LEVEL_BG);
+		entry.setLocation(subject.getToBeSeenAt());
 		return entry;
 	}
 
@@ -144,6 +148,7 @@ public class RedcapParser {
 		entry.setSubject(subject);
 		entry.setSource("Imported from RedCap");
 		entry.addType(AppointmentType.LEVEL_B);
+		entry.setLocation(subject.getToBeSeenAt());
 		return entry;
 	}
 
@@ -162,6 +167,7 @@ public class RedcapParser {
 		entry.setSource("Imported from RedCap");
 		entry.setTime(time);
 		entry.addType(AppointmentType.LEVEL_A);
+		entry.setLocation(subject.getToBeSeenAt());
 		return entry;
 	}
 
diff --git a/appointment-import/src/main/java/smash/appointment/parse/SubjectDao.java b/appointment-import/src/main/java/smash/appointment/parse/SubjectDao.java
index 38dada1071019e5a5ea1033139c222c598b4aa77..3cbfc396f1eecd04359564cb55e3c6fcbc9e5772 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/SubjectDao.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/SubjectDao.java
@@ -13,7 +13,7 @@ public class SubjectDao {
 	private List<Subject>	subjects = new ArrayList<>();
 
 	public void addSubject(Subject subject, String errorPrefix) {
-		if (subject.getNdNumber() != null && !subject.getNdNumber().trim().isEmpty()) {
+		if (subject.getNdNumber() != null && !Utils.simplifyString(subject.getNdNumber()).isEmpty()) {
 			Subject existing = getByNdNumber(subject.getNdNumber());
 			if (existing != null) {
 				if (!existing.getScreeningNumber().equals(subject.getScreeningNumber())) {
@@ -30,7 +30,7 @@ public class SubjectDao {
 		}
 	}
 
-	private Subject getByScreeningNumber(String screeningNumber) {
+	Subject getByScreeningNumber(String screeningNumber) {
 		for (Subject s : subjects) {
 			if (screeningNumber.equals(s.getScreeningNumber())) {
 				return s;
diff --git a/appointment-import/src/main/java/smash/appointment/parse/SubjectSqlExporter.java b/appointment-import/src/main/java/smash/appointment/parse/SubjectSqlExporter.java
index e3056da5f1bb3d9f72a537e606544f557508480b..0e3389198112f172885be125dc195b11e2767dac 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/SubjectSqlExporter.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/SubjectSqlExporter.java
@@ -25,7 +25,7 @@ public class SubjectSqlExporter extends SqlExporter {
 		result.append("nd_number,");
 		result.append("mpower_id,");
 		result.append("screening_number,");
-		result.append("default_appointment_location,");
+		result.append("default_location_id,");
 		result.append("type,");
 		result.append("dead,");
 		result.append("resigned,");
@@ -51,7 +51,20 @@ public class SubjectSqlExporter extends SqlExporter {
 		result.append(getStringVal(subject.getNdNumber()) + ",");
 		result.append(getStringVal(subject.getmPowerId()) + ",");
 		result.append(getStringVal(subject.getScreeningNumber()) + ",");
-		result.append(getStringVal(subject.getToBeSeenAt()) + ",");
+		switch (subject.getToBeSeenAt()) {
+			case ("L"):
+				result.append("(select id from web_location where name = 'LIH'),");
+				break;
+			case ("F"):
+				result.append("(select id from web_location where name = 'Flying Team'),");
+				break;
+			case ("P"):
+				result.append("(select id from web_location where name = 'PRC'),");
+				break;
+			default:
+				throw new RuntimeException("Unknown location: " + subject.getToBeSeenAt());
+		}
+
 		result.append(getStringVal(subject.getType().toString().substring(0, 1)) + ",");
 		result.append(subject.isDead() + ",");
 		result.append(subject.isResigned() + ",");
diff --git a/appointment-import/src/main/java/smash/appointment/parse/Visit.java b/appointment-import/src/main/java/smash/appointment/parse/Visit.java
index 2762806afb7da798ed27ad773fbd4571d4885288..b585c524ba3264bef582ee8c4657f1a9b65b4077 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/Visit.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/Visit.java
@@ -28,6 +28,8 @@ public class Visit {
 
 	private Subject								 subject;
 	private List<AppointmentEntry> appointments	= new ArrayList<>();
+	
+	private String startDate;
 
 	public Visit(Subject subject) {
 		if (subject==null) {
@@ -75,8 +77,10 @@ public class Visit {
 	public String getStartDate() {
 		if (appointments.size() > 0) {
 			return appointments.get(0).getDay().substring(0, 10);
-		} else {
+		} else if (startDate==null){
 			return "1900-01-01";
+		} else {
+			return startDate;
 		}
 	}
 
@@ -106,4 +110,8 @@ public class Visit {
 		this.subject = subject;
 	}
 
+	public void setStartDate(String newDate) {
+		this.startDate = newDate;
+	}
+
 }
diff --git a/appointment-import/src/main/java/smash/appointment/parse/VisitSqlExporter.java b/appointment-import/src/main/java/smash/appointment/parse/VisitSqlExporter.java
index 16077d37622b97edd5c407abebc6e4344112a3b9..730b6c09cfc0d9e9d432ab5ed42f0322db30a5f6 100644
--- a/appointment-import/src/main/java/smash/appointment/parse/VisitSqlExporter.java
+++ b/appointment-import/src/main/java/smash/appointment/parse/VisitSqlExporter.java
@@ -24,7 +24,7 @@ public class VisitSqlExporter extends SqlExporter {
 			boolean entryFinished= isFinished;
 			if (isBefore(entry, Calendar.getInstance()))
 				entryFinished=true;
-			result.append(appointmentSqlExporter.toSql(entry, entryFinished)+"\n");
+			result.append(appointmentSqlExporter.toSql(entry)+"\n");
 		}
 
 		return result.toString();
diff --git a/appointment-import/src/test/java/smash/appointment/parse/AllTests.java b/appointment-import/src/test/java/smash/appointment/parse/AllTests.java
index 5d18d8096f02dd342ce2227684342276b60de532..1755cc4b57cebbf8c89aea509a19e366bdd54907 100644
--- a/appointment-import/src/test/java/smash/appointment/parse/AllTests.java
+++ b/appointment-import/src/test/java/smash/appointment/parse/AllTests.java
@@ -12,6 +12,7 @@ import org.junit.runners.Suite.SuiteClasses;
 		PrcControlParserTest.class, //
 		PrcFlyingParserTest.class, //
 		PrcSubjectsParserTest.class, //
+		RedcapCalendarParserTest.class, //
 		RedcapParserTest.class, //
 
 		SubjectDaoTest.class, //
diff --git a/appointment-import/src/test/java/smash/appointment/parse/AppointmentDaoTest.java b/appointment-import/src/test/java/smash/appointment/parse/AppointmentDaoTest.java
index 82dba7faaf64b77c6ffda2e6d87bcca7244ce7fe..98c1a8ad0fb2f444c7506a4c44b24efcf62fab45 100644
--- a/appointment-import/src/test/java/smash/appointment/parse/AppointmentDaoTest.java
+++ b/appointment-import/src/test/java/smash/appointment/parse/AppointmentDaoTest.java
@@ -1,13 +1,20 @@
 package smash.appointment.parse;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
+import java.text.ParseException;
+
+import org.apache.log4j.Logger;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.Test;
 
 public class AppointmentDaoTest {
+	Logger logger = Logger.getLogger(AppointmentDaoTest.class);
 
 	@AfterClass
 	public static void tearDownAfterClass() throws Exception {
@@ -22,23 +29,23 @@ public class AppointmentDaoTest {
 	}
 
 	@Test
-	public void getVisits() {
+	public void getVisits() throws ParseException {
 		Subject subject1 = new Subject("a", "b", "c", "d");
 		AppointmentEntry appointment = new AppointmentEntry();
 		appointment.setSubject(subject1);
-		appointment.setDay("2016-02-02");
+		appointment.setDay("2026-02-02");
 		appointment.addType(AppointmentType.LEVEL_A);
-		
+
 		AppointmentEntry appointment2 = new AppointmentEntry();
 		appointment2.setSubject(subject1);
-		appointment2.setDay("2016-02-02");
+		appointment2.setDay("2026-02-02");
 		appointment2.addType(AppointmentType.LEVEL_B);
-		
+
 		AppointmentEntry appointment3 = new AppointmentEntry();
 		appointment3.setSubject(subject1);
-		appointment3.setDay("2011-02-02");
+		appointment3.setDay("2021-02-02");
 		appointment3.addType(AppointmentType.LEVEL_A);
-		
+
 		AppointmentDao appointmentDao = new AppointmentDao();
 		appointmentDao.addAppointment(appointment);
 		appointmentDao.addAppointment(appointment2);
@@ -47,23 +54,67 @@ public class AppointmentDaoTest {
 	}
 
 	@Test
-	public void getVisits2() {
+	public void getVisits2() throws ParseException {
 		Subject subject1 = new Subject("a", "b", "c", "d");
 		Subject subject2 = new Subject("a1", "b1", "c1", "d1");
 		AppointmentEntry appointment = new AppointmentEntry();
 		appointment.setSubject(subject1);
-		appointment.setDay("2016-02-02");
+		appointment.setDay("2026-02-02");
 		appointment.addType(AppointmentType.LEVEL_A);
-		
+
 		AppointmentEntry appointment3 = new AppointmentEntry();
 		appointment3.setSubject(subject2);
-		appointment3.setDay("2016-02-02");
+		appointment3.setDay("2026-02-02");
 		appointment3.addType(AppointmentType.LEVEL_B);
-		
+
 		AppointmentDao appointmentDao = new AppointmentDao();
 		appointmentDao.addAppointment(appointment);
 		appointmentDao.addAppointment(appointment3);
 		assertEquals(2, appointmentDao.getVisits().size());
 	}
 
+	@Test
+	public void getShouldBeFinished() {
+		AppointmentDao appointmentDao = new AppointmentDao();
+		assertTrue(appointmentDao.shouldBeFinished("2014-01-01"));
+		assertTrue(appointmentDao.shouldBeFinished("2017-01-01"));
+		assertFalse(appointmentDao.shouldBeFinished("2018-01-01"));
+	}
+
+	@Test
+	public void createNextVisitForControl() throws ParseException {
+		Subject subject = new Subject("a", "b", "c", "d");
+		subject.setType(SubjectType.CONTROL);
+		AppointmentEntry appointment3 = new AppointmentEntry();
+		appointment3.setSubject(subject);
+		appointment3.setDay("2016-02-02");
+		appointment3.addType(AppointmentType.LEVEL_B);
+
+		Visit visit = new Visit(subject);
+		visit.addAppointment(appointment3);
+
+		AppointmentDao appointmentDao = new AppointmentDao();
+		Visit nextVisit = appointmentDao.createNextVisit(visit);
+		assertNotNull(nextVisit);
+		assertTrue(nextVisit.getStartDate().startsWith("2020"));
+	}
+
+	@Test
+	public void createNextVisitForPatient() throws ParseException {
+		Subject subject = new Subject("a", "b", "c", "d");
+		subject.setType(SubjectType.PATIENT);
+		AppointmentEntry appointment3 = new AppointmentEntry();
+		appointment3.setSubject(subject);
+		appointment3.setDay("2016-02-02");
+		appointment3.addType(AppointmentType.LEVEL_B);
+
+		Visit visit = new Visit(subject);
+		visit.addAppointment(appointment3);
+
+		AppointmentDao appointmentDao = new AppointmentDao();
+		Visit nextVisit = appointmentDao.createNextVisit(visit);
+		assertNotNull(nextVisit);
+		assertTrue(nextVisit.getStartDate().startsWith("2017"));
+	}
+
 }
diff --git a/appointment-import/src/test/java/smash/appointment/parse/PrcControlParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/PrcControlParserTest.java
index 9558de7cbac2412517d9969e30dea5f5617aa457..8c44d431a5bd0ff46906d9394ae003a13436e5a1 100644
--- a/appointment-import/src/test/java/smash/appointment/parse/PrcControlParserTest.java
+++ b/appointment-import/src/test/java/smash/appointment/parse/PrcControlParserTest.java
@@ -42,17 +42,17 @@ public class PrcControlParserTest extends TestBase {
 		assertEquals("DDD", subject.getAddress());
 		assertEquals("L-2423", subject.getZipCode());
 		assertEquals("Luxembourg", subject.getCity());
-		assertEquals("", subject.getCountry());
+		assertEquals("Luxembourg", subject.getCountry());
 		assertEquals("123", subject.getPhone1());
 		assertEquals("456", subject.getPhone2());
-		assertEquals("789", subject.getPhone3());
+		assertEquals("", subject.getPhone3());
 		assertEquals("mail@mail.lu", subject.getMail());
 		assertEquals("", subject.getDiagnosisYear());
 		assertEquals("", subject.getDiagnosis());
 		assertEquals("", subject.getReferal());
 		assertEquals("2016-03-29", subject.getAddDate());
 		assertEquals("ND3333", subject.getNdNumber());
-		assertEquals("", subject.getBirthDate());
+		assertEquals("1999-09-10", subject.getBirthDate());
 	}
 
 
diff --git a/appointment-import/src/test/java/smash/appointment/parse/PrcFlyingParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/PrcFlyingParserTest.java
index ba4224e9e2496171b9f16502c33128f3384021fb..222e092c6a1544fb79baebc876032ed8c00bc78d 100644
--- a/appointment-import/src/test/java/smash/appointment/parse/PrcFlyingParserTest.java
+++ b/appointment-import/src/test/java/smash/appointment/parse/PrcFlyingParserTest.java
@@ -35,9 +35,9 @@ public class PrcFlyingParserTest extends TestBase {
 		assertTrue(entries.size() > 0);
 
 		Subject subject = entries.get(0);
-		assertEquals("P-222", subject.getScreeningNumber());
-		assertEquals("DOE John", subject.getSurname());
-		assertEquals("", subject.getName());
+		assertEquals("F-222", subject.getScreeningNumber());
+		assertEquals("DOE", subject.getSurname());
+		assertEquals("John", subject.getName());
 		assertTrue(subject.getRemarks().contains("notes"));
 		assertEquals("8, rue des Nowhere", subject.getAddress());
 		assertEquals("F-57100", subject.getZipCode());
@@ -45,9 +45,9 @@ public class PrcFlyingParserTest extends TestBase {
 		assertEquals("France", subject.getCountry());
 		assertEquals("001234325435", subject.getPhone1());
 		assertEquals("666", subject.getPhone2());
-		assertEquals("777", subject.getPhone3());
+		assertEquals("", subject.getPhone3());
 		assertEquals("mail@address.lu", subject.getMail());
-		assertEquals("1998", subject.getDiagnosisYear());
+		assertEquals("", subject.getDiagnosisYear());
 		assertEquals("BLA", subject.getDiagnosis());
 		assertEquals("DR", subject.getReferal());
 		assertEquals("2016-07-06", subject.getAddDate());
diff --git a/appointment-import/src/test/java/smash/appointment/parse/PrcSubjectsParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/PrcSubjectsParserTest.java
index b5281b382d80ca1ab4355f6bbc8cf22b031e7669..2c3a28ce8abe1d0de8960fc4082523b80c8338c0 100644
--- a/appointment-import/src/test/java/smash/appointment/parse/PrcSubjectsParserTest.java
+++ b/appointment-import/src/test/java/smash/appointment/parse/PrcSubjectsParserTest.java
@@ -75,6 +75,11 @@ public class PrcSubjectsParserTest extends TestBase {
 		assertFalse(subject.isDead());
 		assertTrue(subject.isResigned());
 
-	}
 
+		subject = entries.get(5);
+		assertFalse(subject.isDead());
+
+		subject = entries.get(6);
+		assertFalse(subject.isDead());
+	}
 }
diff --git a/appointment-import/src/test/java/smash/appointment/parse/RedcapCalendarParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/RedcapCalendarParserTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2a9a17fae5e05b342e817ba4fd29e4d0d7bf8d49
--- /dev/null
+++ b/appointment-import/src/test/java/smash/appointment/parse/RedcapCalendarParserTest.java
@@ -0,0 +1,76 @@
+package smash.appointment.parse;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RedcapCalendarParserTest extends TestBase{
+	RedcapCalendarParser parser = new RedcapCalendarParser();
+
+	@AfterClass
+	public static void tearDownAfterClass() throws Exception {
+	}
+
+	@Before
+	public void setUp()  {
+		super.setUp();
+		parser.setSubjectDao(subjectDao);
+		List<Subject> subjects = new ArrayList<>();
+		for (int count =0 ;count<10000;count++) {
+			String nd = count+"";
+			while (nd.length()<4) {
+				nd = "0"+nd;
+			}
+			Subject subject = new Subject("name "+nd, "surname"+nd, "ND"+nd, count+"");
+			
+			String screening = nd;
+			if (screening.startsWith("0")) {
+				screening = screening.substring(1);
+			}
+			subject.setScreeningNumber("P-"+screening);
+			subject.setToBeSeenAt("PRC");
+			if (count>=3000) {
+				screening=screening.substring(1);
+				subject.setScreeningNumber("L-"+screening);
+				subject.setToBeSeenAt("LIH");
+			}
+			if (count>=7000) {
+				subject.setScreeningNumber("F-"+nd);
+				subject.setToBeSeenAt("FLYING TEAM");
+			}
+			subjects.add(subject);
+		}
+		subjectDao.setSubjects(subjects);
+	}
+
+	@After
+	public void tearDown() throws Exception {
+	}
+
+	@Test
+	public void testParse() throws Exception{
+		List<AppointmentEntry> result = parser.parse("testFiles/redcap_calendar.sql", null);
+		assertEquals(2, result.size());
+	}
+
+//	@Test
+//	public void test() throws Exception{
+//		List<AppointmentEntry> result = parser.parse("c:/Users/piotr.gawron/Desktop/tmp/prc/redcap_events_calendar.sql", Calendar.getInstance());
+//	}
+
+	@Test
+	public void testParse2() throws Exception{
+		Calendar future =Calendar.getInstance();
+		future.set(Calendar.YEAR, 4000);
+		List<AppointmentEntry> result = parser.parse("testFiles/redcap_calendar.sql", future);
+		assertEquals(0, result.size());
+	}
+
+}
diff --git a/appointment-import/testFiles/prcControlesExample.xlsx b/appointment-import/testFiles/prcControlesExample.xlsx
index 2277978b4984e2871171b48d30d06cc32d9ee31e..a3143cb40d39499dd598cea9f473fe6c49f1f2f3 100644
Binary files a/appointment-import/testFiles/prcControlesExample.xlsx and b/appointment-import/testFiles/prcControlesExample.xlsx differ
diff --git a/appointment-import/testFiles/prcFlyingTeam.xlsx b/appointment-import/testFiles/prcFlyingTeam.xlsx
index 56646dc463b43ec98bbf36b20c83cade9069ac44..a3296b81a92b108d4d31115c134211c19223c306 100644
Binary files a/appointment-import/testFiles/prcFlyingTeam.xlsx and b/appointment-import/testFiles/prcFlyingTeam.xlsx differ
diff --git a/appointment-import/testFiles/prcSubjectsExample.xlsx b/appointment-import/testFiles/prcSubjectsExample.xlsx
index b728be7a0083e5574a6fc513934de0535fb19065..986303d98419537e3952a2d557457cb85f468693 100644
Binary files a/appointment-import/testFiles/prcSubjectsExample.xlsx and b/appointment-import/testFiles/prcSubjectsExample.xlsx differ
diff --git a/appointment-import/testFiles/redcap_calendar.sql b/appointment-import/testFiles/redcap_calendar.sql
new file mode 100644
index 0000000000000000000000000000000000000000..c6586541fe09946d50bf9716e3fa1652a3f2eafd
--- /dev/null
+++ b/appointment-import/testFiles/redcap_calendar.sql
@@ -0,0 +1,68 @@
+-- MySQL dump 10.13  Distrib 5.5.54, for debian-linux-gnu (x86_64)
+--
+-- Host: localhost    Database: redcap
+-- ------------------------------------------------------
+-- Server version	5.5.54-0ubuntu0.14.04.1
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `redcap_events_calendar`
+--
+
+DROP TABLE IF EXISTS `redcap_events_calendar`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `redcap_events_calendar` (
+  `cal_id` int(10) NOT NULL AUTO_INCREMENT,
+  `record` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
+  `project_id` int(10) DEFAULT NULL,
+  `event_id` int(10) DEFAULT NULL,
+  `baseline_date` date DEFAULT NULL,
+  `group_id` int(10) DEFAULT NULL,
+  `event_date` date DEFAULT NULL,
+  `event_time` varchar(5) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'HH:MM',
+  `event_status` int(2) DEFAULT NULL COMMENT 'NULL=Ad Hoc, 0=Due Date, 1=Scheduled, 2=Confirmed, 3=Cancelled, 4=No Show',
+  `note_type` int(2) DEFAULT NULL,
+  `notes` text COLLATE utf8_unicode_ci,
+  `extra_notes` text COLLATE utf8_unicode_ci,
+  PRIMARY KEY (`cal_id`),
+  KEY `event_id` (`event_id`),
+  KEY `group_id` (`group_id`),
+  KEY `project_date` (`project_id`,`event_date`),
+  KEY `project_record` (`project_id`,`record`),
+  CONSTRAINT `redcap_events_calendar_ibfk_1` FOREIGN KEY (`event_id`) REFERENCES `redcap_events_metadata` (`event_id`) ON DELETE CASCADE ON UPDATE CASCADE,
+  CONSTRAINT `redcap_events_calendar_ibfk_2` FOREIGN KEY (`group_id`) REFERENCES `redcap_data_access_groups` (`group_id`) ON DELETE SET NULL ON UPDATE CASCADE,
+  CONSTRAINT `redcap_events_calendar_ibfk_3` FOREIGN KEY (`project_id`) REFERENCES `redcap_projects` (`project_id`) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB AUTO_INCREMENT=2107 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Calendar Data';
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `redcap_events_calendar`
+--
+
+LOCK TABLES `redcap_events_calendar` WRITE;
+/*!40000 ALTER TABLE `redcap_events_calendar` DISABLE KEYS */;
+INSERT INTO `redcap_events_calendar` VALUES (7,NULL,12,NULL,NULL,NULL,'2015-05-06','08:00',NULL,NULL,'Patient, Level A',NULL),(8,NULL,12,NULL,NULL,NULL,'2015-05-06','12:00',NULL,NULL,'Patient Level A',NULL),(1336,'ND0333',12,41,'2016-10-27',NULL,'2018-09-07','',0,NULL,'',NULL);
+/*!40000 ALTER TABLE `redcap_events_calendar` ENABLE KEYS */;
+UNLOCK TABLES;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2017-03-03 15:52:47
diff --git a/smash/smash/settings.py b/smash/smash/settings.py
index 750194e784535c6c688f7a79d77b91ab0c8bbf63..ced5f8308f701c7e9957c99f9b1f69cb6a48a903 100644
--- a/smash/smash/settings.py
+++ b/smash/smash/settings.py
@@ -21,6 +21,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
 ALLOWED_HOSTS = ['prc.parkinson.lu']
 
+DEBUG = True
 
 # Application definition
 
@@ -31,10 +32,12 @@ INSTALLED_APPS = [
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.staticfiles',
+    'debug_toolbar',
     'web'
 ]
 
 MIDDLEWARE = [
+    'debug_toolbar.middleware.DebugToolbarMiddleware',
     'django.middleware.security.SecurityMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.common.CommonMiddleware',
@@ -80,6 +83,9 @@ AUTH_PASSWORD_VALIDATORS = [
     },
 ]
 
+INTERNAL_IPS = [
+    '127.0.0.1'
+]
 
 # Internationalization
 # https://docs.djangoproject.com/en/1.10/topics/i18n/
diff --git a/smash/web/admin.py b/smash/web/admin.py
index a375578b188739c1300310912e3daab9741c38db..a23a9b196ec0e20424eee10bfd2cc3210a588c43 100644
--- a/smash/web/admin.py
+++ b/smash/web/admin.py
@@ -14,6 +14,7 @@ admin.site.register(Item)
 admin.site.register(Room)
 admin.site.register(AppointmentType)
 admin.site.register(Language, LanguageAdmin)
+admin.site.register(Location)
 admin.site.register(Worker)
 admin.site.register(FlyingTeam)
 admin.site.register(Avaibility)
diff --git a/smash/web/forms.py b/smash/web/forms.py
index ee7d125774ba686dede8a5c6da27a43ee4122af1..b8866f178c2da1094f2633e42a432c1740ea2dec 100644
--- a/smash/web/forms.py
+++ b/smash/web/forms.py
@@ -139,7 +139,7 @@ class AppointmentEditForm(ModelForm):
 class AppointmentAddForm(ModelForm):
     class Meta:
         model = Appointment
-        exclude = ['is_finished']
+        exclude = ['status']
 
     datetime_when = forms.DateTimeField(label='Appointment on (YYYY-MM-DD HH:MM)',
         widget=forms.DateTimeInput(DATETIMEPICKER_DATE_ATTRS)
@@ -158,6 +158,7 @@ class VisitDetailForm(ModelForm):
         exclude = ['is_finished']
 
 class VisitAddForm(ModelForm):
+    subject = forms.ModelChoiceField(queryset=Subject.objects.order_by('last_name','first_name'))
     datetime_begin = forms.DateField(label="Visit begins on",
         widget=forms.TextInput(attrs=DATEPICKER_DATE_ATTRS)
     )
diff --git a/smash/web/models.py b/smash/web/models.py
index acd7adac081a76b3d7d8390fad258003bf4d4fc9..663a5a3530df7320a198fe16c43892002cc48977 100644
--- a/smash/web/models.py
+++ b/smash/web/models.py
@@ -10,6 +10,15 @@ from datetime import timedelta
 def get_current_year():
     return datetime.datetime.now().year
 
+class Location (models.Model):
+    name = models.CharField(max_length=20)
+
+    def __str__(self):
+        return "%s" % (self.name)
+
+    def __unicode__(self):
+        return "%s" % (self.name)
+
 class Language (models.Model):
     name = models.CharField(max_length=20)
     image = models.ImageField()
@@ -35,13 +44,6 @@ class Subject(models.Model):
         (SEX_CHOICES_FEMALE,'Female'),
     )
 
-    LOCATION_CHOICES_LIH = 'L'
-    LOCATION_CHOICES = (
-        (LOCATION_CHOICES_LIH,'LIH'),
-        ('P','PRC'),
-        ('F','FLYING TEAM'),
-    )
-
     SUBJECT_TYPE_CHOICES_CONTROL = 'C'
     SUBJECT_TYPE_CHOICES = (
         (SUBJECT_TYPE_CHOICES_CONTROL,'CONTROL'),
@@ -75,9 +77,8 @@ class Subject(models.Model):
         default= False,
         editable=False
     )
-    default_appointment_location = models.CharField(max_length=1,
-        choices=LOCATION_CHOICES,
-        verbose_name='Default appointment location'
+    default_location = models.ForeignKey(Location,
+        verbose_name='Default appointment location',
     )
     first_name = models.CharField(max_length=50,
         verbose_name='First name'
@@ -91,7 +92,7 @@ class Subject(models.Model):
     )
     phone_number = models.CharField(max_length=20,
         null=True,
-	blank=True,
+	    blank=True,
         verbose_name='Phone number'
     )
     phone_number_2 = models.CharField(max_length=20,
@@ -142,7 +143,7 @@ class Subject(models.Model):
 	    blank=True,
         verbose_name='MPower ID'
     )
-    comments = models.CharField(max_length=2000,
+    comments = models.TextField(max_length=2000,
 	    blank=True,
         verbose_name='Comments'
     )
@@ -205,11 +206,8 @@ class Visit(models.Model):
         return "%s %s" % (self.subject.first_name, self.subject.last_name)
 
     def follow_up_title(self):
-        visits = Visit.objects.filter(subject=self.subject, datetime_begin__lt =self.datetime_begin)
-        if len(visits)==0:
-            return "First visit"
-        else:
-            return "Follow up "+str(len(visits))
+        count = Visit.objects.filter(subject=self.subject, datetime_begin__lt =self.datetime_begin).count()
+        return "Visit " + str(count + 1)
 
     def mark_as_finished(self):
         self.is_finished = True
@@ -232,20 +230,6 @@ class Visit(models.Model):
                             datetime_end = visit_started+time_to_next_visit+datetime.timedelta(days=93)
                             )
 
-
-    def end_if_appointments_were_finished(self):
-        the_appointments = self.appointment_set.all()
-        finished = True
-
-        for appointment in the_appointments:
-            if appointment.is_finished == False:
-                finished = False
-
-        if finished:
-            self.is_finished = True
-            self.save()
-
-
 class Item (models.Model):
     is_fixed = models.BooleanField(
         default=False,
@@ -349,6 +333,9 @@ class Worker (models.Model):
     languages = models.ManyToManyField(Language,
         verbose_name='Known languages'
     )
+    locations = models.ManyToManyField(Location,
+        verbose_name='Locations'
+    )
     appointments = models.ManyToManyField('Appointment', blank=True,
         verbose_name='Appointments'
     )
@@ -370,12 +357,13 @@ class Worker (models.Model):
     email = models.EmailField(
         verbose_name='E-mail'
     )
+    ROLE_CHOICES_SECRETARY = "SECRETARY"
     ROLE_CHOICES = (
         ('DOCTOR', 'Doctor'),
         ('NURSE', 'Nurse'),
         ('PSYCHOLOGIST', 'Psychologist'),
         ('TECHNICIAN', 'Technician'),
-        ('SECRETARY', 'Secretary')
+        (ROLE_CHOICES_SECRETARY, 'Secretary')
     )
     role = models.CharField(max_length=20, choices=ROLE_CHOICES,
         verbose_name='Role'
@@ -480,6 +468,17 @@ class Holiday(models.Model):
 
 
 class Appointment(models.Model):
+    APPOINTMENT_STATUS_SCHEDULED = 'SCHEDULED';
+    APPOINTMENT_STATUS_FINISHED = 'FINISHED';
+    APPOINTMENT_STATUS_CANCELLED = 'CANCELLED';
+    APPOINTMENT_STATUS_NO_SHOW = 'NO_SHOW';
+    APPOINTMENT_STATUS_CHOICES = (
+        (APPOINTMENT_STATUS_SCHEDULED, 'Scheduled'),
+        (APPOINTMENT_STATUS_FINISHED, 'Finished'),
+        (APPOINTMENT_STATUS_CANCELLED, 'Cancelled'),
+        (APPOINTMENT_STATUS_NO_SHOW, 'No Show'),
+    )
+
     flying_team = models.ForeignKey(FlyingTeam,
         verbose_name='Flying team (if applicable)',
         null=True, blank=True
@@ -496,10 +495,13 @@ class Appointment(models.Model):
         null=True,
         blank=True
     )
+    location = models.ForeignKey(Location,
+        verbose_name='Location',
+    )
     visit = models.ForeignKey(Visit,
         verbose_name='Visit ID'
     )
-    comment = models.CharField(max_length=1024,
+    comment = models.TextField(max_length=1024,
         verbose_name='Comment',
         null=True,
         blank=True
@@ -511,14 +513,23 @@ class Appointment(models.Model):
     length = models.IntegerField(
         verbose_name='Appointment length (in minutes)'
     )#Potentially redundant; but can be used to manually adjust appointment's length
-    is_finished = models.BooleanField(
-        verbose_name='Has the appointment ended?',
-        default=False,
-        editable=False
+
+    status = models.CharField(max_length=20, choices=APPOINTMENT_STATUS_CHOICES,
+        verbose_name='Status',
+        editable=False,
+        default=APPOINTMENT_STATUS_SCHEDULED
     )
 
     def mark_as_finished(self):
-        self.is_finished = True
+        self.status = Appointment.APPOINTMENT_STATUS_FINISHED
+        self.save()
+
+    def mark_as_cancelled(self):
+        self.status = Appointment.APPOINTMENT_STATUS_CANCELLED
+        self.save()
+
+    def mark_as_no_show(self):
+        self.status = Appointment.APPOINTMENT_STATUS_NO_SHOW
         self.save()
 
     def datetime_until(self):
@@ -547,7 +558,7 @@ class Appointment(models.Model):
 
     def title(self):
         if self.visit.subject.screening_number=="---":
-            return self.comment
+            return self.comment.replace("\n", ";")
         else:
             title = self.visit.subject.first_name + " " + self.visit.subject.last_name + " type: "
             for type in self.appointment_types.all():
diff --git a/smash/web/templates/_base.html b/smash/web/templates/_base.html
index 3291f0ce7a57198e9098bf34a517d3250c971b01..17bfe4b650906bd2e289de59a69aca3863bb81ca 100644
--- a/smash/web/templates/_base.html
+++ b/smash/web/templates/_base.html
@@ -123,36 +123,33 @@ desired effect
           <!-- /.messages-menu -->
 
           <!-- Notifications Menu -->
-          <li class="dropdown notifications-menu" style="display: none">
+          {% if notifications.0 > 0 %}
+          <li class="dropdown notifications-menu" >
             <!-- Menu toggle button -->
             <a href="#" class="dropdown-toggle" data-toggle="dropdown">
               <i class="fa fa-bell-o"></i>
-              <span class="label label-warning">
-				0
-              </span>
+              <span class="label label-warning"> {{notifications.0}}</span>
             </a>
             <ul class="dropdown-menu">
-              <li class="header">
-				  You have 0 notifications
-          <hr />
-          (Not implemented yet)
-			  </li>
-			  {% comment "TODO: Implement notifications" %}
+              <li class="header"> You have {{notifications.0}} notification(s): </li>
               <li>
                 <!-- Inner Menu: contains the notifications -->
                 <ul class="menu">
-                  <li><!-- start notification -->
-                    <a href="#">
-                      <i class="fa fa-users text-aqua"></i> 5 new members joined today
-                    </a>
-                  </li>
+                  {% for notification in notifications.1 %}
+                    {% if notification.count > 0 %}
+                      <li><!-- start notification -->
+                        <a href="{% url notification.type %}">
+                          <i class="fa {{notification.style}}"></i> {{ notification.title }}: {{ notification.count }}
+                        </a>
+                      </li>
+                    {% endif %}
+                  {% endfor %}
                   <!-- end notification -->
                 </ul>
               </li>
-              {% endcomment %}
-              <li class="footer"><a href="#">View all</a></li>
             </ul>
           </li>
+          {% endif %}
           <!-- User Account Menu -->
           <li class="dropdown user user-menu">
             <!-- Menu Toggle Button -->
@@ -289,13 +286,20 @@ desired effect
 			</a>
 		</li>
 
-		<li data-desc="mail_templates">
+    <li data-desc="mail_templates">
 			<a href="{% url 'web.views.mail_templates' %}">
 				<i class="fa fa-envelope-o"></i>
 				<span>Mail templates</span>
 			</a>
 		</li>
 
+    <li data-desc="export">
+			<a href="{% url 'web.views.export' %}">
+				<i class="fa fa-file-excel-o"></i>
+				<span>Export</span>
+			</a>
+		</li>
+
 		{% comment "Multi-level" %}
         <li class="treeview">
           <a href="#"><i class="fa fa-link"></i> <span>Multilevel</span>
diff --git a/smash/web/templates/appointments/edit.html b/smash/web/templates/appointments/edit.html
index 35d60f3c2867725aba99acce1025b07806e50934..76515ca22b49cbc2a832d93e694be4c60a3fe0e9 100644
--- a/smash/web/templates/appointments/edit.html
+++ b/smash/web/templates/appointments/edit.html
@@ -53,8 +53,16 @@
           {% endif %}
 				</div>
 			{% endfor %}
-      <div class="col-md-6">
-        <a href="{% url 'web.views.appointment_mark' id 'finished' %}" class="btn btn-warning btn-block">Mark as finished</a>
+      <div class="col-md-6 form-group">
+        <label for="{# TODO #}" class="col-sm-4 control-label">
+          Status:
+        </label>
+          <div class="btn-group-vertical col-sm-8">
+            <label  class="btn btn-primary">{{ status }}</label>
+            <a href="{% url 'web.views.appointment_mark' id 'finished' %}" class="btn btn-warning btn-block">Mark as finished</a>
+            <a href="{% url 'web.views.appointment_mark' id 'cancelled' %}" class="btn btn-warning btn-block">Mark as cancelled</a>
+            <a href="{% url 'web.views.appointment_mark' id 'no_show' %}" class="btn btn-warning btn-block">Mark as no show</a>
+          </div>
       </div>
 		</div><!-- /.box-body -->
 
diff --git a/smash/web/templates/appointments/index.html b/smash/web/templates/appointments/index.html
index c440bab2db3df666951f494dd723c02cae913f32..0a44243a9216474997aa1b3d404d77cd4375f3b6 100644
--- a/smash/web/templates/appointments/index.html
+++ b/smash/web/templates/appointments/index.html
@@ -67,6 +67,7 @@
 				<thead>
 					<tr>
             <th>Subject</th>
+            <th>Visit</th>
             <th>Type</th>
 						<th>Date</th>
 						<th>Details</th>
@@ -76,13 +77,19 @@
 
       			{% for approach in approaching_list %}
   				<tr>
-  					<td>
               {% if approach.visit.subject.screening_number == "---" %}
-                N/A
+                <td>
+                </td>
+                <td>
+                </td>
               {% else %}
-                {{ approach.visit.subject.first_name }} {{ approach.visit.subject.last_name }}
+                <td>
+                  {{ approach.visit.subject.first_name }} {{ approach.visit.subject.last_name }} ({{ approach.visit.subject.nd_number }})
+                </td>
+                <td>
+                  {{ approach.visit.follow_up_title }}
+                </td>
               {% endif %}
-  					</td>
             <td>
               {% for type in approach.appointment_types.all %}
                 {{ type.code }},
@@ -136,9 +143,10 @@
 				header: {
 					left: 'prev,next today',
 					center: 'title',
-					right: 'month,agendaWeek'
+					right: 'month,agendaWeek',
 				},
 				editable: false,
+        weekNumbers: true,
 				events: [
         {% for appointment in full_list %}
           {
@@ -147,7 +155,7 @@
             end: '{{ appointment.datetime_until | date:"c" }}',
             color: '{{ appointment.color }}',
             subject_id: '{{ appointment.visit.subject.id }}',
-            id: '{{ appointment.id }}'
+            id: '{{ appointment.id }}',
           },
         {% endfor %}
           ],
diff --git a/smash/web/templates/appointments/list.html b/smash/web/templates/appointments/list.html
new file mode 100644
index 0000000000000000000000000000000000000000..1c7393d3a5c5307af237f5caf01b8c0e909aea65
--- /dev/null
+++ b/smash/web/templates/appointments/list.html
@@ -0,0 +1,70 @@
+{% extends "_base.html" %}
+{% load static %}
+
+{% block styles %}
+{{ block.super }}
+  <!-- DataTables -->
+  <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}">
+
+  <!-- fullCalendar 2.2.5-->
+  <link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.min.css' %}">
+  <link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.print.css' %}" media="print">
+{% endblock styles %}
+
+{% block ui_active_tab %}'appointments'{% endblock ui_active_tab %}
+{% block page_header %}Appointments{% endblock page_header %}
+{% block page_description %}{% endblock page_description %}
+
+{% block title %}{{ block.super }} - Appointments{% endblock %}
+
+{% block breadcrumb %}
+{% include "appointments/breadcrumb.html" %}
+{% endblock breadcrumb %}
+
+{% block maincontent %}
+<div class="row">
+	<div class="col-md-16">
+			<table id="approaching_table" class="table table-bordered table-striped">
+				<thead>
+					<tr>
+            <th>Subject</th>
+            <th>Visit</th>
+            <th>Type</th>
+						<th>Date</th>
+						<th>Details</th>
+					</tr>
+				</thead>
+				<tbody>
+
+      			{% for approach in appointment_list %}
+  				<tr>
+              {% if approach.visit.subject.screening_number == "---" %}
+                <td>
+                </td>
+                <td>
+                </td>
+              {% else %}
+                <td>
+                  {{ approach.visit.subject.first_name }} {{ approach.visit.subject.last_name }} ({{ approach.visit.subject.nd_number }})
+                </td>
+                <td>
+                  {{ approach.visit.follow_up_title }}
+                </td>
+              {% endif %}
+            <td>
+              {% for type in approach.appointment_types.all %}
+                {{ type.code }},
+              {% endfor %}
+            </td>
+        			<td>{{ approach.datetime_when | date:"Y-m-d H:i" }}</td>
+        			<td>
+        				<a href="{% url 'web.views.appointment_edit' approach.id %}" type="button" class="btn btn-block btn-default">Details</a>
+        			</td>
+  				</tr>
+		      	{% endfor %}
+				</tbody>
+			</table>
+
+	</div>
+</div>
+{% endblock maincontent %}
diff --git a/smash/web/templates/export/breadcrumb.html b/smash/web/templates/export/breadcrumb.html
new file mode 100644
index 0000000000000000000000000000000000000000..38d433b854ad90bc3070e001f23bdaed3827a8cb
--- /dev/null
+++ b/smash/web/templates/export/breadcrumb.html
@@ -0,0 +1,4 @@
+			  <li><a href="{% url 'web.views.appointments' %}"><i class="fa fa-dashboard"></i> Dashboard</a></li>
+			  <li class="active">
+			  	<a href="{% url 'web.views.subjects' %}">Export</a>
+			  </li>
diff --git a/smash/web/templates/export/index.html b/smash/web/templates/export/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..0fe811b04f426f927905f4a716f2936f5c27f859
--- /dev/null
+++ b/smash/web/templates/export/index.html
@@ -0,0 +1,34 @@
+{% extends "_base.html" %}
+{% load static %}
+
+{% block styles %}
+{{ block.super }}
+{% endblock styles %}
+
+{% block ui_active_tab %}'export'{% endblock ui_active_tab %}
+{% block page_header %}Export{% endblock page_header %}
+{% block page_description %}{% endblock page_description %}
+
+{% block title %}{{ block.super }} - Export to csv{% endblock %}
+
+{% block breadcrumb %}
+{% include "export/breadcrumb.html" %}
+{% endblock breadcrumb %}
+
+{% block maincontent %}
+
+<div>
+	<a href="{% url 'web.views.export_to_csv2' 'subjects' %}" class="btn btn-app">
+      <i class="fa fa-download"></i>
+      Subjects
+    </a>
+		<br/>
+		<a href="{% url 'web.views.export_to_csv2' 'appointments' %}" class="btn btn-app">
+	      <i class="fa fa-download"></i>
+	      Appointments
+	    </a>
+</div>
+
+<div class="box-body">
+</div>
+{% endblock maincontent %}
diff --git a/smash/web/templates/subjects/visitdetails.html b/smash/web/templates/subjects/visitdetails.html
index c3432d99fe5f918a15f0e8327ec11ecb9afba38c..02933fd2130c2d74e2f8953bc92b5beca2078ea7 100644
--- a/smash/web/templates/subjects/visitdetails.html
+++ b/smash/web/templates/subjects/visitdetails.html
@@ -24,6 +24,7 @@
 <div class="box box-info">
   <div class="box-header with-border">
     <a href="{% url 'web.views.visits' %}" class="btn btn-block btn-default" onclick="history.back()">Back</a>
+    <a href="{% url 'web.views.visit_add' id %}" type = "button" class="btn btn-block btn-default">Add visit</a>
   </div>
 
   <div class="box-body">
@@ -94,11 +95,11 @@
                       {% endif %}
                     </td>
                     <td>
-                      {% if app.is_finished %}
-                        FINISHED
-                      {% else %}
+                      {% ifequal app.status "SCHEDULED" %}
                         <a href="{% url 'web.views.appointment_edit' app.id %}" type="button" class="btn btn-block btn-default">Edit</a>
-                      {% endif %}
+                      {% else %}
+                        {{ app.status }}
+                      {% endifequal %}
                     </td>
                   </tr>
                   {% endfor %}
@@ -113,6 +114,7 @@
 
       {% endfor %}
     </form>
+
   </div><!-- /.box-body -->
 
 </div>
diff --git a/smash/web/templates/visits/details.html b/smash/web/templates/visits/details.html
index 7385a5102267d52079bd736eb289a1a6cbeaa865..ae9ae29df2b6f2511bd7aa09e0adbccccab4c509 100644
--- a/smash/web/templates/visits/details.html
+++ b/smash/web/templates/visits/details.html
@@ -119,11 +119,11 @@
       {% endif %}
     </td>
     	<td>
-        {% if app.is_finished %}
-          FINISHED
-        {% else %}
+        {% ifequal app.status "SCHEDULED" %}
           <a href="{% url 'web.views.appointment_edit' app.id %}" type="button" class="btn btn-block btn-default">Edit</a>
-        {% endif %}
+        {% else %}
+          {{ app.status }}
+        {% endifequal %}
       </td>
   </tr>
   {% endfor %}
diff --git a/smash/web/tests/functions.py b/smash/web/tests/functions.py
new file mode 100644
index 0000000000000000000000000000000000000000..e343416887c17204c9ab04ee4ed91274b3c9a99e
--- /dev/null
+++ b/smash/web/tests/functions.py
@@ -0,0 +1,46 @@
+from datetime import timedelta
+
+from web.models import *
+from web.views import *
+
+def create_location(name="test"):
+    return Location.objects.create(name=name)
+
+def get_test_location():
+    locations = Location.objects.filter(name = "test");
+    if len(locations)>0:
+        return locations[0]
+    else:
+        return  create_location()
+
+def create_subject():
+    return Subject.objects.create(
+        first_name="Piotr",
+        last_name="Gawron",
+        default_location = get_test_location(),
+        sex= Subject.SEX_CHOICES_MALE)
+
+def create_user():
+    return User.objects.create_user(
+        username='piotr',
+        email='jacob@bla',
+        password='top_secret')
+
+def create_worker():
+    return Worker.objects.create(
+        first_name='piotr',
+        last_name="gawron",
+        email='jacob@bla',
+        )
+
+def create_visit(subject):
+    return Visit.objects.create(datetime_begin=get_today_midnight_date()+datetime.timedelta(days=-31),
+                                datetime_end=get_today_midnight_date()+datetime.timedelta(days=31),
+                                subject =subject,
+                                is_finished = False)
+
+def create_appointment(visit):
+    return Appointment.objects.create(
+        visit = visit,
+        length = 30,
+        location = get_test_location())
diff --git a/smash/web/tests/test_SubjectAddForm.py b/smash/web/tests/test_SubjectAddForm.py
index 92b032d07979d0de60fe4ef5c468b6a8175b8e04..bbe6a553652b01e679857d3bc38b288bb68cfd3c 100644
--- a/smash/web/tests/test_SubjectAddForm.py
+++ b/smash/web/tests/test_SubjectAddForm.py
@@ -2,13 +2,16 @@ from django.test import TestCase
 from web.forms import SubjectAddForm
 from web.models import Subject
 
+from web.tests.functions import *
+
 class SubjectAddFormTests(TestCase):
     def setUp(self):
+        location = get_test_location()
         self.sample_data = {'first_name': 'name',
             'last_name': 'name',
             'sex' : Subject.SEX_CHOICES_MALE,
             'type' : Subject.SUBJECT_TYPE_CHOICES_CONTROL,
-            'default_appointment_location' : Subject.LOCATION_CHOICES_LIH,
+            'default_location' : location.id,
             'country' : 'Luxembourg'
         }
     def test_validation(self):
diff --git a/smash/web/tests/test_SubjectEditForm.py b/smash/web/tests/test_SubjectEditForm.py
index 223b55954c6b61a5375a4243cb7f4619c1b1d9ee..340d2f4cd6832fbe43af3c5e2296c52a76253289 100644
--- a/smash/web/tests/test_SubjectEditForm.py
+++ b/smash/web/tests/test_SubjectEditForm.py
@@ -3,14 +3,16 @@ from web.forms import SubjectAddForm
 from web.forms import SubjectEditForm
 from web.models import Subject
 
+from web.tests.functions import *
 
 class SubjectEditFormTests(TestCase):
     def setUp(self):
+        location = get_test_location()
         self.sample_data = {'first_name': 'name',
             'last_name': 'name',
             'sex' : Subject.SEX_CHOICES_MALE,
             'type' : Subject.SUBJECT_TYPE_CHOICES_CONTROL,
-            'default_appointment_location' : Subject.LOCATION_CHOICES_LIH,
+            'default_location' : location.id,
             'country' : 'Luxembourg',
             'screening_number' : '123',
             'nd_number' : 'nd_123'
diff --git a/smash/web/tests/test_VisitAddForm.py b/smash/web/tests/test_VisitAddForm.py
index ae3c4baa3576b9114e3a705c1a6894f11c3985f8..d292124c4fd6b89f8e83a01c0f8ac451655c7519 100644
--- a/smash/web/tests/test_VisitAddForm.py
+++ b/smash/web/tests/test_VisitAddForm.py
@@ -4,13 +4,16 @@ from web.forms import VisitAddForm
 from web.models import Subject
 from web.models import Visit
 
+from web.tests.functions import *
+
 class SubjectAddFormTests(TestCase):
     def setUp(self):
+        location = get_test_location()
         subject_data = {'first_name': 'name',
             'last_name': 'name',
             'sex' : Subject.SEX_CHOICES_MALE,
             'type' : Subject.SUBJECT_TYPE_CHOICES_CONTROL,
-            'default_appointment_location' : Subject.LOCATION_CHOICES_LIH,
+            'default_location' : location.id,
             'country' : 'Luxembourg',
         }
         self.subject = SubjectAddForm(data=subject_data).save()
diff --git a/smash/web/tests/test_view_appointments.py b/smash/web/tests/test_view_appointments.py
new file mode 100644
index 0000000000000000000000000000000000000000..e65829a7fd9c9429d9d9ff4407adf8b3bfad868a
--- /dev/null
+++ b/smash/web/tests/test_view_appointments.py
@@ -0,0 +1,50 @@
+from django.contrib.auth.models import User
+from django.test import TestCase, RequestFactory
+from django.urls import reverse
+
+from web.views import *
+from web.tests.functions import *
+
+class AppointmentsViewTests(TestCase):
+    def setUp(self):
+        # Every test needs access to the request factory.
+        self.factory = RequestFactory()
+        self.user = User.objects.create_user(
+            username='piotr', email='jacob@bla', password='top_secret')
+
+    def test_appointments_list_request(self):
+        request = self.factory.get(reverse('web.views.appointments'));
+        request.user = self.user
+        response = appointments(request);
+        self.assertEqual(response.status_code, 200)
+
+    def test_mark_as_finished(self):
+        subject = create_subject();
+        visit = create_visit(subject)
+        appointment = create_appointment(visit)
+        request = self.factory.get(reverse('web.views.appointment_mark', args=[appointment.id, 'finished']));
+        request.user = self.user
+        response = appointment_mark(request, appointment.id, 'finished');
+        self.assertEqual(response.status_code, 302)
+
+    def test_mark_as_cancelled(self):
+        subject = create_subject();
+        visit = create_visit(subject)
+        appointment = create_appointment(visit)
+        request = self.factory.get(reverse('web.views.appointment_mark', args=[appointment.id, 'cancelled']));
+        request.user = self.user
+        response = appointment_mark(request, appointment.id, 'cancelled');
+        self.assertEqual(response.status_code, 302)
+        update_appointment = Appointment.objects.filter(id= appointment.id)[0]
+        self.assertEqual(update_appointment.status, Appointment.APPOINTMENT_STATUS_CANCELLED)
+
+    def test_mark_as_no_show(self):
+        subject = create_subject();
+        visit = create_visit(subject)
+        appointment = create_appointment(visit)
+        request = self.factory.get(reverse('web.views.appointment_mark', args=[appointment.id, 'no_show']));
+        request.user = self.user
+        response = appointment_mark(request, appointment.id, 'no_show');
+        self.assertEqual(response.status_code, 302)
+        update_appointment = Appointment.objects.filter(id= appointment.id)[0]
+        self.assertEqual(update_appointment.status, Appointment.APPOINTMENT_STATUS_NO_SHOW)
diff --git a/smash/web/tests/test_view_functions.py b/smash/web/tests/test_view_functions.py
new file mode 100644
index 0000000000000000000000000000000000000000..7651e37a4ee5eabfb2e337ec8e05e60b6277a174
--- /dev/null
+++ b/smash/web/tests/test_view_functions.py
@@ -0,0 +1,30 @@
+from django.test import TestCase
+from web.forms import SubjectAddForm
+from web.forms import VisitAddForm
+from web.models import Subject
+from web.models import Visit
+
+from web.tests.functions import *
+
+class ViewFunctionsTests(TestCase):
+    def setUp(self):
+        create_location("tescik")
+        return
+
+    def test_locations_for_user(self):
+        user = create_user()
+
+        self.assertEquals(Location.objects.all().count(), len(get_filter_locations(user)))
+
+    def test_locations_for_worker(self):
+        worker = create_worker()
+
+        self.assertEquals(Location.objects.all().count(), len(get_filter_locations(worker)))
+
+    def test_locations_for_worker_with_location(self):
+        worker = create_worker()
+        worker.locations = [get_test_location()]
+        worker.save()
+        create_location()
+
+        self.assertEquals(1, len(get_filter_locations(worker)))
diff --git a/smash/web/tests/test_view_notifications.py b/smash/web/tests/test_view_notifications.py
new file mode 100644
index 0000000000000000000000000000000000000000..48a93568ccffcf17e457bce57cde71c904f36a56
--- /dev/null
+++ b/smash/web/tests/test_view_notifications.py
@@ -0,0 +1,198 @@
+from django.contrib.auth.models import User
+from django.test import TestCase, RequestFactory
+from django.urls import reverse
+
+from web.views import *
+
+from web.models import *
+
+from web.tests.functions import *
+
+import datetime
+
+
+class NotificationViewTests(TestCase):
+    def setUp(self):
+        # Every test needs access to the request factory.
+        self.factory = RequestFactory()
+        self.user = User.objects.create_user(
+            username='piotr', email='jacob@bla', password='top_secret')
+
+    def test_get_exceeded_visit_notifications_count(self):
+        original_notification = get_visits_without_appointments_count(self.user)
+
+        subject = create_subject()
+        visit = create_visit(subject)
+        visit.datetime_end = "2011-01-01"
+        visit.save()
+        appointment = create_appointment(visit)
+
+        notification = get_exceeded_visit_notifications_count(self.user)
+        self.assertEquals(original_notification.count + 1, notification.count)
+
+    def test_get_exceeded_visit_notifications_count_2(self):
+        original_notification = get_visits_without_appointments_count(self.user)
+
+        subject = create_subject()
+        visit = create_visit(subject)
+        visit.datetime_end = "2011-01-01"
+        visit.is_finished = True
+        visit.save()
+        appointment = create_appointment(visit)
+
+        notification = get_exceeded_visit_notifications_count(self.user)
+        self.assertEquals(original_notification.count, notification.count)
+
+    def test_get_visits_without_appointments_count(self):
+        original_notification = get_visits_without_appointments_count(self.user)
+        subject = create_subject()
+        visit = create_visit(subject)
+
+        notification = get_visits_without_appointments_count(self.user)
+        self.assertEquals(original_notification.count + 1, notification.count)
+
+
+    def test_get_visits_without_appointments_count_3(self):
+        original_notification = get_visits_without_appointments_count(self.user)
+        subject = create_subject()
+        visit = create_visit(subject)
+        appointment = create_appointment(visit)
+
+        appointment.status = Appointment.APPOINTMENT_STATUS_CANCELLED
+        appointment.save()
+
+        notification = get_visits_without_appointments_count(self.user)
+        self.assertEquals(original_notification.count + 1, notification.count)
+
+    def test_get_approaching_visits_without_appointments_count(self):
+        original_notification = get_approaching_visits_without_appointments_count(self.user)
+        subject = create_subject()
+        visit = create_visit(subject)
+        visit.datetime_begin = get_today_midnight_date()+datetime.timedelta(days=2)
+        visit.save()
+
+        notification = get_approaching_visits_without_appointments_count(self.user)
+        self.assertEquals(original_notification.count + 1, notification.count)
+
+    def test_get_approaching_visits_without_appointments_count_2(self):
+        original_notification = get_approaching_visits_without_appointments_count(self.user)
+        subject = create_subject()
+        visit = create_visit(subject)
+        visit.datetime_begin = get_today_midnight_date()+datetime.timedelta(days=2)
+        visit.save()
+        appointment = create_appointment(visit)
+
+        notification = get_approaching_visits_without_appointments_count(self.user)
+        self.assertEquals(original_notification.count, notification.count)
+
+    def test_get_approaching_visits_without_appointments_count_3(self):
+        original_notification = get_approaching_visits_without_appointments_count(self.user)
+        subject = create_subject()
+        visit = create_visit(subject)
+        visit.datetime_begin = get_today_midnight_date()+datetime.timedelta(days=2)
+        visit.save()
+        appointment = create_appointment(visit)
+
+        appointment.status = Appointment.APPOINTMENT_STATUS_CANCELLED
+        appointment.save()
+
+        notification = get_approaching_visits_without_appointments_count(self.user)
+        self.assertEquals(original_notification.count + 1, notification.count)
+
+    def test_get_subject_with_no_visit_notifications_count(self):
+        original_notification = get_subject_with_no_visit_notifications_count(self.user)
+        subject = create_subject()
+
+        notification = get_subject_with_no_visit_notifications_count(self.user)
+        self.assertEquals(original_notification.count + 1, notification.count)
+
+    def test_get_subject_with_no_visit_notifications_count_2(self):
+        original_notification = get_subject_with_no_visit_notifications_count(self.user)
+        subject = create_subject()
+
+        visit = create_visit(subject)
+        visit.is_finished=True
+        visit.save()
+
+        notification = get_subject_with_no_visit_notifications_count(self.user)
+        self.assertEquals(original_notification.count + 1, notification.count)
+
+    def test_get_subject_with_no_visit_notifications_count_3(self):
+        original_notification = get_subject_with_no_visit_notifications_count(self.user)
+        subject = create_subject()
+
+        visit = create_visit(subject)
+
+        notification = get_subject_with_no_visit_notifications_count(self.user)
+        self.assertEquals(original_notification.count, notification.count)
+
+    def test_get_subject_with_no_visit_notifications_count_4(self):
+        original_notification = get_subject_with_no_visit_notifications_count(self.user)
+        subject = create_subject()
+        subject.dead = True
+        subject.save()
+
+        notification = get_subject_with_no_visit_notifications_count(self.user)
+        self.assertEquals(original_notification.count, notification.count)
+
+    def test_get_subject_with_no_visit_notifications_count_5(self):
+        original_notification = get_subject_with_no_visit_notifications_count(self.user)
+        subject = create_subject()
+        subject.resigned = True
+        subject.save()
+
+        notification = get_subject_with_no_visit_notifications_count(self.user)
+        self.assertEquals(original_notification.count, notification.count)
+
+    def test_get_unfinished_appointments_count(self):
+        original_notification = get_unfinished_appointments_count(self.user)
+        subject = create_subject()
+        visit = create_visit(subject)
+        appointment = create_appointment(visit)
+        appointment.datetime_when = "2011-01-01"
+        appointment.status = Appointment.APPOINTMENT_STATUS_SCHEDULED
+        appointment.save()
+
+        notification = get_unfinished_appointments_count(self.user)
+        self.assertEquals(original_notification.count + 1, notification.count)
+
+    def test_get_unfinished_appointments_count_2(self):
+        original_notification = get_unfinished_appointments_count(self.user)
+        subject = create_subject()
+        visit = create_visit(subject)
+        appointment = create_appointment(visit)
+        appointment.datetime_when = "2011-01-01"
+        appointment.status = Appointment.APPOINTMENT_STATUS_CANCELLED
+        appointment.save()
+
+        notification = get_unfinished_appointments_count(self.user)
+        self.assertEquals(original_notification.count, notification.count)
+
+    def test_get_subject_with_no_visit_notifications_count_for_many_locations(self):
+        create_location("l1")
+        create_location("l2")
+        original_notification = get_subject_with_no_visit_notifications_count(self.user)
+        subject = create_subject()
+
+        notification = get_subject_with_no_visit_notifications_count(self.user)
+        self.assertEquals(original_notification.count + 1, notification.count)
+
+    def test_get_subject_with_no_visit_notifications_count_for_invalid_location(self):
+        worker = create_worker()
+        worker.locations= [create_location("l2")]
+        worker.save()
+
+        original_notification = get_subject_with_no_visit_notifications_count(worker)
+
+        subject = create_subject()
+        subject.default_location=create_location("l1")
+        subject.save()
+
+        notification = get_subject_with_no_visit_notifications_count(worker)
+        self.assertEquals(original_notification.count, notification.count)
+
+        worker.locations= Location.objects.filter(name="l1")
+        worker.save()
+
+        notification = get_subject_with_no_visit_notifications_count(worker)
+        self.assertEquals(original_notification.count +1, notification.count)
diff --git a/smash/web/tests/test_view_visit.py b/smash/web/tests/test_view_visit.py
new file mode 100644
index 0000000000000000000000000000000000000000..8006943047ef7c88e86d492a1f732e9615957b20
--- /dev/null
+++ b/smash/web/tests/test_view_visit.py
@@ -0,0 +1,26 @@
+from django.contrib.auth.models import User
+from django.test import TestCase, RequestFactory
+from django.urls import reverse
+
+from web.views import *
+
+from web.models import *
+
+from web.tests.functions import *
+
+class VisitViewTests(TestCase):
+    def setUp(self):
+        # Every test needs access to the request factory.
+        self.factory = RequestFactory()
+        self.user = User.objects.create_user(
+            username='piotr', email='jacob@bla', password='top_secret')
+
+    def test_visit_details_request(self):
+        subject = create_subject()
+        visit = create_visit(subject)
+        appointment = create_appointment(visit)
+
+        request = self.factory.get(reverse('web.views.visit_details', args=[visit.id]));
+        request.user = self.user
+        response = visit_details(request, visit.id);
+        self.assertEqual(response.status_code, 200)
diff --git a/smash/web/urls.py b/smash/web/urls.py
index bf78ef96158d66d42d82d4f585b9269f60fad24f..fd7a2f8a936c658c3b356240c93993e1efe0a48f 100644
--- a/smash/web/urls.py
+++ b/smash/web/urls.py
@@ -14,43 +14,62 @@ Including another URLconf
     2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
 """
 from django.conf.urls import url
+from django.conf.urls import include
+
 from web import views
 
+from django.conf import settings
+
 urlpatterns = [
-    url(r'appointments$', views.appointments, name='web.views.appointments'),
-    url(r'appointments/details/(?P<id>\d+)$', views.appointment_details, name='web.views.appointment_details'),
-    url(r'appointments/add/(?P<id>\d+)$', views.appointment_add, name='web.views.appointment_add'),
-    url(r'appointments/edit/(?P<id>\d+)$', views.appointment_edit, name='web.views.appointment_edit'),
-    url(r'appointments/edit_datetime/(?P<id>\d+)$', views.appointment_edit_datetime, name='web.views.appointment_edit_datetime'),
-    url(r'appointments/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.appointment_mark, name='web.views.appointment_mark'),
-
-    url(r'visits$', views.visits, name='web.views.visits'),
-    url(r'visits/details/(?P<id>\d+)$', views.visit_details, name='web.views.visit_details'),
-    url(r'visits/add$', views.visit_add, name='web.views.visit_add'),
-    url(r'visit/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.visit_mark, name='web.views.visit_mark'),
-
-    url(r'subjects$', views.subjects, name='web.views.subjects'),
-    url(r'subjects/add$', views.subject_add, name='web.views.subject_add'),
-    url(r'subjects/details/(?P<id>\d+)$', views.subject_details, name='web.views.subject_details'),
-    url(r'subjects/subject_visit_details/(?P<id>\d+)$', views.subject_visit_details, name='web.views.subject_visit_details'),
-    url(r'subjects/edit/(?P<id>\d+)$', views.subject_edit, name='web.views.subject_edit'),
-    url(r'subjects/delete/(?P<id>\d+)$', views.subject_delete, name='web.views.subject_delete'),
-    url(r'subjects/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.subject_mark, name='web.views.subject_mark'),
-
-    url(r'doctors$', views.doctors, name='web.views.doctors'),
-    url(r'doctors/add$', views.doctor_add, name='web.views.doctor_add'),
-    url(r'doctors/details/(?P<doctor_id>\d+)$', views.doctor_details, name='web.views.doctor_details'),
-    url(r'doctors/edit/(?P<doctor_id>\d+)$', views.doctor_edit, name='web.views.doctor_edit'),
-    url(r'doctors/availability/(?P<doctor_id>\d+)$', views.doctor_availability, name='web.views.doctor_availability'),
-    url(r'doctors/availability/(?P<doctor_id>\d+)/delete/(?P<availability_id>\d+)$', views.doctor_availability_delete, name='web.views.doctor_availability_delete'),
-
-    url(r'equipment_and_rooms$', views.equipment_and_rooms, name='web.views.equipment_and_rooms'),
-    url(r'equipment_and_rooms/eqdef$', views.equipment_def, name='web.views.equipment_def'),
-
-    url(r'mail_templates$', views.mail_templates, name='web.views.mail_templates'),
-
-    url(r'login$', views.login, name='web.views.login'),
-    url(r'logout$', views.logout, name='web.views.logout'),
+    url(r'^appointments$', views.appointments, name='web.views.appointments'),
+    url(r'^appointments/unfinished$', views.unfinished_appointments, name='web.views.unfinished_appointments'),
+    url(r'^appointments/details/(?P<id>\d+)$', views.appointment_details, name='web.views.appointment_details'),
+    url(r'^appointments/add/(?P<id>\d+)$', views.appointment_add, name='web.views.appointment_add'),
+    url(r'^appointments/edit/(?P<id>\d+)$', views.appointment_edit, name='web.views.appointment_edit'),
+    url(r'^appointments/edit_datetime/(?P<id>\d+)$', views.appointment_edit_datetime, name='web.views.appointment_edit_datetime'),
+    url(r'^appointments/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.appointment_mark, name='web.views.appointment_mark'),
+
+    url(r'^visits$', views.visits, name='web.views.visits'),
+    url(r'^visits/exceeded$', views.exceeded_visits, name='web.views.exceeded_visits'),
+    url(r'^visits/unfinished$', views.unfinished_visits, name='web.views.unfinished_visits'),
+    url(r'^visits/approaching$', views.approaching_visits_without_appointments, name='web.views.approaching_visits_without_appointments'),
+    url(r'^visits/details/(?P<id>\d+)$', views.visit_details, name='web.views.visit_details'),
+    url(r'^visits/add$', views.visit_add, name='web.views.visit_add'),
+    url(r'^visits/add/(?P<subject_id>\d+)$', views.visit_add, name='web.views.visit_add'),
+    url(r'^visit/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.visit_mark, name='web.views.visit_mark'),
+
+    url(r'^subjects$', views.subjects, name='web.views.subjects'),
+    url(r'^subjects/no_visit$', views.subject_no_visits, name='web.views.subject_no_visits'),
+    url(r'^subjects/add$', views.subject_add, name='web.views.subject_add'),
+    url(r'^subjects/details/(?P<id>\d+)$', views.subject_details, name='web.views.subject_details'),
+    url(r'^subjects/subject_visit_details/(?P<id>\d+)$', views.subject_visit_details, name='web.views.subject_visit_details'),
+    url(r'^subjects/edit/(?P<id>\d+)$', views.subject_edit, name='web.views.subject_edit'),
+    url(r'^subjects/delete/(?P<id>\d+)$', views.subject_delete, name='web.views.subject_delete'),
+    url(r'^subjects/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.subject_mark, name='web.views.subject_mark'),
+
+    url(r'^doctors$', views.doctors, name='web.views.doctors'),
+    url(r'^doctors/add$', views.doctor_add, name='web.views.doctor_add'),
+    url(r'^doctors/details/(?P<doctor_id>\d+)$', views.doctor_details, name='web.views.doctor_details'),
+    url(r'^doctors/edit/(?P<doctor_id>\d+)$', views.doctor_edit, name='web.views.doctor_edit'),
+    url(r'^doctors/availability/(?P<doctor_id>\d+)$', views.doctor_availability, name='web.views.doctor_availability'),
+    url(r'^doctors/availability/(?P<doctor_id>\d+)/delete/(?P<availability_id>\d+)$', views.doctor_availability_delete, name='web.views.doctor_availability_delete'),
+
+    url(r'^equipment_and_rooms$', views.equipment_and_rooms, name='web.views.equipment_and_rooms'),
+    url(r'^equipment_and_rooms/eqdef$', views.equipment_def, name='web.views.equipment_def'),
+
+    url(r'^mail_templates$', views.mail_templates, name='web.views.mail_templates'),
+
+    url(r'^export$', views.export, name='web.views.export'),
+    url(r'^export/(?P<type>[A-z]+)$', views.export_to_csv2, name='web.views.export_to_csv2'),
+
+    url(r'^login$', views.login, name='web.views.login'),
+    url(r'^logout$', views.logout, name='web.views.logout'),
 
 	url(r'^$', views.index, name='web.views.index')
 ]
+
+if settings.DEBUG:
+    import debug_toolbar
+    urlpatterns += [
+        url(r'^__debug__/', include(debug_toolbar.urls)),
+    ]
diff --git a/smash/web/views.py b/smash/web/views.py
index 99aa99903befe437ab2250e772219adf384e6fb3..af3596fd90d77341f9c0622d0c84c8629f8d3415 100644
--- a/smash/web/views.py
+++ b/smash/web/views.py
@@ -12,6 +12,12 @@ from django.shortcuts import render
 from django.db.models import Q
 import collections
 import datetime
+from django.db.models import Count
+from django.db.models import Case
+from django.db.models import When
+
+import csv
+
 
 # See https://docs.djangoproject.com/en/1.10/topics/http/views/#customizing-error-views
 # They should work ONLY in production! (DEBUG=False)
@@ -27,17 +33,17 @@ def index(request):
 	return redirect(login)
 
 
-def e404_page_not_found(request):
-	return render(request, "errors/404.html", context)
+def e404_page_not_found(request, context = None):
+	return render(request, "errors/404.html", context, status=404)
 
-def e500_error(request):
-	return render(request, "errors/500.html", context)
+def e500_error(request, context = None):
+	return render(request, "errors/500.html", context, status=500)
 
-def e403_permission_denied(request):
-	return render(request, "errors/403.html", context)
+def e403_permission_denied(request, context = None):
+	return render(request, "errors/403.html", context, status=403)
 
-def e400_bad_request(request):
-	return render(request, "errors/400.html", context)
+def e400_bad_request(request, context = None):
+	return render(request, "errors/400.html", context, status=400)
 
 
 def login(request):
@@ -56,6 +62,131 @@ def login(request):
 
 	return render(request, "login.html", context)
 
+class NotificationCount(object):
+	title = ""
+	count = 0
+	style = ""
+	type = ''
+
+	def __init__(self, title ="Unknown", count = 0, style = "fa fa-users text-aqua", type = 'web.views.appointments'):
+		self.title = title
+		self.count = count
+		self.style = style
+		self.type = type
+
+def get_filter_locations(user):
+	worker = None
+	if isinstance(user, User):
+		workers = Worker.objects.filter(user=user)
+		if len(workers)>0:
+			worker = workers[0]
+	else:
+		worker = user
+
+	if worker==None or worker.locations.count() == 0:
+		return Location.objects.all()
+	else:
+		return worker.locations.all()
+
+def get_exceeded_visits(user):
+	return Visit.objects.filter(datetime_end__lt = get_today_midnight_date(),
+								is_finished = False,
+								subject__default_location__in = get_filter_locations(user)
+								).order_by('datetime_begin')
+
+def get_exceeded_visit_notifications_count(user):
+	notification = NotificationCount(
+		title = "exceeded visit time",
+		count = get_exceeded_visits(user).count(),
+		style = "fa fa-thermometer-4 text-red",
+		type = 'web.views.exceeded_visits')
+	return notification
+
+
+def get_subjects_with_no_visit(user):
+	result = Subject.objects.annotate(my_count=Count(Case(When(visit__is_finished=False, then=1)))).filter(
+		dead=False,
+		resigned=False,
+		my_count=0,
+		default_location__in = get_filter_locations(user)
+		)
+	return result
+
+def get_subject_with_no_visit_notifications_count(user):
+	notification = NotificationCount(
+		title = "subject without visit",
+		count = get_subjects_with_no_visit(user).count(),
+	 	style = "fa fa-users text-aqua",
+		type = 'web.views.subject_no_visits')
+	return notification
+
+
+def get_visits_without_appointments_count(user):
+	notification = NotificationCount(
+		title = "unfinished visits ",
+		count = get_unfinished_visits(user).count(),
+		style = "fa fa-user-times text-yellow",
+		type = 'web.views.unfinished_visits')
+	return notification
+
+def get_unfinished_visits(user):
+	today = get_today_midnight_date()
+	#list visits that have no scheduled appointments and taking place now
+	return Visit.objects.annotate(my_count=Count(Case(When(appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED, then=1)))).filter(
+		datetime_begin__lt = today,
+		datetime_end__gt = today,
+		is_finished = False,
+		subject__default_location__in = get_filter_locations(user),
+		my_count=0)
+
+def get_approaching_visits_without_appointments_count(user):
+	notification = NotificationCount(
+		title = "approaching visits ",
+		count = get_approaching_visits_without_appointments(user).count(),
+		style = "fa fa-users text-aqua",
+		type = 'web.views.approaching_visits_without_appointments')
+	return notification
+
+def get_approaching_visits_without_appointments(user):
+	today = get_today_midnight_date()
+	today_plus_two_months =today+datetime.timedelta(days=62)
+	return Visit.objects.annotate(my_count=Count(Case(When(appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED, then=1)))).filter(
+		datetime_begin__gt = today,
+		datetime_begin__lt = today_plus_two_months,
+		is_finished = False,
+		subject__default_location__in = get_filter_locations(user),
+		my_count=0)
+
+
+def get_unfinished_appointments_count(user):
+	return NotificationCount(
+		title = "unfinished appointments ",
+		count = get_unfinished_appointments(user).count(),
+		style = "fa fa-history text-yellow",
+		type = 'web.views.unfinished_appointments')
+
+def get_unfinished_appointments(user):
+	return Appointment.objects.filter(
+		datetime_when__lt = get_today_midnight_date(),
+		status = Appointment.APPOINTMENT_STATUS_SCHEDULED,
+		location__in = get_filter_locations(user),
+		)
+
+def get_notifications(the_user):
+	workers = Worker.objects.filter(user=the_user)
+	notifications = []
+	count = 0;
+	if len(workers)>0:
+		person = workers[0]
+		if person.role == Worker.ROLE_CHOICES_SECRETARY:
+			notifications.append(get_exceeded_visit_notifications_count(person))
+			notifications.append(get_visits_without_appointments_count(person))
+			notifications.append(get_approaching_visits_without_appointments_count(person))
+			notifications.append(get_unfinished_appointments_count(person))
+			notifications.append(get_subject_with_no_visit_notifications_count(person))
+			for notification in notifications:
+				count += notification.count
+	return (count, notifications)
 
 """
 Saturates response with information about logged user
@@ -64,10 +195,13 @@ Saturates response with information about logged user
 def wrap_response(request, template, params):
 	person, role = Worker.get_details(request.user)
 
+	notifications = get_notifications(request.user)
+
 	final_params = params.copy()
 	final_params.update({
 		'person' : person,
-		'role': role
+		'role': role,
+		'notifications': notifications
 	})
 
 	return render(request, template, final_params)
@@ -87,6 +221,25 @@ def visits(request):
 
 	return wrap_response(request, 'visits/index.html', context)
 
+def exceeded_visits(request):
+	context = {
+		'visit_list': get_exceeded_visits(request.user)
+	}
+	return wrap_response(request, 'visits/index.html', context)
+
+def unfinished_visits(request):
+	context = {
+		'visit_list': get_unfinished_visits(request.user)
+	}
+
+	return wrap_response(request, 'visits/index.html', context)
+
+def approaching_visits_without_appointments(request):
+	context = {
+		'visit_list': get_approaching_visits_without_appointments(request.user)
+	}
+
+	return wrap_response(request, 'visits/index.html', context)
 
 def visit_details(request, id):
 	displayedVisit = get_object_or_404(Visit, id=id)
@@ -96,7 +249,7 @@ def visit_details(request, id):
 	listOfAppointments = displayedVisit.appointment_set.all()
 	canFinish=True
 	for appointment in listOfAppointments:
-		if not appointment.is_finished:
+		if appointment.status == Appointment.APPOINTMENT_STATUS_SCHEDULED:
 			canFinish=False;
 	vform = VisitDetailForm(instance=displayedVisit)
 	sform = SubjectDetailForm(instance=displayedSubject)
@@ -108,19 +261,23 @@ def visit_mark(request, id, as_what):
 	if as_what == 'finished':
 		visit.mark_as_finished()
 
-	visit = get_object_or_404(Visit, id=id)
-	return redirect(visit_details, id=visit.subject.latest_visit().id)
+	return redirect(visit_details, id=id)
 
 
 
-def visit_add(request):
+def visit_add(request, subject_id = -1):
 	if request.method == 'POST':
 		form = VisitAddForm(request.POST, request.FILES)
 		if form.is_valid():
 			form.save()
 			return redirect(visits)
 	else:
-		form = VisitAddForm()
+		subjects = Subject.objects.filter(id=subject_id)
+		subject = None
+		if len(subjects)>0:
+			subject = subjects[0]
+		form = VisitAddForm(initial={'subject':subject})
+
 
 	return wrap_response(request, 'visits/add.html', {'form': form})
 
@@ -147,6 +304,13 @@ def subject_add(request):
 
 	return wrap_response(request, 'subjects/add.html', {'form': form})
 
+def subject_no_visits(request):
+	subjects_list = get_subjects_with_no_visit(request.user).order_by('-last_name')
+	context = {
+		'subjects_list':  subjects_list
+	}
+
+	return wrap_response(request, 'subjects/index.html', context)
 
 def subject_details(request, id):
 	the_subject = get_object_or_404(Subject, id=id)
@@ -190,6 +354,12 @@ def appointment_mark(request, id, as_what):
 	appointment = get_object_or_404(Appointment, id=id)
 	if as_what == 'finished':
 		appointment.mark_as_finished()
+	elif as_what == 'cancelled':
+		appointment.mark_as_cancelled()
+	elif as_what == 'no_show':
+		appointment.mark_as_no_show()
+	else:
+		return e500_error(request)
 	return redirect(visit_details, id=appointment.visit.id)
 
 def subject_visit_details(request, id):
@@ -198,16 +368,13 @@ def subject_visit_details(request, id):
 	endlist = []
 	for vis in visits:
 		assign = vis.appointment_set.all()
-		print assign
 		finished = vis.is_finished
 		visid = vis.id
 		visit_title = vis.follow_up_title()
 		visform = VisitDetailForm(instance=vis)
 		endlist.append((visform,assign,finished,visid,visit_title))
 
-	#print len(endlist)
-	#print endlist[0]
-	return wrap_response(request, 'subjects/visitdetails.html', {'display': endlist})
+	return wrap_response(request, 'subjects/visitdetails.html', {'display': endlist, "id":id})
 
 def doctors(request):
 	doctors_list = Worker.objects.order_by('-last_name')
@@ -317,29 +484,43 @@ def suggest_details(Appointment appoint):
 
 """
 
-
-def appointments(request):
-	futureDate = datetime.datetime.now()+datetime.timedelta(days=93)
-	planning_list = Appointment.objects.filter(datetime_when__isnull=True, visit__datetime_begin__lt = futureDate)
-
+def get_today_midnight_date():
 	today = datetime.datetime.now()
 	today_midnight = datetime.datetime(today.year,today.month,today.day)
-	month_ago = today +datetime.timedelta(days=-31)
-	approaching_list = Appointment.objects.filter(datetime_when__gt = today_midnight, is_finished = False).order_by('datetime_when')
-	full_list = Appointment.objects.filter(datetime_when__gt = month_ago).order_by('datetime_when')
+	return today_midnight
+
+def get_calendar_full_appointments(user):
+	month_ago = get_today_midnight_date() + datetime.timedelta(days=-31)
+	return Appointment.objects.filter(
+			datetime_when__gt = month_ago,
+			location__in = get_filter_locations(user),
+			).order_by('datetime_when')
+
 
+def appointments(request):
+	approaching_list = Appointment.objects.filter(
+		datetime_when__gt = get_today_midnight_date(),
+		location__in = get_filter_locations(request.user),
+		status = Appointment.APPOINTMENT_STATUS_SCHEDULED
+		).order_by('datetime_when')
 
-	for plan in planning_list:
-		plan.datetime_when = plan.visit.datetime_begin
+	full_list = get_calendar_full_appointments(request.user)
 
 	context = {
-		'planning_list': planning_list,
 		'approaching_list': approaching_list,
 		'full_list': full_list
 	}
 
 	return wrap_response(request, "appointments/index.html",context)
 
+def unfinished_appointments(request):
+	appointments = get_unfinished_appointments(request.user)
+	context = {
+		'appointment_list': appointments,
+	}
+
+	return wrap_response(request, "appointments/list.html",context)
+
 def appointment_details(request, id):
 	the_appointment = get_object_or_404(Appointment, id=id)
 	form = AppointmentDetailForm(instance=the_appointment)
@@ -347,10 +528,7 @@ def appointment_details(request, id):
 
 
 def appointment_add(request, id):
-	today = datetime.datetime.now()
-	today_midnight = datetime.datetime(today.year,today.month,today.day)
-	month_ago = today +datetime.timedelta(days=-31)
-	full_list = Appointment.objects.filter(datetime_when__gt = month_ago).order_by('datetime_when')
+	full_list = get_calendar_full_appointments(request.user)
 	if request.method == 'POST':
 		form = AppointmentAddForm(request.POST, request.FILES)
 		form.fields['visit'].widget = forms.HiddenInput()
@@ -373,12 +551,11 @@ def appointment_edit(request, id):
 			data = form.cleaned_data
 			vis = data['visit']
 			visit = get_object_or_404(Visit, id=vis.id)
-			visit.end_if_appointments_were_finished()
 
 			return redirect(appointments)
 	else:
 		form = AppointmentEditForm(instance=the_appointment)
-	return wrap_response(request, 'appointments/edit.html', {'form': form, 'id':id})
+	return wrap_response(request, 'appointments/edit.html', {'form': form, 'id':id, 'status': the_appointment.status})
 
 
 def appointment_edit_datetime(request, id):
@@ -392,3 +569,63 @@ def appointment_edit_datetime(request, id):
 		the_appointment.datetime_when = the_appointment.visit.datetime_begin
 		form = AppointmentEditForm(instance=the_appointment)
 	return wrap_response(request, 'appointments/edit.html', {'form': form})
+
+def export_to_csv2(request, type="subjects"):
+    #Create the HttpResponse object with the appropriate CSV header.
+	response = HttpResponse(content_type='text/csv')
+	response['Content-Disposition'] = 'attachment; filename="'+type+'-'+get_today_midnight_date().strftime("%Y-%m-%d")+'.csv"'
+
+	writer = csv.writer(response, quotechar =str(u'"'), quoting = csv.QUOTE_ALL)
+	if type=="subjects":
+		write_subjects_to_csv(writer)
+	elif type=="appointments":
+		write_appointments_to_csv(writer)
+	else:
+		return e500_error(request)
+	return response
+
+def write_subjects_to_csv(writer):
+	subject_fields = []
+	for field in Subject._meta.fields:
+		if  field.name!="ID":
+			subject_fields.append(field)
+
+	field_names = []
+	for field in subject_fields:
+		field_names.append(field.verbose_name)
+
+	writer.writerow(field_names)
+
+	subjects = Subject.objects.order_by('-last_name')
+	for subject in subjects:
+		row = []
+		for field in subject_fields:
+			row.append(getattr(subject,field.name))
+		writer.writerow(row)
+
+def write_appointments_to_csv(writer):
+	appointments_fields = []
+	for field in Appointment._meta.fields:
+		if field.name!="visit" and field.name!="id" and	field.name!="worker_assigned" and field.name!="appointment_types" and field.name!="room" and field.name!="flying_team":
+			appointments_fields.append(field)
+
+	field_names = []
+	for field in appointments_fields:
+		field_names.append(field.verbose_name)
+
+	writer.writerow(field_names)
+
+	appointments = Appointment.objects.order_by('-datetime_when')
+
+	for appointment in appointments:
+		row = []
+		row.append(appointment.visit.subject.nd_number)
+		row.append(appointment.visit.subject.last_name)
+		row.append(appointment.visit.subject.first_name)
+		row.append(appointment.visit.follow_up_title())
+		for field in appointments_fields:
+			row.append(getattr(appointment,field.name))
+		writer.writerow(row)
+
+def export(request):
+	return wrap_response(request, 'export/index.html',{})