eu.ggnet.dwoss.report.eao.ReportLineEao.java Source code

Java tutorial

Introduction

Here is the source code for eu.ggnet.dwoss.report.eao.ReportLineEao.java

Source

/*
 * Copyright (C) 2014 GG-Net GmbH - Oliver Gnther
 *
 * 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.eao;

import java.util.*;
import java.util.stream.Collectors;

import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.*;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.*;

import eu.ggnet.dwoss.report.assist.Reports;
import eu.ggnet.dwoss.report.entity.ReportLine;
import eu.ggnet.dwoss.report.entity.partial.SimpleReportLine;
import eu.ggnet.dwoss.rules.*;
import eu.ggnet.dwoss.util.DateFormats;
import eu.ggnet.dwoss.util.persistence.eao.AbstractEao;

import com.mysema.query.jpa.impl.JPAQuery;

import static eu.ggnet.dwoss.report.entity.QReportLine.reportLine;
import static eu.ggnet.dwoss.report.entity.ReportLine.SingleReferenceType.WARRANTY;
import static eu.ggnet.dwoss.report.entity.partial.QSimpleReportLine.simpleReportLine;
import static eu.ggnet.dwoss.rules.PositionType.*;

/**
 * Entity Access Object for ReportLine.
 * <p>
 * @author pascal.perau
 */
@Stateless
public class ReportLineEao extends AbstractEao<ReportLine> {

    private static final Logger L = LoggerFactory.getLogger(ReportLineEao.class);

    @Inject
    @Reports
    private EntityManager em;

    @Override
    public EntityManager getEntityManager() {
        return em;
    }

    public ReportLineEao(EntityManager em) {
        this();
        this.em = em;
    }

    public ReportLineEao() {
        super(ReportLine.class);
    }

    public List<SimpleReportLine> findAllSimple() {
        return em.createQuery("SELECT r FROM SimpleReportLine r", SimpleReportLine.class).getResultList();
    }

    /**
     * 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, limited by first and max ordered by reportDate descending.
     */
    public List<ReportLine> findAllReverse(int firstResult, int maxResults) {
        return em.createNamedQuery("ReportLine.allReverse", ReportLine.class).setFirstResult(firstResult)
                .setMaxResults(maxResults).getResultList();
    }

    /**
     * Returns all ReportLines ordered by reportDate descending.
     * <p>
     * @return all ReportLines ordered by reportDate descending.
     */
    public List<ReportLine> findAllReverse() {
        return em.createNamedQuery("ReportLine.allReverse", ReportLine.class).getResultList();
    }

    public Date findLastReported() {
        return em.createNamedQuery("ReportLine.lastReported", Date.class).getSingleResult();
    }

    public List<ReportLine> findByUniqueUnitId(long id) {
        return em.createNamedQuery("ReportLine.byUniqueUnitId", ReportLine.class).setParameter(1, id)
                .getResultList();
    }

    /**
     * Returns all lines matching the refurbishId.
     * <p>
     * @param id the refurbishId
     * @return all lines matching the refurbishId.
     */
    public List<ReportLine> findByRefurbishId(String id) {
        return em.createNamedQuery("ReportLine.byRefurbishId", ReportLine.class).setParameter(1, id)
                .getResultList();
    }

    public List<ReportLine> findBetweenDates(Date start, Date end) {
        return em.createNamedQuery("ReportLine.betweenDates", ReportLine.class).setParameter(1, start)
                .setParameter(2, end).getResultList();
    }

