Files

398 lines
14 KiB
C#

using adas_core.Application.Exceptions;
using adas_core.Application.Repositories.Interfaces;
using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.Masters;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Models.Responses;
using adas_core.Domain.Utils;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Driver;
namespace adas_core.Application.Services;
public class PointOfCareService(
ILogger<PointOfCareService> logger,
IPointOfCareRepository pointOfCareRepository,
Lazy<IPatientService> patientService,
Lazy<IUnitService> unitService,
ISubscribersService subscribersService,
Lazy<IClientMessageService> clientMessageService,
Lazy<IAdmissionService> admissionService,
IHttpContextAccessor httpContextAccessor,
ILocalAuditService auditService,
ICacheService cacheService,
IOptions<CacheSettings> cacheSettings)
: IPointOfCareService
{
private readonly CacheSettings? _cacheSettings = cacheSettings.Value ;
public async Task<PointOfCare?> InsertPointOfCare(PointOfCare pointOfCare)
{
try
{
var unit = await unitService.Value.FindById(pointOfCare.UnitId);
if (unit == null)
{
logger.LogError("Unit id: {unitId} Not Found. PointOfCare not inserted", pointOfCare.UnitId);
return null;
}
pointOfCare.UnitId = unit.Id;
await pointOfCareRepository.InsertOneAsync(pointOfCare);
await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, pointOfCare);
return await FindById(pointOfCare.Id);
}
catch (Exception ex)
{
logger.LogError("Exception inserting pointOfCare: {pointOfCare}, Exception: {ex}", pointOfCare, ex);
return null;
}
}
public async Task Delete(ObjectId id)
{
var poc = await FindById(id);
if (poc is not { AdmissionId: null }) return;
await pointOfCareRepository.Delete(id);
await cacheService.DeleteByPatternAsync(CacheKeys.PointOfCareBase(id));
await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, poc, null);
}
public async Task DeletePoCsByUnitId(ObjectId unitId)
{
await pointOfCareRepository.DeleteManyByUnitId(unitId);
await cacheService.DeleteByPatternAsync(CacheKeyPatterns.ForEntity(CacheEnum.EntityType.PontOfCare));
}
public async Task<HashSet<ObjectId>> FindAllIdCamerasInUse()
{
return await pointOfCareRepository.FindAllIdCamerasInUse();
}
public async Task<HashSet<ObjectId>> FindAllIdRelaysInUse()
{
return await pointOfCareRepository.FindAllIdRelaysInUse();
}
public async Task<HashSet<ObjectId>> FindAllIdBeaconsInUse()
{
return await pointOfCareRepository.FindAllIdBeaconsInUse();
}
public async Task<IEnumerable<PointOfCare>?> FindAllByUnitIdWithDevices(ObjectId unitId)
{
var result = await pointOfCareRepository.FindAllByUnitIdWithDevices(unitId);
return result ?? [];
}
public async Task<PointOfCare?> Update(PointOfCare pointOfCare)
{
var oldPoc = await pointOfCareRepository.FindById(pointOfCare.Id);
await pointOfCareRepository.Update(pointOfCare);
var updatedPoc = await GetInfo(pointOfCare.Id);
await cacheService.DeleteByPatternAsync(CacheKeys.PointOfCareBase(pointOfCare.Id));
await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldPoc, updatedPoc);
if (updatedPoc == null) return null;
SendPointOfCareBroadcast(updatedPoc, OperationType.UpdatedPointOfCare);
return updatedPoc;
}
public async Task UpdateUnit(ObjectId id, Unit unit)
{
var poc = await FindById(id);
if (poc == null)
return;
await pointOfCareRepository.UpdateUnitId(id, unit);
await cacheService.DeleteByPatternAsync(CacheKeys.PointOfCareBase(id));
var newPoc = await FindById(id);
await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, poc, newPoc!);
SendPointOfCareBroadcast(poc, OperationType.UpdatedPointOfCare);
}
public async Task<List<PointOfCare>> GetAll()
{
var c = await pointOfCareRepository.GetAll();
return c ?? [];
}
public async Task<List<PointOfCare>> GetAllConfigs()
{
var c = await pointOfCareRepository.GetAllConfigs();
return c ?? [];
}
public async Task<List<PointOfCare>> GetAllLocationInfo()
{
var c = await pointOfCareRepository.GetAllLocationInfo();
return c ?? [];
}
public async Task<PaginationResponse<PointOfCare>> GetPaginatedPoCs(PaginationFilter filter)
{
var result = pointOfCareRepository.GetPaginatedPoCs(filter);
var count = await result.CountDocumentsAsync();
var data = await result.Skip((filter.PageNumber - 1) * filter.PageSize)
.Limit(filter.PageSize)
.ToCursorAsync();
var dataList = await data.ToListAsync();
return new PaginationResponse<PointOfCare>(dataList, filter.PageNumber, filter.PageSize, count);
}
public async Task UpdateConfiguration(ObjectId id, PointOfCareConfiguration configuration)
{
var old = await pointOfCareRepository.GetPoCConfiguration(id) ??
throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed);
await pointOfCareRepository.UpdateConfiguration(id, configuration);
await cacheService.DeleteByPatternAsync(CacheKeys.PointOfCareBase(id));
await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, old.Configuration,
configuration);
}
public async Task<PointOfCare?> FindById(ObjectId id)
{
return await pointOfCareRepository.FindByIdAllConfig(id);
}
public async Task<PointOfCare?> FindByIdAllConfig(ObjectId id)
{
return await pointOfCareRepository.FindByIdAllConfig(id);
}
public async Task<IEnumerable<PointOfCare>?> FindAllByUnitId(ObjectId unit)
{
var result = await pointOfCareRepository.FindAllByUnitId(unit);
return result ?? [];
}
public async Task<IEnumerable<PointOfCare>> FindByUnitAndStatus(ObjectId unitId, StatusEnum.PointOfCare poc,
bool excludeVirtual = false)
{
return await pointOfCareRepository.FindByUnitAndStatus(unitId, poc, excludeVirtual);
}
/// <summary>
/// Check nex admission when patient has exit from poc
/// </summary>
/// <param name="patientLocation">PoC id</param>
public async void CheckNextAdmission(ObjectId? patientLocation)
{
try
{
if (patientLocation == null) return;
var pocToCheck = await GetInfo(patientLocation.Value,null);
if (pocToCheck != null && pocToCheck.Status != StatusEnum.PointOfCare.Locked)
{
if (pocToCheck.AdmissionId != null)
{
pocToCheck.Status = StatusEnum.PointOfCare.Reserved;
}
else
{
// Sabemos que puede ser una lista, pero limitamos directamente a 1 elemento
var next = await admissionService.Value.GetAdmissionByPointOfCareId(pocToCheck.Id);
var adm = next.FirstOrDefault();
if (adm != null)
{
pocToCheck.Admission = adm;
pocToCheck.AdmissionId = adm.Id;
pocToCheck.Status = StatusEnum.PointOfCare.Reserved;
}
else
{
pocToCheck.Status = StatusEnum.PointOfCare.Available;
}
}
await Update(pocToCheck);
}
}
catch (Exception e)
{
logger.LogError("Error checking next admission for PointOfCare {pocId}: {message}", patientLocation,
e.Message);
}
}
public async Task<PointOfCare?> FindByBedAndUnitId(string? bed, ObjectId? unitId)
{
if (unitId == null || string.IsNullOrEmpty(bed)) return null;
return await pointOfCareRepository.FindByBedAndUnitId(bed, unitId.Value);
}
public async Task UpdateRelayConfig(PointOfCare poc)
{
var oldPoc = await pointOfCareRepository.GetPoCConfiguration(poc.Id);
if (poc.Configuration?.RelayIdList != null)
{
await pointOfCareRepository.UpdateRelayConfig(poc.Id, poc.Configuration.RelayIdList);
await cacheService.DeleteByPatternAsync(CacheKeys.PointOfCareBase(poc.Id));
await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldPoc, poc);
}
}
public async Task<IEnumerable<PointOfCare>?> FindByRoom(string room)
{
return await pointOfCareRepository.FindByRoom(room);
}
public async Task<IEnumerable<PointOfCare>?> FindByBed(string bed)
{
return await pointOfCareRepository.FindByBed(bed);
}
public async Task<List<PointOfCare>> FindAllByUnitIds(List<ObjectId> unitIds)
{
var filter = Builders<PointOfCare>.Filter.In(p => p.UnitId, unitIds);
return await pointOfCareRepository.FindByFilter(filter);
}
public async Task<PointOfCare?> GetInfo(ObjectId id, bool fillPatientData = true)
{
var poc = await FindById(id);
if (poc == null) return null;
var unit = await unitService.Value.FindById(poc.UnitId);
if (unit is { Name: not null })
poc.UnitName = unit.Name;
if (fillPatientData)
{
var patient = await patientService.Value.GetByPointOfCare(poc);
if (patient != null)
{
poc.Patientid = patient.Id;
poc.Patient = patient;
}
if (poc.AdmissionId != null)
{
var admission = await admissionService.Value.GetAdmissionByIdAsync(poc.AdmissionId.Value);
if (admission != null)
poc.Admission = admission;
}
}
return poc;
}
public async Task<PointOfCare?> GetInfo(ObjectId id, LocaleEnum? locale, bool fillPatientData = true,
CancellationToken ct = default)
{
var (key, ttl) = CacheKeys.PointOfCareBaseKeyWithTtl(_cacheSettings, id);
var poc = await cacheService.GetOrSetObjectAsync(key,
() => pointOfCareRepository.FindById(id),
ttl, ct);
if (poc == null || !fillPatientData)
return poc;
var unit = await unitService.Value.FindById(poc.UnitId);
if (unit?.Name != null)
poc.UnitName = unit.Name;
var patient = locale != null
? await patientService.Value.GetByPointOfCareAndLocale(poc, unit, locale)
: await patientService.Value.GetByPointOfCare(poc);
if (patient != null)
{
poc.Patientid = patient.Id;
poc.Patient = patient;
}
if (poc.AdmissionId == null) return poc;
var admission = await admissionService.Value.GetAdmissionByIdAsync(poc.AdmissionId.Value);
if (admission != null)
poc.Admission = admission;
return poc;
}
public async Task<PointOfCare?> FindPoCByPatientId(ObjectId patientId)
{
var patient = await patientService.Value.FindById(patientId);
if (patient is { PointOfCareId: not null })
return await FindById(patient.PointOfCareId.Value);
return null;
}
public async Task<PointOfCare?> FindPoCByPatientNumber(string patientNumber)
{
var patient = await patientService.Value.FindByPatientNumber(patientNumber);
if (patient is { PointOfCareId: not null })
return await FindById(patient.PointOfCareId.Value);
return null;
}
public async Task<long> CountPoCsByUnitId(ObjectId unitId)
{
return await pointOfCareRepository.CountByUnitId(unitId);
}
public async Task<long> CountVirtualPoCsByUnitId(ObjectId unitId)
{
return await pointOfCareRepository.CountVirtualsByUnitId(unitId);
}
public async Task SetPointOfCareStatus(ObjectId id, StatusEnum.PointOfCare status)
{
var pointOfCare = await GetInfo(id,null);
if (pointOfCare == null) return;
pointOfCare.Status = status;
await pointOfCareRepository.Update(pointOfCare);
await cacheService.DeleteByPatternAsync(CacheKeys.PointOfCareBase(id));
var oldPoc = await auditService.DeepCopyAsync(pointOfCare);
if (oldPoc != null)
await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldPoc, pointOfCare);
// await _patientService.Value.UpdatePatientAltable()
SendPointOfCareBroadcast(pointOfCare, OperationType.UpdatedPointOfCare);
}
public async Task<PointOfCare?> FindPoCByPatientLocation(PatientLocation patientLocation)
{
return await pointOfCareRepository.FindByPatientLocation(patientLocation);
}
private void SendPointOfCareBroadcast(PointOfCare pointOfCare, OperationType operation)
{
try
{
var subscribers = subscribersService.GetSubscribers()
.Where(s => s.LocationIds.Any(c => c == pointOfCare.Id)).ToList();
foreach (var subscriber in subscribers)
_ = clientMessageService.Value.SendAsync(subscriber.Id, operation, pointOfCare);
}
catch (Exception ex)
{
logger.LogError("Exception sending PoC broadcast. Operation type: {op}. Exception: {ex}",
operation.ToString(), ex);
}
}
}