Beispiel #1
0
        ///<summary>PatNum can be 0.</summary>
        public static void MakeLogEntry(Permissions permType, long patNum, string logText)
        {
            //No need to check RemotingRole; no call to db.
            SecurityLog securityLog = new SecurityLog();

            securityLog.PermType = permType;
            securityLog.UserNum  = Security.CurUser.UserNum;
            securityLog.LogText  = logText;         //"From: "+Environment.MachineName+" - "+logText;
            securityLog.CompName = Environment.MachineName;
            securityLog.PatNum   = patNum;
            SecurityLogs.Insert(securityLog);
        }
Beispiel #2
0
 ///<summary>Take a SecurityLog object to save to the database. Creates a SecurityLogHash object as well.</summary>
 public static void MakeLogEntry(SecurityLog secLog)
 {
     if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
     {
         Meth.GetVoid(MethodBase.GetCurrentMethod(), secLog);
         return;
     }
     secLog.SecurityLogNum = SecurityLogs.Insert(secLog);
     SecurityLogHashes.InsertSecurityLogHash(secLog.SecurityLogNum);            //uses db date/time
     if (secLog.PermType == Permissions.AppointmentCreate)
     {
         EntryLogs.Insert(new EntryLog(secLog.UserNum, EntryLogFKeyType.Appointment, secLog.FKey, secLog.LogSource));
     }
 }
Beispiel #3
0
        ///<summary>Used when making a security log from a remote server, possibly with multithreaded connections.</summary>
        public static void MakeLogEntryNoCache(Permissions permType, long patnum, string logText, long userNum, LogSources source)
        {
            SecurityLog securityLog = new SecurityLog();

            securityLog.PermType       = permType;
            securityLog.UserNum        = userNum;
            securityLog.LogText        = logText;
            securityLog.CompName       = Environment.MachineName;
            securityLog.PatNum         = patnum;
            securityLog.FKey           = 0;
            securityLog.LogSource      = source;
            securityLog.SecurityLogNum = SecurityLogs.InsertNoCache(securityLog);
            SecurityLogHashes.InsertSecurityLogHashNoCache(securityLog.SecurityLogNum);
        }
        ///<summary>Creates a new SecurityLogHash entry in the Db.</summary>
        public static void InsertSecurityLogHash(long securityLogNum)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                Meth.GetVoid(MethodBase.GetCurrentMethod(), securityLogNum);
                return;
            }
            SecurityLog     securityLog     = SecurityLogs.GetOne(securityLogNum);   //need a fresh copy because of time stamps, etc.
            SecurityLogHash securityLogHash = new SecurityLogHash();

            //Set the FK
            securityLogHash.SecurityLogNum = securityLog.SecurityLogNum;
            //Hash the securityLog
            securityLogHash.LogHash = GetHashString(securityLog);
            Insert(securityLogHash);
        }
Beispiel #5
0
        ///<summary>Takes a foreign key to a table associated with that PermType.  PatNum can be 0.</summary>
        public static void MakeLogEntry(Permissions permType, long patNum, string logText, long fKey)
        {
            //No need to check RemotingRole; no call to db.
            SecurityLog securityLog = new SecurityLog();

            securityLog.PermType = permType;
            if (Security.CurUser != null)            //if this is generated by Patient Portal web service then we won't have a CurUser set
            {
                securityLog.UserNum = Security.CurUser.UserNum;
            }
            securityLog.LogText        = logText;   //"From: "+Environment.MachineName+" - "+logText;
            securityLog.CompName       = Environment.MachineName;
            securityLog.PatNum         = patNum;
            securityLog.FKey           = fKey;
            securityLog.SecurityLogNum = SecurityLogs.Insert(securityLog);
            //Create a hash of the security log.
            SecurityLogHashes.InsertSecurityLogHash(securityLog.SecurityLogNum);            //uses db date/time
        }
Beispiel #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));
        }
Beispiel #7
0
        public static void SyncByClinicAndTypes(List <ApptReminderRule> listNew, long clinicNum, params ApptReminderType[] arrTypes)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                Meth.GetVoid(MethodBase.GetCurrentMethod(), listNew, clinicNum, arrTypes);
                return;
            }
            if (arrTypes.Length == 0)
            {
                return;
            }
            List <ApptReminderRule> listOld = ApptReminderRules.GetForClinicAndTypes(clinicNum, arrTypes);        //ClinicNum can be 0

            if (Crud.ApptReminderRuleCrud.Sync(listNew, listOld))
            {
                SecurityLogs.MakeLogEntry(Permissions.Setup, 0, string.Join(", ", arrTypes.Select(x => x.GetDescription()))
                                          + " rules changed for ClinicNum: " + clinicNum.ToString() + ".");
            }
        }
Beispiel #8
0
        ///<summary>Any filenames mentioned in the fileList which are not attached to the given patient are properly attached to that patient. Returns the total number of documents that were newly attached to the patient.</summary>
        public static int InsertMissing(Patient patient, List <string> fileList)
        {
            //No need to check RemotingRole; no call to db.
            int       countAdded = 0;
            DataTable table      = Documents.GetFileNamesForPatient(patient.PatNum);

            for (int j = 0; j < fileList.Count; j++)
            {
                string fileName = Path.GetFileName(fileList[j]);
                if (!IsAcceptableFileName(fileName))
                {
                    continue;
                }
                bool inList = false;
                for (int i = 0; i < table.Rows.Count && !inList; i++)
                {
                    inList = (table.Rows[i]["FileName"].ToString() == fileName);
                }
                if (!inList)                //OD found new images in the patient's folder that aren't part of the DB.
                {
                    Document doc = new Document();
                    if (PrefC.AtoZfolderUsed == DataStorageType.LocalAtoZ)
                    {
                        doc.DateCreated = File.GetLastWriteTime(fileList[j]);
                    }
                    else                      //Cloud
                    {
                        doc.DateCreated = DateTime.Now;
                    }
                    DateTime datePrevious = doc.DateTStamp;
                    doc.Description = fileName;
                    doc.DocCategory = Defs.GetFirstForCategory(DefCat.ImageCats, true).DefNum;
                    doc.FileName    = fileName;
                    doc.PatNum      = patient.PatNum;
                    Insert(doc, patient);
                    countAdded++;
                    string docCat = Defs.GetDef(DefCat.ImageCats, doc.DocCategory).ItemName;
                    SecurityLogs.MakeLogEntry(Permissions.ImageEdit, patient.PatNum, Lans.g("ContrImages", "Document Created: A file") + ", " + doc.FileName + ", "
                                              + Lans.g("ContrImages", "placed into the patient's AtoZ images folder from outside of the program was detected and a record automatically inserted into the first image category") + ", " + docCat, doc.DocNum, datePrevious);
                }
            }
            return(countAdded);
        }
Beispiel #9
0
        public static EmailMessage GetEmailMessageForPortalStatement(Statement stmt, Patient pat)
        {
            //No need to check RemotingRole; no call to db.
            if (stmt.PatNum != pat.PatNum)
            {
                string logMsg = Lans.g("Statements", "Mismatched PatNums detected between current patient and current statement:") + "\r\n"
                                + Lans.g("Statements", "Statement PatNum:") + " " + stmt.PatNum + " " + Lans.g("Statements", "(assumed correct)") + "\r\n"
                                + Lans.g("Statements", "Patient PatNum:") + " " + pat.PatNum + " " + Lans.g("Statements", "(possibly incorrect)");
                SecurityLogs.MakeLogEntry(Permissions.StatementPatNumMismatch, stmt.PatNum, logMsg, LogSources.Diagnostic);
            }
            EmailMessage message = new EmailMessage();

            message.PatNum      = pat.PatNum;
            message.ToAddress   = pat.Email;
            message.FromAddress = EmailAddresses.GetByClinic(pat.ClinicNum).GetFrom();
            string emailBody;

            if (stmt.EmailSubject != null && stmt.EmailSubject != "")
            {
                message.Subject = stmt.EmailSubject;
            }
            else              //Subject was not preset, set a default subject.
            {
                message.Subject = Lans.g("Statements", "New Statement Available");
            }
            if (stmt.EmailBody != null && stmt.EmailBody != "")
            {
                emailBody = stmt.EmailBody;
            }
            else              //Body was not preset, set a body text.
            {
                emailBody = Lans.g("Statements", "Dear") + " [nameFLnoPref],\r\n\r\n"
                            + Lans.g("Statements", "A new account statement is available.") + "\r\n\r\n"
                            + Lans.g("Statements", "To view your account statement, log on to our portal by following these steps:") + "\r\n\r\n"
                            + Lans.g("Statements", "1. Visit the following URL in a web browser:") + " " + PrefC.GetString(PrefName.PatientPortalURL) + ".\r\n"
                            + Lans.g("Statements", "2. Enter your credentials to gain access to your account.") + "\r\n"
                            + Lans.g("Statements", "3. Click the Account icon on the left and select the Statements tab.");
            }
            message.BodyText = Statements.ReplaceVarsForEmail(emailBody, pat, stmt);
            return(message);
        }