    /**
     * Returns all Reportlines, which are not jet in a Report of the contractor and have a reporting date between (including) from and till.
     * <p/>
     * If the contractor is null the Query unreportedFromTillAll will be executed.
     * <p/>
     * @param type        the contractor as filter
     * @param till        the date as upper border
     * @param from        the date as lower border
     * @param includeOnly selects positionTypes which should only be included.
     * @return the matching report lines.
     */
    public List<ReportLine> findUnreported(TradeName type, Date from, Date till, PositionType... includeOnly) {
        L.info("findUnreported(type={},from={},till={},includeOnly={})", type, from, till, includeOnly);
        Objects.requireNonNull(type, "The Type must not be null");
        List<PositionType> positionTypes = new ArrayList<>();
        List<TradeName> contractors = new ArrayList<>();
        Calendar cal = Calendar.getInstance();
        cal.set(2001, 01, 01);
        if (includeOnly != null && includeOnly.length > 0)
            positionTypes = Arrays.asList(includeOnly);
        contractors.add(type);
        TypedQuery<ReportLine> query;
        if (positionTypes.isEmpty() && contractors.isEmpty()) {
            L.debug("Using Query ReportLine.unreported");
            query = em.createNamedQuery("ReportLine.unreported", ReportLine.class);
        } else if (positionTypes.isEmpty()) {
            L.debug("Using Query ReportLine.unreportedbyContractors");
            query = em.createNamedQuery("ReportLine.unreportedbyContractors", ReportLine.class)
                    .setParameter("contractors", contractors);
        } else if (contractors.isEmpty()) {
            L.debug("Using Query ReportLine.unreportedbyPositionTypes");
            query = em.createNamedQuery("ReportLine.unreportedbyPositionTypes", ReportLine.class)
                    .setParameter("positionTypes", positionTypes);
        } else {
            L.debug("Using Query ReportLine.unreportedbyContractorsPositionTypes");
            query = em.createNamedQuery("ReportLine.unreportedbyContractorsPositionTypes", ReportLine.class)
                    .setParameter("contractors", contractors).setParameter("positionTypes", positionTypes);
        }
        query.setParameter("from", (from == null ? cal.getTime() : from));
        query.setParameter("till", till);
        query.setParameter("type", type);
        return query.getResultList();
    }

    public List<ReportLine> findUnreportedUnits(TradeName type, Date from, Date till) {
        return findUnreported(type, from, till, PositionType.UNIT, PositionType.UNIT_ANNEX);
    }

    /**
     * Returns a collection with {@link PositionType#UNIT} or {@link PositionType#UNIT_ANNEX} with the same uniqueUnitId and dossierId.
     * <p>
     * @param uniqueUnitId the uniqueUnitId
     * @param dossierId    the dossierId
     * @return a collection with {@link PositionType#UNIT} or {@link PositionType#UNIT_ANNEX} with the same uniqueUnitId and dossierId.
     */
    public List<ReportLine> findUnitsAlike(long uniqueUnitId, long dossierId) {
        return new JPAQuery(em).from(reportLine)
                .where(reportLine.positionType.in(Arrays.asList(UNIT, UNIT_ANNEX)),
                        reportLine.uniqueUnitId.eq(uniqueUnitId), reportLine.dossierId.eq(dossierId))
                .list(reportLine);
    }

    public List<ReportLine> findReportedUnitsbyRefurbishId(Collection<String> refurbishId) {
        return new JPAQuery(em).from(reportLine).where(reportLine.positionType.in(Arrays.asList(UNIT, UNIT_ANNEX)),
                reportLine.refurbishId.in(refurbishId), reportLine.reports.isNotEmpty()).list(reportLine);
    }

    /**
     * This Method returns all unreported Warranties.
     * <p>
     * @return all unreported warranties.
     */
    public List<ReportLine> findUnreportedWarrentys() {
        // This works in mysql, but fails in hsqldb.
        //        return new JPAQuery(em).from(reportLine)
        //                .where(reportLine.positionType.eq(PRODUCT_BATCH),
        //                        reportLine.singleReferences.containsKey(WARRANTY),
        //                        reportLine.reports.isEmpty()).list(reportLine);
        return new JPAQuery(em).from(reportLine)
                .where(reportLine.positionType.eq(PRODUCT_BATCH), reportLine.reports.isEmpty()).list(reportLine)
                .stream().filter(l -> l.getReference(WARRANTY) != null).collect(Collectors.toList());
    }

