Refactor EntryService to allow shared DisplayId for transfers; update related tests and migration files
This commit is contained in:
169
src/Duempelkas.Infrastructure/Migrations/20260403093901_AllowSharedDisplayIdForTransfers.Designer.cs
generated
Normal file
169
src/Duempelkas.Infrastructure/Migrations/20260403093901_AllowSharedDisplayIdForTransfers.Designer.cs
generated
Normal file
@@ -0,0 +1,169 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Duempelkas.Infrastructure.Persistence;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Duempelkas.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(FinanceDbContext))]
|
||||
[Migration("20260403093901_AllowSharedDisplayIdForTransfers")]
|
||||
partial class AllowSharedDisplayIdForTransfers
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.5");
|
||||
|
||||
modelBuilder.Entity("Duempelkas.Domain.Entities.Account", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<decimal>("CarryoverBalance")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime>("CreatedUtc")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Accounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Duempelkas.Domain.Entities.Entry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AccountId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime>("CreatedUtc")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(false);
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("TransferLinkId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DisplayId");
|
||||
|
||||
b.HasIndex("TransferLinkId");
|
||||
|
||||
b.HasIndex("AccountId", "Date");
|
||||
|
||||
b.ToTable("Entries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Duempelkas.Domain.Entities.TransferLink", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreatedUtc")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Note")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SourceEntryId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("TargetEntryId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SourceEntryId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("TargetEntryId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("TransferLinks");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Duempelkas.Domain.Entities.Entry", b =>
|
||||
{
|
||||
b.HasOne("Duempelkas.Domain.Entities.Account", "Account")
|
||||
.WithMany("Entries")
|
||||
.HasForeignKey("AccountId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Duempelkas.Domain.Entities.TransferLink", "TransferLink")
|
||||
.WithMany()
|
||||
.HasForeignKey("TransferLinkId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.Navigation("Account");
|
||||
|
||||
b.Navigation("TransferLink");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Duempelkas.Domain.Entities.TransferLink", b =>
|
||||
{
|
||||
b.HasOne("Duempelkas.Domain.Entities.Entry", "SourceEntry")
|
||||
.WithMany()
|
||||
.HasForeignKey("SourceEntryId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Duempelkas.Domain.Entities.Entry", "TargetEntry")
|
||||
.WithMany()
|
||||
.HasForeignKey("TargetEntryId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SourceEntry");
|
||||
|
||||
b.Navigation("TargetEntry");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Duempelkas.Domain.Entities.Account", b =>
|
||||
{
|
||||
b.Navigation("Entries");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Duempelkas.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AllowSharedDisplayIdForTransfers : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Entries_DisplayId",
|
||||
table: "Entries");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Entries_DisplayId",
|
||||
table: "Entries",
|
||||
column: "DisplayId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Entries_DisplayId",
|
||||
table: "Entries");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Entries_DisplayId",
|
||||
table: "Entries",
|
||||
column: "DisplayId",
|
||||
unique: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,8 +80,7 @@ namespace Duempelkas.Infrastructure.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DisplayId")
|
||||
.IsUnique();
|
||||
b.HasIndex("DisplayId");
|
||||
|
||||
b.HasIndex("TransferLinkId");
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ public class EntryConfiguration : IEntityTypeConfiguration<Entry>
|
||||
{
|
||||
builder.HasKey(e => e.Id);
|
||||
builder.Property(e => e.DisplayId).IsRequired().HasMaxLength(20);
|
||||
builder.HasIndex(e => e.DisplayId).IsUnique();
|
||||
builder.HasIndex(e => e.DisplayId);
|
||||
builder.Property(e => e.Title).IsRequired().HasMaxLength(500);
|
||||
builder.Property(e => e.Amount).HasColumnType("decimal(18,2)");
|
||||
builder.Property(e => e.Type).HasConversion<int>();
|
||||
|
||||
@@ -63,7 +63,7 @@ public class EntryService : IEntryService
|
||||
{
|
||||
await using var db = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
var displayId = await GenerateDisplayIdAsync(db, accountId, date.Year);
|
||||
var displayId = await GenerateDisplayIdAsync(db, date.Year);
|
||||
|
||||
var entry = new Entry
|
||||
{
|
||||
@@ -88,12 +88,12 @@ public class EntryService : IEntryService
|
||||
await using var db = await _dbFactory.CreateDbContextAsync();
|
||||
await using var transaction = await db.Database.BeginTransactionAsync();
|
||||
|
||||
var sourceDisplayId = await GenerateDisplayIdAsync(db, sourceAccountId, date.Year);
|
||||
var transferDisplayId = await GenerateDisplayIdAsync(db, date.Year);
|
||||
|
||||
var sourceEntry = new Entry
|
||||
{
|
||||
AccountId = sourceAccountId,
|
||||
DisplayId = sourceDisplayId,
|
||||
DisplayId = transferDisplayId,
|
||||
Type = EntryType.Expense,
|
||||
Date = date,
|
||||
Title = title,
|
||||
@@ -103,12 +103,10 @@ public class EntryService : IEntryService
|
||||
db.Entries.Add(sourceEntry);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var targetDisplayId = await GenerateDisplayIdAsync(db, targetAccountId, date.Year);
|
||||
|
||||
var targetEntry = new Entry
|
||||
{
|
||||
AccountId = targetAccountId,
|
||||
DisplayId = targetDisplayId,
|
||||
DisplayId = transferDisplayId,
|
||||
Type = EntryType.Income,
|
||||
Date = date,
|
||||
Title = title,
|
||||
@@ -234,13 +232,12 @@ public class EntryService : IEntryService
|
||||
if (otherEntry.AccountId != newLinkedAccountId)
|
||||
{
|
||||
otherEntry.AccountId = newLinkedAccountId;
|
||||
otherEntry.DisplayId = await GenerateDisplayIdAsync(db, newLinkedAccountId, date.Year);
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private static async Task<string> GenerateDisplayIdAsync(FinanceDbContext db, int accountId, int year)
|
||||
private static async Task<string> GenerateDisplayIdAsync(FinanceDbContext db, int year)
|
||||
{
|
||||
var prefix = $"{year}-";
|
||||
var maxDisplayId = await db.Entries
|
||||
|
||||
Reference in New Issue
Block a user