Erweiterungen
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>de.assecutor.votianlt</groupId>
|
<groupId>de.assecutor.votianlt</groupId>
|
||||||
<artifactId>votianlt</artifactId>
|
<artifactId>votianlt</artifactId>
|
||||||
<version>0.9.4</version>
|
<version>0.9.5</version>
|
||||||
|
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
|||||||
@@ -380,7 +380,11 @@ public class MessageController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean allCompleted = allTasks.stream().allMatch(task -> task.isCompleted());
|
var mandatoryTasks = allTasks.stream().filter(task -> !task.isOptional()).toList();
|
||||||
|
if (mandatoryTasks.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean allCompleted = mandatoryTasks.stream().allMatch(task -> task.isCompleted());
|
||||||
|
|
||||||
if (allCompleted) {
|
if (allCompleted) {
|
||||||
updateJobStatusToCompleted(jobId);
|
updateJobStatusToCompleted(jobId);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.vaadin.flow.component.confirmdialog.ConfirmDialog;
|
|||||||
import com.vaadin.flow.component.dialog.Dialog;
|
import com.vaadin.flow.component.dialog.Dialog;
|
||||||
|
|
||||||
import com.vaadin.flow.component.datepicker.DatePicker;
|
import com.vaadin.flow.component.datepicker.DatePicker;
|
||||||
|
import com.vaadin.flow.component.html.Div;
|
||||||
import com.vaadin.flow.component.html.H2;
|
import com.vaadin.flow.component.html.H2;
|
||||||
import com.vaadin.flow.component.timepicker.TimePicker;
|
import com.vaadin.flow.component.timepicker.TimePicker;
|
||||||
import com.vaadin.flow.component.html.H3;
|
import com.vaadin.flow.component.html.H3;
|
||||||
@@ -797,38 +798,42 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
summaryTitle.getStyle().set("margin", "0");
|
summaryTitle.getStyle().set("margin", "0");
|
||||||
summaryLayout.add(summaryTitle);
|
summaryLayout.add(summaryTitle);
|
||||||
|
|
||||||
// Net total
|
Div priceTable = new Div();
|
||||||
HorizontalLayout netRow = new HorizontalLayout();
|
priceTable.getStyle().set("width", "100%");
|
||||||
netRow.setWidthFull();
|
|
||||||
netRow.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
|
// Net total row
|
||||||
Span netLabel = new Span(getTranslation("addjob.summary.net") + ":");
|
Div netRow = new Div();
|
||||||
|
netRow.getStyle().set("display", "flex").set("justify-content", "space-between").set("padding", "4px 0");
|
||||||
|
Span netLabelSpan = new Span(getTranslation("addjob.summary.net") + ":");
|
||||||
|
netLabelSpan.getStyle().set("padding-right", "8px");
|
||||||
netTotalLabel = new Span("0,00 €");
|
netTotalLabel = new Span("0,00 €");
|
||||||
netTotalLabel.getStyle().set("font-weight", "bold");
|
netTotalLabel.getStyle().set("font-weight", "bold").set("white-space", "nowrap");
|
||||||
netRow.add(netLabel, netTotalLabel);
|
netRow.add(netLabelSpan, netTotalLabel);
|
||||||
summaryLayout.add(netRow);
|
priceTable.add(netRow);
|
||||||
|
|
||||||
// VAT total
|
// VAT total row
|
||||||
HorizontalLayout vatRow = new HorizontalLayout();
|
Div vatRow = new Div();
|
||||||
vatRow.setWidthFull();
|
vatRow.getStyle().set("display", "flex").set("justify-content", "space-between").set("padding", "4px 0");
|
||||||
vatRow.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
|
Span vatLabelSpan = new Span(getTranslation("addjob.summary.vat") + ":");
|
||||||
Span vatLabel = new Span(getTranslation("addjob.summary.vat") + ":");
|
vatLabelSpan.getStyle().set("padding-right", "8px");
|
||||||
vatTotalLabel = new Span("0,00 €");
|
vatTotalLabel = new Span("0,00 €");
|
||||||
vatTotalLabel.getStyle().set("font-weight", "bold");
|
vatTotalLabel.getStyle().set("font-weight", "bold").set("white-space", "nowrap");
|
||||||
vatRow.add(vatLabel, vatTotalLabel);
|
vatRow.add(vatLabelSpan, vatTotalLabel);
|
||||||
summaryLayout.add(vatRow);
|
priceTable.add(vatRow);
|
||||||
|
|
||||||
// Gross total
|
// Gross total row
|
||||||
HorizontalLayout grossRow = new HorizontalLayout();
|
Div grossRow = new Div();
|
||||||
grossRow.setWidthFull();
|
grossRow.getStyle().set("display", "flex").set("justify-content", "space-between").set("padding", "4px 0");
|
||||||
grossRow.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
|
Span grossLabelSpan = new Span(getTranslation("addjob.summary.gross") + ":");
|
||||||
Span grossLabel = new Span(getTranslation("addjob.summary.gross") + ":");
|
grossLabelSpan.getStyle().set("padding-right", "8px").set("font-weight", "bold");
|
||||||
grossLabel.getStyle().set("font-size", "var(--lumo-font-size-l)");
|
|
||||||
grossTotalLabel = new Span("0,00 €");
|
grossTotalLabel = new Span("0,00 €");
|
||||||
grossTotalLabel.getStyle().set("font-size", "var(--lumo-font-size-l)");
|
grossTotalLabel.getStyle().set("font-size", "var(--lumo-font-size-l)");
|
||||||
grossTotalLabel.getStyle().set("font-weight", "bold");
|
grossTotalLabel.getStyle().set("font-weight", "bold");
|
||||||
grossTotalLabel.getStyle().set("color", "var(--lumo-primary-text-color)");
|
grossTotalLabel.getStyle().set("color", "var(--lumo-primary-text-color)").set("white-space", "nowrap");
|
||||||
grossRow.add(grossLabel, grossTotalLabel);
|
grossRow.add(grossLabelSpan, grossTotalLabel);
|
||||||
summaryLayout.add(grossRow);
|
priceTable.add(grossRow);
|
||||||
|
|
||||||
|
summaryLayout.add(priceTable);
|
||||||
|
|
||||||
content.add(summaryLayout);
|
content.add(summaryLayout);
|
||||||
|
|
||||||
|
|||||||
@@ -316,24 +316,40 @@ public class CreateInvoiceView extends VerticalLayout implements HasUrlParameter
|
|||||||
BigDecimal vatAmount = netAmount.multiply(vatRate);
|
BigDecimal vatAmount = netAmount.multiply(vatRate);
|
||||||
BigDecimal totalAmount = netAmount.add(vatAmount);
|
BigDecimal totalAmount = netAmount.add(vatAmount);
|
||||||
|
|
||||||
VerticalLayout summaryInfo = new VerticalLayout();
|
Div priceTable = new Div();
|
||||||
summaryInfo.setSpacing(true);
|
priceTable.getStyle().set("width", "100%");
|
||||||
summaryInfo.setWidthFull();
|
|
||||||
|
|
||||||
// Show only net sum, VAT sums, and total amount without individual services
|
priceTable.add(createPriceRow(getTranslation("createinvoice.summary.net") + ":",
|
||||||
summaryInfo.add(new HorizontalLayout(new Span(getTranslation("createinvoice.summary.net")),
|
netAmount.setScale(2, RoundingMode.HALF_UP) + " €", false));
|
||||||
new Span(netAmount.setScale(2, RoundingMode.HALF_UP) + " €")));
|
priceTable.add(createPriceRow(
|
||||||
summaryInfo.add(new HorizontalLayout(
|
getTranslation("createinvoice.summary.vat",
|
||||||
new Span(getTranslation("createinvoice.summary.vat",
|
vatRate.multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).toString()) + ":",
|
||||||
vatRate.multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).toString())),
|
vatAmount.setScale(2, RoundingMode.HALF_UP) + " €", false));
|
||||||
new Span(vatAmount.setScale(2, RoundingMode.HALF_UP) + " €")));
|
priceTable.add(createPriceRow(getTranslation("createinvoice.summary.total") + ":",
|
||||||
summaryInfo.add(new HorizontalLayout(new Span(getTranslation("createinvoice.summary.total")),
|
totalAmount.setScale(2, RoundingMode.HALF_UP) + " €", true));
|
||||||
new Span(totalAmount.setScale(2, RoundingMode.HALF_UP) + " €")));
|
|
||||||
|
|
||||||
section.add(summaryInfo);
|
section.add(priceTable);
|
||||||
return section;
|
return section;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Div createPriceRow(String label, String value, boolean bold) {
|
||||||
|
Div row = new Div();
|
||||||
|
row.getStyle().set("display", "flex").set("justify-content", "space-between").set("padding", "4px 0");
|
||||||
|
|
||||||
|
Span labelSpan = new Span(label);
|
||||||
|
labelSpan.getStyle().set("padding-right", "8px");
|
||||||
|
|
||||||
|
Span valueSpan = new Span(value);
|
||||||
|
valueSpan.getStyle().set("white-space", "nowrap");
|
||||||
|
if (bold) {
|
||||||
|
labelSpan.getStyle().set("font-weight", "bold");
|
||||||
|
valueSpan.getStyle().set("font-weight", "bold");
|
||||||
|
}
|
||||||
|
|
||||||
|
row.add(labelSpan, valueSpan);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
private BigDecimal calculateServicePrice(Service service) {
|
private BigDecimal calculateServicePrice(Service service) {
|
||||||
if (service.getCalculationBasis() == null) {
|
if (service.getCalculationBasis() == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -271,9 +271,15 @@ public class JobSummaryView extends Main implements HasUrlParameter<String>, Has
|
|||||||
|
|
||||||
// Preis basierend auf den hinterlegten Leistungen berechnen
|
// Preis basierend auf den hinterlegten Leistungen berechnen
|
||||||
PriceCalculationResult priceResult = calculatePriceFromServices(job);
|
PriceCalculationResult priceResult = calculatePriceFromServices(job);
|
||||||
infoBox.add(new Span(getTranslation("jobsummary.info.netto") + ": " + formatPrice(priceResult.netAmount())));
|
|
||||||
infoBox.add(new Span(getTranslation("jobsummary.info.ust") + ": " + formatPrice(priceResult.vatAmount())));
|
Div priceTable = new Div();
|
||||||
infoBox.add(new Span(getTranslation("jobsummary.info.gesamt") + ": " + formatPrice(priceResult.totalAmount())));
|
priceTable.getStyle().set("width", "100%");
|
||||||
|
|
||||||
|
priceTable.add(createPriceRow(getTranslation("jobsummary.info.netto") + ":", formatPrice(priceResult.netAmount()), false));
|
||||||
|
priceTable.add(createPriceRow(getTranslation("jobsummary.info.ust") + ":", formatPrice(priceResult.vatAmount()), false));
|
||||||
|
priceTable.add(createPriceRow(getTranslation("jobsummary.info.gesamt") + ":", formatPrice(priceResult.totalAmount()), true));
|
||||||
|
|
||||||
|
infoBox.add(priceTable);
|
||||||
|
|
||||||
if (job.getRemark() != null && !job.getRemark().isBlank()) {
|
if (job.getRemark() != null && !job.getRemark().isBlank()) {
|
||||||
infoBox.add(new Span(getTranslation("jobsummary.info.bemerkung") + ": " + job.getRemark()));
|
infoBox.add(new Span(getTranslation("jobsummary.info.bemerkung") + ": " + job.getRemark()));
|
||||||
@@ -411,6 +417,24 @@ public class JobSummaryView extends Main implements HasUrlParameter<String>, Has
|
|||||||
return nf.format(price);
|
return nf.format(price);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Div createPriceRow(String label, String value, boolean bold) {
|
||||||
|
Div row = new Div();
|
||||||
|
row.getStyle().set("display", "flex").set("justify-content", "space-between").set("padding", "4px 0");
|
||||||
|
|
||||||
|
Span labelSpan = new Span(label);
|
||||||
|
labelSpan.getStyle().set("padding-right", "8px");
|
||||||
|
|
||||||
|
Span valueSpan = new Span(value);
|
||||||
|
valueSpan.getStyle().set("white-space", "nowrap");
|
||||||
|
if (bold) {
|
||||||
|
labelSpan.getStyle().set("font-weight", "bold");
|
||||||
|
valueSpan.getStyle().set("font-weight", "bold");
|
||||||
|
}
|
||||||
|
|
||||||
|
row.add(labelSpan, valueSpan);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
private String resolveAppUserName(String appUserIdString) {
|
private String resolveAppUserName(String appUserIdString) {
|
||||||
try {
|
try {
|
||||||
ObjectId id = new ObjectId(appUserIdString);
|
ObjectId id = new ObjectId(appUserIdString);
|
||||||
|
|||||||
@@ -625,6 +625,7 @@ jobs.notification.deleted=Auftrag {0} wurde gelöscht
|
|||||||
jobs.notification.delete.error=Fehler beim Löschen: {0}
|
jobs.notification.delete.error=Fehler beim Löschen: {0}
|
||||||
|
|
||||||
# Create Invoice
|
# Create Invoice
|
||||||
|
createinvoice.title=Rechnung erstellen \u2013 Auftrag {0}
|
||||||
createinvoice.error.invalidid=Ungültige Job-ID
|
createinvoice.error.invalidid=Ungültige Job-ID
|
||||||
createinvoice.error.notfound=Job nicht gefunden
|
createinvoice.error.notfound=Job nicht gefunden
|
||||||
createinvoice.button.create=Rechnung erstellen
|
createinvoice.button.create=Rechnung erstellen
|
||||||
@@ -641,6 +642,7 @@ createinvoice.route.duration=Fahrtzeit
|
|||||||
createinvoice.column.service=Leistung
|
createinvoice.column.service=Leistung
|
||||||
createinvoice.column.basis=Berechnungsbasis
|
createinvoice.column.basis=Berechnungsbasis
|
||||||
createinvoice.summary.net=Nettosumme
|
createinvoice.summary.net=Nettosumme
|
||||||
|
createinvoice.summary.vat=MwSt. ({0}%)
|
||||||
createinvoice.summary.total=Gesamtsumme
|
createinvoice.summary.total=Gesamtsumme
|
||||||
createinvoice.notification.noservices=Bitte wählen Sie mindestens eine Leistung aus
|
createinvoice.notification.noservices=Bitte wählen Sie mindestens eine Leistung aus
|
||||||
createinvoice.notification.nouser=Benutzer nicht gefunden
|
createinvoice.notification.nouser=Benutzer nicht gefunden
|
||||||
|
|||||||
@@ -625,6 +625,7 @@ jobs.notification.deleted=Job {0} deleted
|
|||||||
jobs.notification.delete.error=Error deleting job: {0}
|
jobs.notification.delete.error=Error deleting job: {0}
|
||||||
|
|
||||||
# Create Invoice
|
# Create Invoice
|
||||||
|
createinvoice.title=Create Invoice \u2013 Job {0}
|
||||||
createinvoice.error.invalidid=Invalid Job ID
|
createinvoice.error.invalidid=Invalid Job ID
|
||||||
createinvoice.error.notfound=Job not found
|
createinvoice.error.notfound=Job not found
|
||||||
createinvoice.button.create=Create Invoice
|
createinvoice.button.create=Create Invoice
|
||||||
@@ -641,6 +642,7 @@ createinvoice.route.duration=Duration
|
|||||||
createinvoice.column.service=Service
|
createinvoice.column.service=Service
|
||||||
createinvoice.column.basis=Calculation Basis
|
createinvoice.column.basis=Calculation Basis
|
||||||
createinvoice.summary.net=Net Total
|
createinvoice.summary.net=Net Total
|
||||||
|
createinvoice.summary.vat=VAT ({0}%)
|
||||||
createinvoice.summary.total=Total Amount
|
createinvoice.summary.total=Total Amount
|
||||||
createinvoice.notification.noservices=Please select at least one service
|
createinvoice.notification.noservices=Please select at least one service
|
||||||
createinvoice.notification.nouser=User not found
|
createinvoice.notification.nouser=User not found
|
||||||
|
|||||||
@@ -625,6 +625,7 @@ jobs.notification.deleted=Trabajo {0} eliminado
|
|||||||
jobs.notification.delete.error=Error al eliminar trabajo: {0}
|
jobs.notification.delete.error=Error al eliminar trabajo: {0}
|
||||||
|
|
||||||
# Create Invoice
|
# Create Invoice
|
||||||
|
createinvoice.title=Crear Factura \u2013 Trabajo {0}
|
||||||
createinvoice.error.invalidid=ID de Trabajo Inválido
|
createinvoice.error.invalidid=ID de Trabajo Inválido
|
||||||
createinvoice.error.notfound=Trabajo no encontrado
|
createinvoice.error.notfound=Trabajo no encontrado
|
||||||
createinvoice.button.create=Crear Factura
|
createinvoice.button.create=Crear Factura
|
||||||
@@ -641,6 +642,7 @@ createinvoice.route.duration=Duración
|
|||||||
createinvoice.column.service=Servicio
|
createinvoice.column.service=Servicio
|
||||||
createinvoice.column.basis=Base de Cálculo
|
createinvoice.column.basis=Base de Cálculo
|
||||||
createinvoice.summary.net=Total Neto
|
createinvoice.summary.net=Total Neto
|
||||||
|
createinvoice.summary.vat=IVA ({0}%)
|
||||||
createinvoice.summary.total=Total General
|
createinvoice.summary.total=Total General
|
||||||
createinvoice.notification.noservices=Por favor seleccione al menos un servicio
|
createinvoice.notification.noservices=Por favor seleccione al menos un servicio
|
||||||
createinvoice.notification.nouser=Usuario no encontrado
|
createinvoice.notification.nouser=Usuario no encontrado
|
||||||
|
|||||||
@@ -625,6 +625,7 @@ jobs.notification.deleted=Emploi {0} supprimé
|
|||||||
jobs.notification.delete.error=Erreur lors de la suppression : {0}
|
jobs.notification.delete.error=Erreur lors de la suppression : {0}
|
||||||
|
|
||||||
# Create Invoice
|
# Create Invoice
|
||||||
|
createinvoice.title=Cr\u00e9er une Facture \u2013 Travail {0}
|
||||||
createinvoice.error.invalidid=ID d'Emploi Invalide
|
createinvoice.error.invalidid=ID d'Emploi Invalide
|
||||||
createinvoice.error.notfound=Emploi non trouvé
|
createinvoice.error.notfound=Emploi non trouvé
|
||||||
createinvoice.button.create=Créer une Facture
|
createinvoice.button.create=Créer une Facture
|
||||||
@@ -640,7 +641,8 @@ createinvoice.route.distance=Distance
|
|||||||
createinvoice.route.duration=Durée
|
createinvoice.route.duration=Durée
|
||||||
createinvoice.column.service=Service
|
createinvoice.column.service=Service
|
||||||
createinvoice.column.basis=Base de Calcul
|
createinvoice.column.basis=Base de Calcul
|
||||||
createsummary.net=Total Net
|
createinvoice.summary.net=Total Net
|
||||||
|
createinvoice.summary.vat=TVA ({0}%)
|
||||||
createinvoice.summary.total=Montant Total
|
createinvoice.summary.total=Montant Total
|
||||||
createinvoice.notification.noservices=Veuillez sélectionner au moins un service
|
createinvoice.notification.noservices=Veuillez sélectionner au moins un service
|
||||||
createinvoice.notification.nouser=Utilisateur non trouvé
|
createinvoice.notification.nouser=Utilisateur non trouvé
|
||||||
|
|||||||
Reference in New Issue
Block a user