Files
amrez-nova-eop-services-api/AMREZ.EOP.Infrastructures/Repositories/DocControlStatusRepository.cs
Thanakarn Klangkasame 1e636aa3d5 [Add] MasterData Services.
2025-11-26 10:29:56 +07:00

149 lines
5.4 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.Brand;
using AMREZ.EOP.Contracts.DTOs.MasterData.DocControlStatus;
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 DocControlStatusRepository : IDocControlStatusRepository
{
private readonly IDbScope _scope;
private readonly ITenantResolver _tenantResolver;
private readonly IHttpContextAccessor _http;
public DocControlStatusRepository(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<DocControlStatus?> GetAsync(Guid id, CancellationToken ct = default)
{
var tid = EnsureTenant(out var db);
return await db.DocControlStatuses.AsNoTracking()
.Where(x => x.Id == id && !x.IsDeleted)
.Where(x => x.Scope == "tenant" ? x.TenantId == tid : true)
.FirstOrDefaultAsync(ct);
}
public async Task<PagedResponse<DocControlStatus>> SearchEffectiveAsync(Guid tenantId, DocControlStatusListRequest req,
CancellationToken ct = default)
{
var tid = EnsureTenant(out var db);
var tenantQ = db.DocControlStatuses.AsNoTracking()
.Where(b => b.Scope == "tenant" && b.TenantId == tid && !b.IsDeleted);
var overriddenIds = db.DocControlStatuses
.Where(t => t.Scope == "tenant" && t.TenantId == tid && !t.IsDeleted && t.OverridesGlobalId != null)
.Select(t => t.OverridesGlobalId!.Value);
var blockedIds = db.DocControlStatusBlocks
.Where(b => b.TenantId == tid)
.Select(b => b.GlobalId);
var globalsQ = db.DocControlStatuses.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<DocControlStatus>(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.DocControlStatuses.AnyAsync(b =>
!b.IsDeleted &&
b.Code == norm &&
(b.Scope == "tenant" && b.TenantId == tid), ct);
}
public async Task AddAsync(DocControlStatus entity, CancellationToken ct = default)
{
EnsureTenant(out var db);
await db.DocControlStatuses.AddAsync(entity, ct);
await db.SaveChangesAsync(ct);
}
public async Task UpdateAsync(DocControlStatus entity, CancellationToken ct = default)
{
EnsureTenant(out var db);
db.DocControlStatuses.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.DocControlStatuses.FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted, ct);
if (b is null) return 0;
if (b.Scope == "global")
{
var exists = await db.DocControlStatusBlocks
.AnyAsync(x => x.TenantId == tid && x.GlobalId == id, ct);
if (exists) return 0;
var block = new DocControlStatusBlock
{
Id = Guid.NewGuid(),
TenantId = tid,
GlobalId = id
};
await db.DocControlStatusBlocks.AddAsync(block, ct);
return await db.SaveChangesAsync(ct);
}
if (b.TenantId != tid) return 0;
b.IsDeleted = true;
return await db.SaveChangesAsync(ct);
}
}