Beispiel #10
0
        ///<summary>Updates the claim to the database.</summary>
        public static UpdateData UpdateClaim(Claim ClaimCur, List <ClaimValCodeLog> listClaimValCodes, ClaimCondCodeLog claimCondCodeLog,
                                             List <Procedure> listProcsToUpdatePlaceOfService, Patient pat, bool doMakeSecLog, Permissions permissionToLog)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                return(Meth.GetObject <UpdateData>(MethodBase.GetCurrentMethod(), ClaimCur, listClaimValCodes, claimCondCodeLog, listProcsToUpdatePlaceOfService,
                                                   pat, doMakeSecLog, permissionToLog));
            }
            UpdateData data = new UpdateData();

            Claims.Update(ClaimCur);
            if (listClaimValCodes != null)
            {
                ClaimValCodeLogs.UpdateList(listClaimValCodes);
            }
            if (claimCondCodeLog != null)
            {
                if (claimCondCodeLog.IsNew)
                {
                    ClaimCondCodeLogs.Insert(claimCondCodeLog);
                }
                else
                {
                    ClaimCondCodeLogs.Update(claimCondCodeLog);
                }
            }
            foreach (Procedure proc in listProcsToUpdatePlaceOfService)
            {
                Procedure oldProc = proc.Copy();
                proc.PlaceService = ClaimCur.PlaceService;
                Procedures.Update(proc, oldProc);
            }
            if (doMakeSecLog)
            {
                SecurityLogs.MakeLogEntry(permissionToLog, ClaimCur.PatNum,
                                          pat.GetNameLF() + ", Date of service: " + ClaimCur.DateService.ToShortDateString());
            }
            data.ListSendQueueItems = Claims.GetQueueList(ClaimCur.ClaimNum, ClaimCur.ClinicNum, 0);
            return(data);
        }
Beispiel #11
0
		///<summary>Hides all operatories that are not the master op and moves any appointments passed in into the master op.
		///Throws exceptions</summary>
		public static void MergeOperatoriesIntoMaster(long masterOpNum,List<long> listOpNumsToMerge,List<Appointment> listApptsToMerge) {
			//No need to check RemotingRole; No db call.
			List<Operatory> listOps=Operatories.GetDeepCopy();
			Operatory masterOp=listOps.FirstOrDefault(x => x.OperatoryNum==masterOpNum);
			if(masterOp==null) {
				throw new ApplicationException(Lans.g("Operatories","Operatory to merge into no longer exists."));
			}
			if(listApptsToMerge.Count>0) {
				//All appts in listAppts are appts that we are going to move to new op.
				List<Appointment> listApptsNew=listApptsToMerge.Select(x => x.Copy()).ToList();//Copy object so that we do not change original object in memory.
				listApptsNew.ForEach(x => x.Op=masterOpNum);//Associate to new op selection
				Appointments.Sync(listApptsNew,listApptsToMerge,0);
			}
			List<Operatory> listOpsToMerge=listOps.Select(x=> x.Copy()).ToList();//Copy object so that we do not change original object in memory.
			listOpsToMerge.FindAll(x => x.OperatoryNum!=masterOpNum && listOpNumsToMerge.Contains(x.OperatoryNum))
				.ForEach(x => x.IsHidden=true);
			Operatories.Sync(listOpsToMerge,listOps);
			SecurityLogs.MakeLogEntry(Permissions.Setup,0
				,Lans.g("Operatories","The following operatories and all of their appointments were merged into the")
					+" "+masterOp.Abbrev+" "+Lans.g("Operatories","operatory;")+" "
					+string.Join(", ",listOpsToMerge.FindAll(x => x.OperatoryNum!=masterOpNum && listOpNumsToMerge.Contains(x.OperatoryNum)).Select(x => x.Abbrev)));
		}
        ///<summary>Gets a good chunk of the data used in the TP Module.</summary>
        public static TPModuleData GetModuleData(long patNum, bool doMakeSecLog, long userNum = 0)
        {
            if (RemotingClient.RemotingRole != RemotingRole.ServerWeb)
            {
                userNum = Security.CurUser.UserNum;                    //must be before normal remoting role check to get user at workstation
            }
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) //Remoting role check here to reduce round-trips to the server.
            {
                return(Meth.GetObject <TPModuleData>(MethodBase.GetCurrentMethod(), patNum, doMakeSecLog, userNum));
            }
            TPModuleData tpData = new TPModuleData();

            tpData.Fam         = Patients.GetFamily(patNum);
            tpData.Pat         = tpData.Fam.GetPatient(patNum);
            tpData.PatPlanList = PatPlans.Refresh(patNum);
            if (!PatPlans.IsPatPlanListValid(tpData.PatPlanList))
            {
                //PatPlans had invalid references and need to be refreshed.
                tpData.PatPlanList = PatPlans.Refresh(patNum);
            }
            tpData.SubList     = InsSubs.RefreshForFam(tpData.Fam);
            tpData.InsPlanList = InsPlans.RefreshForSubList(tpData.SubList);
            tpData.BenefitList = Benefits.Refresh(tpData.PatPlanList, tpData.SubList);
            tpData.ClaimList   = Claims.Refresh(tpData.Pat.PatNum);
            tpData.HistList    = ClaimProcs.GetHistList(tpData.Pat.PatNum, tpData.BenefitList, tpData.PatPlanList, tpData.InsPlanList, DateTime.Today,
                                                        tpData.SubList);
            tpData.ListSubLinks = SubstitutionLinks.GetAllForPlans(tpData.InsPlanList);
            TreatPlanType tpTypeCur = (tpData.Pat.DiscountPlanNum == 0?TreatPlanType.Insurance:TreatPlanType.Discount);

            TreatPlans.AuditPlans(patNum, tpTypeCur, userNum);
            tpData.ListProcedures = Procedures.Refresh(patNum);
            tpData.ListTreatPlans = TreatPlans.GetAllForPat(patNum);
            tpData.ArrProcTPs     = ProcTPs.Refresh(patNum);
            if (doMakeSecLog)
            {
                SecurityLogs.MakeLogEntry(Permissions.TPModule, patNum, "");
            }
            return(tpData);
        }
Beispiel #13
0
        ///<summary>Deletes all adjustments for a procedure</summary>
        public static void DeleteForProcedure(long procNum)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                Meth.GetVoid(MethodBase.GetCurrentMethod(), procNum);
                return;
            }
            //Create log for each adjustment that is going to be deleted.
            string            command         = "SELECT * FROM adjustment WHERE ProcNum = " + POut.Long(procNum); //query for all adjustments of a procedure
            List <Adjustment> listAdjustments = Crud.AdjustmentCrud.SelectMany(command);

            for (int i = 0; i < listAdjustments.Count; i++)                                      //loops through the rows
            {
                SecurityLogs.MakeLogEntry(Permissions.AdjustmentEdit, listAdjustments[i].PatNum, //and creates audit trail entry for every row to be deleted
                                          "Delete adjustment for patient: "
                                          + Patients.GetLim(listAdjustments[i].PatNum).GetNameLF() + ", "
                                          + (listAdjustments[i].AdjAmt).ToString("c"), 0, listAdjustments[i].SecDateTEdit);
            }
            //Delete each adjustment for the procedure.
            command = "DELETE FROM adjustment WHERE ProcNum = " + POut.Long(procNum);
            Db.NonQ(command);
        }
