///<summary>Moves all MedLab objects and any embedded PDFs tied to the MedLabResults to the PatCur. ///If the MedLab objects were not originally attached to a patient, any embedded PDFs will be in the image folder in a directory called ///"MedLabEmbeddedFiles" and will be moved to PatCur's image folder. ///If PatCur is null or the MedLabs are already attached to PatCur, does nothing.</summary> private void MoveLabsAndImagesHelper() { //if they have selected the same patient, nothing to do if (PatCur == null || PatCur.PatNum == _medLabCur.PatNum) { return; } //if the MedLab object(s) were attached to a patient and they are being moved to another patient, move the associated documents Patient patOld = Patients.GetPat(_medLabCur.PatNum); MedLabs.UpdateAllPatNums(ListMedLabs.Select(x => x.MedLabNum).ToList(), PatCur.PatNum); string atozFrom = ""; string atozTo = ""; if (PrefC.AtoZfolderUsed == DataStorageType.LocalAtoZ) { string atozPath = ImageStore.GetPreferredAtoZpath(); //if patOld is null, the file was placed into the image folder in a directory named MedLabEmbeddedFiles, not a patient's image folder if (patOld == null) { atozFrom = ODFileUtils.CombinePaths(atozPath, "MedLabEmbeddedFiles"); } else { atozFrom = ImageStore.GetPatientFolder(patOld, atozPath); } atozTo = ImageStore.GetPatientFolder(PatCur, atozPath); } else if (CloudStorage.IsCloudStorage) { atozFrom = ODFileUtils.CombinePaths(ImageStore.GetPreferredAtoZpath(), "MedLabEmbeddedFiles", '/'); atozTo = ImageStore.GetPatientFolder(PatCur, ""); } //get list of all DocNums of files referenced by MedLabResults which were embedded in the MedLab HL7 message as base64 text //in order to move the file (if not storing images in db) and assign (or reassign) the FileName List <long> listDocNums = ListMedLabs .SelectMany(x => x.ListMedLabResults .Select(y => y.DocNum) .Where(y => y > 0)) .Distinct().ToList(); List <Document> listDocs = Documents.GetByNums(listDocNums); int fileMoveFailures = 0; for (int i = 0; i < listDocs.Count; i++) { Document doc = listDocs[i]; string destFileName = Documents.GetUniqueFileNameForPatient(PatCur, doc.DocNum, Path.GetExtension(doc.FileName)); if (PrefC.AtoZfolderUsed == DataStorageType.LocalAtoZ) { string fromFilePath = ODFileUtils.CombinePaths(atozFrom, doc.FileName); if (!File.Exists(fromFilePath)) { //the DocNum in the MedLabResults table is pointing to a file that either doesn't exist or is not accessible, can't move/copy it fileMoveFailures++; continue; } string destFilePath = ODFileUtils.CombinePaths(atozTo, destFileName); if (File.Exists(destFilePath)) //should never happen, since we already got a unique file name, but just in case //The file being copied has the same name as a file that exists in the destination folder, use a unique file name and update document table { destFileName = patOld.PatNum.ToString() + "_" + doc.FileName; //try to prepend patient's PatNum to the original file name destFilePath = ODFileUtils.CombinePaths(atozTo, destFileName); while (File.Exists(destFilePath)) { //if still not unique, try appending date/time to seconds precision until the file name is unique destFileName = patOld.PatNum.ToString() + "_" + Path.GetFileNameWithoutExtension(doc.FileName) + "_" + DateTime.Now.ToString("yyyyMMddhhmmss") + Path.GetExtension(doc.FileName); destFilePath = ODFileUtils.CombinePaths(atozTo, destFileName); } } try { File.Copy(fromFilePath, destFilePath); } catch (Exception ex) { ex.DoNothing(); fileMoveFailures++; continue; } //try to delete the original file try { File.Delete(fromFilePath); } catch (Exception ex) { ex.DoNothing(); //If we cannot delete the file, could be a permission issue or someone has the file open currently //Just skip deleting the file, which means there could be an image in the old pat's folder that may need to be deleted manually fileMoveFailures++; } } else if (CloudStorage.IsCloudStorage) { //move files around in the cloud FormProgress FormP = new FormProgress(false); FormP.DisplayText = "Uploading..."; FormP.NumberFormat = "F"; FormP.NumberMultiplication = 1; FormP.MaxVal = 100; //Doesn't matter what this value is as long as it is greater than 0 FormP.TickMS = 1000; OpenDentalCloud.Core.TaskStateMove state = CloudStorage.MoveAsync(atozFrom , atozTo , new OpenDentalCloud.ProgressHandler(FormP.OnProgress)); FormP.ShowDialog(); //Don't allow users to cancel from here due to the limitations of the current feature for figuring out which files were moved successfully. } //if we get here the file was copied successfully or not storing images in the database, so update the document row //Safe to update the document FileName and PatNum to PatCur and new file name doc.PatNum = PatCur.PatNum; doc.FileName = destFileName; Documents.Update(doc); } ListMedLabs.ForEach(x => x.PatNum = PatCur.PatNum); //update local list, done after moving files _medLabCur = ListMedLabs[0]; if (fileMoveFailures > 0) //will never be > 0 if storing images in the db { MessageBox.Show(Lan.g(this, "Some files attached to the MedLab objects could not be moved.") + "\r\n" + Lan.g(this, "This could be due to a missing file, a file being open, or a permission issue on the file which is preventing the move.") + "\r\n" + Lan.g(this, "The file(s) will have to be moved manually from the Image module.") + "\r\n" + Lan.g(this, "Number of files not moved") + ": " + fileMoveFailures.ToString()); } }
private void FormTreatPlanEdit_Load(object sender, System.EventArgs e) { //this window never comes up for new TP. Always saved ahead of time. if (!Security.IsAuthorized(Permissions.TreatPlanEdit, PlanCur.DateTP)) { butOK.Enabled = false; butDelete.Enabled = false; butPickResponsParty.Enabled = false; butClearResponsParty.Enabled = false; butSigClear.Enabled = false; butDocumentDetach.Enabled = false; textHeading.ReadOnly = true; textDateTP.ReadOnly = true; textNote.ReadOnly = true; if (Security.IsAuthorized(Permissions.TreatPlanSign, PlanCur.DateTP)) //User has permission to edit the heading field. { textHeading.ReadOnly = false; butOK.Enabled = true; } } if (!Security.IsAuthorized(Permissions.TreatPlanPresenterEdit, true)) { butPickPresenter.Visible = false; } if (PlanCur.UserNumPresenter > 0) { _presenterCur = Userods.GetUser(PlanCur.UserNumPresenter); _presenterOld = _presenterCur.Copy(); textPresenter.Text = _presenterCur.UserName; } textUserEntry.Text = Userods.GetName(PlanCur.SecUserNumEntry); textDateTP.Text = PlanCur.DateTP.ToShortDateString(); textHeading.Text = PlanCur.Heading; textNote.Text = PlanCur.Note; if (PrefC.GetBool(PrefName.EasyHidePublicHealth)) { labelResponsParty.Visible = false; textResponsParty.Visible = false; butPickResponsParty.Visible = false; butClearResponsParty.Visible = false; } if (PlanCur.ResponsParty != 0) { textResponsParty.Text = Patients.GetLim(PlanCur.ResponsParty).GetNameLF(); } if (PlanCur.Signature != "") //Per Nathan 01 OCT 2015: In addition to invalidating signature (old behavior) we will also block editing signed TPs. { butOK.Enabled = false; textHeading.ReadOnly = true; textDateTP.ReadOnly = true; textNote.ReadOnly = true; butClearResponsParty.Enabled = false; butPickResponsParty.Enabled = false; butSigClear.Visible = true; butDocumentDetach.Enabled = false; } else { butSigClear.Visible = false; butSigClear.Enabled = false; } if (PlanCur.DocNum > 0) //Was set at some point in the past. { Document doc = Documents.GetByNum(PlanCur.DocNum); if (doc.DocNum == 0) { textDocument.Text = "(" + Lan.g(this, "Missing Document") + ")"; //Invalid Fkey to document.DocNum butDocumentView.Enabled = false; } else { textDocument.Text = doc.Description; if (!Documents.DocExists(doc.DocNum)) { textDocument.Text += " (" + Lan.g(this, "Unreachable File") + ")"; //Document points to unreachable file butDocumentView.Enabled = false; } } } else //hide document controls because there is no attached document { labelDocument.Visible = false; textDocument.Visible = false; butDocumentView.Visible = false; butDocumentDetach.Visible = false; } }
///<summary>Uses sheet framework to generate a PDF file, save it to patient's image folder, and attempt to launch file with defualt reader. ///If using ImagesStoredInDB it will not launch PDF. If no valid patient is selected you cannot perform this action.</summary> private void butPDF_Click(object sender, EventArgs e) { if (PatCur == null) //not attached to a patient when form loaded and they haven't selected a patient to attach to yet { MsgBox.Show(this, "The Medical Lab must be attached to a patient before the PDF can be saved."); return; } if (PatCur.PatNum > 0 && _medLabCur.PatNum != PatCur.PatNum) //save the current patient attached to the MedLab if it has been changed { MoveLabsAndImagesHelper(); } Cursor = Cursors.WaitCursor; SheetDef sheetDef = SheetUtil.GetMedLabResultsSheetDef(); Sheet sheet = SheetUtil.CreateSheet(sheetDef, _medLabCur.PatNum); SheetFiller.FillFields(sheet, null, null, _medLabCur); //create the file in the temp folder location, then import so it works when storing images in the db string tempPath = ODFileUtils.CombinePaths(PrefC.GetTempFolderPath(), _medLabCur.PatNum.ToString() + ".pdf"); SheetPrinting.CreatePdf(sheet, tempPath, null, _medLabCur); HL7Def defCur = HL7Defs.GetOneDeepEnabled(true); long category = defCur.LabResultImageCat; if (category == 0) { category = Defs.GetFirstForCategory(DefCat.ImageCats, true).DefNum; //put it in the first category. } //create doc-------------------------------------------------------------------------------------- OpenDentBusiness.Document docc = null; try { docc = ImageStore.Import(tempPath, category, Patients.GetPat(_medLabCur.PatNum)); } catch (Exception ex) { ex.DoNothing(); Cursor = Cursors.Default; MsgBox.Show(this, "Error saving document."); return; } finally { //Delete the temp file since we don't need it anymore. try { File.Delete(tempPath); } catch { //Do nothing. This file will likely get cleaned up later. } } docc.Description = Lan.g(this, "MedLab Result"); docc.DateCreated = DateTime.Now; Documents.Update(docc); string filePathAndName = ""; if (PrefC.AtoZfolderUsed == DataStorageType.LocalAtoZ) { string patFolder = ImageStore.GetPatientFolder(Patients.GetPat(_medLabCur.PatNum), ImageStore.GetPreferredAtoZpath()); filePathAndName = ODFileUtils.CombinePaths(patFolder, docc.FileName); } else if (CloudStorage.IsCloudStorage) { FormProgress FormP = new FormProgress(); FormP.DisplayText = "Downloading..."; FormP.NumberFormat = "F"; FormP.NumberMultiplication = 1; FormP.MaxVal = 100; //Doesn't matter what this value is as long as it is greater than 0 FormP.TickMS = 1000; OpenDentalCloud.Core.TaskStateDownload state = CloudStorage.DownloadAsync( ImageStore.GetPatientFolder(Patients.GetPat(_medLabCur.PatNum), ImageStore.GetPreferredAtoZpath()) , docc.FileName , new OpenDentalCloud.ProgressHandler(FormP.OnProgress)); if (FormP.ShowDialog() == DialogResult.Cancel) { state.DoCancel = true; return; } filePathAndName = PrefC.GetRandomTempFile(Path.GetExtension(docc.FileName)); File.WriteAllBytes(filePathAndName, state.FileContent); } Cursor = Cursors.Default; if (filePathAndName != "") { Process.Start(filePathAndName); } SecurityLogs.MakeLogEntry(Permissions.SheetEdit, sheet.PatNum, sheet.Description + " from " + sheet.DateTimeSheet.ToShortDateString() + " pdf was created"); DialogResult = DialogResult.OK; }
private void butPickRxListImage_Click(object sender, EventArgs e) { if (PrefC.AtoZfolderUsed == DataStorageType.InDatabase) { MsgBox.Show(this, "This option is not supported with images stored in the database."); return; } FormImageSelect formIS = new FormImageSelect(); formIS.PatNum = PatCur.PatNum; formIS.ShowDialog(); if (formIS.DialogResult != DialogResult.OK) { return; } string patFolder = ImageStore.GetPatientFolder(PatCur, ImageStore.GetPreferredAtoZpath()); Document doc = Documents.GetByNum(formIS.SelectedDocNum); if (!ImageStore.HasImageExtension(doc.FileName)) { MsgBox.Show(this, "The selected file is not a supported image type."); return; } textDocDateDesc.Text = doc.DateTStamp.ToShortDateString() + " - " + doc.Description.ToString(); if (BitmapOriginal != null) { BitmapOriginal.Dispose(); } if (PrefC.AtoZfolderUsed == DataStorageType.LocalAtoZ) { BitmapOriginal = ImageStore.OpenImage(doc, patFolder); } else { FormProgress FormP = new FormProgress(); FormP.DisplayText = "Downloading Image..."; FormP.NumberFormat = "F"; FormP.NumberMultiplication = 1; FormP.MaxVal = 100; //Doesn't matter what this value is as long as it is greater than 0 FormP.TickMS = 1000; OpenDentalCloud.Core.TaskStateDownload state = CloudStorage.DownloadAsync(patFolder , doc.FileName , new OpenDentalCloud.ProgressHandler(FormP.OnProgress)); FormP.ShowDialog(); if (FormP.DialogResult == DialogResult.Cancel) { state.DoCancel = true; return; } else { using (MemoryStream ms = new MemoryStream(state.FileContent)) { BitmapOriginal = new Bitmap(ms); } } } Bitmap bitmap = ImageHelper.ApplyDocumentSettingsToImage(doc, BitmapOriginal, ImageSettingFlags.ALL); pictBox.BackgroundImage = bitmap; resizePictBox(); }
private void butMerge_Click(object sender, EventArgs e) { if (_patTo.PatNum == _patFrom.PatNum) { MsgBox.Show(this, "Cannot merge a patient account into itself. Please select a different patient to merge from."); return; } string msgText = ""; if (_patFrom.FName.Trim().ToLower() != _patTo.FName.Trim().ToLower() || _patFrom.LName.Trim().ToLower() != _patTo.LName.Trim().ToLower() || _patFrom.Birthdate != _patTo.Birthdate) { //mismatch msgText = Lan.g(this, "The two patients do not have the same first name, last name, and birthdate."); if (Programs.UsingEcwTightOrFullMode()) { msgText += "\r\n" + Lan.g(this, "The patients must first be merged from within eCW, then immediately merged in the same order in Open Dental. " + "If the patients are not merged in this manner, some information may not properly bridge between eCW and Open Dental."); } msgText += "\r\n\r\n" + Lan.g(this, "Into patient name") + ": " + Patients.GetNameFLnoPref(_patTo.LName, _patTo.FName, "") + ", " //using Patients.GetNameFLnoPref to omit MiddleI + Lan.g(this, "Into patient birthdate") + ": " + _patTo.Birthdate.ToShortDateString() + "\r\n" + Lan.g(this, "From patient name") + ": " + Patients.GetNameFLnoPref(_patFrom.LName, _patFrom.FName, "") + ", " //using Patients.GetNameFLnoPref to omit MiddleI + Lan.g(this, "From patient birthdate") + ": " + _patFrom.Birthdate.ToShortDateString() + "\r\n\r\n" + Lan.g(this, "Merge the patient on the bottom into the patient shown on the top?"); if (MessageBox.Show(msgText, "", MessageBoxButtons.YesNo) != DialogResult.Yes) { return; //The user chose not to merge } } else //name and bd match { if (!MsgBox.Show(this, MsgBoxButtons.YesNo, "Merge the patient at the bottom into the patient shown at the top?")) { return; //The user chose not to merge. } } if (_patFrom.PatNum == _patFrom.Guarantor) { Family fam = Patients.GetFamily(_patFrom.PatNum); if (fam.ListPats.Length > 1) { msgText = Lan.g(this, "The patient you have chosen to merge from is a guarantor. Merging this patient into another account will cause all " + "family members of the patient being merged from to be moved into the same family as the patient account being merged into.") + "\r\n" + Lan.g(this, "Do you wish to continue with the merge?"); if (MessageBox.Show(msgText, "", MessageBoxButtons.YesNo) != DialogResult.Yes) { return; //The user chose not to merge. } } } Cursor = Cursors.WaitCursor; if (Patients.MergeTwoPatients(_patTo.PatNum, _patFrom.PatNum)) { //The patient has been successfully merged. //Now copy the physical images from the old patient to the new if they are using an AtoZ image share. //This has to happen in the UI because the middle tier server might not have access to the image share. //If the users are storing images within the database, those images have already been taken care of in the merge method above. int fileCopyFailures = 0; if (PrefC.AtoZfolderUsed == DataStorageType.LocalAtoZ) { #region Copy AtoZ Documents //Move the patient documents within the 'patFrom' A to Z folder to the 'patTo' A to Z folder. //We have to be careful here of documents with the same name. We have to rename such documents //so that no documents are overwritten/lost. string atoZpath = ImageStore.GetPreferredAtoZpath(); string atozFrom = ImageStore.GetPatientFolder(_patFrom, atoZpath); string atozTo = ImageStore.GetPatientFolder(_patTo, atoZpath); string[] fromFiles = Directory.GetFiles(atozFrom); foreach (string fileCur in fromFiles) { string fileName = Path.GetFileName(fileCur); string destFileName = fileName; string destFilePath = ODFileUtils.CombinePaths(atozTo, fileName); if (File.Exists(destFilePath)) { //The file being copied has the same name as a possibly different file within the destination a to z folder. //We need to copy the file under a unique file name and then make sure to update the document table to reflect //the change. destFileName = _patFrom.PatNum.ToString() + "_" + fileName; destFilePath = ODFileUtils.CombinePaths(atozTo, destFileName); while (File.Exists(destFilePath)) { destFileName = _patFrom.PatNum.ToString() + "_" + fileName + "_" + DateTime.Now.ToString("yyyyMMddhhmmss"); destFilePath = ODFileUtils.CombinePaths(atozTo, destFileName); } } try { File.Copy(fileCur, destFilePath); //Will throw exception if file already exists. } catch (Exception ex) { ex.DoNothing(); fileCopyFailures++; continue; //copy failed, increment counter and move onto the next file } //If the copy did not fail, try to delete the old file. //We can now safely update the document FileName and PatNum to the "to" patient. Documents.MergePatientDocument(_patFrom.PatNum, _patTo.PatNum, fileName, destFileName); try { File.Delete(fileCur); } catch (Exception ex) { ex.DoNothing(); //If we were unable to delete the file then it is probably because someone has the document open currently. //Just skip deleting the file. This means that occasionally there will be an extra file in their backup //which is just clutter but at least the merge is guaranteed this way. } } #endregion Copy AtoZ Documents } //end if AtoZFolderUsed else if (CloudStorage.IsCloudStorage) { string atozFrom = ImageStore.GetPatientFolder(_patFrom, ""); string atozTo = ImageStore.GetPatientFolder(_patTo, ""); FormProgress FormP = new FormProgress(); FormP.DisplayText = "Moving Documents..."; FormP.NumberFormat = "F"; FormP.NumberMultiplication = 1; FormP.MaxVal = 100; //Doesn't matter what this value is as long as it is greater than 0 FormP.TickMS = 1000; OpenDentalCloud.Core.TaskStateMove state = CloudStorage.MoveAsync(atozFrom , atozTo , new OpenDentalCloud.ProgressHandler(FormP.OnProgress)); if (FormP.ShowDialog() == DialogResult.Cancel) { state.DoCancel = true; fileCopyFailures = state.CountTotal - state.CountSuccess; } else { fileCopyFailures = state.CountFailed; } } Cursor = Cursors.Default; if (fileCopyFailures > 0) { MessageBox.Show(Lan.g(this, "Some files belonging to the from patient were not copied.") + "\r\n" + Lan.g(this, "Number of files not copied") + ": " + fileCopyFailures); } textPatientIDFrom.Text = ""; textPatientNameFrom.Text = ""; textPatFromBirthdate.Text = ""; CheckUIState(); //Make log entry here not in parent form because we can merge multiple patients at a time. SecurityLogs.MakeLogEntry(Permissions.PatientMerge, _patTo.PatNum, "Patient: " + _patFrom.GetNameFL() + "\r\nPatNum From: " + _patFrom.PatNum + "\r\nPatNum To: " + _patTo.PatNum); MsgBox.Show(this, "Patients merged successfully."); } //end MergeTwoPatients Cursor = Cursors.Default; }
private void butGiveAccess_Click(object sender, EventArgs e) { string interval = PrefC.GetStringSilent(PrefName.MobileSyncIntervalMinutes); if (interval == "" || interval == "0") //not a paid customer or chooses not to synch { MessageBox.Show("Synch must be setup first from the Tools menu, Mobile and Patient Portal Synch. Interval must not be blank or zero."); return; } //we won't check PrefName.MobileSyncWorkstationName because we are forcing the synch if (System.Environment.MachineName.ToUpper() != PrefC.GetStringSilent(PrefName.MobileSyncWorkstationName).ToUpper()) { //Since GetStringSilent returns "" before OD is connected to db, this gracefully loops out if (!MsgBox.Show(this, MsgBoxButtons.OKCancel, "Warning. Workstation is not entered in the Tools menu, Mobile and Patient Portal Synch. No automatic synch is taking place. Continue anyway?")) { return; } } if (PrefC.GetDate(PrefName.MobileExcludeApptsBeforeDate).Year < 1880) { MessageBox.Show("Full Synch must be run first first from the Tools menu, Mobile and Patient Portal Synch."); return; } if (butGiveAccess.Text == "Provide Online Access") //When form open opens with a blank password { Cursor = Cursors.WaitCursor; //1. Fill password. textOnlinePassword.Text = GenerateRandomPassword(8, 10); //won't save until OK or Print //2. Fill link. textOnlineLink.Text = GetPatientPortalLink(); //3. Reset timestamps for this patient to trigger all their objects to upload with the next synch LabPanels.ResetTimeStamps(PatCur.PatNum); Diseases.ResetTimeStamps(PatCur.PatNum); Allergies.ResetTimeStamps(PatCur.PatNum); MedicationPats.ResetTimeStamps(PatCur.PatNum); Statements.ResetTimeStamps(PatCur.PatNum); Documents.ResetTimeStamps(PatCur.PatNum); //4. Make the password editable in case they want to change it. textOnlinePassword.ReadOnly = false; //5. Save password to db PatCur.OnlinePassword = textOnlinePassword.Text; Patients.Update(PatCur, PatOld); PatOld.OnlinePassword = textOnlinePassword.Text; //so that subsequent Updates will work. //6. Force a synch FormMobile.SynchFromMain(true); //7. Insert EhrMeasureEvent EhrMeasureEvent newMeasureEvent = new EhrMeasureEvent(); newMeasureEvent.DateTEvent = DateTime.Now; newMeasureEvent.EventType = EhrMeasureEventType.OnlineAccessProvided; newMeasureEvent.PatNum = PatCur.PatNum; newMeasureEvent.MoreInfo = ""; EhrMeasureEvents.Insert(newMeasureEvent); //8. Rename button butGiveAccess.Text = "Remove Online Access"; Cursor = Cursors.Default; } else //remove access { Cursor = Cursors.WaitCursor; //1. Clear password textOnlinePassword.Text = ""; //2. Make in uneditable textOnlinePassword.ReadOnly = true; //3. Save password to db PatCur.OnlinePassword = textOnlinePassword.Text; Patients.Update(PatCur, PatOld); PatOld.OnlinePassword = textOnlinePassword.Text; //5. Force a synch FormMobile.SynchFromMain(true); //no event to insert //6. Rename button butGiveAccess.Text = "Provide Online Access"; Cursor = Cursors.Default; } }
private void butMerge_Click(object sender, EventArgs e) { if (_patTo.PatNum == _patFrom.PatNum) { MsgBox.Show(this, "Cannot merge a patient account into itself. Please select a different patient to merge from."); return; } string msgText = ""; if (_patFrom.FName.Trim().ToLower() != _patTo.FName.Trim().ToLower() || _patFrom.LName.Trim().ToLower() != _patTo.LName.Trim().ToLower() || _patFrom.Birthdate != _patTo.Birthdate) { //mismatch msgText = Lan.g(this, "The two patients do not have the same first name, last name, and birthdate."); if (Programs.UsingEcwTightOrFullMode()) { msgText += "\r\n" + Lan.g(this, "The patients must first be merged from within eCW, then immediately merged in the same order in Open Dental. " + "If the patients are not merged in this manner, some information may not properly bridge between eCW and Open Dental."); } msgText += "\r\n\r\n" + Lan.g(this, "Into patient name") + ": " + Patients.GetNameFLnoPref(_patTo.LName, _patTo.FName, "") + ", " //using Patients.GetNameFLnoPref to omit MiddleI + Lan.g(this, "Into patient birthdate") + ": " + _patTo.Birthdate.ToShortDateString() + "\r\n" + Lan.g(this, "From patient name") + ": " + Patients.GetNameFLnoPref(_patFrom.LName, _patFrom.FName, "") + ", " //using Patients.GetNameFLnoPref to omit MiddleI + Lan.g(this, "From patient birthdate") + ": " + _patFrom.Birthdate.ToShortDateString() + "\r\n\r\n" + Lan.g(this, "Merge the patient on the bottom into the patient shown on the top?"); if (MessageBox.Show(msgText, "", MessageBoxButtons.YesNo) != DialogResult.Yes) { return; //The user chose not to merge } } else //name and bd match { if (!MsgBox.Show(this, MsgBoxButtons.YesNo, "Merge the patient at the bottom into the patient shown at the top?")) { return; //The user chose not to merge. } } if (_patFrom.PatNum == _patFrom.Guarantor) { Family fam = Patients.GetFamily(_patFrom.PatNum); if (fam.ListPats.Length > 1) { msgText = Lan.g(this, "The patient you have chosen to merge from is a guarantor. Merging this patient into another account will cause all " + "family members of the patient being merged from to be moved into the same family as the patient account being merged into.") + "\r\n" + Lan.g(this, "Do you wish to continue with the merge?"); if (MessageBox.Show(msgText, "", MessageBoxButtons.YesNo) != DialogResult.Yes) { return; //The user chose not to merge. } } } Cursor = Cursors.WaitCursor; List <Task> listPatientTasks = Tasks.RefreshPatientTickets(_patFrom.PatNum); //Get this before the merge, because the merge updates Task.KeyNum. bool isSuccessfulMerge = false; try { isSuccessfulMerge = Patients.MergeTwoPatients(_patTo.PatNum, _patFrom.PatNum); } catch (Exception ex) { SecurityLogs.MakeLogEntry(Permissions.PatientMerge, _patTo.PatNum, "Error occurred while merging Patient: " + _patFrom.GetNameFL() + "\r\nPatNum From: " + _patFrom.PatNum + "\r\nPatNum To: " + _patTo.PatNum); Cursor = Cursors.Default; FriendlyException.Show(Lan.g(this, "Unable to fully merge patients. Contact support."), ex); } if (isSuccessfulMerge) { //The patient has been successfully merged. #region Refresh Patient's Tasks List <Signalod> listSignals = new List <Signalod>(); foreach (Task task in listPatientTasks) { Signalod signal = new Signalod(); signal.IType = InvalidType.Task; signal.FKeyType = KeyType.Task; signal.FKey = task.TaskNum; signal.DateViewing = DateTime.MinValue; //Mimics Signalods.SetInvalid() listSignals.Add(signal); } Signalods.SetInvalid(InvalidType.TaskPatient, KeyType.Undefined, _patTo.PatNum); //Ensure anyone viewing Patient tab of new pat gets refreshed. Signalods.Insert(listSignals.ToArray()); //Refreshes existing tasks in all other tabs. //Causes Task area and open Task Edit windows to refresh immediately. No popups, alright to pass empty lists for listRefreshedTaskNotes and //listBlockedTaskLists. FormOpenDental.S_HandleRefreshedTasks(listSignals, listPatientTasks.Select(x => x.TaskNum).ToList(), listPatientTasks, new List <TaskNote>() , new List <UserOdPref>()); #endregion //Now copy the physical images from the old patient to the new if they are using an AtoZ image share. //This has to happen in the UI because the middle tier server might not have access to the image share. //If the users are storing images within the database, those images have already been taken care of in the merge method above. int fileCopyFailures = 0; if (PrefC.AtoZfolderUsed == DataStorageType.LocalAtoZ) { #region Copy AtoZ Documents //Move the patient documents within the 'patFrom' A to Z folder to the 'patTo' A to Z folder. //We have to be careful here of documents with the same name. We have to rename such documents //so that no documents are overwritten/lost. string atoZpath = ImageStore.GetPreferredAtoZpath(); string atozFrom = ImageStore.GetPatientFolder(_patFrom, atoZpath); string atozTo = ImageStore.GetPatientFolder(_patTo, atoZpath); string[] fromFiles = Directory.GetFiles(atozFrom); if (atozFrom == atozTo) { //Very rarely, two patients have the same image folder. PatFrom and PatTo both have Documents that point to the same file. Since we //are about to copy the image file for PatFrom to PatTo's directory and delete the file from PatFrom's directory, we would break the //file reference for PatTo's Document. In this case, skip deleting the original file, since PatTo's Document still references it. Documents.MergePatientDocuments(_patFrom.PatNum, _patTo.PatNum); } else { foreach (string fileCur in fromFiles) { string fileName = Path.GetFileName(fileCur); string destFileName = fileName; string destFilePath = ODFileUtils.CombinePaths(atozTo, fileName); if (File.Exists(destFilePath)) { //The file being copied has the same name as a possibly different file within the destination a to z folder. //We need to copy the file under a unique file name and then make sure to update the document table to reflect //the change. destFileName = _patFrom.PatNum.ToString() + "_" + fileName; destFilePath = ODFileUtils.CombinePaths(atozTo, destFileName); while (File.Exists(destFilePath)) { destFileName = _patFrom.PatNum.ToString() + "_" + fileName + "_" + DateTime.Now.ToString("yyyyMMddhhmmss"); destFilePath = ODFileUtils.CombinePaths(atozTo, destFileName); } } try { File.Copy(fileCur, destFilePath); //Will throw exception if file already exists. } catch (Exception ex) { ex.DoNothing(); fileCopyFailures++; continue; //copy failed, increment counter and move onto the next file } //If the copy did not fail, try to delete the old file. //We can now safely update the document FileName and PatNum to the "to" patient. Documents.MergePatientDocument(_patFrom.PatNum, _patTo.PatNum, fileName, destFileName); try { File.Delete(fileCur); } catch (Exception ex) { ex.DoNothing(); //If we were unable to delete the file then it is probably because someone has the document open currently. //Just skip deleting the file. This means that occasionally there will be an extra file in their backup //which is just clutter but at least the merge is guaranteed this way. } } } #endregion Copy AtoZ Documents } //end if AtoZFolderUsed else if (CloudStorage.IsCloudStorage) { string atozFrom = ImageStore.GetPatientFolder(_patFrom, ""); string atozTo = ImageStore.GetPatientFolder(_patTo, ""); if (atozFrom == atozTo) { //Very rarely, two patients have the same image folder. PatFrom and PatTo both have Documents that point to the same file. Since we //are about to copy the image file for PatFrom to PatTo's directory and delete the file from PatFrom's directory, we would break the //file reference for PatTo's Document. In this case, skip deleting the original file, since PatTo's Document still references it. Documents.MergePatientDocuments(_patFrom.PatNum, _patTo.PatNum); } else { FormProgress FormP = new FormProgress(); FormP.DisplayText = "Moving Documents..."; FormP.NumberFormat = "F"; FormP.NumberMultiplication = 1; FormP.MaxVal = 100; //Doesn't matter what this value is as long as it is greater than 0 FormP.TickMS = 1000; OpenDentalCloud.Core.TaskStateMove state = CloudStorage.MoveAsync(atozFrom , atozTo , new OpenDentalCloud.ProgressHandler(FormP.OnProgress)); if (FormP.ShowDialog() == DialogResult.Cancel) { state.DoCancel = true; fileCopyFailures = state.CountTotal - state.CountSuccess; } else { fileCopyFailures = state.CountFailed; } } } Cursor = Cursors.Default; if (fileCopyFailures > 0) { MessageBox.Show(Lan.g(this, "Some files belonging to the from patient were not copied.") + "\r\n" + Lan.g(this, "Number of files not copied") + ": " + fileCopyFailures); } //Make log entry here not in parent form because we can merge multiple patients at a time. SecurityLogs.MakeLogEntry(Permissions.PatientMerge, _patTo.PatNum, "Patient: " + _patFrom.GetNameFL() + "\r\nPatNum From: " + _patFrom.PatNum + "\r\nPatNum To: " + _patTo.PatNum); textPatientIDFrom.Text = ""; textPatientNameFrom.Text = ""; textPatFromBirthdate.Text = ""; //This will cause CheckUIState() to disabled the merge button until the user selects a new _patFrom. _patFrom = null; CheckUIState(); MsgBox.Show(this, "Patients merged successfully."); } //end MergeTwoPatients Cursor = Cursors.Default; }
private void butOK_Click(object sender, System.EventArgs e) { if (textDate.errorProvider1.GetError(textDate) != "") { MessageBox.Show(Lan.g(this, "Please fix data entry errors first.")); return; } if (textDate.Text == "") { MsgBox.Show(this, "Please enter a date."); return; } if (textTime.Text == "") { MsgBox.Show(this, "Please enter a time."); return; } DateTime time; if (!DateTime.TryParse(textTime.Text, out time)) { MsgBox.Show(this, "Please enter a valid time."); return; } //We had a security bug where users could change the date to a more recent date, and then subsequently delete. //The code below is for that specific scenario. DateTime dateTimeEntered = PIn.DateT(textDate.Text + " " + textTime.Text); if (dateTimeEntered > DocCur.DateCreated) { //user is trying to change the date to some date after the previously linked date //is the new doc date allowed? if (!Security.IsAuthorized(Permissions.ImageDelete, DocCur.DateCreated, true)) { //suppress the default security message above (it's too confusing for this case) and generate our own here MessageBox.Show(this, Lan.g(this, "Not allowed to future date this image from") + ": " + "\r\n" + DocCur.DateCreated.ToString() + " to " + dateTimeEntered.ToString() + "\r\n\r\n" + Lan.g(this, "A user with the SecurityAdmin permission must grant you access for") + ":\r\n" + GroupPermissions.GetDesc(Permissions.ImageDelete)); return; } } try{ DocCur.ToothNumbers = Tooth.FormatRangeForDb(textToothNumbers.Text); } catch (ApplicationException ex) { MessageBox.Show(ex.Message); return; } DocCur.DocCategory = _listImageCatDefs[listCategory.SelectedIndex].DefNum; DocCur.ImgType = (ImageType)listType.SelectedIndex; DocCur.Description = textDescript.Text; DocCur.DateCreated = dateTimeEntered; try{ //incomplete DocCur.ToothNumbers = Tooth.FormatRangeForDb(textToothNumbers.Text); } catch (ApplicationException ex) { MessageBox.Show(ex.Message); return; } //DocCur.Note=textNote.Text; //Docs.Cur.LastAltered=DateTime.Today; //if(IsNew){ // DocCur.Insert(PatCur); //} //else{ if (Documents.Update(DocCur, DocOld)) { ImageStore.LogDocument(Lan.g(this, "Document Edited") + ": ", Permissions.ImageEdit, DocCur, DocOld.DateTStamp); } //} DialogResult = DialogResult.OK; }