diff --git a/.gitignore b/.gitignore index 694db65d9869500b8ada53accd417f9a8d60ef11..e882e145fcec335b65eaeade223514c9ce1824a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,18 @@ # Disable virtualenv env/* +# Disable migration files +smash/web/migrations/* + +# Folder with db statics (dev mode) +smash/~/ + # Disable python bytecode *.pyc # Disable local developer settings local_settings.py + +#tmp files +appointment-import/testFiles/~* +appointment-import/tmp.sql diff --git a/appointment-import/.classpath b/appointment-import/.classpath new file mode 100644 index 0000000000000000000000000000000000000000..f7b62f180179a74fbb8400870e0e56b071065daa --- /dev/null +++ b/appointment-import/.classpath @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" output="target/classes" path="src/main/java"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="src" output="target/test-classes" path="src/test/java"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="output" path="target/classes"/> +</classpath> diff --git a/appointment-import/.gitignore b/appointment-import/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b83d22266ac8aa2f8df2edef68082c789727841d --- /dev/null +++ b/appointment-import/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/appointment-import/.project b/appointment-import/.project new file mode 100644 index 0000000000000000000000000000000000000000..eee5e1c7df61a5e6865e9a8584bb8c4c4becfe6a --- /dev/null +++ b/appointment-import/.project @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>appointment-import</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.m2e.core.maven2Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>org.eclipse.m2e.core.maven2Nature</nature> + </natures> +</projectDescription> diff --git a/appointment-import/.settings/org.eclipse.core.resources.prefs b/appointment-import/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000000000000000000000000000000000..04cfa2c1a8566d64dd12fcf7a8e895fe02e1856f --- /dev/null +++ b/appointment-import/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/<project>=UTF-8 diff --git a/appointment-import/.settings/org.eclipse.jdt.core.prefs b/appointment-import/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000000000000000000000000000000000..bbcbc93486d53c73668b275ea5daf41b66ba9c41 --- /dev/null +++ b/appointment-import/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/appointment-import/.settings/org.eclipse.m2e.core.prefs b/appointment-import/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000000000000000000000000000000000000..14b697b7bbb0d85e8d8ee19141a2a92d9ce211be --- /dev/null +++ b/appointment-import/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/appointment-import/pom.xml b/appointment-import/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..a2244ee9c27fc393f0190108de420b7cb272a67c --- /dev/null +++ b/appointment-import/pom.xml @@ -0,0 +1,72 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>smash</groupId> + <artifactId>appointment-import</artifactId> + <version>0.0.1-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>appointment-import</name> + <url>http://maven.apache.org</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> +<dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <version>1.2.17</version> +</dependency> +<dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi-ooxml</artifactId> + <version>3.15</version> +</dependency> +<dependency> + <groupId>commons-cli</groupId> + <artifactId>commons-cli</artifactId> + <version>1.3.1</version> +</dependency> + </dependencies> + + <build> + <plugins> +<plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.5.1</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> +</plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <configuration> + <source>1.7</source> + <target>1.7</target> + <archive> + <manifest> + <addClasspath>true</addClasspath> + <mainClass>smash.appointment.parse.Main</mainClass> + </manifest> + </archive> + <descriptorRefs> + <descriptorRef>jar-with-dependencies</descriptorRef> + </descriptorRefs> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/appointment-import/src/main/java/smash/appointment/parse/AppointmentDao.java b/appointment-import/src/main/java/smash/appointment/parse/AppointmentDao.java new file mode 100644 index 0000000000000000000000000000000000000000..fa9a57f9a3fc80456e4bfa307da2375548751569 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/AppointmentDao.java @@ -0,0 +1,108 @@ +package smash.appointment.parse; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + +public class AppointmentDao { + Logger logger = Logger.getLogger(AppointmentDao.class); + private List<AppointmentEntry> appointments = new ArrayList<>(); + + public void addAppointments(List<AppointmentEntry> appointmentsToAdd) { + for (AppointmentEntry appointmentEntry : appointmentsToAdd) { + addAppointment(appointmentEntry); + } + } + + /** + * @return the appointments + * @see #appointments + */ + public List<AppointmentEntry> getAppointments() { + return appointments; + } + + /** + * @param appointments + * the appointments to set + * @see #appointments + */ + public void setAppointments(List<AppointmentEntry> appointments) { + this.appointments = appointments; + } + + public List<Visit> getVisits() { + List<Visit> result = new ArrayList<>(); + Map<Subject, List<AppointmentEntry>> subjectAppointments = new HashMap<>(); + for (AppointmentEntry entry : appointments) { + if (subjectAppointments.get(entry.getSubject()) == null) { + subjectAppointments.put(entry.getSubject(), new ArrayList<AppointmentEntry>()); + } + subjectAppointments.get(entry.getSubject()).add(entry); + } + for (Subject subject : subjectAppointments.keySet()) { + result.addAll(getVisitsForSubject(subject, subjectAppointments.get(subject))); + } + return result; + } + + private List<Visit> getVisitsForSubject(Subject subject, List<AppointmentEntry> list) { + Comparator<AppointmentEntry> comparator = new Comparator<AppointmentEntry>() { + + @Override + public int compare(AppointmentEntry o1, AppointmentEntry o2) { + String date1 = o1.getDay().substring(0, 10); + String date2 = o2.getDay().substring(0, 10); + if (date1.compareTo(date2) == 0) { + if (o1.getTypes().contains(AppointmentType.LEVEL_A) || o1.getTypes().contains(AppointmentType.LEVEL_A_TQ)) { + return -1; + } else if (o2.getTypes().contains(AppointmentType.LEVEL_A) || o2.getTypes().contains(AppointmentType.LEVEL_A_TQ)) { + return 1; + } else { + return 0; + } + } else { + return date1.compareTo(date2); + } + } + }; + Collections.sort(list, comparator); + + List<Visit> result = new ArrayList<>(); + Visit currentVisit = new Visit(subject); + for (AppointmentEntry appointmentEntry : list) { + if (appointmentEntry.getTypes().contains(AppointmentType.LEVEL_A) || appointmentEntry.getTypes().contains(AppointmentType.LEVEL_A_TQ)) { + if (currentVisit.getAppointments().size() > 0) { + result.add(currentVisit); + } + + currentVisit = new Visit(subject); + currentVisit.addAppointment(appointmentEntry); + } else { + 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(); + currentVisit.getLastAppointment().setSource(source); + } else { + currentVisit.addAppointment(appointmentEntry); + } + } + } + if (currentVisit.getAppointments().size() > 0) { + result.add(currentVisit); + } + return result; + } + + 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 new file mode 100644 index 0000000000000000000000000000000000000000..b4faf7c678c40b3daa3f6429d2314ce8d11e87ce --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/AppointmentEntry.java @@ -0,0 +1,147 @@ +package smash.appointment.parse; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class AppointmentEntry { + private String day; + private String time; + private String duration; + private Subject subject; + private Set<AppointmentType> types = new HashSet<>(); + private String source; + + /** + * @return the time + * @see #time + */ + public String getTime() { + if (time == null || time.trim().isEmpty()) { + return "09:00"; + } else { + return time; + } + } + + /** + * @param time + * the time to set + * @see #time + */ + public void setTime(String time) { + this.time = time; + } + + /** + * @return the subject + * @see #subject + */ + public Subject getSubject() { + return subject; + } + + /** + * @param subject + * the subject to set + * @see #subject + */ + public void setSubject(Subject subject) { + this.subject = subject; + } + + /** + * @return the type + * @see #type + */ + public Set<AppointmentType> getTypes() { + return types; + } + + /** + * @param type + * the type to set + * @see #type + */ + public void addType(AppointmentType type) { + this.types.add(type); + } + + /** + * @return the day + * @see #day + */ + public String getDay() { + return day; + } + + /** + * @param day + * the day to set + * @see #day + */ + public void setDay(String day) { + this.day = day; + } + + /** + * @return the source + * @see #source + */ + public String getSource() { + return source; + } + + /** + * @param source + * the source to set + * @see #source + */ + public void setSource(String source) { + this.source = source; + } + + @Override + public String toString() { + return day + " " + time + " " + subject + " " + types + "\t\t[source: " + source + "]"; + } + + /** + * @return the duration + * @see #duration + */ + public String getDuration() { + if (duration == null || duration.trim().isEmpty()) { + int count = 0; + for (AppointmentType type : types) { + count += type.getTime(); + } + return count + ""; + } + return duration; + } + + /** + * @param duration + * the duration to set + * @see #duration + */ + public void setDuration(String duration) { + this.duration = duration; + } + + public void addTypes(AppointmentType[] typesToAdd) { + for (AppointmentType appointmentType : typesToAdd) { + addType(appointmentType); + } + + } + + public void addTypes(Collection<AppointmentType> typesToAdd) { + for (AppointmentType appointmentType : typesToAdd) { + addType(appointmentType); + } + + } +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/AppointmentSqlExporter.java b/appointment-import/src/main/java/smash/appointment/parse/AppointmentSqlExporter.java new file mode 100644 index 0000000000000000000000000000000000000000..6966c9ec3dcea9a0d39f302eb625c6aeb923005a --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/AppointmentSqlExporter.java @@ -0,0 +1,36 @@ +package smash.appointment.parse; + +public class AppointmentSqlExporter extends SqlExporter { + + public String toSql(AppointmentEntry appointment, boolean isFinished) { + StringBuilder result = new StringBuilder(""); + + result.append("insert into web_appointment ("); + result.append("datetime_when, "); + result.append("length, "); + result.append("is_finished, "); + result.append("comment, "); + result.append("visit_id) "); + + result.append("values ("); + result.append(getStringVal(appointment.getDay() + " " + appointment.getTime()+"+00") + ","); + result.append(getStringVal(appointment.getDuration()) + ","); + result.append(isFinished + ","); + result.append(getStringVal(appointment.getSource()) + ","); + result.append("(select max(id) from web_visit)"); + result.append(");"); + + for (AppointmentType type : appointment.getTypes()) { + result.append("insert 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(");"); + } + + return result.toString(); + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/AppointmentType.java b/appointment-import/src/main/java/smash/appointment/parse/AppointmentType.java new file mode 100644 index 0000000000000000000000000000000000000000..bceb087694fe573ae698e4251a7364557624f402 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/AppointmentType.java @@ -0,0 +1,29 @@ +package smash.appointment.parse; + +public enum AppointmentType { + LEVEL_BV(90,"BV"), // + LEVEL_BG(30,"BG"), // + LEVEL_SB(30,"SB"), // + + LEVEL_A_TQ(120,"A_TQ"), // + LEVEL_A(120,"A"), // + LEVEL_B(90,"B"), // + LEVEL_B_M_POWER(70,"mPower"), // + OTHER(60,"OTHER"), // + ; + + private int time; + private String abbreviation; + + private AppointmentType(int defaultTime, String abbreviation) { + this.time=defaultTime; + this.abbreviation=abbreviation; + } + public int getTime() { + return time; + } + public String getAbbreviation() { + return abbreviation; + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/AppointmentTypeCollection.java b/appointment-import/src/main/java/smash/appointment/parse/AppointmentTypeCollection.java new file mode 100644 index 0000000000000000000000000000000000000000..c4fdcc15a17c91f517da687112ce87bff8298940 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/AppointmentTypeCollection.java @@ -0,0 +1,78 @@ +package smash.appointment.parse; + +public enum AppointmentTypeCollection { + LEVEL_A_BV_BG(new AppointmentType[] { AppointmentType.LEVEL_A, AppointmentType.LEVEL_BV, AppointmentType.LEVEL_BG }, // + new String[] { "BV + BG + neuro level A" }), // + LEVEL_A_B(new AppointmentType[] { AppointmentType.LEVEL_A, AppointmentType.LEVEL_B }, // + new String[] { "level B + level A neuro" }), // + + LEVEL_B_BV_SB(new AppointmentType[] { AppointmentType.LEVEL_B, AppointmentType.LEVEL_BV, AppointmentType.LEVEL_SB }, // + new String[] { "level B + BV + SB" }), // + + LEVEL_B_BV_BG(new AppointmentType[] { AppointmentType.LEVEL_B, AppointmentType.LEVEL_BV, AppointmentType.LEVEL_BG }, // + new String[] { "level B + BV + BG" }), // + + LEVEL_B_BG(new AppointmentType[] { AppointmentType.LEVEL_B, AppointmentType.LEVEL_BG }, // + new String[] { "level B + BG" }), // + + LEVEL_B_BV(new AppointmentType[] { AppointmentType.LEVEL_B, AppointmentType.LEVEL_BV }, // + new String[] { "level B + BV" }), // + + LEVEL_BV_BG_SB_MPOWER( + new AppointmentType[] { AppointmentType.LEVEL_BV, AppointmentType.LEVEL_BG, AppointmentType.LEVEL_SB, AppointmentType.LEVEL_B_M_POWER, }, // + new String[] { "evel BV + BG + SB + mPower", "BV + BG + SB + mPower" }), // + + LEVEL_BG_SB_MPOWER( + new AppointmentType[] { AppointmentType.LEVEL_BG, AppointmentType.LEVEL_SB, AppointmentType.LEVEL_B_M_POWER, }, // + new String[] { "level BG + SB + mPower" }), // + LEVEL_BV_BG_SB(new AppointmentType[] { AppointmentType.LEVEL_BV, AppointmentType.LEVEL_BG, AppointmentType.LEVEL_SB }, // + new String[] { "evel BV + BG + SB", "BV + BG + SB" }), // + LEVEL_BV_SB(new AppointmentType[] { AppointmentType.LEVEL_BV, AppointmentType.LEVEL_SB }, // + new String[] { "evel BV + SB", "BV + SB" }), // + LEVEL_BV_BG(new AppointmentType[] { AppointmentType.LEVEL_BV, AppointmentType.LEVEL_BG }, // + new String[] { "evel BV + BG", "BV + BG" }), // + LEVEL_BG_SB(new AppointmentType[] { AppointmentType.LEVEL_BG, AppointmentType.LEVEL_SB }, // + new String[] { "evel BG + SB", "BG + SB" }), // + LEVEL_BV(new AppointmentType[] { AppointmentType.LEVEL_BV }, // + new String[] { "evel BV", "BV" }), // + LEVEL_BG(new AppointmentType[] { AppointmentType.LEVEL_BG }, // + new String[] { "evel BG", "BG" }), // + LEVEL_SB(new AppointmentType[] { AppointmentType.LEVEL_SB }, // + new String[] { "evel SB", "SB" }), // + + LEVEL_A_TQ(new AppointmentType[] { AppointmentType.LEVEL_A_TQ }, // + new String[] { "TQ" }), // + LEVEL_A(new AppointmentType[] { AppointmentType.LEVEL_A }, // + new String[] { "level A" }), // + LEVEL_B(new AppointmentType[] { AppointmentType.LEVEL_B }, // + new String[] { "evel B" }), // + LEVEL_B_M_POWER(new AppointmentType[] { AppointmentType.LEVEL_B_M_POWER }, // + new String[] { "mPower" }), // + OTHER(new AppointmentType[] {}, // + new String[] {}), // + ; + private String[] queryStrings; + private AppointmentType[] types; + + private AppointmentTypeCollection(AppointmentType[] types, String[] queryStrings) { + this.queryStrings = queryStrings; + this.types = types; + } + + /** + * @return the queryStrings + * @see #queryStrings + */ + public String[] getQueryStrings() { + return queryStrings; + } + + /** + * @return the types + * @see #types + */ + public AppointmentType[] getTypes() { + return types; + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/CellParser.java b/appointment-import/src/main/java/smash/appointment/parse/CellParser.java new file mode 100644 index 0000000000000000000000000000000000000000..3780a8006712edf884e6e5d1ad6f1a5ecd34ca0b --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/CellParser.java @@ -0,0 +1,162 @@ +package smash.appointment.parse; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.log4j.Logger; + +public class CellParser { + Logger logger = Logger.getLogger(CellParser.class); + + private SubjectDao subjectDao; + + Pattern timePattern = Pattern.compile("^[0-9][0-9]\\:[0-9][0-9]"); + + public String extractTime(String content) { + String result = null; + Matcher matcher = timePattern.matcher(content); + if (matcher.find()) { + result = matcher.group(); + } + return result; + } + + public String removeTime(String content) { + Matcher matcher = timePattern.matcher(content); + if (matcher.find()) { + content = matcher.replaceFirst("").trim(); + } + return content; + } + + public AppointmentEntry parseAppointment(String query, String defaultTime) { + AppointmentEntry result = new AppointmentEntry(); + + String time = extractTime(query); + if (time != null) { + query = removeTime(query); + } else { + time = defaultTime; + } + result.setTime(time); + + Subject subject = extractSubject(query); + result.setSubject(subject); + + AppointmentTypeCollection type = extractType(query); + if (type == null) { + result.addType(AppointmentType.OTHER); + } else { + result.addTypes(type.getTypes()); + } + + result.setSource(query); + return result; + } + + private AppointmentTypeCollection extractType(String query) { + + String simplifiedQuery = Utils.simplifyString(query); + + AppointmentTypeCollection result = null; + + String usedString = null; + for (AppointmentTypeCollection type : AppointmentTypeCollection.values()) { + boolean matchFound = false; + for (String string : type.getQueryStrings()) { + if (!matchFound) { + String simplifiedString = Utils.simplifyString(string); + + if (simplifiedQuery.contains(simplifiedString)) { + matchFound = true; + if (result == null) { + result = type; + usedString = string; + } else { + if (string.contains(usedString)) { + result = type; + usedString = string; + } else if (usedString.contains(string)) { + // new one is a substring of old + } else { // if there is no substring then we might have a problem + AppointmentTypeCollection newType = result; + if (usedString.length() < string.length()) { + usedString = string; + newType = type; + } + logger.warn("More than one type possible for query: " + query + ". Type 1: " + result + ". Type 2: " + type + ". Choosing: " + newType); + result = newType; + } + } + + } + } + } + } + return result; + } + + private Subject extractSubject(String query) { + Subject result = null; + String simplifiedQuery = Utils.simplifyString(query); + + SubjectIndexer[] mainIndices = new SubjectIndexer[] { // + new NameSurnameIndexer(), // + new SurnameNameIndexer(), // + new NdNumberIndexer(),// + }; + + result = getByIndices(query, simplifiedQuery, mainIndices); + if (result == null) { + SubjectIndexer[] secondaryIndices = new SubjectIndexer[] { // + new SurnameIndexer(), // + }; + result = getByIndices(query, simplifiedQuery, secondaryIndices); + } + return result; + } + + private Subject getByIndices(String query, String simplifiedQuery, SubjectIndexer[] mainIndices) { + Subject result = null; + for (Subject subject : subjectDao.getSubjects()) { + boolean matchFound = false; + for (SubjectIndexer indexer : mainIndices) { + if (!matchFound) { + if (indexer.match(subject, simplifiedQuery)) { + matchFound = true; + if (result == null) { + result = subject; + } else { + Subject newResult = result; + if (indexer.isBetter(subject, result)) { + newResult = subject; + } + logger.warn( + "[" + indexer.getClass().getSimpleName() + "]" + "More than one subject possible for query: " + query + ". Subject 1: " + result + + ". Subject 2: " + subject + ". Choosing: " + newResult); + result = newResult; + } + } + } + } + } + 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/LihControlMappingParser.java b/appointment-import/src/main/java/smash/appointment/parse/LihControlMappingParser.java new file mode 100644 index 0000000000000000000000000000000000000000..3163eed9966d052bea816326d4ae3632ff2406bc --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/LihControlMappingParser.java @@ -0,0 +1,157 @@ +package smash.appointment.parse; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +import org.apache.poi.ss.usermodel.Row; + +public class LihControlMappingParser extends SubjectParser { + + @Override + protected String parseScreeningNumber(Row row) { + String number = getString(row.getCell(0)); + if (number.trim().isEmpty()) { + return ""; + } else { + if (number.length() == 1) { + number = "00" + number; + } else if (number.length() == 2) { + number = "0" + number; + } + return "L-" + number; + } + } + + @Override + protected String parseName(Row row) { + return getString(row.getCell(8)); + } + + @Override + protected String parseSurname(Row row) { + return getString(row.getCell(9)); + } + + @Override + protected String parseNdNumber(Row row) { + String number = getString(row.getCell(7)); + + if (number.equalsIgnoreCase("PK") ||number.equalsIgnoreCase("CHEM") || number.equalsIgnoreCase("Flying Team")) { + number = ""; + } + return number; + } + + @Override + protected String getSheetName() { + return "Sheet1"; + } + + @Override + protected int getInitRow() { + return 1; + } + + @Override + protected String parseBirthDate(Row row) { + return ""; + } + + @Override + protected String parsemPowerId(Row row) { + return ""; + } + + @Override + protected String parseAddDate(Row row) { + return getDate(row.getCell(1), Calendar.getInstance()); + } + + @Override + protected String parseReferal(Row row) { + return ""; + } + + @Override + protected String parseDiagnosisYear(Row row) { + return ""; + } + + @Override + protected String parseMail(Row row) { + return ""; + } + + @Override + protected String parsePhone3(Row row) { + return ""; + } + + @Override + protected String parsePhone2(Row row) { + return ""; + } + + @Override + protected String parsePhone1(Row row) { + return getString(row.getCell(10)); + } + + @Override + protected String parseCity(Row row) { + return ""; + + } + + @Override + protected String parseCountry(Row row) { + return ""; + } + + @Override + protected String parseZipCode(Row row) { + return ""; + } + + @Override + protected String parseAddress(Row row) { + return ""; + } + + @Override + protected String parseRemarks(Row row) { + return ""; + } + + @Override + protected String parseDiagnosis(Row row) { + return ""; + } + + @Override + protected SubjectType parseType(Row row) { + return SubjectType.CONTROL; + } + + @Override + protected List<String> parseLanguages(Row row) { + return new ArrayList<>(); + } + + @Override + protected String parseToBeSeenAt(Row row) { + return "L"; + } + + @Override + protected boolean parseDead(Row row) { + return false; + } + + @Override + protected boolean parseResigned(Row row) { + return false; + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/LihControlParser.java b/appointment-import/src/main/java/smash/appointment/parse/LihControlParser.java new file mode 100644 index 0000000000000000000000000000000000000000..fe44bb6fc33c679718a54aa51af1443565341be6 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/LihControlParser.java @@ -0,0 +1,209 @@ +package smash.appointment.parse; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +import org.apache.poi.ss.usermodel.Row; + +public class LihControlParser extends SubjectParser { + + @Override + protected String parseScreeningNumber(Row row) { + String number = getString(row.getCell(0)); + if (number.trim().isEmpty()) { + return ""; + } else { + return "L-" + number; + } + } + + @Override + protected String parseName(Row row) { + return getString(row.getCell(2)); + } + + @Override + protected String parseSurname(Row row) { + return getString(row.getCell(1)); + } + + @Override + protected String parseNdNumber(Row row) { + return ""; + } + + @Override + protected String getSheetName() { + return "Screening log"; + } + + @Override + protected int getInitRow() { + return 1; + } + + @Override + protected String parseBirthDate(Row row) { + return getDate(row.getCell(5), null); + } + + @Override + protected String parsemPowerId(Row row) { + return ""; + } + + private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); + + @Override + protected String parseAddDate(Row row) { + return DATE_FORMATTER.format(Calendar.getInstance().getTime()); + } + + @Override + protected String parseReferal(Row row) { + return ""; + } + + @Override + protected String parseDiagnosisYear(Row row) { + return ""; + } + + @Override + protected String parseMail(Row row) { + return getString(row.getCell(8)); + } + + @Override + protected String parsePhone3(Row row) { + return ""; + } + + @Override + protected String parsePhone2(Row row) { + return getString(row.getCell(7)); + } + + @Override + protected String parsePhone1(Row row) { + return getString(row.getCell(6)); + } + + @Override + protected String parseCity(Row row) { + return getString(row.getCell(12)); + + } + + @Override + protected String parseCountry(Row row) { + return ""; + } + + @Override + protected String parseZipCode(Row row) { + return getString(row.getCell(11)); + } + + @Override + protected String parseAddress(Row row) { + return getString(row.getCell(9)) + ", " + getString(row.getCell(10)); + } + + @Override + protected String parseRemarks(Row row) { + List<String> remarks = new ArrayList<>(); + String info = getString(row.getCell(4)); + if (!info.trim().isEmpty()) { + remarks.add("PD family relation=" + info); + } + remarks.add(getString(row.getCell(13))); + remarks.add(getComments(row.getCell(14))); + remarks.add(getComments(row.getCell(15))); + remarks.add(getComments(row.getCell(16))); + remarks.add(getString(row.getCell(18))); + remarks.add(getString(row.getCell(19))); + String result = ""; + for (String string : remarks) { + if (!string.trim().isEmpty()) { + result += string.trim() + "\n"; + } + } + return result; + } + + @Override + protected String parseDiagnosis(Row row) { + return ""; + } + + @Override + protected SubjectType parseType(Row row) { + return SubjectType.CONTROL; + } + + @Override + protected List<String> parseLanguages(Row row) { + List<String> result = new ArrayList<>(); + + String languages = getString(row.getCell(3)); + String langAbbreviations[] = new String[] {}; + if (languages.indexOf(",") >= 0) { + langAbbreviations = languages.split(","); + } else if (languages.indexOf("+") >= 0) { + langAbbreviations = languages.split("\\+"); + } else { + langAbbreviations = languages.split("/"); + } + for (String string : langAbbreviations) { + if (!string.trim().isEmpty()) { + result.add(getMappedLanguage(string.trim())); + } + } + return result; + } + + protected String getMappedLanguage(String abbreviation) { + switch (abbreviation.toUpperCase()) { + case ("F"): + return "French"; + case ("D"): + return "German"; + case ("GB"): + return "English"; + case ("P"): + return "Portuguese"; + case ("PT"): + return "Portuguese"; + case ("ENG"): + return "English"; + case ("EN"): + return "English"; + case ("FR"): + return "French"; + case ("L"): + return "Luxembourgish"; + case ("LUX"): + return "Luxembourgish"; + } + logger.warn("Unknown language abbreviation: " + abbreviation); + return ""; + } + + @Override + protected String parseToBeSeenAt(Row row) { + return "L"; + } + + @Override + protected boolean parseDead(Row row) { + return false; + } + + @Override + protected boolean parseResigned(Row row) { + return false; + } +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/Main.java b/appointment-import/src/main/java/smash/appointment/parse/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..59a12ffb85d8be2c62b77c3c7db03416eae1dea6 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/Main.java @@ -0,0 +1,157 @@ +package smash.appointment.parse; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.log4j.Logger; + +public class Main { + private static Logger logger = Logger.getLogger(Main.class); + + SubjectDao subjectDao = new SubjectDao(); + AppointmentDao appointmentDao = new AppointmentDao(); + + public void run(String[] args) throws Exception { + + Options options = new Options(); + Option agenda = Option.builder().required().argName("file").hasArg().desc("PRC agenda").longOpt("agenda").build(); + Option subjects = Option.builder().required().argName("file").hasArg().desc("PRC subjects").longOpt("subjects").build(); + Option controls = Option.builder().required().argName("file").hasArg().desc("PRC controls").longOpt("controls").build(); + Option flyingTeam = Option.builder().required().argName("file").hasArg().desc("PRC flying-team").longOpt("flying-team").build(); + Option lihControls = Option.builder().required().argName("file").hasArg().desc("LIH controls").longOpt("lih-controls").build(); + Option lihMappingControls = Option.builder().required().argName("file").hasArg().desc("LIH controls mapping").longOpt("lih-mapping").build(); + Option redCap = Option.builder().required().argName("file").hasArg().desc("RedCap appointments").longOpt("red-cap").build(); + options.addOption(agenda); + options.addOption(subjects); + options.addOption(controls); + options.addOption(flyingTeam); + options.addOption(lihControls); + options.addOption(lihMappingControls); + options.addOption(redCap); + + CommandLineParser parser = new DefaultParser(); + try { + CommandLine line = parser.parse(options, args); + + String subjectsFile = line.getOptionValue("subjects"); + for (Subject subject : processPrcSubjects(subjectsFile)) { + subjectDao.addSubject(subject, "[" + subjectsFile + ";" + subject.getScreeningNumber() + ";" + subject.getName() + " " + subject.getSurname() + "]"); + } + + String controlsFile = line.getOptionValue("controls"); + for (Subject subject : processPrcControls(controlsFile)) { + subjectDao.addSubject(subject, "[" + controlsFile + ";" + subject.getScreeningNumber() + ";" + subject.getName() + " " + subject.getSurname() + "]"); + } + + String flyingTeamFile = line.getOptionValue("flying-team"); + for (Subject subject : processFlyingTeamControls(flyingTeamFile)) { + subjectDao.addSubject(subject, "[" + flyingTeamFile + ";" + subject.getScreeningNumber() + ";" + subject.getName() + " " + subject.getSurname() + "]"); + } + + String lihMappingControlsFile = line.getOptionValue("lih-mapping"); + for (Subject subject : processLihMappingControls(lihMappingControlsFile)) { + subjectDao.addSubject( + subject, "[" + lihMappingControlsFile + ";" + subject.getScreeningNumber() + ";" + subject.getName() + " " + subject.getSurname() + "]"); + } + + String lihControlsFile = line.getOptionValue("lih-controls"); + for (Subject subject : processLihControls(lihControlsFile)) { + subjectDao + .addSubject(subject, "[" + lihControlsFile + ";" + subject.getScreeningNumber() + ";" + subject.getName() + " " + subject.getSurname() + "]"); + } + + subjectDao.addSubject(Visit.UNKNOWN, ""); + + String agendaFile = line.getOptionValue("agenda"); + Calendar today = Calendar.getInstance(); + today.set(Calendar.HOUR, 5); + appointmentDao.addAppointments(processPrcAppointments(agendaFile, today)); + + String redCapFile = line.getOptionValue("red-cap"); + appointmentDao.addAppointments(processRedCapAppointments(redCapFile)); + + System.out.println("delete from web_appointment_appointment_types;"); + System.out.println("delete from web_subject_languages;"); + System.out.println("delete from web_appointment;"); + System.out.println("delete from web_visit;"); + System.out.println("delete from web_subject;"); + SubjectSqlExporter subjectSqlExporter = new SubjectSqlExporter(); + // logger.debug("SUBJECTS: "); + for (Subject subject : subjectDao.getSubjects()) { + System.out.println(subjectSqlExporter.toSql(subject)); + } + + VisitSqlExporter visitSqlExporter = new VisitSqlExporter(); + List<Visit> visits = appointmentDao.getVisits(); + for (int i = 0; i < visits.size(); i++) { + Visit visit = visits.get(i); + boolean finished = false; + if (i < visits.size() - 1) { + if (visit.getSubject().equals(visits.get(i + 1).getSubject())) { + finished = true; + } + } + System.out.println(visitSqlExporter.toSql(visit, finished)); + } + + } catch (ParseException exp) { + System.out.println(exp.getMessage()); + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp("java -jar file.jar", options); + } + } + + private List<AppointmentEntry> processRedCapAppointments(String agendaFile) throws Exception{ + RedcapParser parser = new RedcapParser(); + parser.setSubjectDao(subjectDao); + return parser.parse(agendaFile); + } + + private List<Subject> processLihMappingControls(String lihMappingControlsFile) throws Exception { + LihControlMappingParser parser = new LihControlMappingParser(); + return parser.processExcel(lihMappingControlsFile); + } + + private List<Subject> processLihControls(String lihControlsFile) throws Exception { + LihControlParser parser = new LihControlParser(); + return parser.processExcel(lihControlsFile); + } + + private List<Subject> processFlyingTeamControls(String flyingTeamFile) throws Exception { + PrcFlyingParser parser = new PrcFlyingParser(); + return parser.processExcel(flyingTeamFile); + } + + private List<Subject> processPrcControls(String controlsFile) throws Exception { + PrcControlParser parser = new PrcControlParser(); + return parser.processExcel(controlsFile); + } + + private List<AppointmentEntry> processPrcAppointments(String agendaFile, Calendar minDate) throws Exception { + XlsxCalendarProcessor processor = new XlsxCalendarProcessor(); + processor.setSubjectDao(subjectDao); + List<AppointmentEntry> entries = processor.processExcel(agendaFile, minDate); + + return entries; + } + + public static void main(String[] args) throws Exception { + new Main().run(args); + } + + private List<Subject> processPrcSubjects(String subjectsFile) throws Exception { + PrcSubjectsParser parser = new PrcSubjectsParser(); + return parser.processExcel(subjectsFile); + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/NameSurnameIndexer.java b/appointment-import/src/main/java/smash/appointment/parse/NameSurnameIndexer.java new file mode 100644 index 0000000000000000000000000000000000000000..2ed820ad2e1b4609692d2eaf7233254a6784c0fc --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/NameSurnameIndexer.java @@ -0,0 +1,9 @@ +package smash.appointment.parse; + +public class NameSurnameIndexer extends SubjectIndexer { + + public String getIndexedString(Subject subject) { + return Utils.simplifyString(subject.getName() + subject.getSurname()); + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/NdNumberIndexer.java b/appointment-import/src/main/java/smash/appointment/parse/NdNumberIndexer.java new file mode 100644 index 0000000000000000000000000000000000000000..cd96a4a1a0149f439d7436689350279fe87d92fb --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/NdNumberIndexer.java @@ -0,0 +1,9 @@ +package smash.appointment.parse; + +public class NdNumberIndexer extends SubjectIndexer { + + public String getIndexedString(Subject subject) { + return Utils.simplifyString(subject.getNdNumber()); + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/PrcControlParser.java b/appointment-import/src/main/java/smash/appointment/parse/PrcControlParser.java new file mode 100644 index 0000000000000000000000000000000000000000..e0c6e4f5407e09e29609ac6ae55c76a9a14ecdb4 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/PrcControlParser.java @@ -0,0 +1,184 @@ +package smash.appointment.parse; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; + +public class PrcControlParser extends SubjectParser { + + @Override + protected String parseScreeningNumber(Row row) { + String number = getString(row.getCell(16)); + if (number.trim().isEmpty()) { + return ""; + } else { + if (number.length() == 1) { + number = "00" + number; + } else if (number.length() == 2) { + number = "0" + number; + } + return "P-" + number; + } + } + + @Override + protected String parseName(Row row) { + return getString(row.getCell(1)); + } + + @Override + protected String parseSurname(Row row) { + return getString(row.getCell(0)); + } + + @Override + protected String parseNdNumber(Row row) { + return getString(row.getCell(14)); + } + + @Override + protected String getSheetName() { + return "Contrôles"; + } + + @Override + protected int getInitRow() { + return 1; + } + + @Override + protected String parseBirthDate(Row row) { + return ""; + } + + @Override + protected String parsemPowerId(Row row) { + return ""; + } + + @Override + protected String parseAddDate(Row row) { + return getDate(row.getCell(8), Calendar.getInstance()); + } + + @Override + protected String parseReferal(Row row) { + return ""; + } + + @Override + protected String parseDiagnosisYear(Row row) { + return ""; + } + + @Override + protected String parseMail(Row row) { + return getString(row.getCell(5)); + } + + @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 ""; + } + + @Override + protected String parsePhone1(Row row) { + String phones[] = getPhones(row); + return phones[0].trim(); + } + + @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; + } + + @Override + protected String parseCountry(Row row) { + return ""; + } + + @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 ""; + } + + @Override + protected String parseAddress(Row row) { + return getString(row.getCell(2)); + } + + @Override + protected String parseRemarks(Row row) { + String remark1 = getString(row.getCell(9)); + String remark2 = ""; + + String result = ""; + if (!remark1.trim().isEmpty()) { + result = result + remark1 + "\n"; + } + if (!remark2.trim().isEmpty()) { + result = result + remark2 + "\n"; + } + return result; + } + + @Override + protected String parseDiagnosis(Row row) { + return ""; + } + + @Override + protected SubjectType parseType(Row row) { + return SubjectType.CONTROL; + } + + @Override + protected List<String> parseLanguages(Row row) { + return new ArrayList<>(); + } + + @Override + protected String parseToBeSeenAt(Row row) { + return "P"; + } + @Override + protected boolean parseDead(Row row) { + return false; + } + + @Override + 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 new file mode 100644 index 0000000000000000000000000000000000000000..efb92ca21c1289dc67732144365ba7e10fc08b65 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/PrcFlyingParser.java @@ -0,0 +1,179 @@ +package smash.appointment.parse; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; + +public class PrcFlyingParser extends SubjectParser { + + @Override + protected String parseScreeningNumber(Row row) { + String number = getString(row.getCell(25)); + if (number.trim().isEmpty()) { + return ""; + } else { + if (number.length() == 1) { + number = "00" + number; + } else if (number.length() == 2) { + number = "0" + number; + } + return "P-" + number; + } + } + + @Override + protected String parseName(Row row) { + return ""; + } + + @Override + protected String parseSurname(Row row) { + return getString(row.getCell(0)); + } + + @Override + protected String parseNdNumber(Row row) { + return getString(row.getCell(23)); + } + + @Override + protected String getSheetName() { + return "Leudelange"; + } + + @Override + protected int getInitRow() { + return 2; + } + + @Override + protected String parseBirthDate(Row row) { + return parseDateOfBirth(row.getCell(27)); + } + + @Override + protected String parsemPowerId(Row row) { + return ""; + } + + @Override + protected String parseAddDate(Row row) { + return getDate(row.getCell(11),Calendar.getInstance()); + } + + @Override + protected String parseReferal(Row row) { + return getString(row.getCell(10)); + } + + @Override + protected String parseDiagnosisYear(Row row) { + return getString(row.getCell(8)); + } + + @Override + protected String parseMail(Row row) { + return getString(row.getCell(6)); + } + + @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 ""; + } + + @Override + protected String parsePhone1(Row row) { + String phones[] = getPhones(row); + return phones[0].trim(); + } + + @Override + protected String parseCity(Row row) { + return getString(row.getCell(3)); + } + + @Override + protected String parseCountry(Row row) { + return getString(row.getCell(4)); + } + + @Override + protected String parseZipCode(Row row) { + return getString(row.getCell(2)); + } + + @Override + protected String parseAddress(Row row) { + return getString(row.getCell(1)); + } + + @Override + protected String parseRemarks(Row row) { + String remark1 = getString(row.getCell(7)); + String remark2 = getString(row.getCell(18)); + + String result = ""; + if (!remark1.trim().isEmpty()) { + result = result + remark1 + "\n"; + } + if (!remark2.trim().isEmpty()) { + result = result + remark2 + "\n"; + } + return result; + } + + @Override + protected String parseDiagnosis(Row row) { + return getString(row.getCell(9)); + } + + @Override + protected SubjectType parseType(Row row) { + String name = (parseName(row) + " " + parseSurname(row)).toLowerCase(); + if (name.indexOf("(c)") >= 0 || name.indexOf("©") >= 0) { + return SubjectType.CONTROL; + } else { + return SubjectType.PATIENT; + } + } + + @Override + protected List<String> parseLanguages(Row row) { + return new ArrayList<>(); + } + @Override + protected String parseToBeSeenAt(Row row) { + return "P"; + } + + @Override + protected boolean parseDead(Row row) { + return false; + } + + @Override + protected boolean parseResigned(Row row) { + return false; + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/PrcSubjectsParser.java b/appointment-import/src/main/java/smash/appointment/parse/PrcSubjectsParser.java new file mode 100644 index 0000000000000000000000000000000000000000..b24a61be5c22d4b6af45cc8a0347a598a9fe2108 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/PrcSubjectsParser.java @@ -0,0 +1,193 @@ +package smash.appointment.parse; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Row; + +public class PrcSubjectsParser extends SubjectParser { + + @Override + protected String parseScreeningNumber(Row row) { + String number = getString(row.getCell(25)); + if (number.trim().isEmpty()) { + return ""; + } else { + if (number.length() == 1) { + number = "00" + number; + } else if (number.length() == 2) { + number = "0" + number; + } + return "P-" + number; + } + } + + @Override + protected String parseName(Row row) { + return getString(row.getCell(1)); + } + + @Override + protected String parseSurname(Row row) { + return getString(row.getCell(0)); + } + + @Override + protected String parseNdNumber(Row row) { + return getString(row.getCell(22)); + } + + @Override + protected String getSheetName() { + return "Feuil1"; + } + + @Override + protected int getInitRow() { + return 1; + } + + @Override + protected String parseBirthDate(Row row) { + return parseDateOfBirth(row.getCell(27)); + } + + @Override + protected String parsemPowerId(Row row) { + return getString(row.getCell(23)); + } + + @Override + protected String parseAddDate(Row row) { + return getDate(row.getCell(14), Calendar.getInstance()); + } + + @Override + protected String parseReferal(Row row) { + return getString(row.getCell(13)); + } + + @Override + protected String parseDiagnosisYear(Row row) { + return getString(row.getCell(11)); + } + + @Override + protected String parseMail(Row row) { + return getString(row.getCell(10)); + } + + @Override + protected String parsePhone3(Row row) { + return getString(row.getCell(9)); + } + + @Override + protected String parsePhone2(Row row) { + return getString(row.getCell(8)); + } + + @Override + protected String parsePhone1(Row row) { + return getString(row.getCell(7)); + } + + @Override + protected String parseCity(Row row) { + return getString(row.getCell(5)); + } + + @Override + protected String parseCountry(Row row) { + return getString(row.getCell(6)); + } + + @Override + protected String parseZipCode(Row row) { + return getString(row.getCell(4)); + } + + @Override + protected String parseAddress(Row row) { + return getString(row.getCell(3)); + } + + @Override + protected String parseRemarks(Row row) { + String remark1 = getString(row.getCell(2)); + String remark2 = getString(row.getCell(20)); + + String result = ""; + if (!remark1.trim().isEmpty()) { + result = result + remark1 + "\n"; + } + if (!remark2.trim().isEmpty()) { + result = result + remark2 + "\n"; + } + return result; + } + + @Override + protected String parseDiagnosis(Row row) { + return getString(row.getCell(12)); + } + + @Override + protected SubjectType parseType(Row row) { + return SubjectType.PATIENT; + } + + @Override + protected List<String> parseLanguages(Row row) { + return new ArrayList<>(); + } + + @Override + protected String parseToBeSeenAt(Row row) { + return "P"; + } + + @Override + protected boolean parseDead(Row row) { + if (row.getCell(0).getCellStyle().getFillBackgroundColorColor() != null) { + return true; + } + return false; + } + + @Override + protected boolean parseResigned(Row row) { + try { + int colorId = row.getSheet().getWorkbook().getFontAt(row.getCell(0).getCellStyle().getFontIndex()).getColor(); + //special case for black + if (colorId == 32767) { + return false; + } + IndexedColors color = IndexedColors.fromInt(colorId); + switch (color) { + case RED: + return true; + case SEA_GREEN: + return false; + case PINK: + return false; + case PLUM: + return false; + case BLUE: + return false; + case BLACK: + return false; + case GREEN: + return false; + default: + logger.debug("Unknown font color: " + color); + return false; + } + } catch (Exception 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/RedcapParser.java b/appointment-import/src/main/java/smash/appointment/parse/RedcapParser.java new file mode 100644 index 0000000000000000000000000000000000000000..8ba9e39616c177ea8487d95bd2a959f3964e09de --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/RedcapParser.java @@ -0,0 +1,209 @@ +package smash.appointment.parse; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +public class RedcapParser { + Logger logger = Logger.getLogger(RedcapParser.class); + + private SubjectDao subjectDao; + + public List<AppointmentEntry> parse(String filename) throws FileNotFoundException, IOException { + List<AppointmentEntry> result = new ArrayList<>(); + try (BufferedReader br = new BufferedReader(new FileReader(filename))) { + int lineNumber = 0; + String line; + while ((line = br.readLine()) != null) { + lineNumber++; + if (lineNumber == 1) { + continue; + } + String tmp[] = line.split("\t", -1); + + String ndNumber = tmp[0]; + Subject subject = subjectDao.getByNdNumber(ndNumber); + if (subject == null) { + logger.warn("Cannot find subject with id: " + ndNumber); + } else { + if (tmp.length < 8) { + logger.warn("Invalid row (not enough cells): " + line); + } else { + subject.addLanguage(tmp[4]); + subject.addLanguage(tmp[5]); + subject.addLanguage(tmp[6]); + subject.addLanguage(tmp[7]); + if (!tmp[3].trim().isEmpty()) { + subject.setSex(tmp[3]); + } + if (!tmp[2].trim().isEmpty()) { + subject.setBirthDate(tmp[2]); + } + + // for now only PRC and flying team subjects + if (subject.getToBeSeenAt() == null || subject.getToBeSeenAt().startsWith("P") || subject.getToBeSeenAt().startsWith("F")) { + List<AppointmentEntry> subjectAppointments = new ArrayList<>(); + if (!tmp[9].isEmpty()) { + subjectAppointments.add(createEntryLevelA(tmp[9], tmp[10], subject)); + } + + if (!tmp[13].isEmpty()) { + subjectAppointments.add(createEntryLevelB(tmp[13], tmp[14], subject)); + } + + if (!tmp[17].isEmpty()) { + subjectAppointments.add(createEntryLevelBG(tmp[17], tmp[18], subject)); + } + + if (!tmp[21].isEmpty()) { + subjectAppointments.add(createEntryLevelBV(tmp[21], tmp[22], subject)); + } + + if (!tmp[41].isEmpty()) { + subjectAppointments.add(createEntryLevelSB(tmp[41], subject)); + } + + if (!tmp[45].isEmpty()) { + subjectAppointments.add(createEntryLevelMPower(tmp[45], subject)); + } + + result.addAll(subjectAppointments); + } + } + } + + } + } + return result; + + } + + private AppointmentEntry createEntryLevelMPower(String from, Subject subject) { + AppointmentEntry entry = new AppointmentEntry(); + String date = getDate(from); + entry.setDay(date); + entry.setSubject(subject); + entry.setSource("Imported from RedCap"); + entry.addType(AppointmentType.LEVEL_B_M_POWER); + return entry; + } + + private AppointmentEntry createEntryLevelSB(String from, Subject subject) { + AppointmentEntry entry = new AppointmentEntry(); + String date = getDate(from); + entry.setDay(date); + entry.setSubject(subject); + entry.setSource("Imported from RedCap"); + entry.addType(AppointmentType.LEVEL_SB); + return entry; + } + + private AppointmentEntry createEntryLevelBV(String from, String to, Subject subject) { + AppointmentEntry entry = new AppointmentEntry(); + String date = getDate(from); + String date2 = getDate(to); + if (!date.equals(date2)) { + logger.warn("Different start and end date for level BV appointment. Subject: " + subject.getNdNumber()); + } + entry.setDay(date); + entry.setSubject(subject); + entry.setSource("Imported from RedCap"); + entry.addType(AppointmentType.LEVEL_BV); + return entry; + } + + private AppointmentEntry createEntryLevelBG(String from, String to, Subject subject) { + AppointmentEntry entry = new AppointmentEntry(); + String date = getDate(from); + String date2 = getDate(to); + if (!date.equals(date2)) { + logger.warn("Different start and end date for level BG appointment. Subject: " + subject.getNdNumber()); + } + entry.setDay(date); + entry.setSubject(subject); + entry.setSource("Imported from RedCap"); + entry.addType(AppointmentType.LEVEL_BG); + return entry; + } + + private AppointmentEntry createEntryLevelB(String from, String to, Subject subject) { + AppointmentEntry entry = new AppointmentEntry(); + String date = getDate(from); + String date2 = getDate(to); + if (!date.equals(date2)) { + logger.warn("Different start and end date for level B appointment. Subject: " + subject.getNdNumber()); + } + entry.setDay(date); + entry.setSubject(subject); + entry.setSource("Imported from RedCap"); + entry.addType(AppointmentType.LEVEL_B); + return entry; + } + + private AppointmentEntry createEntryLevelA(String from, String to, Subject subject) { + AppointmentEntry entry = new AppointmentEntry(); + String date = getDate(from); + String date2 = getDate(to); + if (!date.equals(date2)) { + logger.warn("Different start and end date for level A appointment. Subject: " + subject.getNdNumber() + "; " + date + ", " + date2); + } + String time = getTime(from); + String duration = getDuration(from, to); + entry.setDay(date); + entry.setDuration(duration); + entry.setSubject(subject); + entry.setSource("Imported from RedCap"); + entry.setTime(time); + entry.addType(AppointmentType.LEVEL_A); + return entry; + } + + private String getDuration(String string, String string2) { + if (string2.isEmpty()) { + return null; + } + String time1 = getTime(string); + String time2 = getTime(string2); + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + LocalDateTime dateTime1 = LocalDateTime.parse("2014-11-25 " + time1 + ":00", formatter); + LocalDateTime dateTime2 = LocalDateTime.parse("2014-11-25 " + time2 + ":00", formatter); + + long diffInMinutes = java.time.Duration.between(dateTime1, dateTime2).toMinutes(); + + return diffInMinutes + ""; + } + + private String getTime(String string) { + return string.split(" ")[1]; + } + + private String getDate(String string) { + return string.split(" ")[0]; + } + + /** + * @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/SqlExporter.java b/appointment-import/src/main/java/smash/appointment/parse/SqlExporter.java new file mode 100644 index 0000000000000000000000000000000000000000..a5c19bb25f2b4a06d5d88b9cedcce94ae89d028b --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/SqlExporter.java @@ -0,0 +1,52 @@ +package smash.appointment.parse; + +import java.text.SimpleDateFormat; +import java.util.Calendar; + +public class SqlExporter { + + private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); + + public SqlExporter() { + super(); + } + + protected boolean isBefore(AppointmentEntry entry, Calendar minDate) { + String entryDate = entry.getDay(); + String beforeDate = DATE_FORMATTER.format(minDate.getTime()); + if (entryDate.compareTo(beforeDate) < 0) { + return true; + } else { + return false; + } + } + + protected String getStringVal(String arg) { + if (arg == null) { + return "null"; + } else if (arg.isEmpty()) { + return "''"; + } else { + return "'" + arg.replace("'", "''") + "'"; + } + } + + protected String getIntVal(String diagnosisYear) { + if (diagnosisYear == null || diagnosisYear.trim().isEmpty()) { + return "0"; + } else { + return diagnosisYear; + } + } + + protected String getDateVal(String arg) { + if (arg == null) { + return "null"; + } else if (arg.isEmpty()) { + return "null"; + } else { + return "'" + arg + "'"; + } + } + +} \ No newline at end of file diff --git a/appointment-import/src/main/java/smash/appointment/parse/Subject.java b/appointment-import/src/main/java/smash/appointment/parse/Subject.java new file mode 100644 index 0000000000000000000000000000000000000000..893fbfd450461c84d13f68ebd85ccb4c3162e942 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/Subject.java @@ -0,0 +1,569 @@ +package smash.appointment.parse; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +public class Subject { + Logger logger = Logger.getLogger(Subject.class); + + private String name; + private String surname; + private String ndNumber; + private String screeningNumber; + private String sex = ""; + private String remarks; + private String birthDate; + private String address; + private String zipCode; + private String country; + private String city; + private String phone1; + private String phone2; + private String phone3; + private String mail; + private String diagnosisYear; + private String diagnosis; + private String referal; + private String addDate; + private String mPowerId; + private SubjectType type; + private String toBeSeenAt; + private boolean dead = false; + private boolean resigned = false; + + private List<String> languages = new ArrayList<>(); + + public Subject(String name, String surname, String ndNumber, String screeningNumber) { + this.setName(name); + this.setSurname(surname); + this.setNdNumber(ndNumber); + this.setScreeningNumber(screeningNumber); + } + + /** + * @return the name + * @see #name + */ + public String getName() { + return name; + } + + /** + * @param name + * the name to set + * @see #name + */ + public void setName(String name) { + if (name != null && name.length() > 50) { + logger.warn("Name too long. Trimming: " + name); + name = name.substring(0, 50); + } + this.name = name; + } + + /** + * @return the surname + * @see #surname + */ + public String getSurname() { + return surname; + } + + /** + * @param surname + * the surname to set + * @see #surname + */ + public void setSurname(String surname) { + if (surname != null && surname.length() > 50) { + logger.warn("Surname too long. Trimming: " + surname); + surname = surname.substring(0, 50); + } + this.surname = surname; + } + + /** + * @return the ndNumber + * @see #ndNumber + */ + public String getNdNumber() { + return ndNumber; + } + + /** + * @param ndNumber + * the ndNumber to set + * @see #ndNumber + */ + public void setNdNumber(String ndNumber) { + this.ndNumber = ndNumber; + } + + /** + * @return the screeningNumber + * @see #screeningNumber + */ + public String getScreeningNumber() { + return screeningNumber; + } + + /** + * @param screeningNumber + * the screeningNumber to set + * @see #screeningNumber + */ + public void setScreeningNumber(String screeningNumber) { + this.screeningNumber = screeningNumber; + } + + @Override + public String toString() { + return this.getName() + " " + this.getSurname() + " (" + this.getNdNumber() + "; " + this.getScreeningNumber() + ")"; + } + + public void addLanguage(String string) { + if (!string.trim().isEmpty() && !string.equalsIgnoreCase("OTHER")) { + if (!languages.contains(string)) { + this.languages.add(string); + } + } + } + + /** + * @return the sex + * @see #sex + */ + public String getSex() { + return sex; + } + + /** + * @param sex + * the sex to set + * @see #sex + */ + public void setSex(String sex) { + this.sex = sex; + } + + /** + * @return the birthDate + * @see #birthDate + */ + public String getBirthDate() { + return birthDate; + } + + /** + * @param birthDate + * the birthDate to set + * @see #birthDate + */ + public void setBirthDate(String birthDate) { + this.birthDate = birthDate; + } + + /** + * @return the languages + * @see #languages + */ + public List<String> getLanguages() { + return languages; + } + + /** + * @param languages + * the languages to set + * @see #languages + */ + public void setLanguages(List<String> languages) { + this.languages = languages; + } + + /** + * @return the remarks + * @see #remarks + */ + public String getRemarks() { + return remarks; + } + + /** + * @param remarks + * the remarks to set + * @see #remarks + */ + public void setRemarks(String remarks) { + this.remarks = remarks; + } + + /** + * @return the address + * @see #address + */ + public String getAddress() { + return address; + } + + /** + * @param address + * the address to set + * @see #address + */ + public void setAddress(String address) { + this.address = address; + } + + /** + * @return the zipCode + * @see #zipCode + */ + public String getZipCode() { + return zipCode; + } + + /** + * @param zipCode + * the zipCode to set + * @see #zipCode + */ + public void setZipCode(String zipCode) { + if (zipCode != null && zipCode.length() > 7) { + logger.warn("Surname too long. Ignoring: " + zipCode); + this.zipCode = ""; + } else { + this.zipCode = zipCode; + } + } + + /** + * @return the country + * @see #country + */ + public String getCountry() { + return country; + } + + /** + * @param country + * the country to set + * @see #country + */ + public void setCountry(String country) { + this.country = country; + } + + /** + * @return the city + * @see #city + */ + public String getCity() { + return city; + } + + /** + * @param city + * the city to set + * @see #city + */ + public void setCity(String city) { + this.city = city; + } + + /** + * @return the phone1 + * @see #phone1 + */ + public String getPhone1() { + return phone1; + } + + /** + * @param phone1 + * the phone1 to set + * @see #phone1 + */ + public void setPhone1(String phone1) { + if (phone1 != null && phone1.length() > 20) { + logger.warn("Invalid phone. Ignoring: " + phone1); + } else { + this.phone1 = phone1; + } + } + + /** + * @return the phone2 + * @see #phone2 + */ + public String getPhone2() { + return phone2; + } + + /** + * @param phone2 + * the phone2 to set + * @see #phone2 + */ + public void setPhone2(String phone2) { + if (phone2 != null && phone2.length() > 20) { + logger.warn("Invalid phone. Ignoring: " + phone2); + } else { + this.phone2 = phone2; + } + } + + /** + * @return the phone3 + * @see #phone3 + */ + public String getPhone3() { + return phone3; + } + + /** + * @param phone3 + * the phone3 to set + * @see #phone3 + */ + public void setPhone3(String phone3) { + if (phone3 != null && phone3.length() > 20) { + logger.warn("Invalid phone. Ignoring: " + phone3); + } else { + this.phone3 = phone3; + } + } + + /** + * @return the mail + * @see #mail + */ + public String getMail() { + return mail; + } + + /** + * @param mail + * the mail to set + * @see #mail + */ + public void setMail(String mail) { + this.mail = mail; + } + + /** + * @return the diagnosisYear + * @see #diagnosisYear + */ + public String getDiagnosisYear() { + return diagnosisYear; + } + + /** + * @param diagnosisYear + * the diagnosisYear to set + * @see #diagnosisYear + */ + public void setDiagnosisYear(String diagnosisYear) { + this.diagnosisYear = diagnosisYear; + } + + /** + * @return the diagnosis + * @see #diagnosis + */ + public String getDiagnosis() { + return diagnosis; + } + + /** + * @param diagnosis + * the diagnosis to set + * @see #diagnosis + */ + public void setDiagnosis(String diagnosis) { + this.diagnosis = diagnosis; + } + + /** + * @return the referal + * @see #referal + */ + public String getReferal() { + return referal; + } + + /** + * @param referal + * the referal to set + * @see #referal + */ + public void setReferal(String referal) { + this.referal = referal; + } + + /** + * @return the mPowerId + * @see #mPowerId + */ + public String getmPowerId() { + return mPowerId; + } + + /** + * @param mPowerId + * the mPowerId to set + * @see #mPowerId + */ + public void setmPowerId(String mPowerId) { + this.mPowerId = mPowerId; + } + + /** + * @return the addDate + * @see #addDate + */ + public String getAddDate() { + return addDate; + } + + /** + * @param addDate + * the addDate to set + * @see #addDate + */ + public void setAddDate(String addDate) { + this.addDate = addDate; + } + + /** + * @return the type + * @see #type + */ + public SubjectType getType() { + return type; + } + + /** + * @param type + * the type to set + * @see #type + */ + public void setType(SubjectType type) { + this.type = type; + } + + public void update(Subject subject, String errorPrefix) { + setName(getMergedValue("name", this.getName(), subject.getName(), errorPrefix)); + setSurname(getMergedValue("surname", this.getSurname(), subject.getSurname(), errorPrefix)); + setNdNumber(getMergedValue("ndNumber", this.getNdNumber(), subject.getNdNumber(), errorPrefix)); + setScreeningNumber(getMergedValue("screeningNumber", this.getScreeningNumber(), subject.getScreeningNumber(), errorPrefix)); + setSex(getMergedValue("sex", this.getSex(), subject.getSex(), errorPrefix)); + setRemarks(getMergedValue("remarks", this.getRemarks(), subject.getRemarks(), errorPrefix)); + setBirthDate(getMergedValue("birthDate", this.getBirthDate(), subject.getBirthDate(), errorPrefix)); + setAddress(getMergedValue("address", this.getAddress(), subject.getAddress(), errorPrefix)); + setZipCode(getMergedValue("zipCode", this.getZipCode(), subject.getZipCode(), errorPrefix)); + setCountry(getMergedValue("country", this.getCountry(), subject.getCountry(), errorPrefix)); + setCity(getMergedValue("city", this.getCity(), subject.getCity(), errorPrefix)); + setPhone1(getMergedValue("phone1", this.getPhone1(), subject.getPhone1(), errorPrefix)); + setPhone2(getMergedValue("phone2", this.getPhone2(), subject.getPhone2(), errorPrefix)); + setPhone3(getMergedValue("phone3", this.getPhone3(), subject.getPhone3(), errorPrefix)); + setMail(getMergedValue("mail", this.getMail(), subject.getMail(), errorPrefix)); + setDiagnosisYear(getMergedValue("diagnosisYear", this.getDiagnosisYear(), subject.getDiagnosisYear(), errorPrefix)); + setDiagnosis(getMergedValue("diagnosis", this.getDiagnosis(), subject.getDiagnosis(), errorPrefix)); + setReferal(getMergedValue("referal", this.getReferal(), subject.getReferal(), errorPrefix)); + setAddDate(getMergedValue("addDate", this.getAddDate(), subject.getAddDate(), errorPrefix)); + setmPowerId(getMergedValue("mPowerId", this.getmPowerId(), subject.getmPowerId(), errorPrefix)); + setType(getMergedValue("type", this.getType(), subject.getType(), errorPrefix)); + // override only when to be seen by flying team + if (subject.getToBeSeenAt().equals("F")) { + setToBeSeenAt(subject.getToBeSeenAt()); + } + addLanguages(subject.getLanguages()); + } + + private SubjectType getMergedValue(String string, SubjectType existingValue, SubjectType newValue, String errorPrefix) { + if (existingValue == null) { + return newValue; + } else if (newValue == null) { + return existingValue; + } else if (existingValue.equals(newValue)) { + return existingValue; + } else { + logger.warn(errorPrefix + "New " + string + " differs from old one. (new: " + newValue + ", " + existingValue + "). Skipping"); + return existingValue; + } + } + + private String getMergedValue(String string, String existingValue, String newValue, String errorPrefix) { + if (existingValue == null || existingValue.trim().isEmpty()) { + return newValue; + } else if (newValue == null || newValue.trim().isEmpty()) { + return existingValue; + } else if (existingValue.trim().equalsIgnoreCase(newValue.trim())) { + return existingValue; + } else { + logger.warn(errorPrefix + "New " + string + " differs from old one. (new: " + newValue + ", " + existingValue + "). Skipping"); + return existingValue; + } + } + + /** + * @return the toBeSeenAt + * @see #toBeSeenAt + */ + public String getToBeSeenAt() { + return toBeSeenAt; + } + + /** + * @param toBeSeenAt + * the toBeSeenAt to set + * @see #toBeSeenAt + */ + public void setToBeSeenAt(String toBeSeenAt) { + this.toBeSeenAt = toBeSeenAt; + } + + /** + * @return the dead + * @see #dead + */ + public boolean isDead() { + return dead; + } + + /** + * @param dead + * the dead to set + * @see #dead + */ + public void setDead(boolean dead) { + this.dead = dead; + } + + /** + * @return the resigned + * @see #resigned + */ + public boolean isResigned() { + return resigned; + } + + /** + * @param resigned + * the resigned to set + * @see #resigned + */ + public void setResigned(boolean resigned) { + this.resigned = resigned; + } + + public void addLanguages(List<String> langs) { + for (String string : langs) { + addLanguage(string); + } + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/SubjectDao.java b/appointment-import/src/main/java/smash/appointment/parse/SubjectDao.java new file mode 100644 index 0000000000000000000000000000000000000000..38dada1071019e5a5ea1033139c222c598b4aa77 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/SubjectDao.java @@ -0,0 +1,87 @@ +package smash.appointment.parse; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +public class SubjectDao { + Logger logger = Logger.getLogger(SubjectDao.class); + private List<Subject> subjects = new ArrayList<>(); + + public void addSubject(Subject subject, String errorPrefix) { + if (subject.getNdNumber() != null && !subject.getNdNumber().trim().isEmpty()) { + Subject existing = getByNdNumber(subject.getNdNumber()); + if (existing != null) { + if (!existing.getScreeningNumber().equals(subject.getScreeningNumber())) { + logger.error(errorPrefix + " Nd number taken by subject: " + existing.getScreeningNumber()); + return; + } + } + } + Subject existing = getByScreeningNumber(subject.getScreeningNumber()); + if (existing != null) { + existing.update(subject, errorPrefix); + } else { + subjects.add(subject); + } + } + + private Subject getByScreeningNumber(String screeningNumber) { + for (Subject s : subjects) { + if (screeningNumber.equals(s.getScreeningNumber())) { + return s; + } + } + return null; + } + + public void readFile(String filename) throws IOException { + try (BufferedReader br = new BufferedReader(new FileReader(filename))) { + String line; + int lineCount = 1; + while ((line = br.readLine()) != null) { + String tmp[] = line.split("\t"); + addSubject(new Subject(tmp[0], tmp[1], tmp[2], tmp[3]), "[" + filename + ":" + lineCount + "]"); + lineCount++; + } + } + } + + /** + * @return the subjects + * @see #subjects + */ + public List<Subject> getSubjects() { + return subjects; + } + + /** + * @param subjects + * the subjects to set + * @see #subjects + */ + public void setSubjects(List<Subject> subjects) { + this.subjects = subjects; + } + + public Subject getByNdNumber(String ndNumber) { + ndNumber = Utils.simplifyString(ndNumber); + for (Subject s : subjects) { + if (ndNumber.equalsIgnoreCase(s.getNdNumber())) { + return s; + } + } + return null; + } + + public void addSubjects(List<Subject> processPrcSubjects, String errorPrefix) { + for (Subject subject : processPrcSubjects) { + addSubject(subject, errorPrefix); + } + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/SubjectIndexer.java b/appointment-import/src/main/java/smash/appointment/parse/SubjectIndexer.java new file mode 100644 index 0000000000000000000000000000000000000000..b120fdc9ccb1cf77902c71b1427d8fdde344801d --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/SubjectIndexer.java @@ -0,0 +1,25 @@ +package smash.appointment.parse; + +import org.apache.log4j.Logger; + +public abstract class SubjectIndexer { + Logger logger = Logger.getLogger(SubjectIndexer.class); + + public abstract String getIndexedString(Subject subject); + + public boolean match(Subject subject, String simplifiedQuery) { + String indexedString = getIndexedString(subject); + if (indexedString.length() == 0) { + return false; + } + // logger.debug("Check: " + simplifiedQuery + " against: " + indexedString); + if (simplifiedQuery.startsWith(indexedString)) { + return true; + } + return false; + } + + public boolean isBetter(Subject subject, Subject oldSubject) { + return getIndexedString(subject).length() > getIndexedString(oldSubject).length(); + } +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/SubjectParser.java b/appointment-import/src/main/java/smash/appointment/parse/SubjectParser.java new file mode 100644 index 0000000000000000000000000000000000000000..6292d3cb961547a986c42b59c3b0d665d2225bd9 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/SubjectParser.java @@ -0,0 +1,242 @@ +package smash.appointment.parse; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.poi.EncryptedDocumentException; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.Comment; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.RichTextString; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; + +public abstract class SubjectParser { + private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); + Logger logger = Logger.getLogger(SubjectParser.class); + DataFormatter df = new DataFormatter(); + + public List<Subject> processExcel(String filename) throws EncryptedDocumentException, InvalidFormatException, IOException, ParseException { + List<Subject> result = new ArrayList<>(); + InputStream inp = new FileInputStream(filename); + Workbook workbook = WorkbookFactory.create(inp); + Iterator<Sheet> sheetIter = workbook.sheetIterator(); + while (sheetIter.hasNext()) { + Sheet sheet = sheetIter.next(); + String name = sheet.getSheetName().trim(); + if (name.trim().toLowerCase().equals(getSheetName().toLowerCase())) { + result.addAll(processSheet(sheet)); + } else { + logger.debug(filename + "Skipping sheet: " + name); + } + } + return result; + } + + private List<Subject> processSheet(Sheet sheet) { + List<Subject> result = new ArrayList<>(); + int rowCount = sheet.getPhysicalNumberOfRows(); + for (int rowId = getInitRow(); rowId < rowCount; rowId++) { + Row subjectRow = sheet.getRow(rowId); + Subject subject = parseSubject(subjectRow); + if (subject != null) { + result.add(subject); + } + } + return result; + } + + private Subject parseSubject(Row row) { + String screeningNumber = parseScreeningNumber(row); + if (screeningNumber == null || screeningNumber.isEmpty()) { + logger.debug("Skipping row: (" + getString(row.getCell(0)) + ", " + getString(row.getCell(1)) + ")"); + return null; + } + String name = parseName(row); + String surname = parseSurname(row); + String ndNumber = parseNdNumber(row); + Subject result = new Subject(name, surname, ndNumber, screeningNumber); + + result.setRemarks(parseRemarks(row)); + result.setAddress(parseAddress(row)); + result.setZipCode(parseZipCode(row)); + result.setCity(parseCity(row)); + result.setCountry(parseCountry(row)); + result.setPhone1(parsePhone1(row)); + result.setPhone2(parsePhone2(row)); + result.setPhone3(parsePhone3(row)); + result.setMail(parseMail(row)); + result.setDiagnosisYear(parseDiagnosisYear(row)); + result.setDiagnosis(parseDiagnosis(row)); + result.setReferal(parseReferal(row)); + result.setAddDate(parseAddDate(row)); + result.setmPowerId(parsemPowerId(row)); + result.setBirthDate(parseBirthDate(row)); + result.setType(parseType(row)); + result.addLanguages(parseLanguages(row)); + result.setToBeSeenAt(parseToBeSeenAt(row)); + result.setDead(parseDead(row)); + result.setResigned(parseResigned(row)); + + return result; + } + + protected abstract boolean parseDead(Row row); + + protected abstract boolean parseResigned(Row row); + + protected abstract String parseToBeSeenAt(Row row); + + protected abstract List<String> parseLanguages(Row row); + + protected abstract SubjectType parseType(Row row); + + protected abstract String parseBirthDate(Row row); + + protected abstract String parsemPowerId(Row row); + + protected abstract String parseAddDate(Row row); + + protected abstract String parseReferal(Row row); + + protected abstract String parseDiagnosisYear(Row row); + + protected abstract String parseDiagnosis(Row row); + + protected abstract String parseMail(Row row); + + protected abstract String parsePhone3(Row row); + + protected abstract String parsePhone2(Row row); + + protected abstract String parsePhone1(Row row); + + protected abstract String parseCity(Row row); + + protected abstract String parseCountry(Row row); + + protected abstract String parseZipCode(Row row); + + protected abstract String parseAddress(Row row); + + protected abstract String parseRemarks(Row row); + + protected abstract String parseScreeningNumber(Row row); + + protected abstract String parseName(Row row); + + protected abstract String parseSurname(Row row); + + protected abstract String parseNdNumber(Row row); + + protected abstract String getSheetName(); + + protected abstract int getInitRow(); + + protected String getString(Cell cell) { + if (cell == null) { + return ""; + } + if (cell.getCellTypeEnum().equals(CellType.STRING)) { + return cell.getStringCellValue().trim(); + } + return df.formatCellValue(cell).trim(); + } + + protected String getComments(Cell cell) { + Comment comment = cell.getCellComment(); + if (comment != null) { + RichTextString richTextString = comment.getString(); + if (richTextString != null) { + return richTextString.getString(); + + } + } + return ""; + } + + protected String getDate(Cell cell, Calendar defaultDate) { + String defaultDateString = ""; + if (defaultDate != null) { + defaultDateString = DATE_FORMATTER.format(defaultDate.getTime()); + } + if (cell == null) { + return defaultDateString; + } + String result = null; + if (cell.getCellTypeEnum().equals(CellType.STRING)) { + result = getString(cell); + } else if (HSSFDateUtil.isCellDateFormatted(cell)) { + Date date = cell.getDateCellValue(); + if (date != null) { + result = DATE_FORMATTER.format(date); + } else { + result = defaultDateString; + } + } else { + result = getString(cell); + } + if (result == null || result.trim().isEmpty()) { + result = defaultDateString; + } + result = fixDate(result, defaultDateString); + return result; + } + + protected String fixDate(String result) { + return fixDate(result, null); + } + + protected String fixDate(String result, String defaultDateString) { + result = result.replaceAll("\\?", ""); + result = result.replaceAll("jan", "01"); + result = result.replaceAll("fev", "02"); + result = result.replaceAll("mar", "03"); + result = result.replaceAll("avr", "04"); + result = result.replaceAll("may", "05"); + result = result.replaceAll("aou", "08"); + result = result.replaceAll("cot", "08"); + result = result.replaceAll("sep", "09"); + result = result.replaceAll("oct", "10"); + if (result.length() != 10) { + logger.warn("Invalid date. Ignoring: " + result); + result = defaultDateString; + } + if (result.indexOf("/") >= 0) { + String tmp[] = result.split("/"); + result = tmp[2] + "-" + tmp[1] + "-" + tmp[0]; + } + if (result.length() == 10 && result.charAt(2) == '-') { + String tmp[] = result.split("-"); + result = tmp[2] + "-" + tmp[1] + "-" + tmp[0]; + } + return result; + } + + protected String parseDateOfBirth(Cell cell) { + String date = getString(cell).replaceAll(" ", ""); + if (date.length() < 8) { + return ""; + } + String year = date.substring(0, 4); + String month = date.substring(4, 6); + String day = date.substring(6, 8); + String result = year + "-" + month + "-" + day; + return result; + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/SubjectSqlExporter.java b/appointment-import/src/main/java/smash/appointment/parse/SubjectSqlExporter.java new file mode 100644 index 0000000000000000000000000000000000000000..e3056da5f1bb3d9f72a537e606544f557508480b --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/SubjectSqlExporter.java @@ -0,0 +1,74 @@ +package smash.appointment.parse; + +public class SubjectSqlExporter extends SqlExporter { + + public String toSql(Subject subject) { + StringBuilder result = new StringBuilder(""); + + result.append("insert into web_subject ("); + result.append("sex, "); + result.append("last_name, "); + result.append("first_name, "); + result.append("comments,"); + result.append("address,"); + result.append("postal_code, "); + result.append("city, "); + result.append("country, "); + result.append("phone_number,"); + result.append("phone_number_2,"); + result.append("phone_number_3,"); + result.append("email,"); + result.append("year_of_diagnosis,"); + result.append("diagnosis,"); + result.append("referral,"); + result.append("date_added,"); + result.append("nd_number,"); + result.append("mpower_id,"); + result.append("screening_number,"); + result.append("default_appointment_location,"); + result.append("type,"); + result.append("dead,"); + result.append("resigned,"); + result.append("date_born) "); + + result.append("values ("); + result.append(getStringVal(subject.getSex()) + ","); + result.append(getStringVal(subject.getSurname()) + ","); + result.append(getStringVal(subject.getName()) + ","); + result.append(getStringVal(subject.getRemarks()) + ","); + result.append(getStringVal(subject.getAddress()) + ","); + result.append(getStringVal(subject.getZipCode()) + ","); + result.append(getStringVal(subject.getCity()) + ","); + result.append(getStringVal(subject.getCountry()) + ","); + result.append(getStringVal(subject.getPhone1()) + ","); + result.append(getStringVal(subject.getPhone2()) + ","); + result.append(getStringVal(subject.getPhone3()) + ","); + result.append(getStringVal(subject.getMail()) + ","); + result.append(getIntVal(subject.getDiagnosisYear()) + ","); + result.append(getStringVal(subject.getDiagnosis()) + ","); + result.append(getStringVal(subject.getReferal()) + ","); + result.append(getDateVal(subject.getAddDate()) + ","); + result.append(getStringVal(subject.getNdNumber()) + ","); + result.append(getStringVal(subject.getmPowerId()) + ","); + result.append(getStringVal(subject.getScreeningNumber()) + ","); + result.append(getStringVal(subject.getToBeSeenAt()) + ","); + result.append(getStringVal(subject.getType().toString().substring(0, 1)) + ","); + result.append(subject.isDead() + ","); + result.append(subject.isResigned() + ","); + result.append(getDateVal(subject.getBirthDate())); + result.append(");\n"); + + for (String langueage : subject.getLanguages()) { + result.append("insert into web_subject_languages ("); + result.append("subject_id, "); + result.append("language_id) "); + result.append("values ("); + result.append("(select max(id) from web_subject), "); + result.append("(select id from web_language where name=" + getStringVal(langueage) + ") "); + result.append(");\n"); + } + + return result.toString(); + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/SubjectType.java b/appointment-import/src/main/java/smash/appointment/parse/SubjectType.java new file mode 100644 index 0000000000000000000000000000000000000000..a1ef995b0ccebeb8a0500126b8df6cad8f95177d --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/SubjectType.java @@ -0,0 +1,5 @@ +package smash.appointment.parse; + +public enum SubjectType { + PATIENT, CONTROL; +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/SurnameIndexer.java b/appointment-import/src/main/java/smash/appointment/parse/SurnameIndexer.java new file mode 100644 index 0000000000000000000000000000000000000000..10c1a29f3e39236ed33c0c819e6a30d4420de99c --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/SurnameIndexer.java @@ -0,0 +1,9 @@ +package smash.appointment.parse; + +public class SurnameIndexer extends SubjectIndexer { + + public String getIndexedString(Subject subject) { + return Utils.simplifyString(subject.getSurname()); + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/SurnameNameIndexer.java b/appointment-import/src/main/java/smash/appointment/parse/SurnameNameIndexer.java new file mode 100644 index 0000000000000000000000000000000000000000..7de6d7c4ef96e23ee9b75a72fa5d32eb1f6b5ad1 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/SurnameNameIndexer.java @@ -0,0 +1,9 @@ +package smash.appointment.parse; + +public class SurnameNameIndexer extends SubjectIndexer { + + public String getIndexedString(Subject subject) { + return Utils.simplifyString(subject.getSurname() + subject.getName()); + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/Utils.java b/appointment-import/src/main/java/smash/appointment/parse/Utils.java new file mode 100644 index 0000000000000000000000000000000000000000..916487ba6948c86609d8a4e273f5b4bed574121b --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/Utils.java @@ -0,0 +1,7 @@ +package smash.appointment.parse; + +public class Utils { + public static String simplifyString(String query) { + return query.replaceAll("[\\s\\-©]", "").toLowerCase().replaceAll("\\(c\\)", ""); + } +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/Visit.java b/appointment-import/src/main/java/smash/appointment/parse/Visit.java new file mode 100644 index 0000000000000000000000000000000000000000..2762806afb7da798ed27ad773fbd4571d4885288 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/Visit.java @@ -0,0 +1,109 @@ +package smash.appointment.parse; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +import org.apache.log4j.Logger; + +public class Visit { + static Subject UNKNOWN; + static { + UNKNOWN = new Subject("NOBODY","","","---"); + UNKNOWN.setType(SubjectType.CONTROL); + UNKNOWN.setAddDate("1900-01-01"); + UNKNOWN.setAddress(""); + UNKNOWN.setZipCode(""); + UNKNOWN.setCity(""); + UNKNOWN.setCountry(""); + UNKNOWN.setmPowerId(""); + UNKNOWN.setReferal(""); + UNKNOWN.setRemarks(""); + UNKNOWN.setDiagnosis(""); + UNKNOWN.setToBeSeenAt("P"); + } + Logger logger = Logger.getLogger(Visit.class); + + private Subject subject; + private List<AppointmentEntry> appointments = new ArrayList<>(); + + public Visit(Subject subject) { + if (subject==null) { + subject = UNKNOWN; + } + this.subject = subject; + } + + public void addAppointment(AppointmentEntry entry) { + appointments.add(entry); + } + + /** + * @return the appointments + * @see #appointments + */ + public List<AppointmentEntry> getAppointments() { + return appointments; + } + + /** + * @param appointments + * the appointments to set + * @see #appointments + */ + public void setAppointments(List<AppointmentEntry> appointments) { + this.appointments = appointments; + } + + public String getLastAppointmentDate() { + if (appointments.size() == 0) { + return "1900-01-01"; + } + return getLastAppointment().getDay().substring(0, 10); + } + + public AppointmentEntry getLastAppointment() { + if (appointments.size() > 0) { + return appointments.get(appointments.size() - 1); + } else { + return null; + } + } + + public String getStartDate() { + if (appointments.size() > 0) { + return appointments.get(0).getDay().substring(0, 10); + } else { + return "1900-01-01"; + } + } + + private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); + + public String getEndDate() throws ParseException { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(DATE_FORMATTER.parse(getStartDate())); + calendar.add(Calendar.MONTH, 3); + return DATE_FORMATTER.format(calendar.getTime()); + } + + /** + * @return the subject + * @see #subject + */ + public Subject getSubject() { + return subject; + } + + /** + * @param subject + * the subject to set + * @see #subject + */ + public void setSubject(Subject subject) { + this.subject = subject; + } + +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/VisitSqlExporter.java b/appointment-import/src/main/java/smash/appointment/parse/VisitSqlExporter.java new file mode 100644 index 0000000000000000000000000000000000000000..16077d37622b97edd5c407abebc6e4344112a3b9 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/VisitSqlExporter.java @@ -0,0 +1,32 @@ +package smash.appointment.parse; + +import java.text.ParseException; +import java.util.Calendar; + +public class VisitSqlExporter extends SqlExporter { + AppointmentSqlExporter appointmentSqlExporter = new AppointmentSqlExporter(); + public String toSql(Visit visit, boolean isFinished) throws ParseException { + StringBuilder result = new StringBuilder(""); + + result.append("insert into web_visit ("); + result.append("subject_id, "); + result.append("datetime_begin, "); + result.append("datetime_end, "); + result.append("is_finished)"); + + result.append("values ("); + result.append("(SELECT id from web_subject where screening_number = "+getStringVal(visit.getSubject().getScreeningNumber()) + "),"); + result.append(getStringVal(visit.getStartDate()) + ","); + result.append(getStringVal(visit.getEndDate()) + ","); + result.append(isFinished); + result.append(");\n"); + for (AppointmentEntry entry: visit.getAppointments()) { + boolean entryFinished= isFinished; + if (isBefore(entry, Calendar.getInstance())) + entryFinished=true; + result.append(appointmentSqlExporter.toSql(entry, entryFinished)+"\n"); + } + + return result.toString(); + } +} diff --git a/appointment-import/src/main/java/smash/appointment/parse/XlsxCalendarProcessor.java b/appointment-import/src/main/java/smash/appointment/parse/XlsxCalendarProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..0c6e2a1419f1cbfc83e1eaafebedafed8553ca88 --- /dev/null +++ b/appointment-import/src/main/java/smash/appointment/parse/XlsxCalendarProcessor.java @@ -0,0 +1,181 @@ +package smash.appointment.parse; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.log4j.Logger; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.FormulaEvaluator; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; + +public class XlsxCalendarProcessor { + Logger logger = Logger.getLogger(XlsxCalendarProcessor.class); + + private SubjectDao subjectDao; + + public List<AppointmentEntry> processExcel(String filename, Calendar minDate) throws Exception { + List<AppointmentEntry> result = new ArrayList<AppointmentEntry>(); + InputStream inp = new FileInputStream(filename); + Workbook workbook = WorkbookFactory.create(inp); + Iterator<Sheet> sheetIter = workbook.sheetIterator(); + while (sheetIter.hasNext()) { + Sheet sheet = sheetIter.next(); + String name = sheet.getSheetName().trim(); + if (name.contains("2017")) { + String monthName = name.split(" ")[0]; + String monthNumber = parseMonth(monthName); + result.addAll(processSheet(sheet, "2017-" + monthNumber)); + } else { + logger.debug("Skipping sheet: " + name); + } + } + if (minDate != null) { + Set<AppointmentEntry> toBeRemoved = new HashSet<>(); + + for (AppointmentEntry entry : result) { + if (isBefore(entry, minDate)) { + toBeRemoved.add(entry); + } + } + result.removeAll(toBeRemoved); + } + + return result; + } + + private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); + + private boolean isBefore(AppointmentEntry entry, Calendar minDate) { + String entryDate = entry.getDay(); + String beforeDate = DATE_FORMATTER.format(minDate.getTime()); + if (entryDate.compareTo(beforeDate) < 0) { + return true; + } else { + return false; + } + } + + int[] dayColumns = new int[] { 3, 4, 5, 6, 7 }; + + int[] weekStartRows = new int[] { 5, 23, 41, 59, 77, 95 }; + + int hourColum = 0; + int dayOfMonthRowOffset = 0; + int calendarRowStartOffset = 3; + int calendarRowEndOffset = 18; + + private List<AppointmentEntry> processSheet(Sheet sheet, String string) { + FormulaEvaluator evaluator = sheet.getWorkbook().getCreationHelper().createFormulaEvaluator(); + + List<AppointmentEntry> result = new ArrayList<AppointmentEntry>(); + + CellParser parser = new CellParser(); + parser.setSubjectDao(subjectDao); + + for (int weekOffset : weekStartRows) { + Row weekRow = sheet.getRow(weekOffset + dayOfMonthRowOffset); + for (int dayColumnOffset : dayColumns) { + Cell dayCell = weekRow.getCell(dayColumnOffset); + String dayOfMonth = "0"; + evaluator.evaluateInCell(dayCell); + if (dayCell.getCellTypeEnum().equals(CellType.NUMERIC)) { + dayOfMonth = ((int) dayCell.getNumericCellValue()) + ""; + } else { + dayOfMonth = dayCell.getStringCellValue(); + } + if (dayOfMonth.length() == 1) { + dayOfMonth = "0" + dayOfMonth; + } + if (!dayOfMonth.equals("00")) { + String day = string + "-" + dayOfMonth; + + String hour = "08:00"; + for (int hourOffset = calendarRowStartOffset; hourOffset < calendarRowEndOffset; hourOffset++) { + Row hourRow = sheet.getRow(weekOffset + hourOffset); + + Cell hourCell = hourRow.getCell(hourColum); + if (hourCell.getCellTypeEnum().equals(CellType.NUMERIC)) { + + SimpleDateFormat formatTime = new SimpleDateFormat("HH:mm"); + String hourString = formatTime.format(hourCell.getDateCellValue()); + + if (isHour(hourString)) { + hour = hourString; + } + } + + Cell queryCell = hourRow.getCell(dayColumnOffset); + if (queryCell != null) { + if (queryCell.getCellTypeEnum().equals(CellType.STRING)) { + String query = queryCell.getStringCellValue(); + + if (query != null && !query.isEmpty()) { + AppointmentEntry entry = parser.parseAppointment(query, hour); + entry.setDay(day); + + result.add(entry); + } + } else if (!queryCell.getCellTypeEnum().equals(CellType.BLANK)) { + logger + .warn("Skipping cell: " + queryCell.getAddress() + ", " + queryCell.getSheet().getSheetName() + ", type: " + queryCell.getCellTypeEnum()); + } + } + } + } + } + + } + return result; + } + + Pattern timePattern = Pattern.compile("^[0-9][0-9]\\:[0-9][0-9]"); + + private boolean isHour(String hourString) { + Matcher matcher = timePattern.matcher(hourString); + return matcher.find(); + } + + private String parseMonth(String monthName) throws ParseException { + Date date = new SimpleDateFormat("MMMM", Locale.ENGLISH).parse(monthName); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + String result = (cal.get(Calendar.MONTH) + 1) + ""; + if (result.length() == 1) { + result = "0" + result; + } + 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/resources/log4j.properties b/appointment-import/src/main/resources/log4j.properties new file mode 100644 index 0000000000000000000000000000000000000000..c3a78a9276a81dd3ed72637dae8f44705769a156 --- /dev/null +++ b/appointment-import/src/main/resources/log4j.properties @@ -0,0 +1,8 @@ +#Set root logger 's level and its appender to an appender called CONSOLE which is defined below. +log4j.rootLogger=fatal, CONSOLE + +#Set the behavior of the CONSOLE appender +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n +#log4j.appender.CONSOLE.layout.ConversionPattern=%m%n diff --git a/appointment-import/src/test/java/smash/appointment/parse/AllTests.java b/appointment-import/src/test/java/smash/appointment/parse/AllTests.java new file mode 100644 index 0000000000000000000000000000000000000000..5d18d8096f02dd342ce2227684342276b60de532 --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/AllTests.java @@ -0,0 +1,25 @@ +package smash.appointment.parse; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ AppointmentDaoTest.class, // + CellParserTest.class, // + LihControlMappingParserTest.class, // + LihControlParserTest.class, // + PrcControlParserTest.class, // + PrcFlyingParserTest.class, // + PrcSubjectsParserTest.class, // + RedcapParserTest.class, // + + SubjectDaoTest.class, // + SubjectParserTest.class, // + VisitTest.class, // + XlsxCalendarProcessorTest.class, // +}) + +public class AllTests { + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/AppointmentDaoTest.java b/appointment-import/src/test/java/smash/appointment/parse/AppointmentDaoTest.java new file mode 100644 index 0000000000000000000000000000000000000000..82dba7faaf64b77c6ffda2e6d87bcca7244ce7fe --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/AppointmentDaoTest.java @@ -0,0 +1,69 @@ +package smash.appointment.parse; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class AppointmentDaoTest { + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void getVisits() { + Subject subject1 = new Subject("a", "b", "c", "d"); + AppointmentEntry appointment = new AppointmentEntry(); + appointment.setSubject(subject1); + appointment.setDay("2016-02-02"); + appointment.addType(AppointmentType.LEVEL_A); + + AppointmentEntry appointment2 = new AppointmentEntry(); + appointment2.setSubject(subject1); + appointment2.setDay("2016-02-02"); + appointment2.addType(AppointmentType.LEVEL_B); + + AppointmentEntry appointment3 = new AppointmentEntry(); + appointment3.setSubject(subject1); + appointment3.setDay("2011-02-02"); + appointment3.addType(AppointmentType.LEVEL_A); + + AppointmentDao appointmentDao = new AppointmentDao(); + appointmentDao.addAppointment(appointment); + appointmentDao.addAppointment(appointment2); + appointmentDao.addAppointment(appointment3); + assertEquals(2, appointmentDao.getVisits().size()); + } + + @Test + public void getVisits2() { + 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.addType(AppointmentType.LEVEL_A); + + AppointmentEntry appointment3 = new AppointmentEntry(); + appointment3.setSubject(subject2); + appointment3.setDay("2016-02-02"); + appointment3.addType(AppointmentType.LEVEL_B); + + AppointmentDao appointmentDao = new AppointmentDao(); + appointmentDao.addAppointment(appointment); + appointmentDao.addAppointment(appointment3); + assertEquals(2, appointmentDao.getVisits().size()); + } + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/CellParseTestCase.java b/appointment-import/src/test/java/smash/appointment/parse/CellParseTestCase.java new file mode 100644 index 0000000000000000000000000000000000000000..a43dcbc578952867a0cd36fcbd74d1284fbc3466 --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/CellParseTestCase.java @@ -0,0 +1,15 @@ +package smash.appointment.parse; + +class CellParseTestCase { + String query; + Subject subject; + String time; + AppointmentType[] types; + + public CellParseTestCase(String query, Subject subject, String time, AppointmentType[] types) { + this.query = query; + this.subject = subject; + this.time = time; + this.types = types; + } +}; diff --git a/appointment-import/src/test/java/smash/appointment/parse/CellParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/CellParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..56ae493787677dad7bf08861061720b5302a161e --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/CellParserTest.java @@ -0,0 +1,147 @@ +package smash.appointment.parse; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.apache.log4j.Logger; +import org.junit.Before; +import org.junit.Test; + +public class CellParserTest extends TestBase { + Logger logger = Logger.getLogger(CellParserTest.class); + + List<CellParseTestCase> testCases; + CellParser parser; + + @Before + public void setUp() { + super.setUp(); + + parser = new CellParser(); + parser.setSubjectDao(subjectDao); + + testCases = new ArrayList<CellParseTestCase>(); + + testCases.add(new CellParseTestCase("Piotr Gawron level A FU V3", piotrGawron, null, new AppointmentType[] { AppointmentType.LEVEL_A })); + testCases.add(new CellParseTestCase("09:00 Jan Kowalski-Nowak level A", janKowalskiNowak, "09:00", new AppointmentType[] { AppointmentType.LEVEL_A })); + testCases.add( + new CellParseTestCase( + "ND0002 l664574645 (sms)evel BV © + SB ©", janKowalskiNowak, null, new AppointmentType[] { AppointmentType.LEVEL_BV, AppointmentType.LEVEL_SB })); + testCases.add(new CellParseTestCase("ND0001 654654631 level B ©", piotrGawron, null, new AppointmentType[] { AppointmentType.LEVEL_B })); + testCases.add( + new CellParseTestCase( + "John Doe BV + BG + SB", johnDoe, null, new AppointmentType[] { AppointmentType.LEVEL_BV, AppointmentType.LEVEL_BG, AppointmentType.LEVEL_SB })); + testCases.add(new CellParseTestCase("Kowalski-Nowak m-Power", janKowalskiNowak, null, new AppointmentType[] { AppointmentType.LEVEL_B_M_POWER })); + testCases.add(new CellParseTestCase("ND0004 Name BV ©", cateKowalsky, null, new AppointmentType[] { AppointmentType.LEVEL_BV })); + testCases.add( + new CellParseTestCase("ND0004 level BV (c) + SB ©", cateKowalsky, null, new AppointmentType[] { AppointmentType.LEVEL_BV, AppointmentType.LEVEL_SB })); + testCases.add( + new CellParseTestCase( + "Cate Kowalsky level BV + BG + SB + m-Power", cateKowalsky, null, + new AppointmentType[] { AppointmentType.LEVEL_BV, AppointmentType.LEVEL_BG, AppointmentType.LEVEL_SB, AppointmentType.LEVEL_B_M_POWER })); + testCases.add(new CellParseTestCase("sb name level A", null, null, new AppointmentType[] { AppointmentType.LEVEL_A })); + testCases.add(new CellParseTestCase("Andrew Dude level A FU V3", andrewDude, null, new AppointmentType[] { AppointmentType.LEVEL_A })); + testCases.add( + new CellParseTestCase( + "Gawron Piotr BV + BG + neuro level A (FU)", piotrGawron, null, + new AppointmentType[] { AppointmentType.LEVEL_A, AppointmentType.LEVEL_BV, AppointmentType.LEVEL_BG })); + + testCases.add( + new CellParseTestCase( + "Gawron Piotr level B © + level A neuro ©", piotrGawron, null, new AppointmentType[] { AppointmentType.LEVEL_A, AppointmentType.LEVEL_B })); + + testCases.add( + new CellParseTestCase( + "Gawron Piotr level B © + BV © + SB ©", piotrGawron, null, + new AppointmentType[] { AppointmentType.LEVEL_B, AppointmentType.LEVEL_BV, AppointmentType.LEVEL_SB })); + + testCases.add( + new CellParseTestCase( + "Gawron Piotr level B + BV + BG", piotrGawron, null, + new AppointmentType[] { AppointmentType.LEVEL_B, AppointmentType.LEVEL_BV, AppointmentType.LEVEL_BG })); + + testCases.add( + new CellParseTestCase("Gawron Piotr level B + BG", piotrGawron, null, new AppointmentType[] { AppointmentType.LEVEL_B, AppointmentType.LEVEL_BG })); + testCases.add( + new CellParseTestCase( + "Gawron Piotr level B © + BV © + SB ©", piotrGawron, null, + new AppointmentType[] { AppointmentType.LEVEL_B, AppointmentType.LEVEL_BV, AppointmentType.LEVEL_SB })); + testCases.add( + new CellParseTestCase( + "Gawron Piotr level BG + SB + M-Power", piotrGawron, null, + new AppointmentType[] { AppointmentType.LEVEL_BG, AppointmentType.LEVEL_SB, AppointmentType.LEVEL_B_M_POWER })); + + testCases.add( + new CellParseTestCase("Gawron Piotr level B + BV", piotrGawron, null, new AppointmentType[] { AppointmentType.LEVEL_B, AppointmentType.LEVEL_BV })); + testCases.add( + new CellParseTestCase( + "Gawron Piotr level BG + SB + M-Power", piotrGawron, null, + new AppointmentType[] { AppointmentType.LEVEL_BG, AppointmentType.LEVEL_SB, AppointmentType.LEVEL_B_M_POWER })); + + } + + @Test + public void testExtractTime() { + for (CellParseTestCase testCase : testCases) { + String result = parser.extractTime(testCase.query); + assertEquals("Invalid time parsed from query: " + testCase.query, testCase.time, result); + } + } + + @Test + public void testRemoveTime() { + for (CellParseTestCase testCase : testCases) { + String result = parser.removeTime(testCase.query); + if (testCase.time == null) { + assertEquals("query after removing time should be the same for query: " + testCase.query, testCase.query, result); + } else { + assertFalse(testCase.query.equals(result)); + } + } + } + + @Test + public void testRemoveTime2() { + String result = parser.removeTime("09:00 John Doe level B"); + assertEquals("John Doe level B", result); + } + + @Test + public void testExtractAppointment() { + String defaultTime = "23:55"; + for (CellParseTestCase testCase : testCases) { + AppointmentEntry appointment = parser.parseAppointment(testCase.query, defaultTime); + if (testCase.time != null) { + assertEquals("Invalid time parsed from query: " + testCase.query, testCase.time, appointment.getTime()); + } else { + assertEquals("Invalid time parsed from query (default value expected): " + testCase.query, defaultTime, appointment.getTime()); + } + assertEquals("Invalid subject parsed from query: " + testCase.query, testCase.subject, appointment.getSubject()); + assertTrue( + "Invalid type parsed from query: " + testCase.query + " expected: " + Arrays.asList(testCase.types) + "; found: " + appointment.getTypes(), + equalTypes(Arrays.asList(testCase.types), appointment.getTypes())); + } + } + + private boolean equalTypes(List<AppointmentType> types, Collection<AppointmentType> types2) { + for (AppointmentType type : types) { + if (!types2.contains(type)) { + return false; + } + } + for (AppointmentType type : types2) { + if (!types.contains(type)) { + return false; + } + } + + return true; + } + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/LihControlMappingParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/LihControlMappingParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b281fe89d51262e0f562e36a481c3124b0567d7c --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/LihControlMappingParserTest.java @@ -0,0 +1,80 @@ +package smash.appointment.parse; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class LihControlMappingParserTest extends TestBase { + Logger logger = Logger.getLogger(LihControlMappingParserTest.class); + + LihControlMappingParser processor = new LihControlMappingParser(); + + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() { + super.setUp(); + } + + @After + public void tearDown() throws Exception { + } + + private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); + + @Test + public void test() throws Exception { + List<Subject> entries = processor.processExcel("testFiles/lihControlMappingExample.xlsx"); + assertTrue(entries.size() > 0); + + Subject subject = entries.get(0); + assertEquals("L-001", subject.getScreeningNumber()); + assertEquals("Piotrek", subject.getName()); + assertEquals("Gawron", subject.getSurname()); + assertEquals("", subject.getAddress()); + assertEquals("", subject.getZipCode()); + assertEquals("", subject.getCity()); + assertEquals("", subject.getCountry()); + assertEquals("343", subject.getPhone1()); + assertEquals("", subject.getPhone2()); + assertEquals("", subject.getPhone3()); + assertEquals("", subject.getMail()); + assertEquals("", subject.getDiagnosisYear()); + assertEquals("", subject.getDiagnosis()); + assertEquals("", subject.getReferal()); + assertEquals("2015-08-03", subject.getAddDate()); + assertEquals("ND3333", subject.getNdNumber()); + assertEquals("", subject.getBirthDate()); + + for (Subject s:entries) { + DATE_FORMATTER.parse(s.getAddDate()); + } + } + + + @Test + public void testFixDate() throws Exception { + DATE_FORMATTER.parse(processor.fixDate("2016-cot-31")); + Date d = DATE_FORMATTER.parse(processor.fixDate("25-11-1951")); + assertEquals("1951-11-25",DATE_FORMATTER.format(d)); + DATE_FORMATTER.parse(processor.fixDate("1957??-10-25")); + DATE_FORMATTER.parse(processor.fixDate("2016?-sep-12")); + DATE_FORMATTER.parse(processor.fixDate("2016-aou-26")); + DATE_FORMATTER.parse(processor.fixDate("2016-avr-14")); + DATE_FORMATTER.parse(processor.fixDate("2016-fev-03")); + DATE_FORMATTER.parse(processor.fixDate("-","2016-01-01")); + } + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/LihControlParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/LihControlParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bce5ee61b716e85c661cbae9db0ff0c792362469 --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/LihControlParserTest.java @@ -0,0 +1,68 @@ +package smash.appointment.parse; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class LihControlParserTest extends TestBase { + Logger logger = Logger.getLogger(LihControlParserTest.class); + + LihControlParser processor = new LihControlParser(); + + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() { + super.setUp(); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testParseLang() throws Exception { + assertEquals("English",processor.getMappedLanguage("EN")); + } + @Test + public void test() throws Exception { + List<Subject> entries = processor.processExcel("testFiles/lihControlExample.xlsx"); + assertTrue(entries.size() > 0); + + Subject subject = entries.get(0); + assertEquals("L-001", subject.getScreeningNumber()); + assertEquals("Name", subject.getName()); + assertEquals("Surname", subject.getSurname()); + assertTrue(subject.getRemarks().contains("001 rdv 01/09/2015 9h jyf")); + assertTrue(subject.getRemarks().contains("PD family relation=pd info")); + assertEquals("11, Rue blabla", subject.getAddress()); + assertEquals("L-3322", subject.getZipCode()); + assertEquals("Luxembourg", subject.getCity()); + assertEquals("", subject.getCountry()); + assertEquals("123456789", subject.getPhone1()); + assertEquals("321654", subject.getPhone2()); + assertEquals("", subject.getPhone3()); + assertEquals("email@pt.lu", subject.getMail()); + assertEquals("", subject.getDiagnosisYear()); + assertEquals("", subject.getDiagnosis()); + assertEquals("", subject.getReferal()); + assertNotNull(subject.getAddDate()); + assertEquals("", subject.getNdNumber()); + assertEquals("1937-01-03", subject.getBirthDate()); + assertTrue(subject.getRemarks().contains("some other remark")); + assertTrue(subject.getRemarks().contains("at home: NMS + RFQ 1 + RFQ 2 + REM + PDSS: manque une page ds RFQ => Linda pr level b 09/09/15")); + assertTrue(subject.getLanguages().contains("French")); + assertTrue(subject.getLanguages().contains("German")); + } + + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/PrcControlParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/PrcControlParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9558de7cbac2412517d9969e30dea5f5617aa457 --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/PrcControlParserTest.java @@ -0,0 +1,59 @@ +package smash.appointment.parse; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class PrcControlParserTest extends TestBase { + Logger logger = Logger.getLogger(PrcSubjectsParserTest.class); + + PrcControlParser processor = new PrcControlParser(); + + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() { + super.setUp(); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void test() throws Exception { + List<Subject> entries = processor.processExcel("testFiles/prcControlesExample.xlsx"); + assertTrue(entries.size() > 0); + + Subject subject = entries.get(0); + assertEquals("P-333", subject.getScreeningNumber()); + assertEquals("CCC", subject.getName()); + assertEquals("BBB", subject.getSurname()); + assertTrue(subject.getRemarks().contains("note")); + assertEquals("DDD", subject.getAddress()); + assertEquals("L-2423", subject.getZipCode()); + assertEquals("Luxembourg", subject.getCity()); + assertEquals("", subject.getCountry()); + assertEquals("123", subject.getPhone1()); + assertEquals("456", subject.getPhone2()); + assertEquals("789", 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()); + } + + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/PrcFlyingParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/PrcFlyingParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ba4224e9e2496171b9f16502c33128f3384021fb --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/PrcFlyingParserTest.java @@ -0,0 +1,60 @@ +package smash.appointment.parse; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class PrcFlyingParserTest extends TestBase { + Logger logger = Logger.getLogger(PrcSubjectsParserTest.class); + + PrcFlyingParser processor = new PrcFlyingParser(); + + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() { + super.setUp(); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void test() throws Exception { + List<Subject> entries = processor.processExcel("testFiles/prcFlyingTeam.xlsx"); + assertTrue(entries.size() > 0); + + Subject subject = entries.get(0); + assertEquals("P-222", subject.getScreeningNumber()); + assertEquals("DOE John", subject.getSurname()); + assertEquals("", subject.getName()); + assertTrue(subject.getRemarks().contains("notes")); + assertEquals("8, rue des Nowhere", subject.getAddress()); + assertEquals("F-57100", subject.getZipCode()); + assertEquals("Paris", subject.getCity()); + assertEquals("France", subject.getCountry()); + assertEquals("001234325435", subject.getPhone1()); + assertEquals("666", subject.getPhone2()); + assertEquals("777", subject.getPhone3()); + assertEquals("mail@address.lu", subject.getMail()); + assertEquals("1998", subject.getDiagnosisYear()); + assertEquals("BLA", subject.getDiagnosis()); + assertEquals("DR", subject.getReferal()); + assertEquals("2016-07-06", subject.getAddDate()); + assertTrue(subject.getRemarks().contains("Questionnaires OK")); + assertEquals("ND2222", subject.getNdNumber()); + assertEquals("1945-01-02", subject.getBirthDate()); + } + + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/PrcSubjectsParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/PrcSubjectsParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b5281b382d80ca1ab4355f6bbc8cf22b031e7669 --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/PrcSubjectsParserTest.java @@ -0,0 +1,80 @@ +package smash.appointment.parse; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class PrcSubjectsParserTest extends TestBase { + Logger logger = Logger.getLogger(PrcSubjectsParserTest.class); + + PrcSubjectsParser processor = new PrcSubjectsParser(); + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() { + super.setUp(); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void test() throws Exception { + List<Subject> entries = processor.processExcel("testFiles/prcSubjectsExample.xlsx"); + assertTrue(entries.size() > 0); + + Subject subject = entries.get(0); + assertEquals("P-111", subject.getScreeningNumber()); + assertEquals("abcdef", subject.getSurname()); + assertEquals("Piotr", subject.getName()); + assertTrue(subject.getRemarks().contains("this is remark")); + assertEquals("Jaskolki, 6", subject.getAddress()); + assertEquals("D-66636", subject.getZipCode()); + assertEquals("Trier", subject.getCity()); + assertEquals("Deutschland", subject.getCountry()); + assertEquals("0049 12 34 556 76", subject.getPhone1()); + assertEquals("tel2", subject.getPhone2()); + assertEquals("tel3", subject.getPhone3()); + assertEquals("piotr.cos@uni.lu", subject.getMail()); + assertEquals("1999", subject.getDiagnosisYear()); + assertEquals("unknown", subject.getDiagnosis()); + assertEquals("PG", subject.getReferal()); + assertEquals("2015-10-14", subject.getAddDate()); + assertTrue(subject.getRemarks().contains("Questionnaires OK")); + assertEquals("ND1111", subject.getNdNumber()); + assertEquals("m_id", subject.getmPowerId()); + assertEquals("1972-01-02", subject.getBirthDate()); + assertFalse(subject.isDead()); + assertFalse(subject.isResigned()); + + subject = entries.get(1); + assertTrue(subject.isDead()); + assertTrue(subject.isResigned()); + + subject = entries.get(2); + assertFalse(subject.isDead()); + assertFalse(subject.isResigned()); + + subject = entries.get(3); + assertFalse(subject.isDead()); + assertFalse(subject.isResigned()); + + subject = entries.get(4); + assertFalse(subject.isDead()); + assertTrue(subject.isResigned()); + + } + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/RedcapParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/RedcapParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e912829f7d1345aeedb3b5aa079e1d35c0eff59b --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/RedcapParserTest.java @@ -0,0 +1,74 @@ +package smash.appointment.parse; + +import static org.junit.Assert.*; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; + +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class RedcapParserTest extends TestBase{ + Logger logger = Logger.getLogger(RedcapParserTest.class); + RedcapParser parser = new RedcapParser(); + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() { + super.setUp(); + parser.setSubjectDao(subjectDao); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testParseFile() throws FileNotFoundException, IOException { + List<AppointmentEntry> entries = parser.parse("testFiles/redcap_imp.txt"); + assertTrue(entries.size() > 0); + assertEquals(3, subjectDao.getByNdNumber("ND0001").getLanguages().size()); + + int levelACount = 0; + int levelBCount = 0; + int levelBVCount = 0; + int levelBGCount = 0; + int levelSBCount = 0; + int levelMPowerCount = 0; + for (AppointmentEntry appointmentEntry : entries) { + if (appointmentEntry.getTypes().contains(AppointmentType.LEVEL_A)) { + levelACount++; + } + if (appointmentEntry.getTypes().contains(AppointmentType.LEVEL_B)) { + levelBCount++; + } + if (appointmentEntry.getTypes().contains(AppointmentType.LEVEL_BG)) { + levelBGCount++; + } + if (appointmentEntry.getTypes().contains(AppointmentType.LEVEL_BV)) { + levelBVCount++; + } + if (appointmentEntry.getTypes().contains(AppointmentType.LEVEL_SB)) { + levelSBCount++; + } + if (appointmentEntry.getTypes().contains(AppointmentType.LEVEL_B_M_POWER)) { + levelMPowerCount++; + } + } + assertTrue(levelACount > 0); + assertTrue(levelBCount > 0); + assertTrue(levelBVCount > 0); + assertTrue(levelBGCount > 0); + assertTrue(levelSBCount > 0); + assertTrue(levelMPowerCount > 0); + + } + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/SubjectDaoTest.java b/appointment-import/src/test/java/smash/appointment/parse/SubjectDaoTest.java new file mode 100644 index 0000000000000000000000000000000000000000..66fc18c54fc04749163cbd38d5a4cbc0c29a5e9f --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/SubjectDaoTest.java @@ -0,0 +1,32 @@ +package smash.appointment.parse; + +import static org.junit.Assert.assertEquals; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class SubjectDaoTest { + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testReadFile() throws Exception { + SubjectDao subjectDao = new SubjectDao(); + subjectDao.readFile("testFiles/subjects.txt"); + assertEquals(2, subjectDao.getSubjects().size()); + assertEquals("Piotr", subjectDao.getSubjects().get(0).getName()); + } + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/SubjectParserTest.java b/appointment-import/src/test/java/smash/appointment/parse/SubjectParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a9efafaf25f0c43f333bd4afa97c370dddc5c4ce --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/SubjectParserTest.java @@ -0,0 +1,32 @@ +package smash.appointment.parse; + +import static org.junit.Assert.*; + +import java.util.Calendar; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class SubjectParserTest { + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testParseDate() { + SubjectParser parser = new PrcControlParser(); + assertEquals("", parser.getDate(null, null)); + } + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/TestBase.java b/appointment-import/src/test/java/smash/appointment/parse/TestBase.java new file mode 100644 index 0000000000000000000000000000000000000000..b9663f46e9e6dfe9a395fecd0166b97de4ef75e0 --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/TestBase.java @@ -0,0 +1,25 @@ +package smash.appointment.parse; + +public class TestBase { + SubjectDao subjectDao; + + Subject piotrGawron = new Subject("Piotr", "Gawron", "ND0001", "1"); + Subject janKowalskiNowak = new Subject("Jan", "Kowalski-Nowak", "ND0002", "2"); + Subject johnDoe = new Subject("John", "Doe", "ND0003", "3"); + Subject cateKowalsky = new Subject("Cate", "Kowalsky", "ND0004", "4"); + Subject andrewDude = new Subject(" Andrew ", " Dude ", "ND0005", "5"); + Subject unknownDude = new Subject(" Unknownnnnnnnn ", " Dude ", "ND0006", "6"); + + public void setUp() { + subjectDao = new SubjectDao(); + + subjectDao.addSubject(new Subject("Piotr Marcin", "Gawron", "ND1005", "1005"), null); + subjectDao.addSubject(piotrGawron, null); + subjectDao.addSubject(janKowalskiNowak, null); + subjectDao.addSubject(johnDoe, null); + subjectDao.addSubject(cateKowalsky, null); + subjectDao.addSubject(andrewDude, null); + subjectDao.addSubject(unknownDude, null); + } + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/VisitTest.java b/appointment-import/src/test/java/smash/appointment/parse/VisitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fd3eb2d963d5699e12d1abc642d67070226e9a3a --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/VisitTest.java @@ -0,0 +1,48 @@ +package smash.appointment.parse; + +import static org.junit.Assert.*; + +import java.text.ParseException; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class VisitTest { + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testGetStartDate() { + Subject subject = new Subject("!", "", "4", "5"); + Visit visit = new Visit(subject); + AppointmentEntry entry = new AppointmentEntry(); + entry.setSubject(subject); + entry.setDay("2015-02-01 8:00"); + visit.addAppointment(entry); + assertEquals("2015-02-01", visit.getStartDate()); + } + + @Test + public void testGetEndDate() throws ParseException { + Subject subject = new Subject("!", "", "4", "5"); + Visit visit = new Visit(subject); + AppointmentEntry entry = new AppointmentEntry(); + entry.setSubject(subject); + entry.setDay("2015-02-01 8:00"); + visit.addAppointment(entry); + assertEquals("2015-05-01", visit.getEndDate()); + } + +} diff --git a/appointment-import/src/test/java/smash/appointment/parse/XlsxCalendarProcessorTest.java b/appointment-import/src/test/java/smash/appointment/parse/XlsxCalendarProcessorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8e23b0a920bfd4ef3d4f0c218a767e502bae523b --- /dev/null +++ b/appointment-import/src/test/java/smash/appointment/parse/XlsxCalendarProcessorTest.java @@ -0,0 +1,41 @@ +package smash.appointment.parse; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.FileNotFoundException; +import java.util.Calendar; +import java.util.List; + +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class XlsxCalendarProcessorTest extends TestBase { + Logger logger = Logger.getLogger(XlsxCalendarProcessorTest.class); + + XlsxCalendarProcessor processor = new XlsxCalendarProcessor(); + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() { + super.setUp(); + processor.setSubjectDao(subjectDao); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testReadExcel() throws Exception { + List<AppointmentEntry> entries = processor.processExcel("testFiles/calendarExample.xlsx", Calendar.getInstance()); + assertTrue(entries.size() > 0); + } + +} diff --git a/appointment-import/src/test/resources/log4j.properties b/appointment-import/src/test/resources/log4j.properties new file mode 100644 index 0000000000000000000000000000000000000000..e108a78cf8570a6f5bfc3e00dfaee3c45a1e829e --- /dev/null +++ b/appointment-import/src/test/resources/log4j.properties @@ -0,0 +1,8 @@ +#Set root logger 's level and its appender to an appender called CONSOLE which is defined below. +log4j.rootLogger=debug, CONSOLE + +#Set the behavior of the CONSOLE appender +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n +#log4j.appender.CONSOLE.layout.ConversionPattern=%m%n diff --git a/appointment-import/testFiles/calendarExample.xlsx b/appointment-import/testFiles/calendarExample.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b8a0e42b59245f10692d9739ade2a0e8e4cc8b03 Binary files /dev/null and b/appointment-import/testFiles/calendarExample.xlsx differ diff --git a/appointment-import/testFiles/lihControlExample.xlsx b/appointment-import/testFiles/lihControlExample.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..526e749bdf8cb818d13e98b763afb22b3ec3b071 Binary files /dev/null and b/appointment-import/testFiles/lihControlExample.xlsx differ diff --git a/appointment-import/testFiles/lihControlMappingExample.xlsx b/appointment-import/testFiles/lihControlMappingExample.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4d54795013bdb361399cc256f0c51ae913af2cf5 Binary files /dev/null and b/appointment-import/testFiles/lihControlMappingExample.xlsx differ diff --git a/appointment-import/testFiles/prcControlesExample.xlsx b/appointment-import/testFiles/prcControlesExample.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2277978b4984e2871171b48d30d06cc32d9ee31e Binary files /dev/null and b/appointment-import/testFiles/prcControlesExample.xlsx differ diff --git a/appointment-import/testFiles/prcFlyingTeam.xlsx b/appointment-import/testFiles/prcFlyingTeam.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..56646dc463b43ec98bbf36b20c83cade9069ac44 Binary files /dev/null and b/appointment-import/testFiles/prcFlyingTeam.xlsx differ diff --git a/appointment-import/testFiles/prcSubjectsExample.xlsx b/appointment-import/testFiles/prcSubjectsExample.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b728be7a0083e5574a6fc513934de0535fb19065 Binary files /dev/null and b/appointment-import/testFiles/prcSubjectsExample.xlsx differ diff --git a/appointment-import/testFiles/redcap_imp.txt b/appointment-import/testFiles/redcap_imp.txt new file mode 100644 index 0000000000000000000000000000000000000000..8065e5c6c17ca5d0d5803ba08831feb0798a0406 --- /dev/null +++ b/appointment-import/testFiles/redcap_imp.txt @@ -0,0 +1,8 @@ +Subject ID Event Name Date/Time of Birth Sex Language: most fluent Language: second most fluent Language: third most fluent Language: fourth most fluent Basic assessment (Level A) Basic assessment: start date Basic assessment: end date Basic assessment: number of visits Detailed neuropsychological assessment (Level B) Detailed neuropsychological assessment: start date Detailed neuropsychological assessment: end date Detailed neuropsychological assessment: number of visits Detailed motor assessment (Level B) Detailed motor assessment: start date Detailed motor assessment: end date Detailed motor assessment: number of visits Detailed sensory assessment (Level B) Detailed sensory assessment: start date Detailed sensory assessment: end date Detailed sensory assessment: number of visits PSP (Level B) PSP: start date PSP: end date PSP: number of visits Blood Blood: date Urine Urine: date CSF CSF: date Imaging Imaging: date Stool Stool: collection acceptance by patient Stool: collection date proposed Stool: date collected Skin biopsy Skin biopsy: date Saliva Saliva: date mPower mPower: date +ND0001 Visit 1 1955-10-24 10:44 M Polish German French Yes 2015-01-04 10:14 2015-03-04 14:18 1 Yes 2015-03-04 Yes 2015-03-04 Yes 2016-10-20 Yes 2015-03-04 2015-03-11 +ND0001 Visit 2 Yes 2016-12-12 09:34 2017-01-24 10:46 2 +ND0002 Visit 1 1956-05-22 14:53 M Polish Yes 2015-03-04 14:56 2015-03-04 17:43 1 Yes 2015-07-29 2015-07-29 1 No No No Yes 2015-05-13 Yes 2015-05-13 No No No No Yes 2015-05-13 +ND0002 Visit 2 Yes 2016-01-18 10:00 2016-01-18 13:10 1 Yes 2016-05-26 2016-05-26 1 Yes 2016-01-18 Yes 2016-01-18 Yes Yes 2016-05-26 2016-05-26 Yes 2016-05-26 Yes 2016-01-18 +ND0003 Visit 1 1957-07-15 09:21 F Polish German Rusian English Yes 2015-03-11 09:25 2015-03-11 14:58 1 Yes 2015-11-12 2015-11-12 1 Yes 2015-03-11 Yes 2015-03-11 Yes 2015-03-11 +ND0003 Visit 2 Yes 2016-04-27 11:31 2016-05-11 13:30 2 Yes 2016-06-16 2016-06-16 1 Yes 2016-08-18 2016-08-18 1 Yes 2016-04-27 Yes 2016-04-27 Yes Yes 2016-04-27 2016-04-28 Yes 2016-07-28 Yes 2016-04-27 +ND0003 Visit 3 \ No newline at end of file diff --git a/appointment-import/testFiles/subjects.txt b/appointment-import/testFiles/subjects.txt new file mode 100644 index 0000000000000000000000000000000000000000..c55594f7ee41d31b0b81aaf1b38b46eb949d5bb4 --- /dev/null +++ b/appointment-import/testFiles/subjects.txt @@ -0,0 +1,2 @@ +Piotr Gawron ND0001 1 +John Doe ND0002 2 diff --git a/smash/web/models.py b/smash/web/models.py index c5b2915b5b2839bb9cd92bd1defb4f12061592fa..2de5fe18f0332705220e344e9e625f62e3e65a6b 100644 --- a/smash/web/models.py +++ b/smash/web/models.py @@ -5,6 +5,7 @@ from django.utils import timezone from django.contrib.auth.models import User, AnonymousUser import datetime +from datetime import timedelta def get_current_year(): return datetime.datetime.now().year @@ -34,36 +35,50 @@ class Subject(models.Model): (SEX_CHOICES_FEMALE,'Female'), ) - STATUS_CHOICES_DEAD = 'DEA' - STATUS_CHOICES_REJECTED = 'REJ' - STATUS_CHOICES_NOT_CONTACTED = 'NCO' - STATUS_CHOICES_TEST_GROUP = 'TST' - STATUS_CHOICES_LEVEL_A = 'LEA' - STATUS_CHOICES_LEVEL_B = 'LEB' - STATUS_CHOICES_OPTED_OUT = 'OPT' + LOCATION_CHOICES_LIH = 'L' + LOCATION_CHOICES = ( + (LOCATION_CHOICES_LIH,'LIH'), + ('P','PRC'), + ('F','FLYING TEAM'), + ) - STATUS_CHOICES = ( - (STATUS_CHOICES_NOT_CONTACTED, 'Not contacted'), - (STATUS_CHOICES_TEST_GROUP, 'Test group'), - (STATUS_CHOICES_LEVEL_A, 'Level A'), - (STATUS_CHOICES_LEVEL_B, 'Level B'), - (STATUS_CHOICES_OPTED_OUT, 'Opted out'), - (STATUS_CHOICES_REJECTED, 'Rejected'), - (STATUS_CHOICES_DEAD, 'Dead') + SUBJECT_TYPE_CHOICES_CONTROL = 'C' + SUBJECT_TYPE_CHOICES = ( + (SUBJECT_TYPE_CHOICES_CONTROL,'CONTROL'), + ('P','PATIENT'), ) def mark_as_dead(self): - self.status = self.STATUS_CHOICES_DEAD + self.dead = True self.save() def mark_as_rejected(self): - self.status = self.STATUS_CHOICES_REJECTED + self.resigned = True self.save() sex = models.CharField(max_length=1, choices=SEX_CHOICES, verbose_name='Sex' ) + type = models.CharField(max_length=1, + choices=SUBJECT_TYPE_CHOICES, + verbose_name='Type' + ) + + dead = models.BooleanField( + verbose_name='Dead', + default= False, + editable=False + ) + resigned = models.BooleanField( + verbose_name='Resigned', + default= False, + editable=False + ) + default_appointment_location = models.CharField(max_length=1, + choices=LOCATION_CHOICES, + verbose_name='Default appointment location' + ) first_name = models.CharField(max_length=50, verbose_name='First name' ) @@ -127,10 +142,6 @@ class Subject(models.Model): blank=True, verbose_name='MPower ID' ) - status = models.CharField(max_length=3, choices=STATUS_CHOICES, - verbose_name='Status', - default='NCO' - ) comments = models.CharField(max_length=2000, blank=True, verbose_name='Comments' @@ -155,6 +166,16 @@ class Subject(models.Model): verbose_name='Year of diagnosis (YYYY)' ) + def latest_visit(self): + visits = self.visit_set.all() + if len(visits)==0: + return None + result = visits[0]; + for visit in visits: + if (visit.datetime_begin > result.datetime_begin): + result = visit + return result + def __str__(self): return "%s %s" % (self.first_name, self.last_name) @@ -173,19 +194,6 @@ class Visit(models.Model): verbose_name='Visit ends at' ) # Deadline before which all appointments need to be scheduled - TYPE_CHOICES_LEVEL_A_VISIT = 'A' - TYPE_CHOICES_LEVEL_B_VISIT = 'B' - TYPE_CHOICES_OTHER = 'O' - - TYPE_CHOICES = ( - (TYPE_CHOICES_LEVEL_A_VISIT, 'Level A visit'), - (TYPE_CHOICES_LEVEL_B_VISIT, 'Level B visit'), - (TYPE_CHOICES_OTHER, 'Other') - ) - visit_type = models.CharField(max_length=1, choices=TYPE_CHOICES, - verbose_name='Visit type', - default='O' - ) is_finished = models.BooleanField( verbose_name='Has ended', default=False @@ -196,6 +204,35 @@ class Visit(models.Model): def __str__(self): 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)) + + def mark_as_finished(self): + self.is_finished = True + self.save() + + visit_finished = self.datetime_begin + + appointments = Appointment.objects.filter(visit=self) + + for appointment in appointments: + visit_finished = max(visit_finished,appointment.datetime_when) + + time_to_next_visit = datetime.timedelta(days=365) + if self.subject.type== Subject.SUBJECT_TYPE_CHOICES_CONTROL: + time_to_next_visit = datetime.timedelta(days=365*3+366) + + Visit.objects.create( + subject = self.subject, + datetime_begin = visit_finished+time_to_next_visit, + datetime_end = visit_finished+time_to_next_visit+datetime.timedelta(days=93) + ) + + def end_if_appointments_were_finished(self): the_appointments = self.appointment_set.all() finished = True @@ -257,6 +294,11 @@ class Room (models.Model): class AppointmentType (models.Model): + + + DEFAULT_COLOR = '#cfc600' + DEFAULT_FONT_COLOR = '#00000' + required_equipment = models.ManyToManyField(Item, verbose_name='Required equipment', blank = True @@ -270,6 +312,18 @@ class AppointmentType (models.Model): default_duration = models.IntegerField( verbose_name='Default duration (in minutes)' ) + calendar_color_priority = models.IntegerField( + verbose_name='Calendar color priority', + default=1 + ) + calendar_color = models.CharField(max_length=2000, + verbose_name='Calendar color', + default=DEFAULT_COLOR + ) + calendar_font_color = models.CharField(max_length=2000, + verbose_name='Calendar color', + default=DEFAULT_FONT_COLOR + ) rest_time = models.IntegerField( verbose_name='Suggested rest time' ) @@ -434,9 +488,8 @@ class Appointment(models.Model): verbose_name='Worker conducting the assessment (if applicable)', null=True, blank=True ) - appointment_type = models.ForeignKey(AppointmentType, - verbose_name='Appointment type', - null=True, blank=True + appointment_types = models.ManyToManyField(AppointmentType, + verbose_name='Appointment types', ) room = models.ForeignKey(Room, verbose_name='Room ID', @@ -446,6 +499,11 @@ class Appointment(models.Model): visit = models.ForeignKey(Visit, verbose_name='Visit ID' ) + comment = models.CharField(max_length=1024, + verbose_name='Comment', + null=True, + blank=True + ) datetime_when = models.DateTimeField( verbose_name='Appointment on', null=True, blank=True @@ -455,5 +513,43 @@ class Appointment(models.Model): )#Potentially redundant; but can be used to manually adjust appointment's length is_finished = models.BooleanField( verbose_name='Has the appointment ended?', - default=False + default=False, + editable=False ) + + def mark_as_finished(self): + self.is_finished = True + self.save() + + def datetime_until(self): + if self.datetime_when is None: + return None + else: + return self.datetime_when + timedelta(minutes=max(self.length, 15)) + + def color(self): + result = AppointmentType.DEFAULT_COLOR + priority = 1000000 + for type in self.appointment_types.all(): + if type.calendar_color_priority<priority: + priority=type.calendar_color_priority + result = type.calendar_color + return result + + def font_color(self): + result = AppointmentType.DEFAULT_FONT_COLOR + priority = 1000000 + for type in self.appointment_types.all(): + if type.calendar_color_priority<priority: + priority=type.calendar_color_priority + result = type.calendar_font_color + return result + + def title(self): + if self.visit.subject.screening_number=="---": + return self.comment + else: + title = self.visit.subject.first_name + " " + self.visit.subject.last_name + " type: " + for type in self.appointment_types.all(): + title += type.code+", " + return title diff --git a/smash/web/static/flags/ARABIC.png b/smash/web/static/flags/ARABIC.png new file mode 100644 index 0000000000000000000000000000000000000000..a377d4727f6a0fbc4575a22b7f995557602883a4 Binary files /dev/null and b/smash/web/static/flags/ARABIC.png differ diff --git a/smash/web/static/flags/DK.png b/smash/web/static/flags/DK.png new file mode 100644 index 0000000000000000000000000000000000000000..a95f38161ab8696b49cc6271e144901d702f046f Binary files /dev/null and b/smash/web/static/flags/DK.png differ diff --git a/smash/web/static/flags/ES.png b/smash/web/static/flags/ES.png new file mode 100644 index 0000000000000000000000000000000000000000..3d4cc208cfcfcaceb63cbe885847a532d6607148 Binary files /dev/null and b/smash/web/static/flags/ES.png differ diff --git a/smash/web/static/flags/FI.png b/smash/web/static/flags/FI.png new file mode 100644 index 0000000000000000000000000000000000000000..86d788a476e4ae0deba086210e73aa1d8f42693c Binary files /dev/null and b/smash/web/static/flags/FI.png differ diff --git a/smash/web/static/flags/GR.png b/smash/web/static/flags/GR.png new file mode 100644 index 0000000000000000000000000000000000000000..14cb515ebc0b044efbc4bd511e42fdb65bfd790e Binary files /dev/null and b/smash/web/static/flags/GR.png differ diff --git a/smash/web/static/flags/HU.png b/smash/web/static/flags/HU.png new file mode 100644 index 0000000000000000000000000000000000000000..bf0afeba93a6db0346bf96a3c92314490479cb8e Binary files /dev/null and b/smash/web/static/flags/HU.png differ diff --git a/smash/web/static/flags/IT.png b/smash/web/static/flags/IT.png new file mode 100644 index 0000000000000000000000000000000000000000..ee61e0633bda155c34a9a5c54c5329f302921d0b Binary files /dev/null and b/smash/web/static/flags/IT.png differ diff --git a/smash/web/static/flags/NL.png b/smash/web/static/flags/NL.png new file mode 100644 index 0000000000000000000000000000000000000000..8607b766ea0b14c025b25aeddfd9bbffab4d2773 Binary files /dev/null and b/smash/web/static/flags/NL.png differ diff --git a/smash/web/static/flags/PL.png b/smash/web/static/flags/PL.png new file mode 100644 index 0000000000000000000000000000000000000000..f7633f09e0166de0a1ef17d7bd86fb324843e7c1 Binary files /dev/null and b/smash/web/static/flags/PL.png differ diff --git a/smash/web/static/flags/RO.png b/smash/web/static/flags/RO.png new file mode 100644 index 0000000000000000000000000000000000000000..80d3bec04ffee83721e9e7f7bf33067b6cd9c40e Binary files /dev/null and b/smash/web/static/flags/RO.png differ diff --git a/smash/web/static/flags/SE.png b/smash/web/static/flags/SE.png new file mode 100644 index 0000000000000000000000000000000000000000..6b32d1d2e4ed46b74c6ac4bf11eba11c67961241 Binary files /dev/null and b/smash/web/static/flags/SE.png differ diff --git a/smash/web/static/flags/SK.png b/smash/web/static/flags/SK.png new file mode 100644 index 0000000000000000000000000000000000000000..765ec9971ecafee3247e9d4e58cadb3b65b625b8 Binary files /dev/null and b/smash/web/static/flags/SK.png differ diff --git a/smash/web/templates/_base.html b/smash/web/templates/_base.html index 51c5c09345f639344d6e55aa1593da2dd119fae2..3291f0ce7a57198e9098bf34a517d3250c971b01 100644 --- a/smash/web/templates/_base.html +++ b/smash/web/templates/_base.html @@ -347,7 +347,7 @@ desired effect {% block footer %} <!-- To the right --> <div class="pull-right hidden-xs"> - Version: <strong>preview 0.1.1</strong> (20 Feb 2017) + Version: <strong>preview 0.1.2</strong> (1 Mar 2017) </div> <!-- Default to the left --> diff --git a/smash/web/templates/appointments/add.html b/smash/web/templates/appointments/add.html index cbfab41313139b6f86ca04f75ecf70884db431f8..ea975643a3f0a4fe536878447e77c41fc709adf8 100644 --- a/smash/web/templates/appointments/add.html +++ b/smash/web/templates/appointments/add.html @@ -7,6 +7,10 @@ <!-- 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"> + {% include "includes/datetimepicker.css.html" %} {% endblock styles %} @@ -55,8 +59,17 @@ </div> {% endfor %} </div> + <div class="col-md-6"> + <div class="box box-primary"> + <div class="box-body no-padding"> + <div id="calendar"></div> + </div> + </div> + </div> </div><!-- /.box-body --> + + <div class="box-footer"> <div class="col-sm-6"> <button type="submit" class="btn btn-block btn-success">Add</button> @@ -66,6 +79,8 @@ </div> </div><!-- /.box-footer --> </form> + + </div> {% endblock %} @@ -78,6 +93,8 @@ <script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script> <script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script> + <script src="{% static 'AdminLTE/plugins/moment.js/moment.min.js' %}"></script> + <script src="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.min.js' %}"></script> <script> $(function () { $('#table').DataTable({ @@ -88,6 +105,52 @@ "info": true, "autoWidth": false }); + + $('#calendar').fullCalendar({ + header: { + left: 'prev,next today', + center: 'title', + right: 'month,agendaWeek' + }, + editable: false, + dayClick: function(date, jsEvent, view) { + var dateString = date.format(); + if (dateString.indexOf("T")>=0) { + dateString=dateString.replace("T"," "); + } else { + dateString=dateString+" 09:00"; + } + document.getElementById("id_datetime_when").value = dateString; + + }, + eventClick: function(calEvent, jsEvent, view) { + + var dateString = calEvent.start.format(); + if (dateString.indexOf("T")>0) { + dateString=dateString.replace("T"," "); + } else { + dateString=dateString+" 09:00"; + } + if (dateString.indexOf("+")>=0) { + dateString= dateString.substring(0,dateString.indexOf("+")); + } + document.getElementById("id_datetime_when").value = dateString; + + }, + events: [ + {% for appointment in full_appointment_list %} + { + title: '{{ appointment.title }}', + start: '{{ appointment.datetime_when | date:"c" }}', + end: '{{ appointment.datetime_until | date:"c" }}', + color: '{{ appointment.color }}', + subject_id: '{{ appointment.visit.subject.id }}', + id: '{{ appointment.id }}' + }, + {% endfor %} + ], + }); + }); </script> diff --git a/smash/web/templates/appointments/edit.html b/smash/web/templates/appointments/edit.html index 0b53364f4d057564b06d7272fabc28ec384ca9f0..35d60f3c2867725aba99acce1025b07806e50934 100644 --- a/smash/web/templates/appointments/edit.html +++ b/smash/web/templates/appointments/edit.html @@ -53,6 +53,9 @@ {% 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> </div><!-- /.box-body --> <div class="box-footer"> diff --git a/smash/web/templates/appointments/index.html b/smash/web/templates/appointments/index.html index d743a78d353469e78e931c2df8d476d1fcd2ecfd..c440bab2db3df666951f494dd723c02cae913f32 100644 --- a/smash/web/templates/appointments/index.html +++ b/smash/web/templates/appointments/index.html @@ -66,10 +66,9 @@ <table id="approaching_table" class="table table-bordered table-striped"> <thead> <tr> - <th>Subject name</th> - <th>Full information</th> + <th>Subject</th> + <th>Type</th> <th>Date</th> - <th>Time</th> <th>Details</th> </tr> </thead> @@ -78,15 +77,20 @@ {% for approach in approaching_list %} <tr> <td> - {{ approach.visit.subject.first_name }} {{ approach.visit.subject.last_name }} + {% if approach.visit.subject.screening_number == "---" %} + N/A + {% else %} + {{ approach.visit.subject.first_name }} {{ approach.visit.subject.last_name }} + {% endif %} </td> + <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.subject_details' approach.visit.subject.id %}" type="button" class="btn btn-block btn-default">Subject's details</a> - </td> - <td>{{ approach.datetime_when | date:"d-M-Y" }}</td> - <td>{{ approach.datetime_when | time:"H:i" }}</td> - <td> - <a href="{% url 'web.views.appointment_details' approach.id %}" type="button" class="btn btn-block btn-default">Details</a> + <a href="{% url 'web.views.appointment_edit' approach.id %}" type="button" class="btn btn-block btn-default">Details</a> </td> </tr> {% endfor %} @@ -123,6 +127,7 @@ "lengthChange": false, "searching": true, "ordering": true, + "order": [[ 2, "asc"]], "info": true, "autoWidth": false }); @@ -135,13 +140,14 @@ }, editable: false, events: [ - {% for approach in approaching_list %} + {% for appointment in full_list %} { - title: '{{ approach.visit.subject.first_name }} {{ approach.visit.subject.last_name }}', - start: '{{ approach.datetime_when | date:"c" }}', - color: '#cfc600', - subject_id: '{{ approach.visit.subject.id }}', - id: '{{ approach.id }}' + title: '{{ appointment.title }}', + start: '{{ appointment.datetime_when | date:"c" }}', + end: '{{ appointment.datetime_until | date:"c" }}', + color: '{{ appointment.color }}', + subject_id: '{{ appointment.visit.subject.id }}', + id: '{{ appointment.id }}' }, {% endfor %} ], diff --git a/smash/web/templates/subjects/index.html b/smash/web/templates/subjects/index.html index e2955a291d44e766e00a43386cde9de299caa98b..9212f52b7b24dcbabd7f0d3b32fca919732bf600 100644 --- a/smash/web/templates/subjects/index.html +++ b/smash/web/templates/subjects/index.html @@ -36,10 +36,11 @@ <th>Last name</th> <th>Country</th> <th data-sorter="false" data-filter="false">Languages</th> - <th class="filter-select filter-exact" data-placeholder="Select type">Type</th> + <th class="filter-select filter-exact" data-placeholder="Select location">Default location</th> + <th>Dead</th> + <th>Resigned</th> <th>Details</th> <th>Edit</th> - <th>Delete</th> </tr> </thead> @@ -60,10 +61,11 @@ {% endfor %} {% endautoescape %} </td> - <td>{{ subject.get_status_display }}</td> + <td>{{ subject.get_default_appointment_location_display }}</td> + <td>{% if subject.dead %} YES {% else %} NO {% endif %} </td> + <td>{% if subject.resigned %} YES {% else %} NO {% endif %} </td> <td><a href="{% url 'web.views.subject_details' subject.id %}" type="button" class="btn btn-block btn-default">Details</a></td> <td><a href="{% url 'web.views.subject_edit' subject.id %}" type="button" class="btn btn-block btn-default">Edit</a></td> - <td><a href="{% url 'web.views.subject_delete' subject.id %}" type="button" class="btn btn-block btn-default">Delete</a></td> </tr> {% endfor %} diff --git a/smash/web/templates/subjects/visitdetails.html b/smash/web/templates/subjects/visitdetails.html index 2b6476e6c0bd8c4f22002a409106cf9473951cea..c3432d99fe5f918a15f0e8327ec11ecb9afba38c 100644 --- a/smash/web/templates/subjects/visitdetails.html +++ b/smash/web/templates/subjects/visitdetails.html @@ -31,7 +31,7 @@ {% for element in display %} <div class="box box-widget widget-user-2"> <div class="widget-user-header bg-green"> - <h3 class="widget-user-username">Visit {{ forloop.counter }}</h3> + <h3 class="widget-user-username">{{ element.4 }}</h3> <h5 class="widget-user-desc"> {% if element.2 %}(Finished) {% else %}(Not finished) @@ -78,7 +78,13 @@ {% for app in element.1 %} <tr> <td>{{ forloop.counter }}</td> - <td>{{ app.appointment_type }}</td> + <td style="background-color:{{app.color}} !important"> + <font COLOR="{{app.font_color}}"> + {% for type in app.appointment_types.all %} + {{ type.code }}, + {% endfor %} + </font> + </td> <td>{{ app.datetime_when | date:"d-M-Y" }}</td> <td>{{ app.datetime_when | time:"H:i" }}</td> <td>{{ app.length }}</td> @@ -88,7 +94,11 @@ {% endif %} </td> <td> - <a href="{% url 'web.views.appointment_edit' app.id %}" type="button" class="btn btn-block btn-default">Edit</a> + {% if app.is_finished %} + FINISHED + {% else %} + <a href="{% url 'web.views.appointment_edit' app.id %}" type="button" class="btn btn-block btn-default">Edit</a> + {% endif %} </td> </tr> {% endfor %} diff --git a/smash/web/templates/visits/details.html b/smash/web/templates/visits/details.html index 5462e19d94ba10159d423ff50cbdccbe26422700..7385a5102267d52079bd736eb289a1a6cbeaa865 100644 --- a/smash/web/templates/visits/details.html +++ b/smash/web/templates/visits/details.html @@ -11,10 +11,10 @@ {% endblock styles %} {% block ui_active_tab %}'visits'{% endblock ui_active_tab %} -{% block page_header %}Details of the visit{% endblock page_header %} +{% block page_header %}Details of the visit ({{ visit.follow_up_title }}) {% endblock page_header %} {% block page_description %}{% endblock page_description %} -{% block title %}{{ block.super }} - Details of visit {% endblock %} +{% block title %}{{ block.super }} - Details of visit ({{ visit.follow_up_title }}) {% endblock %} {% block breadcrumb %} {% include "subjects/breadcrumb.html" %} @@ -29,7 +29,9 @@ </div> <div class="box-header with-border"> - <h3 class="box-title">Details of visit</h3> + <h3 class="box-title">Details of visit + + </h3> </div> <form class="form-horizontal"> @@ -41,7 +43,7 @@ </label> <div class="col-sm-8"> - {{ field|add_class:'form-control' }} + {{ field|disable|add_class:'form-control' }} </div> {% if field.errors %} @@ -57,8 +59,14 @@ Visit finished </label> <div class="col-sm-8"> - {% if visFinished %}<button type="button" class="btn btn-block btn-danger">YES</button> - {% else %}<button type="button" class="btn btn-block btn-success">NO</button> + {% if visFinished %}<div class="btn btn-block">YES</div> + {% else %}<div class="btn btn-block"> + {% if canFinish %} + <a href="{% url 'web.views.visit_mark' vid 'finished' %}" class="btn btn-warning btn-block">Mark as finished</a> + {% else %} + Waiting for appointments to finish. + {% endif %} + </div> {% endif %} </div> </div> @@ -95,7 +103,13 @@ {% for app in loApp %} <tr> <td>{{ forloop.counter }}</td> - <td>{{ app.appointment_type }}</td> + <td style="background-color:{{app.color}} !important"> + <font COLOR="{{app.font_color}}"> + {% for type in app.appointment_types.all %} + {{ type.code }}, + {% endfor %} + </font> + </td> <td>{{ app.datetime_when | date:"d-M-Y" }}</td> <td>{{ app.datetime_when | time:"H:i" }}</td> <td>{{ app.length }}</td> @@ -105,7 +119,11 @@ {% endif %} </td> <td> - <a href="{% url 'web.views.appointment_edit' app.id %}" type="button" class="btn btn-block btn-default">Edit</a> + {% if app.is_finished %} + FINISHED + {% else %} + <a href="{% url 'web.views.appointment_edit' app.id %}" type="button" class="btn btn-block btn-default">Edit</a> + {% endif %} </td> </tr> {% endfor %} diff --git a/smash/web/templates/visits/index.html b/smash/web/templates/visits/index.html index adb835d2f3166d5a462010292d963f30516d77d8..65a47aea2b1bbf053fc0e350164edff192c9ce72 100644 --- a/smash/web/templates/visits/index.html +++ b/smash/web/templates/visits/index.html @@ -41,8 +41,7 @@ <th>Full information</th> <th>Visit begins</th> <th>Visit ends</th> - <th>Visit type</th> - <th>Finished?</th> + <th>Finished?</th> </tr> </thead> <tbody> @@ -58,10 +57,7 @@ <td> {{ visit.datetime_end }} </td> - <td> - {{ visit.get_visit_type_display }} - </td> - <td> + <td> {% if visit.is_finished %}<button type="button" class="btn btn-block btn-success">YES</button> {% else %}<button type="button" class="btn btn-block btn-danger">NO</button> {% endif %} diff --git a/smash/web/tests/test_SubjectAddForm.py b/smash/web/tests/test_SubjectAddForm.py index 41fdb32027d0dfe0f14c13344c43b5bbeb5fbe9c..92b032d07979d0de60fe4ef5c468b6a8175b8e04 100644 --- a/smash/web/tests/test_SubjectAddForm.py +++ b/smash/web/tests/test_SubjectAddForm.py @@ -6,8 +6,9 @@ class SubjectAddFormTests(TestCase): def setUp(self): self.sample_data = {'first_name': 'name', 'last_name': 'name', - 'status' : Subject.STATUS_CHOICES_NOT_CONTACTED, 'sex' : Subject.SEX_CHOICES_MALE, + 'type' : Subject.SUBJECT_TYPE_CHOICES_CONTROL, + 'default_appointment_location' : Subject.LOCATION_CHOICES_LIH, 'country' : 'Luxembourg' } def test_validation(self): diff --git a/smash/web/tests/test_SubjectEditForm.py b/smash/web/tests/test_SubjectEditForm.py index 604c3a0c6b10bceb71c135af9114cf0fe68a406f..223b55954c6b61a5375a4243cb7f4619c1b1d9ee 100644 --- a/smash/web/tests/test_SubjectEditForm.py +++ b/smash/web/tests/test_SubjectEditForm.py @@ -8,8 +8,9 @@ class SubjectEditFormTests(TestCase): def setUp(self): self.sample_data = {'first_name': 'name', 'last_name': 'name', - 'status' : Subject.STATUS_CHOICES_NOT_CONTACTED, 'sex' : Subject.SEX_CHOICES_MALE, + 'type' : Subject.SUBJECT_TYPE_CHOICES_CONTROL, + 'default_appointment_location' : Subject.LOCATION_CHOICES_LIH, '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 9a35892b17104ab8d46beaaffbc004890821386e..ae3c4baa3576b9114e3a705c1a6894f11c3985f8 100644 --- a/smash/web/tests/test_VisitAddForm.py +++ b/smash/web/tests/test_VisitAddForm.py @@ -8,15 +8,15 @@ class SubjectAddFormTests(TestCase): def setUp(self): subject_data = {'first_name': 'name', 'last_name': 'name', - 'status' : Subject.STATUS_CHOICES_NOT_CONTACTED, 'sex' : Subject.SEX_CHOICES_MALE, + 'type' : Subject.SUBJECT_TYPE_CHOICES_CONTROL, + 'default_appointment_location' : Subject.LOCATION_CHOICES_LIH, 'country' : 'Luxembourg', } self.subject = SubjectAddForm(data=subject_data).save() self.sample_data = {'datetime_begin': "2017-01-01", 'datetime_end': "2017-02-02", - 'visit_type': Visit.TYPE_CHOICES_OTHER, 'subject' : self.subject.id } diff --git a/smash/web/urls.py b/smash/web/urls.py index 4a71af8d219c17bfc38fc7546edd2bc090122305..bf78ef96158d66d42d82d4f585b9269f60fad24f 100644 --- a/smash/web/urls.py +++ b/smash/web/urls.py @@ -22,10 +22,12 @@ urlpatterns = [ 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'), diff --git a/smash/web/views.py b/smash/web/views.py index d48eade117e0ec66c7fda1a861920c1b4da14b7a..99aa99903befe437ab2250e772219adf384e6fb3 100644 --- a/smash/web/views.py +++ b/smash/web/views.py @@ -94,10 +94,23 @@ def visit_details(request, id): vid = displayedVisit.id displayedSubject = displayedVisit.subject listOfAppointments = displayedVisit.appointment_set.all() + canFinish=True + for appointment in listOfAppointments: + if not appointment.is_finished: + canFinish=False; vform = VisitDetailForm(instance=displayedVisit) sform = SubjectDetailForm(instance=displayedSubject) - return wrap_response(request, 'visits/details.html', {'vform': vform, 'sform': sform, 'loApp': listOfAppointments, 'visFinished': visFinished, 'vid': vid}) + return wrap_response(request, 'visits/details.html', {'vform': vform, 'sform': sform, 'loApp': listOfAppointments, 'visFinished': visFinished,'canFinish': canFinish, 'vid': vid, 'visit': displayedVisit}) + +def visit_mark(request, id, as_what): + visit = get_object_or_404(Visit, id=id) + 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) + def visit_add(request): @@ -173,6 +186,12 @@ def subject_mark(request, id, as_what): who.mark_as_rejected() return redirect(subject_edit, id=id) +def appointment_mark(request, id, as_what): + appointment = get_object_or_404(Appointment, id=id) + if as_what == 'finished': + appointment.mark_as_finished() + return redirect(visit_details, id=appointment.visit.id) + def subject_visit_details(request, id): locsubject = get_object_or_404(Subject, id=id) visits = locsubject.visit_set.all() @@ -182,8 +201,9 @@ def subject_visit_details(request, id): 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)) + endlist.append((visform,assign,finished,visid,visit_title)) #print len(endlist) #print endlist[0] @@ -301,7 +321,12 @@ 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) - approaching_list = Appointment.objects.filter(datetime_when__gt = datetime.datetime.now()) + + 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') for plan in planning_list: @@ -309,7 +334,8 @@ def appointments(request): context = { 'planning_list': planning_list, - 'approaching_list': approaching_list + 'approaching_list': approaching_list, + 'full_list': full_list } return wrap_response(request, "appointments/index.html",context) @@ -321,6 +347,10 @@ 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') if request.method == 'POST': form = AppointmentAddForm(request.POST, request.FILES) form.fields['visit'].widget = forms.HiddenInput() @@ -331,7 +361,7 @@ def appointment_add(request, id): form = AppointmentAddForm(initial={'visit': id}) form.fields['visit'].widget = forms.HiddenInput() - return wrap_response(request, 'appointments/add.html', {'form': form, 'visitID': id}) + return wrap_response(request, 'appointments/add.html', {'form': form, 'visitID': id, 'full_appointment_list': full_list}) def appointment_edit(request, id): the_appointment = get_object_or_404(Appointment, id=id) @@ -348,7 +378,7 @@ def appointment_edit(request, id): return redirect(appointments) else: form = AppointmentEditForm(instance=the_appointment) - return wrap_response(request, 'appointments/edit.html', {'form': form}) + return wrap_response(request, 'appointments/edit.html', {'form': form, 'id':id}) def appointment_edit_datetime(request, id):