feat(FinalizeDocument): aus CommonJobs kopiert, mit einfachen Fehlerbehebungen unter Verwendung von Copilot
- Programmiersprache von VSC zu C# geändert - Framework von .NET Framework zu .NET geändert
This commit is contained in:
432
EnvelopeGenerator.ServiceHost/Jobs/FinalizeDocumentJob.cs
Normal file
432
EnvelopeGenerator.ServiceHost/Jobs/FinalizeDocumentJob.cs
Normal file
@@ -0,0 +1,432 @@
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using DigitalData.Modules.Base;
|
||||
using DigitalData.Modules.Database;
|
||||
using DigitalData.Modules.Logging;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.ServiceHost.Exceptions;
|
||||
using EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
||||
using GdPicture14;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Quartz;
|
||||
|
||||
namespace EnvelopeGenerator.ServiceHost.Jobs;
|
||||
|
||||
public class FinalizeDocumentJob : IJob
|
||||
{
|
||||
private readonly LicenseManager _licenseManager = new();
|
||||
private GdViewer? _gdViewer;
|
||||
|
||||
private LogConfig? _logConfig;
|
||||
private Logger? _logger;
|
||||
private MSSQLServer? _database;
|
||||
private DbConfig? _config;
|
||||
private string _databaseConnectionString = string.Empty;
|
||||
|
||||
private ConfigModel? _configModel;
|
||||
private EnvelopeModel? _envelopeModel;
|
||||
private ReportModel? _reportModel;
|
||||
|
||||
private ActionService? _actionService;
|
||||
|
||||
private PDFBurner? _pdfBurner;
|
||||
private PDFMerger? _pdfMerger;
|
||||
private ReportCreator? _reportCreator;
|
||||
|
||||
private const int CompleteWaitTime = 1;
|
||||
private string _parentFolderUid = string.Empty;
|
||||
private TempFiles? _tempFiles;
|
||||
|
||||
private sealed class EnvelopeData
|
||||
{
|
||||
public int EnvelopeId { get; set; }
|
||||
public string EnvelopeUuid { get; set; } = string.Empty;
|
||||
public string DocumentPath { get; set; } = string.Empty;
|
||||
public List<string> AnnotationData { get; set; } = new();
|
||||
public byte[]? DocAsByte { get; set; }
|
||||
}
|
||||
|
||||
public Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
var gdPictureKey = (string)context.MergedJobDataMap[Value.GDPICTURE];
|
||||
_logConfig = (LogConfig)context.MergedJobDataMap[Value.LOGCONFIG];
|
||||
_logger = _logConfig.GetLogger();
|
||||
_tempFiles = new TempFiles(_logConfig);
|
||||
_tempFiles.Create();
|
||||
var jobId = context.JobDetail.Key;
|
||||
_logger.Debug("Starting job {0}", jobId);
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Debug("Loading GdViewer..");
|
||||
_gdViewer = new GdViewer();
|
||||
_licenseManager.RegisterKEY(gdPictureKey);
|
||||
|
||||
_logger.Debug("Loading Database..");
|
||||
var connectionString = (string)context.MergedJobDataMap[Value.DATABASE];
|
||||
_databaseConnectionString = MSSQLServer.DecryptConnectionString(connectionString);
|
||||
_database = new MSSQLServer(_logConfig, _databaseConnectionString);
|
||||
|
||||
_logger.Debug("Loading Models & Services");
|
||||
var state = GetState();
|
||||
InitializeModels(state);
|
||||
|
||||
_logger.Debug("Loading Configuration..");
|
||||
_config = _configModel?.LoadConfiguration() ?? new DbConfig();
|
||||
state.DbConfig = _config;
|
||||
|
||||
InitializeServices(state);
|
||||
|
||||
_logger.Debug("Loading PDFBurner..");
|
||||
var pdfBurnerParams = (PDFBurnerParams)context.MergedJobDataMap[Value.PDF_BURNER_PARAMS];
|
||||
_pdfBurner = new PDFBurner(_logConfig, gdPictureKey, pdfBurnerParams, _databaseConnectionString);
|
||||
|
||||
_logger.Debug("Loading PDFMerger..");
|
||||
_pdfMerger = new PDFMerger(_logConfig, gdPictureKey);
|
||||
|
||||
_logger.Debug("Loading ReportCreator..");
|
||||
_reportCreator = new ReportCreator(_logConfig, state);
|
||||
|
||||
_config.DocumentPath = _config.DocumentPath;
|
||||
|
||||
_logger.Debug("DocumentPath: [{0}]", _config.DocumentPath);
|
||||
_logger.Debug("ExportPath: [{0}]", _config.ExportPath);
|
||||
|
||||
var completeStatus = EnvelopeStatus.EnvelopeCompletelySigned;
|
||||
var sql = $"SELECT * FROM TBSIG_ENVELOPE WHERE STATUS = {completeStatus} AND DATEDIFF(minute, CHANGED_WHEN, GETDATE()) >= {CompleteWaitTime} ORDER BY GUID";
|
||||
var table = _database.GetDatatable(sql);
|
||||
|
||||
var envelopeIds = table.Rows.Cast<DataRow>()
|
||||
.Select(r => r.Field<int>("GUID"))
|
||||
.ToList();
|
||||
|
||||
if (envelopeIds.Count > 0)
|
||||
{
|
||||
_logger.Info("Found [{0}] completed envelopes.", envelopeIds.Count);
|
||||
}
|
||||
|
||||
var total = envelopeIds.Count;
|
||||
var current = 1;
|
||||
|
||||
foreach (var id in envelopeIds)
|
||||
{
|
||||
_logger.Info("Finalizing Envelope [{0}] ({1}/{2})", id, current, total);
|
||||
try
|
||||
{
|
||||
var envelope = _envelopeModel?.GetById(id);
|
||||
if (envelope is null)
|
||||
{
|
||||
_logger.Warn("Envelope could not be loaded for Id [{0}]!", id);
|
||||
throw new ArgumentNullException(nameof(EnvelopeData));
|
||||
}
|
||||
|
||||
_logger.Debug("Loading Envelope Data..");
|
||||
var envelopeData = GetEnvelopeData(id);
|
||||
|
||||
if (envelopeData is null)
|
||||
{
|
||||
_logger.Warn("EnvelopeData could not be loaded for Id [{0}]!", id);
|
||||
throw new ArgumentNullException(nameof(EnvelopeData));
|
||||
}
|
||||
|
||||
_logger.Debug("Burning Annotations to pdf ...");
|
||||
var burnedDocument = BurnAnnotationsToPdf(envelopeData);
|
||||
if (burnedDocument is null)
|
||||
{
|
||||
_logger.Warn("Document could not be finalized!");
|
||||
throw new ApplicationException("Document could not be finalized");
|
||||
}
|
||||
|
||||
if (_actionService?.CreateReport(envelope) == false)
|
||||
{
|
||||
_logger.Warn("Document Report could not be created!");
|
||||
throw new ApplicationException("Document Report could not be created");
|
||||
}
|
||||
|
||||
_logger.Debug("Creating report..");
|
||||
var report = _reportCreator!.CreateReport(envelope);
|
||||
_logger.Debug("Report created!");
|
||||
|
||||
_logger.Debug("Merging documents ...");
|
||||
var mergedDocument = _pdfMerger!.MergeDocuments(burnedDocument, report);
|
||||
_logger.Debug("Documents merged!");
|
||||
|
||||
var outputDirectoryPath = Path.Combine(_config.ExportPath, _parentFolderUid);
|
||||
_logger.Debug("oOutputDirectoryPath is {0}", outputDirectoryPath);
|
||||
if (!Directory.Exists(outputDirectoryPath))
|
||||
{
|
||||
_logger.Debug("Directory not existing. Creating ... ");
|
||||
Directory.CreateDirectory(outputDirectoryPath);
|
||||
}
|
||||
|
||||
var outputFilePath = Path.Combine(outputDirectoryPath, $"{envelope.Uuid}.pdf");
|
||||
_logger.Debug("Writing finalized Pdf to disk..");
|
||||
_logger.Info("Output path is [{0}]", outputFilePath);
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllBytes(outputFilePath, mergedDocument);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn("Could not export final document to disk!");
|
||||
throw new ExportDocumentException("Could not export final document to disk!", ex);
|
||||
}
|
||||
|
||||
_logger.Debug("Writing EB-bytes to database...");
|
||||
UpdateFileDb(outputFilePath, envelope.Id);
|
||||
|
||||
if (!SendFinalEmails(envelope))
|
||||
{
|
||||
throw new ApplicationException("Final emails could not be sent!");
|
||||
}
|
||||
|
||||
_logger.Info("Report-mails successfully sent!");
|
||||
|
||||
_logger.Debug("Setting envelope status..");
|
||||
if (_actionService?.FinalizeEnvelope(envelope) == false)
|
||||
{
|
||||
_logger.Warn("Envelope could not be finalized!");
|
||||
throw new ApplicationException("Envelope could not be finalized");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex);
|
||||
_logger.Warn(ex, "Unhandled exception while working envelope [{0}]", id);
|
||||
}
|
||||
|
||||
current += 1;
|
||||
_logger.Info("Envelope [{0}] finalized!", id);
|
||||
}
|
||||
|
||||
_logger.Debug("Completed job {0} successfully!", jobId);
|
||||
}
|
||||
catch (MergeDocumentException ex)
|
||||
{
|
||||
_logger.Warn("Certificate Document job failed at step: Merging documents!");
|
||||
_logger.Error(ex);
|
||||
}
|
||||
catch (ExportDocumentException ex)
|
||||
{
|
||||
_logger.Warn("Certificate Document job failed at step: Exporting document!");
|
||||
_logger.Error(ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn("Certificate Document job failed!");
|
||||
_logger.Error(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_logger.Debug("Job execution for [{0}] ended", jobId);
|
||||
}
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void UpdateFileDb(string filePath, long envelopeId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var imageData = ReadFile(filePath);
|
||||
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)
|
||||
{
|
||||
_logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[]? ReadFile(string path)
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
var numBytes = fileInfo.Length;
|
||||
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
using var reader = new BinaryReader(stream);
|
||||
return reader.ReadBytes((int)numBytes);
|
||||
}
|
||||
|
||||
private bool SendFinalEmails(Envelope envelope)
|
||||
{
|
||||
var mailToCreator = (FinalEmailType)(envelope.FinalEmailToCreator ?? 0);
|
||||
var mailToReceivers = (FinalEmailType)(envelope.FinalEmailToReceivers ?? 0);
|
||||
|
||||
if (mailToCreator != FinalEmailType.No)
|
||||
{
|
||||
_logger?.Debug("Sending email to creator ...");
|
||||
SendFinalEmailToCreator(envelope, mailToCreator);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.Warn("No SendFinalEmailToCreator - oMailToCreator [{0}] <> [{1}] ", mailToCreator, FinalEmailType.No);
|
||||
}
|
||||
|
||||
if (mailToReceivers != FinalEmailType.No)
|
||||
{
|
||||
_logger?.Debug("Sending emails to receivers..");
|
||||
SendFinalEmailToReceivers(envelope, mailToReceivers);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.Warn("No SendFinalEmailToReceivers - oMailToCreator [{0}] <> [{1}] ", mailToReceivers, FinalEmailType.No);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SendFinalEmailToCreator(Envelope envelope, FinalEmailType mailToCreator)
|
||||
{
|
||||
var includeAttachment = SendFinalEmailWithAttachment(mailToCreator);
|
||||
_logger?.Debug("Attachment included: [{0}]", includeAttachment);
|
||||
|
||||
if (_actionService?.CompleteEnvelope(envelope) == false)
|
||||
{
|
||||
_logger?.Error(new Exception("CompleteEnvelope failed"), "Envelope could not be completed for receiver [{0}]", envelope.User?.Email);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SendFinalEmailToReceivers(Envelope envelope, FinalEmailType mailToReceivers)
|
||||
{
|
||||
var includeAttachment = SendFinalEmailWithAttachment(mailToReceivers);
|
||||
_logger?.Debug("Attachment included: [{0}]", includeAttachment);
|
||||
|
||||
foreach (var receiver in envelope.EnvelopeReceivers ?? Enumerable.Empty<EnvelopeReceiver>())
|
||||
{
|
||||
if (_actionService?.CompleteEnvelope(envelope, receiver.Receiver) == false)
|
||||
{
|
||||
_logger?.Error(new Exception("CompleteEnvelope failed"), "Envelope could not be completed for receiver [{0}]", receiver.Receiver?.EmailAddress);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool SendFinalEmailWithAttachment(FinalEmailType type)
|
||||
{
|
||||
return type == FinalEmailType.YesWithAttachment;
|
||||
}
|
||||
|
||||
private byte[] BurnAnnotationsToPdf(EnvelopeData envelopeData)
|
||||
{
|
||||
var envelopeId = envelopeData.EnvelopeId;
|
||||
|
||||
_logger?.Info("Burning [{0}] signatures", envelopeData.AnnotationData.Count);
|
||||
var annotations = envelopeData.AnnotationData;
|
||||
var inputPath = string.Empty;
|
||||
if (envelopeData.DocAsByte is null)
|
||||
{
|
||||
inputPath = envelopeData.DocumentPath;
|
||||
_logger?.Info("Input path: [{0}]", inputPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.Debug("we got bytes..");
|
||||
inputPath = _config!.DocumentPathOrigin;
|
||||
_logger?.Debug("oInputPath: {0}", _config.DocumentPathOrigin);
|
||||
}
|
||||
|
||||
if (envelopeData.DocAsByte is null)
|
||||
{
|
||||
var directorySource = Path.GetDirectoryName(inputPath) ?? string.Empty;
|
||||
var split = directorySource.Split('\\');
|
||||
_parentFolderUid = split[^1];
|
||||
}
|
||||
else
|
||||
{
|
||||
_parentFolderUid = envelopeData.EnvelopeUuid;
|
||||
}
|
||||
|
||||
_logger?.Info("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?.Debug("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();
|
||||
}
|
||||
|
||||
private void InitializeServices(State state)
|
||||
{
|
||||
_actionService = new ActionService(state, _database!);
|
||||
}
|
||||
|
||||
private void InitializeModels(State state)
|
||||
{
|
||||
_configModel = new ConfigModel(state);
|
||||
_envelopeModel = new EnvelopeModel(state);
|
||||
_reportModel = new ReportModel(state);
|
||||
}
|
||||
|
||||
private State GetState()
|
||||
{
|
||||
return new State
|
||||
{
|
||||
LogConfig = _logConfig!,
|
||||
Database = _database!,
|
||||
UserId = 0,
|
||||
Config = null,
|
||||
DbConfig = null
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user