diff --git a/.gitignore b/.gitignore index c2a137f..d543419 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ buildNumber.properties frontend/ node_modules/ + +data/ diff --git a/.project b/.project index 1330282..bd288b1 100644 --- a/.project +++ b/.project @@ -11,12 +11,12 @@ - org.eclipse.m2e.core.maven2Builder + org.springframework.ide.eclipse.boot.validation.springbootbuilder - org.springframework.ide.eclipse.boot.validation.springbootbuilder + org.eclipse.m2e.core.maven2Builder diff --git a/pom.xml b/pom.xml index c9f439b..bc6a829 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,4 @@ - - + 4.0.0 de.kreth.invoice @@ -163,6 +161,23 @@ 5.0.3 test + + net.sf.jasperreports + jasperreports + 6.19.1 + + + + com.lowagie + itext + 2.1.7 + + diff --git a/src/main/java/de/kreth/invoice/data/BaseEntity.java b/src/main/java/de/kreth/invoice/data/BaseEntity.java index 78d8a6e..15178e2 100644 --- a/src/main/java/de/kreth/invoice/data/BaseEntity.java +++ b/src/main/java/de/kreth/invoice/data/BaseEntity.java @@ -5,22 +5,26 @@ import java.time.LocalDateTime; import javax.persistence.Column; import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.MappedSuperclass; import javax.persistence.PrePersist; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + @MappedSuperclass public class BaseEntity implements Serializable { private static final long serialVersionUID = 6953593432069408729L; @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) + @GeneratedValue private int id; @Column(name = "created") + @CreationTimestamp private LocalDateTime createdDate; @Column(name = "updated") + @UpdateTimestamp private LocalDateTime changeDate; public int getId() { @@ -70,20 +74,26 @@ public class BaseEntity implements Serializable { @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) + } + if (obj == null) { return false; - if (getClass() != obj.getClass()) + } + if (getClass() != obj.getClass()) { return false; + } BaseEntity other = (BaseEntity) obj; if (createdDate == null) { - if (other.createdDate != null) + if (other.createdDate != null) { return false; - } else if (!createdDate.equals(other.createdDate)) + } + } else if (!createdDate.equals(other.createdDate)) { return false; - if (id != other.id) + } + if (id != other.id) { return false; + } return true; } diff --git a/src/main/java/de/kreth/invoice/data/Invoice.java b/src/main/java/de/kreth/invoice/data/Invoice.java index b7d21d7..275fd79 100644 --- a/src/main/java/de/kreth/invoice/data/Invoice.java +++ b/src/main/java/de/kreth/invoice/data/Invoice.java @@ -6,8 +6,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; @@ -21,11 +24,13 @@ public class Invoice extends BaseEntity { private String invoiceId; private LocalDateTime invoiceDate; + private String signImagePath; + @OneToMany(mappedBy = "invoice") private List items; -// @ManyToOne(cascade = CascadeType.REFRESH) -// @JoinColumn(name = "user_id", nullable = false, updatable = false) + @ManyToOne(cascade = CascadeType.REFRESH) + @JoinColumn(name = "user_id", nullable = false, updatable = false) private User user; public String getInvoiceId() { @@ -68,6 +73,10 @@ public class Invoice extends BaseEntity { BigDecimal::add); } + public String getSignImagePath() { + return signImagePath; + } + @Override public String toString() { return "Invoice [invoiceId=" + invoiceId + ", itemscount=" diff --git a/src/main/java/de/kreth/invoice/data/InvoiceItem.java b/src/main/java/de/kreth/invoice/data/InvoiceItem.java index 1189b81..19117f9 100644 --- a/src/main/java/de/kreth/invoice/data/InvoiceItem.java +++ b/src/main/java/de/kreth/invoice/data/InvoiceItem.java @@ -21,6 +21,8 @@ public class InvoiceItem extends BaseEntity { private LocalDateTime end; @Column(nullable = true, length = 15) private String participants; + @Column(nullable = true, length = 255) + private String description; @ManyToOne(optional = false) @JoinColumn(name = "article_id", nullable = false, updatable = false) @@ -33,6 +35,8 @@ public class InvoiceItem extends BaseEntity { @Column(name = "sum_price") private BigDecimal sumPrice; + private BigDecimal pricePerHour; + public String getTitle() { return getArticle().getTitle(); } @@ -101,6 +105,14 @@ public class InvoiceItem extends BaseEntity { return start.until(end, ChronoUnit.MINUTES); } + public String getDescription() { + return description; + } + + public BigDecimal getPricePerHour() { + return pricePerHour; + } + @Override public String toString() { return "InvoiceItem [id=" + getId() + ", start=" + start + ", end=" @@ -119,28 +131,37 @@ public class InvoiceItem extends BaseEntity { @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) + } + if (obj == null) { return false; - if (getClass() != obj.getClass()) + } + if (getClass() != obj.getClass()) { return false; + } InvoiceItem other = (InvoiceItem) obj; if (article == null) { - if (other.article != null) + if (other.article != null) { return false; - } else if (!article.equals(other.article)) + } + } else if (!article.equals(other.article)) { return false; + } if (end == null) { - if (other.end != null) + if (other.end != null) { return false; - } else if (!end.equals(other.end)) + } + } else if (!end.equals(other.end)) { return false; + } if (start == null) { - if (other.start != null) + if (other.start != null) { return false; - } else if (!start.equals(other.start)) + } + } else if (!start.equals(other.start)) { return false; + } return true; } diff --git a/src/main/java/de/kreth/invoice/data/User.java b/src/main/java/de/kreth/invoice/data/User.java index 2b5ad4d..478fca5 100644 --- a/src/main/java/de/kreth/invoice/data/User.java +++ b/src/main/java/de/kreth/invoice/data/User.java @@ -2,10 +2,13 @@ package de.kreth.invoice.data; import java.util.Objects; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; +import javax.persistence.OneToOne; import javax.persistence.Table; import org.keycloak.representations.AccessToken; @@ -21,6 +24,12 @@ public class User extends BaseEntity { private String familyName; private String email; + @OneToOne(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL) + private UserBank bank; + + @OneToOne(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL) + private UserAdress adress; + @Column(name = "PRINCIPAL_ID", nullable = false, length = 40, updatable = false, insertable = true, unique = true) public String getPrincipalId() { return principalId; @@ -55,4 +64,11 @@ public class User extends BaseEntity { return email; } + public UserBank getBank() { + return bank; + } + + public UserAdress getAdress() { + return adress; + } } diff --git a/src/main/java/de/kreth/invoice/report/InvoiceReportSource.java b/src/main/java/de/kreth/invoice/report/InvoiceReportSource.java new file mode 100644 index 0000000..5ae8209 --- /dev/null +++ b/src/main/java/de/kreth/invoice/report/InvoiceReportSource.java @@ -0,0 +1,229 @@ +package de.kreth.invoice.report; + +import java.math.BigDecimal; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.util.Iterator; +import java.util.List; + +import de.kreth.invoice.data.Invoice; +import de.kreth.invoice.data.InvoiceItem; +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JRDataSourceProvider; +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JRField; +import net.sf.jasperreports.engine.JasperReport; +import net.sf.jasperreports.engine.base.JRBaseField; + +public class InvoiceReportSource implements JRDataSource, JRDataSourceProvider { + + public static final String FIELD_INVOICE_NO = "INVOICE_NO"; + + public static final String FIELD_INVOICE_DATE = "INVOICE_DATE"; + + public static final String FIELD_INVOICE_SUM = "INVOICE_SUM"; + + public static final String FIELD_USER_PRENAME = "USER_PRENAME"; + + public static final String FIELD_USER_SURNAME = "USER_SURNAME"; + + public static final String FIELD_USER_ADRESS1 = "USER_ADRESS1"; + + public static final String FIELD_USER_ADRESS2 = "USER_ADRESS2"; + + public static final String FIELD_USER_ZIP = "USER_ZIPCODE"; + + public static final String FIELD_USER_CITY = "USER_CITY"; + + public static final String FIELD_BANK_NAME = "BANK_NAME"; + + public static final String FIELD_BANK_IBAN = "BANK_IBAN"; + + public static final String FIELD_BANK_BIC = "BANK_BIC"; + + public static final String FIELD_SIGNATURE_PATH = "FIELD_SIGNATURE_PATH"; + + public static final String FIELD_ARTICLE_TITLE = "ARTICLE_TITLE"; + + public static final String FIELD_ARTICLE_DESCRIPTION = "ARTICLE_DESCRIPTION"; + + public static final String FIELD_ARTICLE_PRICE_PER_HOUR = "ARTICLE_PRICE_PER_HOUR"; + + public static final String FIELD_ITEM_START = "ITEM_START"; + + public static final String FIELD_ITEM_END = "ITEM_END"; + + public static final String FIELD_ITEM_PARTICIPANTS = "FIELD_ITEM_PARTICIPANTS"; + + public static final String FIELD_ITEM_DURATION_MINUTES = "ITEM_DURATION_MINUTES"; + + public static final String FIELD_ITEM_SUM = "ITEM_SUM"; + + private Invoice invoice; + + private Iterator itemIterator; + + private InvoiceItem currentItem; + + public InvoiceReportSource() { + } + + public void setInvoice(Invoice invoice) { + this.invoice = invoice; + List items = invoice.getItems(); + items.sort(this::compare); + itemIterator = items.iterator(); + } + + private int compare(InvoiceItem i1, InvoiceItem i2) { + return i1.getStart().compareTo(i2.getStart()); + } + + @Override + public boolean next() throws JRException { + if (itemIterator.hasNext() == false) { + currentItem = null; + return false; + } + currentItem = itemIterator.next(); + return true; + } + + @Override + public Object getFieldValue(JRField jrField) throws JRException { + switch (jrField.getName()) { + case FIELD_INVOICE_NO: + return invoice.getInvoiceId(); + case FIELD_INVOICE_DATE: + return invoice.getInvoiceDate(); + case FIELD_INVOICE_SUM: + return invoice.getSum(); + case FIELD_USER_PRENAME: + return invoice.getUser().getGivenName(); + case FIELD_USER_SURNAME: + return invoice.getUser().getFamilyName(); + + case FIELD_BANK_NAME: + return invoice.getUser().getBank().getBankName(); + case FIELD_BANK_IBAN: + return invoice.getUser().getBank().getIban(); + case FIELD_BANK_BIC: + return invoice.getUser().getBank().getBic(); + case FIELD_USER_ADRESS1: + return invoice.getUser().getAdress().getAdress1(); + case FIELD_USER_ADRESS2: + return invoice.getUser().getAdress().getAdress2(); + case FIELD_USER_ZIP: + return invoice.getUser().getAdress().getZip(); + case FIELD_USER_CITY: + return invoice.getUser().getAdress().getCity(); + + case FIELD_SIGNATURE_PATH: + return invoice.getSignImagePath(); + default: + break; + } + + if (currentItem != null) { + + switch (jrField.getName()) { + case FIELD_ARTICLE_TITLE: + return currentItem.getTitle(); + case FIELD_ARTICLE_DESCRIPTION: + return currentItem.getDescription(); + case FIELD_ARTICLE_PRICE_PER_HOUR: + return currentItem.getPricePerHour(); + case FIELD_ITEM_START: + return currentItem.getStart(); + case FIELD_ITEM_END: + return currentItem.getEnd(); + case FIELD_ITEM_DURATION_MINUTES: + return currentItem.getDurationInMinutes(); + case FIELD_ITEM_SUM: + return currentItem.getSumPrice(); + case FIELD_ITEM_PARTICIPANTS: + return currentItem.getParticipants(); + + default: + break; + } + } + + return null; + } + + public static JRDataSource getDataSource() { + return new InvoiceReportSource(); + } + + @Override + public boolean supportsGetFieldsOperation() { + return true; + } + + @Override + public JRField[] getFields(JasperReport report) + throws JRException, UnsupportedOperationException { + JRField[] fields = { + new InternalField(FIELD_INVOICE_NO, "Invoice No", String.class), + new InternalField(FIELD_INVOICE_DATE, "Invoice date", + LocalDateTime.class), + new InternalField(FIELD_INVOICE_SUM, "Invoice sum", + BigDecimal.class), + new InternalField(FIELD_USER_PRENAME, "User Prename", + String.class), + new InternalField(FIELD_USER_SURNAME, "User Surname", + String.class), + + new InternalField(FIELD_USER_ADRESS1, "User Adress1", + String.class), + new InternalField(FIELD_USER_ADRESS2, "User Âdress2", + String.class), + new InternalField(FIELD_USER_ZIP, "User Zipcode", String.class), + new InternalField(FIELD_USER_CITY, "User City", String.class), + + new InternalField(FIELD_BANK_NAME, "Bank Name", String.class), + new InternalField(FIELD_BANK_IBAN, "Bank IBAN", String.class), + new InternalField(FIELD_BANK_BIC, "Bank Bic", String.class), + + new InternalField(FIELD_ARTICLE_TITLE, "Article Title", + String.class), + new InternalField(FIELD_ARTICLE_DESCRIPTION, + "Article Description", String.class), + new InternalField(FIELD_ARTICLE_PRICE_PER_HOUR, + "Article Price per Hour", BigDecimal.class), + new InternalField(FIELD_ITEM_START, "Item Start", + LocalDateTime.class), + new InternalField(FIELD_ITEM_END, "Item End", + LocalDateTime.class), + new InternalField(FIELD_ITEM_DURATION_MINUTES, + "Item Duration in Minutes", Long.class), + new InternalField(FIELD_ITEM_PARTICIPANTS, "Item Participants", + String.class), + new InternalField(FIELD_ITEM_SUM, "Item Sum", + BigDecimal.class), + new InternalField(FIELD_SIGNATURE_PATH, "Signature Image Path", + Path.class) }; + return fields; + } + + @Override + public JRDataSource create(JasperReport report) throws JRException { + return this; + } + + @Override + public void dispose(JRDataSource dataSource) throws JRException { + } + + static class InternalField extends JRBaseField { + private static final long serialVersionUID = -495777796541981790L; + + InternalField(String name, String desc, Class clazz) { + this.name = name; + this.description = desc; + this.valueClass = clazz; + this.valueClassName = clazz.getName(); + } + } +} diff --git a/src/main/java/de/kreth/invoice/report/Signature.java b/src/main/java/de/kreth/invoice/report/Signature.java new file mode 100644 index 0000000..9acca86 --- /dev/null +++ b/src/main/java/de/kreth/invoice/report/Signature.java @@ -0,0 +1,59 @@ +package de.kreth.invoice.report; + +import java.io.File; +import java.io.FileFilter; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Objects; + +import org.apache.commons.io.FilenameUtils; + +import de.kreth.invoice.data.User; + +public class Signature { + + private final User user; + + public Signature(User user) { + super(); + this.user = Objects.requireNonNull(user); + } + + public OutputStream createOutputStream(String fileName) throws IOException { + File dir = new File("images"); + dir.mkdirs(); + return new FileOutputStream(new File(dir, user.getId() + "." + FilenameUtils.getExtension(fileName))); + } + + public boolean isSignatureImageExists() { + File[] listFiles = new File("images").listFiles(new FileFilter() { + + @Override + public boolean accept(File pathname) { + return pathname.getName().startsWith(user.getId() + "."); + } + }); + return listFiles != null && listFiles.length > 0; + } + + /** + * Check with {@link #isSignatureImageExists()} existence first. + * + * @return + * @throws NullPointerException if image does not exist. + */ + public File getSignatureUrl() { + File[] listFiles = new File("images").listFiles(new FileFilter() { + + @Override + public boolean accept(File pathname) { + return pathname.getName().startsWith(user.getId() + "."); + } + }); + if (listFiles == null || listFiles.length == 0) { + throw new NullPointerException("Image file does not exist"); + } + return listFiles[0]; + } +} diff --git a/src/main/java/de/kreth/invoice/security/UserManager.java b/src/main/java/de/kreth/invoice/security/UserManager.java index 2089a64..d16ac43 100644 --- a/src/main/java/de/kreth/invoice/security/UserManager.java +++ b/src/main/java/de/kreth/invoice/security/UserManager.java @@ -49,7 +49,7 @@ public class UserManager { User user = new User(); AccessToken accessToken = getAccessToken(); user.setPrincipal(accessToken); - return user; + return save(user); } } diff --git a/src/main/java/de/kreth/invoice/views/UserDetailsDialog.java b/src/main/java/de/kreth/invoice/views/UserDetailsDialog.java new file mode 100644 index 0000000..7641b82 --- /dev/null +++ b/src/main/java/de/kreth/invoice/views/UserDetailsDialog.java @@ -0,0 +1,227 @@ +package de.kreth.invoice.views; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.util.Objects; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.dialog.Dialog; +import com.vaadin.flow.component.html.Hr; +import com.vaadin.flow.component.html.Image; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.component.upload.Upload; +import com.vaadin.flow.data.binder.Binder; +import com.vaadin.flow.data.binder.BinderValidationStatus; +import com.vaadin.flow.server.AbstractStreamResource; +import com.vaadin.flow.server.InputStreamFactory; +import com.vaadin.flow.server.StreamResource; + +import de.kreth.invoice.data.Adress; +import de.kreth.invoice.data.User; +import de.kreth.invoice.data.UserAdress; +import de.kreth.invoice.data.UserBank; +import de.kreth.invoice.persistence.UserAdressRepository; +import de.kreth.invoice.persistence.UserBankRepository; +import de.kreth.invoice.report.Signature; + +public class UserDetailsDialog extends Dialog { + + private static final long serialVersionUID = -6255487997073609068L; + + private Logger logger = LoggerFactory.getLogger(getClass()); + + private final Binder bankBinder = new Binder<>(); + private final Binder adressBinder = new Binder<>(); + + private final TextField loginName; + + private final TextField prename; + + private final TextField surname; + + private final TextField bankName; + + private final TextField iban; + + private final TextField bic; + + private final TextField adress1; + + private final TextField adress2; + + private final TextField zipCode; + + private final TextField city; + + private final Button okButton; + + private final Image signatureImage; + + private final UserBankRepository bankRepository; + private final UserAdressRepository adressRepository; + + private User user; + + private UserBank bank; + + private UserAdress adress; + + public UserDetailsDialog(UserBankRepository bankRepository, UserAdressRepository adressRepository) { + this.bankRepository = bankRepository; + this.adressRepository = adressRepository; + + loginName = new TextField(); + loginName.setLabel("Login Name"); + loginName.setEnabled(false); + + prename = new TextField(); + prename.setLabel("Vorname"); + prename.setEnabled(false); + + surname = new TextField(); + surname.setLabel("Nachname"); + + bankName = new TextField(); + bankName.setLabel("Name der Bank"); + bankBinder.forField(bankName) + .asRequired("Der BankName darf nicht leer sein.") + .bind(UserBank::getBankName, UserBank::setBankName); + + iban = new TextField(); + iban.setLabel("IBAN"); + bankBinder.forField(iban) + .asRequired("Die IBAN darf nicht leer sein.") + .bind(UserBank::getIban, UserBank::setIban); + + bic = new TextField(); + bic.setLabel("BIC"); + bankBinder.forField(bic).bind(UserBank::getBic, UserBank::setBic); + + adress1 = new TextField(); + adress1.setLabel("Straße"); + adressBinder.forField(adress1) + .asRequired("Die Straße muss angegeben sein.") + .bind(Adress::getAdress1, Adress::setAdress1); + + adress2 = new TextField(); + adress2.setLabel("Adresszusatz"); + adressBinder.forField(adress2) + .bind(Adress::getAdress2, Adress::setAdress2); + + zipCode = new TextField(); + zipCode.setLabel("Postleitzahl"); + adressBinder.forField(zipCode) + .asRequired("Die Postleitzahl muss angegeben sein.") + .bind(Adress::getZip, Adress::setZip); + + city = new TextField(); + city.setLabel("Ort"); + adressBinder.forField(city) + .asRequired("Der Ort muss angegeben sein.") + .bind(Adress::getCity, Adress::setCity); + + signatureImage = new Image(); + signatureImage.setWidth("192px"); + signatureImage.setHeight("62px"); + signatureImage.setAlt("Keine Unterschrift konfiguriert"); + + Upload upload = new Upload(this::receiveUpload); + upload.addFinishedListener(ev -> updateSignatureImage()); + + VerticalLayout layout = new VerticalLayout(); + layout.add(loginName, prename, surname); + layout.add(new Hr()); + layout.add(bankName, iban, bic); + layout.add(new Hr()); + HorizontalLayout cityLayout = new HorizontalLayout(); + cityLayout.add(zipCode, city); + + layout.add(adress1, adress2, cityLayout, new HorizontalLayout(signatureImage, upload)); + + okButton = new Button("OK", ev -> { + BinderValidationStatus bankValidation = bankBinder.validate(); + + BinderValidationStatus adressValidation = adressBinder.validate(); + if (bankValidation.isOk() && adressValidation.isOk()) { + close(); + } + }); + + Button cancel = new Button("Abbrechen", ev -> close()); + + HorizontalLayout buttons = new HorizontalLayout(); + buttons.add(okButton, cancel); + layout.add(buttons); + + add(layout); + } + + private OutputStream receiveUpload(String filename, String mimeType) { + + Signature signature = new Signature(user); + try { + return signature.createOutputStream(filename); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +// +// public Registration addOkClickListener(ClickListener listener) { +// return okButton.addClickListener(listener); +// } + + public void setUser(User user) { + this.user = Objects.requireNonNull(user); + this.bank = bankRepository.findByUser(user); + this.adress = adressRepository.findByUser(user); + if (this.bank == null) { + this.bank = new UserBank(); + } + if (this.adress == null) { + this.adress = new UserAdress(); + } + updateSignatureImage(); + } + + private void updateSignatureImage() { + if (user != null) { + Signature signature = new Signature(user); + if (signature.isSignatureImageExists()) { + File signatureUrl = signature.getSignatureUrl(); + logger.info("Showing signature: {}", signatureUrl); + + StreamResource resource = new StreamResource(getAriaLabelString(), new InputStreamFactory() { + + private static final long serialVersionUID = 1L; + + @Override + public InputStream createInputStream() { + try { + return new FileInputStream(signatureUrl); + } catch (FileNotFoundException e) { + throw new UncheckedIOException(e); + } + } + }); + signatureImage.setSrc(resource); + } else { + signatureImage.setSrc((AbstractStreamResource) null); + } + } + } + + public User getUser() { + return user; + } + +} diff --git a/src/main/resources/reports/mtv_gross_buchholz.jrxml b/src/main/resources/reports/mtv_gross_buchholz.jrxml new file mode 100644 index 0000000..4fedf13 --- /dev/null +++ b/src/main/resources/reports/mtv_gross_buchholz.jrxml @@ -0,0 +1,586 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <band height="89" splitType="Stretch"> + <staticText> + <reportElement x="0" y="25" width="556" height="20" uuid="38e32426-ceb9-40ee-af7a-ab84b566d96b"/> + <textElement textAlignment="Center"> + <font fontName="Arial" size="12" isBold="false"/> + </textElement> + <text><![CDATA[MTV Groß-Buchholz von 1898 e.V.]]></text> + </staticText> + <staticText> + <reportElement x="0" y="37" width="556" height="15" uuid="88043ee4-db2c-43ca-96f2-fa078918d134"> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + </reportElement> + <textElement textAlignment="Center"> + <font size="9"/> + </textElement> + <text><![CDATA[Rotekreuzstraße 25 - 30627 Hannover - Tel.: 0511/57 11 86 - Fax: 0511/57 11 61]]></text> + </staticText> + <staticText> + <reportElement x="376" y="0" width="103" height="12" uuid="7927de72-6eab-475d-821b-5267f0fea03e"> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + <property name="com.jaspersoft.studio.unit.width" value="pixel"/> + </reportElement> + <box> + <topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement verticalAlignment="Middle"> + <font size="8"/> + </textElement> + <text><![CDATA[Lfd Nr. Rechnungsbuch: +]]></text> + </staticText> + <staticText> + <reportElement x="376" y="12" width="103" height="13" uuid="85798559-a680-4640-a1c4-2283b1304317"/> + <textElement verticalAlignment="Middle"> + <font size="8"/> + </textElement> + <text><![CDATA[Datum Rechnungsbuch: +]]></text> + </staticText> + <line> + <reportElement x="474" y="8" width="81" height="1" uuid="b5037544-4ab0-4b5c-a92d-4191bba0a0b1"> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + </reportElement> + </line> + <line> + <reportElement x="474" y="20" width="81" height="1" uuid="788013ff-1f4a-4420-b4b6-3dd9e405eea2"> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + </reportElement> + </line> + <staticText> + <reportElement x="3" y="73" width="550" height="14" uuid="195e05ca-09bb-4890-8444-6cba59da2388"> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + </reportElement> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Arial" size="6"/> + </textElement> + <text><![CDATA[(o. Übungsleiter-Lizenz)]]></text> + </staticText> + <staticText> + <reportElement x="0" y="48" width="556" height="25" uuid="762705d5-be9c-476f-b2ff-dc07cab925f9"/> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font size="16" isUnderline="true"/> + </textElement> + <text><![CDATA[Monatsabrechnung Übungsleitervergütung +]]></text> + </staticText> + </band> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/reports/mtv_gross_buchholz_trainer.jrxml b/src/main/resources/reports/mtv_gross_buchholz_trainer.jrxml new file mode 100644 index 0000000..dfeea7e --- /dev/null +++ b/src/main/resources/reports/mtv_gross_buchholz_trainer.jrxml @@ -0,0 +1,782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <band height="89" splitType="Stretch"> + <staticText> + <reportElement x="0" y="25" width="556" height="15" uuid="38e32426-ceb9-40ee-af7a-ab84b566d96b"/> + <textElement textAlignment="Center"> + <font fontName="Arial" size="12" isBold="false"/> + </textElement> + <text><![CDATA[MTV Groß-Buchholz von 1898 e.V.]]></text> + </staticText> + <staticText> + <reportElement x="0" y="37" width="556" height="15" uuid="88043ee4-db2c-43ca-96f2-fa078918d134"> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + </reportElement> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font size="9"/> + </textElement> + <text><![CDATA[Rotekreuzstraße 25 - 30627 Hannover]]></text> + </staticText> + <staticText> + <reportElement x="376" y="0" width="103" height="10" uuid="7927de72-6eab-475d-821b-5267f0fea03e"> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + <property name="com.jaspersoft.studio.unit.width" value="pixel"/> + </reportElement> + <box> + <topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement verticalAlignment="Middle"> + <font size="8"/> + </textElement> + <text><![CDATA[Lfd Nr. Rechnungsbuch: +]]></text> + </staticText> + <staticText> + <reportElement x="376" y="12" width="103" height="10" uuid="85798559-a680-4640-a1c4-2283b1304317"/> + <textElement verticalAlignment="Middle"> + <font size="8"/> + </textElement> + <text><![CDATA[Datum Rechnungsbuch: +]]></text> + </staticText> + <line> + <reportElement x="474" y="8" width="81" height="1" uuid="b5037544-4ab0-4b5c-a92d-4191bba0a0b1"> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + </reportElement> + </line> + <line> + <reportElement x="474" y="20" width="81" height="1" uuid="788013ff-1f4a-4420-b4b6-3dd9e405eea2"> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + </reportElement> + </line> + <staticText> + <reportElement x="3" y="78" width="550" height="10" uuid="195e05ca-09bb-4890-8444-6cba59da2388"> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + </reportElement> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Arial" size="6"/> + </textElement> + <text><![CDATA[zur Inanspruchnahme eines städtischen Zuschusses zu den Personalkosten von Sportübungsleitern]]></text> + </staticText> + <staticText> + <reportElement x="0" y="72" width="550" height="10" uuid="6e3eed4f-1c4d-4383-a358-c58f73d4d103"> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + </reportElement> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Arial" size="6"/> + </textElement> + <text><![CDATA[zur Vorlage bei der Landeshauptstadt Hannover]]></text> + </staticText> + <staticText> + <reportElement x="0" y="52" width="556" height="21" uuid="762705d5-be9c-476f-b2ff-dc07cab925f9"/> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font size="16" isUnderline="true"/> + </textElement> + <text><![CDATA[Monatsabrechnung Übungsleitervergütung +]]></text> + </staticText> + </band> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 0000000..c5c91aa --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,71 @@ + +CREATE TABLE USER ( + ID INT(11) NOT NULL, + EMAIL VARCHAR(45) NOT NULL, + GIVEN_NAME VARCHAR(45) NOT NULL, + FAMILY_NAME VARCHAR(45) NOT NULL, + PRINCIPAL_ID VARCHAR(45) NOT NULL, + UPDATED TIMESTAMP NOT NULL, + CREATED TIMESTAMP NOT NULL +); + +CREATE TABLE ADRESS ( + ID INT(11) NOT NULL, + ADRESS_TYPE VARCHAR(31) NOT NULL, + ADRESS1 VARCHAR(255) DEFAULT NULL, + ADRESS2 VARCHAR(255) DEFAULT NULL, + ZIP VARCHAR(45) DEFAULT NULL, + CITY VARCHAR(155) DEFAULT NULL, + UPDATED TIMESTAMP NOT NULL, + CREATED TIMESTAMP NOT NULL +); + +CREATE TABLE ARTICLE ( + ID INT(11) NOT NULL, + PRICE DOUBLE NOT NULL, + TITLE VARCHAR(50) NOT NULL, + DESCRIPTION VARCHAR(255) DEFAULT NULL, + USER_ID INT(11) NOT NULL, + REPORT VARCHAR(45) NOT NULL DEFAULT '/REPORTS/MTV_GROSS_BUCHHOLZ.JRXML', + UPDATED TIMESTAMP NOT NULL, + CREATED TIMESTAMP NOT NULL +); + +CREATE TABLE BANKING_CONNECTION ( + ID INT(11) NOT NULL, + OWNER_TYPE VARCHAR(31) NOT NULL, + BANKNAME VARCHAR(255) DEFAULT NULL, + BIC VARCHAR(255) DEFAULT NULL, + IBAN VARCHAR(255) DEFAULT NULL, + UPDATED TIMESTAMP NOT NULL, + CREATED TIMESTAMP NOT NULL +); + +CREATE TABLE INVOICE ( + ID INT(11) NOT NULL, + INVOICE_DATE DATETIME NOT NULL, + INVOICE_ID VARCHAR(150) NOT NULL, + USER_ID INT(11) NOT NULL, + SIGN_IMAGE_PATH VARCHAR(255) DEFAULT NULL, + UPDATED TIMESTAMP NOT NULL, + CREATED TIMESTAMP NOT NULL +); + +CREATE TABLE INVOICE_ITEM ( + ID INT(11) NOT NULL, + START DATETIME NOT NULL, + END VARCHAR(45) NOT NULL, + ARTICLE_ID INT(11) NOT NULL, + PARTICIPANTS VARCHAR(15) DEFAULT NULL, + SUM_PRICE DECIMAL(7,2) NOT NULL, + RECHNUNG_ID INT(11) DEFAULT NULL, + INVOICE_ID INT(11) DEFAULT NULL, + UPDATED TIMESTAMP NOT NULL, + CREATED TIMESTAMP NOT NULL, + TITLE VARCHAR(100) NOT NULL, + DESCRIPTION VARCHAR(255) DEFAULT NULL, + USER_ID INT(11) NOT NULL, + PRICEPERHOUR DECIMAL(7,2) NOT NULL, + REPORT VARCHAR(255) DEFAULT NULL +); +