diff --git a/DocumentOperator.Application/Common/DTOs/SwissQrCodeExtractionResult.cs b/DocumentOperator.Application/Common/DTOs/SwissQrCodeExtractionResult.cs index 4db1e7a..c0f9738 100644 --- a/DocumentOperator.Application/Common/DTOs/SwissQrCodeExtractionResult.cs +++ b/DocumentOperator.Application/Common/DTOs/SwissQrCodeExtractionResult.cs @@ -1,116 +1,37 @@ namespace DocumentOperator.Application.Common.DTOs; /// -/// Response containing extracted Swiss QR Code data and passed-through references. +/// Response containing extracted Swiss QR Code in dual format. /// -/// Reference strings passed through from the request -/// Parsed Swiss QR Code data from the last page of the PDF +/// Parsed Swiss QR Bill (structured format) +/// Raw Swiss QR Code lines (original newline-separated format) /// /// { -/// "references": ["REF-001", "REF-002"], -/// "qrCodeData": { -/// "qrType": "SPC", -/// "version": "0200", -/// "codingType": "1", -/// "iban": "CH4431999123000889012", -/// "creditor": { -/// "addressType": "S", -/// "name": "Robert Schneider AG", -/// "street": "Rue du Lac", -/// "buildingNumber": "1268", -/// "postalCode": "2501", -/// "city": "Biel", -/// "country": "CH" -/// }, -/// "amount": 1949.75, +/// "bill": { +/// "version": "V2_0", +/// "amount": 630.20, /// "currency": "CHF", +/// "account": "CH953000520280564701R", +/// "creditor": { +/// "type": "Structured", +/// "name": "ALMAT AG", +/// "town": "Tagelswangen" +/// }, /// "referenceType": "QRR", -/// "reference": "210000000003139471430009017" -/// } +/// "reference": "000000000000000000252080824" +/// }, +/// "rawLines": [ +/// "SPC", +/// "0200", +/// "1", +/// "CH953000520280564701R", +/// "S", +/// "ALMAT AG", +/// "..." +/// ] /// } /// public record SwissQrCodeExtractionResult( - IReadOnlyList References, - SwissQrCodeDataDto QrCodeData -); - -/// -/// Swiss QR Code data according to Swiss QR Bill Standard 2.0. -/// Contains all fields defined in the Swiss Payment Standards. -/// -public record SwissQrCodeDataDto( - /// QR type - always "SPC" for Swiss Payment Code - string QrType, - - /// Version of the Swiss QR Code standard (e.g., "0200" for version 2.0) - string Version, - - /// Character set code (always "1" for UTF-8) - string CodingType, - - /// IBAN of the creditor (payee) - string Iban, - - /// Creditor (payee) information - AddressDataDto Creditor, - - /// Ultimate creditor information (optional) - AddressDataDto? UltimateCreditor, - - /// Payment amount (null if not specified) - decimal? Amount, - - /// Currency code (CHF or EUR) - string Currency, - - /// Ultimate debtor (payer) information (optional) - AddressDataDto? UltimateDebtor, - - /// Reference type: "QRR" (QR Reference), "SCOR" (Creditor Reference ISO 11649), or "NON" (No Reference) - string ReferenceType, - - /// Payment reference (format depends on ReferenceType) - string? Reference, - - /// Unstructured message (max 140 characters) - string? UnstructuredMessage, - - /// Bill information (structured data for automated processing) - string? BillInformation, - - /// Alternative procedure parameters (up to 2 entries) - IReadOnlyList? AlternativeProcedureParameters -); - -/// -/// Address data in Swiss QR Code (creditor or debtor). -/// Can be either structured (S) or combined (K) format. -/// -public record AddressDataDto( - /// Address type: "S" for structured, "K" for combined - string AddressType, - - /// Name of person or company - string Name, - - /// Street name (structured address only) - string? Street, - - /// Building number (structured address only) - string? BuildingNumber, - - /// Address line 1 (combined address only) - string? AddressLine1, - - /// Address line 2 (combined address only) - string? AddressLine2, - - /// Postal code - string PostalCode, - - /// City/town name - string City, - - /// Two-letter country code (ISO 3166-1 alpha-2) - string Country + SwissQrBillDto Bill, + IReadOnlyList RawLines ); diff --git a/DocumentOperator.Application/Common/Interfaces/ISwissQrCodeProcessor.cs b/DocumentOperator.Application/Common/Interfaces/ISwissQrCodeProcessor.cs index c832fe8..baa746a 100644 --- a/DocumentOperator.Application/Common/Interfaces/ISwissQrCodeProcessor.cs +++ b/DocumentOperator.Application/Common/Interfaces/ISwissQrCodeProcessor.cs @@ -1,4 +1,4 @@ -using DocumentOperator.Domain.ValueObjects; +using Codecrete.SwissQRBill.Generator; namespace DocumentOperator.Application.Common.Interfaces; @@ -9,16 +9,21 @@ namespace DocumentOperator.Application.Common.Interfaces; public interface ISwissQrCodeProcessor { /// - /// Extracts and parses Swiss QR Code from the last page of a PDF document. + /// Extracts and parses Swiss QR Code from a PDF document. + /// Returns both parsed Bill object and raw QR text lines. /// /// PDF document as byte array + /// Optional: Specific page numbers to scan (1-indexed). If null, scans all pages starting with last page. /// Cancellation token - /// Parsed Swiss QR Code data + /// Tuple: (Parsed Codecrete Bill, Raw QR lines as string array) /// - /// Thrown when no Swiss QR Code is found on the last page + /// Thrown when no Swiss QR Code is found in the specified pages /// /// /// Thrown when PDF processing fails /// - Task ExtractSwissQrCodeAsync(byte[] pdfBytes, CancellationToken cancellationToken = default); + Task<(Bill Bill, string[] RawLines)> ExtractSwissQrCodeAsync( + byte[] pdfBytes, + int[]? pageNumbers = null, + CancellationToken cancellationToken = default); } diff --git a/DocumentOperator.Application/DocumentOperator.Application.csproj b/DocumentOperator.Application/DocumentOperator.Application.csproj index b86574b..d8bc74e 100644 --- a/DocumentOperator.Application/DocumentOperator.Application.csproj +++ b/DocumentOperator.Application/DocumentOperator.Application.csproj @@ -6,8 +6,18 @@ enable + + + + + + + + + + @@ -19,11 +29,6 @@ - - - - - diff --git a/DocumentOperator.Application/SwissQrCode/Queries/ExtractSwissQrCodeQuery.cs b/DocumentOperator.Application/SwissQrCode/Queries/ExtractSwissQrCodeQuery.cs index c1f3447..8c093fa 100644 --- a/DocumentOperator.Application/SwissQrCode/Queries/ExtractSwissQrCodeQuery.cs +++ b/DocumentOperator.Application/SwissQrCode/Queries/ExtractSwissQrCodeQuery.cs @@ -19,11 +19,6 @@ public record ExtractSwissQrCodeQuery : IRequest /// PDF as Base64 string (API clients) /// public string? Base64Pdf { get; init; } - - /// - /// Optional reference strings (passed through to response for external tracking) - /// - public IReadOnlyList? References { get; init; } } /// @@ -34,23 +29,24 @@ public class ExtractSwissQrCodeQueryHandler(ISwissQrCodeProcessor qrCodeProcesso : IRequestHandler { /// - /// Extracts and parses Swiss QR Code from the last page of the PDF + /// Extracts and parses Swiss QR Code from the PDF (default: scans all pages starting with last) + /// Returns both parsed Bill DTO and raw QR text lines /// public async Task Handle(ExtractSwissQrCodeQuery request, CancellationToken cancellationToken) { // Use byte[] if available, otherwise convert Base64 byte[] pdfBytes = request.PdfBytes ?? Convert.FromBase64String(request.Base64Pdf!); - // Extract and parse Swiss QR Code from last page (can throw PdfProcessingException or QrCodeNotFoundException) - var qrCodeData = await qrCodeProcessor.ExtractSwissQrCodeAsync(pdfBytes, cancellationToken); + // Extract: returns (Bill, RawLines) + var (bill, rawLines) = await qrCodeProcessor.ExtractSwissQrCodeAsync(pdfBytes, pageNumbers: null, cancellationToken); - // Map domain value object to DTO using AutoMapper - var qrCodeDto = mapper.Map(qrCodeData); + // Map Codecrete Bill to DTO using AutoMapper + var billDto = mapper.Map(bill); - // Return references (passed through) + QR code data + // Return references (passed through) + Bill DTO + raw lines return new SwissQrCodeExtractionResult( - References: request.References ?? [], - QrCodeData: qrCodeDto + Bill: billDto, + RawLines: rawLines ); } }