Beispiel #14
0
        ///<summary>This method will remove and/or add a fee for the fee information passed in.
        ///codeText will typically be one valid procedure code.  E.g. D1240
        ///If an amt of -1 is passed in, then it indicates a "blank" entry which will cause deletion of any existing fee.
        ///Returns listFees back after importing the passed in fee information.
        ///Does not make any database calls.  This is left up to the user to take action on the list of fees returned.
        ///Also, makes security log entries based on how the fee changed.  Does not make a log for codes that were removed (user already warned)</summary>
        public static List <Fee> Import(string codeText, double amt, long feeSchedNum, long clinicNum, long provNum, List <Fee> listFees)
        {
            //No need to check RemotingRole; no call to db.
            if (!ProcedureCodes.IsValidCode(codeText))
            {
                return(listFees);               //skip for now. Possibly insert a code in a future version.
            }
            string   feeOldStr    = "";
            long     codeNum      = ProcedureCodes.GetCodeNum(codeText);
            Fee      fee          = listFees.FirstOrDefault(x => x.CodeNum == codeNum && x.FeeSched == feeSchedNum && x.ClinicNum == clinicNum && x.ProvNum == provNum);
            DateTime datePrevious = DateTime.MinValue;

            if (fee != null)
            {
                feeOldStr    = Lans.g("FormFeeSchedTools", "Old Fee") + ": " + fee.Amount.ToString("c") + ", ";
                datePrevious = fee.SecDateTEdit;
                listFees.Remove(fee);
            }
            if (amt == -1)
            {
                return(listFees);
            }
            fee           = new Fee();
            fee.Amount    = amt;
            fee.FeeSched  = feeSchedNum;
            fee.CodeNum   = ProcedureCodes.GetCodeNum(codeText);
            fee.ClinicNum = clinicNum;    //Either 0 because you're importing on an HQ schedule or local clinic because the feesched is localizable.
            fee.ProvNum   = provNum;
            listFees.Add(fee);            //Insert new fee specific to the active clinic.
            SecurityLogs.MakeLogEntry(Permissions.ProcFeeEdit, 0, Lans.g("FormFeeSchedTools", "Procedure") + ": " + codeText + ", " + feeOldStr
                                      + Lans.g("FormFeeSchedTools", "New Fee") + ": " + amt.ToString("c") + ", "
                                      + Lans.g("FormFeeSchedTools", "Fee Schedule") + ": " + FeeScheds.GetDescription(feeSchedNum) + ". "
                                      + Lans.g("FormFeeSchedTools", "Fee changed using the Import button in the Fee Tools window."), ProcedureCodes.GetCodeNum(codeText),
                                      DateTime.MinValue);
            SecurityLogs.MakeLogEntry(Permissions.LogFeeEdit, 0, "Fee changed", fee.FeeNum, datePrevious);
            return(listFees);
        }
Beispiel #15
0
        ///<summary>Returns an email message for the patient based on the statement passed in.</summary>
        public static EmailMessage GetEmailMessageForStatement(Statement stmt, Patient pat)
        {
            if (stmt.PatNum != pat.PatNum)
            {
                string logMsg = Lans.g("Statements", "Mismatched PatNums detected between current patient and current statement:") + "\r\n"
                                + Lans.g("Statements", "Statement PatNum:") + " " + stmt.PatNum + " " + Lans.g("Statements", "(assumed correct)") + "\r\n"
                                + Lans.g("Statements", "Patient PatNum:") + " " + pat.PatNum + " " + Lans.g("Statements", "(possibly incorrect)");
                SecurityLogs.MakeLogEntry(Permissions.StatementPatNumMismatch, stmt.PatNum, logMsg, LogSources.Diagnostic);
            }
            //No need to check RemotingRole; no call to db.
            EmailMessage message = new EmailMessage();

            message.PatNum      = pat.PatNum;
            message.ToAddress   = pat.Email;
            message.FromAddress = EmailAddresses.GetByClinic(pat.ClinicNum).GetFrom();
            string str;

            if (stmt.EmailSubject != null && stmt.EmailSubject != "")
            {
                str = stmt.EmailSubject; //Set str to the email subject if one was already set.
            }
            else                         //Subject was not set.  Set str to the default billing email subject.
            {
                str = PrefC.GetString(PrefName.BillingEmailSubject);
            }
            message.Subject = Statements.ReplaceVarsForEmail(str, pat, stmt);
            if (stmt.EmailBody != null && stmt.EmailBody != "")
            {
                str = stmt.EmailBody; //Set str to the email body if one was already set.
            }
            else                      //Body was not set.  Set str to the default billing email body text.
            {
                str = PrefC.GetString(PrefName.BillingEmailBodyText);
            }
            message.BodyText = Statements.ReplaceVarsForEmail(str, pat, stmt);
            return(message);
        }
Beispiel #16
0
        ///<summary>Creates a new discount adjustment for the given procedure using the discount plan fee.</summary>
        public static void CreateAdjustmentForDiscountPlan(Procedure procedure)
        {
            //No need to check RemotingRole; no call to db.
            DiscountPlan discountPlan = DiscountPlans.GetPlan(Patients.GetPat(procedure.PatNum).DiscountPlanNum);

            if (discountPlan == null)
            {
                return;                //No discount plan.
            }
            //Figure out how much the patient saved and make an adjustment for the difference so that the office find how much money they wrote off.
            double discountAmt = Fees.GetAmount(procedure.CodeNum, discountPlan.FeeSchedNum, procedure.ClinicNum, procedure.ProvNum);

            if (discountAmt == -1)
            {
                return;                //No fee entered, don't make adjustment.
            }
            double adjAmt = procedure.ProcFee - discountAmt;

            if (adjAmt <= 0)
            {
                return;                //We do not need to create adjustments for 0 dollars.
            }
            Adjustment adjustmentCur = new Adjustment();

            adjustmentCur.DateEntry = DateTime.Today;
            adjustmentCur.AdjDate   = DateTime.Today;
            adjustmentCur.ProcDate  = procedure.ProcDate;
            adjustmentCur.ProvNum   = procedure.ProvNum;
            adjustmentCur.PatNum    = procedure.PatNum;
            adjustmentCur.AdjType   = discountPlan.DefNum;
            adjustmentCur.ClinicNum = procedure.ClinicNum;
            adjustmentCur.AdjAmt    = (-adjAmt);
            adjustmentCur.ProcNum   = procedure.ProcNum;
            Insert(adjustmentCur);
            TsiTransLogs.CheckAndInsertLogsIfAdjTypeExcluded(adjustmentCur);
            SecurityLogs.MakeLogEntry(Permissions.AdjustmentCreate, procedure.PatNum, "Adjustment made for discount plan: " + adjustmentCur.AdjAmt.ToString("f"));
        }
Beispiel #17
0
        ///<summary>Update Appointment.Confirmed. Returns true if update was allowed. Returns false if it was prevented.</summary>
        public static bool UpdateAppointmentConfirmationStatus(long aptNum, long confirmDefNum, string commaListOfExcludedDefNums)
        {
            Appointment aptCur = Appointments.GetOneApt(aptNum);

            if (aptCur == null)
            {
                return(false);
            }
            List <long> preventChangeFrom = commaListOfExcludedDefNums.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(long.Parse).ToList();

            if (preventChangeFrom.Contains(aptCur.Confirmed))              //This appointment is in a confirmation state that can no longer be updated.
            {
                return(false);
            }
            //Keep the update small.
            Appointment aptOld = aptCur.Copy();

            aptCur.Confirmed = confirmDefNum;
            Appointments.Update(aptCur, aptOld);           //Appointments S-Class handles Signalods
            SecurityLogs.MakeLogEntry(Permissions.ApptConfirmStatusEdit, aptCur.PatNum, "Appointment confirmation status changed from "
                                      + Defs.GetName(DefCat.ApptConfirmed, aptOld.Confirmed) + " to " + Defs.GetName(DefCat.ApptConfirmed, aptCur.Confirmed)
                                      + " due to an eConfirmation.", aptCur.AptNum, LogSources.AutoConfirmations, aptOld.DateTStamp);
            return(true);
        }
