Enhance envelope creation and update functionality
Added new optional properties to `CreateEnvelopeCommand` for detailed configuration, including `EnvelopeId`, `Language`, `UseAccessCode`, and expiration settings. Introduced `ResolveEnvelopeSettingsAsync` to centralize settings resolution logic. Updated `CreateEnvelopeCommandHandler` to handle new properties and improve envelope creation/update flow. Added `EnvelopeSettings` record for structured settings management. Enhanced SQL update logic with `UseSQLExecutor` support. Improved handling of language resolution, reminders, and expiration rules.
This commit is contained in:
@@ -12,8 +12,66 @@ namespace EnvelopeGenerator.Application.Envelopes.Commands;
|
||||
/// </summary>
|
||||
public record CreateEnvelopeCommand : IRequest<EnvelopeDto?>
|
||||
{
|
||||
/// <summary>
|
||||
/// Optionale Umschlag-ID fuer Aktualisierungsvorgaenge.
|
||||
/// </summary>
|
||||
public int? EnvelopeId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Kennung des ausgewaehlten Umschlagtyps (Vorlage).
|
||||
/// </summary>
|
||||
public int? EnvelopeTypeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sprachcode fuer Umschlaginhalt und Benachrichtigungen.
|
||||
/// </summary>
|
||||
public string? Language { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gibt an, ob der Zugriffscode fuer Empfaenger aktiviert ist.
|
||||
/// </summary>
|
||||
public bool? UseAccessCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Zertifizierungstyp fuer den Signaturprozess.
|
||||
/// </summary>
|
||||
public int? CertificationType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Finale E-Mail-Einstellung fuer den Ersteller.
|
||||
/// </summary>
|
||||
public int? FinalEmailToCreator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Finale E-Mail-Einstellung fuer die Empfaenger.
|
||||
/// </summary>
|
||||
public int? FinalEmailToReceivers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gibt an, ob Erinnerungs-E-Mails aktiviert sind.
|
||||
/// </summary>
|
||||
public bool? SendReminderEmails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Anzahl der Tage bis zur ersten Erinnerung.
|
||||
/// </summary>
|
||||
public int? FirstReminderDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Intervall in Tagen zwischen Erinnerungs-E-Mails.
|
||||
/// </summary>
|
||||
public int? ReminderIntervalDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Anzahl der Tage bis zum Ablauf des Umschlags.
|
||||
/// </summary>
|
||||
public int? ExpiresWhenDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Anzahl der Tage vor Ablauf, ab denen gewarnt wird.
|
||||
/// </summary>
|
||||
public int? ExpiresWarningWhenDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Der Titel des Umschlags. Dies ist ein Pflichtfeld.
|
||||
/// </summary>
|
||||
@@ -29,10 +87,19 @@ public record CreateEnvelopeCommand : IRequest<EnvelopeDto?>
|
||||
/// </summary>
|
||||
public bool TFAEnabled { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gibt an, ob der Umschlag nach dem Speichern sofort versendet werden soll.
|
||||
/// </summary>
|
||||
public bool Send { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optionaler PDF-Dokumentinhalt als Base64.
|
||||
/// </summary>
|
||||
public CreateEnvelopeDocumentDto? Document { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Empfaengerliste inklusive optionaler Signaturfeld-Koordinaten.
|
||||
/// </summary>
|
||||
public List<CreateEnvelopeReceiverDto> Receivers { get; init; } = new();
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -33,6 +33,8 @@ public class CreateEnvelopeCommandHandler : IRequestHandler<CreateEnvelopeComman
|
||||
|
||||
private IRepository<EnvelopeReceiver> EnvelopeReceiverRepository => _provider.GetRequiredService<IRepository<EnvelopeReceiver>>();
|
||||
|
||||
private IRepository<EnvelopeType> EnvelopeTypeRepository => _provider.GetRequiredService<IRepository<EnvelopeType>>();
|
||||
|
||||
private IRepository<Receiver> ReceiverRepository => _provider.GetRequiredService<IRepository<Receiver>>();
|
||||
|
||||
private IRepository<DocReceiverElement> DocReceiverElementRepository => _provider.GetRequiredService<IRepository<DocReceiverElement>>();
|
||||
@@ -73,6 +75,7 @@ public class CreateEnvelopeCommandHandler : IRequestHandler<CreateEnvelopeComman
|
||||
var now = DateTime.Now;
|
||||
var title = request.Title?.Trim() ?? string.Empty;
|
||||
var message = request.Message?.Trim() ?? string.Empty;
|
||||
var settings = await ResolveEnvelopeSettingsAsync(request, existing: null, cancel);
|
||||
|
||||
Envelope envelope;
|
||||
if (request.EnvelopeId is int envelopeId)
|
||||
@@ -85,11 +88,27 @@ public class CreateEnvelopeCommandHandler : IRequestHandler<CreateEnvelopeComman
|
||||
if (envelope.UserId != request.UserId)
|
||||
throw new ForbiddenException();
|
||||
|
||||
settings = await ResolveEnvelopeSettingsAsync(request, envelope, cancel);
|
||||
|
||||
await Repository.UpdateAsync(e =>
|
||||
{
|
||||
e.Title = title;
|
||||
e.Message = message;
|
||||
e.TfaEnabled = request.TFAEnabled;
|
||||
e.EnvelopeTypeId = settings.EnvelopeTypeId;
|
||||
e.Language = settings.Language;
|
||||
e.UseAccessCode = settings.UseAccessCode;
|
||||
e.CertificationType = settings.CertificationType;
|
||||
e.FinalEmailToCreator = settings.FinalEmailToCreator;
|
||||
e.FinalEmailToReceivers = settings.FinalEmailToReceivers;
|
||||
e.SendReminderEmails = settings.SendReminderEmails;
|
||||
e.FirstReminderDays = settings.FirstReminderDays;
|
||||
e.ReminderIntervalDays = settings.ReminderIntervalDays;
|
||||
e.ExpiresWhenDays = settings.ExpiresWhenDays;
|
||||
e.ExpiresWarningWhenDays = settings.ExpiresWarningWhenDays;
|
||||
e.ContractType = settings.ContractType;
|
||||
e.ExpiresWhen = settings.ExpiresWhen;
|
||||
e.ExpiresWarningWhen = settings.ExpiresWarningWhen;
|
||||
e.Status = EnvelopeStatus.EnvelopeSaved;
|
||||
e.ChangedWhen = now;
|
||||
}, e => e.Id == envelopeId, cancel);
|
||||
@@ -97,6 +116,20 @@ public class CreateEnvelopeCommandHandler : IRequestHandler<CreateEnvelopeComman
|
||||
envelope.Title = title;
|
||||
envelope.Message = message;
|
||||
envelope.TfaEnabled = request.TFAEnabled;
|
||||
envelope.EnvelopeTypeId = settings.EnvelopeTypeId;
|
||||
envelope.Language = settings.Language;
|
||||
envelope.UseAccessCode = settings.UseAccessCode;
|
||||
envelope.CertificationType = settings.CertificationType;
|
||||
envelope.FinalEmailToCreator = settings.FinalEmailToCreator;
|
||||
envelope.FinalEmailToReceivers = settings.FinalEmailToReceivers;
|
||||
envelope.SendReminderEmails = settings.SendReminderEmails;
|
||||
envelope.FirstReminderDays = settings.FirstReminderDays;
|
||||
envelope.ReminderIntervalDays = settings.ReminderIntervalDays;
|
||||
envelope.ExpiresWhenDays = settings.ExpiresWhenDays;
|
||||
envelope.ExpiresWarningWhenDays = settings.ExpiresWarningWhenDays;
|
||||
envelope.ContractType = settings.ContractType;
|
||||
envelope.ExpiresWhen = settings.ExpiresWhen;
|
||||
envelope.ExpiresWarningWhen = settings.ExpiresWarningWhen;
|
||||
envelope.Status = EnvelopeStatus.EnvelopeSaved;
|
||||
envelope.ChangedWhen = now;
|
||||
}
|
||||
@@ -114,12 +147,61 @@ public class CreateEnvelopeCommandHandler : IRequestHandler<CreateEnvelopeComman
|
||||
AddedWhen = now,
|
||||
ChangedWhen = now,
|
||||
Comment = string.Empty,
|
||||
Language = "de-DE",
|
||||
EnvelopeTypeId = settings.EnvelopeTypeId,
|
||||
Language = settings.Language,
|
||||
TfaEnabled = request.TFAEnabled,
|
||||
UseAccessCode = false,
|
||||
SendReminderEmails = false
|
||||
UseAccessCode = settings.UseAccessCode,
|
||||
CertificationType = settings.CertificationType,
|
||||
FinalEmailToCreator = settings.FinalEmailToCreator,
|
||||
FinalEmailToReceivers = settings.FinalEmailToReceivers,
|
||||
SendReminderEmails = settings.SendReminderEmails,
|
||||
FirstReminderDays = settings.FirstReminderDays,
|
||||
ReminderIntervalDays = settings.ReminderIntervalDays,
|
||||
ExpiresWhenDays = settings.ExpiresWhenDays,
|
||||
ExpiresWarningWhenDays = settings.ExpiresWarningWhenDays,
|
||||
ExpiresWhen = settings.ExpiresWhen,
|
||||
ExpiresWarningWhen = settings.ExpiresWarningWhen,
|
||||
ContractType = settings.ContractType
|
||||
}, cancel);
|
||||
|
||||
if (request.UseSQLExecutor)
|
||||
{
|
||||
await Repository.UpdateAsync(e =>
|
||||
{
|
||||
e.EnvelopeTypeId = settings.EnvelopeTypeId;
|
||||
e.Language = settings.Language;
|
||||
e.UseAccessCode = settings.UseAccessCode;
|
||||
e.CertificationType = settings.CertificationType;
|
||||
e.FinalEmailToCreator = settings.FinalEmailToCreator;
|
||||
e.FinalEmailToReceivers = settings.FinalEmailToReceivers;
|
||||
e.SendReminderEmails = settings.SendReminderEmails;
|
||||
e.FirstReminderDays = settings.FirstReminderDays;
|
||||
e.ReminderIntervalDays = settings.ReminderIntervalDays;
|
||||
e.ExpiresWhenDays = settings.ExpiresWhenDays;
|
||||
e.ExpiresWarningWhenDays = settings.ExpiresWarningWhenDays;
|
||||
e.ExpiresWhen = settings.ExpiresWhen;
|
||||
e.ExpiresWarningWhen = settings.ExpiresWarningWhen;
|
||||
e.ContractType = settings.ContractType;
|
||||
e.ChangedWhen = now;
|
||||
}, e => e.Id == envelope.Id, cancel);
|
||||
|
||||
envelope.EnvelopeTypeId = settings.EnvelopeTypeId;
|
||||
envelope.Language = settings.Language;
|
||||
envelope.UseAccessCode = settings.UseAccessCode;
|
||||
envelope.CertificationType = settings.CertificationType;
|
||||
envelope.FinalEmailToCreator = settings.FinalEmailToCreator;
|
||||
envelope.FinalEmailToReceivers = settings.FinalEmailToReceivers;
|
||||
envelope.SendReminderEmails = settings.SendReminderEmails;
|
||||
envelope.FirstReminderDays = settings.FirstReminderDays;
|
||||
envelope.ReminderIntervalDays = settings.ReminderIntervalDays;
|
||||
envelope.ExpiresWhenDays = settings.ExpiresWhenDays;
|
||||
envelope.ExpiresWarningWhenDays = settings.ExpiresWarningWhenDays;
|
||||
envelope.ExpiresWhen = settings.ExpiresWhen;
|
||||
envelope.ExpiresWarningWhen = settings.ExpiresWarningWhen;
|
||||
envelope.ContractType = settings.ContractType;
|
||||
envelope.ChangedWhen = now;
|
||||
}
|
||||
|
||||
await Mediator.Send(new CreateHistoryCommand
|
||||
{
|
||||
EnvelopeId = envelope.Id,
|
||||
@@ -143,6 +225,105 @@ public class CreateEnvelopeCommandHandler : IRequestHandler<CreateEnvelopeComman
|
||||
return _mapper.Map<EnvelopeDto>(envelope);
|
||||
}
|
||||
|
||||
private async Task<EnvelopeSettings> ResolveEnvelopeSettingsAsync(CreateEnvelopeCommand request, Envelope? existing, CancellationToken cancel)
|
||||
{
|
||||
EnvelopeType? selectedType = null;
|
||||
if (request.EnvelopeTypeId is int envelopeTypeId && envelopeTypeId > 0)
|
||||
{
|
||||
selectedType = await EnvelopeTypeRepository.Query
|
||||
.FirstOrDefaultAsync(t => t.Id == envelopeTypeId, cancel)
|
||||
?? throw new BadRequestException($"Envelope type {envelopeTypeId} not found.");
|
||||
}
|
||||
|
||||
var expiresWhenDays = Math.Max(0,
|
||||
request.ExpiresWhenDays
|
||||
?? selectedType?.ExpiresWhenDays
|
||||
?? existing?.ExpiresWhenDays
|
||||
?? 0);
|
||||
|
||||
var expiresWarningWhenDays = Math.Max(0,
|
||||
request.ExpiresWarningWhenDays
|
||||
?? selectedType?.ExpiresWarningWhenDays
|
||||
?? existing?.ExpiresWarningWhenDays
|
||||
?? 0);
|
||||
|
||||
var useAccessCode = request.UseAccessCode
|
||||
?? selectedType?.UseAccessCode
|
||||
?? existing?.UseAccessCode
|
||||
?? false;
|
||||
|
||||
if (request.TFAEnabled)
|
||||
useAccessCode = true;
|
||||
|
||||
return new EnvelopeSettings(
|
||||
EnvelopeTypeId: request.EnvelopeTypeId ?? existing?.EnvelopeTypeId,
|
||||
Language: ResolveLanguage(request.Language, selectedType?.Language, existing?.Language),
|
||||
UseAccessCode: useAccessCode,
|
||||
CertificationType: request.CertificationType
|
||||
?? (int?)selectedType?.CertificationType
|
||||
?? existing?.CertificationType
|
||||
?? (int)CertificationType.AdvancedElectronicSignature,
|
||||
FinalEmailToCreator: request.FinalEmailToCreator
|
||||
?? (int?)selectedType?.FinalEmailToCreator
|
||||
?? existing?.FinalEmailToCreator
|
||||
?? (int)FinalEmailType.No,
|
||||
FinalEmailToReceivers: request.FinalEmailToReceivers
|
||||
?? (int?)selectedType?.FinalEmailToReceivers
|
||||
?? existing?.FinalEmailToReceivers
|
||||
?? (int)FinalEmailType.No,
|
||||
SendReminderEmails: request.SendReminderEmails
|
||||
?? selectedType?.SendReminderEmails
|
||||
?? existing?.SendReminderEmails
|
||||
?? false,
|
||||
FirstReminderDays: Math.Max(0,
|
||||
request.FirstReminderDays
|
||||
?? selectedType?.FirstReminderDays
|
||||
?? existing?.FirstReminderDays
|
||||
?? 0),
|
||||
ReminderIntervalDays: Math.Max(0,
|
||||
request.ReminderIntervalDays
|
||||
?? selectedType?.ReminderIntervalDays
|
||||
?? existing?.ReminderIntervalDays
|
||||
?? 0),
|
||||
ExpiresWhenDays: expiresWhenDays,
|
||||
ExpiresWarningWhenDays: expiresWarningWhenDays,
|
||||
ExpiresWhen: expiresWhenDays > 0 ? DateTime.Now.AddDays(expiresWhenDays) : null,
|
||||
ExpiresWarningWhen: expiresWarningWhenDays > 0 ? DateTime.Now.AddDays(expiresWarningWhenDays) : null,
|
||||
ContractType: existing?.ContractType
|
||||
?? selectedType?.ContractType
|
||||
?? (int)ContractType.Contract);
|
||||
}
|
||||
|
||||
private static string ResolveLanguage(string? preferred, string? fallback1, string? fallback2)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(preferred))
|
||||
return preferred.Trim();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(fallback1))
|
||||
return fallback1.Trim();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(fallback2))
|
||||
return fallback2.Trim();
|
||||
|
||||
return "de-DE";
|
||||
}
|
||||
|
||||
private sealed record EnvelopeSettings(
|
||||
int? EnvelopeTypeId,
|
||||
string Language,
|
||||
bool UseAccessCode,
|
||||
int CertificationType,
|
||||
int FinalEmailToCreator,
|
||||
int FinalEmailToReceivers,
|
||||
bool SendReminderEmails,
|
||||
int FirstReminderDays,
|
||||
int ReminderIntervalDays,
|
||||
int ExpiresWhenDays,
|
||||
int ExpiresWarningWhenDays,
|
||||
DateTime? ExpiresWhen,
|
||||
DateTime? ExpiresWarningWhen,
|
||||
int ContractType);
|
||||
|
||||
private async Task<string> ResolveSenderReferenceAsync(Envelope envelope, CancellationToken cancel)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(envelope.User?.Email))
|
||||
|
||||
Reference in New Issue
Block a user