feat: Adressbuch mit Kundennummer, Update-Flow und interne Einträge
- Menüpunkt "Kunden" in "Adressbuch" umbenannt und App-Label "Verfügbare Jobs" zu "Auftragsliste" geändert (alle 10 Sprachen) - Fortlaufende Kundennummer (usrId) ab 10000 über neuen SequenceGeneratorService und Counter-Dokument in misc-Collection - Abholung/Lieferstation-Dialog: Änderungen an verknüpften Stammdaten aktualisieren den bestehenden Adressbuch-Eintrag statt einen neuen zu erzeugen; Checkbox-Label wechselt zu "Adresse im Adressbuch aktualisieren" - Geänderte Adressen ohne Checkbox werden als interner Customer (internal=true) gesichert und im Adressbuch ausgeblendet - E-Mail in AddCustomer und in Stations-Dialogen kein Pflichtfeld mehr; "(Login)" aus profile.email entfernt - Manuelles Beenden eines Auftrags öffnet neue Seite JobManualCompleteView statt eines Dialogs
This commit is contained in:
@@ -55,7 +55,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
String get jobs => 'Jobs';
|
String get jobs => 'Jobs';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get availableJobs => 'Verfügbare Jobs';
|
String get availableJobs => 'Auftragsliste';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get chats => 'Chats';
|
String get chats => 'Chats';
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
String get jobs => 'Jobs';
|
String get jobs => 'Jobs';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get availableJobs => 'Available Jobs';
|
String get availableJobs => 'Order List';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get chats => 'Chats';
|
String get chats => 'Chats';
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class AppLocalizationsEs extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get jobs => 'Trabajos';
|
String get jobs => 'Trabajos';
|
||||||
@override
|
@override
|
||||||
String get availableJobs => 'Trabajos Disponibles';
|
String get availableJobs => 'Lista de pedidos';
|
||||||
@override
|
@override
|
||||||
String get chats => 'Chats';
|
String get chats => 'Chats';
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class AppLocalizationsEt extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get jobs => 'Tööd';
|
String get jobs => 'Tööd';
|
||||||
@override
|
@override
|
||||||
String get availableJobs => 'Saadaolevad tööd';
|
String get availableJobs => 'Tellimuste loend';
|
||||||
@override
|
@override
|
||||||
String get chats => 'Vestlused';
|
String get chats => 'Vestlused';
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class AppLocalizationsFr extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get jobs => 'Emplois';
|
String get jobs => 'Emplois';
|
||||||
@override
|
@override
|
||||||
String get availableJobs => 'Emplois Disponibles';
|
String get availableJobs => 'Liste des commandes';
|
||||||
@override
|
@override
|
||||||
String get chats => 'Discussions';
|
String get chats => 'Discussions';
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class AppLocalizationsLt extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get jobs => 'Darbai';
|
String get jobs => 'Darbai';
|
||||||
@override
|
@override
|
||||||
String get availableJobs => 'Galimi darbai';
|
String get availableJobs => 'Užsakymų sąrašas';
|
||||||
@override
|
@override
|
||||||
String get chats => 'Pokalbiai';
|
String get chats => 'Pokalbiai';
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class AppLocalizationsLv extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get jobs => 'Darbi';
|
String get jobs => 'Darbi';
|
||||||
@override
|
@override
|
||||||
String get availableJobs => 'Pieejamie darbi';
|
String get availableJobs => 'Pasūtījumu saraksts';
|
||||||
@override
|
@override
|
||||||
String get chats => 'Tērzēšanas';
|
String get chats => 'Tērzēšanas';
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class AppLocalizationsPl extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get jobs => 'Zadania';
|
String get jobs => 'Zadania';
|
||||||
@override
|
@override
|
||||||
String get availableJobs => 'Dostępne Zadania';
|
String get availableJobs => 'Lista zleceń';
|
||||||
@override
|
@override
|
||||||
String get chats => 'Czaty';
|
String get chats => 'Czaty';
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class AppLocalizationsRu extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get jobs => 'Задания';
|
String get jobs => 'Задания';
|
||||||
@override
|
@override
|
||||||
String get availableJobs => 'Доступные задания';
|
String get availableJobs => 'Список заказов';
|
||||||
@override
|
@override
|
||||||
String get chats => 'Чаты';
|
String get chats => 'Чаты';
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class AppLocalizationsTr extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get jobs => 'İşler';
|
String get jobs => 'İşler';
|
||||||
@override
|
@override
|
||||||
String get availableJobs => 'Mevcut İşler';
|
String get availableJobs => 'Sipariş Listesi';
|
||||||
@override
|
@override
|
||||||
String get chats => 'Sohbetler';
|
String get chats => 'Sohbetler';
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import '../task.dart';
|
|||||||
|
|
||||||
// Signature Task
|
// Signature Task
|
||||||
class SignatureTask extends Task {
|
class SignatureTask extends Task {
|
||||||
|
final String? note;
|
||||||
|
|
||||||
SignatureTask({
|
SignatureTask({
|
||||||
required super.id,
|
required super.id,
|
||||||
required super.jobId,
|
required super.jobId,
|
||||||
@@ -14,11 +16,19 @@ class SignatureTask extends Task {
|
|||||||
super.title,
|
super.title,
|
||||||
super.description,
|
super.description,
|
||||||
super.displayName,
|
super.displayName,
|
||||||
|
this.note,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory SignatureTask.fromJson(Map<String, dynamic> json) {
|
factory SignatureTask.fromJson(Map<String, dynamic> json) {
|
||||||
final commonProps = Task.parseCommonProperties(json);
|
final commonProps = Task.parseCommonProperties(json);
|
||||||
|
|
||||||
|
String? note;
|
||||||
|
final taskSpecificData = json['taskSpecificData'];
|
||||||
|
if (taskSpecificData is Map<String, dynamic>) {
|
||||||
|
final n = taskSpecificData['note'];
|
||||||
|
if (n is String) note = n;
|
||||||
|
}
|
||||||
|
|
||||||
return SignatureTask(
|
return SignatureTask(
|
||||||
id: commonProps['id'],
|
id: commonProps['id'],
|
||||||
jobId: commonProps['jobId'],
|
jobId: commonProps['jobId'],
|
||||||
@@ -31,6 +41,7 @@ class SignatureTask extends Task {
|
|||||||
title: commonProps['title'],
|
title: commonProps['title'],
|
||||||
description: commonProps['description'],
|
description: commonProps['description'],
|
||||||
displayName: commonProps['displayName'],
|
displayName: commonProps['displayName'],
|
||||||
|
note: note,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +58,11 @@ class SignatureTask extends Task {
|
|||||||
'taskOrder': taskOrder,
|
'taskOrder': taskOrder,
|
||||||
'description': description,
|
'description': description,
|
||||||
'displayName': displayName,
|
'displayName': displayName,
|
||||||
'taskSpecificData': {'taskType': 'SIGNATURE', 'title': title},
|
'taskSpecificData': {
|
||||||
|
'taskType': 'SIGNATURE',
|
||||||
|
'title': title,
|
||||||
|
'note': note,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +79,7 @@ class SignatureTask extends Task {
|
|||||||
String? title,
|
String? title,
|
||||||
String? description,
|
String? description,
|
||||||
String? displayName,
|
String? displayName,
|
||||||
|
String? note,
|
||||||
}) {
|
}) {
|
||||||
return SignatureTask(
|
return SignatureTask(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
@@ -77,6 +93,7 @@ class SignatureTask extends Task {
|
|||||||
title: title ?? this.title,
|
title: title ?? this.title,
|
||||||
description: description ?? this.description,
|
description: description ?? this.description,
|
||||||
displayName: displayName ?? this.displayName,
|
displayName: displayName ?? this.displayName,
|
||||||
|
note: note ?? this.note,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -831,6 +831,42 @@ class DatabaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save signature note (Bemerkung) for a task into user_data table
|
||||||
|
Future<void> saveTaskSignatureNote(String taskId, String note) async {
|
||||||
|
try {
|
||||||
|
if (_store == null) {
|
||||||
|
developer.log('Database not initialized', name: 'DatabaseService');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final key = 'task_signature_note:$taskId';
|
||||||
|
await saveKeyValue(key, note);
|
||||||
|
} catch (e, st) {
|
||||||
|
developer.log(
|
||||||
|
'Error saving task signature note: $e',
|
||||||
|
name: 'DatabaseService',
|
||||||
|
);
|
||||||
|
developer.log('Stack trace: $st', name: 'DatabaseService');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load signature note (Bemerkung) for a task from user_data table
|
||||||
|
Future<String?> loadTaskSignatureNote(String taskId) async {
|
||||||
|
try {
|
||||||
|
if (_store == null) {
|
||||||
|
developer.log('Database not initialized', name: 'DatabaseService');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return await loadKeyValue('task_signature_note:$taskId');
|
||||||
|
} catch (e, st) {
|
||||||
|
developer.log(
|
||||||
|
'Error loading task signature note: $e',
|
||||||
|
name: 'DatabaseService',
|
||||||
|
);
|
||||||
|
developer.log('Stack trace: $st', name: 'DatabaseService');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Load signature SVG for a task from user_data table
|
/// Load signature SVG for a task from user_data table
|
||||||
Future<String?> loadTaskSignature(String taskId) async {
|
Future<String?> loadTaskSignature(String taskId) async {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -622,10 +622,11 @@ class _TaskViewState extends State<TaskView> {
|
|||||||
builder:
|
builder:
|
||||||
(context) => SignatureCaptureScreen(
|
(context) => SignatureCaptureScreen(
|
||||||
task: task,
|
task: task,
|
||||||
onSignatureCompleted: (String svg) async {
|
onSignatureCompleted: (String svg, String note) async {
|
||||||
try {
|
try {
|
||||||
// Persist SVG only (no PNG)
|
// Persist SVG only (no PNG)
|
||||||
await _databaseService.saveTaskSignature(task.id, svg);
|
await _databaseService.saveTaskSignature(task.id, svg);
|
||||||
|
await _databaseService.saveTaskSignatureNote(task.id, note);
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
developer.log(
|
developer.log(
|
||||||
'Error saving task signature: $e',
|
'Error saving task signature: $e',
|
||||||
@@ -649,6 +650,7 @@ class _TaskViewState extends State<TaskView> {
|
|||||||
'signatureSvg': svg,
|
'signatureSvg': svg,
|
||||||
'svgLength': svg.length,
|
'svgLength': svg.length,
|
||||||
'hasSignature': true,
|
'hasSignature': true,
|
||||||
|
'signatureNote': note,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -896,6 +898,10 @@ class _TaskViewState extends State<TaskView> {
|
|||||||
task.description != null
|
task.description != null
|
||||||
? localizeKnownText(context, task.description!)
|
? localizeKnownText(context, task.description!)
|
||||||
: null;
|
: null;
|
||||||
|
final String? signatureNote =
|
||||||
|
(task is SignatureTask && task.note != null && task.note!.trim().isNotEmpty)
|
||||||
|
? task.note!.trim()
|
||||||
|
: null;
|
||||||
|
|
||||||
if (displayName?.isNotEmpty == true) {
|
if (displayName?.isNotEmpty == true) {
|
||||||
return Column(
|
return Column(
|
||||||
@@ -906,14 +912,39 @@ class _TaskViewState extends State<TaskView> {
|
|||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(description!, style: subtitleStyle),
|
Text(description!, style: subtitleStyle),
|
||||||
],
|
],
|
||||||
|
if (signatureNote != null) ...[
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(signatureNote, style: subtitleStyle),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (description?.isNotEmpty == true) {
|
if (description?.isNotEmpty == true) {
|
||||||
|
if (signatureNote != null) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(description!, style: titleStyle),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(signatureNote, style: subtitleStyle),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
return Text(description!, style: titleStyle);
|
return Text(description!, style: titleStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (signatureNote != null) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(_getStandardTaskDisplayText(task), style: titleStyle),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(signatureNote, style: subtitleStyle),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Fall back to standard text based on task type
|
// Fall back to standard text based on task type
|
||||||
return Text(_getStandardTaskDisplayText(task), style: titleStyle);
|
return Text(_getStandardTaskDisplayText(task), style: titleStyle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import '../widgets/offline_banner.dart';
|
|||||||
|
|
||||||
class SignatureCaptureScreen extends StatefulWidget {
|
class SignatureCaptureScreen extends StatefulWidget {
|
||||||
final SignatureTask task;
|
final SignatureTask task;
|
||||||
final void Function(String svg) onSignatureCompleted;
|
final void Function(String svg, String note) onSignatureCompleted;
|
||||||
|
|
||||||
const SignatureCaptureScreen({
|
const SignatureCaptureScreen({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -23,6 +23,7 @@ class SignatureCaptureScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _SignatureCaptureScreenState extends State<SignatureCaptureScreen> {
|
class _SignatureCaptureScreenState extends State<SignatureCaptureScreen> {
|
||||||
late final SignatureController _controller;
|
late final SignatureController _controller;
|
||||||
|
final TextEditingController _noteController = TextEditingController();
|
||||||
bool _hasSignature = false;
|
bool _hasSignature = false;
|
||||||
bool _isMobilePlatform = false;
|
bool _isMobilePlatform = false;
|
||||||
|
|
||||||
@@ -84,6 +85,7 @@ class _SignatureCaptureScreenState extends State<SignatureCaptureScreen> {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
_controller.removeListener(_onSignatureChanged);
|
_controller.removeListener(_onSignatureChanged);
|
||||||
_controller.dispose();
|
_controller.dispose();
|
||||||
|
_noteController.dispose();
|
||||||
_restoreOrientation();
|
_restoreOrientation();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
@@ -155,14 +157,15 @@ class _SignatureCaptureScreenState extends State<SignatureCaptureScreen> {
|
|||||||
|
|
||||||
// Build SVG from the captured signature points
|
// Build SVG from the captured signature points
|
||||||
final String svg = _buildSvgFromPoints(_controller.points);
|
final String svg = _buildSvgFromPoints(_controller.points);
|
||||||
|
final String note = _noteController.text.trim();
|
||||||
|
|
||||||
// Close this screen first to show the updated TaskView quickly
|
// Close this screen first to show the updated TaskView quickly
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
_restoreOrientation();
|
_restoreOrientation();
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
// Then notify the caller (SVG only)
|
// Then notify the caller (SVG + Bemerkung)
|
||||||
widget.onSignatureCompleted(svg);
|
widget.onSignatureCompleted(svg, note);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -233,6 +236,16 @@ class _SignatureCaptureScreenState extends State<SignatureCaptureScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
TextField(
|
||||||
|
controller: _noteController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).completeTaskNote,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
|
minLines: 1,
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import de.assecutor.votianlt.model.AppUser;
|
|||||||
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.task.BaseTask;
|
import de.assecutor.votianlt.model.task.BaseTask;
|
||||||
|
import de.assecutor.votianlt.model.task.SignatureTask;
|
||||||
import de.assecutor.votianlt.pages.service.AppUserService;
|
import de.assecutor.votianlt.pages.service.AppUserService;
|
||||||
import de.assecutor.votianlt.repository.AppUserRepository;
|
import de.assecutor.votianlt.repository.AppUserRepository;
|
||||||
import de.assecutor.votianlt.repository.CargoItemRepository;
|
import de.assecutor.votianlt.repository.CargoItemRepository;
|
||||||
@@ -133,6 +134,14 @@ public class MessageController {
|
|||||||
List<JobWithRelatedDataDTO> jobsWithRelatedData = assignedJobs.stream().map(job -> {
|
List<JobWithRelatedDataDTO> jobsWithRelatedData = assignedJobs.stream().map(job -> {
|
||||||
List<CargoItem> cargoItems = cargoItemRepository.findByJobId(job.getId());
|
List<CargoItem> cargoItems = cargoItemRepository.findByJobId(job.getId());
|
||||||
List<BaseTask> tasks = taskAssignmentService.findTasksForJob(job);
|
List<BaseTask> tasks = taskAssignmentService.findTasksForJob(job);
|
||||||
|
for (BaseTask task : tasks) {
|
||||||
|
if (task instanceof SignatureTask signatureTask && task.getId() != null) {
|
||||||
|
List<Signature> signatures = signatureRepository.findByTaskIdOrderByCreatedAtDesc(task.getId());
|
||||||
|
if (!signatures.isEmpty()) {
|
||||||
|
signatureTask.setNote(signatures.get(0).getNote());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return new JobWithRelatedDataDTO(job, cargoItems, tasks);
|
return new JobWithRelatedDataDTO(job, cargoItems, tasks);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
@@ -246,13 +255,18 @@ public class MessageController {
|
|||||||
Object extra = payload.get("extraData");
|
Object extra = payload.get("extraData");
|
||||||
if (extra instanceof Map<?, ?> extraData) {
|
if (extra instanceof Map<?, ?> extraData) {
|
||||||
Object signatureSvgObj = extraData.get("signatureSvg");
|
Object signatureSvgObj = extraData.get("signatureSvg");
|
||||||
|
Object signatureNoteObj = extraData.get("signatureNote");
|
||||||
|
String signatureNote = signatureNoteObj instanceof String s ? s : null;
|
||||||
if (signatureSvgObj instanceof String signatureSvg) {
|
if (signatureSvgObj instanceof String signatureSvg) {
|
||||||
if (!signatureSvg.isBlank()) {
|
if (!signatureSvg.isBlank()) {
|
||||||
String completedBy = task.getCompletedBy() != null ? task.getCompletedBy() : "Unknown";
|
String completedBy = task.getCompletedBy() != null ? task.getCompletedBy() : "Unknown";
|
||||||
Signature signatureEntry = new Signature(new ObjectId(taskId.toString()), signatureSvg,
|
Signature signatureEntry = new Signature(new ObjectId(taskId.toString()), signatureSvg,
|
||||||
completedBy);
|
signatureNote, completedBy);
|
||||||
signatureRepository.save(signatureEntry);
|
signatureRepository.save(signatureEntry);
|
||||||
extraDataSummary = "Unterschrift erfasst (SVG, " + signatureSvg.length() + " Zeichen)";
|
extraDataSummary = "Unterschrift erfasst (SVG, " + signatureSvg.length() + " Zeichen)";
|
||||||
|
if (signatureNote != null && !signatureNote.isBlank()) {
|
||||||
|
extraDataSummary += ", Bemerkung: " + signatureNote;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
extraDataSummary = "Leere Unterschrift";
|
extraDataSummary = "Leere Unterschrift";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package de.assecutor.votianlt.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Document(collection = "misc")
|
||||||
|
public class Counter {
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
private long sequence;
|
||||||
|
}
|
||||||
@@ -53,4 +53,10 @@ public class Customer {
|
|||||||
|
|
||||||
@Field("owner")
|
@Field("owner")
|
||||||
private ObjectId owner;
|
private ObjectId owner;
|
||||||
|
|
||||||
|
@Field("internal")
|
||||||
|
private boolean internal;
|
||||||
|
|
||||||
|
@Field("usrId")
|
||||||
|
private Integer usrId;
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@ public class Signature {
|
|||||||
|
|
||||||
private ObjectId taskId;
|
private ObjectId taskId;
|
||||||
private String signatureSvg;
|
private String signatureSvg;
|
||||||
|
private String note;
|
||||||
private LocalDateTime createdAt;
|
private LocalDateTime createdAt;
|
||||||
private String completedBy;
|
private String completedBy;
|
||||||
|
|
||||||
@@ -35,4 +36,9 @@ public class Signature {
|
|||||||
this.signatureSvg = signatureSvg;
|
this.signatureSvg = signatureSvg;
|
||||||
this.completedBy = completedBy;
|
this.completedBy = completedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Signature(ObjectId taskId, String signatureSvg, String note, String completedBy) {
|
||||||
|
this(taskId, signatureSvg, completedBy);
|
||||||
|
this.note = note;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,20 @@
|
|||||||
package de.assecutor.votianlt.model.task;
|
package de.assecutor.votianlt.model.task;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.data.annotation.Transient;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class SignatureTask extends BaseTask {
|
public class SignatureTask extends BaseTask {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
@JsonIgnore
|
||||||
|
private String note;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTaskType() {
|
public String getTaskType() {
|
||||||
return "SIGNATURE";
|
return "SIGNATURE";
|
||||||
@@ -21,11 +27,17 @@ public class SignatureTask extends BaseTask {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getTaskSpecificData() {
|
public Object getTaskSpecificData() {
|
||||||
return new TaskSpecificData();
|
return new TaskSpecificData(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
public class TaskSpecificData {
|
public class TaskSpecificData {
|
||||||
public String taskType = getTaskType();
|
public String taskType = getTaskType();
|
||||||
// No specific data for signature task
|
public String note;
|
||||||
|
|
||||||
|
public TaskSpecificData(String note) {
|
||||||
|
this.note = note;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,10 +56,28 @@ public class DeliveryStationDialog extends Dialog {
|
|||||||
private String zip;
|
private String zip;
|
||||||
private String city;
|
private String city;
|
||||||
private boolean saveAddress;
|
private boolean saveAddress;
|
||||||
|
private boolean addressDiffersFromCustomer;
|
||||||
|
private org.bson.types.ObjectId customerId;
|
||||||
|
|
||||||
|
public boolean isAddressDiffersFromCustomer() {
|
||||||
|
return addressDiffersFromCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressDiffersFromCustomer(boolean addressDiffersFromCustomer) {
|
||||||
|
this.addressDiffersFromCustomer = addressDiffersFromCustomer;
|
||||||
|
}
|
||||||
private List<BaseTask> tasks = new ArrayList<>();
|
private List<BaseTask> tasks = new ArrayList<>();
|
||||||
private boolean addressValidatedByGoogle;
|
private boolean addressValidatedByGoogle;
|
||||||
private AddressValidationResult addressValidationResult;
|
private AddressValidationResult addressValidationResult;
|
||||||
|
|
||||||
|
public org.bson.types.ObjectId getCustomerId() {
|
||||||
|
return customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomerId(org.bson.types.ObjectId customerId) {
|
||||||
|
this.customerId = customerId;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAddressValidatedByGoogle() {
|
public boolean isAddressValidatedByGoogle() {
|
||||||
return addressValidatedByGoogle;
|
return addressValidatedByGoogle;
|
||||||
}
|
}
|
||||||
@@ -214,6 +232,7 @@ public class DeliveryStationDialog extends Dialog {
|
|||||||
|
|
||||||
private final DeliveryStationTile.TranslationHelper translationHelper;
|
private final DeliveryStationTile.TranslationHelper translationHelper;
|
||||||
private final java.util.Map<String, Customer> companyAddressOptions = new java.util.LinkedHashMap<>();
|
private final java.util.Map<String, Customer> companyAddressOptions = new java.util.LinkedHashMap<>();
|
||||||
|
private org.bson.types.ObjectId selectedCustomerId;
|
||||||
|
|
||||||
public DeliveryStationDialog(String dialogTitle, List<Customer> customers,
|
public DeliveryStationDialog(String dialogTitle, List<Customer> customers,
|
||||||
DeliveryStationTile.TranslationHelper translationHelper, SaveListener saveListener,
|
DeliveryStationTile.TranslationHelper translationHelper, SaveListener saveListener,
|
||||||
@@ -512,6 +531,13 @@ public class DeliveryStationDialog extends Dialog {
|
|||||||
zip.setValue(data.getZip());
|
zip.setValue(data.getZip());
|
||||||
if (data.getCity() != null)
|
if (data.getCity() != null)
|
||||||
city.setValue(data.getCity());
|
city.setValue(data.getCity());
|
||||||
|
selectedCustomerId = data.getCustomerId();
|
||||||
|
if (selectedCustomerId == null && customerSelectedFromOptions) {
|
||||||
|
Customer matched = companyAddressOptions.get(companyOption);
|
||||||
|
if (matched != null) {
|
||||||
|
selectedCustomerId = matched.getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
saveAddress.setValue(customerSelectedFromOptions ? false : data.isSaveAddress());
|
saveAddress.setValue(customerSelectedFromOptions ? false : data.isSaveAddress());
|
||||||
updateSaveAddressState();
|
updateSaveAddressState();
|
||||||
|
|
||||||
@@ -548,10 +574,43 @@ public class DeliveryStationDialog extends Dialog {
|
|||||||
data.setZip(zip.getValue());
|
data.setZip(zip.getValue());
|
||||||
data.setCity(city.getValue());
|
data.setCity(city.getValue());
|
||||||
data.setSaveAddress(saveAddress.getValue());
|
data.setSaveAddress(saveAddress.getValue());
|
||||||
|
data.setCustomerId(selectedCustomerId);
|
||||||
|
data.setAddressDiffersFromCustomer(computeAddressDiffers());
|
||||||
data.setTasks(new ArrayList<>(tasksState));
|
data.setTasks(new ArrayList<>(tasksState));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean computeAddressDiffers() {
|
||||||
|
boolean hasAnyValue = !isBlank(resolveCompanyValue(company.getValue())) || !isBlank(firstName.getValue())
|
||||||
|
|| !isBlank(lastName.getValue()) || !isBlank(phone.getValue()) || !isBlank(mail.getValue())
|
||||||
|
|| !isBlank(street.getValue()) || !isBlank(houseNumber.getValue())
|
||||||
|
|| !isBlank(addressAddition.getValue()) || !isBlank(zip.getValue()) || !isBlank(city.getValue());
|
||||||
|
if (!hasAnyValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (selectedCustomerId == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Customer linked = findCustomerById(selectedCustomerId);
|
||||||
|
return linked == null || !matchesCurrentCustomer(linked);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Customer findCustomerById(org.bson.types.ObjectId id) {
|
||||||
|
if (id == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (Customer c : companyAddressOptions.values()) {
|
||||||
|
if (c != null && id.equals(c.getId())) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlank(String value) {
|
||||||
|
return value == null || value.trim().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean validateRequiredFields() {
|
private boolean validateRequiredFields() {
|
||||||
// Address tab validation
|
// Address tab validation
|
||||||
boolean addressValid = true;
|
boolean addressValid = true;
|
||||||
@@ -601,11 +660,9 @@ public class DeliveryStationDialog extends Dialog {
|
|||||||
String value = mail.getValue();
|
String value = mail.getValue();
|
||||||
String normalizedValue = value == null ? "" : value.trim();
|
String normalizedValue = value == null ? "" : value.trim();
|
||||||
boolean empty = normalizedValue.isEmpty();
|
boolean empty = normalizedValue.isEmpty();
|
||||||
boolean required = Boolean.TRUE.equals(saveAddress.getValue());
|
|
||||||
boolean invalid = !empty && !normalizedValue.contains("@");
|
boolean invalid = !empty && !normalizedValue.contains("@");
|
||||||
boolean hasError = invalid || (required && empty);
|
applyErrorStyling(mail, invalid);
|
||||||
applyErrorStyling(mail, hasError);
|
return !invalid;
|
||||||
return !hasError;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyErrorStyling(com.vaadin.flow.component.Component field, boolean error) {
|
private void applyErrorStyling(com.vaadin.flow.component.Component field, boolean error) {
|
||||||
@@ -648,10 +705,12 @@ public class DeliveryStationDialog extends Dialog {
|
|||||||
companyField.addValueChangeListener(event -> {
|
companyField.addValueChangeListener(event -> {
|
||||||
Customer customer = companyAddressOptions.get(event.getValue());
|
Customer customer = companyAddressOptions.get(event.getValue());
|
||||||
if (customer == null) {
|
if (customer == null) {
|
||||||
|
selectedCustomerId = null;
|
||||||
updateSaveAddressState();
|
updateSaveAddressState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectedCustomerId = customer.getId();
|
||||||
if (customer.getTitle() != null
|
if (customer.getTitle() != null
|
||||||
&& ("Herr".equalsIgnoreCase(customer.getTitle()) || "Frau".equalsIgnoreCase(customer.getTitle())
|
&& ("Herr".equalsIgnoreCase(customer.getTitle()) || "Frau".equalsIgnoreCase(customer.getTitle())
|
||||||
|| "Divers".equalsIgnoreCase(customer.getTitle()))) {
|
|| "Divers".equalsIgnoreCase(customer.getTitle()))) {
|
||||||
@@ -680,27 +739,34 @@ public class DeliveryStationDialog extends Dialog {
|
|||||||
|
|
||||||
companyField.addCustomValueSetListener(event -> {
|
companyField.addCustomValueSetListener(event -> {
|
||||||
companyField.setValue(event.getDetail());
|
companyField.setValue(event.getDetail());
|
||||||
|
selectedCustomerId = null;
|
||||||
updateSaveAddressState();
|
updateSaveAddressState();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSaveAddressState() {
|
private void updateSaveAddressState() {
|
||||||
Customer selectedCustomer = companyAddressOptions.get(company.getValue());
|
Customer selectedCustomer = companyAddressOptions.get(company.getValue());
|
||||||
boolean customerSelectedFromOptions = selectedCustomer != null && matchesCurrentCustomer(selectedCustomer);
|
boolean customerDataMatches = selectedCustomer != null && matchesCurrentCustomer(selectedCustomer);
|
||||||
|
|
||||||
if (customerSelectedFromOptions) {
|
if (customerDataMatches) {
|
||||||
saveAddress.setValue(false);
|
saveAddress.setValue(false);
|
||||||
saveAddress.setEnabled(false);
|
saveAddress.setEnabled(false);
|
||||||
|
saveAddress.setLabel(translationHelper.getTranslation("addjob.address.save"));
|
||||||
updateMailRequirement();
|
updateMailRequirement();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveAddress.setEnabled(true);
|
saveAddress.setEnabled(true);
|
||||||
|
if (selectedCustomerId != null) {
|
||||||
|
saveAddress.setLabel(translationHelper.getTranslation("addjob.address.update"));
|
||||||
|
} else {
|
||||||
|
saveAddress.setLabel(translationHelper.getTranslation("addjob.address.save"));
|
||||||
|
}
|
||||||
updateMailRequirement();
|
updateMailRequirement();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMailRequirement() {
|
private void updateMailRequirement() {
|
||||||
mail.setRequiredIndicatorVisible(Boolean.TRUE.equals(saveAddress.getValue()));
|
mail.setRequiredIndicatorVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildCompanyAddressLabel(Customer customer) {
|
private String buildCompanyAddressLabel(Customer customer) {
|
||||||
@@ -1343,10 +1409,14 @@ public class DeliveryStationDialog extends Dialog {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SIGNATURE:
|
case SIGNATURE:
|
||||||
Span info = new Span(translationHelper.getTranslation("addjob.tasks.signature.noconfig"));
|
TextField signatureNoteField = new TextField(
|
||||||
info.getStyle().set("color", "var(--lumo-secondary-text-color)");
|
translationHelper.getTranslation("addjob.tasks.signature.notelabel"));
|
||||||
info.getStyle().set("font-style", "italic");
|
signatureNoteField.setPlaceholder(
|
||||||
configContainer.add(info);
|
translationHelper.getTranslation("addjob.tasks.signature.notelabel.placeholder"));
|
||||||
|
signatureNoteField.setWidthFull();
|
||||||
|
signatureNoteField.setValue(task.getDescription() != null ? task.getDescription() : "");
|
||||||
|
signatureNoteField.addValueChangeListener(ev -> task.setDescription(ev.getValue()));
|
||||||
|
configContainer.add(signatureNoteField);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TODOLIST:
|
case TODOLIST:
|
||||||
|
|||||||
@@ -228,6 +228,25 @@ public class PickupStationDialog extends Dialog {
|
|||||||
public void setCargoItems(List<CargoItem> cargoItems) {
|
public void setCargoItems(List<CargoItem> cargoItems) {
|
||||||
this.cargoItems = cargoItems != null ? cargoItems : new ArrayList<>();
|
this.cargoItems = cargoItems != null ? cargoItems : new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private org.bson.types.ObjectId customerId;
|
||||||
|
private boolean addressDiffersFromCustomer;
|
||||||
|
|
||||||
|
public org.bson.types.ObjectId getCustomerId() {
|
||||||
|
return customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomerId(org.bson.types.ObjectId customerId) {
|
||||||
|
this.customerId = customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAddressDiffersFromCustomer() {
|
||||||
|
return addressDiffersFromCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressDiffersFromCustomer(boolean addressDiffersFromCustomer) {
|
||||||
|
this.addressDiffersFromCustomer = addressDiffersFromCustomer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface SaveListener {
|
public interface SaveListener {
|
||||||
@@ -250,6 +269,7 @@ public class PickupStationDialog extends Dialog {
|
|||||||
private final ComboBox<String> customerComboBox;
|
private final ComboBox<String> customerComboBox;
|
||||||
private final Map<String, Customer> customerLabelMap = new LinkedHashMap<>();
|
private final Map<String, Customer> customerLabelMap = new LinkedHashMap<>();
|
||||||
private final Map<String, Customer> companyCustomerMap = new LinkedHashMap<>();
|
private final Map<String, Customer> companyCustomerMap = new LinkedHashMap<>();
|
||||||
|
private org.bson.types.ObjectId selectedCustomerId;
|
||||||
private DatePicker appointmentDatePicker;
|
private DatePicker appointmentDatePicker;
|
||||||
private TimePicker appointmentTimePicker;
|
private TimePicker appointmentTimePicker;
|
||||||
private Checkbox digitalProcessingCheckbox;
|
private Checkbox digitalProcessingCheckbox;
|
||||||
@@ -431,14 +451,17 @@ public class PickupStationDialog extends Dialog {
|
|||||||
customerComboBox.addValueChangeListener(ev -> {
|
customerComboBox.addValueChangeListener(ev -> {
|
||||||
String selected = ev.getValue();
|
String selected = ev.getValue();
|
||||||
if (selected == null) {
|
if (selected == null) {
|
||||||
|
selectedCustomerId = null;
|
||||||
updateSaveAddressState();
|
updateSaveAddressState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Customer c = customerLabelMap.get(selected);
|
Customer c = customerLabelMap.get(selected);
|
||||||
if (c == null) {
|
if (c == null) {
|
||||||
|
selectedCustomerId = null;
|
||||||
updateSaveAddressState();
|
updateSaveAddressState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
selectedCustomerId = c.getId();
|
||||||
if (c.getCompanyName() != null)
|
if (c.getCompanyName() != null)
|
||||||
company.setValue(c.getCompanyName());
|
company.setValue(c.getCompanyName());
|
||||||
else
|
else
|
||||||
@@ -663,6 +686,15 @@ public class PickupStationDialog extends Dialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.getCustomerId() != null) {
|
||||||
|
selectedCustomerId = data.getCustomerId();
|
||||||
|
} else {
|
||||||
|
Customer matched = customerLabelMap.get(data.getCustomerSelection());
|
||||||
|
if (matched == null) {
|
||||||
|
matched = companyCustomerMap.get(normalizeValue(data.getCompany()));
|
||||||
|
}
|
||||||
|
selectedCustomerId = matched != null ? matched.getId() : null;
|
||||||
|
}
|
||||||
saveAddress.setValue(data.isSaveAddress());
|
saveAddress.setValue(data.isSaveAddress());
|
||||||
updateSaveAddressState();
|
updateSaveAddressState();
|
||||||
}
|
}
|
||||||
@@ -681,6 +713,8 @@ public class PickupStationDialog extends Dialog {
|
|||||||
data.setZip(zip.getValue());
|
data.setZip(zip.getValue());
|
||||||
data.setCity(city.getValue());
|
data.setCity(city.getValue());
|
||||||
data.setSaveAddress(saveAddress.getValue());
|
data.setSaveAddress(saveAddress.getValue());
|
||||||
|
data.setCustomerId(selectedCustomerId);
|
||||||
|
data.setAddressDiffersFromCustomer(computeAddressDiffers());
|
||||||
data.setCustomerSelection(customerComboBox.getValue());
|
data.setCustomerSelection(customerComboBox.getValue());
|
||||||
if (appointmentDatePicker != null) {
|
if (appointmentDatePicker != null) {
|
||||||
data.setAppointmentDate(appointmentDatePicker.getValue());
|
data.setAppointmentDate(appointmentDatePicker.getValue());
|
||||||
@@ -820,6 +854,7 @@ public class PickupStationDialog extends Dialog {
|
|||||||
companyField.addValueChangeListener(event -> {
|
companyField.addValueChangeListener(event -> {
|
||||||
String selectedCompany = event.getValue();
|
String selectedCompany = event.getValue();
|
||||||
if (selectedCompany == null || selectedCompany.trim().isEmpty()) {
|
if (selectedCompany == null || selectedCompany.trim().isEmpty()) {
|
||||||
|
selectedCustomerId = null;
|
||||||
updateSaveAddressState();
|
updateSaveAddressState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -829,6 +864,7 @@ public class PickupStationDialog extends Dialog {
|
|||||||
|
|
||||||
if (matchingCustomer.isPresent()) {
|
if (matchingCustomer.isPresent()) {
|
||||||
Customer customer = matchingCustomer.get();
|
Customer customer = matchingCustomer.get();
|
||||||
|
selectedCustomerId = customer.getId();
|
||||||
if (customer.getTitle() != null
|
if (customer.getTitle() != null
|
||||||
&& ("Herr".equalsIgnoreCase(customer.getTitle()) || "Frau".equalsIgnoreCase(customer.getTitle())
|
&& ("Herr".equalsIgnoreCase(customer.getTitle()) || "Frau".equalsIgnoreCase(customer.getTitle())
|
||||||
|| "Divers".equalsIgnoreCase(customer.getTitle()))) {
|
|| "Divers".equalsIgnoreCase(customer.getTitle()))) {
|
||||||
@@ -859,6 +895,7 @@ public class PickupStationDialog extends Dialog {
|
|||||||
|
|
||||||
companyField.addCustomValueSetListener(event -> {
|
companyField.addCustomValueSetListener(event -> {
|
||||||
companyField.setValue(event.getDetail());
|
companyField.setValue(event.getDetail());
|
||||||
|
selectedCustomerId = null;
|
||||||
updateSaveAddressState();
|
updateSaveAddressState();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -866,17 +903,23 @@ public class PickupStationDialog extends Dialog {
|
|||||||
private void updateSaveAddressState() {
|
private void updateSaveAddressState() {
|
||||||
Customer selectedCustomer = customerLabelMap.get(customerComboBox.getValue());
|
Customer selectedCustomer = customerLabelMap.get(customerComboBox.getValue());
|
||||||
Customer selectedCompanyCustomer = companyCustomerMap.get(normalizeValue(company.getValue()));
|
Customer selectedCompanyCustomer = companyCustomerMap.get(normalizeValue(company.getValue()));
|
||||||
boolean existingCustomerSelected = selectedCustomer != null && matchesCustomer(selectedCustomer);
|
boolean customerDataMatches = selectedCustomer != null && matchesCustomer(selectedCustomer);
|
||||||
boolean existingCompanySelected = selectedCompanyCustomer != null && matchesCustomer(selectedCompanyCustomer);
|
boolean companyDataMatches = selectedCompanyCustomer != null && matchesCustomer(selectedCompanyCustomer);
|
||||||
|
|
||||||
if (existingCustomerSelected || existingCompanySelected) {
|
if (customerDataMatches || companyDataMatches) {
|
||||||
saveAddress.setValue(false);
|
saveAddress.setValue(false);
|
||||||
saveAddress.setEnabled(false);
|
saveAddress.setEnabled(false);
|
||||||
|
saveAddress.setLabel(translationHelper.getTranslation("addjob.address.save"));
|
||||||
updateMailRequirement();
|
updateMailRequirement();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveAddress.setEnabled(true);
|
saveAddress.setEnabled(true);
|
||||||
|
if (selectedCustomerId != null) {
|
||||||
|
saveAddress.setLabel(translationHelper.getTranslation("addjob.address.update"));
|
||||||
|
} else {
|
||||||
|
saveAddress.setLabel(translationHelper.getTranslation("addjob.address.save"));
|
||||||
|
}
|
||||||
updateMailRequirement();
|
updateMailRequirement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -906,6 +949,40 @@ public class PickupStationDialog extends Dialog {
|
|||||||
return value == null ? "" : value.trim();
|
return value == null ? "" : value.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean computeAddressDiffers() {
|
||||||
|
boolean hasAnyValue = !normalizeValue(company.getValue()).isEmpty()
|
||||||
|
|| !normalizeValue(firstName.getValue()).isEmpty() || !normalizeValue(lastName.getValue()).isEmpty()
|
||||||
|
|| !normalizeValue(phone.getValue()).isEmpty() || !normalizeValue(mail.getValue()).isEmpty()
|
||||||
|
|| !normalizeValue(street.getValue()).isEmpty() || !normalizeValue(houseNumber.getValue()).isEmpty()
|
||||||
|
|| !normalizeValue(addressAddition.getValue()).isEmpty() || !normalizeValue(zip.getValue()).isEmpty()
|
||||||
|
|| !normalizeValue(city.getValue()).isEmpty();
|
||||||
|
if (!hasAnyValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (selectedCustomerId == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Customer linked = findCustomerById(selectedCustomerId);
|
||||||
|
return linked == null || !matchesCustomer(linked);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Customer findCustomerById(org.bson.types.ObjectId id) {
|
||||||
|
if (id == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (Customer c : customerLabelMap.values()) {
|
||||||
|
if (c != null && id.equals(c.getId())) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Customer c : companyCustomerMap.values()) {
|
||||||
|
if (c != null && id.equals(c.getId())) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// Appointments & Processing Tab
|
// Appointments & Processing Tab
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|||||||
@@ -13,4 +13,6 @@ public interface CustomerRepository extends MongoRepository<Customer, ObjectId>
|
|||||||
Slice<Customer> findAllBy(Pageable pageable);
|
Slice<Customer> findAllBy(Pageable pageable);
|
||||||
|
|
||||||
List<Customer> findByOwner(ObjectId owner);
|
List<Customer> findByOwner(ObjectId owner);
|
||||||
|
|
||||||
|
List<Customer> findByOwnerAndInternalFalse(ObjectId owner);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,13 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
public class AddCustomerService {
|
public class AddCustomerService {
|
||||||
private final AddCustomerRepository addCustomerRepository;
|
private final AddCustomerRepository addCustomerRepository;
|
||||||
private final SecurityService securityService;
|
private final SecurityService securityService;
|
||||||
|
private final SequenceGeneratorService sequenceGeneratorService;
|
||||||
|
|
||||||
AddCustomerService(AddCustomerRepository addCustomerRepository, SecurityService securityService) {
|
AddCustomerService(AddCustomerRepository addCustomerRepository, SecurityService securityService,
|
||||||
|
SequenceGeneratorService sequenceGeneratorService) {
|
||||||
this.addCustomerRepository = addCustomerRepository;
|
this.addCustomerRepository = addCustomerRepository;
|
||||||
this.securityService = securityService;
|
this.securityService = securityService;
|
||||||
|
this.sequenceGeneratorService = sequenceGeneratorService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCustomer(Customer customer) {
|
public void addCustomer(Customer customer) {
|
||||||
@@ -25,6 +28,35 @@ public class AddCustomerService {
|
|||||||
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());
|
customer.setOwner(currentUser.getId());
|
||||||
|
if (customer.getUsrId() == null) {
|
||||||
|
customer.setUsrId(sequenceGeneratorService.nextCustomerNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
addCustomerRepository.save(customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addInternalCustomer(Customer customer) {
|
||||||
|
if (customer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
customer.setId(null);
|
||||||
|
customer.setInternal(true);
|
||||||
|
addCustomer(customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateCustomer(Customer customer) {
|
||||||
|
if (customer == null || customer.getId() == null) {
|
||||||
|
throw new IllegalArgumentException("Kunden-ID fehlt");
|
||||||
|
}
|
||||||
|
validateCustomer(customer);
|
||||||
|
|
||||||
|
Customer existing = addCustomerRepository.findById(customer.getId())
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("Kunde nicht gefunden"));
|
||||||
|
customer.setCreatedBy(existing.getCreatedBy());
|
||||||
|
customer.setOwner(existing.getOwner());
|
||||||
|
if (customer.getUsrId() == null) {
|
||||||
|
customer.setUsrId(existing.getUsrId());
|
||||||
|
}
|
||||||
|
|
||||||
addCustomerRepository.save(customer);
|
addCustomerRepository.save(customer);
|
||||||
}
|
}
|
||||||
@@ -35,13 +67,10 @@ public class AddCustomerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String mail = customer.getMail() != null ? customer.getMail().trim() : "";
|
String mail = customer.getMail() != null ? customer.getMail().trim() : "";
|
||||||
if (mail.isEmpty()) {
|
if (!mail.isEmpty() && !mail.contains("@")) {
|
||||||
throw new IllegalArgumentException("E-Mail-Adresse ist ein Pflichtfeld");
|
|
||||||
}
|
|
||||||
if (!mail.contains("@")) {
|
|
||||||
throw new IllegalArgumentException("Bitte geben Sie eine gültige E-Mail-Adresse ein");
|
throw new IllegalArgumentException("Bitte geben Sie eine gültige E-Mail-Adresse ein");
|
||||||
}
|
}
|
||||||
|
|
||||||
customer.setMail(mail);
|
customer.setMail(mail.isEmpty() ? null : mail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class CustomerService {
|
|||||||
|
|
||||||
public List<Customer> findAllForCurrentOwner() {
|
public List<Customer> findAllForCurrentOwner() {
|
||||||
ObjectId ownerId = securityService.getCurrentUserId();
|
ObjectId ownerId = securityService.getCurrentUserId();
|
||||||
return todoRepository.findByOwner(ownerId);
|
return todoRepository.findByOwnerAndInternalFalse(ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Customer save(Customer customer) {
|
public Customer save(Customer customer) {
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package de.assecutor.votianlt.pages.service;
|
||||||
|
|
||||||
|
import de.assecutor.votianlt.model.Counter;
|
||||||
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
|
import org.springframework.data.mongodb.core.FindAndModifyOptions;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
|
import org.springframework.data.mongodb.core.query.Update;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SequenceGeneratorService {
|
||||||
|
|
||||||
|
public static final String CUSTOMER_NUMBER_SEQ = "customerNumber";
|
||||||
|
public static final int CUSTOMER_NUMBER_START = 10000;
|
||||||
|
|
||||||
|
private final MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
|
public SequenceGeneratorService(MongoTemplate mongoTemplate) {
|
||||||
|
this.mongoTemplate = mongoTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int nextCustomerNumber() {
|
||||||
|
return (int) nextSequence(CUSTOMER_NUMBER_SEQ, CUSTOMER_NUMBER_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long nextSequence(String sequenceId, long startValue) {
|
||||||
|
ensureInitialized(sequenceId, startValue - 1);
|
||||||
|
Counter updated = mongoTemplate.findAndModify(
|
||||||
|
Query.query(Criteria.where("_id").is(sequenceId)),
|
||||||
|
new Update().inc("sequence", 1),
|
||||||
|
FindAndModifyOptions.options().returnNew(true),
|
||||||
|
Counter.class);
|
||||||
|
return updated != null ? updated.getSequence() : startValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureInitialized(String sequenceId, long initialValue) {
|
||||||
|
boolean exists = mongoTemplate.exists(
|
||||||
|
Query.query(Criteria.where("_id").is(sequenceId)),
|
||||||
|
Counter.class);
|
||||||
|
if (exists) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Counter counter = new Counter();
|
||||||
|
counter.setId(sequenceId);
|
||||||
|
counter.setSequence(initialValue);
|
||||||
|
try {
|
||||||
|
mongoTemplate.insert(counter);
|
||||||
|
} catch (DuplicateKeyException ignored) {
|
||||||
|
// Ein anderer Thread hat den Counter gleichzeitig angelegt — passt.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -81,9 +81,8 @@ public class AddCustomerView extends Main implements HasDynamicTitle {
|
|||||||
fax = new TextField(getTranslation("profile.fax"));
|
fax = new TextField(getTranslation("profile.fax"));
|
||||||
fax.setWidthFull();
|
fax.setWidthFull();
|
||||||
|
|
||||||
// E-Mail (Pflichtfeld)
|
// E-Mail (optional)
|
||||||
mail = new TextField(getTranslation("profile.email"));
|
mail = new TextField(getTranslation("profile.email"));
|
||||||
mail.setRequiredIndicatorVisible(true);
|
|
||||||
mail.setWidthFull();
|
mail.setWidthFull();
|
||||||
mail.addBlurListener(e -> validateEmail());
|
mail.addBlurListener(e -> validateEmail());
|
||||||
|
|
||||||
@@ -179,8 +178,9 @@ public class AddCustomerView extends Main implements HasDynamicTitle {
|
|||||||
|
|
||||||
binder.forField(fax).bind(Customer::getFax, Customer::setFax);
|
binder.forField(fax).bind(Customer::getFax, Customer::setFax);
|
||||||
|
|
||||||
binder.forField(mail).asRequired(getTranslation("profile.validation.email.required"))
|
binder.forField(mail)
|
||||||
.withValidator(email -> email.contains("@"), getTranslation("profile.validation.email.invalid"))
|
.withValidator(email -> email == null || email.isBlank() || email.contains("@"),
|
||||||
|
getTranslation("profile.validation.email.invalid"))
|
||||||
.bind(Customer::getMail, Customer::setMail);
|
.bind(Customer::getMail, Customer::setMail);
|
||||||
|
|
||||||
binder.forField(street).asRequired(getTranslation("profile.validation.street.required"))
|
binder.forField(street).asRequired(getTranslation("profile.validation.street.required"))
|
||||||
@@ -247,10 +247,7 @@ public class AddCustomerView extends Main implements HasDynamicTitle {
|
|||||||
|
|
||||||
private void validateEmail() {
|
private void validateEmail() {
|
||||||
String value = mail.getValue();
|
String value = mail.getValue();
|
||||||
if (value == null || value.trim().isEmpty()) {
|
if (value != null && !value.trim().isEmpty() && !value.contains("@")) {
|
||||||
mail.setInvalid(true);
|
|
||||||
mail.setErrorMessage(getTranslation("profile.validation.email.required"));
|
|
||||||
} else if (!value.contains("@")) {
|
|
||||||
mail.setInvalid(true);
|
mail.setInvalid(true);
|
||||||
mail.setErrorMessage(getTranslation("profile.validation.email.invalid"));
|
mail.setErrorMessage(getTranslation("profile.validation.email.invalid"));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -137,12 +137,16 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
private TextField pickupZip;
|
private TextField pickupZip;
|
||||||
private TextField pickupCity;
|
private TextField pickupCity;
|
||||||
private Checkbox savePickupAddress;
|
private Checkbox savePickupAddress;
|
||||||
|
private org.bson.types.ObjectId pickupCustomerId;
|
||||||
|
private boolean pickupAddressDiffers;
|
||||||
|
|
||||||
// Delivery stations as tiles in a 3x3 grid (max 7 delivery + 1 pickup + 1 plus
|
// Delivery stations as tiles in a 3x3 grid (max 7 delivery + 1 pickup + 1 plus
|
||||||
// = 9)
|
// = 9)
|
||||||
private final List<StationTile> deliveryStationTilesList = new ArrayList<>();
|
private final List<StationTile> deliveryStationTilesList = new ArrayList<>();
|
||||||
private final List<DeliveryStation> deliveryStationsState = new ArrayList<>();
|
private final List<DeliveryStation> deliveryStationsState = new ArrayList<>();
|
||||||
private final List<Boolean> deliveryStationsSaveAddress = new ArrayList<>();
|
private final List<Boolean> deliveryStationsSaveAddress = new ArrayList<>();
|
||||||
|
private final List<org.bson.types.ObjectId> deliveryStationsCustomerId = new ArrayList<>();
|
||||||
|
private final List<Boolean> deliveryStationsAddressDiffers = new ArrayList<>();
|
||||||
private final List<String> deliveryStationsMailState = new ArrayList<>();
|
private final List<String> deliveryStationsMailState = new ArrayList<>();
|
||||||
private final List<Div> deliveryStationSlotList = new ArrayList<>();
|
private final List<Div> deliveryStationSlotList = new ArrayList<>();
|
||||||
private final List<Span> deliveryStationDistanceChips = new ArrayList<>();
|
private final List<Span> deliveryStationDistanceChips = new ArrayList<>();
|
||||||
@@ -721,6 +725,8 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
// Add empty state for this station
|
// Add empty state for this station
|
||||||
deliveryStationsState.add(new DeliveryStation());
|
deliveryStationsState.add(new DeliveryStation());
|
||||||
deliveryStationsSaveAddress.add(true);
|
deliveryStationsSaveAddress.add(true);
|
||||||
|
deliveryStationsCustomerId.add(null);
|
||||||
|
deliveryStationsAddressDiffers.add(false);
|
||||||
deliveryStationsMailState.add(null);
|
deliveryStationsMailState.add(null);
|
||||||
deliveryStationsValidatedByGoogle.add(false);
|
deliveryStationsValidatedByGoogle.add(false);
|
||||||
|
|
||||||
@@ -769,6 +775,8 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
deliveryStationTilesList.remove(removeIdx);
|
deliveryStationTilesList.remove(removeIdx);
|
||||||
deliveryStationsState.remove(removeIdx);
|
deliveryStationsState.remove(removeIdx);
|
||||||
deliveryStationsSaveAddress.remove(removeIdx);
|
deliveryStationsSaveAddress.remove(removeIdx);
|
||||||
|
deliveryStationsCustomerId.remove(removeIdx);
|
||||||
|
deliveryStationsAddressDiffers.remove(removeIdx);
|
||||||
deliveryStationsMailState.remove(removeIdx);
|
deliveryStationsMailState.remove(removeIdx);
|
||||||
deliveryStationsValidatedByGoogle.remove(removeIdx);
|
deliveryStationsValidatedByGoogle.remove(removeIdx);
|
||||||
deliveryStationTasksState.remove(removeIdx);
|
deliveryStationTasksState.remove(removeIdx);
|
||||||
@@ -867,6 +875,8 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
pickupZip.setValue(data.getZip() != null ? data.getZip() : "");
|
pickupZip.setValue(data.getZip() != null ? data.getZip() : "");
|
||||||
pickupCity.setValue(data.getCity() != null ? data.getCity() : "");
|
pickupCity.setValue(data.getCity() != null ? data.getCity() : "");
|
||||||
savePickupAddress.setValue(data.isSaveAddress());
|
savePickupAddress.setValue(data.isSaveAddress());
|
||||||
|
pickupCustomerId = data.getCustomerId();
|
||||||
|
pickupAddressDiffers = data.isAddressDiffersFromCustomer();
|
||||||
|
|
||||||
// Sync appointment fields for binder/submit
|
// Sync appointment fields for binder/submit
|
||||||
pickupDate.setValue(data.getAppointmentDate());
|
pickupDate.setValue(data.getAppointmentDate());
|
||||||
@@ -913,6 +923,7 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
currentData.setZip(pickupZip.getValue());
|
currentData.setZip(pickupZip.getValue());
|
||||||
currentData.setCity(pickupCity.getValue());
|
currentData.setCity(pickupCity.getValue());
|
||||||
currentData.setSaveAddress(savePickupAddress.getValue());
|
currentData.setSaveAddress(savePickupAddress.getValue());
|
||||||
|
currentData.setCustomerId(pickupCustomerId);
|
||||||
currentData.setCustomerSelection(customerSelection.getValue());
|
currentData.setCustomerSelection(customerSelection.getValue());
|
||||||
// Pre-fill pickup-specific fields
|
// Pre-fill pickup-specific fields
|
||||||
currentData.setAppointmentDate(pickupDate.getValue());
|
currentData.setAppointmentDate(pickupDate.getValue());
|
||||||
@@ -1137,6 +1148,14 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
station.setCity(data.getCity());
|
station.setCity(data.getCity());
|
||||||
station.setTasks(data.getTasks() != null ? new ArrayList<>(data.getTasks()) : new ArrayList<>());
|
station.setTasks(data.getTasks() != null ? new ArrayList<>(data.getTasks()) : new ArrayList<>());
|
||||||
deliveryStationsSaveAddress.set(idx, data.isSaveAddress());
|
deliveryStationsSaveAddress.set(idx, data.isSaveAddress());
|
||||||
|
while (deliveryStationsCustomerId.size() <= idx) {
|
||||||
|
deliveryStationsCustomerId.add(null);
|
||||||
|
}
|
||||||
|
deliveryStationsCustomerId.set(idx, data.getCustomerId());
|
||||||
|
while (deliveryStationsAddressDiffers.size() <= idx) {
|
||||||
|
deliveryStationsAddressDiffers.add(false);
|
||||||
|
}
|
||||||
|
deliveryStationsAddressDiffers.set(idx, data.isAddressDiffersFromCustomer());
|
||||||
deliveryStationsMailState.set(idx, trimToNull(data.getMail()));
|
deliveryStationsMailState.set(idx, trimToNull(data.getMail()));
|
||||||
|
|
||||||
// Store tasks for this delivery station
|
// Store tasks for this delivery station
|
||||||
@@ -1182,6 +1201,9 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
currentData.setZip(station.getZip());
|
currentData.setZip(station.getZip());
|
||||||
currentData.setCity(station.getCity());
|
currentData.setCity(station.getCity());
|
||||||
currentData.setSaveAddress(deliveryStationsSaveAddress.get(actualIndex));
|
currentData.setSaveAddress(deliveryStationsSaveAddress.get(actualIndex));
|
||||||
|
if (actualIndex < deliveryStationsCustomerId.size()) {
|
||||||
|
currentData.setCustomerId(deliveryStationsCustomerId.get(actualIndex));
|
||||||
|
}
|
||||||
if (actualIndex < deliveryStationsValidatedByGoogle.size()) {
|
if (actualIndex < deliveryStationsValidatedByGoogle.size()) {
|
||||||
currentData.setAddressValidatedByGoogle(deliveryStationsValidatedByGoogle.get(actualIndex));
|
currentData.setAddressValidatedByGoogle(deliveryStationsValidatedByGoogle.get(actualIndex));
|
||||||
}
|
}
|
||||||
@@ -1817,8 +1839,7 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEU: Kunden anlegen, wenn Checkboxen aktiviert
|
// Kunden anlegen/aktualisieren bzw. intern sichern
|
||||||
if (savePickupAddress.getValue()) {
|
|
||||||
Customer pickupCustomer = new Customer();
|
Customer pickupCustomer = new Customer();
|
||||||
pickupCustomer.setCompanyName(pickupCompany.getValue());
|
pickupCustomer.setCompanyName(pickupCompany.getValue());
|
||||||
pickupCustomer.setTitle(pickupSalutation.getValue());
|
pickupCustomer.setTitle(pickupSalutation.getValue());
|
||||||
@@ -1831,11 +1852,18 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
pickupCustomer.setAddressAddition(pickupAddressAddition.getValue());
|
pickupCustomer.setAddressAddition(pickupAddressAddition.getValue());
|
||||||
pickupCustomer.setZip(pickupZip.getValue());
|
pickupCustomer.setZip(pickupZip.getValue());
|
||||||
pickupCustomer.setCity(pickupCity.getValue());
|
pickupCustomer.setCity(pickupCity.getValue());
|
||||||
|
if (savePickupAddress.getValue()) {
|
||||||
|
if (pickupCustomerId != null) {
|
||||||
|
pickupCustomer.setId(pickupCustomerId);
|
||||||
|
addCustomerService.updateCustomer(pickupCustomer);
|
||||||
|
} else {
|
||||||
addCustomerService.addCustomer(pickupCustomer);
|
addCustomerService.addCustomer(pickupCustomer);
|
||||||
}
|
}
|
||||||
// Save delivery station addresses as customers if checkbox is checked
|
} else if (pickupAddressDiffers) {
|
||||||
|
addCustomerService.addInternalCustomer(pickupCustomer);
|
||||||
|
}
|
||||||
|
// Delivery-Stationen: anlegen, aktualisieren oder als intern sichern
|
||||||
for (int i = 0; i < deliveryStationsState.size(); i++) {
|
for (int i = 0; i < deliveryStationsState.size(); i++) {
|
||||||
if (i < deliveryStationsSaveAddress.size() && deliveryStationsSaveAddress.get(i)) {
|
|
||||||
DeliveryStation ds = deliveryStationsState.get(i);
|
DeliveryStation ds = deliveryStationsState.get(i);
|
||||||
Customer deliveryCustomer = new Customer();
|
Customer deliveryCustomer = new Customer();
|
||||||
deliveryCustomer.setCompanyName(ds.getCompany());
|
deliveryCustomer.setCompanyName(ds.getCompany());
|
||||||
@@ -1849,8 +1877,23 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
deliveryCustomer.setAddressAddition(ds.getAddressAddition());
|
deliveryCustomer.setAddressAddition(ds.getAddressAddition());
|
||||||
deliveryCustomer.setZip(ds.getZip());
|
deliveryCustomer.setZip(ds.getZip());
|
||||||
deliveryCustomer.setCity(ds.getCity());
|
deliveryCustomer.setCity(ds.getCity());
|
||||||
|
boolean saveRequested = i < deliveryStationsSaveAddress.size()
|
||||||
|
&& deliveryStationsSaveAddress.get(i);
|
||||||
|
org.bson.types.ObjectId existingId = i < deliveryStationsCustomerId.size()
|
||||||
|
? deliveryStationsCustomerId.get(i)
|
||||||
|
: null;
|
||||||
|
boolean addressDiffers = i < deliveryStationsAddressDiffers.size()
|
||||||
|
&& deliveryStationsAddressDiffers.get(i);
|
||||||
|
if (saveRequested) {
|
||||||
|
if (existingId != null) {
|
||||||
|
deliveryCustomer.setId(existingId);
|
||||||
|
addCustomerService.updateCustomer(deliveryCustomer);
|
||||||
|
} else {
|
||||||
addCustomerService.addCustomer(deliveryCustomer);
|
addCustomerService.addCustomer(deliveryCustomer);
|
||||||
}
|
}
|
||||||
|
} else if (addressDiffers) {
|
||||||
|
addCustomerService.addInternalCustomer(deliveryCustomer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect tasks from all delivery stations and set stationOrder
|
// Collect tasks from all delivery stations and set stationOrder
|
||||||
@@ -2119,6 +2162,8 @@ public class AddJobView extends Main implements HasDynamicTitle {
|
|||||||
deliveryStationTilesList.remove(idx);
|
deliveryStationTilesList.remove(idx);
|
||||||
deliveryStationsState.remove(idx);
|
deliveryStationsState.remove(idx);
|
||||||
deliveryStationsSaveAddress.remove(idx);
|
deliveryStationsSaveAddress.remove(idx);
|
||||||
|
deliveryStationsCustomerId.remove(idx);
|
||||||
|
deliveryStationsAddressDiffers.remove(idx);
|
||||||
deliveryStationsMailState.remove(idx);
|
deliveryStationsMailState.remove(idx);
|
||||||
deliveryStationsValidatedByGoogle.remove(idx);
|
deliveryStationsValidatedByGoogle.remove(idx);
|
||||||
deliveryStationTasksState.remove(idx);
|
deliveryStationTasksState.remove(idx);
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ public class CustomersView extends Main implements HasDynamicTitle {
|
|||||||
createBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
createBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||||
|
|
||||||
todoGrid = new Grid<>();
|
todoGrid = new Grid<>();
|
||||||
todoGrid.setItems(query -> todoService.list(toSpringPageRequest(query)).stream());
|
todoGrid.setItems(query -> todoService.list(toSpringPageRequest(query)).stream()
|
||||||
|
.filter(c -> !c.isInternal()));
|
||||||
todoGrid.addColumn(Customer::getCompanyName).setHeader(getTranslation("customers.column.company"));
|
todoGrid.addColumn(Customer::getCompanyName).setHeader(getTranslation("customers.column.company"));
|
||||||
todoGrid.setSizeFull();
|
todoGrid.setSizeFull();
|
||||||
todoGrid.addClassName("data-grid");
|
todoGrid.addClassName("data-grid");
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
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.Main;
|
||||||
|
import com.vaadin.flow.component.html.Span;
|
||||||
|
import com.vaadin.flow.component.notification.Notification;
|
||||||
|
import com.vaadin.flow.component.notification.NotificationVariant;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.component.textfield.TextArea;
|
||||||
|
import com.vaadin.flow.router.BeforeEvent;
|
||||||
|
import com.vaadin.flow.router.HasDynamicTitle;
|
||||||
|
import com.vaadin.flow.router.HasUrlParameter;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
import com.vaadin.flow.theme.lumo.LumoUtility;
|
||||||
|
import de.assecutor.votianlt.model.Job;
|
||||||
|
import de.assecutor.votianlt.model.JobHistoryType;
|
||||||
|
import de.assecutor.votianlt.model.JobStatus;
|
||||||
|
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
|
||||||
|
import de.assecutor.votianlt.repository.JobRepository;
|
||||||
|
import de.assecutor.votianlt.security.SecurityService;
|
||||||
|
import de.assecutor.votianlt.service.JobHistoryService;
|
||||||
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.bson.types.ObjectId;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Route(value = "job_manual_complete", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
|
||||||
|
@RolesAllowed("USER")
|
||||||
|
@Slf4j
|
||||||
|
public class JobManualCompleteView extends Main implements HasUrlParameter<String>, HasDynamicTitle {
|
||||||
|
|
||||||
|
private final JobRepository jobRepository;
|
||||||
|
private final JobHistoryService jobHistoryService;
|
||||||
|
private final SecurityService securityService;
|
||||||
|
private final VerticalLayout content;
|
||||||
|
|
||||||
|
public JobManualCompleteView(JobRepository jobRepository, JobHistoryService jobHistoryService,
|
||||||
|
SecurityService securityService) {
|
||||||
|
this.jobRepository = jobRepository;
|
||||||
|
this.jobHistoryService = jobHistoryService;
|
||||||
|
this.securityService = securityService;
|
||||||
|
|
||||||
|
setSizeFull();
|
||||||
|
addClassNames(LumoUtility.BoxSizing.BORDER, LumoUtility.Display.FLEX, LumoUtility.FlexDirection.COLUMN,
|
||||||
|
LumoUtility.Padding.MEDIUM, LumoUtility.Gap.SMALL);
|
||||||
|
addClassName("data-view");
|
||||||
|
|
||||||
|
add(new ViewToolbar(getTranslation("jobsummary.dialog.manualcomplete.title")));
|
||||||
|
|
||||||
|
content = new VerticalLayout();
|
||||||
|
content.setSpacing(true);
|
||||||
|
content.setPadding(true);
|
||||||
|
content.setWidthFull();
|
||||||
|
content.addClassNames("form-shell", "form-card");
|
||||||
|
add(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPageTitle() {
|
||||||
|
return getTranslation("jobsummary.dialog.manualcomplete.title");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setParameter(BeforeEvent event, String parameter) {
|
||||||
|
content.removeAll();
|
||||||
|
|
||||||
|
if (parameter == null || parameter.isBlank()) {
|
||||||
|
content.add(new Span(getTranslation("jobhistory.error.no.id")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectId jobId;
|
||||||
|
try {
|
||||||
|
jobId = new ObjectId(parameter);
|
||||||
|
} catch (Exception e) {
|
||||||
|
content.add(new Span(getTranslation("jobhistory.error.invalid.id", parameter)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Job job = jobRepository.findById(jobId).orElse(null);
|
||||||
|
if (job == null) {
|
||||||
|
content.add(new Span(getTranslation("jobhistory.error.not.found", parameter)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void render(Job job) {
|
||||||
|
Span warningText = new Span(getTranslation("jobsummary.dialog.manualcomplete.text", job.getJobNumber()));
|
||||||
|
warningText.getStyle().set("color", "var(--lumo-error-text-color)");
|
||||||
|
|
||||||
|
TextArea reasonField = new TextArea(getTranslation("jobsummary.dialog.manualcomplete.reason"));
|
||||||
|
reasonField.setWidthFull();
|
||||||
|
reasonField.setMinHeight("100px");
|
||||||
|
reasonField.setRequired(true);
|
||||||
|
|
||||||
|
content.add(warningText, reasonField);
|
||||||
|
|
||||||
|
HorizontalLayout buttonBar = new HorizontalLayout();
|
||||||
|
buttonBar.setWidthFull();
|
||||||
|
buttonBar.setJustifyContentMode(HorizontalLayout.JustifyContentMode.END);
|
||||||
|
buttonBar.setSpacing(true);
|
||||||
|
|
||||||
|
Button cancelButton = new Button(getTranslation("jobsummary.dialog.manualcomplete.cancel"),
|
||||||
|
e -> getUI().ifPresent(ui -> ui.navigate("job_summary/" + job.getId().toHexString())));
|
||||||
|
|
||||||
|
Button confirmButton = new Button(getTranslation("jobsummary.dialog.manualcomplete.confirm"));
|
||||||
|
confirmButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_ERROR);
|
||||||
|
confirmButton.addClickListener(e -> {
|
||||||
|
String reason = reasonField.getValue();
|
||||||
|
if (reason == null || reason.trim().isEmpty()) {
|
||||||
|
reasonField.setInvalid(true);
|
||||||
|
reasonField.setErrorMessage(getTranslation("jobsummary.dialog.manualcomplete.reason.required"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
JobStatus oldStatus = job.getStatus();
|
||||||
|
job.setStatus(JobStatus.COMPLETED);
|
||||||
|
job.setUpdatedAt(LocalDateTime.now());
|
||||||
|
jobRepository.save(job);
|
||||||
|
|
||||||
|
String currentUser = securityService.getCurrentUsername();
|
||||||
|
jobHistoryService.logStatusChange(job, oldStatus, JobStatus.COMPLETED, currentUser);
|
||||||
|
|
||||||
|
String description = String.format("Auftrag manuell beendet von %s. Begründung: %s",
|
||||||
|
currentUser, reason.trim());
|
||||||
|
jobHistoryService.logCustomEvent(job.getId(),
|
||||||
|
getTranslation("jobsummary.history.manualcomplete.reason"),
|
||||||
|
description, currentUser, JobHistoryType.STATUS_CHANGE);
|
||||||
|
|
||||||
|
Notification
|
||||||
|
.show(getTranslation("jobsummary.notification.completed", job.getJobNumber()), 3000,
|
||||||
|
Notification.Position.BOTTOM_END)
|
||||||
|
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
|
||||||
|
getUI().ifPresent(ui -> ui.navigate("job_summary/" + job.getId().toHexString()));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Notification
|
||||||
|
.show(getTranslation("jobsummary.notification.complete.error", ex.getMessage()), 5000,
|
||||||
|
Notification.Position.BOTTOM_END)
|
||||||
|
.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonBar.add(cancelButton, confirmButton);
|
||||||
|
content.add(buttonBar);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,6 @@ import com.vaadin.flow.component.notification.Notification;
|
|||||||
import com.vaadin.flow.component.notification.NotificationVariant;
|
import com.vaadin.flow.component.notification.NotificationVariant;
|
||||||
import com.vaadin.flow.component.icon.Icon;
|
import com.vaadin.flow.component.icon.Icon;
|
||||||
import com.vaadin.flow.component.icon.VaadinIcon;
|
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||||
import com.vaadin.flow.component.textfield.TextArea;
|
|
||||||
import com.vaadin.flow.component.AttachEvent;
|
import com.vaadin.flow.component.AttachEvent;
|
||||||
import com.vaadin.flow.component.DetachEvent;
|
import com.vaadin.flow.component.DetachEvent;
|
||||||
import com.vaadin.flow.component.UI;
|
import com.vaadin.flow.component.UI;
|
||||||
@@ -60,8 +59,6 @@ import de.assecutor.votianlt.service.JobUpdateBroadcaster;
|
|||||||
import de.assecutor.votianlt.service.LocationService;
|
import de.assecutor.votianlt.service.LocationService;
|
||||||
import de.assecutor.votianlt.service.MessageService;
|
import de.assecutor.votianlt.service.MessageService;
|
||||||
import de.assecutor.votianlt.service.TaskAssignmentService;
|
import de.assecutor.votianlt.service.TaskAssignmentService;
|
||||||
import de.assecutor.votianlt.model.JobHistoryType;
|
|
||||||
import de.assecutor.votianlt.security.SecurityService;
|
|
||||||
import de.assecutor.votianlt.util.DateTimeFormatUtil;
|
import de.assecutor.votianlt.util.DateTimeFormatUtil;
|
||||||
import jakarta.annotation.security.RolesAllowed;
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
@@ -91,7 +88,6 @@ public class JobSummaryView extends Main implements HasUrlParameter<String>, Has
|
|||||||
private final LocationService locationService;
|
private final LocationService locationService;
|
||||||
private final ServiceRepository serviceRepository;
|
private final ServiceRepository serviceRepository;
|
||||||
private final TaskAssignmentService taskAssignmentService;
|
private final TaskAssignmentService taskAssignmentService;
|
||||||
private final SecurityService securityService;
|
|
||||||
|
|
||||||
@Value("${app.google.maps.api-key}")
|
@Value("${app.google.maps.api-key}")
|
||||||
private String googleMapsApiKey;
|
private String googleMapsApiKey;
|
||||||
@@ -107,8 +103,7 @@ public class JobSummaryView extends Main implements HasUrlParameter<String>, Has
|
|||||||
PhotoRepository photoRepository, CommentRepository commentRepository, AppUserService appUserService,
|
PhotoRepository photoRepository, CommentRepository commentRepository, AppUserService appUserService,
|
||||||
MessageService messageService, JobHistoryService jobHistoryService,
|
MessageService messageService, JobHistoryService jobHistoryService,
|
||||||
JobUpdateBroadcaster jobUpdateBroadcaster, LocationService locationService,
|
JobUpdateBroadcaster jobUpdateBroadcaster, LocationService locationService,
|
||||||
ServiceRepository serviceRepository, TaskAssignmentService taskAssignmentService,
|
ServiceRepository serviceRepository, TaskAssignmentService taskAssignmentService) {
|
||||||
SecurityService securityService) {
|
|
||||||
this.jobRepository = jobRepository;
|
this.jobRepository = jobRepository;
|
||||||
this.cargoItemRepository = cargoItemRepository;
|
this.cargoItemRepository = cargoItemRepository;
|
||||||
this.signatureRepository = signatureRepository;
|
this.signatureRepository = signatureRepository;
|
||||||
@@ -121,7 +116,6 @@ public class JobSummaryView extends Main implements HasUrlParameter<String>, Has
|
|||||||
this.locationService = locationService;
|
this.locationService = locationService;
|
||||||
this.serviceRepository = serviceRepository;
|
this.serviceRepository = serviceRepository;
|
||||||
this.taskAssignmentService = taskAssignmentService;
|
this.taskAssignmentService = taskAssignmentService;
|
||||||
this.securityService = securityService;
|
|
||||||
|
|
||||||
setSizeFull();
|
setSizeFull();
|
||||||
addClassNames(LumoUtility.BoxSizing.BORDER, LumoUtility.Display.FLEX, LumoUtility.FlexDirection.COLUMN,
|
addClassNames(LumoUtility.BoxSizing.BORDER, LumoUtility.Display.FLEX, LumoUtility.FlexDirection.COLUMN,
|
||||||
@@ -224,7 +218,8 @@ public class JobSummaryView extends Main implements HasUrlParameter<String>, Has
|
|||||||
&& job.getStatus() != JobStatus.CANCELLED) {
|
&& job.getStatus() != JobStatus.CANCELLED) {
|
||||||
manualCompleteButton = new Button(getTranslation("jobsummary.button.manualcomplete"));
|
manualCompleteButton = new Button(getTranslation("jobsummary.button.manualcomplete"));
|
||||||
manualCompleteButton.addThemeVariants(ButtonVariant.LUMO_ERROR);
|
manualCompleteButton.addThemeVariants(ButtonVariant.LUMO_ERROR);
|
||||||
manualCompleteButton.addClickListener(e -> openManualCompleteDialog(job));
|
manualCompleteButton.addClickListener(e -> getUI()
|
||||||
|
.ifPresent(ui -> ui.navigate("job_manual_complete/" + job.getId().toHexString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Job History Button for toolbar
|
// Create Job History Button for toolbar
|
||||||
@@ -379,75 +374,6 @@ public class JobSummaryView extends Main implements HasUrlParameter<String>, Has
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openManualCompleteDialog(Job job) {
|
|
||||||
Dialog dialog = DialogStylingHelper.createStyledDialog(
|
|
||||||
getTranslation("jobsummary.dialog.manualcomplete.title"), "560px");
|
|
||||||
|
|
||||||
VerticalLayout dialogContent = DialogStylingHelper.createContentLayout("520px");
|
|
||||||
|
|
||||||
Span warningText = new Span(getTranslation("jobsummary.dialog.manualcomplete.text", job.getJobNumber()));
|
|
||||||
warningText.getStyle().set("color", "var(--lumo-error-text-color)");
|
|
||||||
|
|
||||||
TextArea reasonField = new TextArea(getTranslation("jobsummary.dialog.manualcomplete.reason"));
|
|
||||||
reasonField.setWidthFull();
|
|
||||||
reasonField.setMinHeight("100px");
|
|
||||||
reasonField.setRequired(true);
|
|
||||||
|
|
||||||
dialogContent.add(warningText, reasonField);
|
|
||||||
dialog.add(DialogStylingHelper.wrapContent(dialogContent));
|
|
||||||
|
|
||||||
HorizontalLayout buttonBar = new HorizontalLayout();
|
|
||||||
buttonBar.setWidthFull();
|
|
||||||
buttonBar.setJustifyContentMode(HorizontalLayout.JustifyContentMode.END);
|
|
||||||
buttonBar.setSpacing(true);
|
|
||||||
|
|
||||||
Button cancelButton = new Button(getTranslation("jobsummary.dialog.manualcomplete.cancel"),
|
|
||||||
e -> dialog.close());
|
|
||||||
|
|
||||||
Button confirmButton = new Button(getTranslation("jobsummary.dialog.manualcomplete.confirm"));
|
|
||||||
confirmButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_ERROR);
|
|
||||||
confirmButton.addClickListener(e -> {
|
|
||||||
String reason = reasonField.getValue();
|
|
||||||
if (reason == null || reason.trim().isEmpty()) {
|
|
||||||
reasonField.setInvalid(true);
|
|
||||||
reasonField.setErrorMessage(getTranslation("jobsummary.dialog.manualcomplete.reason.required"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
JobStatus oldStatus = job.getStatus();
|
|
||||||
job.setStatus(JobStatus.COMPLETED);
|
|
||||||
job.setUpdatedAt(LocalDateTime.now());
|
|
||||||
jobRepository.save(job);
|
|
||||||
|
|
||||||
String currentUser = securityService.getCurrentUsername();
|
|
||||||
jobHistoryService.logStatusChange(job, oldStatus, JobStatus.COMPLETED, currentUser);
|
|
||||||
|
|
||||||
String description = String.format("Auftrag manuell beendet von %s. Begründung: %s",
|
|
||||||
currentUser, reason.trim());
|
|
||||||
jobHistoryService.logCustomEvent(job.getId(),
|
|
||||||
getTranslation("jobsummary.history.manualcomplete.reason"),
|
|
||||||
description, currentUser, JobHistoryType.STATUS_CHANGE);
|
|
||||||
|
|
||||||
dialog.close();
|
|
||||||
Notification
|
|
||||||
.show(getTranslation("jobsummary.notification.completed", job.getJobNumber()), 3000,
|
|
||||||
Notification.Position.BOTTOM_END)
|
|
||||||
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
|
|
||||||
getUI().ifPresent(ui -> ui.navigate("job_summary/" + job.getId().toHexString()));
|
|
||||||
} catch (Exception ex) {
|
|
||||||
Notification
|
|
||||||
.show(getTranslation("jobsummary.notification.complete.error", ex.getMessage()), 5000,
|
|
||||||
Notification.Position.BOTTOM_END)
|
|
||||||
.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonBar.add(cancelButton, confirmButton);
|
|
||||||
dialog.getFooter().add(buttonBar);
|
|
||||||
dialog.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
private VerticalLayout borderedBox() {
|
private VerticalLayout borderedBox() {
|
||||||
VerticalLayout box = new VerticalLayout();
|
VerticalLayout box = new VerticalLayout();
|
||||||
box.addClassName("summary-card");
|
box.addClassName("summary-card");
|
||||||
|
|||||||
@@ -86,7 +86,8 @@ public class ShowCustomersView extends VerticalLayout implements HasDynamicTitle
|
|||||||
var customers = customerService.findAll();
|
var customers = customerService.findAll();
|
||||||
var currentUserId = securityService.getCurrentUserId();
|
var currentUserId = securityService.getCurrentUserId();
|
||||||
var ownCustomers = customers.stream()
|
var ownCustomers = customers.stream()
|
||||||
.filter(c -> c.getCreatedBy() != null && c.getCreatedBy().equals(currentUserId)).toList();
|
.filter(c -> c.getCreatedBy() != null && c.getCreatedBy().equals(currentUserId))
|
||||||
|
.filter(c -> !c.isInternal()).toList();
|
||||||
grid.setItems(ownCustomers);
|
grid.setItems(ownCustomers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,4 +10,6 @@ import java.util.List;
|
|||||||
@Repository
|
@Repository
|
||||||
public interface SignatureRepository extends MongoRepository<Signature, ObjectId> {
|
public interface SignatureRepository extends MongoRepository<Signature, ObjectId> {
|
||||||
List<Signature> findByTaskId(ObjectId taskId);
|
List<Signature> findByTaskId(ObjectId taskId);
|
||||||
|
|
||||||
|
List<Signature> findByTaskIdOrderByCreatedAtDesc(ObjectId taskId);
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ dialog.confirm=Bestätigen
|
|||||||
# Navigation and Main Layout
|
# Navigation and Main Layout
|
||||||
nav.jobs=Aufträge
|
nav.jobs=Aufträge
|
||||||
nav.job.create=Auftragserstellung
|
nav.job.create=Auftragserstellung
|
||||||
nav.customers=Kunden
|
nav.customers=Adressbuch
|
||||||
nav.appusers=App-Nutzer
|
nav.appusers=App-Nutzer
|
||||||
nav.statistics=Statistiken
|
nav.statistics=Statistiken
|
||||||
nav.invoices=Rechnungen
|
nav.invoices=Rechnungen
|
||||||
@@ -31,7 +31,7 @@ profile.lastname=Nachname
|
|||||||
profile.phone=Telefonnummer
|
profile.phone=Telefonnummer
|
||||||
profile.fax=Telefon (Fax)
|
profile.fax=Telefon (Fax)
|
||||||
profile.mobile=Telefon (Mobil)
|
profile.mobile=Telefon (Mobil)
|
||||||
profile.email=E-Mail-Adresse (Login)*
|
profile.email=E-Mail-Adresse
|
||||||
profile.street=Straße
|
profile.street=Straße
|
||||||
profile.housenr=Hausnr
|
profile.housenr=Hausnr
|
||||||
profile.addressadd=Adresszusatz
|
profile.addressadd=Adresszusatz
|
||||||
@@ -447,7 +447,8 @@ addjob.address.city.placeholder.pickup=Ort (Abholung)
|
|||||||
addjob.address.city.placeholder.delivery=Ort (Lieferung)
|
addjob.address.city.placeholder.delivery=Ort (Lieferung)
|
||||||
addjob.address.delivery.street.placeholder=Straße (Lieferung)
|
addjob.address.delivery.street.placeholder=Straße (Lieferung)
|
||||||
addjob.address.delivery.addition.placeholder=Adresszusatz (Lieferung)
|
addjob.address.delivery.addition.placeholder=Adresszusatz (Lieferung)
|
||||||
addjob.address.save=Adresse speichern
|
addjob.address.save=Adresse in Adressbuch übernehmen
|
||||||
|
addjob.address.update=Adresse im Adressbuch aktualisieren
|
||||||
addjob.section.pickup=Abholung
|
addjob.section.pickup=Abholung
|
||||||
addjob.section.delivery=Lieferung
|
addjob.section.delivery=Lieferung
|
||||||
addjob.stations.apply=Stationen \u00fcbernehmen
|
addjob.stations.apply=Stationen \u00fcbernehmen
|
||||||
@@ -513,7 +514,8 @@ addjob.tasks.photo.min=Min. Fotos
|
|||||||
addjob.tasks.photo.max=Max. Fotos
|
addjob.tasks.photo.max=Max. Fotos
|
||||||
addjob.tasks.barcode.min=Min. Barcodes
|
addjob.tasks.barcode.min=Min. Barcodes
|
||||||
addjob.tasks.barcode.max=Max. Barcodes
|
addjob.tasks.barcode.max=Max. Barcodes
|
||||||
addjob.tasks.signature.noconfig=Keine Konfiguration erforderlich
|
addjob.tasks.signature.notelabel=Bemerkung (optional)
|
||||||
|
addjob.tasks.signature.notelabel.placeholder=Hinweistext für die Bemerkung eingeben
|
||||||
addjob.tasks.todolist.title=To-Do Liste
|
addjob.tasks.todolist.title=To-Do Liste
|
||||||
addjob.tasks.todolist.item.placeholder=To-Do eingeben
|
addjob.tasks.todolist.item.placeholder=To-Do eingeben
|
||||||
addjob.tasks.todolist.add=To-Do hinzufügen
|
addjob.tasks.todolist.add=To-Do hinzufügen
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ dialog.cancel=T\u00fchista
|
|||||||
dialog.confirm=Kinnita
|
dialog.confirm=Kinnita
|
||||||
nav.jobs=Tellimused
|
nav.jobs=Tellimused
|
||||||
nav.job.create=Tellimuse loomine
|
nav.job.create=Tellimuse loomine
|
||||||
nav.customers=Kliendid
|
nav.customers=Aadressiraamat
|
||||||
nav.appusers=\u00c4pikasutajad
|
nav.appusers=\u00c4pikasutajad
|
||||||
nav.statistics=Statistika
|
nav.statistics=Statistika
|
||||||
nav.invoices=Arved
|
nav.invoices=Arved
|
||||||
@@ -27,7 +27,7 @@ profile.lastname=Perekonnanimi
|
|||||||
profile.phone=Telefoninumber
|
profile.phone=Telefoninumber
|
||||||
profile.fax=Telefon (faks)
|
profile.fax=Telefon (faks)
|
||||||
profile.mobile=Telefon (mobiil)
|
profile.mobile=Telefon (mobiil)
|
||||||
profile.email=E-posti aadress (sisselogimine)*
|
profile.email=E-posti aadress
|
||||||
profile.street=T\u00e4nav
|
profile.street=T\u00e4nav
|
||||||
profile.housenr=Majanumber
|
profile.housenr=Majanumber
|
||||||
profile.addressadd=Aadressi t\u00e4iend
|
profile.addressadd=Aadressi t\u00e4iend
|
||||||
@@ -396,7 +396,8 @@ addjob.address.city.placeholder.pickup=Asukoht (pealekorje)
|
|||||||
addjob.address.city.placeholder.delivery=Asukoht (kohaletoimetamine)
|
addjob.address.city.placeholder.delivery=Asukoht (kohaletoimetamine)
|
||||||
addjob.address.delivery.street.placeholder=T\u00e4nav (kohaletoimetamine)
|
addjob.address.delivery.street.placeholder=T\u00e4nav (kohaletoimetamine)
|
||||||
addjob.address.delivery.addition.placeholder=Aadressi t\u00e4iend (kohaletoimetamine)
|
addjob.address.delivery.addition.placeholder=Aadressi t\u00e4iend (kohaletoimetamine)
|
||||||
addjob.address.save=Salvesta aadress
|
addjob.address.save=Lisa aadress aadressiraamatusse
|
||||||
|
addjob.address.update=Uuenda aadressi aadressiraamatus
|
||||||
addjob.section.pickup=Pealekorje
|
addjob.section.pickup=Pealekorje
|
||||||
addjob.section.delivery=Kohaletoimetamine
|
addjob.section.delivery=Kohaletoimetamine
|
||||||
addjob.stations.apply=Rakenda jaamad
|
addjob.stations.apply=Rakenda jaamad
|
||||||
@@ -462,7 +463,8 @@ addjob.tasks.photo.min=Min. fotosid
|
|||||||
addjob.tasks.photo.max=Max. fotosid
|
addjob.tasks.photo.max=Max. fotosid
|
||||||
addjob.tasks.barcode.min=Min. v\u00f6\u00f6tkoode
|
addjob.tasks.barcode.min=Min. v\u00f6\u00f6tkoode
|
||||||
addjob.tasks.barcode.max=Max. v\u00f6\u00f6tkoode
|
addjob.tasks.barcode.max=Max. v\u00f6\u00f6tkoode
|
||||||
addjob.tasks.signature.noconfig=Seadistamine pole vajalik
|
addjob.tasks.signature.notelabel=Märkus (valikuline)
|
||||||
|
addjob.tasks.signature.notelabel.placeholder=Sisestage vihje tekst märkusele
|
||||||
addjob.tasks.todolist.title=\u00dclesannete nimekiri
|
addjob.tasks.todolist.title=\u00dclesannete nimekiri
|
||||||
addjob.tasks.todolist.item.placeholder=Sisestage \u00fclesanne
|
addjob.tasks.todolist.item.placeholder=Sisestage \u00fclesanne
|
||||||
addjob.tasks.todolist.add=Lisa \u00fclesanne
|
addjob.tasks.todolist.add=Lisa \u00fclesanne
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ dialog.confirm=Confirm
|
|||||||
# Navigation and Main Layout
|
# Navigation and Main Layout
|
||||||
nav.jobs=Jobs
|
nav.jobs=Jobs
|
||||||
nav.job.create=Create Job
|
nav.job.create=Create Job
|
||||||
nav.customers=Customers
|
nav.customers=Address Book
|
||||||
nav.appusers=App Users
|
nav.appusers=App Users
|
||||||
nav.statistics=Statistics
|
nav.statistics=Statistics
|
||||||
nav.invoices=Invoices
|
nav.invoices=Invoices
|
||||||
@@ -31,7 +31,7 @@ profile.lastname=Last Name
|
|||||||
profile.phone=Phone Number
|
profile.phone=Phone Number
|
||||||
profile.fax=Phone (Fax)
|
profile.fax=Phone (Fax)
|
||||||
profile.mobile=Phone (Mobile)
|
profile.mobile=Phone (Mobile)
|
||||||
profile.email=Email Address (Login)*
|
profile.email=Email Address
|
||||||
profile.street=Street
|
profile.street=Street
|
||||||
profile.housenr=House No.
|
profile.housenr=House No.
|
||||||
profile.addressadd=Address Suffix
|
profile.addressadd=Address Suffix
|
||||||
@@ -447,7 +447,8 @@ addjob.address.city.placeholder.pickup=City (Pickup)
|
|||||||
addjob.address.city.placeholder.delivery=City (Delivery)
|
addjob.address.city.placeholder.delivery=City (Delivery)
|
||||||
addjob.address.delivery.street.placeholder=Street (Delivery)
|
addjob.address.delivery.street.placeholder=Street (Delivery)
|
||||||
addjob.address.delivery.addition.placeholder=Address suffix (Delivery)
|
addjob.address.delivery.addition.placeholder=Address suffix (Delivery)
|
||||||
addjob.address.save=Save Address
|
addjob.address.save=Add address to address book
|
||||||
|
addjob.address.update=Update address in address book
|
||||||
addjob.section.pickup=Pickup
|
addjob.section.pickup=Pickup
|
||||||
addjob.section.delivery=Delivery
|
addjob.section.delivery=Delivery
|
||||||
addjob.stations.apply=Apply Stations
|
addjob.stations.apply=Apply Stations
|
||||||
@@ -513,7 +514,8 @@ addjob.tasks.photo.min=Min. Photos
|
|||||||
addjob.tasks.photo.max=Max. Photos
|
addjob.tasks.photo.max=Max. Photos
|
||||||
addjob.tasks.barcode.min=Min. Barcodes
|
addjob.tasks.barcode.min=Min. Barcodes
|
||||||
addjob.tasks.barcode.max=Max. Barcodes
|
addjob.tasks.barcode.max=Max. Barcodes
|
||||||
addjob.tasks.signature.noconfig=No configuration required
|
addjob.tasks.signature.notelabel=Note (optional)
|
||||||
|
addjob.tasks.signature.notelabel.placeholder=Enter hint text for the note
|
||||||
addjob.tasks.todolist.title=To-Do List
|
addjob.tasks.todolist.title=To-Do List
|
||||||
addjob.tasks.todolist.item.placeholder=Enter to-do
|
addjob.tasks.todolist.item.placeholder=Enter to-do
|
||||||
addjob.tasks.todolist.add=Add To-Do
|
addjob.tasks.todolist.add=Add To-Do
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ dialog.confirm=Confirmar
|
|||||||
# Navigation and Main Layout
|
# Navigation and Main Layout
|
||||||
nav.jobs=Pedidos
|
nav.jobs=Pedidos
|
||||||
nav.job.create=Crear pedido
|
nav.job.create=Crear pedido
|
||||||
nav.customers=Clientes
|
nav.customers=Libreta de direcciones
|
||||||
nav.appusers=Usuarios de la app
|
nav.appusers=Usuarios de la app
|
||||||
nav.statistics=Estad\u00edsticas
|
nav.statistics=Estad\u00edsticas
|
||||||
nav.invoices=Facturas
|
nav.invoices=Facturas
|
||||||
@@ -31,7 +31,7 @@ profile.lastname=Apellido
|
|||||||
profile.phone=N\u00famero de tel\u00e9fono
|
profile.phone=N\u00famero de tel\u00e9fono
|
||||||
profile.fax=Tel\u00e9fono (Fax)
|
profile.fax=Tel\u00e9fono (Fax)
|
||||||
profile.mobile=Tel\u00e9fono (M\u00f3vil)
|
profile.mobile=Tel\u00e9fono (M\u00f3vil)
|
||||||
profile.email=Direcci\u00f3n de correo electr\u00f3nico (Login)*
|
profile.email=Direcci\u00f3n de correo electr\u00f3nico
|
||||||
profile.street=Calle
|
profile.street=Calle
|
||||||
profile.housenr=N\u00famero
|
profile.housenr=N\u00famero
|
||||||
profile.addressadd=Complemento de direcci\u00f3n
|
profile.addressadd=Complemento de direcci\u00f3n
|
||||||
@@ -447,7 +447,8 @@ addjob.address.city.placeholder.pickup=Localidad (Recogida)
|
|||||||
addjob.address.city.placeholder.delivery=Localidad (Entrega)
|
addjob.address.city.placeholder.delivery=Localidad (Entrega)
|
||||||
addjob.address.delivery.street.placeholder=Calle (Entrega)
|
addjob.address.delivery.street.placeholder=Calle (Entrega)
|
||||||
addjob.address.delivery.addition.placeholder=Complemento de direcci\u00f3n (Entrega)
|
addjob.address.delivery.addition.placeholder=Complemento de direcci\u00f3n (Entrega)
|
||||||
addjob.address.save=Guardar direcci\u00f3n
|
addjob.address.save=A\u00f1adir direcci\u00f3n a la libreta de direcciones
|
||||||
|
addjob.address.update=Actualizar direcci\u00f3n en la libreta de direcciones
|
||||||
addjob.section.pickup=Recogida
|
addjob.section.pickup=Recogida
|
||||||
addjob.section.delivery=Entrega
|
addjob.section.delivery=Entrega
|
||||||
addjob.stations.apply=Aplicar estaciones
|
addjob.stations.apply=Aplicar estaciones
|
||||||
@@ -513,7 +514,8 @@ addjob.tasks.photo.min=M\u00edn. fotos
|
|||||||
addjob.tasks.photo.max=M\u00e1x. fotos
|
addjob.tasks.photo.max=M\u00e1x. fotos
|
||||||
addjob.tasks.barcode.min=M\u00edn. c\u00f3digos de barras
|
addjob.tasks.barcode.min=M\u00edn. c\u00f3digos de barras
|
||||||
addjob.tasks.barcode.max=M\u00e1x. c\u00f3digos de barras
|
addjob.tasks.barcode.max=M\u00e1x. c\u00f3digos de barras
|
||||||
addjob.tasks.signature.noconfig=No se requiere configuraci\u00f3n
|
addjob.tasks.signature.notelabel=Nota (opcional)
|
||||||
|
addjob.tasks.signature.notelabel.placeholder=Introducir texto de sugerencia para la nota
|
||||||
addjob.tasks.todolist.title=Lista de tareas pendientes
|
addjob.tasks.todolist.title=Lista de tareas pendientes
|
||||||
addjob.tasks.todolist.item.placeholder=Introducir tarea pendiente
|
addjob.tasks.todolist.item.placeholder=Introducir tarea pendiente
|
||||||
addjob.tasks.todolist.add=A\u00f1adir tarea pendiente
|
addjob.tasks.todolist.add=A\u00f1adir tarea pendiente
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ dialog.confirm=Confirmer
|
|||||||
# Navigation and Main Layout
|
# Navigation and Main Layout
|
||||||
nav.jobs=Missions
|
nav.jobs=Missions
|
||||||
nav.job.create=Cr\u00e9ation de mission
|
nav.job.create=Cr\u00e9ation de mission
|
||||||
nav.customers=Clients
|
nav.customers=Carnet d'adresses
|
||||||
nav.appusers=Utilisateurs d'app
|
nav.appusers=Utilisateurs d'app
|
||||||
nav.statistics=Statistiques
|
nav.statistics=Statistiques
|
||||||
nav.invoices=Factures
|
nav.invoices=Factures
|
||||||
@@ -31,7 +31,7 @@ profile.lastname=Nom
|
|||||||
profile.phone=Num\u00e9ro de t\u00e9l\u00e9phone
|
profile.phone=Num\u00e9ro de t\u00e9l\u00e9phone
|
||||||
profile.fax=T\u00e9l\u00e9phone (fax)
|
profile.fax=T\u00e9l\u00e9phone (fax)
|
||||||
profile.mobile=T\u00e9l\u00e9phone (mobile)
|
profile.mobile=T\u00e9l\u00e9phone (mobile)
|
||||||
profile.email=Adresse e-mail (connexion)*
|
profile.email=Adresse e-mail
|
||||||
profile.street=Rue
|
profile.street=Rue
|
||||||
profile.housenr=N\u00b0
|
profile.housenr=N\u00b0
|
||||||
profile.addressadd=Compl\u00e9ment d'adresse
|
profile.addressadd=Compl\u00e9ment d'adresse
|
||||||
@@ -447,7 +447,8 @@ addjob.address.city.placeholder.pickup=Ville (enl\u00e8vement)
|
|||||||
addjob.address.city.placeholder.delivery=Ville (livraison)
|
addjob.address.city.placeholder.delivery=Ville (livraison)
|
||||||
addjob.address.delivery.street.placeholder=Rue (livraison)
|
addjob.address.delivery.street.placeholder=Rue (livraison)
|
||||||
addjob.address.delivery.addition.placeholder=Compl\u00e9ment d'adresse (livraison)
|
addjob.address.delivery.addition.placeholder=Compl\u00e9ment d'adresse (livraison)
|
||||||
addjob.address.save=Enregistrer l'adresse
|
addjob.address.save=Ajouter l'adresse au carnet d'adresses
|
||||||
|
addjob.address.update=Mettre \u00e0 jour l'adresse dans le carnet d'adresses
|
||||||
addjob.section.pickup=Enl\u00e8vement
|
addjob.section.pickup=Enl\u00e8vement
|
||||||
addjob.section.delivery=Livraison
|
addjob.section.delivery=Livraison
|
||||||
addjob.stations.apply=Appliquer les stations
|
addjob.stations.apply=Appliquer les stations
|
||||||
@@ -513,7 +514,8 @@ addjob.tasks.photo.min=Min. photos
|
|||||||
addjob.tasks.photo.max=Max. photos
|
addjob.tasks.photo.max=Max. photos
|
||||||
addjob.tasks.barcode.min=Min. codes-barres
|
addjob.tasks.barcode.min=Min. codes-barres
|
||||||
addjob.tasks.barcode.max=Max. codes-barres
|
addjob.tasks.barcode.max=Max. codes-barres
|
||||||
addjob.tasks.signature.noconfig=Aucune configuration n\u00e9cessaire
|
addjob.tasks.signature.notelabel=Note (optionnelle)
|
||||||
|
addjob.tasks.signature.notelabel.placeholder=Saisir le texte d'indication pour la note
|
||||||
addjob.tasks.todolist.title=Liste de t\u00e2ches
|
addjob.tasks.todolist.title=Liste de t\u00e2ches
|
||||||
addjob.tasks.todolist.item.placeholder=Saisir la t\u00e2che
|
addjob.tasks.todolist.item.placeholder=Saisir la t\u00e2che
|
||||||
addjob.tasks.todolist.add=Ajouter une t\u00e2che
|
addjob.tasks.todolist.add=Ajouter une t\u00e2che
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ dialog.confirm=Patvirtinti
|
|||||||
# Navigation and Main Layout
|
# Navigation and Main Layout
|
||||||
nav.jobs=Užsakymai
|
nav.jobs=Užsakymai
|
||||||
nav.job.create=Užsakymo kūrimas
|
nav.job.create=Užsakymo kūrimas
|
||||||
nav.customers=Klientai
|
nav.customers=Adres\u0173 knyga
|
||||||
nav.appusers=Programėlės naudotojai
|
nav.appusers=Programėlės naudotojai
|
||||||
nav.statistics=Statistika
|
nav.statistics=Statistika
|
||||||
nav.invoices=Sąskaitos faktūros
|
nav.invoices=Sąskaitos faktūros
|
||||||
@@ -31,7 +31,7 @@ profile.lastname=Pavardė
|
|||||||
profile.phone=Telefono numeris
|
profile.phone=Telefono numeris
|
||||||
profile.fax=Telefonas (faksas)
|
profile.fax=Telefonas (faksas)
|
||||||
profile.mobile=Telefonas (mob.)
|
profile.mobile=Telefonas (mob.)
|
||||||
profile.email=El. pašto adresas (prisijungimas)*
|
profile.email=El. pašto adresas*
|
||||||
profile.street=Gatvė
|
profile.street=Gatvė
|
||||||
profile.housenr=Namo nr.
|
profile.housenr=Namo nr.
|
||||||
profile.addressadd=Adreso priedas
|
profile.addressadd=Adreso priedas
|
||||||
@@ -447,7 +447,8 @@ addjob.address.city.placeholder.pickup=Vietovė (atsiėmimas)
|
|||||||
addjob.address.city.placeholder.delivery=Vietovė (pristatymas)
|
addjob.address.city.placeholder.delivery=Vietovė (pristatymas)
|
||||||
addjob.address.delivery.street.placeholder=Gatvė (pristatymas)
|
addjob.address.delivery.street.placeholder=Gatvė (pristatymas)
|
||||||
addjob.address.delivery.addition.placeholder=Adreso priedas (pristatymas)
|
addjob.address.delivery.addition.placeholder=Adreso priedas (pristatymas)
|
||||||
addjob.address.save=Išsaugoti adresą
|
addjob.address.save=Pridėti adresą į adresų knygą
|
||||||
|
addjob.address.update=Atnaujinti adresą adresų knygoje
|
||||||
addjob.section.pickup=Atsiėmimas
|
addjob.section.pickup=Atsiėmimas
|
||||||
addjob.section.delivery=Pristatymas
|
addjob.section.delivery=Pristatymas
|
||||||
addjob.stations.apply=Pritaikyti stotis
|
addjob.stations.apply=Pritaikyti stotis
|
||||||
@@ -513,7 +514,8 @@ addjob.tasks.photo.min=Min. nuotraukų
|
|||||||
addjob.tasks.photo.max=Maks. nuotraukų
|
addjob.tasks.photo.max=Maks. nuotraukų
|
||||||
addjob.tasks.barcode.min=Min. brūkšninių kodų
|
addjob.tasks.barcode.min=Min. brūkšninių kodų
|
||||||
addjob.tasks.barcode.max=Maks. brūkšninių kodų
|
addjob.tasks.barcode.max=Maks. brūkšninių kodų
|
||||||
addjob.tasks.signature.noconfig=Konfigūracija nereikalinga
|
addjob.tasks.signature.notelabel=Pastaba (neprivaloma)
|
||||||
|
addjob.tasks.signature.notelabel.placeholder=Įveskite patarimo tekstą pastabai
|
||||||
addjob.tasks.todolist.title=Užduočių sąrašas
|
addjob.tasks.todolist.title=Užduočių sąrašas
|
||||||
addjob.tasks.todolist.item.placeholder=Įveskite užduotį
|
addjob.tasks.todolist.item.placeholder=Įveskite užduotį
|
||||||
addjob.tasks.todolist.add=Pridėti užduotį
|
addjob.tasks.todolist.add=Pridėti užduotį
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ dialog.confirm=Apstiprināt
|
|||||||
# Navigation and Main Layout
|
# Navigation and Main Layout
|
||||||
nav.jobs=Uzdevumi
|
nav.jobs=Uzdevumi
|
||||||
nav.job.create=Izveidot uzdevumu
|
nav.job.create=Izveidot uzdevumu
|
||||||
nav.customers=Klienti
|
nav.customers=Adrešu gr\u0101mata
|
||||||
nav.appusers=Lietotnes lietotāji
|
nav.appusers=Lietotnes lietotāji
|
||||||
nav.statistics=Statistika
|
nav.statistics=Statistika
|
||||||
nav.invoices=Rēķini
|
nav.invoices=Rēķini
|
||||||
@@ -31,7 +31,7 @@ profile.lastname=Uzvārds
|
|||||||
profile.phone=Tālruņa numurs
|
profile.phone=Tālruņa numurs
|
||||||
profile.fax=Tālrunis (fakss)
|
profile.fax=Tālrunis (fakss)
|
||||||
profile.mobile=Tālrunis (mobilais)
|
profile.mobile=Tālrunis (mobilais)
|
||||||
profile.email=E-pasta adrese (pieteikšanās)*
|
profile.email=E-pasta adrese
|
||||||
profile.street=Iela
|
profile.street=Iela
|
||||||
profile.housenr=Mājas nr.
|
profile.housenr=Mājas nr.
|
||||||
profile.addressadd=Adreses papildinājums
|
profile.addressadd=Adreses papildinājums
|
||||||
@@ -447,7 +447,8 @@ addjob.address.city.placeholder.pickup=Vieta (saņemšana)
|
|||||||
addjob.address.city.placeholder.delivery=Vieta (piegāde)
|
addjob.address.city.placeholder.delivery=Vieta (piegāde)
|
||||||
addjob.address.delivery.street.placeholder=Iela (piegāde)
|
addjob.address.delivery.street.placeholder=Iela (piegāde)
|
||||||
addjob.address.delivery.addition.placeholder=Adreses papildinājums (piegāde)
|
addjob.address.delivery.addition.placeholder=Adreses papildinājums (piegāde)
|
||||||
addjob.address.save=Saglabāt adresi
|
addjob.address.save=Pievienot adresi adrešu grāmatai
|
||||||
|
addjob.address.update=Atjaunin\u0101t adresi adrešu gr\u0101mat\u0101
|
||||||
addjob.section.pickup=Saņemšana
|
addjob.section.pickup=Saņemšana
|
||||||
addjob.section.delivery=Piegāde
|
addjob.section.delivery=Piegāde
|
||||||
addjob.stations.apply=Pārņemt stacijas
|
addjob.stations.apply=Pārņemt stacijas
|
||||||
@@ -513,7 +514,8 @@ addjob.tasks.photo.min=Min. fotogrāfijas
|
|||||||
addjob.tasks.photo.max=Maks. fotogrāfijas
|
addjob.tasks.photo.max=Maks. fotogrāfijas
|
||||||
addjob.tasks.barcode.min=Min. svītrkodi
|
addjob.tasks.barcode.min=Min. svītrkodi
|
||||||
addjob.tasks.barcode.max=Maks. svītrkodi
|
addjob.tasks.barcode.max=Maks. svītrkodi
|
||||||
addjob.tasks.signature.noconfig=Konfigurācija nav nepieciešama
|
addjob.tasks.signature.notelabel=Piezīme (neobligāta)
|
||||||
|
addjob.tasks.signature.notelabel.placeholder=Ievadiet padoma tekstu piezīmei
|
||||||
addjob.tasks.todolist.title=Uzdevumu saraksts
|
addjob.tasks.todolist.title=Uzdevumu saraksts
|
||||||
addjob.tasks.todolist.item.placeholder=Ievadiet uzdevumu
|
addjob.tasks.todolist.item.placeholder=Ievadiet uzdevumu
|
||||||
addjob.tasks.todolist.add=Pievienot uzdevumu
|
addjob.tasks.todolist.add=Pievienot uzdevumu
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ dialog.confirm=Potwierd\u017a
|
|||||||
# Navigation and Main Layout
|
# Navigation and Main Layout
|
||||||
nav.jobs=Zlecenia
|
nav.jobs=Zlecenia
|
||||||
nav.job.create=Tworzenie zlecenia
|
nav.job.create=Tworzenie zlecenia
|
||||||
nav.customers=Klienci
|
nav.customers=Ksi\u0105\u017cka adresowa
|
||||||
nav.appusers=U\u017cytkownicy aplikacji
|
nav.appusers=U\u017cytkownicy aplikacji
|
||||||
nav.statistics=Statystyki
|
nav.statistics=Statystyki
|
||||||
nav.invoices=Faktury
|
nav.invoices=Faktury
|
||||||
@@ -31,7 +31,7 @@ profile.lastname=Nazwisko
|
|||||||
profile.phone=Numer telefonu
|
profile.phone=Numer telefonu
|
||||||
profile.fax=Telefon (faks)
|
profile.fax=Telefon (faks)
|
||||||
profile.mobile=Telefon (kom\u00f3rkowy)
|
profile.mobile=Telefon (kom\u00f3rkowy)
|
||||||
profile.email=Adres e-mail (login)*
|
profile.email=Adres e-mail
|
||||||
profile.street=Ulica
|
profile.street=Ulica
|
||||||
profile.housenr=Nr domu
|
profile.housenr=Nr domu
|
||||||
profile.addressadd=Dodatek do adresu
|
profile.addressadd=Dodatek do adresu
|
||||||
@@ -447,7 +447,8 @@ addjob.address.city.placeholder.pickup=Miejscowo\u015b\u0107 (odbi\u00f3r)
|
|||||||
addjob.address.city.placeholder.delivery=Miejscowo\u015b\u0107 (dostawa)
|
addjob.address.city.placeholder.delivery=Miejscowo\u015b\u0107 (dostawa)
|
||||||
addjob.address.delivery.street.placeholder=Ulica (dostawa)
|
addjob.address.delivery.street.placeholder=Ulica (dostawa)
|
||||||
addjob.address.delivery.addition.placeholder=Dodatek do adresu (dostawa)
|
addjob.address.delivery.addition.placeholder=Dodatek do adresu (dostawa)
|
||||||
addjob.address.save=Zapisz adres
|
addjob.address.save=Dodaj adres do ksi\u0105\u017cki adresowej
|
||||||
|
addjob.address.update=Zaktualizuj adres w ksi\u0105\u017cce adresowej
|
||||||
addjob.section.pickup=Odbi\u00f3r
|
addjob.section.pickup=Odbi\u00f3r
|
||||||
addjob.section.delivery=Dostawa
|
addjob.section.delivery=Dostawa
|
||||||
addjob.stations.apply=Zastosuj stacje
|
addjob.stations.apply=Zastosuj stacje
|
||||||
@@ -513,7 +514,8 @@ addjob.tasks.photo.min=Min. zdj\u0119\u0107
|
|||||||
addjob.tasks.photo.max=Maks. zdj\u0119\u0107
|
addjob.tasks.photo.max=Maks. zdj\u0119\u0107
|
||||||
addjob.tasks.barcode.min=Min. kod\u00f3w kreskowych
|
addjob.tasks.barcode.min=Min. kod\u00f3w kreskowych
|
||||||
addjob.tasks.barcode.max=Maks. kod\u00f3w kreskowych
|
addjob.tasks.barcode.max=Maks. kod\u00f3w kreskowych
|
||||||
addjob.tasks.signature.noconfig=Konfiguracja nie jest wymagana
|
addjob.tasks.signature.notelabel=Notatka (opcjonalnie)
|
||||||
|
addjob.tasks.signature.notelabel.placeholder=Wprowadź tekst podpowiedzi dla notatki
|
||||||
addjob.tasks.todolist.title=Lista zada\u0144
|
addjob.tasks.todolist.title=Lista zada\u0144
|
||||||
addjob.tasks.todolist.item.placeholder=Wprowad\u017a zadanie
|
addjob.tasks.todolist.item.placeholder=Wprowad\u017a zadanie
|
||||||
addjob.tasks.todolist.add=Dodaj zadanie
|
addjob.tasks.todolist.add=Dodaj zadanie
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ dialog.confirm=Подтвердить
|
|||||||
# Navigation and Main Layout
|
# Navigation and Main Layout
|
||||||
nav.jobs=Заказы
|
nav.jobs=Заказы
|
||||||
nav.job.create=Создание заказа
|
nav.job.create=Создание заказа
|
||||||
nav.customers=Клиенты
|
nav.customers=Адресная книга
|
||||||
nav.appusers=Пользователи приложения
|
nav.appusers=Пользователи приложения
|
||||||
nav.statistics=Статистика
|
nav.statistics=Статистика
|
||||||
nav.invoices=Счета
|
nav.invoices=Счета
|
||||||
@@ -31,7 +31,7 @@ profile.lastname=Фамилия
|
|||||||
profile.phone=Номер телефона
|
profile.phone=Номер телефона
|
||||||
profile.fax=Телефон (факс)
|
profile.fax=Телефон (факс)
|
||||||
profile.mobile=Телефон (мобильный)
|
profile.mobile=Телефон (мобильный)
|
||||||
profile.email=Адрес электронной почты (логин)*
|
profile.email=Адрес электронной почты
|
||||||
profile.street=Улица
|
profile.street=Улица
|
||||||
profile.housenr=Дом
|
profile.housenr=Дом
|
||||||
profile.addressadd=Дополнение к адресу
|
profile.addressadd=Дополнение к адресу
|
||||||
@@ -447,7 +447,8 @@ addjob.address.city.placeholder.pickup=Город (забор)
|
|||||||
addjob.address.city.placeholder.delivery=Город (доставка)
|
addjob.address.city.placeholder.delivery=Город (доставка)
|
||||||
addjob.address.delivery.street.placeholder=Улица (доставка)
|
addjob.address.delivery.street.placeholder=Улица (доставка)
|
||||||
addjob.address.delivery.addition.placeholder=Дополнение к адресу (доставка)
|
addjob.address.delivery.addition.placeholder=Дополнение к адресу (доставка)
|
||||||
addjob.address.save=Сохранить адрес
|
addjob.address.save=Добавить адрес в адресную книгу
|
||||||
|
addjob.address.update=Обновить адрес в адресной книге
|
||||||
addjob.section.pickup=Забор
|
addjob.section.pickup=Забор
|
||||||
addjob.section.delivery=Доставка
|
addjob.section.delivery=Доставка
|
||||||
addjob.stations.apply=Применить станции
|
addjob.stations.apply=Применить станции
|
||||||
@@ -513,7 +514,8 @@ addjob.tasks.photo.min=Мин. фото
|
|||||||
addjob.tasks.photo.max=Макс. фото
|
addjob.tasks.photo.max=Макс. фото
|
||||||
addjob.tasks.barcode.min=Мин. штрих-кодов
|
addjob.tasks.barcode.min=Мин. штрих-кодов
|
||||||
addjob.tasks.barcode.max=Макс. штрих-кодов
|
addjob.tasks.barcode.max=Макс. штрих-кодов
|
||||||
addjob.tasks.signature.noconfig=Настройка не требуется
|
addjob.tasks.signature.notelabel=Примечание (необязательно)
|
||||||
|
addjob.tasks.signature.notelabel.placeholder=Введите текст подсказки для примечания
|
||||||
addjob.tasks.todolist.title=Список дел
|
addjob.tasks.todolist.title=Список дел
|
||||||
addjob.tasks.todolist.item.placeholder=Введите задачу
|
addjob.tasks.todolist.item.placeholder=Введите задачу
|
||||||
addjob.tasks.todolist.add=Добавить задачу
|
addjob.tasks.todolist.add=Добавить задачу
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ dialog.confirm=Onayla
|
|||||||
# Navigation and Main Layout
|
# Navigation and Main Layout
|
||||||
nav.jobs=\u0130\u015fler
|
nav.jobs=\u0130\u015fler
|
||||||
nav.job.create=\u0130\u015f Olu\u015ftur
|
nav.job.create=\u0130\u015f Olu\u015ftur
|
||||||
nav.customers=M\u00fc\u015fteriler
|
nav.customers=Adres Defteri
|
||||||
nav.appusers=Uygulama Kullan\u0131c\u0131lar\u0131
|
nav.appusers=Uygulama Kullan\u0131c\u0131lar\u0131
|
||||||
nav.statistics=\u0130statistikler
|
nav.statistics=\u0130statistikler
|
||||||
nav.invoices=Faturalar
|
nav.invoices=Faturalar
|
||||||
@@ -31,7 +31,7 @@ profile.lastname=Soyad
|
|||||||
profile.phone=Telefon Numaras\u0131
|
profile.phone=Telefon Numaras\u0131
|
||||||
profile.fax=Telefon (Faks)
|
profile.fax=Telefon (Faks)
|
||||||
profile.mobile=Telefon (Mobil)
|
profile.mobile=Telefon (Mobil)
|
||||||
profile.email=E-Posta Adresi (Giri\u015f)*
|
profile.email=E-Posta Adresi*
|
||||||
profile.street=Sokak
|
profile.street=Sokak
|
||||||
profile.housenr=Kap\u0131 No
|
profile.housenr=Kap\u0131 No
|
||||||
profile.addressadd=Adres Eki
|
profile.addressadd=Adres Eki
|
||||||
@@ -447,7 +447,8 @@ addjob.address.city.placeholder.pickup=\u015eehir (Al\u0131m)
|
|||||||
addjob.address.city.placeholder.delivery=\u015eehir (Teslimat)
|
addjob.address.city.placeholder.delivery=\u015eehir (Teslimat)
|
||||||
addjob.address.delivery.street.placeholder=Sokak (Teslimat)
|
addjob.address.delivery.street.placeholder=Sokak (Teslimat)
|
||||||
addjob.address.delivery.addition.placeholder=Adres eki (Teslimat)
|
addjob.address.delivery.addition.placeholder=Adres eki (Teslimat)
|
||||||
addjob.address.save=Adresi Kaydet
|
addjob.address.save=Adresi adres defterine ekle
|
||||||
|
addjob.address.update=Adres defterindeki adresi g\u00fcncelle
|
||||||
addjob.section.pickup=Al\u0131m
|
addjob.section.pickup=Al\u0131m
|
||||||
addjob.section.delivery=Teslimat
|
addjob.section.delivery=Teslimat
|
||||||
addjob.stations.apply=\u0130stasyonlar\u0131 \u00fcbernehmennehmen
|
addjob.stations.apply=\u0130stasyonlar\u0131 \u00fcbernehmennehmen
|
||||||
@@ -513,7 +514,8 @@ addjob.tasks.photo.min=Min. Foto\u011fraf
|
|||||||
addjob.tasks.photo.max=Maks. Foto\u011fraf
|
addjob.tasks.photo.max=Maks. Foto\u011fraf
|
||||||
addjob.tasks.barcode.min=Min. Barkod
|
addjob.tasks.barcode.min=Min. Barkod
|
||||||
addjob.tasks.barcode.max=Maks. Barkod
|
addjob.tasks.barcode.max=Maks. Barkod
|
||||||
addjob.tasks.signature.noconfig=Yap\u0131land\u0131rma gerekli de\u011fil
|
addjob.tasks.signature.notelabel=Not (iste\u011fe ba\u011fl\u0131)
|
||||||
|
addjob.tasks.signature.notelabel.placeholder=Not i\u00e7in ipucu metnini girin
|
||||||
addjob.tasks.todolist.title=Yap\u0131lacaklar Listesi
|
addjob.tasks.todolist.title=Yap\u0131lacaklar Listesi
|
||||||
addjob.tasks.todolist.item.placeholder=Yap\u0131lacak \u00f6\u011feyi girin
|
addjob.tasks.todolist.item.placeholder=Yap\u0131lacak \u00f6\u011feyi girin
|
||||||
addjob.tasks.todolist.add=Yap\u0131lacak \u00d6\u011fe Ekle
|
addjob.tasks.todolist.add=Yap\u0131lacak \u00d6\u011fe Ekle
|
||||||
|
|||||||
Reference in New Issue
Block a user