SHA256
Moved and renamed Db/Entity services for better organization.
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
using FluentValidation;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Somnia.GuestLog.Enums.Services;
|
||||
using Somnia.GuestLog.Infrastructure;
|
||||
using Somnia.GuestLog.Models;
|
||||
using Somnia.GuestLog.Models.DTOs;
|
||||
using Somnia.GuestLog.Models.Entities;
|
||||
using Somnia.GuestLog.Utils;
|
||||
|
||||
namespace Somnia.GuestLog.Services.Entity;
|
||||
|
||||
public class GuestDocumentEntityService(
|
||||
ILogger<GuestDocumentEntityService> logger,
|
||||
IDbContextFactory<GuestLogContext> contextFactory,
|
||||
IValidator<GuestDocumentDTO> dtoValidator
|
||||
) : IGuestDocumentEntityService
|
||||
{
|
||||
public async Task<Result> CreateDocumentAsync(GuestDocumentDTO dto)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dto);
|
||||
|
||||
var valResult = dtoValidator.Validate(dto);
|
||||
if (!valResult.IsValid)
|
||||
{
|
||||
logger.LogWarning("GuestDocumentService - CreateDocument: Dto validation failed. Fix the errors: {errorList}", valResult.Errors);
|
||||
return Result.Fail(ResultCode.FailedValidation);
|
||||
}
|
||||
|
||||
//Dto must be valid, so null warings shouldn't matter.
|
||||
GuestAddress addressItem = new()
|
||||
{
|
||||
Address = dto.Address,
|
||||
AddressCity = dto.AddressCity,
|
||||
AddressProvince = dto.AddressProvince,
|
||||
AddressState = dto.AddressState,
|
||||
AddressCountry = dto.AddressCountry!,
|
||||
ZipCode = dto.ZipCode,
|
||||
};
|
||||
|
||||
DateTime createTime = DateTime.UtcNow;
|
||||
GuestDocument dbItem = new()
|
||||
{
|
||||
DocumentType = dto.DocumentType!,
|
||||
DocumentNum = dto.DocumentNum!,
|
||||
IssueDate = DateOnly.FromDateTime(dto.IssueDate!.Value),
|
||||
SupportNum = dto.SupportNum,
|
||||
Nationality = dto.Nationality!,
|
||||
Name = dto.Name!,
|
||||
Surname = dto.Surname!,
|
||||
Surname2 = dto.Surname2,
|
||||
BirthDate = DateOnly.FromDateTime(dto.BirthDate!.Value),
|
||||
Gender = dto.Gender,
|
||||
PhoneNumber = dto.PhoneNumber,
|
||||
EmailAddress = dto.EmailAddress,
|
||||
AddressDetails = addressItem,
|
||||
CreateTime = createTime,
|
||||
UpdateTime = createTime,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
await dbContext.AddAsync(dbItem);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
logger.LogInformation("GuestDocumentService - CreateDocument: GuestDocument Created: '{id}'", dbItem.GetFullKey());
|
||||
return Result.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "GuestDocumentService - CreateDocument: Error creating GuestDocument: '{id}'", dbItem.GetFullKey());
|
||||
return Result.FailUnknownError();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<Result> UpdateDocumentAsync(GuestDocumentDTO dto)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Result> DeleteDocumentAsync(GuestDocumentDTO dto)
|
||||
{
|
||||
if (dto.DocumentType is null || dto.DocumentNum is null)
|
||||
{
|
||||
throw new InvalidOperationException("GuestDocumentService - DeleteDocument: A DTO without key can't be deleted!");
|
||||
}
|
||||
|
||||
return DeleteDocumentAsync(dto.DocumentType, dto.DocumentNum);
|
||||
}
|
||||
|
||||
public async Task<Result> DeleteDocumentAsync(string docType, string docNum)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
GuestDocument? dbItem = await dbContext.GuestDocuments.FindAsync(docType, docNum);
|
||||
if (dbItem is null)
|
||||
{
|
||||
logger.LogWarning("GuestDocumentService - DeleteDocument: Error deleting GuestDocument. Entity not found with key: '{key}-{key2}'", docType, docNum);
|
||||
return Result.Fail(ResultCode.NotFound);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
dbContext.GuestDocuments.Remove(dbItem);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
logger.LogInformation("GuestDocumentService - DeleteDocument: GuestDocument deleted: '{id}'", dbItem.GetFullKey());
|
||||
return Result.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "GuestDocumentService - CreateDocument: Error deleting GuestDocument: '{id}'", dbItem.GetFullKey());
|
||||
return Result.FailUnknownError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<GuestDocumentDTO?> GetDtoByIdAsync(string docType, string docNum)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
GuestDocument? dbItem = await dbContext.GuestDocuments.FindAsync(docType, docNum);
|
||||
return dbItem is not null ? GetDtoFromDb(dbItem) : null;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<GuestDocumentDTO>> GetDtoListAsync()
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
var dbList = await dbContext.GuestDocuments
|
||||
.OrderByDescending(e => e.UpdateTime)
|
||||
.ToListAsync();
|
||||
|
||||
return dbList.Select(GetDtoFromDb);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get GuestDocumentDTO from DB with the given filters.
|
||||
/// Result count can be limited for perfomance reasons.
|
||||
/// </summary>
|
||||
/// <param name="filter">Filters to use</param>
|
||||
/// <param name="limit">Result count. Set to 0 for unlimited results</param>
|
||||
/// <returns>Filtered GuestDocumentDTO result list</returns>
|
||||
public async Task<IEnumerable<GuestDocumentDTO>> GetDtoListByFilterAsync(GuestDocFilterDTO filter, int limit = 0)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
|
||||
var query = dbContext.GuestDocuments.AsQueryable();
|
||||
|
||||
query = query.WhereIf(!string.IsNullOrEmpty(filter.DocumentType),
|
||||
e => e.DocumentType == filter.DocumentType);
|
||||
query = query.WhereIf(!string.IsNullOrEmpty(filter.DocumentNumber),
|
||||
e => e.DocumentNum == filter.DocumentNumber);
|
||||
|
||||
query = query.WhereIf(!string.IsNullOrEmpty(filter.Name),
|
||||
e => EF.Functions.Like(e.Name, filter.Name));
|
||||
query = query.WhereIf(!string.IsNullOrEmpty(filter.Surname),
|
||||
e => EF.Functions.Like(e.Surname, filter.Surname));
|
||||
|
||||
query = query.OrderByDescending(e => e.UpdateTime);
|
||||
|
||||
if (limit > 0)
|
||||
{
|
||||
query = query.Take(limit);
|
||||
}
|
||||
|
||||
var dbList = await query.ToListAsync();
|
||||
|
||||
return dbList.Select(x => GetDtoFromDb(x));
|
||||
}
|
||||
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
private static GuestDocumentDTO GetDtoFromDb(GuestDocument dbItem)
|
||||
{
|
||||
return EntityMapping.MapGuestDocumentEntityToDTO(dbItem);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Somnia.GuestLog.Models.DTOs;
|
||||
|
||||
namespace Somnia.GuestLog.Services.Entity;
|
||||
|
||||
public interface IGuestDocumentEntityService
|
||||
{
|
||||
public Task<Result> CreateDocumentAsync(GuestDocumentDTO dto);
|
||||
public Task<Result> UpdateDocumentAsync(GuestDocumentDTO dto);
|
||||
public Task<Result> DeleteDocumentAsync(GuestDocumentDTO dto);
|
||||
public Task<Result> DeleteDocumentAsync(string docType, string docNum);
|
||||
|
||||
public Task<GuestDocumentDTO?> GetDtoByIdAsync(string docType, string docNum);
|
||||
public Task<IEnumerable<GuestDocumentDTO>> GetDtoListByFilterAsync(GuestDocFilterDTO filter, int limit = 0);
|
||||
public Task<IEnumerable<GuestDocumentDTO>> GetDtoListAsync();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Somnia.GuestLog.Models.DTOs;
|
||||
using Somnia.GuestLog.Models.QueryConfigs;
|
||||
|
||||
namespace Somnia.GuestLog.Services.Entity;
|
||||
|
||||
public interface IStayEntryEntityService
|
||||
{
|
||||
public Task<Result> CreateEntryAsync(StayEntryDTO dto);
|
||||
public Task<Result> UpdateEntryAsync(StayEntryDTO updatedDto);
|
||||
public Task<Result> DeleteEntryAsync(StayEntryDTO dto);
|
||||
public Task<Result> DeleteEntryAsync(long id);
|
||||
|
||||
public Task<StayEntryDTO?> GetDtoByIdAsync(long id, StayEntryQueryConfig? queryConfig = null);
|
||||
public Task<IEnumerable<StayEntryDTO>> GetDtoListAsync(StayEntryQueryConfig? queryConfig = null);
|
||||
public Task<IEnumerable<StayEntryDTO>> GetDtoListByFilterAsync(StayEntryFilterDTO filter, int limit = 0, StayEntryQueryConfig? queryConfig = null);
|
||||
|
||||
|
||||
public Task<bool> IsGuestInStayInPeriod(string docType, string docNum, DateTime startTime, DateTime endTime);
|
||||
public Task<IEnumerable<StayEntryDTO>> GetStaysWithGuest(string docType, string docNum, StayEntryQueryConfig? queryConfig = null);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
using FluentValidation;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Somnia.GuestLog.Enums.Services;
|
||||
using Somnia.GuestLog.Infrastructure;
|
||||
using Somnia.GuestLog.Models;
|
||||
using Somnia.GuestLog.Models.DTOs;
|
||||
using Somnia.GuestLog.Models.Entities;
|
||||
using Somnia.GuestLog.Models.QueryConfigs;
|
||||
using Somnia.GuestLog.Utils;
|
||||
|
||||
namespace Somnia.GuestLog.Services.Entity;
|
||||
|
||||
public class StayEntryEntityService(
|
||||
ILogger<StayEntryEntityService> logger,
|
||||
IDbContextFactory<GuestLogContext> contextFactory,
|
||||
IValidator<StayEntryDTO> dtoValidator
|
||||
) : IStayEntryEntityService
|
||||
{
|
||||
public async Task<Result> CreateEntryAsync(StayEntryDTO dto)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dto);
|
||||
|
||||
var valResult = await dtoValidator.ValidateAsync(dto);
|
||||
if (!valResult.IsValid)
|
||||
{
|
||||
logger.LogWarning("StayEntryService - CreateEntryAsync: Dto validation failed. Fix the errors: {errorList}", valResult.Errors);
|
||||
return Result.Fail(ResultCode.FailedValidation);
|
||||
}
|
||||
|
||||
DateTime createTime = DateTime.UtcNow;
|
||||
StayEntry dbStay = new()
|
||||
{
|
||||
DateIn = dto.DateIn!.Value.ToUniversalTime(),
|
||||
DateOut = dto.DateOut!.Value.ToUniversalTime(),
|
||||
RoomCount = dto.RoomCount!.Value,
|
||||
RoomNumber = dto.RoomNumber,
|
||||
PaymentMethod = dto.PaymentMethod!,
|
||||
CreateTime = createTime,
|
||||
UpdateTime = createTime,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
|
||||
//Check and add GuestDocuments
|
||||
foreach (GuestDocumentDTO guestDto in dto.GuestDocuments!)
|
||||
{
|
||||
//Get it from db.
|
||||
GuestDocument? dbGuest = await dbContext.GuestDocuments.FindAsync(guestDto.DocumentType, guestDto.DocumentNum)
|
||||
?? throw new InvalidOperationException($"GuestDocument not found! Id: '{guestDto.FullKey}'");
|
||||
|
||||
//Check if Guest is already in other stay during the same period.
|
||||
bool isInOtherStay = await this.IsGuestInStayInPeriod(dbGuest.DocumentType, dbGuest.DocumentNum, dbStay.DateIn, dbStay.DateOut);
|
||||
if (isInOtherStay)
|
||||
{
|
||||
string period = $"{dbStay.DateIn}-{dbStay.DateOut}";
|
||||
return Result.FailWithContext(ResultCode.GuestCurrentlyInStay, dbGuest.GetFullKey(), period);
|
||||
}
|
||||
|
||||
//Add dbGuest to dbStay.
|
||||
dbStay.GuestDocuments.Add(dbGuest);
|
||||
}
|
||||
|
||||
await dbContext.AddAsync(dbStay);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
logger.LogInformation("StayEntryService - CreateEntryAsync: StayEntry Created: '{id}'", dbStay.GetFullKey());
|
||||
return Result.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "StayEntryService - CreateEntryAsync: Error creating StayEntry");
|
||||
return Result.FailUnknownError();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<Result> UpdateEntryAsync(StayEntryDTO updatedDto)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<Result> DeleteEntryAsync(StayEntryDTO dto)
|
||||
{
|
||||
if (dto.Id is null)
|
||||
{
|
||||
throw new InvalidOperationException("StayEntryService - DeleteEntry: A DTO without key can't be deleted!");
|
||||
}
|
||||
|
||||
return await DeleteEntryAsync(dto.Id.Value);
|
||||
}
|
||||
|
||||
public async Task<Result> DeleteEntryAsync(long id)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
StayEntry? dbItem = await dbContext.StayEntries.FindAsync(id);
|
||||
if (dbItem is null)
|
||||
{
|
||||
logger.LogWarning("StayEntryService - DeleteEntry: Error deleting StayEntry. Entity not found with key: '{key}'", id);
|
||||
return Result.Fail(ResultCode.NotFound);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
dbContext.StayEntries.Remove(dbItem);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
logger.LogInformation("StayEntryService - DeleteEntry: StayEntry deleted: '{id}'", dbItem.GetFullKey());
|
||||
return Result.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "StayEntryService - DeleteEntry: Error deleting StayEntry: '{id}'", dbItem.GetFullKey());
|
||||
return Result.FailUnknownError();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<StayEntryDTO?> GetDtoByIdAsync(long id, StayEntryQueryConfig? queryConfig = null)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
StayEntry? dbItem = await dbContext.StayEntries
|
||||
.Where(e => e.Id == id)
|
||||
.AddQueryConfig(queryConfig)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
return dbItem is not null ? GetDtoFromDb(dbItem, queryConfig) : null;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<StayEntryDTO>> GetDtoListAsync(StayEntryQueryConfig? queryConfig = null)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
|
||||
var dbList = await dbContext.StayEntries
|
||||
.AddQueryConfig(queryConfig)
|
||||
.OrderByDescending(e => e.UpdateTime)
|
||||
.ToListAsync();
|
||||
|
||||
return dbList.Select(e => GetDtoFromDb(e, queryConfig));
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<StayEntryDTO>> GetDtoListByFilterAsync(StayEntryFilterDTO filter, int limit = 0, StayEntryQueryConfig? queryConfig = null)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
|
||||
var query = dbContext.StayEntries
|
||||
.AddQueryConfig(queryConfig)
|
||||
.AsQueryable();
|
||||
|
||||
query = query.WhereIf(filter.DateInStart is not null && filter.DateInEnd is not null,
|
||||
e => e.DateIn >= filter.DateInStart!.Value.ToUniversalTime()
|
||||
&& e.DateIn < filter.DateInEnd!.Value.ToUniversalTime());
|
||||
query = query.WhereIf(!string.IsNullOrEmpty(filter.RoomNumber),
|
||||
e => EF.Functions.Like(e.RoomNumber, $"%{filter.RoomNumber}%"));
|
||||
query = query.WhereIf(!string.IsNullOrEmpty(filter.PaymentMethod),
|
||||
e => e.PaymentMethod == filter.PaymentMethod);
|
||||
|
||||
query = query.OrderByDescending(e => e.DateIn);
|
||||
|
||||
if (limit > 0)
|
||||
{
|
||||
query = query.Take(limit);
|
||||
}
|
||||
|
||||
var dbList = await query
|
||||
.ToListAsync();
|
||||
|
||||
return dbList.Select(x => GetDtoFromDb(x, queryConfig));
|
||||
}
|
||||
|
||||
|
||||
public async Task<bool> IsGuestInStayInPeriod(string docType, string docNum, DateTime startTime, DateTime endTime)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
|
||||
bool rs = await dbContext.StayEntries
|
||||
.AnyAsync(s => s.DateIn < endTime && s.DateOut > startTime
|
||||
&& s.GuestDocuments.Any(g => g.DocumentType == docType && g.DocumentNum == docNum)
|
||||
);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<StayEntryDTO>> GetStaysWithGuest(string docType, string docNum, StayEntryQueryConfig? queryConfig = null)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
|
||||
var rs = await dbContext.StayEntries
|
||||
.Where(s => s.GuestDocuments.Any(g => g.DocumentType == docType && g.DocumentNum == docNum))
|
||||
.AddQueryConfig(queryConfig)
|
||||
.OrderByDescending(e => e.DateIn)
|
||||
.ToListAsync();
|
||||
|
||||
return rs.Select(e => GetDtoFromDb(e, queryConfig));
|
||||
}
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
private static StayEntryDTO GetDtoFromDb(StayEntry dbItem, StayEntryQueryConfig? queryConfig)
|
||||
{
|
||||
queryConfig ??= StayEntryQueryConfig.DefaultQueryConfig;
|
||||
|
||||
return EntityMapping.MapStayEntryEntityToDTO(dbItem, queryConfig.IncludeGuests);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user