package org.sigmah.server.handler;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import com.google.inject.persist.Transactional;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import org.sigmah.server.dispatch.impl.UserDispatch.UserExecutionContext;
import org.sigmah.server.domain.Indicator;
import org.sigmah.server.domain.IndicatorValue;
import org.sigmah.server.domain.ReportingPeriod;
import org.sigmah.server.domain.Site;
import org.sigmah.server.handler.base.AbstractCommandHandler;
import org.sigmah.server.handler.util.Handlers;
import org.sigmah.server.handler.util.ReportingPeriodValidation;
import org.sigmah.shared.command.UpdateMonthlyReports;
import org.sigmah.shared.command.result.VoidResult;
import org.sigmah.shared.dispatch.CommandException;
import org.sigmah.shared.util.Month;
/**
* Handler for {@link UpdateMonthlyReports} command
*
* @author Alex Bertram
* @author Maxime Lombard (mlombard@ideia.fr)
*/
public class UpdateMonthlyReportsHandler extends AbstractCommandHandler<UpdateMonthlyReports, VoidResult> {
/**
* {@inheritDoc}
*/
@Override
public VoidResult execute(final UpdateMonthlyReports cmd, final UserExecutionContext context) throws CommandException {
Site site = em().find(Site.class, cmd.getSiteId());
final Map<Month, ReportingPeriod> periods = new HashMap<>();
for (ReportingPeriod period : site.getReportingPeriods()) {
final ReportingPeriod oldPeriod = periods.put(
Handlers.monthFromRange(period.getDate1(), period.getDate2()), period);
if (oldPeriod != null) {
removeUnusedPeriod(oldPeriod);
}
}
performChanges(cmd, periods, site);
return new VoidResult();
}
@Transactional
protected void performChanges(final UpdateMonthlyReports cmd, Map<Month, ReportingPeriod> periods, Site site) {
for (UpdateMonthlyReports.Change change : cmd.getChanges()) {
ReportingPeriod period = periods.get(change.month);
if (period == null) {
period = new ReportingPeriod(site);
final Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(Calendar.YEAR, change.month.getYear());
calendar.set(Calendar.MONTH, change.month.getMonth() - 1);
calendar.set(Calendar.DATE, 5);
period.setDate1(calendar.getTime());
calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE) - 5);
period.setDate2(calendar.getTime());
em().persist(period);
periods.put(change.month, period);
} else {
final boolean wasValid = ReportingPeriodValidation.validate(period);
if (!wasValid) {
em().merge(period);
}
}
updateIndicatorValue(em(), period, change.indicatorId, change.value, false);
}
}
@Transactional
protected void removeUnusedPeriod(final ReportingPeriod period) {
// Removing every values associated with the given period.
em().createQuery("delete from IndicatorValue v where v.reportingPeriod.id = :period")
.setParameter("period", period.getId())
.executeUpdate();
// Removing the unused period.
em().remove(period);
}
private void updateIndicatorValue(EntityManager em, ReportingPeriod period, int indicatorId, Double value, boolean creating) {
if (value == null && !creating) {
int rowsAffected =
em.createQuery("delete IndicatorValue v where v.indicator.id = ?1 and v.reportingPeriod.id = ?2").setParameter(1, indicatorId)
.setParameter(2, period.getId()).executeUpdate();
assert rowsAffected <= 1 : "whoops, deleted too many";
} else if (value != null) {
int rowsAffected = 0;
if (!creating) {
// Updating the row with the new value.
rowsAffected =
em.createQuery("update IndicatorValue v set v.value = ?1 where " + "v.indicator.id = ?2 and " + "v.reportingPeriod.id = ?3")
.setParameter(1, value).setParameter(2, indicatorId).setParameter(3, period.getId()).executeUpdate();
}
if (rowsAffected == 0) {
IndicatorValue iValue = new IndicatorValue(period, em.getReference(Indicator.class, indicatorId), value);
em.persist(iValue);
}
}
}
}