Compare commits
62 Commits
7af934ea19
...
feat/servi
| Author | SHA1 | Date | |
|---|---|---|---|
| cb7d154f64 | |||
| a3f404b9ae | |||
| 1f7eb5d4ea | |||
| e1ae3ffccb | |||
| 3e3bfaa904 | |||
| f8422ed94c | |||
| c64c63925e | |||
| 2c8ae23203 | |||
| b4be718994 | |||
| 33bf5b1a51 | |||
| 6a9792bb57 | |||
| 6954a86358 | |||
| d6c5b63c49 | |||
| 8ca360d47e | |||
| 2dadefecc5 | |||
| 162f066b08 | |||
| 6592642945 | |||
| 855f22cf87 | |||
| 726673e277 | |||
| 65d615f43e | |||
| f0f92c5400 | |||
| 7e34f01f6a | |||
| f449767bf9 | |||
| f8ec6065c2 | |||
| fabfe80666 | |||
| bdb3863c07 | |||
| e5295b8302 | |||
| 00a9cf06da | |||
| 1b387238e8 | |||
| bda4f3dbef | |||
| 2458d0c07a | |||
| a72cbab195 | |||
| bcf4e63f7c | |||
| 5aabeb4510 | |||
| 32edc6474d | |||
| 71bfe3b323 | |||
| 089d2bd1cb | |||
| 65c72bcf77 | |||
| 2d8375f26a | |||
| a7cfb099fa | |||
| 7a0d4e2fa7 | |||
| 3955ee9f39 | |||
| 9bdf24d7d5 | |||
| 993ca82596 | |||
| ce9958a8b1 | |||
| 6c54473d5a | |||
| 9ad4352e02 | |||
| 90031db6a5 | |||
| bc07af9622 | |||
| 4caf8cd192 | |||
| 5423d5317b | |||
| 6c8c8f22a3 | |||
| 5100504f16 | |||
| 15f8baf54c | |||
| 4e847fa737 | |||
| 53ff48dc3c | |||
| ab67b3fba2 | |||
| 3855a8fa1e | |||
| 052da02bd0 | |||
| 53a9a3e3eb | |||
| c2ab18e184 | |||
| 8f845e8a9a |
@@ -71,6 +71,7 @@ public class EnvelopeController : ControllerBase
|
|||||||
[HttpGet("doc-result")]
|
[HttpGet("doc-result")]
|
||||||
public async Task<IActionResult> GetDocResultAsync([FromQuery] ReadEnvelopeQuery query, [FromQuery] bool view = false)
|
public async Task<IActionResult> GetDocResultAsync([FromQuery] ReadEnvelopeQuery query, [FromQuery] bool view = false)
|
||||||
{
|
{
|
||||||
|
query.IncludeDocResult = true;
|
||||||
var envelopes = await _mediator.Send(query.Authorize(User.GetId()));
|
var envelopes = await _mediator.Send(query.Authorize(User.GetId()));
|
||||||
var envelope = envelopes.FirstOrDefault();
|
var envelope = envelopes.FirstOrDefault();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
|
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
|
||||||
using DigitalData.UserManager.Application.DTOs.User;
|
using DigitalData.UserManager.Application.DTOs.User;
|
||||||
|
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||||
using EnvelopeGenerator.Domain.Constants;
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
using EnvelopeGenerator.Domain.Interfaces;
|
using EnvelopeGenerator.Domain.Interfaces;
|
||||||
@@ -174,4 +175,9 @@ public record EnvelopeDto : IEnvelope
|
|||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<DocumentDto>? Documents { get; set; }
|
public IEnumerable<DocumentDto>? Documents { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<EnvelopeReceiverDto>? EnvelopeReceivers { get; set; }
|
||||||
}
|
}
|
||||||
@@ -14,4 +14,10 @@ public record EnvelopeQueryBase
|
|||||||
/// Die universell eindeutige Kennung des Umschlags.
|
/// Die universell eindeutige Kennung des Umschlags.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string? Uuid { get; set; }
|
public virtual string? Uuid { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wenn gesetzt, wird das DocResult-Feld in der Abfrage einbezogen.
|
||||||
|
/// Standardmäßig wird DocResult nicht geladen, um große Binärdaten zu vermeiden.
|
||||||
|
/// </summary>
|
||||||
|
public bool IncludeDocResult { get; set; } = false;
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.6" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -78,26 +78,29 @@
|
|||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
|
||||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.2" />
|
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.2" />
|
||||||
<PackageReference Include="CommandDotNet">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.20" />
|
||||||
|
<PackageReference Include="CommandDotNet">
|
||||||
<Version>7.0.5</Version>
|
<Version>7.0.5</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
||||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||||
<PackageReference Include="CommandDotNet">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.17" />
|
||||||
<Version>8.1.1</Version>
|
<PackageReference Include="CommandDotNet">
|
||||||
</PackageReference>
|
<Version>8.1.1</Version>
|
||||||
</ItemGroup>
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
|
||||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||||
<PackageReference Include="CommandDotNet">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.6" />
|
||||||
<Version>8.1.1</Version>
|
<PackageReference Include="CommandDotNet">
|
||||||
</PackageReference>
|
<Version>8.1.1</Version>
|
||||||
</ItemGroup>
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ public record ReadEnvelopeQuery : EnvelopeQueryBase, IRequest<IEnumerable<Envelo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int? UserId { get; init; }
|
public int? UserId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optionaler Zeitfilter in Minuten; wenn gesetzt, werden nur Umschläge zurückgegeben,
|
||||||
|
/// deren letzte Änderung mindestens diese Anzahl an Minuten zurückliegt.
|
||||||
|
/// </summary>
|
||||||
|
public int? MinMinutesSinceLastChange { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Setzt den Benutzerkontext für die Abfrage.
|
/// Setzt den Benutzerkontext für die Abfrage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -132,6 +138,12 @@ public class ReadEnvelopeQueryHandler : IRequestHandler<ReadEnvelopeQuery, IEnum
|
|||||||
query = query.Where(e => !status.Ignore.Contains(e.Status));
|
query = query.Where(e => !status.Ignore.Contains(e.Status));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.MinMinutesSinceLastChange is int minMinutesSinceLastChange)
|
||||||
|
{
|
||||||
|
query = query.Where(e => e.ChangedWhen.HasValue
|
||||||
|
&& EF.Functions.DateDiffMinute(e.ChangedWhen.Value, DateTime.Now) >= minMinutesSinceLastChange);
|
||||||
|
}
|
||||||
|
|
||||||
var envelopes = await query
|
var envelopes = await query
|
||||||
.Include(e => e.Documents)
|
.Include(e => e.Documents)
|
||||||
.ToListAsync(cancel);
|
.ToListAsync(cancel);
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using MediatR;
|
||||||
|
using EnvelopeGenerator.Application.Common.Dto;
|
||||||
|
using DigitalData.Core.Exceptions;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.Envelopes.Queries;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Repräsentiert eine Abfrage für Umschläge.
|
||||||
|
/// </summary>
|
||||||
|
public record ReadSingleEnvelopeDocResultQuery() : IRequest<byte[]>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public ReadSingleEnvelopeQuery Envelope { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verarbeitet <see cref="ReadEnvelopeQuery"/> und liefert passende <see cref="EnvelopeDto"/>-Ergebnisse.
|
||||||
|
/// </summary>
|
||||||
|
public class ReadSingleEnvelopeDocResultQueryHandler : IRequestHandler<ReadSingleEnvelopeDocResultQuery, byte[]>
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediator"></param>
|
||||||
|
public ReadSingleEnvelopeDocResultQueryHandler(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<byte[]> Handle(ReadSingleEnvelopeDocResultQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
request.Envelope.IncludeDocResult = true;
|
||||||
|
var result = await _mediator.Send(request.Envelope, cancellationToken);
|
||||||
|
return result.DocResult is byte[] docResult && docResult.Length > 0
|
||||||
|
? docResult
|
||||||
|
: throw new NotFoundException($"Document for Envelope with ID {request.Envelope.Id} not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using MediatR;
|
||||||
|
using EnvelopeGenerator.Application.Common.Query;
|
||||||
|
using EnvelopeGenerator.Application.Common.Dto;
|
||||||
|
using AutoMapper;
|
||||||
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using DigitalData.Core.Exceptions;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.Envelopes.Queries;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Repräsentiert eine Abfrage für einen einzelnen Umschlag.
|
||||||
|
/// </summary>
|
||||||
|
public record ReadSingleEnvelopeQuery : EnvelopeQueryBase, IRequest<EnvelopeDto>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Optionaler Benutzerfilter; wenn gesetzt, werden nur Umschläge des Benutzers geladen.
|
||||||
|
/// </summary>
|
||||||
|
public int? UserId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Setzt den Benutzerkontext für die Abfrage.
|
||||||
|
/// </summary>
|
||||||
|
public ReadSingleEnvelopeQuery Authorize(int userId) => this with { UserId = userId };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verarbeitet <see cref="ReadSingleEnvelopeQuery"/> und liefert ein einzelnes <see cref="EnvelopeDto"/>-Ergebnis.
|
||||||
|
/// </summary>
|
||||||
|
public class ReadSingleEnvelopeQueryHandler : IRequestHandler<ReadSingleEnvelopeQuery, EnvelopeDto>
|
||||||
|
{
|
||||||
|
private readonly IRepository<Envelope> _repository;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repository"></param>
|
||||||
|
/// <param name="mapper"></param>
|
||||||
|
public ReadSingleEnvelopeQueryHandler(IRepository<Envelope> repository, IMapper mapper)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="cancel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<EnvelopeDto> Handle(ReadSingleEnvelopeQuery request, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
var query = _repository.Query;
|
||||||
|
|
||||||
|
if (request.UserId is int userId)
|
||||||
|
query = query.Where(e => e.UserId == userId);
|
||||||
|
|
||||||
|
if (request.Id is int id)
|
||||||
|
query = query.Where(e => e.Id == id);
|
||||||
|
|
||||||
|
if (request.Uuid is string uuid)
|
||||||
|
query = query.Where(e => e.Uuid == uuid);
|
||||||
|
|
||||||
|
var envelopes = await query
|
||||||
|
.Include(e => e.Documents)
|
||||||
|
.Take(2)
|
||||||
|
.ToListAsync(cancel);
|
||||||
|
|
||||||
|
if (envelopes.Count > 1)
|
||||||
|
throw new BadRequestException($"Multiple envelopes found for the given criteria: Id={request.Id}, Uuid={request.Uuid}, UserId={request.UserId}");
|
||||||
|
|
||||||
|
return envelopes.SingleOrDefault() is Envelope envelope
|
||||||
|
? _mapper.Map<EnvelopeDto>(envelope)
|
||||||
|
: throw new NotFoundException($"Envelope with Id={request.Id}, Uuid={request.Uuid} not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
|
using DigitalData.Core.Exceptions;
|
||||||
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.ThirdPartyModules.Queries;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Query to read the license text of a third-party module.
|
||||||
|
/// Either <see cref="Id"/> or <see cref="Name"/> must be provided, but not both.
|
||||||
|
/// </summary>
|
||||||
|
public record ReadThirdPartyModuleLicenseQuery : IRequest<string>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The unique identifier of the third-party module (optional).
|
||||||
|
/// </summary>
|
||||||
|
public int? Id { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the third-party module (optional).
|
||||||
|
/// </summary>
|
||||||
|
public string? Name { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to filter only active modules. Defaults to <c>true</c>.
|
||||||
|
/// </summary>
|
||||||
|
public bool Active { get; init; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles <see cref="ReadThirdPartyModuleLicenseQuery"/> and returns the license text of a third-party module.
|
||||||
|
/// </summary>
|
||||||
|
public class ReadThirdPartyModuleLicenseQueryHandler : IRequestHandler<ReadThirdPartyModuleLicenseQuery, string>
|
||||||
|
{
|
||||||
|
private readonly IRepository<ThirdPartyModule> _repository;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ReadThirdPartyModuleLicenseQueryHandler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repository">The repository for accessing third-party modules.</param>
|
||||||
|
public ReadThirdPartyModuleLicenseQueryHandler(IRepository<ThirdPartyModule> repository)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the query by filtering on Id or Name and returning the license text.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The query parameters.</param>
|
||||||
|
/// <param name="cancel">A cancellation token.</param>
|
||||||
|
/// <returns>The license text of the matching third-party module.</returns>
|
||||||
|
/// <exception cref="BadRequestException">
|
||||||
|
/// Thrown when neither Id nor Name is provided, or when both are provided.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="InvalidOperationException">
|
||||||
|
/// Thrown when multiple modules match the given criteria, indicating a data integrity issue.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="NotFoundException">
|
||||||
|
/// Thrown when no module matches the given criteria.
|
||||||
|
/// </exception>
|
||||||
|
public async Task<string> Handle(ReadThirdPartyModuleLicenseQuery request, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
if (request.Id is null && request.Name is null)
|
||||||
|
throw new BadRequestException("Either Id or Name must be provided.");
|
||||||
|
|
||||||
|
if (request.Id is not null && request.Name is not null)
|
||||||
|
throw new BadRequestException("Only one of Id or Name must be provided, not both.");
|
||||||
|
|
||||||
|
var query = _repository.Query
|
||||||
|
.Where(m => m.Active == request.Active);
|
||||||
|
|
||||||
|
if (request.Id is int id)
|
||||||
|
query = query.Where(m => m.Id == id);
|
||||||
|
|
||||||
|
if (request.Name is string name)
|
||||||
|
query = query.Where(m => m.Name == name);
|
||||||
|
|
||||||
|
var modules = await query
|
||||||
|
.Take(2)
|
||||||
|
.ToListAsync(cancel);
|
||||||
|
|
||||||
|
if (modules.Count > 1)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Data integrity violation: multiple third-party modules found for the given criteria (Id={request.Id}, Name={request.Name}, Active={request.Active}).");
|
||||||
|
|
||||||
|
return modules.SingleOrDefault() is ThirdPartyModule module
|
||||||
|
? module.License
|
||||||
|
: throw new NotFoundException(
|
||||||
|
$"Third-party module not found for the given criteria (Id={request.Id}, Name={request.Name}, Active={request.Active}).");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -140,7 +140,9 @@ namespace EnvelopeGenerator.Domain.Entities
|
|||||||
= false;
|
= false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if NETFRAMEWORK
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
|
#endif
|
||||||
[Column("DOC_RESULT")]
|
[Column("DOC_RESULT")]
|
||||||
public byte[]
|
public byte[]
|
||||||
#if nullable
|
#if nullable
|
||||||
|
|||||||
61
EnvelopeGenerator.Domain/Entities/ThirdPartyModule.cs
Normal file
61
EnvelopeGenerator.Domain/Entities/ThirdPartyModule.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using EnvelopeGenerator.Domain.Interfaces.Auditing;
|
||||||
|
#if NETFRAMEWORK
|
||||||
|
using System;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Domain.Entities
|
||||||
|
{
|
||||||
|
[Table("TBDD_3RD_PARTY_MODULES", Schema = "dbo")]
|
||||||
|
public class ThirdPartyModule : IHasChangedWhen, IHasChangedWho
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
[Column("GUID")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("ACTIVE", TypeName = "bit")]
|
||||||
|
public bool Active { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("NAME", TypeName = "varchar(50)")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[Column("DESCRIPTION", TypeName = "varchar(500)")]
|
||||||
|
public string
|
||||||
|
#if nullable
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Description { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("LICENSE", TypeName = "varchar(max)")]
|
||||||
|
public string License { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("VERSION", TypeName = "varchar(20)")]
|
||||||
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
[Column("ADDED_WHO", TypeName = "varchar(50)")]
|
||||||
|
public string
|
||||||
|
#if nullable
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
AddedWho { get; set; }
|
||||||
|
|
||||||
|
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||||
|
public DateTime? AddedWhen { get; set; }
|
||||||
|
|
||||||
|
[Column("CHANGED_WHO", TypeName = "varchar(50)")]
|
||||||
|
public string
|
||||||
|
#if nullable
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
ChangedWho { get; set; }
|
||||||
|
|
||||||
|
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||||
|
public DateTime? ChangedWhen { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -81,6 +81,8 @@ public abstract class EGDbContextBase : DbContext
|
|||||||
|
|
||||||
public DbSet<EnvelopeReport> EnvelopeReports { get; set; }
|
public DbSet<EnvelopeReport> EnvelopeReports { get; set; }
|
||||||
|
|
||||||
|
public DbSet<ThirdPartyModule> ThirdPartyModules { get; set; }
|
||||||
|
|
||||||
private readonly DbTriggerParams _triggers;
|
private readonly DbTriggerParams _triggers;
|
||||||
|
|
||||||
private readonly ILogger
|
private readonly ILogger
|
||||||
@@ -202,6 +204,10 @@ public abstract class EGDbContextBase : DbContext
|
|||||||
.HasForeignKey(annot => annot.ElementId);
|
.HasForeignKey(annot => annot.ElementId);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region EnvelopeReport
|
||||||
|
modelBuilder.Entity<EnvelopeReport>().HasNoKey();
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Trigger
|
#region Trigger
|
||||||
// Configure entities to handle database triggers
|
// Configure entities to handle database triggers
|
||||||
void AddTrigger<T>() where T : class => _triggers
|
void AddTrigger<T>() where T : class => _triggers
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using EnvelopeGenerator.Application.Envelopes.Queries;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.ServiceHost.Controllers;
|
||||||
|
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class DocResultController(IMediator mediator) : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetAsync([FromQuery] ReadSingleEnvelopeDocResultQuery query, [FromQuery] bool download = false, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
var bytes = await mediator.Send(query, cancel);
|
||||||
|
|
||||||
|
if (download)
|
||||||
|
return File(bytes, "application/pdf", $"envelope_{query.Envelope.Uuid}.pdf");
|
||||||
|
|
||||||
|
return File(bytes, "application/pdf");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using EnvelopeGenerator.Application.Envelopes.Queries;
|
||||||
|
using EnvelopeGenerator.ServiceHost.Jobs;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.ServiceHost.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mediator"></param>
|
||||||
|
/// <param name="job"></param>
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class FinalizeDocumentController(IMediator mediator, FinalizeDocumentJob job) : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> FinalizeEnvelopeDocument([FromQuery] ReadSingleEnvelopeQuery query, [FromQuery] bool forceRegenerate = false, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
var envelope = await mediator.Send(query, cancel);
|
||||||
|
|
||||||
|
// TODO: migrate forceRegenerate input to FinalizeDocumentJob as property and remove this check from controller
|
||||||
|
if (envelope.DocResult is null || forceRegenerate)
|
||||||
|
await job.ExecuteAsync(envelope, cancel);
|
||||||
|
|
||||||
|
var docResult = await mediator.Send(new ReadSingleEnvelopeDocResultQuery() { Envelope = query }, cancel);
|
||||||
|
return File(docResult, "application/pdf", $"envelope_{query.Uuid}.pdf");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using EnvelopeGenerator.ServiceHost.Jobs;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.ServiceHost.Controllers;
|
||||||
|
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class WorkerController(JobStateManager jobStateManager) : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly JobStateManager _jobStateManager = jobStateManager;
|
||||||
|
|
||||||
|
[HttpGet(nameof(FinalizeDocumentJob))]
|
||||||
|
public IActionResult GetStateOfFinalizeDocumentJob() => Ok(_jobStateManager.GetState<FinalizeDocumentJob>());
|
||||||
|
|
||||||
|
[HttpPost(nameof(FinalizeDocumentJob))]
|
||||||
|
public IActionResult SetStateOfFinalizeDocumentJob([FromQuery] State state)
|
||||||
|
{
|
||||||
|
_jobStateManager.SetState<FinalizeDocumentJob>(state);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="DigitalData.Core.API" Version="2.2.1" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||||
<PackageReference Include="GdPicture" Version="14.3.3" />
|
<PackageReference Include="GdPicture" Version="14.3.3" />
|
||||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.4" />
|
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.4" />
|
||||||
@@ -18,16 +20,27 @@
|
|||||||
<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.*" />
|
<PackageReference Include="DevExpress.Reporting.Core" Version="24.2.*" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Caching.SqlServer" Version="8.0.17" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
|
||||||
<ProjectReference Include="..\EnvelopeGenerator.Domain\EnvelopeGenerator.Domain.csproj" />
|
<ProjectReference Include="..\EnvelopeGenerator.Domain\EnvelopeGenerator.Domain.csproj" />
|
||||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
||||||
<ProjectReference Include="..\EnvelopeGenerator.PdfEditor\EnvelopeGenerator.PdfEditor.csproj" />
|
<ProjectReference Include="..\EnvelopeGenerator.PdfEditor\EnvelopeGenerator.PdfEditor.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Controllers\" />
|
<Compile Update="Jobs\FinalizeDocument\rptEnvelopeHistory.cs">
|
||||||
|
<SubType>Component</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Jobs\FinalizeDocument\rptEnvelopeHistory.Designer.cs">
|
||||||
|
<DependentUpon>rptEnvelopeHistory.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<EmbeddedResource Update="Jobs\FinalizeDocument\rptEnvelopeHistory.resx">
|
||||||
|
<DependentUpon>rptEnvelopeHistory.cs</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using DigitalData.Modules.Database;
|
|
||||||
using EnvelopeGenerator.ServiceHost.Jobs;
|
using EnvelopeGenerator.ServiceHost.Jobs;
|
||||||
using EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
using EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
||||||
using GdPicture14;
|
using GdPicture14;
|
||||||
@@ -11,25 +10,23 @@ public static class DependencyInjection
|
|||||||
[Obsolete("Check obsoleted services")]
|
[Obsolete("Check obsoleted services")]
|
||||||
public static IServiceCollection AddFinalizeDocumentJob(this IServiceCollection services, IConfiguration configuration)
|
public static IServiceCollection AddFinalizeDocumentJob(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
services.Configure<WorkerOptions>(configuration.GetSection(nameof(WorkerOptions)));
|
services.Configure<WorkerOptions>(configuration.GetSection("Worker"));
|
||||||
services.AddSingleton<FinalizeDocumentJob>();
|
services.AddSingleton(provider =>
|
||||||
|
{
|
||||||
|
var options = provider.GetRequiredService<IOptions<WorkerOptions>>().Value;
|
||||||
|
var manager = new JobStateManager(options.InitialJobState);
|
||||||
|
return manager;
|
||||||
|
});
|
||||||
|
services.AddScoped<FinalizeDocumentJob>();
|
||||||
services.AddScoped<ActionService>();
|
services.AddScoped<ActionService>();
|
||||||
services.AddSingleton<TempFiles>();
|
services.AddSingleton<TempFiles>();
|
||||||
services.AddScoped<PDFBurner>();
|
services.AddScoped<PDFBurner>();
|
||||||
services.AddScoped<PDFMerger>();
|
services.AddScoped<PDFMerger>();
|
||||||
services.AddScoped<ReportModel>();
|
services.AddScoped<ReportCreator>();
|
||||||
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.
|
||||||
services.AddTransient<GdViewer>();
|
services.AddTransient<GdViewer>();
|
||||||
// Add LicenseManager
|
services.AddSingleton<LicenseManagerFactory>();
|
||||||
services.AddTransient(provider =>
|
|
||||||
{
|
|
||||||
var options = provider.GetRequiredService<IOptions<WorkerOptions>>().Value;
|
|
||||||
var licenseManager = new LicenseManager();
|
|
||||||
licenseManager.RegisterKEY(options.GdPictureLicenseKey);
|
|
||||||
return licenseManager;
|
|
||||||
});
|
|
||||||
services.AddTransient<AnnotationManager>();
|
services.AddTransient<AnnotationManager>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using DigitalData.Core.Abstraction.Application.Repository;
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
|
using EnvelopeGenerator.Application.Common.Dto;
|
||||||
|
using EnvelopeGenerator.Application.Common.Dto.Receiver;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.ServiceHost.Jobs;
|
namespace EnvelopeGenerator.ServiceHost.Jobs;
|
||||||
@@ -10,25 +12,25 @@ namespace EnvelopeGenerator.ServiceHost.Jobs;
|
|||||||
public class ActionService(IRepository<History> histRepo)
|
public class ActionService(IRepository<History> histRepo)
|
||||||
{
|
{
|
||||||
[Obsolete("This is a placeholder service added by copilot. Migrate the actual logic from CommonServices.Jobs")]
|
[Obsolete("This is a placeholder service added by copilot. Migrate the actual logic from CommonServices.Jobs")]
|
||||||
public bool CreateReport(Envelope envelope, CancellationToken cancel = default)
|
public bool CreateReport(EnvelopeDto envelope, CancellationToken cancel = default)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("This is a placeholder service added by copilot. Migrate the actual logic from CommonServices.Jobs")]
|
[Obsolete("This is a placeholder service added by copilot. Migrate the actual logic from CommonServices.Jobs")]
|
||||||
public bool FinalizeEnvelope(Envelope envelope, CancellationToken cancel = default)
|
public bool FinalizeEnvelope(EnvelopeDto envelope, CancellationToken cancel = default)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("This is a placeholder service added by copilot. Migrate the actual logic from CommonServices.Jobs")]
|
[Obsolete("This is a placeholder service added by copilot. Migrate the actual logic from CommonServices.Jobs")]
|
||||||
public bool CompleteEnvelope(Envelope envelope, CancellationToken cancel = default)
|
public bool CompleteEnvelope(EnvelopeDto envelope, CancellationToken cancel = default)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("This is a placeholder service added by copilot. Migrate the actual logic from CommonServices.Jobs")]
|
[Obsolete("This is a placeholder service added by copilot. Migrate the actual logic from CommonServices.Jobs")]
|
||||||
public bool CompleteEnvelope(Envelope envelope, Receiver receiver, CancellationToken cancel = default)
|
public bool CompleteEnvelope(EnvelopeDto envelope, ReceiverDto receiver, CancellationToken cancel = default)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using EnvelopeGenerator.Domain.Entities;
|
|||||||
using EnvelopeGenerator.Infrastructure;
|
using EnvelopeGenerator.Infrastructure;
|
||||||
using EnvelopeGenerator.PdfEditor;
|
using EnvelopeGenerator.PdfEditor;
|
||||||
using EnvelopeGenerator.ServiceHost.Exceptions;
|
using EnvelopeGenerator.ServiceHost.Exceptions;
|
||||||
|
using EnvelopeGenerator.ServiceHost.Jobs;
|
||||||
using GdPicture14;
|
using GdPicture14;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
@@ -11,16 +12,7 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
||||||
|
|
||||||
//TODO: check if licence manager is needed as a dependency to
|
public class PDFBurner(IOptions<WorkerOptions> workerOptions, EGDbContext context, ILogger<PDFBurner> logger, LicenseManagerFactory licenseManagerFactory, AnnotationManager manager)
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="workerOptions"></param>
|
|
||||||
/// <param name="context2"></param>
|
|
||||||
/// <param name="logger2"></param>
|
|
||||||
/// <param name="licenseManager"></param>
|
|
||||||
/// <param name="annotationManager2"></param>
|
|
||||||
public class PDFBurner(IOptions<WorkerOptions> workerOptions, EGDbContext context, ILogger<PDFBurner> logger, LicenseManager licenseManager, AnnotationManager manager)
|
|
||||||
{
|
{
|
||||||
private readonly WorkerOptions.PDFBurnerOptions _options = workerOptions.Value.PdfBurner;
|
private readonly WorkerOptions.PDFBurnerOptions _options = workerOptions.Value.PdfBurner;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using EnvelopeGenerator.ServiceHost.Exceptions;
|
using EnvelopeGenerator.ServiceHost.Exceptions;
|
||||||
|
using EnvelopeGenerator.ServiceHost.Jobs;
|
||||||
using GdPicture14;
|
using GdPicture14;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
@@ -7,16 +8,16 @@ namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
|||||||
public class PDFMerger
|
public class PDFMerger
|
||||||
{
|
{
|
||||||
private readonly AnnotationManager _manager;
|
private readonly AnnotationManager _manager;
|
||||||
private readonly LicenseManager _licenseManager;
|
private readonly LicenseManagerFactory _licenseManagerFactory;
|
||||||
|
|
||||||
private const bool AllowRasterization = true;
|
private const bool AllowRasterization = true;
|
||||||
private const bool AllowVectorization = true;
|
private const bool AllowVectorization = true;
|
||||||
|
|
||||||
private readonly PdfConversionConformance _pdfaConformanceLevel = PdfConversionConformance.PDF_A_1b;
|
private readonly PdfConversionConformance _pdfaConformanceLevel = PdfConversionConformance.PDF_A_1b;
|
||||||
|
|
||||||
public PDFMerger(LicenseManager licenseManager, AnnotationManager annotationManager)
|
public PDFMerger(LicenseManagerFactory licenseManagerFactory, AnnotationManager annotationManager)
|
||||||
{
|
{
|
||||||
_licenseManager = licenseManager;
|
_licenseManagerFactory = licenseManagerFactory;
|
||||||
_manager = annotationManager;
|
_manager = annotationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,103 +1,30 @@
|
|||||||
using System.Data;
|
using DevExpress.Xpo;
|
||||||
using DigitalData.Core.Abstraction.Application.Repository;
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
using EnvelopeGenerator.Domain.Constants;
|
using EnvelopeGenerator.Application.Common.Dto;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
using EnvelopeGenerator.ServiceHost.Exceptions;
|
using EnvelopeGenerator.ServiceHost.Exceptions;
|
||||||
using EnvelopeGenerator.ServiceHost.Extensions;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
||||||
|
|
||||||
[Obsolete("Instead of ReportModel create and use EnvelopeReport mediator queries")]
|
public class ReportCreator(IRepository<EnvelopeReport> reportRepo)
|
||||||
public class ReportCreator(ReportModel ReportModel, ILogger<ReportCreator> Logger, IRepository<EnvelopeReport> reportRepo)
|
|
||||||
{
|
{
|
||||||
[Obsolete("Solve the spaghetti...")]
|
public async Task<byte[]> CreateReportAsync(EnvelopeDto envelope, CancellationToken cancel = default)
|
||||||
private Envelope? _envelope;
|
|
||||||
|
|
||||||
[Obsolete("Instead of ReportModel create and use EnvelopeReport mediator queries and solve this spaghetti...")]
|
|
||||||
public byte[] CreateReport(Envelope envelope)
|
|
||||||
{
|
{
|
||||||
try
|
var reports = await reportRepo.Where(r => r.EnvelopeId == envelope.Id).ToListAsync(cancel);
|
||||||
{
|
|
||||||
Logger.LogDebug("Loading report data..");
|
|
||||||
var table = ReportModel.List(envelope.Id);
|
|
||||||
var items = GetReportSource(table);
|
|
||||||
|
|
||||||
_envelope = envelope;
|
if (reports.Count == 0)
|
||||||
|
throw new CreateReportException("Could not prepare report data! No report data found!");
|
||||||
|
|
||||||
if (items.Count == 0)
|
var items = reports
|
||||||
{
|
.Select(r => new ReportItem(r, envelope))
|
||||||
throw new CreateReportException("No report data found!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.LogDebug("Creating report with [{count}] items..", items.Count);
|
|
||||||
var buffer = DoCreateReport(items);
|
|
||||||
Logger.LogDebug("Report created!");
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogError(ex);
|
|
||||||
throw new CreateReportException("Could not prepare report data!", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ReportItem> GetReportSource(DataTable dataTable)
|
|
||||||
{
|
|
||||||
Logger.LogDebug("Preparing report data");
|
|
||||||
return dataTable.Rows
|
|
||||||
.Cast<DataRow>()
|
|
||||||
.Select(ToReportItem)
|
|
||||||
.OrderByDescending(r => r.ItemDate)
|
.OrderByDescending(r => r.ItemDate)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] DoCreateReport(List<ReportItem> reportItems)
|
|
||||||
{
|
|
||||||
var items = reportItems.Select(MergeEnvelope).ToList();
|
|
||||||
var source = new ReportSource { Items = items };
|
var source = new ReportSource { Items = items };
|
||||||
var report = new rptEnvelopeHistory { DataSource = source, DataMember = "Items" };
|
var report = new rptEnvelopeHistory { DataSource = source, DataMember = "Items" };
|
||||||
|
|
||||||
Logger.LogDebug("Creating report in memory..");
|
|
||||||
report.CreateDocument();
|
report.CreateDocument();
|
||||||
|
|
||||||
Logger.LogDebug("Exporting report to stream..");
|
|
||||||
using var stream = new MemoryStream();
|
using var stream = new MemoryStream();
|
||||||
report.ExportToPdf(stream);
|
report.ExportToPdf(stream);
|
||||||
|
|
||||||
Logger.LogDebug("Writing report to buffer..");
|
|
||||||
return stream.ToArray();
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Solve this spaghetti...")]
|
|
||||||
private ReportItem MergeEnvelope(ReportItem item)
|
|
||||||
{
|
|
||||||
if (item.Envelope is null)
|
|
||||||
{
|
|
||||||
item.Envelope = _envelope;
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ReportItem ToReportItem(DataRow row)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new ReportItem
|
|
||||||
{
|
|
||||||
EnvelopeId = row.ItemEx("ENVELOPE_ID", 0),
|
|
||||||
EnvelopeTitle = row.ItemEx("HEAD_TITLE", string.Empty),
|
|
||||||
EnvelopeSubject = row.ItemEx("HEAD_SUBJECT", string.Empty),
|
|
||||||
ItemDate = row.ItemEx("POS_WHEN", DateTime.MinValue),
|
|
||||||
ItemStatus = (EnvelopeStatus)row.ItemEx("POS_STATUS", 0),
|
|
||||||
ItemUserReference = row.ItemEx("POS_WHO", string.Empty)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogError(ex);
|
|
||||||
throw new CreateReportException("Could not read data from database!", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using EnvelopeGenerator.Application.Common.Dto;
|
||||||
using EnvelopeGenerator.Domain.Constants;
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
|
|
||||||
@@ -5,15 +6,32 @@ namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
|||||||
|
|
||||||
public class ReportItem
|
public class ReportItem
|
||||||
{
|
{
|
||||||
public Envelope? Envelope { get; set; }
|
public ReportItem() { }
|
||||||
public int EnvelopeId { get; set; }
|
|
||||||
|
public ReportItem(EnvelopeReport report, EnvelopeDto envelope)
|
||||||
|
{
|
||||||
|
CreatorFullName = envelope.User is not null
|
||||||
|
? $"{envelope.User.Prename} {envelope.User.Name}".Trim()
|
||||||
|
: string.Empty;
|
||||||
|
CreatorEmailAddress = envelope.User?.Email ?? string.Empty;
|
||||||
|
EnvelopeTitle = report.HeadTitle ?? string.Empty;
|
||||||
|
EnvelopeUuid = report.HeadUuid ?? string.Empty;
|
||||||
|
EnvelopeCertificationType = envelope.CertificationType is int certType ? ((CertificationType)certType).ToString() : "null";
|
||||||
|
ItemStatus = (EnvelopeStatus)report.PosStatus;
|
||||||
|
ItemUserReference = report.PosWho ?? string.Empty;
|
||||||
|
ItemDate = report.PosWhen ?? DateTime.MinValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header fields (from Envelope)
|
||||||
|
public string CreatorFullName { get; set; } = string.Empty;
|
||||||
|
public string CreatorEmailAddress { get; set; } = string.Empty;
|
||||||
public string EnvelopeTitle { get; set; } = string.Empty;
|
public string EnvelopeTitle { get; set; } = string.Empty;
|
||||||
public string EnvelopeSubject { get; set; } = string.Empty;
|
public string EnvelopeUuid { get; set; } = string.Empty;
|
||||||
|
public string EnvelopeCertificationType { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
// Detail fields (from EnvelopeReport)
|
||||||
public EnvelopeStatus ItemStatus { get; set; }
|
public EnvelopeStatus ItemStatus { get; set; }
|
||||||
|
|
||||||
public string ItemStatusTranslated => ItemStatus.ToString();
|
public string ItemStatusTranslated => ItemStatus.ToString();
|
||||||
|
|
||||||
public string ItemUserReference { get; set; } = string.Empty;
|
public string ItemUserReference { get; set; } = string.Empty;
|
||||||
public DateTime ItemDate { get; set; }
|
public DateTime ItemDate { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
736
EnvelopeGenerator.ServiceHost/Jobs/FinalizeDocument/rptEnvelopeHistory.Designer.cs
generated
Normal file
736
EnvelopeGenerator.ServiceHost/Jobs/FinalizeDocument/rptEnvelopeHistory.Designer.cs
generated
Normal file
@@ -0,0 +1,736 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Printing;
|
||||||
|
using DevExpress.DataAccess.ObjectBinding;
|
||||||
|
using DevExpress.XtraPrinting;
|
||||||
|
using DevExpress.XtraReports.UI;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
||||||
|
|
||||||
|
public partial class rptEnvelopeHistory : XtraReport
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && components != null)
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.components = new Container();
|
||||||
|
var resources = new ComponentResourceManager(typeof(rptEnvelopeHistory));
|
||||||
|
this.TopMargin = new TopMarginBand();
|
||||||
|
this.BottomMargin = new BottomMarginBand();
|
||||||
|
this.XrLabel1 = new XRLabel();
|
||||||
|
this.pageInfo1 = new XRPageInfo();
|
||||||
|
this.pageInfo2 = new XRPageInfo();
|
||||||
|
this.ReportHeader = new ReportHeaderBand();
|
||||||
|
this.label1 = new XRLabel();
|
||||||
|
this.XrTable3 = new XRTable();
|
||||||
|
this.XrTableRow8 = new XRTableRow();
|
||||||
|
this.XrTableCell13 = new XRTableCell();
|
||||||
|
this.XrTableCell15 = new XRTableCell();
|
||||||
|
this.XrTableRow9 = new XRTableRow();
|
||||||
|
this.XrTableCell14 = new XRTableCell();
|
||||||
|
this.XrTableCell17 = new XRTableCell();
|
||||||
|
this.XrTableCell16 = new XRTableCell();
|
||||||
|
this.XrTableCell18 = new XRTableCell();
|
||||||
|
this.XrTableRow10 = new XRTableRow();
|
||||||
|
this.XrTableCell19 = new XRTableCell();
|
||||||
|
this.XrTableCell20 = new XRTableCell();
|
||||||
|
this.XrTableCell21 = new XRTableCell();
|
||||||
|
this.XrTableCell22 = new XRTableCell();
|
||||||
|
this.XrTableRow11 = new XRTableRow();
|
||||||
|
this.XrTableCell23 = new XRTableCell();
|
||||||
|
this.XrTableCell24 = new XRTableCell();
|
||||||
|
this.XrTableCell25 = new XRTableCell();
|
||||||
|
this.XrTableCell26 = new XRTableCell();
|
||||||
|
this.GroupHeader1 = new GroupHeaderBand();
|
||||||
|
this.table1 = new XRTable();
|
||||||
|
this.tableRow1 = new XRTableRow();
|
||||||
|
this.tableCell1 = new XRTableCell();
|
||||||
|
this.tableCell2 = new XRTableCell();
|
||||||
|
this.tableCell3 = new XRTableCell();
|
||||||
|
this.Detail = new DetailBand();
|
||||||
|
this.table2 = new XRTable();
|
||||||
|
this.tableRow2 = new XRTableRow();
|
||||||
|
this.tableCell4 = new XRTableCell();
|
||||||
|
this.tableCell5 = new XRTableCell();
|
||||||
|
this.tableCell6 = new XRTableCell();
|
||||||
|
this.Title = new XRControlStyle();
|
||||||
|
this.DetailCaption1 = new XRControlStyle();
|
||||||
|
this.DetailData1 = new XRControlStyle();
|
||||||
|
this.DetailData3_Odd = new XRControlStyle();
|
||||||
|
this.PageInfo = new XRControlStyle();
|
||||||
|
this.ObjectDataSource1 = new ObjectDataSource(this.components);
|
||||||
|
((ISupportInitialize)this.XrTable3).BeginInit();
|
||||||
|
((ISupportInitialize)this.table1).BeginInit();
|
||||||
|
((ISupportInitialize)this.table2).BeginInit();
|
||||||
|
((ISupportInitialize)this.ObjectDataSource1).BeginInit();
|
||||||
|
((ISupportInitialize)this).BeginInit();
|
||||||
|
//
|
||||||
|
// TopMargin
|
||||||
|
//
|
||||||
|
this.TopMargin.Dpi = 254F;
|
||||||
|
this.TopMargin.HeightF = 190.6042F;
|
||||||
|
this.TopMargin.Name = "TopMargin";
|
||||||
|
//
|
||||||
|
// BottomMargin
|
||||||
|
//
|
||||||
|
this.BottomMargin.Controls.AddRange(new XRControl[] { this.XrLabel1, this.pageInfo1, this.pageInfo2 });
|
||||||
|
this.BottomMargin.Dpi = 254F;
|
||||||
|
this.BottomMargin.Name = "BottomMargin";
|
||||||
|
//
|
||||||
|
// XrLabel1
|
||||||
|
//
|
||||||
|
this.XrLabel1.BorderColor = Color.FromArgb(165, 36, 49);
|
||||||
|
this.XrLabel1.Borders = BorderSide.Top;
|
||||||
|
this.XrLabel1.Dpi = 254F;
|
||||||
|
this.XrLabel1.Font = new Font("Arial", 8.25F, FontStyle.Bold);
|
||||||
|
this.XrLabel1.LocationFloat = new DevExpress.Utils.PointFloat(896.5417F, 0F);
|
||||||
|
this.XrLabel1.Name = "XrLabel1";
|
||||||
|
this.XrLabel1.Padding = new PaddingInfo(0, 0, 0, 0, 254F);
|
||||||
|
this.XrLabel1.SizeF = new SizeF(645.5836F, 58F);
|
||||||
|
this.XrLabel1.StyleName = "Title";
|
||||||
|
this.XrLabel1.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrLabel1.StylePriority.UseBorders = false;
|
||||||
|
this.XrLabel1.StylePriority.UseFont = false;
|
||||||
|
this.XrLabel1.StylePriority.UsePadding = false;
|
||||||
|
this.XrLabel1.Text = "Erstellt mit SignFlow";
|
||||||
|
//
|
||||||
|
// pageInfo1
|
||||||
|
//
|
||||||
|
this.pageInfo1.BorderColor = Color.FromArgb(165, 36, 49);
|
||||||
|
this.pageInfo1.Borders = BorderSide.Top;
|
||||||
|
this.pageInfo1.Dpi = 254F;
|
||||||
|
this.pageInfo1.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F);
|
||||||
|
this.pageInfo1.Name = "pageInfo1";
|
||||||
|
this.pageInfo1.PageInfo = DevExpress.XtraPrinting.PageInfo.DateTime;
|
||||||
|
this.pageInfo1.SizeF = new SizeF(896.5417F, 58F);
|
||||||
|
this.pageInfo1.StyleName = "PageInfo";
|
||||||
|
this.pageInfo1.StylePriority.UseBorderColor = false;
|
||||||
|
this.pageInfo1.StylePriority.UseBorders = false;
|
||||||
|
this.pageInfo1.TextFormatString = "{0:dddd, d. MMMM yyyy HH:mm}";
|
||||||
|
//
|
||||||
|
// pageInfo2
|
||||||
|
//
|
||||||
|
this.pageInfo2.BorderColor = Color.FromArgb(165, 36, 49);
|
||||||
|
this.pageInfo2.Borders = BorderSide.Top;
|
||||||
|
this.pageInfo2.Dpi = 254F;
|
||||||
|
this.pageInfo2.LocationFloat = new DevExpress.Utils.PointFloat(1542.125F, 0F);
|
||||||
|
this.pageInfo2.Name = "pageInfo2";
|
||||||
|
this.pageInfo2.SizeF = new SizeF(357.875F, 58F);
|
||||||
|
this.pageInfo2.StyleName = "PageInfo";
|
||||||
|
this.pageInfo2.StylePriority.UseBorderColor = false;
|
||||||
|
this.pageInfo2.StylePriority.UseBorders = false;
|
||||||
|
this.pageInfo2.TextAlignment = TextAlignment.TopRight;
|
||||||
|
this.pageInfo2.TextFormatString = "Seite {0} von {1}";
|
||||||
|
//
|
||||||
|
// ReportHeader
|
||||||
|
//
|
||||||
|
this.ReportHeader.Controls.AddRange(new XRControl[] { this.label1, this.XrTable3 });
|
||||||
|
this.ReportHeader.Dpi = 254F;
|
||||||
|
this.ReportHeader.HeightF = 406.0843F;
|
||||||
|
this.ReportHeader.Name = "ReportHeader";
|
||||||
|
//
|
||||||
|
// label1
|
||||||
|
//
|
||||||
|
this.label1.BackColor = Color.FromArgb(224, 224, 224);
|
||||||
|
this.label1.BorderColor = Color.FromArgb(165, 36, 49);
|
||||||
|
this.label1.Borders = BorderSide.Bottom;
|
||||||
|
this.label1.BorderWidth = 2F;
|
||||||
|
this.label1.Dpi = 254F;
|
||||||
|
this.label1.Font = new Font("Segoe UI", 14.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||||
|
this.label1.ForeColor = Color.Black;
|
||||||
|
this.label1.LocationFloat = new DevExpress.Utils.PointFloat(0.0002422333F, 0F);
|
||||||
|
this.label1.Name = "label1";
|
||||||
|
this.label1.Padding = new PaddingInfo(10, 10, 5, 5, 254F);
|
||||||
|
this.label1.SizeF = new SizeF(1900F, 77.32857F);
|
||||||
|
this.label1.StyleName = "Title";
|
||||||
|
this.label1.StylePriority.UseBackColor = false;
|
||||||
|
this.label1.StylePriority.UseBorderColor = false;
|
||||||
|
this.label1.StylePriority.UseBorders = false;
|
||||||
|
this.label1.StylePriority.UseBorderWidth = false;
|
||||||
|
this.label1.StylePriority.UseFont = false;
|
||||||
|
this.label1.StylePriority.UseForeColor = false;
|
||||||
|
this.label1.StylePriority.UsePadding = false;
|
||||||
|
this.label1.Text = "Signierungszertifikat";
|
||||||
|
//
|
||||||
|
// XrTable3
|
||||||
|
//
|
||||||
|
this.XrTable3.Dpi = 254F;
|
||||||
|
this.XrTable3.LocationFloat = new DevExpress.Utils.PointFloat(0.0002422333F, 96.60422F);
|
||||||
|
this.XrTable3.Name = "XrTable3";
|
||||||
|
this.XrTable3.OddStyleName = "DetailData3_Odd";
|
||||||
|
this.XrTable3.Rows.AddRange(new XRTableRow[] { this.XrTableRow8, this.XrTableRow9, this.XrTableRow10, this.XrTableRow11 });
|
||||||
|
this.XrTable3.SizeF = new SizeF(1900F, 284.4801F);
|
||||||
|
//
|
||||||
|
// XrTableRow8
|
||||||
|
//
|
||||||
|
this.XrTableRow8.Cells.AddRange(new XRTableCell[] { this.XrTableCell13, this.XrTableCell15 });
|
||||||
|
this.XrTableRow8.Dpi = 254F;
|
||||||
|
this.XrTableRow8.Name = "XrTableRow8";
|
||||||
|
this.XrTableRow8.Weight = 1D;
|
||||||
|
//
|
||||||
|
// XrTableCell13
|
||||||
|
//
|
||||||
|
this.XrTableCell13.BackColor = Color.FromArgb(224, 224, 224);
|
||||||
|
this.XrTableCell13.BorderColor = Color.FromArgb(165, 36, 49);
|
||||||
|
this.XrTableCell13.Borders = BorderSide.Bottom;
|
||||||
|
this.XrTableCell13.BorderWidth = 1F;
|
||||||
|
this.XrTableCell13.Dpi = 254F;
|
||||||
|
this.XrTableCell13.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell13.Name = "XrTableCell13";
|
||||||
|
this.XrTableCell13.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell13.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell13.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell13.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell13.StylePriority.UseBorderWidth = false;
|
||||||
|
this.XrTableCell13.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell13.Text = "Ersteller";
|
||||||
|
this.XrTableCell13.Weight = 0.38139956730411484D;
|
||||||
|
//
|
||||||
|
// XrTableCell15
|
||||||
|
//
|
||||||
|
this.XrTableCell15.BackColor = Color.FromArgb(224, 224, 224);
|
||||||
|
this.XrTableCell15.BorderColor = Color.FromArgb(165, 36, 49);
|
||||||
|
this.XrTableCell15.Borders = BorderSide.Bottom;
|
||||||
|
this.XrTableCell15.BorderWidth = 1F;
|
||||||
|
this.XrTableCell15.Dpi = 254F;
|
||||||
|
this.XrTableCell15.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell15.Name = "XrTableCell15";
|
||||||
|
this.XrTableCell15.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell15.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell15.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell15.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell15.StylePriority.UseBorderWidth = false;
|
||||||
|
this.XrTableCell15.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell15.Text = "Umschlag";
|
||||||
|
this.XrTableCell15.Weight = 0.49859081604996847D;
|
||||||
|
//
|
||||||
|
// XrTableRow9
|
||||||
|
//
|
||||||
|
this.XrTableRow9.Cells.AddRange(new XRTableCell[] { this.XrTableCell14, this.XrTableCell17, this.XrTableCell16, this.XrTableCell18 });
|
||||||
|
this.XrTableRow9.Dpi = 254F;
|
||||||
|
this.XrTableRow9.Name = "XrTableRow9";
|
||||||
|
this.XrTableRow9.Weight = 1D;
|
||||||
|
//
|
||||||
|
// XrTableCell14
|
||||||
|
//
|
||||||
|
this.XrTableCell14.BackColor = Color.White;
|
||||||
|
this.XrTableCell14.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell14.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell14.Dpi = 254F;
|
||||||
|
this.XrTableCell14.Font = new Font("Arial", 8.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell14.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell14.Multiline = true;
|
||||||
|
this.XrTableCell14.Name = "XrTableCell14";
|
||||||
|
this.XrTableCell14.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell14.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell14.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell14.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell14.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell14.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell14.Text = "Name";
|
||||||
|
this.XrTableCell14.Weight = 0.11578820509129036D;
|
||||||
|
//
|
||||||
|
// XrTableCell17
|
||||||
|
//
|
||||||
|
this.XrTableCell17.BackColor = Color.White;
|
||||||
|
this.XrTableCell17.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell17.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell17.Dpi = 254F;
|
||||||
|
this.XrTableCell17.ExpressionBindings.AddRange(new ExpressionBinding[] { new ExpressionBinding("BeforePrint", "Text", "[CreatorFullName]") });
|
||||||
|
this.XrTableCell17.Font = new Font("Arial", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell17.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell17.Multiline = true;
|
||||||
|
this.XrTableCell17.Name = "XrTableCell17";
|
||||||
|
this.XrTableCell17.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell17.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell17.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell17.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell17.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell17.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell17.Text = "XrTableCell17";
|
||||||
|
this.XrTableCell17.Weight = 0.2656113622128245D;
|
||||||
|
//
|
||||||
|
// XrTableCell16
|
||||||
|
//
|
||||||
|
this.XrTableCell16.BackColor = Color.White;
|
||||||
|
this.XrTableCell16.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell16.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell16.Dpi = 254F;
|
||||||
|
this.XrTableCell16.Font = new Font("Arial", 8.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell16.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell16.Multiline = true;
|
||||||
|
this.XrTableCell16.Name = "XrTableCell16";
|
||||||
|
this.XrTableCell16.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell16.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell16.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell16.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell16.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell16.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell16.Text = "Titel";
|
||||||
|
this.XrTableCell16.Weight = 0.11578821158083684D;
|
||||||
|
//
|
||||||
|
// XrTableCell18
|
||||||
|
//
|
||||||
|
this.XrTableCell18.BackColor = Color.White;
|
||||||
|
this.XrTableCell18.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell18.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell18.Dpi = 254F;
|
||||||
|
this.XrTableCell18.ExpressionBindings.AddRange(new ExpressionBinding[] { new ExpressionBinding("BeforePrint", "Text", "[EnvelopeTitle]") });
|
||||||
|
this.XrTableCell18.Font = new Font("Arial", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell18.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell18.Multiline = true;
|
||||||
|
this.XrTableCell18.Name = "XrTableCell18";
|
||||||
|
this.XrTableCell18.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell18.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell18.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell18.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell18.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell18.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell18.Text = "XrTableCell18";
|
||||||
|
this.XrTableCell18.Weight = 0.38280260446913167D;
|
||||||
|
//
|
||||||
|
// XrTableRow10
|
||||||
|
//
|
||||||
|
this.XrTableRow10.Cells.AddRange(new XRTableCell[] { this.XrTableCell19, this.XrTableCell20, this.XrTableCell21, this.XrTableCell22 });
|
||||||
|
this.XrTableRow10.Dpi = 254F;
|
||||||
|
this.XrTableRow10.Name = "XrTableRow10";
|
||||||
|
this.XrTableRow10.Weight = 1D;
|
||||||
|
//
|
||||||
|
// XrTableCell19
|
||||||
|
//
|
||||||
|
this.XrTableCell19.BackColor = Color.White;
|
||||||
|
this.XrTableCell19.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell19.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell19.Dpi = 254F;
|
||||||
|
this.XrTableCell19.Font = new Font("Arial", 8.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell19.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell19.Multiline = true;
|
||||||
|
this.XrTableCell19.Name = "XrTableCell19";
|
||||||
|
this.XrTableCell19.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell19.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell19.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell19.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell19.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell19.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell19.Text = "EmailAddress";
|
||||||
|
this.XrTableCell19.Weight = 0.11578820509129036D;
|
||||||
|
//
|
||||||
|
// XrTableCell20
|
||||||
|
//
|
||||||
|
this.XrTableCell20.BackColor = Color.White;
|
||||||
|
this.XrTableCell20.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell20.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell20.Dpi = 254F;
|
||||||
|
this.XrTableCell20.ExpressionBindings.AddRange(new ExpressionBinding[] { new ExpressionBinding("BeforePrint", "Text", "[CreatorEmailAddress]") });
|
||||||
|
this.XrTableCell20.Font = new Font("Arial", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell20.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell20.Multiline = true;
|
||||||
|
this.XrTableCell20.Name = "XrTableCell20";
|
||||||
|
this.XrTableCell20.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell20.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell20.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell20.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell20.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell20.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell20.Text = "XrTableCell20";
|
||||||
|
this.XrTableCell20.Weight = 0.2656113622128245D;
|
||||||
|
//
|
||||||
|
// XrTableCell21
|
||||||
|
//
|
||||||
|
this.XrTableCell21.BackColor = Color.White;
|
||||||
|
this.XrTableCell21.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell21.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell21.Dpi = 254F;
|
||||||
|
this.XrTableCell21.Font = new Font("Arial", 8.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell21.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell21.Multiline = true;
|
||||||
|
this.XrTableCell21.Name = "XrTableCell21";
|
||||||
|
this.XrTableCell21.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell21.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell21.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell21.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell21.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell21.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell21.Text = "Umschlag-ID";
|
||||||
|
this.XrTableCell21.Weight = 0.11578821158083684D;
|
||||||
|
//
|
||||||
|
// XrTableCell22
|
||||||
|
//
|
||||||
|
this.XrTableCell22.BackColor = Color.White;
|
||||||
|
this.XrTableCell22.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell22.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell22.Dpi = 254F;
|
||||||
|
this.XrTableCell22.ExpressionBindings.AddRange(new ExpressionBinding[] { new ExpressionBinding("BeforePrint", "Text", "[EnvelopeUuid]") });
|
||||||
|
this.XrTableCell22.Font = new Font("Arial", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell22.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell22.Multiline = true;
|
||||||
|
this.XrTableCell22.Name = "XrTableCell22";
|
||||||
|
this.XrTableCell22.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell22.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell22.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell22.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell22.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell22.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell22.Text = "XrTableCell22";
|
||||||
|
this.XrTableCell22.Weight = 0.38280260446913167D;
|
||||||
|
//
|
||||||
|
// XrTableRow11
|
||||||
|
//
|
||||||
|
this.XrTableRow11.Cells.AddRange(new XRTableCell[] { this.XrTableCell23, this.XrTableCell24, this.XrTableCell25, this.XrTableCell26 });
|
||||||
|
this.XrTableRow11.Dpi = 254F;
|
||||||
|
this.XrTableRow11.Name = "XrTableRow11";
|
||||||
|
this.XrTableRow11.Weight = 1D;
|
||||||
|
//
|
||||||
|
// XrTableCell23
|
||||||
|
//
|
||||||
|
this.XrTableCell23.BackColor = Color.White;
|
||||||
|
this.XrTableCell23.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell23.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell23.Dpi = 254F;
|
||||||
|
this.XrTableCell23.Font = new Font("Arial", 8.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell23.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell23.Multiline = true;
|
||||||
|
this.XrTableCell23.Name = "XrTableCell23";
|
||||||
|
this.XrTableCell23.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell23.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell23.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell23.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell23.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell23.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell23.Weight = 0.11578820509129036D;
|
||||||
|
//
|
||||||
|
// XrTableCell24
|
||||||
|
//
|
||||||
|
this.XrTableCell24.BackColor = Color.White;
|
||||||
|
this.XrTableCell24.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell24.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell24.Dpi = 254F;
|
||||||
|
this.XrTableCell24.Font = new Font("Arial", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell24.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell24.Multiline = true;
|
||||||
|
this.XrTableCell24.Name = "XrTableCell24";
|
||||||
|
this.XrTableCell24.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell24.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell24.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell24.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell24.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell24.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell24.Weight = 0.2656113622128245D;
|
||||||
|
//
|
||||||
|
// XrTableCell25
|
||||||
|
//
|
||||||
|
this.XrTableCell25.BackColor = Color.White;
|
||||||
|
this.XrTableCell25.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell25.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell25.Dpi = 254F;
|
||||||
|
this.XrTableCell25.Font = new Font("Arial", 8.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell25.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell25.Multiline = true;
|
||||||
|
this.XrTableCell25.Name = "XrTableCell25";
|
||||||
|
this.XrTableCell25.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell25.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell25.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell25.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell25.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell25.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell25.Text = "Zertifizierung";
|
||||||
|
this.XrTableCell25.Weight = 0.11578821158083684D;
|
||||||
|
//
|
||||||
|
// XrTableCell26
|
||||||
|
//
|
||||||
|
this.XrTableCell26.BackColor = Color.White;
|
||||||
|
this.XrTableCell26.BorderColor = Color.Empty;
|
||||||
|
this.XrTableCell26.Borders = BorderSide.None;
|
||||||
|
this.XrTableCell26.Dpi = 254F;
|
||||||
|
this.XrTableCell26.ExpressionBindings.AddRange(new ExpressionBinding[] { new ExpressionBinding("BeforePrint", "Text", "[EnvelopeCertificationType]") });
|
||||||
|
this.XrTableCell26.Font = new Font("Arial", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||||
|
this.XrTableCell26.ForeColor = Color.Black;
|
||||||
|
this.XrTableCell26.Multiline = true;
|
||||||
|
this.XrTableCell26.Name = "XrTableCell26";
|
||||||
|
this.XrTableCell26.StyleName = "DetailCaption1";
|
||||||
|
this.XrTableCell26.StylePriority.UseBackColor = false;
|
||||||
|
this.XrTableCell26.StylePriority.UseBorderColor = false;
|
||||||
|
this.XrTableCell26.StylePriority.UseBorders = false;
|
||||||
|
this.XrTableCell26.StylePriority.UseFont = false;
|
||||||
|
this.XrTableCell26.StylePriority.UseForeColor = false;
|
||||||
|
this.XrTableCell26.Text = "XrTableCell26";
|
||||||
|
this.XrTableCell26.Weight = 0.38280260446913161D;
|
||||||
|
//
|
||||||
|
// GroupHeader1
|
||||||
|
//
|
||||||
|
this.GroupHeader1.Controls.AddRange(new XRControl[] { this.table1 });
|
||||||
|
this.GroupHeader1.Dpi = 254F;
|
||||||
|
this.GroupHeader1.GroupUnion = GroupUnion.WithFirstDetail;
|
||||||
|
this.GroupHeader1.HeightF = 71.12F;
|
||||||
|
this.GroupHeader1.Name = "GroupHeader1";
|
||||||
|
//
|
||||||
|
// table1
|
||||||
|
//
|
||||||
|
this.table1.Dpi = 254F;
|
||||||
|
this.table1.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F);
|
||||||
|
this.table1.Name = "table1";
|
||||||
|
this.table1.Rows.AddRange(new XRTableRow[] { this.tableRow1 });
|
||||||
|
this.table1.SizeF = new SizeF(1900F, 71.12F);
|
||||||
|
//
|
||||||
|
// tableRow1
|
||||||
|
//
|
||||||
|
this.tableRow1.Cells.AddRange(new XRTableCell[] { this.tableCell1, this.tableCell2, this.tableCell3 });
|
||||||
|
this.tableRow1.Dpi = 254F;
|
||||||
|
this.tableRow1.Name = "tableRow1";
|
||||||
|
this.tableRow1.Weight = 1D;
|
||||||
|
//
|
||||||
|
// tableCell1
|
||||||
|
//
|
||||||
|
this.tableCell1.BackColor = Color.FromArgb(224, 224, 224);
|
||||||
|
this.tableCell1.BorderColor = Color.FromArgb(165, 36, 49);
|
||||||
|
this.tableCell1.Borders = BorderSide.Bottom;
|
||||||
|
this.tableCell1.BorderWidth = 1F;
|
||||||
|
this.tableCell1.Dpi = 254F;
|
||||||
|
this.tableCell1.ForeColor = Color.Black;
|
||||||
|
this.tableCell1.Name = "tableCell1";
|
||||||
|
this.tableCell1.StyleName = "DetailCaption1";
|
||||||
|
this.tableCell1.StylePriority.UseBackColor = false;
|
||||||
|
this.tableCell1.StylePriority.UseBorderColor = false;
|
||||||
|
this.tableCell1.StylePriority.UseBorders = false;
|
||||||
|
this.tableCell1.StylePriority.UseBorderWidth = false;
|
||||||
|
this.tableCell1.StylePriority.UseForeColor = false;
|
||||||
|
this.tableCell1.Text = "Ereignis";
|
||||||
|
this.tableCell1.Weight = 0.51726482588176181D;
|
||||||
|
//
|
||||||
|
// tableCell2
|
||||||
|
//
|
||||||
|
this.tableCell2.BackColor = Color.FromArgb(224, 224, 224);
|
||||||
|
this.tableCell2.BorderColor = Color.FromArgb(165, 36, 49);
|
||||||
|
this.tableCell2.Borders = BorderSide.Bottom;
|
||||||
|
this.tableCell2.BorderWidth = 1F;
|
||||||
|
this.tableCell2.Dpi = 254F;
|
||||||
|
this.tableCell2.ForeColor = Color.Black;
|
||||||
|
this.tableCell2.Name = "tableCell2";
|
||||||
|
this.tableCell2.StyleName = "DetailCaption1";
|
||||||
|
this.tableCell2.StylePriority.UseBackColor = false;
|
||||||
|
this.tableCell2.StylePriority.UseBorderColor = false;
|
||||||
|
this.tableCell2.StylePriority.UseBorders = false;
|
||||||
|
this.tableCell2.StylePriority.UseBorderWidth = false;
|
||||||
|
this.tableCell2.StylePriority.UseForeColor = false;
|
||||||
|
this.tableCell2.Text = "Benutzer";
|
||||||
|
this.tableCell2.Weight = 0.45140669898958585D;
|
||||||
|
//
|
||||||
|
// tableCell3
|
||||||
|
//
|
||||||
|
this.tableCell3.BackColor = Color.FromArgb(224, 224, 224);
|
||||||
|
this.tableCell3.BorderColor = Color.FromArgb(165, 36, 49);
|
||||||
|
this.tableCell3.Borders = BorderSide.Bottom;
|
||||||
|
this.tableCell3.BorderWidth = 1F;
|
||||||
|
this.tableCell3.Dpi = 254F;
|
||||||
|
this.tableCell3.ForeColor = Color.Black;
|
||||||
|
this.tableCell3.Name = "tableCell3";
|
||||||
|
this.tableCell3.StyleName = "DetailCaption1";
|
||||||
|
this.tableCell3.StylePriority.UseBackColor = false;
|
||||||
|
this.tableCell3.StylePriority.UseBorderColor = false;
|
||||||
|
this.tableCell3.StylePriority.UseBorders = false;
|
||||||
|
this.tableCell3.StylePriority.UseBorderWidth = false;
|
||||||
|
this.tableCell3.StylePriority.UseForeColor = false;
|
||||||
|
this.tableCell3.Text = "Zeitstempel";
|
||||||
|
this.tableCell3.Weight = 0.22479583469004233D;
|
||||||
|
//
|
||||||
|
// Detail
|
||||||
|
//
|
||||||
|
this.Detail.Controls.AddRange(new XRControl[] { this.table2 });
|
||||||
|
this.Detail.Dpi = 254F;
|
||||||
|
this.Detail.HeightF = 86.174F;
|
||||||
|
this.Detail.HierarchyPrintOptions.Indent = 50.8F;
|
||||||
|
this.Detail.Name = "Detail";
|
||||||
|
//
|
||||||
|
// table2
|
||||||
|
//
|
||||||
|
this.table2.Dpi = 254F;
|
||||||
|
this.table2.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F);
|
||||||
|
this.table2.Name = "table2";
|
||||||
|
this.table2.Rows.AddRange(new XRTableRow[] { this.tableRow2 });
|
||||||
|
this.table2.SizeF = new SizeF(1900F, 63.42F);
|
||||||
|
//
|
||||||
|
// tableRow2
|
||||||
|
//
|
||||||
|
this.tableRow2.Cells.AddRange(new XRTableCell[] { this.tableCell4, this.tableCell5, this.tableCell6 });
|
||||||
|
this.tableRow2.Dpi = 254F;
|
||||||
|
this.tableRow2.Name = "tableRow2";
|
||||||
|
this.tableRow2.Weight = 11.683999633789062D;
|
||||||
|
//
|
||||||
|
// tableCell4
|
||||||
|
//
|
||||||
|
this.tableCell4.Borders = BorderSide.None;
|
||||||
|
this.tableCell4.Dpi = 254F;
|
||||||
|
this.tableCell4.ExpressionBindings.AddRange(new ExpressionBinding[] { new ExpressionBinding("BeforePrint", "Text", "[ItemStatusTranslated]") });
|
||||||
|
this.tableCell4.Name = "tableCell4";
|
||||||
|
this.tableCell4.StyleName = "DetailData1";
|
||||||
|
this.tableCell4.StylePriority.UseBorders = false;
|
||||||
|
this.tableCell4.Weight = 0.51726482142156094D;
|
||||||
|
//
|
||||||
|
// tableCell5
|
||||||
|
//
|
||||||
|
this.tableCell5.Dpi = 254F;
|
||||||
|
this.tableCell5.ExpressionBindings.AddRange(new ExpressionBinding[] { new ExpressionBinding("BeforePrint", "Text", "[ItemUserReference]") });
|
||||||
|
this.tableCell5.Name = "tableCell5";
|
||||||
|
this.tableCell5.StyleName = "DetailData1";
|
||||||
|
this.tableCell5.Weight = 0.45140669932916544D;
|
||||||
|
//
|
||||||
|
// tableCell6
|
||||||
|
//
|
||||||
|
this.tableCell6.Dpi = 254F;
|
||||||
|
this.tableCell6.ExpressionBindings.AddRange(new ExpressionBinding[] { new ExpressionBinding("BeforePrint", "Text", "[ItemDate]") });
|
||||||
|
this.tableCell6.Name = "tableCell6";
|
||||||
|
this.tableCell6.StyleName = "DetailData1";
|
||||||
|
this.tableCell6.StylePriority.UseTextAlignment = false;
|
||||||
|
this.tableCell6.TextAlignment = TextAlignment.MiddleRight;
|
||||||
|
this.tableCell6.Weight = 0.22479581593269077D;
|
||||||
|
//
|
||||||
|
// Title
|
||||||
|
//
|
||||||
|
this.Title.BackColor = Color.Transparent;
|
||||||
|
this.Title.BorderColor = Color.Black;
|
||||||
|
this.Title.Borders = BorderSide.None;
|
||||||
|
this.Title.BorderWidth = 1F;
|
||||||
|
this.Title.Font = new Font("Arial", 14.25F);
|
||||||
|
this.Title.ForeColor = Color.FromArgb(75, 75, 75);
|
||||||
|
this.Title.Name = "Title";
|
||||||
|
this.Title.Padding = new PaddingInfo(15, 15, 0, 0, 254F);
|
||||||
|
//
|
||||||
|
// DetailCaption1
|
||||||
|
//
|
||||||
|
this.DetailCaption1.BackColor = Color.FromArgb(75, 75, 75);
|
||||||
|
this.DetailCaption1.BorderColor = Color.White;
|
||||||
|
this.DetailCaption1.Borders = BorderSide.Left;
|
||||||
|
this.DetailCaption1.BorderWidth = 2F;
|
||||||
|
this.DetailCaption1.Font = new Font("Arial", 8.25F, FontStyle.Bold);
|
||||||
|
this.DetailCaption1.ForeColor = Color.White;
|
||||||
|
this.DetailCaption1.Name = "DetailCaption1";
|
||||||
|
this.DetailCaption1.Padding = new PaddingInfo(15, 15, 0, 0, 254F);
|
||||||
|
this.DetailCaption1.TextAlignment = TextAlignment.MiddleLeft;
|
||||||
|
//
|
||||||
|
// DetailData1
|
||||||
|
//
|
||||||
|
this.DetailData1.BorderColor = Color.Transparent;
|
||||||
|
this.DetailData1.Borders = BorderSide.Left;
|
||||||
|
this.DetailData1.BorderWidth = 2F;
|
||||||
|
this.DetailData1.Font = new Font("Arial", 8.25F);
|
||||||
|
this.DetailData1.ForeColor = Color.Black;
|
||||||
|
this.DetailData1.Name = "DetailData1";
|
||||||
|
this.DetailData1.Padding = new PaddingInfo(15, 15, 0, 0, 254F);
|
||||||
|
this.DetailData1.TextAlignment = TextAlignment.MiddleLeft;
|
||||||
|
//
|
||||||
|
// DetailData3_Odd
|
||||||
|
//
|
||||||
|
this.DetailData3_Odd.BackColor = Color.FromArgb(231, 231, 231);
|
||||||
|
this.DetailData3_Odd.BorderColor = Color.Transparent;
|
||||||
|
this.DetailData3_Odd.Borders = BorderSide.None;
|
||||||
|
this.DetailData3_Odd.BorderWidth = 1F;
|
||||||
|
this.DetailData3_Odd.Font = new Font("Arial", 8.25F);
|
||||||
|
this.DetailData3_Odd.ForeColor = Color.Black;
|
||||||
|
this.DetailData3_Odd.Name = "DetailData3_Odd";
|
||||||
|
this.DetailData3_Odd.Padding = new PaddingInfo(15, 15, 0, 0, 254F);
|
||||||
|
this.DetailData3_Odd.TextAlignment = TextAlignment.MiddleLeft;
|
||||||
|
//
|
||||||
|
// PageInfo
|
||||||
|
//
|
||||||
|
this.PageInfo.Font = new Font("Arial", 8.25F, FontStyle.Bold);
|
||||||
|
this.PageInfo.ForeColor = Color.FromArgb(75, 75, 75);
|
||||||
|
this.PageInfo.Name = "PageInfo";
|
||||||
|
this.PageInfo.Padding = new PaddingInfo(15, 15, 0, 0, 254F);
|
||||||
|
//
|
||||||
|
// ObjectDataSource1
|
||||||
|
//
|
||||||
|
this.ObjectDataSource1.DataMember = "Items";
|
||||||
|
this.ObjectDataSource1.Name = "ObjectDataSource1";
|
||||||
|
//
|
||||||
|
// rptEnvelopeHistory
|
||||||
|
//
|
||||||
|
this.Bands.AddRange(new Band[] { this.TopMargin, this.BottomMargin, this.ReportHeader, this.GroupHeader1, this.Detail });
|
||||||
|
this.ComponentStorage.AddRange(new IComponent[] { this.ObjectDataSource1 });
|
||||||
|
this.DataSource = this.ObjectDataSource1;
|
||||||
|
this.Dpi = 254F;
|
||||||
|
this.Font = new Font("Arial", 9.75F);
|
||||||
|
this.Margins = new Margins(100, 100, 191, 100);
|
||||||
|
this.PageHeight = 2970;
|
||||||
|
this.PageWidth = 2100;
|
||||||
|
this.PaperKind = (DevExpress.Drawing.Printing.DXPaperKind)System.Drawing.Printing.PaperKind.A4;
|
||||||
|
this.ReportUnit = ReportUnit.TenthsOfAMillimeter;
|
||||||
|
this.SnapGridSize = 25F;
|
||||||
|
this.StyleSheet.AddRange(new XRControlStyle[] { this.Title, this.DetailCaption1, this.DetailData1, this.DetailData3_Odd, this.PageInfo });
|
||||||
|
this.Version = "24.2";
|
||||||
|
this.Watermark.ImageSource = new DevExpress.XtraPrinting.Drawing.ImageSource("img", resources.GetString("rptEnvelopeHistory.Watermark.ImageSource"));
|
||||||
|
this.Watermark.ImageTransparency = 220;
|
||||||
|
((ISupportInitialize)this.XrTable3).EndInit();
|
||||||
|
((ISupportInitialize)this.table1).EndInit();
|
||||||
|
((ISupportInitialize)this.table2).EndInit();
|
||||||
|
((ISupportInitialize)this.ObjectDataSource1).EndInit();
|
||||||
|
((ISupportInitialize)this).EndInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private TopMarginBand TopMargin;
|
||||||
|
private BottomMarginBand BottomMargin;
|
||||||
|
private XRPageInfo pageInfo1;
|
||||||
|
private XRPageInfo pageInfo2;
|
||||||
|
private ReportHeaderBand ReportHeader;
|
||||||
|
private XRLabel label1;
|
||||||
|
private GroupHeaderBand GroupHeader1;
|
||||||
|
private XRTable table1;
|
||||||
|
private XRTableRow tableRow1;
|
||||||
|
private XRTableCell tableCell1;
|
||||||
|
private XRTableCell tableCell2;
|
||||||
|
private XRTableCell tableCell3;
|
||||||
|
private DetailBand Detail;
|
||||||
|
private XRTable table2;
|
||||||
|
private XRTableRow tableRow2;
|
||||||
|
private XRTableCell tableCell4;
|
||||||
|
private XRTableCell tableCell5;
|
||||||
|
private XRTableCell tableCell6;
|
||||||
|
private ObjectDataSource ObjectDataSource1;
|
||||||
|
private XRControlStyle Title;
|
||||||
|
private XRControlStyle DetailCaption1;
|
||||||
|
private XRControlStyle DetailData1;
|
||||||
|
private XRControlStyle DetailData3_Odd;
|
||||||
|
private XRControlStyle PageInfo;
|
||||||
|
private XRLabel XrLabel1;
|
||||||
|
private XRTable XrTable3;
|
||||||
|
private XRTableRow XrTableRow8;
|
||||||
|
private XRTableCell XrTableCell13;
|
||||||
|
private XRTableCell XrTableCell15;
|
||||||
|
private XRTableRow XrTableRow9;
|
||||||
|
private XRTableCell XrTableCell14;
|
||||||
|
private XRTableCell XrTableCell17;
|
||||||
|
private XRTableCell XrTableCell16;
|
||||||
|
private XRTableCell XrTableCell18;
|
||||||
|
private XRTableRow XrTableRow10;
|
||||||
|
private XRTableCell XrTableCell19;
|
||||||
|
private XRTableCell XrTableCell20;
|
||||||
|
private XRTableCell XrTableCell21;
|
||||||
|
private XRTableCell XrTableCell22;
|
||||||
|
private XRTableRow XrTableRow11;
|
||||||
|
private XRTableCell XrTableCell23;
|
||||||
|
private XRTableCell XrTableCell24;
|
||||||
|
private XRTableCell XrTableCell25;
|
||||||
|
private XRTableCell XrTableCell26;
|
||||||
|
}
|
||||||
@@ -1,103 +1,9 @@
|
|||||||
using DevExpress.XtraReports.UI;
|
namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
||||||
using DevExpress.Drawing;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
public partial class rptEnvelopeHistory
|
||||||
|
|
||||||
public class rptEnvelopeHistory : XtraReport
|
|
||||||
{
|
{
|
||||||
public rptEnvelopeHistory()
|
public rptEnvelopeHistory()
|
||||||
{
|
{
|
||||||
BuildLayout();
|
InitializeComponent();
|
||||||
}
|
|
||||||
|
|
||||||
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 string? DataMember { get; set; }
|
|
||||||
|
|
||||||
public void CreateDocument()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ExportToPdf(Stream stream)
|
|
||||||
{
|
|
||||||
stream.Write(Array.Empty<byte>(), 0, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,4 @@
|
|||||||
using DigitalData.Core.Abstraction.Application.Repository;
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
using DigitalData.Modules.Database;
|
|
||||||
using EnvelopeGenerator.Application.Common.Dto;
|
using EnvelopeGenerator.Application.Common.Dto;
|
||||||
using EnvelopeGenerator.Application.Configuration.Queries;
|
using EnvelopeGenerator.Application.Configuration.Queries;
|
||||||
using EnvelopeGenerator.Application.Envelopes.Queries;
|
using EnvelopeGenerator.Application.Envelopes.Queries;
|
||||||
@@ -8,10 +7,8 @@ using EnvelopeGenerator.Domain.Entities;
|
|||||||
using EnvelopeGenerator.ServiceHost.Exceptions;
|
using EnvelopeGenerator.ServiceHost.Exceptions;
|
||||||
using EnvelopeGenerator.ServiceHost.Extensions;
|
using EnvelopeGenerator.ServiceHost.Extensions;
|
||||||
using EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
using EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
||||||
using GdPicture.Internal.MSOfficeBinary.translator.Spreadsheet.XlsFileFormat.Records;
|
|
||||||
using GdPicture14;
|
using GdPicture14;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Data.SqlClient;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
@@ -39,24 +36,13 @@ public class FinalizeDocumentJob(IOptions<WorkerOptions> options, ILogger<Finali
|
|||||||
|
|
||||||
public bool RethrowOnError { get; set; } = true;
|
public bool RethrowOnError { get; set; } = true;
|
||||||
|
|
||||||
public async Task ExecuteAsync(CancellationToken cancel = default)
|
public async Task ExecuteAsync(IEnumerable<EnvelopeDto> envelopes, CancellationToken cancel = default)
|
||||||
{
|
{
|
||||||
var gdPictureKey = _options.GdPictureLicenseKey;
|
|
||||||
tempFiles.Create();
|
tempFiles.Create();
|
||||||
var jobId = typeof(FinalizeDocumentJob).FullName;
|
var jobId = typeof(FinalizeDocumentJob).FullName;
|
||||||
|
|
||||||
_config = await mediator.Send(new ReadDefaultConfigQuery(), cancel);
|
_config = await mediator.Send(new ReadDefaultConfigQuery(), cancel);
|
||||||
|
|
||||||
var envelopes = await envRepo
|
|
||||||
.Where(e => e.Status == EnvelopeStatus.EnvelopeCompletelySigned
|
|
||||||
&& e.ChangedWhen.HasValue
|
|
||||||
&& EF.Functions.DateDiffMinute(e.ChangedWhen.Value, DateTime.Now) >= CompleteWaitTime)
|
|
||||||
.OrderBy(e => e.Id)
|
|
||||||
.ToListAsync(cancel);
|
|
||||||
|
|
||||||
if (envelopes.Count > 0)
|
|
||||||
logger.LogInformation("Found [{count}] completed envelopes.", envelopes.Count);
|
|
||||||
|
|
||||||
foreach (var envelope in envelopes)
|
foreach (var envelope in envelopes)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -65,25 +51,36 @@ public class FinalizeDocumentJob(IOptions<WorkerOptions> options, ILogger<Finali
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex, "Unhandled exception while working envelope [{id}]", envelope.Id);
|
logger.LogWarning(ex, "An unexpected exception was ignored while processing the envelope with ID [{id}].", envelope.Id);
|
||||||
|
|
||||||
if(RethrowOnError)
|
if(RethrowOnError)
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.LogInformation("Envelope [{id}] finalized!", envelope.Id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Finalize(Envelope envelope, CancellationToken cancel)
|
public Task ExecuteAsync(EnvelopeDto envelope, CancellationToken cancel = default) => ExecuteAsync([envelope], cancel);
|
||||||
|
|
||||||
|
public async Task ExecuteAsync(CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
var envelopes = await mediator.Send(new ReadEnvelopeQuery()
|
||||||
|
{
|
||||||
|
Status = new () { Include = [EnvelopeStatus.EnvelopeCompletelySigned] },
|
||||||
|
MinMinutesSinceLastChange = CompleteWaitTime,
|
||||||
|
}, cancel);
|
||||||
|
|
||||||
|
await ExecuteAsync(envelopes, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Finalize(EnvelopeDto envelope, CancellationToken cancel)
|
||||||
{
|
{
|
||||||
var annotations = await docStatusRepo.Where(s => s.EnvelopeId == envelope.Id).Select(s => s.Value).ToListAsync(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)
|
var burnedDocument = pdfBurner!.BurnAnnotsToPDF(envelope.Documents?.FirstOrDefault()?.ByteData!, annotations, envelope.Id)
|
||||||
?? throw new ApplicationException("Document could not be finalized");
|
?? throw new ApplicationException("Document could not be finalized");
|
||||||
|
|
||||||
actionService.CreateReport(envelope, cancel);
|
actionService.CreateReport(envelope, cancel);
|
||||||
|
|
||||||
var report = reportCreator!.CreateReport(envelope);
|
var report = await reportCreator!.CreateReportAsync(envelope, cancel);
|
||||||
|
|
||||||
var mergedDocument = pdfMerger!.MergeDocuments(burnedDocument, report);
|
var mergedDocument = pdfMerger!.MergeDocuments(burnedDocument, report);
|
||||||
|
|
||||||
@@ -108,10 +105,10 @@ public class FinalizeDocumentJob(IOptions<WorkerOptions> options, ILogger<Finali
|
|||||||
|
|
||||||
SendFinalEmails(envelope);
|
SendFinalEmails(envelope);
|
||||||
|
|
||||||
actionService?.FinalizeEnvelope(envelope, cancel);
|
actionService.FinalizeEnvelope(envelope, cancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SendFinalEmails(Envelope envelope)
|
private bool SendFinalEmails(EnvelopeDto envelope)
|
||||||
{
|
{
|
||||||
var mailToCreator = (FinalEmailType)(envelope.FinalEmailToCreator ?? 0);
|
var mailToCreator = (FinalEmailType)(envelope.FinalEmailToCreator ?? 0);
|
||||||
var mailToReceivers = (FinalEmailType)(envelope.FinalEmailToReceivers ?? 0);
|
var mailToReceivers = (FinalEmailType)(envelope.FinalEmailToReceivers ?? 0);
|
||||||
@@ -133,9 +130,9 @@ public class FinalizeDocumentJob(IOptions<WorkerOptions> options, ILogger<Finali
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SendFinalEmailToCreator(Envelope envelope, FinalEmailType mailToCreator)
|
private bool SendFinalEmailToCreator(EnvelopeDto envelope, FinalEmailType mailToCreator)
|
||||||
{
|
{
|
||||||
if (actionService?.CompleteEnvelope(envelope) == false)
|
if (actionService.CompleteEnvelope(envelope) == false)
|
||||||
{
|
{
|
||||||
logger?.LogError(new Exception("CompleteEnvelope failed"), "Envelope could not be completed for receiver [{email}]", envelope.User?.Email);
|
logger?.LogError(new Exception("CompleteEnvelope failed"), "Envelope could not be completed for receiver [{email}]", envelope.User?.Email);
|
||||||
return false;
|
return false;
|
||||||
@@ -144,15 +141,12 @@ public class FinalizeDocumentJob(IOptions<WorkerOptions> options, ILogger<Finali
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SendFinalEmailToReceivers(Envelope envelope, FinalEmailType mailToReceivers)
|
private bool SendFinalEmailToReceivers(EnvelopeDto envelope, FinalEmailType mailToReceivers)
|
||||||
{
|
{
|
||||||
foreach (var receiver in envelope.EnvelopeReceivers ?? Enumerable.Empty<EnvelopeReceiver>())
|
foreach (var receiver in envelope.EnvelopeReceivers ?? [])
|
||||||
{
|
{
|
||||||
if (actionService?.CompleteEnvelope(envelope, receiver.Receiver) == false)
|
if (!actionService.CompleteEnvelope(envelope, receiver.Receiver!))
|
||||||
{
|
|
||||||
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;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
using Microsoft.Data.SqlClient;
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
namespace DigitalData.Modules.Database;
|
namespace EnvelopeGenerator.ServiceHost.Jobs.Infrastructure;
|
||||||
|
|
||||||
public class MSSQLServer(IConfiguration configuration)
|
public class MSSQLServer(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
|
|||||||
19
EnvelopeGenerator.ServiceHost/Jobs/JobStateManager.cs
Normal file
19
EnvelopeGenerator.ServiceHost/Jobs/JobStateManager.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using AngleSharp.Common;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.ServiceHost.Jobs;
|
||||||
|
|
||||||
|
public class JobStateManager(Dictionary<string, State>? initialState = null)
|
||||||
|
{
|
||||||
|
private readonly ConcurrentDictionary<Type, State> _states = new();
|
||||||
|
|
||||||
|
public State GetState<TJob>() => _states.GetOrAdd(typeof(TJob), type => initialState?.GetOrDefault(type.Name, State.Stopped) ?? State.Stopped);
|
||||||
|
|
||||||
|
public State SetState<TJob>(State state) => _states[typeof(TJob)] = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum State
|
||||||
|
{
|
||||||
|
Running,
|
||||||
|
Stopped
|
||||||
|
}
|
||||||
39
EnvelopeGenerator.ServiceHost/Jobs/LicenseManagerFactory.cs
Normal file
39
EnvelopeGenerator.ServiceHost/Jobs/LicenseManagerFactory.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using EnvelopeGenerator.Application.ThirdPartyModules.Queries;
|
||||||
|
using GdPicture14;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.ServiceHost.Jobs;
|
||||||
|
|
||||||
|
public class LicenseManagerFactory
|
||||||
|
{
|
||||||
|
private static readonly string _cacheKey = Guid.NewGuid().ToString();
|
||||||
|
private readonly IServiceScopeFactory scopeFactory;
|
||||||
|
private readonly IMemoryCache cache;
|
||||||
|
|
||||||
|
public LicenseManagerFactory(IServiceScopeFactory scopeFactory, IMemoryCache cache)
|
||||||
|
{
|
||||||
|
this.scopeFactory = scopeFactory;
|
||||||
|
this.cache = cache;
|
||||||
|
_ = CreateAsync(); // Preload the license key into the cache
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<LicenseManager> CreateAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var key = await GetLicenseKeyAsync(cancellationToken);
|
||||||
|
var licenseManager = new LicenseManager();
|
||||||
|
licenseManager.RegisterKEY(key);
|
||||||
|
return licenseManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetLicenseKeyAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await cache.GetOrCreateAsync(_cacheKey, async entry =>
|
||||||
|
{
|
||||||
|
entry.Priority = CacheItemPriority.NeverRemove;
|
||||||
|
using var scope = scopeFactory.CreateScope();
|
||||||
|
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
|
||||||
|
return await mediator.Send(new ReadThirdPartyModuleLicenseQuery { Name = "GdPicture", Active =true }, cancellationToken);
|
||||||
|
}) ?? throw new InvalidOperationException("License key could not be retrieved.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using DigitalData.Modules.Database;
|
|
||||||
using System.Data;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.ServiceHost.Jobs;
|
|
||||||
|
|
||||||
[Obsolete("Create and use EnvelopeReport mediator queries")]
|
|
||||||
public class ReportModel(MSSQLServer Database)
|
|
||||||
{
|
|
||||||
[Obsolete("Create and use EnvelopeReport mediator queries")]
|
|
||||||
public DataTable List(int envelopeId)
|
|
||||||
{
|
|
||||||
var sql = $"SELECT * FROM VWSIG_ENVELOPE_REPORT WHERE ENVELOPE_ID = {envelopeId}";
|
|
||||||
return Database.GetDatatable(sql);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,22 @@
|
|||||||
using EnvelopeGenerator.ServiceHost.Jobs.FinalizeDocument;
|
|
||||||
using System.Drawing;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.ServiceHost.Jobs;
|
namespace EnvelopeGenerator.ServiceHost.Jobs;
|
||||||
|
|
||||||
public class WorkerOptions
|
public class WorkerOptions
|
||||||
{
|
{
|
||||||
public string GdPictureLicenseKey { get; set; } = null!;
|
private int _delayMilliseconds = 1000;
|
||||||
|
|
||||||
[Obsolete("Use ILogger.")]
|
public int DelayMilliseconds
|
||||||
public bool Debug { get; set; }
|
{
|
||||||
|
get => _delayMilliseconds;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < 1)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(value), "Delay must be at least 1 millisecond.");
|
||||||
|
|
||||||
|
_delayMilliseconds = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<string, State> InitialJobState { get; set; } = [];
|
||||||
|
|
||||||
public PDFBurnerOptions PdfBurner { get; set; } = new();
|
public PDFBurnerOptions PdfBurner { get; set; } = new();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
namespace EnvelopeGenerator.ServiceHost.Middleware;
|
||||||
|
|
||||||
|
using DigitalData.Core.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Middleware for handling exceptions globally in the application.
|
||||||
|
/// Captures exceptions thrown during the request pipeline execution,
|
||||||
|
/// logs them, and returns an appropriate HTTP response with a JSON error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="ExceptionHandlingMiddleware"/> class.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="next">The next middleware in the request pipeline.</param>
|
||||||
|
/// <param name="logger">The logger instance for logging exceptions.</param>
|
||||||
|
public class ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the middleware to handle the HTTP request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The HTTP context of the current request.</param>
|
||||||
|
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||||
|
public async Task InvokeAsync(HttpContext context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await next(context); // Continue down the pipeline
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await HandleExceptionAsync(context, ex, logger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles exceptions by logging them and writing an appropriate JSON response.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The HTTP context of the current request.</param>
|
||||||
|
/// <param name="exception">The exception that occurred.</param>
|
||||||
|
/// <param name="logger">The logger instance for logging the exception.</param>
|
||||||
|
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||||
|
private static async Task HandleExceptionAsync(HttpContext context, Exception exception, ILogger logger)
|
||||||
|
{
|
||||||
|
context.Response.ContentType = "application/json";
|
||||||
|
|
||||||
|
string message;
|
||||||
|
|
||||||
|
switch (exception)
|
||||||
|
{
|
||||||
|
case BadRequestException badRequestEx:
|
||||||
|
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||||
|
message = badRequestEx.Message;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotFoundException notFoundEx:
|
||||||
|
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||||
|
message = notFoundEx.Message;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger.LogError(exception, "Unhandled exception occurred.");
|
||||||
|
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||||
|
message = "An unexpected error occurred.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await context.Response.WriteAsync(JsonSerializer.Serialize(new
|
||||||
|
{
|
||||||
|
message
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,73 @@
|
|||||||
|
using DigitalData.UserManager.DependencyInjection;
|
||||||
|
using EnvelopeGenerator.Application;
|
||||||
|
using EnvelopeGenerator.Infrastructure;
|
||||||
using EnvelopeGenerator.ServiceHost;
|
using EnvelopeGenerator.ServiceHost;
|
||||||
using EnvelopeGenerator.ServiceHost.Extensions;
|
using EnvelopeGenerator.ServiceHost.Extensions;
|
||||||
|
using EnvelopeGenerator.ServiceHost.Middleware;
|
||||||
|
using Microsoft.AspNetCore.Localization;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add services to the container.
|
#region Kestrel & Windows Service Configuration
|
||||||
|
if (builder.Configuration.GetValue<bool>("UseWindowsService"))
|
||||||
|
{
|
||||||
|
builder.Host.UseWindowsService();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (builder.Configuration.GetValue<bool>("UseCustomKestrelEndpoints"))
|
||||||
|
{
|
||||||
|
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
|
||||||
|
{
|
||||||
|
var serverConfigSection = context.Configuration.GetSection("ServerConfig");
|
||||||
|
serverOptions.Configure(serverConfigSection);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
var config = builder.Configuration;
|
||||||
|
var connStr = config.GetConnectionString("Default") ??
|
||||||
|
throw new InvalidOperationException("Connection string 'Default' is missing in the configuration.");
|
||||||
|
|
||||||
|
#region Service configuration
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
builder.Services.AddFinalizeDocumentJob(builder.Configuration);
|
|
||||||
builder.Services.AddHostedService<Worker>();
|
builder.Services.AddHostedService<Worker>();
|
||||||
|
builder.Services.AddDistributedSqlServerCache(options =>
|
||||||
|
{
|
||||||
|
options.ConnectionString = connStr;
|
||||||
|
options.SchemaName = "dbo";
|
||||||
|
options.TableName = "TBDD_CACHE";
|
||||||
|
});
|
||||||
|
#pragma warning disable CS0618
|
||||||
|
builder.Services.AddFinalizeDocumentJob(config);
|
||||||
|
builder.Services.AddEnvelopeGeneratorInfrastructureServices(
|
||||||
|
opt =>
|
||||||
|
{
|
||||||
|
opt.AddDbTriggerParams(config);
|
||||||
|
opt.AddDbContext((provider, options) =>
|
||||||
|
{
|
||||||
|
var logger = provider.GetRequiredService<ILogger<EGDbContext>>();
|
||||||
|
options.UseSqlServer(connStr)
|
||||||
|
.LogTo(log => logger.LogInformation("{log}", log), Microsoft.Extensions.Logging.LogLevel.Trace)
|
||||||
|
.EnableSensitiveDataLogging()
|
||||||
|
.EnableDetailedErrors();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
builder.Services.AddEnvelopeGeneratorServices(config);
|
||||||
|
builder.Services.AddMemoryCache();
|
||||||
|
builder.Services.AddUserManager<EGDbContext>();
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
builder.Services.AddLocalization();
|
||||||
|
#endregion
|
||||||
|
|
||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
app.UseMiddleware<ExceptionHandlingMiddleware>();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
@@ -22,6 +75,18 @@ if (app.Environment.IsDevelopment())
|
|||||||
app.UseSwaggerUI();
|
app.UseSwaggerUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Localizer
|
||||||
|
var supportedCultureNames = config.GetSection("SupportedCultures").Get<string[]>() ?? ["de-DE", "en-US"];
|
||||||
|
var supportedCultures = supportedCultureNames.Select(cName => new CultureInfo(cName)).ToList();
|
||||||
|
var requestLocalizationOptions = new RequestLocalizationOptions
|
||||||
|
{
|
||||||
|
SupportedCultures = supportedCultures,
|
||||||
|
SupportedUICultures = supportedCultures
|
||||||
|
};
|
||||||
|
requestLocalizationOptions.RequestCultureProviders.Add(new QueryStringRequestCultureProvider());
|
||||||
|
app.UseRequestLocalization(requestLocalizationOptions);
|
||||||
|
#endregion
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
using EnvelopeGenerator.ServiceHost.Jobs;
|
using EnvelopeGenerator.ServiceHost.Jobs;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.ServiceHost;
|
namespace EnvelopeGenerator.ServiceHost;
|
||||||
|
|
||||||
public class Worker : BackgroundService
|
public class Worker : BackgroundService
|
||||||
{
|
{
|
||||||
private readonly ILogger<Worker> _logger;
|
private readonly ILogger<Worker> _logger;
|
||||||
private readonly int _delayMilliseconds;
|
private readonly WorkerOptions _options;
|
||||||
private readonly FinalizeDocumentJob _finalizeDocumentJob;
|
private readonly JobStateManager _jobStateManager;
|
||||||
|
private readonly IServiceScopeFactory _scopeFactory;
|
||||||
|
|
||||||
public Worker(ILogger<Worker> logger, IConfiguration configuration, FinalizeDocumentJob finalizeDocumentJob)
|
public Worker(ILogger<Worker> logger, IOptions<WorkerOptions> options, JobStateManager jobStateManager, IServiceScopeFactory scopeFactory)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_delayMilliseconds = Math.Max(1, configuration.GetValue("Worker:DelayMilliseconds", 1000));
|
_options = options.Value;
|
||||||
_finalizeDocumentJob = finalizeDocumentJob;
|
_jobStateManager = jobStateManager;
|
||||||
|
_scopeFactory = scopeFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
@@ -24,8 +27,14 @@ public class Worker : BackgroundService
|
|||||||
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
|
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _finalizeDocumentJob.ExecuteAsync(stoppingToken);
|
if (_jobStateManager.GetState<FinalizeDocumentJob>() == State.Running)
|
||||||
await Task.Delay(_delayMilliseconds, stoppingToken);
|
{
|
||||||
|
using var scope = _scopeFactory.CreateScope();
|
||||||
|
var finalizeDocumentJob = scope.ServiceProvider.GetRequiredService<FinalizeDocumentJob>();
|
||||||
|
await finalizeDocumentJob.ExecuteAsync(stoppingToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(_options.DelayMilliseconds, stoppingToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Information"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Worker": {
|
"Worker": {
|
||||||
"DelayMilliseconds": 1000
|
"DelayMilliseconds": 1000,
|
||||||
|
// InitialJobState: State values are 0 = Running, 1 = Stopped. Defaults to 1 (Stopped) if not specified.
|
||||||
|
"InitialJobState": {
|
||||||
|
"FinalizeDocumentJob": 0
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*",
|
||||||
|
"SupportedCultures": [ "de-DE", "en-US" ],
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
|
||||||
|
},
|
||||||
|
"UseWindowsService": false,
|
||||||
|
"UseCustomKestrelEndpoints": false,
|
||||||
|
"ServerConfig": {
|
||||||
|
"Endpoints": {
|
||||||
|
"Http": {
|
||||||
|
"Url": "http://localhost:1111"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -193,13 +193,17 @@ public static class Extensions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Envelope
|
#region Envelope
|
||||||
public static CreateEnvelopeCommand CreateEnvelopeCommand(this Faker fake, int userId) => new()
|
public static CreateEnvelopeCommand CreateEnvelopeCommand(this Faker fake, int userId)
|
||||||
{
|
{
|
||||||
Message = fake.Lorem.Paragraph(fake.Random.Number(2, 5)),
|
var cmd = new CreateEnvelopeCommand
|
||||||
Title = fake.Lorem.Words(fake.Random.Number(3, 4)).Join(" "),
|
{
|
||||||
UserId = userId,
|
Message = fake.Lorem.Paragraph(fake.Random.Number(2, 5)),
|
||||||
UseSQLExecutor = false
|
Title = fake.Lorem.Words(fake.Random.Number(3, 4)).Join(" "),
|
||||||
};
|
UseSQLExecutor = false
|
||||||
|
};
|
||||||
|
cmd.Authorize(userId);
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
public static List<CreateEnvelopeCommand> CreateEnvelopeCommands(this Faker fake, params int[] userIDs)
|
public static List<CreateEnvelopeCommand> CreateEnvelopeCommands(this Faker fake, params int[] userIDs)
|
||||||
=> Enumerable.Range(0, userIDs.Length)
|
=> Enumerable.Range(0, userIDs.Length)
|
||||||
|
|||||||
308
EnvelopeGenerator.Tests/Application/MediatorExtensionsTests.cs
Normal file
308
EnvelopeGenerator.Tests/Application/MediatorExtensionsTests.cs
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
using DigitalData.Core.Exceptions;
|
||||||
|
using EnvelopeGenerator.Application.Common.Extensions;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Tests.Application;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class MediatorExtensionsTests
|
||||||
|
{
|
||||||
|
#region Stub infrastructure
|
||||||
|
|
||||||
|
private sealed class StubRequest<TResponse> : IRequest<TResponse?> { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimal <see cref="ISender"/> stub that returns a pre-configured response for any <see cref="ISender.Send{TResponse}"/> call.
|
||||||
|
/// </summary>
|
||||||
|
private sealed class StubSender : ISender
|
||||||
|
{
|
||||||
|
private readonly object? _response;
|
||||||
|
|
||||||
|
public StubSender(object? response) => _response = response;
|
||||||
|
|
||||||
|
public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
return Task.FromResult((TResponse)_response!);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Send<TRequest>(TRequest request, CancellationToken cancellationToken = default) where TRequest : IRequest
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<object?> Send(object request, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
return Task.FromResult(_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAsyncEnumerable<TResponse> CreateStream<TResponse>(IStreamRequest<TResponse> request, CancellationToken cancellationToken = default)
|
||||||
|
=> throw new NotImplementedException();
|
||||||
|
|
||||||
|
public IAsyncEnumerable<object?> CreateStream(object request, CancellationToken cancellationToken = default)
|
||||||
|
=> throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ISender CreateSender<T>(T? response) => new StubSender(response);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Throw — non-null scalar
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Throw_WithNonNullResponse_ReturnsResponse()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<string>("hello");
|
||||||
|
var request = new StubRequest<string?>();
|
||||||
|
|
||||||
|
var result = await sender.GetOr(request).Throw(() => new InvalidOperationException());
|
||||||
|
|
||||||
|
Assert.That(result, Is.EqualTo("hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Throw — null response
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Throw_WithNullResponse_ThrowsCustomException()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<string>(null);
|
||||||
|
var request = new StubRequest<string?>();
|
||||||
|
|
||||||
|
var ex = Assert.ThrowsAsync<InvalidOperationException>(
|
||||||
|
() => sender.GetOr(request).Throw(() => new InvalidOperationException("custom")));
|
||||||
|
|
||||||
|
Assert.That(ex!.Message, Is.EqualTo("custom"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Throw — empty collection
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Throw_WithEmptyList_ThrowsCustomException()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<List<string>>(new List<string>());
|
||||||
|
var request = new StubRequest<List<string>?>();
|
||||||
|
|
||||||
|
Assert.ThrowsAsync<ArgumentException>(
|
||||||
|
() => sender.GetOr(request).Throw(() => new ArgumentException("empty")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Throw — non-empty collection
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Throw_WithNonEmptyList_ReturnsResponse()
|
||||||
|
{
|
||||||
|
var expected = new List<int> { 1, 2 };
|
||||||
|
var sender = CreateSender<List<int>>(expected);
|
||||||
|
var request = new StubRequest<List<int>?>();
|
||||||
|
|
||||||
|
var result = await sender.GetOr(request).Throw(() => new InvalidOperationException());
|
||||||
|
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Throw — string edge case (string implements IEnumerable)
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Throw_WithEmptyString_ReturnsEmptyString()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<string>("");
|
||||||
|
var request = new StubRequest<string?>();
|
||||||
|
|
||||||
|
var result = await sender.GetOr(request).Throw(() => new InvalidOperationException("should not throw"));
|
||||||
|
|
||||||
|
Assert.That(result, Is.EqualTo(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ThrowNotFound — non-null scalar
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ThrowNotFound_WithNonNullResponse_ReturnsResponse()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<string>("hello");
|
||||||
|
var request = new StubRequest<string?>();
|
||||||
|
|
||||||
|
var result = await sender.GetOr(request).ThrowNotFound();
|
||||||
|
|
||||||
|
Assert.That(result, Is.EqualTo("hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ThrowNotFound_WithExceptionMessage_AndNonNullResponse_ReturnsResponse()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<int>(42);
|
||||||
|
var request = new StubRequest<int?>();
|
||||||
|
|
||||||
|
var result = await sender.GetOr(request).ThrowNotFound("not found");
|
||||||
|
|
||||||
|
Assert.That(result, Is.EqualTo(42));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ThrowNotFound — null response
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ThrowNotFound_WithNullResponse_ThrowsNotFoundException()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<string>(null);
|
||||||
|
var request = new StubRequest<string?>();
|
||||||
|
|
||||||
|
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOr(request).ThrowNotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ThrowNotFound_WithNullResponse_AndCustomMessage_ContainsMessage()
|
||||||
|
{
|
||||||
|
const string message = "Entity not found";
|
||||||
|
var sender = CreateSender<string>(null);
|
||||||
|
var request = new StubRequest<string?>();
|
||||||
|
|
||||||
|
var ex = Assert.ThrowsAsync<NotFoundException>(
|
||||||
|
() => sender.GetOr(request).ThrowNotFound(message));
|
||||||
|
|
||||||
|
Assert.That(ex!.Message, Does.Contain(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ThrowNotFound_WithNullResponse_HasDefaultMessageWithTypeName()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<string>(null);
|
||||||
|
var request = new StubRequest<string?>();
|
||||||
|
|
||||||
|
var ex = Assert.ThrowsAsync<NotFoundException>(() => sender.GetOr(request).ThrowNotFound());
|
||||||
|
|
||||||
|
Assert.That(ex!.Message, Does.Contain(nameof(String)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ThrowNotFound — empty collection
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ThrowNotFound_WithEmptyList_ThrowsNotFoundException()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<List<string>>(new List<string>());
|
||||||
|
var request = new StubRequest<List<string>?>();
|
||||||
|
|
||||||
|
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOr(request).ThrowNotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ThrowNotFound_WithEmptyArray_ThrowsNotFoundException()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<int[]>(Array.Empty<int>());
|
||||||
|
var request = new StubRequest<int[]?>();
|
||||||
|
|
||||||
|
Assert.ThrowsAsync<NotFoundException>(() => sender.GetOr(request).ThrowNotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ThrowNotFound_WithEmptyCollection_AndCustomMessage_ContainsMessage()
|
||||||
|
{
|
||||||
|
const string message = "No items found";
|
||||||
|
var sender = CreateSender<List<int>>(new List<int>());
|
||||||
|
var request = new StubRequest<List<int>?>();
|
||||||
|
|
||||||
|
var ex = Assert.ThrowsAsync<NotFoundException>(
|
||||||
|
() => sender.GetOr(request).ThrowNotFound(message));
|
||||||
|
|
||||||
|
Assert.That(ex!.Message, Does.Contain(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ThrowNotFound — non-empty collection
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ThrowNotFound_WithNonEmptyList_ReturnsResponse()
|
||||||
|
{
|
||||||
|
var expected = new List<string> { "a", "b" };
|
||||||
|
var sender = CreateSender<List<string>>(expected);
|
||||||
|
var request = new StubRequest<List<string>?>();
|
||||||
|
|
||||||
|
var result = await sender.GetOr(request).ThrowNotFound();
|
||||||
|
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ThrowNotFound_WithNonEmptyArray_ReturnsResponse()
|
||||||
|
{
|
||||||
|
var expected = new[] { 1, 2, 3 };
|
||||||
|
var sender = CreateSender<int[]>(expected);
|
||||||
|
var request = new StubRequest<int[]?>();
|
||||||
|
|
||||||
|
var result = await sender.GetOr(request).ThrowNotFound();
|
||||||
|
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ThrowInvalidOperation — null response
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ThrowInvalidOperation_WithNullResponse_ThrowsInvalidOperationException()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<string>(null);
|
||||||
|
var request = new StubRequest<string?>();
|
||||||
|
|
||||||
|
Assert.ThrowsAsync<InvalidOperationException>(
|
||||||
|
() => sender.GetOr(request).ThrowInvalidOperation());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ThrowInvalidOperation_WithNullResponse_AndCustomMessage_ContainsMessage()
|
||||||
|
{
|
||||||
|
const string message = "Something went wrong";
|
||||||
|
var sender = CreateSender<string>(null);
|
||||||
|
var request = new StubRequest<string?>();
|
||||||
|
|
||||||
|
var ex = Assert.ThrowsAsync<InvalidOperationException>(
|
||||||
|
() => sender.GetOr(request).ThrowInvalidOperation(message));
|
||||||
|
|
||||||
|
Assert.That(ex!.Message, Does.Contain(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region CancellationToken
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Throw_WithCancelledToken_ThrowsOperationCanceledException()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<string>("value");
|
||||||
|
var request = new StubRequest<string?>();
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
cts.Cancel();
|
||||||
|
|
||||||
|
Assert.ThrowsAsync<OperationCanceledException>(
|
||||||
|
() => sender.GetOr(request, cts.Token).Throw(() => new InvalidOperationException()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ThrowNotFound_WithCancelledToken_ThrowsOperationCanceledException()
|
||||||
|
{
|
||||||
|
var sender = CreateSender<string>("value");
|
||||||
|
var request = new StubRequest<string?>();
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
cts.Cancel();
|
||||||
|
|
||||||
|
Assert.ThrowsAsync<OperationCanceledException>(
|
||||||
|
() => sender.GetOr(request, cts.Token).ThrowNotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user