///<summary>Sends the passed in attachments to ClaimConnect.  Will set the attachment id to the claim if needed.</summary>
 private void AddAttachments(List <ClaimConnect.ImageAttachment> listAttachments)
 {
     if (string.IsNullOrWhiteSpace(_claimCur.AttachmentID))
     {
         //If an attachment has not already been created, create one.
         string attachmentId = ClaimConnect.CreateAttachment(listAttachments, textNarrative.Text, _claimCur);
         //Update claim if attachmentID was set. Must happen here so that the validation will consider the new attachmentID.
         _claimCur.AttachmentID = attachmentId;
         //Set the claims attached flag to 'Misc' so that the attachmentID will write to the PWK segment
         //when the claim is generated as an 837.
         if (string.IsNullOrEmpty(_claimCur.AttachedFlags))
         {
             _claimCur.AttachedFlags = "Misc";
         }
         else                  //Comma delimited
         {
             _claimCur.AttachedFlags = ",Misc";
         }
     }
     else              //An attachment already exists for this claim.
     {
         ClaimConnect.AddAttachment(_claimCur, listAttachments);
     }
     Claims.Update(_claimCur);
 }
        ///<summary>Wipes out the existing attachmentID, makes a securitylog for the old ID, and clears the 'Misc' attached flag on the claim.
        ///This must be done when a non-DXC attachmentID has been detected so that claim validation will work as expected.</summary>
        private void ClearAttachmentID()
        {
            //Blindly set the claim's attached flags back to 'Mail' so that, deep down in the 837 text generation logic, the PWK segment will not be written
            //which will allow DentalXChange to validate the claim as if it is brand new with no attachments. See X837_5010.GenerateMessageText().
            _claimCur.AttachedFlags = "Mail";
            string oldAttachmentID = _claimCur.AttachmentID;

            _claimCur.AttachmentID = "";
            Claims.Update(_claimCur);
            SecurityLogs.MakeLogEntry(Permissions.ClaimEdit, _claimCur.PatNum
                                      , $"Removed attachmentID {oldAttachmentID} for ClaimNum:{_claimCur.ClaimNum}");
        }
Esempio n. 3
0
        private void butUpdate_Click(object sender, EventArgs e)
        {
            if (comboCustomTracking.SelectedIndex == -1)
            {
                //Defaults to -1 when editing and old ClaimTracking where TrackingDefNum is 0 ('None') and ClaimTrackingStatusExcludesNone is true.
                MsgBox.Show(this, "You must specify a Custom Track Status.");
                return;
            }
            if (PrefC.GetBool(PrefName.ClaimTrackingRequiresError) &&
                ((ODBoxItem <Def>)comboErrorCode.SelectedItem).Tag == null &&
                comboErrorCode.Enabled)
            {
                MsgBox.Show(this, "You must specify an error code.");                //Do they have to specify an error code even if they set the status to None?
                return;
            }
            if (comboCustomTracking.GetSelectedDefNum() == 0)
            {
                if (!MsgBox.Show(this, MsgBoxButtons.OKCancel, "Setting the status to none will disable filtering in the Outstanding Claims Report."
                                 + "  Do you wish to set the status of this claim to none?"))
                {
                    return;
                }
            }
            Def errorCodeDef = ((ODBoxItem <Def>)comboErrorCode.SelectedItem).Tag;

            for (int i = 0; i < _listClaims.Count; i++)        //when not called from FormRpOutstandingIns, this should only have one claim.
            {
                _listClaims[i].CustomTracking = comboCustomTracking.GetSelectedDefNum();
                Claims.Update(_listClaims[i]);
                ClaimTracking trackCur = ListNewClaimTracks[i];
                if (trackCur == null)
                {
                    trackCur          = new ClaimTracking();
                    trackCur.ClaimNum = _listClaims[i].ClaimNum;
                }
                trackCur.Note                = textNotes.Text;
                trackCur.TrackingDefNum      = comboCustomTracking.GetSelectedDefNum();
                trackCur.TrackingErrorDefNum = errorCodeDef.DefNum;
                trackCur.UserNum             = Security.CurUser.UserNum;
                if (trackCur.ClaimTrackingNum == 0)                //new claim tracking status.
                {
                    ClaimTrackings.Insert(trackCur);
                }
                else                   //existing claim tracking status
                {
                    ClaimTrackings.Update(trackCur);
                }
                ListNewClaimTracks[i] = trackCur;              //Update list.
            }
            DialogResult = DialogResult.OK;
        }
