148 lines
5.2 KiB
C#
148 lines
5.2 KiB
C#
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
|
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
|
using AMREZ.EOP.Abstractions.Storage;
|
|
using AMREZ.EOP.Contracts.DTOs.Common;
|
|
using AMREZ.EOP.Contracts.DTOs.MasterData.Country;
|
|
using AMREZ.EOP.Domain.Entities.MasterData;
|
|
using AMREZ.EOP.Infrastructures.Data;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace AMREZ.EOP.Infrastructures.Repositories;
|
|
|
|
public sealed class CountryRepository : ICountryRepository
|
|
{
|
|
private readonly IDbScope _scope;
|
|
private readonly ITenantResolver _tenantResolver;
|
|
private readonly IHttpContextAccessor _http;
|
|
|
|
public CountryRepository(IDbScope scope, ITenantResolver tenantResolver, IHttpContextAccessor http)
|
|
{
|
|
_scope = scope;
|
|
_tenantResolver = tenantResolver;
|
|
_http = http;
|
|
}
|
|
|
|
private Guid EnsureTenant(out AppDbContext db)
|
|
{
|
|
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
|
var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant");
|
|
_scope.EnsureForTenant(tc);
|
|
db = _scope.Get<AppDbContext>();
|
|
|
|
if (!string.IsNullOrWhiteSpace(tc.Id) && Guid.TryParse(tc.Id, out var g) && g != Guid.Empty)
|
|
return g;
|
|
|
|
var key = (http.Items.TryGetValue("TargetTenantKey", out var v) ? v as string : null) ?? tc.Id;
|
|
if (string.IsNullOrWhiteSpace(key)) throw new InvalidOperationException("Tenant key missing");
|
|
|
|
var cfg = db.Set<AMREZ.EOP.Domain.Entities.Tenancy.TenantConfig>()
|
|
.AsNoTracking()
|
|
.FirstOrDefault(x => x.TenantKey == key);
|
|
if (cfg is null) throw new InvalidOperationException($"Tenant '{key}' not found");
|
|
return cfg.TenantId;
|
|
}
|
|
|
|
public async Task<Country?> GetAsync(Guid id, CancellationToken ct = default)
|
|
{
|
|
var tid = EnsureTenant(out var db);
|
|
return await db.Countries.AsNoTracking()
|
|
.Where(x => x.Id == id && !x.IsDeleted)
|
|
.Where(x => x.Scope == "tenant" ? x.TenantId == tid : true)
|
|
.FirstOrDefaultAsync(ct);
|
|
}
|
|
|
|
public async Task<PagedResponse<Country>> SearchEffectiveAsync(Guid tenantId, CountryListRequest req,
|
|
CancellationToken ct = default)
|
|
{
|
|
var tid = EnsureTenant(out var db);
|
|
|
|
var tenantQ = db.Countries.AsNoTracking()
|
|
.Where(b => b.Scope == "tenant" && b.TenantId == tid && !b.IsDeleted);
|
|
|
|
var overriddenIds = db.Countries
|
|
.Where(t => t.Scope == "tenant" && t.TenantId == tid && !t.IsDeleted && t.OverridesGlobalId != null)
|
|
.Select(t => t.OverridesGlobalId!.Value);
|
|
|
|
var blockedIds = db.CountryBlocks
|
|
.Where(b => b.TenantId == tid)
|
|
.Select(b => b.GlobalId);
|
|
|
|
var globalsQ = db.Countries.AsNoTracking()
|
|
.Where(g => g.Scope == "global" && !g.IsDeleted)
|
|
.Where(g => !overriddenIds.Contains(g.Id) && !blockedIds.Contains(g.Id));
|
|
|
|
var q = tenantQ.Union(globalsQ);
|
|
|
|
if (!req.IncludeInactive) q = q.Where(x => x.IsActive);
|
|
|
|
if (!string.IsNullOrWhiteSpace(req.Search))
|
|
{
|
|
var s = req.Search.Trim();
|
|
q = q.Where(x => x.Code.Contains(s) || x.Name.Contains(s));
|
|
}
|
|
|
|
var total = await q.CountAsync(ct);
|
|
var items = await q
|
|
.OrderBy(x => x.Code)
|
|
.ThenBy(x => x.Name)
|
|
.Skip((req.Page - 1) * req.PageSize)
|
|
.Take(req.PageSize)
|
|
.ToListAsync(ct);
|
|
|
|
return new PagedResponse<Country>(req.Page, req.PageSize, total, items);
|
|
}
|
|
|
|
public async Task<bool> CodeExistsAsync(Guid tenantId, string code, CancellationToken ct = default)
|
|
{
|
|
var tid = EnsureTenant(out var db);
|
|
var norm = code.Trim();
|
|
return await db.Countries.AnyAsync(b =>
|
|
!b.IsDeleted &&
|
|
b.Code == norm &&
|
|
(b.Scope == "tenant" && b.TenantId == tid), ct);
|
|
}
|
|
|
|
public async Task AddAsync(Country entity, CancellationToken ct = default)
|
|
{
|
|
EnsureTenant(out var db);
|
|
await db.Countries.AddAsync(entity, ct);
|
|
await db.SaveChangesAsync(ct);
|
|
}
|
|
|
|
public async Task UpdateAsync(Country entity, CancellationToken ct = default)
|
|
{
|
|
EnsureTenant(out var db);
|
|
db.Countries.Update(entity);
|
|
await db.SaveChangesAsync(ct);
|
|
}
|
|
|
|
public async Task<int> SoftDeleteAsync(Guid id, Guid tenantId, CancellationToken ct = default)
|
|
{
|
|
var tid = EnsureTenant(out var db);
|
|
|
|
var b = await db.Countries.FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted, ct);
|
|
if (b is null) return 0;
|
|
|
|
if (b.Scope == "global")
|
|
{
|
|
var exists = await db.CountryBlocks
|
|
.AnyAsync(x => x.TenantId == tid && x.GlobalId == id, ct);
|
|
if (exists) return 0;
|
|
|
|
var block = new CountryBlock
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
TenantId = tid,
|
|
GlobalId = id
|
|
};
|
|
await db.CountryBlocks.AddAsync(block, ct);
|
|
return await db.SaveChangesAsync(ct);
|
|
}
|
|
|
|
if (b.TenantId != tid) return 0;
|
|
|
|
b.IsDeleted = true;
|
|
return await db.SaveChangesAsync(ct);
|
|
}
|
|
} |