Compare commits

...

17 commits

Author SHA1 Message Date
dc71c8704b NOTICKET: Fix this
All checks were successful
Quality Check / Linting Check (push) Successful in 11s
Quality Check / Javadoc Check (push) Successful in 21s
2024-05-17 11:57:22 +02:00
a74b5863f9 NOTICKET: Fix MedicationDao ReadAll 2024-05-17 11:57:22 +02:00
dd369a5478 NOTICKET: Fix MedicationDao 2024-05-17 11:57:22 +02:00
66c676469e #18: WIP 2024-05-17 11:57:22 +02:00
d0dbea49e5 #23: Create Medication Modal 2024-05-17 11:57:22 +02:00
6908e8129b Merge pull request '#10 story/pfleger-modul-sperren-und-loschen-von-pflegern' (#37) from story/pfleger-modul-sperren-und-loschen-von-pflegern into main
All checks were successful
Quality Check / Linting Check (push) Successful in 19s
Javadoc Deploy / Javadoc (push) Successful in 34s
Quality Check / Javadoc Check (push) Successful in 31s
Reviewed-on: #37
Reviewed-by: Dominik Säume <dominik.saeume@hmmh.de>
2024-05-16 11:57:12 +00:00
Dorian Nemec
e583d825ec #10 JavaDoc ergänzt #2
All checks were successful
Quality Check / Linting Check (push) Successful in 16s
Quality Check / Linting Check (pull_request) Successful in 22s
Quality Check / Javadoc Check (push) Successful in 35s
Quality Check / Javadoc Check (pull_request) Successful in 33s
2024-05-16 13:54:32 +02:00
Dorian Nemec
d9e0aa2049 #10 dataSources.xml ergänzt
All checks were successful
Quality Check / Linting Check (push) Successful in 15s
Quality Check / Linting Check (pull_request) Successful in 21s
Quality Check / Javadoc Check (push) Successful in 35s
Quality Check / Javadoc Check (pull_request) Successful in 32s
2024-05-16 13:24:09 +02:00
Dorian Nemec
814f0a367b #10 toString korrigiert
All checks were successful
Quality Check / Linting Check (push) Successful in 15s
Quality Check / Linting Check (pull_request) Successful in 21s
Quality Check / Javadoc Check (push) Successful in 36s
Quality Check / Javadoc Check (pull_request) Successful in 34s
2024-05-16 13:17:08 +02:00
Dorian Nemec
505d9e3f5c #10 Javadoc Änderungen ergänzt
Some checks failed
Quality Check / Linting Check (push) Successful in 16s
Quality Check / Linting Check (pull_request) Successful in 20s
Quality Check / Javadoc Check (push) Failing after 22s
Quality Check / Javadoc Check (pull_request) Failing after 20s
2024-05-16 13:14:56 +02:00
Dorian Nemec
d982242718 #10 Javadoc addiert
All checks were successful
Quality Check / Linting Check (push) Successful in 16s
Quality Check / Linting Check (pull_request) Successful in 21s
Quality Check / Javadoc Check (push) Successful in 34s
Quality Check / Javadoc Check (pull_request) Successful in 32s
2024-05-16 11:58:49 +02:00
Dorian Nemec
b401bdd91b #10 Javadoc addiert
All checks were successful
Quality Check / Linting Check (push) Successful in 16s
Quality Check / Linting Check (pull_request) Successful in 21s
Quality Check / Javadoc Check (push) Successful in 37s
Quality Check / Javadoc Check (pull_request) Successful in 34s
2024-05-16 11:42:21 +02:00
d8de1e17fa
#10: Cleanup
All checks were successful
Quality Check / Linting Check (push) Successful in 17s
Quality Check / Linting Check (pull_request) Successful in 21s
Quality Check / Javadoc Check (push) Successful in 34s
Quality Check / Javadoc Check (pull_request) Successful in 32s
Signed-off-by: Dominik Säume <Dominik.Saeume@hmmh.de>
2024-05-16 10:37:55 +02:00
arminribic
353146cbd7 #10: Deletedate calculated & DeletreBurtton enabled/disabled
Some checks failed
Quality Check / Linting Check (push) Failing after 12s
Quality Check / Javadoc Check (push) Successful in 21s
Quality Check / Linting Check (pull_request) Failing after 12s
Quality Check / Javadoc Check (pull_request) Successful in 20s
2024-05-16 10:20:23 +02:00
arminribic
917aa8275f
#10: Add Base for Delete Date Functionality
All checks were successful
Quality Check / Linting Check (push) Successful in 12s
Quality Check / Javadoc Check (push) Successful in 21s
2024-05-15 12:08:48 +02:00
arminribic
453616c175
#10: Update Views to Reflect Locked and Active Nurses 2024-05-15 12:08:22 +02:00
arminribic
9353c9990e
#10: Modify Model, Dao and Fixtures 2024-05-15 12:04:25 +02:00
21 changed files with 875 additions and 49 deletions

Binary file not shown.

View file

@ -67,7 +67,6 @@ public class MedicationFixture implements Fixture<Medication> {
Ingredient warfarinnatrium = new Ingredient("Warfarinnatrium"); Ingredient warfarinnatrium = new Ingredient("Warfarinnatrium");
medications.add(new Medication( medications.add(new Medication(
1,
"Metformin", "Metformin",
"AstraZeneca", "AstraZeneca",
List.of( List.of(
@ -81,7 +80,6 @@ public class MedicationFixture implements Fixture<Medication> {
100 100
)); ));
medications.add(new Medication( medications.add(new Medication(
2,
"Lisinopril", "Lisinopril",
"Teva Pharmaceuticals", "Teva Pharmaceuticals",
List.of( List.of(
@ -95,7 +93,6 @@ public class MedicationFixture implements Fixture<Medication> {
150 150
)); ));
medications.add(new Medication( medications.add(new Medication(
3,
"Simvastatin", "Simvastatin",
"Mylan", "Mylan",
List.of( List.of(
@ -109,7 +106,6 @@ public class MedicationFixture implements Fixture<Medication> {
80 80
)); ));
medications.add(new Medication( medications.add(new Medication(
4,
"Enoxaparin", "Enoxaparin",
"Sanofi", "Sanofi",
List.of( List.of(
@ -122,7 +118,6 @@ public class MedicationFixture implements Fixture<Medication> {
120 120
)); ));
medications.add(new Medication( medications.add(new Medication(
5,
"Levothyroxin", "Levothyroxin",
"Sandoz", "Sandoz",
List.of( List.of(
@ -136,7 +131,6 @@ public class MedicationFixture implements Fixture<Medication> {
90 90
)); ));
medications.add(new Medication( medications.add(new Medication(
6,
"Warfarin", "Warfarin",
"Apotex Inc.", "Apotex Inc.",
List.of( List.of(

View file

@ -46,6 +46,14 @@ public class NurseFixture implements Fixture<Nurse> {
"Armout", "Armout",
"9876543210" "9876543210"
)); ));
nurses.add(new Nurse(
"Björnd",
"Heideberger",
"69420",
true
));
NurseDao dao = DaoFactory.getInstance().createNurseDAO(); NurseDao dao = DaoFactory.getInstance().createNurseDAO();
for (Nurse nurse : nurses) { for (Nurse nurse : nurses) {
dao.create(nurse); dao.create(nurse);

View file

@ -1,8 +1,10 @@
package de.hitec.nhplus.main; package de.hitec.nhplus.main;
import de.hitec.nhplus.Main; import de.hitec.nhplus.Main;
import de.hitec.nhplus.nurse.Nurse;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.control.SelectionModel;
import javafx.scene.control.Tab; import javafx.scene.control.Tab;
import javafx.scene.control.TabPane; import javafx.scene.control.TabPane;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
@ -16,6 +18,8 @@ import java.util.Objects;
* *
* @author Bernd Heidemann * @author Bernd Heidemann
* @author Dominik Säume * @author Dominik Säume
* @author Armin Ribic
* @author Dorian Nemec
*/ */
public class MainWindowController { public class MainWindowController {
@FXML @FXML
@ -29,14 +33,25 @@ public class MainWindowController {
@FXML @FXML
private Tab treatmentTab; private Tab treatmentTab;
@FXML @FXML
private AnchorPane nursePage;
@FXML
private Tab nurseTab; private Tab nurseTab;
@FXML @FXML
private TabPane nurseTabPane;
@FXML
private AnchorPane activeNursePage;
@FXML
private Tab activeNurseTab;
@FXML
private AnchorPane lockedNursePage;
@FXML
private Tab lockedNurseTab;
@FXML
private AnchorPane medicationPage; private AnchorPane medicationPage;
@FXML @FXML
private Tab medicationTab; private Tab medicationTab;
/**
* Initialization method that is called after the binding of all the fields.
*/
@FXML @FXML
public void initialize() { public void initialize() {
loadPatientPage(); loadPatientPage();
@ -46,6 +61,12 @@ public class MainWindowController {
treatmentTab.setOnSelectionChanged(event -> loadTreatmentsPage()); treatmentTab.setOnSelectionChanged(event -> loadTreatmentsPage());
nurseTab.setOnSelectionChanged(event -> loadNursePage()); nurseTab.setOnSelectionChanged(event -> loadNursePage());
medicationTab.setOnSelectionChanged(event -> loadMedicationPage()); medicationTab.setOnSelectionChanged(event -> loadMedicationPage());
nurseTabPane.getSelectionModel().select(activeNurseTab);
activeNurseTab.setOnSelectionChanged(event -> loadActiveNursePage());
lockedNurseTab.setOnSelectionChanged(event -> loadLockedNursePage());
} }
/** /**
@ -67,7 +88,7 @@ public class MainWindowController {
} }
/** /**
* Loads the treatment page into its tab. * Loads the {@link } page into its tab.
*/ */
private void loadTreatmentsPage() { private void loadTreatmentsPage() {
try { try {
@ -88,15 +109,47 @@ public class MainWindowController {
* Loads the nurse page into its tab. * Loads the nurse page into its tab.
*/ */
private void loadNursePage() { private void loadNursePage() {
SelectionModel<Tab> selectionModel = nurseTabPane.getSelectionModel();
Tab selectedTab = selectionModel.getSelectedItem();
if(selectedTab == activeNurseTab){
loadActiveNursePage();
}
if(selectedTab == lockedNurseTab){
loadLockedNursePage();
}
}
/**
* Loads the active {@link Nurse} page into its tab.
*/
private void loadActiveNursePage() {
try { try {
BorderPane nursePane = FXMLLoader.load( BorderPane activeNursePane = FXMLLoader.load(
Objects.requireNonNull(Main.class.getResource("/de/hitec/nhplus/nurse/AllNurseView.fxml")) Objects.requireNonNull(Main.class.getResource("/de/hitec/nhplus/nurse/AllNurseView.fxml"))
); );
nursePage.getChildren().setAll(nursePane); activeNursePage.getChildren().setAll(activeNursePane);
AnchorPane.setTopAnchor(nursePane, 0d); AnchorPane.setTopAnchor(activeNursePane, 0d);
AnchorPane.setBottomAnchor(nursePane, 0d); AnchorPane.setBottomAnchor(activeNursePane, 0d);
AnchorPane.setLeftAnchor(nursePane, 0d); AnchorPane.setLeftAnchor(activeNursePane, 0d);
AnchorPane.setRightAnchor(nursePane, 0d); AnchorPane.setRightAnchor(activeNursePane, 0d);
} catch (IOException exception) {
exception.printStackTrace();
}
}
/**
* Loads the locked {@link Nurse} page into its tab.
*/
private void loadLockedNursePage() {
try {
BorderPane lockedNursePane = FXMLLoader.load(
Objects.requireNonNull(Main.class.getResource("/de/hitec/nhplus/nurse/LockedNurseView.fxml"))
);
lockedNursePage.getChildren().setAll(lockedNursePane);
AnchorPane.setTopAnchor(lockedNursePane, 0d);
AnchorPane.setBottomAnchor(lockedNursePane, 0d);
AnchorPane.setLeftAnchor(lockedNursePane, 0d);
AnchorPane.setRightAnchor(lockedNursePane, 0d);
} catch (IOException exception) { } catch (IOException exception) {
exception.printStackTrace(); exception.printStackTrace();
} }

View file

@ -1,17 +1,24 @@
package de.hitec.nhplus.medication; package de.hitec.nhplus.medication;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.stream.Collectors;
import de.hitec.nhplus.Main;
import de.hitec.nhplus.datastorage.DaoFactory; import de.hitec.nhplus.datastorage.DaoFactory;
import de.hitec.nhplus.medication.database.MedicationDao; import de.hitec.nhplus.medication.database.MedicationDao;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView; import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import java.sql.SQLException; import javafx.stage.Stage;
import java.util.stream.Collectors;
/** /**
* The controller for viewing all {@link Medication}s. * The controller for viewing all {@link Medication}s.
@ -50,14 +57,20 @@ public class AllMedicationController {
this.columnName.setCellValueFactory(new PropertyValueFactory<>("name")); this.columnName.setCellValueFactory(new PropertyValueFactory<>("name"));
this.columnManufacturer.setCellValueFactory(new PropertyValueFactory<>("manufacturer")); this.columnManufacturer.setCellValueFactory(new PropertyValueFactory<>("manufacturer"));
this.columnIngredient.setCellValueFactory( this.columnIngredient.setCellValueFactory(
cellData -> new SimpleStringProperty( cellData -> {
cellData Medication medication = cellData.getValue();
.getValue() List<Ingredient> ingredients = medication.getIngredients();
.getIngredients() if(ingredients.isEmpty()){
.stream() return new SimpleStringProperty("");
.map(ingredient -> ingredient.getName()) }
.collect(Collectors.joining("\n"))
)); return new SimpleStringProperty(
ingredients
.stream()
.map(ingredient -> ingredient.getName())
.collect(Collectors.joining("\n"))
);
});
this.columnPossibleSideEffects.setCellValueFactory(new PropertyValueFactory<>("possibleSideEffects")); this.columnPossibleSideEffects.setCellValueFactory(new PropertyValueFactory<>("possibleSideEffects"));
this.columnAdministrationMethod.setCellValueFactory(new PropertyValueFactory<>("administrationMethod")); this.columnAdministrationMethod.setCellValueFactory(new PropertyValueFactory<>("administrationMethod"));
this.columnCurrentStock.setCellValueFactory(new PropertyValueFactory<>("currentStock")); this.columnCurrentStock.setCellValueFactory(new PropertyValueFactory<>("currentStock"));
@ -76,4 +89,36 @@ public class AllMedicationController {
exception.printStackTrace(); exception.printStackTrace();
} }
} }
public void createMedication(Medication medication) {
dao = DaoFactory.getInstance().createMedicationDAO();
try {
dao.create(medication);
} catch (SQLException exception) {
exception.printStackTrace();
}
}
@FXML
public void handleNewMedication() {
try {
FXMLLoader loader = new FXMLLoader(
Main.class.getResource("/de/hitec/nhplus/medication/MedicationModal.fxml")
);
BorderPane pane = loader.load();
Scene scene = new Scene(pane);
Stage stage = new Stage();
MedicationModalController controller = loader.getController();
controller.initialize(stage, this, null);
stage.setScene(scene);
stage.setTitle("NHPlus - Neues Medikament");
stage.setResizable(true);
stage.setAlwaysOnTop(true);
stage.showAndWait();
} catch (IOException exception) {
exception.printStackTrace();
}
}
} }

View file

@ -17,7 +17,7 @@ public class Ingredient {
} }
public String getName() { public String getName() {
return name.get(); return name.getValue();
} }
public SimpleStringProperty nameProperty() { public SimpleStringProperty nameProperty() {

View file

@ -0,0 +1,92 @@
package de.hitec.nhplus.medication;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.text.Text;
public class IngredientListCell extends ListCell<Ingredient> {
private final TextField textField;
private final Button deleteButton;
private static final double BUILTIN_BORDER_WIDTH = 1;
private static final double CELL_SPACING = 4;
private static final double CELL_PADDING = 4;
private static final double BUTTON_PADDING_X = 8;
private static final double BUTTON_PADDING_Y = 4;
private final double totalSpacing;
public IngredientListCell() {
this.setPadding(new Insets(CELL_PADDING));
textField = new TextField();
textField.setPromptText("Inhaltsstoff");
textField.textProperty().addListener(this::onTextFieldUpdate);
deleteButton = new Button("-");
deleteButton.setPadding(new Insets(
BUTTON_PADDING_Y,
BUTTON_PADDING_X,
BUTTON_PADDING_Y,
BUTTON_PADDING_X
));
deleteButton.setOnAction(event -> getListView().getItems().remove(this));
// Calculate Delete Button Width
Text textNode = new Text(deleteButton.getText());
textNode.setFont(deleteButton.getFont());
double calculatedDeleteButtonWidth = textNode.getLayoutBounds().getWidth() + BUTTON_PADDING_X * 2;
totalSpacing = BUILTIN_BORDER_WIDTH * 2 // List View
+ CELL_PADDING * 2
+ CELL_SPACING
+ calculatedDeleteButtonWidth;
}
@Override
protected void updateItem(Ingredient item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
} else {
String oldText = textField.getText();
String newText = oldText != null && !oldText.isEmpty() ? oldText : item.getName();
textField.setText(newText);
BorderPane cellPane = new BorderPane();
cellPane.setCenter(textField);
cellPane.setRight(deleteButton);
BorderPane.setMargin(deleteButton, new Insets(0, 0, 0, CELL_SPACING));
setGraphic(cellPane);
}
}
private void onTextFieldUpdate(ObservableValue<? extends String> observable, String oldValue, String newValue) {
getItem().setName(textField.getText());
textField.setMinWidth(getTextFieldRequiredWidth(textField));
ListView<Ingredient> listView = getListView();
double max = listView.lookupAll("*")
.stream()
.filter(node -> node instanceof IngredientListCell)
.mapToDouble(node -> getTextFieldRequiredWidth(((IngredientListCell) node).textField))
.max()
.orElse(0);
getListView().setMinWidth(max + totalSpacing);
}
private double getTextFieldRequiredWidth(TextField textField) {
Text textNode = new Text(textField.getText());
textNode.setFont(textField.getFont());
return textNode.getLayoutBounds().getWidth()
+ textField.getPadding().getLeft()
+ textField.getPadding().getRight()
+ BUILTIN_BORDER_WIDTH * 2;
}
}

View file

@ -0,0 +1,118 @@
package de.hitec.nhplus.medication;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import static de.hitec.nhplus.utils.Validator.*;
public class MedicationModalController {
@FXML
public ListView<Ingredient> listViewIngredients;
@FXML
public TextField textFieldName;
@FXML
public TextField textFieldManufacturer;
@FXML
public TextField textFieldAdministrationMethod;
@FXML
public TextField textFieldCurrentStock;
@FXML
public TextArea textAreaPossibleSideEffects;
@FXML
public Button buttonSave;
private Stage stage;
private Medication medication;
private final ObservableList<Ingredient> ingredients = FXCollections.observableArrayList();
private AllMedicationController controller;
@FXML
public void initialize(Stage stage, AllMedicationController controller, Medication medication) {
this.stage = stage;
this.controller=controller;
if( medication != null){
this.medication = medication;
}else {
this.medication = new Medication(
"",
"",
new ArrayList<>(),
"",
"",
0
);
this.buttonSave.setDisable(true);
}
listViewIngredients.setCellFactory(cellData -> new IngredientListCell());
listViewIngredients.setItems(ingredients);
showData();
ChangeListener<String> inputMedicationValidationListener = (observableValue, oldText, newText) -> {
boolean isValid = isValidMedicationName(textFieldName.getText())
&& isValidMedicationManufacturer(textFieldManufacturer.getText())
&& isValidMedicationAdministrationMethod(textFieldAdministrationMethod.getText())
&& isValidStock(textFieldCurrentStock.getText());
this.buttonSave.setDisable(!isValid);
};
this.textFieldName.textProperty().addListener(inputMedicationValidationListener);
this.textFieldManufacturer.textProperty().addListener(inputMedicationValidationListener);
this.textFieldAdministrationMethod.textProperty().addListener(inputMedicationValidationListener);
this.textFieldCurrentStock.textProperty().addListener(inputMedicationValidationListener);
}
private void showData(){
ingredients.setAll(medication.getIngredients());
textFieldName.setText(medication.getName());
textFieldManufacturer.setText(medication.getManufacturer());
textFieldAdministrationMethod.setText(medication.getAdministrationMethod());
textFieldCurrentStock.setText(String.valueOf(medication.getCurrentStock()));
textAreaPossibleSideEffects.setText(medication.getPossibleSideEffects());
}
@FXML
public void handleSave() {
this.medication.setName(textFieldName.getText());
this.medication.setManufacturer(textFieldManufacturer.getText());
this.medication.setAdministrationMethod(textFieldAdministrationMethod.getText());
this.medication.setCurrentStock(Integer.parseInt(textFieldCurrentStock.getText()));
this.medication.setPossibleSideEffects(textAreaPossibleSideEffects.getText());
this.medication.setIngredients(ingredients
.stream()
.map(Ingredient::getName)
.distinct()
.filter(Predicate.not(String::isEmpty))
.map(Ingredient::new)
.toList()
);
controller.createMedication(medication);
controller.readAllAndShowInTableView();
stage.close();
}
@FXML
public void handleCancel() {
stage.close();
}
@FXML
public void handleAddIngredient() {
ingredients.add(new Ingredient(""));
}
}

View file

@ -29,6 +29,7 @@ public class MedicationDao implements Dao<Medication> {
@Override @Override
public void create(Medication medication) throws SQLException { public void create(Medication medication) throws SQLException {
connection.setAutoCommit(false); //Switch to Manual Commit, to do an SQL Transaction
final String medicationSQL = """ final String medicationSQL = """
INSERT INTO medication INSERT INTO medication
(name, manufacturer, possibleSideEffects, administrationMethod, currentStock) (name, manufacturer, possibleSideEffects, administrationMethod, currentStock)
@ -42,6 +43,15 @@ public class MedicationDao implements Dao<Medication> {
medicationStatement.setInt(5, medication.getCurrentStock()); medicationStatement.setInt(5, medication.getCurrentStock());
medicationStatement.execute(); medicationStatement.execute();
ResultSet generatedKeys = connection.createStatement().executeQuery("SELECT last_insert_rowid()");
connection.commit(); //Finish SQL Transaction
connection.setAutoCommit(true); //Switch back Mode
if (!generatedKeys.next()) {
return;
}
int newId = generatedKeys.getInt(1);
final String ingredientSQL = """ final String ingredientSQL = """
INSERT INTO medication_ingredient INSERT INTO medication_ingredient
(id, name) (id, name)
@ -49,7 +59,7 @@ public class MedicationDao implements Dao<Medication> {
"""; """;
for (Ingredient ingredient : medication.getIngredients()) { for (Ingredient ingredient : medication.getIngredients()) {
PreparedStatement ingredientStatement = this.connection.prepareStatement(ingredientSQL); PreparedStatement ingredientStatement = this.connection.prepareStatement(ingredientSQL);
ingredientStatement.setInt(1, medication.getId()); ingredientStatement.setInt(1, newId);
ingredientStatement.setString(2, ingredient.getName()); ingredientStatement.setString(2, ingredient.getName());
ingredientStatement.execute(); ingredientStatement.execute();
} }
@ -90,20 +100,26 @@ public class MedicationDao implements Dao<Medication> {
result.getInt(1), result.getInt(1),
result.getString(2), result.getString(2),
result.getString(3), result.getString(3),
List.of(), new ArrayList<>(),
result.getString(4), result.getString(4),
result.getString(5), result.getString(5),
result.getInt(6) result.getInt(6)
); );
medications.add(medication); medications.add(medication);
lastMedicationId = currentMedicationId;
continue;
} }
List<Ingredient> ingredients = ingredientMap.computeIfAbsent(currentMedicationId, k -> new ArrayList<>()); List<Ingredient> ingredients = ingredientMap.computeIfAbsent(currentMedicationId, k -> new ArrayList<>());
ingredients.add(new Ingredient(result.getString(7))); String ingredientName = result.getString(7);
if(ingredientName == null){
continue;
}
ingredients.add(new Ingredient(ingredientName));
lastMedicationId = currentMedicationId; lastMedicationId = currentMedicationId;
} }
for (Medication medication : medications) { for (Medication medication : medications) {
List<Ingredient> ingredients = ingredientMap.get(medication.getId());
if(ingredients.isEmpty()){
continue;
}
medication.setIngredients(ingredientMap.get(medication.getId())); medication.setIngredients(ingredientMap.get(medication.getId()));
} }

View file

@ -33,6 +33,8 @@ public class AllNurseController {
@FXML @FXML
public Button buttonAdd; public Button buttonAdd;
@FXML @FXML
public Button buttonLock;
@FXML
private TableView<Nurse> tableView; private TableView<Nurse> tableView;
@FXML @FXML
private TableColumn<Nurse, Long> columnId; private TableColumn<Nurse, Long> columnId;
@ -89,7 +91,7 @@ public class AllNurseController {
this.nurses.clear(); this.nurses.clear();
this.dao = DaoFactory.getInstance().createNurseDAO(); this.dao = DaoFactory.getInstance().createNurseDAO();
try { try {
this.nurses.setAll(this.dao.readAll()); this.nurses.setAll(this.dao.readAllActive());
}catch (SQLException exception){ }catch (SQLException exception){
exception.printStackTrace(); exception.printStackTrace();
} }
@ -119,5 +121,20 @@ public class AllNurseController {
clearTextfields(); clearTextfields();
} }
@FXML
public void handleLock(){
Nurse selectedItem = this.tableView.getSelectionModel().getSelectedItem();
if (selectedItem == null){
return;
}
try {
selectedItem.setLocked(true);
this.dao.update(selectedItem);
}catch (SQLException exception){
exception.printStackTrace();
}
readAllAndShowInTableView();
}
} }

View file

@ -0,0 +1,136 @@
package de.hitec.nhplus.nurse;
import de.hitec.nhplus.datastorage.DaoFactory;
import de.hitec.nhplus.nurse.database.NurseDao;
import de.hitec.nhplus.treatment.Treatment;
import de.hitec.nhplus.treatment.database.TreatmentDao;
import de.hitec.nhplus.utils.DateConverter;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Controller for all locked nurses.
* @author Armin Ribic
* @author Dorian Nemec
*/
public class LockedNurseController {
@FXML
public Button buttonDelete;
@FXML
private Button buttonUnlock;
@FXML
public TableView<Nurse> tableView;
@FXML
public TableColumn<Nurse, Long> columnId;
@FXML
public TableColumn<Nurse, String> columnFirstName;
@FXML
public TableColumn<Nurse, String> columnSurName;
@FXML
public TableColumn<Nurse, String> columnPhoneNumber;
@FXML
public TableColumn<Nurse, String> columnDeleteDate;
private final ObservableList<Nurse> nurses = FXCollections.observableArrayList();
private final Map<Nurse, List<Treatment>> treatmentsPerNurse = new HashMap<>();
private NurseDao dao;
private TreatmentDao treatmentDao;
/**
* This method allows initializing a {@link LockedNurseController} object
* that is called after the binding of all the fields.
*/
public void initialize() {
this.readAllAndShowInTableView();
this.columnId.setCellValueFactory(new PropertyValueFactory<>("id"));
this.columnFirstName.setCellValueFactory(new PropertyValueFactory<>("firstName"));
this.columnSurName.setCellValueFactory(new PropertyValueFactory<>("surName"));
this.columnPhoneNumber.setCellValueFactory(new PropertyValueFactory<>("phoneNumber"));
this.columnDeleteDate.setCellValueFactory(cellData -> new SimpleStringProperty(
DateConverter.convertLocalDateToString(cellData.getValue().calculateDeleteDate()))
);
buttonDelete.setDisable(true);
this.tableView.setItems(this.nurses);
}
/**
* Reads all locked {@link Nurse} data and shows it in the table.
*/
private void readAllAndShowInTableView() {
this.nurses.clear();
this.treatmentsPerNurse.clear();
this.dao = DaoFactory.getInstance().createNurseDAO();
this.treatmentDao = DaoFactory.getInstance().createTreatmentDao();
try {
this.nurses.addAll(this.dao.readAllLocked());
this.nurses.forEach(
nurse -> {
try {
this.treatmentsPerNurse.put(nurse, this.treatmentDao.readTreatmentsByNurse(nurse.getId()));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
);
} catch (SQLException exception) {
exception.printStackTrace();
}
}
@FXML
public void handleDelete() {
Nurse selectedItem = this.tableView.getSelectionModel().getSelectedItem();
if (selectedItem == null) {
return;
}
try {
this.dao.delete(selectedItem.getId());
} catch (SQLException exception) {
exception.printStackTrace();
}
readAllAndShowInTableView();
}
@FXML
public void handleMouseClick() {
Nurse nurse = tableView.getSelectionModel().getSelectedItem();
boolean canBeDeleted = nurse.calculateDeleteDate().isBefore(LocalDate.now());
buttonDelete.setDisable(!canBeDeleted);
}
@FXML
public void unlockNurse() {
Nurse selectedItem = this.tableView.getSelectionModel().getSelectedItem();
if (selectedItem == null) {
return;
}
try {
selectedItem.setLocked(false);
this.dao.update(selectedItem);
} catch (SQLException exception) {
exception.printStackTrace();
}
readAllAndShowInTableView();
}
}

View file

@ -1,26 +1,36 @@
package de.hitec.nhplus.nurse; package de.hitec.nhplus.nurse;
import de.hitec.nhplus.datastorage.DaoFactory;
import de.hitec.nhplus.main.Person; import de.hitec.nhplus.main.Person;
import de.hitec.nhplus.treatment.Treatment;
import de.hitec.nhplus.utils.DateConverter;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.StringJoiner; import java.util.StringJoiner;
/** /**
* The model for a {@link Nurse}. * The model for a {@link Nurse}.
* *
* @author Dominik Säume * @author Dominik Säume
* @author Armin Ribic
* @author Dorian Nemec
*/ */
public class Nurse extends Person { public class Nurse extends Person {
private SimpleIntegerProperty id; private SimpleIntegerProperty id;
private final SimpleStringProperty phoneNumber; private final SimpleStringProperty phoneNumber;
private final SimpleBooleanProperty locked;
/** /**
* This constructor allows instantiating a {@link Nurse} object, * This constructor allows instantiating a {@link Nurse} object,
* before it is stored in the database, by omitting the {@link Nurse#id ID} value. * before it is stored in the database, by omitting the {@link Nurse#id ID} value.
* * It includes the locked Property.
* @implSpec Instances created with this constructor can be directly passed to * @implSpec This was added for usage in the {@link de.hitec.nhplus.fixtures.NurseFixture NurseFixture}.
* {@link de.hitec.nhplus.nurse.database.NurseDao#create NurseDao.create}.
*/ */
public Nurse( public Nurse(
String firstName, String firstName,
@ -29,6 +39,22 @@ public class Nurse extends Person {
) { ) {
super(firstName, surName); super(firstName, surName);
this.phoneNumber = new SimpleStringProperty(phoneNumber); this.phoneNumber = new SimpleStringProperty(phoneNumber);
this.locked = new SimpleBooleanProperty(false);
}
/**
* This constructor allows instantiating a {@link Nurse} object with
* specifying if the nurse is locked or not.
*/
public Nurse(
String firstName,
String surName,
String phoneNumber,
Boolean isLocked
) {
super(firstName, surName);
this.phoneNumber = new SimpleStringProperty(phoneNumber);
this.locked = new SimpleBooleanProperty(isLocked);
} }
/** /**
@ -38,11 +64,38 @@ public class Nurse extends Person {
int id, int id,
String firstName, String firstName,
String surName, String surName,
String phoneNumber String phoneNumber,
Boolean isLocked
) { ) {
super(firstName, surName); super(firstName, surName);
this.id = new SimpleIntegerProperty(id); this.id = new SimpleIntegerProperty(id);
this.phoneNumber = new SimpleStringProperty(phoneNumber); this.phoneNumber = new SimpleStringProperty(phoneNumber);
this.locked = new SimpleBooleanProperty(isLocked);
}
/**
* Calculates the date when the {@link Nurse} can be deleted.
*/
public LocalDate calculateDeleteDate() {
List<Treatment> treatments;
try {
treatments = DaoFactory.getInstance().createTreatmentDao().readTreatmentsByNurse(this.getId());
}catch (SQLException exception){
treatments = null;
}
if(treatments == null){
return LocalDate.now().plusDays(1);
}
LocalDate newestDate = LocalDate.of(1980, 1, 1);
for (Treatment treatment : treatments) {
LocalDate date = DateConverter.convertStringToLocalDate(treatment.getDate());
if (date.isAfter(newestDate)) {
newestDate = date;
}
}
return newestDate.plusYears(10);
} }
public void setPhoneNumber(String phoneNumber) { public void setPhoneNumber(String phoneNumber) {
@ -65,6 +118,19 @@ public class Nurse extends Person {
return phoneNumber; return phoneNumber;
} }
public boolean isLocked() {
return locked.get();
}
public SimpleBooleanProperty lockedProperty() {
return locked;
}
public void setLocked(boolean locked) {
this.locked.set(locked);
}
@Override @Override
public String toString() { public String toString() {
return new StringJoiner(System.lineSeparator()) return new StringJoiner(System.lineSeparator())
@ -73,6 +139,7 @@ public class Nurse extends Person {
.add("FirstName: " + this.getFirstName()) .add("FirstName: " + this.getFirstName())
.add("SurName: " + this.getSurName()) .add("SurName: " + this.getSurName())
.add("PhoneNumber: " + this.getPhoneNumber()) .add("PhoneNumber: " + this.getPhoneNumber())
.add("IsLocked: " + this.isLocked())
.toString(); .toString();
} }

View file

@ -17,6 +17,7 @@ import java.util.List;
* @author Dominik Säume * @author Dominik Säume
*/ */
public class NurseDao extends DaoImp<Nurse> { public class NurseDao extends DaoImp<Nurse> {
public NurseDao(Connection connection) { public NurseDao(Connection connection) {
super(connection); super(connection);
} }
@ -25,13 +26,14 @@ public class NurseDao extends DaoImp<Nurse> {
protected PreparedStatement getCreateStatement(Nurse nurse) throws SQLException { protected PreparedStatement getCreateStatement(Nurse nurse) throws SQLException {
final String SQL = """ final String SQL = """
INSERT INTO nurse INSERT INTO nurse
(firstName, surName, phoneNumber) (firstName, surName, phoneNumber, isLocked)
VALUES (?, ?, ?) VALUES (?, ?, ?, ?)
"""; """;
PreparedStatement statement = this.connection.prepareStatement(SQL); PreparedStatement statement = this.connection.prepareStatement(SQL);
statement.setString(1, nurse.getFirstName()); statement.setString(1, nurse.getFirstName());
statement.setString(2, nurse.getSurName()); statement.setString(2, nurse.getSurName());
statement.setString(3, nurse.getPhoneNumber()); statement.setString(3, nurse.getPhoneNumber());
statement.setBoolean(4, nurse.isLocked());
return statement; return statement;
} }
@ -49,7 +51,8 @@ public class NurseDao extends DaoImp<Nurse> {
result.getInt(1), result.getInt(1),
result.getString(2), result.getString(2),
result.getString(3), result.getString(3),
result.getString(4) result.getString(4),
result.getBoolean(5)
); );
} }
@ -58,7 +61,6 @@ public class NurseDao extends DaoImp<Nurse> {
final String SQL = "SELECT * FROM nurse"; final String SQL = "SELECT * FROM nurse";
return this.connection.prepareStatement(SQL); return this.connection.prepareStatement(SQL);
} }
@Override @Override
protected List<Nurse> getListFromResultSet(ResultSet result) throws SQLException { protected List<Nurse> getListFromResultSet(ResultSet result) throws SQLException {
ArrayList<Nurse> list = new ArrayList<>(); ArrayList<Nurse> list = new ArrayList<>();
@ -68,20 +70,38 @@ public class NurseDao extends DaoImp<Nurse> {
return list; return list;
} }
@Override /**
* Read all database entries of active {@link Nurse}s into a {@link List} of model instances.
*/
public List<Nurse> readAllActive() throws SQLException {
final String SQL = "SELECT * FROM nurse WHERE isLocked=false";
return getListFromResultSet(this.connection.prepareStatement(SQL).executeQuery());
}
/**
* Read all database entries of locked {@link Nurse}s into a {@link List} of model instances.
*/
public List<Nurse> readAllLocked() throws SQLException {
final String SQL = "SELECT * FROM nurse WHERE isLocked=true";
return getListFromResultSet(this.connection.prepareStatement(SQL).executeQuery());
}
@Override
protected PreparedStatement getUpdateStatement(Nurse nurse) throws SQLException { protected PreparedStatement getUpdateStatement(Nurse nurse) throws SQLException {
final String SQL = """ final String SQL = """
UPDATE nurse SET UPDATE nurse SET
firstName = ?, firstName = ?,
surName = ?, surName = ?,
phoneNumber = ? phoneNumber = ?,
isLocked = ?
WHERE id = ? WHERE id = ?
"""; """;
PreparedStatement statement = this.connection.prepareStatement(SQL); PreparedStatement statement = this.connection.prepareStatement(SQL);
statement.setString(1, nurse.getFirstName()); statement.setString(1, nurse.getFirstName());
statement.setString(2, nurse.getSurName()); statement.setString(2, nurse.getSurName());
statement.setString(3, nurse.getPhoneNumber()); statement.setString(3, nurse.getPhoneNumber());
statement.setInt(4, nurse.getId()); statement.setBoolean(4, nurse.isLocked());
statement.setInt(5, nurse.getId());
return statement; return statement;
} }
@ -92,4 +112,6 @@ public class NurseDao extends DaoImp<Nurse> {
statement.setInt(1, id); statement.setInt(1, id);
return statement; return statement;
} }
} }

View file

@ -148,4 +148,28 @@ public class Validator {
public static boolean isValidRoomNumber(String text) { public static boolean isValidRoomNumber(String text) {
return !text.isBlank(); return !text.isBlank();
} }
public static boolean isValidMedicationName(String text) {
return !text.isBlank();
}
public static boolean isValidMedicationManufacturer(String text) {
return !text.isBlank();
}
public static boolean isValidMedicationAdministrationMethod(String text) {
return !text.isBlank();
}
public static boolean isValidStock(String text) {
if (text.isBlank()) {
return false;
}
try {
int stock = Integer.parseInt(text);
return stock >= 0;
} catch (Exception exception) {
return false;
}
}
} }

View file

@ -16,7 +16,14 @@
<AnchorPane fx:id="treatmentPage"/> <AnchorPane fx:id="treatmentPage"/>
</Tab> </Tab>
<Tab fx:id="nurseTab" text="Pfleger"> <Tab fx:id="nurseTab" text="Pfleger">
<AnchorPane fx:id="nursePage"/> <TabPane fx:id="nurseTabPane" tabClosingPolicy="UNAVAILABLE">
<Tab fx:id="activeNurseTab" text="Pfleger">
<AnchorPane fx:id="activeNursePage"/>
</Tab>
<Tab fx:id="lockedNurseTab" text="Gesperrte Pfleger">
<AnchorPane fx:id="lockedNursePage"/>
</Tab>
</TabPane>
</Tab> </Tab>
<Tab fx:id="medicationTab" text="Medikamente"> <Tab fx:id="medicationTab" text="Medikamente">
<AnchorPane fx:id="medicationPage"/> <AnchorPane fx:id="medicationPage"/>

View file

@ -66,6 +66,7 @@
fx:id="buttonAdd" fx:id="buttonAdd"
mnemonicParsing="false" mnemonicParsing="false"
prefWidth="90.0" prefWidth="90.0"
onAction="#handleNewMedication"
text="Hinzufügen" text="Hinzufügen"
/> />
<Button <Button

View file

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane
xmlns="http://javafx.com/javafx/17.0.2-ea"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="de.hitec.nhplus.medication.MedicationModalController"
>
<padding>
<Insets top="8" left="8" bottom="8" right="8"/>
</padding>
<top>
<GridPane hgap="8.0">
<columnConstraints>
<ColumnConstraints hgrow="NEVER"/>
<ColumnConstraints hgrow="ALWAYS"/>
<ColumnConstraints hgrow="NEVER"/>
<ColumnConstraints hgrow="NEVER"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER"/>
</rowConstraints>
<!-- Row 0-->
<Label
GridPane.rowIndex="0"
GridPane.columnIndex="0"
text="Name:"
/>
<TextField
fx:id="textFieldName"
GridPane.rowIndex="0"
GridPane.columnIndex="1"
/>
<Label
GridPane.rowIndex="0"
GridPane.columnIndex="3"
text="Hersteller:"
/>
<TextField
fx:id="textFieldManufacturer"
GridPane.rowIndex="0"
GridPane.columnIndex="4"
/>
<!-- Row 1 -->
<Label
GridPane.rowIndex="1"
GridPane.columnIndex="0"
text="Verabreichungsmethode:"
/>
<TextField
fx:id="textFieldAdministrationMethod"
GridPane.rowIndex="1"
GridPane.columnIndex="1"
/>
<Label
GridPane.rowIndex="1"
GridPane.columnIndex="3"
text="Lagerbestand:"
/>
<TextField
fx:id="textFieldCurrentStock"
GridPane.rowIndex="1"
GridPane.columnIndex="4"
/>
</GridPane>
</top>
<center>
<BorderPane>
<padding>
<Insets top="8" bottom="8"/>
</padding>
<left>
<BorderPane>
<BorderPane.margin>
<Insets right="8"/>
</BorderPane.margin>
<top>
<Label text="Inhaltsstoffe:"/>
</top>
<center>
<ListView fx:id="listViewIngredients" minWidth="200">
<BorderPane.margin>
<Insets top="8"/>
</BorderPane.margin>
</ListView>
</center>
<bottom>
<AnchorPane>
<BorderPane.margin>
<Insets top="8"/>
</BorderPane.margin>
<Button
onAction="#handleAddIngredient"
text="+"
AnchorPane.leftAnchor="0"
AnchorPane.rightAnchor="0"
/>
</AnchorPane>
</bottom>
</BorderPane>
</left>
<center>
<BorderPane>
<top>
<Label text="Nebenwirkungen"/>
</top>
<center>
<TextArea fx:id="textAreaPossibleSideEffects"/>
</center>
</BorderPane>
</center>
</BorderPane>
</center>
<bottom>
<BorderPane>
<right>
<HBox spacing="8.0">
<Button
fx:id="buttonSave"
prefWidth="90"
mnemonicParsing="false"
onAction="#handleSave"
text="Speichern"
/>
<Button
prefWidth="90"
mnemonicParsing="false"
onAction="#handleCancel"
text="Abbrechen"
/>
</HBox>
</right>
</BorderPane>
</bottom>
</BorderPane>

View file

@ -77,10 +77,11 @@
text="Hinzufügen" text="Hinzufügen"
/> />
<Button <Button
fx:id="buttonDelete" fx:id="buttonLock"
mnemonicParsing="false" mnemonicParsing="false"
onAction="#handleLock"
prefWidth="90.0" prefWidth="90.0"
text="Löschen" text="Sperren"
/> />
</HBox> </HBox>
</right> </right>

View file

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="de.hitec.nhplus.nurse.LockedNurseController"
>
<padding>
<Insets top="8" left="8" right="8" bottom="8"/>
</padding>
<center>
<TableView fx:id="tableView" layoutX="31.0" layoutY="40" onMouseClicked="#handleMouseClick" >
<columns>
<TableColumn
fx:id="columnId"
minWidth="40.0"
text="ID"
/>
<TableColumn
fx:id="columnSurName"
minWidth="140.0"
text="Nachname"
/>
<TableColumn
fx:id="columnFirstName"
minWidth="140.0"
text="Vorname"
/>
<TableColumn
fx:id="columnPhoneNumber"
minWidth="140.0"
text="Telefonnummer"
/>
<TableColumn
fx:id="columnDeleteDate"
minWidth="140.0"
text="Löschen ab"
/>
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>
</center>
<bottom>
<BorderPane>
<BorderPane.margin>
<Insets top="8.0"/>
</BorderPane.margin>
<center>
<HBox spacing="8.0">
<padding>
<Insets right="8.0"/>
</padding>
</HBox>
</center>
<right>
<HBox>
<spacing>8.0</spacing>
<Button
fx:id="buttonUnlock"
mnemonicParsing="false"
onAction="#unlockNurse"
prefWidth="90.0"
text="Entsperren"
/>
<Button
fx:id="buttonDelete"
mnemonicParsing="false"
onAction="#handleDelete"
prefWidth="90.0"
text="Löschen"
/>
</HBox>
</right>
</BorderPane>
</bottom>
</BorderPane>

View file

@ -3,5 +3,6 @@ CREATE TABLE nurse
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
firstName TEXT NOT NULL, firstName TEXT NOT NULL,
surName TEXT NOT NULL, surName TEXT NOT NULL,
phoneNumber TEXT NOT NULL phoneNumber TEXT NOT NULL,
isLocked BOOLEAN NOT NULL DEFAULT false
) )

View file

@ -119,7 +119,7 @@
fx:id="textAreaRemarks" fx:id="textAreaRemarks"
HBox.hgrow="ALWAYS" HBox.hgrow="ALWAYS"
/> />
<VBox> <VBox spacing="8.0">
<Button <Button
fx:id="buttonSave" fx:id="buttonSave"
prefWidth="90" prefWidth="90"