    /**
     * Returns all ReportLines, which are at the given Customer id from to till the given Dates
     * <p/>
     * @param type the customer Id which the ReportLines must be have
     * @param till the date as upper border
     * @param from the date as lower border
     * @return the matching report lines.
     */
    public List<ReportLine> findbyDocumentTypeFromTill(DocumentType type, Date from, Date till) {
        return new JPAQuery(em).from(reportLine)
                .where(reportLine.documentType.eq(type), reportLine.reportingDate.between(from, till))
                .list(reportLine);
    }

    /**
     * Returns all reportlines matching the productId, the contractor and have no contractor part no set.
     * <p>
     * @param productId  the product id
     * @param contractor the contractor
     * @return all reportlines matching the productId, the contractor and have no contractor part no set.
     */
    public List<ReportLine> findByProductIdMissingContractorPartNo(long productId, TradeName contractor) {
        return em.createNamedQuery("ReportLine.byProductIdMissingContractorPartNo", ReportLine.class)
                .setParameter(1, productId).setParameter(2, contractor).getResultList();
    }

    public List<ReportLine> findMissingContractorPartNo(TradeName contractor) {
        return new JPAQuery(em).from(reportLine).where(reportLine.positionType.eq(UNIT)
                .and(reportLine.contractorPartNo.isNull()).and(reportLine.contractor.eq(contractor)))
                .list(reportLine);
    }

    /**
     * Generates a list of {@link DailyRevenue} that hold report data for INVOICES - ANNULATION_INVOICES in a date range containing daily summed prices
     * for specific {@link PositionType}s.
     * <p>
     * @param posTypes the {@link PositionType} that is searched for
     * @param start    the starting date range for the collected data
     * @param end      the end date range for the collected data
     * @return a list of {@link DailyRevenue} that hold report data for INVOICES - ANNULATION_INVOICES in a date range containing daily summed prices
     *         for specific {@link PositionType}s
     */
    public List<Set<DailyRevenue>> findRevenueDataByPositionTypesAndDate(List<PositionType> posTypes, Date start,
            Date end) {
        try {
            L.info("Attempt to find revenue report data with posType={}, start={}, end={}", posTypes, start, end);

            List<Integer> posTypeOrdinals = new ArrayList<>();
            for (PositionType positionType : posTypes) {
                posTypeOrdinals.add(positionType.ordinal());
            }
            Query q = em.createNativeQuery("SELECT reportingDate, documentTypeName, sum(price), salesChannelName"
                    + " FROM ReportLine rl WHERE rl.positionType in(:positions) and rl.reportingDate >= :start"
                    + " and rl.reportingDate <= :end and rl.documentType in(1,3) GROUP BY rl.reportingDate, rl.documentTypeName, rl.salesChannelName");
            q.setParameter("positions", posTypeOrdinals);
            q.setParameter("start", start);
            q.setParameter("end", end);
            List<Object[]> data = q.getResultList();
            List<DailyRevenue> reportData = new ArrayList<>();
            for (Object[] object : data) {
                reportData.add(new DailyRevenue((Date) object[0], (String) object[1], (double) object[2],
                        (String) object[3]));
            }

            Map<Date, Set<DailyRevenue>> revReports = new HashMap<>();
            for (DailyRevenue revenueReportCarrier : reportData) {
                Date d = DateUtils.truncate(revenueReportCarrier.getReportingDate(), Calendar.DATE);
                Set<DailyRevenue> neededSet = revReports.get(d);
                if (neededSet == null) {
                    neededSet = new HashSet<>();
                    neededSet.add(revenueReportCarrier);
                    revReports.put(d, neededSet);
                } else {
                    neededSet.add(revenueReportCarrier);
                }
            }

            return new ArrayList<>(revReports.values());
        } catch (Exception e) {
            L.error(ExceptionUtils.getStackTrace(e));
            return null;
        }
    }