Beispiel #18
0
        ///<summary>Throws Exception.
        ///Checks to see if the query is safe for replication and if the user has permission to run a command query if it is a command query.</summary>
        public static bool IsSqlAllowed(string command)
        {
            if (!IsSafeSqlForReplication(command))
            {
                return(false);
            }
            bool isCommand;

            try {
                isCommand = IsCommandSql(command);
            }
            catch {
                throw new ApplicationException("Validation failed. Please remove mid-query comments and try again.");
            }
            if (isCommand && !Security.IsAuthorized(Permissions.CommandQuery))
            {
                return(false);
            }
            if (isCommand)
            {
                SecurityLogs.MakeLogEntry(Permissions.CommandQuery, 0, "Command query run.");
            }
            return(true);
        }
Beispiel #19
0
        ///<summary>Takes a screening sheet that is associated to a patient and processes any corresponding ScreenCharts found.
        ///Processing will create treatment planned or completed procedures for the patient.
        ///Supply the sheet and then a bitwise enum of screen chart types to digest.
        ///listProcOrigVals, nulls are allowed, the first represents the fluoride field, second is assessment field, all others are other procs.</summary>
        public static void ProcessScreenChart(Sheet sheet, ScreenChartType chartTypes, long provNum, long sheetNum, List <SheetField> listChartOrigVals
                                              , List <SheetField> listProcOrigVals)
        {
            //No need to check RemotingRole; no call to db.
            if (sheet == null || sheet.PatNum == 0)
            {
                return;                //An invalid screening sheet was passed in.
            }
            List <string> listToothVals    = new List <string>();
            List <string> listToothValsOld = new List <string>();

            //Process treatment planned sealants.
            foreach (SheetField field in sheet.SheetFields)             //Go through the supplied sheet's fields and find the field.
            {
                if (chartTypes.HasFlag(ScreenChartType.TP) && field.FieldType == SheetFieldType.ScreenChart && field.FieldName == "ChartSealantTreatment")
                {
                    listToothVals = field.FieldValue.Split(';').ToList();
                    if (listToothVals[0] == "1")         //Primary tooth chart
                    {
                        continue;                        //Skip primary tooth charts because we do not need to create any TP procedures for them.
                    }
                    listToothVals.RemoveAt(0);           //Remove the toothchart type value
                    if (listChartOrigVals[0] != null)    //Shouldn't be null if ChartSealantTreatment exists
                    {
                        listToothValsOld = listChartOrigVals[0].FieldValue.Split(';').ToList();
                        listToothValsOld.RemoveAt(0);                        //Remove the toothchart type value
                    }
                    ScreenChartType chartType = ScreenChartType.TP;
                    ProcessScreenChartHelper(sheet.PatNum, listToothVals, chartType, provNum, sheetNum, listToothValsOld);
                    break;
                }
            }
            listToothVals = new List <string>();            //Clear out the tooth values for the next tooth chart.
            //Process completed sealants.
            foreach (SheetField field in sheet.SheetFields) //Go through the supplied sheet's fields and find the field.
            {
                if (chartTypes.HasFlag(ScreenChartType.C) && field.FieldType == SheetFieldType.ScreenChart && field.FieldName == "ChartSealantComplete")
                {
                    listToothVals = field.FieldValue.Split(';').ToList();
                    if (listToothVals[0] == "1")         //Primary tooth chart
                    {
                        continue;                        //Skip primary tooth charts because we do not need to create any TP procedures for them.
                    }
                    listToothVals.RemoveAt(0);           //Remove the toothchart type value
                    if (listChartOrigVals[1] != null)    //Shouldn't be null if ChartSealantTreatment exists
                    {
                        listToothValsOld = listChartOrigVals[1].FieldValue.Split(';').ToList();
                        listToothValsOld.RemoveAt(0);                        //Remove the toothchart type value
                    }
                    ScreenChartType chartType = ScreenChartType.C;
                    ProcessScreenChartHelper(sheet.PatNum, listToothVals, chartType, provNum, sheetNum, listToothValsOld);
                    break;
                }
            }
            //Process if the user wants to TP fluoride and/or assessment procedures and/or other procedures.
            foreach (SheetField field in sheet.SheetFields)
            {
                if (field.FieldType != SheetFieldType.CheckBox)
                {
                    continue;                    //Only care about check box types.
                }
                if (field.FieldName != "FluorideProc" && field.FieldName != "AssessmentProc" && !field.FieldName.StartsWith("Proc:"))
                {
                    continue;                    //Field name must be one of the two hard coded values, or a FieldName that starts with "Proc".
                }
                //Make other proc with provNum and patNum
                SheetField sheetFieldOrig = listProcOrigVals.FirstOrDefault(x => x.FieldName == field.FieldName && x.FieldType == SheetFieldType.CheckBox);
                if (sheetFieldOrig == null || sheetFieldOrig.FieldValue != "" || field.FieldValue != "X")
                {
                    //Either not found or field was previously checked (already charted proc) or field is not checked (do not chart).
                    continue;
                }
                string strProcCode = "";
                switch (field.FieldName)
                {
                case "FluorideProc":                        //Original value was blank, new value is "checked", make the D1206 (fluoride) proc.
                    strProcCode = "D1206";
                    break;

                case "AssessmentProc":                        //Original value was blank, new value is "checked", make the D0191 (assessment) proc.
                    strProcCode = "D0191";
                    break;

                default:                                        //Original value was blank, new value is "checked", make the proc.
                    strProcCode = field.FieldName.Substring(5); //Drop "Proc:" from FieldName.
                    break;
                }
                Procedure proc = Procedures.CreateProcForPatNum(sheet.PatNum, ProcedureCodes.GetCodeNum(strProcCode), "", "", ProcStat.C, provNum);
                if (proc != null)
                {
                    SecurityLogs.MakeLogEntry(Permissions.ProcEdit, sheet.PatNum, strProcCode + " " + Lans.g("Screens", "treatment planned during screening."));
                }
            }
        }
