Пример #1
0
        ///<summary>Hides FeeScheds that are not hidden and not in use by anything. Returns the number of fee scheds that were hidden.</summary>
        public static long HideUnusedScheds()
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                return(Meth.GetLong(MethodBase.GetCurrentMethod()));
            }
            ODEvent.Fire(ODEventType.HideUnusedFeeSchedules, Lans.g("FormFeeScheds", "Finding unused fee schedules..."));
            string      command       = @"SELECT feesched.FeeSchedNum 
				FROM feesched
				LEFT JOIN provider ON provider.FeeSched=feesched.FeeSchedNum
				LEFT JOIN patient ON patient.FeeSched=feesched.FeeSchedNum
				LEFT JOIN insplan ON insplan.FeeSched=feesched.FeeSchedNum
					OR insplan.AllowedFeeSched=feesched.FeeSchedNum
					OR insplan.CopayFeeSched=feesched.FeeSchedNum
				LEFT JOIN discountplan ON discountplan.FeeSchedNum=feesched.FeeSchedNum
				WHERE COALESCE(provider.FeeSched,patient.FeeSched,insplan.FeeSched,discountplan.FeeSchedNum) IS NULL
				AND feesched.IsHidden=0"                ;
            List <long> listFeeScheds = Db.GetListLong(command);

            if (listFeeScheds.Count == 0)
            {
                return(0);
            }
            ODEvent.Fire(ODEventType.HideUnusedFeeSchedules, Lans.g("FormFeeScheds", "Hiding unused fee schedules..."));
            command = "UPDATE feesched SET IsHidden=1 WHERE FeeSchedNum IN(" + string.Join(",", listFeeScheds.Select(x => POut.Long(x))) + ")";
            long rowsChanged = Db.NonQ(command);

            return(rowsChanged);
        }
Пример #2
0
        private void butHideUnused_Click(object sender, EventArgs e)
        {
            if (!MsgBox.Show(this, MsgBoxButtons.OKCancel, "Hide fee schedules that are not in use by insurance plans, patients, or providers?\r\n"
                             + "A backup of the database will be made first."))
            {
                return;
            }
            bool   hasChanged     = FeeScheds.Sync(_listFeeScheds, _listFeeSchedsOld);
            Action actionProgress = ODProgress.Show(ODEventType.HideUnusedFeeSchedules, startingMessage: Lans.g(this, "Backing up database..."));

            try {
                MiscData.MakeABackup();
            }
            catch (Exception ex) {
                actionProgress?.Invoke();
                FriendlyException.Show(Lans.g(this, "Unable to make a backup. No fee schedules have been altered."), ex);
                return;
            }
            ODEvent.Fire(ODEventType.HideUnusedFeeSchedules, Lans.g(this, "Hiding unused fee schedules..."));
            long countChanged = FeeScheds.HideUnusedScheds();

            if (hasChanged || countChanged > 0)
            {
                DataValid.SetInvalid(InvalidType.FeeScheds);
            }
            actionProgress?.Invoke();
            MessageBox.Show(countChanged.ToString() + " " + Lans.g(this, "unused fee schedules hidden."));
            _listFeeScheds    = FeeScheds.GetDeepCopy(_isSelectionMode);
            _listFeeSchedsOld = _listFeeScheds.Select(x => x.Copy()).ToList();
            FillGrid();
        }
Пример #3
0
        private void butMovePats_Click(object sender, EventArgs e)
        {
            if (gridMain.SelectedIndices.Length < 1)
            {
                MsgBox.Show(this, "You must select at least one clinic to move patients from.");
                return;
            }
            List <Clinic> listClinicsFrom = gridMain.SelectedIndices.OfType <int>().Select(x => (Clinic)gridMain.Rows[x].Tag).ToList();
            List <Clinic> listClinicsTo   = gridMain.Rows.Select(x => x.Tag as Clinic).ToList();

            if (_clinicNumTo == -1)
            {
                MsgBox.Show(this, "You must pick a 'To' clinic in the box above to move patients to.");
                return;
            }
            Clinic clinicTo = listClinicsTo.FirstOrDefault(x => x.ClinicNum == _clinicNumTo);

            if (clinicTo == null)
            {
                MsgBox.Show(this, "The clinic could not be found.");
                return;
            }
            Action actionCloseProgress = ODProgressOld.ShowProgressStatus("ClinicReassign", this, Lan.g(this, "Gathering patient data") + "...");
            Dictionary <long, List <long> > dictClinicPats = Patients.GetPatNumsByClinic(listClinicsFrom.Select(x => x.ClinicNum).ToList()).Select()
                                                             .GroupBy(x => PIn.Long(x["ClinicNum"].ToString()), x => PIn.Long(x["PatNum"].ToString()))
                                                             .ToDictionary(x => x.Key, x => x.ToList());

            actionCloseProgress?.Invoke();
            int totalPatCount = dictClinicPats.Sum(x => x.Value.Count);

            if (totalPatCount == 0)
            {
                MsgBox.Show(this, "The selected clinics are not clinics for any patients.");
                return;
            }
            string strClinicFromDesc = string.Join(", ", listClinicsFrom.FindAll(x => dictClinicPats.ContainsKey(x.ClinicNum)).Select(x => (x.ClinicNum == 0?"HQ":x.Abbr)));
            string strClinicToDesc   = clinicTo.Abbr;
            string msg = Lan.g(this, "Move all patients to") + " " + strClinicToDesc + " " + Lan.g(this, "from the following clinics") + ": " + strClinicFromDesc + "?";

            if (MessageBox.Show(msg, "", MessageBoxButtons.OKCancel) != DialogResult.OK)
            {
                return;
            }
            actionCloseProgress = ODProgressOld.ShowProgressStatus("ClinicReassign", this, Lan.g(this, "Moving patients") + "...");
            int           patsMoved   = 0;
            List <Action> listActions = dictClinicPats.Select(x => new Action(() => {
                patsMoved += x.Value.Count;
                ODEvent.Fire(new ODEventArgs("ClinicReassign", Lan.g(this, "Moving patients") + ": " + patsMoved + " out of " + totalPatCount));
                Patients.ChangeClinicsForAll(x.Key, clinicTo.ClinicNum);               //update all clinicNums to new clinic
                SecurityLogs.MakeLogEntry(Permissions.PatientEdit, 0, "Clinic changed for " + x.Value.Count + " patients from "
                                          + (x.Key == 0 ? "HQ" : Clinics.GetAbbr(x.Key)) + " to " + clinicTo.Abbr + ".");
            })).ToList();

            ODThread.RunParallel(listActions, TimeSpan.FromMinutes(2));
            actionCloseProgress?.Invoke();
            _dictClinicalCounts = Clinics.GetClinicalPatientCount();
            FillGrid();
            MsgBox.Show(this, "Done");
        }
Пример #4
0
        private void butGetNextBatch_Click(object sender, EventArgs e)
        {
            Action actionCloseProgress = ODProgress.Show(ODEventType.Billing, startingMessage: "Retrieving family information.  Please wait...");

            ODEvent.Fire(ODEventType.Billing, Lan.g(this, "Filling the grid.  This may take awhile..."));
            FillNextBatch();
            actionCloseProgress();
        }
