Commit f89a5a71 by Tuomas Riihimäki

Statistics

1 parent c98a99af
...@@ -18,18 +18,64 @@ ...@@ -18,18 +18,64 @@
*/ */
package fi.codecrew.moya.beans; package fi.codecrew.moya.beans;
import java.io.Serializable;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.ejb.Local; import javax.ejb.Local;
import fi.codecrew.moya.beans.StatisticsBeanLocal.ProductSlotcountMover;
import fi.codecrew.moya.model.Product;
@Local @Local
public interface StatisticsBeanLocal { public interface StatisticsBeanLocal {
public Long getGroupMembershipsEnteredEvent(); public Long getGroupMembershipsEnteredEvent();
public Long getCardDeliveredCount(); public Long getCardDeliveredCount();
public Long getGroupMembershipsTotalCount(); public Long getGroupMembershipsTotalCount();
public Map<Long, Long> getHourlyIncomingStatistics(long startingFromMillis, int hourCount); public Map<Long, Long> getHourlyIncomingStatistics(long startingFromMillis, int hourCount);
public static class ProductSlotcountMover implements Serializable {
/**
*
*/
private static final long serialVersionUID = -7759706761198824766L;
private final Product product;
private Long totalSlots;
private Long unusedSlots;
public ProductSlotcountMover(Product p) {
this.product = p;
}
public Long getTotalSlots() {
return totalSlots;
}
public void setTotalSlots(Long totalSlots) {
this.totalSlots = totalSlots;
}
public Long getUnusedSlots() {
return unusedSlots;
}
public void setUnusedSlots(Long unusedSlots) {
this.unusedSlots = unusedSlots;
}
public Product getProduct() {
return product;
}
}
List<ProductSlotcountMover> getUnusedSlots(boolean onlyPaid);
} }
...@@ -217,7 +217,7 @@ public class ProductBean implements ProductBeanLocal { ...@@ -217,7 +217,7 @@ public class ProductBean implements ProductBeanLocal {
if (prod.getPlaces() != null && !prod.getPlaces().isEmpty()) { if (prod.getPlaces() != null && !prod.getPlaces().isEmpty()) {
Long selectableCount = placeFacade.countSelectable(prod); Long selectableCount = placeFacade.countSelectable(prod);
Long unusedSlots = slotfacade.findUnusedSlotsCount(prod); Long unusedSlots = slotfacade.findUnusedSlotsCount(prod, false);
int freeCount = selectableCount.intValue() - unusedSlots.intValue(); int freeCount = selectableCount.intValue() - unusedSlots.intValue();
logger.info("Prodlimit selectable {}, unused {}, free {}, prod {}", selectableCount, unusedSlots, freeCount, prod); logger.info("Prodlimit selectable {}, unused {}, free {}, prod {}", selectableCount, unusedSlots, freeCount, prod);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
*/ */
package fi.codecrew.moya.beans; package fi.codecrew.moya.beans;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -32,8 +33,10 @@ import org.slf4j.LoggerFactory; ...@@ -32,8 +33,10 @@ import org.slf4j.LoggerFactory;
import fi.codecrew.moya.enums.apps.EventPermission; import fi.codecrew.moya.enums.apps.EventPermission;
import fi.codecrew.moya.facade.GroupMembershipFacade; import fi.codecrew.moya.facade.GroupMembershipFacade;
import fi.codecrew.moya.facade.PlaceSlotFacade;
import fi.codecrew.moya.facade.PrintedCardFacade; import fi.codecrew.moya.facade.PrintedCardFacade;
import fi.codecrew.moya.model.GroupMembership; import fi.codecrew.moya.model.GroupMembership;
import fi.codecrew.moya.model.Product;
/** /**
* Session Bean implementation class FoodWaveBean * Session Bean implementation class FoodWaveBean
...@@ -50,7 +53,11 @@ public class StatisticsBean implements StatisticsBeanLocal { ...@@ -50,7 +53,11 @@ public class StatisticsBean implements StatisticsBeanLocal {
@EJB @EJB
PrintedCardFacade printedCardFacade; PrintedCardFacade printedCardFacade;
@EJB
private PlaceSlotFacade psfacade;
@EJB
private ProductBeanLocal prodbean;
@Override @Override
@RolesAllowed(EventPermission.S_VIEW_STATISTICS) @RolesAllowed(EventPermission.S_VIEW_STATISTICS)
...@@ -72,18 +79,18 @@ public class StatisticsBean implements StatisticsBeanLocal { ...@@ -72,18 +79,18 @@ public class StatisticsBean implements StatisticsBeanLocal {
@Override @Override
public Map<Long, Long> getHourlyIncomingStatistics(long startingFromMillis, int hourCount) { public Map<Long, Long> getHourlyIncomingStatistics(long startingFromMillis, int hourCount) {
List<GroupMembership> groupMemberships = groupMembershipFacade.findAllEnteredBetween(startingFromMillis, (startingFromMillis + ((long) hourCount)*60l*60l*1000l)); List<GroupMembership> groupMemberships = groupMembershipFacade.findAllEnteredBetween(startingFromMillis, (startingFromMillis + ((long) hourCount) * 60l * 60l * 1000l));
HashMap<Long, Long> retMap = new HashMap<>(); HashMap<Long, Long> retMap = new HashMap<>();
long currentTimestamp = startingFromMillis; long currentTimestamp = startingFromMillis;
long hour = (60l*60l*1000l); long hour = (60l * 60l * 1000l);
long hourEntered = 0; long hourEntered = 0;
for(GroupMembership gm : groupMemberships) { for (GroupMembership gm : groupMemberships) {
// find the hour this one belongs to (sometime we need to skip empty hours) // find the hour this one belongs to (sometime we need to skip empty hours)
while(gm.getEnteredEvent().getTimeInMillis() > currentTimestamp+hour) { while (gm.getEnteredEvent().getTimeInMillis() > currentTimestamp + hour) {
retMap.put(currentTimestamp, hourEntered); retMap.put(currentTimestamp, hourEntered);
hourEntered = 0; hourEntered = 0;
...@@ -97,13 +104,19 @@ public class StatisticsBean implements StatisticsBeanLocal { ...@@ -97,13 +104,19 @@ public class StatisticsBean implements StatisticsBeanLocal {
return retMap; return retMap;
} }
@Override
public List<ProductSlotcountMover> getUnusedSlots(boolean onlyPaid) {
List<ProductSlotcountMover> ret = new ArrayList<>();
for (Product p : prodbean.getProducts()) {
logger.info("Products for stats {}", p);
ProductSlotcountMover m = new ProductSlotcountMover(p);
m.setUnusedSlots(psfacade.findUnusedSlotsCount(p, onlyPaid));
m.setTotalSlots(psfacade.totalSlotcount(p, onlyPaid));
if (m.getTotalSlots() > 0 && m.getUnusedSlots() > 0) {
ret.add(m);
}
}
return ret;
}
} }
...@@ -113,37 +113,59 @@ public class PlaceSlotFacade extends IntegerPkGenericFacade<PlaceSlot> { ...@@ -113,37 +113,59 @@ public class PlaceSlotFacade extends IntegerPkGenericFacade<PlaceSlot> {
return getEm().createQuery(q).getResultList(); return getEm().createQuery(q).getResultList();
} }
public Long findUnusedSlotsCount(Product prod) { public Long findUnusedSlotsCount(Product prod, boolean paidOnly) {
CriteriaBuilder cb = getEm().getCriteriaBuilder(); CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<Long> q = cb.createQuery(Long.class); CriteriaQuery<Long> q = cb.createQuery(Long.class);
Root<PlaceSlot> root = q.from(PlaceSlot.class); Root<PlaceSlot> root = q.from(PlaceSlot.class);
q.select(cb.count(root)); q.select(cb.count(root));
Path<Bill> bill = root.get(PlaceSlot_.bill); Path<Bill> bill = root.get(PlaceSlot_.bill);
List<Predicate> preds = new ArrayList<>();
preds.add(cb.equal(root.get(PlaceSlot_.product), prod));
if (paidOnly) {
// Only if bill is paid
preds.add(cb.isNotNull(bill.get(Bill_.paidDate)));
} else {
// If expire is null or has not passed, count it
Path<Calendar> billexp = bill.get(Bill_.expires); Path<Calendar> billexp = bill.get(Bill_.expires);
q.where(cb.equal(root.get(PlaceSlot_.product), prod), preds.add(cb.or(
cb.or(cb.isNull(billexp), cb.isNull(billexp),
cb.greaterThan(billexp, Calendar.getInstance()) cb.greaterThan(billexp, Calendar.getInstance())
), ));
cb.isNull(root.get(PlaceSlot_.place)), }
cb.isNull(root.get(PlaceSlot_.used))
); // Check that slot is not used
preds.add(cb.isNull(root.get(PlaceSlot_.place)));
preds.add(cb.isNull(root.get(PlaceSlot_.used)));
q.where(preds.toArray(new Predicate[preds.size()]));
Long count = super.getSingleNullableResult(getEm().createQuery(q)); Long count = super.getSingleNullableResult(getEm().createQuery(q));
return count; return count;
} }
public Long totalSlotcount(Product prod) { public Long totalSlotcount(Product prod, boolean paidOnly) {
CriteriaBuilder cb = getEm().getCriteriaBuilder(); CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<Long> q = cb.createQuery(Long.class); CriteriaQuery<Long> q = cb.createQuery(Long.class);
Root<PlaceSlot> root = q.from(PlaceSlot.class); Root<PlaceSlot> root = q.from(PlaceSlot.class);
q.select(cb.count(root)); q.select(cb.count(root));
Path<Bill> bill = root.get(PlaceSlot_.bill); Path<Bill> bill = root.get(PlaceSlot_.bill);
List<Predicate> preds = new ArrayList<>();
preds.add(cb.equal(root.get(PlaceSlot_.product), prod));
if (paidOnly) {
preds.add(cb.isNotNull(bill.get(Bill_.paidDate)));
} else {
Path<Calendar> billexp = bill.get(Bill_.expires); Path<Calendar> billexp = bill.get(Bill_.expires);
q.where(cb.equal(root.get(PlaceSlot_.product), prod), preds.add(cb.or(
cb.or(cb.isNull(billexp), cb.isNull(billexp),
cb.greaterThan(billexp, Calendar.getInstance()) cb.greaterThan(billexp, Calendar.getInstance())
) ));
); }
q.where(preds.toArray(new Predicate[preds.size()]));
Long count = super.getSingleNullableResult(getEm().createQuery(q)); Long count = super.getSingleNullableResult(getEm().createQuery(q));
return count; return count;
......
<!DOCTYPE html <!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:products="http://java.sun.com/jsf/composite/tools/products" xmlns:foodwave="http://java.sun.com/jsf/composite/tools" xmlns:p="http://primefaces.org/ui">
xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:products="http://java.sun.com/jsf/composite/tools/products"
xmlns:foodwave="http://java.sun.com/jsf/composite/tools"
xmlns:p="http://primefaces.org/ui"
>
<h:body> <h:body>
<ui:composition template="#{sessionHandler.template}"> <ui:composition template="#{sessionHandler.template}">
<ui:define name="content"> <ui:define name="content">
Sisällä: <p:outputLabel value="#{basicStatisticsView.groupMembershipsEnteredCount} / #{basicStatisticsView.groupMembershipsTotalCount}" /><br /> Sisällä: <h:outputText value="#{basicStatisticsView.groupMembershipsEnteredCount} / #{basicStatisticsView.groupMembershipsTotalCount}" />
Korttei: <p:outputLabel value="#{basicStatisticsView.cardDeliveredCount}" /> <br />
Korttei: <h:outputText value="#{basicStatisticsView.cardDeliveredCount}" />
<br />
<h2>Laskutettuja paikkaslotteja</h2>
<p:dataTable var="slot" value="#{basicStatisticsView.unusedBilledSlots}">
<p:column headerText="Tuote">
<h:outputText value="#{slot.product.name}" />
</p:column>
<p:column headerText="Paikkaslotteja yhteensä">
<h:outputText value="#{slot.totalSlots}" />
</p:column>
<p:column headerText="Käyttämättömiä slotteja">
<h:outputText value="#{slot.unusedSlots}" />
</p:column>
</p:dataTable>
<h2>Maksettuja paikkaslotteja</h2>
<p:dataTable var="slot" value="#{basicStatisticsView.unusedPaidSlots}">
<p:column headerText="Tuote">
<h:outputText value="#{slot.product.name}" />
</p:column>
<p:column headerText="Paikkaslotteja yhteensä">
<h:outputText value="#{slot.totalSlots}" />
</p:column>
<p:column headerText="Käyttämättömiä slotteja">
<h:outputText value="#{slot.unusedSlots}" />
</p:column>
</p:dataTable>
</ui:define> </ui:define>
</ui:composition> </ui:composition>
</h:body> </h:body>
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
*/ */
package fi.codecrew.moya.web.reports; package fi.codecrew.moya.web.reports;
import java.util.List;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.enterprise.context.ConversationScoped; import javax.enterprise.context.ConversationScoped;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
...@@ -29,6 +31,7 @@ import javax.inject.Named; ...@@ -29,6 +31,7 @@ import javax.inject.Named;
import fi.codecrew.moya.beans.EventBeanLocal; import fi.codecrew.moya.beans.EventBeanLocal;
import fi.codecrew.moya.beans.LectureBeanLocal; import fi.codecrew.moya.beans.LectureBeanLocal;
import fi.codecrew.moya.beans.StatisticsBeanLocal; import fi.codecrew.moya.beans.StatisticsBeanLocal;
import fi.codecrew.moya.beans.StatisticsBeanLocal.ProductSlotcountMover;
import fi.codecrew.moya.enums.apps.LecturePermission; import fi.codecrew.moya.enums.apps.LecturePermission;
import fi.codecrew.moya.model.Lecture; import fi.codecrew.moya.model.Lecture;
import fi.codecrew.moya.model.LectureGroup; import fi.codecrew.moya.model.LectureGroup;
...@@ -43,6 +46,11 @@ public class BasicStatisticsView extends GenericCDIView { ...@@ -43,6 +46,11 @@ public class BasicStatisticsView extends GenericCDIView {
@EJB @EJB
private StatisticsBeanLocal statisticsBean; private StatisticsBeanLocal statisticsBean;
private List<ProductSlotcountMover> billedslots;
private List<ProductSlotcountMover> paidslots;
public Long getGroupMembershipsEnteredCount() { public Long getGroupMembershipsEnteredCount() {
return statisticsBean.getGroupMembershipsEnteredEvent(); return statisticsBean.getGroupMembershipsEnteredEvent();
} }
...@@ -56,7 +64,18 @@ public class BasicStatisticsView extends GenericCDIView { ...@@ -56,7 +64,18 @@ public class BasicStatisticsView extends GenericCDIView {
return statisticsBean.getGroupMembershipsTotalCount(); return statisticsBean.getGroupMembershipsTotalCount();
} }
public List<ProductSlotcountMover> getUnusedBilledSlots()
{
if (billedslots == null) {
billedslots = statisticsBean.getUnusedSlots(false);
}
return billedslots;
}
public List<ProductSlotcountMover> getUnusedPaidSlots()
{
if (paidslots == null) {
paidslots = statisticsBean.getUnusedSlots(true);
}
return paidslots;
}
} }
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!