Dashboard working
This commit is contained in:
parent
2ba4968556
commit
6284a4d7bf
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
||||
}
|
|
@ -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
|
||||
);
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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>
|
||||
|
|
Reference in New Issue