Compare commits

...

16 Commits

Author SHA1 Message Date
7af934ea19 Integrate DevExpress Reporting for envelope history
Added DevExpress.Reporting.Core package reference. Refactored rptEnvelopeHistory to inherit from XtraReport and build its layout programmatically using DevExpress bands, tables, and styling. The report now uses A4 paper size, custom margins, and DevExpress UI components for rendering.
2026-03-09 21:27:06 +01:00
b65367fb6d Refactor FinalizeDocumentJob dependencies and method call
Removed unused constructor parameters from FinalizeDocumentJob for cleaner dependency injection. Updated actionService.FinalizeEnvelope to accept a cancellation token. Added missing using directive for Microsoft.Extensions.Options.
2026-03-09 21:26:52 +01:00
25c31108cb Add EnvelopeReport repository dependency to ReportCreator
Updated ReportCreator constructor to require an IRepository<EnvelopeReport> parameter, enabling direct access to envelope report data within the class. This change prepares the class for future data operations involving envelope reports.
2026-03-09 21:26:19 +01:00
4083833b19 Add EnvelopeReports DbSet to EGDbContextBase
Added EnvelopeReports DbSet property to EGDbContextBase, enabling Entity Framework to manage and query EnvelopeReport entities.
2026-03-09 21:25:30 +01:00
f53bc65acf Add EnvelopeReport entity mapped to VWSIG_ENVELOPE_REPORT
Introduced the EnvelopeReport class in the Domain.Entities namespace, mapped to the "VWSIG_ENVELOPE_REPORT" table using EF Core data annotations. The entity includes properties for envelope ID, head UUID, title, message, status, timestamp, and user, with appropriate column mappings and validation attributes.
2026-03-09 21:25:15 +01:00
070d9be00c Remove obsolete State class and DI registration
Removed the deprecated State class and its properties from the codebase. Also removed State from the dependency injection configuration, as it is no longer used.
2026-03-09 16:52:52 +01:00
6f7b04a26e Refactor: remove strict checks and logging in finalization
Removed exception throwing and logging for failed report creation, email sending, and envelope finalization in FinalizeDocumentJob. Now, these methods are called without checking their return values. Also improved exception message for file export to include envelope Id and added null-forgiving operator to _config.ExportPath.
2026-03-09 16:31:31 +01:00
473358e2b9 Make ExportPath non-nullable in ConfigDto
Changed ExportPath from a nullable string to a non-nullable string in ConfigDto and initialized it with the null-forgiving operator. This ensures ExportPath always has a value and cannot be null.
2026-03-09 16:30:39 +01:00
8f3aa69cbf Refactor document save to use async repository update
Replaced manual SQL and file read with async repository update for saving final document bytes. Removed obsolete helper methods and cleaned up unused imports for improved maintainability and testability.
2026-03-09 16:18:20 +01:00
eededeb1f1 Remove SendFinalEmailWithAttachment and related logic
Removed the SendFinalEmailWithAttachment method and all references to it from SendFinalEmailToCreator and SendFinalEmailToReceivers. The logic for determining email attachments based on FinalEmailType is no longer used. Other functionality in these methods remains unchanged.
2026-03-09 15:41:56 +01:00
737774f077 Remove PDF annotation and envelope data methods
Removed BurnAnnotationsToPdf, GetEnvelopeData, and GetAnnotationData from FinalizeDocumentJob. These methods handled document reading, annotation retrieval, and PDF annotation burning. This change reflects a refactor or shift in document processing responsibilities.
2026-03-09 15:34:58 +01:00
69499273cc Refactor FinalizeDocumentJob to async and use docStatusRepo
Refactored FinalizeDocumentJob to make the Finalize method asynchronous and fetch document annotations from docStatusRepo instead of using GetEnvelopeData. Updated constructor to inject IRepository<Domain.Entities.DocumentStatus>. Improved logging and removed obsolete envelopeData checks.
2026-03-09 15:32:32 +01:00
ead33ab2e7 Refactor Envelope properties; add DefaultDocument property
Refactored property declarations in the Envelope class for improved readability by removing unnecessary line breaks and nullable preprocessor directives. Added a [NotMapped] DefaultDocument property to return the first document in the Documents list, or null if none exist.
2026-03-09 15:09:51 +01:00
d1e2840617 Clean up debug logging in FinalizeDocumentJob
Removed numerous debug-level log statements to reduce log verbosity and focus on warnings and information logs. Updated some log messages to use interpolated strings for clarity. Refactored GetAnnotationData to use C# collection expressions for improved code conciseness.
2026-03-09 11:35:49 +01:00
a39ef6a0e2 Improve error handling in FinalizeDocumentJob
Added RethrowOnError property to control exception rethrowing during envelope finalization. Exceptions are now logged as errors and, if RethrowOnError is true, rethrown to enable stricter error handling and halt execution on failure.
2026-03-09 11:30:43 +01:00
7d620988d8 Refactor envelope finalization into a private method
Extracted envelope finalization logic from the foreach loop into a new private Finalize(Envelope envelope) method. This improves code readability and maintainability by encapsulating all steps of the finalization process without changing functionality.
2026-03-09 11:25:36 +01:00
10 changed files with 188 additions and 240 deletions

