示例#1
0
        public static bool IsTransworldEnabled(long clinicNum)
        {
            //No need to check RemotingRole;no call to db.
            Program progCur = Programs.GetCur(ProgramName.Transworld);

            if (progCur == null || !progCur.Enabled)
            {
                return(false);
            }
            Dictionary <long, List <ProgramProperty> > dictAllProps = ProgramProperties.GetForProgram(progCur.ProgramNum)
                                                                      .GroupBy(x => x.ClinicNum)
                                                                      .ToDictionary(x => x.Key, x => x.ToList());

            if (dictAllProps.Count == 0)
            {
                return(false);
            }
            List <long> listDisabledClinicNums = new List <long>();

            if (!PrefC.HasClinicsEnabled)
            {
                return(TsiTransLogs.ValidateClinicSftpDetails(dictAllProps[0], false));
            }
            List <Clinic> listAllClinics = Clinics.GetDeepCopy();

            listDisabledClinicNums.AddRange(dictAllProps.Where(x => !TsiTransLogs.ValidateClinicSftpDetails(x.Value, false)).Select(x => x.Key));
            listDisabledClinicNums.AddRange(listAllClinics
                                            .FindAll(x => x.IsHidden || (listDisabledClinicNums.Contains(0) && !dictAllProps.ContainsKey(x.ClinicNum)))//if no props for HQ, skip other clinics without props
                                            .Select(x => x.ClinicNum)
                                            );
            return(!listDisabledClinicNums.Contains(clinicNum));
        }
示例#2
0
        ///<summary>Creates and inserts a discount adjustment for the passed in procedure.  Used by prepayment tool.</summary>
        public static void CreateDiscountAdjustment(Procedure proc, double discountPercentage, long adjType)
        {
            Adjustment adj = new Adjustment {
                DateEntry = DateTime.Today,
                AdjDate   = DateTime.Today,
                ProcDate  = proc.ProcDate,
                ProvNum   = proc.ProvNum,
                ProcNum   = proc.ProcNum,
                ClinicNum = proc.ClinicNum,
                PatNum    = proc.PatNum,
                AdjType   = adjType,
                AdjAmt    = -(proc.ProcFee * discountPercentage)         //Flip the sign to make it a negative adjustment.
            };

            Adjustments.Insert(adj);
            TsiTransLogs.CheckAndInsertLogsIfAdjTypeExcluded(adj);
        }
示例#3
0
        ///<summary>Creates a new discount adjustment for the given procedure.</summary>
        public static void CreateAdjustmentForDiscount(Procedure procedure)
        {
            //No need to check RemotingRole; no call to db.
            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   = PrefC.GetLong(PrefName.TreatPlanDiscountAdjustmentType);
            AdjustmentCur.ClinicNum = procedure.ClinicNum;
            AdjustmentCur.AdjAmt    = -procedure.Discount;       //Discount must be negative here.
            AdjustmentCur.ProcNum   = procedure.ProcNum;
            Insert(AdjustmentCur);
            TsiTransLogs.CheckAndInsertLogsIfAdjTypeExcluded(AdjustmentCur);
        }
示例#4
0
        public static void CreateSalesTaxRefundIfNeeded(Procedure procedure, Adjustment adjustmentExistingLocked)
        {
            Adjustment adjustmentSalesTaxReturn = new Adjustment();

            adjustmentSalesTaxReturn.DateEntry = DateTime.Today;
            adjustmentSalesTaxReturn.AdjDate   = DateTime.Today;
            adjustmentSalesTaxReturn.ProcDate  = procedure.ProcDate;
            adjustmentSalesTaxReturn.ProvNum   = procedure.ProvNum;
            adjustmentSalesTaxReturn.PatNum    = procedure.PatNum;
            adjustmentSalesTaxReturn.AdjType   = AvaTax.SalesTaxReturnAdjType;
            adjustmentSalesTaxReturn.ClinicNum = procedure.ClinicNum;
            adjustmentSalesTaxReturn.ProcNum   = procedure.ProcNum;
            if (AvaTax.DoCreateReturnAdjustment(procedure, adjustmentExistingLocked, adjustmentSalesTaxReturn))
            {
                Insert(adjustmentSalesTaxReturn);
                TsiTransLogs.CheckAndInsertLogsIfAdjTypeExcluded(adjustmentSalesTaxReturn);
            }
        }