Пример #5
0
 ///<summary>Uses reflection to invoke private methods of the ConvertDatabase class in order from least to greatest if needed.
 ///The old way of converting the database was to manually daisy chain methods together.
 ///The new way is to just add a method that follows a strict naming pattern which this method will invoke when needed.</summary>
 private void InvokeConvertMethods()
 {
     DataConnection.CommandTimout = 7200;          //2 hours, because conversion commands may take longer to run.
     //Loop through the list of convert databases methods from front to back because it has already been sorted (least to greatest).
     foreach (ConvertDatabasesMethodInfo convertMethodInfo in ListConvertMethods)
     {
         //This pattern of using reflection to invoke our convert methods started in v17.1 so we will skip all methods prior to that version.
         if (convertMethodInfo.VersionCur < new Version(17, 1))
         {
             continue;
         }
         //Skip all methods that are below or equal to our "from" version.
         if (convertMethodInfo.VersionCur <= FromVersion)
         {
             continue;
         }
         //This convert method needs to be invoked.
         ODEvent.Fire(new ODEventArgs("ConvertDatabases", "Upgrading database to version: " //No translations in convert script.
                                      + convertMethodInfo.VersionCur.ToString(3)));         //Only show the major, minor, build (preserves old functionality).
         try {
             //Use reflection to invoke the private static method.
             convertMethodInfo.MethodInfoCur.Invoke(this, new object[] { });
         }
         catch (Exception ex) {
             string message = Lan.g(this, "Convert Database failed ");
             try {
                 string methodName = convertMethodInfo.MethodInfoCur.Name;
                 if (!string.IsNullOrEmpty(methodName))
                 {
                     message += Lan.g(this, "during: ") + methodName + "() ";
                 }
                 string command = Db.LastCommand;
                 if (!string.IsNullOrEmpty(command))
                 {
                     message += Lan.g(this, "while running: ") + command + ";";
                 }
             }
             catch (Exception e) {
                 e.DoNothing();                        //If this fails for any reason then just continue.
             }
             throw new Exception(message + "  " + ex.Message + "  " + ex.InnerException.Message, ex.InnerException);
         }
         //Update the preference that keeps track of what version Open Dental has successfully upgraded to.
         //Always require major, minor, build, revision.  Will throw an exception if the revision was not explicitly set (which we always set).
         Prefs.UpdateStringNoCache(PrefName.DataBaseVersion, convertMethodInfo.VersionCur.ToString(4));
     }
     DataConnection.CommandTimout = 3600;          //Set back to default of 1 hour.
 }
Пример #6
0
        /*
         * ///<summary>Must make sure Refresh is done first.  Returns the sum of all adjustments for this patient.  Amount might be pos or neg.</summary>
         * public static double ComputeBal(Adjustment[] List){
         *      double retVal=0;
         *      for(int i=0;i<List.Length;i++){
         *              retVal+=List[i].AdjAmt;
         *      }
         *      return retVal;
         * }*/

        ///<summary>Returns the number of finance or billing charges deleted.</summary>
        public static long UndoFinanceOrBillingCharges(DateTime dateUndo, bool isBillingCharges)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                return(Meth.GetLong(MethodBase.GetCurrentMethod(), dateUndo, isBillingCharges));
            }
            string adjTypeStr    = "Finance";
            long   adjTypeDefNum = PrefC.GetLong(PrefName.FinanceChargeAdjustmentType);

            if (isBillingCharges)
            {
                adjTypeStr    = "Billing";
                adjTypeDefNum = PrefC.GetLong(PrefName.BillingChargeAdjustmentType);
            }
            string command = "SELECT adjustment.AdjAmt,patient.PatNum,patient.Guarantor,patient.LName,patient.FName,patient.Preferred,patient.MiddleI,"
                             + "adjustment.SecDateTEdit "
                             + "FROM adjustment "
                             + "INNER JOIN patient ON patient.PatNum=adjustment.PatNum "
                             + "WHERE AdjDate=" + POut.Date(dateUndo) + " "
                             + "AND AdjType=" + POut.Long(adjTypeDefNum);
            DataTable     table       = Db.GetTable(command);
            List <Action> listActions = new List <Action>();
            int           loopCount   = 0;

            foreach (DataRow row in table.Rows)             //loops through the rows and creates audit trail entry for every row to be deleted
            {
                listActions.Add(new Action(() => {
                    SecurityLogs.MakeLogEntry(Permissions.AdjustmentEdit, PIn.Long(row["PatNum"].ToString()),
                                              "Delete adjustment for patient, undo " + adjTypeStr.ToLower() + " charges: "
                                              + Patients.GetNameLF(row["LName"].ToString(), row["FName"].ToString(), row["Preferred"].ToString(), row["MiddleI"].ToString())
                                              + ", " + PIn.Double(row["AdjAmt"].ToString()).ToString("c"), 0, PIn.DateT(row["SecDateTEdit"].ToString()));
                    if (++loopCount % 5 == 0)
                    {
                        ODEvent.Fire(new ODEventArgs(adjTypeStr + "Charge", Lans.g("FinanceCharge", "Creating log entries for " + adjTypeStr.ToLower() + " charges")
                                                     + ": " + loopCount + " out of " + table.Rows.Count));
                    }
                }));
            }
            ODThread.RunParallel(listActions, TimeSpan.FromMinutes(2));
            command = "DELETE FROM adjustment WHERE AdjDate=" + POut.Date(dateUndo) + " AND AdjType=" + POut.Long(adjTypeDefNum);
            ODEvent.Fire(new ODEventArgs(adjTypeStr + "Charge", Lans.g("FinanceCharge", "Deleting") + " " + table.Rows.Count + " "
                                         + Lans.g("FinanceCharge", adjTypeStr.ToLower() + " charge adjustments") + "..."));
            return(Db.NonQ(command));
        }
        private void menuItemGridGoToAccount_Click(object sender, EventArgs e)
        {
            //accessed by right clicking the history grid
            if (gridMain.SelectedIndices.Length != 1)
            {
                MsgBox.Show(this, "Please select exactly one item first.");
                return;
            }
            DataRow row    = (DataRow)gridMain.ListGridRows[gridMain.GetSelectedIndex()].Tag;
            long    patNum = PIn.Long(row["PatNum"].ToString());

            if (patNum == 0)
            {
                MsgBox.Show(this, "Please select an item with a patient.");
                return;
            }
            ODEvent.Fire(ODEventType.FormProcNotBilled_GoTo, patNum);
            SendToBack();
        }
