This commit is contained in:
2026-01-07 10:39:36 +01:00
parent 652d2b1513
commit ce012ff82f
16 changed files with 25 additions and 66 deletions

View File

@@ -9,7 +9,6 @@ import de.assecutor.votianlt.model.CargoItem;
import de.assecutor.votianlt.model.Job;
import de.assecutor.votianlt.model.task.BaseTask;
import de.assecutor.votianlt.pages.service.AppUserService;
import de.assecutor.votianlt.pages.service.UserService;
import de.assecutor.votianlt.repository.AppUserRepository;
import de.assecutor.votianlt.repository.CargoItemRepository;
import de.assecutor.votianlt.repository.JobRepository;
@@ -71,7 +70,6 @@ public class MessageController {
private final JobHistoryService jobHistoryService;
private final EmailService emailService;
private final MessageService messageService;
private final UserService userService;
private final ObjectMapper objectMapper;
private final ClientConnectionService clientConnectionService;
@@ -79,7 +77,7 @@ public class MessageController {
AppUserService appUserService, JobRepository jobRepository, CargoItemRepository cargoItemRepository,
TaskRepository taskRepository, PhotoRepository photoRepository, BarcodeRepository barcodeRepository,
SignatureRepository signatureRepository, CommentRepository commentRepository, JobHistoryService jobHistoryService,
EmailService emailService, MessageService messageService, UserService userService, ObjectMapper objectMapper,
EmailService emailService, MessageService messageService, ObjectMapper objectMapper,
ClientConnectionService clientConnectionService) {
this.mqttPublisher = mqttPublisher;
this.appUserRepository = appUserRepository;
@@ -94,7 +92,6 @@ public class MessageController {
this.jobHistoryService = jobHistoryService;
this.emailService = emailService;
this.messageService = messageService;
this.userService = userService;
this.objectMapper = objectMapper;
this.clientConnectionService = clientConnectionService;
}
@@ -483,10 +480,6 @@ public class MessageController {
}
}
private void completeTask(Object tid) {
completeTaskWithHistory(tid, null);
}
private void completeTaskWithHistory(Object tid, String extraDataSummary) {
String taskIdStr = tid.toString();
try {
@@ -615,13 +608,6 @@ public class MessageController {
return userClientIdMapping.get(userId);
}
/**
* Get the userId (AppUser ID) for a given clientId
*/
private String getUserIdForClientId(String clientId) {
return clientIdUserMapping.get(clientId);
}
/**
* Handle pong response from a client.
* Client sends to /server/{clientId}/pong with payload { timestamp }.

View File

@@ -32,9 +32,7 @@ public class MqttMessagingPlugin implements MessagingPlugin {
// Topic templates
private static final String TOPIC_TO_CLIENT = "/client/%s/%s"; // /client/{clientId}/{messageType}
private static final String TOPIC_FROM_CLIENT = "/server/%s/%s"; // /server/{clientId}/{messageType}
private static final String TOPIC_ACK_TO_CLIENT = "/client/%s/ack"; // /client/{clientId}/ack (messageId in payload)
private static final String TOPIC_ACK_FROM_CLIENT = "/server/%s/ack"; // /server/{clientId}/ack (messageId in payload)
// Subscription patterns
private static final String PATTERN_FROM_CLIENT = "/server/+/%s"; // /server/+/{messageType}
@@ -52,7 +50,6 @@ public class MqttMessagingPlugin implements MessagingPlugin {
private static final String CONFIG_USERNAME = "username";
private static final String CONFIG_PASSWORD = "password";
private static final String CONFIG_CLIENT_ID = "client.id";
private static final String CONFIG_AUTO_RECONNECT = "auto.reconnect";
private static final String CONFIG_CLEAN_START = "clean.start";
private static final String CONFIG_CONNECTION_TIMEOUT = "connection.timeout.seconds";
private static final String CONFIG_KEEP_ALIVE = "keep.alive.seconds";

View File

@@ -6,7 +6,6 @@ import org.springframework.data.mongodb.core.mapping.Document;
import org.bson.types.ObjectId;
import java.time.LocalDateTime;
import java.util.List;
/**
* Photo entity for storing photo data from task completions. References the job

View File

@@ -43,13 +43,23 @@ class MqttPublisherImpl implements MqttPublisher {
@Override
public void publishAsJson(String topic, Object payload, boolean retained) {
try {
// Parse topic to extract clientId and messageType
// Expected format: /client/{clientId}/{messageType}
String[] parts = topic.split("/");
if (parts.length < 4 || !"client".equals(parts[1])) {
log.warn("Invalid topic format: {}. Expected /client/{clientId}/{messageType}", topic);
return;
}
String clientId = parts[2];
String messageType = parts[3];
// Use MessageDeliveryService for reliable delivery
DeliveryOptions options = DeliveryOptions.builder()
.requiresAck(true)
.retained(retained)
.build();
deliveryService.sendMessage(topic, payload, options)
deliveryService.sendToClient(clientId, messageType, payload, options)
.thenAccept(receipt -> {
log.info("=== MESSAGE DELIVERY SUBMITTED ===");
log.info("Topic: {}", topic);

View File

@@ -36,7 +36,6 @@ import lombok.extern.slf4j.Slf4j;
import static com.vaadin.flow.theme.lumo.LumoUtility.*;
import java.util.List;
import java.util.Optional;
@AnonymousAllowed
@Slf4j

View File

@@ -25,8 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
@Route(value = "add-app-user", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
@RolesAllowed({ "USER", "ADMIN" })
public class AddAppUserView extends VerticalLayout {
private final AppUserService appUserService;
private final Binder<AppUser> binder = new Binder<>(AppUser.class);
// Form fields
@@ -40,7 +38,6 @@ public class AddAppUserView extends VerticalLayout {
@Autowired
public AddAppUserView(AppUserService appUserService) {
this.appUserService = appUserService;
setSizeFull();
setPadding(true);
setSpacing(true);
@@ -182,10 +179,6 @@ public class AddAppUserView extends VerticalLayout {
AppUser newAppUser = new AppUser();
binder.writeBean(newAppUser);
// Save AppUser first to get the ObjectId
AppUser savedUser = appUserService.createAppUser(newAppUser);
// Show success message
Notification.show("App-Nutzer erfolgreich angelegt", 3000, Notification.Position.MIDDLE);

View File

@@ -41,7 +41,6 @@ import de.assecutor.votianlt.model.task.BarcodeTask;
import de.assecutor.votianlt.model.task.CommentTask;
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 de.assecutor.votianlt.pages.service.AppUserService;
@@ -854,7 +853,9 @@ public class AddJobView extends Main {
binder.bind(deliveryPhone, Job::getDeliveryPhone, Job::setDeliveryPhone);
binder.bind(deliveryAddressAddition, Job::getDeliveryAddressAddition, Job::setDeliveryAddressAddition);
binder.bind(digitalProcessing, Job::isDigitalProcessing, Job::setDigitalProcessing);
binder.forField(digitalProcessing).bind(
Job::isDigitalProcessing,
(job, value) -> job.setDigitalProcessing(Boolean.TRUE.equals(value)));
// Bind appUser with converter: AppUser object <-> String ID
binder.forField(appUser).withConverter(
@@ -1972,6 +1973,9 @@ public class AddJobView extends Main {
configContainer.add(barcodeLayout);
break;
default:
throw new IllegalArgumentException("Unbekannter TaskType: " + taskType);
}
}
@@ -2245,9 +2249,6 @@ public class AddJobView extends Main {
taskContainer.add(taskTypeCombo, configContainer);
taskContainer.add(deleteXButton);
// The task is already in tasksState from loadTasksFromTemplate
// Find the index and use it for the UI
int taskIndex = tasksState.size() - 1; // This should be the last added task
final BaseTask[] currentTask = { task };
// Set up the value change listener for the combo box

View File

@@ -1,7 +1,5 @@
package de.assecutor.votianlt.pages.view;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.H3;

View File

@@ -10,7 +10,6 @@ import com.vaadin.flow.router.Route;
import de.assecutor.votianlt.model.PriceTable;
import de.assecutor.votianlt.pages.base.ui.view.AdminLayout;
import de.assecutor.votianlt.repository.PriceTableRepository;
import de.assecutor.votianlt.security.SecurityService;
import jakarta.annotation.security.RolesAllowed;
@Route(value = "admin-price-table", layout = AdminLayout.class)

View File

@@ -12,7 +12,6 @@ import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.theme.lumo.LumoUtility;
import de.assecutor.votianlt.model.Customer;
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
import de.assecutor.votianlt.pages.service.CustomerService;
import java.time.Clock;

View File

@@ -16,7 +16,6 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.textfield.EmailField;
import com.vaadin.flow.component.textfield.TextField;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
@@ -219,7 +218,9 @@ public class EditProfileView extends HorizontalLayout {
binder.forField(faxField).bind(User::getFax, User::setFax);
// Abweichende Rechnungsadresse binden
binder.forField(diffInvoiceAddress).bind(User::isDiffInvoiceAddress, User::setDiffInvoiceAddress);
binder.forField(diffInvoiceAddress).bind(
User::isDiffInvoiceAddress,
(user, value) -> user.setDiffInvoiceAddress(Boolean.TRUE.equals(value)));
binder.forField(invCompanyField).bind(User::getInvCompany, User::setInvCompany);
binder.forField(invCompanyAddField).bind(User::getInvCompanyAddition, User::setInvCompanyAddition);
binder.forField(invFirstnameField).bind(User::getInvFirstname, User::setInvFirstname);

View File

@@ -50,7 +50,6 @@ import org.bson.types.ObjectId;
import java.util.ArrayList;
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")
@@ -66,7 +65,6 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
private final PhotoRepository photoRepository;
private final CommentRepository commentRepository;
private final AppUserService appUserService;
private final MessageService messageService;
private final VerticalLayout content;
private final List<Div> taskCards = new ArrayList<>();
@@ -83,7 +81,6 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
this.photoRepository = photoRepository;
this.commentRepository = commentRepository;
this.appUserService = appUserService;
this.messageService = messageService;
setSizeFull();
addClassNames(LumoUtility.BoxSizing.BORDER, LumoUtility.Display.FLEX, LumoUtility.FlexDirection.COLUMN,
@@ -142,9 +139,6 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
String appUserId = job.getAppUser();
String jobNumber = job.getJobNumber() != null ? job.getJobNumber() : job.getId().toHexString();
// Check if messages exist for this job
List<de.assecutor.votianlt.model.Message> existingMessages = messageService.getMessagesForJob(job.getId());
// Navigate to message details view with job conversation
// Format: message-details/{clientId}/job-{jobNumber}
String conversationId = "job-" + jobNumber;
@@ -541,7 +535,7 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
if (confirmationTask.getButtonText() != null && !confirmationTask.getButtonText().isBlank()) {
content.add(new Span("Button-Text: " + confirmationTask.getButtonText()));
}
} else if (task instanceof SignatureTask signatureTask) {
} else if (task instanceof SignatureTask) {
content.add(new Span("Unterschrift erforderlich"));
// Show signature if task is completed
@@ -578,7 +572,7 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
log.debug("Failed to load signature for task {}: {}", task.getId(), e.getMessage());
}
}
} else if (task instanceof BarcodeTask barcodeTask) {
} else if (task instanceof BarcodeTask) {
content.add(new Span("Barcode-Scan erforderlich"));
// Show barcodes if task is completed

View File

@@ -37,7 +37,6 @@ import de.assecutor.votianlt.model.MessageType;
import de.assecutor.votianlt.pages.service.AppUserService;
import de.assecutor.votianlt.service.MessageBroadcaster;
import de.assecutor.votianlt.service.MessageService;
import de.assecutor.votianlt.security.SecurityService;
import de.assecutor.votianlt.event.MessageReadStatusChangedEvent;
import org.springframework.context.ApplicationEventPublisher;
import jakarta.annotation.security.RolesAllowed;
@@ -75,7 +74,6 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
private final AppUserService appUserService;
private final MessageService messageService;
private final SecurityService securityService;
private final MessageBroadcaster messageBroadcaster;
private final ApplicationEventPublisher eventPublisher;
@@ -98,11 +96,10 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
private static final float JPEG_COMPRESSION_QUALITY = 0.8f;
public MessageDetailsView(AppUserService appUserService, MessageService messageService,
SecurityService securityService, MessageBroadcaster messageBroadcaster,
MessageBroadcaster messageBroadcaster,
ApplicationEventPublisher eventPublisher) {
this.appUserService = appUserService;
this.messageService = messageService;
this.securityService = securityService;
this.messageBroadcaster = messageBroadcaster;
this.eventPublisher = eventPublisher;
@@ -800,9 +797,6 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
return;
}
String sender = Optional.ofNullable(securityService.getCurrentUsername()).filter(name -> !name.isBlank())
.orElse("System");
ensureJobContextForConversation(currentMessages);
try {

View File

@@ -15,7 +15,6 @@ import com.vaadin.flow.router.Route;
import de.assecutor.votianlt.model.Job;
import de.assecutor.votianlt.model.JobStatus;
import de.assecutor.votianlt.repository.JobRepository;
import de.assecutor.votianlt.security.SecurityService;
import jakarta.annotation.security.RolesAllowed;
import org.springframework.beans.factory.annotation.Autowired;
@@ -29,13 +28,11 @@ public class ShowJobsView extends VerticalLayout {
private final TextField searchField = new TextField("Auftragsnummer suchen");
private final ComboBox<String> statusFilter = new ComboBox<>("Status");
private final JobRepository jobRepository;
private final SecurityService securityService;
private final Grid<Job> grid = new Grid<>(Job.class, false);
@Autowired
public ShowJobsView(JobRepository jobRepository, SecurityService securityService) {
public ShowJobsView(JobRepository jobRepository) {
this.jobRepository = jobRepository;
this.securityService = securityService;
setSizeFull();
setPadding(true);
setSpacing(true);

View File

@@ -8,8 +8,6 @@ import org.springframework.stereotype.Service;
import com.itextpdf.html2pdf.HtmlConverter;
import java.io.ByteArrayOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.time.LocalDate;
@@ -160,8 +158,6 @@ public class CustomerInvoiceService {
private String fillCustomerInvoiceHtmlWithInvoiceData(String html, CustomerInvoiceData data) {
String filledHtml = html;
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(Locale.GERMANY);
// Replace invoice header data
filledHtml = filledHtml.replace("${invoiceData.invoiceNumber}", nvl(data.getInvoiceNumber()));
filledHtml = filledHtml.replace("${invoiceData.invoiceDate}", nvl(data.getFormattedInvoiceDate()));

View File

@@ -1,9 +1,7 @@
package de.assecutor.votianlt.service;
import de.assecutor.votianlt.model.AppUser;
import de.assecutor.votianlt.model.Job;
import de.assecutor.votianlt.model.User;
import de.assecutor.votianlt.repository.AppUserRepository;
import de.assecutor.votianlt.repository.JobRepository;
import de.assecutor.votianlt.repository.TaskRepository;
import de.assecutor.votianlt.repository.UserRepository;
@@ -21,8 +19,6 @@ import java.util.Optional;
@RequiredArgsConstructor
@Slf4j
public class EmailService {
private final AppUserRepository appUserRepository;
private final UserRepository userRepository;
private final JobRepository jobRepository;
private final TaskRepository taskRepository;