Erweiterungen
This commit is contained in:
@@ -51,4 +51,7 @@ public class Customer
|
|||||||
|
|
||||||
@Field("created_by")
|
@Field("created_by")
|
||||||
private ObjectId createdBy;
|
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.Pageable;
|
||||||
import org.springframework.data.domain.Slice;
|
import org.springframework.data.domain.Slice;
|
||||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface CustomerRepository extends MongoRepository<Customer, ObjectId> {
|
public interface CustomerRepository extends MongoRepository<Customer, ObjectId> {
|
||||||
|
|
||||||
// If you don't need a total row count, Slice is better than Page.
|
// If you don't need a total row count, Slice is better than Page.
|
||||||
Slice<Customer> findAllBy(Pageable pageable);
|
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
|
// Setze den aktuellen Benutzer als Ersteller - jetzt direkt aus der Session
|
||||||
de.assecutor.votianlt.model.User currentUser = securityService.getCurrentDatabaseUser();
|
de.assecutor.votianlt.model.User currentUser = securityService.getCurrentDatabaseUser();
|
||||||
customer.setCreatedBy(currentUser.getId());
|
customer.setCreatedBy(currentUser.getId());
|
||||||
|
customer.setOwner(currentUser.getId());
|
||||||
|
|
||||||
addCustomerRepository.save(customer);
|
addCustomerRepository.save(customer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,18 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
|
import de.assecutor.votianlt.security.SecurityService;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
public class CustomerService {
|
public class CustomerService {
|
||||||
|
|
||||||
private final CustomerRepository todoRepository;
|
private final CustomerRepository todoRepository;
|
||||||
|
private final SecurityService securityService;
|
||||||
|
|
||||||
CustomerService(CustomerRepository todoRepository) {
|
CustomerService(CustomerRepository todoRepository, SecurityService securityService) {
|
||||||
this.todoRepository = todoRepository;
|
this.todoRepository = todoRepository;
|
||||||
|
this.securityService = securityService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Customer> list(org.springframework.data.domain.Pageable pageable) {
|
public List<Customer> list(org.springframework.data.domain.Pageable pageable) {
|
||||||
@@ -29,6 +32,11 @@ public class CustomerService {
|
|||||||
return todoRepository.findAll();
|
return todoRepository.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Customer> findAllForCurrentOwner() {
|
||||||
|
ObjectId ownerId = securityService.getCurrentUserId();
|
||||||
|
return todoRepository.findByOwner(ownerId);
|
||||||
|
}
|
||||||
|
|
||||||
public Customer save(Customer customer) {
|
public Customer save(Customer customer) {
|
||||||
return todoRepository.save(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.Job;
|
||||||
import de.assecutor.votianlt.model.TaskEntry;
|
import de.assecutor.votianlt.model.TaskEntry;
|
||||||
import de.assecutor.votianlt.pages.service.AddJobService;
|
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.base.ui.component.ViewToolbar;
|
||||||
|
import de.assecutor.votianlt.pages.service.AddCustomerService;
|
||||||
|
import de.assecutor.votianlt.model.Customer;
|
||||||
|
|
||||||
import jakarta.annotation.security.RolesAllowed;
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -49,6 +52,8 @@ import java.util.Optional;
|
|||||||
public class AddJobView extends Main {
|
public class AddJobView extends Main {
|
||||||
|
|
||||||
private final AddJobService addJobService;
|
private final AddJobService addJobService;
|
||||||
|
private final CustomerService customerService;
|
||||||
|
private final AddCustomerService addCustomerService;
|
||||||
|
|
||||||
// Customer selection
|
// Customer selection
|
||||||
private ComboBox<String> customerSelection;
|
private ComboBox<String> customerSelection;
|
||||||
@@ -116,10 +121,14 @@ public class AddJobView extends Main {
|
|||||||
|
|
||||||
private final Binder<Job> binder = new Binder<>(Job.class);
|
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.addJobService = addJobService;
|
||||||
|
this.addCustomerService = addCustomerService;
|
||||||
|
this.customerService = customerService;
|
||||||
initializeComponents();
|
initializeComponents();
|
||||||
populateTestData(); // Pre-populate all required fields with test data
|
|
||||||
setupLayout();
|
setupLayout();
|
||||||
setupValidation();
|
setupValidation();
|
||||||
loadDraftIfExists();
|
loadDraftIfExists();
|
||||||
@@ -128,9 +137,56 @@ public class AddJobView extends Main {
|
|||||||
private void initializeComponents() {
|
private void initializeComponents() {
|
||||||
// Customer selection
|
// Customer selection
|
||||||
customerSelection = new ComboBox<>("Auftraggeber/Rechnungsempfänger");
|
customerSelection = new ComboBox<>("Auftraggeber/Rechnungsempfänger");
|
||||||
customerSelection.setItems("Kunde01 | KOTVor K01Nach");
|
|
||||||
customerSelection.setPlaceholder("Wählen Sie einen Auftraggeber aus...");
|
customerSelection.setPlaceholder("Wählen Sie einen Auftraggeber aus...");
|
||||||
customerSelection.setWidthFull();
|
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 = new Button("Vorbelegte Adressfelder leeren");
|
||||||
preloadAddressButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
preloadAddressButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||||
@@ -138,30 +194,29 @@ public class AddJobView extends Main {
|
|||||||
|
|
||||||
// Pickup address
|
// Pickup address
|
||||||
pickupCompany = new TextField("Firma");
|
pickupCompany = new TextField("Firma");
|
||||||
pickupCompany.setPlaceholder("z.B. IKEA, McDonald's, DHL...");
|
pickupCompany.setPlaceholder("Firmenname");
|
||||||
pickupCompany.setValue("Test Abholfirma GmbH");
|
|
||||||
addGooglePlacesAutocomplete(pickupCompany, 0); // Stage 0 für Pickup
|
addGooglePlacesAutocomplete(pickupCompany, 0); // Stage 0 für Pickup
|
||||||
pickupSalutation = new ComboBox<>("Anrede");
|
pickupSalutation = new ComboBox<>("Anrede");
|
||||||
pickupSalutation.setItems("Herr", "Frau", "Divers");
|
pickupSalutation.setItems("Herr", "Frau", "Divers");
|
||||||
pickupSalutation.setPlaceholder("Anrede wählen...");
|
pickupSalutation.setPlaceholder("Anrede wählen...");
|
||||||
pickupFirstName = new TextField("Vorname");
|
pickupFirstName = new TextField("Vorname");
|
||||||
pickupFirstName.setPlaceholder("Max");
|
pickupFirstName.setPlaceholder("Vorname");
|
||||||
pickupFirstName.setRequiredIndicatorVisible(true);
|
pickupFirstName.setRequiredIndicatorVisible(true);
|
||||||
pickupLastName = new TextField("Nachname");
|
pickupLastName = new TextField("Nachname");
|
||||||
pickupLastName.setPlaceholder("Mustermann");
|
pickupLastName.setPlaceholder("Nachname");
|
||||||
pickupLastName.setRequiredIndicatorVisible(true);
|
pickupLastName.setRequiredIndicatorVisible(true);
|
||||||
pickupPhone = new TextField("Telefonnummer");
|
pickupPhone = new TextField("Telefonnummer");
|
||||||
pickupPhone.setPlaceholder("+49 123 456789");
|
pickupPhone.setPlaceholder("Telefonnummer");
|
||||||
pickupStreet = new TextField("Straße");
|
pickupStreet = new TextField("Straße");
|
||||||
pickupStreet.setPlaceholder("Musterstraße");
|
pickupStreet.setPlaceholder("Musterstraße");
|
||||||
pickupStreet.setRequiredIndicatorVisible(true);
|
pickupStreet.setRequiredIndicatorVisible(true);
|
||||||
pickupHouseNumber = new TextField("Hausnummer");
|
pickupHouseNumber = new TextField("Hausnummer");
|
||||||
pickupHouseNumber.setPlaceholder("123");
|
pickupHouseNumber.setPlaceholder("Hausnummer");
|
||||||
pickupHouseNumber.setRequiredIndicatorVisible(true);
|
pickupHouseNumber.setRequiredIndicatorVisible(true);
|
||||||
pickupAddressAddition = new TextField("Adresszusatz");
|
pickupAddressAddition = new TextField("Adresszusatz");
|
||||||
pickupAddressAddition.setPlaceholder("2. OG, Hinterhaus...");
|
pickupAddressAddition.setPlaceholder("2. OG, Hinterhaus...");
|
||||||
pickupZip = new TextField("Postleitzahl");
|
pickupZip = new TextField("Postleitzahl");
|
||||||
pickupZip.setPlaceholder("12345");
|
pickupZip.setPlaceholder("Postleitzahl");
|
||||||
pickupZip.setRequiredIndicatorVisible(true);
|
pickupZip.setRequiredIndicatorVisible(true);
|
||||||
pickupCity = new TextField("Ort");
|
pickupCity = new TextField("Ort");
|
||||||
pickupCity.setPlaceholder("Hamburg");
|
pickupCity.setPlaceholder("Hamburg");
|
||||||
@@ -170,30 +225,29 @@ public class AddJobView extends Main {
|
|||||||
|
|
||||||
// Delivery address
|
// Delivery address
|
||||||
deliveryCompany = new TextField("Firma");
|
deliveryCompany = new TextField("Firma");
|
||||||
deliveryCompany.setPlaceholder("z.B. EDEKA, Bauhaus, Amazon...");
|
deliveryCompany.setPlaceholder("Firmenname");
|
||||||
deliveryCompany.setValue("Test Lieferfirma AG");
|
|
||||||
addGooglePlacesAutocomplete(deliveryCompany, 1); // Stage 1 für Delivery
|
addGooglePlacesAutocomplete(deliveryCompany, 1); // Stage 1 für Delivery
|
||||||
deliverySalutation = new ComboBox<>("Anrede");
|
deliverySalutation = new ComboBox<>("Anrede");
|
||||||
deliverySalutation.setItems("Herr", "Frau", "Divers");
|
deliverySalutation.setItems("Herr", "Frau", "Divers");
|
||||||
deliverySalutation.setPlaceholder("Anrede wählen...");
|
deliverySalutation.setPlaceholder("Anrede wählen...");
|
||||||
deliveryFirstName = new TextField("Vorname");
|
deliveryFirstName = new TextField("Vorname");
|
||||||
deliveryFirstName.setPlaceholder("Anna");
|
deliveryFirstName.setPlaceholder("Vorname");
|
||||||
deliveryFirstName.setRequiredIndicatorVisible(true);
|
deliveryFirstName.setRequiredIndicatorVisible(true);
|
||||||
deliveryLastName = new TextField("Nachname");
|
deliveryLastName = new TextField("Nachname");
|
||||||
deliveryLastName.setPlaceholder("Beispiel");
|
deliveryLastName.setPlaceholder("Nachname");
|
||||||
deliveryLastName.setRequiredIndicatorVisible(true);
|
deliveryLastName.setRequiredIndicatorVisible(true);
|
||||||
deliveryPhone = new TextField("Telefonnummer");
|
deliveryPhone = new TextField("Telefonnummer");
|
||||||
deliveryPhone.setPlaceholder("+49 987 654321");
|
deliveryPhone.setPlaceholder("Telefonnummer");
|
||||||
deliveryStreet = new TextField("Straße");
|
deliveryStreet = new TextField("Straße");
|
||||||
deliveryStreet.setPlaceholder("Beispielweg");
|
deliveryStreet.setPlaceholder("Beispielweg");
|
||||||
deliveryStreet.setRequiredIndicatorVisible(true);
|
deliveryStreet.setRequiredIndicatorVisible(true);
|
||||||
deliveryHouseNumber = new TextField("Hausnr");
|
deliveryHouseNumber = new TextField("Hausnr");
|
||||||
deliveryHouseNumber.setPlaceholder("456");
|
deliveryHouseNumber.setPlaceholder("Hausnummer");
|
||||||
deliveryHouseNumber.setRequiredIndicatorVisible(true);
|
deliveryHouseNumber.setRequiredIndicatorVisible(true);
|
||||||
deliveryAddressAddition = new TextField("Adresszusatz");
|
deliveryAddressAddition = new TextField("Adresszusatz");
|
||||||
deliveryAddressAddition.setPlaceholder("Erdgeschoss, links...");
|
deliveryAddressAddition.setPlaceholder("Erdgeschoss, links...");
|
||||||
deliveryZip = new TextField("Postleitzahl");
|
deliveryZip = new TextField("Postleitzahl");
|
||||||
deliveryZip.setPlaceholder("54321");
|
deliveryZip.setPlaceholder("Postleitzahl");
|
||||||
deliveryZip.setRequiredIndicatorVisible(true);
|
deliveryZip.setRequiredIndicatorVisible(true);
|
||||||
deliveryCity = new TextField("Ort");
|
deliveryCity = new TextField("Ort");
|
||||||
deliveryCity.setPlaceholder("Berlin");
|
deliveryCity.setPlaceholder("Berlin");
|
||||||
@@ -208,7 +262,7 @@ public class AddJobView extends Main {
|
|||||||
|
|
||||||
// Price field
|
// Price field
|
||||||
price = new TextField("Preis");
|
price = new TextField("Preis");
|
||||||
price.setPlaceholder("z.B. 150.00");
|
price.setPlaceholder("Betrag eingeben");
|
||||||
price.setRequiredIndicatorVisible(true);
|
price.setRequiredIndicatorVisible(true);
|
||||||
|
|
||||||
// Erzwinge Komma als Dezimaltrennzeichen: ersetze Punkt beim Tippen
|
// Erzwinge Komma als Dezimaltrennzeichen: ersetze Punkt beim Tippen
|
||||||
@@ -230,32 +284,7 @@ public class AddJobView extends Main {
|
|||||||
submitButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
submitButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateTestData() {
|
// Testdaten entfernt
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupLayout() {
|
private void setupLayout() {
|
||||||
setSizeFull();
|
setSizeFull();
|
||||||
@@ -805,16 +834,44 @@ public class AddJobView extends Main {
|
|||||||
cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
|
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)
|
// All validations passed, save the job with cargo items and tasks (tasks may be empty)
|
||||||
Job savedJob = addJobService.addJobWithCargo(job, cargoFilled, tasksState);
|
Job savedJob = addJobService.addJobWithCargo(job, cargoFilled, tasksState);
|
||||||
|
|
||||||
// Erfolgsmeldung anzeigen
|
// Erfolgsmeldung und Navigation zur Zusammenfassung
|
||||||
Notification successNotification = Notification.show(
|
Notification successNotification = Notification.show(
|
||||||
"Auftrag erfolgreich erstellt! Auftragsnummer: " + savedJob.getJobNumber());
|
"Auftrag erfolgreich erstellt! Auftragsnummer: " + savedJob.getJobNumber());
|
||||||
successNotification.setDuration(5000);
|
successNotification.setDuration(2000);
|
||||||
|
getUI().ifPresent(ui -> ui.navigate(JobSummaryView.class, savedJob.getId().toHexString()));
|
||||||
// Formular zurücksetzen
|
|
||||||
clearForm();
|
|
||||||
} else {
|
} else {
|
||||||
// Validation failed, show error message
|
// Validation failed, show error message
|
||||||
Notification errorNotification = Notification.show(
|
Notification errorNotification = Notification.show(
|
||||||
@@ -833,6 +890,10 @@ public class AddJobView extends Main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// showSummary entfernt; Zusammenfassung als eigene Route
|
||||||
|
|
||||||
|
// Zusammenfassungs-Helfer entfernt (Route übernimmt Darstellung)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
cargoItemsState.clear();
|
cargoItemsState.clear();
|
||||||
cargoList.removeAll();
|
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