Пример #8
0
        private void FillSubGrid(bool isRefreshNeeded = false, string grouping95 = "")
        {
            Action loadingProgress = null;

            Cursor = Cursors.WaitCursor;
            bugSubmissionControl.ClearCustomerInfo();
            bugSubmissionControl.SetTextDevNoteEnabled(false);
            if (isRefreshNeeded)
            {
                loadingProgress = ODProgressOld.ShowProgressStatus("FormBugSubmissions", this, Lan.g(this, "Refreshing Data") + "...", false);
                #region Refresh Logic
                if (_viewMode.In(FormBugSubmissionMode.ViewOnly, FormBugSubmissionMode.ValidationMode))
                {
                    _listAllSubs = ListViewedSubs;
                }
                else
                {
                    _listAllSubs = BugSubmissions.GetAllInRange(dateRangePicker.GetDateTimeFrom(), dateRangePicker.GetDateTimeTo());
                }
                try {
                    _dictPatients = RegistrationKeys.GetPatientsByKeys(_listAllSubs.Select(x => x.RegKey).ToList());
                }
                catch (Exception e) {
                    e.DoNothing();
                    _dictPatients = new Dictionary <string, Patient>();
                }
                #endregion
            }
            gridSubs.BeginUpdate();
            #region gridSubs columns
            gridSubs.Columns.Clear();
            gridSubs.Columns.Add(new ODGridColumn("Submitter", 140));
            gridSubs.Columns.Add(new ODGridColumn("Vers.", 55, GridSortingStrategy.VersionNumber));
            if (comboGrouping.SelectedIndex == 0)           //Group by 'None'
            {
                gridSubs.Columns.Add(new ODGridColumn("DateTime", 75, GridSortingStrategy.DateParse));
            }
            else
            {
                gridSubs.Columns.Add(new ODGridColumn("Count", 75, GridSortingStrategy.AmountParse));
            }
            gridSubs.Columns.Add(new ODGridColumn("HasBug", 50, HorizontalAlignment.Center));
            gridSubs.Columns.Add(new ODGridColumn("Msg Text", 300));
            gridSubs.AllowSortingByColumn = true;
            #endregion
            #region Filter Logic
            ODEvent.Fire(new ODEventArgs("FormBugSubmissions", "Filtering Data"));
            List <string> listSelectedVersions = comboVersions.ListSelectedItems.Select(x => (string)x).ToList();
            if (listSelectedVersions.Contains("All"))
            {
                listSelectedVersions.Clear();
            }
            List <string> listSelectedRegKeys = comboRegKeys.ListSelectedItems.Select(x => (string)x).ToList();
            if (listSelectedRegKeys.Contains("All"))
            {
                listSelectedRegKeys.Clear();
            }
            List <string> listStackFilters = textStackFilter.Text.Split(',')
                                             .Where(x => !string.IsNullOrWhiteSpace(x))
                                             .Select(x => x.ToLower()).ToList();
            List <string> listPatNumFilters = textPatNums.Text.Split(',')
                                              .Where(x => !string.IsNullOrWhiteSpace(x))
                                              .Select(x => x.ToLower()).ToList();
            _listAllSubs.ForEach(x => x.TagOD = null);
            List <BugSubmission> listFilteredSubs = _listAllSubs.Where(x =>
                                                                       PassesFilterValidation(x, listSelectedRegKeys, listStackFilters, listPatNumFilters, listSelectedVersions, grouping95)
                                                                       ).ToList();
            if (isRefreshNeeded)
            {
                FillVersionsFilter(listFilteredSubs);
                FillRegKeyFilter(listFilteredSubs);
            }
            #endregion
            #region Grouping Logic
            List <BugSubmission> listGroupedSubs;
            int index = 0;
            List <BugSubmission> listGridSubmissions = new List <BugSubmission>();
            foreach (BugSubmission sub in listFilteredSubs)
            {
                ODEvent.Fire(new ODEventArgs("FormBugSubmissions", "Grouping Data: " + POut.Double(((double)index++ / (double)listFilteredSubs.Count) * 100) + "%"));
                if (sub.TagOD != null)
                {
                    continue;
                }
                switch (comboGrouping.SelectedIndex)
                {
                case 0:
                    #region None
                    sub.TagOD = new List <BugSubmission>()
                    {
                        sub
                    };                                                                      //Tag is a specific bugSubmission
                    listGridSubmissions.Add(sub.Copy());
                    #endregion
                    break;

                case 1:
                    #region RegKey/Ver/Stack
                    listGroupedSubs = listFilteredSubs.FindAll(x => x.TagOD == null && x.RegKey == sub.RegKey &&
                                                               x.Info.DictPrefValues[PrefName.ProgramVersion] == sub.Info.DictPrefValues[PrefName.ProgramVersion] &&
                                                               x.ExceptionStackTrace == sub.ExceptionStackTrace &&
                                                               x.BugId == sub.BugId);
                    if (listGroupedSubs.Count == 0)
                    {
                        continue;
                    }
                    listGroupedSubs = listGroupedSubs.OrderByDescending(x => new Version(x.Info.DictPrefValues[PrefName.ProgramVersion]))
                                      .ThenByDescending(x => x.SubmissionDateTime).ToList();
                    listGroupedSubs.ForEach(x => x.TagOD = true);                          //So we don't considered previously handled submissions.
                    listGroupedSubs.First().TagOD = listGroupedSubs;                       //First element is what is shown in grid, still wont be considered again.
                    listGridSubmissions.Add(listGroupedSubs.First().Copy());
                    #endregion
                    break;

                case 2:
                    #region StackTrace
                    listGroupedSubs = listFilteredSubs.FindAll(x => x.TagOD == null && x.ExceptionStackTrace == sub.ExceptionStackTrace && x.BugId == sub.BugId);
                    if (listGroupedSubs.Count == 0)
                    {
                        continue;
                    }
                    listGroupedSubs = listGroupedSubs.OrderByDescending(x => new Version(x.Info.DictPrefValues[PrefName.ProgramVersion]))
                                      .ThenByDescending(x => x.SubmissionDateTime).ToList();
                    listGroupedSubs.ForEach(x => x.TagOD = true);                          //So we don't considered previously handled submissions.
                    listGroupedSubs.First().TagOD = listGroupedSubs;                       //First element is what is shown in grid, still wont be considered again.
                    listGridSubmissions.Add(listGroupedSubs.First().Copy());
                    #endregion
                    break;

                case 3:
                    #region 95%
                    //At this point all bugSubmissions in listFilteredSubs is at least a 95% match. Group them all together in a single row.
                    listGroupedSubs = listFilteredSubs;
                    listGroupedSubs = listGroupedSubs.OrderByDescending(x => new Version(x.Info.DictPrefValues[PrefName.ProgramVersion]))
                                      .ThenByDescending(x => x.SubmissionDateTime).ToList();
                    listGroupedSubs.ForEach(x => x.TagOD = true);                          //So we don't considered previously handled submissions.
                    listGroupedSubs.First().TagOD = listGroupedSubs;                       //First element is what is shown in grid, still wont be considered again.
                    listGridSubmissions.Add(listGroupedSubs.First().Copy());
                    #endregion
                    break;
                }
            }
            #endregion
            #region Sorting Logic
            ODEvent.Fire(new ODEventArgs("FormBugSubmissions", "Sorting Data"));
            switch (comboSortBy.SelectedIndex)
            {
            case 0:
                listGridSubmissions = listGridSubmissions.OrderByDescending(x => new Version(x.Info.DictPrefValues[PrefName.ProgramVersion]))
                                      .ThenByDescending(x => GetGroupCount(x))
                                      .ThenByDescending(x => x.SubmissionDateTime).ToList();
                break;
            }
            #endregion
            #region Fill gridSubs
            gridSubs.Rows.Clear();
            index = 0;
            foreach (BugSubmission sub in listGridSubmissions)
            {
                ODEvent.Fire(new ODEventArgs("FormBugSubmissions", "Filling Grid: " + POut.Double(((double)index++ / (double)listFilteredSubs.Count) * 100) + "%"));
                gridSubs.Rows.Add(GetODGridRowForSub(sub));
            }
            gridSubs.EndUpdate();
            #endregion
            try {
                loadingProgress?.Invoke();                //When this function executes quickly this can fail rarely, fail silently because of WaitCursor.
            }
            catch (Exception ex) {
                ex.DoNothing();
            }
            Cursor = Cursors.Default;
        }
