books/backend/Books.Api.Tests/AiBookkeeper/ToonFormatConverterTests.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

214 lines
7.1 KiB
C#

using Books.Api.AiBookkeeper;
using AwesomeAssertions;
namespace Books.Api.Tests.AiBookkeeper;
/// <summary>
/// Unit tests for ToonFormatConverter.
/// Verifies that ChartOfAccountsDto is correctly converted to .toon format.
/// </summary>
[Trait("Category", "Unit")]
public class ToonFormatConverterTests
{
[Fact]
public void ConvertToToon_EuGoodsAccount_HasEuRegion()
{
// Arrange
var chartOfAccounts = CreateChartOfAccounts(
CreateAccount("2050", "EU-erhvervelser varer", "cogs", "IEUV"));
// Act
var result = ToonFormatConverter.ConvertToToon(chartOfAccounts);
// Assert - Account 2050 should have region EU
result.Should().Contain("2050,EU-erhvervelser varer,Variable omkostninger,IEUV,EU,,");
}
[Fact]
public void ConvertToToon_EuServicesAccount_HasEuRegion()
{
// Arrange
var chartOfAccounts = CreateChartOfAccounts(
CreateAccount("2100", "EU-erhvervelser ydelser", "cogs", "IEUY"));
// Act
var result = ToonFormatConverter.ConvertToToon(chartOfAccounts);
// Assert - Account 2100 should have region EU
result.Should().Contain("2100,EU-erhvervelser ydelser,Variable omkostninger,IEUY,EU,,");
}
[Fact]
public void ConvertToToon_WorldGoodsAccount_HasWorldRegion()
{
// Arrange
var chartOfAccounts = CreateChartOfAccounts(
CreateAccount("2150", "Varekøb verden", "cogs", "IVV"));
// Act
var result = ToonFormatConverter.ConvertToToon(chartOfAccounts);
// Assert - Account 2150 should have region WORLD
result.Should().Contain("2150,Varekøb verden,Variable omkostninger,IVV,WORLD,,");
}
[Fact]
public void ConvertToToon_WorldServicesAccount_HasWorldRegion()
{
// Arrange
var chartOfAccounts = CreateChartOfAccounts(
CreateAccount("2200", "Ydelseskøb verden", "cogs", "IVY"));
// Act
var result = ToonFormatConverter.ConvertToToon(chartOfAccounts);
// Assert - Account 2200 should have region WORLD
result.Should().Contain("2200,Ydelseskøb verden,Variable omkostninger,IVY,WORLD,,");
}
[Fact]
public void ConvertToToon_DomesticAccount_HasEmptyRegion()
{
// Arrange
var chartOfAccounts = CreateChartOfAccounts(
CreateAccount("7320", "Køb af software", "expense", "I25"));
// Act
var result = ToonFormatConverter.ConvertToToon(chartOfAccounts);
// Assert - Account 7320 should have empty region (available for all regions)
result.Should().Contain("7320,Køb af software,Administrationsomkostninger,I25,,,");
}
[Fact]
public void ConvertToToon_AccountWithNoVatCode_HasEmptyRegion()
{
// Arrange
var chartOfAccounts = CreateChartOfAccounts(
CreateAccount("7000", "Kontorartikler", "expense", null));
// Act
var result = ToonFormatConverter.ConvertToToon(chartOfAccounts);
// Assert - Account with no VAT code should have empty region
result.Should().Contain("7000,Kontorartikler,Administrationsomkostninger,,,,");
}
[Fact]
public void ConvertToToon_MixedAccounts_CorrectRegionsAssigned()
{
// Arrange
var chartOfAccounts = CreateChartOfAccounts(
CreateAccount("2000", "Vareforbrug", "cogs", "I25"),
CreateAccount("2050", "EU-erhvervelser varer", "cogs", "IEUV"),
CreateAccount("2150", "Varekøb verden", "cogs", "IVV"),
CreateAccount("7320", "Køb af software", "expense", "I25"));
// Act
var result = ToonFormatConverter.ConvertToToon(chartOfAccounts);
// Assert
result.Should().Contain("2000,Vareforbrug,Variable omkostninger,I25,,,"); // Empty region
result.Should().Contain("2050,EU-erhvervelser varer,Variable omkostninger,IEUV,EU,,"); // EU
result.Should().Contain("2150,Varekøb verden,Variable omkostninger,IVV,WORLD,,"); // WORLD
result.Should().Contain("7320,Køb af software,Administrationsomkostninger,I25,,,"); // Empty region
}
[Fact]
public void ConvertToToon_ContainsMetaSection()
{
// Arrange
var chartOfAccounts = CreateChartOfAccounts(
CreateAccount("7000", "Kontorartikler", "expense", "I25"));
// Act
var result = ToonFormatConverter.ConvertToToon(chartOfAccounts);
// Assert
result.Should().Contain("meta:");
result.Should().Contain("source: Books API");
result.Should().Contain("organizationId: company-1");
result.Should().Contain("accountType: expense");
result.Should().Contain("totalAccounts: 1");
}
[Fact]
public void ConvertToToon_ContainsAccountsHeader()
{
// Arrange
var chartOfAccounts = CreateChartOfAccounts(
CreateAccount("7000", "Kontorartikler", "expense", "I25"),
CreateAccount("7100", "Porto", "expense", "I25"));
// Act
var result = ToonFormatConverter.ConvertToToon(chartOfAccounts);
// Assert
result.Should().Contain("accounts[2]{number,name,category,vatCode,region,vatRubric,suggestions}:");
}
[Fact]
public void MapCategory_ExpenseAccount_ReturnsAdministrationsomkostninger()
{
var result = ToonFormatConverter.MapCategory("expense");
result.Should().Be("Administrationsomkostninger");
}
[Fact]
public void MapCategory_CogsAccount_ReturnsVariableOmkostninger()
{
var result = ToonFormatConverter.MapCategory("cogs");
result.Should().Be("Variable omkostninger");
}
[Fact]
public void MapCategory_PersonnelAccount_ReturnsLønomkostninger()
{
var result = ToonFormatConverter.MapCategory("personnel");
result.Should().Be("Lønomkostninger");
}
[Fact]
public void MapCategory_FinancialAccount_ReturnsRenteudgifter()
{
var result = ToonFormatConverter.MapCategory("financial");
result.Should().Be("Renteudgifter");
}
[Fact]
public void GenerateSuggestions_IncludesWordsFromName()
{
var result = ToonFormatConverter.GenerateSuggestions("Køb af software", "7320");
result.Should().Contain("køb");
result.Should().Contain("software");
result.Should().Contain("7320");
}
[Fact]
public void GenerateSuggestions_ExcludesShortWords()
{
var result = ToonFormatConverter.GenerateSuggestions("IT og software", "7320");
result.Should().NotContain("og"); // "og" has only 2 characters
result.Should().Contain("software");
}
private static ChartOfAccountsDto CreateChartOfAccounts(params AiAccountDto[] accounts)
{
return new ChartOfAccountsDto
{
CompanyId = "company-1",
Accounts = accounts.ToList()
};
}
private static AiAccountDto CreateAccount(string number, string name, string type, string? vatCode)
{
return new AiAccountDto
{
AccountNumber = number,
Name = name,
AccountType = type,
VatCodeId = vatCode
};
}
}