Refactor: Rename DocumentOperator to DocumentService
Updated project and solution files to rename and restructure `DocumentOperator` to `DocumentService`. Modified project references in `DocumentService.API.csproj`, `DocumentService.Application.csproj`, and `DocumentService.Infrastructure.csproj` to reflect the new naming convention. Updated `DocumentService.sln` to remove old project references, add new ones, and adjust configuration and nested project mappings accordingly. This change aligns the project structure with the new naming convention.
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
namespace DocumentService.Application.Common.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// DTO for attachment check result returned to API layer
|
||||
/// </summary>
|
||||
public record AttachmentCheckResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the PDF contains any attachments
|
||||
/// </summary>
|
||||
public bool HasAttachments { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Total number of attachments in the PDF
|
||||
/// </summary>
|
||||
public int AttachmentCount { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// List of attachment metadata (file details)
|
||||
/// </summary>
|
||||
public List<AttachmentDto> Attachments { get; init; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DTO for individual attachment metadata
|
||||
/// </summary>
|
||||
public record AttachmentDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Attachment file name (e.g., "invoice.xml", "document.pdf")
|
||||
/// </summary>
|
||||
public string FileName { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// MIME type of the attachment (e.g., "text/xml", "application/pdf")
|
||||
/// </summary>
|
||||
public string MimeType { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Attachment file size in bytes
|
||||
/// </summary>
|
||||
public long Size { get; init; }
|
||||
}
|
||||
60
DocumentService.Application/Common/DTOs/AttachmentInfo.cs
Normal file
60
DocumentService.Application/Common/DTOs/AttachmentInfo.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
namespace DocumentService.Application.Common.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Represents complete attachment information for a PDF document.
|
||||
/// Immutable value object containing attachment presence flag, count, and detailed metadata.
|
||||
/// </summary>
|
||||
public sealed class AttachmentInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the PDF contains any attachments
|
||||
/// </summary>
|
||||
public bool HasAttachments { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of attachments in the PDF
|
||||
/// </summary>
|
||||
public int AttachmentCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of attachment metadata (file details)
|
||||
/// </summary>
|
||||
public IReadOnlyList<AttachmentMetadata> Attachments { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the AttachmentInfo class.
|
||||
/// </summary>
|
||||
/// <param name="hasAttachments">Whether PDF has attachments</param>
|
||||
/// <param name="attachmentCount">Total number of attachments</param>
|
||||
/// <param name="attachments">List of attachment metadata (can be empty)</param>
|
||||
public AttachmentInfo(bool hasAttachments, int attachmentCount, IReadOnlyList<AttachmentMetadata> attachments)
|
||||
{
|
||||
HasAttachments = hasAttachments;
|
||||
AttachmentCount = attachmentCount;
|
||||
Attachments = attachments ?? [];
|
||||
|
||||
// Defensive Programming: Ensure count matches list length
|
||||
if (Attachments.Count != attachmentCount)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"Attachment count mismatch: expected {attachmentCount}, got {Attachments.Count}",
|
||||
nameof(attachments));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an AttachmentInfo instance for a PDF with no attachments.
|
||||
/// </summary>
|
||||
public static AttachmentInfo Empty =>
|
||||
new(
|
||||
hasAttachments: false,
|
||||
attachmentCount: 0,
|
||||
attachments: []);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return HasAttachments
|
||||
? $"PDF has {AttachmentCount} attachment(s): {string.Join(", ", Attachments.Select(a => a.FileName))}"
|
||||
: "PDF has no attachments";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
namespace DocumentService.Application.Common.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Represents metadata of a single PDF attachment (embedded file).
|
||||
/// Immutable value object containing file information without the actual binary data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the AttachmentMetadata class.
|
||||
/// </remarks>
|
||||
/// <param name="fileName">Attachment file name</param>
|
||||
/// <param name="mimeType">MIME type (e.g., "text/xml")</param>
|
||||
/// <param name="sizeBytes">File size in bytes</param>
|
||||
public sealed class AttachmentMetadata(string fileName, string mimeType, long sizeBytes)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the attachment file name (e.g., "invoice.xml", "document.pdf")
|
||||
/// </summary>
|
||||
public string FileName { get; } = fileName ?? string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MIME type of the attachment (e.g., "text/xml", "application/pdf")
|
||||
/// </summary>
|
||||
public string MimeType { get; } = mimeType ?? "application/octet-stream"; // Default MIME type if unknown
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attachment file size in bytes
|
||||
/// </summary>
|
||||
public long SizeBytes { get; } = sizeBytes;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attachment file size in kilobytes (computed property)
|
||||
/// </summary>
|
||||
public double SizeKB => SizeBytes / 1024.0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attachment file size in megabytes (computed property)
|
||||
/// </summary>
|
||||
public double SizeMB => SizeBytes / 1024.0 / 1024.0;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{FileName} ({MimeType}, {SizeKB:F2} KB)";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
namespace DocumentService.Application.Common.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// PDF/A validation result including conformance level and validation errors/warnings
|
||||
/// </summary>
|
||||
public record PdfAValidationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the PDF is valid (no errors)
|
||||
/// </summary>
|
||||
public bool IsValid { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// PDF version (e.g., "1.4", "1.7")
|
||||
/// </summary>
|
||||
public string PdfVersion { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Number of pages in the PDF
|
||||
/// </summary>
|
||||
public int PageCount { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// File size in bytes
|
||||
/// </summary>
|
||||
public long FileSize { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the PDF is encrypted
|
||||
/// </summary>
|
||||
public bool Encrypted { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// PDF/A version (e.g., "PDF/A-1b", "PDF/A-2a", "PDF/A-3u") or null if not PDF/A compliant
|
||||
/// </summary>
|
||||
public string? PdfAVersion { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the PDF conforms to PDF/A standard
|
||||
/// </summary>
|
||||
public bool PdfACompliant { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Validation errors (e.g., "PDF/A documents cannot be encrypted")
|
||||
/// </summary>
|
||||
public IReadOnlyList<string> Errors { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Validation warnings (e.g., "Manual verification recommended: All fonts must be embedded")
|
||||
/// </summary>
|
||||
public IReadOnlyList<string> Warnings { get; init; } = [];
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace DocumentService.Application.Common.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Response mit PDF-Metadaten
|
||||
/// </summary>
|
||||
/// <param name="PageCount">Anzahl der Seiten</param>
|
||||
/// <param name="FileSizeBytes">Dateigröße in Bytes</param>
|
||||
/// <param name="FileSizeMB">Dateigröße in MB (gerundet auf 2 Dezimalstellen)</param>
|
||||
/// <param name="PdfVersion">PDF-Version (z.B. "1.4")</param>
|
||||
/// <param name="HasAttachments">Hat das PDF Anhänge?</param>
|
||||
/// <param name="AttachmentCount">Anzahl der Anhänge</param>
|
||||
/// <param name="IsEncrypted">Ist das PDF passwortgeschützt/verschlüsselt?</param>
|
||||
public record PdfValidationResult(
|
||||
int PageCount,
|
||||
long FileSizeBytes,
|
||||
double FileSizeMB,
|
||||
string PdfVersion,
|
||||
bool HasAttachments,
|
||||
int AttachmentCount,
|
||||
bool IsEncrypted);
|
||||
93
DocumentService.Application/Common/DTOs/SwissQrBillDto.cs
Normal file
93
DocumentService.Application/Common/DTOs/SwissQrBillDto.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
namespace DocumentService.Application.Common.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Swiss QR Bill data transfer object (mapped from Codecrete Bill)
|
||||
/// </summary>
|
||||
public record SwissQrBillDto
|
||||
{
|
||||
/// <summary>QR Bill standard version (e.g., "V2_0")</summary>
|
||||
public required string Version { get; init; }
|
||||
|
||||
/// <summary>Payment amount (null if not specified)</summary>
|
||||
public decimal? Amount { get; init; }
|
||||
|
||||
/// <summary>Payment currency (CHF or EUR)</summary>
|
||||
public required string Currency { get; init; }
|
||||
|
||||
/// <summary>Creditor's IBAN account number</summary>
|
||||
public required string Account { get; init; }
|
||||
|
||||
/// <summary>Creditor address</summary>
|
||||
public required AddressDto Creditor { get; init; }
|
||||
|
||||
/// <summary>Payment reference type: "QRR", "SCOR", or "NON"</summary>
|
||||
public required string ReferenceType { get; init; }
|
||||
|
||||
/// <summary>Payment reference (format depends on ReferenceType)</summary>
|
||||
public string? Reference { get; init; }
|
||||
|
||||
/// <summary>Debtor address (optional)</summary>
|
||||
public AddressDto? Debtor { get; init; }
|
||||
|
||||
/// <summary>Additional unstructured message (max 140 chars)</summary>
|
||||
public string? UnstructuredMessage { get; init; }
|
||||
|
||||
/// <summary>Additional structured bill information</summary>
|
||||
public string? BillInformation { get; init; }
|
||||
|
||||
/// <summary>Alternative payment schemes (max 2)</summary>
|
||||
public IReadOnlyList<AlternativeSchemeDto>? AlternativeSchemes { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Address data transfer object (mapped from Codecrete Address)
|
||||
/// </summary>
|
||||
public record AddressDto
|
||||
{
|
||||
/// <summary>Address type: "Structured" or "CombinedElements"</summary>
|
||||
public required string Type { get; init; }
|
||||
|
||||
/// <summary>Name of person or company</summary>
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>Street name (structured address only)</summary>
|
||||
public string? Street { get; init; }
|
||||
|
||||
/// <summary>House number (structured address only)</summary>
|
||||
public string? HouseNo { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Address line 1 (combined address only).
|
||||
/// OBSOLETE: Use structured address instead. Will be removed when Codecrete v4 is adopted.
|
||||
/// </summary>
|
||||
[Obsolete("Use structured address (Street + HouseNo) instead. This field will be removed when upgrading to Codecrete.SwissQRBill.Generator v4.x")]
|
||||
public string? AddressLine1 { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Address line 2 (combined address only).
|
||||
/// OBSOLETE: Use structured address instead. Will be removed when Codecrete v4 is adopted.
|
||||
/// </summary>
|
||||
[Obsolete("Use structured address (Street + HouseNo) instead. This field will be removed when upgrading to Codecrete.SwissQRBill.Generator v4.x")]
|
||||
public string? AddressLine2 { get; init; }
|
||||
|
||||
/// <summary>Postal code</summary>
|
||||
public required string PostalCode { get; init; }
|
||||
|
||||
/// <summary>Town/city name</summary>
|
||||
public required string Town { get; init; }
|
||||
|
||||
/// <summary>Two-letter country code (ISO 3166-1 alpha-2)</summary>
|
||||
public required string CountryCode { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alternative payment scheme (mapped from Codecrete AlternativeScheme)
|
||||
/// </summary>
|
||||
public record AlternativeSchemeDto
|
||||
{
|
||||
/// <summary>Scheme name (e.g., "AV1", "AV2")</summary>
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>Scheme instruction/parameter</summary>
|
||||
public required string Instruction { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace DocumentService.Application.Common.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Response containing extracted Swiss QR Code in dual format.
|
||||
/// </summary>
|
||||
/// <param name="Bill">Parsed Swiss QR Bill (structured format)</param>
|
||||
/// <param name="RawLines">Raw Swiss QR Code lines (original newline-separated format)</param>
|
||||
/// <example>
|
||||
/// {
|
||||
/// "bill": {
|
||||
/// "version": "V2_0",
|
||||
/// "amount": 630.20,
|
||||
/// "currency": "CHF",
|
||||
/// "account": "CH953000520280564701R",
|
||||
/// "creditor": {
|
||||
/// "type": "Structured",
|
||||
/// "name": "ALMAT AG",
|
||||
/// "town": "Tagelswangen"
|
||||
/// },
|
||||
/// "referenceType": "QRR",
|
||||
/// "reference": "000000000000000000252080824"
|
||||
/// },
|
||||
/// "rawLines": [
|
||||
/// "SPC",
|
||||
/// "0200",
|
||||
/// "1",
|
||||
/// "CH953000520280564701R",
|
||||
/// "S",
|
||||
/// "ALMAT AG",
|
||||
/// "..."
|
||||
/// ]
|
||||
/// }
|
||||
/// </example>
|
||||
public record SwissQrCodeExtractionResult(
|
||||
SwissQrBillDto Bill,
|
||||
IReadOnlyList<string> RawLines
|
||||
);
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace DocumentService.Application.Common.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// DTO for ZUGFeRD check result
|
||||
/// </summary>
|
||||
public record ZugferdCheckResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the PDF contains ZUGFeRD XML attachment
|
||||
/// </summary>
|
||||
public bool HasZugferd { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// ZUGFeRD XML file name (e.g., "factur-x.xml")
|
||||
/// </summary>
|
||||
public string? ZugferdFileName { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// ZUGFeRD XML file size in bytes
|
||||
/// </summary>
|
||||
public long? ZugferdFileSize { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// MIME type of the ZUGFeRD XML file
|
||||
/// </summary>
|
||||
public string? ZugferdMimeType { get; init; }
|
||||
}
|
||||
Reference in New Issue
Block a user