Пример #9
0
 ///<summary>Uses reflection to invoke private methods of the ConvertDatabase class in order from least to greatest if needed.
 ///The old way of converting the database was to manually daisy chain methods together.
 ///The new way is to just add a method that follows a strict naming pattern which this method will invoke when needed.</summary>
 public static void InvokeConvertMethods()
 {
     DataConnection.CommandTimeout = 43200; //12 hours, because conversion commands may take longer to run.
     ConvertDatabases.To2_8_2();            //begins going through the chain of conversion steps
     Logger.DoVerboseLoggingArgs doVerboseLogging = Logger.DoVerboseLogging;
     ODException.SwallowAnyException(() => {
         //Need to run queries here because PrefC has not been initialized.
         string command     = "SELECT ValueString FROM preference WHERE PrefName='HasVerboseLogging'";
         string valueString = Db.GetScalar(command);
         if (valueString.ToLower().Split(',').ToList().Exists(x => x == Environment.MachineName.ToLower()))
         {
             Logger.DoVerboseLogging = () => true;
             //Switch logger to a directory that won't have permissions issues.
             Logger.UseMyDocsDirectory();
         }
         Logger.LogVerbose("Starting convert script");
     });
     //Continue going through the chain of conversion methods starting at v17.1.1 via reflection.
     //Loop through the list of convert databases methods from front to back because it has already been sorted (least to greatest).
     foreach (ConvertDatabasesMethodInfo convertMethodInfo in ListConvertMethods)
     {
         //This pattern of using reflection to invoke our convert methods started in v17.1 so we will skip all methods prior to that version.
         if (convertMethodInfo.VersionCur < new Version(17, 1))
         {
             continue;
         }
         //Skip all methods that are below or equal to our "from" version.
         if (convertMethodInfo.VersionCur <= FromVersion)
         {
             continue;
         }
         //This convert method needs to be invoked.
         ODEvent.Fire(ODEventType.ConvertDatabases, "Upgrading database to version: " //No translations in convert script.
                      + convertMethodInfo.VersionCur.ToString(3));                    //Only show the major, minor, build (preserves old functionality).
         try {
             //Use reflection to invoke the private static method.
             convertMethodInfo.MethodInfoCur.Invoke(null, new object[] { });
         }
         catch (Exception ex) {
             string message = Lans.g("ClassConvertDatabase", "Convert Database failed ");
             try {
                 string methodName = convertMethodInfo.MethodInfoCur.Name;
                 if (!string.IsNullOrEmpty(methodName))
                 {
                     message += Lans.g("ClassConvertDatabase", "during: ") + methodName + "() ";
                 }
                 string command = Db.LastCommand;
                 if (!string.IsNullOrEmpty(command))
                 {
                     message += Lans.g("ClassConvertDatabase", "while running: ") + command + ";";
                 }
             }
             catch (Exception e) {
                 e.DoNothing();                        //If this fails for any reason then just continue.
             }
             throw new Exception(message + "  " + ex.Message + "  " + ex.InnerException.Message, ex.InnerException);
         }
         //Update the preference that keeps track of what version Open Dental has successfully upgraded to.
         //Always require major, minor, build, revision.  Will throw an exception if the revision was not explicitly set (which we always set).
         Prefs.UpdateStringNoCache(PrefName.DataBaseVersion, convertMethodInfo.VersionCur.ToString(4));
     }
     ODException.SwallowAnyException(() => {
         Logger.LogVerbose("Ending convert script");
         Logger.DoVerboseLogging = doVerboseLogging;
     });
     DataConnection.CommandTimeout = 3600;          //Set back to default of 1 hour.
 }
Пример #10
0
        ///<summary>Balances all selected accounts.</summary>
        private void butTransfer_Click(object sender, EventArgs e)
        {
            //FormIncomeTransferManage requires PaymentCreate to run.
            //This form requires SecurityAdmin and a password to open, and although rare,
            // a SecuirtyAdmin doesn't have to have PaymentCreate permission
            if (!Security.IsAuthorized(Permissions.PaymentCreate))
            {
                return;
            }
            //Make sure the user wants to run the tool.
            if (!MsgBox.Show(this, MsgBoxButtons.YesNo, "This process can take a long time and cannot be reversed.\r\n\r\nContinue?"))
            {
                return;
            }
            Action actionCloseProgress = ODProgress.Show(ODEventType.Billing);

            //Build list of families based off of selected rows.
            _logger.WriteLine("This is the summary of all transactions that took place.This can be saved for later reference if one or more"
                              + " transactions need to be undone outside of the tool.\r\n", LogLevel.Information);
            //Do income transfers if applicable.
            for (int i = _batchNum - 1; i < _listBatches.Count(); i++)     //_batchNum is 1-based, so drop i by 1 to make sure the current batch is included
            {
                string logText = "";
                if (checkAllocateCharges.Checked)
                {
                    ODEvent.Fire(ODEventType.Billing, Lan.g(this, $"Creating income transfers for batch {_batchNum}/{_listBatches.Count()} please wait..."));
                    foreach (FamilyAccount famAccountCur in _dictCurrentFamilyBatch.Select(x => x.Value))
                    {
                        //Clear the list of splits in case any are hanging around from a previous run.
                        famAccountCur.ListSplits.Clear();
                        famAccountCur.ListSplitsAssociated.Clear();
                        //Make lists of positive and negative charges.
                        List <AccountEntry> listPosCharges        = famAccountCur.Account.ListAccountCharges.Where(x => x.AmountEnd > 0).ToList();
                        List <AccountEntry> listNegCharges        = famAccountCur.Account.ListAccountCharges.Where(x => x.AmountEnd < 0).ToList();
                        List <long>         listPatNumsForCharges = listPosCharges.Select(x => x.PatNum).Distinct().ToList();
                        List <AccountEntry> listEntriesForPats    = famAccountCur.Account.ListAccountCharges.FindAll(x => x.PatNum.In(listPatNumsForCharges));
                        //This catch will save us some time if they run the tool on the same family twice.
                        if (listPosCharges.Count() == 0 || listNegCharges.Count() == 0)
                        {
                            continue;                            //No need to add to logText, CreateTransfers wouldn't return anything either.
                        }
                        Payment payCur = CreatePaymentTransferHelper(famAccountCur.Guarantor);
                        logText += CreateTransfers(listPosCharges, listNegCharges, listEntriesForPats, famAccountCur, payCur);
                        logText += CreditsToUnallocated(listNegCharges, famAccountCur, payCur);
                        //Remove any $0 splits created from CreateTransfers.
                        famAccountCur.ListSplits.RemoveAll(x => x.SplitAmt == 0);
                        foreach (PaySplit split in famAccountCur.ListSplits)
                        {
                            PaySplits.Insert(split);
                        }
                        //Go through family accounts and update FSplitNums.
                        foreach (PaySplits.PaySplitAssociated split in famAccountCur.ListSplitsAssociated)
                        {
                            //Update the FSplitNum after inserts are made.
                            if (split.PaySplitLinked != null && split.PaySplitOrig != null)
                            {
                                PaySplits.UpdateFSplitNum(split.PaySplitOrig.SplitNum, split.PaySplitLinked.SplitNum);
                            }
                        }
                    }
                }
                //Transfer balances to guarantor if applicable.
                if (checkGuarAllocate.Checked)
                {
                    ODEvent.Fire(ODEventType.Billing, Lan.g(this, $"Transferring remaining balance to guarantor for batch {_batchNum}/{_listBatches.Count()} please wait..."));
                    logText += "Balances transferred to Guarantor:\r\n";
                    logText += TransferToGuarantor();
                }
                //load up the next batch
                ODEvent.Fire(ODEventType.Billing, Lan.g(this, $"Loading next batch please wait..."));
                FillNextBatch();
                _logger.WriteLine(logText, LogLevel.Information);
            }
            actionCloseProgress();
        }
Пример #11
0
 protected override void OnClosed(EventArgs e)
 {
     base.OnClosed(e);
     ODEvent.Fire(new ODEventArgs("ErxBrowserClosed", PatCur));
 }
