/** * Copyright © ${project.inceptionYear} Instituto Superior Técnico * * This file is part of Fenix IST. * * Fenix IST is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Fenix IST is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Fenix IST. If not, see <http://www.gnu.org/licenses/>. */ package pt.ist.fenix.task.exportData.santanderCardGeneration; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.fenixedu.academic.domain.Degree; import org.fenixedu.academic.domain.Department; import org.fenixedu.academic.domain.ExecutionYear; import org.fenixedu.academic.domain.Person; import org.fenixedu.academic.domain.StudentCurricularPlan; import org.fenixedu.academic.domain.Teacher; import org.fenixedu.academic.domain.accounting.events.insurance.InsuranceEvent; import org.fenixedu.academic.domain.degree.DegreeType; import org.fenixedu.academic.domain.exceptions.DomainException; import org.fenixedu.academic.domain.phd.PhdIndividualProgramProcess; import org.fenixedu.academic.domain.phd.PhdIndividualProgramProcessState; import org.fenixedu.academic.domain.student.Registration; import org.fenixedu.academic.domain.student.RegistrationProtocol; import org.fenixedu.academic.domain.student.Student; import org.fenixedu.academic.domain.student.registrationStates.RegistrationState; import org.fenixedu.bennu.core.domain.Bennu; import org.fenixedu.bennu.core.domain.User; import org.fenixedu.idcards.domain.SantanderBatch; import org.fenixedu.idcards.domain.SantanderEntry; import org.fenixedu.idcards.domain.SantanderProblem; import org.fenixedu.spaces.domain.Space; import org.joda.time.DateTime; import org.joda.time.YearMonthDay; import org.slf4j.Logger; import pt.ist.fenixedu.contracts.domain.accessControl.ActiveEmployees; import pt.ist.fenixedu.contracts.domain.accessControl.ActiveGrantOwner; import pt.ist.fenixedu.contracts.domain.personnelSection.contracts.PersonContractSituation; import pt.ist.fenixedu.contracts.domain.util.CategoryType; import pt.ist.fenixframework.Atomic; import pt.ist.fenixframework.FenixFramework; public class SantanderBatchFillerWorker { private static String recordEnd = "*"; private static String lineEnd = "\r\n"; private static String alamedaAddr = "Avenida Rovisco Pais, 1"; private static String alamedaZip = "1049-001"; private static String alamedaTown = "Lisboa"; private static String tagusAddr = "Av. Prof. Doutor Aníbal Cavaco Silva"; private static String tagusZip = "2744-016"; private static String tagusTown = "Porto Salvo"; private static String itnAddr = "Estrada Nacional 10 (ao Km 139,7)"; private static String itnZip = "2695-066"; private static String itnTown = "Bobadela"; private static String IST_FULL_NAME = "Instituto Superior Técnico"; protected final Logger logger; public SantanderBatchFillerWorker(final Logger logger) { this.logger = logger; } public void run() { logger.info("[" + (new DateTime()).toString("yyyy-MM-dd HH:mm") + "] Looking for open batches to populate...\n"); for (SantanderBatch batch : Bennu.getInstance().getSantanderBatchesSet()) { if (batch.getGenerated() != null) { continue; } final Set<Object[]> lines = new HashSet<Object[]>(); for (User user : Bennu.getInstance().getUserSet()) { if (user.getPerson() != null) { generateLine(lines, batch, user.getPerson()); } } fillBatch(batch, lines); } logger.info("[" + (new DateTime()).toString("yyyy-MM-dd HH:mm") + "] Work finished. :)"); } @Atomic private void fillBatch(final SantanderBatch batch, final Set<Object[]> lines) { for (final Object[] o : lines) { final Person person = (Person) o[0]; final String line = (String) o[1]; new SantanderEntry(batch, person, line); } batch.setGenerated(new DateTime()); logger.info("Processed batch #" + batch.getExternalId()); logger.info("Total number of records: " + batch.getSantanderEntriesSet().size() + "\n"); } private void generateLine(final Set<Object[]> lines, SantanderBatch batch, Person person) { /* * 1. Teacher * 2. Researcher * 3. Employee * 4. GrantOwner * 5. Student */ String line = null; if (treatAsStudent(person, batch.getExecutionYear())) { line = createLine(batch, person, "STUDENT"); } else if (treatAsTeacher(person)) { line = createLine(batch, person, "TEACHER"); } else if (treatAsResearcher(person)) { line = createLine(batch, person, "RESEARCHER"); } else if (treatAsEmployee(person)) { line = createLine(batch, person, "EMPLOYEE"); } else if (treatAsGrantOwner(person)) { line = createLine(batch, person, "GRANT_OWNER"); } else { return; } if (line != null) { lines.add(new Object[] { person, line }); //new SantanderEntry(batch, person, line); } } private boolean treatAsTeacher(Person person) { if (person.getTeacher() != null) { return person.getTeacher().isActiveContractedTeacher(); } return false; } private boolean treatAsResearcher(Person person) { if (person.getResearcher() != null) { return person.getResearcher().isActiveContractedResearcher(); } return false; } private boolean treatAsEmployee(Person person) { if (person.getEmployee() != null) { return person.getEmployee().isActive(); } return false; } private boolean treatAsGrantOwner(Person person) { return (isGrantOwner(person)) || (new ActiveGrantOwner().isMember(person.getUser()) && person.getEmployee() != null && !new ActiveEmployees().isMember(person.getUser()) && person.getPersonProfessionalData() != null); } private boolean treatAsStudent(Person person, ExecutionYear executionYear) { if (person.getStudent() != null) { final List<Registration> activeRegistrations = person.getStudent().getActiveRegistrations(); for (final Registration registration : activeRegistrations) { if (registration.isBolonha() && !registration.getDegreeType().isEmpty()) { return true; } } final InsuranceEvent event = person.getInsuranceEventFor(executionYear); final PhdIndividualProgramProcess phdIndividualProgramProcess = event != null && event.isClosed() ? find(person.getPhdIndividualProgramProcessesSet()) : null; return (phdIndividualProgramProcess != null); } return false; } private boolean isGrantOwner(final Person person) { if (new ActiveGrantOwner().isMember(person.getUser())) { final PersonContractSituation currentGrantOwnerContractSituation = person.getPersonProfessionalData() != null ? person.getPersonProfessionalData() .getCurrentPersonContractSituationByCategoryType(CategoryType.GRANT_OWNER) : null; if (currentGrantOwnerContractSituation != null && currentGrantOwnerContractSituation.getProfessionalCategory() != null && person.getEmployee() != null && person.getEmployee().getCurrentWorkingPlace() != null) { return true; } } return false; } private PhdIndividualProgramProcess find(final Set<PhdIndividualProgramProcess> phdIndividualProgramProcesses) { PhdIndividualProgramProcess result = null; for (final PhdIndividualProgramProcess process : phdIndividualProgramProcesses) { if (process.getActiveState() == PhdIndividualProgramProcessState.WORK_DEVELOPMENT) { if (result != null) { return null; } result = process; } } return result; } private String makeStringBlock(String content, int size) { int fillerLength = size - content.length(); if (fillerLength < 0) { throw new DomainException("Content is bigger than string block."); } StringBuilder blockBuilder = new StringBuilder(size); blockBuilder.append(content); for (int i = 0; i < fillerLength; i++) { blockBuilder.append(" "); } return blockBuilder.toString(); } private String makeZeroPaddedNumber(int number, int size) { if (String.valueOf(number).length() > size) { throw new DomainException("Number has more digits than allocated room."); } String format = "%0" + size + "d"; return String.format(format, number); } private String purgeString(final String name) { if (!StringUtils.isAlphaSpace(name)) { final char[] ca = new char[name.length()]; int j = 0; for (int i = 0; i < name.length(); i++) { final char c = name.charAt(i); if (Character.isLetter(c) || c == ' ') { ca[j++] = c; } } return new String(ca); } return name; } private String[] harvestNames(String name) { String[] result = new String[3]; String purgedName = purgeString(name); String cleanedName = StringUtils.trimToEmpty(purgedName); String[] names = cleanedName.split(" "); result[0] = names[0].length() > 15 ? names[0].substring(0, 15) : names[0]; result[1] = names[names.length - 1].length() > 15 ? names[names.length - 1].substring(0, 15) : names[names.length - 1]; String midNames = names.length > 2 ? names[1] : ""; for (int i = 2; i < (names.length - 1); i++) { if (midNames.length() + names[i].length() + 1 > 40) { break; } midNames += " "; midNames += names[i]; } result[2] = midNames; return result; } private String getHomeCountry(Person person) { String countryName = person.getCountryOfBirth().getName(); if (countryName.length() > 10) { return person.getCountryOfBirth().getThreeLetterCode(); } return countryName; } private String getExpireDate(ExecutionYear year) { String result = ""; int beginYear = year.getBeginCivilYear(); int endYear = beginYear + 3; result = beginYear + "/" + endYear; return result; } private String getDegreeCode(SantanderBatch batch, Person person) { final PhdIndividualProgramProcess process = getPhdProcess(person); if (process != null) { logger.debug("phdProcess: " + process.getExternalId()); return process.getPhdProgram().getAcronym(); } final Degree degree = getDegree(batch, person); return degree == null ? null : degree.getSigla(); } private Degree getDegree(SantanderBatch batch, Person person) { final Student student = person.getStudent(); if (student == null) { return null; } final DateTime begin = batch.getExecutionYear().getBeginDateYearMonthDay().toDateTimeAtMidnight(); final DateTime end = batch.getExecutionYear().getEndDateYearMonthDay().toDateTimeAtMidnight(); final Set<StudentCurricularPlan> studentCurricularPlans = new HashSet<StudentCurricularPlan>(); StudentCurricularPlan pickedSCP; for (final Registration registration : student.getRegistrationsSet()) { if (!registration.isActive()) { continue; } if (registration.getDegree().isEmpty()) { continue; } final RegistrationProtocol registrationAgreement = registration.getRegistrationProtocol(); if (!registrationAgreement.allowsIDCard()) { continue; } final DegreeType degreeType = registration.getDegreeType(); if (!degreeType.isBolonhaType()) { continue; } for (final StudentCurricularPlan studentCurricularPlan : registration.getStudentCurricularPlansSet()) { if (studentCurricularPlan.isActive()) { if (degreeType == DegreeType.BOLONHA_DEGREE || degreeType == DegreeType.BOLONHA_MASTER_DEGREE || degreeType == DegreeType.BOLONHA_INTEGRATED_MASTER_DEGREE || degreeType == DegreeType.BOLONHA_ADVANCED_SPECIALIZATION_DIPLOMA) { studentCurricularPlans.add(studentCurricularPlan); } else { final RegistrationState registrationState = registration.getActiveState(); if (registrationState != null) { final DateTime dateTime = registrationState.getStateDate(); if (!dateTime.isBefore(begin) && !dateTime.isAfter(end)) { studentCurricularPlans.add(studentCurricularPlan); } } } } } } if (studentCurricularPlans.isEmpty()) { return null; } pickedSCP = Collections.max(studentCurricularPlans, new Comparator<StudentCurricularPlan>() { @Override public int compare(final StudentCurricularPlan o1, final StudentCurricularPlan o2) { final DegreeType degreeType1 = o1.getDegreeType(); final DegreeType degreeType2 = o2.getDegreeType(); if (degreeType1 == degreeType2) { final YearMonthDay yearMonthDay1 = o1.getStartDateYearMonthDay(); final YearMonthDay yearMonthDay2 = o2.getStartDateYearMonthDay(); final int c = yearMonthDay1.compareTo(yearMonthDay2); return c == 0 ? o1.getExternalId().compareTo(o2.getExternalId()) : c; } else { return degreeType1.compareTo(degreeType2); } } }); return pickedSCP.getRegistration().getDegree(); // final String degreeNameForIdCard = degree.getIdCardName(); // if (degreeNameForIdCard == null || degreeNameForIdCard.isEmpty()) { // throw new Error("No degree name for id card specified."); // } // if (degreeNameForIdCard.length() > 50) { // throw new Error("Length of degree name for id card to long: " + degreeNameForIdCard + " has more than 50 characters."); // } // return degreeNameForIdCard; //return pickedSCP.getRegistration().getDegree().getSigla(); } private CampusAddress getCampusAddress(Person person, String role) { Space campus = null; Map<String, CampusAddress> campi = getCampi(); switch (role) { case "STUDENT": boolean matched = false; if (person.getStudent() != null) { final List<Registration> activeRegistrations = person.getStudent().getActiveRegistrations(); for (final Registration registration : activeRegistrations) { if (registration.isBolonha() && !registration.getDegreeType().isEmpty()) { matched = true; campus = person.getStudent().getLastActiveRegistration().getCampus(); } } } if (!matched) { campus = FenixFramework.getDomainObject("2448131360897"); } break; case "EMPLOYEE": try { campus = person.getEmployee().getCurrentCampus(); } catch (NullPointerException npe) { return null; } break; case "TEACHER": try { campus = person.getPersonProfessionalData().getGiafProfessionalDataByCategoryType(CategoryType.TEACHER) .getCampus(); } catch (NullPointerException npe) { return null; } break; case "RESEARCHER": try { campus = person.getPersonProfessionalData().getGiafProfessionalDataByCategoryType(CategoryType.RESEARCHER) .getCampus(); } catch (NullPointerException npe) { return null; } break; case "GRANT_OWNER": try { campus = person.getPersonProfessionalData().getGiafProfessionalDataByCategoryType(CategoryType.GRANT_OWNER) .getCampus(); } catch (NullPointerException npe) { return null; } break; default: break; } if (campus == null) { return null; } if (campus.getName().equals("Alameda")) { return campi.get("alameda"); } if (campus.getName().equals("Taguspark")) { return campi.get("tagus"); } if (campus.getName().equals("Tecnológico e Nuclear")) { return campi.get("itn"); } return null; } private String createLine(SantanderBatch batch, Person person, String role) { // if (SantanderPhotoEntry.getOrCreatePhotoEntryForPerson(person) == null) { // return null; // } StringBuilder strBuilder = new StringBuilder(1505); String recordType = "2"; String idNumber = makeStringBlock(person.getUsername(), 10); String[] names = harvestNames(person.getName()); String name = makeStringBlock(names[0], 15); String surname = makeStringBlock(names[1], 15); String middleNames = makeStringBlock(names[2], 40); String degreeCode = makeStringBlock(getDegreeDescription(batch, person, role), 16); if (role.equals("STUDENT") && degreeCode.startsWith(" ")) { return null; } CampusAddress campusAddr = getCampusAddress(person, role); if (campusAddr == null) { return null; } String address1 = makeStringBlock(campusAddr.getAddress(), 50); String address2 = makeStringBlock((IST_FULL_NAME + (degreeCode == null ? "" : " " + degreeCode)).trim(), 50); //makeStringBlock(getDegreeDescription(batch, person, role), 50); String zipCode = campusAddr.getZip(); String town = makeStringBlock(campusAddr.getTown(), 30); String homeCountry = makeStringBlock("", 10); String residenceCountry = makeStringBlock(person.getUsername(), 10); // As stipulated this field will carry the istId instead. String expireDate = getExpireDate(batch.getExecutionYear()); // if (role == RoleType.STUDENT) { // degreeCode = getDegreeCode(batch, person); // if (degreeCode == null) { // return null; // } // degreeCode = makeStringBlock(degreeCode, 16); // } else if (role == RoleType.GRANT_OWNER) { // degreeCode = getDegreeCode(batch, person); // if (degreeCode == null) { // degreeCode = makeStringBlock("", 16); // } else { // degreeCode = makeStringBlock(degreeCode, 16); // } // } else { // degreeCode = makeStringBlock("", 16); // } String backNumber = makeZeroPaddedNumber(Integer.parseInt(person.getUsername().substring(3)), 10); String chip1 = buildChip1Block(batch, person, role); String chip2 = makeStringBlock("", 180); String chip3 = makeStringBlock("", 180); String chip4 = makeStringBlock("", 180); String chip5 = makeStringBlock("", 180); String chip6 = makeStringBlock("", 180); String filler = makeStringBlock("", 145); strBuilder.append(recordType); strBuilder.append(idNumber); strBuilder.append(name); strBuilder.append(surname); strBuilder.append(middleNames); strBuilder.append(address1); strBuilder.append(address2); strBuilder.append(zipCode); strBuilder.append(town); strBuilder.append(homeCountry); strBuilder.append(residenceCountry); strBuilder.append(expireDate); strBuilder.append(degreeCode); strBuilder.append(backNumber); strBuilder.append(chip1); strBuilder.append(chip2); strBuilder.append(chip3); strBuilder.append(chip4); strBuilder.append(chip5); strBuilder.append(chip6); strBuilder.append(filler); strBuilder.append(recordEnd); strBuilder.append(lineEnd); return strBuilder.toString(); } private String getDegreeDescription(final SantanderBatch batch, final Person person, String roleType) { if (roleType.equals("STUDENT") || roleType.equals("GRANT_OWNER")) { final PhdIndividualProgramProcess process = getPhdProcess(person); if (process != null) { logger.debug("phdProcess: " + process.getExternalId()); return process.getPhdProgram().getAcronym(); } final Degree degree = //getDegree(person.getStudent()); getDegree(batch, person); if (degree != null) { return degree.getSigla(); // final String degreeNameForIdCard = degree.getIdCardName(); // if (degreeNameForIdCard == null || degreeNameForIdCard.isEmpty()) { // throw new Error("No degree name for id card specified."); // } // if (degreeNameForIdCard.length() > 50) { // throw new Error("Length of degree name for id card to long: " + degreeNameForIdCard + " has more than 50 characters."); // } // return degreeNameForIdCard; //return pickedSCP.getRegistration().getDegree().getSigla(); } } if (roleType.equals("TEACHER")) { final Teacher teacher = person.getTeacher(); final Department department = teacher.getDepartment(); if (department != null) { //return department.getDepartmentUnit().getIdentificationCardLabel(); return department.getAcronym(); } } //return "Técnico Lisboa"; return ""; } private PhdIndividualProgramProcess getPhdProcess(final Person person) { final InsuranceEvent event = person.getInsuranceEventFor(ExecutionYear.readCurrentExecutionYear()); return event != null && event.isClosed() ? find(person.getPhdIndividualProgramProcessesSet()) : null; } private Degree getDegree(final Student student) { Degree degree = null; for (final Registration registration : student.getRegistrationsSet()) { if (registration.isActive() && (degree == null || degree.getDegreeType().ordinal() < registration.getDegreeType().ordinal())) { degree = registration.getDegree(); } } return degree; } private String buildChip1Block(SantanderBatch batch, Person person, String role) { StringBuilder chip1String = new StringBuilder(185); String idNumber = makeZeroPaddedNumber(Integer.parseInt(person.getUsername().substring(3)), 10); String roleCode = "7"; /*switch (role) { case STUDENT: roleCode = "1"; break; case TEACHER: roleCode = "2"; break; case EMPLOYEE: roleCode = "3"; break; default: roleCode = "7"; break; }*/ String curricularYear = "00"; String executionYear = "00000000"; String unit = makeStringBlock("", 11); if (role.equals("TEACHER")) { unit = makeStringBlock(person.getTeacher().getDepartment().getAcronym(), 11); } String activeCard = "0"; String personPin = "0000"; String institutionPin = "0000"; String accessContrl = makeStringBlock("", 10); String altRoleKey = makeStringBlock("", 5); String altRoleCode = " "; String altRoleTemplate = " "; String altRoleDescription = makeStringBlock("", 20); if (roleCode.equals("7")) { switch (role) { case "STUDENT": altRoleKey = "CATEG"; altRoleCode = "1"; altRoleTemplate = "02"; altRoleDescription = makeStringBlock("Estudante/Student", 20); break; case "TEACHER": altRoleKey = "CATEG"; altRoleCode = "2"; altRoleTemplate = "02"; altRoleDescription = makeStringBlock("Docente/Faculty", 20); break; case "EMPLOYEE": altRoleKey = "CATEG"; altRoleCode = "3"; altRoleTemplate = "02"; altRoleDescription = makeStringBlock("Funcionario/Staff", 20); break; case "RESEARCHER": altRoleKey = "CATEG"; altRoleCode = "8"; altRoleTemplate = "02"; altRoleDescription = makeStringBlock("Invest./Researcher", 20); break; case "GRANT_OWNER": altRoleKey = "CATEG"; altRoleCode = "9"; altRoleTemplate = "02"; altRoleDescription = makeStringBlock("Bolseiro/Grant Owner", 20); break; default: break; } } String filler = makeStringBlock("", 101); chip1String.append(idNumber); chip1String.append(roleCode); chip1String.append(curricularYear); chip1String.append(executionYear); chip1String.append(unit); chip1String.append(activeCard); chip1String.append(personPin); chip1String.append(institutionPin); chip1String.append(accessContrl); chip1String.append(altRoleKey); chip1String.append(altRoleCode); chip1String.append(altRoleTemplate); chip1String.append(altRoleDescription); chip1String.append(filler); return chip1String.toString(); } private void generateProblem(SantanderBatch batch, Person person, String cause) { new SantanderProblem(batch, person, cause); } private class CampusAddress { private final String address; private final String zip; private final String town; private CampusAddress(String address, String zip, String town) { this.address = address; this.zip = zip; this.town = town; } public String getAddress() { return address; } public String getZip() { return zip; } public String getTown() { return town; } } private Map<String, CampusAddress> getCampi() { Map<String, CampusAddress> exports = new HashMap<String, CampusAddress>(); exports.put("alameda", new CampusAddress(alamedaAddr, alamedaZip, alamedaTown)); exports.put("tagus", new CampusAddress(tagusAddr, tagusZip, tagusTown)); exports.put("itn", new CampusAddress(itnAddr, itnZip, itnTown)); return exports; } }