392 lines
14 KiB
Java
392 lines
14 KiB
Java
package storagesim;
|
|
|
|
import java.time.LocalDate;
|
|
import java.time.temporal.IsoFields;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.Random;
|
|
import java.util.stream.Collectors;
|
|
|
|
import lib.OpenSimplexNoise;
|
|
import lib.SQLConnection;
|
|
|
|
/**
|
|
* Runs a loop with a strict interval to simulate time passing
|
|
*
|
|
* @author Manuel
|
|
*/
|
|
|
|
public class Simulation {
|
|
|
|
boolean running;
|
|
|
|
public LocalDate currentTime;
|
|
|
|
OpenSimplexNoise noise;
|
|
|
|
final float STEPS_PER_SECOND = 1 / 30f;
|
|
final int MAX_STEPS = 1;
|
|
final int TOLERANCE = 200;
|
|
|
|
public Simulation() {
|
|
this.running = false;
|
|
|
|
this.currentTime = LocalDate.now();
|
|
//this.currentTime = LocalDate.parse("2020-02-06");
|
|
|
|
this.noise = new OpenSimplexNoise();
|
|
}
|
|
|
|
/**
|
|
* Starts and contains the loop
|
|
*
|
|
* @author Manuel
|
|
*/
|
|
public void run(LocalDate time) {
|
|
// initialise timing values
|
|
double interval = 1000f / (STEPS_PER_SECOND);
|
|
double previousMillis = System.currentTimeMillis() - interval;
|
|
|
|
this.currentTime = time;
|
|
|
|
do {
|
|
// update current time
|
|
double currentMillis = System.currentTimeMillis();
|
|
double deltaMillis = currentMillis - previousMillis;
|
|
|
|
// run code if enough time has passed
|
|
int steps = 0;
|
|
while (deltaMillis >= interval && steps < MAX_STEPS) {
|
|
// --------------------
|
|
// this is the code that is executed in the specified interval
|
|
SQLConnection db = new SQLConnection();
|
|
System.out.println("Date: " + this.currentTime.toString());
|
|
simulateSales(db);
|
|
sellItems(db);
|
|
disposeItems(db);
|
|
receiveOrders(db);
|
|
sortStorage(db);
|
|
checkStorage(db);
|
|
sortStatistics(db);
|
|
db.close();
|
|
this.currentTime.plusDays(1);
|
|
// this.running = false;
|
|
// --------------------
|
|
steps++;
|
|
deltaMillis -= interval;
|
|
}
|
|
if (steps > 0) {
|
|
// only change time if any code was executed
|
|
previousMillis = currentMillis;
|
|
}
|
|
} while (this.running);
|
|
}
|
|
|
|
/**
|
|
* Removes all Items sold in the last time frame
|
|
*
|
|
* @author Johann
|
|
*/
|
|
public void sellItems(SQLConnection db) {
|
|
// Liste der verkauften waren wird erstellt
|
|
ArrayList<HashMap<String, String>> Verkauft = db.queryToMap(
|
|
"SELECT * FROM t_statistik WHERE `Woche` = " + this.currentTime.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
|
|
int MengePalette; // Zwischenspeicher für die Menge der Items auf einer Palette
|
|
|
|
for (HashMap<String, String> Artikel : Verkauft) {
|
|
int VerkaufteID = Integer.parseInt(Artikel.get("f_Artikel_ID")); // ID des momentan Bearbeiteten Produktes
|
|
|
|
// Alle Paletten werden zwischengespeichert
|
|
ArrayList<HashMap<String, String>> Paletten = db.queryToMap("SELECT * FROM t_mindesthaltbarkeit WHERE `f_ProduktID` = " + VerkaufteID + " ORDER BY Menge");
|
|
|
|
int Zähler = 0; // in einer späteren for() schleife wird ein weiterer Zähler benötigt
|
|
|
|
for (int VerkaufteMenge = Integer.parseInt(Artikel.get("Menge")); VerkaufteMenge > 0; Zähler++) {
|
|
if (Paletten.size() > Zähler) {
|
|
// Der Rest auf einer Palette an Items
|
|
MengePalette = Integer.parseInt(Paletten.get(Zähler).get("Menge"));
|
|
|
|
if (VerkaufteMenge <= MengePalette) // Wenn mehr auf der einen Palette ist als verkauft wurde
|
|
{
|
|
MengePalette -= VerkaufteMenge;
|
|
VerkaufteMenge = 0; // Alles wurde entfernt und die Palette wurde neu beschrieben
|
|
} else // Wenn mehr verkauft wurde als auf der einen Palette war
|
|
{
|
|
VerkaufteMenge -= MengePalette;
|
|
// Die Palette wird gelert, und die Variable neu beschrieben, es wird die
|
|
// nächste Palette zu rate gezogen
|
|
MengePalette = 0;
|
|
}
|
|
db.execute("UPDATE t_mindesthaltbarkeit SET `Menge` = " + MengePalette
|
|
+ " WHERE t_mindesthaltbarkeit.`ID` = " + Paletten.get(Zähler).get("ID"));
|
|
db.execute("UPDATE t_lager SET `Menge` = " + MengePalette
|
|
+ " WHERE t_lager.`Paletten_ID` = " + Paletten.get(Zähler).get("ID"));
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Disposes of all items that have expired
|
|
*
|
|
* @author Johann
|
|
*/
|
|
public void disposeItems(SQLConnection db) {
|
|
ArrayList<HashMap<String, String>> Waren = db.queryToMap("SELECT t_mindesthaltbarkeit.ID, t_mindesthaltbarkeit.Haltbarkeit, t_mindesthaltbarkeit.Menge, t_artikel.Name FROM t_mindesthaltbarkeit INNER JOIN t_artikel ON t_mindesthaltbarkeit.f_ProduktID = t_artikel.ID");
|
|
// Waren liste wird erstellt
|
|
|
|
// Nach Produkten die verworfen werden müssen suchen
|
|
|
|
for (HashMap<String, String> Ware : Waren) {
|
|
LocalDate Datum2 = LocalDate.parse(Ware.get("Haltbarkeit")); // Das DAtum des wahrscheinlich nichtmehr
|
|
// Haltbaren abfragen
|
|
|
|
// Compare
|
|
if (this.currentTime.isAfter(Datum2)) // Abfagen ob das Item abgelaufen ist
|
|
{
|
|
int ID = Integer.parseInt(Ware.get("ID")); // Speichern welches Produkt abgelaufen ist
|
|
|
|
System.out.printf("Eine Pallette mit %s %s ist abgelaufen.\n", Ware.get("Menge"), Ware.get("Name"));
|
|
|
|
db.execute("UPDATE t_mindesthaltbarkeit SET `Menge` = '0' WHERE t_mindesthaltbarkeit.`ID` = "
|
|
+ ID); // produkt verwerfen
|
|
db.execute("UPDATE t_lager SET `Menge` = '0' WHERE t_lager.`Paletten_ID` = "
|
|
+ ID);
|
|
}
|
|
}
|
|
|
|
// Leere Paletten wegwerfen
|
|
|
|
Waren = db.queryToMap("SELECT * FROM t_mindesthaltbarkeit"); // Liste mit allen Palette wird aufgerufen
|
|
|
|
for (HashMap<String, String> Ware : Waren) {
|
|
if (Integer.parseInt(Ware.get("Menge")) == 0) // Wenn eine Palette leer ist
|
|
{
|
|
db.execute("DELETE FROM t_mindesthaltbarkeit WHERE t_mindesthaltbarkeit.`ID` = " + Ware.get("ID")); // Palette
|
|
// wir
|
|
// geleert
|
|
}
|
|
}
|
|
|
|
// Leere Paletten in der Haupttabelle werden verworfen
|
|
|
|
Waren = db.queryToMap("SELECT * FROM t_lager"); // Liste der Waren in der Haupttabelle wird erstellt
|
|
|
|
for (HashMap<String, String> Ware : Waren) {
|
|
if (Integer.parseInt(Ware.get("Menge")) == 0) // Leere Paletten werden gesucht
|
|
{
|
|
// leere Palette wird gelöscht
|
|
db.execute("DELETE FROM t_lager WHERE t_lager.`Lagerplatz` = " + Ware.get("Lagerplatz"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Receive orders and puts them into storage
|
|
*
|
|
* @author Johann, Manuel
|
|
*/
|
|
public void receiveOrders(SQLConnection db) {
|
|
ArrayList<HashMap<String, String>> Angekommen = db.queryToMap(
|
|
"SELECT t_bestellungen.ID, f_Artikel_ID, Einkaufspreis, Ankunftsdatum, Menge, Marke, Name FROM t_bestellungen " +
|
|
"INNER JOIN t_artikel ON t_bestellungen.f_Artikel_ID = t_artikel.ID " +
|
|
"WHERE Ankunftsdatum <= ('" + this.currentTime.toString() + "')");
|
|
ArrayList<HashMap<String, String>> Artikel = db
|
|
.queryToMap("SELECT ID, `MHK in Tagen`, Anzahl_pro_Palette FROM t_artikel");
|
|
ArrayList<HashMap<String, String>> Haltbarkeit;
|
|
|
|
LocalDate HaltbarBis;
|
|
int MHKinTagen;
|
|
|
|
for (HashMap<String, String> row : Angekommen) {
|
|
int Artikel_ID = Integer.parseInt(row.get("f_Artikel_ID"));
|
|
|
|
MHKinTagen = Integer.parseInt(Artikel.get(Artikel_ID - 1).get("MHK in Tagen"));
|
|
if (MHKinTagen >= 0) {
|
|
HaltbarBis = this.currentTime.plusDays(MHKinTagen);
|
|
} else {
|
|
HaltbarBis = LocalDate.parse("9999-12-31");
|
|
}
|
|
|
|
int PalettenMenge = Integer.parseInt(Artikel.get(Artikel_ID - 1).get("Anzahl_pro_Palette"));
|
|
int BestellMenge = Integer.parseInt(row.get("Menge"));
|
|
|
|
while (BestellMenge > 0) {
|
|
int Menge = BestellMenge > PalettenMenge ? PalettenMenge : BestellMenge;
|
|
BestellMenge -= Menge;
|
|
|
|
db.execute("INSERT INTO t_mindesthaltbarkeit SET f_ProduktID = " + row.get("f_Artikel_ID")
|
|
+ ", Haltbarkeit = ('" + HaltbarBis.toString() + "')" + ", Menge = " + Menge);
|
|
|
|
Haltbarkeit = db.queryToMap("SELECT ID, f_ProduktID, Haltbarkeit, Menge FROM t_mindesthaltbarkeit");
|
|
String palettenID = Haltbarkeit.get(Haltbarkeit.size()-1).get("ID") ;
|
|
int lagerplatz = findStorageSpace(db);
|
|
|
|
db.execute("INSERT INTO t_lager SET Lagerplatz = " + lagerplatz + ", Paletten_ID = " + palettenID + ", f_Artikel_ID = "
|
|
+ row.get("f_Artikel_ID") + ", Ankunft = ('" + row.get("Ankunftsdatum") + "')" + ", Menge = "
|
|
+ Menge);
|
|
}
|
|
|
|
db.execute("DELETE FROM t_bestellungen WHERE ID = " + row.get("ID"));
|
|
}
|
|
|
|
while (Angekommen.size() > 0) {
|
|
BWLHelper.Bestellungen(db, this.currentTime, Angekommen, "Pascal");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Goes through all available storage locations and finds the first empty in
|
|
* line
|
|
*
|
|
* @author Manuel
|
|
*/
|
|
public int findStorageSpace(SQLConnection db) {
|
|
ArrayList<HashMap<String, String>> Lagerplätze = db.queryToMap("SELECT Lagerplatz FROM t_lager");
|
|
ArrayList<Integer> BelegteLagerplätze = new ArrayList<>(
|
|
Lagerplätze.stream().filter((map) -> map.containsKey("Lagerplatz"))
|
|
.map(map -> Integer.parseInt(map.get("Lagerplatz"))).collect(Collectors.toList()));
|
|
BelegteLagerplätze.sort((a, b) -> Integer.compare(a, b));
|
|
int val = 1;
|
|
for (int i = 0; i < BelegteLagerplätze.size(); i++) {
|
|
if (val < BelegteLagerplätze.get(i)) {
|
|
break;
|
|
} else {
|
|
val = BelegteLagerplätze.get(i) + 1;
|
|
}
|
|
}
|
|
return val;
|
|
}
|
|
|
|
/**
|
|
* Sorts storage to group products by type and removes gaps
|
|
*
|
|
* @author Johann
|
|
*/
|
|
public void sortStorage(SQLConnection db) {
|
|
ArrayList<HashMap<String, String>> products = db.queryToMap("SELECT ID FROM t_artikel");
|
|
int Lagerplatz = 1;
|
|
|
|
ArrayList<HashMap<String, String>> Waren = db.queryToMap("SELECT * FROM t_lager");
|
|
ArrayList<HashMap<String, String>> Waren_unverändert = db.queryToMap("SELECT * FROM t_lager");
|
|
String[][] Waren_sortiert = new String[Waren.size()][5];
|
|
|
|
for (HashMap<String, String> product : products) {
|
|
int productID = Integer.parseInt(product.get("ID"));
|
|
|
|
Waren = db.queryToMap("SELECT * FROM t_lager WHERE f_Artikel_ID = " + productID);
|
|
|
|
if (Waren.size() != 0) {
|
|
for (HashMap<String, String> Ware : Waren) {
|
|
Waren_sortiert[Lagerplatz - 1][0] = Integer.toString(Lagerplatz);
|
|
Waren_sortiert[Lagerplatz - 1][1] = Ware.get("Paletten_ID");
|
|
Waren_sortiert[Lagerplatz - 1][2] = Ware.get("f_Artikel_ID");
|
|
Waren_sortiert[Lagerplatz - 1][3] = Ware.get("Ankunft");
|
|
Waren_sortiert[Lagerplatz - 1][4] = Ware.get("Menge");
|
|
Lagerplatz++;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int u = 0; u <= Waren_sortiert.length - 1; u++) {
|
|
db.execute("UPDATE `t_lager` SET `Lagerplatz` = " + Waren_sortiert[u][0] + ", Paletten_ID = " + Waren_sortiert[u][1] + ", `f_Artikel_ID` = "
|
|
+ Waren_sortiert[u][2] + ", `Ankunft` = ('" + Waren_sortiert[u][3] + "')" + ", `Menge` = "
|
|
+ Waren_sortiert[u][4] + " WHERE `t_lager`.`Lagerplatz` = "
|
|
+ Waren_unverändert.get(u).get("Lagerplatz"));
|
|
}
|
|
|
|
System.out.println("Lager wurde sortiert.");
|
|
}
|
|
|
|
/**
|
|
* Check if items have to be restocked and order them accordingly
|
|
*
|
|
* @author Pascal
|
|
*/
|
|
public void checkStorage(SQLConnection db) {
|
|
ArrayList<HashMap<String, String>> produkte = db.queryToMap("SELECT * FROM t_artikel");
|
|
for (HashMap<String, String> produkt : produkte) {
|
|
int produktID = Integer.parseInt(produkt.get("ID"));
|
|
|
|
int sollbestand = Integer.parseInt(produkt.get("Sollbestand"));
|
|
|
|
int ZinsenProzent = 8;
|
|
|
|
if (sollbestand > 0) {
|
|
boolean sicherheitsbestand = produkt.get("Sicherheitsbestand") == "1";
|
|
|
|
BWLHelper.sys2(db, this.currentTime, produktID, 7, sollbestand, ZinsenProzent, sicherheitsbestand);
|
|
} else {
|
|
BWLHelper.sys1(db, this.currentTime, produktID, ZinsenProzent);
|
|
}
|
|
}
|
|
|
|
BWLHelper.lagerStatistik(db, this.currentTime.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
|
|
}
|
|
|
|
/**
|
|
* Summarises sales statistics in extra table
|
|
*
|
|
* @author Johann
|
|
*/
|
|
public void sortStatistics(SQLConnection db) {
|
|
ArrayList<HashMap<String, String>> products = db.queryToMap("SELECT ID FROM t_artikel");
|
|
ArrayList<HashMap<String, String>> Verkaufszahlen;
|
|
int KWoche = currentTime.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
|
|
int Verkauft;
|
|
|
|
db.execute("TRUNCATE t_verkaufszahlen");
|
|
|
|
for(int n = 1; n < KWoche; n++)
|
|
{
|
|
Verkaufszahlen = db.queryToMap("SELECT * FROM `t_statistik` WHERE `Woche` = " + n);
|
|
if(Verkaufszahlen.size() > 0)
|
|
{
|
|
for (HashMap<String, String> product : products) {
|
|
int productID = Integer.parseInt(product.get("ID"));
|
|
|
|
Verkauft = 0;
|
|
|
|
Verkaufszahlen = db.queryToMap("SELECT * FROM `t_statistik` WHERE `f_Artikel_ID` = " + productID + " AND `Woche` = " + n);
|
|
if(Verkaufszahlen.size() > 0)
|
|
{
|
|
for(int u = 0; u < Verkaufszahlen.size(); u++)
|
|
{
|
|
Verkauft += Integer.parseInt(Verkaufszahlen.get(u).get("Menge"));
|
|
}
|
|
db.execute("INSERT INTO `t_verkaufszahlen` (`ID`, `f_Artikel_ID`, `Woche`, `Menge`, `Verkaufspreis`) VALUES (NULL, '" + productID + "', '" + n + "', '" + Verkauft + "', '" + Verkaufszahlen.get(0).get("Verkaufspreis") + "')");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Simulate sales through random noise
|
|
*
|
|
* @author Manuel
|
|
*/
|
|
public void simulateSales(SQLConnection db) {
|
|
ArrayList<HashMap<String, String>> products = db.queryToMap("SELECT ID, Verkaufspreis, Anzahl_pro_Palette FROM t_artikel");
|
|
Random r = new Random();
|
|
|
|
for (HashMap<String, String> product : products) {
|
|
int productID = Integer.parseInt(product.get("ID"));
|
|
int variance = Integer.parseInt(product.get("Anzahl_pro_Palette"));
|
|
|
|
double stepSize = 52f * (r.nextDouble() + 0.00001) * 4;
|
|
double val = (1 + this.noise.eval(productID * 100, this.currentTime.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR) / stepSize)) / 20.0;
|
|
int sales = (int)(val * variance) + 1;
|
|
|
|
//TODO somewhere we should check if we have enough of a product in storage
|
|
|
|
db.execute("INSERT INTO t_statistik SET f_Artikel_ID = " + productID +
|
|
", Woche = " + this.currentTime.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR) +
|
|
", Menge = " + sales +
|
|
", Verkaufspreis = " + product.get("Verkaufspreis"));
|
|
}
|
|
}
|
|
}
|