Erweiterungen

This commit is contained in:
2025-08-14 12:34:43 +02:00
parent 9ad857b8a7
commit 40de64c95e
6 changed files with 190 additions and 173 deletions

View File

@@ -5,6 +5,7 @@ import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field; import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.annotation.Transient;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -71,9 +72,6 @@ public class Job {
@Field("pickup_city") @Field("pickup_city")
private String pickupCity; private String pickupCity;
@Field("save_pickup_address")
private boolean savePickupAddress;
// Lieferadresse // Lieferadresse
@Field("delivery_company") @Field("delivery_company")
private String deliveryCompany; private String deliveryCompany;
@@ -105,9 +103,6 @@ public class Job {
@Field("delivery_city") @Field("delivery_city")
private String deliveryCity; private String deliveryCity;
@Field("save_delivery_address")
private boolean saveDeliveryAddress;
// Digitale Abwicklung per App // Digitale Abwicklung per App
@Field("digital_processing") @Field("digital_processing")
private boolean digitalProcessing; private boolean digitalProcessing;
@@ -126,10 +121,6 @@ public class Job {
@Field("remark") @Field("remark")
private String remark; private String remark;
// Aufgaben
@Field("tasks")
private List<String> tasks;
// Preis (netto) // Preis (netto)
@Field("price") @Field("price")
private BigDecimal price; private BigDecimal price;

View File

@@ -0,0 +1,25 @@
package de.assecutor.votianlt.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "tasks")
public class TaskEntry {
@Id
private ObjectId id;
@Field("job_id")
private ObjectId jobId;
@Field("text")
private String text;
}

View File

@@ -3,9 +3,12 @@ package de.assecutor.votianlt.pages.add_job.service;
import de.assecutor.votianlt.model.CargoItem; import de.assecutor.votianlt.model.CargoItem;
import de.assecutor.votianlt.model.Job; import de.assecutor.votianlt.model.Job;
import de.assecutor.votianlt.model.JobStatus; import de.assecutor.votianlt.model.JobStatus;
import de.assecutor.votianlt.repository.CargoItemRepository; import de.assecutor.votianlt.model.TaskEntry;
import de.assecutor.votianlt.repository.JobRepository; import de.assecutor.votianlt.repository.JobRepository;
import de.assecutor.votianlt.repository.TaskRepository;
import de.assecutor.votianlt.security.SecurityService; import de.assecutor.votianlt.security.SecurityService;
import de.assecutor.votianlt.repository.CargoItemRepository;
import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
@@ -15,22 +18,22 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j @Slf4j
public class AddJobService { public class AddJobService {
private final JobRepository jobRepository;
private final CargoItemRepository cargoItemRepository; private final CargoItemRepository cargoItemRepository;
private final JobRepository jobRepository;
private final TaskRepository taskRepository;
private final SecurityService securityService; private final SecurityService securityService;
/** /**
* Speichert einen neuen Auftrag samt CargoItems (separat in cargo_items) * Speichert einen neuen Auftrag samt CargoItems und Tasks
* @param job der Auftrag * @param job der Auftrag
* @param transientCargo zugehörige, noch nicht gespeicherte CargoItems aus der View * @param transientCargo zugehörige, noch nicht gespeicherte CargoItems aus der View
*/ */
public Job addJobWithCargo(Job job, List<CargoItem> transientCargo) { public Job addJobWithCargo(Job job, List<CargoItem> transientCargo, List<TaskEntry> transientTasks) {
try { try {
// Metadaten setzen // Metadaten setzen
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
@@ -46,11 +49,15 @@ public class AddJobService {
// Auftrag speichern // Auftrag speichern
Job savedJob = jobRepository.save(job); Job savedJob = jobRepository.save(job);
final ObjectId jobId = savedJob.getId();
boolean modified = false;
// CargoItems separat mit Referenz auf Job speichern, IDs im Job verknüpfen // CargoItems separat mit Referenz auf Job speichern, IDs im Job verknüpfen
if (transientCargo != null && !transientCargo.isEmpty()) { if (transientCargo != null && !transientCargo.isEmpty()) {
final ObjectId jobId = savedJob.getId(); List<CargoItem> itemsWithJob = transientCargo.stream()
List<CargoItem> itemsWithJob = transientCargo.stream().map(ci -> { .filter(Objects::nonNull)
.filter(ci -> ci.getDescription() != null && !ci.getDescription().isBlank())
.map(ci -> {
CargoItem copy = new CargoItem(); CargoItem copy = new CargoItem();
copy.setJobId(jobId); copy.setJobId(jobId);
copy.setDescription(ci.getDescription()); copy.setDescription(ci.getDescription());
@@ -60,9 +67,24 @@ public class AddJobService {
copy.setWidthMm(ci.getWidthMm()); copy.setWidthMm(ci.getWidthMm());
copy.setHeightMm(ci.getHeightMm()); copy.setHeightMm(ci.getHeightMm());
return copy; return copy;
}).collect(java.util.stream.Collectors.toList()); }).toList();
List<CargoItem> savedItems = cargoItemRepository.saveAll(itemsWithJob); var savedItems = cargoItemRepository.saveAll(itemsWithJob);
List<ObjectId> cargoIds = savedItems.stream().map(CargoItem::getId).collect(java.util.stream.Collectors.toList()); var cargoIds = savedItems.stream().map(CargoItem::getId).toList();
modified = true;
// Tasks separat speichern und referenzieren
if (transientTasks != null && !transientTasks.isEmpty()) {
var prepared = transientTasks.stream()
.filter(Objects::nonNull)
.filter(te -> te.getText() != null && !te.getText().isBlank())
.peek(te -> te.setJobId(jobId))
.toList();
var savedTasks = taskRepository.saveAll(prepared);
var taskIds = savedTasks.stream().map(de.assecutor.votianlt.model.TaskEntry::getId).toList();
modified = true;
}
}
if (modified) {
savedJob = jobRepository.save(savedJob); savedJob = jobRepository.save(savedJob);
} }
@@ -75,36 +97,6 @@ public class AddJobService {
} }
} }
/**
* Speichert einen neuen Auftrag in der MongoDB
*/
public Job addJob(Job job) {
try {
// Metadaten setzen
LocalDateTime now = LocalDateTime.now();
job.setCreatedAt(now);
job.setUpdatedAt(now);
job.setStatus(JobStatus.CREATED);
job.setCreatedBy(securityService.getCurrentUsername());
// Auftragsnummer generieren, falls nicht vorhanden
if (job.getJobNumber() == null || job.getJobNumber().isEmpty()) {
job.setJobNumber(generateJobNumber());
}
// Auftrag speichern
Job savedJob = jobRepository.save(job);
log.info("Auftrag erfolgreich gespeichert: {}", savedJob.getJobNumber());
return savedJob;
} catch (Exception e) {
log.error("Fehler beim Speichern des Auftrags: {}", e.getMessage(), e);
throw new RuntimeException("Auftrag konnte nicht gespeichert werden: " + e.getMessage());
}
}
/** /**
* Aktualisiert einen bestehenden Auftrag * Aktualisiert einen bestehenden Auftrag
*/ */
@@ -206,7 +198,7 @@ public class AddJobService {
/** /**
* Speichert einen Auftrag als Entwurf (für automatisches Speichern) * Speichert einen Auftrag als Entwurf (für automatisches Speichern)
*/ */
public Job saveDraft(Job job) { public void saveDraft(Job job) {
try { try {
// Prüfen ob bereits ein Entwurf für diesen Benutzer existiert // Prüfen ob bereits ein Entwurf für diesen Benutzer existiert
String currentUser = securityService.getCurrentUsername(); String currentUser = securityService.getCurrentUsername();
@@ -215,7 +207,7 @@ public class AddJobService {
Job draftJob; Job draftJob;
if (!existingDrafts.isEmpty()) { if (!existingDrafts.isEmpty()) {
// Bestehenden Entwurf aktualisieren // Bestehenden Entwurf aktualisieren
draftJob = existingDrafts.get(0); draftJob = existingDrafts.getFirst();
updateJobFromForm(draftJob, job); updateJobFromForm(draftJob, job);
draftJob.setUpdatedAt(LocalDateTime.now()); draftJob.setUpdatedAt(LocalDateTime.now());
} else { } else {
@@ -236,8 +228,6 @@ public class AddJobService {
Job savedDraft = jobRepository.save(draftJob); Job savedDraft = jobRepository.save(draftJob);
log.info("Entwurf automatisch gespeichert für Benutzer: {}", currentUser); log.info("Entwurf automatisch gespeichert für Benutzer: {}", currentUser);
return savedDraft;
} catch (Exception e) { } catch (Exception e) {
log.error("Fehler beim Speichern des Entwurfs: {}", e.getMessage(), e); log.error("Fehler beim Speichern des Entwurfs: {}", e.getMessage(), e);
throw new RuntimeException("Entwurf konnte nicht gespeichert werden: " + e.getMessage()); throw new RuntimeException("Entwurf konnte nicht gespeichert werden: " + e.getMessage());
@@ -261,7 +251,6 @@ public class AddJobService {
existingJob.setPickupAddressAddition(formJob.getPickupAddressAddition()); existingJob.setPickupAddressAddition(formJob.getPickupAddressAddition());
existingJob.setPickupZip(formJob.getPickupZip()); existingJob.setPickupZip(formJob.getPickupZip());
existingJob.setPickupCity(formJob.getPickupCity()); existingJob.setPickupCity(formJob.getPickupCity());
existingJob.setSavePickupAddress(formJob.isSavePickupAddress());
// Delivery address // Delivery address
existingJob.setDeliveryCompany(formJob.getDeliveryCompany()); existingJob.setDeliveryCompany(formJob.getDeliveryCompany());
@@ -274,7 +263,6 @@ public class AddJobService {
existingJob.setDeliveryAddressAddition(formJob.getDeliveryAddressAddition()); existingJob.setDeliveryAddressAddition(formJob.getDeliveryAddressAddition());
existingJob.setDeliveryZip(formJob.getDeliveryZip()); existingJob.setDeliveryZip(formJob.getDeliveryZip());
existingJob.setDeliveryCity(formJob.getDeliveryCity()); existingJob.setDeliveryCity(formJob.getDeliveryCity());
existingJob.setSaveDeliveryAddress(formJob.isSaveDeliveryAddress());
// Digital processing // Digital processing
existingJob.setDigitalProcessing(formJob.isDigitalProcessing()); existingJob.setDigitalProcessing(formJob.isDigitalProcessing());
@@ -284,7 +272,6 @@ public class AddJobService {
existingJob.setPickupDate(formJob.getPickupDate()); existingJob.setPickupDate(formJob.getPickupDate());
existingJob.setDeliveryDate(formJob.getDeliveryDate()); existingJob.setDeliveryDate(formJob.getDeliveryDate());
existingJob.setRemark(formJob.getRemark()); existingJob.setRemark(formJob.getRemark());
existingJob.setTasks(formJob.getTasks());
existingJob.setPrice(formJob.getPrice()); existingJob.setPrice(formJob.getPrice());
} }
@@ -293,15 +280,6 @@ public class AddJobService {
*/ */
public Optional<Job> findCurrentDraft(String username) { public Optional<Job> findCurrentDraft(String username) {
List<Job> drafts = jobRepository.findByCreatedByAndIsDraftTrue(username); List<Job> drafts = jobRepository.findByCreatedByAndIsDraftTrue(username);
return drafts.isEmpty() ? Optional.empty() : Optional.of(drafts.get(0)); return drafts.isEmpty() ? Optional.empty() : Optional.of(drafts.getFirst());
}
/**
* Löscht alle Entwürfe eines Benutzers
*/
public void deleteUserDrafts(String username) {
List<Job> drafts = jobRepository.findByCreatedByAndIsDraftTrue(username);
jobRepository.deleteAll(drafts);
log.info("Entwürfe für Benutzer {} gelöscht", username);
} }
} }

View File

@@ -33,11 +33,16 @@ import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import com.vaadin.flow.theme.lumo.LumoUtility; 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.pages.add_job.service.AddJobService; import de.assecutor.votianlt.pages.add_job.service.AddJobService;
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar; import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import de.assecutor.votianlt.model.CargoItem;
import java.util.*;
import java.util.Objects;
import de.assecutor.votianlt.model.TaskEntry;
import java.util.Optional; import java.util.Optional;
@Route(value = "add_job", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class) @Route(value = "add_job", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
@@ -100,11 +105,16 @@ public class AddJobView extends Main {
// Submit button // Submit button
private Button submitButton; private Button submitButton;
// Transient transfer list for cargo items (not part of Job entity anymore)
private java.util.List<de.assecutor.votianlt.model.CargoItem> jobTransientCargo;
// Backing list for cargo items to mirror UI rows
private final List<CargoItem> cargoItemsState = new ArrayList<>();
// Stage sections for drag and drop // Stage sections for drag and drop
// Backing list for tasks to mirror UI rows
private final List<TaskEntry> tasksState = new ArrayList<>();
// Dynamic lists and additional controls // Dynamic lists and additional controls
// Cargo section UI refs for error highlighting
private VerticalLayout cargoAreaContainer;
private Span cargoError;
private VerticalLayout cargoList; private VerticalLayout cargoList;
private VerticalLayout tasksList; private VerticalLayout tasksList;
private TextArea remarkArea; private TextArea remarkArea;
@@ -647,13 +657,11 @@ public class AddJobView extends Main {
binder.bind(pickupSalutation, Job::getPickupSalutation, Job::setPickupSalutation); binder.bind(pickupSalutation, Job::getPickupSalutation, Job::setPickupSalutation);
binder.bind(pickupPhone, Job::getPickupPhone, Job::setPickupPhone); binder.bind(pickupPhone, Job::getPickupPhone, Job::setPickupPhone);
binder.bind(pickupAddressAddition, Job::getPickupAddressAddition, Job::setPickupAddressAddition); binder.bind(pickupAddressAddition, Job::getPickupAddressAddition, Job::setPickupAddressAddition);
binder.bind(savePickupAddress, Job::isSavePickupAddress, Job::setSavePickupAddress);
binder.bind(deliveryCompany, Job::getDeliveryCompany, Job::setDeliveryCompany); binder.bind(deliveryCompany, Job::getDeliveryCompany, Job::setDeliveryCompany);
binder.bind(deliverySalutation, Job::getDeliverySalutation, Job::setDeliverySalutation); binder.bind(deliverySalutation, Job::getDeliverySalutation, Job::setDeliverySalutation);
binder.bind(deliveryPhone, Job::getDeliveryPhone, Job::setDeliveryPhone); binder.bind(deliveryPhone, Job::getDeliveryPhone, Job::setDeliveryPhone);
binder.bind(deliveryAddressAddition, Job::getDeliveryAddressAddition, Job::setDeliveryAddressAddition); binder.bind(deliveryAddressAddition, Job::getDeliveryAddressAddition, Job::setDeliveryAddressAddition);
binder.bind(saveDeliveryAddress, Job::isSaveDeliveryAddress, Job::setSaveDeliveryAddress);
binder.bind(digitalProcessing, Job::isDigitalProcessing, Job::setDigitalProcessing); binder.bind(digitalProcessing, Job::isDigitalProcessing, Job::setDigitalProcessing);
binder.bind(appUser, Job::getAppUser, Job::setAppUser); binder.bind(appUser, Job::getAppUser, Job::setAppUser);
@@ -800,54 +808,33 @@ public class AddJobView extends Main {
job.setPickupDate(pickupDate.getValue()); job.setPickupDate(pickupDate.getValue());
job.setDeliveryDate(deliveryDate.getValue()); job.setDeliveryDate(deliveryDate.getValue());
if (remarkArea != null) job.setRemark(remarkArea.getValue()); if (remarkArea != null) job.setRemark(remarkArea.getValue());
if (tasksList != null) {
java.util.List<String> tasks = new java.util.ArrayList<>();
tasksList.getChildren().forEach(comp -> {
if (comp instanceof com.vaadin.flow.component.orderedlayout.HorizontalLayout row) {
row.getChildren().filter(c -> c instanceof TextField).forEach(tf -> {
String v = ((TextField) tf).getValue();
if (v != null && !v.trim().isEmpty()) tasks.add(v.trim());
});
}
});
job.setTasks(tasks);
}
if (cargoList != null) {
java.util.List<de.assecutor.votianlt.model.CargoItem> items = new java.util.ArrayList<>();
cargoList.getChildren().forEach(comp -> {
if (comp instanceof com.vaadin.flow.component.orderedlayout.HorizontalLayout row) {
String desc = null; Integer qty = null; Double weight = null, len = null, wid = null, hei = null;
for (com.vaadin.flow.component.Component c : row.getChildren().toList()) {
if (c instanceof TextField tf && tf.getLabel() != null && tf.getLabel().contains("Beschreibung")) desc = tf.getValue();
if (c instanceof IntegerField ifld) qty = ifld.getValue();
if (c instanceof NumberField nf) {
String label = nf.getLabel();
if (label != null) {
switch (label) {
case "Gewicht" -> weight = nf.getValue();
case "Länge" -> len = nf.getValue();
case "Breite" -> wid = nf.getValue();
case "Höhe" -> hei = nf.getValue();
}
}
}
}
if (desc != null || qty != null || weight != null || len != null || wid != null || hei != null) {
de.assecutor.votianlt.model.CargoItem ci = new de.assecutor.votianlt.model.CargoItem();
ci.setDescription(desc); ci.setQuantity(qty); ci.setWeightKg(weight);
ci.setLengthMm(len); ci.setWidthMm(wid); ci.setHeightMm(hei);
items.add(ci);
}
}
});
// temporär im Job-Objekt als Transfertyp beilegen (über transient Helper)
jobTransientCargo = items;
}
// Validate all required fields using the binder // Validate all required fields using the binder
if (binder.writeBeanIfValid(job)) { if (binder.writeBeanIfValid(job)) {
// All validations passed, save the job with cargo items // Ensure at least one cargo item is provided (tasks may be empty)
Job savedJob = addJobService.addJobWithCargo(job, jobTransientCargo); // Definition: Ein Cargo-Item gilt nur als gefüllt, wenn eine Beschreibung vorhanden ist
List<CargoItem> cargoFilled = cargoItemsState.stream()
.filter(Objects::nonNull)
.filter(ci -> ci.getDescription() != null && !ci.getDescription().isBlank())
.toList();
if (cargoFilled.isEmpty()) {
Notification errorNotification = Notification.show(
"Bitte fügen Sie mindestens eine Ladungszeile hinzu.");
errorNotification.setDuration(5000);
return;
}
// toggle cargo error highlight
boolean hasCargo = !cargoFilled.isEmpty();
cargoError.setVisible(!hasCargo);
if (!hasCargo) {
cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-error-color-50pct)");
} else {
cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
}
// 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 anzeigen
Notification successNotification = Notification.show( Notification successNotification = Notification.show(
@@ -865,6 +852,9 @@ public class AddJobView extends Main {
} catch (Exception e) { } catch (Exception e) {
// Other errors // Other errors
// 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( Notification errorNotification = Notification.show(
"Fehler beim Erstellen des Auftrags: " + e.getMessage()); "Fehler beim Erstellen des Auftrags: " + e.getMessage());
errorNotification.setDuration(5000); errorNotification.setDuration(5000);
@@ -872,11 +862,19 @@ public class AddJobView extends Main {
} }
/** /**
cargoItemsState.clear();
cargoList.removeAll();
* Setzt alle Formularfelder zurück * Setzt alle Formularfelder zurück
*/ */
private void clearForm() { private void clearForm() {
// Reset cargo state and UI
cargoItemsState.clear();
if (cargoList != null) cargoList.removeAll();
// Reset binder to clear validation state // Reset binder to clear validation state
binder.readBean(new Job()); binder.readBean(new Job());
// Reset tasks state and UI
tasksState.clear();
if (tasksList != null) tasksList.removeAll();
// Customer selection // Customer selection
customerSelection.clear(); customerSelection.clear();
@@ -937,7 +935,6 @@ public class AddJobView extends Main {
job.setPickupAddressAddition(pickupAddressAddition.getValue()); job.setPickupAddressAddition(pickupAddressAddition.getValue());
job.setPickupZip(pickupZip.getValue()); job.setPickupZip(pickupZip.getValue());
job.setPickupCity(pickupCity.getValue()); job.setPickupCity(pickupCity.getValue());
job.setSavePickupAddress(savePickupAddress.getValue());
// Delivery address // Delivery address
job.setDeliveryCompany(deliveryCompany.getValue()); job.setDeliveryCompany(deliveryCompany.getValue());
@@ -950,7 +947,6 @@ public class AddJobView extends Main {
job.setDeliveryAddressAddition(deliveryAddressAddition.getValue()); job.setDeliveryAddressAddition(deliveryAddressAddition.getValue());
job.setDeliveryZip(deliveryZip.getValue()); job.setDeliveryZip(deliveryZip.getValue());
job.setDeliveryCity(deliveryCity.getValue()); job.setDeliveryCity(deliveryCity.getValue());
job.setSaveDeliveryAddress(saveDeliveryAddress.getValue());
// Digital processing // Digital processing
job.setDigitalProcessing(digitalProcessing.getValue()); job.setDigitalProcessing(digitalProcessing.getValue());
@@ -1015,28 +1011,32 @@ public class AddJobView extends Main {
wrapper.setWidthFull(); wrapper.setWidthFull();
wrapper.setSpacing(true); wrapper.setSpacing(true);
VerticalLayout cargoArea = new VerticalLayout(); cargoAreaContainer = new VerticalLayout();
cargoArea.setWidthFull(); cargoAreaContainer.setWidthFull();
cargoArea.setSpacing(true); cargoAreaContainer.setSpacing(true);
cargoArea.getStyle().set("background", "var(--lumo-base-color)"); cargoAreaContainer.getStyle().set("background", "var(--lumo-base-color)");
cargoArea.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)"); cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
cargoArea.getStyle().set("border-radius", "var(--lumo-border-radius-m)"); cargoAreaContainer.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
cargoArea.getStyle().set("padding", "var(--lumo-space-m)"); cargoAreaContainer.getStyle().set("padding", "var(--lumo-space-m)");
wrapper.add(new H3("Ladung")); H3 cargoTitle = new H3("Ladung");
cargoError = new Span("Bitte fügen Sie mindestens eine Ladungszeile hinzu.");
cargoError.getStyle().set("color", "var(--lumo-error-text-color)");
cargoError.getStyle().set("font-size", "var(--lumo-font-size-s)");
cargoError.setVisible(false);
wrapper.add(cargoTitle);
cargoList = new VerticalLayout(); cargoList = new VerticalLayout();
cargoList.setPadding(false); cargoList.setPadding(false);
cargoList.setSpacing(true); cargoList.setSpacing(true);
cargoArea.add(cargoList); cargoAreaContainer.add(cargoError, cargoList);
java.util.function.BiConsumer<String, java.util.function.Consumer<HorizontalLayout>> addCargoRow = (iconName, afterCreate) -> { java.util.function.BiConsumer<String, java.util.function.Consumer<HorizontalLayout>> addCargoRow = (iconName, afterCreate) -> {
HorizontalLayout row = new HorizontalLayout(); HorizontalLayout row = new HorizontalLayout();
row.setWidthFull(); row.setWidthFull();
row.setAlignItems(FlexComponent.Alignment.END); row.setAlignItems(FlexComponent.Alignment.END);
ComboBox<String> desc = new ComboBox<>("Beschreibung"); ComboBox<String> desc = new ComboBox<>("Beschreibung");
desc.setItems("Europalette", "Einwegpalette", "Düsseldorfer-Palette", "Gitterboxpalette", "Gitterwagen", "Paket"); desc.setItems("Europalette", "Einwegpalette", "Düsseldorfer-Palette", "Gitterboxpalette", "Gitterwagen", "Paket");
desc.setAllowCustomValue(true); desc.setAllowCustomValue(true);
@@ -1064,10 +1064,43 @@ public class AddJobView extends Main {
Button remove = new Button(new Icon(VaadinIcon.CLOSE_SMALL)); Button remove = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
remove.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY); remove.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
remove.addClickListener(e -> cargoList.remove(row)); remove.addClickListener(e -> {
int idx = cargoList.getChildren().toList().indexOf(row);
if (idx >= 0 && idx < cargoItemsState.size()) {
cargoItemsState.remove(idx);
}
cargoList.remove(row);
});
row.add(desc, qty, weight, len, wid, hei, remove); row.add(desc, qty, weight, len, wid, hei, remove);
cargoList.add(row); cargoList.add(row);
// Ensure backing list is in sync: add new item and bind change listeners
CargoItem item = new CargoItem();
cargoItemsState.add(item);
// Pre-fill current input values into backing item
item.setDescription(desc.getValue());
item.setQuantity(qty.getValue());
item.setWeightKg(weight.getValue());
item.setLengthMm(len.getValue());
// Initialize from current inputs
item.setDescription(desc.getValue());
item.setQuantity(qty.getValue());
item.setWeightKg(weight.getValue());
item.setLengthMm(len.getValue());
item.setWidthMm(wid.getValue());
item.setHeightMm(hei.getValue());
item.setWidthMm(wid.getValue());
item.setHeightMm(hei.getValue());
desc.addValueChangeListener(ev -> item.setDescription(ev.getValue()));
qty.addValueChangeListener(ev -> item.setQuantity(ev.getValue()));
weight.addValueChangeListener(ev -> item.setWeightKg(ev.getValue()));
len.addValueChangeListener(ev -> item.setLengthMm(ev.getValue()));
wid.addValueChangeListener(ev -> item.setWidthMm(ev.getValue()));
hei.addValueChangeListener(ev -> item.setHeightMm(ev.getValue()));
if (afterCreate != null) afterCreate.accept(row); if (afterCreate != null) afterCreate.accept(row);
}; };
@@ -1075,42 +1108,10 @@ public class AddJobView extends Main {
addCargoRow.accept("paket", r -> {}); addCargoRow.accept("paket", r -> {});
addCargoRow.accept("", r -> {}); addCargoRow.accept("", r -> {});
wrapper.add(cargoArea); wrapper.add(cargoAreaContainer);
return wrapper; return wrapper;
} }
private void populateFromJob(Job job) {
// Pickup address
if (job.getPickupCompany() != null) pickupCompany.setValue(job.getPickupCompany());
if (job.getPickupSalutation() != null) pickupSalutation.setValue(job.getPickupSalutation());
if (job.getPickupFirstName() != null) pickupFirstName.setValue(job.getPickupFirstName());
if (job.getPickupLastName() != null) pickupLastName.setValue(job.getPickupLastName());
if (job.getPickupPhone() != null) pickupPhone.setValue(job.getPickupPhone());
if (job.getPickupStreet() != null) pickupStreet.setValue(job.getPickupStreet());
if (job.getPickupHouseNumber() != null) pickupHouseNumber.setValue(job.getPickupHouseNumber());
if (job.getPickupAddressAddition() != null) pickupAddressAddition.setValue(job.getPickupAddressAddition());
if (job.getPickupZip() != null) pickupZip.setValue(job.getPickupZip());
if (job.getPickupCity() != null) pickupCity.setValue(job.getPickupCity());
savePickupAddress.setValue(job.isSavePickupAddress());
// Delivery address
if (job.getDeliveryCompany() != null) deliveryCompany.setValue(job.getDeliveryCompany());
if (job.getDeliverySalutation() != null) deliverySalutation.setValue(job.getDeliverySalutation());
if (job.getDeliveryFirstName() != null) deliveryFirstName.setValue(job.getDeliveryFirstName());
if (job.getDeliveryLastName() != null) deliveryLastName.setValue(job.getDeliveryLastName());
if (job.getDeliveryPhone() != null) deliveryPhone.setValue(job.getDeliveryPhone());
if (job.getDeliveryStreet() != null) deliveryStreet.setValue(job.getDeliveryStreet());
if (job.getDeliveryHouseNumber() != null) deliveryHouseNumber.setValue(job.getDeliveryHouseNumber());
if (job.getDeliveryAddressAddition() != null) deliveryAddressAddition.setValue(job.getDeliveryAddressAddition());
if (job.getDeliveryZip() != null) deliveryZip.setValue(job.getDeliveryZip());
if (job.getDeliveryCity() != null) deliveryCity.setValue(job.getDeliveryCity());
saveDeliveryAddress.setValue(job.isSaveDeliveryAddress());
// Digital processing
digitalProcessing.setValue(job.isDigitalProcessing());
if (job.getAppUser() != null) appUser.setValue(job.getAppUser());
}
private Component createTasksAndNotesSection() { private Component createTasksAndNotesSection() {
VerticalLayout wrapper = new VerticalLayout(); VerticalLayout wrapper = new VerticalLayout();
wrapper.setWidthFull(); wrapper.setWidthFull();
@@ -1144,11 +1145,21 @@ public class AddJobView extends Main {
Button remove = new Button(new Icon(VaadinIcon.CLOSE_SMALL)); Button remove = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
remove.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY); remove.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
remove.addClickListener(e -> tasksList.remove(row)); remove.addClickListener(e -> {
int idx = tasksList.getChildren().toList().indexOf(row);
if (idx >= 0 && idx < tasksState.size()) tasksState.remove(idx);
tasksList.remove(row);
});
row.add(taskField, remove); row.add(taskField, remove);
row.setFlexGrow(1, taskField); row.setFlexGrow(1, taskField);
tasksList.add(row); tasksList.add(row);
// Keep backing tasks list in sync
TaskEntry te = new TaskEntry();
te.setText(taskField.getValue());
tasksState.add(te);
taskField.addValueChangeListener(ev -> te.setText(ev.getValue()));
}; };
// 1 Beispielzeile // 1 Beispielzeile

View File

@@ -0,0 +1,12 @@
package de.assecutor.votianlt.repository;
import de.assecutor.votianlt.model.TaskEntry;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;
public interface TaskRepository extends MongoRepository<TaskEntry, ObjectId> {
List<TaskEntry> findByJobId(ObjectId jobId);
}