Add Swiss QR Code extraction endpoint
Added a new `/extract-swiss-qr-code` endpoint to extract and parse Swiss QR Codes from the last page of a PDF document. Implemented the `ExtractSwissQrCode` handler method, along with helper methods to map domain value objects (`SwissQrCodeData` and `AddressData`) to DTOs. Updated `ExceptionHandlingMiddleware` to handle the new `SwissQrCodeNotFoundException` with a 404 Not Found response. Added integration tests in `ExtractSwissQrCodeEndpointTests` to validate the endpoint's behavior for valid requests, invalid Base64 input, empty references, and empty PDFs. Introduced a helper method to load embedded PDF resources as Base64 strings for testing. Updated `using` directives to include necessary namespaces for the new feature and exception handling.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using DocumentOperator.Application.Common.DTOs;
|
||||
using DocumentOperator.Application.Features.Documents.ExtractSwissQrCode;
|
||||
using DocumentOperator.Application.Features.Documents.ValidatePdf;
|
||||
using DocumentOperator.Domain.Models.ValueObjects;
|
||||
using MediatR;
|
||||
@@ -27,6 +28,16 @@ public static class DocumentEndpoints
|
||||
.Produces<ValidatePdfResponse>(StatusCodes.Status200OK)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status400BadRequest)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status500InternalServerError);
|
||||
|
||||
// POST /api/v1/documents/extract-swiss-qr-code
|
||||
group.MapPost("/extract-swiss-qr-code", ExtractSwissQrCode)
|
||||
.WithName("ExtractSwissQrCode")
|
||||
.WithSummary("Extracts Swiss QR Code from the last page of a PDF document")
|
||||
.WithDescription("Extracts and parses a Swiss QR Code (Swiss QR Bill Standard 2.0) from the last page of a PDF. Returns references (passed through) and all QR code fields.")
|
||||
.Produces<ExtractSwissQrCodeResponse>(StatusCodes.Status200OK)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status400BadRequest)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status404NotFound)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -64,4 +75,79 @@ public static class DocumentEndpoints
|
||||
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts Swiss QR Code from the last page of a PDF document
|
||||
/// </summary>
|
||||
/// <param name="request">References array + PDF as Base64 string</param>
|
||||
/// <param name="mediator">MediatR instance</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>References (passed through) + Swiss QR Code data</returns>
|
||||
/// <response code="200">Swiss QR Code extracted successfully</response>
|
||||
/// <response code="400">Invalid PDF or Base64 format</response>
|
||||
/// <response code="404">No Swiss QR Code found on the last page</response>
|
||||
/// <response code="500">Internal server error during extraction</response>
|
||||
private static async Task<IResult> ExtractSwissQrCode(
|
||||
ExtractSwissQrCodeRequest request,
|
||||
IMediator mediator,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// DTO → Query (Value Objects erstellen)
|
||||
var query = new ExtractSwissQrCodeQuery(
|
||||
References: request.References,
|
||||
PdfContent: Base64String.Create(request.Base64Pdf)
|
||||
);
|
||||
|
||||
// MediatR Handler aufrufen
|
||||
var result = await mediator.Send(query, cancellationToken);
|
||||
|
||||
// Map Domain Value Object → DTO
|
||||
var response = new ExtractSwissQrCodeResponse(
|
||||
References: result.References,
|
||||
QrCodeData: MapQrCodeDataToDto(result.QrCodeData)
|
||||
);
|
||||
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps SwissQrCodeData domain value object to DTO
|
||||
/// </summary>
|
||||
private static SwissQrCodeDataDto MapQrCodeDataToDto(Domain.ValueObjects.SwissQrCodeData qrCodeData)
|
||||
{
|
||||
return new SwissQrCodeDataDto(
|
||||
QrType: qrCodeData.QrType,
|
||||
Version: qrCodeData.Version,
|
||||
CodingType: qrCodeData.CodingType,
|
||||
Iban: qrCodeData.Iban,
|
||||
Creditor: MapAddressToDto(qrCodeData.Creditor),
|
||||
UltimateCreditor: qrCodeData.UltimateCreditor != null ? MapAddressToDto(qrCodeData.UltimateCreditor) : null,
|
||||
Amount: qrCodeData.Amount,
|
||||
Currency: qrCodeData.Currency,
|
||||
UltimateDebtor: qrCodeData.UltimateDebtor != null ? MapAddressToDto(qrCodeData.UltimateDebtor) : null,
|
||||
ReferenceType: qrCodeData.ReferenceType,
|
||||
Reference: qrCodeData.Reference,
|
||||
UnstructuredMessage: qrCodeData.UnstructuredMessage,
|
||||
BillInformation: qrCodeData.BillInformation,
|
||||
AlternativeProcedureParameters: qrCodeData.AlternativeProcedureParameters
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps AddressData domain value object to DTO
|
||||
/// </summary>
|
||||
private static AddressDataDto MapAddressToDto(Domain.ValueObjects.AddressData address)
|
||||
{
|
||||
return new AddressDataDto(
|
||||
AddressType: address.AddressType,
|
||||
Name: address.Name,
|
||||
Street: address.Street,
|
||||
BuildingNumber: address.BuildingNumber,
|
||||
AddressLine1: address.AddressLine1,
|
||||
AddressLine2: address.AddressLine2,
|
||||
PostalCode: address.PostalCode,
|
||||
City: address.City,
|
||||
Country: address.Country
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user