Erweiterungen
This commit is contained in:
@@ -380,7 +380,11 @@ public class MessageController {
|
||||
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) {
|
||||
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.datepicker.DatePicker;
|
||||
import com.vaadin.flow.component.html.Div;
|
||||
import com.vaadin.flow.component.html.H2;
|
||||
import com.vaadin.flow.component.timepicker.TimePicker;
|
||||
import com.vaadin.flow.component.html.H3;
|
||||
@@ -797,38 +798,42 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
||||
summaryTitle.getStyle().set("margin", "0");
|
||||
summaryLayout.add(summaryTitle);
|
||||
|
||||
// Net total
|
||||
HorizontalLayout netRow = new HorizontalLayout();
|
||||
netRow.setWidthFull();
|
||||
netRow.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
|
||||
Span netLabel = new Span(getTranslation("addjob.summary.net") + ":");
|
||||
Div priceTable = new Div();
|
||||
priceTable.getStyle().set("width", "100%");
|
||||
|
||||
// Net total row
|
||||
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.getStyle().set("font-weight", "bold");
|
||||
netRow.add(netLabel, netTotalLabel);
|
||||
summaryLayout.add(netRow);
|
||||
netTotalLabel.getStyle().set("font-weight", "bold").set("white-space", "nowrap");
|
||||
netRow.add(netLabelSpan, netTotalLabel);
|
||||
priceTable.add(netRow);
|
||||
|
||||
// VAT total
|
||||
HorizontalLayout vatRow = new HorizontalLayout();
|
||||
vatRow.setWidthFull();
|
||||
vatRow.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
|
||||
Span vatLabel = new Span(getTranslation("addjob.summary.vat") + ":");
|
||||
// VAT total row
|
||||
Div vatRow = new Div();
|
||||
vatRow.getStyle().set("display", "flex").set("justify-content", "space-between").set("padding", "4px 0");
|
||||
Span vatLabelSpan = new Span(getTranslation("addjob.summary.vat") + ":");
|
||||
vatLabelSpan.getStyle().set("padding-right", "8px");
|
||||
vatTotalLabel = new Span("0,00 €");
|
||||
vatTotalLabel.getStyle().set("font-weight", "bold");
|
||||
vatRow.add(vatLabel, vatTotalLabel);
|
||||
summaryLayout.add(vatRow);
|
||||
vatTotalLabel.getStyle().set("font-weight", "bold").set("white-space", "nowrap");
|
||||
vatRow.add(vatLabelSpan, vatTotalLabel);
|
||||
priceTable.add(vatRow);
|
||||
|
||||
// Gross total
|
||||
HorizontalLayout grossRow = new HorizontalLayout();
|
||||
grossRow.setWidthFull();
|
||||
grossRow.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
|
||||
Span grossLabel = new Span(getTranslation("addjob.summary.gross") + ":");
|
||||
grossLabel.getStyle().set("font-size", "var(--lumo-font-size-l)");
|
||||
// Gross total row
|
||||
Div grossRow = new Div();
|
||||
grossRow.getStyle().set("display", "flex").set("justify-content", "space-between").set("padding", "4px 0");
|
||||
Span grossLabelSpan = new Span(getTranslation("addjob.summary.gross") + ":");
|
||||
grossLabelSpan.getStyle().set("padding-right", "8px").set("font-weight", "bold");
|
||||
grossTotalLabel = new Span("0,00 €");
|
||||
grossTotalLabel.getStyle().set("font-size", "var(--lumo-font-size-l)");
|
||||
grossTotalLabel.getStyle().set("font-weight", "bold");
|
||||
grossTotalLabel.getStyle().set("color", "var(--lumo-primary-text-color)");
|
||||
grossRow.add(grossLabel, grossTotalLabel);
|
||||
summaryLayout.add(grossRow);
|
||||
grossTotalLabel.getStyle().set("color", "var(--lumo-primary-text-color)").set("white-space", "nowrap");
|
||||
grossRow.add(grossLabelSpan, grossTotalLabel);
|
||||
priceTable.add(grossRow);
|
||||
|
||||
summaryLayout.add(priceTable);
|
||||
|
||||
content.add(summaryLayout);
|
||||
|
||||
|
||||
@@ -316,24 +316,40 @@ public class CreateInvoiceView extends VerticalLayout implements HasUrlParameter
|
||||
BigDecimal vatAmount = netAmount.multiply(vatRate);
|
||||
BigDecimal totalAmount = netAmount.add(vatAmount);
|
||||
|
||||
VerticalLayout summaryInfo = new VerticalLayout();
|
||||
summaryInfo.setSpacing(true);
|
||||
summaryInfo.setWidthFull();
|
||||
Div priceTable = new Div();
|
||||
priceTable.getStyle().set("width", "100%");
|
||||
|
||||
// Show only net sum, VAT sums, and total amount without individual services
|
||||
summaryInfo.add(new HorizontalLayout(new Span(getTranslation("createinvoice.summary.net")),
|
||||
new Span(netAmount.setScale(2, RoundingMode.HALF_UP) + " €")));
|
||||
summaryInfo.add(new HorizontalLayout(
|
||||
new Span(getTranslation("createinvoice.summary.vat",
|
||||
vatRate.multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).toString())),
|
||||
new Span(vatAmount.setScale(2, RoundingMode.HALF_UP) + " €")));
|
||||
summaryInfo.add(new HorizontalLayout(new Span(getTranslation("createinvoice.summary.total")),
|
||||
new Span(totalAmount.setScale(2, RoundingMode.HALF_UP) + " €")));
|
||||
priceTable.add(createPriceRow(getTranslation("createinvoice.summary.net") + ":",
|
||||
netAmount.setScale(2, RoundingMode.HALF_UP) + " €", false));
|
||||
priceTable.add(createPriceRow(
|
||||
getTranslation("createinvoice.summary.vat",
|
||||
vatRate.multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).toString()) + ":",
|
||||
vatAmount.setScale(2, RoundingMode.HALF_UP) + " €", false));
|
||||
priceTable.add(createPriceRow(getTranslation("createinvoice.summary.total") + ":",
|
||||
totalAmount.setScale(2, RoundingMode.HALF_UP) + " €", true));
|
||||
|
||||
section.add(summaryInfo);
|
||||
section.add(priceTable);
|
||||
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) {
|
||||
if (service.getCalculationBasis() == null) {
|
||||
return null;
|
||||
|
||||
@@ -271,9 +271,15 @@ public class JobSummaryView extends Main implements HasUrlParameter<String>, Has
|
||||
|
||||
// Preis basierend auf den hinterlegten Leistungen berechnen
|
||||
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())));
|
||||
infoBox.add(new Span(getTranslation("jobsummary.info.gesamt") + ": " + formatPrice(priceResult.totalAmount())));
|
||||
|
||||
Div priceTable = new Div();
|
||||
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()) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
try {
|
||||
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}
|
||||
|
||||
# Create Invoice
|
||||
createinvoice.title=Rechnung erstellen \u2013 Auftrag {0}
|
||||
createinvoice.error.invalidid=Ungültige Job-ID
|
||||
createinvoice.error.notfound=Job nicht gefunden
|
||||
createinvoice.button.create=Rechnung erstellen
|
||||
@@ -641,6 +642,7 @@ createinvoice.route.duration=Fahrtzeit
|
||||
createinvoice.column.service=Leistung
|
||||
createinvoice.column.basis=Berechnungsbasis
|
||||
createinvoice.summary.net=Nettosumme
|
||||
createinvoice.summary.vat=MwSt. ({0}%)
|
||||
createinvoice.summary.total=Gesamtsumme
|
||||
createinvoice.notification.noservices=Bitte wählen Sie mindestens eine Leistung aus
|
||||
createinvoice.notification.nouser=Benutzer nicht gefunden
|
||||
|
||||
@@ -625,6 +625,7 @@ jobs.notification.deleted=Job {0} deleted
|
||||
jobs.notification.delete.error=Error deleting job: {0}
|
||||
|
||||
# Create Invoice
|
||||
createinvoice.title=Create Invoice \u2013 Job {0}
|
||||
createinvoice.error.invalidid=Invalid Job ID
|
||||
createinvoice.error.notfound=Job not found
|
||||
createinvoice.button.create=Create Invoice
|
||||
@@ -641,6 +642,7 @@ createinvoice.route.duration=Duration
|
||||
createinvoice.column.service=Service
|
||||
createinvoice.column.basis=Calculation Basis
|
||||
createinvoice.summary.net=Net Total
|
||||
createinvoice.summary.vat=VAT ({0}%)
|
||||
createinvoice.summary.total=Total Amount
|
||||
createinvoice.notification.noservices=Please select at least one service
|
||||
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}
|
||||
|
||||
# Create Invoice
|
||||
createinvoice.title=Crear Factura \u2013 Trabajo {0}
|
||||
createinvoice.error.invalidid=ID de Trabajo Inválido
|
||||
createinvoice.error.notfound=Trabajo no encontrado
|
||||
createinvoice.button.create=Crear Factura
|
||||
@@ -641,6 +642,7 @@ createinvoice.route.duration=Duración
|
||||
createinvoice.column.service=Servicio
|
||||
createinvoice.column.basis=Base de Cálculo
|
||||
createinvoice.summary.net=Total Neto
|
||||
createinvoice.summary.vat=IVA ({0}%)
|
||||
createinvoice.summary.total=Total General
|
||||
createinvoice.notification.noservices=Por favor seleccione al menos un servicio
|
||||
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}
|
||||
|
||||
# Create Invoice
|
||||
createinvoice.title=Cr\u00e9er une Facture \u2013 Travail {0}
|
||||
createinvoice.error.invalidid=ID d'Emploi Invalide
|
||||
createinvoice.error.notfound=Emploi non trouvé
|
||||
createinvoice.button.create=Créer une Facture
|
||||
@@ -640,7 +641,8 @@ createinvoice.route.distance=Distance
|
||||
createinvoice.route.duration=Durée
|
||||
createinvoice.column.service=Service
|
||||
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.notification.noservices=Veuillez sélectionner au moins un service
|
||||
createinvoice.notification.nouser=Utilisateur non trouvé
|
||||
|
||||
Reference in New Issue
Block a user