From 43d89699a93509c2f85d69b2349f1171d3698eaf Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 18 Feb 2026 12:47:23 +0100 Subject: [PATCH 1/9] 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 2/9] 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 3/9] 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 int EnvelopeId { get; set; } + + /// + /// + /// + public int ReceiverId { get; set; } + + /// + /// Gets or sets the display value associated with the status. /// - public DateTime AddedWhen => StatusChangedWhen; + 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 4/9] 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 5/9] 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 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 DateTime? ChangedWhen => StatusChangedWhen; + /// + public override Expression> BuildQueryExpression() + { + return ds => ds.EnvelopeId == EnvelopeId && ds.ReceiverId == ReceiverId; + } } \ No newline at end of file From f9b1e583df388f6b0a80b2750a50307a64a35b99 Mon Sep 17 00:00:00 2001 From: TekH Date: Fri, 27 Feb 2026 11:31:41 +0100 Subject: [PATCH 6/9] 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 7/9] 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 8/9] 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 9/9] 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