Dashboard working

This commit is contained in:
Danny 2020-06-15 17:47:55 +02:00
parent 2ba4968556
commit 6284a4d7bf
10 changed files with 199 additions and 23 deletions

View File

@ -59,7 +59,7 @@ public class CalculateWarehouseStatsAction {
return articleIds.size();
}
private static class WarehouseStats {
public static class WarehouseStats {
public int numArticles;
public double efficiency;
public double ratioUsedSlots;

View File

@ -1,16 +1,5 @@
package org.hso.ecommerce.controller.cronjob;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
import org.hso.ecommerce.action.booking.CreateBookingAction;
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction;
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.ArticleIdentifier;
@ -27,17 +16,25 @@ import org.hso.ecommerce.entities.supplier.SupplierOrder;
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
import org.hso.ecommerce.repos.booking.BookingRepository;
import org.hso.ecommerce.repos.cronjob.BackgroundJobRepository;
import org.hso.ecommerce.repos.dashboard.DashboardSummaryRepository;
import org.hso.ecommerce.repos.shop.ArticleRepository;
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
import org.hso.ecommerce.repos.supplier.ArticleOfferRepository;
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
import org.hso.ecommerce.repos.supplier.SupplierRepository;
import org.hso.ecommerce.repos.user.UserRepository;
import org.hso.ecommerce.repos.warehouse.SlotRepository;
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.sql.Timestamp;
import java.util.*;
import java.util.Map.Entry;
interface ICronjob {
/**
* Calculate the earliest cronjob execution time that happens after the given reference time.
@ -223,6 +220,9 @@ class CronjobController {
@Autowired
private final BackgroundJobRepository cronjobRepository = null;
@Autowired
final SlotRepository slotRepository = null;
@Autowired
final ArticleRepository articleRepository = null;
@ -241,17 +241,24 @@ class CronjobController {
@Autowired
final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
@Autowired
final DashboardSummaryRepository dashboardSummaryRepository = null;
@Autowired
final SupplierRepository supplierRepository = null;
@Autowired
final SupplierOrderRepository supplierOrderRepository = null;
@Autowired
final UserRepository userRepository = null;
private static Map<String, ICronjob> getCronjobs() {
HashMap<String, ICronjob> map = new HashMap<>();
// Register all existing cronjobs
map.put(BackgroundJob.JOB_REORDER, new Reorder());
map.put(BackgroundJob.JOB_DASHBOARD, new DashboardCronjob());
return Collections.unmodifiableMap(map);
}

View File

@ -0,0 +1,79 @@
package org.hso.ecommerce.controller.cronjob;
import org.hso.ecommerce.action.warehouse.CalculateWarehouseStatsAction;
import org.hso.ecommerce.entities.dashboard.DashboardSummary;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
import org.springframework.stereotype.Component;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class DashboardCronjob implements ICronjob {
@Override
public Calendar nextExecution(Calendar reference) {
reference.add(Calendar.DAY_OF_MONTH, 1);
reference.set(Calendar.HOUR_OF_DAY, 0);
reference.set(Calendar.MINUTE, 0);
reference.set(Calendar.SECOND, 0);
reference.set(Calendar.MILLISECOND, 0);
return reference;
}
@Override
public Calendar previousExecution(Calendar reference) {
reference.set(Calendar.HOUR_OF_DAY, 0);
reference.set(Calendar.MINUTE, 0);
reference.set(Calendar.SECOND, 0);
reference.set(Calendar.MILLISECOND, 0);
return reference;
}
@Override
public void executeAt(Calendar time, CronjobController controller) {
Calendar oneDayBefore = (Calendar) time.clone();
oneDayBefore.add(Calendar.DAY_OF_MONTH, -1);
DashboardSummary dashboardSummary = new DashboardSummary();
List<WarehouseBookingPositionSlotEntry> entries = controller.slotRepository.findAll().stream().map(
s -> controller.warehouseBookingPositionSlotEntryRepository
.getBySlotNum(s.slotNum)
.orElseGet(() -> WarehouseBookingPositionSlotEntry.empty(null, s))
).collect(Collectors.toList());
CalculateWarehouseStatsAction.WarehouseStats warehouseStats = new CalculateWarehouseStatsAction(entries).finish();
dashboardSummary.created = new java.sql.Date(time.getTimeInMillis());
dashboardSummary.todaysCustomersOrders = getSales(oneDayBefore, time, controller);
dashboardSummary.todaysNewCustomers = getNewUsers(oneDayBefore, time, controller);
dashboardSummary.todaysWarehouseCapacity = warehouseStats.efficiency;
dashboardSummary.currentWarehouseCapacity = warehouseStats.ratioUsedSlots;
dashboardSummary.todaysSalesCent = getTurnover(oneDayBefore, time, controller);
controller.dashboardSummaryRepository.save(dashboardSummary);
}
private Integer getSales (Calendar begin, Calendar end, CronjobController controller)
{
return controller.customerOrderRepository.countOrdersInTimespan(
new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
}
private Integer getTurnover (Calendar begin, Calendar end, CronjobController controller)
{
return controller.customerOrderRepository.countTurnoverInTimespan(
new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
}
private Integer getNewUsers (Calendar begin, Calendar end, CronjobController controller)
{
return controller.userRepository.countUsersInTimespan(
new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
}
}

View File

@ -0,0 +1,25 @@
package org.hso.ecommerce.controller.intern;
import org.hso.ecommerce.entities.dashboard.DashboardSummary;
import org.hso.ecommerce.repos.dashboard.DashboardSummaryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class DashboardController {
@Autowired
private DashboardSummaryRepository dashboardSummaryRepository;
@GetMapping("/intern/dashboardsummary")
public List<DashboardSummary> getDashboardEntries()
{
List<DashboardSummary> inTimespan = dashboardSummaryRepository.findInTimespan(PageRequest.of(0, 7) );
return inTimespan;
}
}

View File

@ -15,11 +15,12 @@ public class DashboardSummary {
@NotNull
public java.sql.Date created;
public int todaysCustomers;
public int todaysNewCustomers;
public int todaysCustomersOrders;
public int todaysSuppliersOrders;
public int todaysItemsSold;
public int todaysSalesCent;
public int totalWarehouseCapacity;
public int currentWarehouseCapacity;
public double currentWarehouseCapacity;
public double todaysWarehouseCapacity;
}

View File

@ -0,0 +1,20 @@
package org.hso.ecommerce.repos.dashboard;
import org.hso.ecommerce.entities.dashboard.DashboardSummary;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface DashboardSummaryRepository extends JpaRepository<DashboardSummary, Long> {
@Query("SELECT ds FROM DashboardSummary ds ORDER BY ds.id DESC")
List<DashboardSummary> findInTimespan(
Pageable pageable
);
}

View File

@ -18,4 +18,14 @@ public interface CustomerOrderRepository extends JpaRepository<CustomerOrder, Lo
@Query("SELECT co FROM CustomerOrder co WHERE co.customer.id = :userId ORDER BY co.id DESC")
List<CustomerOrder> getOrdersByUserId(long userId);
@Query("SELECT COUNT(co.id) FROM CustomerOrder co WHERE co.created >= :begin AND co.created < :end")
Integer countOrdersInTimespan(
java.sql.Timestamp begin, java.sql.Timestamp end
);
@Query("SELECT SUM(co.totalGrossCent) FROM CustomerOrder co WHERE co.created >= :begin AND co.created < :end")
Integer countTurnoverInTimespan(
java.sql.Timestamp begin, java.sql.Timestamp end
);
}

View File

@ -13,6 +13,11 @@ public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT c FROM User c WHERE c.email = :email")
Optional<User> findByEmail(String email);
@Query("SELECT COUNT(c.id) FROM User c WHERE c.created >= :begin AND c.created < :end AND c.isEmployee = false")
Integer countUsersInTimespan(
java.sql.Timestamp begin, java.sql.Timestamp end
);
@Query("SELECT count(*) FROM User WHERE isEmployee = true")
Optional<Integer> numberOfEmployees();
}

View File

@ -22,3 +22,8 @@ spring.servlet.multipart.max-request-size=10MB
# EMBEDDED SERVER CONFIGURATION (ServerProperties)
server.address=::1
server.port=8080
spring.thymeleaf.prefix=file:src/main/resources/templates/
spring.thymeleaf.cache=false
spring.resources.static-locations=file:src/main/resources/static/
spring.resources.cache=false

View File

@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
<script src="/js/chart.js"></script>
<script>
function chart(id, name, data, unit) {
document.addEventListener("DOMContentLoaded", function() {
function chart(id, name, data, unit, dates) {
let elm = document.getElementById(id);
let cs = getComputedStyle(elm)
let ctx = elm.getContext('2d');
@ -20,7 +20,7 @@
// The data for our dataset
data: {
labels: ['Freitag', 'Donnerstag', 'Mittwoch', 'Dienstag', 'Montag'],
labels: dates,
datasets: [{
label: name,
backgroundColor: cs.getPropertyValue('--c-primary'),
@ -61,7 +61,6 @@
}
}
});
});
}
</script>
@ -107,7 +106,12 @@
<h3>Verkäufe (Anzahl)</h3>
<canvas id="sales"></canvas>
<script>
chart('sales', 'Verkäufe/Tag', [15, 12, 14, 8, 7])
fetch('./dashboardsummary')
.then(response => response.json())
.then(data => {
chart('sales', 'Verkäufe/Tag', data.map(d => d.todaysCustomersOrders),
"", data.map(g => g.created));
});
</script>
</section>
@ -116,7 +120,12 @@
<h3>Verkäufe (Umsatz)</h3>
<canvas id="umsatz"></canvas>
<script>
chart('umsatz', 'Umsatz/Tag', [1512.45, 1225.15, 1452.54, 814.54, 746.00], "EUR")
fetch('./dashboardsummary')
.then(response => response.json())
.then(data => {
chart('umsatz', 'Umsatz/Tag', data.map(d => d.todaysSalesCent / 100),
"€", data.map(g => g.created));
});
</script>
</section>
@ -125,7 +134,12 @@
<h3>Neukunden</h3>
<canvas id="Neukunden"></canvas>
<script>
chart('Neukunden', 'Neukunden', [1, 1, 0, 5, 0], "")
fetch('./dashboardsummary')
.then(response => response.json())
.then(data => {
chart('Neukunden', 'Neukunden', data.map(d => d.todaysNewCustomers),
"", data.map(g => g.created));
});
</script>
</section>
@ -139,7 +153,12 @@
<h2>Lagerauslastung</h2>
<canvas id="warehouse"></canvas>
<script>
chart('warehouse', 'Lagerauslastung', [50, 30, 20, 80, 60], "%")
fetch('./dashboardsummary')
.then(response => response.json())
.then(data => {
chart('warehouse', 'Lagerauslastung', data.map(d => d.todaysWarehouseCapacity),
"%", data.map(g => g.created));
});
</script>
</section>
@ -148,7 +167,12 @@
<h2>Lagereffizienz</h2>
<canvas id="warehouse-ef"></canvas>
<script>
chart('warehouse-ef', 'Lagereffizienz', [80, 70, 60, 75, 54], "%")
fetch('./dashboardsummary')
.then(response => response.json())
.then(data => {
chart('warehouse-ef', 'Lagereffizienz', data.map(d => d.todaysWarehouseCapacity),
"%", data.map(g => g.created));
});
</script>
</section>