///<summary>Fills the missing data field on the queueItem that was passed in. This contains all missing data on this claim. Claim will not be allowed to be sent electronically unless this string comes back empty.</summary> public static void GetMissingData(ClaimSendQueueItem queueItem) //, out string warnings){ { queueItem.Warnings = ""; queueItem.MissingData = ""; Clearinghouse clearhouse = ClearinghouseL.GetClearinghouse(queueItem.ClearinghouseNum, true); //Suppress error message in case no default medical clearinghouse set. //this is usually just the default clearinghouse or the clearinghouse for the PayorID. if (clearhouse == null) { if (queueItem.MedType == EnumClaimMedType.Dental) { queueItem.MissingData += "No default dental clearinghouse set."; } else { queueItem.MissingData += "No default medical/institutional clearinghouse set."; } return; } if (clearhouse.Eformat == ElectronicClaimFormat.x837D_4010) { X837_4010.Validate(queueItem); //,out warnings); //return; } else if (clearhouse.Eformat == ElectronicClaimFormat.x837D_5010_dental || clearhouse.Eformat == ElectronicClaimFormat.x837_5010_med_inst) { X837_5010.Validate(queueItem); //,out warnings); //return; } else if (clearhouse.Eformat == ElectronicClaimFormat.Renaissance) { queueItem.MissingData = Renaissance.GetMissingData(queueItem); //return; } else if (clearhouse.Eformat == ElectronicClaimFormat.Canadian) { queueItem.MissingData = Canadian.GetMissingData(queueItem); //return; } else if (clearhouse.Eformat == ElectronicClaimFormat.Dutch) { Dutch.GetMissingData(queueItem); //,out warnings); //return; } //return ""; }
///<summary>Returns a string describing all missing data on this claim. Claim will not be allowed to be sent electronically unless this string comes back empty.</summary> public static string GetMissingData(ClaimSendQueueItem queueItem) { Clearinghouse clearhouse = Clearinghouses.GetClearinghouse(queueItem.ClearinghouseNum); if (clearhouse.Eformat == ElectronicClaimFormat.X12) { return(X12.GetMissingData(queueItem)); } else if (clearhouse.Eformat == ElectronicClaimFormat.Renaissance) { return(Renaissance.GetMissingData(queueItem)); } else if (clearhouse.Eformat == ElectronicClaimFormat.Canadian) { return(Canadian.GetMissingData(queueItem)); } return(""); }
///<summary>Returns a string describing all missing data on this claim. Claim will not be allowed to be sent electronically unless this string comes back empty. There is also an out parameter containing any warnings. Warnings will not block sending.</summary> public static void GetMissingData(ClaimSendQueueItem queueItem) //,out string warning) { { StringBuilder strb = new StringBuilder(); string warning = ""; Claim claim = Claims.GetClaim(queueItem.ClaimNum); Patient pat = Patients.GetPat(claim.PatNum); if (!Regex.IsMatch(pat.Address, @"^[a-zA-Z ]+[0-9]+")) //format must be streetname, then some numbers, then anything else. { if (strb.Length != 0) { strb.Append(","); } strb.Append("Patient address format"); } //return strb.ToString(); queueItem.MissingData = strb.ToString(); queueItem.Warnings = warning; }
public static string Run(int scriptNum, string responseExpected, string responseTypeExpected, Claim claim, bool showForms, int pageNumber, int lastPageNumber, double firstExamFee, double diagnosticPhaseFee) { string retVal = ""; ClaimSendQueueItem queueItem = Claims.GetQueueList(claim.ClaimNum, claim.ClinicNum, 0)[0]; Clearinghouse clearinghouseHq = ClearinghouseL.GetClearinghouseHq(queueItem.ClearinghouseNum); Clearinghouse clearinghouseClin = Clearinghouses.OverrideFields(clearinghouseHq, Clinics.ClinicNum); Eclaims.GetMissingData(clearinghouseClin, queueItem); //,out warnings); if (queueItem.MissingData != "") { return("Cannot send predetermination until missing data is fixed:\r\n" + queueItem.MissingData + "\r\n"); } #if DEBUG Canadian.testNumber = scriptNum; claim.PreAuthString = "" + pageNumber + "," + lastPageNumber + "," + firstExamFee + "," + diagnosticPhaseFee; #endif long etransNum = Canadian.SendClaim(clearinghouseClin, queueItem, showForms); Etrans etrans = Etranss.GetEtrans(etransNum); string message = EtransMessageTexts.GetMessageText(etrans.EtransMessageTextNum); CCDFieldInputter formData = new CCDFieldInputter(message); string responseType = formData.GetValue("A04"); if (responseType != responseTypeExpected) { return("Form type is '" + responseType + "' but should be '" + responseTypeExpected + "'\r\n"); } string responseStatus = formData.GetValue("G05"); if (responseStatus != responseExpected) { return("G05 is '" + responseStatus + "' but should be '" + responseExpected + "'\r\n"); } if (responseExpected == "R" && responseTypeExpected == "11") { //so far, only for #6. We need some other way to test if successful transaction string errorMsgCount = formData.GetValue("G06"); if (errorMsgCount == "00") { return("Wrong message count.\r\n"); } } retVal += "Predetermination #" + scriptNum + " page " + pageNumber + " of " + lastPageNumber + " successful.\r\n"; return(retVal); }
public static string Run(int scriptNum, string responseExpected, string responseTypeExpected, Claim claim, bool showForms) { string retVal = ""; ClaimSendQueueItem queueItem = Claims.GetQueueList(claim.ClaimNum, claim.ClinicNum, 0)[0]; Clearinghouse clearinghouseHq = ClearinghouseL.GetClearinghouseHq(queueItem.ClearinghouseNum); Clearinghouse clearinghouseClin = Clearinghouses.OverrideFields(clearinghouseHq, Clinics.ClinicNum); Eclaims.GetMissingData(clearinghouseClin, queueItem); //,out warnings); if (queueItem.MissingData != "") { return("Cannot send claim until missing data is fixed:\r\n" + queueItem.MissingData + "\r\n"); } #if DEBUG Canadian.testNumber = scriptNum; #endif long etransNum = Canadian.SendClaim(clearinghouseClin, queueItem, showForms); Etrans etrans = Etranss.GetEtrans(etransNum); string message = EtransMessageTexts.GetMessageText(etrans.EtransMessageTextNum); CCDFieldInputter formData = new CCDFieldInputter(message); string responseType = formData.GetValue("A04"); if (responseType != responseTypeExpected) { return("Form type should be " + responseTypeExpected + "\r\n"); } string responseStatus = formData.GetValue("G05"); if (responseStatus != responseExpected) { return("G05 should be " + responseExpected + "\r\n"); } if (responseExpected == "R" && responseTypeExpected == "11") { //so far, only for #6. We need some other way to test if successful transaction string errorMsgCount = formData.GetValue("G06"); if (errorMsgCount == "00") { return("Wrong message count.\r\n"); } } retVal += "Claim #" + scriptNum.ToString() + " successful.\r\n"; return(retVal); }
///<summary>Returns a string describing all missing data on this claim. Claim will not be allowed to be sent electronically unless this string comes back empty.</summary> public static string GetMissingData(ClaimSendQueueItem queueItem) { //Our support for Renaissance is minimal, because they do not use the X12 format and we do not recommend that our customers use it. //Thus, we do not perform validation. return(""); }
///<summary>Called once for each claim to be created. For claims with a lot of procedures, this may actually create multiple claims. ///Normally returns empty string unless something went wrong.</summary> public static bool CreateClaim(Clearinghouse clearinghouseClin, ClaimSendQueueItem queueItem, int batchNum) { StringBuilder strb = new StringBuilder(); string t = "\t"; strb.Append("110\t111\t112\t118\t203/403\tF108/204/404\t205/405\t206\t207\t208\t209\t210\t211\t212\t215\t217\t219\t406\t408\t409\t410\t411\t413\t414\t415\t416\t418\t419\t420\t421\t422\t423\t424\t425\t426\t428\t429\t430\t432\t433\r\n"); Claim claim = Claims.GetClaim(queueItem.ClaimNum); Provider provBill = Providers.GetProv(claim.ProvBill); Patient pat = Patients.GetPat(claim.PatNum); InsPlan insplan = InsPlans.GetPlan(claim.PlanNum, new List <InsPlan>()); InsSub insSub = InsSubs.GetSub(claim.InsSubNum, new List <InsSub>()); Carrier carrier = Carriers.GetCarrier(insplan.CarrierNum); List <ClaimProc> claimProcList = ClaimProcs.Refresh(pat.PatNum); List <ClaimProc> claimProcsForClaim = ClaimProcs.GetForSendClaim(claimProcList, claim.ClaimNum); List <Procedure> procList = Procedures.Refresh(claim.PatNum); Procedure proc; ProcedureCode procCode; //ProcedureCode procCode; for (int i = 0; i < claimProcsForClaim.Count; i++) { //claimProcsForClaim already excludes any claimprocs with ProcNum=0, so no payments etc. proc = Procedures.GetProcFromList(procList, claimProcsForClaim[i].ProcNum); //procCode=Pro strb.Append(provBill.SSN + t); //110 strb.Append(provBill.MedicaidID + t); //111 strb.Append(t); //112 strb.Append(t); //118 strb.Append(pat.SSN + t); //203/403 strb.Append(carrier.CarrierName + t); //carrier name? strb.Append(insSub.SubscriberID + t); strb.Append(pat.PatNum.ToString() + t); strb.Append(pat.Birthdate.ToString("dd-MM-yyyy") + t); if (pat.Gender == PatientGender.Female) { strb.Append("2" + t); //"V"+t); } else { strb.Append("1" + t); //M"+t); } strb.Append("1" + t); strb.Append(DutchLName(pat.LName) + t); //last name without prefix strb.Append(DutchLNamePrefix(pat.LName) + t); //prefix strb.Append("2" + t); strb.Append(DutchInitials(pat) + t); //215. initials strb.Append(pat.Zip + t); strb.Append(DutchAddressNumber(pat.Address) + t); //219 house number. Already validated. strb.Append(t); strb.Append(proc.ProcDate.ToString("dd-MM-yyyy") + t); //procDate procCode = ProcedureCodes.GetProcCode(proc.CodeNum); string strProcCode = procCode.ProcCode; if (strProcCode.EndsWith("00")) //ending with 00 indicates it's a lab code. { strb.Append("02" + t); } else { strb.Append("01" + t); //409. Procedure code (01) or lab costs (02) } strb.Append(t); strb.Append(t); strb.Append(strProcCode + t); strb.Append(GetUL(proc, procCode) + t); //414. U/L. strb.Append(Tooth.ToInternat(proc.ToothNum) + t); strb.Append(Tooth.SurfTidyForClaims(proc.Surf, proc.ToothNum) + t); //needs validation strb.Append(t); if (claim.AccidentRelated == "") //not accident { strb.Append("N" + t); } else { strb.Append("J" + t); } strb.Append(pat.SSN + t); strb.Append(t); strb.Append(t); strb.Append(t); strb.Append(proc.ProcFee.ToString("F") + t); strb.Append("1" + t); strb.Append(proc.ProcFee.ToString("F") + t); strb.Append(t); strb.Append(t); strb.Append(proc.ProcFee.ToString("F") + t); strb.Append(t); strb.Append(t); strb.Append("\r\n"); } string saveFolder = clearinghouseClin.ExportPath; if (!Directory.Exists(saveFolder)) { MessageBox.Show(saveFolder + " " + Lans.g("Dutch", "not found.")); return(false); } string saveFile = ODFileUtils.CombinePaths(saveFolder, "claims" + claim.ClaimNum.ToString() + ".txt"); File.WriteAllText(saveFile, strb.ToString()); //MessageBox.Show(strb.ToString()); return(true); }
///<summary>Sets the MissingData and Warnings fields on the queueItem as appropriate.</summary> public static void GetMissingData(Clearinghouse clearinghouseClin, ClaimSendQueueItem queueItem) { StringBuilder sbErrors = new StringBuilder(); StringBuilder sbWarnings = new StringBuilder(); Claim claim = Claims.GetClaim(queueItem.ClaimNum); Provider provClaimTreat = Providers.GetProv(claim.ProvTreat); InsSub insSub = InsSubs.GetOne(claim.InsSubNum); #region Header //TRNSM if (!Regex.IsMatch(clearinghouseClin.SenderTIN, @"^[0-9]+$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Tax ID Number (RAMQ TRNSM) is invalid"); } else { int trnsm = PIn.Int(clearinghouseClin.SenderTIN); if (clearinghouseClin.ISA15 != "T" && trnsm >= 18000 && trnsm <= 18999) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Tax ID Number (RAMQ TRNSM) is a test value on this production claim"); } else if (clearinghouseClin.ISA15 == "T" && (trnsm < 18000 || trnsm > 18999)) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Tax ID Number (RAMQ TRNSM) must be between 18000 and 18999 for this test claim"); } } //DISP if (!Regex.IsMatch(provClaimTreat.NationalProvID, @"^[27][0-9]{5}$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Claim treating provider CDA Number for RAMQ is invalid"); } //DISP_REFNT if (claim.CanadianReferralProviderNum.Trim().Length > 0 && !Regex.IsMatch(claim.CanadianReferralProviderNum.Trim(), @"^[0-9]{6}$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Referral provider CDA Number for RAMQ is invalid"); } //ETAB if (!Regex.IsMatch(provClaimTreat.CanadianOfficeNum, @"^[0-9]{5}$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Claim treating provider Office Number for RAMQ is invalid"); } //SERV if (claim.DateService.Year < 1880) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Claim date of service is invalid or missing"); } #endregion Header #region Insurance //Most fields in the insuranace section are optional and thus do not require validation. //NAM if (!Regex.IsMatch(insSub.SubscriberID, @"^[a-zA-Z]{4}[0-9]{6}[a-zA-Z0-9][0-9]$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Subscriber ID for RAMQ is invalid"); } #endregion Insurance #region Procedures List <ProcedureCode> listProcCodes = ProcedureCodes.GetAllCodes(); List <ClaimProc> listClaimProcsForPat = ClaimProcs.Refresh(claim.PatNum); List <ClaimProc> listClaimProcsForClaim = ClaimProcs.GetForSendClaim(listClaimProcsForPat, claim.ClaimNum); //Excludes labs. List <Procedure> listProcsForPat = Procedures.Refresh(claim.PatNum); foreach (ClaimProc claimProc in listClaimProcsForClaim) { Procedure proc = Procedures.GetProcFromList(listProcsForPat, claimProc.ProcNum); if (proc.ProcFee == 0) { continue; } ProcedureCode procCode = ProcedureCodes.GetProcCode(proc.CodeNum, listProcCodes); if (procCode.NoBillIns) { continue; } //ACTE if (procCode.ProcCode.Length < 5 || !Regex.IsMatch(procCode.ProcCode.Substring(0, 5), @"^[0-9]{5}$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Procedure code invalid '" + procCode.ProcCode + "'"); } List <Procedure> listLabProcs = Procedures.GetCanadianLabFees(proc.ProcNum, listProcsForPat); foreach (Procedure labProc in listLabProcs) { if (labProc.ProcFee == 0) { continue; } ProcedureCode labProcCode = ProcedureCodes.GetProcCode(labProc.CodeNum, listProcCodes); if (labProcCode.ProcCode.Length < 5 || !Regex.IsMatch(labProcCode.ProcCode.Substring(0, 5), @"^[0-9]{5}$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Lab code invalid '" + labProcCode.ProcCode + "'"); } } } #endregion Procedures queueItem.MissingData = sbErrors.ToString(); queueItem.Warnings = sbWarnings.ToString(); }
///<summary>Returns a string describing all missing data on this claim. Claim will not be allowed to be sent electronically unless this string comes back empty.</summary> public static string GetMissingData(ClaimSendQueueItem queueItem) { return(""); }
///<summary>Fills the missing data field on the queueItem that was passed in. This contains all missing data on this claim. Claim will not be allowed to be sent electronically unless this string comes back empty.</summary> public static ClaimSendQueueItem GetMissingData(Clearinghouse clearinghouseClin, ClaimSendQueueItem queueItem) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { return(Meth.GetObject <ClaimSendQueueItem>(MethodBase.GetCurrentMethod(), clearinghouseClin, queueItem)); } queueItem.Warnings = ""; queueItem.MissingData = ""; //this is usually just the default clearinghouse or the clearinghouse for the PayorID. if (clearinghouseClin == null) { if (queueItem.MedType == EnumClaimMedType.Dental) { queueItem.MissingData += "No default dental clearinghouse set."; } else { queueItem.MissingData += "No default medical/institutional clearinghouse set."; } return(queueItem); } #region Data Sanity Checking (for Replication) //Example: We had one replication customer who was able to delete an insurance plan for which was attached to a claim. //Imagine two replication servers, server A and server B. An insplan is created which is not associated to any claims. //Both databases have a copy of the insplan. The internet connection is lost. On server A, a user deletes the insurance //plan (which is allowed because no claims are attached). On server B, a user creates a claim with the insurance plan. //When the internet connection returns, the delete insplan statement is run on server B, which then creates a claim with //an invalid InsPlanNum on server B. Without the checking below, the send claims window would crash for this one scenario. Claim claim = Claims.GetClaim(queueItem.ClaimNum); //This should always exist, because we just did a select to get the queue item. InsPlan insPlan = InsPlans.RefreshOne(claim.PlanNum); if (insPlan == null) //Check for missing PlanNums { queueItem.MissingData = Lans.g("Eclaims", "Claim insurance plan record missing. Please recreate claim."); return(queueItem); } if (claim.InsSubNum2 != 0) { InsPlan insPlan2 = InsPlans.RefreshOne(claim.PlanNum2); if (insPlan2 == null) //Check for missing PlanNums { queueItem.MissingData = Lans.g("Eclaims", "Claim other insurance plan record missing. Please recreate claim."); return(queueItem); //This will let the office send other claims that passed validation without throwing an exception. } } #endregion Data Sanity Checking (for Replication) if (clearinghouseClin.Eformat == ElectronicClaimFormat.x837D_4010) { X837_4010.Validate(clearinghouseClin, queueItem); //,out warnings); //return; } else if (clearinghouseClin.Eformat == ElectronicClaimFormat.x837D_5010_dental || clearinghouseClin.Eformat == ElectronicClaimFormat.x837_5010_med_inst) { X837_5010.Validate(clearinghouseClin, queueItem); //,out warnings); //return; } else if (clearinghouseClin.Eformat == ElectronicClaimFormat.Renaissance) { queueItem.MissingData = Renaissance.GetMissingData(queueItem); //return; } else if (clearinghouseClin.Eformat == ElectronicClaimFormat.Canadian) { queueItem.MissingData = Canadian.GetMissingData(queueItem); //return; } else if (clearinghouseClin.Eformat == ElectronicClaimFormat.Dutch) { Dutch.GetMissingData(queueItem); //,out warnings); //return; } else if (clearinghouseClin.Eformat == ElectronicClaimFormat.Ramq) { Ramq.GetMissingData(queueItem); } return(queueItem); }
///<summary>Sets the MissingData and Warnings fields on the queueItem as appropriate.</summary> public static void GetMissingData(ClaimSendQueueItem queueItem) { StringBuilder sbErrors = new StringBuilder(); StringBuilder sbWarnings = new StringBuilder(); Claim claim = Claims.GetClaim(queueItem.ClaimNum); Provider provClaimTreat = Providers.GetProv(claim.ProvTreat); InsSub insSub = InsSubs.GetOne(claim.InsSubNum); Patient pat = Patients.GetPat(claim.PatNum); #region Header //DISP if (!Regex.IsMatch(provClaimTreat.NationalProvID, @"^[27][0-9]{5}$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Claim treating provider ID for RAMQ is invalid"); } //DISP_REFNT if (claim.CanadianReferralProviderNum.Trim().Length > 0 && !Regex.IsMatch(claim.CanadianReferralProviderNum.Trim(), @"^[0-9]{6}$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Referral provider ID for RAMQ is invalid"); } //ETAB if (!Regex.IsMatch(provClaimTreat.CanadianOfficeNum, @"^[0-9]{5}$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Claim treating provider office number is invalid"); } //SERV if (claim.DateService.Year < 1880) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Claim date of service is invalid or missing"); } #endregion Header #region Insurance //Most fields in the insuranace section are optional and thus do not require validation. //NAM if (!Regex.IsMatch(insSub.SubscriberID, @"^[a-zA-Z]{4}[0-9]{6}[a-zA-Z0-9][0-9]$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Subscriber ID invalid"); } #endregion Insurance #region Procedures List <ProcedureCode> listProcCodes = ProcedureCodes.GetAllCodes(); List <ClaimProc> listClaimProcsForPat = ClaimProcs.Refresh(claim.PatNum); List <ClaimProc> listClaimProcsForClaim = ClaimProcs.GetForSendClaim(listClaimProcsForPat, claim.ClaimNum); //Excludes labs. List <Procedure> listProcsForPat = Procedures.Refresh(claim.PatNum); foreach (ClaimProc claimProc in listClaimProcsForClaim) { Procedure proc = Procedures.GetProcFromList(listProcsForPat, claimProc.ProcNum); if (proc.ProcFee == 0) { continue; } ProcedureCode procCode = ProcedureCodes.GetProcCode(proc.CodeNum, listProcCodes); if (procCode.NoBillIns) { continue; } //ACTE if (procCode.ProcCode.Length < 5 || !Regex.IsMatch(procCode.ProcCode.Substring(0, 5), @"^[0-9]{5}$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Procedure code invalid '" + procCode.ProcCode + "'"); } List <Procedure> listLabProcs = Procedures.GetCanadianLabFees(proc.ProcNum, listProcsForPat); foreach (Procedure labProc in listLabProcs) { if (labProc.ProcFee == 0) { continue; } ProcedureCode labProcCode = ProcedureCodes.GetProcCode(labProc.CodeNum, listProcCodes); if (labProcCode.ProcCode.Length < 5 || !Regex.IsMatch(labProcCode.ProcCode.Substring(0, 5), @"^[0-9]{5}$")) { if (sbErrors.Length != 0) { sbErrors.Append(","); } sbErrors.Append("Lab code invalid '" + labProcCode.ProcCode + "'"); } } } #endregion Procedures queueItem.MissingData = sbErrors.ToString(); queueItem.Warnings = sbWarnings.ToString(); }