Пример #12
0
 ///<summary>Creates actions and runs them in parallel threads to process the insert commands in the queue.</summary>
 public static void InsertBatches()
 {
     if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
     {
         Meth.GetVoid(MethodBase.GetCurrentMethod());
         return;
     }
                 #if DEBUG
     Stopwatch s = new Stopwatch();
     s.Start();
                 #endif
     _insertBatchCount = 0;
     try {
         #region Create List of Actions
         List <Action> listActions = new List <Action>();
         int           numThreads  = Math.Max(INSERT_THREAD_MIN_COUNT, Environment.ProcessorCount); //use at least 8 threads, but use ProcessorCount if more than 8 cores
         for (int i = 0; i < numThreads; i++)                                                       //create numThreads number of actions, 1 per thread to run in parallel
         {
             listActions.Add(new Action(() => {
                 if (!string.IsNullOrEmpty(_serverTo))                         //SetDbT here if server is specified
                 {
                     DataConnection dcon = new DataConnection();
                     dcon.SetDbT(_serverTo, _databaseTo, _userTo, _passwordTo, "", "", DatabaseType.MySql);
                 }
                 bool isBatchQueued = false;
                 bool insertFailed  = true;
                 while (!_areQueueBatchThreadsDone || isBatchQueued)                         //if queue batch thread is done and queue is empty, loop is finished
                 {
                     BatchQueries batch = null;
                     try {
                         lock (_lockObjQueueBatchQueries) {
                             if (_queueBatchQueries.Count == 0)
                             {
                                 //queueBatchThread must not be finished gathering batches but the queue is empty, give the batch thread time to catch up
                                 continue;
                             }
                             batch = _queueBatchQueries.Dequeue();
                         }
                         if (batch == null || (string.IsNullOrEmpty(batch.CommandValuesInsert) && string.IsNullOrEmpty(batch.CommandBulkInsert)))
                         {
                             continue;
                         }
                         Db.NonQ(batch.CommandValuesInsert);
                         insertFailed = false;
                     }
                     catch (Exception ex) {                           //just loop again and wait if necessary
                         ex.DoNothing();
                         insertFailed = true;
                         if (!string.IsNullOrEmpty(batch.CommandBulkInsert))
                         {
                             try {
                                 //If multiple bulk insert commands get here at the same time they will fail 100% of the time for InnoDB an table due to
                                 //a MySQL deadlock issue caused by the sub-select that makes sure it is not trying to insert duplicate rows.
                                 Db.NonQ(batch.CommandBulkInsert);
                                 insertFailed = false;
                             }
                             catch (Exception ex2) {
                                 ex2.DoNothing();
                                 insertFailed = true;
                             }
                         }
                         continue;
                     }
                     finally {
                         lock (_lockObjQueueBatchQueries) {
                             if (!insertFailed)
                             {
                                 insertFailed = true;
                                 _insertBatchCount++;
                             }
                             isBatchQueued = _queueBatchQueries.Count > 0;
                         }
                     }
                 }        //end of while loop
             }));         //end of listActions.Add
         }                //end of for loop
         #endregion Create List of Actions
         ODThread.RunParallel(listActions, TimeSpan.FromHours(12), numThreads, new ODThread.ExceptionDelegate((ex) => {
             ODEvent.Fire(ODEventType.ConvertDatabases, new ProgressBarHelper("Error processing batch insert: " + ex.Message,
                                                                              progressBarEventType: ProgBarEventType.TextMsg));
         }));
     }
     catch (Exception ex) {
         ODEvent.Fire(ODEventType.ConvertDatabases, new ProgressBarHelper("Error inserting batch: " + ex.Message, progressBarEventType: ProgBarEventType.TextMsg));
     }
                 #if DEBUG
     s.Stop();
     Console.WriteLine("InsertDataThread - Done, inserted " + _insertBatchCount + " batches: "
                       + (s.Elapsed.Hours > 0?(s.Elapsed.Hours + " hours "):"") + (s.Elapsed.Minutes > 0?(s.Elapsed.Minutes + " min "):"")
                       + (s.Elapsed.TotalSeconds - (s.Elapsed.Hours * 60 * 60) - (s.Elapsed.Minutes * 60)) + " sec");
                 #endif
 }
Пример #13
0
 ///<summary>Creates actions that load batches of data into the queue for inserting by the insert threads and runs them with
 ///QUEUE_BATCHES_THREAD_COUNT number of parallel threads.  The threads will wait for the queue to drop below MAX_QUEUE_COUNT number of items
 ///before queuing another item.</summary>
 public static void QueueBatches(ODThread odThread)
 {
     if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
     {
         Meth.GetVoid(MethodBase.GetCurrentMethod(), odThread);
         return;
     }
                 #if DEBUG
     Stopwatch s = new Stopwatch();
     s.Start();
                 #endif
     int queueCount = 0;
     try {
         string dbName = GetCurrentDatabase();
         string cmd    = "SELECT COLUMN_NAME,DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS "
                         + "WHERE TABLE_SCHEMA='" + POut.String(dbName) + "' AND TABLE_NAME='" + POut.String(_tempTableName) + "'";
         //Dictionary of key=column name, value=data type for the current table.  Used to determine whether a row value will need to have special
         //characters escaped and will need to be surrounded with quotes (using the MySql QUOTE() method).
         Dictionary <string, string> dictColNamesAndTypes = Db.GetTable(cmd).Select()
                                                            .ToDictionary(x => PIn.String(x["COLUMN_NAME"].ToString()), x => PIn.String(x["DATA_TYPE"].ToString()));
         if (dictColNamesAndTypes.Count < 1)
         {
             return;                    //table doesn't have any columns?  nothing to do?
         }
         #region Get Query Strings
         //data types that require special characters escaped and will be surrounded by quotes (using the MySql QUOTE() method).
         string[]      dataTypeQuotesArr  = new[] { "date", "datetime", "timestamp", "time", "char", "varchar", "text", "mediumtext", "longtext", "blob", "mediumblob", "longblob" };
         StringBuilder sbGetSelectCommand = new StringBuilder(@"SELECT CONCAT('('");
         List <string> listWheres         = new List <string>();
         int           index = 0;
         foreach (KeyValuePair <string, string> kvp in dictColNamesAndTypes)
         {
             sbGetSelectCommand.Append(@",");
             if (index > 0)
             {
                 sbGetSelectCommand.Append(@"',',");
             }
             if (dataTypeQuotesArr.Contains(kvp.Value))
             {
                 sbGetSelectCommand.Append(@"QUOTE(" + kvp.Key + @")");
             }
             else
             {
                 sbGetSelectCommand.Append(POut.String(kvp.Key));
             }
             index++;
         }
         sbGetSelectCommand.Append(@",')') vals FROM `" + _tempTableName + "` ");
         for (int i = 0; i < _listPriKeyMaxPerBatch.Count; i++)
         {
             string where = "WHERE " + POut.String(_tablePriKeyField) + "<=" + POut.Long(_listPriKeyMaxPerBatch[i]);
             if (i > 0)
             {
                 where += " AND " + POut.String(_tablePriKeyField) + ">" + POut.Long(_listPriKeyMaxPerBatch[i - 1]);
             }
             listWheres.Add(where);
         }
         #endregion Get Query Strings
         #region Run Commands and Queue Results
         #region Create List of Actions
         List <Action> listActions = new List <Action>();
         string        colNames    = string.Join(",", dictColNamesAndTypes.Keys.Select(x => POut.String(x)));
         foreach (string whereStr in listWheres)
         {
             listActions.Add(new Action(() => {
                 List <string> listRowVals = Db.GetListString(sbGetSelectCommand.ToString() + whereStr);
                 if (listRowVals == null || listRowVals.Count == 0)
                 {
                     return;
                 }
                 string commandValuesInsert = "REPLACE INTO `" + _tableName + "` (" + colNames + ") VALUES " + string.Join(",", listRowVals);
                 string commandBulkInsert   = "REPLACE INTO `" + _tableName + "` (" + colNames + ") SELECT " + colNames + " FROM `" + _tempTableName + "` " + whereStr + " "
                                              + "AND " + POut.String(_tablePriKeyField) + " NOT IN (SELECT " + POut.String(_tablePriKeyField) + " FROM `" + _tableName + "` " + whereStr + ")";
                 bool isDataQueued = false;
                 while (!isDataQueued)
                 {
                     lock (_lockObjQueueBatchQueries) {
                         if (_queueBatchQueries.Count < MAX_QUEUE_COUNT)                               //Wait until queue is a reasonable size before queueing more.
                         {
                             _queueBatchQueries.Enqueue(new BatchQueries(commandValuesInsert, commandBulkInsert));
                             isDataQueued = true;
                             queueCount++;
                         }
                     }
                     if (!isDataQueued)
                     {
                         Thread.Sleep(100);
                     }
                 }
             }));
         }                //end of command loop
         #endregion Create List of Actions
         ODThread.RunParallel(listActions, TimeSpan.FromHours(12), QUEUE_BATCHES_THREAD_COUNT, new ODThread.ExceptionDelegate((ex) => {
             ODEvent.Fire(ODEventType.ConvertDatabases, new ProgressBarHelper("Error queuing batch: " + ex.Message, progressBarEventType: ProgBarEventType.TextMsg));
         }));
         #endregion Run Commands and Queue Results
     }
     catch (Exception ex) {
         //Don't pass along any exceptions because the main thread will validate that the table was successfully copied and will throw for us.
         ODEvent.Fire(ODEventType.ConvertDatabases, new ProgressBarHelper("Error queuing batch: " + ex.Message, progressBarEventType: ProgBarEventType.TextMsg));
     }
     finally {            //always make sure to notify the main thread that the thread is done so the main thread doesn't wait for eternity
         _areQueueBatchThreadsDone = true;
                         #if DEBUG
         s.Stop();
         Console.WriteLine("QueueQueryBatches - Done, queued " + queueCount + " out of " + _listPriKeyMaxPerBatch.Count + " batches of " + _rowsPerBatch + " rows: "
                           + (s.Elapsed.Hours > 0?(s.Elapsed.Hours + " hours "):"") + (s.Elapsed.Minutes > 0?(s.Elapsed.Minutes + " min "):"")
                           + (s.Elapsed.TotalSeconds - (s.Elapsed.Hours * 60 * 60) - (s.Elapsed.Minutes * 60)) + " sec");
                         #endif
     }
 }
