From 43d89699a93509c2f85d69b2349f1171d3698eaf Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 18 Feb 2026 12:47:23 +0100 Subject: [PATCH 01/74] Add StatusChangedWhen to DocumentStatus entity Added a nullable DateTime property, StatusChangedWhen, to the DocumentStatus entity. This property is required and mapped to the "STATUS_CHANGED_WHEN" column, enabling tracking of when the document status was last updated. --- EnvelopeGenerator.Domain/Entities/DocumentStatus.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs b/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs index c61bb4cd..3bec79c7 100644 --- a/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs +++ b/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs @@ -35,6 +35,10 @@ namespace EnvelopeGenerator.Domain.Entities [Column("STATUS")] public Constants.DocumentStatus Status { get; set; } + [Required] + [Column("STATUS_CHANGED_WHEN", TypeName = "datetime")] + public DateTime? StatusChangedWhen { get; set; } + [Required] [Column("ADDED_WHEN", TypeName = "datetime")] public DateTime AddedWhen { get; set; } From 711f7d12e8e436e2889e21f0e3217fe327a2615d Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 18 Feb 2026 12:48:11 +0100 Subject: [PATCH 02/74] Update MappingProfile for improved DocumentStatus mapping Enhanced mapping logic in MappingProfile: - Set Status to Created or Signed in CreateDocStatusCommand mapping based on Value property. - Automatically set StatusChangedWhen to current UTC time in UpdateDocStatusCommand mapping. --- EnvelopeGenerator.Application/DocStatus/MappingProfile.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/EnvelopeGenerator.Application/DocStatus/MappingProfile.cs b/EnvelopeGenerator.Application/DocStatus/MappingProfile.cs index e1474d7e..bfa86dd5 100644 --- a/EnvelopeGenerator.Application/DocStatus/MappingProfile.cs +++ b/EnvelopeGenerator.Application/DocStatus/MappingProfile.cs @@ -18,11 +18,16 @@ public class MappingProfile : Profile CreateMap() .ForMember(dest => dest.Envelope, opt => opt.Ignore()) .ForMember(dest => dest.Receiver, opt => opt.Ignore()) + .ForMember(dest => dest.Status, opt => opt.MapFrom( + src => src.Value == null + ? Domain.Constants.DocumentStatus.Created + : Domain.Constants.DocumentStatus.Signed)) .MapAddedWhen(); CreateMap() .ForMember(dest => dest.Envelope, opt => opt.Ignore()) .ForMember(dest => dest.Receiver, opt => opt.Ignore()) + .ForMember(dest => dest.StatusChangedWhen, opt => opt.MapFrom(src => DateTime.UtcNow)) .MapChangedWhen(); } } \ No newline at end of file From 1d0c758e00ff67e106060a7e2a61b538ce5d5935 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 18 Feb 2026 12:48:44 +0100 Subject: [PATCH 03/74] Refactor CreateDocStatusCommand structure and properties Refactored CreateDocStatusCommand to remove inheritance from ModifyDocStatusCommandBase and define its own properties. Added EnvelopeId, ReceiverId, and Value properties. Removed the AddedWhen property. The class now directly implements IRequest. --- .../DocStatus/Commands/CreateDocStatusCommand.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/EnvelopeGenerator.Application/DocStatus/Commands/CreateDocStatusCommand.cs b/EnvelopeGenerator.Application/DocStatus/Commands/CreateDocStatusCommand.cs index 01b5d0a9..e8f78240 100644 --- a/EnvelopeGenerator.Application/DocStatus/Commands/CreateDocStatusCommand.cs +++ b/EnvelopeGenerator.Application/DocStatus/Commands/CreateDocStatusCommand.cs @@ -8,12 +8,22 @@ namespace EnvelopeGenerator.Application.DocStatus.Commands; /// /// /// -public record CreateDocStatusCommand : ModifyDocStatusCommandBase, IRequest +public record CreateDocStatusCommand : IRequest { /// - /// Gets timestamp when this record was added. Returns the StatusChangedWhen value. + /// /// - public DateTime AddedWhen => StatusChangedWhen; + public int EnvelopeId { get; set; } + + /// + /// + /// + public int ReceiverId { get; set; } + + /// + /// Gets or sets the display value associated with the status. + /// + public string? Value { get; set; } } /// From 01f3335238b45563b14f6340ee4c25fa95ef2c05 Mon Sep 17 00:00:00 2001 From: TekH Date: Thu, 19 Feb 2026 14:32:35 +0100 Subject: [PATCH 04/74] Refactor ModifyDocStatusCommandBase properties Replaced computed EnvelopeId and ReceiverId with virtual settable properties for greater flexibility. Removed Status, Receiver, and StatusChangedWhen properties. Made Value property virtual and cleaned up related code and comments. --- .../Commands/ModifyDocStatusCommandBase.cs | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/EnvelopeGenerator.Application/DocStatus/Commands/ModifyDocStatusCommandBase.cs b/EnvelopeGenerator.Application/DocStatus/Commands/ModifyDocStatusCommandBase.cs index 259cb500..683e57e8 100644 --- a/EnvelopeGenerator.Application/DocStatus/Commands/ModifyDocStatusCommandBase.cs +++ b/EnvelopeGenerator.Application/DocStatus/Commands/ModifyDocStatusCommandBase.cs @@ -1,5 +1,4 @@ using EnvelopeGenerator.Application.Common.Query; -using EnvelopeGenerator.Domain.Constants; namespace EnvelopeGenerator.Application.DocStatus.Commands; @@ -11,32 +10,17 @@ public record ModifyDocStatusCommandBase : EnvelopeReceiverQueryBase /// /// /// - public int? EnvelopeId => Envelope.Id; + public virtual int EnvelopeId { get; set; } /// /// /// - public int? ReceiverId => Receiver.Id; - - /// - /// - /// - public override ReceiverQueryBase Receiver { get => base.Receiver; set => base.Receiver = value; } - - /// - /// Gets the current status code. - /// - public DocumentStatus Status => Value is null ? DocumentStatus.Created : DocumentStatus.Signed; + public virtual int ReceiverId { get; set; } /// /// Gets or sets the display value associated with the status. /// - public string? Value { get; set; } - - /// - /// Gets timestamp when this record was added. - /// - public DateTime StatusChangedWhen { get; } = DateTime.Now; + public virtual string? Value { get; set; } /// /// Maps the current command to a new instance of the specified type. From 8258d9f43fe0ca3485794bba9dbef4bad4a2a7e8 Mon Sep 17 00:00:00 2001 From: TekH Date: Thu, 19 Feb 2026 14:32:45 +0100 Subject: [PATCH 05/74] Refactor UpdateDocStatusCommand to use generic base class Refactored UpdateDocStatusCommand to inherit from a generic UpdateCommand base class with a new DocStatusUpdateDto record. Added explicit EnvelopeId, ReceiverId, and Value properties. Removed ChangedWhen property and implemented BuildQueryExpression for querying. Updated using directives and improved XML documentation. --- .../Commands/UpdateDocStatusCommand.cs | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/EnvelopeGenerator.Application/DocStatus/Commands/UpdateDocStatusCommand.cs b/EnvelopeGenerator.Application/DocStatus/Commands/UpdateDocStatusCommand.cs index f6c3b57f..dcdd8b18 100644 --- a/EnvelopeGenerator.Application/DocStatus/Commands/UpdateDocStatusCommand.cs +++ b/EnvelopeGenerator.Application/DocStatus/Commands/UpdateDocStatusCommand.cs @@ -1,14 +1,41 @@ -using EnvelopeGenerator.Domain; +using EnvelopeGenerator.Application.Common.Commands; +using EnvelopeGenerator.Domain.Entities; +using System.Linq.Expressions; namespace EnvelopeGenerator.Application.DocStatus.Commands; /// /// /// -public record UpdateDocStatusCommand : ModifyDocStatusCommandBase +/// +public record DocStatusUpdateDto(string? Value); + +/// +/// +/// +public record UpdateDocStatusCommand : UpdateCommand { /// - /// Gets timestamp when this record was added. Returns the StatusChangedWhen value. + /// /// - public DateTime? ChangedWhen => StatusChangedWhen; + public int EnvelopeId { get; set; } + + /// + /// + /// + public int ReceiverId { get; set; } + + /// + /// Gets or sets the display value associated with the status. + /// + public string? Value { get; set; } + + /// + /// + /// + /// + public override Expression> BuildQueryExpression() + { + return ds => ds.EnvelopeId == EnvelopeId && ds.ReceiverId == ReceiverId; + } } \ No newline at end of file From 0d78e9b8f5073ae0932580d8a2a18c98f475b19f Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 23 Feb 2026 09:15:50 +0100 Subject: [PATCH 06/74] Refactor TestEnvelopeController to use MediatR Replaced direct IEnvelopeService usage with MediatR in TestEnvelopeController. Updated GetAll to use ReadEnvelopeQuery via MediatR, removed legacy service logic, and simplified DecodeEnvelopeReceiverId. Removed unused usings, base class inheritance, and obsolete methods. --- .../Test/TestEnvelopeController.cs | 62 ++++++------------- 1 file changed, 19 insertions(+), 43 deletions(-) diff --git a/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeController.cs b/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeController.cs index a4a5058b..011af296 100644 --- a/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeController.cs +++ b/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeController.cs @@ -1,56 +1,32 @@ -using EnvelopeGenerator.Domain.Entities; -using Microsoft.AspNetCore.Mvc; -using EnvelopeGenerator.Application.Common.Dto; +using Microsoft.AspNetCore.Mvc; using EnvelopeGenerator.Application.Common.Extensions; -using EnvelopeGenerator.Application.Common.Interfaces.Services; +using MediatR; +using EnvelopeGenerator.Application.Envelopes.Queries; namespace EnvelopeGenerator.Web.Controllers.Test; [Obsolete("Use MediatR")] -public class TestEnvelopeController : TestControllerBase +public class TestEnvelopeController : ControllerBase { - public TestEnvelopeController(ILogger logger, IEnvelopeService service) : base(logger, service) - { - } + private readonly IMediator _mediator; - [NonAction] - public override Task GetAll() => base.GetAll(); + /// + /// + /// + /// + public TestEnvelopeController(IMediator mediator) + { + _mediator = mediator; + } [HttpGet] - public async Task GetAll([FromQuery] string? envelopeKey = default, [FromQuery] bool withDocuments = false, [FromQuery] bool withHistory = false, [FromQuery] bool withDocumentReceiverElement = false, [FromQuery] bool withUser = false, [FromQuery] bool withAll = true) - { - if (envelopeKey is not null) - { - (var uuid, var signature) = envelopeKey.DecodeEnvelopeReceiverId(); - if (uuid is null) - return BadRequest("UUID is null"); - var envlopeServiceResult = await _service.ReadByUuidAsync( - uuid: uuid, - withDocuments: withDocuments, withHistory: withHistory, withDocumentReceiverElement: withDocumentReceiverElement, withUser: withUser, withAll: withAll); - - if (envlopeServiceResult.IsSuccess) - { - return Ok(envlopeServiceResult.Data); - } - return NotFound(); - } - - var result = await _service.ReadAllWithAsync(documents: withDocuments, history: withHistory); - if (result.IsSuccess) - { - return Ok(result); - } - return NotFound(result); - } + public async Task GetAll([FromQuery] ReadEnvelopeQuery query, CancellationToken cancel) => Ok(await _mediator.Send(query, cancel)); [HttpGet("decode")] - public IActionResult DecodeEnvelopeReceiverId(string envelopeReceiverId, int type = 0) + public IActionResult DecodeEnvelopeReceiverId(string envelopeReceiverId, int type = 0) => type switch { - return type switch - { - 1 => Ok(envelopeReceiverId.GetEnvelopeUuid()), - 2 => Ok(envelopeReceiverId.GetReceiverSignature()), - _ => Ok(envelopeReceiverId.DecodeEnvelopeReceiverId()), - }; - } + 1 => Ok(envelopeReceiverId.GetEnvelopeUuid()), + 2 => Ok(envelopeReceiverId.GetReceiverSignature()), + _ => Ok(envelopeReceiverId.DecodeEnvelopeReceiverId()), + }; } \ No newline at end of file From f5f137396e0e61cb093e80313c1f7a8f359a465c Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 23 Feb 2026 09:38:13 +0100 Subject: [PATCH 07/74] Rename ChangedWhen to ActionDate; add wrapper for compatibility Renamed the ChangedWhen property to ActionDate in the History entity, preserving the database mapping. Added a ChangedWhen property as a wrapper around ActionDate to maintain backward compatibility with existing code. --- EnvelopeGenerator.Domain/Entities/History.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/EnvelopeGenerator.Domain/Entities/History.cs b/EnvelopeGenerator.Domain/Entities/History.cs index aae01cce..f52700a5 100644 --- a/EnvelopeGenerator.Domain/Entities/History.cs +++ b/EnvelopeGenerator.Domain/Entities/History.cs @@ -35,8 +35,10 @@ namespace EnvelopeGenerator.Domain.Entities public DateTime AddedWhen { get; set; } [Column("ACTION_DATE", TypeName = "datetime")] - public DateTime? ChangedWhen { get; set; } - + public DateTime? ActionDate { get; set; } + + public DateTime? ChangedWhen { get => ActionDate; set => ActionDate = value; } + [Column("COMMENT", TypeName = "nvarchar(max)")] public string #if nullable From 511fad3950db2733d573353aaae47d732684d7cc Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 23 Feb 2026 09:58:07 +0100 Subject: [PATCH 08/74] Remove try-catch from Button1/2_Click event handlers Refactored Button1_Click and Button2_Click to eliminate local try-catch blocks, allowing exceptions to propagate. Cleaned up redundant code and improved clarity by moving variable declarations outside of the previous try blocks. Core logic remains unchanged. --- EnvelopeGenerator.BBTests/frmFinalizePDF.vb | 65 +++++++-------------- 1 file changed, 22 insertions(+), 43 deletions(-) diff --git a/EnvelopeGenerator.BBTests/frmFinalizePDF.vb b/EnvelopeGenerator.BBTests/frmFinalizePDF.vb index e6466c73..691a60ca 100644 --- a/EnvelopeGenerator.BBTests/frmFinalizePDF.vb +++ b/EnvelopeGenerator.BBTests/frmFinalizePDF.vb @@ -7,7 +7,6 @@ Imports GdPicture14 Imports Newtonsoft.Json.Linq Imports EnvelopeGenerator.Infrastructure Imports Microsoft.EntityFrameworkCore -Imports System.Text Imports DigitalData.Core.Abstractions Public Class frmFinalizePDF @@ -93,56 +92,36 @@ Public Class frmFinalizePDF End Function Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click - Try + Dim oTable = LoadAnnotationDataForEnvelope() + Dim oJsonList = oTable.Rows. + Cast(Of DataRow). + Select(Function(r As DataRow) r.Item("VALUE").ToString()). + ToList() - Dim oTable = LoadAnnotationDataForEnvelope() - Dim oJsonList = oTable.Rows. - Cast(Of DataRow). - Select(Function(r As DataRow) r.Item("VALUE").ToString()). - ToList() + Dim envelopeId As Integer = CInt(txtEnvelope.Text) + Dim oBuffer As Byte() = ReadEnvelope(envelopeId) + Dim oNewBuffer = PDFBurner.BurnAnnotsToPDF(oBuffer, oJsonList, envelopeId) + Dim desktopPath As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + Dim oNewPath = Path.Combine(desktopPath, $"E{txtEnvelope.Text}R{txtReceiver.Text}.burned.pdf") - Dim envelopeId As Integer = CInt(txtEnvelope.Text) - Dim oBuffer As Byte() = ReadEnvelope(envelopeId) - Dim oNewBuffer = PDFBurner.BurnAnnotsToPDF(oBuffer, oJsonList, envelopeId) - Dim desktopPath As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) - Dim oNewPath = Path.Combine(desktopPath, $"E{txtEnvelope.Text}R{txtReceiver.Text}.burned.pdf") - - File.WriteAllBytes(oNewPath, oNewBuffer) - - Process.Start(oNewPath) - Catch ex As Exception - Dim exMsg As StringBuilder = New StringBuilder(ex.Message).AppendLine() - - Dim innerEx = ex.InnerException - While (innerEx IsNot Nothing) - exMsg.AppendLine(innerEx.Message) - innerEx = innerEx.InnerException - End While - - MsgBox(exMsg.ToString(), MsgBoxStyle.Critical) - End Try + File.WriteAllBytes(oNewPath, oNewBuffer) + Process.Start(oNewPath) End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click - Try - Dim oTable = LoadAnnotationDataForEnvelope() - Dim oJsonList = oTable.Rows. - Cast(Of DataRow). - Select(Function(r As DataRow) r.Item("VALUE").ToString()). - Select(Function(s As String) JObject.Parse(s)). - ToList() + Dim oTable = LoadAnnotationDataForEnvelope() + Dim oJsonList = oTable.Rows. + Cast(Of DataRow). + Select(Function(r As DataRow) r.Item("VALUE").ToString()). + Select(Function(s As String) JObject.Parse(s)). + ToList() - Dim oJObject1 = oJsonList.First() - Dim oJObject2 = oJsonList.ElementAt(1) + Dim oJObject1 = oJsonList.First() + Dim oJObject2 = oJsonList.ElementAt(1) - oJObject1.Merge(oJObject2) + oJObject1.Merge(oJObject2) - txtResult.Text = oJObject1.ToString() - - - Catch ex As Exception - MsgBox(ex.Message, MsgBoxStyle.Critical) - End Try + txtResult.Text = oJObject1.ToString() End Sub End Class \ No newline at end of file From 3b3330bd5468ffc03961c9c3170dabee7860f543 Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 23 Feb 2026 10:04:34 +0100 Subject: [PATCH 09/74] Enhance SQL connection security with encryption options Added Encrypt=True and TrustServerCertificate=True to the SQL Server connection string to ensure encrypted connections and allow trusting the server certificate, improving overall connection security. --- EnvelopeGenerator.BBTests/frmFinalizePDF.vb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EnvelopeGenerator.BBTests/frmFinalizePDF.vb b/EnvelopeGenerator.BBTests/frmFinalizePDF.vb index 691a60ca..56122a17 100644 --- a/EnvelopeGenerator.BBTests/frmFinalizePDF.vb +++ b/EnvelopeGenerator.BBTests/frmFinalizePDF.vb @@ -10,7 +10,7 @@ Imports Microsoft.EntityFrameworkCore Imports DigitalData.Core.Abstractions Public Class frmFinalizePDF - Private Const CONNECTIONSTRING = "Server=sDD-VMP04-SQL17\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=+bk8oAbbQP1AzoHtvZUbd+Mbok2f8Fl4miEx1qssJ5yEaEWoQJ9prg4L14fURpPnqi1WMNs9fE4=;" + Private Const CONNECTIONSTRING = "Server=sDD-VMP04-SQL17\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=+bk8oAbbQP1AzoHtvZUbd+Mbok2f8Fl4miEx1qssJ5yEaEWoQJ9prg4L14fURpPnqi1WMNs9fE4=;" + "Encrypt=True;TrustServerCertificate=True;" Private Database As MSSQLServer Private LogConfig As LogConfig From 689a1b355aca427f7a464fd6bc5c63cea60f8d9c Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 23 Feb 2026 10:54:32 +0100 Subject: [PATCH 10/74] Remove EnvelopeGenerator.WorkerService project Deleted the EnvelopeGenerator.WorkerService project and all related files, including configuration, job scheduling, and temp file management. Removed all references to the project from the solution file. This eliminates the background worker service component from the solution. --- .../Configuration/WorkerSettings.cs | 14 ---- .../EnvelopeGenerator.WorkerService.csproj | 22 ------ EnvelopeGenerator.WorkerService/Program.cs | 67 ----------------- .../Properties/launchSettings.json | 12 --- .../Services/TempFileManager.cs | 74 ------------------- EnvelopeGenerator.WorkerService/Worker.cs | 71 ------------------ .../appsettings.Development.json | 30 -------- .../appsettings.json | 21 ------ EnvelopeGenerator.sln | 7 -- 9 files changed, 318 deletions(-) delete mode 100644 EnvelopeGenerator.WorkerService/Configuration/WorkerSettings.cs delete mode 100644 EnvelopeGenerator.WorkerService/EnvelopeGenerator.WorkerService.csproj delete mode 100644 EnvelopeGenerator.WorkerService/Program.cs delete mode 100644 EnvelopeGenerator.WorkerService/Properties/launchSettings.json delete mode 100644 EnvelopeGenerator.WorkerService/Services/TempFileManager.cs delete mode 100644 EnvelopeGenerator.WorkerService/Worker.cs delete mode 100644 EnvelopeGenerator.WorkerService/appsettings.Development.json delete mode 100644 EnvelopeGenerator.WorkerService/appsettings.json diff --git a/EnvelopeGenerator.WorkerService/Configuration/WorkerSettings.cs b/EnvelopeGenerator.WorkerService/Configuration/WorkerSettings.cs deleted file mode 100644 index dc4d2c91..00000000 --- a/EnvelopeGenerator.WorkerService/Configuration/WorkerSettings.cs +++ /dev/null @@ -1,14 +0,0 @@ -using EnvelopeGenerator.Jobs.FinalizeDocument; - -namespace EnvelopeGenerator.WorkerService.Configuration; - -public sealed class WorkerSettings -{ - public string ConnectionString { get; set; } = string.Empty; - - public bool Debug { get; set; } - - public int IntervalMinutes { get; set; } = 1; - - public PDFBurnerParams PdfBurner { get; set; } = new(); -} diff --git a/EnvelopeGenerator.WorkerService/EnvelopeGenerator.WorkerService.csproj b/EnvelopeGenerator.WorkerService/EnvelopeGenerator.WorkerService.csproj deleted file mode 100644 index aec7186d..00000000 --- a/EnvelopeGenerator.WorkerService/EnvelopeGenerator.WorkerService.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - net8.0 - enable - enable - dotnet-EnvelopeGenerator.WorkerService-0636abb8-6085-477d-9f56-1a9787e84dde - - - - - - - - - - - - - - - diff --git a/EnvelopeGenerator.WorkerService/Program.cs b/EnvelopeGenerator.WorkerService/Program.cs deleted file mode 100644 index 03e8e055..00000000 --- a/EnvelopeGenerator.WorkerService/Program.cs +++ /dev/null @@ -1,67 +0,0 @@ -using EnvelopeGenerator.Domain.Constants; -using EnvelopeGenerator.Jobs.APIBackendJobs; -using EnvelopeGenerator.Jobs.FinalizeDocument; -using EnvelopeGenerator.WorkerService; -using EnvelopeGenerator.WorkerService.Configuration; -using EnvelopeGenerator.WorkerService.Services; -using Quartz; - -var builder = Host.CreateApplicationBuilder(args); - -builder.Services.Configure(builder.Configuration.GetSection("WorkerSettings")); - -builder.Services.AddSingleton(); -builder.Services.AddSingleton(provider => -{ - var settings = provider.GetRequiredService>().Value; - var logger = provider.GetRequiredService>(); - return new PDFBurner(logger, settings.PdfBurner); -}); -builder.Services.AddSingleton(); -builder.Services.AddSingleton(); - -builder.Services.AddQuartz(q => -{ - q.UseMicrosoftDependencyInjectionJobFactory(); - q.UseDefaultThreadPool(tp => tp.MaxConcurrency = 5); - - var settings = new WorkerSettings(); - builder.Configuration.GetSection("WorkerSettings").Bind(settings); - var intervalMinutes = Math.Max(1, settings.IntervalMinutes); - - var finalizeJobKey = new JobKey("FinalizeDocumentJob"); - q.AddJob(opts => opts - .WithIdentity(finalizeJobKey) - .UsingJobData(Value.DATABASE, settings.ConnectionString)); - - q.AddTrigger(opts => opts - .ForJob(finalizeJobKey) - .WithIdentity("FinalizeDocumentJob-trigger") - .StartNow() - .WithSimpleSchedule(x => x - .WithIntervalInMinutes(intervalMinutes) - .RepeatForever())); - - var apiJobKey = new JobKey("APIEnvelopeJob"); - q.AddJob(opts => opts - .WithIdentity(apiJobKey) - .UsingJobData(Value.DATABASE, settings.ConnectionString)); - - q.AddTrigger(opts => opts - .ForJob(apiJobKey) - .WithIdentity("APIEnvelopeJob-trigger") - .StartNow() - .WithSimpleSchedule(x => x - .WithIntervalInMinutes(intervalMinutes) - .RepeatForever())); -}); - -builder.Services.AddQuartzHostedService(options => -{ - options.WaitForJobsToComplete = true; -}); - -builder.Services.AddHostedService(); - -var host = builder.Build(); -host.Run(); diff --git a/EnvelopeGenerator.WorkerService/Properties/launchSettings.json b/EnvelopeGenerator.WorkerService/Properties/launchSettings.json deleted file mode 100644 index ddb5ece8..00000000 --- a/EnvelopeGenerator.WorkerService/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "http://json.schemastore.org/launchsettings.json", - "profiles": { - "EnvelopeGenerator.WorkerService": { - "commandName": "Project", - "dotnetRunMessages": true, - "environmentVariables": { - "DOTNET_ENVIRONMENT": "Development" - } - } - } -} diff --git a/EnvelopeGenerator.WorkerService/Services/TempFileManager.cs b/EnvelopeGenerator.WorkerService/Services/TempFileManager.cs deleted file mode 100644 index f98e1c09..00000000 --- a/EnvelopeGenerator.WorkerService/Services/TempFileManager.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.IO; -using Microsoft.Extensions.Logging; - -namespace EnvelopeGenerator.WorkerService.Services; - -public sealed class TempFileManager -{ - private readonly ILogger _logger; - - public TempFileManager(ILogger logger) - { - _logger = logger; - TempPath = Path.Combine(Path.GetTempPath(), "EnvelopeGenerator"); - } - - public string TempPath { get; } - - public Task CreateAsync(CancellationToken cancellationToken = default) - { - try - { - if (!Directory.Exists(TempPath)) - { - Directory.CreateDirectory(TempPath); - _logger.LogDebug("Created temp folder {TempPath}", TempPath); - } - else - { - CleanUpFiles(); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to create temp folder {TempPath}", TempPath); - throw; - } - - return Task.CompletedTask; - } - - public Task CleanupAsync(CancellationToken cancellationToken = default) - { - try - { - if (Directory.Exists(TempPath)) - { - _logger.LogDebug("Deleting temp folder {TempPath}", TempPath); - Directory.Delete(TempPath, recursive: true); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to clean up temp folder {TempPath}", TempPath); - } - - return Task.CompletedTask; - } - - private void CleanUpFiles() - { - foreach (var file in Directory.GetFiles(TempPath)) - { - try - { - _logger.LogDebug("Deleting temp file {File}", file); - File.Delete(file); - } - catch (Exception ex) - { - _logger.LogWarning(ex, "Failed to delete temp file {File}", file); - } - } - } -} diff --git a/EnvelopeGenerator.WorkerService/Worker.cs b/EnvelopeGenerator.WorkerService/Worker.cs deleted file mode 100644 index d88c3e63..00000000 --- a/EnvelopeGenerator.WorkerService/Worker.cs +++ /dev/null @@ -1,71 +0,0 @@ -using EnvelopeGenerator.WorkerService.Configuration; -using EnvelopeGenerator.WorkerService.Services; -using Microsoft.Data.SqlClient; -using Microsoft.Extensions.Options; - -namespace EnvelopeGenerator.WorkerService; - -public class Worker : BackgroundService -{ - private readonly ILogger _logger; - private readonly WorkerSettings _settings; - private readonly TempFileManager _tempFiles; - - public Worker( - ILogger logger, - IOptions settings, - TempFileManager tempFiles) - { - _logger = logger; - _settings = settings.Value; - _tempFiles = tempFiles; - } - - public override async Task StartAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Starting EnvelopeGenerator worker..."); - _logger.LogInformation("Debug mode: {Debug}", _settings.Debug); - - ValidateConfiguration(); - await EnsureDatabaseConnectionAsync(cancellationToken); - await _tempFiles.CreateAsync(cancellationToken); - - await base.StartAsync(cancellationToken); - } - - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - _logger.LogInformation("EnvelopeGenerator worker is running. Jobs are scheduled every {Interval} minute(s).", Math.Max(1, _settings.IntervalMinutes)); - await Task.Delay(Timeout.Infinite, stoppingToken); - } - - public override async Task StopAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Stopping EnvelopeGenerator worker..."); - await _tempFiles.CleanupAsync(cancellationToken); - await base.StopAsync(cancellationToken); - } - - private void ValidateConfiguration() - { - if (string.IsNullOrWhiteSpace(_settings.ConnectionString)) - { - throw new InvalidOperationException("Connection string cannot be empty. Configure 'WorkerSettings:ConnectionString'."); - } - } - - private async Task EnsureDatabaseConnectionAsync(CancellationToken cancellationToken) - { - try - { - await using var connection = new SqlConnection(_settings.ConnectionString); - await connection.OpenAsync(cancellationToken); - _logger.LogInformation("Database connection established successfully."); - } - catch (Exception ex) - { - _logger.LogError(ex, "Database connection could not be established."); - throw; - } - } -} diff --git a/EnvelopeGenerator.WorkerService/appsettings.Development.json b/EnvelopeGenerator.WorkerService/appsettings.Development.json deleted file mode 100644 index cfa751f3..00000000 --- a/EnvelopeGenerator.WorkerService/appsettings.Development.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Debug", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "WorkerSettings": { - "ConnectionString": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;", - "Debug": true, - "IntervalMinutes": 1, - "PdfBurner": { - "IgnoredLabels": [ - "Date", - "Datum", - "ZIP", - "PLZ", - "Place", - "Ort", - "Position", - "Stellung" - ], - "TopMargin": 0.1, - "YOffset": -0.3, - "FontName": "Arial", - "FontSize": 8, - "FontStyle": "Italic" - } - } -} diff --git a/EnvelopeGenerator.WorkerService/appsettings.json b/EnvelopeGenerator.WorkerService/appsettings.json deleted file mode 100644 index abd01790..00000000 --- a/EnvelopeGenerator.WorkerService/appsettings.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "WorkerSettings": { - "ConnectionString": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;", - "Debug": false, - "IntervalMinutes": 1, - "PdfBurner": { - "IgnoredLabels": ["Date", "Datum", "ZIP", "PLZ", "Place", "Ort", "Position", "Stellung"], - "TopMargin": 0.1, - "YOffset": -0.3, - "FontName": "Arial", - "FontSize": 8, - "FontStyle": "Italic" - } - } -} diff --git a/EnvelopeGenerator.sln b/EnvelopeGenerator.sln index 1b4e2a82..fe942d58 100644 --- a/EnvelopeGenerator.sln +++ b/EnvelopeGenerator.sln @@ -35,8 +35,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Tests", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Jobs", "EnvelopeGenerator.Jobs\EnvelopeGenerator.Jobs.csproj", "{3D0514EA-2681-4B13-AD71-35CC6363DBD7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.WorkerService", "EnvelopeGenerator.WorkerService\EnvelopeGenerator.WorkerService.csproj", "{E3676510-7030-4E85-86E1-51E483E2A3B6}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.API", "EnvelopeGenerator.API\EnvelopeGenerator.API.csproj", "{EC768913-6270-14F4-1DD3-69C87A659462}" EndProject Global @@ -89,10 +87,6 @@ Global {3D0514EA-2681-4B13-AD71-35CC6363DBD7}.Debug|Any CPU.Build.0 = Debug|Any CPU {3D0514EA-2681-4B13-AD71-35CC6363DBD7}.Release|Any CPU.ActiveCfg = Release|Any CPU {3D0514EA-2681-4B13-AD71-35CC6363DBD7}.Release|Any CPU.Build.0 = Release|Any CPU - {E3676510-7030-4E85-86E1-51E483E2A3B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E3676510-7030-4E85-86E1-51E483E2A3B6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E3676510-7030-4E85-86E1-51E483E2A3B6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E3676510-7030-4E85-86E1-51E483E2A3B6}.Release|Any CPU.Build.0 = Release|Any CPU {EC768913-6270-14F4-1DD3-69C87A659462}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EC768913-6270-14F4-1DD3-69C87A659462}.Debug|Any CPU.Build.0 = Debug|Any CPU {EC768913-6270-14F4-1DD3-69C87A659462}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -116,7 +110,6 @@ Global {211619F5-AE25-4BA5-A552-BACAFE0632D3} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB} {224C4845-1CDE-22B7-F3A9-1FF9297F70E8} = {0CBC2432-A561-4440-89BC-671B66A24146} {3D0514EA-2681-4B13-AD71-35CC6363DBD7} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB} - {E3676510-7030-4E85-86E1-51E483E2A3B6} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB} {EC768913-6270-14F4-1DD3-69C87A659462} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution From 898097cdb55fe4e3e7d770233d5b55aea8a43691 Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 23 Feb 2026 10:56:03 +0100 Subject: [PATCH 11/74] Remove EnvelopeGenerator.Jobs project from solution Deleted the EnvelopeGenerator.Jobs project and all its source files. Also removed all references to this project from the solution file, including project entries and build configurations. This cleans up the repository by eliminating unused or deprecated job-related code. --- .../EnvelopeGenerator.Jobs.csproj | 26 -- .../Jobs/APIBackendJobs/APIEnvelopeJob.cs | 151 ---------- .../Jobs/DataRowExtensions.cs | 30 -- .../FinalizeDocumentExceptions.cs | 28 -- .../FinalizeDocument/FinalizeDocumentJob.cs | 229 --------------- .../Jobs/FinalizeDocument/PDFBurner.cs | 277 ------------------ .../Jobs/FinalizeDocument/PDFBurnerParams.cs | 19 -- .../Jobs/FinalizeDocument/PDFMerger.cs | 46 --- .../Jobs/FinalizeDocument/ReportCreator.cs | 91 ------ .../Jobs/FinalizeDocument/ReportItem.cs | 19 -- .../Jobs/FinalizeDocument/ReportSource.cs | 8 - EnvelopeGenerator.sln | 7 - 12 files changed, 931 deletions(-) delete mode 100644 EnvelopeGenerator.Jobs/EnvelopeGenerator.Jobs.csproj delete mode 100644 EnvelopeGenerator.Jobs/Jobs/APIBackendJobs/APIEnvelopeJob.cs delete mode 100644 EnvelopeGenerator.Jobs/Jobs/DataRowExtensions.cs delete mode 100644 EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentExceptions.cs delete mode 100644 EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentJob.cs delete mode 100644 EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurner.cs delete mode 100644 EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurnerParams.cs delete mode 100644 EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFMerger.cs delete mode 100644 EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportCreator.cs delete mode 100644 EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportItem.cs delete mode 100644 EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportSource.cs diff --git a/EnvelopeGenerator.Jobs/EnvelopeGenerator.Jobs.csproj b/EnvelopeGenerator.Jobs/EnvelopeGenerator.Jobs.csproj deleted file mode 100644 index 1779441d..00000000 --- a/EnvelopeGenerator.Jobs/EnvelopeGenerator.Jobs.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - net8.0 - enable - enable - - - - - - - - - - - - - - - - - - - - diff --git a/EnvelopeGenerator.Jobs/Jobs/APIBackendJobs/APIEnvelopeJob.cs b/EnvelopeGenerator.Jobs/Jobs/APIBackendJobs/APIEnvelopeJob.cs deleted file mode 100644 index 7f8fac2b..00000000 --- a/EnvelopeGenerator.Jobs/Jobs/APIBackendJobs/APIEnvelopeJob.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System.Collections.Generic; -using System.Data; -using System.Threading.Tasks; -using EnvelopeGenerator.Domain.Constants; -using Microsoft.Data.SqlClient; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Quartz; - -namespace EnvelopeGenerator.Jobs.APIBackendJobs; - -public class APIEnvelopeJob(ILogger? logger = null) : IJob -{ - private readonly ILogger _logger = logger ?? NullLogger.Instance; - - public async Task Execute(IJobExecutionContext context) - { - var jobId = context.JobDetail.Key.ToString(); - _logger.LogDebug("API Envelopes - Starting job {JobId}", jobId); - - try - { - var connectionString = context.MergedJobDataMap.GetString(Value.DATABASE); - if (string.IsNullOrWhiteSpace(connectionString)) - { - _logger.LogWarning("API Envelopes - Connection string missing"); - return; - } - - await using var connection = new SqlConnection(connectionString); - await connection.OpenAsync(context.CancellationToken); - - await ProcessInvitationsAsync(connection, context.CancellationToken); - await ProcessWithdrawnAsync(connection, context.CancellationToken); - - _logger.LogDebug("API Envelopes - Completed job {JobId} successfully", jobId); - } - catch (System.Exception ex) - { - _logger.LogError(ex, "API Envelopes job failed"); - } - finally - { - _logger.LogDebug("API Envelopes execution for {JobId} ended", jobId); - } - } - - private async Task ProcessInvitationsAsync(SqlConnection connection, System.Threading.CancellationToken cancellationToken) - { - const string sql = "SELECT GUID FROM TBSIG_ENVELOPE WHERE SOURCE = 'API' AND STATUS = 1003 ORDER BY GUID"; - var envelopeIds = new List(); - - await using (var command = new SqlCommand(sql, connection)) - await using (var reader = await command.ExecuteReaderAsync(cancellationToken)) - { - while (await reader.ReadAsync(cancellationToken)) - { - if (reader[0] is int id) - { - envelopeIds.Add(id); - } - } - } - - if (envelopeIds.Count == 0) - { - _logger.LogDebug("SendInvMail - No envelopes found"); - return; - } - - _logger.LogInformation("SendInvMail - Found {Count} envelopes", envelopeIds.Count); - var total = envelopeIds.Count; - var current = 1; - - foreach (var id in envelopeIds) - { - _logger.LogInformation("SendInvMail - Processing Envelope {EnvelopeId} ({Current}/{Total})", id, current, total); - try - { - // Placeholder for invitation email sending logic. - _logger.LogDebug("SendInvMail - Marking envelope {EnvelopeId} as queued", id); - const string updateSql = "UPDATE TBSIG_ENVELOPE SET CURRENT_WORK_APP = @App WHERE GUID = @Id"; - await using var updateCommand = new SqlCommand(updateSql, connection); - updateCommand.Parameters.AddWithValue("@App", "signFLOW_API_EnvJob_InvMail"); - updateCommand.Parameters.AddWithValue("@Id", id); - await updateCommand.ExecuteNonQueryAsync(cancellationToken); - } - catch (System.Exception ex) - { - _logger.LogWarning(ex, "SendInvMail - Unhandled exception while working envelope {EnvelopeId}", id); - } - - current++; - _logger.LogInformation("SendInvMail - Envelope finalized"); - } - } - - private async Task ProcessWithdrawnAsync(SqlConnection connection, System.Threading.CancellationToken cancellationToken) - { - const string sql = @"SELECT ENV.GUID, REJ.COMMENT AS REJECTION_REASON FROM - (SELECT * FROM TBSIG_ENVELOPE WHERE STATUS = 1009 AND SOURCE = 'API') ENV INNER JOIN - (SELECT MAX(GUID) GUID, ENVELOPE_ID, MAX(ADDED_WHEN) ADDED_WHEN, MAX(ACTION_DATE) ACTION_DATE, COMMENT FROM TBSIG_ENVELOPE_HISTORY WHERE STATUS = 1009 GROUP BY ENVELOPE_ID, COMMENT ) REJ ON ENV.GUID = REJ.ENVELOPE_ID LEFT JOIN - (SELECT * FROM TBSIG_ENVELOPE_HISTORY WHERE STATUS = 3004 ) M_Send ON ENV.GUID = M_Send.ENVELOPE_ID - WHERE M_Send.GUID IS NULL"; - - var withdrawn = new List<(int EnvelopeId, string Reason)>(); - await using (var command = new SqlCommand(sql, connection)) - await using (var reader = await command.ExecuteReaderAsync(cancellationToken)) - { - while (await reader.ReadAsync(cancellationToken)) - { - var id = reader.GetInt32(0); - var reason = reader.IsDBNull(1) ? string.Empty : reader.GetString(1); - withdrawn.Add((id, reason)); - } - } - - if (withdrawn.Count == 0) - { - _logger.LogDebug("WithdrawnEnv - No envelopes found"); - return; - } - - _logger.LogInformation("WithdrawnEnv - Found {Count} envelopes", withdrawn.Count); - var total = withdrawn.Count; - var current = 1; - - foreach (var (envelopeId, reason) in withdrawn) - { - _logger.LogInformation("WithdrawnEnv - Processing Envelope {EnvelopeId} ({Current}/{Total})", envelopeId, current, total); - try - { - // Log withdrawn mail trigger placeholder - const string insertHistory = "INSERT INTO TBSIG_ENVELOPE_HISTORY (ENVELOPE_ID, STATUS, USER_REFERENCE, ADDED_WHEN, ACTION_DATE, COMMENT) VALUES (@EnvelopeId, @Status, @UserReference, GETDATE(), GETDATE(), @Comment)"; - await using var insertCommand = new SqlCommand(insertHistory, connection); - insertCommand.Parameters.AddWithValue("@EnvelopeId", envelopeId); - insertCommand.Parameters.AddWithValue("@Status", 3004); - insertCommand.Parameters.AddWithValue("@UserReference", "API"); - insertCommand.Parameters.AddWithValue("@Comment", reason ?? string.Empty); - await insertCommand.ExecuteNonQueryAsync(cancellationToken); - } - catch (System.Exception ex) - { - _logger.LogWarning(ex, "WithdrawnEnv - Unhandled exception while working envelope {EnvelopeId}", envelopeId); - } - - current++; - _logger.LogInformation("WithdrawnEnv - Envelope finalized"); - } - } -} diff --git a/EnvelopeGenerator.Jobs/Jobs/DataRowExtensions.cs b/EnvelopeGenerator.Jobs/Jobs/DataRowExtensions.cs deleted file mode 100644 index 805f6f1f..00000000 --- a/EnvelopeGenerator.Jobs/Jobs/DataRowExtensions.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Data; - -namespace EnvelopeGenerator.Jobs; - -public static class DataRowExtensions -{ - public static T? GetValueOrDefault(this DataRow row, string columnName, T? defaultValue = default) - { - if (!row.Table.Columns.Contains(columnName)) - { - return defaultValue; - } - - var value = row[columnName]; - if (value == DBNull.Value) - { - return defaultValue; - } - - try - { - return (T)Convert.ChangeType(value, typeof(T)); - } - catch - { - return defaultValue; - } - } -} diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentExceptions.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentExceptions.cs deleted file mode 100644 index 847ab06b..00000000 --- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentExceptions.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace EnvelopeGenerator.Jobs.FinalizeDocument; - -public static class FinalizeDocumentExceptions -{ - public class MergeDocumentException : ApplicationException - { - public MergeDocumentException(string message) : base(message) { } - public MergeDocumentException(string message, Exception innerException) : base(message, innerException) { } - } - - public class BurnAnnotationException : ApplicationException - { - public BurnAnnotationException(string message) : base(message) { } - public BurnAnnotationException(string message, Exception innerException) : base(message, innerException) { } - } - - public class CreateReportException : ApplicationException - { - public CreateReportException(string message) : base(message) { } - public CreateReportException(string message, Exception innerException) : base(message, innerException) { } - } - - public class ExportDocumentException : ApplicationException - { - public ExportDocumentException(string message) : base(message) { } - public ExportDocumentException(string message, Exception innerException) : base(message, innerException) { } - } -} diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentJob.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentJob.cs deleted file mode 100644 index 2ddb4e1d..00000000 --- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/FinalizeDocumentJob.cs +++ /dev/null @@ -1,229 +0,0 @@ -using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using EnvelopeGenerator.Domain.Constants; -using EnvelopeGenerator.Domain.Entities; -using Microsoft.Data.SqlClient; -using Microsoft.Extensions.Logging; -using Quartz; -using static EnvelopeGenerator.Jobs.FinalizeDocument.FinalizeDocumentExceptions; - -namespace EnvelopeGenerator.Jobs.FinalizeDocument; - -public class FinalizeDocumentJob : IJob -{ - private readonly ILogger _logger; - private readonly PDFBurner _pdfBurner; - private readonly PDFMerger _pdfMerger; - private readonly ReportCreator _reportCreator; - - private record ConfigSettings(string DocumentPath, string DocumentPathOrigin, string ExportPath); - - public FinalizeDocumentJob( - ILogger logger, - PDFBurner pdfBurner, - PDFMerger pdfMerger, - ReportCreator reportCreator) - { - _logger = logger; - _pdfBurner = pdfBurner; - _pdfMerger = pdfMerger; - _reportCreator = reportCreator; - } - - public async Task Execute(IJobExecutionContext context) - { - var jobId = context.JobDetail.Key.ToString(); - _logger.LogDebug("Starting job {JobId}", jobId); - - try - { - var connectionString = context.MergedJobDataMap.GetString(Value.DATABASE); - if (string.IsNullOrWhiteSpace(connectionString)) - { - _logger.LogWarning("FinalizeDocument - Connection string missing"); - return; - } - - await using var connection = new SqlConnection(connectionString); - await connection.OpenAsync(context.CancellationToken); - - var config = await LoadConfigurationAsync(connection, context.CancellationToken); - var envelopes = await LoadCompletedEnvelopesAsync(connection, context.CancellationToken); - - if (envelopes.Count == 0) - { - _logger.LogInformation("No completed envelopes found"); - return; - } - - var total = envelopes.Count; - var current = 1; - - foreach (var envelopeId in envelopes) - { - _logger.LogInformation("Finalizing Envelope {EnvelopeId} ({Current}/{Total})", envelopeId, current, total); - try - { - var envelopeData = await GetEnvelopeDataAsync(connection, envelopeId, context.CancellationToken); - if (envelopeData is null) - { - _logger.LogWarning("Envelope data not found for {EnvelopeId}", envelopeId); - continue; - } - - var data = envelopeData.Value; - - var envelope = new Envelope - { - Id = envelopeId, - Uuid = data.EnvelopeUuid ?? string.Empty, - Title = data.Title ?? string.Empty, - FinalEmailToCreator = (int)FinalEmailType.No, - FinalEmailToReceivers = (int)FinalEmailType.No - }; - - var burned = _pdfBurner.BurnAnnotsToPDF(data.DocumentBytes, data.AnnotationData, envelopeId); - var report = _reportCreator.CreateReport(connection, envelope); - var merged = _pdfMerger.MergeDocuments(burned, report); - - var outputDirectory = Path.Combine(config.ExportPath, data.ParentFolderUid); - Directory.CreateDirectory(outputDirectory); - var outputPath = Path.Combine(outputDirectory, $"{envelope.Uuid}.pdf"); - await File.WriteAllBytesAsync(outputPath, merged, context.CancellationToken); - - await UpdateDocumentResultAsync(connection, envelopeId, merged, context.CancellationToken); - await ArchiveEnvelopeAsync(connection, envelopeId, context.CancellationToken); - } - catch (MergeDocumentException ex) - { - _logger.LogWarning(ex, "Certificate Document job failed at merging documents"); - } - catch (ExportDocumentException ex) - { - _logger.LogWarning(ex, "Certificate Document job failed at exporting document"); - } - catch (Exception ex) - { - _logger.LogError(ex, "Unhandled exception while working envelope {EnvelopeId}", envelopeId); - } - - current++; - _logger.LogInformation("Envelope {EnvelopeId} finalized", envelopeId); - } - - _logger.LogDebug("Completed job {JobId} successfully", jobId); - } - catch (Exception ex) - { - _logger.LogError(ex, "Certificate Document job failed"); - } - finally - { - _logger.LogDebug("Job execution for {JobId} ended", jobId); - } - } - - private async Task LoadConfigurationAsync(SqlConnection connection, CancellationToken cancellationToken) - { - const string sql = "SELECT TOP 1 DOCUMENT_PATH, EXPORT_PATH FROM TBSIG_CONFIG"; - await using var command = new SqlCommand(sql, connection); - await using var reader = await command.ExecuteReaderAsync(cancellationToken); - if (await reader.ReadAsync(cancellationToken)) - { - var documentPath = reader.IsDBNull(0) ? string.Empty : reader.GetString(0); - var exportPath = reader.IsDBNull(1) ? string.Empty : reader.GetString(1); - return new ConfigSettings(documentPath, documentPath, exportPath); - } - - return new ConfigSettings(string.Empty, string.Empty, Path.GetTempPath()); - } - - private async Task> LoadCompletedEnvelopesAsync(SqlConnection connection, CancellationToken cancellationToken) - { - const string sql = "SELECT GUID FROM TBSIG_ENVELOPE WHERE STATUS = @Status AND DATEDIFF(minute, CHANGED_WHEN, GETDATE()) >= 1 ORDER BY GUID"; - var ids = new List(); - await using var command = new SqlCommand(sql, connection); - command.Parameters.AddWithValue("@Status", (int)EnvelopeStatus.EnvelopeCompletelySigned); - await using var reader = await command.ExecuteReaderAsync(cancellationToken); - while (await reader.ReadAsync(cancellationToken)) - { - ids.Add(reader.GetInt32(0)); - } - - return ids; - } - - private async Task<(int EnvelopeId, string? EnvelopeUuid, string? Title, byte[] DocumentBytes, List AnnotationData, string ParentFolderUid)?> GetEnvelopeDataAsync(SqlConnection connection, int envelopeId, CancellationToken cancellationToken) - { - const string sql = @"SELECT T.GUID, T.ENVELOPE_UUID, T.TITLE, T2.FILEPATH, T2.BYTE_DATA FROM [dbo].[TBSIG_ENVELOPE] T - JOIN TBSIG_ENVELOPE_DOCUMENT T2 ON T.GUID = T2.ENVELOPE_ID - WHERE T.GUID = @EnvelopeId"; - - await using var command = new SqlCommand(sql, connection); - command.Parameters.AddWithValue("@EnvelopeId", envelopeId); - await using var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleRow, cancellationToken); - if (!await reader.ReadAsync(cancellationToken)) - { - return null; - } - - var envelopeUuid = reader.IsDBNull(1) ? string.Empty : reader.GetString(1); - var title = reader.IsDBNull(2) ? string.Empty : reader.GetString(2); - var filePath = reader.IsDBNull(3) ? string.Empty : reader.GetString(3); - var bytes = reader.IsDBNull(4) ? Array.Empty() : (byte[])reader[4]; - await reader.CloseAsync(); - - if (bytes.Length == 0 && !string.IsNullOrWhiteSpace(filePath) && File.Exists(filePath)) - { - bytes = await File.ReadAllBytesAsync(filePath, cancellationToken); - } - - var annotations = await GetAnnotationDataAsync(connection, envelopeId, cancellationToken); - - var parentFolderUid = !string.IsNullOrWhiteSpace(filePath) - ? Path.GetFileName(Path.GetDirectoryName(filePath) ?? string.Empty) - : envelopeUuid; - - return (envelopeId, envelopeUuid, title, bytes, annotations, parentFolderUid ?? envelopeUuid ?? envelopeId.ToString()); - } - - private async Task> GetAnnotationDataAsync(SqlConnection connection, int envelopeId, CancellationToken cancellationToken) - { - const string sql = "SELECT VALUE FROM TBSIG_DOCUMENT_STATUS WHERE ENVELOPE_ID = @EnvelopeId"; - var result = new List(); - await using var command = new SqlCommand(sql, connection); - command.Parameters.AddWithValue("@EnvelopeId", envelopeId); - await using var reader = await command.ExecuteReaderAsync(cancellationToken); - while (await reader.ReadAsync(cancellationToken)) - { - if (!reader.IsDBNull(0)) - { - result.Add(reader.GetString(0)); - } - } - - return result; - } - - private static async Task UpdateDocumentResultAsync(SqlConnection connection, int envelopeId, byte[] bytes, CancellationToken cancellationToken) - { - const string sql = "UPDATE TBSIG_ENVELOPE SET DOC_RESULT = @ImageData WHERE GUID = @EnvelopeId"; - await using var command = new SqlCommand(sql, connection); - command.Parameters.AddWithValue("@ImageData", bytes); - command.Parameters.AddWithValue("@EnvelopeId", envelopeId); - await command.ExecuteNonQueryAsync(cancellationToken); - } - - private static async Task ArchiveEnvelopeAsync(SqlConnection connection, int envelopeId, CancellationToken cancellationToken) - { - const string sql = "UPDATE TBSIG_ENVELOPE SET STATUS = @Status, CHANGED_WHEN = GETDATE() WHERE GUID = @EnvelopeId"; - await using var command = new SqlCommand(sql, connection); - command.Parameters.AddWithValue("@Status", (int)EnvelopeStatus.EnvelopeArchived); - command.Parameters.AddWithValue("@EnvelopeId", envelopeId); - await command.ExecuteNonQueryAsync(cancellationToken); - } -} diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurner.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurner.cs deleted file mode 100644 index 0d04846c..00000000 --- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurner.cs +++ /dev/null @@ -1,277 +0,0 @@ -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using iText.IO.Image; -using iText.Kernel.Colors; -using iText.Kernel.Pdf; -using iText.Kernel.Pdf.Canvas; -using iText.Layout; -using iText.Layout.Element; -using iText.Layout.Font; -using iText.Layout.Properties; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Newtonsoft.Json; -using static EnvelopeGenerator.Jobs.FinalizeDocument.FinalizeDocumentExceptions; -using LayoutImage = iText.Layout.Element.Image; - -namespace EnvelopeGenerator.Jobs.FinalizeDocument; - -public class PDFBurner -{ - private static readonly FontProvider FontProvider = CreateFontProvider(); - private readonly ILogger _logger; - private readonly PDFBurnerParams _pdfBurnerParams; - - public PDFBurner() : this(NullLogger.Instance, new PDFBurnerParams()) - { - } - - public PDFBurner(ILogger logger, PDFBurnerParams? pdfBurnerParams = null) - { - _logger = logger; - _pdfBurnerParams = pdfBurnerParams ?? new PDFBurnerParams(); - } - - public byte[] BurnAnnotsToPDF(byte[] sourceBuffer, IList instantJsonList, int envelopeId) - { - if (sourceBuffer is null || sourceBuffer.Length == 0) - { - throw new BurnAnnotationException("Source document is empty"); - } - - try - { - using var inputStream = new MemoryStream(sourceBuffer); - using var outputStream = new MemoryStream(); - using var reader = new PdfReader(inputStream); - using var writer = new PdfWriter(outputStream); - using var pdf = new PdfDocument(reader, writer); - - foreach (var json in instantJsonList ?? Enumerable.Empty()) - { - if (string.IsNullOrWhiteSpace(json)) - { - continue; - } - - var annotationData = JsonConvert.DeserializeObject(json); - if (annotationData?.annotations is null) - { - continue; - } - - annotationData.annotations.Reverse(); - - foreach (var annotation in annotationData.annotations) - { - try - { - switch (annotation.type) - { - case AnnotationType.Image: - AddImageAnnotation(pdf, annotation, annotationData.attachments); - break; - case AnnotationType.Ink: - AddInkAnnotation(pdf, annotation); - break; - case AnnotationType.Widget: - var formFieldValue = annotationData.formFieldValues?.FirstOrDefault(fv => fv.name == annotation.id); - if (formFieldValue is not null && !_pdfBurnerParams.IgnoredLabels.Contains(formFieldValue.value)) - { - AddFormFieldValue(pdf, annotation, formFieldValue.value); - } - break; - } - } - catch (Exception ex) - { - _logger.LogWarning(ex, "Error applying annotation {AnnotationId} on envelope {EnvelopeId}", annotation.id, envelopeId); - throw new BurnAnnotationException("Adding annotation failed", ex); - } - } - } - - pdf.Close(); - return outputStream.ToArray(); - } - catch (BurnAnnotationException) - { - throw; - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to burn annotations for envelope {EnvelopeId}", envelopeId); - throw new BurnAnnotationException("Annotations could not be burned", ex); - } - } - - private void AddImageAnnotation(PdfDocument pdf, Annotation annotation, Dictionary? attachments) - { - if (attachments is null || string.IsNullOrWhiteSpace(annotation.imageAttachmentId) || !attachments.TryGetValue(annotation.imageAttachmentId, out var attachment)) - { - return; - } - - var page = pdf.GetPage(annotation.pageIndex + 1); - var bounds = annotation.bbox.Select(ToInches).ToList(); - var x = (float)bounds[0]; - var y = (float)bounds[1]; - var width = (float)bounds[2]; - var height = (float)bounds[3]; - - var imageBytes = Convert.FromBase64String(attachment.binary); - var imageData = ImageDataFactory.Create(imageBytes); - var image = new LayoutImage(imageData) - .ScaleAbsolute(width, height) - .SetFixedPosition(annotation.pageIndex + 1, x, y); - - using var canvas = new Canvas(new PdfCanvas(page), page.GetPageSize()); - canvas.Add(image); - } - - private void AddInkAnnotation(PdfDocument pdf, Annotation annotation) - { - if (annotation.lines?.points is null) - { - return; - } - - var page = pdf.GetPage(annotation.pageIndex + 1); - var canvas = new PdfCanvas(page); - var color = ParseColor(annotation.strokeColor); - canvas.SetStrokeColor(color); - canvas.SetLineWidth(1); - - foreach (var segment in annotation.lines.points) - { - var first = true; - foreach (var point in segment) - { - var (px, py) = (ToInches(point[0]), ToInches(point[1])); - if (first) - { - canvas.MoveTo(px, py); - first = false; - } - else - { - canvas.LineTo(px, py); - } - } - canvas.Stroke(); - } - } - - private static FontProvider CreateFontProvider() - { - var provider = new FontProvider(); - provider.AddStandardPdfFonts(); - provider.AddSystemFonts(); - return provider; - } - - private void AddFormFieldValue(PdfDocument pdf, Annotation annotation, string value) - { - var bounds = annotation.bbox.Select(ToInches).ToList(); - var x = (float)bounds[0]; - var y = (float)bounds[1]; - var width = (float)bounds[2]; - var height = (float)bounds[3]; - - var page = pdf.GetPage(annotation.pageIndex + 1); - var canvas = new Canvas(new PdfCanvas(page), page.GetPageSize()); - canvas.SetProperty(Property.FONT_PROVIDER, FontProvider); - canvas.SetProperty(Property.FONT, FontProvider.GetFontSet()); - - var paragraph = new Paragraph(value) - .SetFontSize(_pdfBurnerParams.FontSize) - .SetFontColor(ColorConstants.BLACK) - .SetFontFamily(_pdfBurnerParams.FontName); - - if (_pdfBurnerParams.FontStyle.HasFlag(FontStyle.Italic)) - { - paragraph.SetItalic(); - } - - if (_pdfBurnerParams.FontStyle.HasFlag(FontStyle.Bold)) - { - paragraph.SetBold(); - } - - canvas.ShowTextAligned( - paragraph, - x + (float)_pdfBurnerParams.TopMargin, - y + (float)_pdfBurnerParams.YOffset, - annotation.pageIndex + 1, - iText.Layout.Properties.TextAlignment.LEFT, - iText.Layout.Properties.VerticalAlignment.TOP, - 0); - } - - private static DeviceRgb ParseColor(string? color) - { - if (string.IsNullOrWhiteSpace(color)) - { - return new DeviceRgb(0, 0, 0); - } - - try - { - var drawingColor = ColorTranslator.FromHtml(color); - return new DeviceRgb(drawingColor.R, drawingColor.G, drawingColor.B); - } - catch - { - return new DeviceRgb(0, 0, 0); - } - } - - private static double ToInches(double value) => value / 72d; - private static double ToInches(float value) => value / 72d; - - #region Model - private static class AnnotationType - { - public const string Image = "pspdfkit/image"; - public const string Ink = "pspdfkit/ink"; - public const string Widget = "pspdfkit/widget"; - } - - private sealed class AnnotationData - { - public List? annotations { get; set; } - public Dictionary? attachments { get; set; } - public List? formFieldValues { get; set; } - } - - private sealed class Annotation - { - public string id { get; set; } = string.Empty; - public List bbox { get; set; } = new(); - public string type { get; set; } = string.Empty; - public string imageAttachmentId { get; set; } = string.Empty; - public Lines? lines { get; set; } - public int pageIndex { get; set; } - public string strokeColor { get; set; } = string.Empty; - public string egName { get; set; } = string.Empty; - } - - private sealed class Lines - { - public List>> points { get; set; } = new(); - } - - private sealed class Attachment - { - public string binary { get; set; } = string.Empty; - public string contentType { get; set; } = string.Empty; - } - - private sealed class FormFieldValue - { - public string name { get; set; } = string.Empty; - public string value { get; set; } = string.Empty; - } - #endregion -} diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurnerParams.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurnerParams.cs deleted file mode 100644 index 0b9536fa..00000000 --- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFBurnerParams.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using System.Drawing; - -namespace EnvelopeGenerator.Jobs.FinalizeDocument; - -public class PDFBurnerParams -{ - public List IgnoredLabels { get; } = new() { "Date", "Datum", "ZIP", "PLZ", "Place", "Ort", "Position", "Stellung" }; - - public double TopMargin { get; set; } = 0.1; - - public double YOffset { get; set; } = -0.3; - - public string FontName { get; set; } = "Arial"; - - public int FontSize { get; set; } = 8; - - public FontStyle FontStyle { get; set; } = FontStyle.Italic; -} diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFMerger.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFMerger.cs deleted file mode 100644 index 2306fac7..00000000 --- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/PDFMerger.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.IO; -using iText.Kernel.Pdf; -using iText.Kernel.Utils; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using static EnvelopeGenerator.Jobs.FinalizeDocument.FinalizeDocumentExceptions; - -namespace EnvelopeGenerator.Jobs.FinalizeDocument; - -public class PDFMerger -{ - private readonly ILogger _logger; - - public PDFMerger() : this(NullLogger.Instance) - { - } - - public PDFMerger(ILogger logger) - { - _logger = logger; - } - - public byte[] MergeDocuments(byte[] document, byte[] report) - { - try - { - using var finalStream = new MemoryStream(); - using var documentReader = new PdfReader(new MemoryStream(document)); - using var reportReader = new PdfReader(new MemoryStream(report)); - using var writer = new PdfWriter(finalStream); - using var targetDoc = new PdfDocument(documentReader, writer); - using var reportDoc = new PdfDocument(reportReader); - - var merger = new PdfMerger(targetDoc); - merger.Merge(reportDoc, 1, reportDoc.GetNumberOfPages()); - - targetDoc.Close(); - return finalStream.ToArray(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to merge PDF documents"); - throw new MergeDocumentException("Documents could not be merged", ex); - } - } -} diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportCreator.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportCreator.cs deleted file mode 100644 index b0e4aa08..00000000 --- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportCreator.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System.Data; -using System.IO; -using EnvelopeGenerator.Domain.Entities; -using iText.Kernel.Pdf; -using iText.Layout.Element; -using Microsoft.Data.SqlClient; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using static EnvelopeGenerator.Jobs.FinalizeDocument.FinalizeDocumentExceptions; -using LayoutDocument = iText.Layout.Document; - -namespace EnvelopeGenerator.Jobs.FinalizeDocument; - -public class ReportCreator -{ - private readonly ILogger _logger; - - public ReportCreator() : this(NullLogger.Instance) - { - } - - public ReportCreator(ILogger logger) - { - _logger = logger; - } - - public byte[] CreateReport(SqlConnection connection, Envelope envelope) - { - try - { - var reportItems = LoadReportItems(connection, envelope.Id); - using var stream = new MemoryStream(); - using var writer = new PdfWriter(stream); - using var pdf = new PdfDocument(writer); - using var document = new LayoutDocument(pdf); - - document.Add(new Paragraph("Envelope Finalization Report").SetFontSize(16)); - document.Add(new Paragraph($"Envelope Id: {envelope.Id}")); - document.Add(new Paragraph($"UUID: {envelope.Uuid}")); - document.Add(new Paragraph($"Title: {envelope.Title}")); - document.Add(new Paragraph($"Subject: {envelope.Comment}")); - document.Add(new Paragraph($"Generated: {DateTime.UtcNow:O}")); - document.Add(new Paragraph(" ")); - - var table = new Table(4).UseAllAvailableWidth(); - table.AddHeaderCell("Date"); - table.AddHeaderCell("Status"); - table.AddHeaderCell("User"); - table.AddHeaderCell("EnvelopeId"); - - foreach (var item in reportItems.OrderByDescending(r => r.ItemDate)) - { - table.AddCell(item.ItemDate.ToString("u")); - table.AddCell(item.ItemStatus.ToString()); - table.AddCell(item.ItemUserReference); - table.AddCell(item.EnvelopeId.ToString()); - } - - document.Add(table); - document.Close(); - return stream.ToArray(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Could not create report for envelope {EnvelopeId}", envelope.Id); - throw new CreateReportException("Could not prepare report data", ex); - } - } - - private List LoadReportItems(SqlConnection connection, int envelopeId) - { - const string sql = "SELECT ENVELOPE_ID, POS_WHEN, POS_STATUS, POS_WHO FROM VWSIG_ENVELOPE_REPORT WHERE ENVELOPE_ID = @EnvelopeId"; - var result = new List(); - - using var command = new SqlCommand(sql, connection); - command.Parameters.AddWithValue("@EnvelopeId", envelopeId); - using var reader = command.ExecuteReader(); - while (reader.Read()) - { - result.Add(new ReportItem - { - EnvelopeId = reader.GetInt32(0), - ItemDate = reader.IsDBNull(1) ? DateTime.MinValue : reader.GetDateTime(1), - ItemStatus = reader.IsDBNull(2) ? default : (EnvelopeGenerator.Domain.Constants.EnvelopeStatus)reader.GetInt32(2), - ItemUserReference = reader.IsDBNull(3) ? string.Empty : reader.GetString(3) - }); - } - - return result; - } -} diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportItem.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportItem.cs deleted file mode 100644 index c8e0d52e..00000000 --- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportItem.cs +++ /dev/null @@ -1,19 +0,0 @@ -using EnvelopeGenerator.Domain.Constants; -using EnvelopeGenerator.Domain.Entities; - -namespace EnvelopeGenerator.Jobs.FinalizeDocument; - -public class ReportItem -{ - public Envelope? Envelope { get; set; } - public int EnvelopeId { get; set; } - public string EnvelopeTitle { get; set; } = string.Empty; - public string EnvelopeSubject { get; set; } = string.Empty; - - public EnvelopeStatus ItemStatus { get; set; } - - public string ItemStatusTranslated => ItemStatus.ToString(); - - public string ItemUserReference { get; set; } = string.Empty; - public DateTime ItemDate { get; set; } -} diff --git a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportSource.cs b/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportSource.cs deleted file mode 100644 index 47afd920..00000000 --- a/EnvelopeGenerator.Jobs/Jobs/FinalizeDocument/ReportSource.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; - -namespace EnvelopeGenerator.Jobs.FinalizeDocument; - -public class ReportSource -{ - public List Items { get; set; } = new(); -} diff --git a/EnvelopeGenerator.sln b/EnvelopeGenerator.sln index fe942d58..f55cdd56 100644 --- a/EnvelopeGenerator.sln +++ b/EnvelopeGenerator.sln @@ -33,8 +33,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.PdfEditor EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Tests", "EnvelopeGenerator.Tests\EnvelopeGenerator.Tests.csproj", "{224C4845-1CDE-22B7-F3A9-1FF9297F70E8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Jobs", "EnvelopeGenerator.Jobs\EnvelopeGenerator.Jobs.csproj", "{3D0514EA-2681-4B13-AD71-35CC6363DBD7}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.API", "EnvelopeGenerator.API\EnvelopeGenerator.API.csproj", "{EC768913-6270-14F4-1DD3-69C87A659462}" EndProject Global @@ -83,10 +81,6 @@ Global {224C4845-1CDE-22B7-F3A9-1FF9297F70E8}.Debug|Any CPU.Build.0 = Debug|Any CPU {224C4845-1CDE-22B7-F3A9-1FF9297F70E8}.Release|Any CPU.ActiveCfg = Release|Any CPU {224C4845-1CDE-22B7-F3A9-1FF9297F70E8}.Release|Any CPU.Build.0 = Release|Any CPU - {3D0514EA-2681-4B13-AD71-35CC6363DBD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3D0514EA-2681-4B13-AD71-35CC6363DBD7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3D0514EA-2681-4B13-AD71-35CC6363DBD7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3D0514EA-2681-4B13-AD71-35CC6363DBD7}.Release|Any CPU.Build.0 = Release|Any CPU {EC768913-6270-14F4-1DD3-69C87A659462}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EC768913-6270-14F4-1DD3-69C87A659462}.Debug|Any CPU.Build.0 = Debug|Any CPU {EC768913-6270-14F4-1DD3-69C87A659462}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -109,7 +103,6 @@ Global {6D56C01F-D6CB-4D8A-BD3D-4FD34326998C} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB} {211619F5-AE25-4BA5-A552-BACAFE0632D3} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB} {224C4845-1CDE-22B7-F3A9-1FF9297F70E8} = {0CBC2432-A561-4440-89BC-671B66A24146} - {3D0514EA-2681-4B13-AD71-35CC6363DBD7} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB} {EC768913-6270-14F4-1DD3-69C87A659462} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution From 6d2ec4cc0b8762f6c4234d5c19c450a79dba985f Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 23 Feb 2026 15:54:52 +0100 Subject: [PATCH 12/74] Update DI and Logging packages to v8, adjust binding redirects Upgraded Microsoft.Extensions.DependencyInjection.Abstractions to 8.0.2 and Microsoft.Extensions.Logging.Abstractions to 8.0.3 in project references and packages.config. Updated related binding redirects in App.config. Also modified the solution file to change the build configuration for project {83ED2617-B398-4859-8F59-B38F8807E83E} so Debug|Any CPU now maps to Release|Any CPU. Adjusted System.Memory and System.Buffers binding redirect ranges. --- EnvelopeGenerator.Service/App.config | 8 ++++---- .../EnvelopeGenerator.Service.vbproj | 8 ++++---- EnvelopeGenerator.Service/packages.config | 4 ++-- EnvelopeGenerator.sln | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/EnvelopeGenerator.Service/App.config b/EnvelopeGenerator.Service/App.config index 2d238195..445dd0b3 100644 --- a/EnvelopeGenerator.Service/App.config +++ b/EnvelopeGenerator.Service/App.config @@ -23,7 +23,7 @@ - + @@ -31,7 +31,7 @@ - + @@ -59,7 +59,7 @@ - + @@ -67,7 +67,7 @@ - + diff --git a/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj b/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj index 061d21a6..03df4c62 100644 --- a/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj +++ b/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj @@ -181,11 +181,11 @@ ..\packages\Microsoft.Extensions.DependencyInjection.7.0.0\lib\net462\Microsoft.Extensions.DependencyInjection.dll - - ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.7.0.0\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.8.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll - - ..\packages\Microsoft.Extensions.Logging.Abstractions.7.0.0\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll + + ..\packages\Microsoft.Extensions.Logging.Abstractions.8.0.3\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll diff --git a/EnvelopeGenerator.Service/packages.config b/EnvelopeGenerator.Service/packages.config index 571ea90c..6ccec828 100644 --- a/EnvelopeGenerator.Service/packages.config +++ b/EnvelopeGenerator.Service/packages.config @@ -13,8 +13,8 @@ - - + + diff --git a/EnvelopeGenerator.sln b/EnvelopeGenerator.sln index f55cdd56..5b4ef0bc 100644 --- a/EnvelopeGenerator.sln +++ b/EnvelopeGenerator.sln @@ -53,8 +53,8 @@ Global {5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Debug|Any CPU.Build.0 = Debug|Any CPU {5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Release|Any CPU.ActiveCfg = Debug|Any CPU {5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Release|Any CPU.Build.0 = Debug|Any CPU - {83ED2617-B398-4859-8F59-B38F8807E83E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {83ED2617-B398-4859-8F59-B38F8807E83E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83ED2617-B398-4859-8F59-B38F8807E83E}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {83ED2617-B398-4859-8F59-B38F8807E83E}.Debug|Any CPU.Build.0 = Release|Any CPU {83ED2617-B398-4859-8F59-B38F8807E83E}.Release|Any CPU.ActiveCfg = Debug|Any CPU {83ED2617-B398-4859-8F59-B38F8807E83E}.Release|Any CPU.Build.0 = Debug|Any CPU {4F32A98D-E6F0-4A09-BD97-1CF26107E837}.Debug|Any CPU.ActiveCfg = Debug|Any CPU From f9b1e583df388f6b0a80b2750a50307a64a35b99 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 27 Feb 2026 11:31:41 +0100 Subject: [PATCH 13/74] Remove SaveDocStatusCommand and always create doc status Removed SaveDocStatusCommand and its handler, eliminating logic for updating existing document statuses. DocStatusHandler now always sends CreateDocStatusCommand with simplified parameters when handling DocSignedNotification. This change ensures a new document status is always created instead of updating existing ones. --- .../DocSigned/Handlers/DocStatusHandler.cs | 15 ++-- .../Commands/SaveDocStatusCommand.cs | 77 ------------------- 2 files changed, 6 insertions(+), 86 deletions(-) delete mode 100644 EnvelopeGenerator.Application/DocStatus/Commands/SaveDocStatusCommand.cs diff --git a/EnvelopeGenerator.Application/Common/Notifications/DocSigned/Handlers/DocStatusHandler.cs b/EnvelopeGenerator.Application/Common/Notifications/DocSigned/Handlers/DocStatusHandler.cs index adae66cf..dd90d3c5 100644 --- a/EnvelopeGenerator.Application/Common/Notifications/DocSigned/Handlers/DocStatusHandler.cs +++ b/EnvelopeGenerator.Application/Common/Notifications/DocSigned/Handlers/DocStatusHandler.cs @@ -29,15 +29,12 @@ public class DocStatusHandler : INotificationHandler /// /// /// - public async Task Handle(DocSignedNotification notification, CancellationToken cancel) + public Task Handle(DocSignedNotification notification, CancellationToken cancel) => _sender.Send(new CreateDocStatusCommand() { - await _sender.Send(new SaveDocStatusCommand() - { - Envelope = new() { Id = notification.EnvelopeId }, - Receiver = new() { Id = notification.ReceiverId}, - Value = notification.PsPdfKitAnnotation is PsPdfKitAnnotation annot - ? JsonSerializer.Serialize(annot.Instant, Format.Json.ForAnnotations) + EnvelopeId = notification.EnvelopeId, + ReceiverId = notification.ReceiverId, + Value = notification.PsPdfKitAnnotation is PsPdfKitAnnotation annot + ? JsonSerializer.Serialize(annot.Instant, Format.Json.ForAnnotations) : BlankAnnotationJson - }, cancel); - } + }, cancel); } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DocStatus/Commands/SaveDocStatusCommand.cs b/EnvelopeGenerator.Application/DocStatus/Commands/SaveDocStatusCommand.cs deleted file mode 100644 index 0f041e8a..00000000 --- a/EnvelopeGenerator.Application/DocStatus/Commands/SaveDocStatusCommand.cs +++ /dev/null @@ -1,77 +0,0 @@ -using DigitalData.Core.Abstraction.Application.Repository; -using EnvelopeGenerator.Domain.Entities; -using MediatR; -using Microsoft.EntityFrameworkCore; -using AutoMapper; -using EnvelopeGenerator.Application.Common.Dto; -using EnvelopeGenerator.Application.Common.Extensions; - -namespace EnvelopeGenerator.Application.DocStatus.Commands; - -/// -/// Represents a command to save the status of a document, either by creating a new status or updating an existing one based on the provided envelope and receiver identifiers. -/// It returns the identifier of the saved document status. -/// -public record SaveDocStatusCommand : ModifyDocStatusCommandBase, IRequest; - -/// -/// -/// -public class SaveDocStatusCommandHandler : IRequestHandler -{ - private readonly IMapper _mapper; - - private readonly IRepository _repo; - - private readonly IRepository _envRepo; - - private readonly IRepository _rcvRepo; - - /// - /// - /// - /// - /// - /// - /// - public SaveDocStatusCommandHandler(IMapper mapper, IRepository repo, IRepository rcvRepo, IRepository envRepo) - { - _mapper = mapper; - _repo = repo; - _rcvRepo = rcvRepo; - _envRepo = envRepo; - } - - /// - /// - /// - /// - /// - /// - public async Task Handle(SaveDocStatusCommand request, CancellationToken cancel) - { - // ceck if exists - bool isExists = await _repo.ReadOnly().Where(request).AnyAsync(cancel); - - var env = await _envRepo.ReadOnly().Where(request.Envelope).FirstAsync(cancel); - var rcv = await _rcvRepo.ReadOnly().Where(request.Receiver).FirstAsync(cancel); - - request.Envelope.Id = env.Id; - request.Receiver.Id = rcv.Id; - - if (isExists) - { - var uReq = request.To(); - await _repo.UpdateAsync(uReq, q => q.Where(request), cancel); - } - else - { - var cReq = request.To(); - await _repo.CreateAsync(cReq, cancel); - } - - var docStatus = await _repo.ReadOnly().Where(request).SingleOrDefaultAsync(cancel); - - return _mapper.Map(docStatus); - } -} \ No newline at end of file From 74c4ddda83e2ca606f7c87d519ea6325207fd2f4 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 27 Feb 2026 11:32:45 +0100 Subject: [PATCH 14/74] Remove ModifyDocStatusCommandBase and its properties Deleted the entire ModifyDocStatusCommandBase.cs file, including the record definition, its properties (EnvelopeId, ReceiverId, Value), and the To() mapping method. No code or class definitions remain in this file. --- .../Commands/ModifyDocStatusCommandBase.cs | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 EnvelopeGenerator.Application/DocStatus/Commands/ModifyDocStatusCommandBase.cs diff --git a/EnvelopeGenerator.Application/DocStatus/Commands/ModifyDocStatusCommandBase.cs b/EnvelopeGenerator.Application/DocStatus/Commands/ModifyDocStatusCommandBase.cs deleted file mode 100644 index 683e57e8..00000000 --- a/EnvelopeGenerator.Application/DocStatus/Commands/ModifyDocStatusCommandBase.cs +++ /dev/null @@ -1,38 +0,0 @@ -using EnvelopeGenerator.Application.Common.Query; - -namespace EnvelopeGenerator.Application.DocStatus.Commands; - -/// -/// -/// -public record ModifyDocStatusCommandBase : EnvelopeReceiverQueryBase -{ - /// - /// - /// - public virtual int EnvelopeId { get; set; } - - /// - /// - /// - public virtual int ReceiverId { get; set; } - - /// - /// Gets or sets the display value associated with the status. - /// - public virtual string? Value { get; set; } - - /// - /// Maps the current command to a new instance of the specified type. - /// - /// - /// - public TDest To() where TDest : ModifyDocStatusCommandBase, new() - => new() - { - Key = Key, - Envelope = Envelope, - Receiver = Receiver, - Value = Value - }; -} \ No newline at end of file From 48f4ea0c50c4d4e0d1f2417b8791dee60b49e6ea Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 27 Feb 2026 11:33:53 +0100 Subject: [PATCH 15/74] Use UTC for AddedWhen timestamp in CreateHistoryCommand Changed AddedWhen to use DateTime.UtcNow instead of DateTime.Now to ensure timestamps are stored in UTC, improving consistency across different time zones and deployment environments. --- .../Histories/Commands/CreateHistoryCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Application/Histories/Commands/CreateHistoryCommand.cs b/EnvelopeGenerator.Application/Histories/Commands/CreateHistoryCommand.cs index 4cd83f01..c8a53f59 100644 --- a/EnvelopeGenerator.Application/Histories/Commands/CreateHistoryCommand.cs +++ b/EnvelopeGenerator.Application/Histories/Commands/CreateHistoryCommand.cs @@ -34,7 +34,7 @@ public record CreateHistoryCommand : EnvelopeReceiverQueryBase, IRequest /// /// - public DateTime AddedWhen { get; } = DateTime.Now; + public DateTime AddedWhen { get; } = DateTime.UtcNow; /// /// From afa3694cd72122208a875453cc1c2009c553f461 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 27 Feb 2026 11:34:17 +0100 Subject: [PATCH 16/74] Add MapAddedWhen to History mapping in MappingProfile Imported necessary namespaces and updated the CreateHistoryCommand-to-History mapping to include the MapAddedWhen extension method, likely to handle automatic setting of creation timestamps or similar metadata. --- EnvelopeGenerator.Application/Histories/MappingProfile.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Application/Histories/MappingProfile.cs b/EnvelopeGenerator.Application/Histories/MappingProfile.cs index 6261d5db..71e8916f 100644 --- a/EnvelopeGenerator.Application/Histories/MappingProfile.cs +++ b/EnvelopeGenerator.Application/Histories/MappingProfile.cs @@ -1,4 +1,5 @@ using AutoMapper; +using EnvelopeGenerator.Application.Common.Extensions; using EnvelopeGenerator.Application.Histories.Commands; using EnvelopeGenerator.Domain.Entities; @@ -17,6 +18,7 @@ public class MappingProfile: Profile CreateMap() .ForMember(dest => dest.Envelope, opt => opt.Ignore()) .ForMember(dest => dest.Sender, opt => opt.Ignore()) - .ForMember(dest => dest.Receiver, opt => opt.Ignore()); + .ForMember(dest => dest.Receiver, opt => opt.Ignore()) + .MapAddedWhen(); } } \ No newline at end of file From e0aa963184843977af98017f235a2023555aea0e Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 4 Mar 2026 14:18:28 +0100 Subject: [PATCH 17/74] Add IEnvelope interface and IsReadAndConfirm extension Introduced the IEnvelope interface with an EnvelopeTypeId property in the new EnvelopeGenerator.Domain.Interfaces namespace. Added the EnvelopeExtensions static class with an IsReadAndConfirm extension method to check if EnvelopeTypeId equals 2. --- EnvelopeGenerator.Domain/Interfaces/IEnvelope.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 EnvelopeGenerator.Domain/Interfaces/IEnvelope.cs diff --git a/EnvelopeGenerator.Domain/Interfaces/IEnvelope.cs b/EnvelopeGenerator.Domain/Interfaces/IEnvelope.cs new file mode 100644 index 00000000..bdc709c6 --- /dev/null +++ b/EnvelopeGenerator.Domain/Interfaces/IEnvelope.cs @@ -0,0 +1,15 @@ +namespace EnvelopeGenerator.Domain.Interfaces +{ + public interface IEnvelope + { + int? EnvelopeTypeId { get; set; } + } + + public static class EnvelopeExtensions + { + public static bool IsReadAndConfirm(this IEnvelope envelope) + { + return envelope.EnvelopeTypeId == 2; + } + } +} \ No newline at end of file From 2d0c08b2cea81119c597b583adda765defe182b6 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 4 Mar 2026 14:19:02 +0100 Subject: [PATCH 18/74] Implement IEnvelope and update Envelope.ReadOnly property Envelope now implements the IEnvelope interface. The ReadOnly property is marked as [Obsolete] and delegates to the IsReadAndConfirm extension method instead of directly checking EnvelopeTypeId. Added a using directive for EnvelopeGenerator.Domain.Interfaces. --- EnvelopeGenerator.Domain/Entities/Envelope.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/EnvelopeGenerator.Domain/Entities/Envelope.cs b/EnvelopeGenerator.Domain/Entities/Envelope.cs index 21e52a9d..5ba90338 100644 --- a/EnvelopeGenerator.Domain/Entities/Envelope.cs +++ b/EnvelopeGenerator.Domain/Entities/Envelope.cs @@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema; using EnvelopeGenerator.Domain.Constants; using Newtonsoft.Json; using EnvelopeGenerator.Domain.Interfaces.Auditing; +using EnvelopeGenerator.Domain.Interfaces; #if NETFRAMEWORK using System.Collections.Generic; using System.Linq; @@ -13,7 +14,7 @@ using System.Linq; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_ENVELOPE", Schema = "dbo")] - public class Envelope : IHasAddedWhen, IHasChangedWhen + public class Envelope : IHasAddedWhen, IHasChangedWhen, IEnvelope { public Envelope() { @@ -106,7 +107,8 @@ namespace EnvelopeGenerator.Domain.Entities [JsonIgnore] [NotMapped] - public bool ReadOnly => EnvelopeTypeId == 2; + [Obsolete("Use EnvelopeGenerator.Domain.Interfaces.EnvelopeExtensions.IsReadAndConfirm extension method instead.")] + public bool ReadOnly => this.IsReadAndConfirm(); [Column("CERTIFICATION_TYPE")] public int? CertificationType { get; set; } From 86c99596c4e16720bea8dd5c7af479237fb3ddc3 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 4 Mar 2026 14:19:11 +0100 Subject: [PATCH 19/74] Implement IEnvelope interface in EnvelopeDto EnvelopeDto now implements the IEnvelope interface, enabling it to be used wherever IEnvelope is required. No other modifications were made to the class. --- EnvelopeGenerator.Application/Common/Dto/EnvelopeDto.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Application/Common/Dto/EnvelopeDto.cs b/EnvelopeGenerator.Application/Common/Dto/EnvelopeDto.cs index 029d621a..01c24251 100644 --- a/EnvelopeGenerator.Application/Common/Dto/EnvelopeDto.cs +++ b/EnvelopeGenerator.Application/Common/Dto/EnvelopeDto.cs @@ -2,6 +2,7 @@ using DigitalData.UserManager.Application.DTOs.User; using EnvelopeGenerator.Domain.Constants; using EnvelopeGenerator.Domain.Entities; +using EnvelopeGenerator.Domain.Interfaces; using Microsoft.AspNetCore.Mvc; namespace EnvelopeGenerator.Application.Common.Dto; @@ -10,7 +11,7 @@ namespace EnvelopeGenerator.Application.Common.Dto; /// /// [ApiExplorerSettings(IgnoreApi = true)] -public record EnvelopeDto +public record EnvelopeDto : IEnvelope { /// /// From f44643aa3ecc8ecb8b6ef1195ccfb629311ff2ff Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 4 Mar 2026 15:02:04 +0100 Subject: [PATCH 20/74] Add dynamic email placeholders for confirm/sign workflows Refactored CreatePlaceholders to set email template values based on whether the envelope requires "read and confirm" or signature. Renamed method parameter for clarity and updated usages. Added a TODO for future method unification. Improves email content accuracy for different envelope actions. --- .../Services/EnvelopeMailService.cs | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs b/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs index 0bfc7a4c..4f73ebff 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs @@ -12,6 +12,7 @@ using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly; using EnvelopeGenerator.Application.Common.Extensions; using EnvelopeGenerator.Application.Common.Interfaces.Services; using MediatR; +using EnvelopeGenerator.Domain.Interfaces; namespace EnvelopeGenerator.Application.Services; @@ -49,14 +50,33 @@ public class EnvelopeMailService : EmailOutService, IEnvelopeMailService _sender = sender; } - private async Task> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null) + private async Task> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? er = null) { + if (er!.Envelope.IsReadAndConfirm()) + { + _placeholders["[SIGNATURE_TYPE]"] = "Lesen und bestätigen"; + _placeholders["[DOCUMENT_PROCESS]"] = string.Empty; + _placeholders["[FINAL_STATUS]"] = "Bestätigung"; + _placeholders["[FINAL_ACTION]"] = "Empfänger bestätigt"; + _placeholders["[REJECTED_BY_OTHERS]"] = "anderen Empfänger abgelehnt!"; + _placeholders["[RECEIVER_ACTION]"] = "bestätigt"; + } + else + { + _placeholders["[SIGNATURE_TYPE]"] = "Signieren"; + _placeholders["[DOCUMENT_PROCESS]"] = " und elektronisch unterschreiben"; + _placeholders["[FINAL_STATUS]"] = "Signatur"; + _placeholders["[FINAL_ACTION]"] = "Vertragspartner unterzeichnet"; + _placeholders["[REJECTED_BY_OTHERS]"] = "anderen Vertragspartner abgelehnt! Ihre notwendige Unterzeichnung wurde verworfen."; + _placeholders["[RECEIVER_ACTION]"] = "unterschrieben"; + } + if (accessCode is not null) _placeholders["[DOCUMENT_ACCESS_CODE]"] = accessCode; - if (envelopeReceiverDto?.Envelope is not null && envelopeReceiverDto.Receiver is not null) + if (er?.Envelope is not null && er.Receiver is not null) { - var erId = (envelopeReceiverDto.Envelope.Uuid, envelopeReceiverDto.Receiver.Signature).ToEnvelopeKey(); + var erId = (er.Envelope.Uuid, er.Receiver.Signature).ToEnvelopeKey(); var sigHost = await _configService.ReadDefaultSignatureHost(); var linkToDoc = $"{sigHost}/EnvelopeKey/{erId}"; _placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc; @@ -66,7 +86,8 @@ public class EnvelopeMailService : EmailOutService, IEnvelopeMailService return _placeholders; } - private async Task> CreatePlaceholders(EnvelopeReceiverReadOnlyDto? readOnlyDto = null) + // TODO: merge the two CreatePlaceholders methods by using a common parameter object containing all the required information to create the place holders. + private async Task> CreatePlaceholders(EnvelopeReceiverReadOnlyDto? readOnlyDto = null) { if (readOnlyDto?.Envelope is not null && readOnlyDto.Receiver is not null) { @@ -124,7 +145,7 @@ public class EnvelopeMailService : EmailOutService, IEnvelopeMailService return acResult.ToFail().Notice(LogLevel.Error, "Therefore, access code cannot be sent"); var accessCode = acResult.Data; - var placeholders = await CreatePlaceholders(accessCode: accessCode, envelopeReceiverDto: dto); + var placeholders = await CreatePlaceholders(accessCode: accessCode, er: dto); // Add optional place holders. if (optionalPlaceholders is not null) From 8fed342dc5b097bfb2a73e3e8b3322f99abf5e39 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 4 Mar 2026 15:17:47 +0100 Subject: [PATCH 21/74] Remove [SIGNATURE_TYPE] placeholder from MailParams The [SIGNATURE_TYPE] placeholder and its value ("signieren") were removed from the MailParams section in appsettings.Mail.json. This cleans up unused or unnecessary configuration. --- EnvelopeGenerator.Web/appsettings.Mail.json | 1 - 1 file changed, 1 deletion(-) diff --git a/EnvelopeGenerator.Web/appsettings.Mail.json b/EnvelopeGenerator.Web/appsettings.Mail.json index 61dc2518..22b0e1be 100644 --- a/EnvelopeGenerator.Web/appsettings.Mail.json +++ b/EnvelopeGenerator.Web/appsettings.Mail.json @@ -8,7 +8,6 @@ "MailParams": { "Placeholders": { "[NAME_PORTAL]": "signFlow", - "[SIGNATURE_TYPE]": "signieren", "[REASON]": "" } } From 9a516ab3c94a99a4ce73990779bc9d8c5d6069ca Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 4 Mar 2026 16:09:40 +0100 Subject: [PATCH 22/74] Update and align NuGet dependencies; drop net7.0 from Web - Downgrade Microsoft.Data.SqlClient to 5.2.2 in Application and Infrastructure projects - Downgrade Microsoft.Extensions.DependencyInjection to 8.0.1 for net8.0 in Application - Remove net7.0 target and related packages from Web project - Upgrade OpenApi and Caching.SqlServer to 8.0.17 (net8.0) and 9.0.6 (net9.0) in Web - Ensures consistent, compatible package versions across solution --- .../EnvelopeGenerator.Application.csproj | 6 ++-- .../EnvelopeGenerator.Infrastructure.csproj | 2 +- .../EnvelopeGenerator.Web.csproj | 35 +++---------------- 3 files changed, 8 insertions(+), 35 deletions(-) diff --git a/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj b/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj index 0da15ec9..ba181291 100644 --- a/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj +++ b/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj @@ -37,7 +37,7 @@ - + @@ -80,7 +80,7 @@ - + 7.0.5 @@ -88,7 +88,6 @@ - 8.1.1 @@ -96,7 +95,6 @@ - 8.1.1 diff --git a/EnvelopeGenerator.Infrastructure/EnvelopeGenerator.Infrastructure.csproj b/EnvelopeGenerator.Infrastructure/EnvelopeGenerator.Infrastructure.csproj index f3f03d30..23ff4950 100644 --- a/EnvelopeGenerator.Infrastructure/EnvelopeGenerator.Infrastructure.csproj +++ b/EnvelopeGenerator.Infrastructure/EnvelopeGenerator.Infrastructure.csproj @@ -25,7 +25,7 @@ - + diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index fa60b73d..0c02ae64 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -1,7 +1,7 @@  - net7.0;net8.0;net9.0 + net8.0;net9.0 enable enable EnvelopeGenerator.Web @@ -2093,39 +2093,14 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -2149,8 +2124,8 @@ - - + + From 59d6d25bdd08ce2e7a4c10071039d22d24537168 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 4 Mar 2026 16:09:50 +0100 Subject: [PATCH 23/74] Add ChangedWhen property to History entity Added a [NotMapped] ChangedWhen property to the History entity as a wrapper for ActionDate, providing alternative get/set access without affecting the database schema. --- EnvelopeGenerator.Domain/Entities/History.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/EnvelopeGenerator.Domain/Entities/History.cs b/EnvelopeGenerator.Domain/Entities/History.cs index f52700a5..b7a6bc4c 100644 --- a/EnvelopeGenerator.Domain/Entities/History.cs +++ b/EnvelopeGenerator.Domain/Entities/History.cs @@ -37,6 +37,7 @@ namespace EnvelopeGenerator.Domain.Entities [Column("ACTION_DATE", TypeName = "datetime")] public DateTime? ActionDate { get; set; } + [NotMapped] public DateTime? ChangedWhen { get => ActionDate; set => ActionDate = value; } [Column("COMMENT", TypeName = "nvarchar(max)")] From 08299451bbb181401f6fe7041b01b8b77e351981 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 4 Mar 2026 16:19:33 +0100 Subject: [PATCH 24/74] Customize email placeholders by envelope action type Added logic to set email template placeholders based on whether the envelope requires "Read and Confirm" or "Sign" actions. Placeholders such as [SIGNATURE_TYPE], [DOCUMENT_PROCESS], [FINAL_STATUS], [FINAL_ACTION], [REJECTED_BY_OTHERS], and [RECEIVER_ACTION] are now dynamically set to reflect the correct process and status, improving the accuracy and clarity of notification emails. --- .../Handlers/SendSignedMailHandler.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/EnvelopeGenerator.Application/Common/Notifications/DocSigned/Handlers/SendSignedMailHandler.cs b/EnvelopeGenerator.Application/Common/Notifications/DocSigned/Handlers/SendSignedMailHandler.cs index 73ae86ba..8b7aa4f1 100644 --- a/EnvelopeGenerator.Application/Common/Notifications/DocSigned/Handlers/SendSignedMailHandler.cs +++ b/EnvelopeGenerator.Application/Common/Notifications/DocSigned/Handlers/SendSignedMailHandler.cs @@ -3,6 +3,7 @@ using DigitalData.EmailProfilerDispatcher.Abstraction.Entities; using EnvelopeGenerator.Application.Common.Configurations; using EnvelopeGenerator.Domain.Entities; using Microsoft.Extensions.Options; +using EnvelopeGenerator.Domain.Interfaces; namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers; @@ -45,6 +46,25 @@ public class SendSignedMailHandler : SendMailHandler { "[DOCUMENT_TITLE]", notification.Envelope?.Title ?? string.Empty }, }; + if (notification.Envelope.IsReadAndConfirm()) + { + placeHolders["[SIGNATURE_TYPE]"] = "Lesen und bestätigen"; + placeHolders["[DOCUMENT_PROCESS]"] = string.Empty; + placeHolders["[FINAL_STATUS]"] = "Lesebestätigung"; + placeHolders["[FINAL_ACTION]"] = "Empfänger bestätigt"; + placeHolders["[REJECTED_BY_OTHERS]"] = "anderen Empfänger abgelehnt!"; + placeHolders["[RECEIVER_ACTION]"] = "bestätigt"; + } + else + { + placeHolders["[SIGNATURE_TYPE]"] = "Signieren"; + placeHolders["[DOCUMENT_PROCESS]"] = " und elektronisch unterschreiben"; + placeHolders["[FINAL_STATUS]"] = "Signatur"; + placeHolders["[FINAL_ACTION]"] = "Vertragspartner unterzeichnet"; + placeHolders["[REJECTED_BY_OTHERS]"] = "anderen Vertragspartner abgelehnt! Ihre notwendige Unterzeichnung wurde verworfen."; + placeHolders["[RECEIVER_ACTION]"] = "unterschrieben"; + } + return placeHolders; } } \ No newline at end of file From 8e3c334fa3c6d481cc2c766ba183519d46fcbfd2 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 4 Mar 2026 16:19:45 +0100 Subject: [PATCH 25/74] =?UTF-8?q?Update=20final=20status=20to=20'Lesebest?= =?UTF-8?q?=C3=A4tigung'=20for=20read=20confirm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed the [FINAL_STATUS] placeholder value from "Bestätigung" to the more specific "Lesebestätigung" when an envelope is read and confirmed, improving clarity in status messaging. --- EnvelopeGenerator.Application/Services/EnvelopeMailService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs b/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs index 4f73ebff..ad154298 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs @@ -56,7 +56,7 @@ public class EnvelopeMailService : EmailOutService, IEnvelopeMailService { _placeholders["[SIGNATURE_TYPE]"] = "Lesen und bestätigen"; _placeholders["[DOCUMENT_PROCESS]"] = string.Empty; - _placeholders["[FINAL_STATUS]"] = "Bestätigung"; + _placeholders["[FINAL_STATUS]"] = "Lesebestätigung"; _placeholders["[FINAL_ACTION]"] = "Empfänger bestätigt"; _placeholders["[REJECTED_BY_OTHERS]"] = "anderen Empfänger abgelehnt!"; _placeholders["[RECEIVER_ACTION]"] = "bestätigt"; From bcc17f6def305716d98a5338d14f6a707af6b00a Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 4 Mar 2026 16:49:07 +0100 Subject: [PATCH 26/74] Bump version to 3.11.0 in EnvelopeGenerator.Web.csproj Updated , , and properties from 3.10.0 to 3.11.0 to reflect the new release. No other changes were made. --- EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index 0c02ae64..4612b69b 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -12,9 +12,9 @@ digital data envelope generator web EnvelopeGenerator.Web is an ASP.NET MVC application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly. Assets\icon.ico - 3.10.0 - 3.10.0.0 - 3.10.0.0 + 3.11.0 + 3.11.0.0 + 3.11.0.0 Copyright © 2025 Digital Data GmbH. All rights reserved. From 3d43d1896dafbbca5f9fdde21ef043c1974cba45 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 01:20:12 +0100 Subject: [PATCH 27/74] Add DocConfirmed extension method to Resource.cs Added a new DocConfirmed extension method to the Extensions class in Resource.cs. This method enables retrieval of the "DocConfirmed" localized string via IStringLocalizer, similar to the existing DocSigned method. --- EnvelopeGenerator.Application/Resources/Resource.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/EnvelopeGenerator.Application/Resources/Resource.cs b/EnvelopeGenerator.Application/Resources/Resource.cs index 53c11359..18585f98 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.cs +++ b/EnvelopeGenerator.Application/Resources/Resource.cs @@ -204,6 +204,13 @@ public static class Extensions /// public static string DocSigned(this IStringLocalizer localizer) => localizer[nameof(DocSigned)].Value; + /// + /// + /// + /// + /// + public static string DocConfirmed(this IStringLocalizer localizer) => localizer[nameof(DocConfirmed)].Value; + /// /// /// From 9b660cb25a200fa5a5708d1bcf2da28c4e0fdf99 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 01:20:25 +0100 Subject: [PATCH 28/74] Pass model to EnvelopeSigned view on already signed check Previously, the "EnvelopeSigned" view was returned without a model when an envelope was already signed. Now, the er model object is passed to the view to provide additional context or data. --- EnvelopeGenerator.Web/Controllers/EnvelopeController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs index fed685c4..4bc9692e 100644 --- a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs +++ b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs @@ -91,7 +91,7 @@ public class EnvelopeController : ViewControllerBase if (await _historyService.IsSigned(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress)) { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - return View("EnvelopeSigned"); + return View("EnvelopeSigned", er); } #endregion From 7cd6ca3a5f127d42e340ed50918e619a437137c2 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 01:20:47 +0100 Subject: [PATCH 29/74] Update EnvelopeSigned view model and title logic Set model to EnvelopeReceiverDto and import required types. Update ViewData["Title"] to use DocSigned or DocConfirmed based on Envelope.IsReadAndConfirm() result. --- EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml b/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml index e2c5ae4d..39036493 100644 --- a/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml +++ b/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml @@ -1,5 +1,10 @@ @{ - ViewData["Title"] = _localizer.DocSigned(); + @using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver; + @using EnvelopeGenerator.Domain.Interfaces; + @model EnvelopeReceiverDto; + ViewData["Title"] = Model!.Envelope!.IsReadAndConfirm() + ? _localizer.DocSigned() + : _localizer.DocConfirmed(); }
From 9cfc74aa8864cdf7c02f079e09951957feaebb63 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 01:23:06 +0100 Subject: [PATCH 30/74] Refactor title logic and fix localizer syntax in view Refactored EnvelopeSigned.cshtml to use a local variable for IsReadAndConfirm when setting the page title, improving readability. Also updated Razor syntax for localizer calls in

