diff --git a/pom.xml b/pom.xml
index bc6a829..99764d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,78 +1,78 @@
- 4.0.0
-
- de.kreth.invoice
- trainerinvoice
- Übungsleiterabrechnungen
- 1.0.0-SNAPSHOT
- jar
+ 4.0.0
+
+ de.kreth.invoice
+ trainerinvoice
+ Übungsleiterabrechnungen
+ 1.0.0-SNAPSHOT
+ jar
-
- 11
- 23.0.8
+
+ 11
+ 23.0.8
11.0.1
-
+
-
- org.springframework.boot
- spring-boot-starter-parent
- 2.6.7
-
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.7
+
-
-
+
+
-
-
- central
- https://repo.maven.apache.org/maven2
-
- false
-
-
-
- vaadin-prereleases
-
+
+
+ central
+ https://repo.maven.apache.org/maven2
+
+ false
+
+
+
+ vaadin-prereleases
+
https://maven.vaadin.com/vaadin-prereleases/
-
-
-
- Vaadin Directory
- https://maven.vaadin.com/vaadin-addons
-
- false
-
-
-
+
+
+
+ Vaadin Directory
+ https://maven.vaadin.com/vaadin-addons
+
+ false
+
+
+
-
-
-
- central
- https://repo.maven.apache.org/maven2
-
- false
-
-
-
- vaadin-prereleases
-
+
+
+
+ central
+ https://repo.maven.apache.org/maven2
+
+ false
+
+
+
+ vaadin-prereleases
+
https://maven.vaadin.com/vaadin-prereleases/
-
-
+
+
+
+
+
+
+ com.vaadin
+ vaadin-bom
+ ${vaadin.version}
+ pom
+ import
+
-
-
-
- com.vaadin
- vaadin-bom
- ${vaadin.version}
- pom
- import
-
-
org.keycloak.bom
keycloak-adapter-bom
@@ -80,41 +80,36 @@
pom
import
-
-
+
+
-
-
- com.vaadin
-
- vaadin
-
-
- com.vaadin
- vaadin-spring-boot-starter
-
-
- com.h2database
- h2
- runtime
-
+
+
+ com.vaadin
+
+ vaadin
+
+
+ com.vaadin
+ vaadin-spring-boot-starter
+
+
+
+ com.h2database
+ h2
+ runtime
+
-
- com.vaadin
- exampledata
- 4.1.4
-
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
-
- org.springframework.boot
- spring-boot-starter-data-jpa
-
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
-
- org.springframework.boot
- spring-boot-starter-validation
-
-
org.springframework.boot
spring-boot-starter-security
@@ -128,163 +123,163 @@
keycloak-spring-security-adapter
-
- org.springframework.boot
- spring-boot-devtools
- true
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- com.vaadin
- vaadin-testbench
- test
-
-
-
- org.junit.vintage
- junit-vintage-engine
- test
-
-
- org.hamcrest
- hamcrest-core
-
-
-
-
- io.github.bonigarcia
- webdrivermanager
- 5.0.3
- test
-
- net.sf.jasperreports
- jasperreports
- 6.19.1
+ org.springframework.boot
+ spring-boot-devtools
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ com.vaadin
+ vaadin-testbench
+ test
+
+
+
+ org.junit.vintage
+ junit-vintage-engine
+ test
+
+
+ org.hamcrest
+ hamcrest-core
+
+
+
+
+ io.github.bonigarcia
+ webdrivermanager
+ 5.0.3
+ test
+
+
+ net.sf.jasperreports
+ jasperreports
+ 6.19.1
-
- com.lowagie
- itext
- 2.1.7
+ com.lowagie
+ itext
+ 2.1.7
-
+
-
- spring-boot:run
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- 500
- 240
-
-
+
+ 500
+ 240
+
+
-
-
- com.vaadin
- vaadin-maven-plugin
- ${vaadin.version}
-
-
-
- prepare-frontend
-
-
-
-
-
-
+
+ com.vaadin
+ vaadin-maven-plugin
+ ${vaadin.version}
+
+
+
+ prepare-frontend
+
+
+
+
+
+
-
-
-
- production
-
-
-
- com.vaadin
- vaadin-maven-plugin
- ${vaadin.version}
-
-
-
- build-frontend
-
- compile
-
-
-
- true
-
-
-
-
-
+
+
+
+ production
+
+
+
+ com.vaadin
+ vaadin-maven-plugin
+ ${vaadin.version}
+
+
+
+ build-frontend
+
+ compile
+
+
+
+ true
+
+
+
+
+
-
- it
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- start-spring-boot
- pre-integration-test
-
- start
-
-
-
- stop-spring-boot
- post-integration-test
-
- stop
-
-
-
-
+
+ it
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ start-spring-boot
+ pre-integration-test
+
+ start
+
+
+
+ stop-spring-boot
+ post-integration-test
+
+ stop
+
+
+
+
-
-
- org.apache.maven.plugins
- maven-failsafe-plugin
-
-
-
- integration-test
- verify
-
-
-
-
- false
- true
-
-
-
-
-
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+
+ integration-test
+ verify
+
+
+
+
+ false
+ true
+
+
+
+
+
-
-
+
+
\ No newline at end of file
diff --git a/src/main/java/de/kreth/invoice/Application.java b/src/main/java/de/kreth/invoice/Application.java
index e0f1f3c..b60d628 100644
--- a/src/main/java/de/kreth/invoice/Application.java
+++ b/src/main/java/de/kreth/invoice/Application.java
@@ -1,8 +1,12 @@
package de.kreth.invoice;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.Bean;
import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.component.page.AppShellConfigurator;
@@ -23,9 +27,24 @@ import com.vaadin.flow.theme.Theme;
public class Application extends SpringBootServletInitializer implements AppShellConfigurator {
private static final long serialVersionUID = 8632833774084603989L;
+ private static ResourceBundle bundle = null;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
+ public static String getString(Localization_Properties property) {
+ if (bundle == null) {
+ bundle = resourceBundle();
+ }
+
+ return property.getString(bundle::getString);
+ }
+
+ @Bean
+ static ResourceBundle resourceBundle() {
+
+ ResourceBundle bundle = PropertyResourceBundle.getBundle("localization");
+ return bundle;
+ }
}
diff --git a/src/main/java/de/kreth/invoice/Localization_Properties.java b/src/main/java/de/kreth/invoice/Localization_Properties.java
new file mode 100644
index 0000000..1fffc4b
--- /dev/null
+++ b/src/main/java/de/kreth/invoice/Localization_Properties.java
@@ -0,0 +1,324 @@
+package de.kreth.invoice;
+
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.function.UnaryOperator;
+
+import javax.annotation.processing.Generated;
+
+/**
+ * Property keys from localization.properties
+ */
+@Generated(date = "22.05.2022, 19:41:47", value = "de.kreth.property2java.Generator")
+public enum Localization_Properties {
+
+ /**
+ * caption.invoiceitem.date = "Datum"
+ */
+ CAPTION_INVOICEITEM_DATE ("caption.invoiceitem.date"),
+ /**
+ * caption.user.login = "Anmelden"
+ */
+ CAPTION_USER_LOGIN ("caption.user.login"),
+ /**
+ * error.invoice.title.noitems = "Leere Abrechnung nicht erlaubt."
+ */
+ ERROR_INVOICE_TITLE_NOITEMS ("error.invoice.title.noitems"),
+ /**
+ * caption.invoice.sum = "Summe"
+ */
+ CAPTION_INVOICE_SUM ("caption.invoice.sum"),
+ /**
+ * caption.invoiceitem.participants = "Teilnehmer"
+ */
+ CAPTION_INVOICEITEM_PARTICIPANTS ("caption.invoiceitem.participants"),
+ /**
+ * caption.invoiceitem.add = "Neuer Posten"
+ */
+ CAPTION_INVOICEITEM_ADD ("caption.invoiceitem.add"),
+ /**
+ * caption.invoice.pattern = "Rechnung-{0}"
+ */
+ CAPTION_INVOICE_PATTERN ("caption.invoice.pattern"),
+ /**
+ * caption.invoiceitem.start = "Beginn"
+ */
+ CAPTION_INVOICEITEM_START ("caption.invoiceitem.start"),
+ /**
+ * caption.article.report = "Mit Trainer-Lizenz"
+ */
+ CAPTION_ARTICLE_REPORT ("caption.article.report"),
+ /**
+ * caption.invoice.invoiceno = "Rechnungsnummer"
+ */
+ CAPTION_INVOICE_INVOICENO ("caption.invoice.invoiceno"),
+ /**
+ * caption.invoiceitems = "Rechnungspositionen"
+ */
+ CAPTION_INVOICEITEMS ("caption.invoiceitems"),
+ /**
+ * message.user.passwordmissmatch = "Passworter stimmen nicht überein!"
+ */
+ MESSAGE_USER_PASSWORDMISSMATCH ("message.user.passwordmissmatch"),
+ /**
+ * label.delete = "Löschen"
+ */
+ LABEL_DELETE ("label.delete"),
+ /**
+ * message.user.loginfailure = "Anmeldefehler! Falscher Name oder Passwort?"
+ */
+ MESSAGE_USER_LOGINFAILURE ("message.user.loginfailure"),
+ /**
+ * caption.article.type.trainer = "Trainer"
+ */
+ CAPTION_ARTICLE_TYPE_TRAINER ("caption.article.type.trainer"),
+ /**
+ * caption.invoiceitem.sumprice = "Betrag"
+ */
+ CAPTION_INVOICEITEM_SUMPRICE ("caption.invoiceitem.sumprice"),
+ /**
+ * message.delete.text = "Soll {0} wirklich gelöscht werden?"
+ */
+ MESSAGE_DELETE_TEXT ("message.delete.text"),
+ /**
+ * label.user.register = "Registrieren"
+ */
+ LABEL_USER_REGISTER ("label.user.register"),
+ /**
+ * error.userdetails.bankname_empty = "Bankname darf nicht leer sein."
+ */
+ ERROR_USERDETAILS_BANKNAME_EMPTY ("error.userdetails.bankname_empty"),
+ /**
+ * label.ok = "OK"
+ */
+ LABEL_OK ("label.ok"),
+ /**
+ * label.open = "Öffnen"
+ */
+ LABEL_OPEN ("label.open"),
+ /**
+ * label.discart = "Verwerfen"
+ */
+ LABEL_DISCART ("label.discart"),
+ /**
+ * caption.article = "Artikel"
+ */
+ CAPTION_ARTICLE ("caption.article"),
+ /**
+ * message.article.priceerror = "Bitte legen Sie den Preis fest."
+ */
+ MESSAGE_ARTICLE_PRICEERROR ("message.article.priceerror"),
+ /**
+ * error.userdetails.iban_empty = "Iban darf nicht leer sein."
+ */
+ ERROR_USERDETAILS_IBAN_EMPTY ("error.userdetails.iban_empty"),
+ /**
+ * message.user.create.success = "{0} erstellt!"
+ */
+ MESSAGE_USER_CREATE_SUCCESS ("message.user.create.success"),
+ /**
+ * error.userdetails.prename_empty = "Vorname darf nicht leer sein."
+ */
+ ERROR_USERDETAILS_PRENAME_EMPTY ("error.userdetails.prename_empty"),
+ /**
+ * error.invoice.text.noitems = "Bitte Posten für Rechnung auswählen."
+ */
+ ERROR_INVOICE_TEXT_NOITEMS ("error.invoice.text.noitems"),
+ /**
+ * caption.invoiceitem.end = "Ende"
+ */
+ CAPTION_INVOICEITEM_END ("caption.invoiceitem.end"),
+ /**
+ * caption.invoiceitem = ""
+ */
+ CAPTION_INVOICEITEM ("caption.invoiceitem"),
+ /**
+ * caption.adress.zipcode = "Postleitzahl"
+ */
+ CAPTION_ADRESS_ZIPCODE ("caption.adress.zipcode"),
+ /**
+ * caption.user.password = "Ihr Password:"
+ */
+ CAPTION_USER_PASSWORD ("caption.user.password"),
+ /**
+ * caption.invoiceitem.name = "Rechnungsposition"
+ */
+ CAPTION_INVOICEITEM_NAME ("caption.invoiceitem.name"),
+ /**
+ * message.delete.title = "Wirklich löschen?"
+ */
+ MESSAGE_DELETE_TITLE ("message.delete.title"),
+ /**
+ * error.userdetails.zip_empty = "Postleitzahl darf nicht leer sein."
+ */
+ ERROR_USERDETAILS_ZIP_EMPTY ("error.userdetails.zip_empty"),
+ /**
+ * message.invoiceitem.allfieldsmustbeset = "Start, Ende und Artikel müssen gesetzt sein!"
+ */
+ MESSAGE_INVOICEITEM_ALLFIELDSMUSTBESET ("message.invoiceitem.allfieldsmustbeset"),
+ /**
+ * caption.invoices = "Rechnungen"
+ */
+ CAPTION_INVOICES ("caption.invoices"),
+ /**
+ * caption.user.passwordconfirmation = "Password bestätigen:"
+ */
+ CAPTION_USER_PASSWORDCONFIRMATION ("caption.user.passwordconfirmation"),
+ /**
+ * caption.adress.city = "Ort"
+ */
+ CAPTION_ADRESS_CITY ("caption.adress.city"),
+ /**
+ * caption.invoice.printsignature = "Unterschrift drucken"
+ */
+ CAPTION_INVOICE_PRINTSIGNATURE ("caption.invoice.printsignature"),
+ /**
+ * caption.article.title = "Titel"
+ */
+ CAPTION_ARTICLE_TITLE ("caption.article.title"),
+ /**
+ * caption.article.price = "Stundenpreis"
+ */
+ CAPTION_ARTICLE_PRICE ("caption.article.price"),
+ /**
+ * error.userdetails.adress_empty = "Adresse darf nicht leer sein."
+ */
+ ERROR_USERDETAILS_ADRESS_EMPTY ("error.userdetails.adress_empty"),
+ /**
+ * caption.bank.iban = "IBAN"
+ */
+ CAPTION_BANK_IBAN ("caption.bank.iban"),
+ /**
+ * caption.invoice.create = "Rechnung erstellen"
+ */
+ CAPTION_INVOICE_CREATE ("caption.invoice.create"),
+ /**
+ * error.article.undefined = "Bitte Artikel anlegen."
+ */
+ ERROR_ARTICLE_UNDEFINED ("error.article.undefined"),
+ /**
+ * caption.bank.bic = "BIC"
+ */
+ CAPTION_BANK_BIC ("caption.bank.bic"),
+ /**
+ * caption.article.type.assistant = "Übungsleiter"
+ */
+ CAPTION_ARTICLE_TYPE_ASSISTANT ("caption.article.type.assistant"),
+ /**
+ * error.userdetails.city_empty = "Ort darf nicht leer sein."
+ */
+ ERROR_USERDETAILS_CITY_EMPTY ("error.userdetails.city_empty"),
+ /**
+ * label.cancel = "Abbrechen"
+ */
+ LABEL_CANCEL ("label.cancel"),
+ /**
+ * message.user.create.failure = "Fehler beim Erstellen von Benutzer {0}! Ändern Sie den Benutzernamen oder fragen Sie nach dem Passwort. Detail: {1}"
+ */
+ MESSAGE_USER_CREATE_FAILURE ("message.user.create.failure"),
+ /**
+ * caption.article.description = "Beschreibung"
+ */
+ CAPTION_ARTICLE_DESCRIPTION ("caption.article.description"),
+ /**
+ * caption.user.loginname = "Anmeldename:"
+ */
+ CAPTION_USER_LOGINNAME ("caption.user.loginname"),
+ /**
+ * message.article.error.invoiceexists = "Kann nicht geändert werden, da bereits Rechnungen bestehen. Bitte neuen Artikel anlegen."
+ */
+ MESSAGE_ARTICLE_ERROR_INVOICEEXISTS ("message.article.error.invoiceexists"),
+ /**
+ * error.userdetails.surname_empty = "Nachname darf nicht leer sein."
+ */
+ ERROR_USERDETAILS_SURNAME_EMPTY ("error.userdetails.surname_empty"),
+ /**
+ * label.close = "Schließen"
+ */
+ LABEL_CLOSE ("label.close"),
+ /**
+ * caption.adress.street2 = "Adresse"
+ */
+ CAPTION_ADRESS_STREET2 ("caption.adress.street2"),
+ /**
+ * caption.adress.street1 = "Adresse"
+ */
+ CAPTION_ADRESS_STREET1 ("caption.adress.street1"),
+ /**
+ * caption.user.surname = "Nachname:"
+ */
+ CAPTION_USER_SURNAME ("caption.user.surname"),
+ /**
+ * label.loggedin = "Angemeldet:"
+ */
+ LABEL_LOGGEDIN ("label.loggedin"),
+ /**
+ * label.logout = "Abmelden"
+ */
+ LABEL_LOGOUT ("label.logout"),
+ /**
+ * caption.user.prename = "Vorname:"
+ */
+ CAPTION_USER_PRENAME ("caption.user.prename"),
+ /**
+ * caption.bank.name = "Bankname"
+ */
+ CAPTION_BANK_NAME ("caption.bank.name"),
+ /**
+ * label.addarticle = "Neuer Artikel"
+ */
+ LABEL_ADDARTICLE ("label.addarticle"),
+ /**
+ * label.preview = "Vorschau"
+ */
+ LABEL_PREVIEW ("label.preview"),
+ /**
+ * message.invoiceitem.startbeforeend = "Ende darf nicht vor Start liegen."
+ */
+ MESSAGE_INVOICEITEM_STARTBEFOREEND ("message.invoiceitem.startbeforeend"),
+ /**
+ * caption.articles = "Artikel"
+ */
+ CAPTION_ARTICLES ("caption.articles"),
+ /**
+ * caption.invoice.invoicedate = "Rechnungsdatum"
+ */
+ CAPTION_INVOICE_INVOICEDATE ("caption.invoice.invoicedate"),
+ /**
+ * caption.user.details = "Benutzer Details"
+ */
+ CAPTION_USER_DETAILS ("caption.user.details"),
+ /**
+ * error.userdetails.username_empty = "Anmeldename darf nicht leer sein."
+ */
+ ERROR_USERDETAILS_USERNAME_EMPTY ("error.userdetails.username_empty"),
+ /**
+ * label.store = "Speichern"
+ */
+ LABEL_STORE ("label.store");
+
+ private final String value;
+
+ private Localization_Properties (String value) {
+ this.value = value;
+ }
+
+ /**
+ * Represented Key in property File.
+ * @return key
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Resolves the value for this key from the parameter function.
+ *
+ * e.g. Localization_Properties.getString(resBundle::getString)
+ * @param resourceFunction {@link Properties#getProperty(String)} or {@link ResourceBundle#getString(String)}
+ * @return
+ */
+ public String getString(UnaryOperator resourceFunction) {
+ return resourceFunction.apply(value);
+ }
+}
diff --git a/src/main/java/de/kreth/invoice/business/AbstractBusiness.java b/src/main/java/de/kreth/invoice/business/AbstractBusiness.java
new file mode 100644
index 0000000..e29b0cc
--- /dev/null
+++ b/src/main/java/de/kreth/invoice/business/AbstractBusiness.java
@@ -0,0 +1,57 @@
+package de.kreth.invoice.business;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.repository.CrudRepository;
+
+import de.kreth.invoice.data.BaseEntity;
+
+public abstract class AbstractBusiness implements Business {
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private final Class itemClass;
+
+ private CrudRepository repository;
+
+ public AbstractBusiness(CrudRepository repository, Class itemClass) {
+ super();
+ this.repository = repository;
+ this.itemClass = itemClass;
+ }
+
+ @Override
+ public boolean save(T obj) {
+ repository.save(obj);
+ logger.debug("Stored {}", obj);
+ return true;
+ }
+
+ @Override
+ public boolean delete(T obj) {
+ repository.delete(obj);
+ logger.info("Deleted {}", obj);
+ return true;
+ }
+
+ @Override
+ public List loadAll() {
+ List list = new ArrayList();
+ repository.findAll().forEach(list::add);
+ logger.trace("Loaded {} of {}", list.size(), itemClass.getSimpleName());
+ return list;
+ }
+
+ public List loadAll(Predicate predicate) {
+ List loadAll = loadAll();
+ List result = loadAll.stream().filter(predicate).collect(Collectors.toList());
+ logger.trace("Filtered {} of {} total {}", result.size(), loadAll.size(), itemClass.getSimpleName());
+ return result;
+ }
+
+}
diff --git a/src/main/java/de/kreth/invoice/business/ArticleBusiness.java b/src/main/java/de/kreth/invoice/business/ArticleBusiness.java
new file mode 100644
index 0000000..825d1c2
--- /dev/null
+++ b/src/main/java/de/kreth/invoice/business/ArticleBusiness.java
@@ -0,0 +1,34 @@
+package de.kreth.invoice.business;
+
+import java.util.List;
+
+import org.springframework.stereotype.Component;
+
+import de.kreth.invoice.data.Article;
+import de.kreth.invoice.data.InvoiceItem;
+import de.kreth.invoice.persistence.ArticleRepository;
+import de.kreth.invoice.persistence.InvoiceItemRepository;
+
+@Component
+public class ArticleBusiness extends AbstractBusiness {
+
+ private final ArticleRepository articleRepository;
+ private final InvoiceItemRepository invoiceItemRepository;
+
+ public ArticleBusiness(ArticleRepository articleRepository, InvoiceItemRepository invoiceItemRepository) {
+ super(articleRepository, Article.class);
+ this.articleRepository = articleRepository;
+ this.invoiceItemRepository = invoiceItemRepository;
+ }
+
+ public boolean hasInvoiceItem(Article current) {
+ List items = invoiceItemRepository.findByArticle(current);
+ int size = items.size();
+ return size > 0;
+ }
+
+ public List findByUserId(Long id) {
+ return articleRepository.findByUserId(id);
+ }
+
+}
diff --git a/src/main/java/de/kreth/invoice/business/Business.java b/src/main/java/de/kreth/invoice/business/Business.java
new file mode 100644
index 0000000..3929a12
--- /dev/null
+++ b/src/main/java/de/kreth/invoice/business/Business.java
@@ -0,0 +1,13 @@
+package de.kreth.invoice.business;
+
+import java.util.List;
+
+public interface Business {
+
+ boolean save(T obj);
+
+ boolean delete(T obj);
+
+ List loadAll();
+
+}
\ No newline at end of file
diff --git a/src/main/java/de/kreth/invoice/business/InvoiceBusiness.java b/src/main/java/de/kreth/invoice/business/InvoiceBusiness.java
new file mode 100644
index 0000000..acd397f
--- /dev/null
+++ b/src/main/java/de/kreth/invoice/business/InvoiceBusiness.java
@@ -0,0 +1,84 @@
+package de.kreth.invoice.business;
+
+import java.text.MessageFormat;
+import java.util.List;
+import java.util.Optional;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import de.kreth.invoice.data.Invoice;
+import de.kreth.invoice.data.InvoiceItem;
+import de.kreth.invoice.persistence.InvoiceItemRepository;
+import de.kreth.invoice.persistence.InvoiceRepository;
+
+@Component
+public class InvoiceBusiness extends AbstractBusiness {
+
+ private final InvoiceRepository invoiceRepository;
+ private final InvoiceItemRepository itemRepository;
+
+ @Autowired
+ public InvoiceBusiness(InvoiceRepository invoiceRepository, InvoiceItemRepository itemRepository) {
+ super(invoiceRepository, Invoice.class);
+ this.invoiceRepository = invoiceRepository;
+ this.itemRepository = itemRepository;
+ }
+
+ @Override
+ public boolean save(Invoice obj) {
+
+ for (InvoiceItem i : obj.getItems()) {
+ i.setInvoice(obj);
+ }
+ boolean save = super.save(obj);
+ for (InvoiceItem i : obj.getItems()) {
+ itemRepository.save(i);
+ }
+ return save;
+ }
+
+ public String createNextInvoiceId(List invoices, String pattern) {
+
+ Optional latest = invoices.stream()
+ .filter(i -> filter(i.getInvoiceId(), pattern))
+ .max((o1, o2) -> {
+ return o1.getInvoiceId().compareTo(o2.getInvoiceId());
+ });
+
+ int lastInvoiceId = 0;
+
+ if (latest.isPresent()) {
+ String old = latest.get().getInvoiceId();
+ int start = pattern.indexOf("{0}");
+ String substring = old.substring(start);
+ if (substring.matches("[0-9]+")) {
+ lastInvoiceId = Integer.parseInt(substring);
+ } else {
+ lastInvoiceId++;
+ }
+ }
+
+ lastInvoiceId++;
+ String invoiceNo = MessageFormat.format(pattern, lastInvoiceId);
+ return invoiceNo;
+ }
+
+ boolean filter(String invoiceId, String pattern) {
+
+ int start = Math.min(pattern.indexOf("{0}"), invoiceId.length() - 1);
+ int end = start + 1;
+ while (end < invoiceId.length() && Character.isDigit(invoiceId.charAt(end))) {
+ end++;
+ }
+
+ String strippedPattern = pattern.substring(0, start) + pattern.substring(start + 3);
+ String strippedIId = invoiceId.substring(0, start) + invoiceId.substring(end);
+ return strippedIId.contentEquals(strippedPattern);
+ }
+
+ public List findByUserId(long userId) {
+ return invoiceRepository.findByUserId(userId);
+ }
+
+}
diff --git a/src/main/java/de/kreth/invoice/business/InvoiceItemBusiness.java b/src/main/java/de/kreth/invoice/business/InvoiceItemBusiness.java
new file mode 100644
index 0000000..b75cab8
--- /dev/null
+++ b/src/main/java/de/kreth/invoice/business/InvoiceItemBusiness.java
@@ -0,0 +1,33 @@
+package de.kreth.invoice.business;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.springframework.stereotype.Component;
+
+import de.kreth.invoice.data.InvoiceItem;
+import de.kreth.invoice.data.User;
+import de.kreth.invoice.persistence.InvoiceItemRepository;
+
+@Component
+public class InvoiceItemBusiness extends AbstractBusiness {
+
+ private final InvoiceItemRepository repository;
+
+ public InvoiceItemBusiness(InvoiceItemRepository invoiceItemRepository) {
+ super(invoiceItemRepository, InvoiceItem.class);
+ this.repository = invoiceItemRepository;
+ }
+
+ public List findByInvoiceIsNull(User user) {
+ List findByInvoiceIsNull = repository.findByInvoiceIsNull();
+ for (Iterator iterator = findByInvoiceIsNull.iterator(); iterator.hasNext();) {
+ InvoiceItem invoiceItem = iterator.next();
+ if (invoiceItem.getArticle().getUserId() != user.getId()) {
+ iterator.remove();
+ }
+ }
+ return findByInvoiceIsNull;
+ }
+
+}
diff --git a/src/main/java/de/kreth/invoice/components/InvoiceItemGrid.java b/src/main/java/de/kreth/invoice/components/InvoiceItemGrid.java
deleted file mode 100644
index 372eb01..0000000
--- a/src/main/java/de/kreth/invoice/components/InvoiceItemGrid.java
+++ /dev/null
@@ -1,177 +0,0 @@
-package de.kreth.invoice.components;
-
-import java.math.BigDecimal;
-import java.text.NumberFormat;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.time.format.FormatStyle;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import com.vaadin.flow.component.grid.FooterRow;
-import com.vaadin.flow.component.grid.FooterRow.FooterCell;
-import com.vaadin.flow.component.grid.Grid;
-import com.vaadin.flow.component.grid.GridSelectionModel;
-import com.vaadin.flow.data.provider.DataChangeEvent;
-import com.vaadin.flow.data.provider.DataProvider;
-import com.vaadin.flow.data.provider.DataProviderListener;
-import com.vaadin.flow.data.provider.ListDataProvider;
-import com.vaadin.flow.data.renderer.LocalDateTimeRenderer;
-import com.vaadin.flow.data.renderer.NumberRenderer;
-
-import de.kreth.invoice.data.InvoiceItem;
-import de.kreth.invoice.persistence.InvoiceItemRepository;
-
-class InvoiceItemGrid extends Grid {
-
- private static final long serialVersionUID = -8653320112619816426L;
-
- private final DateTimeFormatter ofLocalizedDateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
-
- private FooterCell priceSumCell;
-
- private FooterCell countCell;
-
- private FooterCell dateSpan;
-
- private final List items = new ArrayList<>();
-
- private InvoiceItemRepository repository;
-
- public InvoiceItemGrid(InvoiceItemRepository invoiceItemRepository) {
-
- this.repository = invoiceItemRepository;
- addClassName("bordered");
- Column titleCol = addColumn(InvoiceItem::getTitle);
- titleCol.setId("Article");
- titleCol.setHeader("Artikel");
-
- Column dateColumn = addColumn(new LocalDateTimeRenderer<>(InvoiceItem::getStart,
- DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));
- dateColumn.setId("Date");
- dateColumn.setHeader("Datum");
-
- Column startColumn = addColumn(new LocalDateTimeRenderer<>(InvoiceItem::getStart,
- DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)));
- startColumn.setId("Start");
- startColumn.setHeader("Beginn");
-
- Column endColumn = addColumn(new LocalDateTimeRenderer<>(InvoiceItem::getEnd,
- DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)));
- endColumn.setId("Ende");
- endColumn.setHeader("Ende");
-
- Column participantColumn = addColumn(InvoiceItem::getParticipants);
- participantColumn.setHeader("Teilnehmer");
-
- Column sumPriceColumn = addColumn(
- new NumberRenderer<>(InvoiceItem::getSumPrice, NumberFormat.getCurrencyInstance()));
- sumPriceColumn.setId("price");
- sumPriceColumn.setHeader("Betrag");
-
-// setSortOrder(GridSortOrder.asc(dateColumn).thenAsc(startColumn));
- FooterRow footer = appendFooterRow();
-
- priceSumCell = footer.getCell(sumPriceColumn);
-// dateSpan = footer.join(dateColumn, startColumn, endColumn);
- dateSpan = footer.getCell(dateColumn);
- countCell = footer.getCell(titleCol);
-
-// addSelectionListener(this::selectionChanged);
-
- items.addAll(repository.findByInvoiceIsNull());
-
- ListDataProvider dataProvider = new ListDataProvider(items);
- setDataProvider(dataProvider);
- dataProvider.addDataProviderListener(new InnerDataProviderListener());
- }
-
- public void refreshData() {
- items.clear();
- items.addAll(repository.findByInvoiceIsNull());
- }
-
- @Override
- public GridSelectionModel setSelectionMode(SelectionMode selectionMode) {
- GridSelectionModel setSelectionMode = super.setSelectionMode(selectionMode);
-// setSelectionMode.addSelectionListener(this::selectionChanged);
- return setSelectionMode;
- }
-
-// @SuppressWarnings("unchecked")
-// private void selectionChanged(SelectionEvent event) {
-// if (event.getAllSelectedItems().isEmpty()) {
-// updateFooterWith(((ListDataProvider) getDataProvider()).getItems());
-// } else {
-// updateFooterWith(event.getAllSelectedItems());
-// }
-// }
-
- protected void internalSetDataProvider(DataProvider dataProvider) {
-
- if (!(dataProvider instanceof ListDataProvider)) {
- throw new IllegalArgumentException("dataProvider must be an instance of ListDataProvider");
- }
-// super.internalSetDataProvider(dataProvider);
- dataProvider.addDataProviderListener(new InnerDataProviderListener());
- updateFooterWith(((ListDataProvider) getDataProvider()).getItems());
- }
-
- private void updateFooterWith(Collection selected) {
- BigDecimal priceSum = BigDecimal.ZERO;
- LocalDate min = null;
- LocalDate max = null;
-
- for (InvoiceItem t : selected) {
- priceSum = priceSum.add(t.getSumPrice());
- min = getMin(min, t.getStart().toLocalDate());
- max = getMax(max, t.getEnd().toLocalDate());
- }
-
- priceSumCell.setText(NumberFormat.getCurrencyInstance().format(priceSum));
- if (min != null && max != null) {
- dateSpan.setText(min.format(ofLocalizedDateFormatter) + " - " + max.format(ofLocalizedDateFormatter));
- } else {
- dateSpan.setText("");
- }
- countCell.setText("Anzahl: " + selected.size());
- }
-
- private LocalDate getMax(LocalDate max, LocalDate localDate) {
- if (max == null) {
- max = localDate;
- } else {
- if (max.isBefore(localDate)) {
- max = localDate;
- }
- }
- return max;
- }
-
- private LocalDate getMin(LocalDate min, LocalDate localDate) {
- if (min == null) {
- min = localDate;
- } else {
- if (min.isAfter(localDate)) {
- min = localDate;
- }
- }
- return min;
- }
-
- private class InnerDataProviderListener implements DataProviderListener {
-
- private static final long serialVersionUID = -6094992880488082586L;
-
- @Override
- public void onDataChange(DataChangeEvent event) {
- if (event.getSource() == getDataProvider()) {
- @SuppressWarnings("unchecked")
- ListDataProvider provider = (ListDataProvider) getDataProvider();
- updateFooterWith(provider.getItems());
- }
- }
-
- }
-}
diff --git a/src/main/java/de/kreth/invoice/components/InvoiceItemOverviewComponent.java b/src/main/java/de/kreth/invoice/components/InvoiceItemOverviewComponent.java
deleted file mode 100644
index 7e5eb09..0000000
--- a/src/main/java/de/kreth/invoice/components/InvoiceItemOverviewComponent.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package de.kreth.invoice.components;
-
-import java.util.List;
-
-import com.vaadin.flow.component.ClickEvent;
-import com.vaadin.flow.component.button.Button;
-import com.vaadin.flow.component.html.H3;
-import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
-import com.vaadin.flow.component.orderedlayout.VerticalLayout;
-
-import de.kreth.invoice.data.Article;
-import de.kreth.invoice.data.InvoiceItem;
-import de.kreth.invoice.data.User;
-import de.kreth.invoice.persistence.ArticleRepository;
-import de.kreth.invoice.persistence.InvoiceItemRepository;
-
-public class InvoiceItemOverviewComponent extends VerticalLayout {
-
- private static final long serialVersionUID = -4486121981960039L;
- private final InvoiceItemGrid grid;
- private final InvoiceItemRepository invoiceItemRepository;
- private final ArticleRepository articleRepository;
- private final User user;
-
- public InvoiceItemOverviewComponent(InvoiceItemRepository invoiceItemRepository,
- ArticleRepository articleRepository, User user) {
- this.invoiceItemRepository = invoiceItemRepository;
- this.articleRepository = articleRepository;
- this.user = user;
- Button addButton = new Button("Hinzufügen", this::createNewitem);
- add(new HorizontalLayout(new H3("Rechnungspositionen"), addButton));
- grid = new InvoiceItemGrid(invoiceItemRepository);
- add(grid);
- }
-
- public void refreshData() {
- grid.refreshData();
- }
-
- private void createNewitem(ClickEvent