Esempio n. 4
0
        ///<summary>Updates all claimproc estimates and also updates claim totals to db. Must supply procList which includes all procedures that this claim is linked to.  Will also need to refresh afterwards to see the results</summary>
        public static void CalculateAndUpdate(List <Procedure> procList, List <InsPlan> planList, Claim claimCur, List <PatPlan> patPlans, List <Benefit> benefitList, int patientAge, List <InsSub> subList)
        {
            //we need more than just the claimprocs for this claim.
            //in order to run Procedures.ComputeEstimates, we need all claimprocs for all procedures attached to this claim
            List <ClaimProc> ClaimProcsAll      = ClaimProcs.Refresh(claimCur.PatNum);
            List <ClaimProc> ClaimProcsForClaim = ClaimProcs.RefreshForClaim(claimCur.ClaimNum);         //will be ordered by line number.
            double           claimFee           = 0;
            double           dedApplied         = 0;
            double           insPayEst          = 0;
            double           insPayAmt          = 0;
            double           writeoff           = 0;
            InsPlan          plan = InsPlans.GetPlan(claimCur.PlanNum, planList);

            if (plan == null)
            {
                return;
            }
            long patPlanNum = PatPlans.GetPatPlanNum(claimCur.InsSubNum, patPlans);

            //first loop handles totals for received items.
            for (int i = 0; i < ClaimProcsForClaim.Count; i++)
            {
                if (ClaimProcsForClaim[i].Status != ClaimProcStatus.Received)
                {
                    continue;                    //disregard any status except Receieved.
                }
                claimFee   += ClaimProcsForClaim[i].FeeBilled;
                dedApplied += ClaimProcsForClaim[i].DedApplied;
                insPayEst  += ClaimProcsForClaim[i].InsPayEst;
                insPayAmt  += ClaimProcsForClaim[i].InsPayAmt;
                writeoff   += ClaimProcsForClaim[i].WriteOff;
            }
            //loop again only for procs not received.
            //And for preauth.
            Procedure ProcCur;
            //InsPlan plan=InsPlans.GetPlan(claimCur.PlanNum,planList);
            List <ClaimProcHist> histList         = ClaimProcs.GetHistList(claimCur.PatNum, benefitList, patPlans, planList, claimCur.ClaimNum, claimCur.DateService, subList);
            List <ClaimProc>     claimProcListOld = new List <ClaimProc>();    //make a copy

            for (int i = 0; i < ClaimProcsAll.Count; i++)
            {
                claimProcListOld.Add(ClaimProcsAll[i].Copy());
            }
            List <ClaimProcHist> loopList = new List <ClaimProcHist>();

            for (int i = 0; i < ClaimProcsForClaim.Count; i++)       //loop through each proc
            {
                ProcCur = Procedures.GetProcFromList(procList, ClaimProcsForClaim[i].ProcNum);
                //in order for ComputeEstimates to give accurate Writeoff when creating a claim, InsPayEst must be filled for the claimproc with status of NotReceived.
                //So, we must set it here.  We need to set it in the claimProcsAll list.  Find the matching one.
                for (int j = 0; j < ClaimProcsAll.Count; j++)
                {
                    if (ClaimProcsAll[j].ClaimProcNum == ClaimProcsForClaim[i].ClaimProcNum)                  //same claimproc in a different list
                    {
                        if (ClaimProcsForClaim[i].Status == ClaimProcStatus.NotReceived &&
                            ProcCur != null)                             //ignores payments, etc
                        {
                            ClaimProcsAll[j].InsPayEst = ClaimProcs.GetInsEstTotal(ClaimProcsAll[j]);
                        }
                    }
                }
                //When this is the secondary claim, HistList includes the primary estimates, which is something we don't want because the primary calculations gets confused.
                //So, we must remove those bad entries from histList.
                for (int h = histList.Count - 1; h >= 0; h--)         //loop through the histList backwards
                {
                    if (histList[h].ProcNum != ProcCur.ProcNum)
                    {
                        continue;                        //Makes sure we will only be excluding histList entries for procs on this claim.
                    }
                    //we already excluded this claimNum when getting the histList.
                    if (histList[h].Status != ClaimProcStatus.NotReceived)
                    {
                        continue;                        //The only ones that are a problem are the ones on the primary claim not received yet.
                    }
                    histList.RemoveAt(h);
                }
                Procedures.ComputeEstimates(ProcCur, claimCur.PatNum, ref ClaimProcsAll, false, planList, patPlans, benefitList, histList, loopList, false, patientAge, subList);
                //then, add this information to loopList so that the next procedure is aware of it.
                loopList.AddRange(ClaimProcs.GetHistForProc(ClaimProcsAll, ProcCur.ProcNum, ProcCur.CodeNum));
            }
            //save changes in the list to the database
            ClaimProcs.Synch(ref ClaimProcsAll, claimProcListOld);
            ClaimProcsForClaim = ClaimProcs.RefreshForClaim(claimCur.ClaimNum);
            //But ClaimProcsAll has not been refreshed.
            for (int i = 0; i < ClaimProcsForClaim.Count; i++)
            {
                if (ClaimProcsForClaim[i].Status != ClaimProcStatus.NotReceived &&
                    ClaimProcsForClaim[i].Status != ClaimProcStatus.Preauth &&
                    ClaimProcsForClaim[i].Status != ClaimProcStatus.CapClaim)
                {
                    continue;
                }
                ProcCur = Procedures.GetProcFromList(procList, ClaimProcsForClaim[i].ProcNum);
                if (ProcCur.ProcNum == 0)
                {
                    continue;                    //ignores payments, etc
                }
                //fee:
                int qty = ProcCur.UnitQty + ProcCur.BaseUnits;
                if (qty == 0)
                {
                    qty = 1;
                }
                if (plan.ClaimsUseUCR)                 //use UCR for the provider of the procedure
                {
                    long provNum = ProcCur.ProvNum;
                    if (provNum == 0)                   //if no prov set, then use practice default.
                    {
                        provNum = PrefC.GetLong(PrefName.PracticeDefaultProv);
                    }
                    //get the fee based on code and prov fee sched
                    double feebilled = Fees.GetAmount0(ProcCur.CodeNum, ProviderC.ListLong[Providers.GetIndexLong(provNum)].FeeSched);
                    if (feebilled > ProcCur.ProcFee)
                    {
                        ClaimProcsForClaim[i].FeeBilled = qty * feebilled;
                    }
                    else
                    {
                        ClaimProcsForClaim[i].FeeBilled = qty * ProcCur.ProcFee;
                    }
                }
                //else if(claimCur.ClaimType=="Cap") {//Even for capitation, use the proc fee.
                //	ClaimProcsForClaim[i].FeeBilled=0;
                //}
                else                  //don't use ucr.  Use the procedure fee instead.
                {
                    ClaimProcsForClaim[i].FeeBilled = qty * ProcCur.ProcFee;
                }
                claimFee += ClaimProcsForClaim[i].FeeBilled;
                if (claimCur.ClaimType == "PreAuth" || claimCur.ClaimType == "Other" || claimCur.ClaimType == "Cap")
                {
                    //only the fee gets calculated, the rest does not
                    ClaimProcs.Update(ClaimProcsForClaim[i]);
                    continue;
                }
                //ClaimProcs.ComputeBaseEst(ClaimProcsForClaim[i],ProcCur.ProcFee,ProcCur.ToothNum,ProcCur.CodeNum,plan,patPlanNum,benefitList,histList,loopList);
                ClaimProcsForClaim[i].InsPayEst  = ClaimProcs.GetInsEstTotal(ClaimProcsForClaim[i]); //Yes, this is duplicated from further up.
                ClaimProcsForClaim[i].DedApplied = ClaimProcs.GetDedEst(ClaimProcsForClaim[i]);
                if (ClaimProcsForClaim[i].Status == ClaimProcStatus.NotReceived)                     //(vs preauth)
                {
                    ClaimProcsForClaim[i].WriteOff = ClaimProcs.GetWriteOffEstimate(ClaimProcsForClaim[i]);
                    writeoff += ClaimProcsForClaim[i].WriteOff;

                    /*
                     * ClaimProcsForClaim[i].WriteOff=0;
                     * if(claimCur.ClaimType=="P" && plan.PlanType=="p") {//Primary && PPO
                     *      double insplanAllowed=Fees.GetAmount(ProcCur.CodeNum,plan.FeeSched);
                     *      if(insplanAllowed!=-1) {
                     *              ClaimProcsForClaim[i].WriteOff=ProcCur.ProcFee-insplanAllowed;
                     *      }
                     *      //else, if -1 fee not found, then do not show a writeoff. User can change writeoff if they disagree.
                     * }
                     * writeoff+=ClaimProcsForClaim[i].WriteOff;*/
                }
                dedApplied += ClaimProcsForClaim[i].DedApplied;
                insPayEst  += ClaimProcsForClaim[i].InsPayEst;
                ClaimProcsForClaim[i].ProcDate = ProcCur.ProcDate.Date;              //this solves a rare bug. Keeps dates synched.
                //It's rare enough that I'm not goint to add it to the db maint tool.
                ClaimProcs.Update(ClaimProcsForClaim[i]);
                //but notice that the ClaimProcs lists are not refreshed until the loop is finished.
            }            //for claimprocs.forclaim
            claimCur.ClaimFee   = claimFee;
            claimCur.DedApplied = dedApplied;
            claimCur.InsPayEst  = insPayEst;
            claimCur.InsPayAmt  = insPayAmt;
            claimCur.WriteOff   = writeoff;
            //Cur=ClaimCur;
            Claims.Update(claimCur);
        }
        ///<summary>Saves all images in the grid to the patient on the claim's directory in the images module. Also creates
        ///a list of ClaimAttach objects to associate to the given claim.</summary>
        private void buttonOK_Click(object sender, EventArgs e)
        {
            //The user must create an image or narrative attachment before sending.
            if (gridAttachedImages.ListGridRows.Count == 0 && textNarrative.Text.Trim().Length == 0)
            {
                MsgBox.Show(this, "An image or narrative must be specified before continuing.");
                return;
            }
            try {
                CreateAndSendAttachments();
            }
            //Creating and sending Attachments will sometimes time out when an arbirtrarily large group of attachments are being sent,
            //at which point each attachment should be sent individually.
            catch (TimeoutException ex) {
                ex.DoNothing();
                ODProgress.ShowAction(() => { BatchSendAttachments(); }, "Sending attachments timed out. Attempting to send individually. Please wait.");
            }
            catch (ODException ex) {
                //ODExceptions should already be Lans.g when throwing meaningful messages.
                //If they weren't translated, the message was from a third party and shouldn't be translated anyway.
                MessageBox.Show(ex.Message);
                return;
            }
            //Validate the claim, if it isn't valid let the user decide if they want to continue
            if (!ValidateClaimHelper())
            {
                if (!MsgBox.Show(this, MsgBoxButtons.YesNo, "There were errors validating the claim, would you like to continue?"))
                {
                    return;
                }
            }
            //Used for determining which category to save the image attachments to. 0 will save the image to the first category in the Images module.
            long imageTypeDefNum   = 0;
            Def  defClaimAttachCat = CheckImageCatDefs().FirstOrDefault();

            if (defClaimAttachCat != null)
            {
                imageTypeDefNum = defClaimAttachCat.DefNum;
            }
            else              //User does not have a Claim Attachment image category, just use the first image category available.
            {
                imageTypeDefNum = Defs.GetCatList((int)DefCat.ImageCats).FirstOrDefault(x => !x.IsHidden).DefNum;
            }
            List <ClaimAttach> listClaimAttachments = new List <ClaimAttach>();

            for (int i = 0; i < gridAttachedImages.ListGridRows.Count; i++)
            {
                ClaimConnect.ImageAttachment imageRow = ((ClaimConnect.ImageAttachment)gridAttachedImages.ListGridRows[i].Tag);
                if (PrefC.GetBool(PrefName.SaveDXCAttachments))
                {
                    Bitmap   imageBitmap = new Bitmap(imageRow.Image);
                    Document docCur      = ImageStore.Import(imageBitmap, imageTypeDefNum, ImageType.Document, _claimPat);
                    imageRow.ImageFileNameActual = docCur.FileName;
                }
                //Create attachment objects
                listClaimAttachments.Add(CreateClaimAttachment(imageRow.ImageFileNameDisplay, imageRow.ImageFileNameActual));
            }
            //Keep a running list of attachments sent to DXC for the claim. This will show in the attachments listbox.
            _claimCur.Attachments.AddRange(listClaimAttachments);
            Claims.Update(_claimCur);
            MsgBox.Show("Attachments sent successfully!");
            DialogResult = DialogResult.OK;
        }