private void setupToolStripMenuItem_Click(object sender, EventArgs e)
 {
     if (!IsEditMode)
     {
         if (!Security.IsAuthorized(Permissions.GraphicalReportSetup))
         {
             return;
         }
         SecurityLogs.MakeLogEntry(Permissions.GraphicalReportSetup, 0, "Accessed graphical reports setup controls.");
     }
     IsEditMode = !IsEditMode;
 }
        ///<summary>Function used by threads to connect to remote databases and sync security lock settings.</summary>
        private static void ConnectAndSyncLocks(ODThread odThread)
        {
            CentralConnection connection = (CentralConnection)odThread.Parameters[0];
            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.GetString(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;
                }
            }
            //Push the preferences to the server.
            Prefs.UpdateStringNoCache(PrefName.SecurityLockDate, _securityLockDate);
            Prefs.UpdateIntNoCache(PrefName.SecurityLockDays, _securityLockDays);
            Prefs.UpdateBoolNoCache(PrefName.SecurityLockIncludesAdmin, _securityLockAdmin);
            Prefs.UpdateBoolNoCache(PrefName.CentralManagerSecurityLock, _securityCentralLock);
            Signalods.SetInvalidNoCache(InvalidType.Prefs);
            SecurityLogs.MakeLogEntryNoCache(Permissions.SecurityAdmin, 0, "Enterprise Management Tool updated security settings");
            odThread.Tag = new List <string>()
            {
                "", "", ""
            };                                                       //No errors.
        }
Beispiel #3
0
 public static void SendData(Program ProgramCur, Patient pat)
 {
     try {
         if (CADIWindow == null)                //Only release this reference once the CADIWindow instance has closed.
         {
             CADIWindow = new CADINativeWindow(new Action(() => CADIWindow = null));
         }
         CADIWindow.SendData(ProgramCur, pat);
     }
     catch (Exception e) {
         MessageBox.Show(e.Message);
         SecurityLogs.MakeLogEntry(Permissions.ChartModule, ODMethodsT.Coalesce(pat).PatNum, e.Message);
     }
 }
Beispiel #4
0
 ///<summary></summary>
 protected override void Dispose(bool disposing)
 {
     if (disposing)            //managed resources
     {
         components?.Dispose();
         //get rid of temp appts on pinboard. =jordan I don't see any docs on why this is here. Doesn't seem quite right, but it works.
         for (int i = 0; i < ListPinBoardItems.Count; i++)
         {
             if (PIn.Int(ListPinBoardItems[i].DataRowAppt["AptStatus"].ToString()) != (int)ApptStatus.UnschedList)
             {
                 continue;
             }
             if (PIn.DateT(ListPinBoardItems[i].DataRowAppt["AptDateTime"].ToString()).Year > 1880)
             {
                 continue;
             }
             Appointment appt = null;
             try{
                 appt = Appointments.GetOneApt(ListPinBoardItems[i].AptNum);
             }
             catch {
                 break;                        //db connection no longer present.
             }
             if (appt == null)
             {
                 continue;
             }
             if (appt.AptDateTime.Year > 1880)                   //date was updated since put on the pinboard
             {
                 continue;
             }
             Appointments.Delete(appt.AptNum, true);
             if (Security.CurUser == null)                  // E.g. clicking Log Off invalidates the user.
             {
                 continue;
             }
             //Make a security log if we still have a valid user logged in.
             string logText = Lan.g(this, "Deleted from pinboard while closing Open Dental") + ": ";
             if (appt.AptDateTime.Year > 1880)
             {
                 logText += appt.AptDateTime.ToString() + ", ";
             }
             logText += appt.ProcDescript;
             SecurityLogs.MakeLogEntry(Permissions.AppointmentEdit, appt.PatNum, logText);
         }
     }
     base.Dispose(disposing);
 }
