parent
903453bf41
commit
013df232ec
@ -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<InvoiceItem> itemIterator; |
||||
|
||||
private InvoiceItem currentItem; |
||||
|
||||
public InvoiceReportSource() { |
||||
} |
||||
|
||||
public void setInvoice(Invoice invoice) { |
||||
this.invoice = invoice; |
||||
List<InvoiceItem> 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(); |
||||
} |
||||
} |
||||
} |
||||
@ -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]; |
||||
} |
||||
} |
||||
@ -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<UserBank> bankBinder = new Binder<>(); |
||||
private final Binder<UserAdress> 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<UserBank> bankValidation = bankBinder.validate(); |
||||
|
||||
BinderValidationStatus<UserAdress> 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; |
||||
} |
||||
|
||||
} |
||||
@ -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 |
||||
); |
||||
|
||||
Loading…
Reference in new issue