Beispiel #20
0
 ///<summary>Helper method so that we do not have to duplicate code.  The length of toothValues must match the length of chartOrigVals.</summary>
 private static void ProcessScreenChartHelper(long patNum, List <string> toothValues, ScreenChartType chartType, long provNum, long sheetNum
                                              , List <string> chartOrigVals)
 {
     //No need to check RemotingRole; no call to db.
     for (int i = 0; i < toothValues.Count; i++)       //toothValues is in the order from low to high tooth number in the chart
     {
         if (!toothValues[i].Contains("S"))            //No sealant, nothing to do.
         {
             continue;
         }
         //Logic to determine if the "S" changed surfaces or was erased between the time the toothchart was opened and when it was submitted.
         string[] newSurfaces  = toothValues[i].Split(',');
         string[] origSurfaces = chartOrigVals[i].Split(',');
         bool     isDiff       = false;
         for (int j = 0; j < origSurfaces.Length; j++)                                                                   //Both arrays have the same length unless the chart doesn't exist in the original.
         {
             if ((newSurfaces[j] == "S" && origSurfaces[j] != "S") || (newSurfaces[j] != "S" && origSurfaces[j] == "S")) //"S" changed surfaces or was removed.
             {
                 isDiff = true;
                 break;
             }
         }
         //If there is no difference don't make any duplicates.  We don't care if they changed a surface from N to PS for example, only S surfaces are important.
         if (!isDiff)
         {
             continue;                    //All the "S" surfaces are the same.
         }
         string surf     = "";
         int    toothNum = 0;
         bool   isMolar  = false;
         bool   isRight  = false;
         bool   isLing   = false;
         string tooth    = "";
         #region Parse ScreenChart FieldValues
         if (i <= 1)               //Top left quadrant of toothchart
         {
             toothNum = i + 2;
             isMolar  = true;
             isRight  = true;
             isLing   = true;
         }
         else if (i > 1 && i <= 3)             //Top middle-left quadrant of toothchart
         {
             toothNum = i + 2;
             isMolar  = false;
             isRight  = true;
             isLing   = true;
         }
         else if (i > 3 && i <= 5)             //Top middle-right quadrant of toothchart
         {
             toothNum = i + 8;
             isMolar  = false;
             isRight  = false;
             isLing   = true;
         }
         else if (i > 5 && i <= 7)             //Top right quadrant of toothchart
         {
             toothNum = i + 8;
             isMolar  = true;
             isRight  = false;
             isLing   = true;
         }
         else if (i > 7 && i <= 9)             //Lower right quadrant of toothchart
         {
             toothNum = i + 10;
             isMolar  = true;
             isRight  = false;
             isLing   = false;
         }
         else if (i > 9 && i <= 11)             //Lower middle-right quadrant of toothchart
         {
             toothNum = i + 10;
             isMolar  = false;
             isRight  = false;
             isLing   = false;
         }
         else if (i > 11 && i <= 13)             //Lower middle-left quadrant of toothchart
         {
             toothNum = i + 16;
             isMolar  = false;
             isRight  = true;
             isLing   = false;
         }
         else if (i > 13)               //Lower left quadrant of toothchart
         {
             toothNum = i + 16;
             isMolar  = true;
             isRight  = true;
             isLing   = false;
         }
         if (isMolar)
         {
             if (isRight)
             {
                 if (newSurfaces[0] == "S")
                 {
                     surf += "D";
                 }
                 if (newSurfaces[1] == "S")
                 {
                     surf += "M";
                 }
             }
             else                      //Is Left side
             {
                 if (newSurfaces[0] == "S")
                 {
                     surf += "M";
                 }
                 if (newSurfaces[1] == "S")
                 {
                     surf += "D";
                 }
             }
             if (isLing && newSurfaces[2] == "S")
             {
                 surf += "L";
             }
             if (!isLing && newSurfaces[2] == "S")
             {
                 surf += "B";
             }
         }
         else                  //Front teeth, only look at 3rd surface position in control as that's the only one the user can see.
         {
             if (newSurfaces[2] == "S")
             {
                 surf = "O";                      //NOTE: Not sure what surface to enter here... This is just a placeholder for now until we figure it out...
             }
         }
         if (toothNum != 0)
         {
             tooth = toothNum.ToString();
         }
         #endregion Parse Toothchart FieldValues
         surf = Tooth.SurfTidyForDisplay(surf, tooth);
         if (chartType == ScreenChartType.TP)               //Create TP'd sealant procs if they don't already exist for this patient.
         {
             if (Procedures.GetProcForPatByToothSurfStat(patNum, toothNum, surf, ProcStat.TP) != null)
             {
                 continue;
             }
             Procedure proc = Procedures.CreateProcForPatNum(patNum, ProcedureCodes.GetCodeNum("D1351"), surf, tooth, ProcStat.TP, provNum);
             if (proc != null)
             {
                 SecurityLogs.MakeLogEntry(Permissions.ProcEdit, patNum, "D1351 " + Lans.g("Screens", "treatment planned during screening with tooth")
                                           + " " + proc.ToothNum.ToString() + " " + Lans.g("Screens", "and surface") + " " + proc.Surf);
             }
         }
         else if (chartType == ScreenChartType.C)
         {
             Procedure proc = Procedures.GetProcForPatByToothSurfStat(patNum, toothNum, surf, ProcStat.TP);
             if (proc == null)                   //A TP procedure does not already exist.
             {
                 proc = Procedures.CreateProcForPatNum(patNum, ProcedureCodes.GetCodeNum("D1351"), surf, tooth, ProcStat.C, provNum);
             }
             else                      //TP proc already exists, set it complete.
             {
                 Procedure procOld = proc.Copy();
                 proc.ProcStatus = ProcStat.C;
                 proc.DateEntryC = DateTime.Now;
                 Procedures.Update(proc, procOld);
             }
             if (proc != null)
             {
                 SecurityLogs.MakeLogEntry(Permissions.ProcComplCreate, patNum, "D1351 " + Lans.g("Screens", "set complete during screening with tooth")
                                           + " " + proc.ToothNum.ToString() + " " + Lans.g("Screens", "and surface") + " " + proc.Surf);
             }
         }
     }
     if (chartType == ScreenChartType.C)
     {
         Recalls.Synch(patNum);
     }
 }
Beispiel #21
0
        ///<summary>Copies one fee schedule to one or more fee schedules.  fromClinicNum, fromProvNum, and toProvNum can be zero.  Set listClinicNumsTo to copy to multiple clinic overrides.  If this list is null or empty, clinicNum 0 will be used.</summary>
        public static void CopyFeeSchedule(FeeSched fromFeeSched, long fromClinicNum, long fromProvNum, FeeSched toFeeSched, List <long> listClinicNumsTo, long toProvNum)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                Meth.GetVoid(MethodBase.GetCurrentMethod(), fromFeeSched, fromClinicNum, fromProvNum, toFeeSched, listClinicNumsTo, toProvNum);
                return;
            }
            if (listClinicNumsTo == null)
            {
                listClinicNumsTo = new List <long>();
            }
            if (listClinicNumsTo.Count == 0)
            {
                listClinicNumsTo.Add(0);
            }
            //Store a local copy of the fees from the old FeeSched
            List <Fee> listFeeLocalCopy = Fees.GetListExact(toFeeSched.FeeSchedNum, listClinicNumsTo, toProvNum);

            //Delete all fees that exactly match setting in "To" combo selections.
            foreach (long clinicNum in listClinicNumsTo)
            {
                Fees.DeleteFees(toFeeSched.FeeSchedNum, clinicNum, toProvNum);
            }
            //Copy:
            List <Fee>    listNewFees = Fees.GetListExact(fromFeeSched.FeeSchedNum, fromClinicNum, fromProvNum);
            int           blockValue  = 0;
            int           blockMax    = (listNewFees.Count * listClinicNumsTo.Count);
            object        locker      = new object();
            List <Action> listActions = new List <Action>();

            foreach (long clinicNumTo in listClinicNumsTo)
            {
                listActions.Add(() => {
                    foreach (Fee fee in listNewFees)
                    {
                        bool isReplacementFee = false;
                        Fee newFee            = fee.Copy();
                        newFee.FeeNum         = 0;
                        newFee.ProvNum        = toProvNum;
                        newFee.ClinicNum      = clinicNumTo;
                        newFee.FeeSched       = toFeeSched.FeeSchedNum;
                        Fees.Insert(newFee);
                        //Check to see if this replaced an old fee with the same fee details
                        Fee oldFee = listFeeLocalCopy.Where(x => x.ProvNum == newFee.ProvNum)
                                     .Where(x => x.ClinicNum == newFee.ClinicNum)
                                     .Where(x => x.CodeNum == newFee.CodeNum)
                                     .Where(x => x.FeeSched == newFee.FeeSched)
                                     .FirstOrDefault();
                        if (oldFee != null)
                        {
                            isReplacementFee = true;
                        }
                        ProcedureCode procCode = ProcedureCodes.GetProcCode(fee.CodeNum);
                        string securityLogText = "Fee Schedule \"" + fromFeeSched.Description + "\" copied to Fee Schedule \"" + toFeeSched.Description + "\", ";
                        if (clinicNumTo != 0)
                        {
                            securityLogText += "To Clinic \"" + Clinics.GetDesc(clinicNumTo) + "\", ";
                        }
                        securityLogText += "Proc Code \"" + procCode.ProcCode + "\", Fee \"" + fee.Amount + "\", ";
                        if (isReplacementFee)
                        {
                            securityLogText += "Replacing Previous Fee \"" + oldFee.Amount + "\"";
                        }
                        SecurityLogs.MakeLogEntry(Permissions.FeeSchedEdit, 0, securityLogText);
                        FeeSchedEvent.Fire(ODEventType.FeeSched,
                                           new ProgressBarHelper(Lans.g("FormFeeSchedTools", "Copying fees, please wait") + "...", blockValue: blockValue, blockMax: blockMax,
                                                                 progressStyle: ProgBarStyle.Continuous));
                        lock (locker) {
                            blockValue++;
                        }
                    }
                });
            }
            //Research and testing will determine whether we can run this on multiple threads.
            ODThread.RunParallel(listActions, TimeSpan.FromMinutes(30), numThreads: 1);
        }
