using ClosedXML.Excel; using HospitalManagementSystem.Doctors; using HospitalManagementSystem.Documents; using HospitalManagementSystem.Dto; using HospitalManagementSystem.GlobalEnum; using HospitalManagementSystem.Patients.Dto; using HospitalManagementSystem.Permissions; using HospitalManagementSystem.Shared; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Linq.Dynamic.Core; using System.Text.Json; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Content; using Volo.Abp.Domain.Repositories; using static HospitalManagementSystem.Permissions.HospitalManagementSystemPermissions; namespace HospitalManagementSystem.Patients { public class PatientAppService : Volo.Abp.Application.Services.ApplicationService { private IRepository _patientrecordRepository; private IRepository _patientRepository; private IRepository _entityDocumentRepository; private IRepository _patientDocumentRepository; private IRepository _doctorrepository; private readonly IWebHostEnvironment _env; private SharedAppService _sharedappService; List uniqueid = new List(); public PatientAppService(IRepository patientrecordRepository, IRepository patientRepository, IWebHostEnvironment env, IRepository entityDocumentRepository, IRepository patientDocumentRepository, SharedAppService sharedappService, IRepository doctorrepository) { _patientrecordRepository = patientrecordRepository; _patientRepository = patientRepository; _env = env; _entityDocumentRepository = entityDocumentRepository; _patientDocumentRepository = patientDocumentRepository; _sharedappService = sharedappService; _doctorrepository = doctorrepository; } #region PatientRecord #region Get Patient List with Paging and Searching [Authorize(HospitalManagementSystemPermissions.Patient.Default)] public async Task> GetPatientRecordListAsync(PagingSortResultDto input, Guid Id) { var queryable = await _patientrecordRepository.GetQueryableAsync(); var filteredQuery = queryable .Include(x => x.Patients) .Include(x => x.DoctorAssigned) .Include(x => x.LabReportUrl) .Include(x => x.MedicationUrl) .Include(x => x.MedicationHistoryUrl) .WhereIf(!string.IsNullOrEmpty(input.Search), x => x.Patients.Name.ToLower().Contains(input.Search.ToLower()) || x.Patients.Email.Contains(input.Search)) .Where(x => x.Patients.Id == Id); var totalCount = await filteredQuery.CountAsync(); filteredQuery = !string.IsNullOrEmpty(input.Sorting) ? filteredQuery.OrderBy(input.Sorting) : filteredQuery.OrderBy(x => x.Id); var pagedQuery = await filteredQuery .Skip(input.SkipCount) .Take(input.MaxResultCount) .ToListAsync(); var patientrecorddto = ObjectMapper.Map, List>(pagedQuery); foreach (var pr in patientrecorddto) { pr.LabReportUrl = filteredQuery.Where(x => x.Id == pr.Id).Select(x => x.LabReportUrl.FilePath).FirstOrDefault(); pr.MedicationUrl = filteredQuery.Where(x => x.Id == pr.Id).Select(x => x.MedicationUrl.FilePath).FirstOrDefault(); pr.MedicationHistoryUrl = filteredQuery.Where(x => x.Id == pr.Id).Select(x => x.MedicationHistoryUrl.FilePath).FirstOrDefault(); } return new PagedResultDto( totalCount, patientrecorddto ); } #endregion #region Get Single Patient by Id [Authorize(HospitalManagementSystemPermissions.Patient.Default)] public async Task GetPatientRecordByIdAsync(Guid id) { var patient = await _patientrecordRepository.GetQueryableAsync().Result .Include(x => x.LabReportUrl) .Include(x => x.MedicationUrl) .Include(x => x.MedicationHistoryUrl) .Where(x => x.Id == id).FirstOrDefaultAsync(); var patientdto = ObjectMapper.Map(patient); patientdto.LabReportUrl = patient.LabReportUrl != null ? patient.LabReportUrl.FilePath : null; patientdto.MedicationUrl = patient.MedicationUrl != null ? patient.MedicationUrl.FilePath : null; patientdto.MedicationHistoryUrl = patient.MedicationHistoryUrl != null ? patient.MedicationHistoryUrl.FilePath : null; return patientdto; } #endregion #region Export Patient Data to Excel public async Task GetExportPatientRecordAsync() { var patientrecord = await _patientrecordRepository.GetQueryableAsync().Result.Include(x => x.Patients).ToListAsync(); var folderPath = Path.Combine(_env.WebRootPath, "temp"); if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); // Ensure the folder exists } var filename = "Patients_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".xlsx"; var filePath = Path.Combine(folderPath, filename); // Create a workbook and worksheet using (var workbook = new XLWorkbook()) { var worksheet = workbook.Worksheets.Add("Patients"); worksheet.Cell(1, 1).Value = "Full Name"; worksheet.Cell(1, 2).Value = "Gender"; worksheet.Cell(1, 3).Value = "Date of Admission"; worksheet.Cell(1, 4).Value = "Discharge Date"; worksheet.Cell(1, 5).Value = "Diagnosis"; worksheet.Cell(1, 6).Value = "Treatment Plan"; worksheet.Cell(1, 7).Value = "Doctor Assigned"; worksheet.Cell(1, 8).Value = "Doctor Notes"; worksheet.Cell(1, 9).Value = "Next Follow-Up"; worksheet.Cell(1, 10).Value = "Lab Report URL"; worksheet.Cell(1, 11).Value = "Medication URL"; worksheet.Cell(1, 12).Value = "Medication History URL"; worksheet.Cell(1, 13).Value = "Status"; for (int i = 0; i < patientrecord.Count; i++) { var patient = patientrecord[i]; worksheet.Cell(i + 2, 1).Value = patient.Patients.Name; worksheet.Cell(i + 2, 2).Value = patient.Patients.Gender.ToString(); worksheet.Cell(i + 2, 3).Value = patient.DateOfAdmission.ToShortDateString(); worksheet.Cell(i + 2, 4).Value = patient.DischargeDate?.ToShortDateString() ?? "N/A"; worksheet.Cell(i + 2, 5).Value = patient.Diagnosis; worksheet.Cell(i + 2, 6).Value = patient.TreatmentPlan; worksheet.Cell(i + 2, 7).Value = (patient.DoctorAssigned?.FirstName + patient.DoctorAssigned?.LastName) ?? "Not Assigned"; worksheet.Cell(i + 2, 8).Value = patient.DoctorNotes; worksheet.Cell(i + 2, 9).Value = patient.NextFollowUp?.ToShortDateString() ?? "N/A"; worksheet.Cell(i + 2, 10).Value = patient.LabReportUrl?.FilePath ?? "No Report"; worksheet.Cell(i + 2, 11).Value = patient.MedicationUrl?.FilePath ?? "No Medication"; worksheet.Cell(i + 2, 12).Value = patient.MedicationHistoryUrl?.FilePath ?? "No History"; worksheet.Cell(i + 2, 13).Value = patient.Status.ToString(); } worksheet.Columns().AdjustToContents(); workbook.SaveAs(filePath); } byte[] fileBytes = await File.ReadAllBytesAsync(filePath); File.Delete(filePath); return new FileDownloadDto { FileName = filename, FileContent = Convert.ToBase64String(fileBytes) // Use Base64 encoding for file content }; } #endregion #region Create Patient [Authorize(HospitalManagementSystemPermissions.Patient.Create)] public async Task CreatePatientRecordAsync(CreateUpdatePatientRecordDto input) { var patientEntity = await _patientRepository.GetAsync(input.PatientId); // Get Patient from DB var doctorEntity = await _doctorrepository.GetAsync(input.DoctorAssignedID.Value); var patientRecord = ObjectMapper.Map(input); patientRecord.Patients = patientEntity; patientRecord.DoctorAssigned = doctorEntity != null ? doctorEntity : null; List entitydocument = new List(); List patientDocuments = new List(); if (input.LabReportUrlID != Guid.Empty) uniqueid.Add(input.LabReportUrlID.Value); if (input.MedicationUrlID != Guid.Empty) uniqueid.Add(input.MedicationUrlID.Value); if (input.MedicationHistoryUrlID != Guid.Empty) uniqueid.Add(input.MedicationHistoryUrlID.Value); if (uniqueid.Count > 0) { entitydocument = await _sharedappService.SaveFileToDocument(patientEntity, uniqueid); foreach (var entity in entitydocument) { switch (entity.TagName) { case "Lab-Report": patientRecord.LabReportUrl = entity; break; case "Medication": patientRecord.MedicationUrl = entity; break; case "Medication-History": patientRecord.MedicationHistoryUrl = entity; break; } } } patientRecord = await _patientrecordRepository.InsertAsync(patientRecord); // Fetch existing patient documents in one query var existingPatientDocs = await _patientDocumentRepository.GetQueryableAsync() .Result.Where(x => x.Patients.Id == input.PatientId) .ToListAsync(); foreach (var document in entitydocument) { var existingDoc = existingPatientDocs.FirstOrDefault(x => x.TagName == document.TagName); var patientDocument = new PatientDocument { Patients = patientEntity, EntityDocuments = document, TagName = document.TagName }; if (existingDoc != null) { existingDoc.EntityDocuments = document; // Update reference await _patientDocumentRepository.UpdateAsync(existingDoc); } else { patientDocuments.Add(patientDocument); } } // Batch insert new patient documents if (patientDocuments.Any()) { await _patientDocumentRepository.InsertManyAsync(patientDocuments); } uniqueid.Clear(); } #endregion #region Update Patient [Authorize(HospitalManagementSystemPermissions.Patient.Edit)] public async Task UpdatePatientRecordAsync(Guid id, CreateUpdatePatientRecordDto input) { try { var patientRecord = await _patientrecordRepository.GetQueryableAsync().Result.Include(x => x.Patients).Include(x => x.DoctorAssigned).Where(x => x.Id == id).FirstOrDefaultAsync(); List entitydocument = new List(); List patientDocuments = new List(); if (patientRecord.DoctorAssigned?.Id != input.DoctorAssignedID.Value) { patientRecord.DoctorAssigned = await _doctorrepository.GetAsync(input.DoctorAssignedID.Value); } ObjectMapper.Map(input, patientRecord); if (input.LabReportUrlID != Guid.Empty) uniqueid.Add(input.LabReportUrlID.Value); if (input.MedicationUrlID != Guid.Empty) uniqueid.Add(input.MedicationUrlID.Value); if (input.MedicationHistoryUrlID != Guid.Empty) uniqueid.Add(input.MedicationHistoryUrlID.Value); if (uniqueid.Count > 0) { entitydocument = await _sharedappService.SaveFileToDocument(patientRecord.Patients, uniqueid); foreach (var entity in entitydocument) { switch (entity.TagName) { case "Lab-Report": patientRecord.LabReportUrl = entity; break; case "Medication": patientRecord.MedicationUrl = entity; break; case "Medication-History": patientRecord.MedicationHistoryUrl = entity; break; } } } // Fetch existing patient documents in one query var existingPatientDocs = await _patientDocumentRepository.GetQueryableAsync() .Result.Where(x => x.Patients.Id == input.PatientId) .ToListAsync(); foreach (var document in entitydocument) { var existingDoc = existingPatientDocs.FirstOrDefault(x => x.TagName == document.TagName); var patientDocument = new PatientDocument { Patients = patientRecord.Patients, EntityDocuments = document, TagName = document.TagName }; if (existingDoc != null) { existingDoc.EntityDocuments = document; // Update reference await _patientDocumentRepository.UpdateAsync(existingDoc); } else { patientDocuments.Add(patientDocument); } } // Batch insert new patient documents if (patientDocuments.Any()) { await _patientDocumentRepository.InsertManyAsync(patientDocuments); } uniqueid.Clear(); patientRecord = await _patientrecordRepository.UpdateAsync(patientRecord); } catch (Exception ex) { throw new Exception(ex.Message); } } #endregion #region Delete Patient [Authorize(HospitalManagementSystemPermissions.Patient.Delete)] public async Task DeletePatientRecordAsync(Guid id) { await _patientrecordRepository.DeleteAsync(id); } #endregion #endregion #region Patient #region Get Patient List with Paging and Searching [Authorize(HospitalManagementSystemPermissions.Patient.Default)] public async Task> GetPatientListAsync(PagingSortResultDto input) { List query; if (!string.IsNullOrEmpty(input.Search)) { query = _patientRepository.GetQueryableAsync().Result .Where(x => x.Name.ToLower().Contains(input.Search.ToLower()) || x.Email.Contains(input.Search)) .OrderBy(input.Sorting ?? (nameof(Patient.Id) + " asc")) .Skip(input.SkipCount) .Take(input.MaxResultCount) .ToList(); } else { query = await _patientRepository.GetPagedListAsync( input.SkipCount, input.MaxResultCount, input.Sorting ?? nameof(Patient.Name) ); } var totalCount = await _patientRepository.CountAsync(); return new PagedResultDto( totalCount, ObjectMapper.Map, List>(query) ); } #endregion #region Get Single Patient by Id [Authorize(HospitalManagementSystemPermissions.Patient.Default)] public async Task GetPatientByIdAsync(Guid id) { var patient = await _patientRepository.GetQueryableAsync().Result.Include(x => x.Images).Where(x => x.Id == id).FirstOrDefaultAsync(); var patientdto = ObjectMapper.Map(patient); patientdto.Imagepath = patient.Images != null ? patient.Images.FilePath : null; return patientdto; } #endregion #region Export Patient Data to Excel public async Task GetExportPatientDataAsync() { var patients = await _patientRepository.GetQueryableAsync().Result.Include(x => x.Images).ToListAsync(); var folderPath = Path.Combine(_env.WebRootPath, "temp"); if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); } var filename = "Patients_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".xlsx"; var filePath = Path.Combine(folderPath, filename); using (var workbook = new XLWorkbook()) { var worksheet = workbook.Worksheets.Add("Patients"); worksheet.Cell(1, 1).Value = "Patient Card ID"; worksheet.Cell(1, 2).Value = "Name"; worksheet.Cell(1, 3).Value = "Gender"; worksheet.Cell(1, 4).Value = "Age"; worksheet.Cell(1, 5).Value = "Mobile"; worksheet.Cell(1, 6).Value = "Email"; worksheet.Cell(1, 7).Value = "Address"; worksheet.Cell(1, 8).Value = "Blood Group"; worksheet.Cell(1, 9).Value = "Insurance Provider"; worksheet.Cell(1, 10).Value = "Patient Images"; for (int i = 0; i < patients.Count; i++) { worksheet.Cell(i + 2, 1).Value = patients[i].PatientCardId; worksheet.Cell(i + 2, 2).Value = patients[i].Name; worksheet.Cell(i + 2, 3).Value = patients[i].Gender.ToString(); worksheet.Cell(i + 2, 4).Value = patients[i].Age; worksheet.Cell(i + 2, 5).Value = patients[i].Mobile; worksheet.Cell(i + 2, 6).Value = patients[i].Email; worksheet.Cell(i + 2, 7).Value = patients[i].Address; worksheet.Cell(i + 2, 8).Value = patients[i].BloodGroup; worksheet.Cell(i + 2, 9).Value = patients[i].InsuranceProvider ?? "N/A"; worksheet.Cell(i + 2, 10).Value = patients[i].Images?.GeneratedFileName ?? "N/A"; } worksheet.Columns().AdjustToContents(); workbook.SaveAs(filePath); } byte[] fileBytes = await File.ReadAllBytesAsync(filePath); File.Delete(filePath); return new FileDownloadDto { FileName = filename, FileContent = Convert.ToBase64String(fileBytes) }; } #endregion #region Create Patient [Authorize(HospitalManagementSystemPermissions.Patient.Create)] public async Task CreatePatientAsync(CreateUpdatePatientDto input) { List patientDocuments = new List(); List entitydocument = new List(); var patient = ObjectMapper.Map(input); patient = await _patientRepository.InsertAsync(patient); if (input.ImageID != Guid.Empty) { uniqueid.Add(input.ImageID.Value); entitydocument = await _sharedappService.SaveFileToDocument(patient, uniqueid, true); foreach (var entity in entitydocument) { if (entity.TagName == "Image") { patient.Images = entity; } } } // Fetch existing patient documents in one query var existingPatientDocs = await _patientDocumentRepository.GetQueryableAsync() .Result.Where(x => x.Patients.Id == patient.Id) .ToListAsync(); foreach (var document in entitydocument) { var existingDoc = existingPatientDocs.FirstOrDefault(x => x.TagName == document.TagName); var patientDocument = new PatientDocument { Patients = patient, EntityDocuments = document, TagName = document.TagName }; if (existingDoc != null) { existingDoc.EntityDocuments = document; // Update reference await _patientDocumentRepository.UpdateAsync(existingDoc); } else { patientDocuments.Add(patientDocument); } } // Batch insert new patient documents if (patientDocuments.Any()) { await _patientDocumentRepository.InsertManyAsync(patientDocuments); } uniqueid.Clear(); } #endregion #region Update Patient [Authorize(HospitalManagementSystemPermissions.Patient.Edit)] public async Task UpdatePatientAsync(Guid id, CreateUpdatePatientDto input) { var patient = await _patientRepository.GetQueryableAsync().Result.Include(x => x.Images).Where(x => x.Id == id).FirstOrDefaultAsync(); List entitydocument = new List(); List patientDocuments = new List(); ObjectMapper.Map(input, patient); if (input.ImageID != Guid.Empty) { uniqueid.Add(input.ImageID.Value); entitydocument = await _sharedappService.SaveFileToDocument(patient, uniqueid); foreach (var entity in entitydocument) { if (entity.TagName == "Image") { patient.Images = entity; } } } // Fetch existing patient documents in one query var existingPatientDocs = await _patientDocumentRepository.GetQueryableAsync() .Result.Where(x => x.Patients.Id == patient.Id) .ToListAsync(); foreach (var document in entitydocument) { var existingDoc = existingPatientDocs.FirstOrDefault(x => x.TagName == document.TagName); var patientDocument = new PatientDocument { Patients = patient, EntityDocuments = document, TagName = document.TagName }; if (existingDoc != null) { existingDoc.EntityDocuments = document; // Update reference await _patientDocumentRepository.UpdateAsync(existingDoc); } else { patientDocuments.Add(patientDocument); } } // Batch insert new patient documents if (patientDocuments.Any()) { await _patientDocumentRepository.InsertManyAsync(patientDocuments); } uniqueid.Clear(); patient = await _patientRepository.UpdateAsync(patient); } #endregion #region Delete Patient [Authorize(HospitalManagementSystemPermissions.Patient.Delete)] public async Task DeletePatientAsync(Guid id) { await _patientRepository.DeleteAsync(id); } #endregion #endregion #region Get Status Dropdown public async Task> GetStatusDropdownAsync() { List statuslist = new List(); statuslist = Enum.GetValues(typeof(Status)) .Cast() .Select(e => new DropDownItems { Label = e.ToString(), Value = (int)e }) .ToList(); statuslist.Add(new DropDownItems { Label = "Select a Status", Value = 0 }); statuslist = statuslist.OrderBy(x => x.Value).ToList(); return await Task.FromResult(statuslist); } #endregion //#region UploadFile //public async Task UploadFileAsync(string TagName, IRemoteStreamContent file) //{ // if (file == null) // { // throw new Exception("File cannot be null"); // } // string patientFolder = Path.Combine(_env.WebRootPath, "temp"); // Guid uniqueId = Guid.NewGuid(); // if (!Directory.Exists(patientFolder)) // { // Directory.CreateDirectory(patientFolder); // } // string fileExtension = Path.GetExtension(file.FileName); // string fileName = $"{uniqueId}({TagName}){fileExtension}"; // string filePath = Path.Combine(patientFolder, fileName); // using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write)) // { // await file.GetStream().CopyToAsync(fileStream); // } // var metadata = new // { // OriginalFileName = file.FileName, // FileName = fileName, // FileSize = new FileInfo(filePath).Length.ToString(), // FilePath = filePath, // UploadDate = DateTime.UtcNow, // FileType = fileExtension, // TagName = TagName, // }; // string jsonFileName = $"{uniqueId}({TagName}).json"; // string jsonFilePath = Path.Combine(patientFolder, jsonFileName); // await File.WriteAllTextAsync(jsonFilePath, JsonSerializer.Serialize(metadata, new JsonSerializerOptions { WriteIndented = true })); // return uniqueId; //} //#endregion //#region SaveFileToDocument //public async Task> SaveFileToDocument(Patient patient, List uniqueIds, bool isNew = false) //{ // try // { // string tempFolder = Path.Combine(_env.WebRootPath, "temp"); // string patientFolder = Path.Combine(_env.WebRootPath, "uploads", $"{patient.Id}({patient.Name})"); // if (!Directory.Exists(patientFolder)) // { // Directory.CreateDirectory(patientFolder); // } // List savedDocuments = new List(); // foreach (var uniqueId in uniqueIds) // { // // Fetch all matching JSON metadata files for the current uniqueId // foreach (var jsonFilePath in Directory.EnumerateFiles(tempFolder, $"{uniqueId}(*).json")) // { // string jsonContent = await File.ReadAllTextAsync(jsonFilePath); // var metadata = JsonSerializer.Deserialize(jsonContent); // string originalFileName = metadata.GetProperty("OriginalFileName").GetString(); // string generatedFileName = metadata.GetProperty("FileName").GetString(); // string fileSize = metadata.GetProperty("FileSize").GetString(); // string filePath = metadata.GetProperty("FilePath").GetString(); // string fileType = metadata.GetProperty("FileType").GetString(); // string tagName = metadata.GetProperty("TagName").GetString(); // DateTime uploadDate = metadata.GetProperty("UploadDate").GetDateTime(); // // Move the file from temp folder to patient folder // string newFilePath = Path.Combine(patientFolder, generatedFileName); // if (File.Exists(filePath)) // { // File.Move(filePath, newFilePath, true); // } // newFilePath = newFilePath.Split("wwwroot")[1]; // var document = new EntityDocument // { // OriginalFileName = originalFileName, // GeneratedFileName = generatedFileName, // FileSize = fileSize, // FilePath = newFilePath, // FileType = fileType, // TagName = tagName, // UploadDate = uploadDate // }; // savedDocuments.Add(document); // // Delete JSON file after processing // File.Delete(jsonFilePath); // } // } // // Batch insert entity documents // if (savedDocuments.Any()) // { // await _entityDocumentRepository.InsertManyAsync(savedDocuments); // } // //// Fetch existing patient documents in one query // //var existingPatientDocs = await _patientDocumentRepository.GetQueryableAsync() // // .Result.Where(x => x.Patients.Id == patient.Id) // // .ToListAsync(); // //List patientDocuments = new List(); // //foreach (var document in savedDocuments) // //{ // // var existingDoc = existingPatientDocs.FirstOrDefault(x => x.TagName == document.TagName); // // var patientDocument = new PatientDocument // // { // // Patients = patient, // // EntityDocuments = document, // // TagName = document.TagName // // }; // // if (existingDoc != null) // // { // // existingDoc.EntityDocuments = document; // Update reference // // await _patientDocumentRepository.UpdateAsync(existingDoc); // // } // // else // // { // // patientDocuments.Add(patientDocument); // // } // //} // //// Batch insert new patient documents // //if (patientDocuments.Any()) // //{ // // await _patientDocumentRepository.InsertManyAsync(patientDocuments); // //} // uniqueid.Clear(); // return savedDocuments; // } // catch (Exception ex) // { // uniqueid.Clear(); // throw new Exception($"Error saving files for patient {patient.Id}: {ex.Message}", ex); // } //} //#endregion } }