View File

@@ -31,7 +31,7 @@ public class ConfigDto
/// <summary> /// <summary>
/// Gets or sets the path where exports will be saved. /// Gets or sets the path where exports will be saved.
/// </summary> /// </summary>
public string? ExportPath { get; set; } public string ExportPath { get; set; } = null!;
/// <summary> /// <summary>
/// Gets or sets the creation timestamp. /// Gets or sets the creation timestamp.

View File

@@ -154,8 +154,7 @@ namespace EnvelopeGenerator.Domain.Entities
#if nullable #if nullable
? ?
#endif #endif
Type Type { get; set; }
{ get; set; }
#if NETFRAMEWORK #if NETFRAMEWORK
[NotMapped] [NotMapped]
@@ -169,22 +168,26 @@ namespace EnvelopeGenerator.Domain.Entities
#if nullable #if nullable
? ?
#endif #endif
Documents Documents { get; set; }
{ get; set; }
[NotMapped]
public Document
#if nullable
?
#endif
DefaultDocument => Documents?.FirstOrDefault();
public List<History> public List<History>
#if nullable #if nullable
? ?
#endif #endif
Histories Histories { get; set; }
{ get; set; }
public List<EnvelopeReceiver> public List<EnvelopeReceiver>
#if nullable #if nullable
? ?
#endif #endif
EnvelopeReceivers EnvelopeReceivers { get; set; }
{ get; set; }
//#if NETFRAMEWORK //#if NETFRAMEWORK
/// <summary> /// <summary>

View File

@@ -0,0 +1,36 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace EnvelopeGenerator.Domain.Entities
{
[Table("VWSIG_ENVELOPE_REPORT", Schema = "dbo")]
public class EnvelopeReport
{
[Column("ENVELOPE_ID", TypeName = "int")]
[Required]
public int EnvelopeId { get; set; }
[Column("HEAD_UUID", TypeName = "nvarchar(36)")]
[Required]
public string HeadUuid { get; set; }
[Column("HEAD_TITLE", TypeName = "nvarchar(128)")]
public string HeadTitle { get; set; }
[Column("HEAD_MESSAGE", TypeName = "nvarchar(max)")]
[Required]
public string HeadMessage { get; set; }
[Column("POS_STATUS", TypeName = "int")]
[Required]
public int PosStatus { get; set; }
[Column("POS_WHEN", TypeName = "datetime")]
public DateTime? PosWhen { get; set; }
[Column("POS_WHO", TypeName = "nvarchar(128)")]
[Required]
public string PosWho { get; set; }
}
}

View File

@@ -79,6 +79,8 @@ public abstract class EGDbContextBase : DbContext
public DbSet<ClientUser> ClientUsers { get; set; } public DbSet<ClientUser> ClientUsers { get; set; }
public DbSet<EnvelopeReport> EnvelopeReports { get; set; }
private readonly DbTriggerParams _triggers; private readonly DbTriggerParams _triggers;
private readonly ILogger private readonly ILogger

View File