    /**
     * Returns the revenue in a range with the supplied Stepsize.
     * A step size of day will return daily revenues, while a stepsize of month returns monthly revenues.
     * For each stepsize the earliest possible day is used as identifier. e.g.: January 2012 it would be 2012-01-01.
     * <p>
     * @param posTypes      the positiontypes to include
     * @param start         the start
     * @param end           the end
     * @param step          the stepsize.
     * @param extraReported
     * @return the Revenue by Date in the stepsize.
     */
    public NavigableMap<Date, Revenue> revenueByPositionTypesAndDate(List<PositionType> posTypes, Date start,
            Date end, Step step, boolean extraReported) {
        L.debug("Attempt to find revenue report data with posType={}, start={}, end={}, {}", posTypes, start, end,
                step);
        TypedQuery<RevenueHolder> q = em.createNamedQuery("ReportLine.revenueByPositionTypesAndDate",
                RevenueHolder.class);
        q.setParameter("positions", posTypes).setParameter("start", start).setParameter("end", end);

        NavigableMap<Date, Revenue> result = prepare(start, end, step);
        for (RevenueHolder holder : q.getResultList()) {
            Revenue revenueStep = result.get(step.truncate(holder.getReportingDate()));
            // Highly unlikely case, but if it happens a detail message might help.
            if (revenueStep == null)
                throw new RuntimeException("No prepared RevenueStep found for " + step.name() + ":reportingDate="
                        + DateFormats.ISO.format(holder.getReportingDate()) + ",truncated="
                        + DateFormats.ISO.format(step.truncate(holder.getReportingDate())) + ",keys="
                        + nice(result.keySet(), step));
            revenueStep.addTo(holder.getSalesChannel(), holder.getDocumentType(), holder.getContractor(),
                    holder.getPrice(), 0., 0.);
        }
        if (!extraReported)
            return result;
        q = em.createNamedQuery("ReportLine.revenueByPositionTypesAndDateReported", RevenueHolder.class);
        q.setParameter("positions", posTypes).setParameter("start", start).setParameter("end", end);
        List<RevenueHolder> resultList = q.getResultList();
        System.out.println("Second run size:" + resultList.size());
        for (RevenueHolder holder : resultList) {
            System.out.println("Second run: " + holder);
            Revenue revenueStep = result.get(step.truncate(holder.getReportingDate()));
            // Highly unlikely case, but if it happens a detail message might help.
            if (revenueStep == null)
                throw new RuntimeException("No prepared RevenueStep found for " + step.name() + ":reportingDate="
                        + DateFormats.ISO.format(holder.getReportingDate()) + ",truncated="
                        + DateFormats.ISO.format(step.truncate(holder.getReportingDate())) + ",keys="
                        + nice(result.keySet(), step));
            revenueStep.addTo(holder.getSalesChannel(), holder.getDocumentType(), holder.getContractor(), 0.,
                    holder.getPrice(), holder.getPurchasePrice());
        }
        return result;
    }

    public List<ReportLine> findBySerialAndPositionTypeAndDossierId(String serial, PositionType positionType,
            long dossierId) {
        return em.createNamedQuery("ReportLine.bySerialAndPositionTypeAndDossierId", ReportLine.class)
                .setParameter(1, serial).setParameter(2, positionType).setParameter(3, dossierId).getResultList();
    }

    /**
     * This method search for a single Report line which is identify by Serial or Refurbish id.
     * <p>
     * @param key Serial or Refurbish id.
     * @return return a found ReportLine.
     */
    public List<SimpleReportLine> findReportLinesByIdentifiers(String key) {
        return new JPAQuery(em).from(simpleReportLine)
                .where(simpleReportLine.refurbishId.eq(key).or(simpleReportLine.serial.eq(key)))
                .list(simpleReportLine);
    }

    private NavigableMap<Date, Revenue> prepare(Date start, Date end, Step step) {
        NavigableMap<Date, Revenue> result = new TreeMap<>();
        Date actual = step.truncate(start);
        end = step.prepareEnd(end);
        while (actual.before(end)) {
            result.put(actual, new Revenue());
            actual = step.incement(actual);
        }
        return result;
    }

    private List<String> nice(Set<Date> dates, Step step) {
        List<String> result = new ArrayList<>();
        for (Date date : dates) {
            result.add(step.format(date) + "(" + DateFormats.ISO.format(date) + ")");
        }
        return result;
    }

}