/* * @(#)EmailDigesterUtil.java * * Copyright 2010 Instituto Superior Tecnico * Founding Authors: Luis Cruz, Nuno Ochoa, Paulo Abrantes * * https://fenix-ashes.ist.utl.pt/ * * This file is part of the Expenditure Tracking Module. * * The Expenditure Tracking Module 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. * * The Expenditure Tracking Module 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 the Expenditure Tracking Module. If not, see <http://www.gnu.org/licenses/>. * */ package pt.ist.expenditureTrackingSystem.domain; import java.util.Calendar; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import org.fenixedu.bennu.core.domain.Bennu; import org.fenixedu.bennu.core.domain.User; import org.fenixedu.bennu.core.groups.Group; import org.fenixedu.bennu.core.security.Authenticate; import org.fenixedu.bennu.core.util.CoreConfiguration; import org.fenixedu.commons.i18n.I18N; import org.fenixedu.messaging.core.domain.Message; import org.fenixedu.messaging.core.template.DeclareMessageTemplate; import org.fenixedu.messaging.core.template.TemplateParameter; import org.jfree.data.time.Month; import org.joda.time.LocalDate; import module.workflow.domain.WorkflowProcess; import pt.ist.expenditureTrackingSystem._development.Bundle; import pt.ist.expenditureTrackingSystem.domain.acquisitions.AcquisitionProcessStateType; import pt.ist.expenditureTrackingSystem.domain.acquisitions.PaymentProcess; import pt.ist.expenditureTrackingSystem.domain.acquisitions.PaymentProcessYear; import pt.ist.expenditureTrackingSystem.domain.acquisitions.RefundProcessStateType; import pt.ist.expenditureTrackingSystem.domain.authorizations.Authorization; import pt.ist.expenditureTrackingSystem.domain.organization.AccountingUnit; import pt.ist.expenditureTrackingSystem.domain.organization.Person; import pt.ist.expenditureTrackingSystem.presentationTier.widgets.Counter; import pt.ist.expenditureTrackingSystem.presentationTier.widgets.MultiCounter; import pt.ist.expenditureTrackingSystem.util.ProcessMapGenerator; /** * * @author Luis Cruz * */ @DeclareMessageTemplate(id = "expenditures.payment.pending", bundle = Bundle.ACQUISITION, description = "template.payment.pending", subject = "template.payment.pending.subject", text = "template.payment.pending.text", parameters = { @TemplateParameter(id = "applicationTitle", description = "template.parameter.application.subtitle"), @TemplateParameter(id = "applicationUrl", description = "template.parameter.application.url"), @TemplateParameter(id = "acquisitions", description = "template.parameter.payment.acquisitions"), @TemplateParameter(id = "refunds", description = "template.parameter.payment.refunds") }) public class EmailDigesterUtil { public static void executeTask() { I18N.setLocale(new Locale(CoreConfiguration.getConfiguration().defaultLocale())); for (Person person : getPeopleToProcess()) { try { User user = person.getUser(); Authenticate.mock(user); Map<AcquisitionProcessStateType, MultiCounter<AcquisitionProcessStateType>> generateAcquisitionMap = ProcessMapGenerator.generateAcquisitionMap(person, true); Map<RefundProcessStateType, MultiCounter<RefundProcessStateType>> generateRefundMap = ProcessMapGenerator.generateRefundMap(person, true); if (!generateAcquisitionMap.isEmpty() || !generateRefundMap.isEmpty()) { Message.fromSystem().to(Group.users(person.getUser())).template("expenditures.payment.pending") .parameter("applicationTitle", Bennu.getInstance().getConfiguration().getApplicationSubTitle()) .parameter("applicationUrl", CoreConfiguration.getConfiguration().applicationUrl()) .parameter("acquisitions", getCounterList(AcquisitionProcessStateType.class.getSimpleName(), generateAcquisitionMap)) .parameter("refunds", getCounterList(RefundProcessStateType.class.getSimpleName(), generateRefundMap)) .and().send(); } } finally { Authenticate.unmock(); } } } public static class MultiCounterBean implements Comparable<MultiCounterBean> { private String name; private int value; private List<String> processes; public String getName() { return name; } public int getValue() { return value; } public List<String> getProcesses() { return processes; } //XXX receiving the relevant super type name here to account for subclasses since we have a class dependent localized name in the properties public <T extends Enum> MultiCounterBean(String relevantTypeName, MultiCounter<T> multiCounter) { Counter<T> counter = ProcessMapGenerator.getDefaultCounter(multiCounter); T countable = counter.getCountableObject(); this.name = relevantTypeName + "." + countable.name(); this.value = counter.getValue(); Set<WorkflowProcess> processes = (Set) counter.getObjects(); this.processes = processes.size() < 25 ? processes.stream().map(p -> p.getProcessNumber()).sorted() .collect(Collectors.toList()) : null; } @Override public int compareTo(MultiCounterBean o) { return name.compareTo(o.getName()); } } //XXX receiving the relevant super type name here to account for subclasses since we have a class dependent localized name in the properties private static <T extends Enum> List<MultiCounterBean> getCounterList(String relevantTypeName, Map<T, MultiCounter<T>> map) { return map.entrySet().stream().map(c -> new MultiCounterBean(relevantTypeName, c.getValue())).sorted() .collect(Collectors.toList()); } private static Collection<Person> getPeopleToProcess() { final Set<Person> people = new HashSet<Person>(); final LocalDate today = new LocalDate(); final ExpenditureTrackingSystem instance = ExpenditureTrackingSystem.getInstance(); for (final Authorization authorization : instance.getAuthorizationsSet()) { if (authorization.isValidFor(today)) { final Person person = authorization.getPerson(); if (person.getOptions().getReceiveNotificationsByEmail()) { people.add(person); } } } for (final RoleType roleType : RoleType.values()) { addPeopleWithRole(people, roleType); } for (final AccountingUnit accountingUnit : instance.getAccountingUnitsSet()) { addPeople(people, accountingUnit.getPeopleSet()); addPeople(people, accountingUnit.getProjectAccountantsSet()); addPeople(people, accountingUnit.getResponsiblePeopleSet()); addPeople(people, accountingUnit.getResponsibleProjectAccountantsSet()); addPeople(people, accountingUnit.getTreasuryMembersSet()); } final PaymentProcessYear paymentProcessYear = PaymentProcessYear.getPaymentProcessYearByYear(Calendar.getInstance().get(Calendar.YEAR)); addRequestors(people, paymentProcessYear); if (today.getMonthOfYear() == Month.JANUARY) { final PaymentProcessYear previousYear = PaymentProcessYear.getPaymentProcessYearByYear(Calendar.getInstance().get(Calendar.YEAR) - 1); addRequestors(people, previousYear); } return people; } private static void addRequestors(final Set<Person> people, final PaymentProcessYear paymentProcessYear) { for (final PaymentProcess paymentProcess : paymentProcessYear.getPaymentProcessSet()) { if (paymentProcess.getRequest() != null) { final Person person = paymentProcess.getRequestor(); if (person != null && person.getOptions().getReceiveNotificationsByEmail()) { people.add(person); } } } } private static void addPeopleWithRole(final Set<Person> people, final RoleType roleType) { addUsers(people, roleType.group().getMembers()); } private static void addUsers(final Set<Person> people, Stream<User> unverified) { unverified.forEach(u -> addPerson(people, u.getExpenditurePerson())); } private static void addPerson(Set<Person> people, Person person) { if (person.getOptions().getReceiveNotificationsByEmail()) { people.add(person); } } private static void addPeople(final Set<Person> people, Collection<Person> unverified) { for (final Person person : unverified) { addPerson(people, person); } } }