and

elements to ensure correct evaluation and formatting. --- EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml b/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml index 39036493..491266fc 100644 --- a/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml +++ b/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml @@ -2,7 +2,8 @@ @using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver; @using EnvelopeGenerator.Domain.Interfaces; @model EnvelopeReceiverDto; - ViewData["Title"] = Model!.Envelope!.IsReadAndConfirm() + bool IsReadAndConfirm = Model!.Envelope!.IsReadAndConfirm(); + ViewData["Title"] = IsReadAndConfirm ? _localizer.DocSigned() : _localizer.DocConfirmed(); } @@ -14,9 +15,9 @@

-

@_localizer["DocumentSuccessfullySigned"]

+

@(_localizer["DocumentSuccessfullySigned"])

-

@_localizer["DocumentSignedConfirmationMessage"]

+

@(_localizer["DocumentSignedConfirmationMessage"])

\ No newline at end of file From e095860b17f587706fc2eeda72c63702fd6aced1 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 01:25:07 +0100 Subject: [PATCH 31/74] Update EnvelopeSigned page to handle confirm vs sign Add conditional logic to EnvelopeSigned.cshtml to display different headings and confirmation messages based on whether the document was signed or confirmed, using the IsReadAndConfirm flag. This improves user feedback by distinguishing between signing and confirming actions. --- .../Views/Envelope/EnvelopeSigned.cshtml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml b/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml index 491266fc..246d3a52 100644 --- a/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml +++ b/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml @@ -15,9 +15,13 @@ -