Пример #14
0
        ///<summary>Backs up the database to the same directory as the original just in case the user did not have sense enough to do a backup first.
        ///Does not work for Oracle, due to some MySQL specific commands inside.</summary>
        public static long MakeABackup()
        {
            //This function should always make the backup on the server itself, and since no directories are
            //referred to (all handled with MySQL), this function will always be referred to the server from
            //client machines.
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                return(Meth.GetLong(MethodBase.GetCurrentMethod()));
            }
            //UpdateStreamLinePassword is purposefully named poorly and used in an odd fashion to sort of obfuscate it from our users.
            //GetStringNoCache() will return blank if pref does not exist.
            if (PrefC.GetStringNoCache(PrefName.UpdateStreamLinePassword) == "abracadabra")
            {
                return(0);
            }
            //only used in two places: upgrading version, and upgrading mysql version.
            //Both places check first to make sure user is using mysql.
            //we have to be careful to throw an exception if the backup is failing.
            DataConnection dcon    = new DataConnection();
            string         command = "SELECT database()";
            DataTable      table   = dcon.GetTable(command);
            string         oldDb   = PIn.String(table.Rows[0][0].ToString());
            string         newDb   = oldDb + "backup_" + DateTime.Today.ToString("MM_dd_yyyy");

            command = "SHOW DATABASES";
            table   = dcon.GetTable(command);
            string[] databases = new string[table.Rows.Count];
            for (int i = 0; i < table.Rows.Count; i++)
            {
                databases[i] = table.Rows[i][0].ToString();
            }
            if (Contains(databases, newDb))            //if the new database name already exists
            //find a unique one
            {
                int    uniqueID      = 1;
                string originalNewDb = newDb;
                do
                {
                    newDb = originalNewDb + "_" + uniqueID.ToString();
                    uniqueID++;
                }while(Contains(databases, newDb));
            }
            command = "CREATE DATABASE `" + newDb + "` CHARACTER SET utf8";
            dcon.NonQ(command);
            command = "SHOW FULL TABLES WHERE Table_type='BASE TABLE'";          //Tables, not views.  Does not work in MySQL 4.1, however we test for MySQL version >= 5.0 in PrefL.
            table   = dcon.GetTable(command);
            string[] tableName = new string[table.Rows.Count];
            for (int i = 0; i < table.Rows.Count; i++)
            {
                tableName[i] = table.Rows[i][0].ToString();
            }
            //switch to using the new database
            DataConnection newDcon = new DataConnection(newDb);

            for (int i = 0; i < tableName.Length; i++)
            {
                //Alert anyone that cares that we are backing up this table.
                ODEvent.Fire(new ODEventArgs("BackupProgress", Lans.g("MiscData", "Backing up table") + ": " + tableName[i]));
                command = "SHOW CREATE TABLE `" + oldDb + "`.`" + tableName[i] + "`";      //also works with views. Added backticks around table name for unusual characters.
                table   = newDcon.GetTable(command);
                command = PIn.ByteArray(table.Rows[0][1]);
                newDcon.NonQ(command);                                              //this has to be run using connection with new database
                command = "INSERT INTO `" + newDb + "`.`" + tableName[i] + "` "
                          + "SELECT * FROM `" + oldDb + "`.`" + tableName[i] + "`"; //Added backticks around table name for unusual characters.
                newDcon.NonQ(command);
            }
            return(0);
        }
Пример #15
0
 protected override void OnClosed(EventArgs e)
 {
     base.OnClosed(e);
     ODEvent.Fire(ODEventType.ErxBrowserClosed, PatCur);
 }