Beispiel #22
0
 ///<summary>A helper method to make a security log entry for deletion.  Because we have several patient field edit windows, this will allow us to change them all at once.</summary>
 public static void MakeDeleteLogEntry(PatField patField)
 {
     SecurityLogs.MakeLogEntry(Permissions.PatientFieldEdit, patField.PatNum, "Deleted patient field " + patField.FieldName + ".  Value before deletion: \"" + patField.FieldValue + "\"");
 }
Beispiel #23
0
        ///<summary>Modified Sync pattern for the OrthoChart.  We cannot use the standard Sync pattern because we have to perform logging when updating
        ///or deleting.</summary>
        public static void Sync(Patient patCur, List <OrthoChart> listNew, List <DisplayField> listOrthDisplayFields, DisplayField displayFieldSignature)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                Meth.GetVoid(MethodBase.GetCurrentMethod(), patCur, listNew, listOrthDisplayFields, displayFieldSignature);
                return;
            }
            List <OrthoChart> listDB = GetAllForPatient(patCur.PatNum);
            //Inserts, updates, or deletes database rows to match supplied list.
            //Adding items to lists changes the order of operation. All inserts are completed first, then updates, then deletes.
            List <OrthoChart> listIns      = new List <OrthoChart>();
            List <OrthoChart> listUpdNew   = new List <OrthoChart>();
            List <OrthoChart> listUpdDB    = new List <OrthoChart>();
            List <OrthoChart> listDel      = new List <OrthoChart>();
            List <string>     listColNames = new List <string>();

            //Remove fields from both lists that are not currently set to display.
            for (int i = 0; i < listOrthDisplayFields.Count; i++)
            {
                listColNames.Add(listOrthDisplayFields[i].Description);
            }
            for (int i = listDB.Count - 1; i >= 0; i--)
            {
                if (!listColNames.Contains(listDB[i].FieldName))
                {
                    listDB.RemoveAt(i);
                }
            }
            listNew = listNew.FindAll(x => listColNames.Contains(x.FieldName));
            listNew.Sort(OrthoCharts.SortDateField);
            listDB.Sort(OrthoCharts.SortDateField);
            int        idxNew = 0;
            int        idxDB  = 0;
            OrthoChart fieldNew;
            OrthoChart fieldDB;

            //Because both lists have been sorted using the same criteria, we can now walk each list to determine which list contians the next element.  The next element is determined by Primary Key.
            //If the New list contains the next item it will be inserted.  If the DB contains the next item, it will be deleted.  If both lists contain the next item, the item will be updated.
            while (idxNew < listNew.Count || idxDB < listDB.Count)
            {
                fieldNew = null;
                if (idxNew < listNew.Count)
                {
                    fieldNew = listNew[idxNew];
                }
                fieldDB = null;
                if (idxDB < listDB.Count)
                {
                    fieldDB = listDB[idxDB];
                }
                //begin compare
                if (fieldNew != null && fieldDB == null)             //listNew has more items, listDB does not.
                {
                    listIns.Add(fieldNew);
                    idxNew++;
                    continue;
                }
                else if (fieldNew == null && fieldDB != null)             //listDB has more items, listNew does not.
                {
                    listDel.Add(fieldDB);
                    idxDB++;
                    continue;
                }
                else if (fieldNew.DateService < fieldDB.DateService)               //newPK less than dbPK, newItem is 'next'
                {
                    listIns.Add(fieldNew);
                    idxNew++;
                    continue;
                }
                else if (fieldNew.DateService > fieldDB.DateService)               //dbPK less than newPK, dbItem is 'next'
                {
                    listDel.Add(fieldDB);
                    idxDB++;
                    continue;
                }
                else if (fieldNew.FieldName.CompareTo(fieldDB.FieldName) < 0)               //New Fieldname Comes First
                {
                    listIns.Add(fieldNew);
                    idxNew++;
                    continue;
                }
                else if (fieldNew.FieldName.CompareTo(fieldDB.FieldName) > 0)               //DB Fieldname Comes First
                {
                    listDel.Add(fieldDB);
                    idxDB++;
                    continue;
                }
                //Both lists contain the 'next' item, update required
                listUpdNew.Add(fieldNew);
                listUpdDB.Add(fieldDB);
                idxNew++;
                idxDB++;
            }
            //Commit changes to DB
            for (int i = 0; i < listIns.Count; i++)
            {
                if (listIns[i].FieldValue == "")               //do not insert new blank values. This happens when fields from today are not used.
                {
                    continue;
                }
                listIns[i].UserNum = Security.CurUser.UserNum;
                Insert(listIns[i]);
            }
            for (int i = 0; i < listUpdNew.Count; i++)
            {
                if (listUpdDB[i].FieldValue == listUpdNew[i].FieldValue)
                {
                    continue;                       //values equal. do not update/create log entry.
                }
                if (listUpdNew[i].FieldValue != "") //Actually update rows that have a new value.
                {
                    Update(listUpdNew[i], listUpdDB[i]);
                }
                else                  //instead of updating to a blank value, we delete the row from the DB.
                {
                    listDel.Add(listUpdDB[i]);
                }
                #region security log entry
                string logText = Lans.g("OrthoCharts", "Ortho chart field edited.  Field date") + ": " + listUpdNew[i].DateService.ToShortDateString() + "  "
                                 + Lans.g("OrthoCharts", "Field name") + ": " + listUpdNew[i].FieldName + "\r\n";
                //Do not log the Base64 information into the audit trail if this is a signature column, log some short descriptive text instead.
                if (displayFieldSignature != null && listUpdNew[i].FieldName == displayFieldSignature.Description)             //This is the signature box
                {
                    if (listUpdDB[i].FieldValue != "" && listUpdNew[i].FieldValue != "")
                    {
                        logText += Lans.g("OrthoCharts", "Signature modified.") + " ";
                    }
                    else if (listUpdDB[i].FieldValue != "" && listUpdNew[i].FieldValue == "")
                    {
                        logText += Lans.g("OrthoCharts", "Signature deleted.") + " ";
                    }
                }
                else                  //Not a signature
                {
                    logText += Lans.g("OrthoCharts", "Old value") + ": \"" + listUpdDB[i].FieldValue + "\"  "
                               + Lans.g("OrthoCharts", "New value") + ": \"" + listUpdNew[i].FieldValue + "\" ";
                }
                logText += listUpdDB[i].DateService.ToString("yyyyMMdd");              //This date stamp must be the last 8 characters for new OrthoEdit audit trail entries.
                SecurityLogs.MakeLogEntry(Permissions.OrthoChartEditFull, patCur.PatNum, logText);
                #endregion
            }
            for (int i = 0; i < listDel.Count; i++)       //All logging should have been performed above in the "Update block"
            {
                Delete(listDel[i].OrthoChartNum);
            }
        }