Beispiel #5
0
        public void SecurityLogs_MakeLogEntry_DuplicateEntry()
        {
            Patient patient = PatientT.CreatePatient(MethodBase.GetCurrentMethod().Name);

            //There are lots of bug submissions with exception text like "Duplicate entry 'XXXXX' for key 'PRIMARY'".
            //OpenDentBusiness.SecurityLogs.MakeLogEntry() seems to be the common theme for most of the submissions.
            //Loop as fast as we can and insert 200 security logs trying to get a duplicate entry exception.
            for (int i = 0; i < 200; i++)
            {
                try {
                    SecurityLogs.MakeLogEntry(Permissions.Accounting, patient.PatNum, "", 0, DateTime.Now.AddDays(-7));
                }
                catch (Exception ex) {
                    Assert.Fail(ex.Message);
                    break;
                }
            }
        }
        private void butRunAllocatorTool_Click(object sender, EventArgs e)
        {
            if (!rbutIHaveRead.Checked)
            {
                PU.MB = Lan.g(this, "You must indicate that you have read the text in the box!");
                return;
            }

            if (MessageBox.Show("Do you want to run the batch allocation?", "Please Respond", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                FormWarnToCloseComputers fwc = new FormWarnToCloseComputers();
                if (fwc.ShowDialog() == DialogResult.Yes)
                {
                    Reporting.Allocators.MyAllocator1_ProviderPayment allocator1 = new OpenDental.Reporting.Allocators.MyAllocator1_ProviderPayment();
                    SecurityLogs.MakeLogEntry(OpenDentBusiness.Permissions.Setup, 0, "Started Batch Allocation For Provider Allocation Tool");
                    allocator1.StartBatchAllocation();
                    SecurityLogs.MakeLogEntry(OpenDentBusiness.Permissions.Setup, 0, "Finished Batch Allocation For Provider Allocation Tool");

                    List <string> commands = new List <string>();
                    if (!PrefC.ContainsKey(MyAllocator1_ProviderPayment.Pref_AllocatorProvider1_ToolHasRun))
                    {
                        commands.Add("INSERT INTO preference VALUES ('"
                                     + MyAllocator1_ProviderPayment.Pref_AllocatorProvider1_ToolHasRun + "','0')");
                    }
                    if (!PrefC.ContainsKey(MyAllocator1_ProviderPayment.Pref_AllocatorProvider1_Use))
                    {
                        commands.Add("INSERT INTO preference VALUES ('"
                                     + MyAllocator1_ProviderPayment.Pref_AllocatorProvider1_Use + "','0')");
                    }
                    if (commands.Count != 0)
                    {
                        Db.NonQOld(commands.ToArray());
                        Cache.Refresh(InvalidType.Prefs);
                    }
                    Prefs.UpdateRaw(MyAllocator1_ProviderPayment.Pref_AllocatorProvider1_ToolHasRun, "1");
                    Prefs.UpdateRaw(MyAllocator1_ProviderPayment.Pref_AllocatorProvider1_Use, "1");
                }
            }
            RefreshForm();
        }
Beispiel #7
0
        public static void ProcessMessage(MessageHL7 message, bool isVerboseLogging)
        {
            SegmentHL7 seg      = message.GetSegment(SegmentNameHL7.PID, true);
            long       patNum   = PIn.Long(seg.GetFieldFullText(2));
            Patient    pat      = Patients.GetPat(patNum);
            Patient    patOld   = null;
            bool       isNewPat = pat == null;

            if (isNewPat)
            {
                pat             = new Patient();
                pat.PatNum      = patNum;
                pat.Guarantor   = patNum;
                pat.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                pat.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                patOld = pat.Copy();
            }
            List <PatientRace> listPatRaces = new List <PatientRace>();

            EcwSegmentPID.ProcessPID(pat, seg, false, listPatRaces);         //IsStandalone=false because should never make it this far.
            //PV1-patient visit---------------------------
            //seg=message.GetSegment(SegmentName.PV1,false);
            //if(seg!=null) {
            //	SegmentPID.ProcessPV1(pat,seg);
            //}
            //SCH- Schedule Activity Information
            seg = message.GetSegment(SegmentNameHL7.SCH, true);
            //The documentation is wrong.  SCH.01 is not the appointment ID, but is instead a sequence# (always 1)
            long        aptNum   = PIn.Long(seg.GetFieldFullText(2));
            Appointment apt      = Appointments.GetOneApt(aptNum);
            Appointment aptOld   = null;
            bool        isNewApt = apt == null;

            if (isNewApt)
            {
                apt           = new Appointment();
                apt.AptNum    = aptNum;
                apt.PatNum    = pat.PatNum;
                apt.AptStatus = ApptStatus.Scheduled;
            }
            else
            {
                aptOld = apt.Copy();
            }
            if (apt.PatNum != pat.PatNum)
            {
                EventLog.WriteEntry("OpenDentHL7", "Appointment does not match patient: " + pat.FName + " " + pat.LName
                                    + ", apt.PatNum:" + apt.PatNum.ToString() + ", pat.PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Error);
                return;                //we can't process this message because wrong patnum.
            }
            apt.Note = seg.GetFieldFullText(7);
            //apt.Pattern=ProcessDuration(seg.GetFieldFullText(9));
            //9 and 10 are not actually available, in spite of the documentation.
            //11-We need start time and stop time
            apt.AptDateTime = DateTimeParse(seg.GetFieldComponent(11, 3));
            DateTime stopTime = DateTimeParse(seg.GetFieldComponent(11, 4));

            apt.Pattern = ProcessPattern(apt.AptDateTime, stopTime);
            apt.ProvNum = pat.PriProv;          //just in case there's not AIG segment.
            //AIG is optional, but looks like the only way to get provider for the appt-----------
            //PV1 seems to frequently be sent instead of AIG.
            SegmentHL7 segAIG = message.GetSegment(SegmentNameHL7.AIG, false);
            SegmentHL7 segPV  = message.GetSegment(SegmentNameHL7.PV1, false);

            if (segAIG != null)
            {
                long provNum = EcwSegmentPID.ProvProcess(segAIG.GetField(3));
                if (provNum != 0)
                {
                    apt.ProvNum = provNum;
                    pat.PriProv = provNum;
                }
            }
            else if (segPV != null)
            {
                long provNum = EcwSegmentPID.ProvProcess(segPV.GetField(7));
                if (provNum != 0)
                {
                    apt.ProvNum = provNum;
                    pat.PriProv = provNum;
                }
            }
            //AIL,AIP seem to be optional, and I'm going to ignore them for now.
            if (pat.FName == "" || pat.LName == "")
            {
                EventLog.WriteEntry("OpenDentHL7", "Appointment not processed due to missing patient first or last name. PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;                //this will also skip the appt insert.
            }
            if (isNewPat)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted patient: " + pat.FName + " " + pat.LName + ", PatNum:" + pat.PatNum.ToString()
                                        , EventLogEntryType.Information);
                }
                Patients.Insert(pat, true);
                SecurityLogs.MakeLogEntry(Permissions.PatientCreate, pat.PatNum, "Created from HL7 for eCW.", LogSources.HL7);
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Patients.Update(pat, patOld);
            }
            //had to move this reconcile here since we might not have a PatNum for new patients until after the insert
            PatientRaces.Reconcile(pat.PatNum, listPatRaces);
            if (isNewApt)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted appointment for: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Appointments.InsertIncludeAptNum(apt, true);
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated appointment for: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Appointments.Update(apt, aptOld);
            }
        }