@@ -17,6 +17,7 @@
<PackageReference Include="System.Collections.Immutable" Version="8.0.0" /> <PackageReference Include="System.Collections.Immutable" Version="8.0.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.16" /> <PackageReference Include="System.Drawing.Common" Version="8.0.16" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" /> <PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageReference Include="DevExpress.Reporting.Core" Version="24.2.*" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -18,7 +18,6 @@ public static class DependencyInjection
services.AddScoped<PDFBurner>(); services.AddScoped<PDFBurner>();
services.AddScoped<PDFMerger>(); services.AddScoped<PDFMerger>();
services.AddScoped<ReportModel>(); services.AddScoped<ReportModel>();
services.AddSingleton<State>();
services.AddScoped<MSSQLServer>(); services.AddScoped<MSSQLServer>();
//TODO: Check lifetime of services. They might be singleton or scoped. //TODO: Check lifetime of services. They might be singleton or scoped.

View File

@@ -1,4 +1,5 @@
using System.Data; using System.Data;
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Constants; using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.ServiceHost.Exceptions; using EnvelopeGenerator.ServiceHost.Exceptions;
@@ -7,7 +8,7 @@ using EnvelopeGenerator.ServiceHost.Extensions;
namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument; namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
[Obsolete("Instead of ReportModel create and use EnvelopeReport mediator queries")] [Obsolete("Instead of ReportModel create and use EnvelopeReport mediator queries")]
public class ReportCreator(ReportModel ReportModel, ILogger<ReportCreator> Logger) public class ReportCreator(ReportModel ReportModel, ILogger<ReportCreator> Logger, IRepository<EnvelopeReport> reportRepo)
{ {
[Obsolete("Solve the spaghetti...")] [Obsolete("Solve the spaghetti...")]
private Envelope? _envelope; private Envelope? _envelope;

View File

@@ -1,9 +1,94 @@
using DevExpress.XtraReports.UI;
using DevExpress.Drawing;
using System.Drawing;
using System.IO; using System.IO;
namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument; namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
public class rptEnvelopeHistory public class rptEnvelopeHistory : XtraReport
{ {
public rptEnvelopeHistory()
{
BuildLayout();
}
private void BuildLayout()
{
Bands.AddRange(
[
new TopMarginBand(),
new BottomMarginBand(),
new ReportHeaderBand { HeightF = 40 },
new PageHeaderBand { HeightF = 24 },
new DetailBand { HeightF = 22 }
]);
var reportHeader = (ReportHeaderBand)Bands[nameof(ReportHeaderBand)]!;
var pageHeader = (PageHeaderBand)Bands[nameof(PageHeaderBand)]!;
var detail = (DetailBand)Bands[nameof(DetailBand)]!;
var title = new XRLabel
{
BoundsF = new RectangleF(0, 0, 750, 28),
Font = new DXFont("Segoe UI", 14, DXFontStyle.Bold),
Text = "Envelope History"
};
reportHeader.Controls.Add(title);
var headerTable = CreateTable(isHeader: true);
pageHeader.Controls.Add(headerTable);
var detailTable = CreateTable(isHeader: false);
detail.Controls.Add(detailTable);
Margins = new DXMargins(40, 40, 40, 40);
PaperKind = (DevExpress.Drawing.Printing.DXPaperKind)System.Drawing.Printing.PaperKind.A4;
}
private static XRTable CreateTable(bool isHeader)
{
var table = new XRTable
{
BoundsF = new RectangleF(0, 0, 750, 22),
Borders = DevExpress.XtraPrinting.BorderSide.All
};
var row = new XRTableRow();
if (isHeader)
{
row.Font = new DXFont("Segoe UI", 9, DXFontStyle.Bold);
row.BackColor = Color.Gainsboro;
row.Cells.Add(CreateCell("Date"));
row.Cells.Add(CreateCell("Status"));
row.Cells.Add(CreateCell("User"));
row.Cells.Add(CreateCell("Title"));
row.Cells.Add(CreateCell("Subject"));
}
else
{
row.Font = new DXFont("Segoe UI", 9, DXFontStyle.Regular);
row.Cells.Add(CreateCell("[ItemDate]"));
row.Cells.Add(CreateCell("[ItemStatusTranslated]"));
row.Cells.Add(CreateCell("[ItemUserReference]"));
row.Cells.Add(CreateCell("[EnvelopeTitle]"));
row.Cells.Add(CreateCell("[EnvelopeSubject]"));
}
table.Rows.Add(row);
return table;
}
private static XRTableCell CreateCell(string textOrExpression)
{
return new XRTableCell
{
Text = textOrExpression,
Padding = new DevExpress.XtraPrinting.PaddingInfo(4, 4, 2, 2),
CanGrow = false
};
}
public object? DataSource { get; set; } public object? DataSource { get; set; }
public string? DataMember { get; set; } public string? DataMember { get; set; }

View File

@@ -1,24 +1,25 @@
using System.Data; using DigitalData.Core.Abstraction.Application.Repository;
using DigitalData.Modules.Database; using DigitalData.Modules.Database;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.Configuration.Queries;
using EnvelopeGenerator.Application.Envelopes.Queries;
using EnvelopeGenerator.Domain.Constants; using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.ServiceHost.Exceptions; using EnvelopeGenerator.ServiceHost.Exceptions;
using EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
using GdPicture14;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Options;
using EnvelopeGenerator.ServiceHost.Extensions; using EnvelopeGenerator.ServiceHost.Extensions;
using EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
using GdPicture.Internal.MSOfficeBinary.translator.Spreadsheet.XlsFileFormat.Records;
using GdPicture14;
using MediatR; using MediatR;
using EnvelopeGenerator.Application.Configuration.Queries; using Microsoft.Data.SqlClient;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.Envelopes.Queries;
using DigitalData.Core.Abstraction.Application.Repository;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using System.Data;
namespace EnvelopeGenerator.ServiceHost.Jobs; namespace EnvelopeGenerator.ServiceHost.Jobs;
[Obsolete("ActionService is a placeholder service added by copilot. Migrate the actual logic from CommonServices.Jobs")] [Obsolete("ActionService is a placeholder service added by copilot. Migrate the actual logic from CommonServices.Jobs")]
public class FinalizeDocumentJob(IOptions<WorkerOptions> options, IConfiguration config, ILogger<FinalizeDocumentJob> logger, TempFiles tempFiles, ActionService actionService, PDFBurner pdfBurner, PDFMerger pdfMerger, ReportCreator reportCreator, ReportModel _reportModel, MSSQLServer _database, GdViewer? _gdViewer, LicenseManager licenseManager, IMediator mediator, IRepository<Envelope> envRepo) public class FinalizeDocumentJob(IOptions<WorkerOptions> options, ILogger<FinalizeDocumentJob> logger, TempFiles tempFiles, ActionService actionService, PDFBurner pdfBurner, PDFMerger pdfMerger, ReportCreator reportCreator, GdViewer? _gdViewer, LicenseManager licenseManager, IMediator mediator, IRepository<Envelope> envRepo, IRepository<Domain.Entities.DocumentStatus> docStatusRepo)
{ {
private readonly WorkerOptions _options = options.Value; private readonly WorkerOptions _options = options.Value;
@@ -36,12 +37,13 @@ public class FinalizeDocumentJob(IOptions<WorkerOptions> options, IConfiguration
public byte[]? DocAsByte { get; set; } public byte[]? DocAsByte { get; set; }
} }
public bool RethrowOnError { get; set; } = true;
public async Task ExecuteAsync(CancellationToken cancel = default) public async Task ExecuteAsync(CancellationToken cancel = default)
{ {
var gdPictureKey = _options.GdPictureLicenseKey; var gdPictureKey = _options.GdPictureLicenseKey;
tempFiles.Create(); tempFiles.Create();
var jobId = typeof(FinalizeDocumentJob).FullName; var jobId = typeof(FinalizeDocumentJob).FullName;
logger.LogDebug("Starting job {jobId}", jobId);
_config = await mediator.Send(new ReadDefaultConfigQuery(), cancel); _config = await mediator.Send(new ReadDefaultConfigQuery(), cancel);
@@ -55,123 +57,58 @@ public class FinalizeDocumentJob(IOptions<WorkerOptions> options, IConfiguration
if (envelopes.Count > 0) if (envelopes.Count > 0)
logger.LogInformation("Found [{count}] completed envelopes.", envelopes.Count); logger.LogInformation("Found [{count}] completed envelopes.", envelopes.Count);
var total = envelopes.Count;
var current = 1;
foreach (var envelope in envelopes) foreach (var envelope in envelopes)
{ {
try try
{ {
var envelopeData = GetEnvelopeData(envelope.Id); await Finalize(envelope, cancel);
if (envelopeData is null)
{
logger.LogWarning("EnvelopeData could not be loaded for Id [{id}]!", envelope.Id);
throw new ArgumentNullException(nameof(EnvelopeData));
}
logger.LogDebug("Burning Annotations to pdf ...");
var burnedDocument = BurnAnnotationsToPdf(envelopeData);
if (burnedDocument is null)
{
logger.LogWarning("Document could not be finalized!");
throw new ApplicationException("Document could not be finalized");
}
if (actionService?.CreateReport(envelope) == false)
{
logger.LogWarning("Document Report could not be created!");
throw new ApplicationException("Document Report could not be created");
}
logger.LogDebug("Creating report..");
var report = reportCreator!.CreateReport(envelope);
logger.LogDebug("Report created!");
logger.LogDebug("Merging documents ...");
var mergedDocument = pdfMerger!.MergeDocuments(burnedDocument, report);
logger.LogDebug("Documents merged!");
var outputDirectoryPath = Path.Combine(_config.ExportPath, _parentFolderUid);
logger.LogDebug("oOutputDirectoryPath is {outputDirectoryPath}", outputDirectoryPath);
if (!Directory.Exists(outputDirectoryPath))
{
logger.LogDebug("Directory not existing. Creating ... ");
Directory.CreateDirectory(outputDirectoryPath);
}
var outputFilePath = Path.Combine(outputDirectoryPath, $"{envelope.Uuid}.pdf");
logger.LogDebug("Writing finalized Pdf to disk..");
logger.LogInformation("Output path is [{outputFilePath}]", outputFilePath);
try
{
File.WriteAllBytes(outputFilePath, mergedDocument);
}
catch (Exception ex)
{
logger.LogWarning("Could not export final document to disk!");
throw new ExportDocumentException("Could not export final document to disk!", ex);
}
logger.LogDebug("Writing EB-bytes to database...");
UpdateFileDb(outputFilePath, envelope.Id);
if (!SendFinalEmails(envelope))
{
throw new ApplicationException("Final emails could not be sent!");
}
logger.LogInformation("Report-mails successfully sent!");
logger.LogDebug("Setting envelope status..");
if (actionService?.FinalizeEnvelope(envelope) == false)
{
logger.LogWarning("Envelope could not be finalized!");
throw new ApplicationException("Envelope could not be finalized");
}
} }
catch (Exception ex) catch (Exception ex)
{ {
logger.LogError(ex); logger.LogError(ex, "Unhandled exception while working envelope [{id}]", envelope.Id);
logger.LogWarning(ex, "Unhandled exception while working envelope [{id}]", envelope.Id);
if(RethrowOnError)
throw;
} }
current += 1;
logger.LogInformation("Envelope [{id}] finalized!", envelope.Id); logger.LogInformation("Envelope [{id}] finalized!", envelope.Id);
} }
logger.LogDebug("Completed job {jobId} successfully!", jobId);
} }
private void UpdateFileDb(string filePath, long envelopeId) private async Task Finalize(Envelope envelope, CancellationToken cancel)
{ {
var annotations = await docStatusRepo.Where(s => s.EnvelopeId == envelope.Id).Select(s => s.Value).ToListAsync(cancel);
var burnedDocument = pdfBurner!.BurnAnnotsToPDF(envelope.DefaultDocument.ByteData!, annotations, envelope.Id)
?? throw new ApplicationException("Document could not be finalized");
actionService.CreateReport(envelope, cancel);
var report = reportCreator!.CreateReport(envelope);
var mergedDocument = pdfMerger!.MergeDocuments(burnedDocument, report);
var outputDirectoryPath = Path.Combine(_config!.ExportPath, _parentFolderUid);
if (!Directory.Exists(outputDirectoryPath))
Directory.CreateDirectory(outputDirectoryPath);
var outputFilePath = Path.Combine(outputDirectoryPath, $"{envelope.Uuid}.pdf");
try try
{ {
var imageData = ReadFile(filePath); File.WriteAllBytes(outputFilePath, mergedDocument);
if (imageData is null)
{
return;
}
var query = $"UPDATE TBSIG_ENVELOPE SET DOC_RESULT = @ImageData WHERE GUID = {envelopeId}";
using var command = new SqlCommand(query, _database!.GetConnection);
command.Parameters.Add(new SqlParameter("@ImageData", imageData));
command.ExecuteNonQuery();
} }
catch (Exception ex) catch (Exception ex)
{ {
logger?.LogError(ex); throw new ExportDocumentException("Could not export final document to disk. Envelope Id is " + envelope.Id, ex);
} }
}
private static byte[]? ReadFile(string path) var outputFile = await File.ReadAllBytesAsync(outputFilePath, cancel);
{ await envRepo.UpdateAsync(e => e.DocResult = outputFile, e => e.Id == envelope.Id, cancel);
var fileInfo = new FileInfo(path);
var numBytes = fileInfo.Length; SendFinalEmails(envelope);
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
using var reader = new BinaryReader(stream); actionService?.FinalizeEnvelope(envelope, cancel);
return reader.ReadBytes((int)numBytes);
} }
private bool SendFinalEmails(Envelope envelope) private bool SendFinalEmails(Envelope envelope)
@@ -180,23 +117,17 @@ public class FinalizeDocumentJob(IOptions<WorkerOptions> options, IConfiguration
var mailToReceivers = (FinalEmailType)(envelope.FinalEmailToReceivers ?? 0); var mailToReceivers = (FinalEmailType)(envelope.FinalEmailToReceivers ?? 0);
if (mailToCreator != FinalEmailType.No) if (mailToCreator != FinalEmailType.No)
{
logger?.LogDebug("Sending email to creator ...");
SendFinalEmailToCreator(envelope, mailToCreator); SendFinalEmailToCreator(envelope, mailToCreator);
}
else else
{ logger?.LogWarning("No SendFinalEmailToCreator - oMailToCreator [{mailToCreator}] <> [{noFinalEmailType}] ", mailToCreator, FinalEmailType.No);
logger?.LogWarning("No SendFinalEmailToCreator - oMailToCreator [{0}] <> [{1}] ", mailToCreator, FinalEmailType.No);
}
if (mailToReceivers != FinalEmailType.No) if (mailToReceivers != FinalEmailType.No)
{ {
logger?.LogDebug("Sending emails to receivers..");
SendFinalEmailToReceivers(envelope, mailToReceivers); SendFinalEmailToReceivers(envelope, mailToReceivers);
} }
else else
{ {
logger?.LogWarning("No SendFinalEmailToReceivers - oMailToCreator [{0}] <> [{1}] ", mailToReceivers, FinalEmailType.No); logger?.LogWarning("No SendFinalEmailToReceivers - oMailToCreator [{mailToReceivers}] <> [{noFinalEmailType}] ", mailToReceivers, FinalEmailType.No);
} }
return true; return true;
@@ -204,12 +135,9 @@ public class FinalizeDocumentJob(IOptions<WorkerOptions> options, IConfiguration
private bool SendFinalEmailToCreator(Envelope envelope, FinalEmailType mailToCreator) private bool SendFinalEmailToCreator(Envelope envelope, FinalEmailType mailToCreator)
{ {
var includeAttachment = SendFinalEmailWithAttachment(mailToCreator);
logger?.LogDebug("Attachment included: [{0}]", includeAttachment);
if (actionService?.CompleteEnvelope(envelope) == false) if (actionService?.CompleteEnvelope(envelope) == false)
{ {
logger?.LogError(new Exception("CompleteEnvelope failed"), "Envelope could not be completed for receiver [{0}]", envelope.User?.Email); logger?.LogError(new Exception("CompleteEnvelope failed"), "Envelope could not be completed for receiver [{email}]", envelope.User?.Email);
return false; return false;
} }
@@ -218,109 +146,15 @@ public class FinalizeDocumentJob(IOptions<WorkerOptions> options, IConfiguration
private bool SendFinalEmailToReceivers(Envelope envelope, FinalEmailType mailToReceivers) private bool SendFinalEmailToReceivers(Envelope envelope, FinalEmailType mailToReceivers)
{ {
var includeAttachment = SendFinalEmailWithAttachment(mailToReceivers);
logger?.LogDebug("Attachment included: [{0}]", includeAttachment);
foreach (var receiver in envelope.EnvelopeReceivers ?? Enumerable.Empty<EnvelopeReceiver>()) foreach (var receiver in envelope.EnvelopeReceivers ?? Enumerable.Empty<EnvelopeReceiver>())
{ {
if (actionService?.CompleteEnvelope(envelope, receiver.Receiver) == false) if (actionService?.CompleteEnvelope(envelope, receiver.Receiver) == false)
{ {
logger?.LogError(new Exception("CompleteEnvelope failed"), "Envelope could not be completed for receiver [{0}]", receiver.Receiver?.EmailAddress); logger?.LogError(new Exception("CompleteEnvelope failed"), "Envelope could not be completed for receiver [{email}]", receiver.Receiver?.EmailAddress);
return false; return false;
} }
} }
return true; return true;
} }
}
private static bool SendFinalEmailWithAttachment(FinalEmailType type)
{
return type == FinalEmailType.YesWithAttachment;
}
private byte[] BurnAnnotationsToPdf(EnvelopeData envelopeData)
{
var envelopeId = envelopeData.EnvelopeId;
logger?.LogInformation("Burning [{0}] signatures", envelopeData.AnnotationData.Count);
var annotations = envelopeData.AnnotationData;
var inputPath = string.Empty;
if (envelopeData.DocAsByte is null)
{
inputPath = envelopeData.DocumentPath;
logger?.LogInformation("Input path: [{0}]", inputPath);
}
else
{
logger?.LogDebug("we got bytes..");
inputPath = _config!.DocumentPath;
logger?.LogDebug("oInputPath: {0}", _config.DocumentPath);
}
if (envelopeData.DocAsByte is null)
{
var directorySource = Path.GetDirectoryName(inputPath) ?? string.Empty;
var split = directorySource.Split('\\');
_parentFolderUid = split[^1];
}
else
{
_parentFolderUid = envelopeData.EnvelopeUuid;
}
logger?.LogInformation("ParentFolderUID: [{0}]", _parentFolderUid);
byte[] inputDocumentBuffer;
if (envelopeData.DocAsByte is not null)
{
inputDocumentBuffer = envelopeData.DocAsByte;
}
else
{
try
{
inputDocumentBuffer = File.ReadAllBytes(inputPath);
}
catch (Exception ex)
{
throw new BurnAnnotationException("Source document could not be read from disk!", ex);
}
}
return pdfBurner!.BurnAnnotsToPDF(inputDocumentBuffer, annotations, envelopeId);
}
private EnvelopeData? GetEnvelopeData(int envelopeId)
{
var sql = $"SELECT T.GUID, T.ENVELOPE_UUID, T.ENVELOPE_TYPE, T2.FILEPATH, T2.BYTE_DATA FROM [dbo].[TBSIG_ENVELOPE] T\n JOIN TBSIG_ENVELOPE_DOCUMENT T2 ON T.GUID = T2.ENVELOPE_ID\n WHERE T.GUID = {envelopeId}";
var table = _database!.GetDatatable(sql);
var row = table.Rows.Cast<DataRow>().SingleOrDefault();
if (row is null)
{
return null;
}
var annotationData = GetAnnotationData(envelopeId);
var data = new EnvelopeData
{
EnvelopeId = envelopeId,
DocumentPath = row.ItemEx("FILEPATH", string.Empty),
AnnotationData = annotationData,
DocAsByte = row.Field<byte[]?>("BYTE_DATA"),
EnvelopeUuid = row.ItemEx("ENVELOPE_UUID", string.Empty)
};
logger?.LogDebug("Document path: [{0}]", data.DocumentPath);
return data;
}
private List<string> GetAnnotationData(int envelopeId)
{
var sql = $"SELECT VALUE FROM TBSIG_DOCUMENT_STATUS WHERE ENVELOPE_ID = {envelopeId}";
var table = _database!.GetDatatable(sql);
return table.Rows.Cast<DataRow>()
.Select(r => r.ItemEx("VALUE", string.Empty))
.ToList();
}
}

View File

@@ -1,13 +0,0 @@
using DigitalData.Modules.Database;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.ServiceHost.Jobs;
[Obsolete("Use DbContext")]
public class State
{
public int UserId { get; set; }
public FormUser? User { get; set; }
public Config? Config { get; set; }
public MSSQLServer? Database { get; set; }
}