示例#5
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"));
        }
示例#6
0
        ///<summary>Sends an SFTP message to TSI to suspend the account for the guarantor passed in.  Returns empty string if successful.
        ///Returns a translated error message that should be displayed to the user if anything goes wrong.</summary>
        public static string SuspendGuar(Patient guar)
        {
            PatAging patAging = Patients.GetAgingListFromGuarNums(new List <long>()
            {
                guar.PatNum
            }).FirstOrDefault();

            if (patAging == null)           //this would only happen if the patient was not in the db??, just in case
            {
                return(Lans.g("TsiTransLogs", "An error occurred when trying to send a suspend message to TSI."));
            }
            long    clinicNum = (PrefC.HasClinicsEnabled?guar.ClinicNum:0);
            Program prog      = Programs.GetCur(ProgramName.Transworld);

            if (prog == null)           //shouldn't be possible, the program link should always exist, just in case
            {
                return(Lans.g("TsiTransLogs", "The Transworld program link does not exist.  Contact support."));
            }
            Dictionary <long, List <ProgramProperty> > dictAllProps = ProgramProperties.GetForProgram(prog.ProgramNum)
                                                                      .GroupBy(x => x.ClinicNum)
                                                                      .ToDictionary(x => x.Key, x => x.ToList());

            if (dictAllProps.Count == 0)           //shouldn't be possible, there should always be a set of props for ClinicNum 0 even if disabled, just in case
            {
                return(Lans.g("TsiTransLogs", "The Transworld program link is not setup properly."));
            }
            if (PrefC.HasClinicsEnabled && !dictAllProps.ContainsKey(clinicNum) && dictAllProps.ContainsKey(0))
            {
                clinicNum = 0;
            }
            string clinicDesc = clinicNum == 0?"Headquarters":Clinics.GetDesc(clinicNum);

            if (!dictAllProps.ContainsKey(clinicNum) ||
                !ValidateClinicSftpDetails(dictAllProps[clinicNum], true))                    //the props should be valid, but this will test the connection using the props
            {
                return(Lans.g("TsiTransLogs", "The Transworld program link is not enabled") + " "
                       + (PrefC.HasClinicsEnabled?(Lans.g("TsiTransLogs", "for the guarantor's clinic") + ", " + clinicDesc + ", "):"")
                       + Lans.g("TsiTransLogs", "or is not setup properly."));
            }
            List <ProgramProperty> listProps = dictAllProps[clinicNum];
            long newBillType = PrefC.GetLong(PrefName.TransworldPaidInFullBillingType);

            if (newBillType == 0 || Defs.GetDef(DefCat.BillingTypes, newBillType) == null)
            {
                return(Lans.g("TsiTransLogs", "The default paid in full billing type is not set.  An automated suspend message cannot be sent until the "
                              + "default paid in full billing type is set in the Transworld program link")
                       + (PrefC.HasClinicsEnabled?(" " + Lans.g("TsiTransLogs", "for the guarantor's clinic") + ", " + clinicDesc):"") + ".");
            }
            string clientId = "";

            if (patAging.ListTsiLogs.Count > 0)
            {
                clientId = patAging.ListTsiLogs[0].ClientId;
            }
            if (string.IsNullOrEmpty(clientId))
            {
                clientId = listProps.Find(x => x.PropertyDesc == "ClientIdAccelerator")?.PropertyValue;
            }
            if (string.IsNullOrEmpty(clientId))
            {
                clientId = listProps.Find(x => x.PropertyDesc == "ClientIdCollection")?.PropertyValue;
            }
            if (string.IsNullOrEmpty(clientId))
            {
                return(Lans.g("TsiTransLogs", "There is no client ID in the Transworld program link")
                       + (PrefC.HasClinicsEnabled?(" " + Lans.g("TsiTransLogs", "for the guarantor's clinic") + ", " + clinicDesc):"") + ".");
            }
            string sftpAddress = listProps.Find(x => x.PropertyDesc == "SftpServerAddress")?.PropertyValue ?? "";
            int    sftpPort;

            if (!int.TryParse(listProps.Find(x => x.PropertyDesc == "SftpServerPort")?.PropertyValue ?? "", out sftpPort))
            {
                sftpPort = 22;              //default to port 22
            }
            string userName     = listProps.Find(x => x.PropertyDesc == "SftpUsername")?.PropertyValue ?? "";
            string userPassword = listProps.Find(x => x.PropertyDesc == "SftpPassword")?.PropertyValue ?? "";

            if (new[] { sftpAddress, userName, userPassword }.Any(x => string.IsNullOrEmpty(x)))
            {
                return(Lans.g("TsiTransLogs", "The SFTP address, username, or password for the Transworld program link") + " "
                       + (PrefC.HasClinicsEnabled?(Lans.g("TsiTransLogs", "for the guarantor's clinic") + ", " + clinicDesc + ", "):"") + Lans.g("TsiTransLogs", "is blank."));
            }
            string msg = TsiMsgConstructor.GenerateUpdate(patAging.PatNum, clientId, TsiTransType.SS, 0.00, patAging.AmountDue);

            try {
                byte[]          fileContents = Encoding.ASCII.GetBytes(TsiMsgConstructor.GetUpdateFileHeader() + "\r\n" + msg);
                TaskStateUpload state        = new Sftp.Upload(sftpAddress, userName, userPassword, sftpPort)
                {
                    Folder        = "/xfer/incoming",
                    FileName      = "TsiUpdates_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".txt",
                    FileContent   = fileContents,
                    HasExceptions = true
                };
                state.Execute(false);
            }
            catch (Exception ex) {
                return(Lans.g("TsiTransLogs", "There was an error sending the update message to Transworld")
                       + (PrefC.HasClinicsEnabled?(" " + Lans.g("TsiTransLogs", "using the program properties for the guarantor's clinic") + ", " + clinicDesc):"") + ".\r\n"
                       + ex.Message);
            }
            //Upload was successful
            TsiTransLog log = new TsiTransLog()
            {
                PatNum    = patAging.PatNum,
                UserNum   = Security.CurUser.UserNum,
                TransType = TsiTransType.SS,
                //TransDateTime=DateTime.Now,//set on insert, not editable by user
                //DemandType=TsiDemandType.Accelerator,//only valid for placement msgs
                //ServiceCode=TsiServiceCode.Diplomatic,//only valid for placement msgs
                ClientId       = clientId,
                TransAmt       = 0.00,
                AccountBalance = patAging.AmountDue,
                FKeyType       = TsiFKeyType.None, //only used for account trans updates
                FKey           = 0,                //only used for account trans updates
                RawMsgText     = msg,
                ClinicNum      = clinicNum
                                 //,TransJson=""//only valid for placement msgs
            };

            TsiTransLogs.Insert(log);
            //update family billing type to the paid in full billing type pref
            Patients.UpdateFamilyBillingType(newBillType, patAging.PatNum);
            return("");
        }
