/// <summary> /// This method decides to insert sample accepted date time for the sample. /// </summary> /// <param name="insertAR">Analysis request parameters</param> /// <returns>true or false indicating whether the sample needs to be collected</returns> private bool DecideToMarkSampleAsAccepted(AnalysisRequestDataModel insertAR) { if (insertAR.SampleReceivedDate.HasValue) { return(true); } return(false); }
private RequestDataStatus AssesClinicalDetailStatus (AnalysisRequestDataModel request, List <ClinicalDetailsDatabaseModel> clinicalDetails) { var status = RequestDataStatus.New; if (!ClinicalDetailsDatabaseModel.AreEqual(request.ClinicalDetails, clinicalDetails)) { status = RequestDataStatus.Dirty; } else { status = RequestDataStatus.Clean; } return(status); }
private RequestDataStatus AssesPatientStatus (PatientModel patient, AnalysisRequestDataModel request) { var status = RequestDataStatus.New; if (patient != null) { if (!patient.AreEqual(request)) { status = RequestDataStatus.Dirty; } else { status = RequestDataStatus.Clean; } } return(status); }
public async Task InsertSampleCollectedDate(AnalysisRequestDataModel request, int loggedInUserId) { var storedProcedure = "[dbo].[usp_UpdateSampleWithCin]"; var parameters = new { Cin = request.Cin, SiteId = request.SiteId, CollectionDate = request.SampleCollectionDate, ReceivedDate = request.SampleReceivedDate, UserId = loggedInUserId }; try { _ = await SelectInsertOrUpdateAsync <dynamic, dynamic>(storedProcedure, parameters); } catch (Exception) { throw; } }
/// <summary> /// Asses the status of request and sample data supplied by /// UI compared with that on database /// </summary> /// <param name="requestAndSample"></param> /// <param name="request"></param> /// <returns>An enum indicating new, dirty or clean status of supplied data /// in comparision with database. /// </returns> private RequestDataStatus AssesRequestAndSampleStatus (RequestAndSampleDatabaseModel requestAndSample, AnalysisRequestDataModel request) { //Setting an initial status of new var status = RequestDataStatus.New; if (requestAndSample != null) { //checks Age, Cin, Site, Collection Date and received date if (!requestAndSample.AreEqual(request)) { status = RequestDataStatus.Dirty; //This will require an update. updates will be done in a later step. } else { status = RequestDataStatus.Clean; } } return(status); }
private async Task <bool> InsertNewCompleteRequest (int patientId, AnalysisRequestDataModel request, int loggedInUserId) { var insertData = new RequestSampleAndClinicalDetailsInsertDatabaseModel(patientId, request, statusDataAccess, loggedInUserId); bool success; if (string.IsNullOrEmpty(insertData.CommaDelimitedClinicalDetailsIds)) { // when clinical details are not available. success = await SelectInsertOrUpdateAsync <bool, dynamic> ("[dbo].[usp_InsertAnalysisRequestSampleAndRequestedTests]", insertData.GetWithoutClinicalDetails()); await InsertSampleCollectedDate(request, loggedInUserId); return(success); } //with clinical details success = await SelectInsertOrUpdateAsync <bool, RequestSampleAndClinicalDetailsInsertDatabaseModel> ("[dbo].[usp_InsertAnalysisRequestClinicalDetailsSampleAndRequestedTests]", insertData); await InsertSampleCollectedDate(request, loggedInUserId); return(success); }
/// <summary> /// Determines whether the patient or an existing analysis request is changed to another patient /// with current submitted request confirmation. Changing patient to a whole another patient is not allowed, but /// updating patient details is allowed except for NationalId / PP /// </summary> /// <param name="request">user submitted request data via UI</param> /// <returns>Returns true if the Nid/Pp does not match with the request of the same CIN on the database</returns> private async Task <ExistingRequestsPatientComparisionArgs> IsPatientDifferentForAnalysisRequest (AnalysisRequestDataModel request) { //get database patient details for the CIN var patient = await patientData.GetPatientBySamplCin(request.Cin); //If no records found on the database for the CIN, return false. if (patient is null) { return(new ExistingRequestsPatientComparisionArgs() { IsAnalysisRequestsPatientChanged = false }); } //If NidPp matches with the user input, return false. if (patient.IsMatch(request)) { return(new ExistingRequestsPatientComparisionArgs() { IsAnalysisRequestsPatientChanged = false }); } // if none of the above matches, It means that the patient changed to another patient for an existing request. // So return true with database patient data. return(new ExistingRequestsPatientComparisionArgs() { IsAnalysisRequestsPatientChanged = true, DatabasePatient = new PatientNidPpAndNameModel() { Fullname = patient.Fullname, NidPp = patient.NidPp } }); }
public async Task <bool> ConfirmRequestAsync(AnalysisRequestDataModel request, int loggedInUserId, bool isSamplePriority = false) { RequestDataStatus requestSampleStatus = RequestDataStatus.New; RequestDataStatus patientStatus = RequestDataStatus.New; RequestDataStatus clinicalDetailsStatus = RequestDataStatus.New; int InsertedPatientId = 0; List <TestsModel> TestsToInsert = new List <TestsModel>(); List <TestsModel> TestsToRemove = new List <TestsModel>(); List <ClinicalDetailsDatabaseModel> clinicalDetails = new List <ClinicalDetailsDatabaseModel>(); List <ResultsDatabaseModel> databaseTestsForRequest = new List <ResultsDatabaseModel>(); #region Request Rejection Criteria - Primary //Requests with no Cin are invalid if (string.IsNullOrEmpty(request.Cin)) { throw new ArgumentNullException("CIN", "COVID Identification number cannot be null! Analysis request not saved!"); } //Requests with not tests are not valid. if (request.Tests.Count == 0) { throw new ArgumentException("A minimum of one test is mandatory to confirm the request!"); } //Checking whether the current request exists on the database. If it does, any edits for the request should not change the patient to a new patient. var PatientDataValidityForAnalysisRequest = await IsPatientDifferentForAnalysisRequest(request); //if the data update criteria for existing request fails, throw an exception saying so... if (PatientDataValidityForAnalysisRequest.IsAnalysisRequestsPatientChanged) { throw new Exception("Cannot confirm request. Cannot change patient for a previously confirmed request!\n" + $"Previous details: {request.Cin}: {PatientDataValidityForAnalysisRequest.DatabasePatient.NidPp} ( {PatientDataValidityForAnalysisRequest.DatabasePatient.Fullname} )\n" + $"Current details: {request.Cin}: {request.NationalIdPassport} ( {request.Fullname} )"); } #endregion #region Fetch Present data //load the sample from database, if exists var requestAndSample = await GetSampleByIdAsync(request.Cin); //fetch patient data specific to the now handlng request PatientModel patient = (await patientData.GetPatientByNidPp(request.NationalIdPassport)).FirstOrDefault(); //if the request and sample exist on the database... if (requestAndSample != null) { //Get clinical details saved on the database for request clinicalDetails = await clinicalDetailsData.GetClinicalDetailsByRequestId(requestAndSample.RequestId); //Get requested tests saved on the database databaseTestsForRequest = await GetRequestedTestsByRequestIdAsync(requestAndSample.RequestId); } #endregion #region Determine request, sample and , clinical details status | Determine Tests to insert / delete //Checking whether the current handling request is new, clean, or dirty. requestSampleStatus = AssesRequestAndSampleStatus(requestAndSample, request); //checking whether the patient for the current request is new, clean or dirty. patientStatus = AssesPatientStatus(patient, request); //if the request and sample was previously saved on database.... if (requestAndSample != null) { //determine the status of clinical details... New, Clean or dirty. clinicalDetailsStatus = AssesClinicalDetailStatus(request, clinicalDetails); //Generate a list of tests to insert for the request TestsToInsert = GetTestsToInsert(request.Tests, databaseTestsForRequest); //Make a list of tests for the request that exists on the database but does not exist on the request. //NOTE: If no results exists for these tests, they will be removed. TestsToRemove = GetTestsToRemove(request.Tests, databaseTestsForRequest); } #endregion #region Insert / Update / Delete from database #region Database IO #region insert / update patient if (patientStatus == RequestDataStatus.Dirty) { var patientToUpdate = new PatientUpdateDatabaseModel() { Id = patient.Id, Fullname = request.Fullname, NidPp = request.NationalIdPassport, Birthdate = DateHelper.GetCD4FormatJustDateNoTime(request.Birthdate), GenderId = request.GenderId, AtollId = request.AtollId, CountryId = request.CountryId, Address = request.Address, PhoneNumber = request.PhoneNumber, InstituteAssignedPatientId = request.InstituteAssignedPatientId }; var isPatientUpdated = await patientData.UpdatePatientById(patientToUpdate); if (!isPatientUpdated) { throw new Exception("Cannot update patient data!"); } } if (patientStatus == RequestDataStatus.New) { //insert patient var patientToInsert = new PatientInsertDatabaseModel() { Fullname = request.Fullname, NidPp = request.NationalIdPassport, Birthdate = DateHelper.GetCD4FormatJustDateNoTime(request.Birthdate), GenderId = request.GenderId, AtollId = request.AtollId, CountryId = request.CountryId, Address = request.Address, PhoneNumber = request.PhoneNumber, InstituteAssignedPatientId = request.InstituteAssignedPatientId }; InsertedPatientId = await patientData.InsertPatient(patientToInsert); if (InsertedPatientId == 0) { throw new Exception("An error occured. Cannot insert the patient!"); } } #endregion #region Case New Request, Everything below the tree is new, Insert all if (requestSampleStatus == RequestDataStatus.New) { //IF REQUEST IS NEW:: CLINICAL DETAILS, SAMPLE AND REQUESTED TESTS //WILL BE NEW FOR SURE. SO HANDLE THEM ALL AT THE SAME TIME var output = await InsertNewCompleteRequest(GetPatientId(patient, InsertedPatientId), request, loggedInUserId); await InsertUpdateSamplePriorityAsync(request.Cin, isSamplePriority, loggedInUserId); return(output); } #endregion #region Update request if (requestSampleStatus == RequestDataStatus.Dirty) { var requestToUpdate = new AnalysisRequestUpdateDatabaseModel() { Id = requestAndSample.RequestId, PatientId = patient.Id, EpisodeNumber = request.EpisodeNumber, Age = request.Age }; var isRequestUpdated = await UpdateRequestAsync(requestToUpdate, loggedInUserId); if (!isRequestUpdated) { throw new Exception("Cannot update request data! [ either episode number, age or patient associated with request was not updated ]"); } } #endregion #region Update Sample if (requestSampleStatus == RequestDataStatus.Dirty) { var sampleToUpdate = new SampleUpdateDatabaseModel() { Cin = request.Cin, SiteId = request.SiteId, CollectionDate = request.SampleCollectionDate, ReceivedDate = request.SampleReceivedDate }; var output = await sampleDataAccess.UpdateSample(sampleToUpdate, loggedInUserId); if (!output) { throw new Exception("Cannot sample details. [May include: Site, collected date or received date]. Please verify!"); } } #endregion #region Update Results Table [Test data | NOT ACTUAL SAMPLE RESULTS] if (TestsToInsert.Count > 0 || TestsToRemove.Count > 0) { var output = await resultDataAccess.ManageRequestedTestsDataAsync(TestsToInsert, TestsToRemove, request.Cin, loggedInUserId); if (!output) { throw new Exception("Error adding or removing requested tests!"); } } #endregion #region Sync Clinical details data if (clinicalDetailsStatus == RequestDataStatus.Dirty) { //Sync string csvClinicalDetails = ClinicalDetailsDataAccess.GetCsvClinicalDetails(request.ClinicalDetails); var output = await clinicalDetailsData.SyncClinicalDetails (csvClinicalDetails, requestAndSample.RequestId); if (!output) { throw new Exception("Cannot update clinical details for the request."); } } #endregion #region Update Sample and Test Priority await InsertUpdateSamplePriorityAsync(request.Cin, isSamplePriority, loggedInUserId); #endregion #endregion #endregion return(true); }
public async Task <Response> Save(AnalysisRequestModel request) { _logger.LogDebug($"Analysis Request received from Billing.\n{JsonConvert.SerializeObject(request, Formatting.Indented)}"); //check for the presence of VALID userid of the user who accepted the sample if (request.Request.SampleReceivedBy == 0 || request.Request.SampleReceivedBy == 1 || request.Request.SampleReceivedBy == 2 || request.Request.SampleReceivedBy == 3) { return(new Response() { Status = 304, Message = "Required parameter not provided or invalid. [SampleReceivedBy:int]" }); } _logger.LogDebug("Building Analysis Request"); var insertAR = new AnalysisRequestDataModel() { EpisodeNumber = request.Request.MemoNumber, Cin = DeriveSampleNo(request.Patient), SiteId = request.Request.SiteId, SampleCollectionDate = GetDatetimeFromTicks(request.Request.SampleCollectedAt), SampleReceivedDate = GetDatetimeFromTicks(request.Request.SampleReceivedAt), NationalIdPassport = request.Patient.NidPp, Fullname = request.Patient.Fullname, Birthdate = GetDatetimeFromTicks(request.Patient.Birthdate), Age = request.Patient.Age, AtollId = request.Patient.AtollId, Address = request.Patient.Address, GenderId = request.Patient.GenderId, PhoneNumber = request.Patient.PhoneNumber, CountryId = request.Patient.NationalityId, Tests = new List <TestsModel>(), ClinicalDetails = new List <ClinicalDetailsSelectionModel>() }; //try parsing patient Id var isPatientIdLong = long.TryParse(request.Patient.PatientId, out var longPatientId); if (isPatientIdLong) { insertAR.InstituteAssignedPatientId = longPatientId; _logger.LogInformation($"Patient Id successfully parsed as long. Patient Id: {longPatientId}"); } if (!isPatientIdLong) { _logger.LogError($"Invalid patient Id. Expected to be numeric long. Actual: {request.Patient.PatientId}"); } var UnmappedTestCodesExist = false; _logger.LogDebug("Mapping analyses"); foreach (var item in request.Analyses.RequestedTests) { var cd4Tests = GetTestIdFromBillingCode(item); if (cd4Tests is null) { _logger.LogWarning($"Billing TestCode: {item} not mapped to any CD4 TestCodes"); UnmappedTestCodesExist = true; continue; } if (cd4Tests.Count == 0) { _logger.LogWarning($"Billing TestCode: {item} not mapped to any CD4 TestCodes"); UnmappedTestCodesExist = true; continue; } insertAR.Tests.AddRange(cd4Tests); _logger.LogDebug($"Billing TestCode: {item} mapped to test(s): {JsonConvert.SerializeObject(cd4Tests)}"); } _logger.LogDebug("Mapping analyses completed"); if (request.Analyses.RequestedTests.Count > 0 && insertAR.Tests.Count == 0) { _logger.LogInformation("Response code 500 with message None of the test codes are mapped. Analysis request not inserted to CD4"); return(new Response() { Status = 500, Message = "None of the test codes are mapped. Analysis request not inserted to CD4" }); } try { _logger.LogDebug("Calling datalayer for inserting/updating analysis request"); await _analysisRequestDataAccess.ConfirmRequestAsync(insertAR, 2); //ToDo: insert the person who received / accepted the sample await _ndaTrackingDataAccess.UpsertSampleReceivedUserIdAsync(insertAR.Cin, request.Request.SampleReceivedBy, 2); //insert the sample accepted date and time if required. if (DecideToMarkSampleAsAccepted(insertAR)) { _logger.LogInformation("Inserting sample accepted date and time"); await _statusDataAccess.SetSampleAcceptedTimeReceivedFromBilling (insertAR.Cin, insertAR.SampleReceivedDate.Value.ToString("yyyy-MM-dd HH:mm:ss")); } if (UnmappedTestCodesExist) { _logger.LogDebug("Response code 201 with message Some unmapped tests / profiles not inserted to CD4."); return(new Response() { Status = 201, Message = "Some unmapped tests / profiles not inserted to CD4." }); } _logger.LogDebug("Response code 200 with message success."); return(new Response() { Status = 200, Message = "Success" }); } catch (Exception ex) { _logger.LogDebug($"Response code 500 with message {ex.Message}."); return(new Response() { Status = 500, Message = ex.Message }); } }
public override async Task <Response> Save(AnalysisRequestModel request, ServerCallContext context) { _logger.LogDebug($"Analysis Request received from Billing.\n{JsonConvert.SerializeObject(request, Formatting.Indented)}"); _logger.LogDebug("Building Analysis Request"); var insertAR = new AnalysisRequestDataModel() { EpisodeNumber = request.Request.MemoNumber, Cin = request.Request.SampleId, SiteId = request.Request.SiteId, SampleCollectionDate = GetDatetimeFromTicks(request.Request.SampleCollectedDateTime), SampleReceivedDate = GetDatetimeFromTicks(request.Request.SampleReceivedDateTime), NationalIdPassport = request.Patient.NidPp, Fullname = request.Patient.Fullname, Birthdate = GetDatetimeFromTicks(request.Patient.Birthdate), Age = request.Patient.Age, AtollId = request.Patient.AtollId, Address = request.Patient.Address, GenderId = request.Patient.GenderId, PhoneNumber = request.Patient.PhoneNumber, CountryId = request.Patient.Nationality, Tests = new List <TestsModel>(), ClinicalDetails = new List <ClinicalDetailsSelectionModel>() }; var UnmappedTestCodesExist = false; _logger.LogDebug("Mapping analyses"); foreach (var item in request.Tests.AnalysisId) { var cd4Tests = GetTestIdFromBillingCode(item); if (cd4Tests is null) { _logger.LogWarning($"Billing TestCode: {item} not mapped to any CD4 TestCodes"); UnmappedTestCodesExist = true; continue; } if (cd4Tests.Count == 0) { _logger.LogWarning($"Billing TestCode: {item} not mapped to any CD4 TestCodes"); UnmappedTestCodesExist = true; continue; } insertAR.Tests.AddRange(cd4Tests); _logger.LogDebug($"Billing TestCode: {item} mapped to test(s): {JsonConvert.SerializeObject(cd4Tests)}"); } _logger.LogDebug("Mapping analyses completed"); if (request.Tests.AnalysisId.Count > 0 && insertAR.Tests.Count == 0) { _logger.LogInformation("Response code 500 with message None of the test codes are mapped. Analysis request not inserted to CD4"); return(new Response() { Status = 500, Message = "None of the test codes are mapped. Analysis request not inserted to CD4" }); } try { _logger.LogDebug("Calling datalayer for inserting/updating analysis request"); await _analysisRequestDataAccess.ConfirmRequestAsync(insertAR, 1); //insert the sample accepted date and time if required. if (DecideToMarkSampleAsAccepted(insertAR)) { _logger.LogInformation("Inserting sample accepted date and time"); await _statusDataAccess.SetSampleAcceptedTimeReceivedFromBilling (insertAR.Cin, insertAR.SampleReceivedDate.Value.ToString("yyyy-MM-dd HH:mm:ss")); } if (UnmappedTestCodesExist) { _logger.LogDebug("Response code 201 with message Some unmapped tests / profiles not inserted to CD4."); return(new Response() { Status = 201, Message = "Some unmapped tests / profiles not inserted to CD4." }); } _logger.LogDebug("Response code 200 with message success."); return(new Response() { Status = 200, Message = "Success" }); } catch (Exception ex) { _logger.LogDebug($"Response code 500 with message {ex.Message}."); return(new Response() { Status = 500, Message = ex.Message }); } }