[Add] MasterData Services.
This commit is contained in:
@@ -11,13 +11,11 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ClosedXML" Version="0.105.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.119.1" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="3.119.1" />
|
||||
<PackageReference Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.21" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -31,72 +31,71 @@ public sealed class IssueTokenPairUseCase : IIssueTokenPairUseCase
|
||||
_http = http;
|
||||
}
|
||||
|
||||
public async Task<IssueTokenPairResponse> ExecuteAsync(IssueTokenPairRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
|
||||
var tenantId = request.TenantId;
|
||||
|
||||
// ---- สร้าง/บันทึก refresh session ----
|
||||
var refreshRaw = Convert.ToBase64String(RandomNumberGenerator.GetBytes(64));
|
||||
var refreshHash = Sha256(refreshRaw);
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
var session = await _users.CreateSessionAsync(new UserSession
|
||||
public async Task<IssueTokenPairResponse> ExecuteAsync(IssueTokenPairRequest request,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
UserId = request.UserId,
|
||||
RefreshTokenHash = refreshHash,
|
||||
IssuedAt = now,
|
||||
ExpiresAt = now.AddDays(RefreshDays),
|
||||
DeviceId = http.Request.Headers["X-Device-Id"].FirstOrDefault(),
|
||||
UserAgent = http.Request.Headers["User-Agent"].FirstOrDefault(),
|
||||
IpAddress = http.Connection.RemoteIpAddress?.ToString()
|
||||
}, ct);
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
|
||||
// ---- เวอร์ชัน/สแตมป์ความปลอดภัย ----
|
||||
var tv = await _users.GetTenantTokenVersionAsync(tenantId, ct);
|
||||
var sstamp = await _users.GetUserSecurityStampAsync(request.UserId, ct) ?? string.Empty;
|
||||
var tenantId = request.TenantId;
|
||||
|
||||
// ---- เตรียม claims พื้นฐาน ----
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new("sub", request.UserId.ToString()),
|
||||
new("email", request.Email),
|
||||
new("tenant", request.Tenant), // tenantKey ที่ FE ใช้
|
||||
new("tenant_id", tenantId.ToString()),
|
||||
new("sid", session.Id.ToString()),
|
||||
new("jti", Guid.NewGuid().ToString("N")),
|
||||
new("tv", tv),
|
||||
new("sstamp", sstamp),
|
||||
new("iat", now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
|
||||
};
|
||||
// ---- สร้าง/บันทึก refresh session ----
|
||||
var refreshRaw = Convert.ToBase64String(RandomNumberGenerator.GetBytes(64));
|
||||
var refreshHash = Sha256(refreshRaw);
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
string[] roles = request.Roles ?? Array.Empty<string>();
|
||||
if (roles.Length == 0)
|
||||
{
|
||||
roles = await _users.GetRoleCodesByUserIdAsync(request.UserId, tenantId, ct);
|
||||
var session = await _users.CreateSessionAsync(new UserSession
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
UserId = request.UserId,
|
||||
RefreshTokenHash = refreshHash,
|
||||
IssuedAt = now,
|
||||
ExpiresAt = now.AddDays(RefreshDays),
|
||||
DeviceId = http.Request.Headers["X-Device-Id"].FirstOrDefault(),
|
||||
UserAgent = http.Request.Headers["User-Agent"].FirstOrDefault(),
|
||||
IpAddress = http.Connection.RemoteIpAddress?.ToString()
|
||||
}, ct);
|
||||
|
||||
var tv = await _users.GetTenantTokenVersionAsync(tenantId, ct);
|
||||
var sstamp = await _users.GetUserSecurityStampAsync(request.UserId, ct) ?? string.Empty;
|
||||
|
||||
// ---- เตรียม claims พื้นฐาน ----
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new("sub", request.UserId.ToString()),
|
||||
new("email", request.Email),
|
||||
new("tenant", request.Tenant), // tenantKey ที่ FE ใช้
|
||||
new("tenant_id", tenantId.ToString()),
|
||||
new("sid", session.Id.ToString()),
|
||||
new("jti", Guid.NewGuid().ToString("N")),
|
||||
new("tv", tv),
|
||||
new("sstamp", sstamp),
|
||||
new("iat", now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
|
||||
};
|
||||
|
||||
string[] roles = request.Roles ?? Array.Empty<string>();
|
||||
if (roles.Length == 0)
|
||||
{
|
||||
roles = await _users.GetRoleCodesByUserIdAsync(request.UserId, tenantId, ct);
|
||||
}
|
||||
|
||||
foreach (var r in roles.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct(StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
claims.Add(new Claim("role", r));
|
||||
claims.Add(new Claim(ClaimTypes.Role, r));
|
||||
}
|
||||
|
||||
var (access, accessExp) = _jwt.CreateAccessToken(claims);
|
||||
|
||||
return new IssueTokenPairResponse
|
||||
{
|
||||
AccessToken = access,
|
||||
AccessExpiresAt = accessExp,
|
||||
RefreshToken = refreshRaw,
|
||||
RefreshExpiresAt = session.ExpiresAt
|
||||
};
|
||||
}
|
||||
|
||||
foreach (var r in roles.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct(StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
claims.Add(new Claim("role", r));
|
||||
claims.Add(new Claim(ClaimTypes.Role, r));
|
||||
}
|
||||
|
||||
// ---- ออก access token ----
|
||||
var (access, accessExp) = _jwt.CreateAccessToken(claims);
|
||||
|
||||
return new IssueTokenPairResponse
|
||||
{
|
||||
AccessToken = access,
|
||||
AccessExpiresAt = accessExp,
|
||||
RefreshToken = refreshRaw,
|
||||
RefreshExpiresAt = session.ExpiresAt
|
||||
};
|
||||
}
|
||||
|
||||
private static string Sha256(string raw)
|
||||
{
|
||||
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(raw));
|
||||
|
||||
@@ -0,0 +1,413 @@
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.ImportData.Location;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Common;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.ImportData.Location;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.District;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Province;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Subdistrict;
|
||||
using AMREZ.EOP.Domain.Entities.MasterData;
|
||||
using AMREZ.EOP.Domain.Entities.Tenancy;
|
||||
using ClosedXML.Excel;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.ImportData.Location;
|
||||
|
||||
public sealed class LocationImportUseCase : ILocationImportUseCase
|
||||
{
|
||||
private readonly IProvinceRepository _provinceRepo;
|
||||
private readonly IDistrictRepository _districtRepo;
|
||||
private readonly ISubdistrictRepository _subdistrictRepo;
|
||||
private readonly ITenantRepository _tenants;
|
||||
private readonly ITenantResolver _tenantResolver;
|
||||
private readonly IHttpContextAccessor _http;
|
||||
private readonly IUnitOfWork _uow;
|
||||
|
||||
public LocationImportUseCase(
|
||||
IProvinceRepository provinceRepo,
|
||||
IDistrictRepository districtRepo,
|
||||
ISubdistrictRepository subdistrictRepo,
|
||||
ITenantRepository tenants,
|
||||
ITenantResolver tenantResolver,
|
||||
IHttpContextAccessor http,
|
||||
IUnitOfWork uow)
|
||||
{
|
||||
_provinceRepo = provinceRepo;
|
||||
_districtRepo = districtRepo;
|
||||
_subdistrictRepo = subdistrictRepo;
|
||||
_tenants = tenants;
|
||||
_tenantResolver = tenantResolver;
|
||||
_http = http;
|
||||
_uow = uow;
|
||||
}
|
||||
|
||||
public async Task<LocationImportResultDto> ExecuteAsync(IFormFile file, CancellationToken ct = default)
|
||||
{
|
||||
if (file == null || file.Length == 0)
|
||||
throw new InvalidOperationException("Excel file is required");
|
||||
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant");
|
||||
|
||||
var tn = await _tenants.GetAsync(tc.Id) ?? throw new InvalidOperationException("Tenant config not found");
|
||||
var tenantId = tn.TenantId;
|
||||
|
||||
var result = new LocationImportResultDto();
|
||||
|
||||
await _uow.BeginAsync(tc, IsolationLevel.ReadCommitted, ct);
|
||||
try
|
||||
{
|
||||
var provincesByCode = await LoadGlobalProvincesAsync(tenantId, ct);
|
||||
var districtsByCode = await LoadGlobalDistrictsAsync(tenantId, ct);
|
||||
var subdistrictsByCode = await LoadGlobalSubdistrictsAsync(tenantId, ct);
|
||||
|
||||
using var stream = new MemoryStream();
|
||||
await file.CopyToAsync(stream, ct);
|
||||
stream.Position = 0;
|
||||
|
||||
using var wb = new XLWorkbook(stream);
|
||||
var ws = wb.Worksheets.First();
|
||||
var lastRow = ws.LastRowUsed().RowNumber();
|
||||
|
||||
// row 1 = header
|
||||
for (var row = 2; row <= lastRow; row++)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
result.RowsRead++;
|
||||
|
||||
string Get(int col)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ws.Cell(row, col).GetString().Trim();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
// 1: CC, 2: AA, 3: TT, 4: CCAATT, 5: จังหวัด, 6: อำเภอ, 7: ตำบล, 8: รหัสไปรษณีย์
|
||||
var cc = Get(1);
|
||||
var aa = Get(2);
|
||||
var tt = Get(3);
|
||||
var locCode = Get(4);
|
||||
|
||||
var provinceName = Get(5);
|
||||
var districtName = Get(6);
|
||||
var subdistrictName = Get(7);
|
||||
var postcode = Get(8);
|
||||
|
||||
string? code = null;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(cc) &&
|
||||
!string.IsNullOrWhiteSpace(aa) &&
|
||||
!string.IsNullOrWhiteSpace(tt))
|
||||
{
|
||||
code =
|
||||
cc.PadLeft(2, '0') +
|
||||
aa.PadLeft(2, '0') +
|
||||
tt.PadLeft(2, '0');
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(locCode))
|
||||
{
|
||||
code = locCode;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
continue;
|
||||
|
||||
code = code.Trim();
|
||||
if (code.Length < 6)
|
||||
code = code.PadLeft(6, '0');
|
||||
else if (code.Length > 6)
|
||||
code = code[..6];
|
||||
|
||||
var isProvince = code.EndsWith("0000", StringComparison.Ordinal);
|
||||
var isDistrict = !isProvince && code.EndsWith("00", StringComparison.Ordinal);
|
||||
var isSubdistrict = !isProvince && !isDistrict;
|
||||
|
||||
if (isProvince)
|
||||
{
|
||||
await ImportProvinceAsync(code, provinceName, provincesByCode, tenantId, result, ct);
|
||||
}
|
||||
else if (isDistrict)
|
||||
{
|
||||
await ImportDistrictAsync(
|
||||
code,
|
||||
provinceName,
|
||||
districtName,
|
||||
provincesByCode,
|
||||
districtsByCode,
|
||||
tenantId,
|
||||
result,
|
||||
ct);
|
||||
}
|
||||
else if (isSubdistrict)
|
||||
{
|
||||
await ImportSubdistrictAsync(
|
||||
code,
|
||||
provinceName,
|
||||
districtName,
|
||||
subdistrictName,
|
||||
postcode,
|
||||
provincesByCode,
|
||||
districtsByCode,
|
||||
subdistrictsByCode,
|
||||
tenantId,
|
||||
result,
|
||||
ct);
|
||||
}
|
||||
}
|
||||
|
||||
await _uow.CommitAsync(ct);
|
||||
return result;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== preload helpers ==========
|
||||
|
||||
private async Task<Dictionary<string, Province>> LoadGlobalProvincesAsync(Guid tenantId, CancellationToken ct)
|
||||
{
|
||||
var req = new ProvinceListRequest
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 500,
|
||||
IncludeInactive = true,
|
||||
Search = null
|
||||
};
|
||||
|
||||
var page = await _provinceRepo.SearchEffectiveAsync(tenantId, req, ct);
|
||||
|
||||
return page.Items
|
||||
.Where(x => x.Scope == "global" && !string.IsNullOrWhiteSpace(x.Code))
|
||||
.GroupBy(x => x.Code!)
|
||||
.ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, District>> LoadGlobalDistrictsAsync(Guid tenantId, CancellationToken ct)
|
||||
{
|
||||
var req = new DistrictListRequest
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 5000,
|
||||
IncludeInactive = true,
|
||||
Search = null
|
||||
};
|
||||
|
||||
var page = await _districtRepo.SearchEffectiveAsync(tenantId, req, ct);
|
||||
|
||||
return page.Items
|
||||
.Where(x => x.Scope == "global" && !string.IsNullOrWhiteSpace(x.Code))
|
||||
.GroupBy(x => x.Code!)
|
||||
.ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, Subdistrict>> LoadGlobalSubdistrictsAsync(Guid tenantId, CancellationToken ct)
|
||||
{
|
||||
var req = new SubdistrictListRequest
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 10000,
|
||||
IncludeInactive = true,
|
||||
Search = null
|
||||
};
|
||||
|
||||
var page = await _subdistrictRepo.SearchEffectiveAsync(tenantId, req, ct);
|
||||
|
||||
return page.Items
|
||||
.Where(x => x.Scope == "global" && !string.IsNullOrWhiteSpace(x.Code))
|
||||
.GroupBy(x => x.Code!)
|
||||
.ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
// ========== import helpers ==========
|
||||
|
||||
private async Task ImportProvinceAsync(
|
||||
string ccaatt,
|
||||
string? provinceName,
|
||||
Dictionary<string, Province> provincesByCode,
|
||||
Guid tenantId,
|
||||
LocationImportResultDto result,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var provCode = ccaatt[..2];
|
||||
|
||||
if (!provincesByCode.TryGetValue(provCode, out var prov))
|
||||
{
|
||||
prov = new Province
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
Scope = "global",
|
||||
Code = provCode,
|
||||
Name = string.IsNullOrWhiteSpace(provinceName) ? provCode : provinceName,
|
||||
IsActive = true,
|
||||
IsSystem = true
|
||||
};
|
||||
|
||||
await _provinceRepo.AddAsync(prov, ct);
|
||||
provincesByCode[provCode] = prov;
|
||||
result.ProvincesCreated++;
|
||||
return;
|
||||
}
|
||||
|
||||
var updated = false;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(provinceName) && prov.Name != provinceName)
|
||||
{
|
||||
prov.Name = provinceName;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
await _provinceRepo.UpdateAsync(prov, ct);
|
||||
result.ProvincesUpdated++;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ImportDistrictAsync(
|
||||
string ccaatt,
|
||||
string? provinceName,
|
||||
string? districtName,
|
||||
Dictionary<string, Province> provincesByCode,
|
||||
Dictionary<string, District> districtsByCode,
|
||||
Guid tenantId,
|
||||
LocationImportResultDto result,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var provCode = ccaatt[..2];
|
||||
var distCode = ccaatt[..4];
|
||||
|
||||
if (!provincesByCode.TryGetValue(provCode, out var prov))
|
||||
{
|
||||
await ImportProvinceAsync(provCode + "0000", provinceName, provincesByCode, tenantId, result, ct);
|
||||
prov = provincesByCode[provCode];
|
||||
}
|
||||
|
||||
if (!districtsByCode.TryGetValue(distCode, out var dist))
|
||||
{
|
||||
dist = new District
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
Scope = "global",
|
||||
Code = distCode,
|
||||
Name = string.IsNullOrWhiteSpace(districtName) ? distCode : districtName,
|
||||
ProvinceId = prov.Id,
|
||||
IsActive = true,
|
||||
IsSystem = true
|
||||
};
|
||||
|
||||
await _districtRepo.AddAsync(dist, ct);
|
||||
districtsByCode[distCode] = dist;
|
||||
result.DistrictsCreated++;
|
||||
return;
|
||||
}
|
||||
|
||||
var updated = false;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(districtName) && dist.Name != districtName)
|
||||
{
|
||||
dist.Name = districtName;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (dist.ProvinceId != prov.Id)
|
||||
{
|
||||
dist.ProvinceId = prov.Id;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
await _districtRepo.UpdateAsync(dist, ct);
|
||||
result.DistrictsUpdated++;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ImportSubdistrictAsync(
|
||||
string ccaatt,
|
||||
string? provinceName,
|
||||
string? districtName,
|
||||
string? subdistrictName,
|
||||
string? postcode,
|
||||
Dictionary<string, Province> provincesByCode,
|
||||
Dictionary<string, District> districtsByCode,
|
||||
Dictionary<string, Subdistrict> subdistrictsByCode,
|
||||
Guid tenantId,
|
||||
LocationImportResultDto result,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var provCode = ccaatt[..2];
|
||||
var distCode = ccaatt[..4];
|
||||
var subCode = ccaatt[..6];
|
||||
|
||||
if (!provincesByCode.TryGetValue(provCode, out var prov))
|
||||
{
|
||||
await ImportProvinceAsync(provCode + "0000", provinceName, provincesByCode, tenantId, result, ct);
|
||||
prov = provincesByCode[provCode];
|
||||
}
|
||||
|
||||
if (!districtsByCode.TryGetValue(distCode, out var dist))
|
||||
{
|
||||
await ImportDistrictAsync(distCode + "00", provinceName, districtName, provincesByCode, districtsByCode, tenantId, result, ct);
|
||||
dist = districtsByCode[distCode];
|
||||
}
|
||||
|
||||
if (!subdistrictsByCode.TryGetValue(subCode, out var sub))
|
||||
{
|
||||
sub = new Subdistrict
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
Scope = "global",
|
||||
Code = subCode,
|
||||
Name = string.IsNullOrWhiteSpace(subdistrictName) ? subCode : subdistrictName,
|
||||
DistrictId = dist.Id,
|
||||
Postcode = string.IsNullOrWhiteSpace(postcode) ? null : postcode,
|
||||
IsActive = true,
|
||||
IsSystem = true
|
||||
};
|
||||
|
||||
await _subdistrictRepo.AddAsync(sub, ct);
|
||||
subdistrictsByCode[subCode] = sub;
|
||||
result.SubdistrictsCreated++;
|
||||
return;
|
||||
}
|
||||
|
||||
var updated = false;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(subdistrictName) && sub.Name != subdistrictName)
|
||||
{
|
||||
sub.Name = subdistrictName;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (sub.DistrictId != dist.Id)
|
||||
{
|
||||
sub.DistrictId = dist.Id;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(postcode) && sub.Postcode != postcode)
|
||||
{
|
||||
sub.Postcode = postcode;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
await _subdistrictRepo.UpdateAsync(sub, ct);
|
||||
result.SubdistrictsUpdated++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Data;
|
||||
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Allergen;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Common;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Allergen;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Allergen;
|
||||
|
||||
public sealed class CreateAllergenUseCase : ICreateAllergenUseCase
|
||||
{
|
||||
private readonly IAllergenRepository _repo;
|
||||
private readonly IUnitOfWork _uow;
|
||||
private readonly ITenantResolver _tenantResolver;
|
||||
private readonly IHttpContextAccessor _http;
|
||||
|
||||
public CreateAllergenUseCase(IAllergenRepository repo, IUnitOfWork uow, ITenantResolver tr, IHttpContextAccessor http)
|
||||
{
|
||||
_repo = repo; _uow = uow; _tenantResolver = tr; _http = http;
|
||||
}
|
||||
|
||||
public async Task<AllergenResponse> ExecuteAsync(AllergenCreateRequest req, CancellationToken ct = default)
|
||||
{
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant");
|
||||
|
||||
await _uow.BeginAsync(tc, IsolationLevel.ReadCommitted, ct);
|
||||
try
|
||||
{
|
||||
var tid = Guid.Parse(tc.Id);
|
||||
|
||||
if (req.Scope == "tenant" && await _repo.CodeExistsAsync(tid, req.Code, ct))
|
||||
throw new InvalidOperationException($"Brand code '{req.Code}' already exists.");
|
||||
|
||||
var entity = new Domain.Entities.MasterData.Allergen()
|
||||
{
|
||||
TenantId = tid,
|
||||
Scope = string.IsNullOrWhiteSpace(req.Scope) ? "tenant" : req.Scope,
|
||||
Code = req.Code.Trim(),
|
||||
Name = req.Name.Trim(),
|
||||
NameI18n = req.NameI18n,
|
||||
Meta = req.Meta,
|
||||
IsActive = req.IsActive,
|
||||
IsSystem = false,
|
||||
OverridesGlobalId = req.OverridesGlobalId
|
||||
};
|
||||
|
||||
await _repo.AddAsync(entity, ct);
|
||||
await _uow.CommitAsync(ct);
|
||||
|
||||
return new AllergenResponse(entity.Id, entity.Scope, entity.Code, entity.Name, entity.NameI18n, entity.OverridesGlobalId, entity.IsActive, entity.IsSystem, entity.Meta);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Allergen;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Allergen;
|
||||
|
||||
public class DeleteAllergenUseCase : IDeleteAllergenUseCase
|
||||
{
|
||||
private readonly IAllergenRepository _repo;
|
||||
private readonly ITenantResolver _tenantResolver;
|
||||
private readonly IHttpContextAccessor _http;
|
||||
|
||||
public DeleteAllergenUseCase(IAllergenRepository repo, ITenantResolver tr, IHttpContextAccessor http)
|
||||
{
|
||||
_repo = repo;
|
||||
_tenantResolver = tr;
|
||||
_http = http;
|
||||
}
|
||||
|
||||
public async Task<bool> ExecuteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant");
|
||||
var tid = Guid.Parse(tc.Id);
|
||||
|
||||
var n = await _repo.SoftDeleteAsync(id, tid, ct);
|
||||
return n > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Allergen;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Allergen;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Allergen;
|
||||
|
||||
public class GetAllergenUseCase : IGetAllergenUseCase
|
||||
{
|
||||
private readonly IAllergenRepository _repo;
|
||||
public GetAllergenUseCase(IAllergenRepository repo) => _repo = repo;
|
||||
|
||||
public async Task<AllergenResponse?> ExecuteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var e = await _repo.GetAsync(id, ct);
|
||||
return e is null ? null : new AllergenResponse(e.Id, e.Scope, e.Code, e.Name, e.NameI18n, e.OverridesGlobalId, e.IsActive, e.IsSystem, e.Meta);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Allergen;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.Common;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Allergen;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Allergen;
|
||||
|
||||
public class ListAllergenUseCase : IListAllergenUseCase
|
||||
{
|
||||
private readonly IAllergenRepository _repo;
|
||||
private readonly ITenantResolver _tenantResolver;
|
||||
private readonly IHttpContextAccessor _http;
|
||||
|
||||
public ListAllergenUseCase(IAllergenRepository repo, ITenantResolver tenantResolver, IHttpContextAccessor http)
|
||||
{
|
||||
_repo = repo;
|
||||
_tenantResolver = tenantResolver;
|
||||
_http = http;
|
||||
}
|
||||
|
||||
public async Task<PagedResponse<AllergenResponse>> ExecuteAsync(AllergenListRequest req, CancellationToken ct = default)
|
||||
{
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant");
|
||||
var tid = Guid.Parse(tc.Id);
|
||||
|
||||
var page = await _repo.SearchEffectiveAsync(tid, req, ct);
|
||||
var items = page.Items.Select(Map).ToList();
|
||||
return new PagedResponse<AllergenResponse>(page.Page, page.PageSize, page.Total, items);
|
||||
}
|
||||
|
||||
private static AllergenResponse Map(Domain.Entities.MasterData.Allergen e) =>
|
||||
new(e.Id, e.Scope, e.Code, e.Name, e.NameI18n, e.OverridesGlobalId, e.IsActive, e.IsSystem, e.Meta);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Data;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Allergen;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Common;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Allergen;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Allergen;
|
||||
|
||||
public class UpdateAllergenUseCase : IUpdateAllergenUseCase
|
||||
{
|
||||
private readonly IAllergenRepository _repo;
|
||||
private readonly IUnitOfWork _uow;
|
||||
|
||||
public UpdateAllergenUseCase(IAllergenRepository repo, IUnitOfWork uow) { _repo = repo; _uow = uow; }
|
||||
|
||||
public async Task<AllergenResponse?> ExecuteAsync(Guid id, AllergenUpdateRequest req, CancellationToken ct = default)
|
||||
{
|
||||
await _uow.BeginAsync(null, IsolationLevel.ReadCommitted, ct);
|
||||
try
|
||||
{
|
||||
var e = await _repo.GetAsync(id, ct);
|
||||
if (e is null) { await _uow.RollbackAsync(ct); return null; }
|
||||
|
||||
e.Name = req.Name.Trim();
|
||||
e.NameI18n = req.NameI18n;
|
||||
e.Meta = req.Meta;
|
||||
e.IsActive = req.IsActive;
|
||||
|
||||
await _repo.UpdateAsync(e, ct);
|
||||
await _uow.CommitAsync(ct);
|
||||
|
||||
return new AllergenResponse(e.Id, e.Scope, e.Code, e.Name, e.NameI18n, e.OverridesGlobalId, e.IsActive, e.IsSystem, e.Meta);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Data;
|
||||
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Brand;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Common;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Brand;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Brand;
|
||||
|
||||
public sealed class CreateBrandUseCase : ICreateBrandUseCase
|
||||
{
|
||||
private readonly IBrandRepository _repo;
|
||||
private readonly IUnitOfWork _uow;
|
||||
private readonly ITenantResolver _tenantResolver;
|
||||
private readonly IHttpContextAccessor _http;
|
||||
|
||||
public CreateBrandUseCase(IBrandRepository repo, IUnitOfWork uow, ITenantResolver tr, IHttpContextAccessor http)
|
||||
{
|
||||
_repo = repo; _uow = uow; _tenantResolver = tr; _http = http;
|
||||
}
|
||||
|
||||
public async Task<BrandResponse> ExecuteAsync(BrandCreateRequest req, CancellationToken ct = default)
|
||||
{
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant");
|
||||
|
||||
await _uow.BeginAsync(tc, IsolationLevel.ReadCommitted, ct);
|
||||
try
|
||||
{
|
||||
var tid = Guid.Parse(tc.Id);
|
||||
|
||||
if (req.Scope == "tenant" && await _repo.CodeExistsAsync(tid, req.Code, ct))
|
||||
throw new InvalidOperationException($"Brand code '{req.Code}' already exists.");
|
||||
|
||||
var entity = new Domain.Entities.MasterData.Brand
|
||||
{
|
||||
TenantId = tid,
|
||||
Scope = string.IsNullOrWhiteSpace(req.Scope) ? "tenant" : req.Scope,
|
||||
Code = req.Code.Trim(),
|
||||
Name = req.Name.Trim(),
|
||||
NameI18n = req.NameI18n,
|
||||
Meta = req.Meta,
|
||||
IsActive = req.IsActive,
|
||||
IsSystem = false,
|
||||
OverridesGlobalId = req.OverridesGlobalId
|
||||
};
|
||||
|
||||
await _repo.AddAsync(entity, ct);
|
||||
await _uow.CommitAsync(ct);
|
||||
|
||||
return new BrandResponse(entity.Id, entity.Scope, entity.Code, entity.Name, entity.NameI18n, entity.OverridesGlobalId, entity.IsActive, entity.IsSystem, entity.Meta);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Brand;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Brand;
|
||||
|
||||
public sealed class DeleteBrandUseCase : IDeleteBrandUseCase
|
||||
{
|
||||
private readonly IBrandRepository _repo;
|
||||
private readonly ITenantResolver _tenantResolver;
|
||||
private readonly IHttpContextAccessor _http;
|
||||
|
||||
public DeleteBrandUseCase(IBrandRepository repo, ITenantResolver tr, IHttpContextAccessor http)
|
||||
{
|
||||
_repo = repo;
|
||||
_tenantResolver = tr;
|
||||
_http = http;
|
||||
}
|
||||
|
||||
public async Task<bool> ExecuteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant");
|
||||
var tid = Guid.Parse(tc.Id);
|
||||
|
||||
var n = await _repo.SoftDeleteAsync(id, tid, ct);
|
||||
return n > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Brand;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Brand;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Brand;
|
||||
|
||||
public sealed class GetBrandUseCase : IGetBrandUseCase
|
||||
{
|
||||
private readonly IBrandRepository _repo;
|
||||
public GetBrandUseCase(IBrandRepository repo) => _repo = repo;
|
||||
|
||||
public async Task<BrandResponse?> ExecuteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var e = await _repo.GetAsync(id, ct);
|
||||
return e is null ? null : new BrandResponse(e.Id, e.Scope, e.Code, e.Name, e.NameI18n, e.OverridesGlobalId, e.IsActive, e.IsSystem, e.Meta);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Brand;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.Common;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Brand;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Brand;
|
||||
|
||||
public sealed class ListBrandsUseCase : IListBrandsUseCase
|
||||
{
|
||||
private readonly IBrandRepository _repo;
|
||||
private readonly ITenantResolver _tenantResolver;
|
||||
private readonly IHttpContextAccessor _http;
|
||||
|
||||
public ListBrandsUseCase(IBrandRepository repo, ITenantResolver tenantResolver, IHttpContextAccessor http)
|
||||
{
|
||||
_repo = repo;
|
||||
_tenantResolver = tenantResolver;
|
||||
_http = http;
|
||||
}
|
||||
|
||||
public async Task<PagedResponse<BrandResponse>> ExecuteAsync(BrandListRequest req, CancellationToken ct = default)
|
||||
{
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant");
|
||||
var tid = Guid.Parse(tc.Id);
|
||||
|
||||
var page = await _repo.SearchEffectiveAsync(tid, req, ct);
|
||||
var items = page.Items.Select(Map).ToList();
|
||||
return new PagedResponse<BrandResponse>(page.Page, page.PageSize, page.Total, items);
|
||||
}
|
||||
|
||||
private static BrandResponse Map(Domain.Entities.MasterData.Brand e) =>
|
||||
new(e.Id, e.Scope, e.Code, e.Name, e.NameI18n, e.OverridesGlobalId, e.IsActive, e.IsSystem, e.Meta);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Data;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Brand;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Common;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Brand;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Brand;
|
||||
|
||||
public sealed class UpdateBrandUseCase : IUpdateBrandUseCase
|
||||
{
|
||||
private readonly IBrandRepository _repo;
|
||||
private readonly IUnitOfWork _uow;
|
||||
|
||||
public UpdateBrandUseCase(IBrandRepository repo, IUnitOfWork uow) { _repo = repo; _uow = uow; }
|
||||
|
||||
public async Task<BrandResponse?> ExecuteAsync(Guid id, BrandUpdateRequest req, CancellationToken ct = default)
|
||||
{
|
||||
await _uow.BeginAsync(null, IsolationLevel.ReadCommitted, ct);
|
||||
try
|
||||
{
|
||||
var e = await _repo.GetAsync(id, ct);
|
||||
if (e is null) { await _uow.RollbackAsync(ct); return null; }
|
||||
|
||||
e.Name = req.Name.Trim();
|
||||
e.NameI18n = req.NameI18n;
|
||||
e.Meta = req.Meta;
|
||||
e.IsActive = req.IsActive;
|
||||
|
||||
await _repo.UpdateAsync(e, ct);
|
||||
await _uow.CommitAsync(ct);
|
||||
|
||||
return new BrandResponse(e.Id, e.Scope, e.Code, e.Name, e.NameI18n, e.OverridesGlobalId, e.IsActive, e.IsSystem, e.Meta);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.District;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.District;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.District;
|
||||
|
||||
public sealed class GetDistrictUseCase : IGetDistrictUseCase
|
||||
{
|
||||
private readonly IDistrictRepository _repo;
|
||||
|
||||
public GetDistrictUseCase(IDistrictRepository repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
public async Task<DistrictResponse?> ExecuteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var e = await _repo.GetAsync(id, ct);
|
||||
if (e is null) return null;
|
||||
|
||||
return new DistrictResponse(
|
||||
e.Id,
|
||||
e.Scope,
|
||||
e.Code,
|
||||
e.Name,
|
||||
e.NameI18n,
|
||||
e.OverridesGlobalId,
|
||||
e.IsActive,
|
||||
e.IsSystem,
|
||||
e.Meta,
|
||||
e.Code,
|
||||
e.ProvinceId,
|
||||
e.Province.Name,
|
||||
e.Province.Code
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.District;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.Common;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.District;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.District;
|
||||
|
||||
public sealed class ListDistrictsUseCase : IListDistrictsUseCase
|
||||
{
|
||||
private readonly IDistrictRepository _repo;
|
||||
private readonly ITenantResolver _tenantResolver;
|
||||
private readonly IHttpContextAccessor _http;
|
||||
|
||||
public ListDistrictsUseCase(
|
||||
IDistrictRepository repo,
|
||||
ITenantResolver tenantResolver,
|
||||
IHttpContextAccessor http)
|
||||
{
|
||||
_repo = repo;
|
||||
_tenantResolver = tenantResolver;
|
||||
_http = http;
|
||||
}
|
||||
|
||||
public async Task<PagedResponse<DistrictResponse>> ExecuteAsync(DistrictListRequest req, CancellationToken ct = default)
|
||||
{
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant");
|
||||
var tid = Guid.Parse(tc.Id);
|
||||
|
||||
var page = await _repo.SearchEffectiveAsync(tid, req, ct);
|
||||
var items = page.Items.Select(Map).ToList();
|
||||
|
||||
return new PagedResponse<DistrictResponse>(page.Page, page.PageSize, page.Total, items);
|
||||
}
|
||||
|
||||
private static DistrictResponse Map(Domain.Entities.MasterData.District e) =>
|
||||
new(
|
||||
e.Id,
|
||||
e.Scope,
|
||||
e.Code,
|
||||
e.Name,
|
||||
e.NameI18n,
|
||||
e.OverridesGlobalId,
|
||||
e.IsActive,
|
||||
e.IsSystem,
|
||||
e.Meta,
|
||||
e.Code,
|
||||
e.ProvinceId,
|
||||
e.Province.Name,
|
||||
e.Province.Code
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Province;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Province;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Province;
|
||||
|
||||
public sealed class GetProvinceUseCase : IGetProvinceUseCase
|
||||
{
|
||||
private readonly IProvinceRepository _repo;
|
||||
|
||||
public GetProvinceUseCase(IProvinceRepository repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
public async Task<ProvinceResponse?> ExecuteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var e = await _repo.GetAsync(id, ct);
|
||||
if (e is null) return null;
|
||||
|
||||
return new ProvinceResponse(
|
||||
e.Id,
|
||||
e.Scope,
|
||||
e.Code,
|
||||
e.Name,
|
||||
e.NameI18n,
|
||||
e.OverridesGlobalId,
|
||||
e.IsActive,
|
||||
e.IsSystem,
|
||||
e.Meta,
|
||||
e.Code
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Province;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.Common;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Province;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Province;
|
||||
|
||||
public sealed class ListProvincesUseCase : IListProvincesUseCase
|
||||
{
|
||||
private readonly IProvinceRepository _repo;
|
||||
private readonly ITenantResolver _tenantResolver;
|
||||
private readonly IHttpContextAccessor _http;
|
||||
|
||||
public ListProvincesUseCase(
|
||||
IProvinceRepository repo,
|
||||
ITenantResolver tenantResolver,
|
||||
IHttpContextAccessor http)
|
||||
{
|
||||
_repo = repo;
|
||||
_tenantResolver = tenantResolver;
|
||||
_http = http;
|
||||
}
|
||||
|
||||
public async Task<PagedResponse<ProvinceResponse>> ExecuteAsync(ProvinceListRequest req, CancellationToken ct = default)
|
||||
{
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant");
|
||||
var tid = Guid.Parse(tc.Id);
|
||||
|
||||
var page = await _repo.SearchEffectiveAsync(tid, req, ct);
|
||||
var items = page.Items.Select(Map).ToList();
|
||||
|
||||
return new PagedResponse<ProvinceResponse>(page.Page, page.PageSize, page.Total, items);
|
||||
}
|
||||
|
||||
private static ProvinceResponse Map(Domain.Entities.MasterData.Province e) =>
|
||||
new(
|
||||
e.Id,
|
||||
e.Scope,
|
||||
e.Code,
|
||||
e.Name,
|
||||
e.NameI18n,
|
||||
e.OverridesGlobalId,
|
||||
e.IsActive,
|
||||
e.IsSystem,
|
||||
e.Meta,
|
||||
e.Code
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Subdistrict;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Subdistrict;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Subdistricts;
|
||||
|
||||
public sealed class GetSubdistrictUseCase : IGetSubdistrictUseCase
|
||||
{
|
||||
private readonly ISubdistrictRepository _repo;
|
||||
|
||||
public GetSubdistrictUseCase(ISubdistrictRepository repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
public async Task<SubdistrictResponse?> ExecuteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var e = await _repo.GetAsync(id, ct);
|
||||
if (e is null) return null;
|
||||
|
||||
return new SubdistrictResponse(
|
||||
e.Id,
|
||||
e.Scope,
|
||||
e.Code,
|
||||
e.Name,
|
||||
e.NameI18n,
|
||||
e.OverridesGlobalId,
|
||||
e.IsActive,
|
||||
e.IsSystem,
|
||||
e.Meta,
|
||||
e.Code,
|
||||
e.Postcode,
|
||||
e.DistrictId,
|
||||
e.District.Name,
|
||||
e.District.Code,
|
||||
e.District.ProvinceId,
|
||||
e.District.Province.Name,
|
||||
e.District.Province.Code
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using AMREZ.EOP.Abstractions.Applications.Tenancy;
|
||||
using AMREZ.EOP.Abstractions.Applications.UseCases.MasterData.Subdistrict;
|
||||
using AMREZ.EOP.Abstractions.Infrastructures.Repositories;
|
||||
using AMREZ.EOP.Contracts.DTOs.Common;
|
||||
using AMREZ.EOP.Contracts.DTOs.MasterData.Subdistrict;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AMREZ.EOP.Application.UseCases.MasterData.Subdistricts;
|
||||
|
||||
public sealed class ListSubdistrictsUseCase : IListSubdistrictsUseCase
|
||||
{
|
||||
private readonly ISubdistrictRepository _repo;
|
||||
private readonly ITenantResolver _tenantResolver;
|
||||
private readonly IHttpContextAccessor _http;
|
||||
|
||||
public ListSubdistrictsUseCase(
|
||||
ISubdistrictRepository repo,
|
||||
ITenantResolver tenantResolver,
|
||||
IHttpContextAccessor http)
|
||||
{
|
||||
_repo = repo;
|
||||
_tenantResolver = tenantResolver;
|
||||
_http = http;
|
||||
}
|
||||
|
||||
public async Task<PagedResponse<SubdistrictResponse>> ExecuteAsync(SubdistrictListRequest req, CancellationToken ct = default)
|
||||
{
|
||||
var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext");
|
||||
var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant");
|
||||
var tid = Guid.Parse(tc.Id);
|
||||
|
||||
var page = await _repo.SearchEffectiveAsync(tid, req, ct);
|
||||
var items = page.Items.Select(Map).ToList();
|
||||
|
||||
return new PagedResponse<SubdistrictResponse>(page.Page, page.PageSize, page.Total, items);
|
||||
}
|
||||
|
||||
private static SubdistrictResponse Map(Domain.Entities.MasterData.Subdistrict e) =>
|
||||
new(
|
||||
e.Id,
|
||||
e.Scope,
|
||||
e.Code,
|
||||
e.Name,
|
||||
e.NameI18n,
|
||||
e.OverridesGlobalId,
|
||||
e.IsActive,
|
||||
e.IsSystem,
|
||||
e.Meta,
|
||||
e.Code,
|
||||
e.Postcode,
|
||||
e.DistrictId,
|
||||
e.District.Name,
|
||||
e.District.Code,
|
||||
e.District.ProvinceId,
|
||||
e.District.Province.Name,
|
||||
e.District.Province.Code
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user