Beispiel #8
0
        public static void ProcessMessage(MessageHL7 message, bool isStandalone, bool isVerboseLogging)
        {
            /*string triggerevent=message.Segments[0].GetFieldComponent(8,1);
             * switch(triggerevent) {
             *      case "A01"://Admit/Visit Information
             *
             *              break;
             *      case "A04"://New Patient Information
             *              ProcessNewPatient(message);
             *              break;
             *      case "A08"://Update Patient Information
             *
             *              break;
             *      case "A28"://Add Patient Information
             *
             *              break;
             *      case "A31"://Update Patient Information
             *
             *              break;
             * }*/
            //MSH-Ignore
            //EVN-Ignore
            //PID-------------------------------------
            SegmentHL7 seg    = message.GetSegment(SegmentNameHL7.PID, true);
            long       patNum = PIn.Long(seg.GetFieldFullText(2));
            Patient    pat    = null;

            if (isStandalone)
            {
                pat = Patients.GetPatByChartNumber(patNum.ToString());
                if (pat == null)
                {
                    //try to find the patient in question by using name and birthdate
                    string   lName        = seg.GetFieldComponent(5, 0);
                    string   fName        = seg.GetFieldComponent(5, 1);
                    DateTime birthdate    = EcwSegmentPID.DateParse(seg.GetFieldFullText(7));
                    long     patNumByName = Patients.GetPatNumByNameAndBirthday(lName, fName, birthdate);
                    if (patNumByName == 0)                   //patient does not exist in OD
                    //so pat will still be null, triggering creation of new patient further down.
                    {
                    }
                    else
                    {
                        pat             = Patients.GetPat(patNumByName);
                        pat.ChartNumber = patNum.ToString();                      //from now on, we will be able to find pat by chartNumber
                    }
                }
            }
            else
            {
                pat = Patients.GetPat(patNum);
            }
            Patient patOld   = null;
            bool    isNewPat = pat == null;

            if (isNewPat)
            {
                pat = new Patient();
                if (isStandalone)
                {
                    pat.ChartNumber = patNum.ToString();
                    //this line does not work if isStandalone, so moved to end
                    //pat.Guarantor=patNum;
                }
                else
                {
                    pat.PatNum    = patNum;
                    pat.Guarantor = patNum;
                }
                pat.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                pat.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                patOld = pat.Copy();
            }
            List <PatientRace> listPatRaces = new List <PatientRace>();
            bool hasNoRaceInStandalone      = (isStandalone && (pat == null || pat.PatNum == 0));

            EcwSegmentPID.ProcessPID(pat, seg, isStandalone, listPatRaces);
            //PV1-patient visit---------------------------
            //seg=message.GetSegment(SegmentName.PV1,false);
            //if(seg!=null) {//this seg is optional
            //	SegmentPID.ProcessPV1(pat,seg);
            //}
            //PD1-additional patient demographics------------
            //seg=message.GetSegment(SegmentName.PD1,false);
            //if(seg!=null) {//this seg is optional
            //	ProcessPD1(pat,seg);
            //}
            //GT1-Guarantor-------------------------------------
            seg = message.GetSegment(SegmentNameHL7.GT1, true);
            EcwSegmentPID.ProcessGT1(pat, seg, isStandalone);
            //IN1-Insurance-------------------------------------
            //List<SegmentHL7> segments=message.GetSegments(SegmentName.IN1);
            //for(int i=0;i<segments.Count;i++) {
            //	ProcessIN1(pat,seg);
            //}
            if (pat.FName == "" || pat.LName == "")
            {
                EventLog.WriteEntry("OpenDentHL7", "Patient demographics not processed due to missing first or last name. PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;
            }
            if (isNewPat)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                pat.PatNum = Patients.Insert(pat, !isStandalone);             //use existing PK if not standalone, standalone will have PatNum=0, so set PatNum here
                SecurityLogs.MakeLogEntry(Permissions.PatientCreate, pat.PatNum, "Created from HL7 for eCW.", LogSources.HL7);
                if (hasNoRaceInStandalone)
                {
                    Patient patientRaceTemp = pat.Copy();                  //Make a deep copy so that we do not accidentally override something.
                    seg = message.GetSegment(SegmentNameHL7.PID, true);
                    //We have to process the PID again in order to correct the patient race.  Patient race(s) will automatically get inserted if needed.
                    EcwSegmentPID.ProcessPID(patientRaceTemp, seg, isStandalone, listPatRaces);
                }
                if (pat.Guarantor == 0)
                {
                    patOld        = pat.Copy();
                    pat.Guarantor = pat.PatNum;
                    Patients.Update(pat, patOld);
                }
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Patients.Update(pat, patOld);
            }
            //had to move this reconcile here since we might not have a PatNum for new patients until after the insert
            PatientRaces.Reconcile(pat.PatNum, listPatRaces);
        }
