private void butActivateReminder_Click(object sender, EventArgs e) { bool isApptRemindAutoEnabled = PrefC.GetBool(PrefName.ApptRemindAutoEnabled); isApptRemindAutoEnabled = !isApptRemindAutoEnabled; Prefs.UpdateBool(PrefName.ApptRemindAutoEnabled, isApptRemindAutoEnabled); SecurityLogs.MakeLogEntry(Permissions.Setup, 0, "Automated appointment eReminders " + (isApptRemindAutoEnabled ? "activated" : "deactivated") + "."); Prefs.RefreshCache(); Signalods.SetInvalid(InvalidType.Prefs); FillECRActivationButtons(); //Add two default reminder rules if none exists. if (isApptRemindAutoEnabled && _dictClinicRules[0].Count(x => x.TypeCur == ApptReminderType.Reminder) == 0) { ApptReminderRule arr = ApptReminderRules.CreateDefaultReminderRule(ApptReminderType.Reminder, 0); //defaults to 3 hours before appt _dictClinicRules[0].Add(arr); ApptReminderRule arr2 = ApptReminderRules.CreateDefaultReminderRule(ApptReminderType.Reminder, 0); arr2.TSPrior = TimeSpan.FromDays(2); _dictClinicRules[0].Add(arr2); FillRemindConfirmData(); } }
private void FormTerminal_FormClosing(object sender, FormClosingEventArgs e) { if (IsSimpleMode) { return; } Process processCur = Process.GetCurrentProcess(); try { Sheets.ClearFromTerminal(PatNum); TerminalActives.DeleteForCmptrSessionAndId(Environment.MachineName, processCur.SessionId, processId: processCur.Id); //Just in case, close remaining forms that are open _formSheetFillEdit.ForceClose(); } catch (Exception) { //SocketException if db connection gets lost. //if either fail, do nothing, the terminalactives will be cleaned up the next time the kiosk mode is enabled for this computer } finally { Signalods.SetInvalid(InvalidType.Kiosk, KeyType.ProcessId, processCur.Id); } }
private void butDone_Click(object sender, EventArgs e) { Sheets.ClearFromTerminal(PatNum); labelForms.Visible = false; listForms.Visible = false; butDone.Visible = false; if (IsSimpleMode) //not subscribed to signals if IsSimpleMode { PatNum = 0; _listSheets = new List <Sheet>(); labelThankYou.Visible = true; return; } //NOT IsSimpleMode from here down TerminalActive terminal; Process processCur = Process.GetCurrentProcess(); try{ terminal = TerminalActives.GetForCmptrSessionAndId(Environment.MachineName, processCur.SessionId, processCur.Id); labelConnection.Visible = false; } catch (Exception) { //SocketException if db connection gets lost. labelConnection.Visible = true; return; } //this terminal shouldn't be running, receptionist must've deleted this kiosk, close the form (causes application exit if NOT IsSimpleMode). if (terminal == null) { Close(); //signal sent in form closing return; } if (terminal.PatNum != 0) { labelWelcome.Visible = true; TerminalActives.SetPatNum(terminal.TerminalActiveNum, 0); PatNum = 0; _listSheets = new List <Sheet>(); Signalods.SetInvalid(InvalidType.Kiosk, KeyType.ProcessId, processCur.Id); //signal the terminal manager to refresh its grid } }
private void butActivateInvites_Click(object sender, EventArgs e) { if (!WebServiceMainHQProxy.IsEServiceActive(_signupOut, eServiceCode.PatientPortal)) //Not yet activated with HQ. { MsgBox.Show(this, "You must first signup for Patient Portal via the Signup tab before activating Patient Portal Invites."); return; } bool isPatPortalInvitesEnabled = PrefC.GetBool(PrefName.PatientPortalInviteEnabled); isPatPortalInvitesEnabled = !isPatPortalInvitesEnabled; Prefs.UpdateBool(PrefName.PatientPortalInviteEnabled, isPatPortalInvitesEnabled); SecurityLogs.MakeLogEntry(Permissions.Setup, 0, "Patient Portal Invites " + (isPatPortalInvitesEnabled ? "activated" : "deactivated") + "."); Prefs.RefreshCache(); Signalods.SetInvalid(InvalidType.Prefs); FillPPInviteActivationButton(); if (isPatPortalInvitesEnabled && _listPatPortalInviteRules.Count == 0) { _listPatPortalInviteRules.Add(ApptReminderRules.CreateDefaultReminderRule(ApptReminderType.PatientPortalInvite, 0, isBeforeAppointment: false)); _listPatPortalInviteRules.Add(ApptReminderRules.CreateDefaultReminderRule(ApptReminderType.PatientPortalInvite, 0, isBeforeAppointment: true)); FillPatPortalInvites(); } }
private void butAdd_Click(object sender, EventArgs e) { FormSheetPicker FormS = new FormSheetPicker(); FormS.SheetType = SheetTypeEnum.PatientForm; FormS.ShowDialog(); if (FormS.DialogResult != DialogResult.OK) { return; } SheetDef sheetDef; Sheet sheet = null; //only useful if not Terminal for (int i = 0; i < FormS.SelectedSheetDefs.Count; i++) { sheetDef = FormS.SelectedSheetDefs[i]; sheet = SheetUtil.CreateSheet(sheetDef, PatNum); SheetParameter.SetParameter(sheet, "PatNum", PatNum); SheetFiller.FillFields(sheet); SheetUtil.CalculateHeights(sheet); if (FormS.TerminalSend) { sheet.InternalNote = ""; //because null not ok sheet.ShowInTerminal = (byte)(Sheets.GetBiggestShowInTerminal(PatNum) + 1); Sheets.SaveNewSheet(sheet); //save each sheet. } } if (FormS.TerminalSend) { //do not show a dialog now. User will need to click the terminal button. FillGrid(); Signalods.SetInvalid(InvalidType.Kiosk); } else { FormSheetFillEdit.ShowForm(sheet, FormSheetFillEdit_FormClosing); } }
private void butClear_Click(object sender, EventArgs e) { if (gridMain.GetSelectedIndex() == -1 || gridMain.GetSelectedIndex() >= _terminalList.Count) { MsgBox.Show(this, "Please select a terminal first."); return; } TerminalActive terminal = _terminalList[gridMain.GetSelectedIndex()]; if (terminal.PatNum == 0) { return; } if (!MsgBox.Show(this, true, "A patient is currently using the terminal. If you continue, they will lose the information that is on their screen. " + "Continue anyway?")) { return; } TerminalActives.SetPatNum(terminal.TerminalActiveNum, 0); Signalods.SetInvalid(InvalidType.Kiosk, KeyType.ProcessId, Process.GetCurrentProcess().Id); FillGrid(); FillPat(); }
private void butActivateConfirm_Click(object sender, EventArgs e) { if (!WebServiceMainHQProxy.IsEServiceActive(_signupOut, eServiceCode.ConfirmationRequest)) //Not yet activated with HQ. { MsgBox.Show(this, "You must first signup for eConfirmations via the Signup tab before activating eConfirmations."); return; } bool isApptConfirmAutoEnabled = PrefC.GetBool(PrefName.ApptConfirmAutoEnabled); isApptConfirmAutoEnabled = !isApptConfirmAutoEnabled; Prefs.UpdateBool(PrefName.ApptConfirmAutoEnabled, isApptConfirmAutoEnabled); SecurityLogs.MakeLogEntry(Permissions.Setup, 0, "Automated appointment eConfirmations " + (isApptConfirmAutoEnabled ? "activated" : "deactivated") + "."); Prefs.RefreshCache(); Signalods.SetInvalid(InvalidType.Prefs); FillECRActivationButtons(); //Add a default confirmation rule if none exists. if (isApptConfirmAutoEnabled && _dictClinicRules[0].Count(x => x.TypeCur == ApptReminderType.ConfirmationFutureDay) == 0) { ApptReminderRule arr = ApptReminderRules.CreateDefaultReminderRule(ApptReminderType.ConfirmationFutureDay, 0); //defaults to 7 days before appt _dictClinicRules[0].Add(arr); FillRemindConfirmData(); } }
///<summary>Save all pref changes relating to the given pref. PrefName must have been included in Init(). ///It is suggested that you use SyncAllPrefs(), it is safer.</summary>> public bool SyncPref(PrefName prefName) { //We ensured that our list had default (ClinicNum 0) prefs when we included defaults in Init(). Should always be available. string hqValue = _listClinicPrefs.First(x => x.ClinicNum == 0 && x.PrefName == prefName).ValueString; //Save the default (HQ) pref first. bool didSave = prefName.Update(hqValue); //Our list will likely have clinic-specific entries which are identical to HQ defaults. //In this case, remove those duplicates so we don't save them to the db. _listClinicPrefs.RemoveAll(x => x.ClinicNum != 0 && x.PrefName == prefName && x.ValueString.Equals(hqValue)); List <ClinicPref> listNonDefaultClinicPrefs = _listClinicPrefs.FindAll(x => x.ClinicNum > 0 && x.PrefName == prefName); if (ClinicPrefs.Sync(listNonDefaultClinicPrefs, ClinicPrefs.GetPrefAllClinics(prefName))) { didSave = true; } if (didSave) { Signalods.SetInvalid(InvalidType.ClinicPrefs); ClinicPrefs.RefreshCache(); } return(didSave); }
private void butDefaultClinicClear_Click(object sender, EventArgs e) { Prefs.UpdateLong(PrefName.TextingDefaultClinicNum, 0); Signalods.SetInvalid(InvalidType.Prefs); FillGridSmsUsage(); }
///<summary>Used in both modes. Loads the list of sheets into the listbox. Then launches the first sheet and goes through the sequence of sheets. ///If user clicks cancel, the seqeunce will exit. If NOT IsSimpleMode, then the TerminalManager can also send a signal to immediately terminate ///the sequence. If PatNum is 0, this will unload the patient by making the form list not visible and the welcome message visible.</summary> private void LoadPatient(bool isRefreshOnly) { TerminalActive terminal = null; _listSheets = new List <Sheet>(); Process processCur = Process.GetCurrentProcess(); if (IsSimpleMode) { if (PatNum > 0) { _listSheets = Sheets.GetForTerminal(PatNum); } } else //NOT IsSimpleMode { try{ terminal = TerminalActives.GetForCmptrSessionAndId(Environment.MachineName, processCur.SessionId, processCur.Id); labelConnection.Visible = false; } catch (Exception) { //SocketException if db connection gets lost. labelConnection.Visible = true; return; } if (terminal == null) { //this terminal shouldn't be running, receptionist must've deleted this kiosk, close the form (causes application exit if NOT IsSimpleMode) Close(); //signal sent in form closing return; } if (terminal.PatNum > 0) { _listSheets = Sheets.GetForTerminal(terminal.PatNum); } if (_listSheets.Count == 0) //either terminal.PatNum is 0 or no sheets for pat { labelWelcome.Visible = true; labelForms.Visible = false; listForms.Visible = false; butDone.Visible = false; if (terminal.PatNum > 0) //pat loaded but no sheets to show, unload pat, update db, send signal { TerminalActives.SetPatNum(terminal.TerminalActiveNum, 0); Signalods.SetInvalid(InvalidType.Kiosk, KeyType.ProcessId, processCur.Id); } PatNum = 0; if (_formSheetFillEdit != null && !_formSheetFillEdit.IsDisposed) { _formSheetFillEdit.ForceClose(); } return; } } //we have a patient loaded who has some sheets to show in the terminal labelWelcome.Visible = false; labelForms.Visible = true; listForms.Visible = true; butDone.Visible = true; listForms.Items.Clear(); _listSheets.ForEach(x => listForms.Items.Add(x.Description)); if (!IsSimpleMode) { if (PatNum == terminal.PatNum) { return; //if the pat was not cleared or replaced just return, if sheets are currently being displayed (loop below), continue displaying them } //PatNum is changed, set it to the db terminalactive and signal others, then begin displaying sheets (loop below) PatNum = terminal.PatNum; if (_formSheetFillEdit != null && !_formSheetFillEdit.IsDisposed) { _formSheetFillEdit.ForceClose(); } Signalods.SetInvalid(InvalidType.Kiosk, KeyType.ProcessId, processCur.Id); } if (!isRefreshOnly) { AutoShowSheets(); } }
private void FormTerminal_Load(object sender, EventArgs e) { Size = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Size; Location = new Point(0, 0); labelConnection.Visible = false; _listSheets = new List <Sheet>(); if (IsSimpleMode) { //PatNum set externally (in FormPatientForms) return; } //NOT SimpleMode from here down Process processCur = Process.GetCurrentProcess(); //Delete all terminalactives for this computer, except new one, based on CompName and SessionID TerminalActives.DeleteForCmptrSessionAndId(Environment.MachineName, processCur.SessionId, excludeId: processCur.Id); string clientName = null; string userName = null; try { clientName = Environment.GetEnvironmentVariable("ClientName"); userName = Environment.GetEnvironmentVariable("UserName"); } catch (Exception) { //user may not have permission to access environment variables or another error could happen } if (string.IsNullOrWhiteSpace(clientName)) { //ClientName only set for remote sessions, try to find suitable replacement. clientName = userName; if (processCur.SessionId < 2 || string.IsNullOrWhiteSpace(userName)) { //if sessionId is 0 or 1, this is not a remote session, use MachineName clientName = Environment.MachineName; } } if (string.IsNullOrWhiteSpace(clientName) || TerminalActives.IsCompClientNameInUse(Environment.MachineName, clientName)) { InputBox iBox = new InputBox("Please enter a unique name to identify this kiosk."); iBox.setTitle(Lan.g(this, "Kiosk Session Name")); iBox.ShowDialog(); while (iBox.DialogResult == DialogResult.OK && TerminalActives.IsCompClientNameInUse(Environment.MachineName, iBox.textResult.Text)) { MsgBox.Show(this, "The name entered is invalid or already in use."); iBox.ShowDialog(); } if (iBox.DialogResult != DialogResult.OK) { DialogResult = DialogResult.Cancel; return; //not allowed to enter kiosk mode unless a unique human-readable name is entered for this computer session } clientName = iBox.textResult.Text; } //if we get here, we have a SessionId (which could be 0 if not in a remote session) and a unique client name for this kiosk TerminalActive terminal = new TerminalActive(); terminal.ComputerName = Environment.MachineName; terminal.SessionId = processCur.SessionId; terminal.SessionName = clientName; terminal.ProcessId = processCur.Id; TerminalActives.Insert(terminal); //tell the database that a terminal is newly active on this computer Signalods.SetInvalid(InvalidType.Kiosk, KeyType.ProcessId, processCur.Id); //signal FormTerminalManager to re-fill grids timer1.Enabled = true; }
public ODForm() { this.Shown += new EventHandler((o, e) => { Signalods.SubscribeSignalProcessor(this); }); }
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 (Defs.IsHidable(DefCur.Category) && checkHidden.Checked) { if (Defs.IsDefinitionInUse(DefCur)) { if (DefCur.DefNum == PrefC.GetLong(PrefName.BrokenAppointmentAdjustmentType) || DefCur.DefNum == PrefC.GetLong(PrefName.AppointmentTimeArrivedTrigger) || DefCur.DefNum == PrefC.GetLong(PrefName.AppointmentTimeSeatedTrigger) || DefCur.DefNum == PrefC.GetLong(PrefName.AppointmentTimeDismissedTrigger) || DefCur.DefNum == PrefC.GetLong(PrefName.TreatPlanDiscountAdjustmentType) || DefCur.DefNum == PrefC.GetLong(PrefName.BillingChargeAdjustmentType) || DefCur.DefNum == PrefC.GetLong(PrefName.FinanceChargeAdjustmentType) || DefCur.DefNum == PrefC.GetLong(PrefName.PrepaymentUnearnedType) || DefCur.DefNum == PrefC.GetLong(PrefName.PracticeDefaultBillType) || DefCur.DefNum == PrefC.GetLong(PrefName.SalesTaxAdjustmentType)) { MsgBox.Show(this, "You cannot hide a definition if it is in use within Module Preferences."); return; } else if (DefCur.DefNum.In( PrefC.GetLong(PrefName.RecallStatusMailed), PrefC.GetLong(PrefName.RecallStatusTexted), PrefC.GetLong(PrefName.RecallStatusEmailed), PrefC.GetLong(PrefName.RecallStatusEmailedTexted))) { MsgBox.Show(this, "You cannot hide a definition that is used as a status in the Setup Recall window."); return; } else if (DefCur.DefNum == PrefC.GetLong(PrefName.WebSchedNewPatConfirmStatus)) { MsgBox.Show(this, "You cannot hide a definition that is used as an appointment confirmation status in Web Sched New Pat Appt."); return; } else if (DefCur.DefNum == PrefC.GetLong(PrefName.WebSchedRecallConfirmStatus)) { MsgBox.Show(this, "You cannot hide a definition that is used as an appointment confirmation status in Web Sched Recall Appt."); return; } else { if (!MsgBox.Show(this, MsgBoxButtons.OKCancel, "Warning: This definition is currently in use within the program.")) { return; } } } //Stop users from hiding the last definition in categories that must have at least one def in them. if (!_defsList.Any(x => x.DefNum != DefCur.DefNum && !x.IsHidden)) { MsgBox.Show(this, "You cannot hide the last definition in this category."); return; } } if (textName.Text == "") { MsgBox.Show(this, "Name required."); return; } switch (DefCur.Category) { case DefCat.AccountQuickCharge: case DefCat.ApptProcsQuickAdd: string[] procCodes = textValue.Text.Split(','); List <string> listProcCodes = new List <string>(); for (int i = 0; i < procCodes.Length; i++) { ProcedureCode procCode = ProcedureCodes.GetProcCode(procCodes[i]); if (procCode.CodeNum == 0) { //Now check to see if the trimmed version of the code does not exist either. procCode = ProcedureCodes.GetProcCode(procCodes[i].Trim()); if (procCode.CodeNum == 0) { MessageBox.Show(Lan.g(this, "Invalid procedure code entered") + ": " + procCodes[i]); return; } } listProcCodes.Add(procCode.ProcCode); } textValue.Text = String.Join(",", listProcCodes); break; case DefCat.AdjTypes: if (textValue.Text != "+" && textValue.Text != "-" && textValue.Text != "dp") { MessageBox.Show(Lan.g(this, "Valid values are +, -, or dp.")); return; } break; case DefCat.BillingTypes: if (textValue.Text != "" && textValue.Text != "E" && textValue.Text != "C") { MsgBox.Show(this, "Valid values are blank, E, or C."); return; } if (checkHidden.Checked && Patients.IsBillingTypeInUse(DefCur.DefNum)) { if (!MsgBox.Show(this, MsgBoxButtons.OKCancel, "Warning: Billing type is currently in use by patients, insurance plans, or preferences.")) { return; } } break; case DefCat.ClaimCustomTracking: int value = 0; if (!Int32.TryParse(textValue.Text, out value) || value < 0) { MsgBox.Show(this, "Days Suppressed must be a valid non-negative number."); return; } break; case DefCat.CommLogTypes: if (textValue.Text != "" && textValue.Text != "MISC" && textValue.Text != "APPT" && textValue.Text != "FIN" && textValue.Text != "RECALL" && textValue.Text != "TEXT") { MessageBox.Show(Lan.g(this, "Valid values are blank,APPT,FIN,RECALL,MISC,or TEXT.")); return; } break; case DefCat.DiscountTypes: int discVal; if (textValue.Text == "") { break; } try { discVal = System.Convert.ToInt32(textValue.Text); } catch { MessageBox.Show(Lan.g(this, "Not a valid number")); return; } if (discVal < 0 || discVal > 100) { MessageBox.Show(Lan.g(this, "Valid values are between 0 and 100")); return; } textValue.Text = discVal.ToString(); break; /*case DefCat.FeeSchedNames: * if(textValue.Text=="C" || textValue.Text=="c") { * textValue.Text="C"; * } * else if(textValue.Text=="A" || textValue.Text=="a") { * textValue.Text="A"; * } * else textValue.Text=""; * break;*/ case DefCat.ImageCats: textValue.Text = textValue.Text.ToUpper().Replace(",", ""); if (!Regex.IsMatch(textValue.Text, @"^[XPS]*$")) { textValue.Text = ""; } break; case DefCat.InsurancePaymentType: if (textValue.Text != "" && textValue.Text != "N") { MsgBox.Show(this, "Valid values are blank or N."); return; } break; case DefCat.OperatoriesOld: if (textValue.Text.Length > 5) { MessageBox.Show(Lan.g(this, "Maximum length of abbreviation is 5.")); return; } break; case DefCat.ProcCodeCats: if (checkHidden.Checked) { if (IsDefCurLastShowing()) { MsgBox.Show(this, "At least one procedure code category must be enabled."); return; } } break; case DefCat.ProviderSpecialties: if (checkHidden.Checked && (Providers.IsSpecialtyInUse(DefCur.DefNum) || Referrals.IsSpecialtyInUse(DefCur.DefNum))) { MsgBox.Show(this, "You cannot hide a specialty if it is in use by a provider or a referral source."); checkHidden.Checked = false; return; } break; case DefCat.RecallUnschedStatus: if (textValue.Text.Length > 7) { MessageBox.Show(Lan.g(this, "Maximum length is 7.")); return; } break; case DefCat.TaskPriorities: if (checkHidden.Checked) { if (IsDefCurLastShowing()) { MsgBox.Show(this, "You cannot hide the last priority."); return; } } break; case DefCat.TxPriorities: if (textValue.Text.Length > 7) { MessageBox.Show(Lan.g(this, "Maximum length of abbreviation is 7.")); return; } break; default: break; } //end switch DefCur.Category DefCur.ItemName = textName.Text; DefCur.ItemValue = _selectedValueString; if (_defCatOptions.EnableValue && !_defCatOptions.IsValueDefNum) { DefCur.ItemValue = textValue.Text; } if (_defCatOptions.EnableColor) { DefCur.ItemColor = butColor.BackColor; } DefCur.IsHidden = checkHidden.Checked; if (IsNew) { Defs.Insert(DefCur); } else { Defs.Update(DefCur); } //Must be after the upsert so that we have access to the DefNum for new Defs. if (DefCur.Category == DefCat.ApptConfirmed) { //==================== EXCLUDE SEND ==================== if (checkExcludeSend.Checked) { _listExcludeSendNums.Add(DefCur.DefNum); } else { _listExcludeSendNums.RemoveAll(x => x == DefCur.DefNum); } string sendString = string.Join(",", _listExcludeSendNums.Distinct().OrderBy(x => x)); Prefs.UpdateString(PrefName.ApptConfirmExcludeESend, sendString); //==================== EXCLUDE CONFIRM ==================== if (checkExcludeConfirm.Checked) { _listExcludeConfirmNums.Add(DefCur.DefNum); } else { _listExcludeConfirmNums.RemoveAll(x => x == DefCur.DefNum); } string confirmString = string.Join(",", _listExcludeConfirmNums.Distinct().OrderBy(x => x)); Prefs.UpdateString(PrefName.ApptConfirmExcludeEConfirm, confirmString); //==================== EXCLUDE REMIND ==================== if (checkExcludeRemind.Checked) { _listExcludeRemindNums.Add(DefCur.DefNum); } else { _listExcludeRemindNums.RemoveAll(x => x == DefCur.DefNum); } string remindString = string.Join(",", _listExcludeRemindNums.Distinct().OrderBy(x => x)); Prefs.UpdateString(PrefName.ApptConfirmExcludeERemind, remindString); Signalods.SetInvalid(InvalidType.Prefs); } DialogResult = DialogResult.OK; }
///<summary>Spawns a new thread to retrieve new signals from the DB, update caches, and broadcast signals to all subscribed forms.</summary> public static void SignalsTick(Action onShutdown, Action <List <ODForm>, List <Signalod> > onProcess, Action onDone) { //No need to check RemotingRole; no call to db. Logger.LogToPath("", LogPath.Signals, LogPhase.Start); List <Signalod> listSignals = new List <Signalod>(); ODThread threadRefreshSignals = new ODThread((o) => { //Get new signals from DB. Logger.LogToPath("RefreshTimed", LogPath.Signals, LogPhase.Start); listSignals = Signalods.RefreshTimed(Signalods.SignalLastRefreshed); Logger.LogToPath("RefreshTimed", LogPath.Signals, LogPhase.End); //Only update the time stamp with signals retreived from the DB. Do NOT use listLocalSignals to set timestamp. if (listSignals.Count > 0) { Signalods.SignalLastRefreshed = listSignals.Max(x => x.SigDateTime); Signalods.ApptSignalLastRefreshed = Signalods.SignalLastRefreshed; } Logger.LogToPath("Found " + listSignals.Count.ToString() + " signals", LogPath.Signals, LogPhase.Unspecified); if (listSignals.Count == 0) { return; } Logger.LogToPath("Signal count(s)", LogPath.Signals, LogPhase.Unspecified, string.Join(" - ", listSignals.GroupBy(x => x.IType).Select(x => x.Key.ToString() + ": " + x.Count()))); if (listSignals.Exists(x => x.IType == InvalidType.ShutDownNow)) { onShutdown(); return; } InvalidType[] cacheRefreshArray = listSignals.FindAll(x => x.FKey == 0 && x.FKeyType == KeyType.Undefined).Select(x => x.IType).Distinct().ToArray(); //Always process signals for ClientDirect users regardless of where the RemoteRole source on the signal is from. //The middle tier server will have refreshed its cache already. bool getCacheFromDb = true; if (RemotingClient.RemotingRole == RemotingRole.ClientWeb && !listSignals.Any(x => x.RemoteRole == RemotingRole.ClientDirect)) { //ClientWebs do not need to tell the middle tier to go to the database unless a ClientDirect has inserted a signal. getCacheFromDb = false; } Cache.Refresh(getCacheFromDb, cacheRefreshArray); onProcess(_listSubscribedForms, listSignals); }); threadRefreshSignals.AddExceptionHandler((e) => { DateTime dateTimeRefreshed; try { //Signal processing should always use the server's time. dateTimeRefreshed = MiscData.GetNowDateTime(); } catch { //If the server cannot be reached, we still need to move the signal processing forward so use local time as a fail-safe. dateTimeRefreshed = DateTime.Now; } Signalods.SignalLastRefreshed = dateTimeRefreshed; Signalods.ApptSignalLastRefreshed = dateTimeRefreshed; }); threadRefreshSignals.AddExitHandler((o) => { Logger.LogToPath("", LogPath.Signals, LogPhase.End); onDone(); }); threadRefreshSignals.Name = "SignalsTick"; threadRefreshSignals.Start(true); }
public static Bug AddBugAndJob(ODForm form, List <BugSubmission> listSelectedSubs, Patient pat) { if (!JobPermissions.IsAuthorized(JobPerm.Concept, true) && !JobPermissions.IsAuthorized(JobPerm.NotifyCustomer, true) && !JobPermissions.IsAuthorized(JobPerm.FeatureManager, true) && !JobPermissions.IsAuthorized(JobPerm.Documentation, true)) { return(null); } if (listSelectedSubs.Count == 0) { MsgBox.Show(form, "You must select a bug submission to create a job for."); return(null); } Job jobNew = new Job(); jobNew.Category = JobCategory.Bug; InputBox titleBox = new InputBox("Provide a brief title for the job."); if (titleBox.ShowDialog() != DialogResult.OK) { return(null); } if (String.IsNullOrEmpty(titleBox.textResult.Text)) { MsgBox.Show(form, "You must type a title to create a job."); return(null); } List <Def> listJobPriorities = Defs.GetDefsForCategory(DefCat.JobPriorities, true); if (listJobPriorities.Count == 0) { MsgBox.Show(form, "You have no priorities setup in definitions."); return(null); } jobNew.Title = titleBox.textResult.Text; long priorityNum = 0; priorityNum = listJobPriorities.FirstOrDefault(x => x.ItemValue.Contains("BugDefault")).DefNum; jobNew.Priority = priorityNum == 0?listJobPriorities.First().DefNum:priorityNum; jobNew.PhaseCur = JobPhase.Concept; jobNew.UserNumConcept = Security.CurUser.UserNum; Bug bugNew = new Bug(); bugNew = Bugs.GetNewBugForUser(); InputBox bugDescription = new InputBox("Provide a brief description for the bug. This will appear in the bug tracker.", jobNew.Title); if (bugDescription.ShowDialog() != DialogResult.OK) { return(null); } if (String.IsNullOrEmpty(bugDescription.textResult.Text)) { MsgBox.Show(form, "You must type a description to create a bug."); return(null); } FormVersionPrompt FormVP = new FormVersionPrompt("Enter versions found"); FormVP.ShowDialog(); if (FormVP.DialogResult != DialogResult.OK || string.IsNullOrEmpty(FormVP.VersionText)) { MsgBox.Show(form, "You must enter a version to create a bug."); return(null); } bugNew.Status_ = BugStatus.Accepted; bugNew.VersionsFound = FormVP.VersionText; bugNew.Description = bugDescription.textResult.Text; BugSubmission sub = listSelectedSubs.First(); jobNew.Requirements = BugSubmissions.GetSubmissionDescription(pat, sub); Jobs.Insert(jobNew); JobLink jobLinkNew = new JobLink(); jobLinkNew.LinkType = JobLinkType.Bug; jobLinkNew.JobNum = jobNew.JobNum; jobLinkNew.FKey = Bugs.Insert(bugNew); JobLinks.Insert(jobLinkNew); BugSubmissions.UpdateBugIds(bugNew.BugId, listSelectedSubs.Select(x => x.BugSubmissionNum).ToList()); if (MsgBox.Show(form, MsgBoxButtons.YesNo, "Would you like to create a task too?")) { long taskNum = CreateTask(pat, sub); if (taskNum != 0) { jobLinkNew = new JobLink(); jobLinkNew.LinkType = JobLinkType.Task; jobLinkNew.JobNum = jobNew.JobNum; jobLinkNew.FKey = taskNum; JobLinks.Insert(jobLinkNew); } } Signalods.SetInvalid(InvalidType.Jobs, KeyType.Job, jobNew.JobNum); FormOpenDental.S_GoToJob(jobNew.JobNum); return(bugNew); }
///<summary>Function used by threads to connect to remote databases and sync user settings.</summary> private static void ConnectAndSyncUsers(ODThread odThread) { CentralConnection connection = (CentralConnection)odThread.Parameters[0]; List <CentralUserData> listCentralUserData = (List <CentralUserData>)odThread.Parameters[1]; string serverName = ""; if (connection.ServiceURI != "") { serverName = connection.ServiceURI; } else { serverName = connection.ServerName + ", " + connection.DatabaseName; } if (!CentralConnectionHelper.UpdateCentralConnection(connection, false)) //No updating the cache since we're going to be connecting to multiple remote servers at the same time. { odThread.Tag = new List <string>() { serverName + "\r\n", "", "" }; connection.ConnectionStatus = "OFFLINE"; return; } string remoteSyncCode = PrefC.GetStringNoCache(PrefName.CentralManagerSyncCode); if (remoteSyncCode != _syncCode) { if (remoteSyncCode == "") { Prefs.UpdateStringNoCache(PrefName.CentralManagerSyncCode, _syncCode); //Lock in the sync code for the remote server. } else { odThread.Tag = new List <string>() { serverName + "\r\n", "", remoteSyncCode }; return; } } //Get remote users, usergroups, associated permissions, and alertsubs List <Userod> listRemoteUsers = Userods.GetUsersNoCache(); #region Detect Conflicts //User conflicts bool nameConflict = false; string nameConflicts = ""; for (int i = 0; i < _listCEMTUsers.Count; i++) { for (int j = 0; j < listRemoteUsers.Count; j++) { if (listRemoteUsers[j].UserName == _listCEMTUsers[i].UserName && listRemoteUsers[j].UserNumCEMT == 0) //User doesn't belong to CEMT { nameConflicts += listRemoteUsers[j].UserName + " already exists in " + serverName + "\r\n"; nameConflict = true; break; } } } if (nameConflict) { odThread.Tag = new List <string>() { serverName + "\r\n", nameConflicts, "" }; return; //Skip on to the next connection. } #endregion Detect Conflicts List <UserGroup> listRemoteCEMTUserGroups = UserGroups.GetCEMTGroupsNoCache(); List <UserGroup> listCEMTUserGroups = new List <UserGroup>(); List <AlertSub> listRemoteAlertSubs = AlertSubs.GetAll(); List <Clinic> listRemoteClinics = Clinics.GetClinicsNoCache(); List <AlertSub> listAlertSubsToInsert = new List <AlertSub>(); for (int i = 0; i < listCentralUserData.Count; i++) { listCEMTUserGroups.Add(listCentralUserData[i].UserGroup.Copy()); } //SyncUserGroups returns the list of UserGroups for deletion so it can be used after syncing Users and GroupPermissions. List <UserGroup> listRemoteCEMTUserGroupsForDeletion = CentralUserGroups.Sync(listCEMTUserGroups, listRemoteCEMTUserGroups); listRemoteCEMTUserGroups = UserGroups.GetCEMTGroupsNoCache(); for (int i = 0; i < listCentralUserData.Count; i++) { List <GroupPermission> listGroupPerms = new List <GroupPermission>(); for (int j = 0; j < listRemoteCEMTUserGroups.Count; j++) { if (listCentralUserData[i].UserGroup.UserGroupNumCEMT == listRemoteCEMTUserGroups[j].UserGroupNumCEMT) { for (int k = 0; k < listCentralUserData[i].ListGroupPermissions.Count; k++) { listCentralUserData[i].ListGroupPermissions[k].UserGroupNum = listRemoteCEMTUserGroups[j].UserGroupNum; //fixing primary keys to be what's in remote db } listGroupPerms = GroupPermissions.GetPermsNoCache(listRemoteCEMTUserGroups[j].UserGroupNum); } } CentralUserods.Sync(listCentralUserData[i].ListUsers, listRemoteUsers); CentralGroupPermissions.Sync(listCentralUserData[i].ListGroupPermissions, listGroupPerms); } //Sync usergroup attaches SyncUserGroupAttaches(listCentralUserData); for (int j = 0; j < listRemoteCEMTUserGroupsForDeletion.Count; j++) { UserGroups.DeleteNoCache(listRemoteCEMTUserGroupsForDeletion[j]); } if (_listAlertSubs.Count > 0) { listRemoteUsers = Userods.GetUsersNoCache(); //Refresh users so we can do alertsubs. } //For each AlertSub, make a copy of that AlertSub for each Clinic. foreach (AlertSub alertSub in _listAlertSubs) { foreach (Clinic clinic in listRemoteClinics) { AlertSub alert = new AlertSub(); alert.ClinicNum = clinic.ClinicNum; alert.Type = alertSub.Type; alert.UserNum = listRemoteUsers.Find(x => x.UserName == _listCEMTUsers.Find(y => y.UserNum == alertSub.UserNum).UserName).UserNum; listAlertSubsToInsert.Add(alert); } } AlertSubs.DeleteAndInsertForSuperUsers(_listCEMTUsers, listAlertSubsToInsert); //Refresh server's cache of userods Signalods.SetInvalidNoCache(InvalidType.Security); SecurityLogs.MakeLogEntryNoCache(Permissions.SecurityAdmin, 0, "Enterprise Management Tool synced users."); odThread.Tag = new List <string>() { "", "", "" }; //No errors. }