@(_localizer["DocumentSuccessfullySigned"])

+

@(IsReadAndConfirm + ? _localizer["DocumentSuccessfullySigned"] + : _localizer["DocumentSuccessfullyConfirmed"])

-

@(_localizer["DocumentSignedConfirmationMessage"])

+

@(IsReadAndConfirm + ? _localizer["DocumentSignedConfirmationMessage"] + : _localizer["DocumentConfirmedConfirmationMessage"])

\ No newline at end of file From f1e38e3bd35ad04e6d093fd5e3eb1f469ec371da Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 09:17:17 +0100 Subject: [PATCH 32/74] Reverse IsReadAndConfirm logic for envelope status texts Swapped the display logic for localized titles and messages based on the IsReadAndConfirm flag. Now, "confirmed" texts are shown when IsReadAndConfirm is true, and "signed" texts when false. This update ensures correct status messaging throughout the envelope confirmation flow. --- .../Views/Envelope/EnvelopeSigned.cshtml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml b/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml index 246d3a52..0aed7cf2 100644 --- a/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml +++ b/EnvelopeGenerator.Web/Views/Envelope/EnvelopeSigned.cshtml @@ -4,8 +4,8 @@ @model EnvelopeReceiverDto; bool IsReadAndConfirm = Model!.Envelope!.IsReadAndConfirm(); ViewData["Title"] = IsReadAndConfirm - ? _localizer.DocSigned() - : _localizer.DocConfirmed(); + ? _localizer.DocConfirmed() + : _localizer.DocSigned(); }
@@ -16,12 +16,12 @@

