Erweiterungen
This commit is contained in:
@@ -51,4 +51,7 @@ public class Customer
|
||||
|
||||
@Field("created_by")
|
||||
private ObjectId createdBy;
|
||||
|
||||
@Field("owner")
|
||||
private ObjectId owner;
|
||||
}
|
||||
@@ -5,9 +5,12 @@ import org.bson.types.ObjectId;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import java.util.List;
|
||||
|
||||
public interface CustomerRepository extends MongoRepository<Customer, ObjectId> {
|
||||
|
||||
// If you don't need a total row count, Slice is better than Page.
|
||||
Slice<Customer> findAllBy(Pageable pageable);
|
||||
|
||||
List<Customer> findByOwner(ObjectId owner);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ public class AddCustomerService {
|
||||
// Setze den aktuellen Benutzer als Ersteller - jetzt direkt aus der Session
|
||||
de.assecutor.votianlt.model.User currentUser = securityService.getCurrentDatabaseUser();
|
||||
customer.setCreatedBy(currentUser.getId());
|
||||
customer.setOwner(currentUser.getId());
|
||||
|
||||
addCustomerRepository.save(customer);
|
||||
}
|
||||
|
||||
@@ -8,15 +8,18 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import org.bson.types.ObjectId;
|
||||
import de.assecutor.votianlt.security.SecurityService;
|
||||
|
||||
@Service
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public class CustomerService {
|
||||
|
||||
private final CustomerRepository todoRepository;
|
||||
private final SecurityService securityService;
|
||||
|
||||
CustomerService(CustomerRepository todoRepository) {
|
||||
CustomerService(CustomerRepository todoRepository, SecurityService securityService) {
|
||||
this.todoRepository = todoRepository;
|
||||
this.securityService = securityService;
|
||||
}
|
||||
|
||||
public List<Customer> list(org.springframework.data.domain.Pageable pageable) {
|
||||
@@ -29,6 +32,11 @@ public class CustomerService {
|
||||
return todoRepository.findAll();
|
||||
}
|
||||
|
||||
public List<Customer> findAllForCurrentOwner() {
|
||||
ObjectId ownerId = securityService.getCurrentUserId();
|
||||
return todoRepository.findByOwner(ownerId);
|
||||
}
|
||||
|
||||
public Customer save(Customer customer) {
|
||||
return todoRepository.save(customer);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,10 @@ import com.vaadin.flow.theme.lumo.LumoUtility;
|
||||
import de.assecutor.votianlt.model.Job;
|
||||
import de.assecutor.votianlt.model.TaskEntry;
|
||||
import de.assecutor.votianlt.pages.service.AddJobService;
|
||||
import de.assecutor.votianlt.pages.service.CustomerService;
|
||||
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
|
||||
import de.assecutor.votianlt.pages.service.AddCustomerService;
|
||||
import de.assecutor.votianlt.model.Customer;
|
||||
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -49,6 +52,8 @@ import java.util.Optional;
|
||||
public class AddJobView extends Main {
|
||||
|
||||
private final AddJobService addJobService;
|
||||
private final CustomerService customerService;
|
||||
private final AddCustomerService addCustomerService;
|
||||
|
||||
// Customer selection
|
||||
private ComboBox<String> customerSelection;
|
||||
@@ -116,10 +121,14 @@ public class AddJobView extends Main {
|
||||
|
||||
private final Binder<Job> binder = new Binder<>(Job.class);
|
||||
|
||||
public AddJobView(AddJobService addJobService) {
|
||||
// Mapping für die Anzeige-Labels der Kunden zur Entität
|
||||
private Map<String, Customer> customerLabelToEntity = new LinkedHashMap<>();
|
||||
|
||||
public AddJobView(AddJobService addJobService, AddCustomerService addCustomerService, CustomerService customerService) {
|
||||
this.addJobService = addJobService;
|
||||
this.addCustomerService = addCustomerService;
|
||||
this.customerService = customerService;
|
||||
initializeComponents();
|
||||
populateTestData(); // Pre-populate all required fields with test data
|
||||
setupLayout();
|
||||
setupValidation();
|
||||
loadDraftIfExists();
|
||||
@@ -128,9 +137,56 @@ public class AddJobView extends Main {
|
||||
private void initializeComponents() {
|
||||
// Customer selection
|
||||
customerSelection = new ComboBox<>("Auftraggeber/Rechnungsempfänger");
|
||||
customerSelection.setItems("Kunde01 | KOTVor K01Nach");
|
||||
customerSelection.setPlaceholder("Wählen Sie einen Auftraggeber aus...");
|
||||
customerSelection.setWidthFull();
|
||||
// Mit Kunden des angemeldeten Benutzers befüllen und Mapping aufbauen
|
||||
List<Customer> ownerCustomers = customerService.findAllForCurrentOwner();
|
||||
customerLabelToEntity.clear();
|
||||
for (Customer c : ownerCustomers) {
|
||||
String label = (c.getCompanyName() != null && !c.getCompanyName().isBlank())
|
||||
? c.getCompanyName() + " | " +
|
||||
((c.getFirstname() != null ? c.getFirstname() : "") + " " + (c.getLastName() != null ? c.getLastName() : "")).trim()
|
||||
: ((c.getFirstname() != null ? c.getFirstname() : "") + " " + (c.getLastName() != null ? c.getLastName() : "")).trim();
|
||||
if (label.isBlank()) {
|
||||
label = "Unbenannter Kunde";
|
||||
}
|
||||
// Bei Duplikaten Label einzigartig machen
|
||||
String uniqueLabel = label;
|
||||
int counter = 2;
|
||||
while (customerLabelToEntity.containsKey(uniqueLabel)) {
|
||||
uniqueLabel = label + " (" + counter++ + ")";
|
||||
}
|
||||
customerLabelToEntity.put(uniqueLabel, c);
|
||||
}
|
||||
customerSelection.setItems(new ArrayList<>(customerLabelToEntity.keySet()));
|
||||
|
||||
// Bei Auswahl eines Kunden Abholfelder befüllen
|
||||
customerSelection.addValueChangeListener(ev -> {
|
||||
String selected = ev.getValue();
|
||||
if (selected == null) return;
|
||||
Customer c = customerLabelToEntity.get(selected);
|
||||
if (c == null) return;
|
||||
|
||||
// Firma
|
||||
if (c.getCompanyName() != null) { pickupCompany.setValue(c.getCompanyName()); } else { pickupCompany.clear(); }
|
||||
// Anrede (nur setzen, wenn vorhanden und zulässig)
|
||||
if (c.getTitle() != null && ("Herr".equalsIgnoreCase(c.getTitle()) || "Frau".equalsIgnoreCase(c.getTitle()) || "Divers".equalsIgnoreCase(c.getTitle()))) {
|
||||
pickupSalutation.setValue(c.getTitle());
|
||||
} else {
|
||||
pickupSalutation.clear();
|
||||
}
|
||||
// Namen
|
||||
if (c.getFirstname() != null) { pickupFirstName.setValue(c.getFirstname()); } else { pickupFirstName.clear(); }
|
||||
if (c.getLastName() != null) { pickupLastName.setValue(c.getLastName()); } else { pickupLastName.clear(); }
|
||||
// Telefon
|
||||
if (c.getTelephone() != null) { pickupPhone.setValue(c.getTelephone()); } else { pickupPhone.clear(); }
|
||||
// Adresse
|
||||
if (c.getStreet() != null) { pickupStreet.setValue(c.getStreet()); } else { pickupStreet.clear(); }
|
||||
if (c.getHouseNumber() != null) { pickupHouseNumber.setValue(c.getHouseNumber()); } else { pickupHouseNumber.clear(); }
|
||||
if (c.getAddressAddition() != null) { pickupAddressAddition.setValue(c.getAddressAddition()); } else { pickupAddressAddition.clear(); }
|
||||
if (c.getZip() != null) { pickupZip.setValue(c.getZip()); } else { pickupZip.clear(); }
|
||||
if (c.getCity() != null) { pickupCity.setValue(c.getCity()); } else { pickupCity.clear(); }
|
||||
});
|
||||
|
||||
preloadAddressButton = new Button("Vorbelegte Adressfelder leeren");
|
||||
preloadAddressButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
@@ -138,30 +194,29 @@ public class AddJobView extends Main {
|
||||
|
||||
// Pickup address
|
||||
pickupCompany = new TextField("Firma");
|
||||
pickupCompany.setPlaceholder("z.B. IKEA, McDonald's, DHL...");
|
||||
pickupCompany.setValue("Test Abholfirma GmbH");
|
||||
pickupCompany.setPlaceholder("Firmenname");
|
||||
addGooglePlacesAutocomplete(pickupCompany, 0); // Stage 0 für Pickup
|
||||
pickupSalutation = new ComboBox<>("Anrede");
|
||||
pickupSalutation.setItems("Herr", "Frau", "Divers");
|
||||
pickupSalutation.setPlaceholder("Anrede wählen...");
|
||||
pickupFirstName = new TextField("Vorname");
|
||||
pickupFirstName.setPlaceholder("Max");
|
||||
pickupFirstName.setPlaceholder("Vorname");
|
||||
pickupFirstName.setRequiredIndicatorVisible(true);
|
||||
pickupLastName = new TextField("Nachname");
|
||||
pickupLastName.setPlaceholder("Mustermann");
|
||||
pickupLastName.setPlaceholder("Nachname");
|
||||
pickupLastName.setRequiredIndicatorVisible(true);
|
||||
pickupPhone = new TextField("Telefonnummer");
|
||||
pickupPhone.setPlaceholder("+49 123 456789");
|
||||
pickupPhone.setPlaceholder("Telefonnummer");
|
||||
pickupStreet = new TextField("Straße");
|
||||
pickupStreet.setPlaceholder("Musterstraße");
|
||||
pickupStreet.setRequiredIndicatorVisible(true);
|
||||
pickupHouseNumber = new TextField("Hausnummer");
|
||||
pickupHouseNumber.setPlaceholder("123");
|
||||
pickupHouseNumber.setPlaceholder("Hausnummer");
|
||||
pickupHouseNumber.setRequiredIndicatorVisible(true);
|
||||
pickupAddressAddition = new TextField("Adresszusatz");
|
||||
pickupAddressAddition.setPlaceholder("2. OG, Hinterhaus...");
|
||||
pickupZip = new TextField("Postleitzahl");
|
||||
pickupZip.setPlaceholder("12345");
|
||||
pickupZip.setPlaceholder("Postleitzahl");
|
||||
pickupZip.setRequiredIndicatorVisible(true);
|
||||
pickupCity = new TextField("Ort");
|
||||
pickupCity.setPlaceholder("Hamburg");
|
||||
@@ -170,30 +225,29 @@ public class AddJobView extends Main {
|
||||
|
||||
// Delivery address
|
||||
deliveryCompany = new TextField("Firma");
|
||||
deliveryCompany.setPlaceholder("z.B. EDEKA, Bauhaus, Amazon...");
|
||||
deliveryCompany.setValue("Test Lieferfirma AG");
|
||||
deliveryCompany.setPlaceholder("Firmenname");
|
||||
addGooglePlacesAutocomplete(deliveryCompany, 1); // Stage 1 für Delivery
|
||||
deliverySalutation = new ComboBox<>("Anrede");
|
||||
deliverySalutation.setItems("Herr", "Frau", "Divers");
|
||||
deliverySalutation.setPlaceholder("Anrede wählen...");
|
||||
deliveryFirstName = new TextField("Vorname");
|
||||
deliveryFirstName.setPlaceholder("Anna");
|
||||
deliveryFirstName.setPlaceholder("Vorname");
|
||||
deliveryFirstName.setRequiredIndicatorVisible(true);
|
||||
deliveryLastName = new TextField("Nachname");
|
||||
deliveryLastName.setPlaceholder("Beispiel");
|
||||
deliveryLastName.setPlaceholder("Nachname");
|
||||
deliveryLastName.setRequiredIndicatorVisible(true);
|
||||
deliveryPhone = new TextField("Telefonnummer");
|
||||
deliveryPhone.setPlaceholder("+49 987 654321");
|
||||
deliveryPhone.setPlaceholder("Telefonnummer");
|
||||
deliveryStreet = new TextField("Straße");
|
||||
deliveryStreet.setPlaceholder("Beispielweg");
|
||||
deliveryStreet.setRequiredIndicatorVisible(true);
|
||||
deliveryHouseNumber = new TextField("Hausnr");
|
||||
deliveryHouseNumber.setPlaceholder("456");
|
||||
deliveryHouseNumber.setPlaceholder("Hausnummer");
|
||||
deliveryHouseNumber.setRequiredIndicatorVisible(true);
|
||||
deliveryAddressAddition = new TextField("Adresszusatz");
|
||||
deliveryAddressAddition.setPlaceholder("Erdgeschoss, links...");
|
||||
deliveryZip = new TextField("Postleitzahl");
|
||||
deliveryZip.setPlaceholder("54321");
|
||||
deliveryZip.setPlaceholder("Postleitzahl");
|
||||
deliveryZip.setRequiredIndicatorVisible(true);
|
||||
deliveryCity = new TextField("Ort");
|
||||
deliveryCity.setPlaceholder("Berlin");
|
||||
@@ -208,7 +262,7 @@ public class AddJobView extends Main {
|
||||
|
||||
// Price field
|
||||
price = new TextField("Preis");
|
||||
price.setPlaceholder("z.B. 150.00");
|
||||
price.setPlaceholder("Betrag eingeben");
|
||||
price.setRequiredIndicatorVisible(true);
|
||||
|
||||
// Erzwinge Komma als Dezimaltrennzeichen: ersetze Punkt beim Tippen
|
||||
@@ -230,32 +284,7 @@ public class AddJobView extends Main {
|
||||
submitButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
}
|
||||
|
||||
private void populateTestData() {
|
||||
// Populate pickup address required fields
|
||||
pickupCompany.setValue("Firma 1");
|
||||
pickupFirstName.setValue("Max");
|
||||
pickupLastName.setValue("Mustermann");
|
||||
pickupStreet.setValue("Musterstraße");
|
||||
pickupHouseNumber.setValue("123");
|
||||
pickupZip.setValue("20095");
|
||||
pickupCity.setValue("Hamburg");
|
||||
|
||||
// Populate delivery address required fields
|
||||
deliveryFirstName.setValue("Anna");
|
||||
deliveryLastName.setValue("Beispiel");
|
||||
deliveryStreet.setValue("Beispielweg");
|
||||
deliveryHouseNumber.setValue("456");
|
||||
deliveryZip.setValue("10115");
|
||||
deliveryCity.setValue("Berlin");
|
||||
|
||||
// Populate price field
|
||||
price.setValue("150.00");
|
||||
|
||||
// Populate date fields with current date + 1 day for pickup, +2 days for delivery
|
||||
java.time.LocalDate today = java.time.LocalDate.now();
|
||||
pickupDate.setValue(today.plusDays(1));
|
||||
deliveryDate.setValue(today.plusDays(2));
|
||||
}
|
||||
// Testdaten entfernt
|
||||
|
||||
private void setupLayout() {
|
||||
setSizeFull();
|
||||
@@ -805,16 +834,44 @@ public class AddJobView extends Main {
|
||||
cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
|
||||
}
|
||||
|
||||
// NEU: Kunden anlegen, wenn Checkboxen aktiviert
|
||||
if (savePickupAddress.getValue()) {
|
||||
Customer pickupCustomer = new Customer();
|
||||
pickupCustomer.setCompanyName(pickupCompany.getValue());
|
||||
pickupCustomer.setTitle(pickupSalutation.getValue());
|
||||
pickupCustomer.setFirstname(pickupFirstName.getValue());
|
||||
pickupCustomer.setLastName(pickupLastName.getValue());
|
||||
pickupCustomer.setTelephone(pickupPhone.getValue());
|
||||
pickupCustomer.setStreet(pickupStreet.getValue());
|
||||
pickupCustomer.setHouseNumber(pickupHouseNumber.getValue());
|
||||
pickupCustomer.setAddressAddition(pickupAddressAddition.getValue());
|
||||
pickupCustomer.setZip(pickupZip.getValue());
|
||||
pickupCustomer.setCity(pickupCity.getValue());
|
||||
addCustomerService.addCustomer(pickupCustomer);
|
||||
}
|
||||
if (saveDeliveryAddress.getValue()) {
|
||||
Customer deliveryCustomer = new Customer();
|
||||
deliveryCustomer.setCompanyName(deliveryCompany.getValue());
|
||||
deliveryCustomer.setTitle(deliverySalutation.getValue());
|
||||
deliveryCustomer.setFirstname(deliveryFirstName.getValue());
|
||||
deliveryCustomer.setLastName(deliveryLastName.getValue());
|
||||
deliveryCustomer.setTelephone(deliveryPhone.getValue());
|
||||
deliveryCustomer.setStreet(deliveryStreet.getValue());
|
||||
deliveryCustomer.setHouseNumber(deliveryHouseNumber.getValue());
|
||||
deliveryCustomer.setAddressAddition(deliveryAddressAddition.getValue());
|
||||
deliveryCustomer.setZip(deliveryZip.getValue());
|
||||
deliveryCustomer.setCity(deliveryCity.getValue());
|
||||
addCustomerService.addCustomer(deliveryCustomer);
|
||||
}
|
||||
|
||||
// All validations passed, save the job with cargo items and tasks (tasks may be empty)
|
||||
Job savedJob = addJobService.addJobWithCargo(job, cargoFilled, tasksState);
|
||||
|
||||
// Erfolgsmeldung anzeigen
|
||||
// Erfolgsmeldung und Navigation zur Zusammenfassung
|
||||
Notification successNotification = Notification.show(
|
||||
"Auftrag erfolgreich erstellt! Auftragsnummer: " + savedJob.getJobNumber());
|
||||
successNotification.setDuration(5000);
|
||||
|
||||
// Formular zurücksetzen
|
||||
clearForm();
|
||||
successNotification.setDuration(2000);
|
||||
getUI().ifPresent(ui -> ui.navigate(JobSummaryView.class, savedJob.getId().toHexString()));
|
||||
} else {
|
||||
// Validation failed, show error message
|
||||
Notification errorNotification = Notification.show(
|
||||
@@ -824,15 +881,19 @@ public class AddJobView extends Main {
|
||||
|
||||
} catch (Exception e) {
|
||||
// Other errors
|
||||
// Reset cargo error
|
||||
if (cargoError != null) cargoError.setVisible(false);
|
||||
if (cargoAreaContainer != null) cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
|
||||
// Reset cargo error
|
||||
if (cargoError != null) cargoError.setVisible(false);
|
||||
if (cargoAreaContainer != null) cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
|
||||
Notification errorNotification = Notification.show(
|
||||
"Fehler beim Erstellen des Auftrags: " + e.getMessage());
|
||||
errorNotification.setDuration(5000);
|
||||
}
|
||||
}
|
||||
|
||||
// showSummary entfernt; Zusammenfassung als eigene Route
|
||||
|
||||
// Zusammenfassungs-Helfer entfernt (Route übernimmt Darstellung)
|
||||
|
||||
/**
|
||||
cargoItemsState.clear();
|
||||
cargoList.removeAll();
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
package de.assecutor.votianlt.pages.view;
|
||||
|
||||
import com.vaadin.flow.component.html.H3;
|
||||
import com.vaadin.flow.component.html.Main;
|
||||
import com.vaadin.flow.component.html.Span;
|
||||
import com.vaadin.flow.component.html.Div;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.UI;
|
||||
import com.vaadin.flow.router.BeforeEvent;
|
||||
import com.vaadin.flow.router.HasUrlParameter;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.theme.lumo.LumoUtility;
|
||||
import de.assecutor.votianlt.model.CargoItem;
|
||||
import de.assecutor.votianlt.model.Job;
|
||||
import de.assecutor.votianlt.model.TaskEntry;
|
||||
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
|
||||
import de.assecutor.votianlt.repository.CargoItemRepository;
|
||||
import de.assecutor.votianlt.repository.JobRepository;
|
||||
import de.assecutor.votianlt.repository.TaskRepository;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
@Route(value = "job_summary", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
|
||||
@PageTitle("Zusammenfassung")
|
||||
@RolesAllowed("USER")
|
||||
public class JobSummaryView extends Main implements HasUrlParameter<String> {
|
||||
|
||||
private final JobRepository jobRepository;
|
||||
private final CargoItemRepository cargoItemRepository;
|
||||
private final TaskRepository taskRepository;
|
||||
|
||||
private VerticalLayout content;
|
||||
|
||||
public JobSummaryView(JobRepository jobRepository,
|
||||
CargoItemRepository cargoItemRepository,
|
||||
TaskRepository taskRepository) {
|
||||
this.jobRepository = jobRepository;
|
||||
this.cargoItemRepository = cargoItemRepository;
|
||||
this.taskRepository = taskRepository;
|
||||
|
||||
setSizeFull();
|
||||
addClassNames(LumoUtility.BoxSizing.BORDER, LumoUtility.Display.FLEX,
|
||||
LumoUtility.FlexDirection.COLUMN, LumoUtility.Padding.MEDIUM,
|
||||
LumoUtility.Gap.SMALL);
|
||||
|
||||
add(new ViewToolbar("Zusammenfassung"));
|
||||
content = new VerticalLayout();
|
||||
content.setSpacing(true);
|
||||
content.setPadding(true);
|
||||
content.setWidthFull();
|
||||
add(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameter(BeforeEvent event, String parameter) {
|
||||
if (parameter == null || parameter.isBlank()) return;
|
||||
ObjectId jobId;
|
||||
try { jobId = new ObjectId(parameter); } catch (Exception e) { return; }
|
||||
|
||||
Job job = jobRepository.findById(jobId).orElse(null);
|
||||
if (job == null) return;
|
||||
List<CargoItem> cargo = cargoItemRepository.findByJobId(jobId);
|
||||
List<TaskEntry> tasks = taskRepository.findByJobId(jobId);
|
||||
|
||||
render(job, cargo, tasks);
|
||||
}
|
||||
|
||||
private void render(Job job, List<CargoItem> cargoItems, List<TaskEntry> tasks) {
|
||||
content.removeAll();
|
||||
|
||||
// Kopfzeile: Abholung/Lieferung
|
||||
HorizontalLayout topRow = new HorizontalLayout();
|
||||
topRow.setWidthFull();
|
||||
topRow.setSpacing(true);
|
||||
|
||||
VerticalLayout pickupBox = borderedBox();
|
||||
pickupBox.add(new H3("Abholung " + (job.getPickupDate() != null ? formatLocalDate(job.getPickupDate()) : "")));
|
||||
pickupBox.add(new Span(valueOrEmpty(job.getPickupCompany())));
|
||||
pickupBox.add(new Span(valueOrEmpty(job.getPickupSalutation())
|
||||
+ (job.getPickupSalutation() != null ? " " : "")
|
||||
+ valueOrEmpty(job.getPickupFirstName())
|
||||
+ (job.getPickupFirstName() != null ? " " : "")
|
||||
+ valueOrEmpty(job.getPickupLastName())));
|
||||
pickupBox.add(new Span(concatAddress(job.getPickupStreet(), job.getPickupHouseNumber())));
|
||||
pickupBox.add(new Span(concatZipCity(job.getPickupZip(), job.getPickupCity())));
|
||||
|
||||
VerticalLayout deliveryBox = borderedBox();
|
||||
deliveryBox.add(new H3("Lieferung " + (job.getDeliveryDate() != null ? formatLocalDate(job.getDeliveryDate()) : "")));
|
||||
deliveryBox.add(new Span(valueOrEmpty(job.getDeliveryCompany())));
|
||||
deliveryBox.add(new Span(valueOrEmpty(job.getDeliverySalutation())
|
||||
+ (job.getDeliverySalutation() != null ? " " : "")
|
||||
+ valueOrEmpty(job.getDeliveryFirstName())
|
||||
+ (job.getDeliveryFirstName() != null ? " " : "")
|
||||
+ valueOrEmpty(job.getDeliveryLastName())));
|
||||
deliveryBox.add(new Span(concatAddress(job.getDeliveryStreet(), job.getDeliveryHouseNumber())));
|
||||
deliveryBox.add(new Span(concatZipCity(job.getDeliveryZip(), job.getDeliveryCity())));
|
||||
|
||||
pickupBox.setWidth("50%");
|
||||
deliveryBox.setWidth("50%");
|
||||
topRow.add(pickupBox, deliveryBox);
|
||||
content.add(topRow);
|
||||
|
||||
// Aufgaben
|
||||
VerticalLayout tasksBox = borderedBox();
|
||||
tasksBox.add(new H3("Zu quittierende Aufgaben"));
|
||||
if (tasks == null || tasks.stream().filter(Objects::nonNull).map(TaskEntry::getText).filter(t -> t != null && !t.isBlank()).findAny().isEmpty()) {
|
||||
tasksBox.add(new Span("Keine Aufgaben"));
|
||||
} else {
|
||||
tasks.stream().filter(Objects::nonNull).map(TaskEntry::getText).filter(t -> t != null && !t.isBlank()).forEach(t -> tasksBox.add(new Span("• " + t)));
|
||||
}
|
||||
content.add(tasksBox);
|
||||
|
||||
// Fracht und weitere Infos
|
||||
HorizontalLayout midRow = new HorizontalLayout();
|
||||
midRow.setWidthFull();
|
||||
midRow.setSpacing(true);
|
||||
|
||||
VerticalLayout cargoBox = borderedBox();
|
||||
cargoBox.add(new H3("Zu transportierende Fracht"));
|
||||
if (cargoItems == null || cargoItems.isEmpty()) {
|
||||
cargoBox.add(new Span("Keine Frachtangaben"));
|
||||
} else {
|
||||
for (CargoItem ci : cargoItems) {
|
||||
if (ci == null) continue;
|
||||
String desc = ci.getDescription();
|
||||
Integer qty = ci.getQuantity();
|
||||
String dims = dimString(ci);
|
||||
String weight = ci.getWeightKg() != null ? ci.getWeightKg() + " kg" : "";
|
||||
String line = (qty != null ? qty + " x " : "") + (desc != null ? desc : "") + (dims.isBlank() ? "" : " " + dims) + (weight.isBlank() ? "" : " " + weight);
|
||||
if (!line.isBlank()) cargoBox.add(new Span(line));
|
||||
}
|
||||
}
|
||||
|
||||
VerticalLayout infoBox = borderedBox();
|
||||
infoBox.add(new H3("Weitere Informationen"));
|
||||
infoBox.add(new Span("Preis: " + (job.getPrice() != null ? formatPrice(job.getPrice()) : "-")));
|
||||
if (job.getRemark() != null && !job.getRemark().isBlank()) {
|
||||
infoBox.add(new Span("Bemerkung: " + job.getRemark()));
|
||||
}
|
||||
if (job.isDigitalProcessing()) {
|
||||
infoBox.add(new Span("Digitale Abwicklung per App: aktiviert"));
|
||||
}
|
||||
if (job.getAppUser() != null && !job.getAppUser().isBlank()) {
|
||||
infoBox.add(new Span("App-Nutzer: " + job.getAppUser()));
|
||||
}
|
||||
|
||||
cargoBox.setWidth("50%");
|
||||
infoBox.setWidth("50%");
|
||||
midRow.add(cargoBox, infoBox);
|
||||
content.add(midRow);
|
||||
|
||||
// Google Maps Karte mit Route
|
||||
addRouteMap(job);
|
||||
}
|
||||
|
||||
private VerticalLayout borderedBox() {
|
||||
VerticalLayout box = new VerticalLayout();
|
||||
box.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
|
||||
box.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
|
||||
box.getStyle().set("background-color", "var(--lumo-base-color)");
|
||||
box.setPadding(true);
|
||||
box.setSpacing(false);
|
||||
return box;
|
||||
}
|
||||
|
||||
private String formatLocalDate(java.time.LocalDate date) {
|
||||
try {
|
||||
java.time.format.DateTimeFormatter fmt = java.time.format.DateTimeFormatter.ofPattern("dd.MM.yyyy").withLocale(Locale.GERMANY);
|
||||
return date.format(fmt);
|
||||
} catch (Exception e) { return ""; }
|
||||
}
|
||||
|
||||
private String valueOrEmpty(String v) { return v == null ? "" : v; }
|
||||
|
||||
private String concatAddress(String street, String house) {
|
||||
String s = valueOrEmpty(street);
|
||||
String h = valueOrEmpty(house);
|
||||
return (s + (h.isBlank() ? "" : " " + h)).trim();
|
||||
}
|
||||
|
||||
private String concatZipCity(String zip, String city) {
|
||||
String z = valueOrEmpty(zip);
|
||||
String c = valueOrEmpty(city);
|
||||
if (!z.isBlank() && !c.isBlank()) return z + " " + c;
|
||||
return (z + " " + c).trim();
|
||||
}
|
||||
|
||||
private String dimString(CargoItem ci) {
|
||||
String len = ci.getLengthMm() != null ? ci.getLengthMm().intValue() + " mm" : "";
|
||||
String wid = ci.getWidthMm() != null ? ci.getWidthMm().intValue() + " mm" : "";
|
||||
String hei = ci.getHeightMm() != null ? ci.getHeightMm().intValue() + " mm" : "";
|
||||
String combined = String.join(" x ", java.util.stream.Stream.of(len, wid, hei)
|
||||
.filter(s -> s != null && !s.isBlank()).toList());
|
||||
return combined.isBlank() ? "" : combined;
|
||||
}
|
||||
|
||||
private String formatPrice(java.math.BigDecimal price) {
|
||||
java.text.NumberFormat nf = java.text.NumberFormat.getCurrencyInstance(Locale.GERMANY);
|
||||
return nf.format(price);
|
||||
}
|
||||
|
||||
private void addRouteMap(Job job) {
|
||||
// Baue Adress-Strings
|
||||
String origin = (concatAddress(job.getPickupStreet(), job.getPickupHouseNumber()) + ", " + concatZipCity(job.getPickupZip(), job.getPickupCity())).trim();
|
||||
String destination = (concatAddress(job.getDeliveryStreet(), job.getDeliveryHouseNumber()) + ", " + concatZipCity(job.getDeliveryZip(), job.getDeliveryCity())).trim();
|
||||
|
||||
if (origin.isBlank() || destination.isBlank()) {
|
||||
// Wenn nicht genug Daten vorhanden sind, Karte nicht anzeigen
|
||||
return;
|
||||
}
|
||||
|
||||
Div map = new Div();
|
||||
map.setWidthFull();
|
||||
map.setHeight("520px");
|
||||
map.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
|
||||
map.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
|
||||
content.add(map);
|
||||
|
||||
String js = (
|
||||
"(function(){" +
|
||||
" var host = $0;" +
|
||||
" function init(){" +
|
||||
" var map = new google.maps.Map(host, {center: {lat: 51.163, lng: 10.447}, zoom: 6});" +
|
||||
" var ds = new google.maps.DirectionsService();" +
|
||||
" var dr = new google.maps.DirectionsRenderer({map: map});" +
|
||||
" ds.route({" +
|
||||
" origin: '" + escapeJs(origin) + "'," +
|
||||
" destination: '" + escapeJs(destination) + "'," +
|
||||
" travelMode: google.maps.TravelMode.DRIVING" +
|
||||
" }, function(res, status){ if(status==='OK'){ dr.setDirections(res); } });" +
|
||||
" }" +
|
||||
" if (!(window.google && window.google.maps)) {" +
|
||||
" var s=document.createElement('script');" +
|
||||
" s.src='https://maps.googleapis.com/maps/api/js?key=AIzaSyDnbitL06iLp3elmj-WtPudCykX9xvXcVE&libraries=places';" +
|
||||
" s.onload=init; document.head.appendChild(s);" +
|
||||
" } else { init(); }" +
|
||||
"})();"
|
||||
);
|
||||
|
||||
// Ausführen im UI-Kontext
|
||||
map.getElement().executeJs(js, map.getElement());
|
||||
}
|
||||
|
||||
// Hilfsfunktion zum einfachen Escapen von JS-Zeichen in Strings
|
||||
private String escapeJs(String s) {
|
||||
if (s == null) return "";
|
||||
return s.replace("\\", "\\\\").replace("'", "\\'").replace("\n", " ").replace("\r", " ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user