books/backend/Books.Api/Domain/Invoices/Events/InvoiceCreatedEvent.cs
Nicolaj Hartmann 1a0922b778 Audit v3: VAT alignment, security, encoding, UX, compliance
VAT System Alignment (LEGAL - Critical):
- Align frontend VAT codes with backend (S25→U25, K25→I25, etc.)
- Add missing codes: UEU, IVV, IVY, REP
- Fix output VAT account 5710→5611 to match StandardDanishAccounts
- Invoice posting now checks fiscal year status before allowing send
- Disallow custom invoice number override (always use auto-numbering)

Security:
- Fix open redirect in AuthController (validate returnUrl is local)
- Store seller CVR/name/address on invoice events (Momsloven §52)

Backend Compliance:
- Add description validation at posting (Bogføringsloven §7)
- SAF-T: add DefaultCurrencyCode, TaxAccountingBasis to header
- SAF-T: add TaxTable to MasterFiles with all VAT codes
- SAF-T: always write balance elements even when zero
- Add financial income account 9100 Renteindtægter

Danish Encoding (~25 fixes):
- Kassekladde: Bogført, Bogføring, Vælg, være, på, Tilføj, Differens
- AttachmentUpload: træk, Understøtter, påkrævet, Bogføringsloven
- keyboardShortcuts: Bogfør, Bogføring display name
- ShortcutsHelpModal: åbne
- DataTable: Genindlæs
- documentProcessing: være
- CloseFiscalYearWizard: årsafslutning

Bugs Fixed:
- Non-null assertion crashes in Kunder.tsx and Produkter.tsx (company!.id)
- StatusBadge typo "Succces"→"Succes"
- HTML entity ø in Kassekladde→proper UTF-8
- AmountText showSign prop was dead code (true || showSign)

UX Improvements:
- Add PageHeader to Bankafstemning and Dashboard loading/empty states
- Responsive columns in Bankafstemning (xs/sm/lg breakpoints)
- Disable misleading buttons: Settings preferences, Kontooversigt edit,
  Loenforstaelse export — with tooltips explaining status
- Add DemoDataDisclaimer to UserSettings
- Fix breadcrumb self-references on 3 pages
- Replace Dashboard fake progress bar with honest message
- Standardize date format DD-MM-YYYY in Bankafstemning and Ordrer
- Replace Input type="number" with InputNumber in Ordrer

Quality:
- Remove 8 redundant console.error statements
- Fix Kreditnotaer breadcrumb "Salg"→"Fakturering" for consistency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:15:45 +01:00

82 lines
2.7 KiB
C#

using Books.Api.Domain.Invoices;
using EventFlow.Aggregates;
namespace Books.Api.Domain.Invoices.Events;
/// <summary>
/// Raised when a new invoice or credit note draft is created.
/// At this point, the invoice/credit note number is assigned (Momsloven §52).
/// </summary>
public class InvoiceCreatedEvent(
string companyId,
string fiscalYearId,
string customerId,
string customerName,
string customerNumber,
string invoiceNumber,
DateOnly invoiceDate,
DateOnly dueDate,
int paymentTermsDays,
string currency,
string? vatCode,
string? notes,
string? reference,
string createdBy,
InvoiceType type = InvoiceType.Invoice,
string? originalInvoiceId = null,
string? originalInvoiceNumber = null,
string? creditReason = null,
string? sellerCvr = null,
string? sellerName = null,
string? sellerAddress = null) : AggregateEvent<InvoiceAggregate, InvoiceId>
{
public string CompanyId { get; } = companyId;
public string FiscalYearId { get; } = fiscalYearId;
public string CustomerId { get; } = customerId;
public string CustomerName { get; } = customerName;
public string CustomerNumber { get; } = customerNumber;
public string InvoiceNumber { get; } = invoiceNumber;
public DateOnly InvoiceDate { get; } = invoiceDate;
public DateOnly DueDate { get; } = dueDate;
public int PaymentTermsDays { get; } = paymentTermsDays;
public string Currency { get; } = currency;
public string? VatCode { get; } = vatCode;
public string? Notes { get; } = notes;
public string? Reference { get; } = reference;
public string CreatedBy { get; } = createdBy;
/// <summary>
/// Type of document: Invoice or CreditNote.
/// </summary>
public InvoiceType Type { get; } = type;
/// <summary>
/// For credit notes: Reference to the original invoice being credited.
/// </summary>
public string? OriginalInvoiceId { get; } = originalInvoiceId;
/// <summary>
/// For credit notes: The invoice number of the original invoice.
/// </summary>
public string? OriginalInvoiceNumber { get; } = originalInvoiceNumber;
/// <summary>
/// For credit notes: Reason for issuing the credit note.
/// </summary>
public string? CreditReason { get; } = creditReason;
/// <summary>
/// Seller CVR number (company registration number).
/// </summary>
public string? SellerCvr { get; } = sellerCvr;
/// <summary>
/// Seller company name.
/// </summary>
public string? SellerName { get; } = sellerName;
/// <summary>
/// Seller company address.
/// </summary>
public string? SellerAddress { get; } = sellerAddress;
}