@(IsReadAndConfirm - ? _localizer["DocumentSuccessfullySigned"] - : _localizer["DocumentSuccessfullyConfirmed"])

+ ? _localizer["DocumentSuccessfullyConfirmed"] + : _localizer["DocumentSuccessfullySigned"])

@(IsReadAndConfirm - ? _localizer["DocumentSignedConfirmationMessage"] - : _localizer["DocumentConfirmedConfirmationMessage"])

+ ? _localizer["DocumentConfirmedConfirmationMessage"] + : _localizer["DocumentSignedConfirmationMessage"])

\ No newline at end of file From bcc53bf9f1fcbea3ed26960a4f2c7f44f432341e Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 09:27:41 +0100 Subject: [PATCH 33/74] Update rejection header for read and confirm envelopes Add logic to display a specific rejection message when an envelope is rejected as part of a "read and confirm" process. The header now distinguishes between external, confirmation-related, and default rejection scenarios for improved user feedback. --- .../Views/Envelope/EnvelopeRejected.cshtml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Web/Views/Envelope/EnvelopeRejected.cshtml b/EnvelopeGenerator.Web/Views/Envelope/EnvelopeRejected.cshtml index 218dd2c0..2ee0a73b 100644 --- a/EnvelopeGenerator.Web/Views/Envelope/EnvelopeRejected.cshtml +++ b/EnvelopeGenerator.Web/Views/Envelope/EnvelopeRejected.cshtml @@ -9,12 +9,14 @@ @using EnvelopeGenerator.Web.Extensions @using Newtonsoft.Json @using Newtonsoft.Json.Serialization +@using EnvelopeGenerator.Domain.Interfaces; @model EnvelopeReceiverDto; @{ var envelope = Model.Envelope; var document = Model.Envelope?.Documents?.FirstOrDefault(); var sender = Model.Envelope?.User; var isExt = ViewBag.IsExt ?? false; + bool IsReadAndConfirm = Model!.Envelope!.IsReadAndConfirm(); }
@@ -54,7 +56,11 @@ c-5.791,5.79-15.176,5.79-20.969,0l-30.32-30.322l-11.676,11.676l30.32,30.32c5.79,5.79,5.79,15.178,0,20.969L299.11,404.045z"/>
-

@(isExt ? _localizer.RejectionInfo1Ext() : _localizer.RejectionInfo1())

+

@(isExt + ? _localizer.RejectionInfo1Ext() + : IsReadAndConfirm + ? _localizer.RejectionInfo1ForConfirmation() + : _localizer.RejectionInfo1())