Beispiel #9
0
        ///<summary>If relationship is self, this loop does nothing.  A new pat will later change guarantor to be same as patnum. </summary>
        public static void ProcessGT1(Patient pat, SegmentHL7 seg, bool useChartNumber)
        {
            long guarNum = PIn.Long(seg.GetFieldFullText(2));

            if (guarNum == 0)           //because we have an example where they sent us this (position 2 is empty): GT1|1||^^||^^^^||||||||
            {
                return;
            }
            if (seg.GetFieldFullText(11) == "1")           //if relationship is self (according to some of their documentation)
            {
                return;
            }
            if (seg.GetFieldComponent(3, 0) == "" ||     //lname
                seg.GetFieldComponent(3, 1) == "")                //fname
            {
                EventLog.WriteEntry("OpenDentHL7", "Guarantor not processed due to missing first or last name. PatNum of patient:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;
            }
            Patient guar    = null;
            Patient guarOld = null;

            //So guarantor is someone else
            if (useChartNumber)
            {
                //try to find guarantor by using chartNumber
                guar = Patients.GetPatByChartNumber(guarNum.ToString());
                if (guar == null)
                {
                    //try to find the guarantor by using name and birthdate
                    string   lName         = seg.GetFieldComponent(3, 0);
                    string   fName         = seg.GetFieldComponent(3, 1);
                    DateTime birthdate     = EcwSegmentPID.DateParse(seg.GetFieldFullText(8));
                    long     guarNumByName = Patients.GetPatNumByNameAndBirthday(lName, fName, birthdate);
                    if (guarNumByName == 0)                   //guarantor does not exist in OD
                    //so guar will still be null, triggering creation of new guarantor further down.
                    {
                    }
                    else
                    {
                        guar             = Patients.GetPat(guarNumByName);
                        guar.ChartNumber = guarNum.ToString();                      //from now on, we will be able to find guar by chartNumber
                    }
                }
            }
            else
            {
                guar = Patients.GetPat(guarNum);
            }
            //we can't necessarily set pat.Guarantor yet, because in Standalone mode, we might not know it yet.
            bool isNewGuar = guar == null;

            if (isNewGuar)             //then we need to add guarantor to db
            {
                guar = new Patient();
                if (useChartNumber)
                {
                    guar.ChartNumber = guarNum.ToString();
                }
                else
                {
                    guar.PatNum = guarNum;
                }
                guar.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                guar.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                guarOld = guar.Copy();
            }
            //guar.Guarantor=guarNum;
            guar.LName     = seg.GetFieldComponent(3, 0);
            guar.FName     = seg.GetFieldComponent(3, 1);
            guar.MiddleI   = seg.GetFieldComponent(3, 2);
            guar.Address   = seg.GetFieldComponent(5, 0);
            guar.Address2  = seg.GetFieldComponent(5, 1);
            guar.City      = seg.GetFieldComponent(5, 2);
            guar.State     = seg.GetFieldComponent(5, 3);
            guar.Zip       = seg.GetFieldComponent(5, 4);
            guar.HmPhone   = PhoneParse(seg.GetFieldFullText(6));
            guar.WkPhone   = PhoneParse(seg.GetFieldFullText(7));
            guar.Birthdate = DateParse(seg.GetFieldFullText(8));
            guar.Gender    = GenderParse(seg.GetFieldFullText(9));
            //11. Guarantor relationship to patient.  We can't really do anything with this value
            guar.SSN = seg.GetFieldFullText(12);
            if (isNewGuar)
            {
                Patients.Insert(guar, !useChartNumber);               //if using chartnumber (standalone mode), then can't insert using existing PK
                SecurityLogs.MakeLogEntry(Permissions.PatientCreate, guar.PatNum, "Created from HL7 for eCW.", LogSources.HL7);
                guarOld        = guar.Copy();
                guar.Guarantor = guar.PatNum;
                Patients.Update(guar, guarOld);
            }
            else
            {
                Patients.Update(guar, guarOld);
            }
            pat.Guarantor = guar.PatNum;
        }
Beispiel #10
0
        ///<summary>Most of the logic for breaking an appointment. Pass in the brokenFee (the number the user enters in the brokenAppointment window),
        ///Optionally pass in if the brokenappointment procedure is being deleted. Returns the broken procedure that was created.</summary>
        public static Procedure BreakAppointment(Appointment appt, Patient pat, ProcedureCode procCode, double feeOverride, bool isDeleteBrokenProc = false)
        {
            //suppressHistory is true due to below logic creating a log with a specific HistAppointmentAction instead of the generic changed.
            DateTime datePrevious    = appt.DateTStamp;
            bool     suppressHistory = false;

            if (procCode != null)
            {
                suppressHistory = procCode.ProcCode == "D9986" || procCode.ProcCode == "D9987";
            }
            Appointments.SetAptStatus(appt, ApptStatus.Broken, suppressHistory); //Appointments S-Class handles Signalods
            if (appt.AptStatus != ApptStatus.Complete)                           //seperate log entry for completed appointments.
            {
                SecurityLogs.MakeLogEntry(Permissions.AppointmentEdit, pat.PatNum,
                                          appt.ProcDescript + ", " + appt.AptDateTime.ToString()
                                          + ", Broken from the Appts module.", appt.AptNum, datePrevious);
            }
            else
            {
                SecurityLogs.MakeLogEntry(Permissions.AppointmentCompleteEdit, pat.PatNum,
                                          appt.ProcDescript + ", " + appt.AptDateTime.ToString()
                                          + ", Broken from the Appts module.", appt.AptNum, datePrevious);
            }
            List <Procedure> listProcedures = Procedures.GetProcsForSingle(appt.AptNum, false);
            //splits should only exist on procs if they are using tp pre-payments
            List <PaySplit> listSplitsForApptProcs = new List <PaySplit>();
            bool            isNonRefundable        = false;
            double          brokenProcAmount       = 0;

            if (listProcedures.Count > 0)
            {
                listSplitsForApptProcs = PaySplits.GetPaySplitsFromProcs(listProcedures.Select(x => x.ProcNum).ToList());
            }
            Procedure brokenProcedure = new Procedure();

            #region Charting the proc
            if (procCode != null)
            {
                switch (procCode.ProcCode)
                {
                case "D9986":                        //Missed
                    HistAppointments.CreateHistoryEntry(appt.AptNum, HistAppointmentAction.Missed);
                    break;

                case "D9987":                        //Cancelled
                    HistAppointments.CreateHistoryEntry(appt.AptNum, HistAppointmentAction.Cancelled);
                    break;
                }
                brokenProcedure.PatNum       = pat.PatNum;
                brokenProcedure.ProvNum      = (procCode.ProvNumDefault > 0 ? procCode.ProvNumDefault : appt.ProvNum);
                brokenProcedure.CodeNum      = procCode.CodeNum;
                brokenProcedure.ProcDate     = DateTime.Today;
                brokenProcedure.DateEntryC   = DateTime.Now;
                brokenProcedure.ProcStatus   = ProcStat.C;
                brokenProcedure.ClinicNum    = appt.ClinicNum;
                brokenProcedure.UserNum      = Security.CurUser.UserNum;
                brokenProcedure.Note         = Lans.g("AppointmentEdit", "Appt BROKEN for") + " " + appt.ProcDescript + "  " + appt.AptDateTime.ToString();
                brokenProcedure.PlaceService = (PlaceOfService)PrefC.GetInt(PrefName.DefaultProcedurePlaceService);              //Default proc place of service for the Practice is used.
                List <InsSub>  listInsSubs    = InsSubs.RefreshForFam(Patients.GetFamily(pat.PatNum));
                List <InsPlan> listInsPlans   = InsPlans.RefreshForSubList(listInsSubs);
                List <PatPlan> listPatPlans   = PatPlans.Refresh(pat.PatNum);
                InsPlan        insPlanPrimary = null;
                InsSub         insSubPrimary  = null;
                if (listPatPlans.Count > 0)
                {
                    insSubPrimary  = InsSubs.GetSub(listPatPlans[0].InsSubNum, listInsSubs);
                    insPlanPrimary = InsPlans.GetPlan(insSubPrimary.PlanNum, listInsPlans);
                }
                double procFee;
                long   feeSch;
                if (insPlanPrimary == null || procCode.NoBillIns)
                {
                    feeSch = FeeScheds.GetFeeSched(0, pat.FeeSched, brokenProcedure.ProvNum);
                }
                else                  //Only take into account the patient's insurance fee schedule if the D9986 procedure is not marked as NoBillIns
                {
                    feeSch = FeeScheds.GetFeeSched(insPlanPrimary.FeeSched, pat.FeeSched, brokenProcedure.ProvNum);
                }
                procFee = Fees.GetAmount0(brokenProcedure.CodeNum, feeSch, brokenProcedure.ClinicNum, brokenProcedure.ProvNum);
                if (insPlanPrimary != null && insPlanPrimary.PlanType == "p" && !insPlanPrimary.IsMedical)         //PPO
                {
                    double provFee = Fees.GetAmount0(brokenProcedure.CodeNum, Providers.GetProv(brokenProcedure.ProvNum).FeeSched, brokenProcedure.ClinicNum,
                                                     brokenProcedure.ProvNum);
                    brokenProcedure.ProcFee = Math.Max(provFee, procFee);
                }
                else
                {
                    brokenProcedure.ProcFee = procFee;
                }
                if (!PrefC.GetBool(PrefName.EasyHidePublicHealth))
                {
                    brokenProcedure.SiteNum = pat.SiteNum;
                }
                Procedures.Insert(brokenProcedure);
                Procedure procOld = brokenProcedure.Copy();
                //Now make a claimproc if the patient has insurance.  We do this now for consistency because a claimproc could get created in the future.
                List <Benefit>   listBenefits          = Benefits.Refresh(listPatPlans, listInsSubs);
                List <ClaimProc> listClaimProcsForProc = ClaimProcs.RefreshForProc(brokenProcedure.ProcNum);
                Procedures.ComputeEstimates(brokenProcedure, pat.PatNum, listClaimProcsForProc, false, listInsPlans, listPatPlans, listBenefits, pat.Age, listInsSubs);
                if (listSplitsForApptProcs.Count > 0 && PrefC.GetBool(PrefName.TpPrePayIsNonRefundable) && procCode.ProcCode == "D9986")
                {
                    //if there are pre-payments, non-refundable pre-payments is turned on, and the broken appointment is a missed code then auto-fill
                    //the window with the sum of the procs for the appointment. Transfer money below after broken procedure is confirmed by the user.
                    //normally goes to the form to let the user speficy, this is the auto filled amount for the form.
                    brokenProcedure.ProcFee = feeOverride;                  //listSplitsForApptProcs.Sum(x => x.SplitAmt);
                    isNonRefundable         = true;
                }
                if (isDeleteBrokenProc)
                {
                    brokenProcedure.ProcStatus = ProcStat.D;
                }
                brokenProcedure.ProcFee = feeOverride;
                brokenProcAmount        = feeOverride;
                Procedures.Update(brokenProcedure, procOld);
            }
            #endregion
            //Note this MUST come after FormProcBroken since clicking cancel in that window will delete the procedure.
            if (isNonRefundable && !isDeleteBrokenProc && listSplitsForApptProcs.Count > 0)
            {
                //transfer what the user specified in the broken appointment window.
                //transfer up to the amount specified by the user
                foreach (Procedure proc in listProcedures)
                {
                    if (brokenProcAmount == 0)
                    {
                        break;
                    }
                    List <PaySplit> listSplitsForAppointmentProcedure = listSplitsForApptProcs.FindAll(x => x.ProcNum == proc.ProcNum);
                    foreach (PaySplit split in listSplitsForAppointmentProcedure)
                    {
                        if (brokenProcAmount == 0)
                        {
                            break;
                        }
                        double amt = Math.Min(brokenProcAmount, split.SplitAmt);
                        Payments.CreateTransferForTpProcs(proc, new List <PaySplit> {
                            split
                        }, brokenProcedure, amt);
                        brokenProcAmount -= amt;
                    }
                }
            }
            return(brokenProcedure);
        }
Beispiel #11
0
        ///<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.
        }