Пример #16
0
        ///<summary>Fills grid based on values in _listEtrans.
        ///Set isRefreshNeeded to true when we need to reinitialize local dictionarys after in memory list is also updated. Required true for first time running.
        ///Also allows you to passed in predetermined filter options.</summary>
        private void FillGrid(bool isRefreshNeeded, List <string> listSelectedStatuses, List <long> listSelectedClinicNums,
                              string carrierName, string checkTraceNum, string amountMin, string amountMax)
        {
            Action actionCloseProgress = null;

            if (isRefreshNeeded)
            {
                actionCloseProgress = ODProgressOld.ShowProgressStatus("Etrans835", this, Lan.g(this, "Gathering data") + "...", false);
                _dictEtrans835s.Clear();
                _dictEtransClaims.Clear();
                _dictClaimPayExists.Clear();
                List <Etrans835Attach>    listAttached        = Etrans835Attaches.GetForEtrans(_listEtranss.Select(x => x.EtransNum).ToArray());
                Dictionary <long, string> dictEtransMessages  = new Dictionary <long, string>();
                List <X12ClaimMatch>      list835ClaimMatches = new List <X12ClaimMatch>();
                Dictionary <long, int>    dictClaimMatchCount = new Dictionary <long, int>(); //1:1 with _listEtranss. Stores how many claim matches each 835 has.
                int batchQueryInterval = 500;                                                 //Every 500 rows we get the next 500 message texts to save memory.
                int rowCur             = 0;
                foreach (Etrans etrans in _listEtranss)
                {
                    if (rowCur % batchQueryInterval == 0)
                    {
                        int range = Math.Min(batchQueryInterval, _listEtranss.Count - rowCur);                   //Either the full batchQueryInterval amount or the remaining amount of etrans.
                        dictEtransMessages = EtransMessageTexts.GetMessageTexts(_listEtranss.GetRange(rowCur, range).Select(x => x.EtransMessageTextNum).ToList(), false);
                    }
                    rowCur++;
                    ODEvent.Fire(new ODEventArgs("Etrans835", Lan.g(this, "Processing 835: ") + ": " + rowCur + " out of " + _listEtranss.Count));
                    List <Etrans835Attach> listAttachedTo835 = listAttached.FindAll(x => x.EtransNum == etrans.EtransNum);
                    X835 x835 = new X835(etrans, dictEtransMessages[etrans.EtransMessageTextNum], etrans.TranSetId835, listAttachedTo835, true);
                    _dictEtrans835s.Add(etrans.EtransNum, x835);
                    List <X12ClaimMatch> listClaimMatches = x835.GetClaimMatches();
                    dictClaimMatchCount.Add(etrans.EtransNum, listClaimMatches.Count);
                    list835ClaimMatches.AddRange(listClaimMatches);
                }
                #region Set 835 unattached in batch and build _dictEtransClaims and _dictClaimPayCheckNums.
                ODEvent.Fire(new ODEventArgs("Etrans835", Lan.g(this, "Gathering internal claim matches.")));
                List <long> listClaimNums = Claims.GetClaimFromX12(list835ClaimMatches);             //Can return null.
                ODEvent.Fire(new ODEventArgs("Etrans835", Lan.g(this, "Building data sets.")));
                int         claimIndexCur        = 0;
                List <long> listMatchedClaimNums = new List <long>();
                foreach (Etrans etrans in _listEtranss)
                {
                    X835 x835 = _dictEtrans835s[etrans.EtransNum];
                    if (listClaimNums != null)
                    {
                        x835.SetClaimNumsForUnattached(listClaimNums.GetRange(claimIndexCur, dictClaimMatchCount[etrans.EtransNum]));
                    }
                    claimIndexCur += dictClaimMatchCount[etrans.EtransNum];
                    listMatchedClaimNums.AddRange(x835.ListClaimsPaid.FindAll(x => x.ClaimNum != 0).Select(x => x.ClaimNum).ToList());
                }
                List <Claim> listClaims = Claims.GetClaimsFromClaimNums(listMatchedClaimNums.Distinct().ToList());
                _dictClaimPayExists = ClaimPayments.HasClaimPayment(listMatchedClaimNums);              //Every claim num is associated to a bool. True when there is an existing claimPayment.
                foreach (Etrans etrans in _listEtranss)
                {
                    X835 x835 = _dictEtrans835s[etrans.EtransNum];
                    #region _dictEtransClaims, _dictClaimPayCheckNums
                    _dictEtransClaims.Add(etrans.EtransNum, new List <Claim>());
                    List <long>  listSubClaimNums = x835.ListClaimsPaid.FindAll(x => x.ClaimNum != 0).Select(y => y.ClaimNum).ToList();
                    List <Claim> listClaimsFor835 = listClaims.FindAll(x => listSubClaimNums.Contains(x.ClaimNum));
                    foreach (Hx835_Claim claim in x835.ListClaimsPaid)
                    {
                        Claim claimCur = listClaimsFor835.FirstOrDefault(x => x.ClaimNum == claim.ClaimNum);                    //Can be null.
                        if (claimCur == null && claim.IsAttachedToClaim && claim.ClaimNum == 0)
                        {
                            claimCur = new Claim();                          //Create empty claim since user detached claim manually, will not be considered in GetStringStatus(...).
                        }
                        if (claimCur != null && claim.IsPreauth)             //User attached preauth to internal claim, no payment needed to be considered 'Finalized' in GetStringStatus(...).
                        {
                            _dictClaimPayExists[claim.ClaimNum] = true;
                        }
                        _dictEtransClaims[etrans.EtransNum].Add(claimCur);
                    }
                    #endregion
                }
                ODEvent.Fire(new ODEventArgs("Etrans835", Lan.g(this, "Filling Grid.")));
                #endregion
            }
            gridMain.BeginUpdate();
            #region Initilize columns only once
            if (gridMain.Columns.Count == 0)
            {
                ODGridColumn col;
                col = new ODGridColumn(Lan.g("TableEtrans835s", "Patient Name"), 250);
                gridMain.Columns.Add(col);
                col = new ODGridColumn(Lan.g("TableEtrans835s", "Carrier Name"), 190);
                gridMain.Columns.Add(col);
                col = new ODGridColumn(Lan.g("TableEtrans835s", "Status"), 80);
                gridMain.Columns.Add(col);
                col = new ODGridColumn(Lan.g("TableEtrans835s", "Date"), 80);
                gridMain.Columns.Add(col);
                col = new ODGridColumn(Lan.g("TableEtrans835s", "Amount"), 80);
                gridMain.Columns.Add(col);
                if (PrefC.HasClinicsEnabled)
                {
                    col = new ODGridColumn(Lan.g("TableEtrans835s", "Clinic"), 70);
                    gridMain.Columns.Add(col);
                }
                col = new ODGridColumn(Lan.g("TableEtrans835s", "Code"), 37, HorizontalAlignment.Center);
                gridMain.Columns.Add(col);
                col = new ODGridColumn(Lan.g("TableEtrans835s", "Note"), 0);
                gridMain.Columns.Add(col);
            }
            #endregion
            gridMain.Rows.Clear();
            foreach (Etrans etrans in _listEtranss)
            {
                X835 x835 = _dictEtrans835s[etrans.EtransNum];
                #region Filter: Carrier Name
                if (carrierName != "" && !x835.PayerName.ToLower().Contains(carrierName.ToLower()))
                {
                    continue;
                }
                #endregion
                string status = GetStringStatus(etrans.EtransNum);
                #region Filter: Status
                if (!listSelectedStatuses.Contains(status.Replace("*", "")))                //The filter will ignore finalized with detached claims.
                {
                    continue;
                }
                #endregion
                //List of ClinicNums for the current etrans.ListClaimsPaid from the DB.
                List <long> listClinicNums = _dictEtransClaims[etrans.EtransNum].Select(x => x == null? 0 :x.ClinicNum).Distinct().ToList();
                #region Filter: Clinics
                if (PrefC.HasClinicsEnabled && !listClinicNums.Exists(x => listSelectedClinicNums.Contains(x)))
                {
                    continue;                    //The ClinicNums associated to the 835 do not match any of the selected ClinicNums, so nothing to show in this 835.
                }
                #endregion
                #region Filter: Check and Trace Value
                if (checkTraceNum != "" && !x835.TransRefNum.Contains(checkTraceNum))               //Trace Number does not match
                {
                    continue;
                }
                #endregion
                #region Filter: Insurance Check Range Min and Max
                if (amountMin != "" && x835.InsPaid < PIn.Decimal(amountMin) || amountMax != "" && x835.InsPaid > PIn.Decimal(amountMax))
                {
                    continue;                    //Either the InsPaid is below or above our range.
                }
                #endregion
                ODGridRow row = new ODGridRow();
                #region Column: Patient Name
                List <string> listPatNames = x835.ListClaimsPaid.Select(x => x.PatientName.ToString()).Distinct().ToList();
                string        patName      = (listPatNames.Count > 0 ? listPatNames[0] : "");
                if (listPatNames.Count > 1)
                {
                    patName = "(" + POut.Long(listPatNames.Count) + ")";
                }
                row.Cells.Add(patName);
                #endregion
                row.Cells.Add(x835.PayerName);
                row.Cells.Add(status);                //See GetStringStatus(...) for possible values.
                row.Cells.Add(POut.Date(etrans.DateTimeTrans));
                row.Cells.Add(POut.Decimal(x835.InsPaid));
                #region Column: Clinic
                if (PrefC.HasClinicsEnabled)
                {
                    string clinicAbbr = "";
                    if (listClinicNums.Count == 1)
                    {
                        if (listClinicNums[0] == 0)
                        {
                            clinicAbbr = Lan.g(this, "Unassigned");
                        }
                        else
                        {
                            clinicAbbr = Clinics.GetAbbr(listClinicNums[0]);
                        }
                    }
                    else if (listClinicNums.Count > 1)
                    {
                        clinicAbbr = "(" + Lan.g(this, "Multiple") + ")";
                    }
                    row.Cells.Add(clinicAbbr);
                }
                #endregion
                row.Cells.Add(x835._paymentMethodCode);
                row.Cells.Add(etrans.Note);
                row.Tag = etrans;
                gridMain.Rows.Add(row);
            }
            gridMain.EndUpdate();
            actionCloseProgress?.Invoke();
        }
