Add WorkflowsClient for PDF validation and QR extraction

Introduced a new `WorkflowsClient` to orchestrate multi-step
operations, combining `IPdfValidationClient` and
`ISwissQrCodeClient`. Added methods to validate PDFs and extract
Swiss QR Codes in a single call, with overloads for byte arrays,
streams, and file paths. Registered `WorkflowsClient` as a scoped
service in `ServiceCollectionExtensions`.

Updated `PdfValidationResult` with an `IsValid` property to
simplify PDF validity checks. Added `IWorkflowsClient` interface
to define the contract for the new client, with detailed XML
documentation for its methods.
This commit is contained in:
2026-08-31 03:21:41 +02:00
parent d1fdbb494b
commit 0c27e4fd91
5 changed files with 152 additions and 1 deletions

View File

@@ -0,0 +1,59 @@
using DocumentService.Application.Common.DTOs;
namespace DocumentService.Client.Interfaces;
/// <summary>
/// Orchestrated multi-step workflows that combine multiple DocumentService operations into
/// a single, higher-level call. Prefer these over manually chaining individual clients.
/// </summary>
public interface IWorkflowsClient
{
/// <summary>
/// Validates the PDF and extracts its Swiss QR Code in a single call.
/// Validation runs first; extraction is only attempted on valid documents.
/// </summary>
/// <param name="pdfBytes">PDF file as byte array.</param>
/// <param name="raw">
/// <c>false</c> (default) – returns a parsed <see cref="SwissQrCodeExtractionResult.Bill"/> object.<br/>
/// <c>true</c> – returns raw QR text lines without parsing.
/// </param>
/// <param name="throwIfInvalid">
/// <c>true</c> (default) – throws <see cref="InvalidOperationException"/> when the PDF fails validation.<br/>
/// <c>false</c> – returns <c>null</c> instead, allowing the caller to handle the case without a try/catch.
/// </param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>
/// Swiss QR Code extraction result, or <c>null</c> if the document is invalid and
/// <paramref name="throwIfInvalid"/> is <c>false</c>.
/// </returns>
/// <exception cref="InvalidOperationException">
/// Thrown when the PDF fails validation and <paramref name="throwIfInvalid"/> is <c>true</c>.
/// </exception>
Task<SwissQrCodeExtractionResult?> ExtractSwissQrCodeValidatedAsync(
byte[] pdfBytes,
bool raw = false,
bool throwIfInvalid = true,
CancellationToken cancellationToken = default);
/// <inheritdoc cref="ExtractSwissQrCodeValidatedAsync(byte[], bool, bool, CancellationToken)"/>
/// <param name="pdfStream">PDF file as a stream.</param>
/// <param name="raw"><inheritdoc cref="ExtractSwissQrCodeValidatedAsync(byte[], bool, bool, CancellationToken)" path="/param[@name='raw']"/></param>
/// <param name="throwIfInvalid"><inheritdoc cref="ExtractSwissQrCodeValidatedAsync(byte[], bool, bool, CancellationToken)" path="/param[@name='throwIfInvalid']"/></param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<SwissQrCodeExtractionResult?> ExtractSwissQrCodeValidatedAsync(
Stream pdfStream,
bool raw = false,
bool throwIfInvalid = true,
CancellationToken cancellationToken = default);
/// <inheritdoc cref="ExtractSwissQrCodeValidatedAsync(byte[], bool, bool, CancellationToken)"/>
/// <param name="filePath">Absolute or relative path to the PDF file.</param>
/// <param name="raw"><inheritdoc cref="ExtractSwissQrCodeValidatedAsync(byte[], bool, bool, CancellationToken)" path="/param[@name='raw']"/></param>
/// <param name="throwIfInvalid"><inheritdoc cref="ExtractSwissQrCodeValidatedAsync(byte[], bool, bool, CancellationToken)" path="/param[@name='throwIfInvalid']"/></param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<SwissQrCodeExtractionResult?> ExtractSwissQrCodeValidatedAsync(
string filePath,
bool raw = false,
bool throwIfInvalid = true,
CancellationToken cancellationToken = default);
}