Compare commits
116 Commits
e037b75f7c
...
release
Author | SHA1 | Date | |
---|---|---|---|
f667d41c3c | |||
3a85997f99 | |||
471d859987 | |||
701e3c9cf6 | |||
e320f5b02b | |||
5aca84c43b | |||
5b483d5c5d | |||
037f1ff671 | |||
99896a4f77 | |||
624ade2032 | |||
99b123565c | |||
be6de240bb | |||
7cf1819460 | |||
17f0c645f1 | |||
bdd1017232 | |||
f4299c33c1 | |||
f86a14b2f8 | |||
2fb5826a3b | |||
b993700ae4 | |||
5d506a1526 | |||
e87d0d8cdd | |||
fb222c9213 | |||
cf9ab66e68 | |||
cdc372d574 | |||
2290f01a8f | |||
3bc0996c73 | |||
758c6810ab | |||
577a4f72f0 | |||
a2aca7a8ca | |||
3b7317a831 | |||
32921a3f87 | |||
63e9bc2336 | |||
31bff55a20 | |||
5861b61565 | |||
f0c9823e45 | |||
6fbb16fea2 | |||
0d547c8903 | |||
5162e3fc19 | |||
8bfe8b37f5 | |||
2e07d03908 | |||
b9e87f5bd4 | |||
cd641d6cc4 | |||
4e9f7800be | |||
8d27c486d5 | |||
714ac4f1de | |||
186db31b17 | |||
fb53c68be3 | |||
19cf6ccfc5 | |||
7fafd14715 | |||
d5181f149a | |||
a950ecb2b9 | |||
f42a50d24d | |||
33118ddb2f | |||
a6a2adc7db | |||
62df2346c3 | |||
c1a0ecdcf3 | |||
a1abbf5329 | |||
deaf283a98 | |||
ffe9af0633 | |||
2989b54593 | |||
b846b919b7 | |||
1f83a82f17 | |||
cd1a8568e6 | |||
53cdb20091 | |||
9389675b5c | |||
97a7f3a8ad | |||
aa2f42a10a | |||
f128a8b9ed | |||
ffea25c082 | |||
d77b8c046a | |||
8fdfe9cc69 | |||
e5332a3348 | |||
c3eaf5ac11 | |||
fa75beb9c4 | |||
4bef17dc0a | |||
79e4986880 | |||
181a09e16b | |||
f4aae9c581
|
|||
ea0c8c45d6
|
|||
8416783e0a | |||
bcbebe8e8d | |||
a570696795 | |||
187656814e | |||
8c0652b26b
|
|||
ef07447abc | |||
bb7b35dc28 | |||
93cfbb4a27 | |||
68cc35cec3 | |||
b2ee048f25 | |||
020a30474e | |||
4bfc8a2cc6 | |||
0ff873baaa | |||
1812c89994 | |||
2442a477c8
|
|||
ebb3c8c235 | |||
e6c068e71a | |||
86e3ced19b | |||
44df9e4b4f | |||
18cbfbf148 | |||
5a0b303601
|
|||
d5825ba7a0
|
|||
774e62f892
|
|||
e1c00eca8f
|
|||
e904eba7a4 | |||
6284a4d7bf | |||
d121532fba
|
|||
0ab185f143 | |||
1dd4b5cfa5 | |||
266bba095a | |||
fa7bdf2f7e | |||
ebeba72278 | |||
f671baf7f0 | |||
3775f96f3f | |||
2394157be8 | |||
bba4173269 | |||
e1d7becc2e |
0
delivery/gradlew
vendored
Normal file → Executable file
@ -4,9 +4,9 @@ package org.hso.ecommerce.supplier;
|
||||
import org.hso.ecommerce.supplier.data.Delivery;
|
||||
import org.hso.ecommerce.supplier.data.DeliveryManager;
|
||||
import org.hso.ecommerce.supplier.data.ReturnStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@ -19,14 +19,19 @@ public class RequestController {
|
||||
public String supplier(HttpServletResponse response, HttpServletRequest request, @RequestBody Delivery delivery) {
|
||||
DeliveryManager.getInstance().add(delivery);
|
||||
|
||||
return delivery.getUuid().toString();
|
||||
return delivery.getUuid();
|
||||
}
|
||||
|
||||
@GetMapping("/status")
|
||||
@GetMapping(value = "/status", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ReturnStatus searchArticles(@RequestParam(value = "trackingID") String trackingID, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
Delivery delivery = DeliveryManager.getInstance().getDeliveryByeID(trackingID);
|
||||
Delivery delivery = DeliveryManager.getInstance().getDeliveryByID(trackingID);
|
||||
if (delivery == null) {
|
||||
Delivery lostDelivery = Delivery.lostDelivery(trackingID);
|
||||
DeliveryManager.getInstance().add(lostDelivery);
|
||||
delivery = lostDelivery;
|
||||
}
|
||||
|
||||
return new ReturnStatus(delivery.getStatus(),delivery.getEstimatedArrival());
|
||||
return new ReturnStatus(delivery.getStatus(), delivery.getEstimatedArrival());
|
||||
}
|
||||
}
|
||||
|
@ -8,38 +8,48 @@ import java.util.UUID;
|
||||
|
||||
public class Delivery {
|
||||
|
||||
private String[] states = {"Bestellung eingegangen","Bestellung auf dem Weg","Lieferung erfolgreich"};
|
||||
private int[] timeBorder = {4,24};
|
||||
private String[] states = {"Bestellung eingegangen", "Bestellung auf dem Weg", "Lieferung erfolgreich"};
|
||||
private int[] timeBorder = {4, 24};
|
||||
|
||||
private String name;
|
||||
private String address;
|
||||
private String estimatedArrival;
|
||||
private Date creationTime;
|
||||
private UUID uuid;
|
||||
|
||||
public Delivery(String name, String address)
|
||||
{
|
||||
// Why is this a string and creationTime a Date?!
|
||||
private String estimatedArrival;
|
||||
|
||||
private Date creationTime;
|
||||
private String uuid;
|
||||
|
||||
public Delivery(String name, String address) {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
this.uuid = UUID.randomUUID();
|
||||
this.uuid = UUID.randomUUID().toString();
|
||||
this.creationTime = new Date();
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
|
||||
this.estimatedArrival = formatter.format(addDays((Date)this.creationTime.clone(),1));
|
||||
this.estimatedArrival = formatter.format(addDays((Date) this.creationTime.clone(), 1));
|
||||
}
|
||||
|
||||
public static Delivery lostDelivery(String uuid) {
|
||||
Delivery delivery = new Delivery("", "");
|
||||
delivery.uuid = uuid;
|
||||
delivery.creationTime = addDays(new Date(), -1);
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
|
||||
delivery.estimatedArrival = formatter.format(addDays((Date) delivery.creationTime.clone(), 1));
|
||||
return delivery;
|
||||
}
|
||||
|
||||
public String getStatus()
|
||||
{
|
||||
public String getStatus() {
|
||||
Date now = new Date();
|
||||
Long timeNow = now.getTime();
|
||||
Long creationTime = this.creationTime.getTime();
|
||||
long timeNow = now.getTime();
|
||||
long creationTime = this.creationTime.getTime();
|
||||
|
||||
Long diff = timeNow - creationTime;
|
||||
// Wow, that's how calculate date diffs.
|
||||
long diff = timeNow - creationTime;
|
||||
double hour = (((diff / 1000.0) / 3600.0));
|
||||
|
||||
for (int i = 0; i < timeBorder.length; i++) {
|
||||
|
||||
if(hour < timeBorder[i])
|
||||
if (hour < timeBorder[i])
|
||||
return states[i];
|
||||
}
|
||||
|
||||
@ -51,15 +61,14 @@ public class Delivery {
|
||||
return estimatedArrival;
|
||||
}
|
||||
|
||||
private Date addDays(Date date, int days)
|
||||
{
|
||||
private static Date addDays(Date date, int days) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(date);
|
||||
cal.add(Calendar.DATE, days);
|
||||
return cal.getTime();
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,18 @@
|
||||
package org.hso.ecommerce.supplier.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class DeliveryManager {
|
||||
|
||||
private List<Delivery> deliveryList;
|
||||
private HashMap<String, Delivery> deliveryList;
|
||||
private static DeliveryManager deliveryManager;
|
||||
|
||||
private DeliveryManager()
|
||||
{
|
||||
deliveryList = new ArrayList<>();
|
||||
deliveryList = new HashMap<>();
|
||||
}
|
||||
|
||||
public static DeliveryManager getInstance () {
|
||||
public static DeliveryManager getInstance() {
|
||||
|
||||
if (DeliveryManager.deliveryManager == null) {
|
||||
DeliveryManager.deliveryManager = new DeliveryManager();
|
||||
@ -22,13 +20,11 @@ public class DeliveryManager {
|
||||
return DeliveryManager.deliveryManager;
|
||||
}
|
||||
|
||||
public boolean add(Delivery delivery)
|
||||
{
|
||||
return deliveryList.add(delivery);
|
||||
public void add(Delivery delivery) {
|
||||
deliveryList.put(delivery.getUuid(), delivery);
|
||||
}
|
||||
|
||||
public Delivery getDeliveryByeID(String uuid)
|
||||
{
|
||||
return deliveryList.parallelStream().filter(d -> d.getUuid().equals(UUID.fromString(uuid))).findAny().get();
|
||||
public Delivery getDeliveryByID(String uuid) {
|
||||
return deliveryList.getOrDefault(uuid, null);
|
||||
}
|
||||
}
|
||||
|
123485
doc/charter/charter.fodt
@ -1,479 +0,0 @@
|
||||
:root {
|
||||
font-family: "Fira Sans";
|
||||
line-height: 1.15;
|
||||
|
||||
--u5: calc(1em * 1.5 * 1.5 * 1.5 * 1.5 * 1.5 );
|
||||
--u4: calc(1em * 1.5 * 1.5 * 1.5 * 1.5);
|
||||
--u3: calc(1em * 1.5 * 1.5 * 1.5);
|
||||
--u2: calc(1em * 1.5 * 1.5);
|
||||
--u1: calc(1em * 1.5);
|
||||
--u0: calc(1em);
|
||||
--u-1: calc(1em * 0.666);
|
||||
--u-2: calc(1em * 0.666 * 0.666);
|
||||
--u-3: calc(1em * 0.666 * 0.666 * 0.666);
|
||||
--u-4: calc(1em * 0.666 * 0.666 * 0.666 * 0.666);
|
||||
|
||||
|
||||
--root-c-base: #ecf0f1;
|
||||
--root-c-base-highlight: #bdc3c7;
|
||||
|
||||
--root-c-primary: #1abc9c;
|
||||
--root-c-primary-highlight: #16a085;
|
||||
|
||||
--root-c-secondary: #9b59b6;
|
||||
--root-c-secondary-highlight: #8e44ad;
|
||||
|
||||
--root-c-black: #2c3e50;
|
||||
--root-c-black-highlight: #34495e;
|
||||
|
||||
|
||||
--c-base: var(--root-c-base);
|
||||
--c-base-highlight: var(--root-c-base-highlight);
|
||||
|
||||
--c-primary:var(--root-c-primary);
|
||||
--c-primary-highlight: var(--root-c-primary-highlight);
|
||||
|
||||
--c-secondary: var(--c-secondary);
|
||||
--c-secondary-highlight: var(--root-c-secondary-highlight);
|
||||
|
||||
--c-black: var(--root-c-black);
|
||||
--c-black-highlight: var(--root-c-black-highlight);
|
||||
}
|
||||
|
||||
.primary {
|
||||
--c-base: var(--root-c-base);
|
||||
--c-base-highlight: var(--root-c-base-highlight);
|
||||
|
||||
--c-primary:var(--root-c-primary);
|
||||
--c-primary-highlight: var(--root-c-primary-highlight);
|
||||
|
||||
--c-secondary: var(--c-secondary);
|
||||
--c-secondary-highlight: var(--root-c-secondary-highlight);
|
||||
|
||||
--c-black: var(--root-c-black);
|
||||
--c-black: var(--root-c-black-highlight);
|
||||
}
|
||||
|
||||
.secondary {
|
||||
--c-base: var(--root-c-base);
|
||||
--c-base-highlight: var(--root-c-base-highlight);
|
||||
|
||||
--c-primary:var(--root-c-secondary);
|
||||
--c-primary-highlight: var(--root-c-secondary-highlight);
|
||||
|
||||
--c-secondary: var(--root-c-primary);
|
||||
--c-secondary-highlight: var(--root-c-primary-highlight);
|
||||
|
||||
--c-black: var(--root-c-black);
|
||||
--c-black-highlight: var(--root-c-black-highlight);
|
||||
}
|
||||
|
||||
.inverted {
|
||||
--c-base: var(--root-c-black);
|
||||
--c-base-highlight: var(--root-c-black-highlight);
|
||||
|
||||
--c-primary:var(--root-c-primary);
|
||||
--c-primary-highlight: var(--root-c-primary-highlight);
|
||||
|
||||
--c-secondary: var(--c-secondary);
|
||||
--c-secondary-highlight: var(--root-c-secondary-highlight);
|
||||
|
||||
--c-black: var(--root-c-base);
|
||||
--c-black-highlight: var(--root-c-base-highlight);
|
||||
}
|
||||
|
||||
|
||||
* {
|
||||
margin: 0em;
|
||||
padding: 0em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
font-size: var(--u0);
|
||||
height: 100%;
|
||||
background-color: var(--c-base);
|
||||
color: var(--c-black)
|
||||
}
|
||||
|
||||
main {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-family: "Fira Mono";
|
||||
padding-top: 1em;
|
||||
padding-bottom: 0.618em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
p {
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: var(--u2);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: var(--u1);
|
||||
}
|
||||
|
||||
h3, h4, h5 {
|
||||
font-size: var(--u0);
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table td,
|
||||
table th {
|
||||
padding: var(--u0);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table th {
|
||||
background-color: var(--c-primary);
|
||||
color: var(--c-base);
|
||||
}
|
||||
|
||||
table tr:nth-child(2n+1) {
|
||||
background-color: var(--c-base-highlight);
|
||||
}
|
||||
|
||||
/*
|
||||
* NAV
|
||||
*/
|
||||
|
||||
nav {
|
||||
|
||||
}
|
||||
|
||||
nav h1 {
|
||||
font-size: var(--u0);
|
||||
margin: 0rem;
|
||||
}
|
||||
|
||||
nav li {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
nav li li {
|
||||
margin-left: var(--u0);
|
||||
}
|
||||
|
||||
nav li a {
|
||||
padding: var(--u0);
|
||||
transition: all 0.1s ease-out;
|
||||
}
|
||||
|
||||
nav li a:hover,
|
||||
nav li a.selected {
|
||||
padding: var(--u0);
|
||||
background-color: var(--c-primary);
|
||||
color: var(--c-base);
|
||||
}
|
||||
/*
|
||||
* FOOTER
|
||||
*/
|
||||
|
||||
footer {
|
||||
padding-top: var(--u3);
|
||||
padding-bottom: var(--u1);
|
||||
}
|
||||
|
||||
/*
|
||||
* INPUTS
|
||||
*/
|
||||
|
||||
form * {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="password"] {
|
||||
|
||||
background-color: var(--c-base);
|
||||
|
||||
border: none;
|
||||
|
||||
border-radius: var(--u-2);
|
||||
margin-top: var(--u0);
|
||||
margin-bottom: var(--u0);
|
||||
|
||||
padding: var(--u0);
|
||||
font-size: var(--u0);
|
||||
color: var(--c-black);
|
||||
|
||||
/* box-shadow: var(--s-0-secondary); */
|
||||
}
|
||||
|
||||
input[type="text"]::placeholder,
|
||||
input[type="password"]::placeholder {
|
||||
color: var(--c-primary-highlight);
|
||||
opacity: 50%;
|
||||
}
|
||||
|
||||
button, .button {
|
||||
font-family: "Fira Mono";
|
||||
font-weight: bold;
|
||||
|
||||
background-color: var(--c-primary);
|
||||
color: var(--c-base);
|
||||
|
||||
border: none;
|
||||
border-radius: var(--u-2);
|
||||
|
||||
margin-bottom: var(--u0);
|
||||
margin-top: var(--u0);
|
||||
|
||||
padding: var(--u0);
|
||||
|
||||
min-width: 10em;
|
||||
|
||||
font-family: "Fira Mono";
|
||||
text-transform: uppercase;
|
||||
font-size: var(--u0);
|
||||
|
||||
/* box-shadow: var(--s-0-secondary); */
|
||||
}
|
||||
|
||||
button:active, .button:active {
|
||||
background-color: var(--c-primary-highlight);
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="password"],
|
||||
button,
|
||||
.button {
|
||||
transition: all 0.1s ease-out;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
min-width: 10em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/*
|
||||
* HERO
|
||||
*/
|
||||
|
||||
.hero {
|
||||
background-color: var(--c-primary);
|
||||
color: var(--c-base);
|
||||
}
|
||||
|
||||
.hero-black {
|
||||
background-color: var(--c-black);
|
||||
color: var(--c-base);
|
||||
}
|
||||
|
||||
/*
|
||||
* LAYOUT
|
||||
*/
|
||||
|
||||
.content-width {
|
||||
max-width: 80rem;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
padding-left: var(--u0);
|
||||
padding-right: var(--u0);
|
||||
}
|
||||
|
||||
.bar-flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.bar-flex > * {
|
||||
margin: var(--u0);
|
||||
}
|
||||
|
||||
.bar-flex > .spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sidebar-layout {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.sidebar-layout > *:nth-child(2) {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.grid.vertical-center {
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.grid.center {
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.grid > * {
|
||||
flex: 1;
|
||||
margin: var(--u0);
|
||||
padding: var(--u0);
|
||||
border-radius: var(--u0);
|
||||
}
|
||||
|
||||
.grid.base > * {
|
||||
background-color: var(--c-base);
|
||||
color: var(--c-black);
|
||||
}
|
||||
|
||||
.grid.black > * {
|
||||
background-color: var(--c-black);
|
||||
color: var(--c-base);
|
||||
}
|
||||
|
||||
.grid.primary > * {
|
||||
background-color: var(--c-primary);
|
||||
color: var(--c-base);
|
||||
}
|
||||
|
||||
.grid.secondary > * {
|
||||
background-color: var(--c-primary-highlight);
|
||||
color: var(--c-base);
|
||||
}
|
||||
|
||||
.hero-primary .grid.shadow > * {
|
||||
/* box-shadow: var(--s-0-secondary); */
|
||||
}
|
||||
|
||||
.hero-black .grid.shadow > * {
|
||||
/* box-shadow: var(--s-0-secondary); */
|
||||
}
|
||||
|
||||
.grid.s > .spacer {
|
||||
box-shadow: none;
|
||||
|
||||
margin: calc(var(--u0) * 2);
|
||||
padding: 0px;
|
||||
|
||||
width: 10rem;
|
||||
max-width: 10rem;
|
||||
min-width: 7.5rem;
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.grid.s > * {
|
||||
max-width: 10rem;
|
||||
min-width: 7.5rem;
|
||||
}
|
||||
|
||||
|
||||
.grid.m > .spacer {
|
||||
box-shadow: none;
|
||||
|
||||
margin: calc(var(--u0) * 2);
|
||||
padding: 0px;
|
||||
|
||||
width: 20rem;
|
||||
max-width: 20rem;
|
||||
min-width: 15rem;
|
||||
height: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.grid.m > * {
|
||||
width: 20rem;
|
||||
max-width: 20rem;
|
||||
min-width: 15rem;
|
||||
}
|
||||
|
||||
.grid.l > .spacer {
|
||||
box-shadow: none;
|
||||
|
||||
margin: calc(var(--u0) * 2);
|
||||
padding: 0px;
|
||||
|
||||
width: 40rem;
|
||||
max-width: 40rem;
|
||||
min-width: 15rem;
|
||||
height: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.grid.l > * {
|
||||
width: 40rem;
|
||||
max-width: 40rem;
|
||||
min-width: 15rem;
|
||||
}
|
||||
|
||||
.vertical-spacer.s {
|
||||
min-height: 10rem;
|
||||
}
|
||||
|
||||
.vertical-spacer.m {
|
||||
min-height: 20rem;
|
||||
}
|
||||
|
||||
.vertical-spacer.l {
|
||||
min-height: 40rem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Impov
|
||||
*/
|
||||
|
||||
.input-icon {
|
||||
/* box-shadow: var(--s-0-secondary); */
|
||||
display: flex;
|
||||
padding: 0px;
|
||||
|
||||
border-radius: var(--u0);
|
||||
}
|
||||
|
||||
.input-icon > input {
|
||||
flex: 1;
|
||||
margin: 0px;
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.input-icon > button {
|
||||
margin: 0px;
|
||||
|
||||
border-top-left-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CONTENT
|
||||
*/
|
||||
|
||||
.price {
|
||||
opacity: 75%;
|
||||
font-size: var(--u1);
|
||||
text-align: right;
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Frontpage</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/ecom.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
</head>
|
||||
<body>
|
||||
<nav class='hero'>
|
||||
<div class='content-width bar-flex'>
|
||||
<h1>Project eCommerce</h1>
|
||||
<button>Angebote</button>
|
||||
<div class='spacer input-icon secondary'>
|
||||
<input type="text" placeholder="Nach Produkten suchen..."/>
|
||||
<button>Finden</button>
|
||||
</div>
|
||||
<button>Login</button>
|
||||
</div>
|
||||
</nav>
|
||||
<main>
|
||||
<div class='hero'>
|
||||
<div class='content-width'>
|
||||
<h1>Angebote</h1>
|
||||
<div class='grid m base shadow'>
|
||||
|
||||
<section>
|
||||
<img src="pics/product-1.jpg">
|
||||
<h2>Lorem Ipsum</h2>
|
||||
<p class='price'> 25.14 €</p>
|
||||
<p>
|
||||
Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<img src="pics/product-2.jpg">
|
||||
<h2>Lorem Ipsum</h2>
|
||||
<p class='price'> 10.14 €</p>
|
||||
<p>
|
||||
Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<img src="pics/product-1.jpg">
|
||||
<h2>Lorem Ipsum</h2>
|
||||
<p class='price'> 25.14 €</p>
|
||||
<p>
|
||||
Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<img src="pics/product-2.jpg">
|
||||
<h2>Lorem Ipsum</h2>
|
||||
<p class='price'> 10.14 €</p>
|
||||
<p>
|
||||
Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<img src="pics/product-3.jpg">
|
||||
<h2>Lorem Ipsum</h2>
|
||||
<p class='price'> 44.14 €</p>
|
||||
<p>
|
||||
|
||||
Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte.
|
||||
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="spacer"></section>
|
||||
<section class="spacer"></section>
|
||||
<section class="spacer"></section>
|
||||
<section class="spacer"></section>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vertical-spacer s"></div>
|
||||
</div>
|
||||
|
||||
<div class=''>
|
||||
<div class='content-width'>
|
||||
<h1>Personalisierte Empfehlungen</h1>
|
||||
<div class="grid l">
|
||||
<img src="undraw/undraw_successful_purchase_secondary.svg"/>
|
||||
<div>
|
||||
<h2>Werde jetzt Kunde</h2>
|
||||
<p> Jetzt Kunde werden und viele Vorteile sichern,
|
||||
wie z.B. personalisierte Empfehlungen. </p>
|
||||
<button>Registieren</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vertical-spacer s"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="hero-black">
|
||||
<div class='content-width bar-flex'>
|
||||
<h3>Project eCommerce</h3>
|
||||
<div class="spacer"></div>
|
||||
<div>
|
||||
<h4>Seite</h4>
|
||||
<ul>
|
||||
<li><a>Login</a></li>
|
||||
<li><a>Angebote</a></li>
|
||||
<li><a>Suche</a></li>
|
||||
<li><a>Mitarbeiter Login</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Mehr</h4>
|
||||
<ul>
|
||||
<li><a>Nutzungsbedingungen</a></li>
|
||||
<li><a>Datenschutz</a></li>
|
||||
<li><a>Über</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,158 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Frontpage</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/ecom.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
</head>
|
||||
<body>
|
||||
<nav class='hero'>
|
||||
<div class='content-width bar-flex'>
|
||||
<h1>Project eCommerce</h1>
|
||||
<button>Angebote</button>
|
||||
<div class='spacer input-icon secondary'>
|
||||
<input type="text" placeholder="Nach Produkten suchen..."/>
|
||||
<button>Finden</button>
|
||||
</div>
|
||||
<button>Login</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="sidebar-layout content-width">
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a>Dashboard</a>
|
||||
<ul>
|
||||
<li><a>Artikel</a></li>
|
||||
<li><a>Umsatzsteuer</a></li>
|
||||
<li><a class='selected'>Geldbuchungen</a></li>
|
||||
<li><a>Einstellungen</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a>Lieferanten</a>
|
||||
<ul>
|
||||
<li><a>Warenbuchungen</a></li>
|
||||
<li><a>Geldbuchungen</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a>Lager</a>
|
||||
<ul>
|
||||
<li><a>Bestandsbuchungen</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a>Kunden</a>
|
||||
<ul>
|
||||
<li><a>Bestellungen</a></li>
|
||||
<li><a>Geldbuchungen</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div class="content-width">
|
||||
<h1>Geldbuchungen</h1>
|
||||
<p>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Datum</th>
|
||||
<th>Betrag</th>
|
||||
<th>Gegenkonto</th>
|
||||
<th>Betreff</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>#100</td>
|
||||
<td>2019-10-08</td>
|
||||
<td>100,50 €</td>
|
||||
<td>Lieferant: Hans</td>
|
||||
<td>Bestellungen: #41</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>#100</td>
|
||||
<td>2019-10-08</td>
|
||||
<td>100,50 €</td>
|
||||
<td>Lieferant: Hans</td>
|
||||
<td>Bestellungen: #41</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>#100</td>
|
||||
<td>2019-10-08</td>
|
||||
<td>100,50 €</td>
|
||||
<td>Lieferant: Hans</td>
|
||||
<td>Bestellungen: #41</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>#100</td>
|
||||
<td>2019-10-08</td>
|
||||
<td>100,50 €</td>
|
||||
<td>Lieferant: Hans</td>
|
||||
<td>Bestellungen: #41</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>#100</td>
|
||||
<td>2019-10-08</td>
|
||||
<td>100,50 €</td>
|
||||
<td>Lieferant: Hans</td>
|
||||
<td>Bestellungen: #41</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>#100</td>
|
||||
<td>2019-10-08</td>
|
||||
<td>100,50 €</td>
|
||||
<td>Lieferant: Hans</td>
|
||||
<td>Bestellungen: #41</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>#100</td>
|
||||
<td>2019-10-08</td>
|
||||
<td>100,50 €</td>
|
||||
<td>Lieferant: Hans</td>
|
||||
<td>Bestellungen: #41</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>#100</td>
|
||||
<td>2019-10-08</td>
|
||||
<td>100,50 €</td>
|
||||
<td>Lieferant: Hans</td>
|
||||
<td>Bestellungen: #41</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>#100</td>
|
||||
<td>2019-10-08</td>
|
||||
<td>100,50 €</td>
|
||||
<td>Lieferant: Hans</td>
|
||||
<td>Bestellungen: #41</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<p>
|
||||
<a class="button">Manuelle Buchung</a>
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="hero-black">
|
||||
<div class='content-width bar-flex'>
|
||||
<h3>Project eCommerce</h3>
|
||||
<div class="spacer"></div>
|
||||
<div>
|
||||
<h4>Seite</h4>
|
||||
<ul>
|
||||
<li><a>Login</a></li>
|
||||
<li><a>Angebote</a></li>
|
||||
<li><a>Suche</a></li>
|
||||
<li><a>Mitarbeiter Login</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Mehr</h4>
|
||||
<ul>
|
||||
<li><a>Nutzungsbedingungen</a></li>
|
||||
<li><a>Datenschutz</a></li>
|
||||
<li><a>Über</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
@ -1,48 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Frontpage</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/ecom.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
</head>
|
||||
<body>
|
||||
<div class='grid m center vertical-center'>
|
||||
<form class='hero primary'>
|
||||
<p>
|
||||
<label>Nutzername</label>
|
||||
<input type="text" placeholder=""/>
|
||||
</p>
|
||||
<p>
|
||||
<label>Passwort</label>
|
||||
<input type="password" placeholder=""/>
|
||||
</p>
|
||||
<button class='secondary'>Login</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<footer class="hero-black">
|
||||
<div class='content-width bar-flex'>
|
||||
<h3>Project eCommerce</h3>
|
||||
<div class="spacer"></div>
|
||||
<div>
|
||||
<h4>Seite</h4>
|
||||
<ul>
|
||||
<li><a>Login</a></li>
|
||||
<li><a>Angebote</a></li>
|
||||
<li><a>Suche</a></li>
|
||||
<li><a>Mitarbeiter Login</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Mehr</h4>
|
||||
<ul>
|
||||
<li><a>Nutzungsbedingungen</a></li>
|
||||
<li><a>Datenschutz</a></li>
|
||||
<li><a>Über</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 20 KiB |
@ -1,11 +0,0 @@
|
||||
package org.hso.ecommerce.action.shop;
|
||||
|
||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
||||
|
||||
public class EnableTrackingAction {
|
||||
|
||||
public static void addTrackingInfo(CustomerOrder customerOrder) {
|
||||
// TODO:
|
||||
customerOrder.trackingId = "555-NASE";
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package org.hso.ecommerce.app;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
/**
|
||||
* TODO clean up this class
|
||||
*/
|
||||
@Controller
|
||||
public class RequestController {
|
||||
|
||||
@GetMapping("/intern/customerOrders/")
|
||||
public String internCustomerOrder() {
|
||||
return "intern/customerOrders/index";
|
||||
}
|
||||
|
||||
@GetMapping("/intern/customerOrders/{id}")
|
||||
public String internCustomerOrdersId() {
|
||||
return "intern/customerOrders/id";
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package org.hso.ecommerce.components;
|
||||
|
||||
import org.hso.ecommerce.entities.warehouse.Slot;
|
||||
import org.hso.ecommerce.repos.warehouse.SlotRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Component
|
||||
public class SlotInitializer {
|
||||
|
||||
@Autowired
|
||||
private final SlotRepository slotRepository = null;
|
||||
|
||||
// TODO: use values form cfg.
|
||||
private final int NUM_SLOTS = 50;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
for (int i = 1; i <= NUM_SLOTS; i++) {
|
||||
if (!slotRepository.findBySlotNum(i).isPresent()) {
|
||||
Slot slotAdded = new Slot();
|
||||
slotAdded.slotNum = i;
|
||||
slotRepository.save(slotAdded);
|
||||
System.out.println("Added Slot " + i + " to DB");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,388 +0,0 @@
|
||||
package org.hso.ecommerce.controller.cronjob;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
import org.hso.ecommerce.action.cronjob.ReorderAction;
|
||||
import org.hso.ecommerce.action.cronjob.UpdateOffersAction;
|
||||
import org.hso.ecommerce.entities.booking.Booking;
|
||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
|
||||
import org.hso.ecommerce.entities.booking.BookingReason;
|
||||
import org.hso.ecommerce.entities.cron.BackgroundJob;
|
||||
import org.hso.ecommerce.entities.shop.Article;
|
||||
import org.hso.ecommerce.entities.supplier.ArticleOffer;
|
||||
import org.hso.ecommerce.entities.supplier.Supplier;
|
||||
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.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.warehouse.WarehouseBookingPositionSlotEntryRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
interface ICronjob {
|
||||
/**
|
||||
* Calculate the earliest cronjob execution time that happens after the given reference time.
|
||||
*
|
||||
* @param reference Position in time to start searching. The implementor is allowed to modify the reference time.
|
||||
* @return A new Calendar instance (or the same) containing the time for next execution.
|
||||
*/
|
||||
Calendar nextExecution(Calendar reference);
|
||||
|
||||
/**
|
||||
* Calculate the latest cronjob execution time that happens before or exactly at the given refernce time.
|
||||
*
|
||||
* @param reference Position in time to start searching. The implementor is allowed to modify the reference time.
|
||||
* @return A new Calendar instance (or the same) containing the time of the last execution.
|
||||
*/
|
||||
Calendar previousExecution(Calendar reference);
|
||||
|
||||
/**
|
||||
* Execute this cronjob.
|
||||
*
|
||||
* @param time The point in time this execution was scheduled. In case of a missed cronjob, the actual time of
|
||||
* this call might be much later.
|
||||
* @param controller Back-reference that allows to use repositories.
|
||||
*/
|
||||
void executeAt(Calendar time, CronjobController controller);
|
||||
|
||||
/**
|
||||
* Get a name for this cronjob, that can be presented to the user in the frontend.
|
||||
*
|
||||
* @return A german name of this cronjob.
|
||||
*/
|
||||
String getDisplayName();
|
||||
}
|
||||
|
||||
@Component
|
||||
class Reorder implements ICronjob {
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Nachbestellung";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar nextExecution(Calendar reference) {
|
||||
if (reference.get(Calendar.HOUR_OF_DAY) >= 8) {
|
||||
reference.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
reference.set(Calendar.HOUR_OF_DAY, 8);
|
||||
reference.set(Calendar.MINUTE, 0);
|
||||
reference.set(Calendar.SECOND, 0);
|
||||
reference.set(Calendar.MILLISECOND, 0);
|
||||
return reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar previousExecution(Calendar reference) {
|
||||
if (reference.get(Calendar.HOUR_OF_DAY) < 8) {
|
||||
reference.add(Calendar.DAY_OF_MONTH, -1);
|
||||
}
|
||||
reference.set(Calendar.HOUR_OF_DAY, 8);
|
||||
reference.set(Calendar.MINUTE, 0);
|
||||
reference.set(Calendar.SECOND, 0);
|
||||
reference.set(Calendar.MILLISECOND, 0);
|
||||
return reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the amount of ordered articles by customers for the given article type in the time between begin and
|
||||
* end.
|
||||
*
|
||||
* @param article The article to search orders for.
|
||||
* @param begin The start time for the search (included)
|
||||
* @param end The end time for the search (excluded)
|
||||
* @return The number of articles that were ordered by customers in the given range.
|
||||
*/
|
||||
private Integer getOrderedAmounts(Article article, Calendar begin, Calendar end, CronjobController controller) {
|
||||
return controller.customerOrderRepository.countOrdersOfArticleInTimespan(
|
||||
article.id,
|
||||
new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the amount of ordered articles by customers for the given article type in the three days before the
|
||||
* given reference time. The return-array contains 3 fields: Index 0: Orders 72 to 48 hours ago; Index 1: Orders 48
|
||||
* to 24 hours ago; Index 2: Orders 24 to 0 hours ago.
|
||||
*
|
||||
* @param article The article for which the customer orders are checked.
|
||||
* @param time The reference time to use for calculation of the last orders.
|
||||
* @return A 3-element array containing the orders of the last three days.
|
||||
*/
|
||||
private Integer[] getOrderedAmounts(Article article, Calendar time, CronjobController controller) {
|
||||
Calendar oneDayBefore = (Calendar) time.clone();
|
||||
oneDayBefore.add(Calendar.DAY_OF_MONTH, -1);
|
||||
Calendar twoDaysBefore = (Calendar) time.clone();
|
||||
twoDaysBefore.add(Calendar.DAY_OF_MONTH, -2);
|
||||
Calendar threeDaysBefore = (Calendar) time.clone();
|
||||
threeDaysBefore.add(Calendar.DAY_OF_MONTH, -3);
|
||||
|
||||
return new Integer[] { //
|
||||
getOrderedAmounts(article, threeDaysBefore, twoDaysBefore, controller), //
|
||||
getOrderedAmounts(article, twoDaysBefore, oneDayBefore, controller), //
|
||||
getOrderedAmounts(article, oneDayBefore, time, controller), //
|
||||
};
|
||||
}
|
||||
|
||||
private HashMap<ArticleIdentifier, ArticleOffer> mapArticleOffers(List<ArticleOffer> articleOffers) {
|
||||
HashMap<ArticleIdentifier, ArticleOffer> map = new HashMap<>();
|
||||
for (ArticleOffer articleOffer : articleOffers) {
|
||||
ArticleIdentifier identifier = new ArticleIdentifier(articleOffer.manufacturer, articleOffer.articleNumber);
|
||||
map.put(identifier, articleOffer);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeAt(Calendar time, CronjobController controller) {
|
||||
List<Supplier> suppliers = controller.supplierRepository.findAll();
|
||||
ReadSupplierDataAction.Result supplierData = new ReadSupplierDataAction(suppliers).finish();
|
||||
|
||||
// Save the new offers in the database
|
||||
List<ArticleOffer> allOffers = controller.articleOfferRepository.findAll();
|
||||
allOffers = new UpdateOffersAction(allOffers, supplierData.cheapestOffer).finish();
|
||||
controller.articleOfferRepository.saveAll(allOffers);
|
||||
|
||||
HashMap<ArticleIdentifier, ArticleOffer> mappedOffers = mapArticleOffers(allOffers);
|
||||
|
||||
// Reorder
|
||||
List<Article> allArticles = controller.articleRepository.findAll();
|
||||
for (Article article : allArticles) {
|
||||
Integer[] orderedAmounts = getOrderedAmounts(article, time, controller);
|
||||
|
||||
Integer undeliveredReorders = controller.supplierOrderRepository
|
||||
.countUndeliveredReorders(article.related.articleNumber);
|
||||
|
||||
int amountInStock = controller.warehouseBookingPositionSlotEntryRepository.getArticleStock(article.id)
|
||||
.orElse(0);
|
||||
|
||||
ReorderAction action = new ReorderAction(article, orderedAmounts,
|
||||
undeliveredReorders,
|
||||
amountInStock,
|
||||
supplierData.cheapestOffer, mappedOffers);
|
||||
SupplierOrder order = action.finish();
|
||||
if (order != null) {
|
||||
controller.supplierOrderRepository.save(order);
|
||||
|
||||
// Create bookings for this order
|
||||
int netPrice = order.totalPriceNet;
|
||||
int vatPercent = order.ordered.vatPercent;
|
||||
int vatAmount = netPrice * vatPercent / 100;
|
||||
int grossPrice = netPrice + vatAmount;
|
||||
|
||||
// Obligation towards the supplier
|
||||
BookingAccountEntry mainAccount = controller.bookingAccountEntryRepository.getByMain()
|
||||
.orElseGet(BookingAccountEntry::newMain);
|
||||
BookingAccountEntry supplierAccount = controller.bookingAccountEntryRepository
|
||||
.getBySupplier(order.supplier.id)
|
||||
.orElseGet(() -> BookingAccountEntry.newSupplier(order.supplier));
|
||||
BookingReason obligationReason = new BookingReason(order);
|
||||
Booking obligationBooking = new CreateBookingAction(mainAccount,
|
||||
supplierAccount,
|
||||
obligationReason,
|
||||
grossPrice).finish();
|
||||
controller.bookingRepository.save(obligationBooking);
|
||||
|
||||
// Input Tax
|
||||
BookingAccountEntry vatAccount = controller.bookingAccountEntryRepository.getByVat()
|
||||
.orElseGet(BookingAccountEntry::newVat);
|
||||
mainAccount = controller.bookingAccountEntryRepository.getByMain().get();
|
||||
BookingReason inputTaxReason = new BookingReason(order);
|
||||
Booking inputTaxBooking = new CreateBookingAction(vatAccount, mainAccount, inputTaxReason, vatAmount)
|
||||
.finish();
|
||||
controller.bookingRepository.save(inputTaxBooking);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ScheduledCronjob {
|
||||
public final Calendar executionTime;
|
||||
public final ICronjob cronjob;
|
||||
public final BackgroundJob model;
|
||||
|
||||
public ScheduledCronjob(Calendar executionTime, ICronjob cronjob, BackgroundJob model) {
|
||||
this.executionTime = executionTime;
|
||||
this.cronjob = cronjob;
|
||||
this.model = model;
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
@RequestMapping("intern/cronjobs")
|
||||
class CronjobController {
|
||||
private static final Logger log = LoggerFactory.getLogger(CronjobController.class);
|
||||
|
||||
private static final Map<String, ICronjob> cronjobs = getCronjobs();
|
||||
|
||||
@Autowired
|
||||
private final BackgroundJobRepository cronjobRepository = null;
|
||||
|
||||
@Autowired
|
||||
final ArticleRepository articleRepository = null;
|
||||
|
||||
@Autowired
|
||||
final ArticleOfferRepository articleOfferRepository = null;
|
||||
|
||||
@Autowired
|
||||
final CustomerOrderRepository customerOrderRepository = null;
|
||||
|
||||
@Autowired
|
||||
final BookingRepository bookingRepository = null;
|
||||
|
||||
@Autowired
|
||||
final BookingAccountEntryRepository bookingAccountEntryRepository = null;
|
||||
|
||||
@Autowired
|
||||
final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
|
||||
|
||||
@Autowired
|
||||
final SupplierRepository supplierRepository = null;
|
||||
|
||||
@Autowired
|
||||
final SupplierOrderRepository supplierOrderRepository = null;
|
||||
|
||||
private static Map<String, ICronjob> getCronjobs() {
|
||||
HashMap<String, ICronjob> map = new HashMap<>();
|
||||
|
||||
// Register all existing cronjobs
|
||||
map.put(BackgroundJob.JOB_REORDER, new Reorder());
|
||||
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
private ScheduledCronjob getNextCronjob() {
|
||||
Calendar currentTime = new GregorianCalendar();
|
||||
Iterable<BackgroundJob> jobs = cronjobRepository.findAll();
|
||||
HashMap<String, BackgroundJob> alreadyExecuted = new HashMap<>();
|
||||
for (BackgroundJob job : jobs) {
|
||||
alreadyExecuted.put(job.jobName, job);
|
||||
}
|
||||
ScheduledCronjob earliestJob = null;
|
||||
for (Entry<String, ICronjob> entry : cronjobs.entrySet()) {
|
||||
ScheduledCronjob resultingJob;
|
||||
BackgroundJob dbEntry = alreadyExecuted.get(entry.getKey());
|
||||
if (dbEntry != null) {
|
||||
Calendar previousExecution = new GregorianCalendar();
|
||||
previousExecution.setTimeInMillis(dbEntry.lastExecution.getTime());
|
||||
Calendar followingSchedule = entry.getValue().nextExecution((Calendar) previousExecution.clone());
|
||||
Calendar lastSchedule = entry.getValue().previousExecution((Calendar) currentTime.clone());
|
||||
if (lastSchedule.getTimeInMillis() > followingSchedule.getTimeInMillis()) {
|
||||
// This happens, if more than one execution was missed.
|
||||
// In this case, run the job only once.
|
||||
followingSchedule = lastSchedule;
|
||||
}
|
||||
resultingJob = new ScheduledCronjob(followingSchedule, entry.getValue(), dbEntry);
|
||||
} else {
|
||||
// This cronjob has never been executed before.
|
||||
Calendar lastScheduleTime = entry.getValue().previousExecution((Calendar) currentTime.clone());
|
||||
BackgroundJob model = new BackgroundJob();
|
||||
model.jobName = entry.getKey();
|
||||
resultingJob = new ScheduledCronjob(lastScheduleTime, entry.getValue(), model);
|
||||
}
|
||||
|
||||
// Look for the job with earliest executionTime - it will run next
|
||||
if (earliestJob == null
|
||||
|| resultingJob.executionTime.getTimeInMillis() < earliestJob.executionTime.getTimeInMillis()) {
|
||||
earliestJob = resultingJob;
|
||||
}
|
||||
}
|
||||
return earliestJob;
|
||||
}
|
||||
|
||||
private void runCronjobExecutionLoop() {
|
||||
Thread.currentThread().setName("Cronjob");
|
||||
try {
|
||||
while (true) {
|
||||
ScheduledCronjob nextJob = getNextCronjob();
|
||||
if (nextJob == null) {
|
||||
// In case there are no cronjobs
|
||||
return;
|
||||
}
|
||||
long waitingTime = nextJob.executionTime.getTimeInMillis() - System.currentTimeMillis();
|
||||
if (waitingTime > 0) {
|
||||
Thread.sleep(waitingTime);
|
||||
}
|
||||
|
||||
try {
|
||||
nextJob.cronjob.executeAt(nextJob.executionTime, this);
|
||||
} catch (Throwable t) {
|
||||
log.error("Failed to execute cronjob " + nextJob.cronjob.getClass() + ":");
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
nextJob.model.lastExecution = new Timestamp(nextJob.executionTime.getTimeInMillis());
|
||||
cronjobRepository.save(nextJob.model);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
log.error("The cronjob execution thread has been interrupted");
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void onPostConstruct() {
|
||||
new Thread(this::runCronjobExecutionLoop).start();
|
||||
}
|
||||
|
||||
class ManualCronjob {
|
||||
public final String identifier;
|
||||
public final String visibleName;
|
||||
|
||||
public ManualCronjob(String identifier, String visibleName) {
|
||||
this.identifier = identifier;
|
||||
this.visibleName = visibleName;
|
||||
}
|
||||
}
|
||||
|
||||
private List<ManualCronjob> listAllCronjobs() {
|
||||
ArrayList<ManualCronjob> entries = new ArrayList<>();
|
||||
for (Entry<String, ICronjob> job : cronjobs.entrySet()) {
|
||||
entries.add(new ManualCronjob(job.getKey(), job.getValue().getDisplayName()));
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String cronjobOverview(Model model) {
|
||||
model.addAttribute("jobs", listAllCronjobs());
|
||||
return "intern/cronjobs/index";
|
||||
}
|
||||
|
||||
@PostMapping("/run/{identifier}")
|
||||
public String runCronjob(Model model, @PathVariable("identifier") String identifier) {
|
||||
ICronjob jobToExecute = cronjobs.get(identifier);
|
||||
if (jobToExecute != null) {
|
||||
jobToExecute.executeAt(new GregorianCalendar(), this);
|
||||
model.addAttribute("info",
|
||||
String.format("Der Cronjob \"%s\" wurde ausgeführt.", jobToExecute.getDisplayName()));
|
||||
} else {
|
||||
model.addAttribute("error", "Der Cronjob konnte nicht gefunden werden.");
|
||||
}
|
||||
model.addAttribute("jobs", listAllCronjobs());
|
||||
return "intern/cronjobs/index";
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package org.hso.ecommerce.controller.intern.customers;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
@Controller
|
||||
//@RequestMapping("...")
|
||||
public class CustomerOrderController {
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
package org.hso.ecommerce.entities.warehouse;
|
||||
|
||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
||||
import org.hso.ecommerce.entities.supplier.SupplierOrder;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "warehouse_booking_reasons")
|
||||
public class WarehouseBookingReason {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Basic
|
||||
public long id;
|
||||
|
||||
public String comment;
|
||||
|
||||
@ManyToOne(optional = true)
|
||||
public SupplierOrder causeSupplierOrder;
|
||||
|
||||
@ManyToOne(optional = true)
|
||||
public CustomerOrder customerOrder;
|
||||
|
||||
public boolean isManuel;
|
||||
|
||||
// Default Constructor is needed for construction by ORM
|
||||
public WarehouseBookingReason() {
|
||||
}
|
||||
|
||||
public WarehouseBookingReason(CustomerOrder order) {
|
||||
this.customerOrder = order;
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package org.hso.ecommerce.repos.warehouse;
|
||||
|
||||
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface WarehouseBookingPositionSlotEntryRepository extends JpaRepository<WarehouseBookingPositionSlotEntry, Long> {
|
||||
|
||||
@Query(value = "Select e.id, e.article_id, e.new_sum_slot, e.slot_id from warehouse_booking_position_entries as e, warehouse_slots as s where e.slot_id = s.id AND e.article_id = :article GROUP BY s.slot_num HAVING max(e.id)", nativeQuery = true)
|
||||
List<WarehouseBookingPositionSlotEntry> getByArticle(long article);
|
||||
|
||||
@Query(value = "SELECT SUM(w.new_sum_slot) FROM warehouse_booking_position_entries as w WHERE w.article_id = :articleid", nativeQuery = true)
|
||||
Optional<Integer> getArticleStock(long articleid);
|
||||
|
||||
@Query(value = "Select e.id, e.article_id, e.new_sum_slot, e.slot_id from warehouse_booking_position_entries as e, warehouse_slots as s where e.slot_id = s.id AND s.slot_num = :slotnum GROUP BY s.slot_num HAVING max(e.id)", nativeQuery = true)
|
||||
Optional<WarehouseBookingPositionSlotEntry> getBySlotNum(long slotnum);
|
||||
|
||||
}
|
||||
|
@ -1,118 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
|
||||
|
||||
<title>Artikelübersicht</title>
|
||||
<script th:src="@{/js/filterTable.js}"></script>
|
||||
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav th:replace="fragments/header :: header">Header</nav>
|
||||
<div class="sidebar-layout content-width">
|
||||
<nav></nav>
|
||||
<div>
|
||||
<h1>Bestellung 1010</h1>
|
||||
|
||||
<script th:src="@{/js/back.js}"></script>
|
||||
<div class="back" data-group="intern" data-insert="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
<main class="sidebar-layout content-width">
|
||||
<nav th:replace="fragments/intern :: sidebar"></nav>
|
||||
<div class="content-width">
|
||||
<div>
|
||||
<h2 id="20202701"> Bestellung vom 27.01.2020 </h2>
|
||||
<div>
|
||||
<table class="key-value">
|
||||
<tr>
|
||||
<th>Nutzer</th>
|
||||
<td><a th:href="@{/intern/customers/498}">K-4850</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Lieferstatus</th>
|
||||
<td><b>Unterwegs</b> <br/> Vorraussichtliche Ankunft: 29.01.2020</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Sendeverfolgungsnummer</th>
|
||||
<td>XE51451436DE</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td>
|
||||
Hans Maier <br/>
|
||||
Hauptstraße 12<br/>
|
||||
74880 Musterstadt<br/>
|
||||
Deutschland <br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Eingelösste Bonuspunkte</th>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Bild</th>
|
||||
<th>Name</th>
|
||||
<th>Menge</th>
|
||||
<th>Preis (Brutto)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-1.jpg}" class="s"/></a></td>
|
||||
<td><a th:href="@{/shop/articles/4151}">Kamera</a></td>
|
||||
<td> 1</td>
|
||||
<td>100,50 EUR</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-2.jpg}" class="s"/></a></td>
|
||||
<td><a th:href="@{/shop/articles/4151}">Earbuds</a></td>
|
||||
<td> 3</td>
|
||||
<td>63,95 EUR</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th>Position</th>
|
||||
<th>Preis</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>Artikel (Netto)</td>
|
||||
<td> 120,00 EUR</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>Bonuspunkte</td>
|
||||
<td> 5,00 EUR</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>Umsatzsteuer (19%)</td>
|
||||
<td> 42,00 EUR</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<h3>Gesammtpreis</h3>
|
||||
</td>
|
||||
<td>
|
||||
<h3>240,79 EUR</h3>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<footer th:replace="fragments/footer :: footer"></footer>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -7,7 +7,7 @@
|
||||
},
|
||||
"articles": [
|
||||
{
|
||||
"title": "TROPIC Geh<EFBFBD>usel<EFBFBD>fter",
|
||||
"title": "TROPIC Gehäuselüfter",
|
||||
"manufacturer": "TROPIC",
|
||||
"articleNumber": "tgl",
|
||||
"vatPercent": 19,
|
||||
@ -31,7 +31,7 @@
|
||||
"shouldBeAdvertised": false
|
||||
},
|
||||
{
|
||||
"title": "Aeroheat CYLON PC-Geh<EFBFBD>use",
|
||||
"title": "Aeroheat CYLON PC-Gehäuse",
|
||||
"manufacturer": "Aeroheat",
|
||||
"articleNumber": "acpcg",
|
||||
"vatPercent": 19,
|
||||
|
@ -1,5 +1,9 @@
|
||||
package org.hso.ecommerce.supplier;
|
||||
|
||||
import org.hso.ecommerce.supplier.carrier.Avian;
|
||||
import org.hso.ecommerce.supplier.carrier.Carrier;
|
||||
import org.hso.ecommerce.supplier.carrier.Posaidon;
|
||||
import org.hso.ecommerce.supplier.carrier.Shredder;
|
||||
import org.hso.ecommerce.supplier.data.Article;
|
||||
import org.hso.ecommerce.supplier.data.Order;
|
||||
import org.hso.ecommerce.supplier.data.OrderConfirmation;
|
||||
@ -22,6 +26,10 @@ public class RequestController {
|
||||
private final HashMap<String, Supplier> knownSuppliers = new HashMap<>();
|
||||
private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
private final Carrier[] carriers = new Carrier[]{
|
||||
new Avian(), new Posaidon(), new Shredder()
|
||||
};
|
||||
|
||||
@PostConstruct
|
||||
public void init() throws IOException {
|
||||
for (Supplier s : ConfigurationReader.read()) {
|
||||
@ -38,7 +46,7 @@ public class RequestController {
|
||||
@GetMapping("/{supplier}/")
|
||||
public Supplier supplier(HttpServletResponse res, @PathVariable("supplier") String supplierName) {
|
||||
Supplier s = knownSuppliers.get(supplierName);
|
||||
if(s == null) {
|
||||
if (s == null) {
|
||||
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
return s;
|
||||
@ -47,16 +55,16 @@ public class RequestController {
|
||||
@PostMapping("/{supplier}/order")
|
||||
public OrderConfirmation order(HttpServletResponse res, @PathVariable("supplier") String supplierName, @RequestBody Order order) {
|
||||
Supplier s = knownSuppliers.get(supplierName);
|
||||
if(s == null) {
|
||||
if (s == null) {
|
||||
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
return null;
|
||||
}
|
||||
|
||||
String dateKey = simpleDateFormat.format(new Date());
|
||||
int dailyVolume = dailySalesVolumeCent.getOrDefault(dateKey,0);
|
||||
int dailyVolume = dailySalesVolumeCent.getOrDefault(dateKey, 0);
|
||||
|
||||
Article a = s.findArticle(order.manufacturer, order.articleNumber);
|
||||
if(a == null) {
|
||||
if (a == null) {
|
||||
res.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
return null;
|
||||
}
|
||||
@ -72,6 +80,8 @@ public class RequestController {
|
||||
}
|
||||
int discount = (discountableNetAmount * s.discount.percentDiscount) / 100;
|
||||
|
||||
Carrier selectedCarrier = carriers[Math.abs((supplierName + java.time.LocalDate.now()).hashCode()) % carriers.length];
|
||||
|
||||
OrderConfirmation confirmation = new OrderConfirmation();
|
||||
confirmation.articleNumber = order.articleNumber;
|
||||
confirmation.discountNetCent = discount;
|
||||
@ -79,6 +89,9 @@ public class RequestController {
|
||||
confirmation.manufacturer = a.manufacturer;
|
||||
confirmation.quantity = order.quantity;
|
||||
confirmation.totalPriceNetCharged = priceNet - discount;
|
||||
confirmation.carrier = selectedCarrier.getName();
|
||||
confirmation.trackingId = selectedCarrier.generateTrackingId();
|
||||
confirmation.estimatedArrival = selectedCarrier.arrivalEstimate();
|
||||
|
||||
if (confirmation.totalPriceNetCharged > order.maxTotalPriceCentNet) {
|
||||
res.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||
|
@ -0,0 +1,28 @@
|
||||
package org.hso.ecommerce.supplier.carrier;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Random;
|
||||
|
||||
public class Avian implements Carrier {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Avian Carriers";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateTrackingId() {
|
||||
Random rnd = new Random();
|
||||
|
||||
return "2001-"
|
||||
+ Integer.toHexString(rnd.nextInt(0xFFFF))
|
||||
+ "--"
|
||||
+ Integer.toHexString(rnd.nextInt(0xFFFF))
|
||||
+ "-"
|
||||
+ Integer.toHexString(rnd.nextInt(0xFFFF));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime arrivalEstimate() {
|
||||
return LocalDateTime.now().plusHours(8);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package org.hso.ecommerce.supplier.carrier;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public interface Carrier {
|
||||
public String getName();
|
||||
|
||||
public String generateTrackingId();
|
||||
|
||||
public LocalDateTime arrivalEstimate();
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package org.hso.ecommerce.supplier.carrier;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Random;
|
||||
|
||||
public class Posaidon implements Carrier {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Poseidon Inc.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateTrackingId() {
|
||||
Random rnd = new Random();
|
||||
return "WAT"
|
||||
+ Integer.toString(rnd.nextInt(Short.MAX_VALUE))
|
||||
+ "3"
|
||||
+ Integer.toString(rnd.nextInt(Short.MAX_VALUE))
|
||||
+ "R";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime arrivalEstimate() {
|
||||
return LocalDateTime.now().plusHours(50);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package org.hso.ecommerce.supplier.carrier;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Random;
|
||||
|
||||
public class Shredder implements Carrier {
|
||||
|
||||
private Random rnd = new Random();
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Schree & Derr";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateTrackingId() {
|
||||
return "O" + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + "0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime arrivalEstimate() {
|
||||
return LocalDateTime.now().plusHours(22);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a random digit followed by a dash.
|
||||
*/
|
||||
private String d() {
|
||||
return Integer.toString(rnd.nextInt(9)) + "-";
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package org.hso.ecommerce.supplier.data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class OrderConfirmation {
|
||||
public String manufacturer;
|
||||
public String articleNumber;
|
||||
@ -9,4 +11,8 @@ public class OrderConfirmation {
|
||||
public int pricePerUnitNetCent;
|
||||
public int discountNetCent;
|
||||
public int totalPriceNetCharged;
|
||||
|
||||
public String carrier;
|
||||
public String trackingId;
|
||||
public LocalDateTime estimatedArrival;
|
||||
}
|
||||
|
@ -5,3 +5,5 @@ e-commerce.db
|
||||
./e-commerce.iml
|
||||
./e-commerce.ipr
|
||||
./e-commerce.iws
|
||||
|
||||
config.yml
|
@ -28,6 +28,7 @@ dependencies {
|
||||
implementation 'com.github.gwenn:sqlite-dialect:0.1.0'
|
||||
implementation 'org.springframework.boot:spring-boot-devtools'
|
||||
implementation 'org.xerial:sqlite-jdbc:3.31.1'
|
||||
implementation 'org.yaml:snakeyaml:1.26'
|
||||
testCompile("org.springframework.boot:spring-boot-starter-test")
|
||||
}
|
||||
|
0
prototype/gradlew → web_backend/gradlew
vendored
@ -1,8 +1,5 @@
|
||||
package org.hso.ecommerce.action.cronjob;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.ArticleIdentifier;
|
||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.Offer;
|
||||
import org.hso.ecommerce.api.SupplierService;
|
||||
@ -14,6 +11,9 @@ import org.hso.ecommerce.entities.supplier.SupplierOrder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ReorderAction {
|
||||
private static final Logger log = LoggerFactory.getLogger(ReorderAction.class);
|
||||
|
||||
@ -102,6 +102,10 @@ public class ReorderAction {
|
||||
createdOrder.numberOfUnits = confirm.quantity;
|
||||
createdOrder.pricePerUnitNetCent = confirm.pricePerUnitNetCent;
|
||||
createdOrder.totalPriceNet = confirm.totalPriceNetCharged;
|
||||
createdOrder.carrier = confirm.carrier;
|
||||
createdOrder.trackingId = confirm.trackingId;
|
||||
createdOrder.estimatedArrival = Timestamp.valueOf(confirm.estimatedArrival);
|
||||
|
||||
return createdOrder;
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@ -101,7 +102,14 @@ public class CreateOrderAction {
|
||||
for (OrderItem item : orderItems) {
|
||||
int needed = item.quantity;
|
||||
|
||||
// Sort for most empty slot first;
|
||||
item.availableSlots.sort(Comparator.comparingInt(a -> a.newSumSlot));
|
||||
|
||||
for (WarehouseBookingPositionSlotEntry slot : item.availableSlots) {
|
||||
if (slot.newSumSlot == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int remove = Math.min(slot.newSumSlot, needed);
|
||||
needed -= remove;
|
||||
|
@ -0,0 +1,16 @@
|
||||
package org.hso.ecommerce.action.shop;
|
||||
|
||||
import org.hso.ecommerce.api.RestServiceForDelivery;
|
||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
||||
import org.springframework.web.client.ResourceAccessException;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Date;
|
||||
|
||||
public class EnableTrackingAction {
|
||||
|
||||
public static void addTrackingInfo(RestServiceForDelivery deliveryService, CustomerOrder customerOrder) throws ResourceAccessException {
|
||||
customerOrder.inDeliverySince = new Timestamp(new Date().getTime());
|
||||
customerOrder.trackingId = deliveryService.getDeliveryID(customerOrder);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package org.hso.ecommerce.action.user;
|
||||
|
||||
import org.hso.ecommerce.api.RestServiceForDelivery;
|
||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
||||
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
|
||||
import org.hso.ecommerce.uimodel.DeliveryData;
|
||||
import org.hso.ecommerce.uimodel.DeliveryDataEnum;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class CreateDeliveryData {
|
||||
|
||||
public static DeliveryData getDeliveryDataFromCustomerOrder(CustomerOrder customerOrder, CustomerOrderRepository customerOrderRepository, RestServiceForDelivery restServiceForDelivery)
|
||||
{
|
||||
if(customerOrder.trackingId == null)
|
||||
return new DeliveryData("", "", DeliveryDataEnum.NO_TRACKING_ID);
|
||||
|
||||
if(customerOrder.deliveredAt == null)
|
||||
{
|
||||
DeliveryData deliveryData = restServiceForDelivery.getDeliveryData(customerOrder.trackingId);
|
||||
|
||||
|
||||
if(deliveryData.isDelivered())
|
||||
{
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MM-yyyy");
|
||||
|
||||
try {
|
||||
calendar.setTime(simpleDateFormat.parse(deliveryData.getEstimatedArrival()));
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
customerOrder.deliveredAt = new Timestamp(calendar.getTimeInMillis());
|
||||
customerOrderRepository.save(customerOrder);
|
||||
}
|
||||
|
||||
return deliveryData;
|
||||
}
|
||||
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
|
||||
return new DeliveryData("Lieferung erfolgreich", formatter.format(customerOrder.deliveredAt), DeliveryDataEnum.OK);
|
||||
}
|
||||
}
|
@ -48,7 +48,7 @@ public class UpdateUserSettingsAction {
|
||||
|
||||
public UpdateResult updateShippingInfo(String salutation, String name, String address) {
|
||||
this.user.salutation = salutation;
|
||||
this.user.name = name;
|
||||
this.user.defaultDeliveryAddress.name = name;
|
||||
this.user.defaultDeliveryAddress.addressString = address;
|
||||
this.repository.save(this.user);
|
||||
return new UpdateResult(true);
|
@ -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;
|
@ -0,0 +1,83 @@
|
||||
package org.hso.ecommerce.api;
|
||||
|
||||
import org.hso.ecommerce.app.config.AppSettings;
|
||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
||||
import org.hso.ecommerce.uimodel.DeliveryData;
|
||||
import org.hso.ecommerce.uimodel.DeliveryDataEnum;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.ResourceAccessException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class RestServiceForDelivery {
|
||||
|
||||
@Autowired
|
||||
private final RestTemplateBuilder restTemplateBuilder = null;
|
||||
|
||||
@Autowired
|
||||
private final AppSettings settings = null;
|
||||
|
||||
private String getDeliveryEndpoint() {
|
||||
return settings.getParcelServiceApiURL();
|
||||
}
|
||||
|
||||
|
||||
public String getDeliveryID(CustomerOrder customerOrder) throws ResourceAccessException {
|
||||
String url = getDeliveryEndpoint() + "/newDelivery";
|
||||
|
||||
RestTemplate restTemplate = restTemplateBuilder.build();
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
Map<String, String> requestBody = new HashMap<>();
|
||||
|
||||
requestBody.put("name", customerOrder.destination.name);
|
||||
requestBody.put("address", customerOrder.destination.addressString);
|
||||
|
||||
HttpEntity<Map<String, String>> entity = new HttpEntity<>(requestBody, headers);
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
|
||||
|
||||
if (response.getStatusCode() == HttpStatus.OK) {
|
||||
return response.getBody();
|
||||
} else {
|
||||
throw new ResourceAccessException("Http Status wrong");
|
||||
}
|
||||
}
|
||||
|
||||
public DeliveryData getDeliveryData(String trackingID) {
|
||||
|
||||
String url = getDeliveryEndpoint() + "/status";
|
||||
|
||||
RestTemplate restTemplate = restTemplateBuilder.build();
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParam("trackingID", trackingID);
|
||||
|
||||
HttpEntity<?> entity = new HttpEntity<>(headers);
|
||||
|
||||
ResponseEntity<DeliveryData> response;
|
||||
|
||||
try {
|
||||
response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, entity, DeliveryData.class);
|
||||
if (response.getStatusCode() == HttpStatus.OK) {
|
||||
return response.getBody();
|
||||
} else {
|
||||
|
||||
return new DeliveryData("", "", DeliveryDataEnum.NO_DATA);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return new DeliveryData("", "", DeliveryDataEnum.NO_DATA);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package org.hso.ecommerce.api.data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class OrderConfirmation {
|
||||
public String manufacturer;
|
||||
public String articleNumber;
|
||||
@ -9,4 +11,8 @@ public class OrderConfirmation {
|
||||
public int pricePerUnitNetCent;
|
||||
public int discountNetCent;
|
||||
public int totalPriceNetCharged;
|
||||
|
||||
public String carrier;
|
||||
public String trackingId;
|
||||
public LocalDateTime estimatedArrival;
|
||||
}
|
@ -13,6 +13,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
@ -0,0 +1,161 @@
|
||||
package org.hso.ecommerce.app.config;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hso.ecommerce.app.config.YAMLData.Address;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Component("appSettings")
|
||||
public class AppSettings {
|
||||
|
||||
private YAMLData data;
|
||||
private final String configFile = "config.yml";
|
||||
|
||||
private String installationName;
|
||||
private String companyName;
|
||||
private Address companyAddress;
|
||||
private int numberOfStorageSpaces;
|
||||
private List<YAMLData.Supplier> suppliers;
|
||||
private String parcelServiceName;
|
||||
private String parcelServiceApiURL;
|
||||
|
||||
/**
|
||||
* on initialization read the config and store the data in static objects
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
data = readConfig();
|
||||
|
||||
installationName = data.getInstallationName();
|
||||
companyName = data.getCompanyName();
|
||||
companyAddress = data.getCompanyAddress();
|
||||
numberOfStorageSpaces = data.getNumberOfStorageSpaces();
|
||||
suppliers = data.getSuppliers();
|
||||
parcelServiceName = data.getParcelServiceName();
|
||||
parcelServiceApiURL = data.getParcelServiceApiURL();
|
||||
|
||||
System.out.println("Initialised Settings!");
|
||||
}
|
||||
|
||||
/**
|
||||
* write the default config file
|
||||
*/
|
||||
public void writeDefaultConfig() {
|
||||
YAMLData data = new YAMLData();
|
||||
data.setInstallationName("eCommerce");
|
||||
data.setCompanyName("eCommerce Shop UG");
|
||||
data.setCompanyAddress(new Address(
|
||||
"Musterstraße",
|
||||
"1",
|
||||
"12345",
|
||||
"Musterstadt",
|
||||
"Germany"
|
||||
));
|
||||
data.setNumberOfStorageSpaces(128);
|
||||
|
||||
List<YAMLData.Supplier> suppliers = new ArrayList<>();
|
||||
suppliers.add(new YAMLData.Supplier(
|
||||
"Bank of Chees",
|
||||
"d41d8cd98f00b204e9800998ecf8427e",
|
||||
"http://[::1]:8081/bank/",
|
||||
4,
|
||||
new Address(
|
||||
"Musterstraße",
|
||||
"2",
|
||||
"12345",
|
||||
"Musterstadt",
|
||||
"Germany"
|
||||
)
|
||||
));
|
||||
suppliers.add(new YAMLData.Supplier(
|
||||
"MDA",
|
||||
"18a17da5bac1cf00551b08c3e98720f5",
|
||||
"http://[::1]:8081/mda/",
|
||||
5,
|
||||
new Address(
|
||||
"Musterstraße",
|
||||
"3",
|
||||
"12345",
|
||||
"Musterstadt",
|
||||
"Germany"
|
||||
)
|
||||
));
|
||||
data.setSuppliers(suppliers);
|
||||
|
||||
data.setParcelServiceName("Parcel Service");
|
||||
data.setParcelServiceApiURL("http://[::1]:8082/");
|
||||
|
||||
try (FileWriter writer = new FileWriter("./" + configFile)) {
|
||||
Yaml yaml = new Yaml();
|
||||
yaml.dump(data, writer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* read a config file named "eCommerce_config.yml" from the applications root directory
|
||||
* @return the settings as YAMLData object
|
||||
*/
|
||||
public YAMLData readConfig() {
|
||||
YAMLData data = new YAMLData();
|
||||
|
||||
File file = new File("./" + configFile);
|
||||
if (!file.exists()) {
|
||||
writeDefaultConfig();
|
||||
}
|
||||
|
||||
try (InputStream inputStream = new FileInputStream("./" + configFile)) {
|
||||
Yaml yaml = new Yaml(new Constructor(YAMLData.class));
|
||||
data = yaml.load(inputStream);
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println("The file \"" + configFile + "\" has not been found, please create a valid Configuration file.");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public YAMLData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public String getInstallationName() {
|
||||
return installationName;
|
||||
}
|
||||
|
||||
public String getCompanyName() {
|
||||
return companyName;
|
||||
}
|
||||
|
||||
public Address getCompanyAddress() {
|
||||
return companyAddress;
|
||||
}
|
||||
|
||||
public int getNumberOfStorageSpaces() {
|
||||
return numberOfStorageSpaces;
|
||||
}
|
||||
|
||||
public List<YAMLData.Supplier> getSuppliers() {
|
||||
return suppliers;
|
||||
}
|
||||
|
||||
public String getParcelServiceName() {
|
||||
return parcelServiceName;
|
||||
}
|
||||
|
||||
public String getParcelServiceApiURL() {
|
||||
return parcelServiceApiURL;
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package org.hso.ecommerce.app.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class YAMLData {
|
||||
|
||||
private String installationName;
|
||||
private String companyName;
|
||||
private Address companyAddress;
|
||||
private int numberOfStorageSpaces;
|
||||
private List<Supplier> suppliers;
|
||||
private String parcelServiceName;
|
||||
private String parcelServiceApiURL;
|
||||
|
||||
|
||||
public String getInstallationName() {
|
||||
return installationName;
|
||||
}
|
||||
public void setInstallationName(String installationName) {
|
||||
this.installationName = installationName;
|
||||
}
|
||||
public String getCompanyName() {
|
||||
return companyName;
|
||||
}
|
||||
public void setCompanyName(String companyName) {
|
||||
this.companyName = companyName;
|
||||
}
|
||||
public Address getCompanyAddress() {
|
||||
return companyAddress;
|
||||
}
|
||||
public void setCompanyAddress(Address companyAddress) {
|
||||
this.companyAddress = companyAddress;
|
||||
}
|
||||
public int getNumberOfStorageSpaces() {
|
||||
return numberOfStorageSpaces;
|
||||
}
|
||||
public void setNumberOfStorageSpaces(int numberOfStorageSpaces) {
|
||||
this.numberOfStorageSpaces = numberOfStorageSpaces;
|
||||
}
|
||||
public List<Supplier> getSuppliers() {
|
||||
return suppliers;
|
||||
}
|
||||
public void setSuppliers(List<Supplier> suppliers) {
|
||||
this.suppliers = suppliers;
|
||||
}
|
||||
public String getParcelServiceName() {
|
||||
return parcelServiceName;
|
||||
}
|
||||
public void setParcelServiceName(String parcelServiceName) {
|
||||
this.parcelServiceName = parcelServiceName;
|
||||
}
|
||||
public String getParcelServiceApiURL() {
|
||||
return parcelServiceApiURL;
|
||||
}
|
||||
public void setParcelServiceApiURL(String parcelServiceApiURL) {
|
||||
this.parcelServiceApiURL = parcelServiceApiURL;
|
||||
}
|
||||
|
||||
public static class Address {
|
||||
|
||||
public String streetName;
|
||||
public String houseNumber;
|
||||
public String zipCode;
|
||||
public String cityName;
|
||||
public String countryName;
|
||||
|
||||
public Address() {
|
||||
// needed by snakeyaml
|
||||
}
|
||||
|
||||
public Address(String streetName, String houseNumber, String zipCode, String cityName, String countryName) {
|
||||
this.streetName = streetName;
|
||||
this.houseNumber = houseNumber;
|
||||
this.zipCode = zipCode;
|
||||
this.cityName = cityName;
|
||||
this.countryName = countryName;
|
||||
}
|
||||
|
||||
public String getStreetName() {
|
||||
return streetName;
|
||||
}
|
||||
|
||||
public void setStreetName(String streetName) {
|
||||
this.streetName = streetName;
|
||||
}
|
||||
|
||||
public String getHouseNumber() {
|
||||
return houseNumber;
|
||||
}
|
||||
|
||||
public void setHouseNumber(String houseNumber) {
|
||||
this.houseNumber = houseNumber;
|
||||
}
|
||||
|
||||
public String getZipCode() {
|
||||
return zipCode;
|
||||
}
|
||||
|
||||
public void setZipCode(String zipCode) {
|
||||
this.zipCode = zipCode;
|
||||
}
|
||||
|
||||
public String getCityName() {
|
||||
return cityName;
|
||||
}
|
||||
|
||||
public void setCityName(String cityName) {
|
||||
this.cityName = cityName;
|
||||
}
|
||||
|
||||
public String getCountryName() {
|
||||
return countryName;
|
||||
}
|
||||
|
||||
public void setCountryName(String countryName) {
|
||||
this.countryName = countryName;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Supplier {
|
||||
|
||||
public String name;
|
||||
public String id;
|
||||
public String apiURL;
|
||||
public int deliveryTime;
|
||||
public Address companyAddress;
|
||||
|
||||
|
||||
public Supplier() {
|
||||
// needed by snakeyaml
|
||||
}
|
||||
|
||||
public Supplier(String name, String id, String apiURL, int deliveryTime, Address companyAddress) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
this.apiURL = apiURL;
|
||||
this.deliveryTime = deliveryTime;
|
||||
this.companyAddress = companyAddress;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getApiURL() {
|
||||
return apiURL;
|
||||
}
|
||||
|
||||
public void setApiURL(String apiURL) {
|
||||
this.apiURL = apiURL;
|
||||
}
|
||||
|
||||
public int getDeliveryTime() {
|
||||
return deliveryTime;
|
||||
}
|
||||
|
||||
public void setDeliveryTime(int deliveryTime) {
|
||||
this.deliveryTime = deliveryTime;
|
||||
}
|
||||
|
||||
public Address getCompanyAddress() {
|
||||
return companyAddress;
|
||||
}
|
||||
|
||||
public void setCompanyAddress(Address companyAddress) {
|
||||
this.companyAddress = companyAddress;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +1,15 @@
|
||||
package org.hso.ecommerce.components;
|
||||
|
||||
import org.hso.ecommerce.entities.booking.PaymentMethod;
|
||||
import org.hso.ecommerce.entities.shop.Address;
|
||||
import org.hso.ecommerce.entities.user.User;
|
||||
import org.hso.ecommerce.repos.user.UserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Component
|
||||
public class AdminInitializer {
|
||||
|
||||
@ -24,9 +23,9 @@ public class AdminInitializer {
|
||||
// create first admin user
|
||||
User firstAdmin = new User();
|
||||
firstAdmin.created = new Timestamp(System.currentTimeMillis());
|
||||
firstAdmin.name = "admin";
|
||||
firstAdmin.defaultPayment = new PaymentMethod();
|
||||
firstAdmin.defaultPayment.creditCardNumber = ""; //set empty number
|
||||
firstAdmin.defaultDeliveryAddress = new Address();
|
||||
firstAdmin.defaultDeliveryAddress.name = "admin";
|
||||
firstAdmin.defaultPayment = null;
|
||||
firstAdmin.email = "admin";
|
||||
firstAdmin.isActive = true;
|
||||
firstAdmin.isEmployee = true;
|
@ -0,0 +1,35 @@
|
||||
package org.hso.ecommerce.components;
|
||||
|
||||
import org.hso.ecommerce.app.config.AppSettings;
|
||||
import org.hso.ecommerce.entities.warehouse.Slot;
|
||||
import org.hso.ecommerce.repos.warehouse.SlotRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Component
|
||||
public class SlotInitializer {
|
||||
|
||||
@Autowired
|
||||
private final SlotRepository slotRepository = null;
|
||||
|
||||
@Autowired
|
||||
private final AppSettings appSettings = null;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
int NUM_SLOTS = appSettings.getNumberOfStorageSpaces();
|
||||
|
||||
for (int i = 1; i <= NUM_SLOTS; i++) {
|
||||
if (!slotRepository.findBySlotNum(i).isPresent()) {
|
||||
Slot slotAdded = new Slot();
|
||||
slotAdded.slotNum = i;
|
||||
slotRepository.save(slotAdded);
|
||||
|
||||
System.out.println("Added Slot " + i + " to DB");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package org.hso.ecommerce.components;
|
||||
|
||||
import org.hso.ecommerce.app.config.AppSettings;
|
||||
import org.hso.ecommerce.app.config.YAMLData;
|
||||
import org.hso.ecommerce.entities.supplier.Supplier;
|
||||
import org.hso.ecommerce.repos.supplier.SupplierRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class SupplierInitializer {
|
||||
|
||||
@Autowired
|
||||
private final SupplierRepository supplierRepository = null;
|
||||
|
||||
@Autowired
|
||||
private final AppSettings appSettings = null;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
for (YAMLData.Supplier cfg : appSettings.getSuppliers()) {
|
||||
Optional<Supplier> sup = supplierRepository.findByUuid(cfg.id);
|
||||
|
||||
Supplier supplier;
|
||||
if (sup.isPresent()) {
|
||||
supplier = sup.get();
|
||||
supplier.name = cfg.name;
|
||||
supplier.apiUrl = cfg.apiURL;
|
||||
} else {
|
||||
supplier = new Supplier();
|
||||
supplier.uuid = cfg.id;
|
||||
supplier.apiUrl = cfg.apiURL;
|
||||
supplier.name = cfg.name;
|
||||
}
|
||||
supplierRepository.save(supplier);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,19 +1,16 @@
|
||||
package org.hso.ecommerce.controller;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.hso.ecommerce.entities.shop.ShoppingCart;
|
||||
import org.hso.ecommerce.entities.user.User;
|
||||
import org.hso.ecommerce.repos.user.UserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.util.Optional;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/")
|
||||
@ -56,14 +53,18 @@ public class LoginController {
|
||||
|
||||
if (gto != null && gto.startsWith("/")) {
|
||||
return "redirect:" + gto;
|
||||
} else if (user.get().isEmployee) {
|
||||
return "redirect:/intern/";
|
||||
} else {
|
||||
return "redirect:/";
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("logout")
|
||||
public String logoutPost(HttpServletResponse response, HttpSession session) {
|
||||
public String logoutPost(@RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart, HttpSession session) {
|
||||
session.removeAttribute("userId");
|
||||
shoppingCart.clear();
|
||||
|
||||
return "redirect:/";
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package org.hso.ecommerce.controller;
|
||||
|
||||
import org.hso.ecommerce.entities.booking.PaymentMethod;
|
||||
import org.hso.ecommerce.entities.shop.Address;
|
||||
import org.hso.ecommerce.entities.user.User;
|
||||
import org.hso.ecommerce.repos.user.UserRepository;
|
||||
@ -47,7 +46,7 @@ public class RegisterController {
|
||||
newUser.email = username;
|
||||
newUser.isEmployee = false;
|
||||
newUser.salutation = salutation;
|
||||
newUser.defaultPayment = PaymentMethod.fromCreditCardNumber("");
|
||||
newUser.defaultPayment = null;
|
||||
|
||||
newUser.isActive = true;
|
||||
newUser.created = new java.sql.Timestamp(System.currentTimeMillis());
|
@ -1,22 +1,23 @@
|
||||
package org.hso.ecommerce.controller;
|
||||
|
||||
import org.hso.ecommerce.action.user.CreateDeliveryData;
|
||||
import org.hso.ecommerce.action.user.UpdateUserSettingsAction;
|
||||
import org.hso.ecommerce.entities.shop.Address;
|
||||
import org.hso.ecommerce.api.RestServiceForDelivery;
|
||||
import org.hso.ecommerce.app.config.AppSettings;
|
||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
||||
import org.hso.ecommerce.entities.user.User;
|
||||
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
|
||||
import org.hso.ecommerce.repos.user.UserRepository;
|
||||
import org.hso.ecommerce.uimodel.DeliveryData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/user")
|
||||
@ -28,6 +29,12 @@ public class UserController {
|
||||
@Autowired
|
||||
private final CustomerOrderRepository customerOrderRepository = null;
|
||||
|
||||
@Autowired
|
||||
private final RestServiceForDelivery restServiceForDelivery = null;
|
||||
|
||||
@Autowired
|
||||
private final AppSettings appSettings = null;
|
||||
|
||||
@GetMapping("/")
|
||||
public String user() {
|
||||
return "redirect:/user/settings";
|
||||
@ -35,28 +42,49 @@ public class UserController {
|
||||
|
||||
@GetMapping("/settings")
|
||||
public String userSettings(Model model,
|
||||
HttpSession session
|
||||
@RequestAttribute("user") User user
|
||||
) {
|
||||
long userId = (long) session.getAttribute("userId");
|
||||
User user = userRepository.findById(userId).get();
|
||||
if(user.defaultDeliveryAddress == null){
|
||||
user.defaultDeliveryAddress = new Address();
|
||||
}
|
||||
model.addAttribute("user", user);
|
||||
|
||||
return "user/settings";
|
||||
}
|
||||
|
||||
@GetMapping("/orders/")
|
||||
public String userOrdeers(HttpSession session,
|
||||
public String userOrders(
|
||||
@RequestAttribute("user") User user,
|
||||
Model model
|
||||
) {
|
||||
List<CustomerOrder> orders = customerOrderRepository.getOrdersByUserId((long) session.getAttribute("userId"));
|
||||
model.addAttribute("orders", orders);
|
||||
List<CustomerOrder> orders = customerOrderRepository.getOrdersByUserId(user.id);
|
||||
|
||||
List<CustomerOrderDelivery> customerOrderDeliveryDataMap = orders
|
||||
.stream()
|
||||
.map(o -> new CustomerOrderDelivery(o, CreateDeliveryData.getDeliveryDataFromCustomerOrder(o, customerOrderRepository, restServiceForDelivery)))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
model.addAttribute("orderDeliveryDataMap", customerOrderDeliveryDataMap);
|
||||
model.addAttribute("deliveryService", appSettings.getParcelServiceName());
|
||||
|
||||
return "user/orders/index";
|
||||
}
|
||||
|
||||
static class CustomerOrderDelivery {
|
||||
private CustomerOrder customerOrder;
|
||||
private DeliveryData deliveryData;
|
||||
|
||||
public CustomerOrderDelivery(CustomerOrder customerOrder, DeliveryData deliveryData) {
|
||||
this.customerOrder = customerOrder;
|
||||
this.deliveryData = deliveryData;
|
||||
}
|
||||
|
||||
public CustomerOrder getCustomerOrder() {
|
||||
return customerOrder;
|
||||
}
|
||||
|
||||
public DeliveryData getDeliveryData() {
|
||||
return deliveryData;
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/settings/changeMail")
|
||||
public String changeMail(HttpSession session,
|
||||
@RequestParam("email") String email,
|
@ -0,0 +1,77 @@
|
||||
package org.hso.ecommerce.controller.cronjob;
|
||||
|
||||
import org.hso.ecommerce.action.booking.CreateBookingAction;
|
||||
import org.hso.ecommerce.entities.booking.Booking;
|
||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
|
||||
import org.hso.ecommerce.entities.booking.BookingReason;
|
||||
import org.hso.ecommerce.entities.supplier.Supplier;
|
||||
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
|
||||
import org.hso.ecommerce.repos.booking.BookingRepository;
|
||||
import org.hso.ecommerce.repos.supplier.SupplierRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
@Component
|
||||
public class AutoSupplierPayment implements ICronjob {
|
||||
|
||||
@Autowired
|
||||
private SupplierRepository supplierRepository = null;
|
||||
|
||||
@Autowired
|
||||
private BookingAccountEntryRepository bookingAccountEntryRepository = null;
|
||||
|
||||
@Autowired
|
||||
private BookingRepository bookingRepository = null;
|
||||
|
||||
@Override
|
||||
public Calendar nextExecution(Calendar reference) {
|
||||
if (reference.get(Calendar.HOUR_OF_DAY) >= 10) {
|
||||
reference.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
reference.set(Calendar.HOUR_OF_DAY, 10);
|
||||
reference.set(Calendar.MINUTE, 0);
|
||||
reference.set(Calendar.SECOND, 0);
|
||||
reference.set(Calendar.MILLISECOND, 0);
|
||||
return reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar previousExecution(Calendar reference) {
|
||||
if (reference.get(Calendar.HOUR_OF_DAY) < 10) {
|
||||
reference.add(Calendar.DAY_OF_MONTH, -1);
|
||||
}
|
||||
reference.set(Calendar.HOUR_OF_DAY, 10);
|
||||
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) {
|
||||
|
||||
for (Supplier supplier : supplierRepository.findAll()) {
|
||||
int debts = bookingAccountEntryRepository
|
||||
.getBySupplier(supplier.id)
|
||||
.map(entry -> entry.newSumCent).orElse(0);
|
||||
|
||||
if (debts > 0) {
|
||||
Booking booking = new CreateBookingAction(
|
||||
bookingAccountEntryRepository.getBySupplier(supplier.id).orElseGet(() -> BookingAccountEntry.newSupplier(supplier)),
|
||||
null,
|
||||
new BookingReason(supplier),
|
||||
debts
|
||||
).finish();
|
||||
|
||||
bookingRepository.save(booking);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Supplier Auto Payment";
|
||||
}
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
package org.hso.ecommerce.controller.cronjob;
|
||||
|
||||
import org.hso.ecommerce.entities.cron.BackgroundJob;
|
||||
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.warehouse.WarehouseBookingPositionSlotEntryRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@Component
|
||||
@RequestMapping("intern/cronjobs")
|
||||
class CronjobController {
|
||||
private static final Logger log = LoggerFactory.getLogger(CronjobController.class);
|
||||
|
||||
private Map<String, ICronjob> cronjobs;
|
||||
|
||||
@Autowired
|
||||
private final BackgroundJobRepository cronjobRepository = null;
|
||||
|
||||
@Autowired
|
||||
final ArticleRepository articleRepository = null;
|
||||
|
||||
@Autowired
|
||||
final ArticleOfferRepository articleOfferRepository = null;
|
||||
|
||||
@Autowired
|
||||
final CustomerOrderRepository customerOrderRepository = null;
|
||||
|
||||
@Autowired
|
||||
final BookingRepository bookingRepository = null;
|
||||
|
||||
@Autowired
|
||||
final BookingAccountEntryRepository bookingAccountEntryRepository = null;
|
||||
|
||||
@Autowired
|
||||
final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
|
||||
|
||||
@Autowired
|
||||
final DashboardSummaryRepository dashboardSummaryRepository = null;
|
||||
|
||||
@Autowired
|
||||
final SupplierRepository supplierRepository = null;
|
||||
|
||||
@Autowired
|
||||
final SupplierOrderRepository supplierOrderRepository = null;
|
||||
|
||||
@Autowired
|
||||
final Reorder reorderJob = null;
|
||||
|
||||
@Autowired
|
||||
final DashboardCronjob dashboardCronjob = null;
|
||||
|
||||
@Autowired
|
||||
final AutoSupplierPayment autoSupplierPaymentJob = null;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
cronjobs = getCronjobs();
|
||||
}
|
||||
|
||||
private Map<String, ICronjob> getCronjobs() {
|
||||
HashMap<String, ICronjob> map = new HashMap<>();
|
||||
|
||||
// Register all existing cronjobs
|
||||
map.put(BackgroundJob.JOB_REORDER, reorderJob);
|
||||
map.put(BackgroundJob.JOB_DASHBOARD, dashboardCronjob);
|
||||
map.put(BackgroundJob.JOB_SUPPLIER_AUTO_PAYMENT, autoSupplierPaymentJob);
|
||||
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
private ScheduledCronjob getNextCronjob() {
|
||||
Calendar currentTime = new GregorianCalendar();
|
||||
Iterable<BackgroundJob> jobs = cronjobRepository.findAll();
|
||||
HashMap<String, BackgroundJob> alreadyExecuted = new HashMap<>();
|
||||
for (BackgroundJob job : jobs) {
|
||||
alreadyExecuted.put(job.jobName, job);
|
||||
}
|
||||
ScheduledCronjob earliestJob = null;
|
||||
for (Entry<String, ICronjob> entry : cronjobs.entrySet()) {
|
||||
ScheduledCronjob resultingJob;
|
||||
BackgroundJob dbEntry = alreadyExecuted.get(entry.getKey());
|
||||
if (dbEntry != null) {
|
||||
Calendar previousExecution = new GregorianCalendar();
|
||||
previousExecution.setTimeInMillis(dbEntry.lastExecution.getTime());
|
||||
Calendar followingSchedule = entry.getValue().nextExecution((Calendar) previousExecution.clone());
|
||||
Calendar lastSchedule = entry.getValue().previousExecution((Calendar) currentTime.clone());
|
||||
if (lastSchedule.getTimeInMillis() > followingSchedule.getTimeInMillis()) {
|
||||
// This happens, if more than one execution was missed.
|
||||
// In this case, run the job only once.
|
||||
followingSchedule = lastSchedule;
|
||||
}
|
||||
resultingJob = new ScheduledCronjob(followingSchedule, entry.getValue(), dbEntry);
|
||||
} else {
|
||||
// This cronjob has never been executed before.
|
||||
Calendar lastScheduleTime = entry.getValue().previousExecution((Calendar) currentTime.clone());
|
||||
BackgroundJob model = new BackgroundJob();
|
||||
model.jobName = entry.getKey();
|
||||
resultingJob = new ScheduledCronjob(lastScheduleTime, entry.getValue(), model);
|
||||
}
|
||||
|
||||
// Look for the job with earliest executionTime - it will run next
|
||||
if (earliestJob == null
|
||||
|| resultingJob.executionTime.getTimeInMillis() < earliestJob.executionTime.getTimeInMillis()) {
|
||||
earliestJob = resultingJob;
|
||||
}
|
||||
}
|
||||
return earliestJob;
|
||||
}
|
||||
|
||||
private void runCronjobExecutionLoop() {
|
||||
Thread.currentThread().setName("Cronjob");
|
||||
try {
|
||||
while (true) {
|
||||
ScheduledCronjob nextJob = getNextCronjob();
|
||||
if (nextJob == null) {
|
||||
// In case there are no cronjobs
|
||||
return;
|
||||
}
|
||||
long waitingTime = nextJob.executionTime.getTimeInMillis() - System.currentTimeMillis();
|
||||
if (waitingTime > 0) {
|
||||
Thread.sleep(waitingTime);
|
||||
}
|
||||
|
||||
try {
|
||||
nextJob.cronjob.executeAt(nextJob.executionTime, this);
|
||||
} catch (Throwable t) {
|
||||
log.error("Failed to execute cronjob " + nextJob.cronjob.getClass() + ":");
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
nextJob.model.lastExecution = new Timestamp(nextJob.executionTime.getTimeInMillis());
|
||||
cronjobRepository.save(nextJob.model);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
log.error("The cronjob execution thread has been interrupted");
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void onPostConstruct() {
|
||||
new Thread(this::runCronjobExecutionLoop).start();
|
||||
}
|
||||
|
||||
class ManualCronjob {
|
||||
public final String identifier;
|
||||
public final String visibleName;
|
||||
|
||||
public ManualCronjob(String identifier, String visibleName) {
|
||||
this.identifier = identifier;
|
||||
this.visibleName = visibleName;
|
||||
}
|
||||
}
|
||||
|
||||
private List<ManualCronjob> listAllCronjobs() {
|
||||
ArrayList<ManualCronjob> entries = new ArrayList<>();
|
||||
for (Entry<String, ICronjob> job : cronjobs.entrySet()) {
|
||||
entries.add(new ManualCronjob(job.getKey(), job.getValue().getDisplayName()));
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String cronjobOverview(Model model) {
|
||||
model.addAttribute("jobs", listAllCronjobs());
|
||||
return "intern/cronjobs/index";
|
||||
}
|
||||
|
||||
@PostMapping("/run/{identifier}")
|
||||
public String runCronjob(Model model, @PathVariable("identifier") String identifier) {
|
||||
ICronjob jobToExecute = cronjobs.get(identifier);
|
||||
if (jobToExecute != null) {
|
||||
jobToExecute.executeAt(new GregorianCalendar(), this);
|
||||
model.addAttribute("info",
|
||||
String.format("Der Cronjob \"%s\" wurde ausgeführt.", jobToExecute.getDisplayName()));
|
||||
} else {
|
||||
model.addAttribute("error", "Der Cronjob konnte nicht gefunden werden.");
|
||||
}
|
||||
model.addAttribute("jobs", listAllCronjobs());
|
||||
return "intern/cronjobs/index";
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
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.hso.ecommerce.repos.shop.CustomerOrderRepository;
|
||||
import org.hso.ecommerce.repos.user.UserRepository;
|
||||
import org.hso.ecommerce.repos.warehouse.SlotRepository;
|
||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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 {
|
||||
|
||||
@Autowired
|
||||
private SlotRepository slotRepository = null;
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository = null;
|
||||
|
||||
@Autowired
|
||||
private WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
|
||||
|
||||
@Autowired
|
||||
private CustomerOrderRepository customerOrderRepository = null;
|
||||
|
||||
@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 = slotRepository.findAll().stream().map(
|
||||
s -> 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 = nullToZero(getSales(oneDayBefore, time));
|
||||
dashboardSummary.todaysNewCustomers = nullToZero(getNewUsers(oneDayBefore, time));
|
||||
dashboardSummary.todaysWarehouseCapacity = warehouseStats.efficiency;
|
||||
dashboardSummary.currentWarehouseCapacity = warehouseStats.ratioUsedSlots;
|
||||
dashboardSummary.todaysSalesCent = nullToZero(getTurnover(oneDayBefore, time));
|
||||
|
||||
controller.dashboardSummaryRepository.save(dashboardSummary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Dashboard refresh";
|
||||
}
|
||||
|
||||
private Integer getSales(Calendar begin, Calendar end) {
|
||||
return customerOrderRepository.countOrdersInTimespan(
|
||||
new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
|
||||
}
|
||||
|
||||
private Integer getTurnover(Calendar begin, Calendar end) {
|
||||
return customerOrderRepository.countTurnoverInTimespan(
|
||||
new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
|
||||
}
|
||||
|
||||
private Integer getNewUsers(Calendar begin, Calendar end) {
|
||||
return userRepository.countUsersInTimespan(
|
||||
new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
|
||||
}
|
||||
|
||||
private int nullToZero(Integer input) {
|
||||
return input == null ? 0 : input;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package org.hso.ecommerce.controller.cronjob;
|
||||
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
interface ICronjob {
|
||||
/**
|
||||
* Calculate the earliest cronjob execution time that happens after the given reference time.
|
||||
*
|
||||
* @param reference Position in time to start searching. The implementor is allowed to modify the reference time.
|
||||
* @return A new Calendar instance (or the same) containing the time for next execution.
|
||||
*/
|
||||
Calendar nextExecution(Calendar reference);
|
||||
|
||||
/**
|
||||
* Calculate the latest cronjob execution time that happens before or exactly at the given refernce time.
|
||||
*
|
||||
* @param reference Position in time to start searching. The implementor is allowed to modify the reference time.
|
||||
* @return A new Calendar instance (or the same) containing the time of the last execution.
|
||||
*/
|
||||
Calendar previousExecution(Calendar reference);
|
||||
|
||||
/**
|
||||
* Execute this cronjob.
|
||||
*
|
||||
* @param time The point in time this execution was scheduled. In case of a missed cronjob, the actual time of
|
||||
* this call might be much later.
|
||||
* @param controller Back-reference that allows to use repositories.
|
||||
*/
|
||||
void executeAt(Calendar time, CronjobController controller);
|
||||
|
||||
/**
|
||||
* Get a name for this cronjob, that can be presented to the user in the frontend.
|
||||
*
|
||||
* @return A german name of this cronjob.
|
||||
*/
|
||||
String getDisplayName();
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
package org.hso.ecommerce.controller.cronjob;
|
||||
|
||||
import org.hso.ecommerce.action.booking.CreateBookingAction;
|
||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction;
|
||||
import org.hso.ecommerce.action.cronjob.ReorderAction;
|
||||
import org.hso.ecommerce.action.cronjob.UpdateOffersAction;
|
||||
import org.hso.ecommerce.entities.booking.Booking;
|
||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
|
||||
import org.hso.ecommerce.entities.booking.BookingReason;
|
||||
import org.hso.ecommerce.entities.shop.Article;
|
||||
import org.hso.ecommerce.entities.supplier.ArticleOffer;
|
||||
import org.hso.ecommerce.entities.supplier.Supplier;
|
||||
import org.hso.ecommerce.entities.supplier.SupplierOrder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
class Reorder implements ICronjob {
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Nachbestellung";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar nextExecution(Calendar reference) {
|
||||
if (reference.get(Calendar.HOUR_OF_DAY) >= 8) {
|
||||
reference.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
reference.set(Calendar.HOUR_OF_DAY, 8);
|
||||
reference.set(Calendar.MINUTE, 0);
|
||||
reference.set(Calendar.SECOND, 0);
|
||||
reference.set(Calendar.MILLISECOND, 0);
|
||||
return reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar previousExecution(Calendar reference) {
|
||||
if (reference.get(Calendar.HOUR_OF_DAY) < 8) {
|
||||
reference.add(Calendar.DAY_OF_MONTH, -1);
|
||||
}
|
||||
reference.set(Calendar.HOUR_OF_DAY, 8);
|
||||
reference.set(Calendar.MINUTE, 0);
|
||||
reference.set(Calendar.SECOND, 0);
|
||||
reference.set(Calendar.MILLISECOND, 0);
|
||||
return reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the amount of ordered articles by customers for the given article type in the time between begin and
|
||||
* end.
|
||||
*
|
||||
* @param article The article to search orders for.
|
||||
* @param begin The start time for the search (included)
|
||||
* @param end The end time for the search (excluded)
|
||||
* @return The number of articles that were ordered by customers in the given range.
|
||||
*/
|
||||
private Integer getOrderedAmounts(Article article, Calendar begin, Calendar end, CronjobController controller) {
|
||||
return controller.customerOrderRepository.countOrdersOfArticleInTimespan(
|
||||
article.id,
|
||||
new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the amount of ordered articles by customers for the given article type in the three days before the
|
||||
* given reference time. The return-array contains 3 fields: Index 0: Orders 72 to 48 hours ago; Index 1: Orders 48
|
||||
* to 24 hours ago; Index 2: Orders 24 to 0 hours ago.
|
||||
*
|
||||
* @param article The article for which the customer orders are checked.
|
||||
* @param time The reference time to use for calculation of the last orders.
|
||||
* @return A 3-element array containing the orders of the last three days.
|
||||
*/
|
||||
private Integer[] getOrderedAmounts(Article article, Calendar time, CronjobController controller) {
|
||||
Calendar oneDayBefore = (Calendar) time.clone();
|
||||
oneDayBefore.add(Calendar.DAY_OF_MONTH, -1);
|
||||
Calendar twoDaysBefore = (Calendar) time.clone();
|
||||
twoDaysBefore.add(Calendar.DAY_OF_MONTH, -2);
|
||||
Calendar threeDaysBefore = (Calendar) time.clone();
|
||||
threeDaysBefore.add(Calendar.DAY_OF_MONTH, -3);
|
||||
|
||||
return new Integer[]{ //
|
||||
getOrderedAmounts(article, threeDaysBefore, twoDaysBefore, controller), //
|
||||
getOrderedAmounts(article, twoDaysBefore, oneDayBefore, controller), //
|
||||
getOrderedAmounts(article, oneDayBefore, time, controller), //
|
||||
};
|
||||
}
|
||||
|
||||
private HashMap<ReadSupplierDataAction.ArticleIdentifier, ArticleOffer> mapArticleOffers(List<ArticleOffer> articleOffers) {
|
||||
HashMap<ReadSupplierDataAction.ArticleIdentifier, ArticleOffer> map = new HashMap<>();
|
||||
for (ArticleOffer articleOffer : articleOffers) {
|
||||
ReadSupplierDataAction.ArticleIdentifier identifier = new ReadSupplierDataAction.ArticleIdentifier(articleOffer.manufacturer, articleOffer.articleNumber);
|
||||
map.put(identifier, articleOffer);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeAt(Calendar time, CronjobController controller) {
|
||||
List<Supplier> suppliers = controller.supplierRepository.findAll();
|
||||
ReadSupplierDataAction.Result supplierData = new ReadSupplierDataAction(suppliers).finish();
|
||||
|
||||
// Save the new offers in the database
|
||||
List<ArticleOffer> allOffers = controller.articleOfferRepository.findAll();
|
||||
allOffers = new UpdateOffersAction(allOffers, supplierData.cheapestOffer).finish();
|
||||
controller.articleOfferRepository.saveAll(allOffers);
|
||||
|
||||
HashMap<ReadSupplierDataAction.ArticleIdentifier, ArticleOffer> mappedOffers = mapArticleOffers(allOffers);
|
||||
|
||||
// Reorder
|
||||
List<Article> allArticles = controller.articleRepository.findAll();
|
||||
for (Article article : allArticles) {
|
||||
Integer[] orderedAmounts = getOrderedAmounts(article, time, controller);
|
||||
|
||||
Integer undeliveredReorders = controller.supplierOrderRepository
|
||||
.countUndeliveredReorders(article.related.articleNumber);
|
||||
|
||||
int amountInStock = controller.warehouseBookingPositionSlotEntryRepository
|
||||
.getByArticle(article.id)
|
||||
.stream()
|
||||
.mapToInt(e -> e.newSumSlot)
|
||||
.sum();
|
||||
|
||||
ReorderAction action = new ReorderAction(article, orderedAmounts,
|
||||
undeliveredReorders,
|
||||
amountInStock,
|
||||
supplierData.cheapestOffer, mappedOffers);
|
||||
SupplierOrder order = action.finish();
|
||||
if (order != null) {
|
||||
controller.supplierOrderRepository.save(order);
|
||||
|
||||
// Create bookings for this order
|
||||
int netPrice = order.totalPriceNet;
|
||||
int vatPercent = order.ordered.vatPercent;
|
||||
int vatAmount = netPrice * vatPercent / 100;
|
||||
int grossPrice = netPrice + vatAmount;
|
||||
|
||||
// Obligation towards the supplier
|
||||
BookingAccountEntry mainAccount = controller.bookingAccountEntryRepository.getByMain()
|
||||
.orElseGet(BookingAccountEntry::newMain);
|
||||
BookingAccountEntry supplierAccount = controller.bookingAccountEntryRepository
|
||||
.getBySupplier(order.supplier.id)
|
||||
.orElseGet(() -> BookingAccountEntry.newSupplier(order.supplier));
|
||||
BookingReason obligationReason = new BookingReason(order);
|
||||
Booking obligationBooking = new CreateBookingAction(mainAccount,
|
||||
supplierAccount,
|
||||
obligationReason,
|
||||
grossPrice).finish();
|
||||
controller.bookingRepository.save(obligationBooking);
|
||||
|
||||
// Input Tax
|
||||
BookingAccountEntry vatAccount = controller.bookingAccountEntryRepository.getByVat()
|
||||
.orElseGet(BookingAccountEntry::newVat);
|
||||
mainAccount = controller.bookingAccountEntryRepository.getByMain().get();
|
||||
BookingReason inputTaxReason = new BookingReason(order);
|
||||
Booking inputTaxBooking = new CreateBookingAction(vatAccount, mainAccount, inputTaxReason, vatAmount)
|
||||
.finish();
|
||||
controller.bookingRepository.save(inputTaxBooking);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package org.hso.ecommerce.controller.cronjob;
|
||||
|
||||
import org.hso.ecommerce.entities.cron.BackgroundJob;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
class ScheduledCronjob {
|
||||
public final Calendar executionTime;
|
||||
public final ICronjob cronjob;
|
||||
public final BackgroundJob model;
|
||||
|
||||
public ScheduledCronjob(Calendar executionTime, ICronjob cronjob, BackgroundJob model) {
|
||||
this.executionTime = executionTime;
|
||||
this.cronjob = cronjob;
|
||||
this.model = model;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -53,7 +53,11 @@ public class InternArticleController {
|
||||
|
||||
for (Article article : articleRepository.findAll()) {
|
||||
UImodelArticles tmp = new UImodelArticles();
|
||||
tmp.addListedArticle(article, warehouseEntryRepository.getArticleStock(article.id).orElse(0));
|
||||
tmp.addListedArticle(article, warehouseEntryRepository
|
||||
.getByArticle(article.id)
|
||||
.stream()
|
||||
.mapToInt(e -> e.newSumSlot)
|
||||
.sum());
|
||||
totals.add(tmp);
|
||||
}
|
||||
|
||||
@ -63,10 +67,14 @@ public class InternArticleController {
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public String internListedArticlesId(Model model, @PathVariable String id) {
|
||||
int articleid = Integer.parseInt(id);
|
||||
long articleId = Long.parseLong(id);
|
||||
UImodelArticle total = new UImodelArticle();
|
||||
total.addArticle(articleRepository.findArticleById(articleid),
|
||||
warehouseEntryRepository.getArticleStock(articleid).orElse(0));
|
||||
total.addArticle(
|
||||
articleRepository.findById(articleId).get(),
|
||||
warehouseEntryRepository.getByArticle(articleId)
|
||||
.stream()
|
||||
.mapToInt(e -> e.newSumSlot)
|
||||
.sum());
|
||||
|
||||
model.addAttribute("ArticleID", total);
|
||||
return "intern/listedArticles/id";
|
||||
@ -112,11 +120,17 @@ public class InternArticleController {
|
||||
@PostMapping("/addArticle/{id}")
|
||||
public RedirectView addArticle(@PathVariable(required = true) String id) {
|
||||
// article is not already listed, create new one
|
||||
int offeredArticleID = Integer.parseInt(id);
|
||||
long offeredArticleID = Long.parseLong(id);
|
||||
|
||||
Article tmpArticle = new Article();
|
||||
|
||||
ArticleOffer offeredArticle = offersRepository.findOfferedArticleById(offeredArticleID);
|
||||
ArticleOffer offeredArticle = offersRepository.findById(offeredArticleID).get();
|
||||
|
||||
// Check for duplicates
|
||||
Optional<Article> related = articleRepository.findArticleByArticleOffer(offeredArticle);
|
||||
if (related.isPresent()) {
|
||||
return new RedirectView("../" + related.get().id);
|
||||
}
|
||||
|
||||
// set default values
|
||||
tmpArticle.description = "";
|
@ -21,7 +21,7 @@ public class WarehouseController {
|
||||
Model model,
|
||||
HttpServletRequest request
|
||||
) {
|
||||
model.addAttribute("bookings", warehouseBookingRepository.findAll());
|
||||
model.addAttribute("bookings", warehouseBookingRepository.findAllDesc());
|
||||
return "intern/warehouse/index";
|
||||
}
|
||||
}
|
@ -1,9 +1,5 @@
|
||||
package org.hso.ecommerce.controller.intern.accounting;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hso.ecommerce.entities.booking.Booking;
|
||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
|
||||
import org.hso.ecommerce.entities.booking.BookingReason;
|
||||
@ -13,6 +9,10 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
public class AccountingController {
|
||||
|
||||
@ -153,7 +153,9 @@ public class AccountingController {
|
||||
} else if (reason.customerPayment != null) {
|
||||
return "Bezahlung mit Kreditkarte " + reason.customerPayment.payment.creditCardNumber;
|
||||
} else if (reason.supplierOrder != null) {
|
||||
return "Lieferanten-Bestellung " + reason.supplierOrder.id;
|
||||
return "Lieferanten-Bestellung " + reason.supplierOrder.supplier.name;
|
||||
} else if (reason.supplierPayment != null) {
|
||||
return "Lieferanten-Zahlung " + reason.supplierPayment.name;
|
||||
} else {
|
||||
return "-";
|
||||
}
|
||||
@ -162,6 +164,10 @@ public class AccountingController {
|
||||
private String linkToReference(BookingReason reason) {
|
||||
if (reason.customerOrder != null) {
|
||||
return "/intern/customerOrders/" + reason.customerOrder.id;
|
||||
} else if (reason.supplierPayment != null) {
|
||||
return "/intern/suppliers/#q=" + reason.supplierPayment.id;
|
||||
} else if (reason.supplierOrder != null) {
|
||||
return "/intern/supplierOrders/#q=" + reason.supplierOrder.id;
|
||||
} else {
|
||||
return null;
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package org.hso.ecommerce.controller.intern.customers;
|
||||
|
||||
import org.hso.ecommerce.action.user.CreateDeliveryData;
|
||||
import org.hso.ecommerce.api.RestServiceForDelivery;
|
||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
||||
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
|
||||
import org.hso.ecommerce.uimodel.DeliveryData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("intern/customerOrders")
|
||||
public class CustomerOrderController {
|
||||
|
||||
@Autowired
|
||||
private final CustomerOrderRepository customerOrderRepository = null;
|
||||
@Autowired
|
||||
private final RestServiceForDelivery restServiceForDelivery = null;
|
||||
|
||||
@GetMapping("")
|
||||
public String internCustomerOrder(Model model) {
|
||||
List<CustomerOrder> orders = customerOrderRepository.getAllOrders();
|
||||
|
||||
List<CustomerOrderDelivery> customerOrderDeliveryDataMap = orders
|
||||
.stream()
|
||||
.map(o -> new CustomerOrderDelivery(o, CreateDeliveryData.getDeliveryDataFromCustomerOrder(o, customerOrderRepository, restServiceForDelivery)))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
model.addAttribute("orderDeliveryDataMap", customerOrderDeliveryDataMap);
|
||||
|
||||
return "intern/customerOrders/index";
|
||||
}
|
||||
|
||||
static class CustomerOrderDelivery {
|
||||
private CustomerOrder customerOrder;
|
||||
private DeliveryData deliveryData;
|
||||
|
||||
public CustomerOrderDelivery(CustomerOrder customerOrder, DeliveryData deliveryData) {
|
||||
this.customerOrder = customerOrder;
|
||||
this.deliveryData = deliveryData;
|
||||
}
|
||||
|
||||
public CustomerOrder getCustomerOrder() {
|
||||
return customerOrder;
|
||||
}
|
||||
|
||||
public DeliveryData getDeliveryData() {
|
||||
return deliveryData;
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public String internCustomerOrdersId(Model model,
|
||||
@PathVariable("id") String id
|
||||
) {
|
||||
CustomerOrder order = customerOrderRepository.findById(Long.parseLong(id)).get();
|
||||
DeliveryData deliveryData = CreateDeliveryData.getDeliveryDataFromCustomerOrder(order, customerOrderRepository, restServiceForDelivery);
|
||||
|
||||
model.addAttribute("order", order);
|
||||
model.addAttribute("deliveryData", deliveryData);
|
||||
|
||||
return "intern/customerOrders/id";
|
||||
}
|
||||
}
|
@ -1,9 +1,5 @@
|
||||
package org.hso.ecommerce.controller.intern.customers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.hso.ecommerce.controller.intern.accounting.AccountingController;
|
||||
import org.hso.ecommerce.controller.intern.accounting.AccountingController.ShortTemplateBookingResult;
|
||||
import org.hso.ecommerce.entities.booking.Booking;
|
||||
@ -13,12 +9,13 @@ import org.hso.ecommerce.repos.booking.BookingRepository;
|
||||
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
|
||||
import org.hso.ecommerce.repos.user.UserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Controller
|
||||
@ -97,24 +94,22 @@ public class CustomersIndexController {
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/resetPassword")
|
||||
public String resetPassword(@PathVariable("id") Long id,
|
||||
public String resetPassword(Model model,
|
||||
@PathVariable("id") Long id,
|
||||
@RequestParam("password") String password,
|
||||
@RequestParam("password2") String password2,
|
||||
HttpServletResponse response,
|
||||
HttpServletRequest request
|
||||
) {
|
||||
if (!password.equals(password2)) {
|
||||
request.setAttribute("error", "Passwörter stimmen nicht überein!");
|
||||
return "/intern/customers/id";
|
||||
return internCustomersId(model, id, response, request);
|
||||
}
|
||||
User user = userRepository.findById(id).get();
|
||||
if (!user.validatePassword(password)) {
|
||||
request.setAttribute("error", "Die Passwörter stimmen nicht mit dem Original überein!");
|
||||
return "/intern/customers/id";
|
||||
}
|
||||
user.setPassword("12345");
|
||||
user.setPassword(password);
|
||||
userRepository.save(user);
|
||||
request.setAttribute("info", "Passwort wurde auf 12345 geändert!");
|
||||
|
||||
return "/intern/customers/id";
|
||||
return "redirect:/intern/customers/" + id.toString();
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -48,7 +47,7 @@ public class SupplierOrderController {
|
||||
|
||||
List<UImodelSupplierOrder> totals = new ArrayList<UImodelSupplierOrder>();
|
||||
|
||||
for (SupplierOrder order : supplierOrderRepository.findAll()) {
|
||||
for (SupplierOrder order : supplierOrderRepository.findAllDesc()) {
|
||||
final Article article = articleRepository.findArticleByArticleOffer(order.ordered).orElse(null);
|
||||
totals.add(new UImodelSupplierOrder(order, article));
|
||||
}
|
||||
@ -115,6 +114,10 @@ public class SupplierOrderController {
|
||||
public String quantity;
|
||||
public String priceTotal;
|
||||
public boolean arrived;
|
||||
public String carrier;
|
||||
public String trackingId;
|
||||
public String estimatedArrival;
|
||||
|
||||
|
||||
public UImodelSupplierOrder(SupplierOrder order, Article article) {
|
||||
this.id = order.id;
|
||||
@ -125,9 +128,13 @@ public class SupplierOrderController {
|
||||
this.quantity = String.valueOf(order.numberOfUnits);
|
||||
this.priceTotal = String.format("%.2f", ((float) order.totalPriceNet / 100));
|
||||
|
||||
Date date = new Date();
|
||||
date.setTime(order.created.getTime());
|
||||
this.dateOrder = new SimpleDateFormat("dd.MM.yyyy").format(date);
|
||||
this.carrier = order.carrier != null ? order.carrier : " - ";
|
||||
this.trackingId = order.trackingId != null ? order.trackingId : " - ";
|
||||
this.estimatedArrival = order.estimatedArrival != null
|
||||
? new SimpleDateFormat("yyyy.MM.dd HH:00").format(order.estimatedArrival) + " Uhr"
|
||||
: " - ";
|
||||
|
||||
this.dateOrder = new SimpleDateFormat("yyyy.MM.dd").format(order.created);
|
||||
|
||||
arrived = order.delivered != null;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package org.hso.ecommerce.controller.intern.warehouse;
|
||||
|
||||
import org.hso.ecommerce.action.shop.EnableTrackingAction;
|
||||
import org.hso.ecommerce.api.RestServiceForDelivery;
|
||||
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
|
||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -10,6 +11,7 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.client.ResourceAccessException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@ -22,6 +24,9 @@ public class TodoController {
|
||||
@Autowired
|
||||
private final WarehouseBookingRepository warehouseBookingRepository = null;
|
||||
|
||||
@Autowired
|
||||
private final RestServiceForDelivery deliveryService = null;
|
||||
|
||||
@GetMapping("todo")
|
||||
public String accountingWarehouseTodo(
|
||||
Model model
|
||||
@ -75,7 +80,14 @@ public class TodoController {
|
||||
|
||||
// Update Delivery Date
|
||||
if (booking.get().reason.customerOrder != null) {
|
||||
EnableTrackingAction.addTrackingInfo(booking.get().reason.customerOrder);
|
||||
try{
|
||||
EnableTrackingAction.addTrackingInfo(deliveryService, booking.get().reason.customerOrder);
|
||||
}
|
||||
catch(ResourceAccessException e)
|
||||
{
|
||||
return "error/500";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
warehouseBookingRepository.save(booking.get());
|
@ -37,6 +37,7 @@ public class ShopArticleController {
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public String shopArticlesById(Model model,
|
||||
@RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart,
|
||||
@PathVariable("id") Long id,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response
|
||||
@ -52,11 +53,14 @@ public class ShopArticleController {
|
||||
}
|
||||
model.addAttribute("article", article);
|
||||
|
||||
if (warehouseBookingPositionSlotEntryRepository.getByArticle(id).get(0).newSumSlot > 0) { //check if in Stock
|
||||
model.addAttribute("inStock", true);
|
||||
} else {
|
||||
model.addAttribute("inStock", false);
|
||||
}
|
||||
int inStock = warehouseBookingPositionSlotEntryRepository
|
||||
.getByArticle(id)
|
||||
.stream()
|
||||
.mapToInt(e -> e.newSumSlot)
|
||||
.sum();
|
||||
|
||||
model.addAttribute("inStock", Math.min(inStock, 10));
|
||||
model.addAttribute("inCart", shoppingCart.getArticleCount(article));
|
||||
|
||||
List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(3, articleRepository.getAdvertisedArticles()); //get 3 advertised Articles
|
||||
model.addAttribute("commercialArticles", commercialArticles);
|
||||
@ -74,7 +78,7 @@ public class ShopArticleController {
|
||||
@RequestParam(value = "set_amount", required = false) Boolean setAmount,
|
||||
@RequestParam("fastcheckout") Boolean fastcheckout
|
||||
) {
|
||||
Article article = articleRepository.findArticleById(id);
|
||||
Article article = articleRepository.findById(id).orElse(null);
|
||||
|
||||
if (article == null) {
|
||||
request.setAttribute("error", "Der Artikel wurde nicht gefunden.");
|
@ -57,12 +57,26 @@ public class ShopCheckoutController {
|
||||
|
||||
CheckoutListTotals totals = new CheckoutListTotals();
|
||||
ArrayList<CheckoutListItem> items = new ArrayList<>();
|
||||
|
||||
boolean inValid = false;
|
||||
|
||||
for (ShoppingCart.ShoppingCartItem item : shoppingCart.getItems()) {
|
||||
Article article = articleRepository.findById(item.getArticleId()).get();
|
||||
|
||||
int inStock = wbeseRepo
|
||||
.getByArticle(item.getArticleId())
|
||||
.stream()
|
||||
.mapToInt(e -> e.newSumSlot)
|
||||
.sum();
|
||||
|
||||
totals.addItem(article, item.getAmount());
|
||||
items.add(new CheckoutListItem(item.getAmount(), article));
|
||||
items.add(new CheckoutListItem(item.getAmount(), Math.min(inStock, 10), article));
|
||||
if (item.getAmount() > inStock) {
|
||||
inValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
request.setAttribute("inValid", inValid);
|
||||
|
||||
request.setAttribute("checkoutItems", items);
|
||||
request.setAttribute("checkoutTotals", totals);
|
||||
@ -87,11 +101,13 @@ public class ShopCheckoutController {
|
||||
public int amount;
|
||||
public Article article;
|
||||
public int total;
|
||||
public int inStock;
|
||||
|
||||
public CheckoutListItem(int amount, Article article) {
|
||||
public CheckoutListItem(int amount, int inStock, Article article) {
|
||||
this.amount = amount;
|
||||
this.article = article;
|
||||
this.total = amount * article.getPriceGross();
|
||||
this.inStock = inStock;
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,7 +125,7 @@ public class ShopCheckoutController {
|
||||
) {
|
||||
|
||||
if (shoppingCart.getRevision() != cartRevision) {
|
||||
request.setAttribute("error", "Der Warenkorb wurde zwischenzeitlich bearbeitet. Daher die Kaufvorgang nicht abgeschlossen werden. Bitte versuchen Sie es erneut.");
|
||||
request.setAttribute("error", "Der Warenkorb wurde zwischenzeitlich bearbeitet. Daher konnte der Kaufvorgang nicht abgeschlossen werden. Bitte versuchen Sie es erneut.");
|
||||
response.setStatus(HttpServletResponse.SC_CONFLICT);
|
||||
return "shop/checkout";
|
||||
}
|
||||
@ -140,6 +156,11 @@ public class ShopCheckoutController {
|
||||
bookingRepository.saveAll(result.bookings);
|
||||
warehouseBookingRepository.save(result.warehouseBooking);
|
||||
|
||||
if (user.defaultPayment == null) {
|
||||
user.defaultPayment = PaymentMethod.fromCreditCardNumber(cardnumber);
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
shoppingCart.clear();
|
||||
|
||||
} catch (CreateOrderAction.ArticleNotInStockException e) {
|