line-gestao-api/Data/AppDbContext.cs

213 lines
7.5 KiB
C#

using line_gestao_api.Models;
using line_gestao_api.Services;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace line_gestao_api.Data;
public class AppDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
{
private readonly ITenantProvider _tenantProvider;
public AppDbContext(DbContextOptions<AppDbContext> options, ITenantProvider tenantProvider) : base(options)
{
_tenantProvider = tenantProvider;
}
public DbSet<Tenant> Tenants => Set<Tenant>();
// ✅ tabela para espelhar a planilha (GERAL)
public DbSet<MobileLine> MobileLines => Set<MobileLine>();
// ✅ tabela para espelhar a aba MUREG
public DbSet<MuregLine> MuregLines => Set<MuregLine>();
// ✅ tabela para espelhar o FATURAMENTO (PF/PJ)
public DbSet<BillingClient> BillingClients => Set<BillingClient>();
// ✅ tabela DADOS DOS USUÁRIOS
public DbSet<UserData> UserDatas => Set<UserData>();
// ✅ tabela VIGÊNCIA
public DbSet<VigenciaLine> VigenciaLines => Set<VigenciaLine>();
// ✅ tabela TROCA DE NÚMERO
public DbSet<TrocaNumeroLine> TrocaNumeroLines => Set<TrocaNumeroLine>();
// ✅ tabela NOTIFICAÇÕES
public DbSet<Notification> Notifications => Set<Notification>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// =========================
// ✅ USER (Identity)
// =========================
modelBuilder.Entity<ApplicationUser>(e =>
{
e.Property(x => x.Name).HasMaxLength(120);
e.HasIndex(x => new { x.TenantId, x.NormalizedEmail })
.IsUnique();
});
// =========================
// ✅ GERAL (MobileLine)
// =========================
modelBuilder.Entity<MobileLine>(e =>
{
// Mantém UNIQUE por Linha por tenant (se Linha puder ser null no banco, Postgres aceita múltiplos nulls)
e.HasIndex(x => new { x.TenantId, x.Linha }).IsUnique();
// performance
e.HasIndex(x => x.Chip);
e.HasIndex(x => x.Cliente);
e.HasIndex(x => x.Usuario);
e.HasIndex(x => x.Skil);
e.HasIndex(x => x.Status);
});
// =========================
// ✅ MUREG (FK para MobileLines)
// =========================
modelBuilder.Entity<MuregLine>(e =>
{
e.HasIndex(x => x.Item);
e.HasIndex(x => x.ICCID);
e.HasIndex(x => x.LinhaAntiga);
e.HasIndex(x => x.LinhaNova);
e.HasIndex(x => x.TenantId);
// FK + index
e.HasIndex(x => x.MobileLineId);
e.HasOne(x => x.MobileLine)
.WithMany(m => m.Muregs)
.HasForeignKey(x => x.MobileLineId)
.OnDelete(DeleteBehavior.Restrict);
});
// =========================
// ✅ FATURAMENTO (BillingClient)
// =========================
modelBuilder.Entity<BillingClient>(e =>
{
// ⚠️ só mantenha se seu banco realmente usa esse nome
e.ToTable("billing_clients");
e.HasKey(x => x.Id);
e.Property(x => x.Tipo).HasMaxLength(2);
e.Property(x => x.Cliente).HasMaxLength(255);
e.HasIndex(x => x.Tipo);
e.HasIndex(x => x.Cliente);
e.HasIndex(x => new { x.Tipo, x.Cliente });
e.HasIndex(x => x.Item);
e.HasIndex(x => x.TenantId);
});
// =========================
// ✅ DADOS DOS USUÁRIOS (UserData)
// ✅ (SEM "Nome" pq não existe no model)
// =========================
modelBuilder.Entity<UserData>(e =>
{
e.HasIndex(x => x.Item);
e.HasIndex(x => x.Cliente);
e.HasIndex(x => x.Linha);
e.HasIndex(x => x.Cpf);
e.HasIndex(x => x.Email);
e.HasIndex(x => x.TenantId);
});
// =========================
// ✅ VIGÊNCIA
// =========================
modelBuilder.Entity<VigenciaLine>(e =>
{
e.HasIndex(x => x.Item);
e.HasIndex(x => x.Cliente);
e.HasIndex(x => x.Linha);
e.HasIndex(x => x.DtTerminoFidelizacao);
e.HasIndex(x => x.TenantId);
});
// =========================
// ✅ TROCA NÚMERO
// =========================
modelBuilder.Entity<TrocaNumeroLine>(e =>
{
e.HasIndex(x => x.Item);
e.HasIndex(x => x.LinhaAntiga);
e.HasIndex(x => x.LinhaNova);
e.HasIndex(x => x.ICCID);
e.HasIndex(x => x.DataTroca);
e.HasIndex(x => x.TenantId);
});
// =========================
// ✅ NOTIFICAÇÕES
// =========================
modelBuilder.Entity<Notification>(e =>
{
e.HasIndex(x => x.DedupKey).IsUnique();
e.HasIndex(x => x.UserId);
e.HasIndex(x => x.Cliente);
e.HasIndex(x => x.Lida);
e.HasIndex(x => x.Data);
e.HasIndex(x => x.VigenciaLineId);
e.HasIndex(x => x.TenantId);
e.HasOne(x => x.User)
.WithMany()
.HasForeignKey(x => x.UserId)
.OnDelete(DeleteBehavior.Restrict);
e.HasOne(x => x.VigenciaLine)
.WithMany()
.HasForeignKey(x => x.VigenciaLineId)
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity<MobileLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
modelBuilder.Entity<MuregLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
modelBuilder.Entity<BillingClient>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
modelBuilder.Entity<UserData>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
modelBuilder.Entity<VigenciaLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
modelBuilder.Entity<TrocaNumeroLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
modelBuilder.Entity<Notification>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
modelBuilder.Entity<ApplicationUser>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
}
public override int SaveChanges()
{
ApplyTenantIds();
return base.SaveChanges();
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
ApplyTenantIds();
return base.SaveChangesAsync(cancellationToken);
}
private void ApplyTenantIds()
{
if (_tenantProvider.TenantId == null)
{
return;
}
var tenantId = _tenantProvider.TenantId.Value;
foreach (var entry in ChangeTracker.Entries<ITenantEntity>().Where(e => e.State == EntityState.Added))
{
if (entry.Entity.TenantId == Guid.Empty)
{
entry.Entity.TenantId = tenantId;
}
}
}
}