Пример #17
0
        private void butOK_Click(object sender, System.EventArgs e)
        {
            if (textDate.errorProvider1.GetError(textDate) != "" ||
                textAPR.errorProvider1.GetError(textAPR) != "" ||
                textAtLeast.errorProvider1.GetError(textAtLeast) != "" ||
                textOver.errorProvider1.GetError(textOver) != "")
            {
                MsgBox.Show(this, "Please fix data entry errors first.");
                return;
            }
            DateTime date = PIn.Date(textDate.Text);

            if (PrefC.GetDate(PrefName.FinanceChargeLastRun).AddDays(25) > date)
            {
                if (!MsgBox.Show(this, true, "Warning.  Finance charges should not be run more than once per month.  Continue?"))
                {
                    return;
                }
            }
            else if (PrefC.GetDate(PrefName.BillingChargeLastRun).AddDays(25) > date)
            {
                if (!MsgBox.Show(this, true, "Warning.  Billing charges should not be run more than once per month.  Continue?"))
                {
                    return;
                }
            }
            if (listBillType.SelectedIndices.Count == 0)
            {
                MsgBox.Show(this, "Please select at least one billing type first.");
                return;
            }
            if (PIn.Long(textAPR.Text) < 2)
            {
                if (!MsgBox.Show(this, true, "The APR is much lower than normal. Do you wish to proceed?"))
                {
                    return;
                }
            }
            if (PrefC.GetBool(PrefName.AgingCalculatedMonthlyInsteadOfDaily) && PrefC.GetDate(PrefName.DateLastAging).AddMonths(1) <= DateTime.Today)
            {
                if (!MsgBox.Show(this, MsgBoxButtons.OKCancel, "It has been more than a month since aging has been run.  It is recommended that you update the "
                                 + "aging date and run aging before continuing."))
                {
                    return;
                }
                //we might also consider a warning if textDate.Text does not match DateLastAging.  Probably not needed for daily aging, though.
            }
            string      chargeType            = (radioFinanceCharge.Checked?"Finance":"Billing");//For display only
            List <long> listSelectedBillTypes = listBillType.SelectedIndices.OfType <int>().Select(x => _listBillingTypeDefs[x].DefNum).ToList();
            Action      actionCloseProgress   = null;
            int         chargesAdded          = 0;

            try {
                actionCloseProgress = ODProgressOld.ShowProgressStatus("FinanceCharge", this, Lan.g(this, "Gathering patients with aged balances") + "...");
                List <PatAging> listPatAgings = Patients.GetAgingListSimple(listSelectedBillTypes, new List <long> {
                });                                                                                                                //Ordered by PatNum, for thread concurrency
                long adjType = PrefC.GetLong(PrefName.FinanceChargeAdjustmentType);
                Dictionary <long, List <Adjustment> > dictPatAdjustments = new Dictionary <long, List <Adjustment> >();
                if (!checkCompound.Checked)
                {
                    int daysOver = (radio30.Checked ? 30
                                                : radio60.Checked ? 60
                                                : 90);
                    DateTime maxAdjDate = MiscData.GetNowDateTime().Date.AddDays(-daysOver);
                    dictPatAdjustments = Adjustments.GetAdjustForPatsByType(listPatAgings.Select(x => x.PatNum).ToList(), adjType, maxAdjDate);
                }
                int           chargesProcessed = 0;
                List <Action> listActions      = new List <Action>();
                foreach (PatAging patAgingCur in listPatAgings)
                {
                    listActions.Add(new Action(() => {
                        if (++chargesProcessed % 5 == 0)
                        {
                            ODEvent.Fire(new ODEventArgs("FinanceCharge", Lan.g(this, "Processing " + chargeType + " charges") + ": " + chargesProcessed + " out of "
                                                         + listPatAgings.Count));
                        }
                        //This WILL NOT be the same as the patient's total balance. Start with BalOver90 since all options include that bucket. Add others if needed.
                        double overallBalance = patAgingCur.BalOver90 + (radio60.Checked?patAgingCur.Bal_61_90:radio30.Checked?(patAgingCur.Bal_31_60 + patAgingCur.Bal_61_90):0);
                        if (overallBalance <= .01d)
                        {
                            return;
                        }
                        if (radioBillingCharge.Checked)
                        {
                            AddBillingCharge(patAgingCur.PatNum, date, textBillingCharge.Text, patAgingCur.PriProv);
                        }
                        else                                                                                 //Finance charge
                        {
                            if (dictPatAdjustments.ContainsKey(patAgingCur.PatNum))                          //Only contains key if checkCompound is not checked.
                            {
                                overallBalance -= dictPatAdjustments[patAgingCur.PatNum].Sum(x => x.AdjAmt); //Dict always contains patNum as key, but list can be empty.
                            }
                            if (!AddFinanceCharge(patAgingCur.PatNum, date, textAPR.Text, textAtLeast.Text, textOver.Text, overallBalance, patAgingCur.PriProv, adjType))
                            {
                                return;
                            }
                        }
                        chargesAdded++;
                    }));
                }
                ODThread.RunParallel(listActions, TimeSpan.FromMinutes(2));               //each group of actions gets X minutes.
                if (radioFinanceCharge.Checked)
                {
                    if (Prefs.UpdateString(PrefName.FinanceChargeAPR, textAPR.Text)
                        | Prefs.UpdateString(PrefName.FinanceChargeLastRun, POut.Date(date, false))
                        | Prefs.UpdateString(PrefName.FinanceChargeAtLeast, textAtLeast.Text)
                        | Prefs.UpdateString(PrefName.FinanceChargeOnlyIfOver, textOver.Text)
                        | Prefs.UpdateString(PrefName.BillingChargeOrFinanceIsDefault, "Finance"))
                    {
                        DataValid.SetInvalid(InvalidType.Prefs);
                    }
                }
                else if (radioBillingCharge.Checked)
                {
                    if (Prefs.UpdateString(PrefName.BillingChargeAmount, textBillingCharge.Text)
                        | Prefs.UpdateString(PrefName.BillingChargeLastRun, POut.Date(date, false))
                        | Prefs.UpdateString(PrefName.BillingChargeOrFinanceIsDefault, "Billing"))
                    {
                        DataValid.SetInvalid(InvalidType.Prefs);
                    }
                }
            }
            finally {
                actionCloseProgress?.Invoke();                //terminates progress bar
            }
            MessageBox.Show(Lan.g(this, chargeType + " charges added") + ": " + chargesAdded);
            if (PrefC.GetBool(PrefName.AgingIsEnterprise))
            {
                if (!RunAgingEnterprise())
                {
                    MsgBox.Show(this, "There was an error calculating aging after the " + chargeType.ToLower() + " charge adjustments were added.\r\n"
                                + "You should run aging later to update affected accounts.");
                }
            }
            else
            {
                DateTime asOfDate = (PrefC.GetBool(PrefName.AgingCalculatedMonthlyInsteadOfDaily)?PrefC.GetDate(PrefName.DateLastAging):DateTime.Today);
                actionCloseProgress = ODProgressOld.ShowProgressStatus("FinanceCharge", this, Lan.g(this, "Calculating aging for all patients as of") + " "
                                                                       + asOfDate.ToShortDateString() + "...");
                Cursor = Cursors.WaitCursor;
                try {
                    Ledgers.RunAging();
                }
                catch (MySqlException ex) {
                    actionCloseProgress?.Invoke();                    //terminates progress bar
                    Cursor = Cursors.Default;
                    if (ex == null || ex.Number != 1213)              //not a deadlock error, just throw
                    {
                        throw;
                    }
                    MsgBox.Show(this, "There was a deadlock error calculating aging after the " + chargeType.ToLower() + " charge adjustments were added.\r\n"
                                + "You should run aging later to update affected accounts.");
                }
                finally {
                    actionCloseProgress?.Invoke();                    //terminates progress bar
                    Cursor = Cursors.Default;
                }
            }
            DialogResult = DialogResult.OK;
        }