Enhance ExtractSwissQrCode feature documentation
Updated `DocumentEndpoints` to include detailed requirements, return values, and use case for the `ExtractSwissQrCode` endpoint. Marked Feature 2 (`ExtractSwissQrCode`) as completed in `PHASENPLAN.md` and `ROADMAP.md`, summarizing achievements and outlining next steps for Feature 3 (`ExtractAttachments`). Enhanced `ExtractSwissQrCodeRequest` and `ExtractSwissQrCodeResponse` DTOs with example JSON payloads for clarity. Expanded `SwissQrCodeDataDto` and `AddressDataDto` with detailed field-level documentation to improve usability and adherence to Swiss QR Bill Standard 2.0.
This commit is contained in:
@@ -33,7 +33,19 @@ public static class DocumentEndpoints
|
||||
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.")
|
||||
.WithDescription(@"Extracts and parses a Swiss QR Code (Swiss QR Bill Standard 2.0) from the last page of a PDF document.
|
||||
|
||||
**Requirements:**
|
||||
- PDF must contain a valid Swiss QR Code on the last page
|
||||
- QR Code must conform to Swiss QR Bill Standard 2.0
|
||||
- References array is required (can be empty)
|
||||
|
||||
**Returns:**
|
||||
- All QR code fields (IBAN, amount, creditor, debtor, reference, etc.)
|
||||
- References array (passed through from request)
|
||||
|
||||
**Use Case:**
|
||||
Extract payment information from Swiss QR invoices for automated processing.")
|
||||
.Produces<ExtractSwissQrCodeResponse>(StatusCodes.Status200OK)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status400BadRequest)
|
||||
.Produces<ProblemDetails>(StatusCodes.Status404NotFound)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ?? DocumentOperator - Phasenplan (Feature-Driven Development)
|
||||
|
||||
> **Stand:** 17.01.2025 | **Aktuell:** Feature 2 - ExtractSwissQrCode ? IN PROGRESS | **Projektdauer:** 6 Wochen
|
||||
> **Stand:** 17.01.2025 | **Aktuell:** Feature 3 - ExtractAttachments ? NEXT | **Projektdauer:** 6 Wochen
|
||||
|
||||
---
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
| Woche | Features / Concerns | Status | Fortschritt |
|
||||
|-------|---------------------|--------|-------------|
|
||||
| **W1** | Feature 1: ValidatePDF | ? Abgeschlossen | 100% (Foundation + Application + API + Swagger fertig) |
|
||||
| **W1-W2** | Feature 2: ExtractSwissQrCode | ? In Progress | 0% (Gerade gestartet!) |
|
||||
| **W2** | Feature 3: ExtractAttachments | ? Geplant | 0% |
|
||||
| **W1-W2** | Feature 2: ExtractSwissQrCode | ? Abgeschlossen | 100% (Domain + Infrastructure + Application + API + Swagger fertig) |
|
||||
| **W2** | Feature 3: ExtractAttachments | ? Nächstes Feature | 0% |
|
||||
| **W2** | Feature 4: ApplyStamp | ? Geplant | 0% |
|
||||
| **W3** | Feature 5: EmbedCertificate | ? Geplant | 0% |
|
||||
| **W3** | Feature 6: ConcatenatePDFs (Async) | ? Geplant | 0% |
|
||||
@@ -170,36 +170,46 @@
|
||||
|
||||
---
|
||||
|
||||
### WOCHE 1-2 - Feature 2: ExtractSwissQrCode | ? In Progress - 0%
|
||||
### WOCHE 1-2 - Feature 2: ExtractSwissQrCode | ? ABGESCHLOSSEN - 100%
|
||||
|
||||
**Dauer:** ~1-2 Tage
|
||||
**Status:** ? In Progress (gerade gestartet!)
|
||||
**Status:** ? Abgeschlossen
|
||||
|
||||
**Endpoint:** POST /api/v1/documents/extract-swiss-qr-code
|
||||
|
||||
**Was wird gebaut:**
|
||||
**Was wurde gebaut:**
|
||||
- Client sendet Referenzen (Array) + PDF (Base64)
|
||||
- API extrahiert Swiss QR Code von **letzter Seite**
|
||||
- API gibt Referenzen + alle QR Code Felder zurück (Swiss QR Bill Standard 2.0)
|
||||
|
||||
**Technologie:**
|
||||
- **DevExpress PDF Document API** (PDF-Zugriff, letzte Seite)
|
||||
- **ZXing.Net.Bindings.Windows.Compatibility** (QR Code Detection)
|
||||
- **Codecrete.SwissQRBill.Generator** (Swiss QR Code Parsing - Standard 2.0)
|
||||
- **System.Drawing.Common** (Bitmap Support)
|
||||
|
||||
**Steps:**
|
||||
- ?? Step 2.1: Domain Layer (SwissQrCodeData Value Object)
|
||||
- ?? Step 2.2: Infrastructure Layer (IQrCodeProcessor + DevExpressSwissQrCodeProcessor + Codecrete Integration)
|
||||
- ?? Step 2.3: Application Layer (ExtractSwissQrCodeQuery + Handler + Validator)
|
||||
- ?? Step 2.4: API Layer (Endpoint + Integration Tests)
|
||||
- ?? Step 2.5: Swagger Dokumentation
|
||||
- ? Step 2.1: Domain Layer (SwissQrCodeData Value Object) - ABGESCHLOSSEN
|
||||
- ? Step 2.2: Infrastructure Layer (ISwissQrCodeProcessor + DevExpressSwissQrCodeProcessor + Library Integration) - ABGESCHLOSSEN
|
||||
- ? Step 2.3: Application Layer (ExtractSwissQrCodeQuery + Handler + Validator + DTOs) - ABGESCHLOSSEN
|
||||
- ? Step 2.4: API Layer (Endpoint + Exception Mapping + Integration Tests) - ABGESCHLOSSEN
|
||||
- ? Step 2.5: Swagger Dokumentation (XML Comments + Examples) - ABGESCHLOSSEN
|
||||
|
||||
**Akzeptanzkriterien:**
|
||||
- ? QR Code wird von letzter Seite extrahiert
|
||||
- ? Alle Swiss QR Bill Felder werden geparst (Standard 2.0)
|
||||
- ? Referenzen werden durchgeschliffen (Echo)
|
||||
- ? Fehler wenn kein QR Code gefunden
|
||||
- ? Fehler wenn kein QR Code gefunden (404 Not Found)
|
||||
- ? Swagger-testbar
|
||||
- ? Tests grün
|
||||
- ? Tests grün (19/19)
|
||||
|
||||
**Ergebnis:**
|
||||
- ? POST /api/v1/documents/extract-swiss-qr-code im Swagger testbar
|
||||
- ? Nested Response Structure (References + SwissQrCodeData)
|
||||
- ? SwissQrCodeNotFoundException wird zu 404 gemappt
|
||||
- ? Unit Tests + Integration Tests grün (19/19)
|
||||
- ? Clean Architecture eingehalten
|
||||
- ? Swagger-Dokumentation vollständig
|
||||
|
||||
---
|
||||
|
||||
@@ -487,21 +497,19 @@
|
||||
|
||||
### Nächstes Feature
|
||||
|
||||
**Feature 2: ExtractSwissQrCode** - **IN PROGRESS**
|
||||
1. ?? Step 2.1: Domain Layer (SwissQrCodeData Value Object)
|
||||
2. ?? Step 2.2: Infrastructure Layer (IQrCodeProcessor + DevExpressSwissQrCodeProcessor + Codecrete Integration)
|
||||
3. ?? Step 2.3: Application Layer (ExtractSwissQrCodeQuery + Handler + Validator + DTOs)
|
||||
4. ?? Step 2.4: API Layer (Endpoint + Integration Tests)
|
||||
5. ?? Step 2.5: Swagger Dokumentation
|
||||
**Feature 3: ExtractAttachments** - **NEXT**
|
||||
1. ?? Step 3.1: Domain Layer (Attachment Value Object)
|
||||
2. ?? Step 3.2: Infrastructure Layer (IAttachmentProcessor + DevExpressAttachmentProcessor)
|
||||
3. ?? Step 3.3: Application Layer (ExtractAttachmentsQuery + Handler + Validator + DTOs)
|
||||
4. ?? Step 3.4: API Layer (Endpoint + Integration Tests)
|
||||
5. ?? Step 3.5: Swagger Dokumentation
|
||||
|
||||
**Erwarteter Zeitaufwand:** ~1-2 Tage
|
||||
**Erwarteter Zeitaufwand:** ~1 Tag
|
||||
|
||||
**Akzeptanzkriterien:**
|
||||
- ? POST /api/v1/documents/extract-swiss-qr-code im Swagger testbar
|
||||
- ? Swiss QR Code wird von letzter Seite extrahiert
|
||||
- ? Alle Swiss QR Bill Felder geparst (Standard 2.0)
|
||||
- ? Referenzen durchgeschliffen
|
||||
- ? Fehler wenn kein QR Code gefunden
|
||||
- ? POST /api/v1/documents/extract-attachments im Swagger testbar
|
||||
- ? Alle Attachments werden extrahiert
|
||||
- ? Attachment-Metadaten werden zurückgegeben
|
||||
- ? Alle Tests grün
|
||||
- ? Clean Architecture eingehalten
|
||||
|
||||
@@ -523,7 +531,12 @@
|
||||
| 17.01.2025 | **Fix: Attachment Detection (Multiple Attachments)** | ? **KORRIGIERT** - ValidatePDF erkennt jetzt auch PDFs mit mehreren Attachments korrekt (globale Suche statt 1000-Zeichen-Limit) - 13/13 Tests grün |
|
||||
| 17.01.2025 | **Fix: Attachment Count (6 Attachments)** | ? **KORRIGIERT** - AttachmentCount wird jetzt korrekt gezählt (objectCount statt objectCount/2). PDFs mit 6 Attachments werden korrekt erkannt - 13/13 Tests grün |
|
||||
| 17.01.2025 | **PHASENPLAN** | ?? **Feature-Reihenfolge geändert** - Neues Feature 2: ExtractSwissQrCode (Swiss QR Bill Standard 2.0) eingefügt. Alte Features 2-5 werden zu Features 3-6. |
|
||||
| 17.01.2025 | **Feature 2 - ExtractSwissQrCode** | ?? **GESTARTET** - Swiss QR Code Extraktion von letzter PDF-Seite (DevExpress + Codecrete.SwissQRBill.Generator) |
|
||||
| 17.01.2025 | **Feature 2 - Step 2.1** | ? **ABGESCHLOSSEN** - Domain Layer (SwissQrCodeData, AddressData, SwissQrCodeNotFoundException) |
|
||||
| 17.01.2025 | **Feature 2 - Step 2.2** | ? **ABGESCHLOSSEN** - Infrastructure Layer (ISwissQrCodeProcessor, DevExpressSwissQrCodeProcessor, ZXing + Codecrete Integration) |
|
||||
| 17.01.2025 | **Feature 2 - Step 2.3** | ? **ABGESCHLOSSEN** - Application Layer (ExtractSwissQrCodeQuery, Handler, Validator, Request/Response DTOs, Unit Tests) |
|
||||
| 17.01.2025 | **Feature 2 - Step 2.4** | ? **ABGESCHLOSSEN** - API Layer (Endpoint, Exception Mapping, Integration Tests - 19/19 Tests grün) |
|
||||
| 17.01.2025 | **Feature 2 - Step 2.5** | ? **ABGESCHLOSSEN** - Swagger Dokumentation (XML Comments, Examples, Endpoint Description) |
|
||||
| 17.01.2025 | **Feature 2** | ? **KOMPLETT ABGESCHLOSSEN** - ExtractSwissQrCode Feature testbar im Swagger UI! (19/19 Tests grün) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
| Feature | Type | Status | Swagger Testbar? |
|
||||
|---------|------|--------|------------------|
|
||||
| **1. ValidatePDF** | Synchron | ? Abgeschlossen | ? |
|
||||
| **2. ExtractSwissQrCode** | Synchron | ? In Progress | ? |
|
||||
| **2. ExtractSwissQrCode** | Synchron | ? Abgeschlossen | ? |
|
||||
| **3. ExtractAttachments** | Synchron | ? Pending | ? |
|
||||
| **4. ApplyStamp** | Synchron | ? Pending | ? |
|
||||
| **5. EmbedCertificate** | Synchron | ? Pending | ? |
|
||||
@@ -279,11 +279,11 @@ Response: { "pageCount": 5, "fileSizeBytes": 1024, "pdfVersion": "1.4", "hasAtta
|
||||
- ? Swagger-Dokumentation vollständig
|
||||
|
||||
**Nächstes Feature:**
|
||||
? **Feature 2: ExtractSwissQrCode**
|
||||
? **Feature 3: ExtractAttachments**
|
||||
|
||||
---
|
||||
|
||||
## ?? FEATURE 2: ExtractSwissQrCode (Synchron) - **IN PROGRESS**
|
||||
## ?? FEATURE 2: ExtractSwissQrCode (Synchron) - **ABGESCHLOSSEN**
|
||||
|
||||
**Was macht dieses Feature?**
|
||||
- Client sendet PDF als Base64 + Referenzen (Array von Strings)
|
||||
@@ -342,11 +342,11 @@ Response:
|
||||
- **Codecrete.SwissQRBill.Generator** (Swiss QR Code Parsing - Standard 2.0)
|
||||
|
||||
**Steps:**
|
||||
- ?? Step 2.1: Domain Layer (SwissQrCodeData Value Object)
|
||||
- ?? Step 2.2: Infrastructure Layer (IQrCodeProcessor + DevExpressSwissQrCodeProcessor)
|
||||
- ?? Step 2.3: Application Layer (ExtractSwissQrCodeQuery + Handler + Validator)
|
||||
- ?? Step 2.4: API Layer (Endpoint + Integration Tests)
|
||||
- ?? Step 2.5: Swagger Dokumentation
|
||||
- ? Step 2.1: Domain Layer (SwissQrCodeData Value Object)
|
||||
- ? Step 2.2: Infrastructure Layer (IQrCodeProcessor + DevExpressSwissQrCodeProcessor)
|
||||
- ? Step 2.3: Application Layer (ExtractSwissQrCodeQuery + Handler + Validator)
|
||||
- ? Step 2.4: API Layer (Endpoint + Integration Tests)
|
||||
- ? Step 2.5: Swagger Dokumentation
|
||||
|
||||
**Akzeptanzkriterien:**
|
||||
- ? QR Code wird von letzter Seite extrahiert
|
||||
@@ -354,6 +354,21 @@ Response:
|
||||
- ? Referenzen werden durchgeschliffen (Echo)
|
||||
- ? Fehler wenn kein QR Code gefunden
|
||||
- ? Swagger-testbar
|
||||
- ? Tests grün (19/19)
|
||||
|
||||
### ? Feature 2 ABGESCHLOSSEN!
|
||||
|
||||
**Was haben wir erreicht?**
|
||||
- ? ExtractSwissQrCode Feature komplett implementiert (Domain ? Infrastructure ? Application ? API ? Tests ? Swagger)
|
||||
- ? Endpoint ist im Swagger UI testbar: `POST /api/v1/documents/extract-swiss-qr-code`
|
||||
- ? Unit Tests + Integration Tests grün (19/19)
|
||||
- ? 3 Libraries integriert: DevExpress PDF, ZXing.Net, Codecrete.SwissQRBill.Generator
|
||||
- ? Vollständige Swiss QR Bill Standard 2.0 Unterstützung
|
||||
- ? Clean Architecture eingehalten
|
||||
- ? Swagger-Dokumentation vollständig
|
||||
|
||||
**Nächstes Feature:**
|
||||
? **Feature 3: ExtractAttachments**
|
||||
|
||||
---
|
||||
|
||||
@@ -1071,7 +1086,12 @@ DocumentOperator.Tests/
|
||||
| 17.01.2025 | **Fix: Attachment Detection (Multiple Attachments)** | ? **KORRIGIERT** - ValidatePDF erkennt jetzt auch PDFs mit mehreren Attachments korrekt (globale Suche statt 1000-Zeichen-Limit) - 13/13 Tests grün |
|
||||
| 17.01.2025 | **Fix: Attachment Count (6 Attachments)** | ? **KORRIGIERT** - AttachmentCount wird jetzt korrekt gezählt (objectCount statt objectCount/2). PDFs mit 6 Attachments werden korrekt erkannt - 13/13 Tests grün |
|
||||
| 17.01.2025 | **ROADMAP** | ?? **Feature-Reihenfolge geändert** - Neues Feature 2: ExtractSwissQrCode (Swiss QR Bill Standard 2.0) eingefügt. Alte Features 2-5 werden zu Features 3-6. |
|
||||
| 17.01.2025 | **Feature 2 - ExtractSwissQrCode** | ?? **GESTARTET** - Swiss QR Code Extraktion von letzter PDF-Seite (DevExpress + Codecrete.SwissQRBill.Generator) |
|
||||
| 17.01.2025 | **Feature 2 - Step 2.1** | ? **ABGESCHLOSSEN** - Domain Layer (SwissQrCodeData, AddressData Value Objects, SwissQrCodeNotFoundException) |
|
||||
| 17.01.2025 | **Feature 2 - Step 2.2** | ? **ABGESCHLOSSEN** - Infrastructure Layer (ISwissQrCodeProcessor, DevExpressSwissQrCodeProcessor, Libraries: Codecrete.SwissQRBill.Generator, ZXing.Net, System.Drawing.Common) |
|
||||
| 17.01.2025 | **Feature 2 - Step 2.3** | ? **ABGESCHLOSSEN** - Application Layer (Query, Handler, Validator, DTOs, Unit Tests - 2/2 grün) |
|
||||
| 17.01.2025 | **Feature 2 - Step 2.4** | ? **ABGESCHLOSSEN** - API Layer (Endpoint /extract-swiss-qr-code, Exception Handling, Integration Tests - 4/4 grün) |
|
||||
| 17.01.2025 | **Feature 2 - Step 2.5** | ? **ABGESCHLOSSEN** - Swagger Dokumentation (XML Comments, Request/Response Beispiele, Endpoint-Beschreibung) |
|
||||
| 17.01.2025 | **Feature 2** | ? **KOMPLETT ABGESCHLOSSEN** - ExtractSwissQrCode Feature testbar im Swagger UI! (19/19 Tests grün) |
|
||||
|
||||
|
||||
---
|
||||
|
||||
@@ -6,6 +6,12 @@ namespace DocumentOperator.Application.Common.DTOs;
|
||||
/// </summary>
|
||||
/// <param name="References">Array of reference strings to pass through in the response</param>
|
||||
/// <param name="Base64Pdf">PDF document encoded as Base64 string</param>
|
||||
/// <example>
|
||||
/// {
|
||||
/// "references": ["REF-001", "REF-002"],
|
||||
/// "base64Pdf": "JVBERi0xLjQK..."
|
||||
/// }
|
||||
/// </example>
|
||||
public record ExtractSwissQrCodeRequest(
|
||||
IReadOnlyList<string> References,
|
||||
string Base64Pdf
|
||||
|
||||
@@ -5,42 +5,112 @@ namespace DocumentOperator.Application.Common.DTOs;
|
||||
/// </summary>
|
||||
/// <param name="References">Reference strings passed through from the request</param>
|
||||
/// <param name="QrCodeData">Parsed Swiss QR Code data from the last page of the PDF</param>
|
||||
/// <example>
|
||||
/// {
|
||||
/// "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,
|
||||
/// "currency": "CHF",
|
||||
/// "referenceType": "QRR",
|
||||
/// "reference": "210000000003139471430009017"
|
||||
/// }
|
||||
/// }
|
||||
/// </example>
|
||||
public record ExtractSwissQrCodeResponse(
|
||||
IReadOnlyList<string> References,
|
||||
SwissQrCodeDataDto QrCodeData
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Swiss QR Code data according to Swiss QR Bill Standard 2.0
|
||||
/// Swiss QR Code data according to Swiss QR Bill Standard 2.0.
|
||||
/// Contains all fields defined in the Swiss Payment Standards.
|
||||
/// </summary>
|
||||
public record SwissQrCodeDataDto(
|
||||
/// <summary>QR type - always "SPC" for Swiss Payment Code</summary>
|
||||
string QrType,
|
||||
|
||||
/// <summary>Version of the Swiss QR Code standard (e.g., "0200" for version 2.0)</summary>
|
||||
string Version,
|
||||
|
||||
/// <summary>Character set code (always "1" for UTF-8)</summary>
|
||||
string CodingType,
|
||||
|
||||
/// <summary>IBAN of the creditor (payee)</summary>
|
||||
string Iban,
|
||||
|
||||
/// <summary>Creditor (payee) information</summary>
|
||||
AddressDataDto Creditor,
|
||||
|
||||
/// <summary>Ultimate creditor information (optional)</summary>
|
||||
AddressDataDto? UltimateCreditor,
|
||||
|
||||
/// <summary>Payment amount (null if not specified)</summary>
|
||||
decimal? Amount,
|
||||
|
||||
/// <summary>Currency code (CHF or EUR)</summary>
|
||||
string Currency,
|
||||
|
||||
/// <summary>Ultimate debtor (payer) information (optional)</summary>
|
||||
AddressDataDto? UltimateDebtor,
|
||||
|
||||
/// <summary>Reference type: "QRR" (QR Reference), "SCOR" (Creditor Reference ISO 11649), or "NON" (No Reference)</summary>
|
||||
string ReferenceType,
|
||||
|
||||
/// <summary>Payment reference (format depends on ReferenceType)</summary>
|
||||
string? Reference,
|
||||
|
||||
/// <summary>Unstructured message (max 140 characters)</summary>
|
||||
string? UnstructuredMessage,
|
||||
|
||||
/// <summary>Bill information (structured data for automated processing)</summary>
|
||||
string? BillInformation,
|
||||
|
||||
/// <summary>Alternative procedure parameters (up to 2 entries)</summary>
|
||||
IReadOnlyList<string>? AlternativeProcedureParameters
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Address data (creditor or debtor) in Swiss QR Code
|
||||
/// Address data in Swiss QR Code (creditor or debtor).
|
||||
/// Can be either structured (S) or combined (K) format.
|
||||
/// </summary>
|
||||
public record AddressDataDto(
|
||||
/// <summary>Address type: "S" for structured, "K" for combined</summary>
|
||||
string AddressType,
|
||||
|
||||
/// <summary>Name of person or company</summary>
|
||||
string Name,
|
||||
|
||||
/// <summary>Street name (structured address only)</summary>
|
||||
string? Street,
|
||||
|
||||
/// <summary>Building number (structured address only)</summary>
|
||||
string? BuildingNumber,
|
||||
|
||||
/// <summary>Address line 1 (combined address only)</summary>
|
||||
string? AddressLine1,
|
||||
|
||||
/// <summary>Address line 2 (combined address only)</summary>
|
||||
string? AddressLine2,
|
||||
|
||||
/// <summary>Postal code</summary>
|
||||
string PostalCode,
|
||||
|
||||
/// <summary>City/town name</summary>
|
||||
string City,
|
||||
|
||||
/// <summary>Two-letter country code (ISO 3166-1 alpha-2)</summary>
|
||||
string Country
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user