示例#7
0
 ///<summary>(HQ Only) Automatically creates or updates a sales tax adjustment for the passted in procedure. If an adjustment is passed in, we go
 ///ahead and update that adjustment, otherwise we check if there is already a sales tax adjustment for the given procedure and if not, we create
 ///a new one. Pass in false to doCalcTax if we have already called the AvaTax API to get the tax estimate recently to avoid redundant calls
 ///(currently only pre-payments uses this flag).
 ///isRepeatCharge indicates if the adjustment is being inserted by the repeat charge tool, currently only used to supress error messages
 ///in the Avatax API.</summary>
 public static void CreateOrUpdateSalesTaxIfNeeded(Procedure procedure, Adjustment salesTaxAdj = null, bool doCalcTax = true, bool isRepeatCharge = false)
 {
     if (!AvaTax.DoSendProcToAvalara(procedure, isRepeatCharge))             //tests isHQ
     {
         return;
     }
     //Check for middle tier as crud is called below
     if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
     {
         Meth.GetVoid(MethodBase.GetCurrentMethod(), procedure, salesTaxAdj, doCalcTax, isRepeatCharge);
         return;
     }
     if (salesTaxAdj == null)
     {
         salesTaxAdj = Adjustments.GetSalesTaxForProc(procedure.ProcNum);
     }
     //If we didn't find any existing adjustments to modify, create an adjustment instead
     if (salesTaxAdj == null)
     {
         salesTaxAdj           = new Adjustment();
         salesTaxAdj.DateEntry = DateTime.Today;
         salesTaxAdj.AdjDate   = procedure.ProcDate;
         salesTaxAdj.ProcDate  = procedure.ProcDate;
         salesTaxAdj.ProvNum   = procedure.ProvNum;
         salesTaxAdj.PatNum    = procedure.PatNum;
         salesTaxAdj.AdjType   = AvaTax.SalesTaxAdjType;
         salesTaxAdj.ClinicNum = procedure.ClinicNum;
         salesTaxAdj.ProcNum   = procedure.ProcNum;
     }
     //if the sales tax adjustment is locked, create a sales tax refund adjustment instead
     if (procedure.ProcDate <= AvaTax.TaxLockDate)
     {
         CreateSalesTaxRefundIfNeeded(procedure, salesTaxAdj);
         return;
     }
     if (!doCalcTax)              //Should only ever happen for pre-payments, where we've already called the api to get the tax amount
     {
         salesTaxAdj.AdjAmt = procedure.TaxAmt;
         Insert(salesTaxAdj);
     }
     else if (AvaTax.DidUpdateAdjustment(procedure, salesTaxAdj))
     {
         string note = DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + ": Tax amount changed from $" + procedure.TaxAmt.ToString("f2") + " to $" + salesTaxAdj.AdjAmt.ToString("f2");
         if (!(procedure.TaxAmt - salesTaxAdj.AdjAmt).IsZero())
         {
             procedure.TaxAmt = salesTaxAdj.AdjAmt;
             Crud.ProcedureCrud.Update(procedure);
         }
         if (salesTaxAdj.AdjNum == 0)
         {
             //The only way to get salesTaxAdj.AdjAmt=0 when AvaTax.DidUpdateAdjustment() returns true is if there was an error.
             if (isRepeatCharge && salesTaxAdj.AdjAmt == 0)                   //this is an error; we would normally not save a new adjustment with amt $0
             {
                 throw new ODException("Encountered an error communicating with AvaTax.  Skip for repeating charges only.  " + salesTaxAdj.AdjNote);
             }
             Insert(salesTaxAdj); //This could be an error or a new adjustment/repeating charge, either way we want to insert
         }
         else                     //updating an existing adjustment. We don't need to check isRepeatCharge because of
         {
             if (!string.IsNullOrWhiteSpace(salesTaxAdj.AdjNote))
             {
                 salesTaxAdj.AdjNote += Environment.NewLine;
             }
             salesTaxAdj.AdjNote += note;                   //If we are updating this adjustment, leave a note indicating what changed
             Update(salesTaxAdj);
         }
     }
     TsiTransLogs.CheckAndInsertLogsIfAdjTypeExcluded(salesTaxAdj);
 }