Beispiel #24
0
 ///<summary>A helper method to make a security log entry for an edit.  Because we have several patient field edit windows, this will allow us to change them all at once.</summary>
 public static void MakeEditLogEntry(PatField patFieldOld, PatField patFieldCur)
 {
     SecurityLogs.MakeLogEntry(Permissions.PatientFieldEdit, patFieldCur.PatNum
                               , "Edited patient field " + patFieldCur.FieldName + "\r\n"
                               + "Old value" + ": \"" + patFieldOld.FieldValue + "\"  New value: \"" + patFieldCur.FieldValue + "\"");
 }
        ///<summary>Called by local practice db to query HQ for EService setup info. Must remain very lite and versionless. Will be used by signup portal.
        ///If HasClinics==true then any SignupOut.EServices entries where ClinicNum==0 are invalid and should be ignored.
        ///If HasClinics==false then SignupOut.EServices should only pay attention items where ClinicNum==0.
        ///This list is kept completely unfiltered by ClinicNum for forward compatibility reasons.
        ///The ClinicNum 0 items are always used by the Signup portal to determine default signup preferences.
        ///However, these items are only used for validation and billing in the case where HasClinics==true.</summary>
        public static EServiceSetup.SignupOut GetEServiceSetupFull(SignupPortalPermission permission, bool isSwitchClinicPref = false)
        {
            //Clinics will be stored in this order at HQ to allow signup portal to display them in proper order.
            List <Clinic> clinics = Clinics.GetDeepCopy().OrderBy(x => x.ItemOrder).ToList();

            if (PrefC.GetBool(PrefName.ClinicListIsAlphabetical))
            {
                clinics = clinics.OrderBy(x => x.Abbr).ToList();
            }
#if DEBUG
            bool isMockChanged = false;
            if (WebServiceMainHQProxy.MockWebServiceMainHQ == null)
            {
                WebServiceMainHQProxy.MockWebServiceMainHQ = new WebServiceMainHQMockDemo();
                isMockChanged = true;
            }
#endif
            EServiceSetup.SignupOut signupOut = ReadXml <EServiceSetup.SignupOut>
                                                (
                WebSerializer.DeserializePrimitiveOrThrow <string>
                (
                    GetWebServiceMainHQInstance().EServiceSetup
                    (
                        CreateWebServiceHQPayload
                        (
                            WriteXml(new EServiceSetup.SignupIn()
            {
                MethodNameInt = (int)EServiceSetup.SetupMethod.GetSignupOutFull,
                HasClinics    = PrefC.HasClinicsEnabled,
                //ClinicNum is not currently used as input.
                ClinicNum                 = 0,
                ProgramVersionStr         = PrefC.GetString(PrefName.ProgramVersion),
                SignupPortalPermissionInt = (int)permission,
                Clinics = clinics
                          .Select(x => new EServiceSetup.SignupIn.ClinicLiteIn()
                {
                    ClinicNum   = x.ClinicNum,
                    ClinicTitle = x.Abbr,
                    IsHidden    = x.IsHidden,
                }).ToList(),
                IsSwitchClinicPref = isSwitchClinicPref,
            }), eServiceCode.Undefined
                        )
                    )
                )
                                                );
#if DEBUG
            if (isMockChanged)
            {
                WebServiceMainHQProxy.MockWebServiceMainHQ = null;
            }
#endif
            //We just got the latest sync info from HQ so update the local db to reflect what HQ says is true.
            #region Reconcile Phones
            List <SmsPhone> listPhonesHQ = signupOut.Phones.Select(x => new SmsPhone()
            {
                ClinicNum        = x.ClinicNum,
                CountryCode      = x.CountryCode,
                DateTimeActive   = x.DateTimeActive,
                DateTimeInactive = x.DateTimeInactive,
                InactiveCode     = x.InactiveCode,
                PhoneNumber      = x.PhoneNumber,
            }).ToList();
            SmsPhones.UpdateOrInsertFromList(listPhonesHQ);
            #endregion
            #region Reconcile practice and clinics
            List <EServiceSetup.SignupOut.SignupOutSms> smsSignups = GetSignups <EServiceSetup.SignupOut.SignupOutSms>(signupOut, eServiceCode.IntegratedTexting);
            bool isCacheInvalid = false;
            bool isSmsEnabled   = false;
            if (PrefC.HasClinicsEnabled)              //Clinics are ON so loop through all clinics and reconcile with HQ.
            {
                List <Clinic> listClinicsAll = Clinics.GetDeepCopy();
                foreach (Clinic clinicDb in listClinicsAll)
                {
                    WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutSms clinicSignup =
                        smsSignups.FirstOrDefault(x => x.ClinicNum == clinicDb.ClinicNum) ?? new WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutSms()
                    {
                        //Not found so turn it off.
                        SmsContractDate = DateTime.MinValue,
                        MonthlySmsLimit = 0,
                        IsEnabled       = false,
                    };
                    Clinic clinicNew = clinicDb.Copy();
                    clinicNew.SmsContractDate = clinicSignup.SmsContractDate;
                    clinicNew.SmsMonthlyLimit = clinicSignup.MonthlySmsLimit;
                    isCacheInvalid           |= Clinics.Update(clinicNew, clinicDb);
                    isSmsEnabled |= clinicSignup.IsEnabled;
                }
            }
            else               //Clinics are off so ClinicNum 0 is the practice clinic.
            {
                WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutSms practiceSignup =
                    smsSignups.FirstOrDefault(x => x.ClinicNum == 0) ?? new WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutSms()
                {
                    //Not found so turn it off.
                    SmsContractDate = DateTime.MinValue,
                    MonthlySmsLimit = 0,
                    IsEnabled       = false,
                };
                isCacheInvalid
                    |= Prefs.UpdateDateT(PrefName.SmsContractDate, practiceSignup.SmsContractDate)
                       | Prefs.UpdateLong(PrefName.TextingDefaultClinicNum, 0)
                       | Prefs.UpdateDouble(PrefName.SmsMonthlyLimit, practiceSignup.MonthlySmsLimit);
                isSmsEnabled |= practiceSignup.IsEnabled;
            }
            #endregion
            #region Reconcile CallFire
            //Turn off CallFire if SMS has been activated.
            //This only happens the first time SMS is turned on and CallFire is still activated.
            if (isSmsEnabled && Programs.IsEnabled(ProgramName.CallFire))
            {
                Program callfire = Programs.GetCur(ProgramName.CallFire);
                if (callfire != null)
                {
                    callfire.Enabled = false;
                    Programs.Update(callfire);
                    Signalods.Insert(new Signalod()
                    {
                        IType = InvalidType.Providers
                    });
                    signupOut.Prompts.Add("Call Fire has been disabled. Cancel Integrated Texting and access program properties to retain Call Fire.");
                }
            }
            #endregion
            #region eConfirmations
            if (Prefs.UpdateBool(PrefName.ApptConfirmAutoSignedUp, IsEServiceActive(signupOut, eServiceCode.ConfirmationRequest)))
            {
                //HQ does not match the local pref. Make it match with HQ.
                isCacheInvalid = true;
                SecurityLogs.MakeLogEntry(Permissions.Setup, 0, "Automated appointment eConfirmations automatically changed by HQ.  Local pref set to "
                                          + IsEServiceActive(signupOut, eServiceCode.ConfirmationRequest).ToString() + ".");
            }
            #endregion
            if (isCacheInvalid)              //Something changed in the db. Alert other workstations and change this workstation immediately.
            {
                Signalods.Insert(new Signalod()
                {
                    IType = InvalidType.Prefs
                });
                Prefs.RefreshCache();
                Signalods.Insert(new Signalod()
                {
                    IType = InvalidType.Providers
                });
                Providers.RefreshCache();
                Clinics.RefreshCache();
            }
            return(signupOut);
        }
