/*
* Copyright (C) 2014 GG-Net GmbH - Oliver Günther
*
* 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/>.
*/
package eu.ggnet.dwoss.report;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.StringUtils;
import eu.ggnet.dwoss.report.assist.ReportUtil;
import eu.ggnet.dwoss.report.entity.Report;
import eu.ggnet.dwoss.report.entity.Report.ViewMode;
import eu.ggnet.dwoss.report.entity.Report.YearSplit;
import eu.ggnet.dwoss.report.entity.ReportLine;
import eu.ggnet.dwoss.report.entity.ReportLine.SingleReferenceType;
import eu.ggnet.dwoss.report.entity.partial.SimpleReportLine;
import eu.ggnet.dwoss.rules.DocumentType;
import eu.ggnet.dwoss.rules.TradeName;
import eu.ggnet.dwoss.util.persistence.RemoteAgent;
import eu.ggnet.dwoss.util.validation.ValidationUtil;
import lombok.experimental.Builder;
import static eu.ggnet.dwoss.report.assist.ReportUtil.*;
import lombok.*;
import static eu.ggnet.dwoss.report.ReportAgent.ViewReportResult.Type.*;
import static eu.ggnet.dwoss.report.entity.Report.ViewMode.DEFAULT;
import static eu.ggnet.dwoss.report.entity.Report.ViewMode.YEARSPLITT_AND_WARRANTIES;
import static eu.ggnet.dwoss.rules.PositionType.*;
/**
*
* @author oliver.guenther
*/
@Remote
@Local
public interface ReportAgent extends RemoteAgent {
@Value
public static class ReportParameter implements Serializable {
public ReportParameter(Report report) {
this(report.getType(), report.getViewMode(), report.getName(), report.getStartingDate(), report.getEndingDate());
}
@Builder
public ReportParameter(TradeName contractor, ViewMode viewMode, String reportName, Date start, Date end) {
this.contractor = contractor;
this.viewMode = (viewMode == null ? DEFAULT : viewMode);
this.reportName = reportName;
this.start = start;
this.end = end;
ValidationUtil.validate(this);
}
@NotNull
private final TradeName contractor;
@NotNull
private final Report.ViewMode viewMode;
@NotNull
@Size(min = 1)
private final String reportName;
@NotNull
private final Date start;
@NotNull
private final Date end;
/**
* Creates a new Report Instance based on the Parameter.
* <p>
* @return a new report.
*/
public Report toNewReport() {
return new Report(reportName, contractor, start, end, viewMode);
}
}
/**
* Kill that name as soon as Possible (old ReportResult is gone)
*/
@Value
public static class ViewReportResult implements Serializable {
/**
* Type of the result, each type is intended for a different table.
*/
public enum Type {
/**
* Lines which should not be stored in the report, as future lines have an implaced here. e.g. a open complaint.
*/
ACTIVE_INFO,
/**
* Lines which represent repayents.
*/
REPAYMENTS,
/**
* Invoice Units with a MFG Date between report date and report date - 1 year.
*/
UNDER_ONE_YEAR,
/**
* Invoice Units with a MFG Date older than report date - 1 year.
*/
PAST_ONE_YEAR,
/**
* Lines which in sum result into zero.
*/
REPORT_INFO,
/**
* Warrenty lines.
*/
WARRENTY,
/**
* Invoiced elements.
*/
INVOICED;
/**
* Retruns all Reportable.
* <p>
* @return all Reortable.
*/
public static EnumSet<Type> allReportable() {
return EnumSet.complementOf(EnumSet.of(ACTIVE_INFO));
}
}
private final EnumMap<Type, NavigableSet<ReportLine>> lines;
private final ReportParameter parameter;
public NavigableSet<ReportLine> getAllLines() {
return lines.values().stream().flatMap(x -> x.stream()).collect(Collectors.toCollection(() -> new TreeSet<>()));
}
/**
* Returns a copy of all relevant report lines.
* A ReportLine is relevant if {@link ReportLine#addedToReportProperty} isd true.
* <p>
* @return a copy of all relevant report lines.
*/
public EnumMap<Type, NavigableSet<ReportLine>> getRelevantLines() {
EnumMap<Type, NavigableSet<ReportLine>> copy = new EnumMap<>(Type.class);
for (Type keySet : Type.allReportable()) {
if ( this.getLines().get(keySet) == null ) continue;
copy.put(keySet, this.getLines().get(keySet).stream().filter((t) -> t.isAddedToReport()).collect(Collectors.toCollection(() -> new TreeSet<>())));
}
return copy;
}
public static ViewReportResult fromReport(Report report) {
Set<ReportLine> warranties = report.getLines().stream()
// This collects all warranties.
.filter(line -> line.getPositionType() == PRODUCT_BATCH && line.getReference(SingleReferenceType.WARRANTY) != null)
.collect(Collectors.toCollection(() -> new TreeSet<>()));
Set<ReportLine> units = report.getLines();
units.removeAll(warranties);
EnumMap<ViewReportResult.Type, NavigableSet<ReportLine>> lines = new EnumMap<>(ViewReportResult.Type.class);
lines.put(REPAYMENTS, ReportUtil.filterRepayed(units));
lines.put(REPORT_INFO, ReportUtil.filterReportInfo(units));
if ( report.getViewMode() == YEARSPLITT_AND_WARRANTIES ) {
YearSplit split = ReportUtil.filterInvoicedSplit(units, report.getStartingDate());
lines.put(UNDER_ONE_YEAR, split.getBefore());
lines.put(PAST_ONE_YEAR, split.getAfter());
lines.put(WARRENTY, filterInvoiced(warranties));
lines.get(REPAYMENTS).addAll(filterRepayed(warranties));
lines.get(REPORT_INFO).addAll(filterReportInfo(warranties));
} else {
lines.put(INVOICED, ReportUtil.filterInvoiced(units));
}
return new ViewReportResult(lines, new ReportParameter(report));
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class SearchParameter implements Serializable {
private String refurbishId;
public boolean isEmpty() {
return StringUtils.isBlank(refurbishId);
}
}
public List<SimpleReportLine> findSimple(SearchParameter search, int firstResult, int maxResults);
public List<ReportLine> find(SearchParameter search, int firstResult, int maxResults);
public long count(SearchParameter search);
/**
* Prepares a report for view and storage.
* <p>
* @param p the parameter of the report
* @param loadUnreported should unreported values earlier than start be included.
* @return a result based on the parameters.
*/
ViewReportResult prepareReport(ReportParameter p, boolean loadUnreported);
/**
* Returns all ReportLines, which have the given document type id from to till the given Dates
* <p/>
* @param type the document type
* @param till the date as upper border
* @param from the date as lower border
* @return the matching report lines.
*/
List<ReportLine> findReportLinesByDocumentType(DocumentType type, Date from, Date till);
/**
* Stores a new report, persisting the report and merging the lines.
* <p/>
* @param report the report to persist.
* @param storeables the lines to merge.
* @return the persisted report.
*/
Report store(Report report, Collection<ReportLine.Storeable> storeables);
/**
* Returns a ReportResult build from an existing Report.
* <p>
* @param reportId the id of the exisitng report
* @return a ReportResult build from an existing Report or null if nothing is found.
*/
ViewReportResult findReportResult(long reportId);
/**
* Returns all ReportLines, limited by first and max ordered by reportDate descending.
* <p>
* @param firstResult the first result to return
* @param maxResults the maximum results to return
* @return all ReportLines, limitied by first and max ordered by reportDate descending.
*/
public List<ReportLine> findAllReportLinesReverse(int firstResult, int maxResults);
/**
* Attaches "dangling" {@link ReportLine}<code>s</code> of {@link DocumentType#COMPLAINT} to existing Reports of contractor. A ReportLine is considered
* "dangling" if:
* <ul>
* <li>It is of {@link PositionType#UNIT}</li>
* <li>It is not in a report of the contractor</li>
* <li>It references a {@link ReportLine} of {@link DocumentType#ANNULATION_INVOICE} or {@link DocumentType#CREDIT_MEMO} which is already in a report of the
* contractor.</li>
* <li></li>
* </ul>
* These "dangling" {@link ReportLine}<code>s</code> are added to the Report that contains the referencing {@link ReportLine} of
* {@link DocumentType#ANNULATION_INVOICE} or {@link DocumentType#CREDIT_MEMO}.
* <p>
* @param type the type as report identifier.
* @param till the upper limit.
* @return the discovered and attached ReportLines.
*/
public Set<ReportLine> attachDanglingComplaints(TradeName type, Date till);
}