Creado apartir del commit b888de6c92056de294456f581a56e25e734d4ab7 de develop

This commit is contained in:
jrojas
2026-06-26 09:52:35 +02:00
commit 319fd3dfb0
746 changed files with 106610 additions and 0 deletions
@@ -0,0 +1,400 @@
using System.Reflection;
using adas_core.Application.Exceptions;
using adas_core.Application.Repositories.Interfaces;
using adas_core.Application.Services.Interfaces;
using adas_core.Application.Subscriptions;
using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.DTO;
using adas_core.Domain.Models.Masters;
using adas_core.Domain.Models.MongoModels;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using MongoDB.Bson;
namespace adas_core.Application.Services;
public class DischargeService : IDischargeService
{
private readonly ILocalAuditService _auditService;
private readonly IClientMessageService _clientMessageService;
private readonly IDischargeRepository _dischargeRepository;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<DischargeService> _logger;
private readonly IMasterListServiceFactory _masterListServiceFactory;
private readonly Lazy<IPatientService> _patientServiceLazy;
private readonly IPointOfCareService _pointOfCareService;
private readonly ISubscribersService _subscribersService;
private readonly IUnitService _unitService;
public DischargeService(ILogger<DischargeService> logger,
ISubscribersService subscribersService,
IDischargeRepository dischargeRepository,
Lazy<IPatientService> patientServiceLazy,
IClientMessageService clientMessageService,
IPointOfCareService pointOfCareService,
IHttpContextAccessor httpContextAccessor,
ILocalAuditService auditService,
IUnitService unitService,
IMasterListServiceFactory masterListServiceFactory)
{
_logger = logger;
_subscribersService = subscribersService;
_dischargeRepository = dischargeRepository;
_patientServiceLazy = patientServiceLazy;
_clientMessageService = clientMessageService;
_pointOfCareService = pointOfCareService;
_pointOfCareService = pointOfCareService;
_httpContextAccessor = httpContextAccessor;
_auditService = auditService;
_unitService = unitService;
_masterListServiceFactory = masterListServiceFactory;
}
public async Task DeleteDischargeAsync(Discharge discharge)
{
//var patient = await _patientServiceLazy.Value.FindById(discharge.PatientId);
//if (!discharge.MedicalDischarge.HasValue || !discharge.AdminDischarge.HasValue
// // || DischargeStatusType.NoAltable.ToString().Equals(patient?.DischargeStatus?.OptionType)
// )
//{
// _logger.LogError("The patient cannot be discharged");
// return;
//}
await DeleteDischargeByIdAsync(discharge.Id);
}
public async Task DeleteDischargeByIdAsync(ObjectId dischargeId)
{
try
{
var dischargeAux = await _dischargeRepository.FindById(dischargeId);
if (dischargeAux == null)
{
_logger.LogError("Error Discharge not found, id: {discharge} ", dischargeId);
return;
}
await _dischargeRepository.Delete(dischargeId);
_logger.LogInformation("Discharge id: {dischargeId} DELETED ", dischargeId);
//var patient = await _patientServiceLazy.Value.FindById(dischargeAux.PatientId);
// if (patient != null)
// await _patientServiceLazy.Value.ArchivePatient(patient);
// else
// _logger.LogError("Patient not found on Discharge id: {discharge} ", dischargeId);
await _auditService.CreateAuditLogAsync(_httpContextAccessor.HttpContext?.User!, dischargeAux, null);
SendDischargeBroadcast(dischargeAux, OperationType.DeleteDischarge);
}
catch (Exception ex)
{
_logger.LogError("Exception deleting discharge id:{admission} . Exception: {ex}", dischargeId, ex);
}
}
public async Task<long> CountDischargesByUnitId(ObjectId unitId)
{
return await _dischargeRepository.CountByUnitId(unitId);
}
public async Task<Discharge?> GetDischargeByIdAsync(ObjectId dischargeId)
{
var result = await _dischargeRepository.FindById(dischargeId) ??
throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing);
if (result.PointOfCareId == null)
return result;
var poc = await _pointOfCareService.GetInfo(result.PointOfCareId.Value, null,false);
result.PatientLocation = new PatientLocation(poc?.UnitName, poc?.Bed, poc?.Room);
return result;
}
public async Task<IEnumerable<Discharge>> GetDischargesAsync()
{
return await _dischargeRepository.FindAll();
}
public async Task<Discharge?> GetDischargeByPatientId(ObjectId patientId)
{
try
{
var discharge = await _dischargeRepository.GetByPatientId(patientId);
if (discharge == null)
_logger.LogError("Discharge not found by patient Id {id}", patientId);
if (discharge is { PointOfCareId: not null })
{
var poc = await _pointOfCareService.GetInfo(discharge.PointOfCareId.Value, null,false);
discharge.PatientLocation = new PatientLocation(poc?.UnitName, poc?.Bed, poc?.Room);
}
return discharge;
}
catch (Exception ex)
{
_logger.LogError("Exception getting discharge by patient id: {id} . Exception: {ex}", patientId, ex);
return null;
}
}
public async Task<Discharge?> InsertDischarge(Discharge discharge)
{
await _dischargeRepository.InsertOneAsync(discharge);
var dischargeAux = await _dischargeRepository.FindById(discharge.Id) ??
throw new ConflictException(HttpEnum.ErrorMessage.ConflictCreationFailed);
_logger.LogInformation("Discharge: {discharge} INSERTED", discharge);
await _auditService.CreateAuditLogAsync(_httpContextAccessor.HttpContext?.User!, null, dischargeAux);
SendDischargeBroadcast(discharge, OperationType.NewDischarge);
return dischargeAux;
}
public async Task<Discharge?> GetDischargeByLocation(PatientLocation location)
{
try
{
return await _dischargeRepository.GetDischargeByLocation(location);
}
catch (Exception e)
{
_logger.LogError($"Unable to get discharge by location on service Exception: {e}");
return null;
}
}
public async Task<Discharge?> GetDischargeByPointOfCareId(ObjectId poc)
{
try
{
var discharge = await _dischargeRepository.GetDischargeByPointOfCareId(poc);
if (discharge == null)
_logger.LogInformation("Discharge not found by PointOfCareId {id}", poc);
if (discharge is { PointOfCareId: not null })
{
var pocInfo = await _pointOfCareService.GetInfo(discharge.PointOfCareId.Value, null,false);
discharge.PatientLocation = new PatientLocation(pocInfo?.UnitName, pocInfo?.Bed, pocInfo?.Room);
}
return discharge;
}
catch (Exception e)
{
_logger.LogError($"Unable to get discharge by location on service Exception: {e}");
return null;
}
}
public async Task<Discharge?> GetDischargeByPointOfCareIdWithLocale(ObjectId location, LocaleEnum dataLocale)
{
var discharge = await GetDischargeByPointOfCareId(location);
if (discharge == null) return null;
var unit = await _unitService.FindById(discharge.UnitId);
if (unit == null) return discharge;
var dischargeWithLocale = await GetDischargeWithLocale(unit, discharge, dataLocale);
return dischargeWithLocale;
}
public async Task UpdateDischargeAsync(Discharge discharge)
{
var oldDischarge = await GetDischargeByIdAsync(discharge.Id) ??
throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed);
await _dischargeRepository.Update(discharge);
await _auditService.CreateAuditLogAsync(_httpContextAccessor.HttpContext?.User!, oldDischarge, discharge);
SendDischargeBroadcast(discharge, OperationType.UpdateDischarge);
_logger.LogInformation("Discharge: {discharge} UPDATED", discharge);
}
public async Task SaveRequest(ApiRequest apiRequest)
{
try
{
if (apiRequest.Discharge?.Patient == null) return;
var patientId = apiRequest.Discharge.Patient.Id;
var patient = await _patientServiceLazy.Value.FindById(patientId);
if (patient == null)
{
_logger.LogError("Error discharging patient id: {id} NOT FOUND", patientId);
return;
}
await _patientServiceLazy.Value.Update(apiRequest.Discharge.Patient);
switch (apiRequest.Type)
{
case "NewDischarge":
{
//TODO: ver qué tipos llegan
if (!"Altable".Equals(apiRequest.Discharge.Patient.DischargeStatus?.OptionType))
{
_logger.LogError("Error discharging. Patient not altable: {patient}", patient);
return;
}
await _dischargeRepository.InsertOneAsync(apiRequest.Discharge);
await _auditService.CreateAuditLogAsync(_httpContextAccessor.HttpContext?.User!, null,
apiRequest.Discharge);
SendDischargeBroadcast(apiRequest.Discharge, OperationType.NewDischarge);
break;
}
case "UpdateDischarge":
{
await GetDischargeByIdAsync(apiRequest.Discharge.Id);
await UpdateDischargeAsync(apiRequest.Discharge);
break;
}
case "DeleteDischarge":
{
if (StatusEnum.Discharge.NoAltable.ToString().Equals(patient.DischargeStatus?.OptionType))
{
_logger.LogError("Error deleting discharge. Patient altable: {patient}", patient);
return;
}
await DeleteDischargeAsync(apiRequest.Discharge);
break;
}
}
}
catch (Exception ex)
{
_logger.LogError("Exception processing discharge api request {discharge} . Exception: {ex}",
apiRequest.Discharge, ex);
}
}
public Task SaveRequestAsync(ApiRequest apiRequest)
{
return Task.FromResult(Task.Run(async () => { await SaveRequest(apiRequest); }));
}
// Revisar
public async void SendDischargeBroadcast(Discharge discharge, OperationType operation)
{
try
{
if (discharge.PointOfCareId == null)
{
_logger.LogError("Error sending discharge broadcast. Unit name is null or empty {discharge} .",
discharge);
return;
}
var subscribersGroup = _subscribersService.GetSubscribers()
.Where(s => s.LocationIds.Any(c => c == discharge.PointOfCareId)).GroupBy(h => h.Locale)
.ToList();
var unit = await _unitService.FindById(discharge.UnitId);
foreach (var group in subscribersGroup)
{
var locale = group.Key ?? LocaleEnum.Default;
IEnumerable<WsSubscriber> subscribers = group;
foreach (var subscriber in subscribers)
{
var dischargeWithLocale = await GetDischargeWithLocale(unit, discharge, locale);
_ = _clientMessageService.SendAsync(subscriber.Id, operation, dischargeWithLocale);
}
}
}
catch (Exception ex)
{
_logger.LogError("Exception sending discharge broadcast. Operation type: {op}. Exception: {ex}",
operation.ToString(), ex);
}
}
public async Task UpdatePatientMasterListItemChange(UpdateOptionMasterListDto opt, IEnumerable<Unit> unitList,
string typeName)
{
var unitIds = unitList.Select(x => x.Id).ToList();
await _dischargeRepository.GetDischargesByUnitIds(unitIds);
var dischargeUpdatedList = await _dischargeRepository.UpdateMasterListOption(unitIds, opt, typeName);
var updatedList = dischargeUpdatedList as Discharge[] ?? dischargeUpdatedList.ToArray();
foreach (var discharge in updatedList)
{
var oldDischarge = updatedList.FirstOrDefault(dis => dis.Id == discharge.Id);
await _auditService.CreateAuditLogAsync(_httpContextAccessor.HttpContext?.User!, oldDischarge!, discharge);
SendDischargeBroadcast(discharge, OperationType.UpdateDischarge);
}
}
public async Task DeletePatientMasterListItem(OptionList opt, IEnumerable<Unit> unitList, string typeName)
{
var unitIds = unitList.Select(x => x.Id).ToList();
var patientUpdatedList = await _dischargeRepository.DeleteMasterListOption(unitIds, opt, typeName);
foreach (var discharge in patientUpdatedList)
{
var dischargeUpdated = await GetDischargeByIdAsync(discharge.Id);
await _auditService.CreateAuditLogAsync(_httpContextAccessor.HttpContext?.User!, discharge, null);
if (dischargeUpdated != null)
SendDischargeBroadcast(discharge, OperationType.UpdateDischarge);
}
}
public async Task DeleteDischargesByUnitId(ObjectId unitId)
{
await _dischargeRepository.DeleteByUnitId(unitId);
}
private async Task<Discharge> GetDischargeWithLocale(Unit? unit, Discharge discharge, LocaleEnum locale)
{
if (unit == null)
return discharge;
if (locale == LocaleEnum.Default)
return discharge;
// Campos del discharge que deben traducirse
var listMap = new List<(string field, ObjectId? listId, MasterListType type)>
{
("serviceOption", unit.ServiceListId, MasterListType.ServiceList),
("destinationOption", unit.DestinationListId, MasterListType.DestinationList)
};
foreach (var (field, listId, masterListType) in listMap)
{
if (listId == null)
continue;
// Obtener propiedad desde DISCHARGE, no Patient
var prop = typeof(Discharge).GetProperty(
field,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (prop == null)
continue;
var propValue = prop.GetValue(discharge);
if (propValue == null)
continue;
// Cargar master list traducida según locale
var listObj = await _masterListServiceFactory
.GetMasterListById(masterListType, listId.Value, locale);
if (listObj == null)
continue;
var master = listObj as dynamic;
IEnumerable<OptionList> masterOptions = master.Options;
// El campo puede ser OptionList simple
if (propValue is OptionList { Id: not null } option)
{
var translated = masterOptions.FirstOrDefault(o => o.Id == option.Id);
if (translated != null) option.Name = translated.Name; // Solo traducimos el nombre
}
}
return discharge;
}
}