commit 2d4000f6cd9499627518745a59e4be0d8ce2bcd4 Author: laurimaaninka Date: Wed Apr 8 19:34:00 2026 +0300 Versio 1, ensimmäinen committi! diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0f0ae34 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +.kotlin +.out/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..3b5e717 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,19 @@ + + + + + sqlite.xerial + true + org.sqlite.JDBC + jdbc:sqlite:$PROJECT_DIR$/tietokanta.db + $ProjectFileDir$ + + + sqlite.xerial + true + org.sqlite.JDBC + jdbc:sqlite:C:\Users\TheHy\OneDrive\Kuljetusruokasovellus\tietokanta.db + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/db-forest-config.xml b/.idea/db-forest-config.xml new file mode 100644 index 0000000..c79cc1a --- /dev/null +++ b/.idea/db-forest-config.xml @@ -0,0 +1,10 @@ + + + + . + ---------------------------------------- + 1:0:8c9f99af-23ef-4827-90d5-7f18c4b74bec + 2:0:c8259506-eca1-4fc2-b380-a099ca4c8bb4 + . + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..302bdd7 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..de5c651 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/fi_lpam_Main.xml b/.idea/runConfigurations/fi_lpam_Main.xml new file mode 100644 index 0000000..f3ebabe --- /dev/null +++ b/.idea/runConfigurations/fi_lpam_Main.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 0000000..c0e01ca --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/out/Ruokamanageri v1.jar b/out/Ruokamanageri v1.jar new file mode 100644 index 0000000..4d57f39 Binary files /dev/null and b/out/Ruokamanageri v1.jar differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..260595f --- /dev/null +++ b/pom.xml @@ -0,0 +1,119 @@ + + 4.0.0 + fi.lpam + Ruokamanageri + 1.0 + + UTF-8 + 25 + 25 + + + + org.openjfx + javafx-base + 25.0.2 + compile + + + org.openjfx + javafx-graphics + 25.0.2 + compile + + + org.openjfx + javafx-controls + 25.0.2 + compile + + + org.openjfx + javafx-fxml + 25.0.2 + compile + + + org.openjfx + javafx-swing + 25.0.2 + compile + + + com.dlsc.gemsfx + gemsfx + 3.10.1 + compile + + + org.apache.pdfbox + pdfbox + 3.0.6 + compile + + + commons-logging + commons-logging + 1.3.5 + + + org.xerial + sqlite-jdbc + 3.51.2.0 + compile + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.0 + + 25 + + + + org.openjfx + javafx-maven-plugin + 0.0.8 + + + + + default-cli + + fi.lpam.Main + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.0 + + + package + + shade + + + true + project-classifier + out\${project.artifactId}.jar + + + fi.lpam.Main + + + + + + + + + diff --git a/src/main/java/fi/lpam/App.java b/src/main/java/fi/lpam/App.java new file mode 100644 index 0000000..47ddc68 --- /dev/null +++ b/src/main/java/fi/lpam/App.java @@ -0,0 +1,61 @@ +package fi.lpam; +import fi.lpam.dataluokat.Tietokanta; +import fi.lpam.gui.Asiakashallinta; +import fi.lpam.gui.Kierroshallinta; +import fi.lpam.gui.KuljetusRaportit; +import fi.lpam.gui.KuljetusListat; +import javafx.application.Application; +import javafx.geometry.Side; +import javafx.scene.Scene; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.image.Image; +import javafx.stage.Stage; + +import java.io.IOException; +import java.util.Objects; + +@SuppressWarnings("InstantiationOfUtilityClass") +public class App extends Application { + static void main() { + launch(); + } + + @Override + public void start(Stage primaryStage) throws IOException { + new Tietokanta(Main.dev); + TabPane root = new TabPane(); + root.setSide(Side.LEFT); + root.setTabMinWidth(50); + root.setTabMinHeight(35); + root.setTabMaxHeight(50); + + Tab asiakasHallinta, kierrostenHallinta, kuljetusListat, kuljetetut; + asiakasHallinta = new Tab("Asiakashallinta", new Asiakashallinta()); + kierrostenHallinta = new Tab("Kierrostenhallinta"); + kuljetusListat = new Tab("Kuljetuslistat"); + kuljetetut = new Tab("Kuljetetut"); + root.getTabs().addAll(asiakasHallinta, kierrostenHallinta, kuljetusListat, kuljetetut); + + root.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { + switch (newValue.getText()) { + case "Asiakashallinta": newValue.setContent(new Asiakashallinta()); break; + case "Kierrostenhallinta": newValue.setContent(new Kierroshallinta()); break; + case "Kuljetuslistat": newValue.setContent(new KuljetusListat()); break; + case "Kuljetetut": newValue.setContent(new KuljetusRaportit()); break; + } + }); + + for (Tab tab : root.getTabs()) { + tab.setClosable(false); + tab.setStyle("-fx-font-size: 18px; -fx-font-weight: bold; -fx-font-family: Open Sans"); + } + + Scene scene = new Scene(root); + primaryStage.setScene(scene); + primaryStage.setTitle("Ruokamanageri"); + primaryStage.setMaximized(true); + primaryStage.show(); + primaryStage.getIcons().add(new Image(Objects.requireNonNull(Main.class.getResourceAsStream("kuljetusruokalaatikko.jpg")))); + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/Main.java b/src/main/java/fi/lpam/Main.java new file mode 100644 index 0000000..efd7e06 --- /dev/null +++ b/src/main/java/fi/lpam/Main.java @@ -0,0 +1,15 @@ +package fi.lpam; + +public class Main { + public static boolean dev; + + static void main(String[] args) { + //noinspection RedundantIfStatement + if (args.length > 0) { + dev = true; + } else { + dev = false; + } + App.main(); + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/dataluokat/Asiakas.java b/src/main/java/fi/lpam/dataluokat/Asiakas.java new file mode 100644 index 0000000..c9af881 --- /dev/null +++ b/src/main/java/fi/lpam/dataluokat/Asiakas.java @@ -0,0 +1,391 @@ +package fi.lpam.dataluokat; + +import fi.lpam.gui.virheDialogit.SiirtoVirhe; + +import java.sql.*; +import java.util.ArrayList; + +@SuppressWarnings("DuplicatedCode") +public class Asiakas implements TietokantaOlio { + private int id = -1; + private String nimi; + private String osoite; + private int maanantaiKpl, tiistaiKpl, keskiviikkoKpl, torstaiKpl, perjantaiKpl; + private int salaatit, pääruoat, jälkiruoat; + private String erityisruokavalio; + private String avainTieto; + private String lisätiedot; + + /** + * Tyhjä konstruktori uusien luomista varten + */ + public Asiakas() { + } + + /** + * Vain MultiColumnListViewin käyttöön + * @param nimi Asiakkaan nimi + */ + public Asiakas(String nimi) { + this.nimi = nimi; + } + + /** + * Kun luetaan asiakas tietokannasta + * @param id asiakkaan id + * @param nimi asiakkaan nimi + * @param osoite osoite + * @param maanantaiKpl kuljetettava määrä + * @param tiistaiKpl kuljetettava määrä + * @param keskiviikkoKpl kuljetettava määrä + * @param torstaiKpl kuljetettava määrä + * @param perjantaiKpl kuljetettava määrä + * @param salaatit kuljetettava määrä + * @param pääruoat kuljetettava määrä + * @param jälkiruoat kuljetettava määrä + * @param erityisruokavalio ... + * @param avainTieto ... + * @param lisätiedot mahdolliset lisätilaukset/tiedot + */ + private Asiakas(int id, String nimi, String osoite, int maanantaiKpl, int tiistaiKpl, int keskiviikkoKpl, int torstaiKpl, int perjantaiKpl, int salaatit, int pääruoat, int jälkiruoat, String erityisruokavalio, String avainTieto, String lisätiedot) { + this.id = id; + this.nimi = nimi; + this.osoite = osoite; + this.maanantaiKpl = maanantaiKpl; + this.tiistaiKpl = tiistaiKpl; + this.keskiviikkoKpl = keskiviikkoKpl; + this.torstaiKpl = torstaiKpl; + this.perjantaiKpl = perjantaiKpl; + this.salaatit = salaatit; + this.pääruoat = pääruoat; + this.jälkiruoat = jälkiruoat; + this.erityisruokavalio = erityisruokavalio; + this.avainTieto = avainTieto; + this.lisätiedot = lisätiedot; + } + + /** + * @param nimi asiakkaan nimi + * @param osoite osoite + * @param maanantaiKpl kuljetettava määrä + * @param tiistaiKpl kuljetettava määrä + * @param keskiviikkoKpl kuljetettava määrä + * @param torstaiKpl kuljetettava määrä + * @param perjantaiKpl kuljetettava määrä + * @param salaatit kuljetettava määrä + * @param pääruoat kuljetettava määrä + * @param jälkiruoat kuljetettava määrä + * @param erityisruokavalio ... + * @param avainTieto ... + * @param lisätiedot mahdolliset lisätilaukset/tiedot + */ + public Asiakas(String nimi, String osoite, int maanantaiKpl, int tiistaiKpl, int keskiviikkoKpl, int torstaiKpl, int perjantaiKpl, int salaatit, int pääruoat, int jälkiruoat, String erityisruokavalio, String avainTieto, String lisätiedot) { + this.nimi = nimi; + this.osoite = osoite; + this.maanantaiKpl = maanantaiKpl; + this.tiistaiKpl = tiistaiKpl; + this.keskiviikkoKpl = keskiviikkoKpl; + this.torstaiKpl = torstaiKpl; + this.perjantaiKpl = perjantaiKpl; + this.salaatit = salaatit; + this.pääruoat = pääruoat; + this.jälkiruoat = jälkiruoat; + this.erityisruokavalio = erityisruokavalio; + this.avainTieto = avainTieto; + this.lisätiedot = lisätiedot; + } + + /** + * Hakee kaikki asiakkaat tietokannan asiakkaat taulusta + * @return ArrayList + */ + public static ArrayList haeKaikki() { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + Statement stmt = tietokanta.createStatement(); + ResultSet rs = stmt.executeQuery("select * from asiakkaat"); + return parsiResultSet(rs); + } catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return null; + } + } + + /** + * Hakee tietokannasta asiakasidn perusteella asiakkaat + * @param IDt haettavat asiakkkaat + * @return Haetut asiakkaat tai null + */ + public static ArrayList haeTietyt(int[] IDt) { + StringBuilder sbIDt = new StringBuilder(); + sbIDt.append(IDt[0]); + for (int i = 1; i < IDt.length; i++) { + sbIDt.append(", ").append(IDt[i]); + } + try (Connection tietokanta = Tietokanta.haeYhteys()) { + String sql = "select * from asiakkaat where id in (" + sbIDt + ") order by instr('" + sbIDt + "', id)"; + Statement stmt = tietokanta.createStatement(); + ResultSet rs = stmt.executeQuery(sql); + return parsiResultSet(rs); + } + catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return null; + } + } + + /** + * Käsittelee ResultSettiä + * @param rs saatu ResultSet + * @return ArrayList + */ + private static ArrayList parsiResultSet(ResultSet rs) { + ArrayList asiakkaat = new ArrayList<>(); + + try { + while (rs.next()) { + Asiakas uusi = new Asiakas( + rs.getInt("id"), + rs.getString("nimi"), + rs.getString("osoite"), + rs.getInt("maanantaiKpl"), + rs.getInt("tiistaiKpl"), + rs.getInt("keskiviikkoKpl"), + rs.getInt("torstaiKpl"), + rs.getInt("perjantaiKpl"), + rs.getInt("salaatit"), + rs.getInt("pääruoat"), + rs.getInt("jälkiruoat"), + rs.getString("erityisruokavalio"), + rs.getString("avainTieto"), + rs.getString("lisätiedot") + ); + asiakkaat.add(uusi); + } + } + catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + } + return asiakkaat; + } + + /** + * Tallentaa uuden asiakkaan tietokantaan. Tietokanta luo automaattisesti id:n asiakkaalle. + * + */ + @Override + public boolean tallennaUusi() { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("INSERT INTO asiakkaat (nimi, osoite, maanantaiKpl, tiistaiKpl, keskiviikkoKpl, torstaiKpl, perjantaiKpl, salaatit, pääruoat, jälkiruoat, erityisruokavalio, avainTieto, lisätiedot) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); + stmt.setString(1, nimi); + stmt.setString(2, osoite); + stmt.setInt(3, maanantaiKpl); + stmt.setInt(4, tiistaiKpl); + stmt.setInt(5, keskiviikkoKpl); + stmt.setInt(6, torstaiKpl); + stmt.setInt(7, perjantaiKpl); + stmt.setInt(8, salaatit); + stmt.setInt(9, pääruoat); + stmt.setInt(10, jälkiruoat); + stmt.setString(11, erityisruokavalio); + stmt.setString(12, avainTieto); + stmt.setString(13, lisätiedot); + int muokatutRivit = stmt.executeUpdate(); + + if (muokatutRivit == 0) { + throw new SQLException("Käyttäjän luominen epäonnistui, rivejä ei muokattu"); + } + try (ResultSet generatedKeys = stmt.getGeneratedKeys()) { + if (generatedKeys.next()) { + this.setId(generatedKeys.getInt(1)); + } + else { + throw new SQLException("Käyttäjän luominen epäonnistui, id:tä ei saatu"); + } + } + } catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return false; + } + return true; + } + + /** + * Päivittää kutsuvan asiakkaan tiedot tietokantaan + */ + @Override + public boolean päivitäTietokantaan() { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("UPDATE asiakkaat set nimi = ?, osoite = ?, maanantaiKpl = ?, tiistaiKpl = ?, keskiviikkoKpl = ?, torstaiKpl = ?, perjantaiKpl = ?, salaatit = ?, pääruoat = ?, jälkiruoat = ?, erityisruokavalio = ?, avainTieto = ?, lisätiedot = ? WHERE id = ?"); + stmt.setString(1, nimi); + stmt.setString(2, osoite); + stmt.setInt(3, maanantaiKpl); + stmt.setInt(4, tiistaiKpl); + stmt.setInt(5, keskiviikkoKpl); + stmt.setInt(6, torstaiKpl); + stmt.setInt(7, perjantaiKpl); + stmt.setInt(8, salaatit); + stmt.setInt(9, pääruoat); + stmt.setInt(10, jälkiruoat); + stmt.setString(11, erityisruokavalio); + stmt.setString(12, avainTieto); + stmt.setString(13, lisätiedot); + stmt.setInt(14, id); + stmt.executeUpdate(); + return true; + } catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return false; + } + } + + /** + * Poistaa asiakkaan tietokannasta + */ + @Override + public boolean poista() { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + String sql = "DELETE FROM asiakkaat WHERE id = " + id; + Statement stmt = tietokanta.createStatement(); + stmt.executeUpdate(sql); + return true; + } catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return false; + } + } + + public boolean tallenna() { + if (this.id == -1) { + return this.tallennaUusi(); + } + else { + return this.päivitäTietokantaan(); + } + } + + /** + * Kierroshallintaa varten toString + * @return asiakkaan nimi + */ + public String toString() { + return this.getNimi(); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getNimi() { + return nimi; + } + + public void setNimi(String nimi) { + this.nimi = nimi; + } + + public String getOsoite() { + return osoite; + } + + public void setOsoite(String osoite) { + this.osoite = osoite; + } + + public int getMaanantaiKpl() { + return maanantaiKpl; + } + + public void setMaanantaiKpl(int maanantaiKpl) { + this.maanantaiKpl = maanantaiKpl; + } + + public int getTiistaiKpl() { + return tiistaiKpl; + } + + public void setTiistaiKpl(int tiistaiKpl) { + this.tiistaiKpl = tiistaiKpl; + } + + public int getKeskiviikkoKpl() { + return keskiviikkoKpl; + } + + public void setKeskiviikkoKpl(int keskiviikkoKpl) { + this.keskiviikkoKpl = keskiviikkoKpl; + } + + public int getTorstaiKpl() { + return torstaiKpl; + } + + public void setTorstaiKpl(int torstaiKpl) { + this.torstaiKpl = torstaiKpl; + } + + public int getPerjantaiKpl() { + return perjantaiKpl; + } + + public void setPerjantaiKpl(int perjantaiKpl) { + this.perjantaiKpl = perjantaiKpl; + } + + public int getSalaatit() { + return salaatit; + } + + public void setSalaatit(int salaatit) { + this.salaatit = salaatit; + } + + public int getPääruoat() { + return pääruoat; + } + + public void setPääruoat(int pääruoat) { + this.pääruoat = pääruoat; + } + + public int getJälkiruoat() { + return jälkiruoat; + } + + public void setJälkiruoat(int jälkiruoat) { + this.jälkiruoat = jälkiruoat; + } + + public String getErityisruokavalio() { + return erityisruokavalio; + } + + public void setErityisruokavalio(String erityisruokavalio) { + this.erityisruokavalio = erityisruokavalio; + } + + public String getAvainTieto() { + return avainTieto; + } + + public void setAvainTieto(String avainTieto) { + this.avainTieto = avainTieto; + } + + public String getLisätiedot() { + return lisätiedot; + } + + public void setLisätiedot(String lisätiedot) { + this.lisätiedot = lisätiedot; + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/dataluokat/Kierros.java b/src/main/java/fi/lpam/dataluokat/Kierros.java new file mode 100644 index 0000000..a8a5a65 --- /dev/null +++ b/src/main/java/fi/lpam/dataluokat/Kierros.java @@ -0,0 +1,218 @@ +package fi.lpam.dataluokat; + +import fi.lpam.gui.virheDialogit.SiirtoVirhe; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import java.sql.*; +import java.util.ArrayList; +import java.util.Iterator; + +public class Kierros implements TietokantaOlio { + private int id = -1; + private int kierrosNumero; + private ObservableList asiakkaat; + + public Kierros(int kierrosNumero, ObservableList asiakkaat) { + this.kierrosNumero = kierrosNumero; + this.asiakkaat = asiakkaat; + } + + private Kierros(int id, int kierrosNumero, ObservableList asiakkaat) { + this.id = id; + this.kierrosNumero = kierrosNumero; + this.asiakkaat = asiakkaat; + } + + /** Hakee kaikki kierrokset tietokannasta + * @return kaikki kierrokset + */ + public static ArrayList haeKaikki() { + ArrayList kierrokset = new ArrayList<>(); + try (Connection tietokanta = Tietokanta.haeYhteys()) { + Statement stmt = tietokanta.createStatement(); + ResultSet rs = stmt.executeQuery("select id, kierrosNumero, asiakkaat from kierrokset"); + while (rs.next()) { + kierrokset.add(new Kierros(rs.getInt(1), rs.getInt(2), FXCollections.observableArrayList(muutaMerkkijonoAsiakkaiksi(rs.getString(3))))); + } + } + catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + } + return kierrokset; + } + + /** + * Hakee tietyn kierroksen + * @param kierrosNumero haettavan kierroksen numero + * @return Kierros, null jos ei löydy + */ + public static Kierros haeKierros(int kierrosNumero) { + Kierros kierros; + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("select id, kierrosNumero, asiakkaat from kierrokset where kierrosNumero = ?"); + stmt.setInt(1, kierrosNumero); + ResultSet rs = stmt.executeQuery(); + kierros = new Kierros(rs.getInt(1), rs.getInt(2), FXCollections.observableArrayList(muutaMerkkijonoAsiakkaiksi(rs.getString(3)))); + return kierros; + } + catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + } + return null; + } + + /** + * Haetaan uniikit kierrosnumerot + * @return kierrosten uniikit kierrosnumerot + */ + public static ArrayList haeKierrosNumerot() { + ArrayList numerot = new ArrayList<>(); + try (Connection tietotokanta = Tietokanta.haeYhteys()) { + Statement stmt = tietotokanta.createStatement(); + ResultSet rs = stmt.executeQuery("select distinct kierrosNumero from kierrokset ORDER BY kierrosNumero"); + while (rs.next()) { + numerot.add(rs.getInt("kierrosNumero")); + } + return numerot; + } + catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return numerot; + } + } + + + @Override + public boolean tallennaUusi() { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("insert into kierrokset (kierrosNumero, asiakkaat) values (?, ?)", Statement.RETURN_GENERATED_KEYS); + stmt.setInt(1, kierrosNumero); + stmt.setString(2, muutaAsiakkaatMerkkijonoksi()); + int muokatutRivit = stmt.executeUpdate(); + + if (muokatutRivit == 0) { + throw new SQLException("Kierroksen luominen epäonnistui, rivejä ei muokattu"); + } + + ResultSet luodutIDt = stmt.getGeneratedKeys(); + if (luodutIDt.next()) { + this.id = luodutIDt.getInt(1); + } else { + throw new SQLException("Kierroksen luominen epäonnistui, idtä ei saatu"); + } + } + + catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return false; + } + return true; + } + + @Override + public boolean päivitäTietokantaan() { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("update kierrokset set asiakkaat = ?, kierrosnumero = ? where id = ?"); + stmt.setString(1, muutaAsiakkaatMerkkijonoksi()); + stmt.setInt(2, kierrosNumero); + stmt.setInt(3, id); + int muokatutRivit = stmt.executeUpdate(); + if (muokatutRivit == 0) { + throw new SQLException("Kierroksen muokkaaminen epäonnistui, rivejä ei muokattu"); + } + } + catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return false; + } + return true; + } + + @Override + public boolean poista() { + if (this.id < 0) return false; + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("delete from kierrokset where id = ?"); + stmt.setInt(1, id); + int muokatutRivit = stmt.executeUpdate(); + if (muokatutRivit == 0) { + throw new SQLException("Kierroksen poisto epäonnistui, rivejä ei muokattu"); + } + } + catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return false; + } + return true; + } + + @Override + public boolean tallenna() { + if (this.id < 0) { + return this.tallennaUusi(); + } + else { + return this.päivitäTietokantaan(); + } + } + + /** + * Muuttaa listan asiakkaista merkkijonoksi + * @return listan asiakkaat muodossa "id id id..." + */ + private String muutaAsiakkaatMerkkijonoksi() { + StringBuilder sb = new StringBuilder(); + if (asiakkaat.isEmpty()) {return sb.toString();} + + Iterator it = asiakkaat.iterator(); + sb.append(it.next().getId()); + while (it.hasNext()) { + sb.append(" ").append(it.next().getId()); + } + return sb.toString(); + } + + private static ArrayList muutaMerkkijonoAsiakkaiksi(String merkkijono) { + String[] strAsiakasIDt = merkkijono.split(" "); + int[] asiakasIDt = new int[strAsiakasIDt.length]; + for (int i = 0; i < strAsiakasIDt.length; i++) { + asiakasIDt[i] = Integer.parseInt(strAsiakasIDt[i]); + } + return Asiakas.haeTietyt(asiakasIDt); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getKierrosNumero() { + return kierrosNumero; + } + + public void setKierrosNumero(int kierrosNumero) { + this.kierrosNumero = kierrosNumero; + } + + public ObservableList getAsiakkaat() { + return asiakkaat; + } + + public void setAsiakkaat(ObservableList asiakkaat) { + this.asiakkaat = asiakkaat; + } + + public String toString() { + return this.kierrosNumero + ": " + this.asiakkaat; + } +} diff --git a/src/main/java/fi/lpam/dataluokat/Kuljetus.java b/src/main/java/fi/lpam/dataluokat/Kuljetus.java new file mode 100644 index 0000000..3d97254 --- /dev/null +++ b/src/main/java/fi/lpam/dataluokat/Kuljetus.java @@ -0,0 +1,366 @@ +package fi.lpam.dataluokat; + +import fi.lpam.gui.virheDialogit.SiirtoVirhe; + +import java.sql.*; +import java.time.LocalDate; +import java.util.ArrayList; + +@SuppressWarnings("DuplicatedCode") +public class Kuljetus implements TietokantaOlio { + private int id = -1; + private int asiakasID; + private String nimi; + private LocalDate kuljetusPäivämäärä; + private int kuljetusKierros; + private int salaatit, pääruoat, jälkiruoat; + private String osoite, lisätieto, avainTieto, ruokarajoite; + + public Kuljetus(Asiakas asiakas, LocalDate pvm, int kuljetusKierros) { + this.asiakasID = asiakas.getId(); + this.nimi = asiakas.getNimi(); + this.kuljetusPäivämäärä = pvm; + this.kuljetusKierros = kuljetusKierros; + int kuljetusKerroin = switch (kuljetusPäivämäärä.getDayOfWeek()) { + case MONDAY -> asiakas.getMaanantaiKpl(); + case TUESDAY -> asiakas.getTiistaiKpl(); + case WEDNESDAY -> asiakas.getKeskiviikkoKpl(); + case THURSDAY -> asiakas.getTorstaiKpl(); + case FRIDAY -> asiakas.getPerjantaiKpl(); + default -> 0; + }; + this.salaatit = kuljetusKerroin * asiakas.getSalaatit(); + this.pääruoat = kuljetusKerroin * asiakas.getPääruoat(); + this.jälkiruoat = kuljetusKerroin * asiakas.getJälkiruoat(); + this.osoite = asiakas.getOsoite(); + this.avainTieto = asiakas.getAvainTieto(); + this.lisätieto = asiakas.getLisätiedot(); + this.ruokarajoite = asiakas.getErityisruokavalio(); + } + + private Kuljetus(int id, int asiakasID, String nimi, LocalDate kuljetusPäivämäärä, int kuljetusKierros, int salaatit, int pääruoat, int jälkiruoat, String osoite, String lisätieto, String avainTieto, String ruokarajoite) { + this.id = id; + this.asiakasID = asiakasID; + this.nimi = nimi; + this.kuljetusPäivämäärä = kuljetusPäivämäärä; + this.kuljetusKierros = kuljetusKierros; + this.salaatit = salaatit; + this.pääruoat = pääruoat; + this.jälkiruoat = jälkiruoat; + this.osoite = osoite; + this.lisätieto = lisätieto; + this.avainTieto = avainTieto; + this.ruokarajoite = ruokarajoite; + } + + public static ArrayList haeKaikki() { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + Statement stmt = tietokanta.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM kuljetukset;"); + return parsiResultSet(rs); + } catch (SQLException e) { + SiirtoVirhe virhe = new SiirtoVirhe(e); + virhe.showAndWait(); + return null; + } + } + + /** + * Hakee yhden päivän kuljetukset riippumatta kierroksesta + * @param päivä haettava päivä + * @return päivän kuljetukset + */ + public static ArrayList haePäivänKuljetukset(LocalDate päivä) { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("SELECT * FROM kuljetukset WHERE kuljetusPäivämäärä = ?;"); + stmt.setDate(1, Date.valueOf(päivä)); + ResultSet rs = stmt.executeQuery(); + return parsiResultSet(rs); + } catch (SQLException e) { + SiirtoVirhe virhe = new SiirtoVirhe(e); + virhe.showAndWait(); + return null; + } + } + + /** + * Hakee tietyn kierroksen kuljetukset + * @param päivä kierroksen päivä + * @param kuljetusKierros kierroksen numero + * @return valitun päivän valitun kierroksen kuljetukset + */ + public static ArrayList haePäivänKuljetuksetKierroksella(LocalDate päivä, int kuljetusKierros) { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("SELECT * FROM kuljetukset WHERE kuljetusKierros = ? and kuljetusPäivämäärä = ?"); + stmt.setInt(1, kuljetusKierros); + stmt.setDate(2, Date.valueOf(päivä)); + ResultSet rs = stmt.executeQuery(); + return parsiResultSet(rs); + } catch (SQLException e) { + SiirtoVirhe virhe = new SiirtoVirhe(e); + virhe.showAndWait(); + return null; + } + } + /** + * Hakee kuljetukset aikajakson perusteella + * + * @param alku jakson alku (sisältyen) + * @param loppu jakson loppu (sisältyen) + * @return Jakson kuljetukset + */ + public static ArrayList haeAikaJakso(LocalDate alku, LocalDate loppu) { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("SELECT * FROM kuljetukset WHERE kuljetusPäivämäärä BETWEEN ? AND ?"); + stmt.setDate(1, Date.valueOf(alku)); + stmt.setDate(2, Date.valueOf(loppu)); + ResultSet rs = stmt.executeQuery(); + return parsiResultSet(rs); + } catch (SQLException e) { + SiirtoVirhe virhe = new SiirtoVirhe(e); + virhe.showAndWait(); + return null; + } + } + + public static ArrayList haeAikaJaksollaJaKierroksella(LocalDate alku, LocalDate loppu, int kuljetusKierros) { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("SELECT * FROM kuljetukset WHERE kuljetusKierros = ? and kuljetusPäivämäärä BETWEEN ? AND ?"); + stmt.setInt(1, kuljetusKierros); + stmt.setDate(2, Date.valueOf(alku)); + stmt.setDate(3, Date.valueOf(loppu)); + ResultSet rs = stmt.executeQuery(); + return parsiResultSet(rs); + } catch (SQLException e) { + SiirtoVirhe virhe = new SiirtoVirhe(e); + virhe.showAndWait(); + return null; + } + } + + @Override + public boolean tallennaUusi() { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("INSERT INTO kuljetukset (asiakasID, nimi, kuljetusPäivämäärä, kuljetusKierros, salaatit, pääruoat, jälkiruoat, ruokarajoite, osoite, avainTieto, lisätieto) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); + stmt.setInt(1, asiakasID); + stmt.setString(2, nimi); + stmt.setDate(3, Date.valueOf(kuljetusPäivämäärä)); + stmt.setInt(4, kuljetusKierros); + stmt.setInt(5, salaatit); + stmt.setInt(6, pääruoat); + stmt.setInt(7, jälkiruoat); + stmt.setString(8, ruokarajoite); + stmt.setString(9, osoite); + stmt.setString(10, avainTieto); + stmt.setString(11, lisätieto); + int muokatutRivit = stmt.executeUpdate(); + + if (muokatutRivit == 0) { + throw new SQLException("Kuljetuksen luominen epäonnistui, rivejä ei muokattu"); + } + try (ResultSet generatedKeys = stmt.getGeneratedKeys()) { + if (generatedKeys.next()) { + this.setId(generatedKeys.getInt(1)); + } else { + throw new SQLException("Kuljetuksen luominen epäonnistui, id:tä ei saatu"); + } + } + } catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return false; + } + return true; + } + + @Override + public boolean päivitäTietokantaan() { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + PreparedStatement stmt = tietokanta.prepareStatement("UPDATE kuljetukset set asiakasID = ?, nimi = ?, kuljetusPäivämäärä = ?, kuljetusKierros = ?, salaatit = ?, pääruoat = ?, jälkiruoat = ?, ruokarajoite = ?, osoite = ?, avainTieto = ?, lisätieto = ? WHERE id = ?"); + stmt.setInt(1, asiakasID); + stmt.setString(2, nimi); + stmt.setDate(3, Date.valueOf(kuljetusPäivämäärä)); + stmt.setInt(4, kuljetusKierros); + stmt.setInt(5, salaatit); + stmt.setInt(6, pääruoat); + stmt.setInt(7, jälkiruoat); + stmt.setString(8, ruokarajoite); + stmt.setString(9, osoite); + stmt.setString(10, avainTieto); + stmt.setString(11, lisätieto); + stmt.setInt(12, id); + stmt.executeUpdate(); + return true; + } catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return false; + } + } + + @Override + public boolean poista() { + try (Connection tietokanta = Tietokanta.haeYhteys()) { + String sql = "DELETE FROM kuljetukset WHERE id = " + id; + Statement stmt = tietokanta.createStatement(); + stmt.executeUpdate(sql); + return true; + } catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + return false; + } + } + + @Override + public boolean tallenna() { + if (this.id == -1) { + return this.tallennaUusi(); + } + else { + return this.päivitäTietokantaan(); + } + } + + private static ArrayList parsiResultSet(ResultSet rs) { + ArrayList kuljetukset = new ArrayList<>(); + + try { + while (rs.next()) { + Kuljetus uusi = new Kuljetus( + rs.getInt("id"), + rs.getInt("asiakasID"), + rs.getString("nimi"), + rs.getDate("kuljetusPäivämäärä").toLocalDate(), + rs.getInt("kuljetusKierros"), + rs.getInt("salaatit"), + rs.getInt("pääruoat"), + rs.getInt("jälkiruoat"), + rs.getString("osoite"), + rs.getString("lisätieto"), + rs.getString("avainTieto"), + rs.getString("ruokarajoite") + ); + kuljetukset.add(uusi); + } + } catch (SQLException e) { + SiirtoVirhe alert = new SiirtoVirhe(e); + alert.showAndWait(); + } + return kuljetukset; + } + + @Override + public String toString() { + return "Kuljetus{" + + "id=" + id + + ", asiakasID=" + asiakasID + + ", nimi='" + nimi + '\'' + + ", kuljetusPäivämäärä=" + kuljetusPäivämäärä + + ", kuljetusKierros=" + kuljetusKierros + + ", salaatit=" + salaatit + + ", pääruoat=" + pääruoat + + ", jälkiruoat=" + jälkiruoat + + ", osoite='" + osoite + '\'' + + ", lisätieto='" + lisätieto + '\'' + + ", avainTieto='" + avainTieto + '\'' + + ", ruokarajoite='" + ruokarajoite + '\'' + + '}'; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getAsiakasID() { + return asiakasID; + } + + public void setAsiakasID(int asiakasID) { + this.asiakasID = asiakasID; + } + + public String getNimi() { + return nimi; + } + + public void setNimi(String nimi) { + this.nimi = nimi; + } + + public LocalDate getKuljetusPäivämäärä() { + return kuljetusPäivämäärä; + } + + public void setKuljetusPäivämäärä(LocalDate kuljetusPäivämäärä) { + this.kuljetusPäivämäärä = kuljetusPäivämäärä; + } + + public int getKuljetusKierros() { + return kuljetusKierros; + } + + public void setKuljetusKierros(int kuljetusKierros) { + this.kuljetusKierros = kuljetusKierros; + } + + public int getSalaatit() { + return salaatit; + } + + public void setSalaatit(int salaatit) { + this.salaatit = salaatit; + } + + public int getPääruoat() { + return pääruoat; + } + + public void setPääruoat(int pääruoat) { + this.pääruoat = pääruoat; + } + + public int getJälkiruoat() { + return jälkiruoat; + } + + public void setJälkiruoat(int jälkiruoat) { + this.jälkiruoat = jälkiruoat; + } + + public String getOsoite() { + return osoite; + } + + public void setOsoite(String osoite) { + this.osoite = osoite; + } + + public String getLisätieto() { + return lisätieto; + } + + public void setLisätieto(String lisätieto) { + this.lisätieto = lisätieto; + } + + public String getAvainTieto() { + return avainTieto; + } + + public void setAvainTieto(String avainTieto) { + this.avainTieto = avainTieto; + } + + public String getRuokarajoite() { + return ruokarajoite; + } + + public void setRuokarajoite(String ruokarajoite) { + this.ruokarajoite = ruokarajoite; + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/dataluokat/RaporttiRivi.java b/src/main/java/fi/lpam/dataluokat/RaporttiRivi.java new file mode 100644 index 0000000..fc944e9 --- /dev/null +++ b/src/main/java/fi/lpam/dataluokat/RaporttiRivi.java @@ -0,0 +1,109 @@ +package fi.lpam.dataluokat; + +import fi.lpam.gui.virheDialogit.SiirtoVirhe; + +import java.sql.*; +import java.time.LocalDate; +import java.util.ArrayList; + +@SuppressWarnings("ClassCanBeRecord") +public class RaporttiRivi { + private final String nimi; + private final LocalDate alkuPvm, loppuPvm; + private final int salaatit, pääruoat, jälkiruoat; + private final String lisätiedot; + + public RaporttiRivi(String nimi, LocalDate alkuPvm, LocalDate loppuPvm, int salaatit, int pääruoat, int jälkiruoat, String lisätiedot) { + this.nimi = nimi; + this.alkuPvm = alkuPvm; + this.loppuPvm = loppuPvm; + this.salaatit = salaatit; + this.pääruoat = pääruoat; + this.jälkiruoat = jälkiruoat; + this.lisätiedot = lisätiedot; + } + + public static ArrayList haeRaportti(LocalDate alkuPvm, LocalDate loppuPvm, boolean tarkka) { + ArrayList raportti = new ArrayList<>(); + try (Connection tietokanta = Tietokanta.haeYhteys()) { + ResultSet rs; + if (tarkka) { + //Jokainen kuljetus saa oman rivin + PreparedStatement stmt = tietokanta.prepareStatement("select nimi, kuljetusPäivämäärä, salaatit, pääruoat, jälkiruoat, lisätieto from kuljetukset where kuljetusPäivämäärä between ? and ? order by nimi"); + stmt.setDate(1, Date.valueOf(alkuPvm)); + stmt.setDate(2, Date.valueOf(loppuPvm)); + rs = stmt.executeQuery(); + + while (rs.next()) { + RaporttiRivi uusi = new RaporttiRivi( + rs.getString(1), + rs.getDate(2).toLocalDate(), + rs.getDate(2).toLocalDate(), + rs.getInt(3), + rs.getInt(4), + rs.getInt(5), + rs.getString(6) + ); + raportti.add(uusi); + } + + } else { + //Kuljetukset summataan yhteen riviin per vastaanottaja + PreparedStatement stmt = tietokanta.prepareStatement("select nimi, kuljetusPäivämäärä, sum(salaatit), sum(pääruoat), sum(jälkiruoat), group_concat(lisätieto, '\n') from kuljetukset where kuljetusPäivämäärä between ? and ? group by nimi order by nimi;"); + stmt.setDate(1, Date.valueOf(alkuPvm)); + stmt.setDate(2, Date.valueOf(loppuPvm)); + rs = stmt.executeQuery(); + + while (rs.next()) { + RaporttiRivi uusi = new RaporttiRivi( + rs.getString(1), + alkuPvm, + loppuPvm, + rs.getInt(3), + rs.getInt(4), + rs.getInt(5), + rs.getString(6) + ); + raportti.add(uusi); + } + } + } catch (SQLException e) { + SiirtoVirhe virhe = new SiirtoVirhe(e); + virhe.showAndWait(); + return null; + } + return raportti; + } + @Override + public String toString() { + return this.nimi + ":\nSal: " + this.salaatit + ", Pr: " + this.pääruoat + ", Jr: " + this.jälkiruoat + "\nLisätiedot:\n" + this.lisätiedot; + } + + public String getNimi() { + return nimi; + } + + public LocalDate getAlkuPvm() { + return alkuPvm; + } + + public LocalDate getLoppuPvm() { + return loppuPvm; + } + + public int getSalaatit() { + return salaatit; + } + + public int getPääruoat() { + return pääruoat; + } + + public int getJälkiruoat() { + return jälkiruoat; + } + + public String getLisätiedot() { + return lisätiedot; + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/dataluokat/Tietokanta.java b/src/main/java/fi/lpam/dataluokat/Tietokanta.java new file mode 100644 index 0000000..a4849eb --- /dev/null +++ b/src/main/java/fi/lpam/dataluokat/Tietokanta.java @@ -0,0 +1,60 @@ +package fi.lpam.dataluokat; + +import fi.lpam.gui.virheDialogit.SiirtoVirhe; +import fi.lpam.gui.virheDialogit.YhteysVirhe; + +import fi.lpam.Main; +import javafx.scene.control.Alert; +import org.apache.commons.lang3.SystemUtils; + +import java.io.*; +import java.sql.*; +import java.util.Objects; + +public class Tietokanta { + private static String osoite; + private static String dbPath = SystemUtils.getUserHome().getAbsolutePath() + "\\OneDrive\\Kuljetusruokasovellus\\tietokanta.db"; + + public Tietokanta(boolean dev) throws IOException { + if (dev) dbPath = "tietokanta.db"; + File file = new File(dbPath); + try { + //noinspection ResultOfMethodCallIgnored + file.getParentFile().mkdirs(); + } + catch (Exception _) {} + //noinspection ResultOfMethodCallIgnored + file.createNewFile(); + + osoite = "jdbc:sqlite:" + file.getAbsolutePath(); + + + try (Connection conn = haeYhteys()) { + InputStream is = Objects.requireNonNull(Main.class.getResourceAsStream("tietokanta.sql")); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + String sql = br.readAllAsString(); + + for (String query : sql.split(";")) { + conn.createStatement().execute(query); + } + + } + catch (Exception e) { + SiirtoVirhe virhe = new SiirtoVirhe(e); + virhe.showAndWait(); + } + + } + + public static Connection haeYhteys() { + + Connection connection = null; + try { + connection = DriverManager.getConnection(osoite); + } catch (Exception e) { + Alert virhe = new YhteysVirhe(e); + virhe.showAndWait(); + } + return connection; + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/dataluokat/TietokantaOlio.java b/src/main/java/fi/lpam/dataluokat/TietokantaOlio.java new file mode 100644 index 0000000..6f698ac --- /dev/null +++ b/src/main/java/fi/lpam/dataluokat/TietokantaOlio.java @@ -0,0 +1,12 @@ +package fi.lpam.dataluokat; + +public interface TietokantaOlio { + + boolean tallennaUusi(); + + boolean päivitäTietokantaan(); + + boolean poista(); + + boolean tallenna(); +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/AsiakasIkkuna.java b/src/main/java/fi/lpam/gui/AsiakasIkkuna.java new file mode 100644 index 0000000..9f82196 --- /dev/null +++ b/src/main/java/fi/lpam/gui/AsiakasIkkuna.java @@ -0,0 +1,204 @@ +package fi.lpam.gui; + +import fi.lpam.dataluokat.Asiakas; + +import fi.lpam.gui.elementit.IntegerSpinner; +import fi.lpam.gui.elementit.TabPohja; +import fi.lpam.Main; +import javafx.geometry.Insets; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.image.Image; +import javafx.scene.layout.GridPane; +import javafx.stage.Stage; + +import java.util.Objects; + + +public class AsiakasIkkuna extends Stage { + final Asiakas käsiteltäväAsiakas; + final TextField tfNimi, tfOsoite, tfRuokarajoitteet, tfAvainTieto, tfLisätiedot; + final IntegerSpinner tfMaanantai, tfTiistai, tfKeskiviikko, tfTorstai, tfPerjantai, tfSalaatit, tfPääruoat, tfJälkiruoat; + + /** + * Luo ikkunan jossa muokataan saatua asiakasta + * @param käsiteltäväAsiakas voi olla uusi, tai vanha. Ikkuna ei välitä + */ + public AsiakasIkkuna(Asiakas käsiteltäväAsiakas) { + this.käsiteltäväAsiakas = käsiteltäväAsiakas; + this.setTitle("Asiakasikkuna"); + + GridPane root = new GridPane(); + root.setPadding(new Insets(15)); + root.setHgap(10); + root.setVgap(10); + root.setOnKeyPressed(e -> { + switch (e.getCode()) { + case ENTER: tallenna(); break; + case ESCAPE: close(); break; + default: break; + }}); + + root.addRow(root.getRowCount(), new Label("Vahvistetut kentät pakollisia")); + + Label nimi = new Label("Asiakkaan etu- ja sukunimi"); + nimi.setStyle("-fx-font-weight: bold;"); + tfNimi = new TextField(); + tfNimi.setPromptText("Pakollinen tieto"); + root.addRow(root.getRowCount(), nimi, tfNimi); + + Label osoite = new Label("Osoite"); + osoite.setStyle("-fx-font-weight: bold;"); + tfOsoite = new TextField(); + tfOsoite.setPromptText("Pakollinen tieto"); + root.addRow(root.getRowCount(), osoite, tfOsoite); + + root.addRow(root.getRowCount(), new Label("Määrät per kuljetus")); + + Label salaatit = new Label("Salaatit"); + tfSalaatit = new IntegerSpinner(); + root.addRow(root.getRowCount(), salaatit, tfSalaatit); + + Label pääruoat = new Label("Pääruoat"); + tfPääruoat = new IntegerSpinner(); + root.addRow(root.getRowCount(), pääruoat, tfPääruoat); + + Label jälkiruoat = new Label("Jälkiruoat"); + tfJälkiruoat = new IntegerSpinner(); + root.addRow(root.getRowCount(), jälkiruoat, tfJälkiruoat); + + root.addRow(root.getRowCount(), new Label("Kuljetukset per päivä")); + + Label maanantai = new Label("Maanantai"); + tfMaanantai = new IntegerSpinner(); + root.addRow(root.getRowCount(), maanantai, tfMaanantai); + + Label tiistai = new Label("Tiistai"); + tfTiistai = new IntegerSpinner(); + root.addRow(root.getRowCount(), tiistai, tfTiistai); + + Label keskiviikko = new Label("Keskiviikko"); + tfKeskiviikko = new IntegerSpinner(); + root.addRow(root.getRowCount(), keskiviikko, tfKeskiviikko); + + Label torstai = new Label("Torstai"); + tfTorstai = new IntegerSpinner(); + root.addRow(root.getRowCount(), torstai, tfTorstai); + + Label perjantai = new Label("Perjantai"); + tfPerjantai = new IntegerSpinner(); + root.addRow(root.getRowCount(), perjantai, tfPerjantai); + + Label ruokarajoitteet = new Label("Ruokarajoitteet"); + tfRuokarajoitteet = new TextField(); + root.addRow(root.getRowCount(), ruokarajoitteet, tfRuokarajoitteet); + + Label avainTieto = new Label("Avaintieto"); + tfAvainTieto = new TextField(); + root.addRow(root.getRowCount(), avainTieto, tfAvainTieto); + + Label lisätiedot = new Label("Kuljetuksen lisätiedot"); + tfLisätiedot = new TextField(); + tfLisätiedot.setPromptText("Näkyy raporteilla"); + root.addRow(root.getRowCount(), lisätiedot, tfLisätiedot); + + Button peruuta = new Button("Peruuta"); + peruuta.setFont(TabPohja.buttonFont); + peruuta.setMinWidth(160); + peruuta.setOnAction(_ -> this.close()); + Button tallenna = new Button("Tallenna"); + tallenna.setFont(TabPohja.buttonFont); + tallenna.setMinWidth(160); + tallenna.setOnAction(_ -> tallenna()); + root.addRow(root.getRowCount(), peruuta, tallenna); + + + this.setScene(new Scene(root)); + this.getIcons().add(new Image(Objects.requireNonNull(Main.class.getResourceAsStream("kuljetusruokalaatikko.jpg")))); + this.setAlwaysOnTop(true); + this.setResizable(false); + + //Saatu asiakas on tullut muokattavaksi + if (käsiteltäväAsiakas.getId() > 0) { + näytäAsiakas(); + } + } + + /** + * Jos saadulla asiakkaalla on id (eli asiakas löytyy tietokannasta ja sillä on tietoja) + * tällä funktiolla täytetään asiakkaan tiedot ikkunan kenttiin + */ + private void näytäAsiakas() { + tfNimi.setText(käsiteltäväAsiakas.getNimi()); + tfOsoite.setText(käsiteltäväAsiakas.getOsoite()); + tfMaanantai.getValueFactory().setValue(käsiteltäväAsiakas.getMaanantaiKpl()); + tfTiistai.getValueFactory().setValue(käsiteltäväAsiakas.getTiistaiKpl()); + tfKeskiviikko.getValueFactory().setValue(käsiteltäväAsiakas.getKeskiviikkoKpl()); + tfTorstai.getValueFactory().setValue(käsiteltäväAsiakas.getTorstaiKpl()); + tfPerjantai.getValueFactory().setValue(käsiteltäväAsiakas.getPerjantaiKpl()); + tfSalaatit.getValueFactory().setValue(käsiteltäväAsiakas.getSalaatit()); + tfPääruoat.getValueFactory().setValue(käsiteltäväAsiakas.getPääruoat()); + tfJälkiruoat.getValueFactory().setValue(käsiteltäväAsiakas.getJälkiruoat()); + tfRuokarajoitteet.setText(käsiteltäväAsiakas.getErityisruokavalio()); + tfAvainTieto.setText(käsiteltäväAsiakas.getAvainTieto()); + tfLisätiedot.setText(käsiteltäväAsiakas.getLisätiedot()); + } + + private void tallenna() { + this.setAlwaysOnTop(false); + String nimi = tfNimi.getText(); + String osoite = tfOsoite.getText(); + + if (nimi.isEmpty() || osoite.isEmpty()) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle("Tarkista tiedot"); + alert.setHeaderText(null); + alert.setContentText("Nimi tai osoite ei voi olla tyhjiä"); + alert.showAndWait(); + return; + } + + käsiteltäväAsiakas.setNimi(nimi); + käsiteltäväAsiakas.setOsoite(osoite); + käsiteltäväAsiakas.setMaanantaiKpl(tfMaanantai.getValue()); + käsiteltäväAsiakas.setTiistaiKpl(tfTiistai.getValue()); + käsiteltäväAsiakas.setKeskiviikkoKpl(tfKeskiviikko.getValue()); + käsiteltäväAsiakas.setTorstaiKpl(tfTorstai.getValue()); + käsiteltäväAsiakas.setPerjantaiKpl(tfPerjantai.getValue()); + käsiteltäväAsiakas.setSalaatit(tfSalaatit.getValue()); + käsiteltäväAsiakas.setPääruoat(tfPääruoat.getValue()); + käsiteltäväAsiakas.setJälkiruoat(tfJälkiruoat.getValue()); + käsiteltäväAsiakas.setErityisruokavalio(tfRuokarajoitteet.getText()); + käsiteltäväAsiakas.setAvainTieto(tfAvainTieto.getText()); + käsiteltäväAsiakas.setLisätiedot(tfLisätiedot.getText()); + + boolean läpi = false; + int maxYritykset = 3; + int yritykset = 0; + while (!läpi) { + if (käsiteltäväAsiakas.getId() > 0) { + läpi = käsiteltäväAsiakas.päivitäTietokantaan(); + } + else { + läpi = käsiteltäväAsiakas.tallennaUusi(); + } + yritykset++; + if (yritykset > maxYritykset) { + break; + } + } + + + if (läpi) { + int viikonKuljetukset = käsiteltäväAsiakas.getMaanantaiKpl() + käsiteltäväAsiakas.getTiistaiKpl() + käsiteltäväAsiakas.getKeskiviikkoKpl() + käsiteltäväAsiakas.getTorstaiKpl() + käsiteltäväAsiakas.getPerjantaiKpl(); + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle("Onnistuimme!"); + alert.setHeaderText("Asiakkaan tallentaminen onnistui!"); + alert.setContentText(String.format("%s saa jatkossa yhteensä \n%s salaattia, %s pääruokaa ja %s jälkiruokaa viikossa", + käsiteltäväAsiakas.getNimi(), käsiteltäväAsiakas.getSalaatit()*viikonKuljetukset, käsiteltäväAsiakas.getPääruoat()*viikonKuljetukset, käsiteltäväAsiakas.getPääruoat()*viikonKuljetukset)); + alert.showAndWait(); + this.close(); + } + this.setAlwaysOnTop(true); + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/Asiakashallinta.java b/src/main/java/fi/lpam/gui/Asiakashallinta.java new file mode 100644 index 0000000..72d308a --- /dev/null +++ b/src/main/java/fi/lpam/gui/Asiakashallinta.java @@ -0,0 +1,156 @@ +package fi.lpam.gui; + +import fi.lpam.dataluokat.Asiakas; +import fi.lpam.gui.elementit.MaaraTableColumn; +import fi.lpam.gui.elementit.TabPohja; +import javafx.collections.FXCollections; +import javafx.scene.control.*; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.scene.input.KeyCode; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.*; + +import java.util.Objects; +import java.util.Optional; + + +@SuppressWarnings("unchecked") +public class Asiakashallinta extends TabPohja { + final TableView tvAsiakkaat = new TableView<>(); + + public Asiakashallinta() { + BorderPane root = new BorderPane(); + this.getChildren().add(root); + root.setPadding(oletusInsets); + + BorderPane yläpalkki = new BorderPane(); + root.setTop(yläpalkki); + Label otsikko = new Label("Asiakashallinta"); + otsikko.setFont(tekstiFont); + yläpalkki.setLeft(otsikko); + + HBox yläpalkinNapit = new HBox(); + yläpalkinNapit.setSpacing(5); + yläpalkki.setRight(yläpalkinNapit); + + Button poistaValittu = new Button("Poista"); + poistaValittu.setOnAction(_ -> poistaValittu()); + poistaValittu.setFont(TabPohja.buttonFont); + yläpalkinNapit.getChildren().add(poistaValittu); + + Button muokkaaAsiakasta = new Button("Muokkaa"); + muokkaaAsiakasta.setOnAction(_ -> muokkaaValittua()); + muokkaaAsiakasta.setFont(TabPohja.buttonFont); + yläpalkinNapit.getChildren().add(muokkaaAsiakasta); + + Button uusiAsiakas = new Button("Uusi asiakas"); + uusiAsiakas.setOnAction(_ -> uusiAsiakas()); + uusiAsiakas.setFont(TabPohja.buttonFont); + yläpalkinNapit.getChildren().add(uusiAsiakas); + + tvAsiakkaat.setEditable(false); + tvAsiakkaat.setPlaceholder(new Label("Ei vielä tietoja")); + tvAsiakkaat.setOnMouseClicked((MouseEvent mouseEvent) -> { + if (mouseEvent.getClickCount() == 2) { + muokkaaValittua(); + } + }); + tvAsiakkaat.setOnKeyPressed(e -> { + if (tvAsiakkaat.getSelectionModel().getSelectedItem() != null) { + if (e.getCode() == KeyCode.ENTER) { + muokkaaValittua(); + } + } + + }); + root.setCenter(tvAsiakkaat); + + TableColumn tcNimi = new TableColumn<>("Nimi"); + tcNimi.setMinWidth(180); + tcNimi.setCellValueFactory(new PropertyValueFactory<>("nimi")); + TableColumn tcOsoite = new TableColumn<>("Osoite"); + tcOsoite.setMinWidth(250); + tcOsoite.setCellValueFactory(new PropertyValueFactory<>("osoite")); + + TableColumn> tcKuljetuspäivät = new TableColumn<>("Kuljetukset per päivä"); + MaaraTableColumn tcMaanantaiKpl = new MaaraTableColumn<>("MA", 20); + tcMaanantaiKpl.setCellValueFactory(new PropertyValueFactory<>("maanantaiKpl")); + MaaraTableColumn tcTiistaiKpl = new MaaraTableColumn<>("TI", 20); + tcTiistaiKpl.setCellValueFactory(new PropertyValueFactory<>("tiistaiKpl")); + MaaraTableColumn tcKeskiviikkoKpl = new MaaraTableColumn<>("KE", 20); + tcKeskiviikkoKpl.setCellValueFactory(new PropertyValueFactory<>("keskiviikkoKpl")); + MaaraTableColumn tcTorstaiKpl = new MaaraTableColumn<>("TO", 20); + tcTorstaiKpl.setCellValueFactory(new PropertyValueFactory<>("torstaiKpl")); + MaaraTableColumn tcPerjantaiKpl = new MaaraTableColumn<>("PE", 20); + tcPerjantaiKpl.setCellValueFactory(new PropertyValueFactory<>("perjantaiKpl")); + tcKuljetuspäivät.getColumns().addAll(tcMaanantaiKpl, tcTiistaiKpl, tcKeskiviikkoKpl, tcTorstaiKpl, tcPerjantaiKpl); + + TableColumn> tcKuljetusmäärät = new TableColumn<>("Määrät per kuljetus"); + MaaraTableColumn tcSalaatit = new MaaraTableColumn<>("Salaatit", 90); + tcSalaatit.setCellValueFactory(new PropertyValueFactory<>("salaatit")); + MaaraTableColumn tcPääruoat = new MaaraTableColumn<>("Pääruoat", 90); + tcPääruoat.setCellValueFactory(new PropertyValueFactory<>("pääruoat")); + MaaraTableColumn tcJälkiruoat = new MaaraTableColumn<>("Jälkiruoat", 90); + tcJälkiruoat.setCellValueFactory(new PropertyValueFactory<>("jälkiruoat")); + tcKuljetusmäärät.getColumns().addAll(tcSalaatit, tcPääruoat, tcJälkiruoat); + + TableColumn tcErityisruokavalio = new TableColumn<>("Ruokarajoitteet"); + tcErityisruokavalio.setMinWidth(150); + tcErityisruokavalio.setCellValueFactory(new PropertyValueFactory<>("erityisruokavalio")); + TableColumn tcAvainTieto = new TableColumn<>("Avaintieto"); + tcAvainTieto.setMinWidth(150); + tcAvainTieto.setCellValueFactory(new PropertyValueFactory<>("avainTieto")); + TableColumn tcLisätiedot = new TableColumn<>("Lisätieto kuljetukselle"); + tcLisätiedot.setMinWidth(250); + tcLisätiedot.setCellValueFactory(new PropertyValueFactory<>("lisätiedot")); + + tvAsiakkaat.getColumns().addAll(tcNimi, tcOsoite, tcKuljetuspäivät, tcKuljetusmäärät, tcErityisruokavalio, tcAvainTieto, tcLisätiedot); + for (TableColumn column : tvAsiakkaat.getColumns()) { + column.setEditable(false); + column.setReorderable(false); + column.setResizable(false); + column.setStyle("-fx-alignment: CENTER; -fx-font-size: 16px;"); + + } + + tvAsiakkaat.setItems(FXCollections.observableArrayList(Objects.requireNonNull(Asiakas.haeKaikki()))); + } + + private void uusiAsiakas() { + Asiakas luotavaAsiakas = new Asiakas(); + AsiakasIkkuna asiakasIkkuna = new AsiakasIkkuna(luotavaAsiakas); + asiakasIkkuna.showAndWait(); + if (luotavaAsiakas.getId() != -1) { + //Asiakas luotu ja id saatu tietokannasta + tvAsiakkaat.getItems().add(luotavaAsiakas); + tvAsiakkaat.refresh(); + } + } + + private void muokkaaValittua() { + Asiakas muokattavaAsiakas = tvAsiakkaat.getSelectionModel().getSelectedItem(); + if (muokattavaAsiakas == null) {return;} + AsiakasIkkuna asiakasIkkuna = new AsiakasIkkuna(muokattavaAsiakas); + asiakasIkkuna.showAndWait(); + tvAsiakkaat.refresh(); + } + + private void poistaValittu() { + Asiakas valittuAsiakas = tvAsiakkaat.getSelectionModel().getSelectedItem(); + boolean läpi = false; + if (valittuAsiakas != null) { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setTitle("Oletko varma?"); + alert.setHeaderText("Poistetaanko valittu valittu asiakas?"); + alert.setContentText(valittuAsiakas.getNimi()); + Optional result = alert.showAndWait(); + if (result.isPresent() && result.get() == ButtonType.OK) { + läpi = valittuAsiakas.poista(); + } + if (läpi) { + tvAsiakkaat.getItems().remove(valittuAsiakas); + tvAsiakkaat.refresh(); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/Kierroshallinta.java b/src/main/java/fi/lpam/gui/Kierroshallinta.java new file mode 100644 index 0000000..fcfef87 --- /dev/null +++ b/src/main/java/fi/lpam/gui/Kierroshallinta.java @@ -0,0 +1,129 @@ +package fi.lpam.gui; + +import com.dlsc.gemsfx.MultiColumnListView; + +import fi.lpam.dataluokat.Asiakas; +import fi.lpam.dataluokat.Kierros; +import fi.lpam.gui.elementit.AsiakasListCell; +import fi.lpam.gui.elementit.TabPohja; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Objects; + +public class Kierroshallinta extends TabPohja { + private final MultiColumnListView mclv = new MultiColumnListView<>(); + private final ArrayList kierrokset = Kierros.haeKaikki(); + private final ArrayList kaikkiAsiakkaat = Asiakas.haeKaikki(); + + public Kierroshallinta() { + BorderPane root = new BorderPane(); + this.getChildren().add(root); + root.setPadding(oletusInsets); + root.setCenter(mclv); + + mclv.setCellFactory(_ -> new AsiakasListCell(mclv)); + mclv.setPlaceholderFrom(new Asiakas("")); + mclv.setPlaceholderTo(new Asiakas("")); + rakennaSarakkeet(); + + BorderPane yläpalkki = new BorderPane(); + root.setTop(yläpalkki); + + Label infoTeksti = new Label("Siirrä asiakkaat haluamallesi kierrokselle. Kierroksia voit lisätä painamalla lisää kierros painiketta.\nTyhjät kierrokset poistuvat kierroksia tallentaessa."); + infoTeksti.setFont(tekstiFont); + yläpalkki.setLeft(infoTeksti); + + HBox yläpalkinNapit = new HBox(); + yläpalkinNapit.setSpacing(5); + yläpalkki.setRight(yläpalkinNapit); + + Button lisääKierros = new Button("Lisää uusi kierros"); + lisääKierros.setOnAction(_ -> lisaaKierros()); + lisääKierros.setFont(TabPohja.buttonFont); + yläpalkinNapit.getChildren().add(lisääKierros); + + Button tallenna = new Button("Tallenna kierrokset"); + tallenna.setFont(TabPohja.buttonFont); + tallenna.setOnAction(_ ->tallennaKierrokset()); + yläpalkinNapit.getChildren().add(tallenna); + + + + + } + + private void rakennaSarakkeet() { + mclv.getColumns().clear(); + ObservableList eiKierroksella = FXCollections.observableArrayList(new ArrayList<>()); + HashSet kierroksellaOlevatAsiakasIDt = new HashSet<>(); + + if (!kierrokset.isEmpty()) { + for (Kierros k : kierrokset) { + MultiColumnListView.ListViewColumn sarake = new MultiColumnListView.ListViewColumn<>(); + sarake.setHeader(new Label("Kierros " + k.getKierrosNumero())); + sarake.setItems(k.getAsiakkaat()); + for (Asiakas asiakas : k.getAsiakkaat()) { + kierroksellaOlevatAsiakasIDt.add(asiakas.getId()); + } + mclv.getColumns().add(sarake); + } + } + + for (Asiakas k : Objects.requireNonNull(kaikkiAsiakkaat)) { + if (!kierroksellaOlevatAsiakasIDt.contains(k.getId())) { + eiKierroksella.add(k); + } + } + MultiColumnListView.ListViewColumn colEiKierroksella = new MultiColumnListView.ListViewColumn<>(); + colEiKierroksella.setHeader(new Label("Ei vielä kierroksella")); + colEiKierroksella.setItems(FXCollections.observableArrayList(eiKierroksella)); + mclv.getColumns().add(colEiKierroksella); + } + + private void lisaaKierros() { + int uudenKierroksenNumero = mclv.getColumns().size(); + Kierros lisättäväKierros = new Kierros(uudenKierroksenNumero, FXCollections.observableArrayList(new ArrayList<>())); + kierrokset.add(lisättäväKierros); + MultiColumnListView.ListViewColumn uusiSarake = new MultiColumnListView.ListViewColumn<>(); + uusiSarake.setHeader(new Label("Kierros " + uudenKierroksenNumero)); + uusiSarake.setItems(lisättäväKierros.getAsiakkaat()); + mclv.getColumns().add(uudenKierroksenNumero-1, uusiSarake); + } + + private void tallennaKierrokset() { + int kierrosNumero = 1; + int index = 0; + for (int i = 0; i < kierrokset.size();) { + Kierros k = kierrokset.get(i); + k.setAsiakkaat(mclv.getColumns().get(index).getItems()); + index++; + + if (k.getAsiakkaat().isEmpty()) { + k.poista(); + kierrokset.remove(i); + continue; + } + + k.setKierrosNumero(kierrosNumero); + kierrosNumero++; + k.tallenna(); + i++; + } + rakennaSarakkeet(); + + Alert info = new Alert(Alert.AlertType.INFORMATION); + info.setTitle("Kierrokset tallennettu"); + info.setHeaderText("Kierrokset tallennettu onnistuneesti"); + info.setContentText(null); + info.showAndWait(); + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/KuljetusListat.java b/src/main/java/fi/lpam/gui/KuljetusListat.java new file mode 100644 index 0000000..012d909 --- /dev/null +++ b/src/main/java/fi/lpam/gui/KuljetusListat.java @@ -0,0 +1,205 @@ +package fi.lpam.gui; + +import fi.lpam.dataluokat.Asiakas; +import fi.lpam.dataluokat.Kierros; +import fi.lpam.dataluokat.Kuljetus; +import fi.lpam.tulostajat.KuljetusListaTulostaja; +import fi.lpam.gui.elementit.MaaraTableColumn; +import fi.lpam.gui.elementit.TabPohja; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.geometry.Pos; +import javafx.scene.control.*; +import javafx.scene.control.cell.ChoiceBoxTableCell; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.scene.control.cell.TextFieldTableCell; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Objects; + + +@SuppressWarnings("unchecked") +public class KuljetusListat extends TabPohja { + private final TableView tableView = new TableView<>(); + private final DatePicker datePicker = new DatePicker(LocalDate.now()); + private final ComboBox kierrosValinta = new ComboBox<>(FXCollections.observableArrayList(Kierros.haeKierrosNumerot())); + private final Label tallennusStatus; + private final Button btnTulosta; + + public KuljetusListat() { + ObservableList määräVaihtoehdot = FXCollections.observableArrayList(); + for (int i = 0; i <= 10; i++) { + määräVaihtoehdot.add(i);} + + BorderPane root = new BorderPane(); + root.setPadding(oletusInsets); + this.getChildren().add(root); + + BorderPane yläpalkki = new BorderPane(); + Label infoTeksti = new Label("Kuljetuslistojen luonti"); + infoTeksti.setFont(tekstiFont); + yläpalkki.setLeft(infoTeksti); + + HBox kierroksenValintaLaatikko = new HBox(); + kierroksenValintaLaatikko.setSpacing(5); + kierroksenValintaLaatikko.setSpacing(5); + kierroksenValintaLaatikko.setAlignment(Pos.CENTER); + Button valitse = new Button("Valitse"); + valitse.setFont(buttonFont); + valitse.setOnAction(_ -> päivitäListanäkymä()); + tallennusStatus = new Label("Tallennettu: Kyllä"); + tallennusStatus.setFont(tekstiFont); + datePicker.valueProperty().addListener(_ -> päivitäListanäkymä()); + kierrosValinta.valueProperty().addListener(_ -> päivitäListanäkymä()); + kierroksenValintaLaatikko.getChildren().addAll( + new Label("Valitse päivämäärä:"), + datePicker, + new Label("Valitse kierros:"), + kierrosValinta, tallennusStatus); + yläpalkki.setCenter(kierroksenValintaLaatikko); + + HBox napit = new HBox(); + napit.setSpacing(5); + Button poista = new Button("Poista kuljetusrivi"); + poista.setOnAction(_ ->poistaRivi()); + poista.setFont(buttonFont); + Button tallenna = new Button("Tallenna"); + tallenna.setFont(buttonFont); + tallenna.setOnAction(_ -> tallennaKierros()); + btnTulosta = new Button("Tulosta lista"); + btnTulosta.setDisable(true); + btnTulosta.setFont(buttonFont); + btnTulosta.setOnAction(_ ->tulostaLista()); + napit.getChildren().addAll(poista, tallenna, btnTulosta); + yläpalkki.setRight(napit); + root.setTop(yläpalkki); + + tableView.setEditable(true); + tableView.setPlaceholder(new Label("Valitse kierros aloittaaksesi")); + root.setCenter(tableView); + + TableColumn tcNimi = new TableColumn<>("Nimi"); + tcNimi.setMinWidth(150); + tcNimi.setCellFactory(TextFieldTableCell.forTableColumn()); + tcNimi.setCellValueFactory(new PropertyValueFactory<>("nimi")); + tcNimi.setOnEditCommit((TableColumn.CellEditEvent event) -> {event.getTableView().getItems().get(event.getTablePosition().getRow()).setNimi(event.getNewValue()); tallennusStatus.setText("Tallennettu: Ei");}); + + TableColumn tcOsoite = new TableColumn<>("Osoite"); + tcOsoite.setMinWidth(250); + tcOsoite.setCellFactory(TextFieldTableCell.forTableColumn()); + tcOsoite.setCellValueFactory(new PropertyValueFactory<>("osoite")); + tcOsoite.setOnEditCommit((TableColumn.CellEditEvent event) -> {event.getTableView().getItems().get(event.getTablePosition().getRow()).setOsoite(event.getNewValue()); tallennusStatus.setText("Tallennettu: Ei");}); + + TableColumn tcSalaatit = new MaaraTableColumn<>("Salaatit", 100); + tcSalaatit.setCellFactory(ChoiceBoxTableCell.forTableColumn(määräVaihtoehdot)); + tcSalaatit.setCellValueFactory(new PropertyValueFactory<>("salaatit")); + tcSalaatit.setOnEditCommit((TableColumn.CellEditEvent event) -> {event.getTableView().getItems().get(event.getTablePosition().getRow()).setSalaatit(event.getNewValue()); tallennusStatus.setText("Tallennettu: Ei");}); + + TableColumn tcPääruoat = new MaaraTableColumn<>("Pääruoat", 100); + tcPääruoat.setCellFactory(ChoiceBoxTableCell.forTableColumn(määräVaihtoehdot)); + tcPääruoat.setCellValueFactory(new PropertyValueFactory<>("pääruoat")); + tcPääruoat.setOnEditCommit((TableColumn.CellEditEvent event) -> {event.getTableView().getItems().get(event.getTablePosition().getRow()).setPääruoat(event.getNewValue()); tallennusStatus.setText("Tallennettu: Ei");}); + + TableColumn tcJälkiruoat = new MaaraTableColumn<>("Jälkiruoat", 100); + tcJälkiruoat.setCellFactory(ChoiceBoxTableCell.forTableColumn(määräVaihtoehdot)); + tcJälkiruoat.setCellValueFactory(new PropertyValueFactory<>("jälkiruoat")); + tcJälkiruoat.setOnEditCommit((TableColumn.CellEditEvent event) -> {event.getTableView().getItems().get(event.getTablePosition().getRow()).setJälkiruoat(event.getNewValue()); tallennusStatus.setText("Tallennettu: Ei");}); + + TableColumn tcRuokarajoite = new TableColumn<>("Ruokarajoite"); + tcRuokarajoite.setMinWidth(200); + tcRuokarajoite.setCellFactory(TextFieldTableCell.forTableColumn()); + tcRuokarajoite.setCellValueFactory(new PropertyValueFactory<>("ruokarajoite")); + tcRuokarajoite.setOnEditCommit((TableColumn.CellEditEvent event) -> {event.getTableView().getItems().get(event.getTablePosition().getRow()).setRuokarajoite(event.getNewValue()); tallennusStatus.setText("Tallennettu: Ei");}); + + TableColumn tcLisätieto = new TableColumn<>("Lisätieto kuljetukselle"); + tcLisätieto.setMinWidth(200); + tcLisätieto.setCellFactory(TextFieldTableCell.forTableColumn()); + tcLisätieto.setCellValueFactory(new PropertyValueFactory<>("lisätieto")); + tcLisätieto.setOnEditCommit((TableColumn.CellEditEvent event) -> {event.getTableView().getItems().get(event.getTablePosition().getRow()).setLisätieto(event.getNewValue()); tallennusStatus.setText("Tallennettu: Ei");}); + + TableColumn tcAvainTieto = new TableColumn<>("Avaintieto"); + tcAvainTieto.setMinWidth(200); + tcAvainTieto.setCellFactory(TextFieldTableCell.forTableColumn()); + tcAvainTieto.setCellValueFactory(new PropertyValueFactory<>("avainTieto")); + tcAvainTieto.setOnEditCommit((TableColumn.CellEditEvent event) -> {event.getTableView().getItems().get(event.getTablePosition().getRow()).setAvainTieto(event.getNewValue()); tallennusStatus.setText("Tallennettu: Ei");}); + + tableView.getColumns().addAll(tcNimi, tcOsoite, tcSalaatit, tcPääruoat, tcJälkiruoat, tcRuokarajoite, tcLisätieto, tcAvainTieto); + + for (TableColumn sarake : tableView.getColumns()) { + sarake.setSortable(false); + sarake.setEditable(true); + sarake.setResizable(true); + sarake.setStyle("-fx-alignment: CENTER; -fx-font-size: 16px;"); + } + } + + private void päivitäListanäkymä() { + LocalDate valittuPäivä = datePicker.getValue(); + int valittuKierros = kierrosValinta.getValue(); + + ArrayList luetutKuljetuksetKierrokselle = Kuljetus.haePäivänKuljetuksetKierroksella(valittuPäivä, valittuKierros); + ObservableList kierroksenAsiakkaat = Objects.requireNonNull(Kierros.haeKierros(valittuKierros)).getAsiakkaat(); + ArrayList näytettävätKuljetukset = new ArrayList<>(); + HashSet näytettävätAsiakasIDt = new HashSet<>(); + //Luodaan kierroksen kuljetusdata kierrosjärjestyksen mukaan + for (Asiakas asiakas : kierroksenAsiakkaat) { + näytettävätKuljetukset.add(new Kuljetus(asiakas, valittuPäivä, valittuKierros)); + näytettävätAsiakasIDt.add(asiakas.getId()); + } + //Yhdistetään tietokannan data järjestys säilyttäen + for (Kuljetus luettuKuljetus : Objects.requireNonNull(luetutKuljetuksetKierrokselle)) { + if (näytettävätAsiakasIDt.contains(luettuKuljetus.getAsiakasID())) { + for (Kuljetus näytettäväKuljetus : näytettävätKuljetukset) { + if (näytettäväKuljetus.getAsiakasID() == luettuKuljetus.getAsiakasID()) { + näytettävätKuljetukset.set(näytettävätKuljetukset.indexOf(näytettäväKuljetus), luettuKuljetus); + } + } + } + else { + näytettävätKuljetukset.add(luettuKuljetus); + } + } + + tableView.setItems(FXCollections.observableArrayList(näytettävätKuljetukset)); + tallennusStatus.setText("Tallennettu: Ei"); + btnTulosta.setDisable(true); + } + + private void poistaRivi() { + Kuljetus valittu = tableView.getSelectionModel().getSelectedItem(); + tableView.getItems().remove(valittu); + if (valittu.getId() > 0) {valittu.poista();} + tableView.refresh(); + tallennusStatus.setText("Tallennettu: Ei"); + } + + private void tallennaKierros() { + try { + for (Kuljetus kuljetus : tableView.getItems()) { + if (kuljetus.getId() > 0) { + kuljetus.päivitäTietokantaan(); + } else { + kuljetus.tallennaUusi(); + } + } + tallennusStatus.setText("Tallennettu: Kyllä"); + btnTulosta.setDisable(false); + } + catch (Exception e) { + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setTitle("Virhe"); + alert.setHeaderText("Tallennus epäonnistui"); + alert.setContentText(e.getMessage()); + alert.showAndWait(); + } + } + + private void tulostaLista() { + KuljetusListaTulostaja.tulosta(tableView.getItems(), kierrosValinta.getValue()); + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/KuljetusRaportit.java b/src/main/java/fi/lpam/gui/KuljetusRaportit.java new file mode 100644 index 0000000..8343ae1 --- /dev/null +++ b/src/main/java/fi/lpam/gui/KuljetusRaportit.java @@ -0,0 +1,100 @@ +package fi.lpam.gui; + +import fi.lpam.dataluokat.RaporttiRivi; +import fi.lpam.tulostajat.KuljetusRaporttiTulostaja; +import fi.lpam.gui.elementit.PaivamaaraTableCell; +import fi.lpam.gui.elementit.TabPohja; +import javafx.collections.FXCollections; +import javafx.geometry.Pos; +import javafx.scene.control.*; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Objects; + + +@SuppressWarnings("unchecked") +public class KuljetusRaportit extends TabPohja { + private final TableView tableView = new TableView<>(); + private final DatePicker alkuPvm, loppuPvm; + private ArrayList raportti; + private final CheckBox tarkka; + + void haeRaportti() { + raportti = RaporttiRivi.haeRaportti(alkuPvm.getValue(), loppuPvm.getValue(), tarkka.isSelected()); + tableView.setItems(FXCollections.observableArrayList(Objects.requireNonNull(raportti))); + tableView.refresh(); + } + + void tulostaRaportti() { + KuljetusRaporttiTulostaja.luoRaportti(raportti, alkuPvm.getValue(), loppuPvm.getValue()); + } + + public KuljetusRaportit() { + BorderPane root = new BorderPane(); + root.setPadding(oletusInsets); + this.getChildren().add(root); + + BorderPane yläpalkki = new BorderPane(); + root.setTop(yläpalkki); + + Label infoTeksti = new Label("Kuljetusraportit"); + infoTeksti.setFont(tekstiFont); + yläpalkki.setLeft(infoTeksti); + + HBox yläpalkinNapit = new HBox(); + yläpalkinNapit.setAlignment(Pos.CENTER); + yläpalkinNapit.setSpacing(5); + yläpalkki.setRight(yläpalkinNapit); + + tarkka = new CheckBox("Tarkka"); + alkuPvm = new DatePicker(LocalDate.now().minusDays(LocalDate.now().getDayOfMonth() - 1)); + loppuPvm = new DatePicker(LocalDate.now()); + Button haeKuljetukset = new Button("Hae"); + haeKuljetukset.setFont(buttonFont); + haeKuljetukset.setOnAction(_ ->haeRaportti()); + Button tulostaRaportti = new Button("Tulosta raportti"); + tulostaRaportti.setFont(buttonFont); + tulostaRaportti.setOnAction(_ ->tulostaRaportti()); + yläpalkinNapit.getChildren().addAll(tarkka, new Label("Hae kuljetukset välillä:"), alkuPvm, new Label("-"), loppuPvm, haeKuljetukset, tulostaRaportti); + + root.setCenter(tableView); + + TableColumn tcNimi = new TableColumn<>("Nimi"); + tcNimi.setMinWidth(150); + tcNimi.setCellValueFactory(new PropertyValueFactory<>("nimi")); + + TableColumn tcPvm = new TableColumn<>("Päivämäärä"); + tcPvm.setMinWidth(150); + tcPvm.setCellFactory(_ ->new PaivamaaraTableCell()); + tcPvm.setCellValueFactory(new PropertyValueFactory<>("loppuPvm")); + + TableColumn tcSalaatit = new TableColumn<>("Salaatit"); + tcSalaatit.setMinWidth(100); + tcSalaatit.setCellValueFactory(new PropertyValueFactory<>("salaatit")); + + TableColumn tcPääruoat = new TableColumn<>("Pääruoat"); + tcPääruoat.setMinWidth(100); + tcPääruoat.setCellValueFactory(new PropertyValueFactory<>("pääruoat")); + + TableColumn tcJälkiruoat = new TableColumn<>("Jälkiruoat"); + tcJälkiruoat.setMinWidth(100); + tcJälkiruoat.setCellValueFactory(new PropertyValueFactory<>("jälkiruoat")); + + TableColumn tcLisätiedot = new TableColumn<>("Lisätiedot"); + tcLisätiedot.setMinWidth(500); + tcLisätiedot.setCellValueFactory(new PropertyValueFactory<>("lisätiedot")); + + tableView.getColumns().addAll(tcNimi, tcPvm, tcSalaatit, tcPääruoat, tcJälkiruoat, tcLisätiedot); + tableView.setPlaceholder(new Label("Hae raportti")); + for (TableColumn sarake : tableView.getColumns()) { + sarake.setSortable(false); + sarake.setEditable(false); + sarake.setResizable(true); + sarake.setStyle("-fx-alignment: CENTER; -fx-font-size: 16px;"); + } + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/elementit/AsiakasListCell.java b/src/main/java/fi/lpam/gui/elementit/AsiakasListCell.java new file mode 100644 index 0000000..a93a08f --- /dev/null +++ b/src/main/java/fi/lpam/gui/elementit/AsiakasListCell.java @@ -0,0 +1,68 @@ +package fi.lpam.gui.elementit; + +import com.dlsc.gemsfx.MultiColumnListView; +import fi.lpam.dataluokat.Asiakas; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.scene.Node; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; + + +public class AsiakasListCell extends MultiColumnListView.ColumnListCell { + private final StackPane wrapper; + + public AsiakasListCell(MultiColumnListView multiColumnListView) { + //noinspection unchecked + super(multiColumnListView); + this.setHeight(150); + this.setPrefHeight(50); + + + VBox content = new VBox(); + content.visibleProperty().bind(placeholder.not().and(emptyProperty().not())); + content.managedProperty().bind(placeholder.not().and(emptyProperty().not())); + + VBox contentPlaceholder = new VBox(); + contentPlaceholder.visibleProperty().bind(placeholder); + contentPlaceholder.managedProperty().bind(placeholder); + + Label label = new Label(); + label.textProperty().bind(textProperty()); + + wrapper = new StackPane(content, contentPlaceholder, label); + setGraphic(wrapper); + setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + } + + @Override + protected Node getSnapshotNode() { + return wrapper; + } + + private final BooleanProperty placeholder = new SimpleBooleanProperty(this, "placeholder", false); + + @Override + protected void updateItem(Asiakas Asiakas, boolean empty) { + super.updateItem(Asiakas, empty); + + placeholder.set(false); + + + if (Asiakas != null && !empty) { + if (Asiakas == getMultiColumnListView().getPlaceholderFrom()) { + placeholder.set(true); + setText(Asiakas.getNimi() + ": " + Asiakas.getOsoite()); + } else if (Asiakas == getMultiColumnListView().getPlaceholderTo()) { + placeholder.set(true); + setText(Asiakas.getNimi() + ": " + Asiakas.getOsoite()); + } else { + setText(Asiakas.getNimi() + ": " + Asiakas.getOsoite()); + } + } else { + setText(""); + } + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/elementit/IntegerSpinner.java b/src/main/java/fi/lpam/gui/elementit/IntegerSpinner.java new file mode 100644 index 0000000..21120ce --- /dev/null +++ b/src/main/java/fi/lpam/gui/elementit/IntegerSpinner.java @@ -0,0 +1,24 @@ +package fi.lpam.gui.elementit; + +import javafx.scene.control.Spinner; +import javafx.scene.control.SpinnerValueFactory; + +public class IntegerSpinner extends Spinner { + /** + * Min 0, Max 50 + */ + public IntegerSpinner() { + super(new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 50)); + this.setEditable(true); + } + + /** + * + * @param min _ + * @param max _ + */ + public IntegerSpinner(int min, int max) { + super(new SpinnerValueFactory.IntegerSpinnerValueFactory(min, max)); + this.setEditable(true); + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/elementit/MaaraTableColumn.java b/src/main/java/fi/lpam/gui/elementit/MaaraTableColumn.java new file mode 100644 index 0000000..3156796 --- /dev/null +++ b/src/main/java/fi/lpam/gui/elementit/MaaraTableColumn.java @@ -0,0 +1,12 @@ +package fi.lpam.gui.elementit; + +import javafx.scene.control.TableColumn; + +public class MaaraTableColumn extends TableColumn { + public MaaraTableColumn(String columnLabel, int minWidth) { + super(columnLabel); + this.setResizable(false); + this.setReorderable(false); + this.setMinWidth(minWidth); + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/elementit/PaivamaaraTableCell.java b/src/main/java/fi/lpam/gui/elementit/PaivamaaraTableCell.java new file mode 100644 index 0000000..238f2d7 --- /dev/null +++ b/src/main/java/fi/lpam/gui/elementit/PaivamaaraTableCell.java @@ -0,0 +1,23 @@ +package fi.lpam.gui.elementit; + +import fi.lpam.dataluokat.RaporttiRivi; +import javafx.scene.control.TableCell; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * Kustomoitu TableCell, joka päivitäTietokantaan sen sisältämän LocalDaten muotoon dd.MM.yyyy + */ +public class PaivamaaraTableCell extends TableCell { + public PaivamaaraTableCell() {} + + @Override + protected void updateItem(LocalDate aika, boolean empty) { + super.updateItem(aika, empty); + if (empty || aika == null) return; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + String muokattuAika = aika.format(formatter); + setText(muokattuAika); + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/elementit/TabPohja.java b/src/main/java/fi/lpam/gui/elementit/TabPohja.java new file mode 100644 index 0000000..12d537e --- /dev/null +++ b/src/main/java/fi/lpam/gui/elementit/TabPohja.java @@ -0,0 +1,25 @@ +package fi.lpam.gui.elementit; + +import javafx.geometry.Insets; +import javafx.scene.layout.*; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; + +/** + * Käyttöliittymän pohja + */ +public class TabPohja extends StackPane { + public static final Insets oletusInsets = new Insets(5); + public static final String oletusStyle = "-fx-background-color: lightgray;"; + public static final Font otsikkoFont = Font.font("Open Sans", FontWeight.BOLD, 18); + public static final Font buttonFont = Font.font("Open Sans", FontWeight.BOLD, 16); + public static final Font tekstiFont = Font.font("Open Sans", FontWeight.NORMAL, 16); + public static final Border oletusBorder = new Border(new BorderStroke(Color.BLACK, BorderStrokeStyle.SOLID, new CornerRadii(5), BorderWidths.DEFAULT)); + + public TabPohja() { + this.setStyle(oletusStyle); + this.setPadding(oletusInsets); + this.setBorder(oletusBorder); + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/virheDialogit/SiirtoVirhe.java b/src/main/java/fi/lpam/gui/virheDialogit/SiirtoVirhe.java new file mode 100644 index 0000000..1146ddd --- /dev/null +++ b/src/main/java/fi/lpam/gui/virheDialogit/SiirtoVirhe.java @@ -0,0 +1,8 @@ +package fi.lpam.gui.virheDialogit; + +public class SiirtoVirhe extends TietokantaVirhe{ + public SiirtoVirhe(Exception e){ + this.setHeaderText("Virhe datan siirrossa"); + this.setContentText(e.getMessage()); + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/gui/virheDialogit/TietokantaVirhe.java b/src/main/java/fi/lpam/gui/virheDialogit/TietokantaVirhe.java new file mode 100644 index 0000000..a2c7f7c --- /dev/null +++ b/src/main/java/fi/lpam/gui/virheDialogit/TietokantaVirhe.java @@ -0,0 +1,20 @@ +package fi.lpam.gui.virheDialogit; + +import fi.lpam.Main; +import javafx.scene.control.Alert; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; + +import java.util.Objects; + + +abstract class TietokantaVirhe extends Alert { + public TietokantaVirhe() { + super(AlertType.ERROR); + this.setTitle("Tietokanta"); + ImageView sql = new ImageView(new Image(Objects.requireNonNull(Main.class.getResourceAsStream("tietokanta.png")))); + sql.setPreserveRatio(true); + sql.setFitHeight(100); + this.setGraphic(sql); + } +} diff --git a/src/main/java/fi/lpam/gui/virheDialogit/YhteysVirhe.java b/src/main/java/fi/lpam/gui/virheDialogit/YhteysVirhe.java new file mode 100644 index 0000000..279a7b8 --- /dev/null +++ b/src/main/java/fi/lpam/gui/virheDialogit/YhteysVirhe.java @@ -0,0 +1,8 @@ +package fi.lpam.gui.virheDialogit; + +public class YhteysVirhe extends TietokantaVirhe{ + public YhteysVirhe(Exception error){ + this.setHeaderText("Virhe yhdistäessä tietokantaan"); + this.setContentText(error.getMessage()); + } +} diff --git a/src/main/java/fi/lpam/tulostajat/KuljetusListaTulostaja.java b/src/main/java/fi/lpam/tulostajat/KuljetusListaTulostaja.java new file mode 100644 index 0000000..c8569a2 --- /dev/null +++ b/src/main/java/fi/lpam/tulostajat/KuljetusListaTulostaja.java @@ -0,0 +1,89 @@ +package fi.lpam.tulostajat; + +import fi.lpam.dataluokat.Kuljetus; +import fi.lpam.gui.virheDialogit.SiirtoVirhe; +import javafx.collections.ObservableList; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.printing.PDFPageable; + +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.io.IOException; +import java.time.format.DateTimeFormatter; + +@SuppressWarnings("DuplicatedCode") +public class KuljetusListaTulostaja extends Tulostaja{ + public static void tulosta(ObservableList kuljetukset, int kierrosnumero) { + int kuljetuksetPerSivu = 17; + try (PDDocument dokumentti = new PDDocument()) { + PDPage sivu = new PDPage(); + dokumentti.addPage(sivu); + PDPageContentStream sisältö = new PDPageContentStream(dokumentti, sivu); + sisältö.beginText(); + + + sisältö.setFont(fontti, fonttiKoko); + sisältö.setLeading(leading); + sisältö.newLineAtOffset(25, 750); + sisältö.showText(kuljetukset.getFirst().getKuljetusPäivämäärä().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) + ", kierros " + kierrosnumero); + sisältö.newLineAtOffset(0, -25); + + int riviLaskuri = 1; + for (Kuljetus kuljetus : kuljetukset) { + //Tyhjää kuljetusta ei tulosteta + if ((kuljetus.getSalaatit() + kuljetus.getPääruoat() + kuljetus.getJälkiruoat()) < 1) {continue;} + + if (riviLaskuri > kuljetuksetPerSivu) { + sisältö.endText(); + sisältö.close(); + PDPage uusiSivu = new PDPage(); + dokumentti.addPage(uusiSivu); + sisältö = new PDPageContentStream(dokumentti, uusiSivu); + sisältö.beginText(); + sisältö.setFont(fontti, fonttiKoko); + sisältö.setLeading(leading); + sisältö.newLineAtOffset(25,750); + riviLaskuri = 0; + } + //Ensimmäinen rivi + sisältö.showText(kuljetus.getNimi()); + int sarake1 = 150; + sisältö.newLineAtOffset(sarake1, 0); + sisältö.showText(kuljetus.getOsoite()); + int sarake2 = 230; + sisältö.newLineAtOffset(sarake2, 0); + sisältö.showText(kuljetus.getAvainTieto()); + + //Toinen rivi + sisältö.newLineAtOffset(-sarake1-sarake2, -15); + sisältö.showText("Sal: " + kuljetus.getSalaatit() + + " Pr: " + kuljetus.getPääruoat() + + " Jr: " + kuljetus.getJälkiruoat()); + sisältö.newLineAtOffset(sarake1, 0); + sisältö.showText(kuljetus.getRuokarajoite()); + sisältö.newLineAtOffset(sarake2, 0); + sisältö.showText(kuljetus.getLisätieto()); + + sisältö.newLineAtOffset(-sarake1-sarake2, -5); + sisältö.showText("________________________________________________________________________________"); + sisältö.newLineAtOffset(0, -20); + + riviLaskuri++; + } + sisältö.endText(); + sisältö.close(); + + PrinterJob tuloste = PrinterJob.getPrinterJob(); + tuloste.setPageable(new PDFPageable(dokumentti)); + if (tuloste.printDialog()) { + tuloste.print(); + + } + } catch (IOException | PrinterException e) { + SiirtoVirhe virhe = new SiirtoVirhe(e); + virhe.showAndWait(); + } + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/tulostajat/KuljetusRaporttiTulostaja.java b/src/main/java/fi/lpam/tulostajat/KuljetusRaporttiTulostaja.java new file mode 100644 index 0000000..f349272 --- /dev/null +++ b/src/main/java/fi/lpam/tulostajat/KuljetusRaporttiTulostaja.java @@ -0,0 +1,67 @@ +package fi.lpam.tulostajat; + +import fi.lpam.dataluokat.RaporttiRivi; + +import java.awt.print.PrinterJob; +import java.time.LocalDate; +import java.util.ArrayList; + +import fi.lpam.gui.virheDialogit.SiirtoVirhe; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.printing.PDFPageable; + +@SuppressWarnings("DuplicatedCode") +public class KuljetusRaporttiTulostaja extends Tulostaja { + public static void luoRaportti(ArrayList raporttiRivit, LocalDate alkuPvm, LocalDate loppuPvm) { + int rivitPerSivu = 44; + try (PDDocument dokumentti = new PDDocument()) { + PDPage sivu = new PDPage(); + dokumentti.addPage(sivu); + PDPageContentStream sisältö = new PDPageContentStream(dokumentti, sivu); + sisältö.beginText(); + + + sisältö.setFont(fontti, fonttiKoko); + sisältö.setLeading(leading); + sisältö.newLineAtOffset(25,750); + sisältö.showText("Raportti aikaväliltä " + alkuPvm + " - " + loppuPvm); + sisältö.newLineAtOffset(0, -25); + + int riviLaskuri = 2; + for (RaporttiRivi rivi : raporttiRivit) { + String[] teksti = rivi.toString().split("\n"); + for (String t : teksti) { + if (riviLaskuri % rivitPerSivu == 0) { + sisältö.endText(); + sisältö.close(); + PDPage uusiSivu = new PDPage(); + dokumentti.addPage(uusiSivu); + sisältö = new PDPageContentStream(dokumentti, uusiSivu); + sisältö.beginText(); + sisältö.setFont(fontti, fonttiKoko); + sisältö.setLeading(leading); + sisältö.newLineAtOffset(25,750); + } + sisältö.showText(t); + riviLaskuri++; + sisältö.newLine(); + } + sisältö.newLineAtOffset(0, -5); + } + sisältö.endText(); + sisältö.close(); + + PrinterJob tuloste = PrinterJob.getPrinterJob(); + tuloste.setPageable(new PDFPageable(dokumentti)); + if (tuloste.printDialog()) { + tuloste.print(); + } + } + catch (Exception e) { + SiirtoVirhe virhe = new SiirtoVirhe(e); + virhe.showAndWait(); + } + } +} \ No newline at end of file diff --git a/src/main/java/fi/lpam/tulostajat/Tulostaja.java b/src/main/java/fi/lpam/tulostajat/Tulostaja.java new file mode 100644 index 0000000..a8eb970 --- /dev/null +++ b/src/main/java/fi/lpam/tulostajat/Tulostaja.java @@ -0,0 +1,11 @@ +package fi.lpam.tulostajat; + +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; + +public abstract class Tulostaja { + static final PDFont fontti = new PDType1Font(Standard14Fonts.FontName.HELVETICA); + static final int fonttiKoko = 14; + static final float leading = 14.5f; +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 0000000..58b192b --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,14 @@ +module fi.lpam.ruokamanageri { + requires javafx.base; + requires javafx.graphics; + requires javafx.controls; + requires com.dlsc.gemsfx; + + requires java.sql; + requires java.desktop; + requires org.apache.pdfbox; + requires org.apache.commons.lang3; + + opens fi.lpam.dataluokat to javafx.base; + exports fi.lpam; +} \ No newline at end of file diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..672ea32 --- /dev/null +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 +Main-Class: fi.lpam.Main diff --git a/src/main/resources/fi/lpam/Kuljetuslaatikko-iconi.ico b/src/main/resources/fi/lpam/Kuljetuslaatikko-iconi.ico new file mode 100644 index 0000000..c41459c Binary files /dev/null and b/src/main/resources/fi/lpam/Kuljetuslaatikko-iconi.ico differ diff --git a/src/main/resources/fi/lpam/kuljetusruokalaatikko.jpg b/src/main/resources/fi/lpam/kuljetusruokalaatikko.jpg new file mode 100644 index 0000000..a3158fb Binary files /dev/null and b/src/main/resources/fi/lpam/kuljetusruokalaatikko.jpg differ diff --git a/src/main/resources/fi/lpam/tietokanta.png b/src/main/resources/fi/lpam/tietokanta.png new file mode 100644 index 0000000..546ecc8 Binary files /dev/null and b/src/main/resources/fi/lpam/tietokanta.png differ diff --git a/src/main/resources/fi/lpam/tietokanta.sql b/src/main/resources/fi/lpam/tietokanta.sql new file mode 100644 index 0000000..3c38a74 --- /dev/null +++ b/src/main/resources/fi/lpam/tietokanta.sql @@ -0,0 +1,39 @@ +create table if not exists asiakkaat ( + id INTEGER PRIMARY KEY, + nimi varchar(255) not null, + osoite varchar(255) not null, + maanantaiKpl int not null, + tiistaiKpl int not null, + keskiviikkoKpl int not null, + torstaiKpl int not null, + perjantaiKpl int not null, + salaatit int not null, + pääruoat int not null, + jälkiruoat int not null, + erityisruokavalio varchar(255), + avainTieto varchar(255), + lisätiedot text +); + +create table if not exists kierrokset ( + id INTEGER PRIMARY KEY, + kierrosNumero int not null, + asiakkaat text not null +); + +create table if not exists kuljetukset ( + id INTEGER PRIMARY KEY, + asiakasID int not null, + nimi varchar(255) not null, + kuljetusPäivämäärä DATE not null, + kuljetusKierros int not null, + salaatit int not null, + pääruoat int not null, + jälkiruoat int not null, + ruokarajoite varchar(255), + osoite varchar(255), + avainTieto varchar(255), + lisätieto varchar(255) +); + +create index if not exists idx_kuljetuspvm on kuljetukset(kuljetusPäivämäärä); \ No newline at end of file diff --git a/tietokanta.db b/tietokanta.db new file mode 100644 index 0000000..d8d5418 Binary files /dev/null and b/tietokanta.db differ