Beispiel #26
0
        ///<summary>Gets the data necessary to load the Family Module.</summary>
        public static LoadData GetLoadData(long patNum, bool doCreateSecLog)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                return(Meth.GetObject <LoadData>(MethodBase.GetCurrentMethod(), patNum, doCreateSecLog));
            }
            LoadData data = new LoadData();

            data.Fam          = Patients.GetFamily(patNum);
            data.Pat          = data.Fam.GetPatient(patNum);
            data.ListPatPlans = PatPlans.Refresh(patNum);
            if (!PatPlans.IsPatPlanListValid(data.ListPatPlans))             //PatPlans had invalid references and need to be refreshed.
            {
                data.ListPatPlans = PatPlans.Refresh(patNum);
            }
            data.PatNote               = PatientNotes.Refresh(patNum, data.Pat.Guarantor);
            data.ListInsSubs           = InsSubs.RefreshForFam(data.Fam);
            data.ListInsPlans          = InsPlans.RefreshForSubList(data.ListInsSubs);
            data.ListBenefits          = Benefits.Refresh(data.ListPatPlans, data.ListInsSubs);
            data.ListRecalls           = Recalls.GetList(data.Fam.ListPats.Select(x => x.PatNum).ToList());
            data.ArrPatFields          = PatFields.Refresh(patNum);
            data.SuperFamilyMembers    = Patients.GetBySuperFamily(data.Pat.SuperFamily);
            data.SuperFamilyGuarantors = Patients.GetSuperFamilyGuarantors(data.Pat.SuperFamily);
            data.DictCloneSpecialities = Patients.GetClonesAndSpecialties(patNum);
            data.PatPict               = Documents.GetPatPictFromDb(patNum);
            data.HasPatPict            = (data.PatPict == null ? YN.No : YN.Yes);
            List <DisplayField> listDisplayFields = DisplayFields.GetForCategory(DisplayFieldCategory.PatientInformation);

            foreach (DisplayField field in listDisplayFields)
            {
                switch (field.InternalName)
                {
                case "Guardians":
                    data.ListGuardians = Guardians.Refresh(patNum);
                    break;

                case "Pat Restrictions":
                    data.ListPatRestricts = PatRestrictions.GetAllForPat(patNum);
                    break;

                case "Payor Types":
                    data.PayorTypeDesc = PayorTypes.GetCurrentDescription(patNum);
                    break;

                case "PatFields":
                    data.ListPatFieldDefLinks = FieldDefLinks.GetForLocation(FieldLocations.Family);
                    break;

                case "References":
                    data.ListCustRefEntries = CustRefEntries.GetEntryListForCustomer(patNum);
                    break;

                case "Referrals":
                    data.ListRefAttaches = RefAttaches.Refresh(patNum);
                    break;

                case "ResponsParty":
                    if (data.Pat.ResponsParty != 0)
                    {
                        data.ResponsibleParty = Patients.GetLim(data.Pat.ResponsParty);
                    }
                    break;
                }
            }
            if (data.Pat.DiscountPlanNum != 0)
            {
                data.DiscountPlan = DiscountPlans.GetPlan(data.Pat.DiscountPlanNum);
            }
            data.ListMergeLinks = PatientLinks.GetLinks(data.Fam.ListPats.Select(x => x.PatNum).ToList(), PatientLinkType.Merge);
            if (doCreateSecLog)
            {
                SecurityLogs.MakeLogEntry(Permissions.FamilyModule, patNum, "");
            }
            return(data);
        }
Beispiel #27
0
        ///<summary>Takes a screening sheet that is associated to a patient and processes any corresponding ScreenCharts found.
        ///Processing will create treatment planned or completed procedures for the patient.
        ///Supply the sheet and then a bitwise enum of screen chart types to digest.
        ///procOrigVals MUST be two items long, nulls are allowed, the first represents the fluoride field, second is assessment field.</summary>
        public static void ProcessScreenChart(Sheet sheet, ScreenChartType chartTypes, long provNum, long sheetNum, List <SheetField> listChartOrigVals
                                              , List <SheetField> listProcOrigVals)
        {
            //No need to check RemotingRole; no call to db.
            if (sheet == null || sheet.PatNum == 0)
            {
                return;                //An invalid screening sheet was passed in.
            }
            List <string> listToothVals    = new List <string>();
            List <string> listToothValsOld = new List <string>();

            //Process treatment planned sealants.
            foreach (SheetField field in sheet.SheetFields)             //Go through the supplied sheet's fields and find the field.
            {
                if (chartTypes.HasFlag(ScreenChartType.TP) && field.FieldType == SheetFieldType.ScreenChart && field.FieldName == "ChartSealantTreatment")
                {
                    listToothVals = field.FieldValue.Split(';').ToList();
                    if (listToothVals[0] == "1")         //Primary tooth chart
                    {
                        continue;                        //Skip primary tooth charts because we do not need to create any TP procedures for them.
                    }
                    listToothVals.RemoveAt(0);           //Remove the toothchart type value
                    if (listChartOrigVals[0] != null)    //Shouldn't be null if ChartSealantTreatment exists
                    {
                        listToothValsOld = listChartOrigVals[0].FieldValue.Split(';').ToList();
                        listToothValsOld.RemoveAt(0);                        //Remove the toothchart type value
                    }
                    ScreenChartType chartType = ScreenChartType.TP;
                    ProcessScreenChartHelper(sheet.PatNum, listToothVals, chartType, provNum, sheetNum, listToothValsOld);
                    break;
                }
            }
            listToothVals = new List <string>();            //Clear out the tooth values for the next tooth chart.
            //Process completed sealants.
            foreach (SheetField field in sheet.SheetFields) //Go through the supplied sheet's fields and find the field.
            {
                if (chartTypes.HasFlag(ScreenChartType.C) && field.FieldType == SheetFieldType.ScreenChart && field.FieldName == "ChartSealantComplete")
                {
                    listToothVals = field.FieldValue.Split(';').ToList();
                    if (listToothVals[0] == "1")         //Primary tooth chart
                    {
                        continue;                        //Skip primary tooth charts because we do not need to create any TP procedures for them.
                    }
                    listToothVals.RemoveAt(0);           //Remove the toothchart type value
                    if (listChartOrigVals[1] != null)    //Shouldn't be null if ChartSealantTreatment exists
                    {
                        listToothValsOld = listChartOrigVals[1].FieldValue.Split(';').ToList();
                        listToothValsOld.RemoveAt(0);                        //Remove the toothchart type value
                    }
                    ScreenChartType chartType = ScreenChartType.C;
                    ProcessScreenChartHelper(sheet.PatNum, listToothVals, chartType, provNum, sheetNum, listToothValsOld);
                    break;
                }
            }
            //Process if the user wants to TP fluoride and / or assessment procedures.
            foreach (SheetField field in sheet.SheetFields)
            {
                if (field.FieldType != SheetFieldType.CheckBox)
                {
                    continue;                    //Only care about check box types.
                }
                if (field.FieldName != "FluorideProc" && field.FieldName != "AssessmentProc")
                {
                    continue;                    //Field name must be one of the two hard coded values.
                }
                //Make D1206 proc with provNum and patNum
                if (field.FieldName == "FluorideProc" && listProcOrigVals[1] != null && listProcOrigVals[1].FieldValue == "" && field.FieldValue == "X")
                {
                    //Original value was blank, new value is "checked", make the D1206 (fluoride) proc.
                    Procedure proc = Procedures.CreateProcForPat(sheet.PatNum, ProcedureCodes.GetCodeNum("D1206"), "", "", ProcStat.C, provNum);
                    if (proc != null)
                    {
                        SecurityLogs.MakeLogEntry(Permissions.ProcEdit, sheet.PatNum, "D1206 " + Lans.g("Screens", "treatment planned during screening"));
                    }
                }
                //Make D0191 proc with provNum and patNum
                if (field.FieldName == "AssessmentProc" && listProcOrigVals[0] != null && listProcOrigVals[0].FieldValue == "" && field.FieldValue == "X")
                {
                    //Original value was blank, new value is "checked", make the D0191 (assessment) proc.
                    Procedure proc = Procedures.CreateProcForPat(sheet.PatNum, ProcedureCodes.GetCodeNum("D0191"), "", "", ProcStat.C, provNum);
                    if (proc != null)
                    {
                        SecurityLogs.MakeLogEntry(Permissions.ProcEdit, sheet.PatNum, "D0191 " + Lans.g("Screens", "treatment planned during screening."));
                    }
                }
            }
        }