books/backend/Books.Api/Commands/Invoices/InvoiceCommandHandlers.cs
Nicolaj Hartmann 1f75c5d791 Add all backend domain, commands, repositories, and tests
This commit includes all previously untracked backend files:

Domain:
- Accounts, Attachments, BankConnections, Customers
- FiscalYears, Invoices, JournalEntryDrafts
- Orders, Products, UserAccess

Commands & Handlers:
- Full CQRS command structure for all domains

Repositories:
- PostgreSQL repositories for all read models
- Bank transaction and ledger repositories

GraphQL:
- Input types, scalars, and types for all entities
- Mutations and queries

Infrastructure:
- Banking integration (Enable Banking client)
- File storage, Invoicing, Reporting, SAF-T export
- Database migrations (003-029)

Tests:
- Integration tests for GraphQL endpoints
- Domain tests
- Invoicing and reporting tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:19:42 +01:00

211 lines
5.8 KiB
C#

using Books.Api.Domain.Invoices;
using EventFlow.Commands;
namespace Books.Api.Commands.Invoices;
public class CreateInvoiceCommandHandler
: CommandHandler<InvoiceAggregate, InvoiceId, CreateInvoiceCommand>
{
public override Task ExecuteAsync(
InvoiceAggregate aggregate,
CreateInvoiceCommand command,
CancellationToken cancellationToken)
{
aggregate.Create(
command.CompanyId,
command.FiscalYearId,
command.CustomerId,
command.CustomerName,
command.CustomerNumber,
command.InvoiceNumber,
command.InvoiceDate,
command.DueDate,
command.PaymentTermsDays,
command.Currency,
command.VatCode,
command.Notes,
command.Reference,
command.CreatedBy);
return Task.CompletedTask;
}
}
public class AddInvoiceLineCommandHandler
: CommandHandler<InvoiceAggregate, InvoiceId, AddInvoiceLineCommand>
{
public override Task ExecuteAsync(
InvoiceAggregate aggregate,
AddInvoiceLineCommand command,
CancellationToken cancellationToken)
{
aggregate.AddLine(
command.Description,
command.Quantity,
command.UnitPrice,
command.VatCode,
command.AccountId,
command.Unit,
command.DiscountPercent);
return Task.CompletedTask;
}
}
public class UpdateInvoiceLineCommandHandler
: CommandHandler<InvoiceAggregate, InvoiceId, UpdateInvoiceLineCommand>
{
public override Task ExecuteAsync(
InvoiceAggregate aggregate,
UpdateInvoiceLineCommand command,
CancellationToken cancellationToken)
{
aggregate.UpdateLine(
command.LineNumber,
command.Description,
command.Quantity,
command.UnitPrice,
command.VatCode,
command.AccountId,
command.Unit,
command.DiscountPercent);
return Task.CompletedTask;
}
}
public class RemoveInvoiceLineCommandHandler
: CommandHandler<InvoiceAggregate, InvoiceId, RemoveInvoiceLineCommand>
{
public override Task ExecuteAsync(
InvoiceAggregate aggregate,
RemoveInvoiceLineCommand command,
CancellationToken cancellationToken)
{
aggregate.RemoveLine(command.LineNumber);
return Task.CompletedTask;
}
}
public class MarkInvoiceSentCommandHandler
: CommandHandler<InvoiceAggregate, InvoiceId, MarkInvoiceSentCommand>
{
public override Task ExecuteAsync(
InvoiceAggregate aggregate,
MarkInvoiceSentCommand command,
CancellationToken cancellationToken)
{
aggregate.Send(
command.LedgerTransactionId,
command.SentBy);
return Task.CompletedTask;
}
}
public class ReceiveInvoicePaymentCommandHandler
: CommandHandler<InvoiceAggregate, InvoiceId, ReceiveInvoicePaymentCommand>
{
public override Task ExecuteAsync(
InvoiceAggregate aggregate,
ReceiveInvoicePaymentCommand command,
CancellationToken cancellationToken)
{
aggregate.ReceivePayment(
command.Amount,
command.BankTransactionId,
command.LedgerTransactionId,
command.PaymentReference,
command.PaymentDate,
command.RecordedBy);
return Task.CompletedTask;
}
}
public class VoidInvoiceCommandHandler
: CommandHandler<InvoiceAggregate, InvoiceId, VoidInvoiceCommand>
{
public override Task ExecuteAsync(
InvoiceAggregate aggregate,
VoidInvoiceCommand command,
CancellationToken cancellationToken)
{
aggregate.Void(
command.Reason,
command.ReversalLedgerTransactionId,
command.VoidedBy);
return Task.CompletedTask;
}
}
// =====================================================
// CREDIT NOTE COMMAND HANDLERS
// =====================================================
public class CreateCreditNoteCommandHandler
: CommandHandler<InvoiceAggregate, InvoiceId, CreateCreditNoteCommand>
{
public override Task ExecuteAsync(
InvoiceAggregate aggregate,
CreateCreditNoteCommand command,
CancellationToken cancellationToken)
{
aggregate.CreateCreditNote(
command.CompanyId,
command.FiscalYearId,
command.CustomerId,
command.CustomerName,
command.CustomerNumber,
command.CreditNoteNumber,
command.CreditNoteDate,
command.Currency,
command.VatCode,
command.Notes,
command.Reference,
command.CreatedBy,
command.OriginalInvoiceId,
command.OriginalInvoiceNumber,
command.CreditReason);
return Task.CompletedTask;
}
}
public class IssueCreditNoteCommandHandler
: CommandHandler<InvoiceAggregate, InvoiceId, IssueCreditNoteCommand>
{
public override Task ExecuteAsync(
InvoiceAggregate aggregate,
IssueCreditNoteCommand command,
CancellationToken cancellationToken)
{
aggregate.Issue(
command.LedgerTransactionId,
command.IssuedBy);
return Task.CompletedTask;
}
}
public class ApplyCreditNoteCommandHandler
: CommandHandler<InvoiceAggregate, InvoiceId, ApplyCreditNoteCommand>
{
public override Task ExecuteAsync(
InvoiceAggregate aggregate,
ApplyCreditNoteCommand command,
CancellationToken cancellationToken)
{
aggregate.ApplyCredit(
command.TargetInvoiceId,
command.TargetInvoiceNumber,
command.Amount,
command.AppliedDate,
command.AppliedBy,
command.LedgerTransactionId);
return Task.CompletedTask;
}
}