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>
214 lines
7.1 KiB
C#
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
|
|
};
|
|
}
|
|
}
|