K2: add EF configurations for cashbook

- BookingCategoryConfiguration with unique index
- CashBookEntryConfiguration with FK relationships
- ClubConfiguration: InitialBalance, MonthlyMembershipFee
- AppDbContext: BookingCategories, CashBookEntries DbSets

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
beo3000 2026-01-03 14:21:59 +01:00
parent 012548e8db
commit 0280e0e05e
5 changed files with 138 additions and 1 deletions

View File

@ -1700,7 +1700,7 @@ public enum CashBookEntryType { Income = 0, Expense = 1 }
| ☐ | Phase | Bereich | Beschreibung | Dateien |
|---|-------|---------|--------------|---------|
| ✓ | K1 | Domain | Entities + Enums | 5 |
| | K2 | Infrastructure | EF Configurations | 4 |
| | K2 | Infrastructure | EF Configurations | 4 |
| ☐ | K3 | Infrastructure | Migration | - |
| ☐ | K4 | Security | Kassenwart Role + Policy | 4 |
| ☐ | K5 | Infrastructure | Repositories | 5 |

View File

@ -37,6 +37,10 @@ public class AppDbContext : DbContext
// Statistics
public DbSet<PlayerGameStatistics> PlayerGameStatistics => Set<PlayerGameStatistics>();
// Cash Book
public DbSet<BookingCategory> BookingCategories => Set<BookingCategory>();
public DbSet<CashBookEntry> CashBookEntries => Set<CashBookEntry>();
// GIF Celebrations
public DbSet<ClubGif> ClubGifs => Set<ClubGif>();
public DbSet<ClubGifRating> ClubGifRatings => Set<ClubGifRating>();

View File

@ -0,0 +1,58 @@
using Koogle.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Koogle.Infrastructure.Data.Configurations;
/// <summary>
/// EF Core configuration for BookingCategory entity.
/// </summary>
public class BookingCategoryConfiguration : IEntityTypeConfiguration<BookingCategory>
{
public void Configure(EntityTypeBuilder<BookingCategory> builder)
{
builder.ToTable("BookingCategories");
builder.HasKey(x => x.Id);
builder.Property(x => x.ClubId)
.IsRequired();
builder.Property(x => x.Name)
.HasMaxLength(100)
.IsRequired();
builder.Property(x => x.Description)
.HasMaxLength(500);
builder.Property(x => x.CategoryType)
.HasConversion<int>()
.IsRequired();
builder.Property(x => x.IsSystemCategory)
.IsRequired();
builder.Property(x => x.Color)
.HasMaxLength(7); // #RRGGBB
builder.Property(x => x.Icon)
.HasMaxLength(50);
builder.Property(x => x.IsActive)
.IsRequired();
builder.HasOne(x => x.Club)
.WithMany(c => c.BookingCategories)
.HasForeignKey(x => x.ClubId)
.OnDelete(DeleteBehavior.NoAction);
builder.HasAlternateKey(x => new { x.Id, x.ClubId });
builder.HasIndex(x => x.ClubId);
builder.HasIndex(x => new { x.ClubId, x.Name })
.HasFilter("[IsDeleted] = 0")
.IsUnique();
builder.HasQueryFilter(x => !x.IsDeleted);
}
}

View File

@ -0,0 +1,69 @@
using Koogle.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Koogle.Infrastructure.Data.Configurations;
/// <summary>
/// EF Core configuration for CashBookEntry entity.
/// </summary>
public class CashBookEntryConfiguration : IEntityTypeConfiguration<CashBookEntry>
{
public void Configure(EntityTypeBuilder<CashBookEntry> builder)
{
builder.ToTable("CashBookEntries");
builder.HasKey(x => x.Id);
builder.Property(x => x.ClubId)
.IsRequired();
builder.Property(x => x.CategoryId)
.IsRequired();
builder.Property(x => x.EntryType)
.HasConversion<int>()
.IsRequired();
builder.Property(x => x.Amount)
.HasPrecision(10, 2)
.IsRequired();
builder.Property(x => x.BookingDate)
.IsRequired();
builder.Property(x => x.Comment)
.HasMaxLength(500);
builder.Property(x => x.ReceiptReference)
.HasMaxLength(100);
builder.HasOne(x => x.Club)
.WithMany(c => c.CashBookEntries)
.HasForeignKey(x => x.ClubId)
.OnDelete(DeleteBehavior.NoAction);
builder.HasOne(x => x.Category)
.WithMany(c => c.CashBookEntries)
.HasForeignKey(x => x.CategoryId)
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne(x => x.Day)
.WithMany()
.HasForeignKey(x => x.DayId)
.OnDelete(DeleteBehavior.SetNull);
builder.HasOne(x => x.Person)
.WithMany()
.HasForeignKey(x => x.PersonId)
.OnDelete(DeleteBehavior.SetNull);
builder.HasIndex(x => x.ClubId);
builder.HasIndex(x => x.CategoryId);
builder.HasIndex(x => x.BookingDate);
builder.HasIndex(x => x.DayId);
builder.HasIndex(x => x.PersonId);
builder.HasQueryFilter(x => !x.IsDeleted);
}
}

View File

@ -29,6 +29,12 @@ public class ClubConfiguration : IEntityTypeConfiguration<Club>
.HasMaxLength(256)
.IsRequired(false);
builder.Property(x => x.InitialBalance)
.HasPrecision(10, 2);
builder.Property(x => x.MonthlyMembershipFee)
.HasPrecision(10, 2);
builder.HasIndex(x => x.Name);
builder.HasIndex(x => x.LoginName);