Files
tiku-backend.net/Tiku.Infrastructure/Persistence/Configurations/PointConfigurations.cs
2026-07-26 19:53:45 +08:00

113 lines
5.9 KiB
C#

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Tiku.Domain.Catalog;
using Tiku.Domain.Commerce;
using Tiku.Domain.Identity;
namespace Tiku.Infrastructure.Persistence.Configurations;
internal sealed class PointActivityTaskConfiguration : IEntityTypeConfiguration<PointActivityTask>
{
public void Configure(EntityTypeBuilder<PointActivityTask> builder)
{
builder.ConfigureTenantEntity("point_activity_tasks");
builder.ConfigureTimestamps();
builder.Property(entity => entity.TaskKey).HasColumnType("citext").HasMaxLength(100);
builder.Property(entity => entity.Title).HasMaxLength(200);
builder.Property(entity => entity.Description).HasMaxLength(1000);
builder.Property(entity => entity.TaskType).HasSnakeCaseEnum();
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.Property(entity => entity.Rules).IsJson("{}");
builder.Property(entity => entity.Metadata).IsJson("{}");
builder.HasIndex(entity => new { entity.TenantId, entity.TaskKey }).IsUnique();
builder.HasIndex(entity => new { entity.TenantId, entity.Status, entity.SortOrder });
builder.ToTable(table =>
{
table.HasCheckConstraint("ck_point_activity_tasks_points", "points > 0");
table.HasCheckConstraint("ck_point_activity_tasks_max_claims", "max_claims_per_user > 0");
});
}
}
internal sealed class PointActivityClaimConfiguration : IEntityTypeConfiguration<PointActivityClaim>
{
public void Configure(EntityTypeBuilder<PointActivityClaim> builder)
{
builder.ConfigureTenantEntity("point_activity_claims");
builder.ConfigureTimestamps();
builder.Property(entity => entity.TaskKey).HasColumnType("citext").HasMaxLength(100);
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.Property(entity => entity.SourceType).HasMaxLength(100);
builder.Property(entity => entity.Metadata).IsJson("{}");
builder.Property(entity => entity.ClaimedAt).HasDefaultValueSql("now()");
builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.TaskId, entity.SourceType, entity.SourceId })
.IsUnique()
.HasFilter("source_type is not null and source_id is not null");
builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.CreatedAt });
builder.HasOne<PointActivityTask>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, entity.TaskId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UserId).OnDelete(DeleteBehavior.Cascade);
builder.ToTable(table =>
{
table.HasCheckConstraint("ck_point_activity_claims_points", "points > 0");
});
}
}
internal sealed class PointExchangeItemConfiguration : IEntityTypeConfiguration<PointExchangeItem>
{
public void Configure(EntityTypeBuilder<PointExchangeItem> builder)
{
builder.ConfigureTenantEntity("point_exchange_items");
builder.ConfigureTimestamps();
builder.Property(entity => entity.ItemKey).HasColumnType("citext").HasMaxLength(100);
builder.Property(entity => entity.Name).HasMaxLength(200);
builder.Property(entity => entity.Description).HasMaxLength(1000);
builder.Property(entity => entity.ItemType).HasSnakeCaseEnum();
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.Property(entity => entity.FulfillmentPayload).IsJson("{}");
builder.Property(entity => entity.Metadata).IsJson("{}");
builder.HasIndex(entity => new { entity.TenantId, entity.ItemKey }).IsUnique();
builder.HasIndex(entity => new { entity.TenantId, entity.RegionId, entity.Status, entity.SortOrder });
builder.HasOne<Region>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, entity.RegionId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.ToTable(table =>
{
table.HasCheckConstraint("ck_point_exchange_items_points_cost", "points_cost > 0");
table.HasCheckConstraint("ck_point_exchange_items_stock", "stock is null or stock >= 0");
table.HasCheckConstraint("ck_point_exchange_items_days", "days is null or days >= 0");
});
}
}
internal sealed class PointExchangeOrderConfiguration : IEntityTypeConfiguration<PointExchangeOrder>
{
public void Configure(EntityTypeBuilder<PointExchangeOrder> builder)
{
builder.ConfigureTenantEntity("point_exchange_orders");
builder.ConfigureTimestamps();
builder.Property(entity => entity.OrderNo).HasMaxLength(100);
builder.Property(entity => entity.ItemName).HasMaxLength(200);
builder.Property(entity => entity.ItemType).HasSnakeCaseEnum();
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.Property(entity => entity.FulfillmentSnapshot).IsJson("{}");
builder.Property(entity => entity.Metadata).IsJson("{}");
builder.Property(entity => entity.OrderedAt).HasDefaultValueSql("now()");
builder.HasIndex(entity => new { entity.TenantId, entity.OrderNo }).IsUnique();
builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.CreatedAt });
builder.HasOne<PointExchangeItem>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, entity.ItemId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UserId).OnDelete(DeleteBehavior.Cascade);
builder.ToTable(table =>
{
table.HasCheckConstraint("ck_point_exchange_orders_points_cost", "points_cost > 0");
});
}
}