Compare commits
214 Commits
b38ffdea34
...
1.0.0
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
e037b75f7c | |||
486f237135 | |||
396d3fda14 | |||
3b1d378968 | |||
5a0b303601
|
|||
d5825ba7a0
|
|||
8199bd8a23 | |||
774e62f892
|
|||
e1c00eca8f
|
|||
e904eba7a4 | |||
6284a4d7bf | |||
3b364ae815
|
|||
2ba4968556 | |||
18f35c43e7 | |||
709c80fa37 | |||
87bade71b4 | |||
b6eb66e348 | |||
0a7722d612 | |||
d121532fba
|
|||
985169117d | |||
fa610cae3b | |||
3bb3c5b513 | |||
15616e05f3 | |||
0ab185f143 | |||
1dd4b5cfa5 | |||
266bba095a | |||
fa7bdf2f7e | |||
76550be9e7 | |||
ef8aa826a3 | |||
114453b5b9 | |||
7397698929 | |||
9fa2c1f3a7
|
|||
327ba182f5
|
|||
30226c5c19 | |||
e0e853a575 | |||
d2b98f083b | |||
a41889b2cb | |||
0f7d248d40 | |||
11ade7b8f9 | |||
a664b42853 | |||
56f4ec0dda | |||
1590821f64 | |||
16803d2b12 | |||
938d16301d | |||
5a59ac11b0 | |||
c194f44308 | |||
fc68e231d3 | |||
6d8a36b7ac | |||
49e26039a3 | |||
28834431ce | |||
5691f0eeec | |||
7f643987f3
|
|||
6b8bf25e0e | |||
ebeba72278 | |||
f671baf7f0 | |||
691916894f
|
|||
e7e2017825 | |||
03d557d67b
|
|||
8fff0e2dca
|
|||
6317780dfa | |||
78a7ad053a | |||
f6554629d7 | |||
eb82d05f4f | |||
41320473d9 | |||
bd6be54149 | |||
99612165f5 | |||
9dff6adb3d | |||
445b504188 | |||
bd8b3db7f3 | |||
8a4ff4cfa5 | |||
2245309198 | |||
d078c44027 | |||
bd8b07990b | |||
2f4c45ed71 | |||
b600040bf3 | |||
4f5e1fe185 | |||
f348d33c94
|
|||
6f90b9c941
|
|||
e53c1e0872
|
|||
e138476d76 | |||
c1b9588189 | |||
5e05100d21 | |||
93a5863fbe | |||
7f652e38f0 | |||
0061d25082
|
|||
d4ddd8a9a3 | |||
a192f0ac51 | |||
9660e52f34 | |||
72ddfa42ef | |||
fc239983a7 | |||
5e1170839e | |||
2ef9eb29ac | |||
f4ba79a4cd | |||
976e2d1949 | |||
b7134a60da | |||
ff4c984f54 | |||
21502a0b1c
|
|||
3775f96f3f | |||
2394157be8 | |||
dfa528484c | |||
1cb52a20d4 | |||
67c101ebea | |||
657d315850 | |||
5d7ecbdfb7 | |||
c8d3ab3ff0 | |||
8a2eff1fe9 | |||
e4d6642d61 | |||
9406bbc4ac | |||
e5b28250c2 | |||
db1d3d31b2 | |||
819cca7f2a | |||
846e448f01 | |||
614a929592 | |||
60699ed847 | |||
83ad1f3999 | |||
5b4c0be1c8 | |||
0256c19e8f | |||
adcd840154 | |||
b5495bda3d | |||
106b00a907 | |||
7c73f69865 | |||
86a2e5d8c2 | |||
8d65998ac2 | |||
178f98d664 | |||
33ff754b9d | |||
8ede86fdce | |||
39eefbdd3e | |||
6e3d1cbcf5 | |||
1ce9a971ba | |||
4711527971 | |||
b7b5c7a6b3 | |||
bba4173269 | |||
e1d7becc2e |
0
delivery/gradlew
vendored
Normal file → Executable file
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.Delivery;
|
||||||
import org.hso.ecommerce.supplier.data.DeliveryManager;
|
import org.hso.ecommerce.supplier.data.DeliveryManager;
|
||||||
import org.hso.ecommerce.supplier.data.ReturnStatus;
|
import org.hso.ecommerce.supplier.data.ReturnStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
@ -19,14 +19,19 @@ public class RequestController {
|
|||||||
public String supplier(HttpServletResponse response, HttpServletRequest request, @RequestBody Delivery delivery) {
|
public String supplier(HttpServletResponse response, HttpServletRequest request, @RequestBody Delivery delivery) {
|
||||||
DeliveryManager.getInstance().add(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) {
|
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 {
|
public class Delivery {
|
||||||
|
|
||||||
private String[] states = {"Bestellung eingegangen","Bestellung auf dem Weg","Lieferung erfolgreich"};
|
private String[] states = {"Bestellung eingegangen", "Bestellung auf dem Weg", "Lieferung erfolgreich"};
|
||||||
private int[] timeBorder = {4,24};
|
private int[] timeBorder = {4, 24};
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private String address;
|
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.name = name;
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.uuid = UUID.randomUUID();
|
this.uuid = UUID.randomUUID().toString();
|
||||||
this.creationTime = new Date();
|
this.creationTime = new Date();
|
||||||
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
|
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();
|
Date now = new Date();
|
||||||
Long timeNow = now.getTime();
|
long timeNow = now.getTime();
|
||||||
Long creationTime = this.creationTime.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));
|
double hour = (((diff / 1000.0) / 3600.0));
|
||||||
|
|
||||||
for (int i = 0; i < timeBorder.length; i++) {
|
for (int i = 0; i < timeBorder.length; i++) {
|
||||||
|
|
||||||
if(hour < timeBorder[i])
|
if (hour < timeBorder[i])
|
||||||
return states[i];
|
return states[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,15 +61,14 @@ public class Delivery {
|
|||||||
return estimatedArrival;
|
return estimatedArrival;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Date addDays(Date date, int days)
|
private static Date addDays(Date date, int days) {
|
||||||
{
|
|
||||||
Calendar cal = Calendar.getInstance();
|
Calendar cal = Calendar.getInstance();
|
||||||
cal.setTime(date);
|
cal.setTime(date);
|
||||||
cal.add(Calendar.DATE, days);
|
cal.add(Calendar.DATE, days);
|
||||||
return cal.getTime();
|
return cal.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getUuid() {
|
public String getUuid() {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
package org.hso.ecommerce.supplier.data;
|
package org.hso.ecommerce.supplier.data;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class DeliveryManager {
|
public class DeliveryManager {
|
||||||
|
|
||||||
private List<Delivery> deliveryList;
|
private HashMap<String, Delivery> deliveryList;
|
||||||
private static DeliveryManager deliveryManager;
|
private static DeliveryManager deliveryManager;
|
||||||
|
|
||||||
private DeliveryManager()
|
private DeliveryManager()
|
||||||
{
|
{
|
||||||
deliveryList = new ArrayList<>();
|
deliveryList = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DeliveryManager getInstance () {
|
public static DeliveryManager getInstance() {
|
||||||
|
|
||||||
if (DeliveryManager.deliveryManager == null) {
|
if (DeliveryManager.deliveryManager == null) {
|
||||||
DeliveryManager.deliveryManager = new DeliveryManager();
|
DeliveryManager.deliveryManager = new DeliveryManager();
|
||||||
@ -22,13 +20,11 @@ public class DeliveryManager {
|
|||||||
return DeliveryManager.deliveryManager;
|
return DeliveryManager.deliveryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean add(Delivery delivery)
|
public void add(Delivery delivery) {
|
||||||
{
|
deliveryList.put(delivery.getUuid(), delivery);
|
||||||
return deliveryList.add(delivery);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Delivery getDeliveryByeID(String uuid)
|
public Delivery getDeliveryByID(String uuid) {
|
||||||
{
|
return deliveryList.getOrDefault(uuid, null);
|
||||||
return deliveryList.parallelStream().filter(d -> d.getUuid().equals(UUID.fromString(uuid))).findAny().get();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
prototype/.gitignore
vendored
2
prototype/.gitignore
vendored
@ -5,3 +5,5 @@ e-commerce.db
|
|||||||
./e-commerce.iml
|
./e-commerce.iml
|
||||||
./e-commerce.ipr
|
./e-commerce.ipr
|
||||||
./e-commerce.iws
|
./e-commerce.iws
|
||||||
|
|
||||||
|
config.yml
|
||||||
|
@ -28,6 +28,7 @@ dependencies {
|
|||||||
implementation 'com.github.gwenn:sqlite-dialect:0.1.0'
|
implementation 'com.github.gwenn:sqlite-dialect:0.1.0'
|
||||||
implementation 'org.springframework.boot:spring-boot-devtools'
|
implementation 'org.springframework.boot:spring-boot-devtools'
|
||||||
implementation 'org.xerial:sqlite-jdbc:3.31.1'
|
implementation 'org.xerial:sqlite-jdbc:3.31.1'
|
||||||
|
implementation 'org.yaml:snakeyaml:1.26'
|
||||||
testCompile("org.springframework.boot:spring-boot-starter-test")
|
testCompile("org.springframework.boot:spring-boot-starter-test")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
0
prototype/gradlew
vendored
Normal file → Executable file
0
prototype/gradlew
vendored
Normal file → Executable file
3
prototype/scripts/addsupplierorders.sql
Normal file
3
prototype/scripts/addsupplierorders.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
INSERT INTO supplier_orders ("created", "delivered", "number_of_units", "price_per_unit_net_cent", "total_price_net", "ordered_id", "supplier_id")
|
||||||
|
VALUES ('0', '0', '42', '42', '42', '1', '1');
|
@ -10,6 +10,7 @@ public class CreateBookingAction {
|
|||||||
|
|
||||||
public CreateBookingAction(BookingAccountEntry source, BookingAccountEntry destination, BookingReason reason, int amountCent) {
|
public CreateBookingAction(BookingAccountEntry source, BookingAccountEntry destination, BookingReason reason, int amountCent) {
|
||||||
booking = new Booking();
|
booking = new Booking();
|
||||||
|
booking.created = new java.sql.Timestamp(System.currentTimeMillis());
|
||||||
booking.reason = reason;
|
booking.reason = reason;
|
||||||
booking.amountCent = amountCent;
|
booking.amountCent = amountCent;
|
||||||
|
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
package org.hso.ecommerce.action.cronjob;
|
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.ArticleIdentifier;
|
||||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.Offer;
|
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.Offer;
|
||||||
import org.hso.ecommerce.api.SupplierService;
|
import org.hso.ecommerce.api.SupplierService;
|
||||||
@ -14,6 +11,9 @@ import org.hso.ecommerce.entities.supplier.SupplierOrder;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class ReorderAction {
|
public class ReorderAction {
|
||||||
private static final Logger log = LoggerFactory.getLogger(ReorderAction.class);
|
private static final Logger log = LoggerFactory.getLogger(ReorderAction.class);
|
||||||
|
|
||||||
@ -102,6 +102,10 @@ public class ReorderAction {
|
|||||||
createdOrder.numberOfUnits = confirm.quantity;
|
createdOrder.numberOfUnits = confirm.quantity;
|
||||||
createdOrder.pricePerUnitNetCent = confirm.pricePerUnitNetCent;
|
createdOrder.pricePerUnitNetCent = confirm.pricePerUnitNetCent;
|
||||||
createdOrder.totalPriceNet = confirm.totalPriceNetCharged;
|
createdOrder.totalPriceNet = confirm.totalPriceNetCharged;
|
||||||
|
createdOrder.carrier = confirm.carrier;
|
||||||
|
createdOrder.trackingId = confirm.trackingId;
|
||||||
|
createdOrder.estimatedArrival = Timestamp.valueOf(confirm.estimatedArrival);
|
||||||
|
|
||||||
return createdOrder;
|
return createdOrder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
|
|||||||
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -74,9 +75,15 @@ public class CreateOrderAction {
|
|||||||
CustomerPayment payment = createPayment();
|
CustomerPayment payment = createPayment();
|
||||||
|
|
||||||
List<Booking> bookingList = new ArrayList<>();
|
List<Booking> bookingList = new ArrayList<>();
|
||||||
bookingList.add(new CreateBookingAction(latestUserBooking, latestMainBooking, new BookingReason(order), order.totalGrossCent).finish());
|
Booking purchaseBooking = new CreateBookingAction(
|
||||||
bookingList.add(new CreateBookingAction(null, latestUserBooking, new BookingReason(payment), order.totalGrossCent).finish());
|
latestUserBooking, latestMainBooking, new BookingReason(order), order.totalGrossCent).finish();
|
||||||
bookingList.add(new CreateBookingAction(latestMainBooking, latestVatBooking, new BookingReason(order), order.totalVatCent).finish());
|
Booking paymentBooking = new CreateBookingAction(
|
||||||
|
null, purchaseBooking.source /* userAccount */, new BookingReason(payment), order.totalGrossCent).finish();
|
||||||
|
Booking vatBooking = new CreateBookingAction(
|
||||||
|
purchaseBooking.destination /* mainAccount */, latestVatBooking, new BookingReason(order), order.totalVatCent).finish();
|
||||||
|
bookingList.add(purchaseBooking);
|
||||||
|
bookingList.add(paymentBooking);
|
||||||
|
bookingList.add(vatBooking);
|
||||||
|
|
||||||
WarehouseBooking warehouseBooking = createWarehouseBooking(order);
|
WarehouseBooking warehouseBooking = createWarehouseBooking(order);
|
||||||
|
|
||||||
@ -95,7 +102,14 @@ public class CreateOrderAction {
|
|||||||
for (OrderItem item : orderItems) {
|
for (OrderItem item : orderItems) {
|
||||||
int needed = item.quantity;
|
int needed = item.quantity;
|
||||||
|
|
||||||
|
// Sort for most empty slot first;
|
||||||
|
item.availableSlots.sort(Comparator.comparingInt(a -> a.newSumSlot));
|
||||||
|
|
||||||
for (WarehouseBookingPositionSlotEntry slot : item.availableSlots) {
|
for (WarehouseBookingPositionSlotEntry slot : item.availableSlots) {
|
||||||
|
if (slot.newSumSlot == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int remove = Math.min(slot.newSumSlot, needed);
|
int remove = Math.min(slot.newSumSlot, needed);
|
||||||
needed -= remove;
|
needed -= remove;
|
||||||
|
|
||||||
@ -103,7 +117,7 @@ public class CreateOrderAction {
|
|||||||
|
|
||||||
bookingPosition.article = item.article;
|
bookingPosition.article = item.article;
|
||||||
bookingPosition.amount = -remove;
|
bookingPosition.amount = -remove;
|
||||||
bookingPosition.slotEntry = slot.copyAddAmount(-remove);
|
bookingPosition.slotEntry = slot.copyAddAmount(-remove, item.article);
|
||||||
bookingPosition.booking = booking;
|
bookingPosition.booking = booking;
|
||||||
|
|
||||||
booking.positions.add(bookingPosition);
|
booking.positions.add(bookingPosition);
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
package org.hso.ecommerce.action.shop;
|
package org.hso.ecommerce.action.shop;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.api.RestServiceForDelivery;
|
||||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
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 class EnableTrackingAction {
|
||||||
|
|
||||||
public static void addTrackingInfo(CustomerOrder customerOrder) {
|
public static void addTrackingInfo(RestServiceForDelivery deliveryService, CustomerOrder customerOrder) throws ResourceAccessException {
|
||||||
// TODO:
|
customerOrder.inDeliverySince = new Timestamp(new Date().getTime());
|
||||||
customerOrder.trackingId = "555-NASE";
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package org.hso.ecommerce.action.user;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.entities.booking.PaymentMethod;
|
||||||
|
import org.hso.ecommerce.entities.user.User;
|
||||||
|
import org.hso.ecommerce.repos.user.UserRepository;
|
||||||
|
|
||||||
|
public class UpdateUserSettingsAction {
|
||||||
|
|
||||||
|
private User user;
|
||||||
|
private UserRepository repository;
|
||||||
|
|
||||||
|
public UpdateUserSettingsAction(User user, UserRepository repository) {
|
||||||
|
this.user = user;
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateResult updateEmail(String newMail) {
|
||||||
|
UpdateResult result = new UpdateResult(false);
|
||||||
|
if (!newMail.contains("@")) {
|
||||||
|
result.errorString = "Ändern der Email-Addresse nicht möglich. Bitte versuchen Sie es erneut.";
|
||||||
|
} else {
|
||||||
|
this.user.email = newMail;
|
||||||
|
this.repository.save(this.user);
|
||||||
|
result.updated = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateResult updatePassword(String oldPassword, String password1, String password2) {
|
||||||
|
UpdateResult result = new UpdateResult(false);
|
||||||
|
if (this.user.validatePassword(oldPassword)) {
|
||||||
|
if (password1.equals(password2)) {
|
||||||
|
if (!password1.equals(oldPassword)) {
|
||||||
|
this.user.setPassword(password1);
|
||||||
|
this.repository.save(this.user);
|
||||||
|
result.updated = true;
|
||||||
|
} else {
|
||||||
|
result.errorString = "Das neue Passwort entspricht dem alten Passwort.";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.errorString = "Die beiden neuen Passwörter stimmen nicht überein. Bitte versuchen Sie es erneut.";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.errorString = "Das eingegebene alte Passwort stimmt nicht mit dem momentan gespeicherten Passwort überein. Bitte versuchen Sie es erneut.";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateResult updateShippingInfo(String salutation, String name, String address) {
|
||||||
|
this.user.salutation = salutation;
|
||||||
|
this.user.defaultDeliveryAddress.name = name;
|
||||||
|
this.user.defaultDeliveryAddress.addressString = address;
|
||||||
|
this.repository.save(this.user);
|
||||||
|
return new UpdateResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateResult updatePaymentInfo(String creditCardNumber) {
|
||||||
|
UpdateResult result = new UpdateResult(false);
|
||||||
|
if (creditCardNumber.matches("[0-9]+")) {
|
||||||
|
this.user.defaultPayment = PaymentMethod.fromCreditCardNumber(creditCardNumber);
|
||||||
|
this.repository.save(this.user);
|
||||||
|
result.updated = true;
|
||||||
|
} else {
|
||||||
|
result.errorString = "Kreditkartennummer darf nur Zahlen enthalten. Bitte versuchen Sie es erneut.";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UpdateResult {
|
||||||
|
public boolean updated; //if true worked, if false not worked
|
||||||
|
public String errorString;
|
||||||
|
|
||||||
|
public UpdateResult(boolean updated, String errorString) {
|
||||||
|
this.updated = updated;
|
||||||
|
this.errorString = errorString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateResult(boolean updated) {
|
||||||
|
this.updated = updated;
|
||||||
|
this.errorString = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
package org.hso.ecommerce.action.warehouse;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CalculateWarehouseStatsAction {
|
||||||
|
|
||||||
|
private List<WarehouseBookingPositionSlotEntry> entryList;
|
||||||
|
|
||||||
|
public CalculateWarehouseStatsAction(List<WarehouseBookingPositionSlotEntry> everyCurrentEntry) {
|
||||||
|
this.entryList = everyCurrentEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarehouseStats finish() {
|
||||||
|
int numArticles = calculateNumArticles();
|
||||||
|
double efficiency = calculateEfficiency();
|
||||||
|
double ratioUsedSlots = calculateRatioSlotsUsed();
|
||||||
|
|
||||||
|
return new WarehouseStats(numArticles, efficiency, ratioUsedSlots);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double calculateRatioSlotsUsed() {
|
||||||
|
int used = 0;
|
||||||
|
|
||||||
|
for (WarehouseBookingPositionSlotEntry entry : entryList) {
|
||||||
|
if (entry.newSumSlot > 0) {
|
||||||
|
used++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((double) used) / entryList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private double calculateEfficiency() {
|
||||||
|
double e = 0;
|
||||||
|
|
||||||
|
for (WarehouseBookingPositionSlotEntry entry : entryList) {
|
||||||
|
if (entry.newSumSlot > 0) {
|
||||||
|
e += entry.newSumSlot / (double) entry.article.warehouseUnitsPerSlot;
|
||||||
|
} else {
|
||||||
|
e += 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return e / entryList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int calculateNumArticles() {
|
||||||
|
HashSet<Long> articleIds = new HashSet<>();
|
||||||
|
|
||||||
|
for (WarehouseBookingPositionSlotEntry entry : entryList) {
|
||||||
|
if (entry.newSumSlot > 0) {
|
||||||
|
articleIds.add(entry.article.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return articleIds.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WarehouseStats {
|
||||||
|
public int numArticles;
|
||||||
|
public double efficiency;
|
||||||
|
public double ratioUsedSlots;
|
||||||
|
|
||||||
|
WarehouseStats(int numArticles, double efficiency, double ratioUsedSlots) {
|
||||||
|
this.numArticles = numArticles;
|
||||||
|
this.efficiency = efficiency;
|
||||||
|
this.ratioUsedSlots = ratioUsedSlots;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package org.hso.ecommerce.action.warehouse;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.entities.booking.BookingReason;
|
||||||
|
import org.hso.ecommerce.entities.shop.Article;
|
||||||
|
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
|
||||||
|
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPosition;
|
||||||
|
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class CreateManuelBookingAction {
|
||||||
|
|
||||||
|
private Article article;
|
||||||
|
private int amount;
|
||||||
|
private Optional<WarehouseBookingPositionSlotEntry> source;
|
||||||
|
private Optional<WarehouseBookingPositionSlotEntry> destination;
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
public CreateManuelBookingAction(Article article, int amount, Optional<WarehouseBookingPositionSlotEntry> source, Optional<WarehouseBookingPositionSlotEntry> destination, String reason) {
|
||||||
|
this.article = article;
|
||||||
|
this.amount = amount;
|
||||||
|
this.source = source;
|
||||||
|
this.destination = destination;
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarehouseBooking finish() throws ArticleSlotConstraintFailedException {
|
||||||
|
WarehouseBooking booking = new WarehouseBooking();
|
||||||
|
booking.created = new Timestamp(new Date().getTime());
|
||||||
|
booking.reason = new BookingReason(reason);
|
||||||
|
|
||||||
|
if (source.isPresent()) {
|
||||||
|
|
||||||
|
if (source.get().article.id != article.id) {
|
||||||
|
throw new ArticleSlotConstraintArticleTypeFailedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
|
||||||
|
bookingPosition.booking = booking;
|
||||||
|
|
||||||
|
bookingPosition.article = article;
|
||||||
|
bookingPosition.amount = -amount;
|
||||||
|
bookingPosition.slotEntry = source.get().copyAddAmount(-amount, article);
|
||||||
|
|
||||||
|
if (bookingPosition.slotEntry.newSumSlot < 0 || bookingPosition.slotEntry.newSumSlot > article.warehouseUnitsPerSlot) {
|
||||||
|
throw new ArticleSlotConstraintFailedException("The quantity of article can only be set in bounds.");
|
||||||
|
}
|
||||||
|
|
||||||
|
booking.positions.add(bookingPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destination.isPresent()) {
|
||||||
|
|
||||||
|
if (destination.get().article.id != article.id && destination.get().newSumSlot > 0) {
|
||||||
|
throw new ArticleSlotConstraintArticleTypeFailedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
|
||||||
|
bookingPosition.booking = booking;
|
||||||
|
|
||||||
|
bookingPosition.article = article;
|
||||||
|
bookingPosition.amount = amount;
|
||||||
|
bookingPosition.slotEntry = destination.get().copyAddAmount(amount, article);
|
||||||
|
|
||||||
|
if (bookingPosition.slotEntry.newSumSlot < 0 || bookingPosition.slotEntry.newSumSlot > article.warehouseUnitsPerSlot) {
|
||||||
|
throw new ArticleSlotConstraintFailedException("The quantity of article can only be set in bounds.");
|
||||||
|
}
|
||||||
|
|
||||||
|
booking.positions.add(bookingPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return booking;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ArticleSlotConstraintFailedException extends Exception {
|
||||||
|
public ArticleSlotConstraintFailedException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArticleSlotConstraintFailedException() {
|
||||||
|
super("The quantity of article can only be set in bounds.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ArticleSlotConstraintArticleTypeFailedException extends ArticleSlotConstraintFailedException {
|
||||||
|
public ArticleSlotConstraintArticleTypeFailedException() {
|
||||||
|
super("The Article in the slot entry does not match.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
package org.hso.ecommerce.action.warehouse;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.entities.booking.BookingReason;
|
||||||
|
import org.hso.ecommerce.entities.shop.Article;
|
||||||
|
import org.hso.ecommerce.entities.supplier.SupplierOrder;
|
||||||
|
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
|
||||||
|
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPosition;
|
||||||
|
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SupplierOrderArrivedAction {
|
||||||
|
|
||||||
|
private final Article article;
|
||||||
|
private final ArrayList<WarehouseBookingPositionSlotEntry> warehouseCandidates;
|
||||||
|
private final SupplierOrder order;
|
||||||
|
|
||||||
|
public SupplierOrderArrivedAction(List<WarehouseBookingPositionSlotEntry> warehouseCandidates, SupplierOrder order, Article article) {
|
||||||
|
this.warehouseCandidates = new ArrayList<>(warehouseCandidates);
|
||||||
|
this.order = order;
|
||||||
|
this.article = article;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result finish() throws NoSpaceInWarehouseException {
|
||||||
|
// Sort for most filled slot first;
|
||||||
|
warehouseCandidates.sort((b, a) -> Integer.compare(a.newSumSlot, b.newSumSlot));
|
||||||
|
|
||||||
|
int needed = order.numberOfUnits;
|
||||||
|
|
||||||
|
WarehouseBooking booking = new WarehouseBooking();
|
||||||
|
booking.created = new Timestamp(new Date().getTime());
|
||||||
|
booking.reason = new BookingReason(order);
|
||||||
|
|
||||||
|
for (WarehouseBookingPositionSlotEntry entry : warehouseCandidates) {
|
||||||
|
int canBeAdded = article.warehouseUnitsPerSlot - entry.newSumSlot;
|
||||||
|
|
||||||
|
if (canBeAdded == 0) {
|
||||||
|
// this slot is full, skip
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int willBeAdded = Math.min(canBeAdded, needed);
|
||||||
|
needed -= willBeAdded;
|
||||||
|
|
||||||
|
WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
|
||||||
|
|
||||||
|
bookingPosition.article = article;
|
||||||
|
bookingPosition.amount = willBeAdded;
|
||||||
|
bookingPosition.slotEntry = entry.copyAddAmount(willBeAdded, article);
|
||||||
|
bookingPosition.booking = booking;
|
||||||
|
|
||||||
|
booking.positions.add(bookingPosition);
|
||||||
|
|
||||||
|
if (needed == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needed > 0) {
|
||||||
|
throw new NoSpaceInWarehouseException(article);
|
||||||
|
}
|
||||||
|
|
||||||
|
order.delivered = new Timestamp(new Date().getTime());
|
||||||
|
return new Result(order, booking);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Result extends Exception {
|
||||||
|
|
||||||
|
private final SupplierOrder order;
|
||||||
|
private final WarehouseBooking booking;
|
||||||
|
|
||||||
|
public Result(SupplierOrder order, WarehouseBooking booking) {
|
||||||
|
this.order = order;
|
||||||
|
this.booking = booking;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SupplierOrder getOrder() {
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarehouseBooking getBooking() {
|
||||||
|
return booking;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class NoSpaceInWarehouseException extends Exception {
|
||||||
|
private Article article;
|
||||||
|
|
||||||
|
public NoSpaceInWarehouseException(Article article) {
|
||||||
|
super("The quantity of article '" + article.title + "' does not fit in warehouse.");
|
||||||
|
this.article = article;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Article getArticle() {
|
||||||
|
return article;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
package org.hso.ecommerce.api.data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
public class OrderConfirmation {
|
public class OrderConfirmation {
|
||||||
public String manufacturer;
|
public String manufacturer;
|
||||||
public String articleNumber;
|
public String articleNumber;
|
||||||
@ -9,4 +11,8 @@ public class OrderConfirmation {
|
|||||||
public int pricePerUnitNetCent;
|
public int pricePerUnitNetCent;
|
||||||
public int discountNetCent;
|
public int discountNetCent;
|
||||||
public int totalPriceNetCharged;
|
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 class Application {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
SpringApplication.run(Application.class, args);
|
SpringApplication.run(Application.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,186 +0,0 @@
|
|||||||
package org.hso.ecommerce.app;
|
|
||||||
|
|
||||||
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.RequestParam;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import javax.servlet.http.HttpSession;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO clean up this class
|
|
||||||
*/
|
|
||||||
@Controller
|
|
||||||
public class RequestController {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private final UserRepository userRepository = null;
|
|
||||||
|
|
||||||
static int notSoRandom = 0;
|
|
||||||
|
|
||||||
@GetMapping("/login")
|
|
||||||
public String login() {
|
|
||||||
return "login";
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/login")
|
|
||||||
public String loginPost(
|
|
||||||
HttpServletRequest request,
|
|
||||||
HttpServletResponse response,
|
|
||||||
@RequestParam("username") String username,
|
|
||||||
@RequestParam("password") String password,
|
|
||||||
HttpSession session
|
|
||||||
) {
|
|
||||||
String gto = (String) session.getAttribute("afterLogin");
|
|
||||||
|
|
||||||
Optional<User> user = userRepository.findByEmail(username);
|
|
||||||
if (!user.isPresent()) {
|
|
||||||
request.setAttribute("error", "Email Adresse falsch.");
|
|
||||||
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
|
||||||
return "login";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user.get().validatePassword(password)) {
|
|
||||||
request.setAttribute("error", "Passwort falsch.");
|
|
||||||
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
|
||||||
return "login";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user.get().isActive) {
|
|
||||||
request.setAttribute("error", "User ist deaktiviert.");
|
|
||||||
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
|
||||||
return "login";
|
|
||||||
}
|
|
||||||
|
|
||||||
session.setAttribute("userId", user.get().getId());
|
|
||||||
|
|
||||||
if (gto != null && gto.startsWith("/")) {
|
|
||||||
return "redirect:" + gto;
|
|
||||||
} else {
|
|
||||||
return "redirect:/";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/logout")
|
|
||||||
public String logoutPost(HttpServletResponse response,
|
|
||||||
HttpSession session
|
|
||||||
) {
|
|
||||||
session.removeAttribute("userId");
|
|
||||||
return "redirect:/";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/")
|
|
||||||
public String intern() {
|
|
||||||
return "intern/index";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/customers/")
|
|
||||||
public String internCustomers() {
|
|
||||||
return "intern/customers/index";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/customers/{id}")
|
|
||||||
public String internCustomersId() {
|
|
||||||
return "intern/customers/id";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/customerOrders/")
|
|
||||||
public String internCustomerOrder() {
|
|
||||||
return "intern/customerOrders/index";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/customerOrders/{id}")
|
|
||||||
public String internCustomerOrdersId() {
|
|
||||||
return "intern/customerOrders/id";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/suppliers/")
|
|
||||||
public String internSuppliers() {
|
|
||||||
return "intern/suppliers/index";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/suppliers/{id}")
|
|
||||||
public String internSuppliersId() {
|
|
||||||
return "intern/suppliers/id";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/supplierOrders/")
|
|
||||||
public String internSupplierOrders() {
|
|
||||||
return "intern/supplierOrders/index";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/supplierOrders/{id}")
|
|
||||||
public String internSupplierOrdersId() {
|
|
||||||
return "intern/supplierOrders/id";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
@GetMapping("/intern/suppliersOffers")
|
|
||||||
public String internSuppliersOffers() {
|
|
||||||
return "intern/offeredArticles/index";
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/intern/accounting/")
|
|
||||||
public String accounting() {
|
|
||||||
return "intern/accounting/index";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/accounting/vat")
|
|
||||||
public String accountingVat() {
|
|
||||||
return "intern/accounting/vat";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/accounting/main")
|
|
||||||
public String accountingIntern() {
|
|
||||||
return "intern/accounting/main";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/accounting/addManual")
|
|
||||||
public String accountingAddManual() {
|
|
||||||
return "intern/accounting/addManual";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/warehouse/")
|
|
||||||
public String accountingWarehouse() {
|
|
||||||
return "intern/warehouse/index";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/warehouse/todo")
|
|
||||||
public String accountingWarehouseTodo() {
|
|
||||||
return "intern/warehouse/todo";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/warehouse/addManual")
|
|
||||||
public String accountingWarehouseAddManual() {
|
|
||||||
return "intern/warehouse/addManual";
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/intern/warehouse/progress/{id}")
|
|
||||||
public String accountingWarehouseProgressIdPost(HttpServletResponse response) {
|
|
||||||
if ((notSoRandom++) % 2 == 1) {
|
|
||||||
return "redirect:/intern/warehouse/progress/450";
|
|
||||||
} else {
|
|
||||||
response.setStatus(409);
|
|
||||||
return "intern/warehouse/error_progress_failed";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/warehouse/progress/{id}")
|
|
||||||
public String accountingWarehouseProgressId() {
|
|
||||||
return "intern/warehouse/id_progress";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/intern/warehouse/slots/")
|
|
||||||
public String accountingWarehouseSlots() {
|
|
||||||
return "intern/warehouse/slots/index";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package org.hso.ecommerce.app;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
|
|
||||||
@Controller
|
|
||||||
@RequestMapping("user")
|
|
||||||
public class UserRequestController {
|
|
||||||
|
|
||||||
@GetMapping("/")
|
|
||||||
public String user() {
|
|
||||||
return "redirect:/user/settings";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/settings")
|
|
||||||
public String userSettings() {
|
|
||||||
return "user/settings";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/orders/")
|
|
||||||
public String userOrdeers() {
|
|
||||||
return "user/orders/index";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/bonuspoints")
|
|
||||||
public String userBonuspoints() {
|
|
||||||
return "user/bonuspoints";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/notifications/")
|
|
||||||
public String userNotifications() {
|
|
||||||
return "user/notifications/index";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class AdminInitializer {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final UserRepository userRepository = null;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
Optional<Integer> numberOfEmployees = userRepository.numberOfEmployees();
|
||||||
|
if (numberOfEmployees.orElse(0) == 0) {
|
||||||
|
// create first admin user
|
||||||
|
User firstAdmin = new User();
|
||||||
|
firstAdmin.created = new Timestamp(System.currentTimeMillis());
|
||||||
|
firstAdmin.defaultDeliveryAddress = new Address();
|
||||||
|
firstAdmin.defaultDeliveryAddress.name = "admin";
|
||||||
|
firstAdmin.defaultPayment = new PaymentMethod();
|
||||||
|
firstAdmin.defaultPayment.creditCardNumber = ""; //set empty number
|
||||||
|
firstAdmin.email = "admin";
|
||||||
|
firstAdmin.isActive = true;
|
||||||
|
firstAdmin.isEmployee = true;
|
||||||
|
firstAdmin.setPassword("admin");
|
||||||
|
userRepository.save(firstAdmin); //save to DB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package org.hso.ecommerce.components;
|
package org.hso.ecommerce.components;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.app.config.AppSettings;
|
||||||
import org.hso.ecommerce.entities.warehouse.Slot;
|
import org.hso.ecommerce.entities.warehouse.Slot;
|
||||||
import org.hso.ecommerce.repos.warehouse.SlotRepository;
|
import org.hso.ecommerce.repos.warehouse.SlotRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -13,11 +14,13 @@ public class SlotInitializer {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private final SlotRepository slotRepository = null;
|
private final SlotRepository slotRepository = null;
|
||||||
|
|
||||||
// TODO: use values form cfg.
|
@Autowired
|
||||||
private final int NUM_SLOTS = 50;
|
private final AppSettings appSettings = null;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
|
int NUM_SLOTS = appSettings.getNumberOfStorageSpaces();
|
||||||
|
|
||||||
for (int i = 1; i <= NUM_SLOTS; i++) {
|
for (int i = 1; i <= NUM_SLOTS; i++) {
|
||||||
if (!slotRepository.findBySlotNum(i).isPresent()) {
|
if (!slotRepository.findBySlotNum(i).isPresent()) {
|
||||||
Slot slotAdded = new Slot();
|
Slot slotAdded = new Slot();
|
||||||
|
@ -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,8 +0,0 @@
|
|||||||
package org.hso.ecommerce.controller;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
|
|
||||||
@Controller
|
|
||||||
//@RequestMapping("...")
|
|
||||||
public class BookingController {
|
|
||||||
}
|
|
@ -1,8 +1,70 @@
|
|||||||
package org.hso.ecommerce.controller;
|
package org.hso.ecommerce.controller;
|
||||||
|
|
||||||
|
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.stereotype.Controller;
|
||||||
|
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
|
@Controller
|
||||||
//@RequestMapping("...")
|
@RequestMapping("/")
|
||||||
public class LoginController {
|
public class LoginController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final UserRepository userRepository = null;
|
||||||
|
|
||||||
|
@GetMapping("login")
|
||||||
|
public String login() {
|
||||||
|
return "login";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("login")
|
||||||
|
public String loginPost(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
@RequestParam("username") String username, @RequestParam("password") String password, HttpSession session) {
|
||||||
|
|
||||||
|
String gto = (String) session.getAttribute("afterLogin");
|
||||||
|
|
||||||
|
Optional<User> user = userRepository.findByEmail(username);
|
||||||
|
if (!user.isPresent()) {
|
||||||
|
request.setAttribute("error", "Die Email Adresse falsch.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return "login";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.get().validatePassword(password)) {
|
||||||
|
request.setAttribute("error", "Das Passwort ist falsch.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return "login";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.get().isActive) {
|
||||||
|
request.setAttribute("error", "Dieses Konto ist deaktiviert..");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return "login";
|
||||||
|
}
|
||||||
|
|
||||||
|
session.setAttribute("userId", user.get().getId());
|
||||||
|
|
||||||
|
if (gto != null && gto.startsWith("/")) {
|
||||||
|
return "redirect:" + gto;
|
||||||
|
} else if (user.get().isEmployee) {
|
||||||
|
return "redirect:/intern/";
|
||||||
|
} else {
|
||||||
|
return "redirect:/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("logout")
|
||||||
|
public String logoutPost(@RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart, HttpSession session) {
|
||||||
|
session.removeAttribute("userId");
|
||||||
|
shoppingCart.clear();
|
||||||
|
|
||||||
|
return "redirect:/";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.hso.ecommerce.controller;
|
package org.hso.ecommerce.controller;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.entities.booking.PaymentMethod;
|
||||||
import org.hso.ecommerce.entities.shop.Address;
|
import org.hso.ecommerce.entities.shop.Address;
|
||||||
import org.hso.ecommerce.entities.user.User;
|
import org.hso.ecommerce.entities.user.User;
|
||||||
import org.hso.ecommerce.repos.user.UserRepository;
|
import org.hso.ecommerce.repos.user.UserRepository;
|
||||||
@ -21,40 +22,32 @@ public class RegisterController {
|
|||||||
private final UserRepository userRepository = null;
|
private final UserRepository userRepository = null;
|
||||||
|
|
||||||
@PostMapping("/register")
|
@PostMapping("/register")
|
||||||
public String registerPost(
|
public String registerPost(HttpServletRequest request, HttpServletResponse response,
|
||||||
HttpServletRequest request,
|
@RequestParam("username") String username, @RequestParam("password") String password,
|
||||||
HttpServletResponse response,
|
@RequestParam("password2") String password2, @RequestParam("salutation") String salutation,
|
||||||
@RequestParam("username") String username,
|
@RequestParam("name") String name, @RequestParam("address") String address,
|
||||||
@RequestParam("password") String password,
|
HttpSession session) {
|
||||||
@RequestParam("password2") String password2,
|
|
||||||
@RequestParam("salutation") String salutation,
|
|
||||||
@RequestParam("name") String name,
|
|
||||||
@RequestParam("address") String address,
|
|
||||||
@RequestParam("type") String type,
|
|
||||||
@RequestParam("ad") String ad,
|
|
||||||
HttpSession session
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Optional<User> user = userRepository.findByEmail(username);
|
Optional<User> user = userRepository.findByEmail(username);
|
||||||
if (user.isPresent()) {
|
if (user.isPresent()) {
|
||||||
request.setAttribute("error", "Email Adresse existiert bereits!");
|
request.setAttribute("error", "Die Email Adresse existiert bereits.");
|
||||||
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
return "register";
|
return "register";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!password.equals(password2)){
|
if (!password.equals(password2)) {
|
||||||
request.setAttribute("error", "Passwörter sind nicht gleich");
|
request.setAttribute("error", "Die Passwörter stimmen nicht überein.");
|
||||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
return "register";
|
return "register";
|
||||||
}
|
}
|
||||||
|
|
||||||
//set values for new user
|
// set values for new user
|
||||||
User newUser = new User();
|
User newUser = new User();
|
||||||
newUser.email = username;
|
newUser.email = username;
|
||||||
newUser.setPassword(password);
|
newUser.setPassword(password);
|
||||||
newUser.email = username;
|
newUser.email = username;
|
||||||
newUser.isEmployee = false;
|
newUser.isEmployee = false;
|
||||||
//TODO for salutation, type, ad are no attributes/fields in the class/database. Add when they are there.
|
newUser.salutation = salutation;
|
||||||
|
newUser.defaultPayment = PaymentMethod.fromCreditCardNumber("");
|
||||||
|
|
||||||
newUser.isActive = true;
|
newUser.isActive = true;
|
||||||
newUser.created = new java.sql.Timestamp(System.currentTimeMillis());
|
newUser.created = new java.sql.Timestamp(System.currentTimeMillis());
|
||||||
@ -69,9 +62,17 @@ public class RegisterController {
|
|||||||
user = userRepository.findByEmail(username);
|
user = userRepository.findByEmail(username);
|
||||||
session.setAttribute("userId", user.get().getId());
|
session.setAttribute("userId", user.get().getId());
|
||||||
|
|
||||||
|
String gto = (String) session.getAttribute("afterLogin");
|
||||||
|
|
||||||
|
//login after register
|
||||||
|
if (gto != null && gto.startsWith("/")) {
|
||||||
|
return "redirect:" + gto;
|
||||||
|
} else {
|
||||||
return "redirect:/";
|
return "redirect:/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/register")
|
@GetMapping("/register")
|
||||||
public String register() {
|
public String register() {
|
||||||
return "register";
|
return "register";
|
||||||
|
@ -1,8 +1,159 @@
|
|||||||
package org.hso.ecommerce.controller;
|
package org.hso.ecommerce.controller;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.action.user.CreateDeliveryData;
|
||||||
|
import org.hso.ecommerce.action.user.UpdateUserSettingsAction;
|
||||||
|
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.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
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
|
@Controller
|
||||||
//@RequestMapping("...")
|
@RequestMapping("/user")
|
||||||
public class UserController {
|
public class UserController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final UserRepository userRepository = null;
|
||||||
|
|
||||||
|
@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";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/settings")
|
||||||
|
public String userSettings(Model model,
|
||||||
|
@RequestAttribute("user") User user
|
||||||
|
) {
|
||||||
|
model.addAttribute("user", user);
|
||||||
|
|
||||||
|
return "user/settings";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/orders/")
|
||||||
|
public String userOrders(
|
||||||
|
@RequestAttribute("user") User user,
|
||||||
|
Model model
|
||||||
|
) {
|
||||||
|
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,
|
||||||
|
HttpServletRequest request
|
||||||
|
) {
|
||||||
|
User user = userRepository.findById((long) session.getAttribute("userId")).get();
|
||||||
|
|
||||||
|
UpdateUserSettingsAction cusa = new UpdateUserSettingsAction(user, userRepository);
|
||||||
|
UpdateUserSettingsAction.UpdateResult result = cusa.updateEmail(email);
|
||||||
|
if (result.updated == false) {
|
||||||
|
request.setAttribute("error", result.errorString);
|
||||||
|
return "user/settings";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "redirect:/user/settings";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/settings/changePwd")
|
||||||
|
public String changePwd(HttpSession session,
|
||||||
|
@RequestParam("old-password") String oldPassword,
|
||||||
|
@RequestParam("password1") String password1,
|
||||||
|
@RequestParam("password2") String password2,
|
||||||
|
HttpServletRequest request
|
||||||
|
) {
|
||||||
|
User user = userRepository.findById((long) session.getAttribute("userId")).get();
|
||||||
|
|
||||||
|
UpdateUserSettingsAction cusa = new UpdateUserSettingsAction(user, userRepository);
|
||||||
|
UpdateUserSettingsAction.UpdateResult result = cusa.updatePassword(oldPassword, password1, password2);
|
||||||
|
if (result.updated == false) {
|
||||||
|
request.setAttribute("error", result.errorString);
|
||||||
|
return "user/settings";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "redirect:/user/settings";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/settings/changeAddress")
|
||||||
|
public String changeAddress(HttpSession session,
|
||||||
|
@RequestParam("salutation") String salutation,
|
||||||
|
@RequestParam("name") String name,
|
||||||
|
@RequestParam("address") String address,
|
||||||
|
HttpServletRequest request
|
||||||
|
) {
|
||||||
|
User user = userRepository.findById((long) session.getAttribute("userId")).get();
|
||||||
|
|
||||||
|
UpdateUserSettingsAction cusa = new UpdateUserSettingsAction(user, userRepository);
|
||||||
|
UpdateUserSettingsAction.UpdateResult result = cusa.updateShippingInfo(salutation, name, address);
|
||||||
|
if (result.updated == false) {
|
||||||
|
request.setAttribute("error", result.errorString);
|
||||||
|
return "user/settings";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "redirect:/user/settings";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/settings/changePaymentInfo")
|
||||||
|
public String changePaymentInfo(HttpSession session,
|
||||||
|
@RequestParam("creditCardNumber") String creditCardNumber,
|
||||||
|
HttpServletRequest request
|
||||||
|
) {
|
||||||
|
User user = userRepository.findById((long) session.getAttribute("userId")).get();
|
||||||
|
|
||||||
|
UpdateUserSettingsAction cusa = new UpdateUserSettingsAction(user, userRepository);
|
||||||
|
UpdateUserSettingsAction.UpdateResult result = cusa.updatePaymentInfo(creditCardNumber);
|
||||||
|
if (result.updated == false) {
|
||||||
|
request.setAttribute("error", result.errorString);
|
||||||
|
return "user/settings";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "redirect:/user/settings";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
@ -1,34 +1,12 @@
|
|||||||
package org.hso.ecommerce.controller.cronjob;
|
package org.hso.ecommerce.controller.cronjob;
|
||||||
|
|
||||||
import java.sql.Timestamp;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
|
|
||||||
import org.hso.ecommerce.action.booking.CreateBookingAction;
|
|
||||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction;
|
|
||||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.ArticleIdentifier;
|
|
||||||
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.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.BookingAccountEntryRepository;
|
||||||
import org.hso.ecommerce.repos.booking.BookingRepository;
|
import org.hso.ecommerce.repos.booking.BookingRepository;
|
||||||
import org.hso.ecommerce.repos.cronjob.BackgroundJobRepository;
|
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.ArticleRepository;
|
||||||
import org.hso.ecommerce.repos.shop.CustomerOderRepository;
|
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
|
||||||
import org.hso.ecommerce.repos.supplier.ArticleOfferRepository;
|
import org.hso.ecommerce.repos.supplier.ArticleOfferRepository;
|
||||||
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
|
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
|
||||||
import org.hso.ecommerce.repos.supplier.SupplierRepository;
|
import org.hso.ecommerce.repos.supplier.SupplierRepository;
|
||||||
@ -37,188 +15,23 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
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 {
|
import javax.annotation.PostConstruct;
|
||||||
/**
|
import java.sql.Timestamp;
|
||||||
* Calculate the earliest cronjob execution time that happens after the given reference time.
|
import java.util.*;
|
||||||
*
|
import java.util.Map.Entry;
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component
|
|
||||||
class Reorder implements ICronjob {
|
|
||||||
@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
|
@Component
|
||||||
|
@RequestMapping("intern/cronjobs")
|
||||||
class CronjobController {
|
class CronjobController {
|
||||||
private static final Logger log = LoggerFactory.getLogger(CronjobController.class);
|
private static final Logger log = LoggerFactory.getLogger(CronjobController.class);
|
||||||
|
|
||||||
private static final Map<String, ICronjob> cronjobs = getCronjobs();
|
private Map<String, ICronjob> cronjobs;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private final BackgroundJobRepository cronjobRepository = null;
|
private final BackgroundJobRepository cronjobRepository = null;
|
||||||
@ -230,7 +43,7 @@ class CronjobController {
|
|||||||
final ArticleOfferRepository articleOfferRepository = null;
|
final ArticleOfferRepository articleOfferRepository = null;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
final CustomerOderRepository customerOrderRepository = null;
|
final CustomerOrderRepository customerOrderRepository = null;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
final BookingRepository bookingRepository = null;
|
final BookingRepository bookingRepository = null;
|
||||||
@ -241,17 +54,36 @@ class CronjobController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
|
final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
final DashboardSummaryRepository dashboardSummaryRepository = null;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
final SupplierRepository supplierRepository = null;
|
final SupplierRepository supplierRepository = null;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
final SupplierOrderRepository supplierOrderRepository = null;
|
final SupplierOrderRepository supplierOrderRepository = null;
|
||||||
|
|
||||||
private static Map<String, ICronjob> getCronjobs() {
|
@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<>();
|
HashMap<String, ICronjob> map = new HashMap<>();
|
||||||
|
|
||||||
// Register all existing cronjobs
|
// Register all existing cronjobs
|
||||||
map.put(BackgroundJob.JOB_REORDER, new Reorder());
|
map.put(BackgroundJob.JOB_REORDER, reorderJob);
|
||||||
|
map.put(BackgroundJob.JOB_DASHBOARD, dashboardCronjob);
|
||||||
|
map.put(BackgroundJob.JOB_SUPPLIER_AUTO_PAYMENT, autoSupplierPaymentJob);
|
||||||
|
|
||||||
return Collections.unmodifiableMap(map);
|
return Collections.unmodifiableMap(map);
|
||||||
}
|
}
|
||||||
@ -328,4 +160,42 @@ class CronjobController {
|
|||||||
public void onPostConstruct() {
|
public void onPostConstruct() {
|
||||||
new Thread(this::runCronjobExecutionLoop).start();
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,15 +1,5 @@
|
|||||||
package org.hso.ecommerce.controller.intern;
|
package org.hso.ecommerce.controller.intern;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
|
|
||||||
import org.hso.ecommerce.entities.shop.Article;
|
import org.hso.ecommerce.entities.shop.Article;
|
||||||
import org.hso.ecommerce.entities.shop.Category;
|
import org.hso.ecommerce.entities.shop.Category;
|
||||||
import org.hso.ecommerce.entities.shop.Image;
|
import org.hso.ecommerce.entities.shop.Image;
|
||||||
@ -27,6 +17,17 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.servlet.view.RedirectView;
|
import org.springframework.web.servlet.view.RedirectView;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("intern/articles")
|
@RequestMapping("intern/articles")
|
||||||
public class InternArticleController {
|
public class InternArticleController {
|
||||||
@ -52,7 +53,11 @@ public class InternArticleController {
|
|||||||
|
|
||||||
for (Article article : articleRepository.findAll()) {
|
for (Article article : articleRepository.findAll()) {
|
||||||
UImodelArticles tmp = new UImodelArticles();
|
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);
|
totals.add(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,16 +67,16 @@ public class InternArticleController {
|
|||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
public String internListedArticlesId(Model model, @PathVariable String id) {
|
public String internListedArticlesId(Model model, @PathVariable String id) {
|
||||||
|
long articleId = Long.parseLong(id);
|
||||||
int articleid = Integer.parseInt(id);
|
|
||||||
|
|
||||||
UImodelArticle total = new UImodelArticle();
|
UImodelArticle total = new UImodelArticle();
|
||||||
|
total.addArticle(
|
||||||
total.addArticle(articleRepository.findArticleById(articleid),
|
articleRepository.findById(articleId).get(),
|
||||||
warehouseEntryRepository.getArticleStock(articleid).orElse(0));
|
warehouseEntryRepository.getByArticle(articleId)
|
||||||
|
.stream()
|
||||||
|
.mapToInt(e -> e.newSumSlot)
|
||||||
|
.sum());
|
||||||
|
|
||||||
model.addAttribute("ArticleID", total);
|
model.addAttribute("ArticleID", total);
|
||||||
|
|
||||||
return "intern/listedArticles/id";
|
return "intern/listedArticles/id";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +85,7 @@ public class InternArticleController {
|
|||||||
@RequestParam(value = "title", required = true) String title,
|
@RequestParam(value = "title", required = true) String title,
|
||||||
@RequestParam(value = "description", required = true) String description,
|
@RequestParam(value = "description", required = true) String description,
|
||||||
@RequestParam(value = "units-per-slot", required = true) String warehouseUnitsPerSlot,
|
@RequestParam(value = "units-per-slot", required = true) String warehouseUnitsPerSlot,
|
||||||
@RequestParam(value = "price_netto", required = true) String pricenetto,
|
@RequestParam(value = "priceNet", required = true) String pricenetto,
|
||||||
@RequestParam(value = "reorderMaxPrice", required = true) String reorderMaxPrice,
|
@RequestParam(value = "reorderMaxPrice", required = true) String reorderMaxPrice,
|
||||||
@RequestParam(value = "autobuy", required = true) Boolean shouldReorder,
|
@RequestParam(value = "autobuy", required = true) Boolean shouldReorder,
|
||||||
@RequestParam(value = "categorie", required = true) String categories,
|
@RequestParam(value = "categorie", required = true) String categories,
|
||||||
@ -115,11 +120,17 @@ public class InternArticleController {
|
|||||||
@PostMapping("/addArticle/{id}")
|
@PostMapping("/addArticle/{id}")
|
||||||
public RedirectView addArticle(@PathVariable(required = true) String id) {
|
public RedirectView addArticle(@PathVariable(required = true) String id) {
|
||||||
// article is not already listed, create new one
|
// article is not already listed, create new one
|
||||||
int offeredArticleID = Integer.parseInt(id);
|
long offeredArticleID = Long.parseLong(id);
|
||||||
|
|
||||||
Article tmpArticle = new Article();
|
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
|
// set default values
|
||||||
tmpArticle.description = "";
|
tmpArticle.description = "";
|
||||||
@ -175,15 +186,22 @@ public class InternArticleController {
|
|||||||
if (imageID.isPresent()) {
|
if (imageID.isPresent()) {
|
||||||
article.image = imageRepository.findImageById(imageID.get()); // add existing img to article
|
article.image = imageRepository.findImageById(imageID.get()); // add existing img to article
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
Path targetPath = Paths.get("./data/img/");
|
||||||
|
if (Files.notExists(targetPath)) {
|
||||||
|
Files.createDirectories(targetPath);
|
||||||
|
}
|
||||||
|
|
||||||
// write new img file to disk
|
// write new img file to disk
|
||||||
Files.newOutputStream(Paths.get("./data/img/", fileName)).write(imgFile.getBytes());
|
Files.newOutputStream(Paths.get(targetPath.toString(), fileName)).write(imgFile.getBytes());
|
||||||
// create new img
|
// create new img
|
||||||
Image newImage = new Image();
|
Image newImage = new Image();
|
||||||
newImage.path = "./data/img/" + fileName; // set new file to new img
|
newImage.path = "./data/img/" + fileName; // set new file to new img
|
||||||
imageRepository.save(newImage); // save new img
|
imageRepository.save(newImage); // save new img
|
||||||
article.image = newImage; // set new img to article
|
article.image = newImage; // set new img to article
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
setDefaultImage(article); // if upload failed, reset to default img
|
setDefaultImage(article); // if upload failed, reset to default img
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,19 +210,12 @@ public class InternArticleController {
|
|||||||
public static class UImodelArticles {
|
public static class UImodelArticles {
|
||||||
|
|
||||||
public String imgPath;
|
public String imgPath;
|
||||||
|
|
||||||
public String title;
|
public String title;
|
||||||
|
|
||||||
public String price;
|
public String price;
|
||||||
|
public String priceNet;
|
||||||
public String price_netto;
|
|
||||||
|
|
||||||
public String categorie;
|
public String categorie;
|
||||||
|
|
||||||
public int stock;
|
public int stock;
|
||||||
|
public long offerID;
|
||||||
public long offer_id;
|
|
||||||
|
|
||||||
public long id;
|
public long id;
|
||||||
|
|
||||||
void addListedArticle(Article article, int stock) {
|
void addListedArticle(Article article, int stock) {
|
||||||
@ -213,7 +224,7 @@ public class InternArticleController {
|
|||||||
this.imgPath = article.image.path;
|
this.imgPath = article.image.path;
|
||||||
}
|
}
|
||||||
this.title = article.title;
|
this.title = article.title;
|
||||||
this.price_netto = String.format("%.2f", ((float) article.shopPricePerUnitNetCent / 100));
|
this.priceNet = String.format("%.2f", ((float) article.shopPricePerUnitNetCent / 100));
|
||||||
this.price = String.format("%.2f", ((float) article.getPriceGross() / 100));
|
this.price = String.format("%.2f", ((float) article.getPriceGross() / 100));
|
||||||
|
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
@ -224,7 +235,7 @@ public class InternArticleController {
|
|||||||
this.categorie = result.toString();
|
this.categorie = result.toString();
|
||||||
|
|
||||||
this.stock = stock;
|
this.stock = stock;
|
||||||
this.offer_id = article.related.id;
|
this.offerID = article.related.id;
|
||||||
this.id = article.id;
|
this.id = article.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,118 +245,31 @@ public class InternArticleController {
|
|||||||
public String imgPath;
|
public String imgPath;
|
||||||
public String title;
|
public String title;
|
||||||
public String price;
|
public String price;
|
||||||
public String price_netto;
|
public String priceNet;
|
||||||
public String reorderMaxPrice;
|
public String reorderMaxPrice;
|
||||||
public String categorie;
|
public String categorie;
|
||||||
public int stock;
|
public int stock;
|
||||||
public long offer_id;
|
public long offerID;
|
||||||
public long id;
|
public long id;
|
||||||
public boolean shouldReorder;
|
public boolean shouldReorder;
|
||||||
public String warehouseUnitsPerSlot;
|
public String warehouseUnitsPerSlot;
|
||||||
public String description;
|
public String description;
|
||||||
|
public int vatPercent;
|
||||||
public String getImgPath() {
|
|
||||||
return imgPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setImgPath(String imgPath) {
|
|
||||||
this.imgPath = imgPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTitle(String title) {
|
|
||||||
this.title = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPrice() {
|
|
||||||
return price;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPrice(String price) {
|
|
||||||
this.price = price;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPrice_netto() {
|
|
||||||
return price_netto;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPrice_netto(String price_netto) {
|
|
||||||
this.price_netto = price_netto;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getReorderMaxPrice() {
|
|
||||||
return reorderMaxPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setReorderMaxPrice(String reorderMaxPrice) {
|
|
||||||
this.reorderMaxPrice = reorderMaxPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCategorie() {
|
public String getCategorie() {
|
||||||
return categorie;
|
return categorie;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCategorie(String categorie) {
|
|
||||||
this.categorie = categorie;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getStock() {
|
|
||||||
return stock;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStock(int stock) {
|
|
||||||
this.stock = stock;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getOffer_id() {
|
|
||||||
return offer_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOffer_id(long offer_id) {
|
|
||||||
this.offer_id = offer_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isShouldReorder() {
|
|
||||||
return shouldReorder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setShouldReorder(boolean shouldReorder) {
|
|
||||||
this.shouldReorder = shouldReorder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getWarehouseUnitsPerSlot() {
|
|
||||||
return warehouseUnitsPerSlot;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWarehouseUnitsPerSlot(String warehouseUnitsPerSlot) {
|
|
||||||
this.warehouseUnitsPerSlot = warehouseUnitsPerSlot;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDescription(String description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addArticle(Article article, int stock) {
|
void addArticle(Article article, int stock) {
|
||||||
if (article.image != null) {
|
if (article.image != null) {
|
||||||
this.imgPath = article.image.path;
|
this.imgPath = article.image.path;
|
||||||
}
|
}
|
||||||
this.title = article.title;
|
this.title = article.title;
|
||||||
this.price_netto = String.format("%.2f", ((float) article.shopPricePerUnitNetCent / 100));
|
this.priceNet = String.format("%.2f", ((float) article.shopPricePerUnitNetCent / 100));
|
||||||
this.price = String.format("%.2f", ((float) article.getPriceGross() / 100));
|
this.price = String.format("%.2f", ((float) article.getPriceGross() / 100));
|
||||||
|
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
@ -357,12 +281,13 @@ public class InternArticleController {
|
|||||||
this.categorie = result.toString();
|
this.categorie = result.toString();
|
||||||
|
|
||||||
this.stock = stock;
|
this.stock = stock;
|
||||||
this.offer_id = article.related.id;
|
this.offerID = article.related.id;
|
||||||
this.id = article.id;
|
this.id = article.id;
|
||||||
this.reorderMaxPrice = String.format("%.2f", ((float) article.reorderMaxPrice / 100));
|
this.reorderMaxPrice = String.format("%.2f", ((float) article.reorderMaxPrice / 100));
|
||||||
this.shouldReorder = article.shouldReorder;
|
this.shouldReorder = article.shouldReorder;
|
||||||
this.warehouseUnitsPerSlot = String.valueOf(article.warehouseUnitsPerSlot);
|
this.warehouseUnitsPerSlot = String.valueOf(article.warehouseUnitsPerSlot);
|
||||||
this.description = article.description;
|
this.description = article.description;
|
||||||
|
this.vatPercent = article.related.vatPercent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,34 @@
|
|||||||
package org.hso.ecommerce.controller.intern;
|
package org.hso.ecommerce.controller.intern;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.controller.intern.accounting.AccountingController;
|
||||||
|
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
|
||||||
|
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
//@RequestMapping("...")
|
@RequestMapping("/intern")
|
||||||
public class InternIndexController {
|
public class InternIndexController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final BookingAccountEntryRepository bookingAccountEntryRepository = null;
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
public String intern(Model model) {
|
||||||
|
Optional<BookingAccountEntry> mainAccount = bookingAccountEntryRepository.getByMain();
|
||||||
|
int mainAccountBalance = mainAccount.map(entry -> entry.newSumCent).orElse(0);
|
||||||
|
Optional<BookingAccountEntry> vatAccount = bookingAccountEntryRepository.getByVat();
|
||||||
|
int vatAccountBalance = vatAccount.map(entry -> entry.newSumCent).orElse(0);
|
||||||
|
|
||||||
|
model.addAttribute("mainAccountBalance", AccountingController.fmtEuro(mainAccountBalance));
|
||||||
|
model.addAttribute("vatAccountBalance", AccountingController.fmtEuro(vatAccountBalance));
|
||||||
|
|
||||||
|
return "intern/index";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,27 @@
|
|||||||
package org.hso.ecommerce.controller.intern;
|
package org.hso.ecommerce.controller.intern;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
//@RequestMapping("...")
|
@RequestMapping("/intern/warehouse/")
|
||||||
public class WarehouseController {
|
public class WarehouseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final WarehouseBookingRepository warehouseBookingRepository = null;
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
public String accountingWarehouse(
|
||||||
|
Model model,
|
||||||
|
HttpServletRequest request
|
||||||
|
) {
|
||||||
|
model.addAttribute("bookings", warehouseBookingRepository.findAllDesc());
|
||||||
|
return "intern/warehouse/index";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,229 @@
|
|||||||
|
package org.hso.ecommerce.controller.intern.accounting;
|
||||||
|
|
||||||
|
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.repos.booking.BookingRepository;
|
||||||
|
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 java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class AccountingController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BookingRepository bookingRepository = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description used to render the html template for the overview of all bookings
|
||||||
|
*/
|
||||||
|
static class TemplateBooking {
|
||||||
|
public String datetime;
|
||||||
|
public String amount;
|
||||||
|
public String source;
|
||||||
|
public String sourceAddr;
|
||||||
|
public String sourceBalance;
|
||||||
|
public String destination;
|
||||||
|
public String destinationAddr;
|
||||||
|
public String destinationBalance;
|
||||||
|
public String reason;
|
||||||
|
public String reference;
|
||||||
|
public String referenceAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description used to render the html template for bookings on a specific account
|
||||||
|
*/
|
||||||
|
public static class ShortTemplateBooking {
|
||||||
|
public String datetime;
|
||||||
|
public String amount;
|
||||||
|
public String source;
|
||||||
|
public String sourceAddr;
|
||||||
|
public String balance;
|
||||||
|
public String reason;
|
||||||
|
public String reference;
|
||||||
|
public String referenceAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ShortTemplateBookingResult {
|
||||||
|
public final String balance;
|
||||||
|
public final List<ShortTemplateBooking> bookings;
|
||||||
|
|
||||||
|
public ShortTemplateBookingResult(String balance, List<ShortTemplateBooking> bookings) {
|
||||||
|
this.balance = balance;
|
||||||
|
this.bookings = bookings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to check which side of the booking (source or destination) is the account we are currently looking at.
|
||||||
|
*/
|
||||||
|
public interface AccountFilter {
|
||||||
|
boolean matches(BookingAccountEntry account);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders template information for the bookings of one specific account.
|
||||||
|
*
|
||||||
|
* @param bookings The (already fetched) booking entities to display
|
||||||
|
* @param currentAccount A filter matching the account that is to be displayed
|
||||||
|
* @return A collection result containing the final balance and all booking entries.
|
||||||
|
*/
|
||||||
|
public ShortTemplateBookingResult buildShortTemplate(List<Booking> bookings, AccountFilter currentAccount) {
|
||||||
|
List<ShortTemplateBooking> templateBookings = new ArrayList<>();
|
||||||
|
for (Booking booking : bookings) {
|
||||||
|
ShortTemplateBooking tb = new ShortTemplateBooking();
|
||||||
|
tb.datetime = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(booking.created);
|
||||||
|
tb.reason = booking.reason.comment;
|
||||||
|
tb.reference = describeReference(booking.reason);
|
||||||
|
tb.referenceAddr = linkToReference(booking.reason);
|
||||||
|
if (booking.destination != null && currentAccount.matches(booking.destination)) {
|
||||||
|
// Money was transferred onto the account we are looking at.
|
||||||
|
tb.amount = fmtEuro(booking.amountCent);
|
||||||
|
if (booking.source != null) {
|
||||||
|
tb.source = describeAccount(booking.source);
|
||||||
|
tb.sourceAddr = linkAddrOfAccount(booking.source);
|
||||||
|
} else {
|
||||||
|
tb.source = "-";
|
||||||
|
tb.sourceAddr = null;
|
||||||
|
}
|
||||||
|
tb.balance = fmtEuro(booking.destination.newSumCent);
|
||||||
|
} else if (booking.source != null && currentAccount.matches(booking.source)) {
|
||||||
|
// Money was transferred away from the account we are looking at.
|
||||||
|
tb.amount = fmtEuro(-booking.amountCent); // Negative because of the transfer away
|
||||||
|
if (booking.destination != null) {
|
||||||
|
tb.source = describeAccount(booking.destination); // 'source' means 'the other account' in this case
|
||||||
|
tb.sourceAddr = linkAddrOfAccount(booking.destination);
|
||||||
|
} else {
|
||||||
|
tb.source = "-";
|
||||||
|
tb.sourceAddr = null;
|
||||||
|
}
|
||||||
|
tb.balance = fmtEuro(booking.source.newSumCent);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"This booking should not appear in this list, because neither source nor destination is the account we are looking at.");
|
||||||
|
}
|
||||||
|
templateBookings.add(tb);
|
||||||
|
}
|
||||||
|
|
||||||
|
String balance = templateBookings.isEmpty() ? fmtEuro(0) : templateBookings.get(0).balance;
|
||||||
|
return new ShortTemplateBookingResult(balance, templateBookings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String fmtEuro(long amountCent) {
|
||||||
|
return String.format("%.2f EUR", amountCent / 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String describeAccount(BookingAccountEntry account) {
|
||||||
|
if (account.isMainAccount) {
|
||||||
|
return "Hauptkonto";
|
||||||
|
} else if (account.isVATAccount) {
|
||||||
|
return "Mehrwertsteuer";
|
||||||
|
} else if (account.supplierAccount != null) {
|
||||||
|
return "Lieferant " + account.supplierAccount.id;
|
||||||
|
} else if (account.userAccount != null) {
|
||||||
|
return "Kunde " + account.userAccount.id;
|
||||||
|
} else {
|
||||||
|
return "- unbekannt -";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String linkAddrOfAccount(BookingAccountEntry account) {
|
||||||
|
if (account.isMainAccount) {
|
||||||
|
return "/intern/accounting/main";
|
||||||
|
} else if (account.isVATAccount) {
|
||||||
|
return "/intern/accounting/vat";
|
||||||
|
} else if (account.supplierAccount != null) {
|
||||||
|
return "/intern/suppliers/" + account.supplierAccount.id;
|
||||||
|
} else if (account.userAccount != null) {
|
||||||
|
return "/intern/customers/" + account.userAccount.id;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String describeReference(BookingReason reason) {
|
||||||
|
if (reason.customerOrder != null) {
|
||||||
|
return reason.customerOrder.id + "";
|
||||||
|
} else if (reason.customerPayment != null) {
|
||||||
|
return "Bezahlung mit Kreditkarte " + reason.customerPayment.payment.creditCardNumber;
|
||||||
|
} else if (reason.supplierOrder != null) {
|
||||||
|
return "Lieferanten-Bestellung " + reason.supplierOrder.supplier.name;
|
||||||
|
} else if (reason.supplierPayment != null) {
|
||||||
|
return "Lieferanten-Zahlung " + reason.supplierPayment.name;
|
||||||
|
} else {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/intern/accounting/")
|
||||||
|
public String accounting(Model model) {
|
||||||
|
List<Booking> bookings = bookingRepository.allBookingsReverseChronologically();
|
||||||
|
List<TemplateBooking> templateBookings = new ArrayList<>();
|
||||||
|
for (Booking booking : bookings) {
|
||||||
|
TemplateBooking tb = new TemplateBooking();
|
||||||
|
tb.datetime = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(booking.created);
|
||||||
|
tb.amount = fmtEuro(booking.amountCent);
|
||||||
|
if (booking.source != null) {
|
||||||
|
tb.source = describeAccount(booking.source);
|
||||||
|
tb.sourceAddr = linkAddrOfAccount(booking.source);
|
||||||
|
tb.sourceBalance = fmtEuro(booking.source.newSumCent);
|
||||||
|
} else {
|
||||||
|
tb.source = "-";
|
||||||
|
tb.sourceAddr = null;
|
||||||
|
tb.sourceBalance = "-";
|
||||||
|
}
|
||||||
|
if (booking.destination != null) {
|
||||||
|
tb.destination = describeAccount(booking.destination);
|
||||||
|
tb.destinationAddr = linkAddrOfAccount(booking.destination);
|
||||||
|
tb.destinationBalance = fmtEuro(booking.destination.newSumCent);
|
||||||
|
} else {
|
||||||
|
tb.destination = "-";
|
||||||
|
tb.destinationAddr = null;
|
||||||
|
tb.destinationBalance = "-";
|
||||||
|
}
|
||||||
|
tb.reason = booking.reason.comment;
|
||||||
|
tb.reference = describeReference(booking.reason);
|
||||||
|
tb.referenceAddr = linkToReference(booking.reason);
|
||||||
|
templateBookings.add(tb);
|
||||||
|
}
|
||||||
|
|
||||||
|
model.addAttribute("bookings", templateBookings);
|
||||||
|
return "intern/accounting/index";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/intern/accounting/vat")
|
||||||
|
public String accountingVat(Model model) {
|
||||||
|
List<Booking> bookings = bookingRepository.vatBookingsReverseChronologically();
|
||||||
|
ShortTemplateBookingResult result = buildShortTemplate(bookings, account -> account.isVATAccount);
|
||||||
|
model.addAttribute("balance", result.balance);
|
||||||
|
model.addAttribute("bookings", result.bookings);
|
||||||
|
return "intern/accounting/vat";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/intern/accounting/main")
|
||||||
|
public String accountingIntern(Model model) {
|
||||||
|
List<Booking> bookings = bookingRepository.mainBookingsReverseChronologically();
|
||||||
|
ShortTemplateBookingResult result = buildShortTemplate(bookings, account -> account.isMainAccount);
|
||||||
|
model.addAttribute("balance", result.balance);
|
||||||
|
model.addAttribute("bookings", result.bookings);
|
||||||
|
return "intern/accounting/main";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,270 @@
|
|||||||
|
package org.hso.ecommerce.controller.intern.accounting;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
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.repos.booking.BookingAccountEntryRepository;
|
||||||
|
import org.hso.ecommerce.repos.booking.BookingRepository;
|
||||||
|
import org.hso.ecommerce.repos.supplier.SupplierRepository;
|
||||||
|
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.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class ManualAccountingController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
final BookingRepository bookingRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
final BookingAccountEntryRepository bookingAccountEntryRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
final UserRepository userRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
final SupplierRepository supplierRepository = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection for the form values used to create a manual booking
|
||||||
|
*/
|
||||||
|
public static class ManualAccounting {
|
||||||
|
String amount;
|
||||||
|
String source;
|
||||||
|
String sourceCustomer;
|
||||||
|
String sourceSupplier;
|
||||||
|
String destination;
|
||||||
|
String destinationCustomer;
|
||||||
|
String destinationSupplier;
|
||||||
|
String reason;
|
||||||
|
String reasonText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor with default values for the form
|
||||||
|
*/
|
||||||
|
public ManualAccounting() {
|
||||||
|
amount = "0.00";
|
||||||
|
reason = "Manual";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(String amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSource(String source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceCustomer() {
|
||||||
|
return sourceCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceCustomer(String sourceCustomer) {
|
||||||
|
this.sourceCustomer = sourceCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceSupplier() {
|
||||||
|
return sourceSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceSupplier(String sourceSupplier) {
|
||||||
|
this.sourceSupplier = sourceSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDestination() {
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestination(String destination) {
|
||||||
|
this.destination = destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDestinationCustomer() {
|
||||||
|
return destinationCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestinationCustomer(String destinationCustomer) {
|
||||||
|
this.destinationCustomer = destinationCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDestinationSupplier() {
|
||||||
|
return destinationSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestinationSupplier(String destinationSupplier) {
|
||||||
|
this.destinationSupplier = destinationSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReason(String reason) {
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReasonText() {
|
||||||
|
return reasonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReasonText(String reasonText) {
|
||||||
|
this.reasonText = reasonText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception to represent errors that can be shown to the user
|
||||||
|
*/
|
||||||
|
public static class InvalidFormDataException extends Exception {
|
||||||
|
public InvalidFormDataException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean sameAccountBothSides(ManualAccounting formData) {
|
||||||
|
// No need to check for NumberFormatException because the numbers were already parsed before.
|
||||||
|
if (!formData.getSource().equals(formData.getDestination())) {
|
||||||
|
return false;
|
||||||
|
} else if (formData.getSource().equals("Cust")
|
||||||
|
&& Long.parseLong(formData.getSourceCustomer()) != Long.parseLong(formData.getDestinationCustomer())) {
|
||||||
|
return false;
|
||||||
|
} else if (formData.getSource().equals("Sup")
|
||||||
|
&& Long.parseLong(formData.getSourceSupplier()) != Long.parseLong(formData.getDestinationSupplier())) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Booking createBooking(ManualAccounting formData) throws InvalidFormDataException {
|
||||||
|
if (formData.getSource() == null) {
|
||||||
|
throw new InvalidFormDataException("Bitte wählen Sie ein Quellkonto aus.");
|
||||||
|
} else if (formData.getDestination() == null) {
|
||||||
|
throw new InvalidFormDataException("Bitte wählen Sie ein Zielkonto aus.");
|
||||||
|
}
|
||||||
|
BookingAccountEntry source = getAccountFromFormData(formData.getSource(), formData.getSourceCustomer(),
|
||||||
|
formData.getSourceSupplier());
|
||||||
|
BookingAccountEntry destination = getAccountFromFormData(formData.getDestination(),
|
||||||
|
formData.getDestinationCustomer(), formData.getDestinationSupplier());
|
||||||
|
|
||||||
|
if (sameAccountBothSides(formData)) {
|
||||||
|
throw new InvalidFormDataException("Quell- und Zielkonto dürfen nicht das selbe sein.");
|
||||||
|
}
|
||||||
|
|
||||||
|
double doubleAmount;
|
||||||
|
try {
|
||||||
|
doubleAmount = Double.parseDouble(formData.amount);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new InvalidFormDataException("Der angegebene Betrag ist ungültig.");
|
||||||
|
}
|
||||||
|
int amountCent = (int) Math.round(doubleAmount * 100);
|
||||||
|
|
||||||
|
BookingReason reason = new BookingReason();
|
||||||
|
if (formData.getReason().equals("Start")) {
|
||||||
|
reason.isStartBooking = true;
|
||||||
|
} else if (formData.getReason().equals("Manual")) {
|
||||||
|
reason.isManuel = true;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Invalid form value for the booking reason: " + formData.getReason());
|
||||||
|
}
|
||||||
|
reason.comment = formData.reasonText;
|
||||||
|
|
||||||
|
CreateBookingAction action = new CreateBookingAction(source, destination, reason, amountCent);
|
||||||
|
return action.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the corresponding account based on user-input
|
||||||
|
*
|
||||||
|
* @param account The chosen value on the radio buttons
|
||||||
|
* @param customer The given customer id from the corresponding text field
|
||||||
|
* @param supplier the given supplier id from the corresponding text field
|
||||||
|
* @return The account entry that can be used to create the new booking
|
||||||
|
* @throws InvalidFormDataException If the user provided incorrect data in any way
|
||||||
|
*/
|
||||||
|
private BookingAccountEntry getAccountFromFormData(String account, String customer, String supplier)
|
||||||
|
throws InvalidFormDataException {
|
||||||
|
if (account.equals("None")) {
|
||||||
|
return null;
|
||||||
|
} else if (account.equals("Main")) {
|
||||||
|
return bookingAccountEntryRepository.getByMain().orElseGet(BookingAccountEntry::newMain);
|
||||||
|
} else if (account.equals("Vat")) {
|
||||||
|
return bookingAccountEntryRepository.getByVat().orElseGet(BookingAccountEntry::newVat);
|
||||||
|
} else if (account.equals("Cust")) {
|
||||||
|
long userId;
|
||||||
|
try {
|
||||||
|
userId = Long.parseLong(customer);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new InvalidFormDataException("Die angegebene Kunden-Nr. ist ungültig.");
|
||||||
|
}
|
||||||
|
Optional<BookingAccountEntry> bookingAccount = bookingAccountEntryRepository.getByUser(userId);
|
||||||
|
if (!bookingAccount.isPresent()) {
|
||||||
|
bookingAccount = userRepository.findById(userId).map((user) -> BookingAccountEntry.newUser(user));
|
||||||
|
}
|
||||||
|
if (bookingAccount.isPresent()) {
|
||||||
|
return bookingAccount.get();
|
||||||
|
} else {
|
||||||
|
throw new InvalidFormDataException("Der Kunde Nr. " + userId + " konnte nicht gefunden werden.");
|
||||||
|
}
|
||||||
|
} else if (account.equals("Sup")) {
|
||||||
|
long supplierId;
|
||||||
|
try {
|
||||||
|
supplierId = Long.parseLong(supplier);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new InvalidFormDataException("Die angegebene Lieferanten-Nr. ist ungültig.");
|
||||||
|
}
|
||||||
|
Optional<BookingAccountEntry> bookingAccount = bookingAccountEntryRepository.getBySupplier(supplierId);
|
||||||
|
if (!bookingAccount.isPresent()) {
|
||||||
|
bookingAccount = supplierRepository.findById(supplierId)
|
||||||
|
.map((sup) -> BookingAccountEntry.newSupplier(sup));
|
||||||
|
}
|
||||||
|
if (bookingAccount.isPresent()) {
|
||||||
|
return bookingAccount.get();
|
||||||
|
} else {
|
||||||
|
throw new InvalidFormDataException(
|
||||||
|
"Der Lieferant Nr. " + supplierId + " konnte nicht gefunden werden.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Invalid form value for an account: " + account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/intern/accounting/addManual")
|
||||||
|
public String accountingAddManual(Model model) {
|
||||||
|
model.addAttribute("form_vals", new ManualAccounting());
|
||||||
|
return "intern/accounting/addManual";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/intern/accounting/addManual")
|
||||||
|
public String accountingAddManualSubmit(Model model, @ModelAttribute ManualAccounting formData) {
|
||||||
|
Booking booking;
|
||||||
|
try {
|
||||||
|
booking = createBooking(formData);
|
||||||
|
bookingRepository.save(booking);
|
||||||
|
model.addAttribute("info", "Die Buchung wurde erfolgreich erstellt.");
|
||||||
|
model.addAttribute("form_vals", new ManualAccounting()); // Reply with empty form on success
|
||||||
|
} catch (InvalidFormDataException e) {
|
||||||
|
model.addAttribute("error", e.getMessage());
|
||||||
|
model.addAttribute("form_vals", formData);
|
||||||
|
}
|
||||||
|
return "intern/accounting/addManual";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,8 +1,71 @@
|
|||||||
package org.hso.ecommerce.controller.intern.customers;
|
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.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
|
@Controller
|
||||||
//@RequestMapping("...")
|
@RequestMapping("intern/customerOrders")
|
||||||
public class CustomerOrderController {
|
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,8 +1,118 @@
|
|||||||
package org.hso.ecommerce.controller.intern.customers;
|
package org.hso.ecommerce.controller.intern.customers;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.controller.intern.accounting.AccountingController;
|
||||||
|
import org.hso.ecommerce.controller.intern.accounting.AccountingController.ShortTemplateBookingResult;
|
||||||
|
import org.hso.ecommerce.entities.booking.Booking;
|
||||||
|
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
||||||
|
import org.hso.ecommerce.entities.user.User;
|
||||||
|
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.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
|
@Controller
|
||||||
//@RequestMapping("...")
|
@RequestMapping("/intern/customers")
|
||||||
public class CustomersIndexController {
|
public class CustomersIndexController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BookingRepository bookingRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final CustomerOrderRepository customerOrderRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final UserRepository userRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AccountingController accountingController = null;
|
||||||
|
|
||||||
|
@GetMapping("")
|
||||||
|
public String internCustomers(Model model) {
|
||||||
|
List<User> users = userRepository.findAll();
|
||||||
|
|
||||||
|
model.addAttribute("users", users);
|
||||||
|
|
||||||
|
return "intern/customers/index";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public String internCustomersId(Model model,
|
||||||
|
@PathVariable("id") Long id,
|
||||||
|
HttpServletResponse response,
|
||||||
|
HttpServletRequest request
|
||||||
|
) {
|
||||||
|
Optional<User> optUser = userRepository.findById(id);
|
||||||
|
if (!optUser.isPresent()) {
|
||||||
|
request.setAttribute("error", "Der User wurde nicht gefunden.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
|
return "error/404";
|
||||||
|
}
|
||||||
|
User user = optUser.get();
|
||||||
|
model.addAttribute("user", user);
|
||||||
|
|
||||||
|
List<CustomerOrder> orders = customerOrderRepository.getOrdersByUserId(id);
|
||||||
|
model.addAttribute("orders", orders);
|
||||||
|
|
||||||
|
List<Booking> bookings = bookingRepository.customerBookingsReverseChronologically(id);
|
||||||
|
ShortTemplateBookingResult result = accountingController.buildShortTemplate(
|
||||||
|
bookings,
|
||||||
|
account -> account.userAccount != null && account.userAccount.id == id);
|
||||||
|
model.addAttribute("balance", result.balance);
|
||||||
|
model.addAttribute("bookings", result.bookings);
|
||||||
|
|
||||||
|
return "intern/customers/id";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{id}/changeState")
|
||||||
|
public String changeState(@PathVariable("id") Long id,
|
||||||
|
@RequestParam(value = "active", required = false) String active,
|
||||||
|
@RequestParam(value = "ma", required = false) String ma
|
||||||
|
) {
|
||||||
|
User user = userRepository.findById(id).get();
|
||||||
|
|
||||||
|
if (active == null)
|
||||||
|
user.isActive = false;
|
||||||
|
else
|
||||||
|
user.isActive = true;
|
||||||
|
|
||||||
|
if (ma == null)
|
||||||
|
user.isEmployee = false;
|
||||||
|
else
|
||||||
|
user.isEmployee = true;
|
||||||
|
|
||||||
|
userRepository.save(user);
|
||||||
|
|
||||||
|
return "redirect:/intern/customers/" + id.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{id}/resetPassword")
|
||||||
|
public String resetPassword(@PathVariable("id") Long id,
|
||||||
|
@RequestParam("password") String password,
|
||||||
|
@RequestParam("password2") String password2,
|
||||||
|
HttpServletRequest request
|
||||||
|
) {
|
||||||
|
if (!password.equals(password2)) {
|
||||||
|
request.setAttribute("error", "Passwörter stimmen nicht überein!");
|
||||||
|
return "intern/customers/id";
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
userRepository.save(user);
|
||||||
|
request.setAttribute("info", "Passwort wurde auf 12345 geändert!");
|
||||||
|
|
||||||
|
return "intern/customers/id";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,157 @@
|
|||||||
package org.hso.ecommerce.controller.intern.suppliers;
|
package org.hso.ecommerce.controller.intern.suppliers;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.controller.intern.accounting.AccountingController;
|
||||||
|
import org.hso.ecommerce.controller.intern.accounting.AccountingController.ShortTemplateBooking;
|
||||||
|
import org.hso.ecommerce.controller.intern.accounting.AccountingController.ShortTemplateBookingResult;
|
||||||
|
import org.hso.ecommerce.entities.booking.Booking;
|
||||||
|
import org.hso.ecommerce.entities.supplier.Supplier;
|
||||||
|
import org.hso.ecommerce.entities.supplier.SupplierOrder;
|
||||||
|
import org.hso.ecommerce.repos.booking.BookingRepository;
|
||||||
|
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
|
||||||
|
import org.hso.ecommerce.repos.supplier.SupplierRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Controller;
|
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;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
//@RequestMapping("...")
|
@RequestMapping("/intern/")
|
||||||
public class SupplierIndexController {
|
public class SupplierIndexController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final SupplierRepository supplierRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final SupplierOrderRepository supplierOrderRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final BookingRepository bookingRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final AccountingController accountingController = null;
|
||||||
|
|
||||||
|
@GetMapping("suppliers")
|
||||||
|
public String listSuppliers(Model model) {
|
||||||
|
|
||||||
|
List<UImodelSuppliers> totals = new ArrayList<UImodelSuppliers>();
|
||||||
|
|
||||||
|
for (Supplier supplier : supplierRepository.findAll()) {
|
||||||
|
UImodelSuppliers tmp = new UImodelSuppliers(supplier.id, supplier.name);
|
||||||
|
totals.add(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
model.addAttribute("suppliers", totals);
|
||||||
|
return "intern/suppliers/index";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/suppliers/{id}")
|
||||||
|
public String supplierDetail(Model model, @PathVariable String id) {
|
||||||
|
|
||||||
|
long supplierId = Long.parseLong(id);
|
||||||
|
|
||||||
|
// add orders from supplier to UImodel
|
||||||
|
List<UImodelSupplierDetailOrders> orders = new ArrayList<UImodelSupplierDetailOrders>();
|
||||||
|
for (SupplierOrder supplierOrder : supplierOrderRepository.findOrderBySupplierID(supplierId)) {
|
||||||
|
orders.add(new UImodelSupplierDetailOrders(supplierOrder));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Table of bookings
|
||||||
|
List<Booking> bookings = bookingRepository.supplierBookingsReverseChronologically(supplierId);
|
||||||
|
ShortTemplateBookingResult bookingResult = accountingController.buildShortTemplate(bookings,
|
||||||
|
account -> account.supplierAccount != null && account.supplierAccount.id == supplierId);
|
||||||
|
|
||||||
|
UImodelSupplierDetail total = new UImodelSupplierDetail(supplierRepository.findSupplierById(supplierId).name,
|
||||||
|
bookingResult.balance, orders, bookingResult.bookings);
|
||||||
|
|
||||||
|
model.addAttribute("SupplierDetail", total);
|
||||||
|
|
||||||
|
return "intern/suppliers/id";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UImodelSuppliers {
|
||||||
|
public long id;
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
public UImodelSuppliers(long id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UImodelSupplierDetail {
|
||||||
|
|
||||||
|
public String name;
|
||||||
|
public String balance;
|
||||||
|
public List<UImodelSupplierDetailOrders> orders;
|
||||||
|
public List<ShortTemplateBooking> bookings;
|
||||||
|
|
||||||
|
public UImodelSupplierDetail(String name, String balance, List<UImodelSupplierDetailOrders> orders,
|
||||||
|
List<ShortTemplateBooking> bookings
|
||||||
|
) {
|
||||||
|
this.name = name;
|
||||||
|
this.balance = balance;
|
||||||
|
this.orders = orders;
|
||||||
|
this.bookings = bookings;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UImodelSupplierDetailOrders {
|
||||||
|
public long id;
|
||||||
|
public String dateOrder;
|
||||||
|
public String articleName;
|
||||||
|
public long articleId;
|
||||||
|
public String priceNet;
|
||||||
|
public String quantity;
|
||||||
|
public String priceTotal;
|
||||||
|
public boolean arrived;
|
||||||
|
|
||||||
|
public UImodelSupplierDetailOrders(SupplierOrder order) {
|
||||||
|
this.id = order.id;
|
||||||
|
this.articleName = order.ordered.title;
|
||||||
|
this.articleId = order.ordered.id;
|
||||||
|
this.priceNet = String.format("%.2f", ((float) order.pricePerUnitNetCent / 100));
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (order.delivered != null) {
|
||||||
|
arrived = true;
|
||||||
|
} else {
|
||||||
|
arrived = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UImodelSupplierDetailBookings {
|
||||||
|
|
||||||
|
public String dateBooking;
|
||||||
|
public String price;
|
||||||
|
public String srcName;
|
||||||
|
public String balance;
|
||||||
|
public String reason;
|
||||||
|
public long orderID;
|
||||||
|
|
||||||
|
public UImodelSupplierDetailBookings(Booking booking) {
|
||||||
|
Date date = new Date();
|
||||||
|
date.setTime(booking.reason.supplierOrder.created.getTime());
|
||||||
|
this.dateBooking = new SimpleDateFormat("dd.MM.yyyy").format(date);
|
||||||
|
this.price = String.format("%.2f", ((float) booking.amountCent / 100));
|
||||||
|
this.srcName = ((booking.source.isMainAccount) ? "Hauptkonto" : booking.source.supplierAccount.name);
|
||||||
|
this.balance = String.format("%.2f", ((float) booking.destination.newSumCent / 100));
|
||||||
|
this.reason = booking.reason.comment;
|
||||||
|
this.orderID = booking.reason.supplierOrder.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,8 @@ public class SupplierOfferController {
|
|||||||
List<UImodelOfferedArticle> totals = new ArrayList<>();
|
List<UImodelOfferedArticle> totals = new ArrayList<>();
|
||||||
|
|
||||||
for (ArticleOffer article : offersRepository.findAll()) {
|
for (ArticleOffer article : offersRepository.findAll()) {
|
||||||
UImodelOfferedArticle tmp = new UImodelOfferedArticle();
|
UImodelOfferedArticle tmp = new UImodelOfferedArticle(article,
|
||||||
tmp.addData(article, articleRepository.findArticleIDByRelatedID(article.id));
|
articleRepository.findArticleIDByRelatedID(article.id));
|
||||||
totals.add(tmp);
|
totals.add(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,95 +40,27 @@ public class SupplierOfferController {
|
|||||||
|
|
||||||
public class UImodelOfferedArticle {
|
public class UImodelOfferedArticle {
|
||||||
|
|
||||||
long offer_id;
|
public long offerId;
|
||||||
String title;
|
public String title;
|
||||||
String manufacturer;
|
public String manufacturer;
|
||||||
String articlenumber;
|
public String articleNumber;
|
||||||
String supplierName;
|
public String supplierName;
|
||||||
String price;
|
public String price;
|
||||||
String ads;
|
public String ads;
|
||||||
int listedArticleId;
|
public int listedArticleId;
|
||||||
boolean offerIsListed; // true --> offered article is listed
|
public boolean offerIsListed; // true --> offered article is listed
|
||||||
|
|
||||||
public long getOffer_id() {
|
public UImodelOfferedArticle(ArticleOffer article, Optional<Integer> listedArticleId) {
|
||||||
return offer_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOffer_id(long offer_id) {
|
this.offerId = article.id;
|
||||||
this.offer_id = offer_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOfferIsListed() {
|
|
||||||
return offerIsListed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOfferIsListed(boolean offerIsListed) {
|
|
||||||
this.offerIsListed = offerIsListed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTitle(String title) {
|
|
||||||
this.title = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getManufacturer() {
|
|
||||||
return manufacturer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setManufacturer(String manufacturer) {
|
|
||||||
this.manufacturer = manufacturer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getArticlenumber() {
|
|
||||||
return articlenumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setArticlenumber(String articlenumber) {
|
|
||||||
this.articlenumber = articlenumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSupplierName() {
|
|
||||||
return supplierName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSupplierName(String supplierName) {
|
|
||||||
this.supplierName = supplierName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPrice() {
|
|
||||||
return price;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPrice(String price) {
|
|
||||||
this.price = price;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAds() {
|
|
||||||
return ads;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAds(String ads) {
|
|
||||||
this.ads = ads;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getListedArticleId() {
|
|
||||||
return listedArticleId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setListedArticleId(int listedArticleId) {
|
|
||||||
this.listedArticleId = listedArticleId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addData(ArticleOffer article, Optional<Integer> listedArticleId) {
|
|
||||||
|
|
||||||
this.offer_id = article.id;
|
|
||||||
this.title = article.title;
|
this.title = article.title;
|
||||||
this.manufacturer = article.manufacturer;
|
this.manufacturer = article.manufacturer;
|
||||||
this.articlenumber = article.articleNumber;
|
this.articleNumber = article.articleNumber;
|
||||||
|
if (article.cheapestSupplier != null) {
|
||||||
this.supplierName = article.cheapestSupplier.name;
|
this.supplierName = article.cheapestSupplier.name;
|
||||||
|
} else {
|
||||||
|
this.supplierName = "-";
|
||||||
|
}
|
||||||
this.price = String.format("%.2f", ((float) article.pricePerUnitNet / 100));
|
this.price = String.format("%.2f", ((float) article.pricePerUnitNet / 100));
|
||||||
this.ads = (article.shouldBeAdvertised) ? "Ja" : "Nein";
|
this.ads = (article.shouldBeAdvertised) ? "Ja" : "Nein";
|
||||||
|
|
||||||
|
@ -1,8 +1,142 @@
|
|||||||
package org.hso.ecommerce.controller.intern.suppliers;
|
package org.hso.ecommerce.controller.intern.suppliers;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.action.warehouse.SupplierOrderArrivedAction;
|
||||||
|
import org.hso.ecommerce.entities.shop.Article;
|
||||||
|
import org.hso.ecommerce.entities.supplier.SupplierOrder;
|
||||||
|
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
|
||||||
|
import org.hso.ecommerce.repos.shop.ArticleRepository;
|
||||||
|
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
|
||||||
|
import org.hso.ecommerce.repos.warehouse.SlotRepository;
|
||||||
|
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
|
||||||
|
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Controller;
|
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.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
//@RequestMapping("...")
|
@RequestMapping("/intern/")
|
||||||
public class SupplierOrderController {
|
public class SupplierOrderController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final SupplierOrderRepository supplierOrderRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final ArticleRepository articleRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final WarehouseBookingRepository warehouseBookingRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final SlotRepository slotRepository = null;
|
||||||
|
|
||||||
|
@GetMapping("supplierOrders")
|
||||||
|
public String listSuppliers(Model model) {
|
||||||
|
|
||||||
|
List<UImodelSupplierOrder> totals = new ArrayList<UImodelSupplierOrder>();
|
||||||
|
|
||||||
|
for (SupplierOrder order : supplierOrderRepository.findAllDesc()) {
|
||||||
|
final Article article = articleRepository.findArticleByArticleOffer(order.ordered).orElse(null);
|
||||||
|
totals.add(new UImodelSupplierOrder(order, article));
|
||||||
|
}
|
||||||
|
|
||||||
|
model.addAttribute("orders", totals);
|
||||||
|
|
||||||
|
return "intern/supplierOrders/index";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/supplierOrders/store/{id}")
|
||||||
|
public String storeOrder(@PathVariable("id") Long supplierOrderID, Model model, HttpServletResponse response) {
|
||||||
|
SupplierOrder order = supplierOrderRepository.findById(supplierOrderID).orElse(null);
|
||||||
|
if (order == null) {
|
||||||
|
model.addAttribute("error", "Die ausgewählte Lieferung konnte nicht gefunden werden.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return listSuppliers(model);
|
||||||
|
}
|
||||||
|
if (order.wasDelivered()) {
|
||||||
|
model.addAttribute("error", "Die ausgewählte Lieferung wurde schon zugestellt.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return listSuppliers(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final Article article = articleRepository.findArticleByArticleOffer(order.ordered).orElse(null);
|
||||||
|
if (article == null) {
|
||||||
|
model.addAttribute("error", "Der bestellte Artikel wurde nicht angelegt, er hätte nicht bestellt werden dürfen.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return listSuppliers(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hard to do efficiently, this should be fine.
|
||||||
|
List<WarehouseBookingPositionSlotEntry> candidates = slotRepository
|
||||||
|
.findAll()
|
||||||
|
.stream()
|
||||||
|
.map(slot ->
|
||||||
|
warehouseBookingPositionSlotEntryRepository.getBySlotNum(slot.slotNum).orElseGet(() ->
|
||||||
|
WarehouseBookingPositionSlotEntry.empty(article, slot)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.filter(entry -> entry.article.id == article.id || entry.newSumSlot == 0)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
SupplierOrderArrivedAction action = new SupplierOrderArrivedAction(candidates, order, article);
|
||||||
|
|
||||||
|
try {
|
||||||
|
SupplierOrderArrivedAction.Result result = action.finish();
|
||||||
|
supplierOrderRepository.save(result.getOrder());
|
||||||
|
warehouseBookingRepository.save(result.getBooking());
|
||||||
|
} catch (SupplierOrderArrivedAction.NoSpaceInWarehouseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return "redirect:/intern/warehouse/todo";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UImodelSupplierOrder {
|
||||||
|
public long id;
|
||||||
|
public String dateOrder;
|
||||||
|
public String supplierName;
|
||||||
|
public String articleName;
|
||||||
|
public long articleId;
|
||||||
|
public String priceNet;
|
||||||
|
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;
|
||||||
|
this.supplierName = order.supplier.name;
|
||||||
|
this.articleName = article != null ? article.title : "error";
|
||||||
|
this.articleId = article != null ? article.id : 0;
|
||||||
|
this.priceNet = String.format("%.2f", ((float) order.pricePerUnitNetCent / 100));
|
||||||
|
this.quantity = String.valueOf(order.numberOfUnits);
|
||||||
|
this.priceTotal = String.format("%.2f", ((float) order.totalPriceNet / 100));
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,140 @@
|
|||||||
|
package org.hso.ecommerce.controller.intern.warehouse;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.action.warehouse.CreateManuelBookingAction;
|
||||||
|
import org.hso.ecommerce.entities.shop.Article;
|
||||||
|
import org.hso.ecommerce.entities.warehouse.Slot;
|
||||||
|
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
|
||||||
|
import org.hso.ecommerce.repos.shop.ArticleRepository;
|
||||||
|
import org.hso.ecommerce.repos.warehouse.SlotRepository;
|
||||||
|
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
|
||||||
|
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
|
||||||
|
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 javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/intern/warehouse/")
|
||||||
|
public class ManuelBookingController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final ArticleRepository articleRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final SlotRepository slotRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final WarehouseBookingRepository warehouseBookingRepository = null;
|
||||||
|
|
||||||
|
@GetMapping("addManual")
|
||||||
|
public String warehouseAddManual(
|
||||||
|
Model model
|
||||||
|
) {
|
||||||
|
|
||||||
|
model.addAttribute("articles", articleRepository.findAll());
|
||||||
|
model.addAttribute("slots", slotRepository.findAll());
|
||||||
|
|
||||||
|
return "intern/warehouse/addManual";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("addManual")
|
||||||
|
public String warehouseAddMaualPost(
|
||||||
|
Model model,
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
@RequestParam("articleId") String articleIdText,
|
||||||
|
@RequestParam("amount") Integer amount,
|
||||||
|
@RequestParam("reason") String reason,
|
||||||
|
@RequestParam("sourceIsSlot") Boolean sourceIsSlot,
|
||||||
|
@RequestParam("sourceSlot") Integer sourceSlotNum,
|
||||||
|
@RequestParam("destinationIsSlot") Boolean destinationIsSlot,
|
||||||
|
@RequestParam("destinationSlot") Integer destinationSlotNum
|
||||||
|
) {
|
||||||
|
|
||||||
|
// The suggestions for articleId in the UI show articles names, seperated by a " - ".
|
||||||
|
// The Number must be extracted first.
|
||||||
|
long articleId = -1;
|
||||||
|
try {
|
||||||
|
articleId = Long.parseLong(articleIdText.split(" - ", 2)[0].trim());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
model.addAttribute("error", "Die Artikel Id konnte nicht erkannt werden.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
|
return "intern/warehouse/addManual";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Optional<Article> optionalArticle = articleRepository.findById(articleId);
|
||||||
|
Article article = null;
|
||||||
|
if (!optionalArticle.isPresent()) {
|
||||||
|
model.addAttribute("error", "Der Artikel konnte nicht gefunden werden.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return "intern/warehouse/addManual";
|
||||||
|
} else {
|
||||||
|
article = optionalArticle.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount <= 0) {
|
||||||
|
model.addAttribute("error", "Eine Anzahl <= 0 kann nicht verbucht werden.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return "intern/warehouse/addManual";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceIsSlot == false && destinationIsSlot == false) {
|
||||||
|
model.addAttribute("error", "Jede Buchung benötigt ein Ziel oder eine Quelle.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return "intern/warehouse/addManual";
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<WarehouseBookingPositionSlotEntry> sourceSlot = Optional.empty();
|
||||||
|
if (sourceIsSlot == true) {
|
||||||
|
sourceSlot = warehouseBookingPositionSlotEntryRepository.getBySlotNum(sourceSlotNum);
|
||||||
|
if (!sourceSlot.isPresent()) {
|
||||||
|
request.setAttribute("error", "Quelllagerplatz wurde nicht gefunden oder ist leer.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return "intern/warehouse/addManual";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<WarehouseBookingPositionSlotEntry> destinationSlot = Optional.empty();
|
||||||
|
if (destinationIsSlot == true) {
|
||||||
|
Optional<Slot> slot = slotRepository.findBySlotNum(destinationSlotNum);
|
||||||
|
if (!slot.isPresent()) {
|
||||||
|
request.setAttribute("error", "Ziellagerplatz wurde nicht gefunden.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return "intern/warehouse/addManual";
|
||||||
|
}
|
||||||
|
|
||||||
|
Article finalArticle = article;
|
||||||
|
destinationSlot = Optional.of(warehouseBookingPositionSlotEntryRepository.getBySlotNum(destinationSlotNum).orElseGet(
|
||||||
|
() -> WarehouseBookingPositionSlotEntry.empty(finalArticle, slot.get())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
warehouseBookingRepository.save(
|
||||||
|
new CreateManuelBookingAction(article, amount, sourceSlot, destinationSlot, reason).finish()
|
||||||
|
);
|
||||||
|
} catch (CreateManuelBookingAction.ArticleSlotConstraintArticleTypeFailedException e) {
|
||||||
|
model.addAttribute("error", "Es befindet sich der falsche Artikeltyp in Quell- oder Ziellagerplatz. ");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return "intern/warehouse/addManual";
|
||||||
|
} catch (CreateManuelBookingAction.ArticleSlotConstraintFailedException e) {
|
||||||
|
model.addAttribute("error", "Die maximale Anzahl an lagerbaren Artikeln im Ziellagerplatz wurde überschritten.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
|
||||||
|
return "intern/warehouse/addManual";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "redirect:/intern/warehouse/todo";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package org.hso.ecommerce.controller.intern.warehouse;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.action.warehouse.CalculateWarehouseStatsAction;
|
||||||
|
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
|
||||||
|
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.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/intern/warehouse/")
|
||||||
|
public class SlotsController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final SlotRepository slotRepository = null;
|
||||||
|
|
||||||
|
@GetMapping("slots/")
|
||||||
|
public String accountingWarehouseSlots(
|
||||||
|
Model model,
|
||||||
|
HttpServletRequest request
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Doing this in a single would be hard and error prone.
|
||||||
|
// Writing native queries should be minimized.
|
||||||
|
// Therefore this method was prefered
|
||||||
|
List<WarehouseBookingPositionSlotEntry> entries = slotRepository.findAll().stream().map(
|
||||||
|
s -> warehouseBookingPositionSlotEntryRepository
|
||||||
|
.getBySlotNum(s.slotNum)
|
||||||
|
.orElseGet(() -> WarehouseBookingPositionSlotEntry.empty(null, s))
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
model.addAttribute("entries", entries);
|
||||||
|
|
||||||
|
model.addAttribute("stats", new CalculateWarehouseStatsAction(entries).finish());
|
||||||
|
return "intern/warehouse/slots/index";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
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;
|
||||||
|
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.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.client.ResourceAccessException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/intern/warehouse/")
|
||||||
|
public class TodoController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final WarehouseBookingRepository warehouseBookingRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final RestServiceForDelivery deliveryService = null;
|
||||||
|
|
||||||
|
@GetMapping("todo")
|
||||||
|
public String accountingWarehouseTodo(
|
||||||
|
Model model
|
||||||
|
) {
|
||||||
|
model.addAttribute("bookings", warehouseBookingRepository.findNotDone());
|
||||||
|
return "intern/warehouse/todo";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("progress/{id}")
|
||||||
|
public String postProgressId(
|
||||||
|
Model model,
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
@PathVariable("id") Long id
|
||||||
|
) {
|
||||||
|
Optional<WarehouseBooking> booking = warehouseBookingRepository.findById(id);
|
||||||
|
if (!booking.isPresent()) {
|
||||||
|
model.addAttribute("error", "Die Buchung wurde nicht gefunden.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
|
return "error/404";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (booking.get().isInProgress) {
|
||||||
|
response.setStatus(409);
|
||||||
|
return "intern/warehouse/error_progress_failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
booking.get().isInProgress = true;
|
||||||
|
warehouseBookingRepository.save(booking.get());
|
||||||
|
|
||||||
|
return "redirect:/intern/warehouse/progress/" + id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("progress/{id}/finish")
|
||||||
|
public String postProgressIdFinish(
|
||||||
|
Model model,
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
@PathVariable("id") Long id
|
||||||
|
) {
|
||||||
|
Optional<WarehouseBooking> booking = warehouseBookingRepository.findById(id);
|
||||||
|
if (!booking.isPresent()) {
|
||||||
|
model.addAttribute("error", "Die Buchung wurde nicht gefunden.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
|
return "error/404";
|
||||||
|
}
|
||||||
|
|
||||||
|
booking.get().isInProgress = true;
|
||||||
|
booking.get().isDone = true;
|
||||||
|
|
||||||
|
// Update Delivery Date
|
||||||
|
if (booking.get().reason.customerOrder != null) {
|
||||||
|
try{
|
||||||
|
EnableTrackingAction.addTrackingInfo(deliveryService, booking.get().reason.customerOrder);
|
||||||
|
}
|
||||||
|
catch(ResourceAccessException e)
|
||||||
|
{
|
||||||
|
return "error/500";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
warehouseBookingRepository.save(booking.get());
|
||||||
|
|
||||||
|
return "redirect:/intern/warehouse/todo";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("progress/{id}")
|
||||||
|
public String getProgressId(Model model,
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
@PathVariable("id") Long id) {
|
||||||
|
Optional<WarehouseBooking> booking = warehouseBookingRepository.findById(id);
|
||||||
|
if (!booking.isPresent()) {
|
||||||
|
model.addAttribute("error", "Die Buchung wurde nicht gefunden.");
|
||||||
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
|
return "error/404";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (booking.get().isDone) {
|
||||||
|
model.addAttribute("info", "Die Buchung wurde schon abgeschlossen.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!booking.get().isInProgress) {
|
||||||
|
// Only reachable if path is manipulated.
|
||||||
|
model.addAttribute("error", "Die Buchung wurde noch nicht zugewiesen!");
|
||||||
|
}
|
||||||
|
|
||||||
|
model.addAttribute("booking", booking.get());
|
||||||
|
return "intern/warehouse/id_progress";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -51,7 +52,11 @@ public class ShopArticleController {
|
|||||||
}
|
}
|
||||||
model.addAttribute("article", article);
|
model.addAttribute("article", article);
|
||||||
|
|
||||||
if (warehouseBookingPositionSlotEntryRepository.getByArticle(id).get(0).newSumSlot > 0) { //check if in Stock
|
if (warehouseBookingPositionSlotEntryRepository
|
||||||
|
.getByArticle(id)
|
||||||
|
.stream()
|
||||||
|
.mapToInt(e -> e.newSumSlot)
|
||||||
|
.sum() > 0) { //check if in Stock
|
||||||
model.addAttribute("inStock", true);
|
model.addAttribute("inStock", true);
|
||||||
} else {
|
} else {
|
||||||
model.addAttribute("inStock", false);
|
model.addAttribute("inStock", false);
|
||||||
@ -102,9 +107,16 @@ public class ShopArticleController {
|
|||||||
Article article = articleRepository.findArticleById(id);
|
Article article = articleRepository.findArticleById(id);
|
||||||
|
|
||||||
if(article.image != null) {
|
if(article.image != null) {
|
||||||
InputStream in = new FileInputStream(article.image.path);
|
File file = new File(article.image.path);
|
||||||
|
File allowedPath = new File("./data/img/");
|
||||||
|
|
||||||
|
if (file.getCanonicalPath().startsWith(allowedPath.getCanonicalPath())) {
|
||||||
|
InputStream in = new FileInputStream(file);
|
||||||
response.setContentType(MediaType.IMAGE_JPEG_VALUE);
|
response.setContentType(MediaType.IMAGE_JPEG_VALUE);
|
||||||
IOUtils.copy(in, response.getOutputStream());
|
IOUtils.copy(in, response.getOutputStream());
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Got illegal file path. DB was modified.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package org.hso.ecommerce.controller.shop;
|
package org.hso.ecommerce.controller.shop;
|
||||||
|
|
||||||
import org.hso.ecommerce.action.shop.CreateOrderAction;
|
import org.hso.ecommerce.action.shop.CreateOrderAction;
|
||||||
import org.hso.ecommerce.action.shop.EnableTrackingAction;
|
|
||||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
|
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
|
||||||
import org.hso.ecommerce.entities.booking.PaymentMethod;
|
import org.hso.ecommerce.entities.booking.PaymentMethod;
|
||||||
import org.hso.ecommerce.entities.shop.Address;
|
import org.hso.ecommerce.entities.shop.Address;
|
||||||
@ -11,7 +10,7 @@ import org.hso.ecommerce.entities.user.User;
|
|||||||
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
|
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
|
||||||
import org.hso.ecommerce.repos.booking.BookingRepository;
|
import org.hso.ecommerce.repos.booking.BookingRepository;
|
||||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
|
import org.hso.ecommerce.repos.shop.ArticleRepository;
|
||||||
import org.hso.ecommerce.repos.shop.CustomerOderRepository;
|
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
|
||||||
import org.hso.ecommerce.repos.user.UserRepository;
|
import org.hso.ecommerce.repos.user.UserRepository;
|
||||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
|
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
|
||||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
|
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
|
||||||
@ -45,7 +44,7 @@ public class ShopCheckoutController {
|
|||||||
private final WarehouseBookingRepository warehouseBookingRepository = null;
|
private final WarehouseBookingRepository warehouseBookingRepository = null;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private final CustomerOderRepository customerOderRepository = null;
|
private final CustomerOrderRepository customerOderRepository = null;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private final WarehouseBookingPositionSlotEntryRepository wbeseRepo = null;
|
private final WarehouseBookingPositionSlotEntryRepository wbeseRepo = null;
|
||||||
@ -110,7 +109,7 @@ public class ShopCheckoutController {
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
if (shoppingCart.getRevision() != cartRevision) {
|
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);
|
response.setStatus(HttpServletResponse.SC_CONFLICT);
|
||||||
return "shop/checkout";
|
return "shop/checkout";
|
||||||
}
|
}
|
||||||
@ -122,7 +121,7 @@ public class ShopCheckoutController {
|
|||||||
user,
|
user,
|
||||||
expectedPrice,
|
expectedPrice,
|
||||||
Address.fromString(address),
|
Address.fromString(address),
|
||||||
PaymentMethod.fromCreditCarNumber(cardnumber),
|
PaymentMethod.fromCreditCardNumber(cardnumber),
|
||||||
bookingEntryRepository.getByUser(user.id).orElse(BookingAccountEntry.newUser(user)),
|
bookingEntryRepository.getByUser(user.id).orElse(BookingAccountEntry.newUser(user)),
|
||||||
bookingEntryRepository.getByVat().orElse(BookingAccountEntry.newVat()),
|
bookingEntryRepository.getByVat().orElse(BookingAccountEntry.newVat()),
|
||||||
bookingEntryRepository.getByMain().orElse(BookingAccountEntry.newMain())
|
bookingEntryRepository.getByMain().orElse(BookingAccountEntry.newMain())
|
||||||
@ -136,7 +135,6 @@ public class ShopCheckoutController {
|
|||||||
CreateOrderAction.Result result = null;
|
CreateOrderAction.Result result = null;
|
||||||
try {
|
try {
|
||||||
result = action.finish();
|
result = action.finish();
|
||||||
EnableTrackingAction.addTrackingInfo(result.customerOrder);
|
|
||||||
|
|
||||||
customerOderRepository.save(result.customerOrder);
|
customerOderRepository.save(result.customerOrder);
|
||||||
bookingRepository.saveAll(result.bookings);
|
bookingRepository.saveAll(result.bookings);
|
||||||
|
@ -7,7 +7,9 @@ import org.hso.ecommerce.repos.shop.CategoryRepository;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
@ -32,9 +34,8 @@ public class ShopSearchController {
|
|||||||
) {
|
) {
|
||||||
model.addAttribute("categories", categoryRepository.getCategories()); //for sidebar
|
model.addAttribute("categories", categoryRepository.getCategories()); //for sidebar
|
||||||
|
|
||||||
term = term.trim();
|
|
||||||
|
|
||||||
if (term != null) { //if search by Term
|
if (term != null) { //if search by Term
|
||||||
|
term = term.trim();
|
||||||
List<Article> articles = SearchByTermAction.searchByTerm(term, articleRepository);
|
List<Article> articles = SearchByTermAction.searchByTerm(term, articleRepository);
|
||||||
model.addAttribute("articles", articles);
|
model.addAttribute("articles", articles);
|
||||||
} else if (category != null) { //if search by Category
|
} else if (category != null) { //if search by Category
|
||||||
@ -46,6 +47,9 @@ public class ShopSearchController {
|
|||||||
return "error/404";
|
return "error/404";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "/shop/search";
|
// Show term in search box
|
||||||
|
model.addAttribute("searchterm", term != null ? term : "");
|
||||||
|
|
||||||
|
return "shop/search";
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package org.hso.ecommerce.entities.booking;
|
package org.hso.ecommerce.entities.booking;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "bookings")
|
@Table(name = "bookings")
|
||||||
@ -14,6 +15,9 @@ public class Booking {
|
|||||||
// always >= 0
|
// always >= 0
|
||||||
public int amountCent;
|
public int amountCent;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public java.sql.Timestamp created;
|
||||||
|
|
||||||
@ManyToOne(optional = true, cascade = CascadeType.ALL)
|
@ManyToOne(optional = true, cascade = CascadeType.ALL)
|
||||||
public BookingAccountEntry source;
|
public BookingAccountEntry source;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.hso.ecommerce.entities.booking;
|
package org.hso.ecommerce.entities.booking;
|
||||||
|
|
||||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
||||||
|
import org.hso.ecommerce.entities.supplier.Supplier;
|
||||||
import org.hso.ecommerce.entities.supplier.SupplierOrder;
|
import org.hso.ecommerce.entities.supplier.SupplierOrder;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
@ -28,6 +29,9 @@ public class BookingReason {
|
|||||||
@ManyToOne(optional = true)
|
@ManyToOne(optional = true)
|
||||||
public SupplierOrder supplierOrder;
|
public SupplierOrder supplierOrder;
|
||||||
|
|
||||||
|
@ManyToOne(optional = true)
|
||||||
|
public Supplier supplierPayment;
|
||||||
|
|
||||||
// Default Constructor is needed for construction by ORM
|
// Default Constructor is needed for construction by ORM
|
||||||
public BookingReason() {
|
public BookingReason() {
|
||||||
}
|
}
|
||||||
@ -40,7 +44,16 @@ public class BookingReason {
|
|||||||
this.customerPayment = customerPayment;
|
this.customerPayment = customerPayment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BookingReason(Supplier supplierPayment) {
|
||||||
|
this.supplierPayment = supplierPayment;
|
||||||
|
}
|
||||||
|
|
||||||
public BookingReason(SupplierOrder supplierOrder) {
|
public BookingReason(SupplierOrder supplierOrder) {
|
||||||
this.supplierOrder = supplierOrder;
|
this.supplierOrder = supplierOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BookingReason(String comment) {
|
||||||
|
this.isManuel = true;
|
||||||
|
this.comment = comment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ public class PaymentMethod {
|
|||||||
|
|
||||||
public String creditCardNumber;
|
public String creditCardNumber;
|
||||||
|
|
||||||
public static PaymentMethod fromCreditCarNumber(String cardnumber) {
|
public static PaymentMethod fromCreditCardNumber(String cardnumber) {
|
||||||
PaymentMethod m = new PaymentMethod();
|
PaymentMethod m = new PaymentMethod();
|
||||||
m.creditCardNumber = cardnumber;
|
m.creditCardNumber = cardnumber;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ public class BackgroundJob {
|
|||||||
|
|
||||||
public static final String JOB_DASHBOARD = "Dashboard";
|
public static final String JOB_DASHBOARD = "Dashboard";
|
||||||
public static final String JOB_REORDER = "SupplierOrder";
|
public static final String JOB_REORDER = "SupplierOrder";
|
||||||
|
public static final String JOB_SUPPLIER_AUTO_PAYMENT = "SupplierAutoPayment";
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@ -15,11 +15,18 @@ public class DashboardSummary {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public java.sql.Date created;
|
public java.sql.Date created;
|
||||||
|
|
||||||
public int todaysCustomers;
|
@NotNull
|
||||||
public int todaysCustomersOrders;
|
public Integer todaysNewCustomers;
|
||||||
public int todaysSuppliersOrders;
|
|
||||||
public int todaysItemsSold;
|
@NotNull
|
||||||
public int todaysSalesCent;
|
public Integer todaysCustomersOrders;
|
||||||
public int totalWarehouseCapacity;
|
|
||||||
public int currentWarehouseCapacity;
|
@NotNull
|
||||||
|
public Integer todaysSalesCent;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Double currentWarehouseCapacity;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Double todaysWarehouseCapacity;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ public class Article {
|
|||||||
@Basic
|
@Basic
|
||||||
public long id;
|
public long id;
|
||||||
|
|
||||||
@ManyToOne(optional = false)
|
@OneToOne(optional = false)
|
||||||
public ArticleOffer related;
|
public ArticleOffer related;
|
||||||
|
|
||||||
public int shopPricePerUnitNetCent;
|
public int shopPricePerUnitNetCent;
|
||||||
|
@ -4,6 +4,7 @@ import org.hso.ecommerce.entities.user.User;
|
|||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ public class CustomerOrder {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public java.sql.Timestamp created;
|
public java.sql.Timestamp created;
|
||||||
|
|
||||||
@NotNull
|
@Column(nullable = true)
|
||||||
public String trackingId;
|
public String trackingId;
|
||||||
|
|
||||||
@Column(nullable = true)
|
@Column(nullable = true)
|
||||||
@ -43,4 +44,16 @@ public class CustomerOrder {
|
|||||||
public int totalNetCent;
|
public int totalNetCent;
|
||||||
public int totalGrossCent;
|
public int totalGrossCent;
|
||||||
public int totalVatCent;
|
public int totalVatCent;
|
||||||
|
|
||||||
|
public String formatInDeliverySince(){
|
||||||
|
return new SimpleDateFormat("dd.MM.yyyy HH:mm").format(inDeliverySince);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String formatCreated(){
|
||||||
|
return new SimpleDateFormat("dd.MM.yyyy HH:mm").format(created);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String formatDeliveredAt(){
|
||||||
|
return new SimpleDateFormat("dd.MM.yyyy HH:mm").format(deliveredAt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,4 +19,8 @@ public class CustomerOrderPosition {
|
|||||||
|
|
||||||
public int pricePerUnit;
|
public int pricePerUnit;
|
||||||
public int quantity;
|
public int quantity;
|
||||||
|
|
||||||
|
public int getSumPrice(){
|
||||||
|
return article.getPriceGross() * quantity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,15 @@ public class SupplierOrder {
|
|||||||
// Includes discounts
|
// Includes discounts
|
||||||
public int totalPriceNet;
|
public int totalPriceNet;
|
||||||
|
|
||||||
|
@Column(nullable = true)
|
||||||
|
public String carrier;
|
||||||
|
|
||||||
|
@Column(nullable = true)
|
||||||
|
public String trackingId;
|
||||||
|
|
||||||
|
@Column(nullable = true)
|
||||||
|
public Timestamp estimatedArrival;
|
||||||
|
|
||||||
@Column(nullable = true)
|
@Column(nullable = true)
|
||||||
public Timestamp delivered;
|
public Timestamp delivered;
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@ public class User {
|
|||||||
@Column(unique = true)
|
@Column(unique = true)
|
||||||
public String email;
|
public String email;
|
||||||
|
|
||||||
|
public String salutation;
|
||||||
|
|
||||||
public String passwordHash;
|
public String passwordHash;
|
||||||
|
|
||||||
public boolean isActive;
|
public boolean isActive;
|
||||||
|
@ -25,7 +25,12 @@ public class WarehouseBookingPositionSlotEntry {
|
|||||||
@ManyToOne
|
@ManyToOne
|
||||||
public Slot slot;
|
public Slot slot;
|
||||||
|
|
||||||
public WarehouseBookingPositionSlotEntry copyAddAmount(int amount) {
|
public WarehouseBookingPositionSlotEntry copyAddAmount(int amount, Article article) {
|
||||||
|
// Article can be changed if newSumSlot == 0.
|
||||||
|
if (this.newSumSlot != 0 && this.article.id != article.id) {
|
||||||
|
throw new IllegalArgumentException("Article does not match.");
|
||||||
|
}
|
||||||
|
|
||||||
WarehouseBookingPositionSlotEntry e = new WarehouseBookingPositionSlotEntry();
|
WarehouseBookingPositionSlotEntry e = new WarehouseBookingPositionSlotEntry();
|
||||||
|
|
||||||
e.article = article;
|
e.article = article;
|
||||||
@ -38,4 +43,14 @@ public class WarehouseBookingPositionSlotEntry {
|
|||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static WarehouseBookingPositionSlotEntry empty(Article article, Slot slot) {
|
||||||
|
WarehouseBookingPositionSlotEntry e = new WarehouseBookingPositionSlotEntry();
|
||||||
|
|
||||||
|
e.article = article;
|
||||||
|
e.slot = slot;
|
||||||
|
e.newSumSlot = 0;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,12 +1,28 @@
|
|||||||
package org.hso.ecommerce.repos.booking;
|
package org.hso.ecommerce.repos.booking;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.hso.ecommerce.entities.booking.Booking;
|
import org.hso.ecommerce.entities.booking.Booking;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface BookingRepository extends JpaRepository<Booking, Long> {
|
public interface BookingRepository extends JpaRepository<Booking, Long> {
|
||||||
|
|
||||||
|
@Query("SELECT b FROM Booking b ORDER BY b.id DESC")
|
||||||
|
List<Booking> allBookingsReverseChronologically();
|
||||||
|
|
||||||
|
@Query("SELECT b FROM Booking b LEFT JOIN b.source s LEFT JOIN b.destination d WHERE s.isMainAccount = 1 OR d.isMainAccount = 1 ORDER BY b.id DESC")
|
||||||
|
List<Booking> mainBookingsReverseChronologically();
|
||||||
|
|
||||||
|
@Query("SELECT b FROM Booking b LEFT JOIN b.source s LEFT JOIN b.destination d WHERE s.isVATAccount = 1 OR d.isVATAccount = 1 ORDER BY b.id DESC")
|
||||||
|
List<Booking> vatBookingsReverseChronologically();
|
||||||
|
|
||||||
|
@Query("SELECT b FROM Booking b LEFT JOIN b.source s LEFT JOIN b.destination d WHERE s.userAccount.id = :customerId OR d.userAccount.id = :customerId ORDER BY b.id DESC")
|
||||||
|
List<Booking> customerBookingsReverseChronologically(long customerId);
|
||||||
|
|
||||||
|
@Query("SELECT b FROM Booking b LEFT JOIN b.source s LEFT JOIN b.destination d WHERE s.supplierAccount.id = :supplierId OR d.supplierAccount.id = :supplierId ORDER BY b.id DESC")
|
||||||
|
List<Booking> supplierBookingsReverseChronologically(long supplierId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.hso.ecommerce.repos.dashboard;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.entities.dashboard.DashboardSummary;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface DashboardSummaryRepository extends JpaRepository<DashboardSummary, Long> {
|
||||||
|
|
||||||
|
@Query("SELECT ds FROM DashboardSummary ds ORDER BY ds.id DESC")
|
||||||
|
List<DashboardSummary> findInTimespan(
|
||||||
|
Pageable pageable
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package org.hso.ecommerce.repos.shop;
|
package org.hso.ecommerce.repos.shop;
|
||||||
|
|
||||||
import org.hso.ecommerce.entities.shop.Article;
|
import org.hso.ecommerce.entities.shop.Article;
|
||||||
|
import org.hso.ecommerce.entities.supplier.ArticleOffer;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import org.springframework.data.repository.query.Param;
|
import org.springframework.data.repository.query.Param;
|
||||||
@ -12,30 +13,41 @@ import java.util.Optional;
|
|||||||
@Repository
|
@Repository
|
||||||
public interface ArticleRepository extends JpaRepository<Article, Long> {
|
public interface ArticleRepository extends JpaRepository<Article, Long> {
|
||||||
|
|
||||||
|
/***
|
||||||
|
* use findById instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
@Query("SELECT a FROM Article a WHERE a.id = :articleId")
|
@Query("SELECT a FROM Article a WHERE a.id = :articleId")
|
||||||
Article findArticleById(@Param("articleId") long articleId);
|
Article findArticleById(@Param("articleId") long articleId);
|
||||||
|
|
||||||
@Query("SELECT a FROM Article a")
|
@Query("SELECT a FROM Article a")
|
||||||
List<Article> findAll();
|
List<Article> findAll();
|
||||||
|
|
||||||
@Query(value = "Select a.* from articles as a, article_offers as ao, warehouse_booking_position_entries as wbpe where a.related_id = ao.id and wbpe.article_id = a.id and ao.should_be_advertised = true group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
|
@Query(value = "SELECT DISTINCT a.* from articles as a, article_offers as ao, warehouse_booking_position_entries as wbpe where a.related_id = ao.id and wbpe.article_id = a.id and ao.should_be_advertised = true group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
|
||||||
List<Article> getAdvertisedArticles();
|
List<Article> getAdvertisedArticles();
|
||||||
|
|
||||||
@Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a ORDER BY co.id DESC")
|
@Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a ORDER BY co.id DESC")
|
||||||
List<Article> getOrderedArticles();
|
List<Article> getOrderedArticles();
|
||||||
|
|
||||||
@Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a WHERE c.id = :customerId ORDER BY co.id DESC")
|
@Query("SELECT DISTINCT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a WHERE c.id = :customerId ORDER BY co.id DESC")
|
||||||
List<Article> getOrderedArticles(long customerId);
|
List<Article> getOrderedArticles(long customerId);
|
||||||
|
|
||||||
|
/***
|
||||||
|
* use type safe findArticleByArticleOffer instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
@Query(value = "SELECT a.id FROM articles a WHERE a.related_id = :relatedId", nativeQuery = true)
|
@Query(value = "SELECT a.id FROM articles a WHERE a.related_id = :relatedId", nativeQuery = true)
|
||||||
Optional<Integer> findArticleIDByRelatedID(@Param("relatedId") long relatedId);
|
Optional<Integer> findArticleIDByRelatedID(@Param("relatedId") long relatedId);
|
||||||
|
|
||||||
|
@Query(value = "SELECT a FROM Article a Where a.related = :related")
|
||||||
|
Optional<Article> findArticleByArticleOffer(ArticleOffer related);
|
||||||
|
|
||||||
@Query(value = "Select a.* from articles as a, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and a.title LIKE %:term% group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
|
@Query(value = "Select a.* from articles as a, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and a.title LIKE %:term% group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
|
||||||
List<Article> getArticlesByTermInTitle(String term);
|
List<Article> getArticlesByTermInTitle(String term);
|
||||||
|
|
||||||
@Query(value = "Select a.* from articles as a, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and a.description LIKE %:term% group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
|
@Query(value = "Select a.* from articles as a, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and a.description LIKE %:term% group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
|
||||||
List<Article> getArticlesByTermInDescription(String term);
|
List<Article> getArticlesByTermInDescription(String term);
|
||||||
|
|
||||||
@Query(value = "Select a.* from articles as a, categories as c, article_categories_bindings as acb, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and acb.articles_id = a.id and acb.categories_id = c.id and c.name = :category group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
|
@Query(value = "Select distinct a.* from articles as a, categories as c, article_categories_bindings as acb, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and acb.articles_id = a.id and acb.categories_id = c.id and c.name = :category group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
|
||||||
List<Article> getArticlesByCategory(String category);
|
List<Article> getArticlesByCategory(String category);
|
||||||
}
|
}
|
@ -1,17 +0,0 @@
|
|||||||
package org.hso.ecommerce.repos.shop;
|
|
||||||
|
|
||||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
import org.springframework.data.jpa.repository.Query;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
public interface CustomerOderRepository extends JpaRepository<CustomerOrder, Long> {
|
|
||||||
|
|
||||||
@Query("SELECT SUM(cop.quantity) FROM CustomerOrderPosition cop JOIN cop.order co WHERE cop.article.id = :articleId AND co.created >= :begin AND co.created < :end")
|
|
||||||
Integer countOrdersOfArticleInTimespan(
|
|
||||||
long articleId, java.sql.Timestamp begin, java.sql.Timestamp end
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
|||||||
|
package org.hso.ecommerce.repos.shop;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.entities.shop.CustomerOrder;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface CustomerOrderRepository extends JpaRepository<CustomerOrder, Long> {
|
||||||
|
|
||||||
|
@Query("SELECT SUM(cop.quantity) FROM CustomerOrderPosition cop JOIN cop.order co WHERE cop.article.id = :articleId AND co.created >= :begin AND co.created < :end")
|
||||||
|
Integer countOrdersOfArticleInTimespan(
|
||||||
|
long articleId, java.sql.Timestamp begin, java.sql.Timestamp end
|
||||||
|
);
|
||||||
|
|
||||||
|
@Query("SELECT co FROM CustomerOrder co ORDER BY co.id DESC")
|
||||||
|
List<CustomerOrder> getAllOrders();
|
||||||
|
|
||||||
|
@Query("SELECT co FROM CustomerOrder co WHERE co.customer.id = :userId ORDER BY co.id DESC")
|
||||||
|
List<CustomerOrder> getOrdersByUserId(long userId);
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(co.id) FROM CustomerOrder co WHERE co.created >= :begin AND co.created < :end")
|
||||||
|
Integer countOrdersInTimespan(
|
||||||
|
java.sql.Timestamp begin, java.sql.Timestamp end
|
||||||
|
);
|
||||||
|
|
||||||
|
@Query("SELECT SUM(co.totalGrossCent) FROM CustomerOrder co WHERE co.created >= :begin AND co.created < :end")
|
||||||
|
Integer countTurnoverInTimespan(
|
||||||
|
java.sql.Timestamp begin, java.sql.Timestamp end
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
@ -3,12 +3,23 @@ package org.hso.ecommerce.repos.supplier;
|
|||||||
import org.hso.ecommerce.entities.supplier.SupplierOrder;
|
import org.hso.ecommerce.entities.supplier.SupplierOrder;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface SupplierOrderRepository extends JpaRepository<SupplierOrder, Long> {
|
public interface SupplierOrderRepository extends JpaRepository<SupplierOrder, Long> {
|
||||||
|
|
||||||
@Query("SELECT SUM(so.numberOfUnits) FROM SupplierOrder so JOIN so.ordered ao WHERE ao.articleNumber = :articleNumber AND so.delivered IS NULL")
|
@Query("SELECT SUM(so.numberOfUnits) FROM SupplierOrder so JOIN so.ordered ao WHERE ao.articleNumber = :articleNumber AND so.delivered IS NULL")
|
||||||
Integer countUndeliveredReorders(String articleNumber);
|
Integer countUndeliveredReorders(String articleNumber);
|
||||||
|
|
||||||
|
@Query(value = "SELECT * FROM supplier_orders as a WHERE a.supplier_id = :supplierId ORDER BY a.id DESC", nativeQuery = true)
|
||||||
|
List<SupplierOrder> findOrderBySupplierID(@Param("supplierId") long supplierId);
|
||||||
|
|
||||||
|
@Query("SELECT a FROM SupplierOrder a")
|
||||||
|
List<SupplierOrder> findAll();
|
||||||
|
|
||||||
|
@Query("SELECT a FROM SupplierOrder a ORDER BY a.id DESC")
|
||||||
|
List<SupplierOrder> findAllDesc();
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,22 @@ package org.hso.ecommerce.repos.supplier;
|
|||||||
|
|
||||||
import org.hso.ecommerce.entities.supplier.Supplier;
|
import org.hso.ecommerce.entities.supplier.Supplier;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface SupplierRepository extends JpaRepository<Supplier, Long> {
|
public interface SupplierRepository extends JpaRepository<Supplier, Long> {
|
||||||
|
|
||||||
|
@Query("SELECT a FROM Supplier a")
|
||||||
|
List<Supplier> findAll();
|
||||||
|
|
||||||
|
@Query("SELECT a FROM Supplier a WHERE a.id = :supplierId")
|
||||||
|
Supplier findSupplierById(@Param("supplierId") long supplierId);
|
||||||
|
|
||||||
|
@Query("SELECT a FROM Supplier a WHERE a.uuid = :uuid")
|
||||||
|
Optional<Supplier> findByUuid(@Param("uuid") String uuid);
|
||||||
}
|
}
|
@ -13,6 +13,11 @@ public interface UserRepository extends JpaRepository<User, Long> {
|
|||||||
@Query("SELECT c FROM User c WHERE c.email = :email")
|
@Query("SELECT c FROM User c WHERE c.email = :email")
|
||||||
Optional<User> findByEmail(String email);
|
Optional<User> findByEmail(String email);
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(c.id) FROM User c WHERE c.created >= :begin AND c.created < :end AND c.isEmployee = false")
|
||||||
|
Integer countUsersInTimespan(
|
||||||
|
java.sql.Timestamp begin, java.sql.Timestamp end
|
||||||
|
);
|
||||||
|
|
||||||
|
@Query("SELECT count(*) FROM User WHERE isEmployee = true")
|
||||||
|
Optional<Integer> numberOfEmployees();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,12 +11,11 @@ import java.util.Optional;
|
|||||||
@Repository
|
@Repository
|
||||||
public interface WarehouseBookingPositionSlotEntryRepository extends JpaRepository<WarehouseBookingPositionSlotEntry, Long> {
|
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)
|
@Query(value = "Select e.* 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);
|
List<WarehouseBookingPositionSlotEntry> getByArticle(long article);
|
||||||
|
|
||||||
|
@Query(value = "Select e.* 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)
|
||||||
@Query(value = "SELECT SUM(w.new_sum_slot) FROM warehouse_booking_position_entries as w WHERE w.article_id = :articleid", nativeQuery = true)
|
Optional<WarehouseBookingPositionSlotEntry> getBySlotNum(long slotnum);
|
||||||
Optional<Integer> getArticleStock(long articleid);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,19 @@ package org.hso.ecommerce.repos.warehouse;
|
|||||||
|
|
||||||
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
|
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface WarehouseBookingRepository extends JpaRepository<WarehouseBooking, Long> {
|
public interface WarehouseBookingRepository extends JpaRepository<WarehouseBooking, Long> {
|
||||||
|
|
||||||
|
@Query("Select b FROM WarehouseBooking b WHERE b.isDone = 0")
|
||||||
|
List<WarehouseBooking> findNotDone();
|
||||||
|
|
||||||
|
@Query("Select b FROM WarehouseBooking b ORDER BY b.id DESC")
|
||||||
|
List<WarehouseBooking> findAllDesc();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
package org.hso.ecommerce.uimodel;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
|
||||||
|
|
||||||
|
public class DeliveryData
|
||||||
|
{
|
||||||
|
|
||||||
|
private final String status;
|
||||||
|
|
||||||
|
private final DeliveryDataEnum deliveryDataEnum;
|
||||||
|
|
||||||
|
private final String estimatedArrival;
|
||||||
|
|
||||||
|
private boolean isDelivered;
|
||||||
|
|
||||||
|
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
|
||||||
|
public DeliveryData(String status, String estimatedArrival) {
|
||||||
|
this.status = status;
|
||||||
|
this.estimatedArrival = estimatedArrival;
|
||||||
|
this.deliveryDataEnum = DeliveryDataEnum.OK;
|
||||||
|
isDelivered = status.equals("Lieferung erfolgreich");
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeliveryData(String status, String estimatedArrival, DeliveryDataEnum deliveryDataEnum) {
|
||||||
|
this.status = status;
|
||||||
|
this.estimatedArrival = estimatedArrival;
|
||||||
|
this.deliveryDataEnum = deliveryDataEnum;
|
||||||
|
isDelivered = status.equals("Lieferung erfolgreich");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDelivered() {
|
||||||
|
return isDelivered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEstimatedArrival() {
|
||||||
|
return estimatedArrival;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allOk() {
|
||||||
|
return deliveryDataEnum == DeliveryDataEnum.OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean noTrackingID() {
|
||||||
|
return deliveryDataEnum == DeliveryDataEnum.NO_TRACKING_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean noData() {
|
||||||
|
return deliveryDataEnum == DeliveryDataEnum.NO_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.hso.ecommerce.uimodel;
|
||||||
|
|
||||||
|
public enum DeliveryDataEnum {
|
||||||
|
OK,
|
||||||
|
NO_TRACKING_ID,
|
||||||
|
NO_DATA
|
||||||
|
}
|
35
prototype/src/main/resources/static/css/manual-cronjobs.css
Normal file
35
prototype/src/main/resources/static/css/manual-cronjobs.css
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
.alert {
|
||||||
|
display: block;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background: #c0392b;
|
||||||
|
color: white;
|
||||||
|
animation: blinking 1s linear infinite;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert > span {
|
||||||
|
display: inline-block;
|
||||||
|
padding-left: 100%;
|
||||||
|
animation: marquee 10s linear infinite;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes marquee {
|
||||||
|
0% { transform: translateX(0); }
|
||||||
|
100% { transform: translateX(-100%); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blinking {
|
||||||
|
60% {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
color: #c0392b;
|
||||||
|
}
|
||||||
|
85% {
|
||||||
|
color: #c0392b;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
BIN
prototype/src/main/resources/static/favicon.ico
Normal file
BIN
prototype/src/main/resources/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
15
prototype/src/main/resources/static/js/editViewUpdateTax.js
vendored
Normal file
15
prototype/src/main/resources/static/js/editViewUpdateTax.js
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
let priceElm = document.getElementById("price");
|
||||||
|
let priceGrossElm = document.getElementById("priceGross");
|
||||||
|
let vatPercent = parseInt(document.getElementById("vatPercent").value);
|
||||||
|
|
||||||
|
let updateFn = () => {
|
||||||
|
let net = Math.floor(priceElm.value*100);
|
||||||
|
let vat = Math.floor((net * vatPercent) / 100);
|
||||||
|
let gross = net + vat;
|
||||||
|
|
||||||
|
priceGrossElm.innerText = (gross / 100.0).toFixed(2).replace("\\.", ",");
|
||||||
|
};
|
||||||
|
|
||||||
|
priceElm.onchange = updateFn;
|
||||||
|
});
|
@ -12,8 +12,6 @@
|
|||||||
<ul class="secondary">
|
<ul class="secondary">
|
||||||
<li><a th:href="@{/}"> > Zur Startseite</a></li>
|
<li><a th:href="@{/}"> > Zur Startseite</a></li>
|
||||||
<li><a th:href="@{/user/settings}">Einstellungen</a></li>
|
<li><a th:href="@{/user/settings}">Einstellungen</a></li>
|
||||||
<li><a th:href="@{/user/bonuspoints}">Bonuspunkte</a></li>
|
|
||||||
<li><a th:href="@{/user/notifications/}">Benachrichtigungen</a></li>
|
|
||||||
<li><a th:href="@{/user/orders/}">Bestellungen</a></li>
|
<li><a th:href="@{/user/orders/}">Bestellungen</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<li><a href="/login">Login</a></li>
|
<li><a href="/login">Login</a></li>
|
||||||
<li><a href="/">Angebote</a></li>
|
<li><a href="/">Angebote</a></li>
|
||||||
<li><a href="/shop/search">Suche</a></li>
|
<li><a href="/shop/search">Suche</a></li>
|
||||||
<li><a href="/intern/">Mitarbeiter Bereich</a></li>
|
<li><a href="/intern/" th:if="${user != null && user.isEmployee}">Mitarbeiter Bereich</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -11,14 +11,14 @@
|
|||||||
<div class='content-width bar-flex'>
|
<div class='content-width bar-flex'>
|
||||||
<a class="button no-padding" href="/"><img class="logo" th:src="@{/img/ecom-logo-base.svg}"></a>
|
<a class="button no-padding" href="/"><img class="logo" th:src="@{/img/ecom-logo-base.svg}"></a>
|
||||||
<form class='spacer input-icon secondary' th:action="@{/shop/search}" method="GET">
|
<form class='spacer input-icon secondary' th:action="@{/shop/search}" method="GET">
|
||||||
<input type="text" name="term" placeholder="Nach Produkten suchen..."/>
|
<input type="text" name="term" placeholder="Nach Produkten suchen..."
|
||||||
|
th:value="${searchterm != null ? searchterm : ''}"/>
|
||||||
<button>Finden</button>
|
<button>Finden</button>
|
||||||
</form>
|
</form>
|
||||||
<a th:unless="${user}" class="button" th:href="@{/login}">Login</a>
|
<a th:unless="${user}" class="button" th:href="@{/login}">Login</a>
|
||||||
<div th:if="${user}" class="dropdown">
|
<div th:if="${user}" class="dropdown">
|
||||||
<a class="dropdown-button button">Mein Konto</a>
|
<a class="dropdown-button button">Mein Konto</a>
|
||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
<a class="black button" th:href="@{/user/notifications/}">Benachrichtigungen</a>
|
|
||||||
<a class="black button" th:href="@{/user/}">Einstellungen</a>
|
<a class="black button" th:href="@{/user/}">Einstellungen</a>
|
||||||
<a class="black button" th:href="@{/user/orders/}">Meine Bestellungen</a>
|
<a class="black button" th:href="@{/user/orders/}">Meine Bestellungen</a>
|
||||||
<form th:if="${user}" method="post" th:action="@{/logout}" class="no-margin">
|
<form th:if="${user}" method="post" th:action="@{/logout}" class="no-margin">
|
||||||
@ -26,7 +26,10 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a class="button" th:href="@{/shop/checkout}">Warenkorb (<span th:text="${shoppingCart.itemCount}"></span>)</a>
|
<a class="button" th:href="@{/shop/checkout}">Warenkorb
|
||||||
|
<th:block th:if="${shoppingCart.itemCount > 0}"> (<span th:text="${shoppingCart.itemCount}"></span>)
|
||||||
|
</th:block>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div th:if="${error}" class="error" id="error-msg">
|
<div th:if="${error}" class="error" id="error-msg">
|
||||||
<div class="content-width bar-flex">
|
<div class="content-width bar-flex">
|
||||||
|
@ -47,6 +47,8 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li><a th:href="@{/intern/cronjobs/}">Cronjobs</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -20,10 +20,10 @@
|
|||||||
<main class="sidebar-layout content-width">
|
<main class="sidebar-layout content-width">
|
||||||
<nav th:replace="fragments/intern :: sidebar"></nav>
|
<nav th:replace="fragments/intern :: sidebar"></nav>
|
||||||
<div class="content-width">
|
<div class="content-width">
|
||||||
<form class="detailgrid">
|
<form th:action="@{/intern/accounting/addManual}" th:object="${form_vals}" method="post" class="detailgrid">
|
||||||
<div class="s">
|
<div class="s">
|
||||||
<label for="amount">Betrag</label>
|
<label for="amount">Betrag</label>
|
||||||
<input type="number" step="0.01" name="amount" value="0.00"/> EUR
|
<input type="number" step="0.01" id="amount" th:field="*{amount}" /> EUR
|
||||||
</div>
|
</div>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
|
|
||||||
@ -31,26 +31,26 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="source">Von Konto:</label>
|
<label for="source">Von Konto:</label>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="s-no" name="destination" value="None" required>
|
<input type="radio" id="s-no" th:field="*{source}" value="None" required>
|
||||||
<label for="s-no">Kein Konto</label>
|
<label for="s-no">Kein Konto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="s-main" name="destination" value="Main" required>
|
<input type="radio" id="s-main" th:field="*{source}" value="Main" required>
|
||||||
<label for="s-main">Hauptkonto</label>
|
<label for="s-main">Hauptkonto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="s-vat" name="destination" value="Vat" required>
|
<input type="radio" id="s-vat" th:field="*{source}" value="Vat" required>
|
||||||
<label for="s-vat">Mehrwertsteuerkonto</label>
|
<label for="s-vat">Mehrwertsteuerkonto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="s-cust" name="destination" value="Cust" required>
|
<input type="radio" id="s-cust" th:field="*{source}" value="Cust" required>
|
||||||
<label for="s-cust">Kundenkonto</label>
|
<label for="s-cust">Kundenkonto</label>
|
||||||
<input placeholder="Kunden Nr." type="text" name="destination-customer" value=""/>
|
<input placeholder="Kunden Nr." type="text" th:field="*{sourceCustomer}" value=""/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="s-sup" name="destination" value="Sup" required>
|
<input type="radio" id="s-sup" th:field="*{source}" value="Sup" required>
|
||||||
<label for="s-sup">Lieferanten Konto</label>
|
<label for="s-sup">Lieferanten Konto</label>
|
||||||
<input placeholder="Lieferanten Nr." type="text" name="destination-sup" value=""/>
|
<input placeholder="Lieferanten Nr." type="text" th:field="*{sourceSupplier}" value=""/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
@ -59,26 +59,26 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="destination">Nach Konto:</label>
|
<label for="destination">Nach Konto:</label>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="d-no" name="destination" value="None" required>
|
<input type="radio" id="d-no" th:field="*{destination}" value="None" required>
|
||||||
<label for="d-no">Kein Konto</label>
|
<label for="d-no">Kein Konto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="d-main" name="destination" value="Main" required>
|
<input type="radio" id="d-main" th:field="*{destination}" value="Main" required>
|
||||||
<label for="d-main">Hauptkonto</label>
|
<label for="d-main">Hauptkonto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="d-vat" name="destination" value="Vat" required>
|
<input type="radio" id="d-vat" th:field="*{destination}" value="Vat" required>
|
||||||
<label for="d-vat">Mehrwertsteuerkonto</label>
|
<label for="d-vat">Mehrwertsteuerkonto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="d-cust" name="destination" value="Cus" required>
|
<input type="radio" id="d-cust" th:field="*{destination}" value="Cust" required>
|
||||||
<label for="d-cust">Kundenkonto</label>
|
<label for="d-cust">Kundenkonto</label>
|
||||||
<input placeholder="Kunden Nr." type="text" name="destination-customer" value=""/>
|
<input placeholder="Kunden Nr." type="text" th:field="*{destinationCustomer}" value=""/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="d-sup" name="destination" value="Sup" required>
|
<input type="radio" id="d-sup" th:field="*{destination}" value="Sup" required>
|
||||||
<label for="d-sup">Lieferanten Konto</label>
|
<label for="d-sup">Lieferanten Konto</label>
|
||||||
<input placeholder="Lieferanten Nr." type="text" name="destination-sup" value=""/>
|
<input placeholder="Lieferanten Nr." type="text" th:field="*{destinationSupplier}" value=""/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
@ -87,13 +87,14 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="reason">Buchungsgrund:</label>
|
<label for="reason">Buchungsgrund:</label>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" name="reason" value="Start">
|
<input type="radio" id="r-start" th:field="*{reason}" value="Start">
|
||||||
<label for="d-sup">Startbuchung</label>
|
<label for="r-start">Startbuchung</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" name="reason" value="Manual" checked>
|
<input type="radio" id="r-manual" th:field="*{reason}" value="Manual">
|
||||||
<label for="d-sup">Manuell</label>
|
<label for="r-manual">Manuell</label>
|
||||||
<input placeholder="Grund" class="full-width" type="text" name="reason-man" value=""/>
|
<input placeholder="Grund" class="full-width" type="text" th:field="*{reasonText}" value=""
|
||||||
|
required="required"/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,48 +49,21 @@
|
|||||||
<th>Referenz</th>
|
<th>Referenz</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr th:each="booking: ${bookings}">
|
||||||
<td>10.09.2019 14:10</td>
|
<td th:text="${booking.datetime}" />
|
||||||
<td>119,00 EUR</td>
|
<td th:text="${booking.amount}" />
|
||||||
<td> -</td>
|
|
||||||
<td> -</td>
|
|
||||||
<td><a th:href="@{/intern/customers/5000}">Kunde 5080</a></td>
|
|
||||||
<td>0 EUR</td>
|
|
||||||
<td>Kunden-Bezahlung</td>
|
|
||||||
<td>Bezahlung mit Kreditkarte XXXXX480</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<td th:if="${booking.sourceAddr}"><a th:href="@{${booking.sourceAddr}}" th:text="${booking.source}" /></td>
|
||||||
<td>10.09.2019 13:45</td>
|
<td th:unless="${booking.sourceAddr}" th:text="${booking.source}" />
|
||||||
<td>19,00 EUR</td>
|
<td th:text="${booking.sourceBalance}" />
|
||||||
<td><a th:href="@{/intern/accounting/main}">Hauptkonto</a></td>
|
|
||||||
<td>331,00 EUR</td>
|
|
||||||
<td><a th:href="@{/intern/accounting/vat}">Mehrwertsteuer</a></td>
|
|
||||||
<td>1510,95 EUR</td>
|
|
||||||
<td>Kunden-Bestellung</td>
|
|
||||||
<td><a th:href="@{/intern/customerOrders/450}">2504</a></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<td th:if="${booking.destinationAddr}"><a th:href="@{${booking.destinationAddr}}" th:text="${booking.destination}" /></td>
|
||||||
<td>10.09.2019 13:45</td>
|
<td th:unless="${booking.destinationAddr}" th:text="${booking.destination}" />
|
||||||
<td>100,00 EUR</td>
|
<td th:text="${booking.destinationBalance}" />
|
||||||
<td><a th:href="@{/intern/customers/5000}">Kunde 5080</a></td>
|
|
||||||
<td>-100,00 EUR</td>
|
|
||||||
<td><a th:href="@{/intern/accounting/main}">Hauptkonto</a></td>
|
|
||||||
<td>350,00 EUR</td>
|
|
||||||
<td>Kunden-Bestellung</td>
|
|
||||||
<td><a th:href="@{/intern/customerOrders/450}">2504</a></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<td th:text="${booking.reason}" />
|
||||||
<td>19.08.2019 12:31</td>
|
<td th:if="${booking.referenceAddr}"><a th:href="@{${booking.referenceAddr}}" th:text="${booking.reference}" /></td>
|
||||||
<td>250,00 EUR</td>
|
<td th:unless="${booking.referenceAddr}" th:text="${booking.reference}" />
|
||||||
<td> -</td>
|
|
||||||
<td> -</td>
|
|
||||||
<td><a th:href="@{/intern/accounting/main}">Hauptkonto</a></td>
|
|
||||||
<td>250,00 EUR</td>
|
|
||||||
<td>Startkapital</td>
|
|
||||||
<td> -</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
<nav th:replace="fragments/intern :: sidebar"></nav>
|
<nav th:replace="fragments/intern :: sidebar"></nav>
|
||||||
<div class="content-width">
|
<div class="content-width">
|
||||||
<h3> Kontostand </h3>
|
<h3> Kontostand </h3>
|
||||||
<h2> 331,00 EUR </h2>
|
<h2 th:text="${balance}" />
|
||||||
<p>
|
<p>
|
||||||
<table id="main-table">
|
<table id="main-table">
|
||||||
<tr>
|
<tr>
|
||||||
@ -42,33 +42,18 @@
|
|||||||
<th>Grund</th>
|
<th>Grund</th>
|
||||||
<th>Referenz</th>
|
<th>Referenz</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr th:each="booking: ${bookings}">
|
||||||
<td>10.09.2019 13:45</td>
|
<td th:text="${booking.datetime}" />
|
||||||
<td>-19,00 EUR</td>
|
<td th:text="${booking.amount}" />
|
||||||
|
|
||||||
<td><a th:href="@{/intern/accounting/vat}">Mehrwertsteuer</a></td>
|
<td th:if="${booking.sourceAddr}"><a th:href="@{${booking.sourceAddr}}" th:text="${booking.source}" /></td>
|
||||||
<td>331,00 EUR</td>
|
<td th:unless="${booking.sourceAddr}" th:text="${booking.source}" />
|
||||||
|
|
||||||
<td>Kunden-Bestellung</td>
|
<td th:text="${booking.balance}" />
|
||||||
<td><a th:href="@{/intern/customerOrders/450}">2504</a></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<td th:text="${booking.reason}" />
|
||||||
<td>10.09.2019 13:45</td>
|
<td th:if="${booking.referenceAddr}"><a th:href="@{${booking.referenceAddr}}" th:text="${booking.reference}" /></td>
|
||||||
<td>100,00 EUR</td>
|
<td th:unless="${booking.referenceAddr}" th:text="${booking.reference}" />
|
||||||
<td><a th:href="@{/intern/customers/5000}">Kunde 5080</a></td>
|
|
||||||
<td>350,00 EUR</td>
|
|
||||||
<td>Kunden-Bestellung</td>
|
|
||||||
<td><a th:href="@{/intern/customerOrders/450}">2504</a></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>19.08.2019 12:31</td>
|
|
||||||
<td>250,00 EUR</td>
|
|
||||||
<td> -</td>
|
|
||||||
<td>250,00 EUR</td>
|
|
||||||
<td>Startkapital</td>
|
|
||||||
<td> -</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<nav th:replace="fragments/intern :: sidebar"></nav>
|
<nav th:replace="fragments/intern :: sidebar"></nav>
|
||||||
<div class="content-width">
|
<div class="content-width">
|
||||||
<h3> Kontostand </h3>
|
<h3> Kontostand </h3>
|
||||||
<h2> 1510.95 EUR </h2>
|
<h2 th:text="${balance}" />
|
||||||
<p>
|
<p>
|
||||||
<table id="main-table">
|
<table id="main-table">
|
||||||
<tr>
|
<tr>
|
||||||
@ -43,13 +43,18 @@
|
|||||||
<th>Grund</th>
|
<th>Grund</th>
|
||||||
<th>Referenz</th>
|
<th>Referenz</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr th:each="booking: ${bookings}">
|
||||||
<td>10.09.2019 13:45</td>
|
<td th:text="${booking.datetime}" />
|
||||||
<td>19,00 EUR</td>
|
<td th:text="${booking.amount}" />
|
||||||
<td><a th:href="@{/intern/accounting/main}">Hauptkonto</a></td>
|
|
||||||
<td>1510,95 EUR</td>
|
<td th:if="${booking.sourceAddr}"><a th:href="@{${booking.sourceAddr}}" th:text="${booking.source}" /></td>
|
||||||
<td>Kunden-Bestellung</td>
|
<td th:unless="${booking.sourceAddr}" th:text="${booking.source}" />
|
||||||
<td><a th:href="@{/intern/customerOrders/450}">2504</a></td>
|
|
||||||
|
<td th:text="${booking.balance}" />
|
||||||
|
|
||||||
|
<td th:text="${booking.reason}" />
|
||||||
|
<td th:if="${booking.referenceAddr}"><a th:href="@{${booking.referenceAddr}}" th:text="${booking.reference}" /></td>
|
||||||
|
<td th:unless="${booking.referenceAddr}" th:text="${booking.reference}" />
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
<!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>Cronjobs</title>
|
||||||
|
<script th:src="@{/js/filterTable.js}"></script>
|
||||||
|
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
|
||||||
|
<link rel="stylesheet" th:href="@{/css/manual-cronjobs.css}"/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav th:replace="fragments/header :: header">Header</nav>
|
||||||
|
<div class="sidebar-layout content-width">
|
||||||
|
<nav></nav>
|
||||||
|
<div>
|
||||||
|
<h1>Cronjobs</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<main class="sidebar-layout content-width">
|
||||||
|
<nav th:replace="fragments/intern :: sidebar"></nav>
|
||||||
|
<div class="content-width">
|
||||||
|
<h3>Manuelle Ausführung von Cronjobs</h3>
|
||||||
|
<div class="alert"><span>
|
||||||
|
WARNUNG<br>
|
||||||
|
Manuelles Triggern von Cronjobs kann zu unerwartetem Verhalten führen!<br>
|
||||||
|
Diese Seite ist nur für Debugging-Zwecke gedacht.
|
||||||
|
</span></div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<table id="main-table">
|
||||||
|
<tr>
|
||||||
|
<th colspan="7">
|
||||||
|
<input type="text" placeholder="Filtern" class="smaller jsFilterTable full-width"
|
||||||
|
data-target-id="main-table"></input>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Cronjob</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
<tr th:each="job: ${jobs}">
|
||||||
|
<td th:text="${job.visibleName}"></td>
|
||||||
|
<td>
|
||||||
|
<form th:action="@{/intern/cronjobs/run/{identifier}(identifier = ${job.identifier})}" method="post">
|
||||||
|
<input class="button smaller" type="submit" value="Ausführen" />
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer th:replace="fragments/footer :: footer"></footer>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -15,7 +15,7 @@
|
|||||||
<div class="sidebar-layout content-width">
|
<div class="sidebar-layout content-width">
|
||||||
<nav></nav>
|
<nav></nav>
|
||||||
<div>
|
<div>
|
||||||
<h1>Bestellung 1010</h1>
|
<h1 th:text="|Bestellung ${order.id}|"></h1>
|
||||||
|
|
||||||
<script th:src="@{/js/back.js}"></script>
|
<script th:src="@{/js/back.js}"></script>
|
||||||
<div class="back" data-group="intern" data-insert="true"></div>
|
<div class="back" data-group="intern" data-insert="true"></div>
|
||||||
@ -25,33 +25,32 @@
|
|||||||
<nav th:replace="fragments/intern :: sidebar"></nav>
|
<nav th:replace="fragments/intern :: sidebar"></nav>
|
||||||
<div class="content-width">
|
<div class="content-width">
|
||||||
<div>
|
<div>
|
||||||
<h2 id="20202701"> Bestellung vom 27.01.2020 </h2>
|
<h2 th:text="| Bestellung vom ${order.created.toString().substring(0,10)}|"></h2>
|
||||||
<div>
|
<div>
|
||||||
<table class="key-value">
|
<table class="key-value">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Nutzer</th>
|
<th>Nutzer</th>
|
||||||
<td><a th:href="@{/intern/customers/498}">K-4850</a></td>
|
<td><a th:href="@{/intern/customers/{id}(id=${order.customer.id})}" th:text="${order.customer.id}"></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Lieferstatus</th>
|
<th>Lieferstatus</th>
|
||||||
<td><b>Unterwegs</b> <br/> Vorraussichtliche Ankunft: 29.01.2020</td>
|
<td th:if="${deliveryData.allOk()}"><span th:text="${deliveryData.getStatus()}" /></td>
|
||||||
|
<td th:if="${deliveryData.noTrackingID()}">Bestellung wurde elektronisch angekündigt</td>
|
||||||
|
<td th:if="${deliveryData.noData()}">DHL-Server ist gerade nicht erreichbar</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td th:if="${order.deliveredAt == null && order.trackingId!=null && !deliveryData.noData()}">Vorraussichtliche Ankunft: <span th:text="${deliveryData.getEstimatedArrival()}" /></td>
|
||||||
|
<td th:if="${order.deliveredAt == null && order.trackingId!=null && deliveryData.noData()}">Vorraussichtliche Ankunft: --:--:---- </td>
|
||||||
|
<td th:if="${order.deliveredAt != null && order.trackingId!=null}"><b>Angekommen</b> Ankunft: <span th:text="${deliveryData.getEstimatedArrival()}" /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Sendeverfolgungsnummer</th>
|
<th>Sendeverfolgungsnummer</th>
|
||||||
<td>XE51451436DE</td>
|
<td th:text="${order.trackingId!=null} ? ${order.trackingId} : 'Es wurde noch keine Sendungsnummer vergeben'"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<td>
|
<td th:text="${order.destination.toString()}"></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>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -62,18 +61,11 @@
|
|||||||
<th>Menge</th>
|
<th>Menge</th>
|
||||||
<th>Preis (Brutto)</th>
|
<th>Preis (Brutto)</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr th:each="position: ${order.positions}">
|
||||||
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-1.jpg}" class="s"/><a></td>
|
<td><a th:href="@{/shop/articles/{id}(id = ${position.article.id})}"><img th:src="@{/shop/articles/{id}/image.jpg(id=${position.article.id})}" class="s"/></a></td>
|
||||||
<td><a th:href="@{/shop/articles/4151}">Kamera<a/></td>
|
<td><a th:href="@{/shop/articles/{id}(id = ${position.article.id})}" th:text="${position.article.title}" class="s"></a></td>
|
||||||
<td> 1</td>
|
<td th:text="${position.quantity}" />
|
||||||
<td>100,50 EUR</td>
|
<td th:text="${#numbers.formatDecimal(position.getSumPrice() * 0.01, 1, 'POINT', 2, 'COMMA')}" />
|
||||||
</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>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th></th>
|
<th></th>
|
||||||
@ -84,28 +76,22 @@
|
|||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>Artikel (Netto)</td>
|
<td>Artikel (Netto)</td>
|
||||||
<td> 120,00 EUR</td>
|
<td th:text="${#numbers.formatDecimal(order.totalNetCent * 0.01, 1, 'POINT', 2, 'COMMA')}" />
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>Bonuspunkte</td>
|
<td>Umsatzsteuer</td>
|
||||||
<td> 5,00 EUR</td>
|
<td th:text="${#numbers.formatDecimal(order.totalVatCent * 0.01, 1, 'POINT', 2, 'COMMA')}" />
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
<td>Umsatzsteuer (19%)</td>
|
|
||||||
<td> 42,00 EUR</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>
|
<td>
|
||||||
<h3>Gesammtpreis</h3>
|
<h3>Gesamtpreis</h3>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<h3>240,79 EUR</h3>
|
<h3 th:text="${#numbers.formatDecimal(order.totalGrossCent * 0.01, 1, 'POINT', 2, 'COMMA')}"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -40,37 +40,17 @@
|
|||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr th:each="order: ${orderDeliveryDataMap}">
|
||||||
<td><a th:href="@{/intern/customers/48584}">101</a></td>
|
<td><a th:href="@{/intern/customers/{id}(id=${order.customerOrder.customer.id})}"
|
||||||
<td>440</td>
|
th:text="${order.customerOrder.customer.id}">101</a></td>
|
||||||
<td>2019-12-54</td>
|
<td th:text="${order.customerOrder.id}"></td>
|
||||||
<td>10,13 EUR</td>
|
<td th:text="${order.customerOrder.created.toString().substring(0, 10)}"></td>
|
||||||
<td>Zugestellt</td>
|
<td th:text="${#numbers.formatDecimal(order.customerOrder.totalGrossCent * 0.01, 1, 'POINT', 2, 'COMMA')}"></td>
|
||||||
<td><a th:href="@{/intern/customerOrders/48584}" class="button smaller">Details</a></td>
|
<td th:if="${order.deliveryData.allOk()}"><span th:text="${order.deliveryData.getStatus()}"/></td>
|
||||||
</tr>
|
<td th:if="${order.deliveryData.noTrackingID()}">Bestellung wurde elektronisch angekündigt</td>
|
||||||
<tr>
|
<td th:if="${order.deliveryData.noData()}">DHL-Server ist gerade nicht erreichbar</td>
|
||||||
<td><a th:href="@{/intern/customers/48584}">102</a></td>
|
<td><a th:href="@{/intern/customerOrders/{id}(id=${order.customerOrder.id})}" class="button smaller">Details</a>
|
||||||
<td>241</td>
|
</td>
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>40,13 EUR</td>
|
|
||||||
<td>In Zustellung</td>
|
|
||||||
<td><a th:href="@{/intern/customerOrders/48584}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><a th:href="@{/intern/customers/48584}">101</a></td>
|
|
||||||
<td>241</td>
|
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>10,13 EUR</td>
|
|
||||||
<td>Erfasst</td>
|
|
||||||
<td><a th:href="@{/intern/customerOrders/48584}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><a th:href="@{/intern/customers/48584}">755</a></td>
|
|
||||||
<td>544</td>
|
|
||||||
<td>2019-12-10</td>
|
|
||||||
<td>45,13 EUR</td>
|
|
||||||
<td>Erfasst</td>
|
|
||||||
<td><a th:href="@{/intern/customerOrders/48584}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<div class="sidebar-layout content-width">
|
<div class="sidebar-layout content-width">
|
||||||
<nav></nav>
|
<nav></nav>
|
||||||
<div>
|
<div>
|
||||||
<h1>Kunde 1510</h1>
|
<h1 th:text="|Kunde ${user.id}|"></h1>
|
||||||
|
|
||||||
<script th:src="@{/js/back.js}"></script>
|
<script th:src="@{/js/back.js}"></script>
|
||||||
<div class="back" data-group="intern" data-insert="true"></div>
|
<div class="back" data-group="intern" data-insert="true"></div>
|
||||||
@ -37,33 +37,26 @@
|
|||||||
<table class="key-value">
|
<table class="key-value">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Nutzer</th>
|
<th>Nutzer</th>
|
||||||
<td><a th:href="@{/intern/customers/498}">1510</a></td>
|
<td><a th:href="@{/intern/customers/{id}(id=${user.id})}" th:text="${user.id}"></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<th>Bonuspunktestand</th>
|
|
||||||
<td>50</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<td>Hans Maier</td>
|
<td th:text="${user.defaultDeliveryAddress != null ? user.defaultDeliveryAddress.name : '-'}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>E-Mail</th>
|
<th>E-Mail</th>
|
||||||
<td>hans.maier@example.com</td>
|
<td th:text="${user.email}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<td>Geschäftskunde, Aktiv</td>
|
<td>
|
||||||
|
<span th:text="${user.isActive} ? 'Aktiv,' : 'Inaktiv,'"></span>
|
||||||
|
<span th:text="${user.isEmployee} ? 'Mitarbeiter' : 'Kunde'"></span>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Adresse</th>
|
<th>Adresse</th>
|
||||||
<td>
|
<td th:Text="${user.defaultDeliveryAddress != null ? user.defaultDeliveryAddress : ''}"></td>
|
||||||
Hans Maier <br/>
|
|
||||||
Hauptstraße 12<br/>
|
|
||||||
74880 Musterstadt<br/>
|
|
||||||
Deutschland <br/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
@ -74,15 +67,15 @@
|
|||||||
<div id="add-actions" class="invisible info-box secondary hero">
|
<div id="add-actions" class="invisible info-box secondary hero">
|
||||||
<h2>Status bearbeiten</h2>
|
<h2>Status bearbeiten</h2>
|
||||||
<p>
|
<p>
|
||||||
<form>
|
<form method="POST" th:action="@{/intern/customers/{id}/changeState(id=${user.id})}">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="checkbox" name="activ" id="activ" checked>
|
<input type="checkbox" name="active" id="active" th:checked="${user.isActive}">
|
||||||
<label for="activ">Aktiv</label> <br/>
|
<label for="active">Aktiv</label> <br/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
|
||||||
<input type="checkbox" name="ma" id="ma">
|
<input type="checkbox" name="ma" id="ma" th:checked="${user.isEmployee}">
|
||||||
<label for="ma">Mitarbeiter-Status</label> <br/>
|
<label for="ma">Mitarbeiter-Status</label> <br/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
@ -94,11 +87,14 @@
|
|||||||
</p>
|
</p>
|
||||||
<h2>Passwort zurücksetzen</h2>
|
<h2>Passwort zurücksetzen</h2>
|
||||||
<p>
|
<p>
|
||||||
<form>
|
<form method="POST" th:action="@{/intern/customers/{id}/resetPassword(id=${user.id})}">
|
||||||
<div>
|
<div>
|
||||||
<label for="password">Passwort</label>
|
<label for="password">Passwort</label>
|
||||||
<input class="full-width" type="password" name="password" placeholder="Passwort" id="password"
|
<input class="full-width" type="password" name="password" placeholder="Passwort" id="password"
|
||||||
|
pattern="(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,}"
|
||||||
required>
|
required>
|
||||||
|
<small>Das Passwort muss mindestens 8 Zeichen enthalten. Es muss aus mindestens einem
|
||||||
|
Großbuchstaben, einem Kleinbuchstaben und einer Zahl bestehen.</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@ -113,10 +109,8 @@
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<h2>Bestellungen</h2>
|
<h2>Bestellungen</h2>
|
||||||
<p>
|
<p>
|
||||||
<table id="main-table">
|
<table id="main-table">
|
||||||
@ -127,26 +121,20 @@
|
|||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr th:each="order: ${orders}">
|
||||||
<td>440</td>
|
<td th:text="${order.id}"></td>
|
||||||
<td>2019-12-54</td>
|
<td th:text="${order.formatCreated()}"></td>
|
||||||
<td>10,13 EUR</td>
|
<td th:text="${#numbers.formatDecimal(order.totalGrossCent * 0.01, 1, 'POINT', 2, 'COMMA')}"></td>
|
||||||
<td>Zugestellt</td>
|
<td th:if="${order.deliveredAt == null}">In Zustellung</td>
|
||||||
<td><a th:href="@{/intern/customerOrders/48584}" class="button smaller">Details</a></td>
|
<td th:if="${order.deliveredAt != null}">Zugestellt</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>241</td>
|
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>40,13 EUR</td>
|
|
||||||
<td>In Zustellung</td>
|
|
||||||
<td><a th:href="@{/intern/customerOrders/48584}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Buchungen</h2>
|
<h2>Buchungen</h2>
|
||||||
<div>
|
<div>
|
||||||
<h4> Kontostand </h4>
|
<h4> Kontostand </h4>
|
||||||
<h3> 0,00 EUR </h3>
|
<h3 th:text="${balance}" />
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
<table id="main-table">
|
<table id="main-table">
|
||||||
@ -164,21 +152,18 @@
|
|||||||
<th>Grund</th>
|
<th>Grund</th>
|
||||||
<th>Referenz</th>
|
<th>Referenz</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr th:each="booking: ${bookings}">
|
||||||
<td>10.09.2019 14:10</td>
|
<td th:text="${booking.datetime}" />
|
||||||
<td>119,00 EUR</td>
|
<td th:text="${booking.amount}" />
|
||||||
<td> -</td>
|
|
||||||
<td>0 EUR</td>
|
<td th:if="${booking.sourceAddr}"><a th:href="@{${booking.sourceAddr}}" th:text="${booking.source}" /></td>
|
||||||
<td>Kunden-Bezahlung</td>
|
<td th:unless="${booking.sourceAddr}" th:text="${booking.source}" />
|
||||||
<td>Bezahlung mit Kreditkarte XXXXXXXX480</td>
|
|
||||||
</tr>
|
<td th:text="${booking.balance}" />
|
||||||
<tr>
|
|
||||||
<td>10.09.2019 13:45</td>
|
<td th:text="${booking.reason}" />
|
||||||
<td>-100,00 EUR</td>
|
<td th:if="${booking.referenceAddr}"><a th:href="@{${booking.referenceAddr}}" th:text="${booking.reference}" /></td>
|
||||||
<td><a th:href="@{/intern/accounting/main}">Hauptkonto</a></td>
|
<td th:unless="${booking.referenceAddr}" th:text="${booking.reference}" />
|
||||||
<td>-100,00 EUR</td>
|
|
||||||
<td>Kunden-Bestellung</td>
|
|
||||||
<td><a th:href="@{/intern/customerOrders/450}">2504</a></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
|
@ -39,85 +39,16 @@
|
|||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr th:each="user: ${users}">
|
||||||
<td>1209</td>
|
<td th:text="${user.id}"></td>
|
||||||
<td>2019-11-10</td>
|
<td th:text="${user.created.toString().substring(0, 10)}"></td>
|
||||||
<td>Hans Maier</td>
|
<td th:text="${user.defaultDeliveryAddress != null ? user.defaultDeliveryAddress.name : ''}"></td>
|
||||||
<td>hans.maier@example.com</td>
|
<td th:text="${user.email}"></td>
|
||||||
<td>Geschäftskunde</td>
|
<td>
|
||||||
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
|
<span th:text="${user.isActive} ? 'Aktiv,' : 'Inaktiv,'"></span>
|
||||||
</tr>
|
<span th:text="${user.isEmployee} ? 'Mitarbeiter' : 'Kunde'"></span>
|
||||||
<tr>
|
</td>
|
||||||
<td>1208</td>
|
<td><a th:href="@{/intern/customers/{id}(id = ${user.id})}" class="button smaller">Details</a></td>
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>Hans Maier</td>
|
|
||||||
<td>hans.maier@example.com</td>
|
|
||||||
<td>Inaktiv, Geschäftskunde</td>
|
|
||||||
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>1207</td>
|
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>Hans Maier</td>
|
|
||||||
<td>hans.maier@example.com</td>
|
|
||||||
<td></td>
|
|
||||||
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>1206</td>
|
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>Hans Maier</td>
|
|
||||||
<td>hans.maier@example.com</td>
|
|
||||||
<td></td>
|
|
||||||
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>1205</td>
|
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>Hans Maier</td>
|
|
||||||
<td>hans.maier@example.com</td>
|
|
||||||
<td></td>
|
|
||||||
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>1204</td>
|
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>Hans Maier</td>
|
|
||||||
<td>hans.maier@example.com</td>
|
|
||||||
<td></td>
|
|
||||||
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>1203</td>
|
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>Hans Maier</td>
|
|
||||||
<td>hans.maier@example.com</td>
|
|
||||||
<td></td>
|
|
||||||
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>1202</td>
|
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>Hans Maier</td>
|
|
||||||
<td>hans.maier@example.com</td>
|
|
||||||
<td></td>
|
|
||||||
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>1201</td>
|
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>Hans Maier</td>
|
|
||||||
<td>hans.maier@example.com</td>
|
|
||||||
<td>Inaktiv, Mitarbeiter</td>
|
|
||||||
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>1214</td>
|
|
||||||
<td>2019-11-10</td>
|
|
||||||
<td>Hans Maier</td>
|
|
||||||
<td>admin@example.com</td>
|
|
||||||
<td>Mitarbeiter</td>
|
|
||||||
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
|
||||||
<script src="/js/chart.js"></script>
|
<script src="/js/chart.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function chart(id, name, data, unit) {
|
function chart(id, name, data, unit, dates) {
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
let elm = document.getElementById(id);
|
let elm = document.getElementById(id);
|
||||||
let cs = getComputedStyle(elm)
|
let cs = getComputedStyle(elm)
|
||||||
let ctx = elm.getContext('2d');
|
let ctx = elm.getContext('2d');
|
||||||
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
// The data for our dataset
|
// The data for our dataset
|
||||||
data: {
|
data: {
|
||||||
labels: ['Freitag', 'Donnerstag', 'Mittwoch', 'Dienstag', 'Montag'],
|
labels: dates,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: name,
|
label: name,
|
||||||
backgroundColor: cs.getPropertyValue('--c-primary'),
|
backgroundColor: cs.getPropertyValue('--c-primary'),
|
||||||
@ -61,7 +61,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@ -88,12 +87,12 @@
|
|||||||
<div class="grid xl">
|
<div class="grid xl">
|
||||||
<section class="primary hero">
|
<section class="primary hero">
|
||||||
<h3>Hauptkonto</h3>
|
<h3>Hauptkonto</h3>
|
||||||
<h2>4080,00 EUR</h2>
|
<h2 th:text="${mainAccountBalance}" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="primary hero">
|
<section class="primary hero">
|
||||||
<h3>Umsatzsteuerkonto</h3>
|
<h3>Umsatzsteuerkonto</h3>
|
||||||
<h2>-505,00 EUR</h2>
|
<h2 th:text="${vatAccountBalance}" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="spacer"></section>
|
<section class="spacer"></section>
|
||||||
@ -107,7 +106,12 @@
|
|||||||
<h3>Verkäufe (Anzahl)</h3>
|
<h3>Verkäufe (Anzahl)</h3>
|
||||||
<canvas id="sales"></canvas>
|
<canvas id="sales"></canvas>
|
||||||
<script>
|
<script>
|
||||||
chart('sales', 'Verkäufe/Tag', [15, 12, 14, 8, 7])
|
fetch('./dashboardsummary')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
chart('sales', 'Verkäufe/Tag', data.map(d => d.todaysCustomersOrders),
|
||||||
|
"", data.map(g => " "+g.created));
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</section>
|
</section>
|
||||||
@ -116,7 +120,12 @@
|
|||||||
<h3>Verkäufe (Umsatz)</h3>
|
<h3>Verkäufe (Umsatz)</h3>
|
||||||
<canvas id="umsatz"></canvas>
|
<canvas id="umsatz"></canvas>
|
||||||
<script>
|
<script>
|
||||||
chart('umsatz', 'Umsatz/Tag', [1512.45, 1225.15, 1452.54, 814.54, 746.00], "EUR")
|
fetch('./dashboardsummary')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
chart('umsatz', 'Umsatz/Tag', data.map(d => d.todaysSalesCent / 100),
|
||||||
|
"€", data.map(g => " "+g.created));
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</section>
|
</section>
|
||||||
@ -125,7 +134,12 @@
|
|||||||
<h3>Neukunden</h3>
|
<h3>Neukunden</h3>
|
||||||
<canvas id="Neukunden"></canvas>
|
<canvas id="Neukunden"></canvas>
|
||||||
<script>
|
<script>
|
||||||
chart('Neukunden', 'Neukunden', [1, 1, 0, 5, 0], "")
|
fetch('./dashboardsummary')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
chart('Neukunden', 'Neukunden', data.map(d => d.todaysNewCustomers),
|
||||||
|
"", data.map(g => " "+g.created));
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</section>
|
</section>
|
||||||
@ -139,7 +153,12 @@
|
|||||||
<h2>Lagerauslastung</h2>
|
<h2>Lagerauslastung</h2>
|
||||||
<canvas id="warehouse"></canvas>
|
<canvas id="warehouse"></canvas>
|
||||||
<script>
|
<script>
|
||||||
chart('warehouse', 'Lagerauslastung', [50, 30, 20, 80, 60], "%")
|
fetch('./dashboardsummary')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
chart('warehouse', 'Lagerauslastung', data.map(d => d.currentWarehouseCapacity * 100),
|
||||||
|
"%", data.map(g => g.created));
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</section>
|
</section>
|
||||||
@ -148,7 +167,12 @@
|
|||||||
<h2>Lagereffizienz</h2>
|
<h2>Lagereffizienz</h2>
|
||||||
<canvas id="warehouse-ef"></canvas>
|
<canvas id="warehouse-ef"></canvas>
|
||||||
<script>
|
<script>
|
||||||
chart('warehouse-ef', 'Lagereffizienz', [80, 70, 60, 75, 54], "%")
|
fetch('./dashboardsummary')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
chart('warehouse-ef', 'Lagereffizienz', data.map(d => d.todaysWarehouseCapacity * 100),
|
||||||
|
"%", data.map(g => g.created));
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</section>
|
</section>
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
|
||||||
<title>Bearbeiten: Artikel</title>
|
<title>Bearbeiten: Artikel</title>
|
||||||
<script th:src="@{/js/filterTable.js}"></script>
|
<script th:src="@{/js/filterTable.js}"></script>
|
||||||
|
<script th:src="@{/js/editViewUpdateTax.js}"></script>
|
||||||
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
|
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -27,17 +28,17 @@
|
|||||||
<input class=" full-width" type="text" id="title" name="title" required="required" pattern=".+" th:value="${ArticleID.title}"/>
|
<input class=" full-width" type="text" id="title" name="title" required="required" pattern=".+" th:value="${ArticleID.title}"/>
|
||||||
</p>
|
</p>
|
||||||
<p class="s">
|
<p class="s">
|
||||||
<label for="ref_disabled">Refernzierter Artikel</label>
|
<label for="ref_disabled">Referenzierter Artikel</label>
|
||||||
<input class="" type="text" id="ref_disabled" th:value="${ArticleID.offer_id}" disabled/>
|
<input class="" type="text" id="ref_disabled" th:value="${ArticleID.offerID}" disabled/>
|
||||||
|
|
||||||
<input type="hidden" id="ref_hidden" th:value="${ArticleID.offer_id}" name="ref-article" />
|
<input type="hidden" id="ref_hidden" th:value="${ArticleID.offerID}" name="ref-article" />
|
||||||
|
|
||||||
<a th:href="${'/intern/supplierOffers/#q=' + ArticleID.id}">Details</a>
|
<a th:href="${'/intern/supplierOffers/#q=' + ArticleID.id}">Details</a>
|
||||||
</p>
|
</p>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<div class="m">
|
<div class="m">
|
||||||
<p>
|
<p>
|
||||||
<label for="img">Bild Hochladen</label>
|
<label for="img">Bild hochladen</label>
|
||||||
<input class="full-width" type="file" id="img" name="img"/>
|
<input class="full-width" type="file" id="img" name="img"/>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@ -47,10 +48,13 @@
|
|||||||
<div class="s">
|
<div class="s">
|
||||||
<p>
|
<p>
|
||||||
<label for="price">Preis (Netto)</label>
|
<label for="price">Preis (Netto)</label>
|
||||||
<input class="" type="number" id="price" step="0.01" name="price_netto" required th:value="${ArticleID.price_netto}"/> EUR <br/>
|
<input class="" type="number" id="price" step="0.01" name="priceNet" required
|
||||||
(19% Mwst.)
|
th:value="${ArticleID.priceNet}"/> EUR <br/>
|
||||||
|
(<span th:text="${ArticleID.vatPercent}"></span>% Mwst.)
|
||||||
|
<input type="hidden" id="vatPercent" name="vatPercent" th:value="${ArticleID.vatPercent}"/>
|
||||||
|
|
||||||
<!-- Info von article ref--> <br/>
|
<!-- Info von article ref--> <br/>
|
||||||
= <span th:text="${ArticleID.price}"></span> EUR Brutto
|
= <span id="priceGross" th:text="${ArticleID.price}"></span> EUR Brutto
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label for="reorderMaxPrice">Maximaler Einkaufspreis (Netto)</label>
|
<label for="reorderMaxPrice">Maximaler Einkaufspreis (Netto)</label>
|
||||||
@ -84,7 +88,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Der Wert wird nur für zukünftige Lagerbuchungen verwendet.
|
Der Wert wird nur für zukünftige Lagerbuchungen verwendet.
|
||||||
Bei Problemen kann können Einheiten aus- und wieder eingebucht werden.
|
Bei Problemen können Einheiten aus- und wieder eingebucht werden.
|
||||||
<!-- TODO: set link g-->
|
<!-- TODO: set link g-->
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
|
@ -50,10 +50,10 @@
|
|||||||
<td><img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}" class="s"/></td>
|
<td><img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}" class="s"/></td>
|
||||||
<td><span th:text="${article.title}"></span></td>
|
<td><span th:text="${article.title}"></span></td>
|
||||||
<td><span th:text="${article.price}"></span> €</td>
|
<td><span th:text="${article.price}"></span> €</td>
|
||||||
<td><span th:text="${article.price_netto}"></span> €</td>
|
<td><span th:text="${article.priceNet}"></span> €</td>
|
||||||
<td><span th:text="${article.categorie}"></span></td>
|
<td><span th:text="${article.categorie}"></span></td>
|
||||||
<td><span th:text="${article.stock}"></span></td>
|
<td><span th:text="${article.stock}"></span></td>
|
||||||
<td><a th:href="${'/intern/supplierOffers/#q=' + article.title}" th:text="${article.offer_id}"></a></td>
|
<td><a th:href="${'/intern/supplierOffers/#q=' + article.title}" th:text="${article.offerID}"></a></td>
|
||||||
<td><a th:href="@{/intern/articles/{id}(id = ${article.id})}" th:text="${article.id}"></a></td>
|
<td><a th:href="@{/intern/articles/{id}(id = ${article.id})}" th:text="${article.id}"></a></td>
|
||||||
<td>
|
<td>
|
||||||
<form th:action="@{/intern/articles/{id}(id = ${article.id})}"><input class="button smaller" type="submit" value="Bearbeiten" /></form>
|
<form th:action="@{/intern/articles/{id}(id = ${article.id})}"><input class="button smaller" type="submit" value="Bearbeiten" /></form>
|
||||||
|
@ -43,8 +43,9 @@
|
|||||||
<tr th:each="article : ${OfferedArticles}">
|
<tr th:each="article : ${OfferedArticles}">
|
||||||
<td><span th:text="${article.title}"></span></td>
|
<td><span th:text="${article.title}"></span></td>
|
||||||
<td><span th:text="${article.manufacturer}"></span></td>
|
<td><span th:text="${article.manufacturer}"></span></td>
|
||||||
<td><span th:text="${article.articlenumber}"></span></td>
|
<td><span th:text="${article.articleNumber}"></span></td>
|
||||||
<td><a th:href="${'/intern/suppliers/#q=' + article.supplierName}" th:text="${article.supplierName}"></a></td>
|
<td th:if="${article.supplierName} == '-'">-</td>
|
||||||
|
<td th:unless="${article.supplierName} == '-'"><a th:href="${'/intern/suppliers/#q=' + article.supplierName}" th:text="${article.supplierName}"></a></td>
|
||||||
<td><span th:text="${article.price}"></span> €</td>
|
<td><span th:text="${article.price}"></span> €</td>
|
||||||
<td><span th:text="${article.ads}"></span></td>
|
<td><span th:text="${article.ads}"></span></td>
|
||||||
<td>
|
<td>
|
||||||
@ -53,7 +54,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- ELSE -->
|
<!-- ELSE -->
|
||||||
<div th:unless="${article.offerIsListed}">
|
<div th:unless="${article.offerIsListed}">
|
||||||
<form class="detailgrid" action="#" th:action="@{/intern/articles/addArticle/{id}(id = ${article.offer_id})}" method="POST">
|
<form class="detailgrid" action="#" th:action="@{/intern/articles/addArticle/{id}(id = ${article.offerId})}" method="POST">
|
||||||
<input class="button smaller" type="submit" value="Hinzufügen" />
|
<input class="button smaller" type="submit" value="Hinzufügen" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,28 +1,24 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
|
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
|
||||||
|
|
||||||
<title>Lieferanten Bestellungen</title>
|
<title>Lieferanten Bestellungen</title>
|
||||||
<script th:src="@{/js/filterTable.js}"></script>
|
<script th:src="@{/js/filterTable.js}"></script>
|
||||||
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
|
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
|
||||||
</head>
|
</head>
|
||||||
|
<body>
|
||||||
<body>
|
<nav th:replace="fragments/header :: header">Header</nav>
|
||||||
<nav th:replace="fragments/header :: header">Header</nav>
|
<div class="sidebar-layout content-width">
|
||||||
<div class="sidebar-layout content-width">
|
|
||||||
<nav></nav>
|
<nav></nav>
|
||||||
<div>
|
<div>
|
||||||
<h1>Lieferanten Bestellungen</h1>
|
<h1>Lieferanten Bestellungen</h1>
|
||||||
|
|
||||||
<script th:src="@{/js/back.js}"></script>
|
<script th:src="@{/js/back.js}"></script>
|
||||||
<div class="back" data-group="intern" data-name="Zurück zu den Bestellungen bei Lieferanten."
|
<div class="back" data-group="intern" data-name="Zurück zu den Bestellungen bei Lieferanten."
|
||||||
data-insert="false"></div>
|
data-insert="false"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<main class="sidebar-layout content-width">
|
<main class="sidebar-layout content-width">
|
||||||
<nav th:replace="fragments/intern :: sidebar"></nav>
|
<nav th:replace="fragments/intern :: sidebar"></nav>
|
||||||
<div class="content-width">
|
<div class="content-width">
|
||||||
<p>
|
<p>
|
||||||
@ -30,9 +26,10 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th colspan="9">
|
<th colspan="9">
|
||||||
<input type="text" placeholder="Filtern" class="smaller jsFilterTable full-width"
|
<input type="text" placeholder="Filtern" class="smaller jsFilterTable full-width"
|
||||||
data-target-id="main-table"></input>
|
data-target-id="main-table">
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Bestellnummer</th>
|
<th>Bestellnummer</th>
|
||||||
<th>Datum</th>
|
<th>Datum</th>
|
||||||
@ -43,61 +40,39 @@
|
|||||||
<th>Gesamtpreis (Netto)</th>
|
<th>Gesamtpreis (Netto)</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>4545</td>
|
<tr th:each="order : ${orders}">
|
||||||
<td>2019-18-10</td>
|
<td><span th:text="${order.id}"></span></td>
|
||||||
<td><a th:href="@{/intern/suppliers/45015}">Cheap AG</a></td>
|
<td><span th:text="${order.dateOrder}"></span></td>
|
||||||
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
|
<td><span th:text="${order.supplierName}"></span></td>
|
||||||
<td>20,00 EUR</td>
|
<td><a th:href="@{/intern/articles/{id}(id = ${order.articleId})}" class="smaller"
|
||||||
<td>10</td>
|
th:text="${order.articleName}"></a></td>
|
||||||
<td>200,00 EUR</td>
|
<td><span th:text="${order.priceNet}"></span> €</td>
|
||||||
<td>Unterwegs <br/><a th:href="@{/intern/warehouse/todo}" class="button smaller">Angekommen</a></td>
|
<td><span th:text="${order.quantity}"></span></td>
|
||||||
</tr>
|
<td><span th:text="${order.priceTotal}"></span> €</td>
|
||||||
<tr>
|
<td>
|
||||||
<td>2455</td>
|
<div th:if="${order.arrived}">
|
||||||
<td>2019-18-10</td>
|
Angekommen
|
||||||
<td><a th:href="@{/intern/suppliers/45015}">Cheap AG</a></td>
|
</div>
|
||||||
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
|
<!-- ELSE -->
|
||||||
<td>20,00 EUR</td>
|
<div th:unless="${order.arrived}">
|
||||||
<td>11</td>
|
Unterwegs: <span th:text="${order.carrier}"></span>, <span
|
||||||
<td>220,00 EUR</td>
|
th:text="${order.trackingId}"></span><br/>
|
||||||
<td>Unterwegs <br/><a th:href="@{/intern/warehouse/todo}" class="button smaller">Angekommen</a></td>
|
<form class="detailgrid" action="#"
|
||||||
</tr>
|
th:action="@{/intern/supplierOrders/store/{id}(id = ${order.id})}" method="POST">
|
||||||
<tr>
|
<input class="button smaller" type="submit" value="Eingang verbuchen"/>
|
||||||
<td>1224</td>
|
</form>
|
||||||
<td>2019-18-10</td>
|
Geschätzte Ankunft: <span th:text="${order.estimatedArrival}"></span>.
|
||||||
<td><a th:href="@{/intern/suppliers/45015}">Cheap AG</a></td>
|
</div>
|
||||||
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
|
</td>
|
||||||
<td>20,00 EUR</td>
|
|
||||||
<td>11</td>
|
|
||||||
<td>220,00 EUR</td>
|
|
||||||
<td>Angekommen</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>4520</td>
|
|
||||||
<td>2019-18-10</td>
|
|
||||||
<td><a th:href="@{/intern/suppliers/45015}">Cheap AG</a></td>
|
|
||||||
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
|
|
||||||
<td>20,00 EUR</td>
|
|
||||||
<td>11</td>
|
|
||||||
<td>220,00 EUR</td>
|
|
||||||
<td>Angekommen</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>4521</td>
|
|
||||||
<td>2019-18-10</td>
|
|
||||||
<td><a th:href="@{/intern/suppliers/45015}">Cheap AG</a></td>
|
|
||||||
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
|
|
||||||
<td>20,00 EUR</td>
|
|
||||||
<td>11</td>
|
|
||||||
<td>220,00 EUR</td>
|
|
||||||
<td>Angekommen</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<footer th:replace="fragments/footer :: footer"></footer>
|
<footer th:replace="fragments/footer :: footer"></footer>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -1,38 +1,35 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
|
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
|
||||||
|
|
||||||
<title>Lieferanten Details</title>
|
<title>Lieferanten Details</title>
|
||||||
<script th:src="@{/js/filterTable.js}"></script>
|
<script th:src="@{/js/filterTable.js}"></script>
|
||||||
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
|
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
|
||||||
</head>
|
</head>
|
||||||
|
<body>
|
||||||
<body>
|
<nav th:replace="fragments/header :: header">Header</nav>
|
||||||
<nav th:replace="fragments/header :: header">Header</nav>
|
<div class="sidebar-layout content-width">
|
||||||
<div class="sidebar-layout content-width">
|
|
||||||
<nav></nav>
|
<nav></nav>
|
||||||
<div>
|
<div>
|
||||||
<h1>Lierfant Cheap AG</h1>
|
<h1>Lieferant <span th:text="${SupplierDetail.name}"></span></h1>
|
||||||
|
|
||||||
<script th:src="@{/js/back.js}"></script>
|
<script th:src="@{/js/back.js}"></script>
|
||||||
<div class="back" data-group="intern" data-insert="true"></div>
|
<div class="back" data-group="intern" data-insert="true"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<main class="sidebar-layout content-width">
|
<main class="sidebar-layout content-width">
|
||||||
<nav th:replace="fragments/intern :: sidebar"></nav>
|
<nav th:replace="fragments/intern :: sidebar"></nav>
|
||||||
<div class="content-width">
|
<div class="content-width">
|
||||||
<h2>Bestellungen</h2>
|
<h2>Bestellungen</h2>
|
||||||
<p>
|
<p>
|
||||||
<table id="main-table">
|
<table id="order-table">
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="9">
|
<th colspan="9">
|
||||||
<input type="text" placeholder="Filtern" class="smaller jsFilterTable full-width"
|
<input type="text" placeholder="Filtern" class="smaller jsFilterTable full-width"
|
||||||
data-target-id="main-table"></input>
|
data-target-id="main-table">
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Bestellnummer</th>
|
<th>Bestellnummer</th>
|
||||||
<th>Datum</th>
|
<th>Datum</th>
|
||||||
@ -42,24 +39,39 @@
|
|||||||
<th>Gesamtpreis (Netto)</th>
|
<th>Gesamtpreis (Netto)</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
</thead>
|
||||||
<td>4545</td>
|
<tbody>
|
||||||
<td>2019-18-10</td>
|
<tr th:each="order : ${SupplierDetail.orders}">
|
||||||
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
|
<td><span th:text="${order.id}"></span></td>
|
||||||
<td>20,00 EUR</td>
|
<td><span th:text="${order.dateOrder}"></span></td>
|
||||||
<td>10</td>
|
<td><a th:href="@{/intern/articles/{id}(id = ${order.articleId})}" class="button smaller" th:text="${order.articleName}"></a></td>
|
||||||
<td>200,00 EUR</td>
|
<td><span th:text="${order.priceNet}"></span> €</td>
|
||||||
<td>Unterwegs <br/><a th:href="@{/intern/warehouse/todo}" class="button smaller">Angekommen</a></td>
|
<td><span th:text="${order.quantity}"></span></td>
|
||||||
|
<td><span th:text="${order.priceTotal}"></span> €</td>
|
||||||
|
<td>
|
||||||
|
<div th:if="${order.arrived}">
|
||||||
|
Angekommen
|
||||||
|
</div>
|
||||||
|
<!-- ELSE -->
|
||||||
|
<div th:unless="${order.arrived}">
|
||||||
|
Unterwegs <br>
|
||||||
|
<form class="detailgrid" action="#" th:action="@{/intern/supplierOrders/store/{id}(id = ${order.id})}" method="POST">
|
||||||
|
<input class="button smaller" type="submit" value="Eingang verbuchen" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
<h2>Buchungen</h2>
|
<h2>Buchungen</h2>
|
||||||
<div>
|
<div>
|
||||||
<h4> Kontostand </h4>
|
<h4> Kontostand </h4>
|
||||||
<h3> -100,00 EUR </h3>
|
<h3 th:text="${SupplierDetail.balance}" />
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
<table id="main-table">
|
<table id="booking-table">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Zeitpunkt</th>
|
<th>Zeitpunkt</th>
|
||||||
<th>Betrag</th>
|
<th>Betrag</th>
|
||||||
@ -68,19 +80,27 @@
|
|||||||
<th>Grund</th>
|
<th>Grund</th>
|
||||||
<th>Referenz</th>
|
<th>Referenz</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>10.09.2019 13:45</td>
|
<tr th:each="booking : ${SupplierDetail.bookings}">
|
||||||
<td>100,00 EUR</td>
|
<td th:text="${booking.datetime}" />
|
||||||
<td><a th:href="@{/intern/accounting/main}">Hauptkonto</a></td>
|
<td th:text="${booking.amount}" />
|
||||||
<td>-100,00 EUR</td>
|
|
||||||
<td>Lieferanten-Bestellung</td>
|
<td th:if="${booking.sourceAddr}"><a th:href="@{${booking.sourceAddr}}" th:text="${booking.source}" /></td>
|
||||||
<td><a th:href="@{/intern/supplierOrders/#q=4520}">2504</a></td>
|
<td th:unless="${booking.sourceAddr}" th:text="${booking.source}" />
|
||||||
|
|
||||||
|
<td th:text="${booking.balance}" />
|
||||||
|
|
||||||
|
<td th:text="${booking.reason}" />
|
||||||
|
<td th:if="${booking.referenceAddr}"><a th:href="@{${booking.referenceAddr}}" th:text="${booking.reference}" /></td>
|
||||||
|
<td th:unless="${booking.referenceAddr}" th:text="${booking.reference}" />
|
||||||
</tr>
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<footer th:replace="fragments/footer :: footer"></footer>
|
<footer th:replace="fragments/footer :: footer"></footer>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user