From 4ce1d2a3706ee2cd2cc4b426d279cab74ea563e9 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 09:28:12 +0100 Subject: [PATCH 34/74] Add RejectionInfo1ForConfirmation extension method Introduced a new extension method, RejectionInfo1ForConfirmation, to the Extensions class in Resource.cs. This method retrieves the localized string for "RejectionInfo1ForConfirmation" from an IStringLocalizer instance, providing functionality similar to the existing RejectionInfo1 method. --- EnvelopeGenerator.Application/Resources/Resource.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/EnvelopeGenerator.Application/Resources/Resource.cs b/EnvelopeGenerator.Application/Resources/Resource.cs index 18585f98..06a29276 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.cs +++ b/EnvelopeGenerator.Application/Resources/Resource.cs @@ -274,6 +274,13 @@ public static class Extensions /// public static string RejectionInfo1(this IStringLocalizer localizer) => localizer[nameof(RejectionInfo1)].Value; + /// + /// + /// + /// + /// + public static string RejectionInfo1ForConfirmation(this IStringLocalizer localizer) => localizer[nameof(RejectionInfo1ForConfirmation)].Value; + /// /// /// From 647c5d235315d34f4fbd2b56ef3e23206b36d251 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 09:31:19 +0100 Subject: [PATCH 35/74] Add localization extensions for confirmation resources Added three new extension methods to the Extensions class in Resource.cs: ConfirmDoc, ConfirmAgree, and ConfirmationProcessTitle. Each method retrieves the localized value for its respective resource key and includes XML documentation, consistent with existing localization methods. --- .../Resources/Resource.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/EnvelopeGenerator.Application/Resources/Resource.cs b/EnvelopeGenerator.Application/Resources/Resource.cs index 06a29276..13223106 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.cs +++ b/EnvelopeGenerator.Application/Resources/Resource.cs @@ -190,6 +190,13 @@ public static class Extensions /// public static string SignDoc(this IStringLocalizer localizer) => localizer[nameof(SignDoc)].Value; + /// + /// + /// + /// + /// + public static string ConfirmDoc(this IStringLocalizer localizer) => localizer[nameof(ConfirmDoc)].Value; + /// /// /// @@ -246,6 +253,13 @@ public static class Extensions /// public static string SigAgree(this IStringLocalizer localizer) => localizer[nameof(SigAgree)].Value; + /// + /// + /// + /// + /// + public static string ConfirmAgree(this IStringLocalizer localizer) => localizer[nameof(ConfirmAgree)].Value; + /// /// /// @@ -309,6 +323,13 @@ public static class Extensions /// public static string SigningProcessTitle(this IStringLocalizer localizer) => localizer[nameof(SigningProcessTitle)].Value; + /// + /// + /// + /// + /// + public static string ConfirmationProcessTitle(this IStringLocalizer localizer) => localizer[nameof(ConfirmationProcessTitle)].Value; + /// /// /// From 44edef8ba1bbba614520c5f2b314011b0fe75622 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 09:43:16 +0100 Subject: [PATCH 36/74] Update envelope view title logic for confirm state Refined the logic for setting ViewData["Title"] in ShowEnvelope.cshtml. Now, if the envelope requires read and confirm, the title displays "Confirm Document" instead of just "Sign Document" or "View Document", providing clearer context for users. --- EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml b/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml index b710f772..6e850e11 100644 --- a/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml +++ b/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml @@ -9,6 +9,7 @@ @using EnvelopeGenerator.Web.Extensions @using Newtonsoft.Json @using Newtonsoft.Json.Serialization +@using EnvelopeGenerator.Domain.Interfaces @model EnvelopeReceiverDto; @{ var userCulture = ViewData["UserCulture"] as Culture; @@ -24,7 +25,11 @@ if (ViewData["IsReadOnly"] is bool isReadOnly_bool) isReadOnly = isReadOnly_bool; - ViewData["Title"] = isReadOnly ? _localizer.ViewDoc() : _localizer.SignDoc(); + ViewData["Title"] = isReadOnly + ? _localizer.ViewDoc() + : envelope.IsReadAndConfirm() + ? _localizer.ConfirmDoc() + : _localizer.SignDoc(); }
@if (!isReadOnly) From f8c7f60cf9c5e91120ac9d07718c621354e401bf Mon Sep 17 00:00:00 2001 From: OlgunR Date: Fri, 6 Mar 2026 09:50:21 +0100 Subject: [PATCH 37/74] Add resource strings for document confirmation workflows Added new localized strings for document confirmation processes in de-DE, en-US, and fr-FR resource files, including confirmation messages, UI labels, and process titles. Fixed a typo in the German resource and ensured consistency for the "SigningProcessTitle" key across languages. --- .../Resources/Resource.de-DE.resx | 38 +++++++++++++++++-- .../Resources/Resource.en-US.resx | 36 ++++++++++++++++-- .../Resources/Resource.fr-FR.resx | 36 ++++++++++++++++-- 3 files changed, 100 insertions(+), 10 deletions(-) diff --git a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx index e16727d0..70182b7b 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx @@ -250,7 +250,7 @@ Sie können bei Bedarf mit {0}, <a href="mailto:{1}?subject={2}&body=Sehr geehrte(r)%20{0},%0A%0A%0A">{1}</a> Kontakt aufnehmen. - Das Vorgang wurde von einer der beteiligten Parteien abgelehnt. Sie können bei Bedarf mit {0}, <a href="mailto:{1}?subject={2}&body=Sehr geehrte(r)%20{0},%0A%0A%0A">{1}</a> Kontakt aufnehmen. + Der Vorgang wurde von einer der beteiligten Parteien abgelehnt. Sie können bei Bedarf mit {0}, <a href="mailto:{1}?subject={2}&body=Sehr geehrte(r)%20{0},%0A%0A%0A">{1}</a> Kontakt aufnehmen. Bitte geben Sie einen Grund an: @@ -261,9 +261,6 @@ Dokument unterschreiben - - Titel des Unterzeichnungs-Vorgangs - Ein unerwarteter Fehler ist aufgetreten. @@ -447,4 +444,37 @@ Dokument wurde zurückgesetzt. + + Dokument erfolgreich gelesen und bestätigt! + + + Sie haben das Dokument gelesen und bestätigt. Im Anschluss erhalten Sie eine schriftliche Bestätigung. + + + Bestätigen + + + Dieser Bestätigungsvorgang wurde abgelehnt! + + + Dokument bestätigen + + + Dokument bestätigt + + + Durch Klick auf Abschließen bestätige ich, das Dokument gelesen und zur Kenntnis genommen zu haben. + + + Bestätigt von + + + Titel des Lesebetätigungs-Vorgangs + + + Titel des Unterzeichnungs-Vorgangs + + + Bestätigungen + \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx index e12eb3bc..1c284156 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx @@ -261,9 +261,6 @@ Sign document - - Title of the signing process - An unexpected error has occurred. @@ -447,4 +444,37 @@ Document has been reset. + + Document successfully red and confirmed! + + + You have read and confirmed the document. You will receive a written confirmation afterwards. + + + Confirm + + + This confirmation process has been rejected! + + + Confirm Document + + + Document confirmed + + + By clicking on “Complete”, I confirm that I have read and taken note of the document. + + + Confirmed by + + + Title of the read confirmation process + + + Title of the signing process + + + Confirmations + \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx b/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx index 766e4fb9..034c7a83 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx @@ -261,9 +261,6 @@ Signer le document - - Titre du processus de signature - Une erreur inattendue s’est produite. @@ -447,4 +444,37 @@ Le document a été réinitialisé. + + Document lu et confirmé avec succès ! + + + Vous avez lu et confirmé le document. Vous recevrez une confirmation écrite par la suite. + + + Confirmer + + + Cette procédure de confirmation a été rejetée ! + + + Confirmer le document + + + Document confirmé + + + En cliquant sur « Terminer », je confirme avoir lu et pris connaissance du document. + + + Confirmé par + + + Titre de la procédure de confirmation de lecture + + + Titre du processus de signature + + + Confirmations + \ No newline at end of file From b64d2b7478a9b1db8b4ce0bf5a6cead4df592ca2 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 09:50:33 +0100 Subject: [PATCH 38/74] Refactor: cache IsReadAndConfirm() result in variable Store envelope.IsReadAndConfirm() in isReadAndConfirm variable to avoid redundant calls and improve code readability when setting ViewData["Title"]. No change to logic or behavior. --- EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml b/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml index 6e850e11..7bdf3fd1 100644 --- a/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml +++ b/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml @@ -25,9 +25,11 @@ if (ViewData["IsReadOnly"] is bool isReadOnly_bool) isReadOnly = isReadOnly_bool; + var isReadAndConfirm = envelope.IsReadAndConfirm(); + ViewData["Title"] = isReadOnly ? _localizer.ViewDoc() - : envelope.IsReadAndConfirm() + : isReadAndConfirm ? _localizer.ConfirmDoc() : _localizer.SignDoc(); } From f6d57b1e386fdc1a7eed314f50f52fb5b3b99688 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 09:52:12 +0100 Subject: [PATCH 39/74] Update progress bar to show Confirmations or Signatures Progress bar label now displays "Confirmations" if isReadAndConfirm is true, otherwise it shows "Signatures". This improves clarity for users based on the envelope's required action. --- EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml b/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml index 7bdf3fd1..8a454993 100644 --- a/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml +++ b/EnvelopeGenerator.Web/Views/Envelope/ShowEnvelope.cshtml @@ -69,7 +69,9 @@
- 0/@signatureCount @_localizer["Signatures"] + 0/@signatureCount @(isReadAndConfirm + ? _localizer["Confirmations"] + : _localizer["Signatures"])
} From ad0c8471726b58fdab632fc4f9c1f6cd59d17f58 Mon Sep 17 00:00:00 2001 From: OlgunR Date: Fri, 6 Mar 2026 09:53:18 +0100 Subject: [PATCH 40/74] Add SigningProcessTitle resource; rename rejection key Added localized SigningProcessTitle entry to de-DE, en-US, and fr-FR resource files. Renamed RejectionInfoConfirmation to RejectionInfo1Confirmation. Removed duplicate SigningProcessTitle entries. No changes to localized values. --- .../Resources/Resource.de-DE.resx | 8 ++++---- .../Resources/Resource.en-US.resx | 8 ++++---- .../Resources/Resource.fr-FR.resx | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx index 70182b7b..16fb00f5 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx @@ -261,6 +261,9 @@ Dokument unterschreiben + + Titel des Unterzeichnungs-Vorgangs + Ein unerwarteter Fehler ist aufgetreten. @@ -453,7 +456,7 @@ Bestätigen - + Dieser Bestätigungsvorgang wurde abgelehnt! @@ -471,9 +474,6 @@ Titel des Lesebetätigungs-Vorgangs - - Titel des Unterzeichnungs-Vorgangs - Bestätigungen diff --git a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx index 1c284156..0e3a1af7 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx @@ -261,6 +261,9 @@ Sign document + + Title of the signing process + An unexpected error has occurred. @@ -453,7 +456,7 @@ Confirm - + This confirmation process has been rejected! @@ -471,9 +474,6 @@ Title of the read confirmation process - - Title of the signing process - Confirmations diff --git a/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx b/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx index 034c7a83..be60d7bb 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx @@ -261,6 +261,9 @@ Signer le document + + Titre du processus de signature + Une erreur inattendue s’est produite. @@ -453,7 +456,7 @@ Confirmer - + Cette procédure de confirmation a été rejetée ! @@ -471,9 +474,6 @@ Titre de la procédure de confirmation de lecture - - Titre du processus de signature - Confirmations From d4eee1718efa71591e5f011cb45de77a9070af0e Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 10:13:45 +0100 Subject: [PATCH 41/74] Bump version to 3.12.0 in project file Updated , , and fields in EnvelopeGenerator.Web.csproj from 3.11.0 to 3.12.0. No other changes were made. --- EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index 4612b69b..f2d2c9fe 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -12,9 +12,9 @@ digital data envelope generator web EnvelopeGenerator.Web is an ASP.NET MVC application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly. Assets\icon.ico - 3.11.0 - 3.11.0.0 - 3.11.0.0 + 3.12.0 + 3.12.0.0 + 3.12.0.0 Copyright © 2025 Digital Data GmbH. All rights reserved. From 65f606f57395ddf1534d16a8d42d33bed163e119 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 12:55:19 +0100 Subject: [PATCH 42/74] Update finalize dialog text based on READ_AND_CONFIRM flag The confirmation dialog when finalizing a document now displays context-appropriate text depending on the READ_AND_CONFIRM flag. If true, it shows localized.confirmAgree; otherwise, it shows localized.sigAgree, improving clarity for different workflows. --- EnvelopeGenerator.Web/wwwroot/js/app.js | 2 +- EnvelopeGenerator.Web/wwwroot/js/app.min.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EnvelopeGenerator.Web/wwwroot/js/app.js b/EnvelopeGenerator.Web/wwwroot/js/app.js index 3ae36e46..62a329e9 100644 --- a/EnvelopeGenerator.Web/wwwroot/js/app.js +++ b/EnvelopeGenerator.Web/wwwroot/js/app.js @@ -255,7 +255,7 @@ class App { return Swal.fire({ title: localized.confirmation, - html: `
${localized.sigAgree}
`, + html: `
${READ_AND_CONFIRM ? localized.confirmAgree : localized.sigAgree}
`, icon: "question", showCancelButton: true, confirmButtonColor: "#3085d6", diff --git a/EnvelopeGenerator.Web/wwwroot/js/app.min.js b/EnvelopeGenerator.Web/wwwroot/js/app.min.js index c07a1e10..8d9a209a 100644 --- a/EnvelopeGenerator.Web/wwwroot/js/app.min.js +++ b/EnvelopeGenerator.Web/wwwroot/js/app.min.js @@ -1,3 +1,3 @@ const formatLocalized=(n,...t)=>typeof n=="string"?n.replace(/\{(\d+)\}/g,(n,i)=>t[i]??""):"";class App{constructor(n,t,i,r,u,f){this.container=f??`#${this.constructor.name.toLowerCase()}`;this.envelopeKey=n;this.pdfKit=null;this.currentDocument=t.envelope.documents[0];this.currentReceiver=t.receiver;this.signatureCount=t.envelope.documents[0].elements.length;this.envelopeReceiver=t;this.documentBytes=i;this.licenseKey=r;this.locale=u}async init(){if(this.pdfKit=await loadPSPDFKit(this.documentBytes,this.container,this.licenseKey,this.locale),addToolbarItems(this.pdfKit,this.handleClick.bind(this)),this.pdfKit.addEventListener("annotations.load",this.handleAnnotationsLoad.bind(this)),this.pdfKit.addEventListener("annotations.change",this.handleAnnotationsChange.bind(this)),this.pdfKit.addEventListener("annotations.create",this.handleAnnotationsCreate.bind(this)),this.pdfKit.addEventListener("annotations.willChange",()=>{Comp.ActPanel.Toggle()}),!READ_AND_CONFIRM)try{let n=await createAnnotations(this.currentDocument,this.envelopeReceiver.envelopeId,this.envelopeReceiver.receiverId);await this.pdfKit.create(n)}catch(n){console.error("Error loading annotations:",n)}READ_AND_CONFIRM||[...document.getElementsByClassName("btn_refresh")].forEach(n=>n.addEventListener("click",()=>this.handleClick("RESET")));[...document.getElementsByClassName("btn_complete")].forEach(n=>n.addEventListener("click",()=>this.handleClick("FINISH")));[...document.getElementsByClassName("btn_reject")].forEach(n=>n.addEventListener("click",()=>this.handleClick("REJECT")))}handleAnnotationsLoad(n){n.toJS()}handleAnnotationsChange(){}async handleAnnotationsCreate(n){const t=n.toJS()[0],i=!!t.formFieldName,r=!!t.isSignature;if(i===!1&&r===!0){const r=t.boundingBox.left-20,u=t.boundingBox.top-20,n=150,i=75,f=new Date,e=await createAnnotationFrameBlob(this.envelopeReceiver.name,this.currentReceiver.signature,f,n,i),o=await fetch(e),s=await o.blob(),h=await this.pdfKit.createAttachment(s),c=createImageAnnotation(new PSPDFKit.Geometry.Rect({left:r,top:u,width:n,height:i}),t.pageIndex,h,generateId(this.envelopeReceiver.envelopeId,this.envelopeReceiver.receiverId,this.fakeElementId--,"signed"));this.pdfKit.create(c)}}async handleClick(n){let t=!1;switch(n){case"RESET":t=await this.handleReset(null);Comp.SignatureProgress.SignedCount=0;t.isConfirmed&&Swal.fire({title:localized.success,text:localized.documentReset,icon:"info"});break;case"FINISH":t=await this.handleFinish(null);t==!0&&(window.location.href=`/Envelope/${this.envelopeKey}`);break;case"REJECT":Swal.fire({title:localized.rejection,html:`
${localized.rejectionReasonQ}
`,icon:"question",input:"text",inputAttributes:{autocapitalize:"off"},showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.complete,cancelButtonText:localized.back,showLoaderOnConfirm:!0,preConfirm:async n=>{try{return await rejectEnvelope(n)}catch(t){Swal.showValidationMessage(` Request failed: ${t} - `)}},allowOutsideClick:()=>!Swal.isLoading()}).then(n=>{if(n.isConfirmed){const t=n.value;t.ok?reload():Swal.showValidationMessage(`Request failed: ${t.message}`)}});break;case"COPY_URL":const n=window.location.href.replace(/\/readonly/gi,"");navigator.clipboard.writeText(n).then(function(){bsNotify(localized.copyLinkSuccess,{alert_type:"success",delay:4,icon_name:"check_circle"})}).catch(function(){bsNotify(localized.copyLinkFailure??localized.unexpectedErrorTitle,{alert_type:"danger",delay:4,icon_name:"error"})});break;case"SHARE":Comp.ShareBackdrop.show();break;case"LOGOUT":await logout()}}async handleFinish(){let n=undefined;if(READ_AND_CONFIRM){const n=JSON.parse(sessionStorage.getItem("pspdf_all_pages_rendered")||"false")===!0;if(!n){const n=JSON.parse(sessionStorage.getItem("pspdf_unviewed_pages")||"[]"),t=n.length?formatLocalized(localized.viewRemainingPages,n.join(", ")):localized.viewAllPages;return await Swal.fire({title:localized.warning,text:t,icon:"warning"}),!1}}else{const i=await this.pdfKit.exportInstantJSON(),r=i.formFieldValues,u=r.filter(n=>isFieldRequired(n)),f=u.some(n=>n.value===undefined||n.value===null||n.value==="");if(f)return Swal.fire({title:localized.warning,text:localized.locationFieldsRequired,icon:"warning"}),!1;const e=new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$"),o=r.filter(n=>isCityField(n));for(var t of o)if(!IS_MOBILE_DEVICE&&!e.test(t.value))return Swal.fire({title:localized.warning,text:formatLocalized(localized.cityFormatInvalid,t.value),icon:"warning"}),!1;const s=await this.validateAnnotations(this.signatureCount);if(s===!1)return Swal.fire({title:localized.warning,text:localized.missingSignatures,icon:"warning"}),!1;n={instant:i,structured:mapSignature(i)}}return Swal.fire({title:localized.confirmation,html:`
${localized.sigAgree}
`,icon:"question",showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.finalize,cancelButtonText:localized.back}).then(async t=>{if(t.isConfirmed){try{await this.pdfKit.save()}catch(i){return Swal.fire({title:localized.warning,text:localized.envelopeSignError,icon:"error"}),!1}try{const t=READ_AND_CONFIRM?await signEnvelope():await signEnvelope(n);if(t.ok)return!0;if(t.status===409)return Swal.fire({title:localized.warning,text:localized.envelopeUnavailable,icon:"warning"}),!1;if(t.status===423)Swal.fire({title:localized.info??localized.warning,text:localized.envelopeRejectedRedirect,icon:"info",timer:2e3,showConfirmButton:!1}).then(()=>{location.reload()});else throw new Error;}catch(i){return Swal.fire({title:localized.warning,text:localized.envelopeSignError,icon:"error"}),!1}}else return!1})}async validateAnnotations(n){const t=await getAnnotations(this.pdfKit),i=t.map(n=>n.toJS()).filter(n=>n.isSignature);return n<=i.length}async handleReset(){const n=Swal.fire({title:localized.resetConfirmTitle,text:localized.resetConfirmText,icon:"question",showCancelButton:!0});if(n.isConfirmed){const n=await deleteAnnotations(this.pdfKit)}return n}fakeElementId=0;} \ No newline at end of file + `)}},allowOutsideClick:()=>!Swal.isLoading()}).then(n=>{if(n.isConfirmed){const t=n.value;t.ok?reload():Swal.showValidationMessage(`Request failed: ${t.message}`)}});break;case"COPY_URL":const n=window.location.href.replace(/\/readonly/gi,"");navigator.clipboard.writeText(n).then(function(){bsNotify(localized.copyLinkSuccess,{alert_type:"success",delay:4,icon_name:"check_circle"})}).catch(function(){bsNotify(localized.copyLinkFailure??localized.unexpectedErrorTitle,{alert_type:"danger",delay:4,icon_name:"error"})});break;case"SHARE":Comp.ShareBackdrop.show();break;case"LOGOUT":await logout()}}async handleFinish(){let n=undefined;if(READ_AND_CONFIRM){const n=JSON.parse(sessionStorage.getItem("pspdf_all_pages_rendered")||"false")===!0;if(!n){const n=JSON.parse(sessionStorage.getItem("pspdf_unviewed_pages")||"[]"),t=n.length?formatLocalized(localized.viewRemainingPages,n.join(", ")):localized.viewAllPages;return await Swal.fire({title:localized.warning,text:t,icon:"warning"}),!1}}else{const i=await this.pdfKit.exportInstantJSON(),r=i.formFieldValues,u=r.filter(n=>isFieldRequired(n)),f=u.some(n=>n.value===undefined||n.value===null||n.value==="");if(f)return Swal.fire({title:localized.warning,text:localized.locationFieldsRequired,icon:"warning"}),!1;const e=new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$"),o=r.filter(n=>isCityField(n));for(var t of o)if(!IS_MOBILE_DEVICE&&!e.test(t.value))return Swal.fire({title:localized.warning,text:formatLocalized(localized.cityFormatInvalid,t.value),icon:"warning"}),!1;const s=await this.validateAnnotations(this.signatureCount);if(s===!1)return Swal.fire({title:localized.warning,text:localized.missingSignatures,icon:"warning"}),!1;n={instant:i,structured:mapSignature(i)}}return Swal.fire({title:localized.confirmation,html:`
${READ_AND_CONFIRM?localized.confirmAgree:localized.sigAgree}
`,icon:"question",showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.finalize,cancelButtonText:localized.back}).then(async t=>{if(t.isConfirmed){try{await this.pdfKit.save()}catch(i){return Swal.fire({title:localized.warning,text:localized.envelopeSignError,icon:"error"}),!1}try{const t=READ_AND_CONFIRM?await signEnvelope():await signEnvelope(n);if(t.ok)return!0;if(t.status===409)return Swal.fire({title:localized.warning,text:localized.envelopeUnavailable,icon:"warning"}),!1;if(t.status===423)Swal.fire({title:localized.info??localized.warning,text:localized.envelopeRejectedRedirect,icon:"info",timer:2e3,showConfirmButton:!1}).then(()=>{location.reload()});else throw new Error;}catch(i){return Swal.fire({title:localized.warning,text:localized.envelopeSignError,icon:"error"}),!1}}else return!1})}async validateAnnotations(n){const t=await getAnnotations(this.pdfKit),i=t.map(n=>n.toJS()).filter(n=>n.isSignature);return n<=i.length}async handleReset(){const n=Swal.fire({title:localized.resetConfirmTitle,text:localized.resetConfirmText,icon:"question",showCancelButton:!0});if(n.isConfirmed){const n=await deleteAnnotations(this.pdfKit)}return n}fakeElementId=0;} \ No newline at end of file From 7c7674c822571db212f2af90bc5da37764f6e629 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 6 Mar 2026 12:55:30 +0100 Subject: [PATCH 43/74] Show "Confirmed by" or "Signed by" label conditionally The signature label now displays "Confirmed by" if READ_AND_CONFIRM is true, otherwise "Signed by". This uses the appropriate localized string when available, defaulting to "Signed by" if not. Previously, only "Signed by" was shown. --- EnvelopeGenerator.Web/wwwroot/js/annotation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Web/wwwroot/js/annotation.js b/EnvelopeGenerator.Web/wwwroot/js/annotation.js index 55b53758..debb5e88 100644 --- a/EnvelopeGenerator.Web/wwwroot/js/annotation.js +++ b/EnvelopeGenerator.Web/wwwroot/js/annotation.js @@ -275,7 +275,7 @@ async function createAnnotationFrameBlob(receiverName, receiverSignature, timest ctx.fillStyle = 'black' ctx.font = `${fontSize * scale}px sans-serif` - ctx.fillText(localized.signedBy ?? 'Signed by', 15 * scale, 10 * scale) + ctx.fillText((READ_AND_CONFIRM ? localized.confirmedBy : localized.signedBy) ?? 'Signed by', 15 * scale, 10 * scale) ctx.fillText(receiverName, 15 * scale, 60 * scale) ctx.fillText(signatureString, 15 * scale, 70 * scale) From 73df248d153b823c9c6b52fbf55dcd73dc32b4ff Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 9 Mar 2026 22:50:55 +0100 Subject: [PATCH 44/74] Update System.Text.Json to 8.0.6 and enhance ClickOnce config - Upgraded System.Text.Json NuGet package and binding redirects to 8.0.6. - Updated project references to use System.Text.Json 8.0.0.6. - Enhanced ClickOnce publishing settings: set PublishUrl, enabled autorun, completed wizard, and added manifest signing with a temporary key. - Minor formatting and property order adjustments in the project file. --- EnvelopeGenerator.Service/App.config | 2 +- .../EnvelopeGenerator.Service.vbproj | 28 +++++++++++++++---- EnvelopeGenerator.Service/packages.config | 2 +- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/EnvelopeGenerator.Service/App.config b/EnvelopeGenerator.Service/App.config index 445dd0b3..a817cfcc 100644 --- a/EnvelopeGenerator.Service/App.config +++ b/EnvelopeGenerator.Service/App.config @@ -51,7 +51,7 @@ - + diff --git a/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj b/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj index 03df4c62..7c4d2948 100644 --- a/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj +++ b/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj @@ -1,4 +1,4 @@ - + @@ -17,7 +17,8 @@ - publish\ + false + P:\Install .Net\0 DD - Smart UP\signFLOW\Finalization\%24%28Version%29\ true Disk false @@ -27,10 +28,11 @@ false false true + true 0 1.0.0.%2a - false false + true true @@ -65,6 +67,18 @@ On + + 905CDA07C40CC715F90A2F2A0C5C0E5BAACE138B + + + EnvelopeGenerator.Service_TemporaryKey.pfx + + + true + + + true + ..\packages\BouncyCastle.Cryptography.2.6.2\lib\net461\BouncyCastle.Cryptography.dll @@ -258,8 +272,8 @@ ..\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll - - ..\packages\System.Text.Json.8.0.5\lib\net462\System.Text.Json.dll + + ..\packages\System.Text.Json.8.0.6\lib\net462\System.Text.Json.dll ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll @@ -337,6 +351,7 @@ + MyApplicationCodeGenerator Application.Designer.vb @@ -382,4 +397,5 @@ - \ No newline at end of file + + diff --git a/EnvelopeGenerator.Service/packages.config b/EnvelopeGenerator.Service/packages.config index 6ccec828..b3d22784 100644 --- a/EnvelopeGenerator.Service/packages.config +++ b/EnvelopeGenerator.Service/packages.config @@ -35,7 +35,7 @@ - + \ No newline at end of file From 18a563ecd18fd8485e763e2dd5a86f1a294a7a2d Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 00:02:22 +0100 Subject: [PATCH 45/74] Improve annotation handling and date retrieval robustness Refactored annotation processing in PDFBurner.vb to handle null elements and annotations safely, preventing possible errors and improving code clarity. Updated GetSignedDate in ReceiverModel.vb to ensure consistent DateTime return values, handle DBNull and type conversions, and improve error handling. --- .../Jobs/FinalizeDocument/PDFBurner.vb | 31 ++++++++++++++++--- .../Models/ReceiverModel.vb | 18 +++++++++-- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/PDFBurner.vb b/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/PDFBurner.vb index 781615ac..97347a72 100644 --- a/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/PDFBurner.vb +++ b/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/PDFBurner.vb @@ -85,16 +85,37 @@ Namespace Jobs.FinalizeDocument 'Add annotations For Each element In elements + If element Is Nothing Then + Continue For + End If + + Dim elementAnnotations = If(element.Annotations, Enumerable.Empty(Of ElementAnnotation)()) + If Not elementAnnotations.Any() Then + Continue For + End If Dim frameX = (element.Left - 0.7 - margin) - Dim frame = element.Annotations.FirstOrDefault(Function(a) a.Name = "frame") + Dim frame = elementAnnotations.FirstOrDefault(Function(a) a.Name = "frame") Dim frameY = element.Top - 0.5 - margin - Dim frameYShift = frame.Y - frameY * inchFactor - Dim frameXShift = frame.X - frameX * inchFactor + Dim frameYShift As Double = 0 + Dim frameXShift As Double = 0 + + If frame IsNot Nothing Then + frameYShift = frame.Y - frameY * inchFactor + frameXShift = frame.X - frameX * inchFactor + End If + + For Each annot In elementAnnotations + If annot Is Nothing Then + Continue For + End If + + Dim yOffsetofFF As Double = 0 + If Not String.IsNullOrEmpty(annot.Name) Then + yOffsetsOfFF.TryGetValue(annot.Name, yOffsetofFF) + End If - For Each annot In element.Annotations - Dim yOffsetofFF As Double = If(yOffsetsOfFF.TryGetValue(annot.Name, yOffsetofFF), yOffsetofFF, 0) Dim y = frameY + yOffsetofFF If annot.Type = AnnotationType.FormField Then diff --git a/EnvelopeGenerator.CommonServices/Models/ReceiverModel.vb b/EnvelopeGenerator.CommonServices/Models/ReceiverModel.vb index 2d2395c9..78408d40 100644 --- a/EnvelopeGenerator.CommonServices/Models/ReceiverModel.vb +++ b/EnvelopeGenerator.CommonServices/Models/ReceiverModel.vb @@ -270,12 +270,26 @@ Public Class ReceiverModel Private Function GetSignedDate(pEmailAddress As String, pEnvelopeId As Integer) As Date Try Dim oStatusInt As Integer = EnvelopeStatus.DocumentSigned - Return Database.GetScalarValue($"SELECT ACTION_DATE FROM [DD_ECM].[dbo].[TBSIG_ENVELOPE_HISTORY] WHERE ENVELOPE_ID = {pEnvelopeId} + Dim value = Database.GetScalarValue($"SELECT ACTION_DATE FROM [DD_ECM].[dbo].[TBSIG_ENVELOPE_HISTORY] WHERE ENVELOPE_ID = {pEnvelopeId} And USER_REFERENCE = '{pEmailAddress}' AND [STATUS] = {oStatusInt}") + If value Is Nothing OrElse value Is DBNull.Value Then + Return DateTime.MinValue + End If + + If TypeOf value Is DateTime Then + Return DirectCast(value, DateTime) + End If + + Dim parsedDate As DateTime + If DateTime.TryParse(value.ToString(), parsedDate) Then + Return parsedDate + End If + + Return DateTime.MinValue Catch ex As Exception Logger.Error(ex) - Return Nothing + Return DateTime.MinValue End Try End Function From 0d56ac74489d428fdbb436685a9d1606017f6d36 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 00:02:32 +0100 Subject: [PATCH 46/74] Downgrade several NuGet package dependencies Reverted multiple packages in packages.config to earlier versions, including EntityFramework, System.Text.Json, System.Buffers, and others. These downgrades address compatibility issues and ensure alignment with other project dependencies. --- EnvelopeGenerator.BBTests/packages.config | 30 +++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/EnvelopeGenerator.BBTests/packages.config b/EnvelopeGenerator.BBTests/packages.config index 1114c525..2b6489de 100644 --- a/EnvelopeGenerator.BBTests/packages.config +++ b/EnvelopeGenerator.BBTests/packages.config @@ -15,13 +15,13 @@ - + - + @@ -62,10 +62,10 @@ - + - - + + @@ -74,23 +74,23 @@ - + - - + + - - + + - + - - + + - - + + \ No newline at end of file From 2f41348c5902b36360efe91b3b7d6e35f27faf18 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 01:23:06 +0100 Subject: [PATCH 47/74] Add System.ComponentModel.Annotations NuGet package Added System.ComponentModel.Annotations v4.7.0 to support data validation and metadata attributes in .NET Framework 4.8 projects. --- EnvelopeGenerator.Service/packages.config | 1 + 1 file changed, 1 insertion(+) diff --git a/EnvelopeGenerator.Service/packages.config b/EnvelopeGenerator.Service/packages.config index b3d22784..86eb10dc 100644 --- a/EnvelopeGenerator.Service/packages.config +++ b/EnvelopeGenerator.Service/packages.config @@ -27,6 +27,7 @@ + From 69892d566c7eb27ff7b13b94263f28df07b0aec7 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 01:23:26 +0100 Subject: [PATCH 48/74] Add System.ComponentModel.Annotations reference to project Added a reference to System.ComponentModel.Annotations v4.2.1.0 in EnvelopeGenerator.Service.vbproj, specifying the HintPath to the appropriate DLL in the packages directory. This enables use of additional data annotation attributes in the project. --- EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj b/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj index 7c4d2948..f9faacfa 100644 --- a/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj +++ b/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj @@ -235,6 +235,9 @@ ..\packages\System.Collections.Immutable.8.0.0\lib\net462\System.Collections.Immutable.dll + + ..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll + From 82c85643c81c2b80a2e3e17814a190d1f3616674 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 01:45:46 +0100 Subject: [PATCH 49/74] Add EF Core, SqlClient, and Microsoft.Extensions packages Updated .vbproj and packages.config to include references and NuGet packages for Microsoft.Data.SqlClient, Entity Framework Core, AutoMapper, and various Microsoft.Extensions libraries (configuration, logging, caching, options). Added import and error checks for SqlClient SNI targets. No source code changes; all updates are related to project and package management. --- .../EnvelopeGenerator.Service.vbproj | 59 +++++++++++++++++++ EnvelopeGenerator.Service/packages.config | 52 ++++++++++------ 2 files changed, 94 insertions(+), 17 deletions(-) diff --git a/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj b/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj index f9faacfa..943edb50 100644 --- a/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj +++ b/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj @@ -291,6 +291,63 @@ + + ..\packages\Microsoft.Data.SqlClient.6.1.4\lib\net462\Microsoft.Data.SqlClient.dll + + + ..\packages\AutoMapper.10.1.1\lib\net461\AutoMapper.dll + + + ..\packages\DigitalData.Core.Abstraction.Application.1.6.0\lib\net462\DigitalData.Core.Abstraction.Application.dll + + + ..\packages\Microsoft.Bcl.HashCode.1.1.1\lib\net461\Microsoft.Bcl.HashCode.dll + + + ..\packages\Microsoft.EntityFrameworkCore.3.1.32\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Abstractions.3.1.32\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Abstractions.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Relational.3.1.32\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll + + + ..\packages\Microsoft.EntityFrameworkCore.SqlServer.3.1.32\lib\netstandard2.0\Microsoft.EntityFrameworkCore.SqlServer.dll + + + ..\packages\Microsoft.Extensions.Caching.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.Caching.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Caching.Memory.8.0.1\lib\net462\Microsoft.Extensions.Caching.Memory.dll + + + ..\packages\Microsoft.Extensions.Configuration.7.0.0\lib\net462\Microsoft.Extensions.Configuration.dll + + + ..\packages\Microsoft.Extensions.Configuration.Abstractions.7.0.0\lib\net462\Microsoft.Extensions.Configuration.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Configuration.Binder.7.0.0\lib\net462\Microsoft.Extensions.Configuration.Binder.dll + + + ..\packages\Microsoft.Extensions.Logging.7.0.0\lib\net462\Microsoft.Extensions.Logging.dll + + + ..\packages\Microsoft.Extensions.Options.8.0.2\lib\net462\Microsoft.Extensions.Options.dll + + + ..\packages\Microsoft.Extensions.Options.ConfigurationExtensions.7.0.0\lib\net462\Microsoft.Extensions.Options.ConfigurationExtensions.dll + + + ..\packages\Microsoft.Extensions.Primitives.8.0.0\lib\net462\Microsoft.Extensions.Primitives.dll + + + ..\packages\System.Data.Common.4.3.0\lib\net451\System.Data.Common.dll + + + ..\packages\System.Diagnostics.DiagnosticSource.8.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll + @@ -398,7 +455,9 @@ + + diff --git a/EnvelopeGenerator.Service/packages.config b/EnvelopeGenerator.Service/packages.config index 86eb10dc..8985181f 100644 --- a/EnvelopeGenerator.Service/packages.config +++ b/EnvelopeGenerator.Service/packages.config @@ -1,34 +1,36 @@  + - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - + + + + @@ -39,4 +41,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file From c523153654505c8920e0a26f943d3eb4c8e596fc Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 02:16:58 +0100 Subject: [PATCH 50/74] Add "Full Finalize Test" button for PDF finalization debug Added a new "Full Finalize Test" button to frmFinalizePDF, along with its event handler. The handler loads annotation data, document bytes, and related entities, logs detailed information about the envelope and signatures, and tests the PDF annotation burning process. The result is saved to the desktop and opened automatically. Also added necessary repository/entity imports for EF Core access. This feature aids in debugging and verifying the full PDF finalization workflow. --- .../frmFinalizePDF.Designer.vb | 12 +++ EnvelopeGenerator.BBTests/frmFinalizePDF.vb | 84 +++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/EnvelopeGenerator.BBTests/frmFinalizePDF.Designer.vb b/EnvelopeGenerator.BBTests/frmFinalizePDF.Designer.vb index 5a2794e2..2cd0616b 100644 --- a/EnvelopeGenerator.BBTests/frmFinalizePDF.Designer.vb +++ b/EnvelopeGenerator.BBTests/frmFinalizePDF.Designer.vb @@ -27,6 +27,7 @@ Partial Class frmFinalizePDF Me.Label2 = New System.Windows.Forms.Label() Me.Button1 = New System.Windows.Forms.Button() Me.Button2 = New System.Windows.Forms.Button() + Me.Button3 = New System.Windows.Forms.Button() Me.txtResult = New System.Windows.Forms.TextBox() Me.txtEnvelope = New System.Windows.Forms.TextBox() Me.SuspendLayout() @@ -75,6 +76,15 @@ Partial Class frmFinalizePDF Me.Button2.Text = "Merge Json" Me.Button2.UseVisualStyleBackColor = True ' + 'Button3 + ' + Me.Button3.Location = New System.Drawing.Point(15, 160) + Me.Button3.Name = "Button3" + Me.Button3.Size = New System.Drawing.Size(166, 23) + Me.Button3.TabIndex = 5 + Me.Button3.Text = "Full Finalize Test" + Me.Button3.UseVisualStyleBackColor = True + ' 'txtResult ' Me.txtResult.Location = New System.Drawing.Point(333, 12) @@ -97,6 +107,7 @@ Partial Class frmFinalizePDF Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font Me.ClientSize = New System.Drawing.Size(800, 450) Me.Controls.Add(Me.txtResult) + Me.Controls.Add(Me.Button3) Me.Controls.Add(Me.Button2) Me.Controls.Add(Me.Button1) Me.Controls.Add(Me.Label2) @@ -116,5 +127,6 @@ Partial Class frmFinalizePDF Friend WithEvents Label2 As Label Friend WithEvents Button1 As Button Friend WithEvents Button2 As Button + Friend WithEvents Button3 As Button Friend WithEvents txtResult As TextBox End Class diff --git a/EnvelopeGenerator.BBTests/frmFinalizePDF.vb b/EnvelopeGenerator.BBTests/frmFinalizePDF.vb index 56122a17..24847ec0 100644 --- a/EnvelopeGenerator.BBTests/frmFinalizePDF.vb +++ b/EnvelopeGenerator.BBTests/frmFinalizePDF.vb @@ -8,6 +8,8 @@ Imports Newtonsoft.Json.Linq Imports EnvelopeGenerator.Infrastructure Imports Microsoft.EntityFrameworkCore Imports DigitalData.Core.Abstractions +Imports DigitalData.Core.Abstraction.Application.Repository +Imports EnvelopeGenerator.Domain.Entities Public Class frmFinalizePDF Private Const CONNECTIONSTRING = "Server=sDD-VMP04-SQL17\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=+bk8oAbbQP1AzoHtvZUbd+Mbok2f8Fl4miEx1qssJ5yEaEWoQJ9prg4L14fURpPnqi1WMNs9fE4=;" + "Encrypt=True;TrustServerCertificate=True;" @@ -124,4 +126,86 @@ Public Class frmFinalizePDF txtResult.Text = oJObject1.ToString() End Sub + + Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click + Try + Dim envelopeId As Integer = CInt(txtEnvelope.Text) + Dim log As New System.Text.StringBuilder() + + ' 1. Load annotation JSON data (same as Service) + Dim oTable = LoadAnnotationDataForEnvelope() + Dim oJsonList = oTable.Rows. + Cast(Of DataRow). + Select(Function(r As DataRow) r.Item("VALUE").ToString()). + ToList() + log.AppendLine($"Annotation JSON count: {oJsonList.Count}") + + ' 2. Load document bytes (same as Service) + Dim oBuffer As Byte() = ReadEnvelope(envelopeId) + log.AppendLine($"Document bytes: {oBuffer.Length}") + + ' 3. Check what BurnAnnotsToPDF will do internally + Using scope = Factory.Shared.ScopeFactory.CreateScope() + Dim envRepo = scope.ServiceProvider.Repository(Of Envelope)() + Dim envelope = envRepo.Where(Function(env) env.Id = envelopeId).FirstOrDefault() + + If envelope Is Nothing Then + log.AppendLine("ERROR: Envelope not found in EF Core!") + txtResult.Text = log.ToString() + Return + End If + + log.AppendLine($"Envelope found: Id={envelope.Id}, EnvelopeTypeId={envelope.EnvelopeTypeId}") + log.AppendLine($"ReadOnly (IsReadAndConfirm): {envelope.ReadOnly}") + + If envelope.ReadOnly Then + log.AppendLine(">>> EARLY RETURN: ReadOnly=True, original PDF returned without burning") + txtResult.Text = log.ToString() + Return + End If + + Dim sigRepo = scope.ServiceProvider.Repository(Of Signature)() + Dim elements = sigRepo _ + .Where(Function(sig) sig.Document.EnvelopeId = envelopeId) _ + .Include(Function(sig) sig.Annotations) _ + .ToList() + + log.AppendLine($"Elements (Signature) count: {elements.Count}") + + If elements.Any() Then + log.AppendLine(">>> PATH: BurnElementAnnotsToPDF (new element-based path)") + For Each elem In elements + Dim annotCount = If(elem.Annotations IsNot Nothing, elem.Annotations.Count(), 0) + log.AppendLine($" Element Id={elem.Id}, Page={elem.Page}, X={elem.X}, Y={elem.Y}, W={elem.Width}, H={elem.Height}, Annotations={annotCount}") + If elem.Annotations IsNot Nothing Then + For Each annot In elem.Annotations + log.AppendLine($" Annot: Name={annot.Name}, Type={annot.Type}, X={annot.X}, Y={annot.Y}, W={annot.Width}, H={annot.Height}") + Next + End If + Next + Else + log.AppendLine(">>> PATH: BurnInstantJSONAnnotsToPDF (old JSON-based path)") + End If + End Using + + ' 4. Actually call BurnAnnotsToPDF (same as Service) + log.AppendLine("") + log.AppendLine("Calling BurnAnnotsToPDF...") + Dim oNewBuffer = PDFBurner.BurnAnnotsToPDF(oBuffer, oJsonList, envelopeId) + log.AppendLine($"Result bytes: {oNewBuffer.Length}") + log.AppendLine($"Same as input: {oBuffer.Length = oNewBuffer.Length AndAlso oBuffer.SequenceEqual(oNewBuffer)}") + + ' 5. Write output + Dim desktopPath As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + Dim oNewPath = Path.Combine(desktopPath, $"E{txtEnvelope.Text}_FullTest.burned.pdf") + File.WriteAllBytes(oNewPath, oNewBuffer) + log.AppendLine($"Output: {oNewPath}") + + txtResult.Text = log.ToString() + Process.Start(oNewPath) + + Catch ex As Exception + txtResult.Text = $"ERROR: {ex.Message}{vbCrLf}{vbCrLf}{ex.ToString()}" + End Try + End Sub End Class \ No newline at end of file From 8a534b84d001b2d7858b21d29880e05273e3b092 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 02:17:17 +0100 Subject: [PATCH 51/74] Update NuGet packages and binding redirects to latest versions Updated NuGet package references and assembly binding redirects in App.config, EnvelopeGenerator.Service.vbproj, and packages.config to newer versions compatible with .NET 4.8/4.6.2/4.6.3. No application logic changes; these updates ensure dependency consistency and improved framework compatibility. --- EnvelopeGenerator.Service/App.config | 12 ++--- .../EnvelopeGenerator.Service.vbproj | 29 ++++++----- EnvelopeGenerator.Service/packages.config | 50 +++++++++---------- 3 files changed, 45 insertions(+), 46 deletions(-) diff --git a/EnvelopeGenerator.Service/App.config b/EnvelopeGenerator.Service/App.config index a817cfcc..9349ae8f 100644 --- a/EnvelopeGenerator.Service/App.config +++ b/EnvelopeGenerator.Service/App.config @@ -15,7 +15,7 @@ - + @@ -23,15 +23,15 @@ - + - + - + @@ -39,7 +39,7 @@ - + @@ -135,7 +135,7 @@ - + diff --git a/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj b/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj index 943edb50..17e5ead9 100644 --- a/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj +++ b/EnvelopeGenerator.Service/EnvelopeGenerator.Service.vbproj @@ -226,8 +226,8 @@ ..\packages\RtfPipe.2.0.7677.4303\lib\net45\RtfPipe.dll - - ..\packages\System.Buffers.4.6.0\lib\net462\System.Buffers.dll + + ..\packages\System.Buffers.4.6.1\lib\net462\System.Buffers.dll ..\packages\System.CodeDom.8.0.0\lib\net462\System.CodeDom.dll @@ -251,18 +251,18 @@ ..\packages\System.IO.Packaging.8.0.1\lib\net462\System.IO.Packaging.dll - - ..\packages\System.Memory.4.6.0\lib\net462\System.Memory.dll + + ..\packages\System.Memory.4.6.3\lib\net462\System.Memory.dll ..\packages\Microsoft.AspNet.WebApi.Client.6.0.0\lib\net45\System.Net.Http.Formatting.dll - - ..\packages\System.Numerics.Vectors.4.6.0\lib\net462\System.Numerics.Vectors.dll + + ..\packages\System.Numerics.Vectors.4.6.1\lib\net462\System.Numerics.Vectors.dll - - ..\packages\System.Runtime.CompilerServices.Unsafe.6.1.0\lib\net462\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.1.2\lib\net462\System.Runtime.CompilerServices.Unsafe.dll @@ -278,12 +278,12 @@ ..\packages\System.Text.Json.8.0.6\lib\net462\System.Text.Json.dll - - ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + ..\packages\System.Threading.Tasks.Extensions.4.6.0\lib\net462\System.Threading.Tasks.Extensions.dll - - ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + + ..\packages\System.ValueTuple.4.6.1\lib\net462\System.ValueTuple.dll @@ -293,7 +293,7 @@ ..\packages\Microsoft.Data.SqlClient.6.1.4\lib\net462\Microsoft.Data.SqlClient.dll - + ..\packages\AutoMapper.10.1.1\lib\net461\AutoMapper.dll @@ -459,5 +459,4 @@ - - + \ No newline at end of file diff --git a/EnvelopeGenerator.Service/packages.config b/EnvelopeGenerator.Service/packages.config index 8985181f..86c8073d 100644 --- a/EnvelopeGenerator.Service/packages.config +++ b/EnvelopeGenerator.Service/packages.config @@ -2,8 +2,16 @@ - + + + + + + + + + @@ -25,30 +33,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -57,4 +41,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file From eb5db3d6bed2a50f3b71addf5f8909f8c7cc3304 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 02:44:12 +0100 Subject: [PATCH 52/74] Remove StatusChangedWhen from DocumentStatus entity The StatusChangedWhen property, previously required and mapped to the "STATUS_CHANGED_WHEN" column, has been removed from the DocumentStatus entity in the EnvelopeGenerator.Domain.Entities namespace. This change simplifies the entity and its mapping. --- EnvelopeGenerator.Domain/Entities/DocumentStatus.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs b/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs index 3bec79c7..7a3a8fcd 100644 --- a/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs +++ b/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs @@ -35,7 +35,6 @@ namespace EnvelopeGenerator.Domain.Entities [Column("STATUS")] public Constants.DocumentStatus Status { get; set; } - [Required] [Column("STATUS_CHANGED_WHEN", TypeName = "datetime")] public DateTime? StatusChangedWhen { get; set; } From 7281cb47c38c30328fc659d75b0c46c0f8097f63 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 03:25:38 +0100 Subject: [PATCH 53/74] Remove duplicate ProjectReference in BBTests.vbproj Eliminated a redundant ProjectReference to EnvelopeGenerator.CommonServices.vbproj from the EnvelopeGenerator.BBTests.vbproj file, ensuring only a single reference remains. This helps prevent potential build issues and maintains project file clarity. --- EnvelopeGenerator.BBTests/EnvelopeGenerator.BBTests.vbproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/EnvelopeGenerator.BBTests/EnvelopeGenerator.BBTests.vbproj b/EnvelopeGenerator.BBTests/EnvelopeGenerator.BBTests.vbproj index de126637..63b3db6d 100644 --- a/EnvelopeGenerator.BBTests/EnvelopeGenerator.BBTests.vbproj +++ b/EnvelopeGenerator.BBTests/EnvelopeGenerator.BBTests.vbproj @@ -487,10 +487,6 @@ {6EA0C51F-C2B1-4462-8198-3DE0B32B74F8} EnvelopeGenerator.CommonServices - - {6ea0c51f-c2b1-4462-8198-3de0b32b74f8} - EnvelopeGenerator.CommonServices - {4f32a98d-e6f0-4a09-bd97-1cf26107e837} EnvelopeGenerator.Domain From 466d0a3a7aa0497c2fa1b0e8898ed330fc0d3390 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 04:07:14 +0100 Subject: [PATCH 54/74] Refactor envelope and annotation data retrieval logic Add private helper functions ReadEnvelope and LoadAnnotationDataForEnvelope to centralize retrieval of envelope byte data and annotation JSON from the database. Update PDF annotation burning logic to use these helpers, improving code reuse and testability. --- .../FinalizeDocument/FinalizeDocumentJob.vb | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/FinalizeDocumentJob.vb b/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/FinalizeDocumentJob.vb index cfd2af5e..c921b4df 100644 --- a/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/FinalizeDocumentJob.vb +++ b/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/FinalizeDocumentJob.vb @@ -230,6 +230,29 @@ Namespace Jobs Return Task.FromResult(True) End Function + +#Region "From BBTests" + Private Function ReadEnvelope(pEnvID As Integer) As Byte() + Dim strSql As String = "Select [BYTE_DATA] from [TBSIG_ENVELOPE_DOCUMENT] WHERE ENVELOPE_ID = " & pEnvID + Dim obyteDB = Database.GetScalarValue(strSql) + If Not IsDBNull(obyteDB) Then + Dim fileData As Byte() = DirectCast(Database.GetScalarValue(strSql), Byte()) + If fileData IsNot Nothing Then + Return fileData + End If + End If + + Throw New InvalidOperationException($"Byte data is null. Envelope ID: {pEnvID}") + + End Function + + Private Function LoadAnnotationDataForEnvelope(pEnvID As Integer) As DataTable + Dim oSql = $"SELECT VALUE FROM [TBSIG_DOCUMENT_STATUS] WHERE ENVELOPE_ID = {pEnvID}" + Return Database.GetDatatable(oSql) + + End Function +#End Region + Private Sub Update_File_DB(pFilePath As String, pEnvelopeID As Long) Dim SqlCom As SqlCommand Dim imageData As Byte() @@ -418,7 +441,18 @@ Namespace Jobs End Try End If - Return PDFBurner.BurnAnnotsToPDF(oInputDocumentBuffer, oAnnotations, pEnvelopeData.EnvelopeId) +#Region "From BBTests" + Dim oTable = LoadAnnotationDataForEnvelope(pEnvelopeId) + Dim oJsonList = oTable.Rows. + Cast(Of DataRow). + Select(Function(r As DataRow) r.Item("VALUE").ToString()). + ToList() + + Dim oBuffer As Byte() = ReadEnvelope(pEnvelopeId) + +#End Region + + Return PDFBurner.BurnAnnotsToPDF(oBuffer, oJsonList, pEnvelopeId) End Function Private Function GetEnvelopeData(pEnvelopeId As Integer) As EnvelopeData From b20aafe7a512a404367d2a309d730756d2391d26 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 04:07:28 +0100 Subject: [PATCH 55/74] Fix PDF/A conversion status check in PDFMerger Previously, the code checked the status of the original document after converting the merged PDF to PDF/A, which could miss conversion errors. Now, it correctly checks the status of the merged PDF to ensure the conversion succeeded. --- .../Jobs/FinalizeDocument/PDFMerger.vb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/PDFMerger.vb b/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/PDFMerger.vb index 207a916c..f0c3f963 100644 --- a/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/PDFMerger.vb +++ b/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/PDFMerger.vb @@ -56,7 +56,7 @@ Public Class PDFMerger ' Convert to PDF/A oMergedPDF.ConvertToPDFA(oFinalStream, PDFAConformanceLevel, ALLOW_VECTORIZATION, ALLOW_RASTERIZATION) - oStatus = oDocumentPDF.GetStat() + oStatus = oMergedPDF.GetStat() If oStatus <> GdPictureStatus.OK Then Throw New MergeDocumentException($"Document could not be converted to PDF/A: {oStatus}") End If From 1f5468b1ac54f8989cf5e396ee5ea395e3da7df6 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Mar 2026 04:07:37 +0100 Subject: [PATCH 56/74] Refactor PDF canvas transform to use Save/Restore state Move Y-axis flip transform inside signature drawing block and wrap with SaveState/RestoreState to prevent side effects on other drawing operations and pages. Removes redundant page-level transformation for better encapsulation. --- EnvelopeGenerator.PdfEditor/Pdf.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/EnvelopeGenerator.PdfEditor/Pdf.cs b/EnvelopeGenerator.PdfEditor/Pdf.cs index 03b629f0..22011f72 100644 --- a/EnvelopeGenerator.PdfEditor/Pdf.cs +++ b/EnvelopeGenerator.PdfEditor/Pdf.cs @@ -105,17 +105,13 @@ namespace EnvelopeGenerator.PdfEditor public Pdf Background(IEnumerable signatures, double widthPx = 1.9500000000000002, double heightPx = 2.52) where TSignature : ISignature { - // once per page - Page(page => - { - var canvas = new PdfCanvas(page); - canvas.ConcatMatrix(1, 0, 0, -1, 0, page.GetPageSize().GetHeight()); - }); - foreach (var signature in signatures) Page(signature.Page, page => { var canvas = new PdfCanvas(page); + canvas.SaveState(); + canvas.ConcatMatrix(1, 0, 0, -1, 0, page.GetPageSize().GetHeight()); + double inchFactor = 72; double magin = .2; double x = (signature.X - .7 - magin) * inchFactor; @@ -134,6 +130,8 @@ namespace EnvelopeGenerator.PdfEditor canvas.SetFillColor(new DeviceRgb(204, 202, 198)) .Rectangle(x, y + height - bottomLineLength, width, bottomLineLength) .Fill(); + + canvas.RestoreState(); }); return this; From ab4cd7c254c4aa9482f4fd1c510109ded8946f64 Mon Sep 17 00:00:00 2001 From: OlgunR Date: Tue, 10 Mar 2026 10:54:52 +0100 Subject: [PATCH 57/74] Update resources for confirmation workflows & English comments in CommonService.Strings.Model Replaced German comments/descriptions with English for clarity and internationalization. Added new resource strings for confirmation/read confirmation statuses (e.g., CompletelyConfirmed, Confirmation, DocumentConfirmed, etc.) to support both signing and read confirmation workflows. Corrected and standardized several existing resource values for consistency across languages. --- .../Strings/Model.Designer.vb | 200 +++++++++++++----- .../Strings/Model.en.resx | 38 +++- .../Strings/Model.resx | 34 ++- 3 files changed, 214 insertions(+), 58 deletions(-) diff --git a/EnvelopeGenerator.CommonServices/Strings/Model.Designer.vb b/EnvelopeGenerator.CommonServices/Strings/Model.Designer.vb index b121b4ef..090ee3b3 100644 --- a/EnvelopeGenerator.CommonServices/Strings/Model.Designer.vb +++ b/EnvelopeGenerator.CommonServices/Strings/Model.Designer.vb @@ -1,10 +1,10 @@ '------------------------------------------------------------------------------ ' -' Dieser Code wurde von einem Tool generiert. -' Laufzeitversion:4.0.30319.42000 +' This code was generated by a tool. +' Runtime Version:4.0.30319.42000 ' -' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -' der Code erneut generiert wird. +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. ' '------------------------------------------------------------------------------ @@ -15,12 +15,12 @@ Imports System Namespace My.Resources - 'Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert - '-Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. - 'Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen - 'mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + 'This class was auto-generated by the StronglyTypedResourceBuilder + 'class via a tool like ResGen or Visual Studio. + 'To add or remove a member, edit your .ResX file then rerun ResGen + 'with the /str option, or rebuild your VS project. ''' - ''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + ''' A strongly-typed resource class, for looking up localized strings, etc. ''' - ''' Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + ''' Returns the cached ResourceManager instance used by this class. '''
_ Public Shared ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager @@ -51,8 +51,8 @@ Namespace My.Resources End Property ''' - ''' Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle - ''' Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + ''' Overrides the current thread's CurrentUICulture property for all + ''' resource lookups using this strongly typed resource class. ''' _ Public Shared Property Culture() As Global.System.Globalization.CultureInfo @@ -65,7 +65,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Zugriffscode korrekt eingegeben ähnelt. + ''' Looks up a localized string similar to Zugriffscode korrekt eingegeben. ''' Public Shared ReadOnly Property AccessCodeCorrect() As String Get @@ -74,7 +74,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Zugriffscode falsch eingegeben ähnelt. + ''' Looks up a localized string similar to Zugriffscode falsch eingegeben. ''' Public Shared ReadOnly Property AccessCodeIncorrect() As String Get @@ -83,7 +83,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Zugriffscode angefordert ähnelt. + ''' Looks up a localized string similar to Zugriffscode angefordert. ''' Public Shared ReadOnly Property AccessCodeRequested() As String Get @@ -92,7 +92,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Fortgeschrittene Elektronische Signatur ähnelt. + ''' Looks up a localized string similar to Fortgeschrittene Elektronische Signatur. ''' Public Shared ReadOnly Property AdvancedElectronicSignature() As String Get @@ -101,7 +101,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Abgeschlossen ähnelt. + ''' Looks up a localized string similar to Abgeschlossen. ''' Public Shared ReadOnly Property Completed() As String Get @@ -110,7 +110,16 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Vollständig Signiert ähnelt. + ''' Looks up a localized string similar to Vollständig bestätigt. + ''' + Public Shared ReadOnly Property CompletelyConfirmed() As String + Get + Return ResourceManager.GetString("CompletelyConfirmed", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Vollständig signiert. ''' Public Shared ReadOnly Property CompletelySigned() As String Get @@ -119,7 +128,25 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Vertrag ähnelt. + ''' Looks up a localized string similar to Lesebestätigung. + ''' + Public Shared ReadOnly Property Confirmation() As String + Get + Return ResourceManager.GetString("Confirmation", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Gelesen und Bestätigt. + ''' + Public Shared ReadOnly Property Confirmed() As String + Get + Return ResourceManager.GetString("Confirmed", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Vertrag. ''' Public Shared ReadOnly Property Contract() As String Get @@ -128,7 +155,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Erstellt ähnelt. + ''' Looks up a localized string similar to Erstellt. ''' Public Shared ReadOnly Property Created() As String Get @@ -137,7 +164,16 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Dokument Rotation geändert ähnelt. + ''' Looks up a localized string similar to Dokument gelesen und bestätigt. + ''' + Public Shared ReadOnly Property DocumentConfirmed() As String + Get + Return ResourceManager.GetString("DocumentConfirmed", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Dokument Rotation geändert. ''' Public Shared ReadOnly Property DocumentMod_Rotation() As String Get @@ -146,7 +182,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Dokument geöffnet ähnelt. + ''' Looks up a localized string similar to Dokument geöffnet. ''' Public Shared ReadOnly Property DocumentOpened() As String Get @@ -155,7 +191,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Unterzeichnung abgelehnt ähnelt. + ''' Looks up a localized string similar to Unterzeichnung abgelehnt. ''' Public Shared ReadOnly Property DocumentRejected() As String Get @@ -164,7 +200,16 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Dokument unterzeichnet ähnelt. + ''' Looks up a localized string similar to Lesebestätigung abgelehnt. + ''' + Public Shared ReadOnly Property DocumentRejectedRaC() As String + Get + Return ResourceManager.GetString("DocumentRejectedRaC", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Dokument unterzeichnet. ''' Public Shared ReadOnly Property DocumentSigned() As String Get @@ -173,7 +218,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Entwurf ähnelt. + ''' Looks up a localized string similar to Entwurf. ''' Public Shared ReadOnly Property Draft() As String Get @@ -182,7 +227,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Archiviert ähnelt. + ''' Looks up a localized string similar to Archiviert. ''' Public Shared ReadOnly Property EnvelopeArchived() As String Get @@ -191,7 +236,16 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Vollständig signiert ähnelt. + ''' Looks up a localized string similar to Vollständig bestätigt. + ''' + Public Shared ReadOnly Property EnvelopeCompletelyConfirmed() As String + Get + Return ResourceManager.GetString("EnvelopeCompletelyConfirmed", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Vollständig signiert. ''' Public Shared ReadOnly Property EnvelopeCompletelySigned() As String Get @@ -200,7 +254,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Umschlag Erstellt ähnelt. + ''' Looks up a localized string similar to Umschlag Erstellt. ''' Public Shared ReadOnly Property EnvelopeCreated() As String Get @@ -209,7 +263,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Umschlag Gelöscht ähnelt. + ''' Looks up a localized string similar to Umschlag Gelöscht. ''' Public Shared ReadOnly Property EnvelopeDeleted() As String Get @@ -218,7 +272,16 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Teil-Signiert ähnelt. + ''' Looks up a localized string similar to Teil-Bestätigt. + ''' + Public Shared ReadOnly Property EnvelopePartlyConfirmed() As String + Get + Return ResourceManager.GetString("EnvelopePartlyConfirmed", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Teil-Signiert. ''' Public Shared ReadOnly Property EnvelopePartlySigned() As String Get @@ -227,7 +290,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Umschlag in Queue ähnelt. + ''' Looks up a localized string similar to Umschlag in Queue. ''' Public Shared ReadOnly Property EnvelopeQueued() As String Get @@ -236,7 +299,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Umschlag abgelehnt ähnelt. + ''' Looks up a localized string similar to Umschlag abgelehnt. ''' Public Shared ReadOnly Property EnvelopeRejected() As String Get @@ -245,7 +308,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Signierungszertifikat erstellt ähnelt. + ''' Looks up a localized string similar to Signierungszertifikat erstellt. ''' Public Shared ReadOnly Property EnvelopeReportCreated() As String Get @@ -254,7 +317,16 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Gespeichert ähnelt. + ''' Looks up a localized string similar to Lesebestätigungszertifikat erstellt. + ''' + Public Shared ReadOnly Property EnvelopeReportCreatedRaC() As String + Get + Return ResourceManager.GetString("EnvelopeReportCreatedRaC", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Gespeichert. ''' Public Shared ReadOnly Property EnvelopeSaved() As String Get @@ -263,7 +335,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Gesendet ähnelt. + ''' Looks up a localized string similar to Gesendet. ''' Public Shared ReadOnly Property EnvelopeSent() As String Get @@ -272,7 +344,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Umschlag zurückgezogen ähnelt. + ''' Looks up a localized string similar to Umschlag zurückgezogen. ''' Public Shared ReadOnly Property EnvelopeWithdrawn() As String Get @@ -281,7 +353,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Zugriffscode versendet ähnelt. + ''' Looks up a localized string similar to Zugriffscode versendet. ''' Public Shared ReadOnly Property MessageAccessCodeSent() As String Get @@ -290,7 +362,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Abschlussemail versendet ähnelt. + ''' Looks up a localized string similar to Abschlussemail versendet. ''' Public Shared ReadOnly Property MessageCompletionSent() As String Get @@ -299,7 +371,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Signaturbestätigung versendet ähnelt. + ''' Looks up a localized string similar to Signaturbestätigung versendet. ''' Public Shared ReadOnly Property MessageConfirmationSent() As String Get @@ -308,7 +380,16 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Löschinformation versendet ähnelt. + ''' Looks up a localized string similar to Lesebestätigung versendet. + ''' + Public Shared ReadOnly Property MessageConfirmationSentRaC() As String + Get + Return ResourceManager.GetString("MessageConfirmationSentRaC", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Löschinformation versendet. ''' Public Shared ReadOnly Property MessageDeletionSent() As String Get @@ -317,7 +398,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Dokumentenlink versendet ähnelt. + ''' Looks up a localized string similar to Dokumentenlink versendet. ''' Public Shared ReadOnly Property MessageInvitationSent() As String Get @@ -326,7 +407,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Nein ähnelt. + ''' Looks up a localized string similar to Nein. ''' Public Shared ReadOnly Property No() As String Get @@ -335,7 +416,16 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Teil-Signiert ähnelt. + ''' Looks up a localized string similar to Teil-Bestätigt. + ''' + Public Shared ReadOnly Property PartlyConfirmed() As String + Get + Return ResourceManager.GetString("PartlyConfirmed", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Teil-Signiert. ''' Public Shared ReadOnly Property PartlySigned() As String Get @@ -344,7 +434,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Qualifizierte Signatur ähnelt. + ''' Looks up a localized string similar to Qualifizierte Signatur. ''' Public Shared ReadOnly Property QualifiedSignature() As String Get @@ -353,7 +443,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Arbeitsanweisung ähnelt. + ''' Looks up a localized string similar to Lesebestätigung. ''' Public Shared ReadOnly Property ReadAndSign() As String Get @@ -362,7 +452,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Wollen Sie die 2-Faktor Definition für diesen Empfänger zurücksetzen. Der Empfänger muss sich dann neu identifizieren! ähnelt. + ''' Looks up a localized string similar to Wollen Sie die 2-Faktor Definition für diesen Empfänger zurücksetzen. Der Empfänger muss sich dann neu identifizieren!. ''' Public Shared ReadOnly Property ResetTOTPUser() As String Get @@ -371,7 +461,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Gespeichert ähnelt. + ''' Looks up a localized string similar to Gespeichert. ''' Public Shared ReadOnly Property Saved() As String Get @@ -380,7 +470,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Gesendet ähnelt. + ''' Looks up a localized string similar to Gesendet. ''' Public Shared ReadOnly Property Sent() As String Get @@ -389,7 +479,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Signatur ähnelt. + ''' Looks up a localized string similar to Signatur. ''' Public Shared ReadOnly Property Signature() As String Get @@ -398,7 +488,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Signatur bestätigt ähnelt. + ''' Looks up a localized string similar to Signatur bestätigt. ''' Public Shared ReadOnly Property SignatureConfirmed() As String Get @@ -407,7 +497,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Signiert ähnelt. + ''' Looks up a localized string similar to Signiert. ''' Public Shared ReadOnly Property Signed() As String Get @@ -416,7 +506,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Erfolgreich! Dialog wird geschlossen. ähnelt. + ''' Looks up a localized string similar to Erfolgreich! Dialog wird geschlossen.. ''' Public Shared ReadOnly Property Success_FormClose() As String Get @@ -425,7 +515,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Unsigniert ähnelt. + ''' Looks up a localized string similar to Unsigniert. ''' Public Shared ReadOnly Property Unsigned() As String Get @@ -434,7 +524,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Ja ähnelt. + ''' Looks up a localized string similar to Ja. ''' Public Shared ReadOnly Property Yes() As String Get @@ -443,7 +533,7 @@ Namespace My.Resources End Property ''' - ''' Sucht eine lokalisierte Zeichenfolge, die Ja, mit Anhang ähnelt. + ''' Looks up a localized string similar to Ja, mit Anhang. ''' Public Shared ReadOnly Property YesWithAttachment() As String Get diff --git a/EnvelopeGenerator.CommonServices/Strings/Model.en.resx b/EnvelopeGenerator.CommonServices/Strings/Model.en.resx index eaa87da2..3f20a194 100644 --- a/EnvelopeGenerator.CommonServices/Strings/Model.en.resx +++ b/EnvelopeGenerator.CommonServices/Strings/Model.en.resx @@ -132,12 +132,27 @@ Completed + + Completely confirmed + + + Completely signed + + + Read Confirmation + + + Read and signed + Contract Created + + Document read and confirmed + Document rotation adapted @@ -147,6 +162,9 @@ Signing rejected + + Read confirmation rejected + Document signed @@ -156,6 +174,9 @@ Archived + + Completely confirmed + Completely signed @@ -165,8 +186,11 @@ Envelope Deleted + + Partially confirmed + - Partly signed + Partially signed Envelope Queued @@ -177,6 +201,9 @@ Signature certificate created + + Read Confirmation Certificate Created + Saved @@ -195,6 +222,9 @@ Confirmation Sent + + Read Confirmation Sent + Deletion Notice Sent @@ -204,6 +234,12 @@ No + + Partially confirmed + + + Partially signed + Qualified Signature diff --git a/EnvelopeGenerator.CommonServices/Strings/Model.resx b/EnvelopeGenerator.CommonServices/Strings/Model.resx index 5e60d70b..cd100930 100644 --- a/EnvelopeGenerator.CommonServices/Strings/Model.resx +++ b/EnvelopeGenerator.CommonServices/Strings/Model.resx @@ -132,8 +132,17 @@ Abgeschlossen + + Vollständig bestätigt + - Vollständig Signiert + Vollständig signiert + + + Lesebestätigung + + + Gelesen und Bestätigt Vertrag @@ -141,6 +150,9 @@ Erstellt + + Dokument gelesen und bestätigt + Dokument Rotation geändert @@ -150,6 +162,9 @@ Unterzeichnung abgelehnt + + Lesebestätigung abgelehnt + Dokument unterzeichnet @@ -159,6 +174,9 @@ Archiviert + + Vollständig bestätigt + Vollständig signiert @@ -168,6 +186,9 @@ Umschlag Gelöscht + + Teil-Bestätigt + Teil-Signiert @@ -180,6 +201,9 @@ Signierungszertifikat erstellt + + Lesebestätigungszertifikat erstellt + Gespeichert @@ -198,6 +222,9 @@ Signaturbestätigung versendet + + Lesebestätigung versendet + Löschinformation versendet @@ -207,6 +234,9 @@ Nein + + Teil-Bestätigt + Teil-Signiert @@ -214,7 +244,7 @@ Qualifizierte Signatur - Arbeitsanweisung + Lesebestätigung Wollen Sie die 2-Faktor Definition für diesen Empfänger zurücksetzen. Der Empfänger muss sich dann neu identifizieren! From 0fd174ee0cf4d92d7106ca000ba684f2f3b36ed9 Mon Sep 17 00:00:00 2001 From: OlgunR Date: Tue, 10 Mar 2026 11:55:57 +0100 Subject: [PATCH 58/74] Update resource strings and comments for read confirmation in Domain.Resources.Model Switched Model.Designer.cs comments from German to English and added new resource string properties for read confirmation workflows. Updated Model.resx and Model.en.resx with new and corrected entries, improved translation consistency, and clarified documentation. --- .../Resources/Model.Designer.cs | 200 +++++++++++++----- .../Resources/Model.en.resx | 37 +++- EnvelopeGenerator.Domain/Resources/Model.resx | 36 +++- 3 files changed, 213 insertions(+), 60 deletions(-) diff --git a/EnvelopeGenerator.Domain/Resources/Model.Designer.cs b/EnvelopeGenerator.Domain/Resources/Model.Designer.cs index fb0cdf39..494ceb99 100644 --- a/EnvelopeGenerator.Domain/Resources/Model.Designer.cs +++ b/EnvelopeGenerator.Domain/Resources/Model.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -13,12 +13,12 @@ namespace My.Resources { /// - /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// A strongly-typed resource class, for looking up localized strings, etc. /// - // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert - // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. - // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen - // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] @@ -33,7 +33,7 @@ namespace My.Resources { } /// - /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Resources.ResourceManager ResourceManager { @@ -47,8 +47,8 @@ namespace My.Resources { } /// - /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle - /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Globalization.CultureInfo Culture { @@ -61,7 +61,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Zugriffscode korrekt eingegeben ähnelt. + /// Looks up a localized string similar to Zugriffscode korrekt eingegeben. /// public static string AccessCodeCorrect { get { @@ -70,7 +70,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Zugriffscode falsch eingegeben ähnelt. + /// Looks up a localized string similar to Zugriffscode falsch eingegeben. /// public static string AccessCodeIncorrect { get { @@ -79,7 +79,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Zugriffscode angefordert ähnelt. + /// Looks up a localized string similar to Zugriffscode angefordert. /// public static string AccessCodeRequested { get { @@ -88,7 +88,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Fortgeschrittene Elektronische Signatur ähnelt. + /// Looks up a localized string similar to Fortgeschrittene Elektronische Signatur. /// public static string AdvancedElectronicSignature { get { @@ -97,7 +97,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Abgeschlossen ähnelt. + /// Looks up a localized string similar to Abgeschlossen. /// public static string Completed { get { @@ -106,7 +106,16 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Vollständig Signiert ähnelt. + /// Looks up a localized string similar to Vollständig bestätigt. + /// + public static string CompletelyConfirmed { + get { + return ResourceManager.GetString("CompletelyConfirmed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vollständig signiert. /// public static string CompletelySigned { get { @@ -115,7 +124,25 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Vertrag ähnelt. + /// Looks up a localized string similar to Lesebestätigung. + /// + public static string Confirmation { + get { + return ResourceManager.GetString("Confirmation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gelesen und bestätigt. + /// + public static string Confirmed { + get { + return ResourceManager.GetString("Confirmed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vertrag. /// public static string Contract { get { @@ -124,7 +151,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Erstellt ähnelt. + /// Looks up a localized string similar to Erstellt. /// public static string Created { get { @@ -133,7 +160,16 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Dokument Rotation geändert ähnelt. + /// Looks up a localized string similar to Dokument gelesen und bestätigt. + /// + public static string DocumentConfirmed { + get { + return ResourceManager.GetString("DocumentConfirmed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dokument Rotation geändert. /// public static string DocumentMod_Rotation { get { @@ -142,7 +178,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Dokument geöffnet ähnelt. + /// Looks up a localized string similar to Dokument geöffnet. /// public static string DocumentOpened { get { @@ -151,7 +187,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Unterzeichnung abgelehnt ähnelt. + /// Looks up a localized string similar to Unterzeichnung abgelehnt. /// public static string DocumentRejected { get { @@ -160,7 +196,16 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Dokument unterzeichnet ähnelt. + /// Looks up a localized string similar to Lesebestätigung abgelehnt. + /// + public static string DocumentRejectedRaC { + get { + return ResourceManager.GetString("DocumentRejectedRaC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dokument unterzeichnet. /// public static string DocumentSigned { get { @@ -169,7 +214,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Entwurf ähnelt. + /// Looks up a localized string similar to Entwurf. /// public static string Draft { get { @@ -178,7 +223,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Archiviert ähnelt. + /// Looks up a localized string similar to Archiviert. /// public static string EnvelopeArchived { get { @@ -187,7 +232,16 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Vollständig signiert ähnelt. + /// Looks up a localized string similar to Vollständig gelesen und bestätigt. + /// + public static string EnvelopeCompletelyConfirmed { + get { + return ResourceManager.GetString("EnvelopeCompletelyConfirmed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vollständig signiert. /// public static string EnvelopeCompletelySigned { get { @@ -196,7 +250,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Umschlag Erstellt ähnelt. + /// Looks up a localized string similar to Umschlag Erstellt. /// public static string EnvelopeCreated { get { @@ -205,7 +259,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Umschlag Gelöscht ähnelt. + /// Looks up a localized string similar to Umschlag Gelöscht. /// public static string EnvelopeDeleted { get { @@ -214,7 +268,16 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Teil-Signiert ähnelt. + /// Looks up a localized string similar to Teil-Bestätigt. + /// + public static string EnvelopePartlyConfirmed { + get { + return ResourceManager.GetString("EnvelopePartlyConfirmed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Teil-Signiert. /// public static string EnvelopePartlySigned { get { @@ -223,7 +286,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Umschlag in Queue ähnelt. + /// Looks up a localized string similar to Umschlag in Queue. /// public static string EnvelopeQueued { get { @@ -232,7 +295,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Umschlag abgelehnt ähnelt. + /// Looks up a localized string similar to Umschlag abgelehnt. /// public static string EnvelopeRejected { get { @@ -241,7 +304,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Signierungszertifikat erstellt ähnelt. + /// Looks up a localized string similar to Signierungszertifikat erstellt. /// public static string EnvelopeReportCreated { get { @@ -250,7 +313,16 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Gespeichert ähnelt. + /// Looks up a localized string similar to Lesebestätigungszertifikat erstellt. + /// + public static string EnvelopeReportCreatedRaC { + get { + return ResourceManager.GetString("EnvelopeReportCreatedRaC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gespeichert. /// public static string EnvelopeSaved { get { @@ -259,7 +331,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Gesendet ähnelt. + /// Looks up a localized string similar to Gesendet. /// public static string EnvelopeSent { get { @@ -268,7 +340,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Umschlag zurückgezogen ähnelt. + /// Looks up a localized string similar to Umschlag zurückgezogen. /// public static string EnvelopeWithdrawn { get { @@ -277,7 +349,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Zugriffscode versendet ähnelt. + /// Looks up a localized string similar to Zugriffscode versendet. /// public static string MessageAccessCodeSent { get { @@ -286,7 +358,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Abschlussemail versendet ähnelt. + /// Looks up a localized string similar to Abschlussemail versendet. /// public static string MessageCompletionSent { get { @@ -295,7 +367,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Signaturbestätigung versendet ähnelt. + /// Looks up a localized string similar to Abschlussbestätigung versendet. /// public static string MessageConfirmationSent { get { @@ -304,7 +376,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Löschinformation versendet ähnelt. + /// Looks up a localized string similar to Löschinformation versendet. /// public static string MessageDeletionSent { get { @@ -313,7 +385,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Dokumentenlink versendet ähnelt. + /// Looks up a localized string similar to Dokumentenlink versendet. /// public static string MessageInvitationSent { get { @@ -322,7 +394,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Nein ähnelt. + /// Looks up a localized string similar to Nein. /// public static string No { get { @@ -331,7 +403,16 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Teil-Signiert ähnelt. + /// Looks up a localized string similar to Teil-Bestätigt. + /// + public static string PartlyConfirmed { + get { + return ResourceManager.GetString("PartlyConfirmed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Teil-Signiert. /// public static string PartlySigned { get { @@ -340,7 +421,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Qualifizierte Signatur ähnelt. + /// Looks up a localized string similar to Qualifizierte Signatur. /// public static string QualifiedSignature { get { @@ -349,7 +430,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Arbeitsanweisung ähnelt. + /// Looks up a localized string similar to Lesebestätigung. /// public static string ReadAndSign { get { @@ -358,7 +439,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Wollen Sie die 2-Faktor Definition für diesen Empfänger zurücksetzen. Der Empfänger muss sich dann neu identifizieren! ähnelt. + /// Looks up a localized string similar to Wollen Sie die 2-Faktor Definition für diesen Empfänger zurücksetzen. Der Empfänger muss sich dann neu identifizieren!. /// public static string ResetTOTPUser { get { @@ -367,7 +448,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Gespeichert ähnelt. + /// Looks up a localized string similar to Gespeichert. /// public static string Saved { get { @@ -376,7 +457,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Gesendet ähnelt. + /// Looks up a localized string similar to Gesendet. /// public static string Sent { get { @@ -385,7 +466,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Signatur ähnelt. + /// Looks up a localized string similar to Signatur. /// public static string Signature { get { @@ -394,7 +475,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Signatur bestätigt ähnelt. + /// Looks up a localized string similar to Signatur bestätigt. /// public static string SignatureConfirmed { get { @@ -403,7 +484,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Signiert ähnelt. + /// Looks up a localized string similar to Signiert. /// public static string Signed { get { @@ -412,7 +493,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Erfolgreich! Dialog wird geschlossen. ähnelt. + /// Looks up a localized string similar to Erfolgreich! Dialog wird geschlossen.. /// public static string Success_FormClose { get { @@ -421,7 +502,16 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Unsigniert ähnelt. + /// Looks up a localized string similar to Unbestätigt. + /// + public static string Unconfirmed { + get { + return ResourceManager.GetString("Unconfirmed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unsigniert. /// public static string Unsigned { get { @@ -430,7 +520,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Ja ähnelt. + /// Looks up a localized string similar to Ja. /// public static string Yes { get { @@ -439,7 +529,7 @@ namespace My.Resources { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Ja, mit Anhang ähnelt. + /// Looks up a localized string similar to Ja, mit Anhang. /// public static string YesWithAttachment { get { diff --git a/EnvelopeGenerator.Domain/Resources/Model.en.resx b/EnvelopeGenerator.Domain/Resources/Model.en.resx index d304b4b5..15c681b6 100644 --- a/EnvelopeGenerator.Domain/Resources/Model.en.resx +++ b/EnvelopeGenerator.Domain/Resources/Model.en.resx @@ -132,15 +132,27 @@ Completed + + Completely confirmed + Completely signed + + Read Confirmation + + + Read and signed + Contract Created + + Document read and signed + Document rotation adapted @@ -150,6 +162,9 @@ Signing rejected + + Read confirmation rejected + Document signed @@ -159,6 +174,9 @@ Archived + + Completely confirmed + Completely signed @@ -168,8 +186,11 @@ Envelope Deleted + + Partially confirmed + - Partly signed + Partially signed Envelope Queued @@ -180,6 +201,9 @@ Signature certificate created + + Read confirmartion certificate created + Saved @@ -196,7 +220,7 @@ Final email sent - Confirmation Sent + Finalization Confirmation Sent Deletion Notice Sent @@ -207,6 +231,12 @@ No + + Partially confirmed + + + Partially signed + Qualified Signature @@ -234,6 +264,9 @@ Successful! Dialog is closed.successful! Dialog is closed. + + Unconfirmed + Unsigned diff --git a/EnvelopeGenerator.Domain/Resources/Model.resx b/EnvelopeGenerator.Domain/Resources/Model.resx index 5e60d70b..0d2cd46f 100644 --- a/EnvelopeGenerator.Domain/Resources/Model.resx +++ b/EnvelopeGenerator.Domain/Resources/Model.resx @@ -132,8 +132,17 @@ Abgeschlossen + + Vollständig bestätigt + - Vollständig Signiert + Vollständig signiert + + + Lesebestätigung + + + Gelesen und bestätigt Vertrag @@ -141,6 +150,9 @@ Erstellt + + Dokument gelesen und bestätigt + Dokument Rotation geändert @@ -150,6 +162,9 @@ Unterzeichnung abgelehnt + + Lesebestätigung abgelehnt + Dokument unterzeichnet @@ -159,6 +174,9 @@ Archiviert + + Vollständig gelesen und bestätigt + Vollständig signiert @@ -168,6 +186,9 @@ Umschlag Gelöscht + + Teil-Bestätigt + Teil-Signiert @@ -180,6 +201,9 @@ Signierungszertifikat erstellt + + Lesebestätigungszertifikat erstellt + Gespeichert @@ -196,7 +220,7 @@ Abschlussemail versendet - Signaturbestätigung versendet + Abschlussbestätigung versendet Löschinformation versendet @@ -207,6 +231,9 @@ Nein + + Teil-Bestätigt + Teil-Signiert @@ -214,7 +241,7 @@ Qualifizierte Signatur - Arbeitsanweisung + Lesebestätigung Wollen Sie die 2-Faktor Definition für diesen Empfänger zurücksetzen. Der Empfänger muss sich dann neu identifizieren! @@ -237,6 +264,9 @@ Erfolgreich! Dialog wird geschlossen. + + Unbestätigt + Unsigniert From 260e8d53bac838b93aa620f7c98e0b7bf94adcfa Mon Sep 17 00:00:00 2001 From: OlgunR Date: Tue, 10 Mar 2026 12:45:56 +0100 Subject: [PATCH 59/74] Update 'SignatureConfirmed' localization strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed 'SignatureConfirmed' value in English to "Finalization confirmed" and in German to "Abschluss bestätigt". Updated designer file comments to match new wording. --- EnvelopeGenerator.CommonServices/Strings/Model.Designer.vb | 2 +- EnvelopeGenerator.CommonServices/Strings/Model.en.resx | 2 +- EnvelopeGenerator.CommonServices/Strings/Model.resx | 2 +- EnvelopeGenerator.Domain/Resources/Model.Designer.cs | 2 +- EnvelopeGenerator.Domain/Resources/Model.en.resx | 2 +- EnvelopeGenerator.Domain/Resources/Model.resx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/EnvelopeGenerator.CommonServices/Strings/Model.Designer.vb b/EnvelopeGenerator.CommonServices/Strings/Model.Designer.vb index 090ee3b3..ed819c29 100644 --- a/EnvelopeGenerator.CommonServices/Strings/Model.Designer.vb +++ b/EnvelopeGenerator.CommonServices/Strings/Model.Designer.vb @@ -488,7 +488,7 @@ Namespace My.Resources End Property ''' - ''' Looks up a localized string similar to Signatur bestätigt. + ''' Looks up a localized string similar to Abschluss bestätigt. ''' Public Shared ReadOnly Property SignatureConfirmed() As String Get diff --git a/EnvelopeGenerator.CommonServices/Strings/Model.en.resx b/EnvelopeGenerator.CommonServices/Strings/Model.en.resx index 3f20a194..968bdc87 100644 --- a/EnvelopeGenerator.CommonServices/Strings/Model.en.resx +++ b/EnvelopeGenerator.CommonServices/Strings/Model.en.resx @@ -259,7 +259,7 @@ Signature - Signature confirmed + Finalization confirmed Signed diff --git a/EnvelopeGenerator.CommonServices/Strings/Model.resx b/EnvelopeGenerator.CommonServices/Strings/Model.resx index cd100930..55a32cb7 100644 --- a/EnvelopeGenerator.CommonServices/Strings/Model.resx +++ b/EnvelopeGenerator.CommonServices/Strings/Model.resx @@ -259,7 +259,7 @@ Signatur - Signatur bestätigt + Abschluss bestätigt Signiert diff --git a/EnvelopeGenerator.Domain/Resources/Model.Designer.cs b/EnvelopeGenerator.Domain/Resources/Model.Designer.cs index 494ceb99..5708d48d 100644 --- a/EnvelopeGenerator.Domain/Resources/Model.Designer.cs +++ b/EnvelopeGenerator.Domain/Resources/Model.Designer.cs @@ -475,7 +475,7 @@ namespace My.Resources { } /// - /// Looks up a localized string similar to Signatur bestätigt. + /// Looks up a localized string similar to Abschluss bestätigt. /// public static string SignatureConfirmed { get { diff --git a/EnvelopeGenerator.Domain/Resources/Model.en.resx b/EnvelopeGenerator.Domain/Resources/Model.en.resx index 15c681b6..47255b7c 100644 --- a/EnvelopeGenerator.Domain/Resources/Model.en.resx +++ b/EnvelopeGenerator.Domain/Resources/Model.en.resx @@ -256,7 +256,7 @@ Signature - Signature confirmed + Finalization confirmed Signed diff --git a/EnvelopeGenerator.Domain/Resources/Model.resx b/EnvelopeGenerator.Domain/Resources/Model.resx index 0d2cd46f..3c18817d 100644 --- a/EnvelopeGenerator.Domain/Resources/Model.resx +++ b/EnvelopeGenerator.Domain/Resources/Model.resx @@ -256,7 +256,7 @@ Signatur - Signatur bestätigt + Abschluss bestätigt Signiert From ca9e25abcbbee49c24b9aa3f1fd1a6c16675a0a5 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 09:28:40 +0100 Subject: [PATCH 60/74] Add IsReadAndSign extension method to IEnvelope Introduced the IsReadAndSign method to IEnvelope extensions, which returns true when EnvelopeTypeId is not 2. This allows clear differentiation between "Read and Sign" and "Read and Confirm" envelope types. --- EnvelopeGenerator.Domain/Interfaces/IEnvelope.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/EnvelopeGenerator.Domain/Interfaces/IEnvelope.cs b/EnvelopeGenerator.Domain/Interfaces/IEnvelope.cs index bdc709c6..f4647701 100644 --- a/EnvelopeGenerator.Domain/Interfaces/IEnvelope.cs +++ b/EnvelopeGenerator.Domain/Interfaces/IEnvelope.cs @@ -11,5 +11,10 @@ { return envelope.EnvelopeTypeId == 2; } + + public static bool IsReadAndSign(this IEnvelope envelope) + { + return envelope.EnvelopeTypeId != 2; + } } } \ No newline at end of file From fa73d939b5849d7a8d79105b0152da19bee23445 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 09:29:24 +0100 Subject: [PATCH 61/74] Only check rejection for read-and-sign envelopes Previously, rejection checks were performed for all envelopes. Now, the code checks for rejecting receivers only if the envelope is of the "read-and-sign" type, avoiding unnecessary queries and logic for other envelope types. --- .../Controllers/EnvelopeController.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs index 4bc9692e..11292c49 100644 --- a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs +++ b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs @@ -7,6 +7,7 @@ using EnvelopeGenerator.Application.Common.Interfaces.Services; using EnvelopeGenerator.Application.EnvelopeReceivers.Queries; using EnvelopeGenerator.Application.Resources; using EnvelopeGenerator.Domain.Constants; +using EnvelopeGenerator.Domain.Interfaces; using EnvelopeGenerator.PdfEditor; using EnvelopeGenerator.Web.Extensions; using EnvelopeGenerator.Web.Models; @@ -162,13 +163,16 @@ public class EnvelopeController : ViewControllerBase } var er_secret = er_secret_res.Data; - //check rejection - var rejRcvrs = await _historyService.ReadRejectingReceivers(er_secret.Envelope!.Id); - if (rejRcvrs.Any()) + //check rejection if the envelope is read-and-sign + if (er_secret.Envelope.IsReadAndSign()) { - await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - ViewBag.IsExt = !rejRcvrs.Contains(er_secret.Receiver); //external if the current user is not rejected - return View("EnvelopeRejected", er_secret); + var rejRcvrs = await _historyService.ReadRejectingReceivers(er_secret.Envelope!.Id); + if (rejRcvrs.Any()) + { + await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + ViewBag.IsExt = !rejRcvrs.Contains(er_secret.Receiver); //external if the current user is not rejected + return View("EnvelopeRejected", er_secret); + } } // show envelope if already logged in From 200258ff736773f66b5e63e5c00bb723c793b660 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 09:43:22 +0100 Subject: [PATCH 62/74] Update EnvelopeDto.ReadOnly to use IsReadAndConfirm() Refactored the ReadOnly property in EnvelopeDto to use the IsReadAndConfirm() extension method instead of directly checking EnvelopeTypeId. Marked the property as [Obsolete] and advised using EnvelopeExtensions.IsReadAndConfirm. --- EnvelopeGenerator.Application/Common/Dto/EnvelopeDto.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Application/Common/Dto/EnvelopeDto.cs b/EnvelopeGenerator.Application/Common/Dto/EnvelopeDto.cs index 01c24251..1222c343 100644 --- a/EnvelopeGenerator.Application/Common/Dto/EnvelopeDto.cs +++ b/EnvelopeGenerator.Application/Common/Dto/EnvelopeDto.cs @@ -75,10 +75,12 @@ public record EnvelopeDto : IEnvelope ///
public int? EnvelopeTypeId { get; set; } + // TODO: use ReadAndConfirm property name /// /// /// - public bool ReadOnly => EnvelopeTypeId == 2; + [Obsolete("Use EnvelopeExtensions.IsReadAndConfirm extension metot instead.")] + public bool ReadOnly => this.IsReadAndConfirm(); /// /// From 8054bb377dffeb8e6ded01c9e8f17bc03db53f90 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 09:43:35 +0100 Subject: [PATCH 63/74] Refine rejection check for read-and-sign envelopes Only return 423 Locked if envelope is read-and-sign and has a rejection history. Also add missing using for Domain.Interfaces in AnnotationController. --- EnvelopeGenerator.Web/Controllers/AnnotationController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Web/Controllers/AnnotationController.cs b/EnvelopeGenerator.Web/Controllers/AnnotationController.cs index e2d64966..aacd27de 100644 --- a/EnvelopeGenerator.Web/Controllers/AnnotationController.cs +++ b/EnvelopeGenerator.Web/Controllers/AnnotationController.cs @@ -6,6 +6,7 @@ using EnvelopeGenerator.Application.Common.Notifications.DocSigned; using EnvelopeGenerator.Application.EnvelopeReceivers.Queries; using EnvelopeGenerator.Application.Histories.Queries; using EnvelopeGenerator.Domain.Constants; +using EnvelopeGenerator.Domain.Interfaces; using EnvelopeGenerator.Web.Extensions; using MediatR; using Microsoft.AspNetCore.Authentication; @@ -65,7 +66,7 @@ public class AnnotationController : ControllerBase // Again check if receiver has already signed if (await _mediator.IsSignedAsync(uuid, signature, cancel)) return Problem(statusCode: 409); - else if (await _mediator.AnyHistoryAsync(uuid, new[] { EnvelopeStatus.EnvelopeRejected, EnvelopeStatus.DocumentRejected }, cancel)) + else if (er.Envelope.IsReadAndSign() && await _mediator.AnyHistoryAsync(uuid, new[] { EnvelopeStatus.EnvelopeRejected, EnvelopeStatus.DocumentRejected }, cancel)) return Problem(statusCode: 423); var docSignedNotification = await _mediator From 717da90c01017fbd600ab4ca0e66176451d46446 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 11:07:33 +0100 Subject: [PATCH 64/74] Add .NET 7.0 support and update project dependencies Added net7.0 to TargetFrameworks in EnvelopeGenerator.Web.csproj and introduced a conditional ItemGroup with required package references for .NET 7.0 compatibility. Also removed clipboard2.svg from the list of included static files. --- .../EnvelopeGenerator.Web.csproj | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index f2d2c9fe..926b4f88 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -1,7 +1,7 @@  - net8.0;net9.0 + net7.0;net8.0;net9.0 enable enable EnvelopeGenerator.Web @@ -626,7 +626,6 @@ - @@ -2093,6 +2092,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + From 48b7afcdc1d6c3d0702cb90d543bc8d9fb816edf Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 11:16:08 +0100 Subject: [PATCH 65/74] Restrict rejection check to ReadAndSign envelopes Previously, rejection logic was applied to all envelopes. Now, the check for rejected receivers and the "EnvelopeRejected" view are only executed if the envelope is of the "ReadAndSign" type, preventing unnecessary rejection handling for other envelope types. --- .../Controllers/EnvelopeController.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs index 11292c49..11f030cf 100644 --- a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs +++ b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs @@ -80,12 +80,15 @@ public class EnvelopeController : ViewControllerBase #region Rejected or Signed //check rejection - var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id); - if (rejRcvrs.Any()) + if (er.Envelope.IsReadAndSign()) { - await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - ViewBag.IsExt = !rejRcvrs.Contains(er.Receiver); //external if the current user is not rejected - return View("EnvelopeRejected", er); + var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id); + if (rejRcvrs.Any()) + { + await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + ViewBag.IsExt = !rejRcvrs.Contains(er.Receiver); //external if the current user is not rejected + return View("EnvelopeRejected", er); + } } //check if it has already signed From e724a74f9cca604d8fbf3d82634c0354968cc191 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 11:19:17 +0100 Subject: [PATCH 66/74] Bump version to 3.12.1 in project file Updated , , and in EnvelopeGenerator.Web.csproj from 3.12.0 to 3.12.1 to reflect a new patch release. No other changes were made. --- EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index 926b4f88..d0084524 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -12,9 +12,9 @@ digital data envelope generator web EnvelopeGenerator.Web is an ASP.NET MVC application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly. Assets\icon.ico - 3.12.0 - 3.12.0.0 - 3.12.0.0 + 3.12.1 + 3.12.1.0 + 3.12.1.0 Copyright © 2025 Digital Data GmbH. All rights reserved. From 5e840db04ca18d4ec64873fee6d8feb2ebd5b235 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 12:05:20 +0100 Subject: [PATCH 67/74] Refactor envelope rejection logic in EnvelopeController Clarified and streamlined the handling of rejected envelopes: - Moved retrieval of rejecting receivers for clarity. - Signed out users when any rejecting receivers are present. - Improved determination of "external" users. - Updated condition for showing the EnvelopeRejected view. - Temporarily hardcoded ViewBag.IsExt with a TODO for future fix. - Removed redundant code for better maintainability. --- .../Controllers/EnvelopeController.cs | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs index 11f030cf..e8068bd2 100644 --- a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs +++ b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs @@ -79,14 +79,16 @@ public class EnvelopeController : ViewControllerBase return this.ViewEnvelopeNotFound(); #region Rejected or Signed - //check rejection - if (er.Envelope.IsReadAndSign()) + var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id); + if (rejRcvrs.Any()) { - var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id); - if (rejRcvrs.Any()) + await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + var isExt = !rejRcvrs.Where(rcv => rcv.Id == er.Receiver!.Id).Any(); //external if the current user is not rejected + + if (er.Envelope.IsReadAndSign() || !isExt) { - await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - ViewBag.IsExt = !rejRcvrs.Contains(er.Receiver); //external if the current user is not rejected + //TODO: Normally assigned to the isExt variable. However, since the relevant keys are not defined in the resx files, it was assigned false. Fix this. + ViewBag.IsExt = true; return View("EnvelopeRejected", er); } } @@ -166,14 +168,17 @@ public class EnvelopeController : ViewControllerBase } var er_secret = er_secret_res.Data; - //check rejection if the envelope is read-and-sign - if (er_secret.Envelope.IsReadAndSign()) + var rejRcvrs = await _historyService.ReadRejectingReceivers(er_secret.Envelope!.Id); + if (rejRcvrs.Any()) { - var rejRcvrs = await _historyService.ReadRejectingReceivers(er_secret.Envelope!.Id); - if (rejRcvrs.Any()) + await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + var isExt = !rejRcvrs.Where(rcv => rcv.Id == er_secret.Receiver!.Id).Any(); //external if the current user is not rejected + + //check rejection if the envelope is read-and-sign or non-external (internal) + if (er_secret.Envelope.IsReadAndSign() || !isExt) { - await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - ViewBag.IsExt = !rejRcvrs.Contains(er_secret.Receiver); //external if the current user is not rejected + //TODO: Normally assigned to the isExt variable. However, since the relevant keys are not defined in the resx files, it was assigned false. Fix this. + ViewBag.IsExt = true; return View("EnvelopeRejected", er_secret); } } From 60db762bccc26da243b642a77f373b88c5100b76 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 12:08:48 +0100 Subject: [PATCH 68/74] Bump project version to 3.12.2 Updated EnvelopeGenerator.Web.csproj to increment , , and from 3.12.1 to 3.12.2, reflecting the new release. No other changes were made. --- EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index d0084524..938b874c 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -12,9 +12,9 @@ digital data envelope generator web EnvelopeGenerator.Web is an ASP.NET MVC application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly. Assets\icon.ico - 3.12.1 - 3.12.1.0 - 3.12.1.0 + 3.12.2 + 3.12.2.0 + 3.12.2.0 Copyright © 2025 Digital Data GmbH. All rights reserved. From 7cb1546934d8422748001085931caeab37f6ed18 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 12:09:23 +0100 Subject: [PATCH 69/74] Add Reject endpoint to AnnotationController Introduced a new Reject endpoint for users with the ReceiverFull role to reject annotations, with optional reason support. Marked the endpoint as obsolete for future exception handling updates. Also standardized the Unauthorized response to remove the custom error message. --- EnvelopeGenerator.Web/Controllers/AnnotationController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Web/Controllers/AnnotationController.cs b/EnvelopeGenerator.Web/Controllers/AnnotationController.cs index aacd27de..0cecccf0 100644 --- a/EnvelopeGenerator.Web/Controllers/AnnotationController.cs +++ b/EnvelopeGenerator.Web/Controllers/AnnotationController.cs @@ -81,6 +81,7 @@ public class AnnotationController : ControllerBase return Ok(); } + //TODO: add logic to check if it is already rejected or signed [Authorize(Roles = Role.ReceiverFull)] [HttpPost("reject")] [Obsolete("Use DigitalData.Core.Exceptions and .Middleware")] @@ -101,7 +102,7 @@ public class AnnotationController : ControllerBase if (envRcvRes.IsFailed) { _logger.LogNotice(envRcvRes.Notices); - return Unauthorized("you are not authirized"); + return Unauthorized(); } var histRes = await _histService.RecordAsync(envRcvRes.Data.EnvelopeId, userReference: mail, EnvelopeStatus.DocumentRejected, comment: reason); From 06c2a07fbcfd9657dd19b218d76b141da7bc1ba8 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 14:11:23 +0100 Subject: [PATCH 70/74] Replace DateTime.UtcNow with DateTime.Now for timestamps Switched all audit and creation timestamps from UTC to local time by replacing DateTime.UtcNow with DateTime.Now across the codebase. This affects audit fields, object creation, and default values for date/time properties. --- .../Common/Extensions/AutoMapperAuditingExtensions.cs | 4 ++-- .../Common/Notifications/SendMailHandler.cs | 2 +- EnvelopeGenerator.Application/DocStatus/MappingProfile.cs | 2 +- .../Histories/Commands/CreateHistoryCommand.cs | 2 +- EnvelopeGenerator.Tests/Application/Fake.cs | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/EnvelopeGenerator.Application/Common/Extensions/AutoMapperAuditingExtensions.cs b/EnvelopeGenerator.Application/Common/Extensions/AutoMapperAuditingExtensions.cs index 4ce31eb1..72f2abef 100644 --- a/EnvelopeGenerator.Application/Common/Extensions/AutoMapperAuditingExtensions.cs +++ b/EnvelopeGenerator.Application/Common/Extensions/AutoMapperAuditingExtensions.cs @@ -13,12 +13,12 @@ public static class AutoMapperAuditingExtensions /// public static IMappingExpression MapAddedWhen(this IMappingExpression expression) where TDestination : IHasAddedWhen - => expression.ForMember(dest => dest.AddedWhen, opt => opt.MapFrom(_ => DateTime.UtcNow)); + => expression.ForMember(dest => dest.AddedWhen, opt => opt.MapFrom(_ => DateTime.Now)); /// /// Maps to the current UTC time. /// public static IMappingExpression MapChangedWhen(this IMappingExpression expression) where TDestination : IHasChangedWhen - => expression.ForMember(dest => dest.ChangedWhen, opt => opt.MapFrom(_ => DateTime.UtcNow)); + => expression.ForMember(dest => dest.ChangedWhen, opt => opt.MapFrom(_ => DateTime.Now)); } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Common/Notifications/SendMailHandler.cs b/EnvelopeGenerator.Application/Common/Notifications/SendMailHandler.cs index 5a97ef03..50cf3662 100644 --- a/EnvelopeGenerator.Application/Common/Notifications/SendMailHandler.cs +++ b/EnvelopeGenerator.Application/Common/Notifications/SendMailHandler.cs @@ -113,7 +113,7 @@ public abstract class SendMailHandler : INotificationHandler() .ForMember(dest => dest.Envelope, opt => opt.Ignore()) .ForMember(dest => dest.Receiver, opt => opt.Ignore()) - .ForMember(dest => dest.StatusChangedWhen, opt => opt.MapFrom(src => DateTime.UtcNow)) + .ForMember(dest => dest.StatusChangedWhen, opt => opt.MapFrom(src => DateTime.Now)) .MapChangedWhen(); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Histories/Commands/CreateHistoryCommand.cs b/EnvelopeGenerator.Application/Histories/Commands/CreateHistoryCommand.cs index c8a53f59..4cd83f01 100644 --- a/EnvelopeGenerator.Application/Histories/Commands/CreateHistoryCommand.cs +++ b/EnvelopeGenerator.Application/Histories/Commands/CreateHistoryCommand.cs @@ -34,7 +34,7 @@ public record CreateHistoryCommand : EnvelopeReceiverQueryBase, IRequest /// /// - public DateTime AddedWhen { get; } = DateTime.UtcNow; + public DateTime AddedWhen { get; } = DateTime.Now; /// /// diff --git a/EnvelopeGenerator.Tests/Application/Fake.cs b/EnvelopeGenerator.Tests/Application/Fake.cs index 1281e7bb..66b3e168 100644 --- a/EnvelopeGenerator.Tests/Application/Fake.cs +++ b/EnvelopeGenerator.Tests/Application/Fake.cs @@ -215,7 +215,7 @@ public static class Extensions Title = faker.Lorem.Paragraph(faker.Random.Number(1, 2)), Message = faker.Lorem.Paragraph(faker.Random.Number(2, 5)), TfaEnabled = tfaEnabled, - AddedWhen = DateTime.UtcNow, + AddedWhen = DateTime.Now, CertificationType = (int)CertificationType.AdvancedElectronicSignature, UseAccessCode = false, ContractType = (int)ContractType.Contract, @@ -273,9 +273,9 @@ public static class Extensions EnvelopeId = envelopeId, ReceiverId = receiverId, Status = ReceiverStatus.Unsigned, - AddedWhen = DateTime.UtcNow, + AddedWhen = DateTime.Now, AccessCode = faker.Random.Number(1000, 9999).ToString(), - ChangedWhen = DateTime.UtcNow, + ChangedWhen = DateTime.Now, CompanyName = faker.Company.CompanyName(), JobTitle = faker.Name.JobTitle(), Name = faker.Name.FullName(), From 05d54e87c3dcefbe930642a914c6da8d042d711d Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 14:19:15 +0100 Subject: [PATCH 71/74] Bump version to 3.12.3 in project file Updated EnvelopeGenerator.Web.csproj to increment , , and from 3.12.2 to 3.12.3, preparing for a new release. No other changes included. --- EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index 938b874c..6c0e5d59 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -12,9 +12,9 @@ digital data envelope generator web EnvelopeGenerator.Web is an ASP.NET MVC application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly. Assets\icon.ico - 3.12.2 - 3.12.2.0 - 3.12.2.0 + 3.12.3 + 3.12.3.0 + 3.12.3.0 Copyright © 2025 Digital Data GmbH. All rights reserved. From 176672d7eb9ce5e0ca56615728d2a7bd06024e4c Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 11 Mar 2026 17:45:27 +0100 Subject: [PATCH 72/74] Add interface import and update email sending condition Added import for EnvelopeGenerator.Domain.Interfaces. Updated logic to send final emails to receivers only if the envelope requires "Read and Sign," adding an extra check to the email dispatch condition. --- .../Jobs/FinalizeDocument/FinalizeDocumentJob.vb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/FinalizeDocumentJob.vb b/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/FinalizeDocumentJob.vb index c921b4df..9b0ca0fe 100644 --- a/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/FinalizeDocumentJob.vb +++ b/EnvelopeGenerator.CommonServices/Jobs/FinalizeDocument/FinalizeDocumentJob.vb @@ -15,6 +15,7 @@ Imports DigitalData.Core.Abstraction.Application Imports EnvelopeGenerator.Infrastructure Imports Microsoft.EntityFrameworkCore Imports DigitalData.Core.Abstractions +Imports EnvelopeGenerator.Domain.Interfaces Namespace Jobs Public Class FinalizeDocumentJob @@ -350,7 +351,7 @@ Namespace Jobs Logger.Warn($"No SendFinalEmailToCreator - oMailToCreator [{oMailToCreator}] <> [{FinalEmailType.No}] ") End If - If oMailToReceivers <> FinalEmailType.No Then + If oMailToReceivers <> FinalEmailType.No And pEnvelope.IsReadAndSign() Then Logger.Debug("Sending emails to receivers..") SendFinalEmailToReceivers(pEnvelope) ', pAttachment Else From 64c018b92e90ddf2d6ff83fb2db23ef9e2c8a491 Mon Sep 17 00:00:00 2001 From: TekH Date: Thu, 12 Mar 2026 16:11:50 +0100 Subject: [PATCH 73/74] Add DbSets for ElementAnnotation and DocumentStatus Added DocumentReceiverElementAnnotations (ElementAnnotation) and DocumentStatus DbSet properties to EGDbContextBase to support database operations for these entities. --- EnvelopeGenerator.Infrastructure/EGDbContext.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/EnvelopeGenerator.Infrastructure/EGDbContext.cs b/EnvelopeGenerator.Infrastructure/EGDbContext.cs index 468aaa4c..cff50672 100644 --- a/EnvelopeGenerator.Infrastructure/EGDbContext.cs +++ b/EnvelopeGenerator.Infrastructure/EGDbContext.cs @@ -47,6 +47,8 @@ public abstract class EGDbContextBase : DbContext public DbSet DocumentReceiverElements { get; set; } + public DbSet DocumentReceiverElementAnnotations { get; set; } + public DbSet DocumentStatus { get; set; } public DbSet EmailTemplate { get; set; } From b5748550d160f072049a432d6985bb766576f8ec Mon Sep 17 00:00:00 2001 From: OlgunR Date: Fri, 13 Mar 2026 10:44:00 +0100 Subject: [PATCH 74/74] Fix typo in document confirmation message Corrected "red" to "read" in the DocumentSuccessfullyConfirmed resource string to ensure proper messaging. --- EnvelopeGenerator.Application/Resources/Resource.en-US.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx index 0e3a1af7..fa6c5afd 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx @@ -448,7 +448,7 @@ Document has been reset. - Document successfully red and confirmed! + Document successfully read and confirmed! You have read and confirmed the document. You will receive a written confirmation afterwards.