Пример #1
0
		///<summary>Gets the last batch number for this clearinghouse and increments it by one.  Saves the new value, then returns it.  So even if the new value is not used for some reason, it will have already been incremented. Remember that LastBatchNumber is never accurate with local data in memory.</summary>
		public static int GetNextBatchNumber(Clearinghouse clearhouse){
			if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) {
				return Meth.GetInt(MethodBase.GetCurrentMethod(),clearhouse);
			}
			//get last batch number
			string command="SELECT LastBatchNumber FROM clearinghouse "
				+"WHERE ClearinghouseNum = "+POut.Long(clearhouse.ClearinghouseNum);
 			DataTable table=Db.GetTable(command);
			int batchNum=PIn.Int(table.Rows[0][0].ToString());
			//and increment it by one
			if(clearhouse.Eformat==ElectronicClaimFormat.Canadian){
				if(batchNum==999999){
					batchNum=1;
				}
				else{
					batchNum++;
				}
			}
			else{
				if(batchNum==999){
					batchNum=1;
				}
				else{
					batchNum++;
				}
			}
			//save the new batch number. Even if user cancels, it will have incremented.
			command="UPDATE clearinghouse SET LastBatchNumber="+batchNum.ToString()
				+" WHERE ClearinghouseNum = "+POut.Long(clearhouse.ClearinghouseNum);
			Db.NonQ(command);
			return batchNum;
		}
Пример #2
0
		///<summary>Called from Eclaims and includes multiple claims.  Returns the string that was sent.  The string needs to be parsed to determine the transaction numbers used for each claim.</summary>
		public static string SendBatch(List<ClaimSendQueueItem> queueItems,int batchNum,Clearinghouse clearhouse,EnumClaimMedType medType){
			//each batch is already guaranteed to be specific to one clearinghouse, one clinic, and one EnumClaimMedType
			//Clearinghouse clearhouse=ClearinghouseL.GetClearinghouse(queueItems[0].ClearinghouseNum);
			string saveFile=GetFileName(clearhouse,batchNum);
			if(saveFile==""){
				return "";
			}
			using(StreamWriter sw=new StreamWriter(saveFile,false,Encoding.ASCII)){
				if(clearhouse.Eformat==ElectronicClaimFormat.x837D_4010) {
					X837_4010.GenerateMessageText(sw,clearhouse,batchNum,queueItems);
				}
				else {//Any of the 3 kinds of 5010
					X837_5010.GenerateMessageText(sw,clearhouse,batchNum,queueItems,medType);
				}
			}
			if(clearhouse.CommBridge==EclaimsCommBridge.PostnTrack){
				//need to clear out all CRLF from entire file
				string strFile="";
				using(StreamReader sr=new StreamReader(saveFile,Encoding.ASCII)){
					strFile=sr.ReadToEnd();
				}
				strFile=strFile.Replace("\r","");
				strFile=strFile.Replace("\n","");
				using(StreamWriter sw=new StreamWriter(saveFile,false,Encoding.ASCII)){
					sw.Write(strFile);
				}
			}
			CopyToArchive(saveFile);
			return File.ReadAllText(saveFile);
		}
Пример #3
0
        ///<summary>Replaces all clinic-level fields in ClearinghouseHq with non-blank fields
        ///from the clinic-level clearinghouse for the passed-in clinicNum. Non clinic-level fields are not replaced.</summary>
        public static Clearinghouse OverrideFields(Clearinghouse clearinghouseHq, long clinicNum)
        {
            //No need to check RemotingRole; no call to db.
            Clearinghouse clearinghouseClin = Clearinghouses.GetForClinic(clearinghouseHq, clinicNum);

            return(OverrideFields(clearinghouseHq, clearinghouseClin));
        }
Пример #4
0
		///<summary>Inserts this clearinghouse into database.</summary>
		public static long Insert(Clearinghouse clearhouse){
			if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) {
				clearhouse.ClearinghouseNum=Meth.GetLong(MethodBase.GetCurrentMethod(),clearhouse);
				return clearhouse.ClearinghouseNum;
			}
			return Crud.ClearinghouseCrud.Insert(clearhouse);
		}
Пример #5
0
 private static void RetrieveReportsAutomaticHelper(Clearinghouse clearinghouseClin, Clearinghouse clearinghouseHq, long defaultClearingHouseNum
                                                    , bool isTimeToRetrieve)
 {
     if (!Directory.Exists(clearinghouseClin.ResponsePath))
     {
         return;
     }
     if (clearinghouseHq.ClearinghouseNum == defaultClearingHouseNum)           //If it's the default dental clearinghouse
     {
         RetrieveAndImport(clearinghouseClin, true, isTimeToRetrieve: isTimeToRetrieve);
     }
     else if (clearinghouseHq.Eformat == ElectronicClaimFormat.None)           //And the format is "None" (accessed from all regions)
     {
         RetrieveAndImport(clearinghouseClin, true, isTimeToRetrieve: isTimeToRetrieve);
     }
     else if (clearinghouseHq.CommBridge == EclaimsCommBridge.BCBSGA)
     {
         BCBSGA.Retrieve(clearinghouseClin, true, new TerminalConnector());
     }
     else if (clearinghouseHq.Eformat == ElectronicClaimFormat.Canadian && CultureInfo.CurrentCulture.Name.EndsWith("CA"))
     {
         //Or the Eformat is Canadian and the region is Canadian.  In Canada, the "Outstanding Reports" are received upon request.
         //Canadian reports must be retrieved using an office num and valid provider number for the office,
         //which will cause all reports for that office to be returned.
         //Here we loop through all providers and find CDAnet providers with a valid provider number and office number, and we only send
         //one report download request for one provider from each office.  For most offices, the loop will only send a single request.
         List <Provider> listProvs      = Providers.GetDeepCopy(true);
         List <string>   listOfficeNums = new List <string>();
         for (int j = 0; j < listProvs.Count; j++)           //Get all unique office numbers from the providers.
         {
             if (!listProvs[j].IsCDAnet || listProvs[j].NationalProvID == "" || listProvs[j].CanadianOfficeNum == "")
             {
                 continue;
             }
             if (!listOfficeNums.Contains(listProvs[j].CanadianOfficeNum))                     //Ignore duplicate office numbers.
             {
                 listOfficeNums.Add(listProvs[j].CanadianOfficeNum);
                 try {
                     clearinghouseHq   = Eclaims.Canadian.GetCanadianClearinghouseHq(null);
                     clearinghouseClin = Clearinghouses.OverrideFields(clearinghouseHq, Clinics.ClinicNum);
                     Eclaims.CanadianOutput.GetOutstandingTransactions(clearinghouseClin, false, true, null, listProvs[j], true, null, null);
                 }
                 catch {
                     //Supress errors importing reports.
                 }
             }
         }
     }
     else if (clearinghouseHq.Eformat == ElectronicClaimFormat.Dutch && CultureInfo.CurrentCulture.Name.EndsWith("DE"))
     {
         //Or the Eformat is German and the region is German
         RetrieveAndImport(clearinghouseClin, true, isTimeToRetrieve: isTimeToRetrieve);
     }
     else if (clearinghouseHq.Eformat != ElectronicClaimFormat.Canadian &&
              clearinghouseHq.Eformat != ElectronicClaimFormat.Dutch &&
              CultureInfo.CurrentCulture.Name.EndsWith("US"))               //Or the Eformat is in any other format and the region is US
     {
         RetrieveAndImport(clearinghouseClin, true, isTimeToRetrieve: isTimeToRetrieve);
     }
 }
Пример #6
0
		///<summary></summary>
		public static void Update(Clearinghouse clearhouse){
			if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) {
				Meth.GetVoid(MethodBase.GetCurrentMethod(),clearhouse);
				return;
			}
			Crud.ClearinghouseCrud.Update(clearhouse);
		}
Пример #7
0
 public static void GenerateMessageText(StreamWriter sw,Clearinghouse clearhouse,int batchNum,List<ClaimSendQueueItem> functionalGroupDental)
 {
     //Interchange Control Header (Interchange number tracked separately from transactionNum)
     //We set it to between 1 and 999 for simplicity
     sw.Write("ISA*00*          *"//ISA01,ISA02: 00 + 10 spaces
         +"00*          *"//ISA03,ISA04: 00 + 10 spaces
         +clearhouse.ISA05+"*"//ISA05: Sender ID type: ZZ=mutually defined. 30=TIN. Validated
         +X12Generator.GetISA06(clearhouse)+"*"//ISA06: Sender ID(TIN). Or might be TIN of Open Dental
         +clearhouse.ISA07+"*"//ISA07: Receiver ID type: ZZ=mutually defined. 30=TIN. Validated
         +Sout(clearhouse.ISA08,15,15)+"*"//ISA08: Receiver ID. Validated to make sure length is at least 2.
         +DateTime.Today.ToString("yyMMdd")+"*"//ISA09: today's date
         +DateTime.Now.ToString("HHmm")+"*"//ISA10: current time
         +"U*00401*"//ISA11 and ISA12.
         //ISA13: interchange control number, right aligned:
         +batchNum.ToString().PadLeft(9,'0')+"*"
         +"0*"//ISA14: no acknowledgment requested
         +clearhouse.ISA15+"*");//ISA15: T=Test P=Production. Validated.
     sw.WriteLine(":~");//ISA16: use ':'
     //Functional groups: one for dental and one for medical
     //But we instead need to restrict file output to either medical OR dental, not both.
     //So this part is changing.  One or the other.
     //if(functionalGroupMedical.Count>0) {
     //	WriteFunctionalGroup(sw,functionalGroupMedical,batchNum,clearhouse);
     //}
     //if(functionalGroupDental.Count>0) {
         WriteFunctionalGroup(sw,functionalGroupDental,batchNum,clearhouse);
     //}
     //Interchange Control Trailer
     sw.WriteLine("IEA*1*"//IEA01: number of functional groups
             +batchNum.ToString().PadLeft(9,'0')+"~");//IEA02: Interchange control number
 }
Пример #8
0
        public static void RetrieveReportsAutomatic(bool isAllClinics)
        {
            List <long> listClinicNums = new List <long>();

            if (isAllClinics)
            {
                listClinicNums = Clinics.GetDeepCopy(true).Select(x => x.ClinicNum).ToList();
            }
            else
            {
                listClinicNums = new List <long> {
                    Clinics.ClinicNum
                };
            }
            string errMsg;
            bool   isTimeToRetrieve = IsTimeToRetrieveReports(true, out errMsg);

            if (isTimeToRetrieve)
            {
                Prefs.UpdateDateT(PrefName.ClaimReportReceiveLastDateTime, DateTime.Now);
            }
            List <Clearinghouse> listClearinghousesHq = GetDeepCopy();
            long defaultClearingHouseNum = PrefC.GetLong(PrefName.ClearinghouseDefaultDent);

            for (int i = 0; i < listClearinghousesHq.Count; i++)
            {
                Clearinghouse clearinghouseHq = listClearinghousesHq[i];
                Clearinghouse clearinghouseClin;
                for (int j = 0; j < listClinicNums.Count; j++)
                {
                    clearinghouseClin = OverrideFields(clearinghouseHq, listClinicNums[j]);
                    RetrieveReportsAutomaticHelper(clearinghouseClin, clearinghouseHq, defaultClearingHouseNum, isTimeToRetrieve);
                }
            }
        }
Пример #9
0
		///<summary>If clearhouse.SenderTIN is blank, then 810624427 will be used to indicate Open Dental.</summary>
		public static string GetISA06(Clearinghouse clearhouse) {
			if(clearhouse.SenderTIN=="") {
				return Sout("810624427",15,15);//TIN of OD.
			}
			else {
				return Sout(clearhouse.SenderTIN,15,15);//already validated to be length at least 2.
			}
		}
Пример #10
0
		///<summary></summary>
		public static void Delete(Clearinghouse clearhouse){
			if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) {
				Meth.GetVoid(MethodBase.GetCurrentMethod(),clearhouse);
				return;
			}
			string command="DELETE FROM clearinghouse WHERE ClearinghouseNum = '"+POut.Long(clearhouse.ClearinghouseNum)+"'";
			Db.NonQ(command);
		}
Пример #11
0
 public static void Update(Clearinghouse clearinghouse, Clearinghouse oldClearinghouse)
 {
     if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
     {
         Meth.GetVoid(MethodBase.GetCurrentMethod(), clearinghouse, oldClearinghouse);
         return;
     }
     Crud.ClearinghouseCrud.Update(clearinghouse, oldClearinghouse);
 }
Пример #12
0
 ///<summary>Inserts this clearinghouse into database.</summary>
 public static long Insert(Clearinghouse clearhouse)
 {
     if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
     {
         clearhouse.ClearinghouseNum = Meth.GetLong(MethodBase.GetCurrentMethod(), clearhouse);
         return(clearhouse.ClearinghouseNum);
     }
     return(Crud.ClearinghouseCrud.Insert(clearhouse));
 }
Пример #13
0
		///<summary>If file creation was successful but communications failed, then this deletes the X12 file.  This is not used in the Tesia bridge because of the unique filenaming.</summary>
		public static void Rollback(Clearinghouse clearhouse,int batchNum){
			if(clearhouse.CommBridge==EclaimsCommBridge.RECS){
				//A RECS rollback never deletes the file, because there is only one
			}
			else{
				//This is a Windows extension, so we do not need to worry about Unix path separator characters.
				File.Delete(ODFileUtils.CombinePaths(clearhouse.ExportPath,"claims"+batchNum.ToString()+".txt"));
			}
		}
Пример #14
0
        public static string Validate(Clearinghouse clearhouse, Carrier carrier, Provider billProv, Clinic clinic, InsPlan insPlan, Patient subscriber, InsSub insSub)
        {
            StringBuilder strb = new StringBuilder();

            X12Validate.ISA(clearhouse, strb);
            X12Validate.Carrier(carrier, strb);
            if (carrier.ElectID.Length < 2)
            {
                if (strb.Length != 0)
                {
                    strb.Append(",");
                }
                strb.Append("Electronic ID");
            }
            if (billProv.SSN.Length != 9)
            {
                if (strb.Length != 0)
                {
                    strb.Append(",");
                }
                strb.Append("Prov TIN 9 digits");
            }
            X12Validate.BillProv(billProv, strb);
            if (clinic == null)
            {
                X12Validate.PracticeAddress(strb);
            }
            else
            {
                X12Validate.Clinic(clinic, strb);
            }
            if (insSub.SubscriberID.Length < 2)
            {
                if (strb.Length != 0)
                {
                    strb.Append(",");
                }
                strb.Append("SubscriberID");
            }
            if (subscriber.Birthdate.Year < 1880)
            {
                if (strb.Length != 0)
                {
                    strb.Append(",");
                }
                strb.Append("Subscriber Birthdate");
            }
            if (insPlan.GroupNum == "")
            {
                if (strb.Length != 0)
                {
                    strb.Append(",");
                }
                strb.Append("Group Number");
            }
            return(strb.ToString());
        }
Пример #15
0
 /// <summary>Sometimes SenderTIN, sometimes OD's TIN.</summary>
 public static string GetGS02(Clearinghouse clearhouse)
 {
     if (clearhouse.SenderTIN == "")
     {
         return(Sout("810624427", 15, 2));
     }
     else
     {
         return(Sout(clearhouse.SenderTIN, 15, 2));             //already validated to be length at least 2.
     }
 }
Пример #16
0
 ///<summary>If clearinghouseClin.SenderTIN is blank, then 810624427 will be used to indicate Open Dental.</summary>
 public static string GetISA06(Clearinghouse clearinghouseClin)
 {
     if (clearinghouseClin.SenderTIN == "")
     {
         return(Sout("810624427", 15, 15));             //TIN of OD.
     }
     else
     {
         return(Sout(clearinghouseClin.SenderTIN, 15, 15));             //already validated to be length at least 2.
     }
 }
Пример #17
0
        ///<summary></summary>
        public static void Delete(Clearinghouse clearhouse)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                Meth.GetVoid(MethodBase.GetCurrentMethod(), clearhouse);
                return;
            }
            string command = "DELETE FROM clearinghouse WHERE ClearinghouseNum = '" + POut.Long(clearhouse.ClearinghouseNum) + "'";

            Db.NonQ(command);
        }
Пример #18
0
        ///<summary>Replaces all clinic-level fields in ClearinghouseHq with non-blank fields
        ///from the clinic-level clearinghouse for the passed-in clinicNum. Non clinic-level fields are not replaced.
        ///If Clinics are disabled, uses clearinghouseHq settings.</summary>
        public static Clearinghouse OverrideFields(Clearinghouse clearinghouseHq, long clinicNum)
        {
            //No need to check RemotingRole; no call to db.
            //Do not use given clinicNum when clinics are disabled.
            //Otherwise clinic level clearinghouse settings that were set when clinics were enabled would be used
            //and user would have no way of fixing them unless they turned clinics back on.
            //Use unassigned settings since they are what show in the UI when editing clearinghouse settings.
            clinicNum = (PrefC.HasClinicsEnabled?clinicNum:0);
            Clearinghouse clearinghouseClin = Clearinghouses.GetForClinic(clearinghouseHq, clinicNum);

            return(OverrideFields(clearinghouseHq, clearinghouseClin));
        }
Пример #19
0
		///<summary>Called from Eclaims and includes multiple claims.</summary>
		public static string SendBatch(List<ClaimSendQueueItem> queueItems,int batchNum) {
			for(int i=0;i<queueItems.Count;i++) {
				//A setting for the clearinghouse could have changed so we need to always refresh the clearinghouse variable before sending any batches.
				if(i==0) {
					clearinghouse=Clearinghouses.GetClearinghouse(queueItems[i].ClearinghouseNum);
				}
				if(!CreateClaim(queueItems[i].PatNum,queueItems[i].ClaimNum,batchNum)) {
					return "";
				}
			}
			return "Sent";
		}
Пример #20
0
        ///<summary>Returns the clearinghouseNum for claims for the supplied payorID.  If the payorID was not entered or if no default was set, then 0 is returned.</summary>
        public static long AutomateClearinghouseSelection(string payorID, EnumClaimMedType medType)
        {
            //No need to check RemotingRole; no call to db.
            //payorID can be blank.  For example, Renaissance does not require payorID.
            if (HList == null)
            {
                RefreshCache();
            }
            Clearinghouse clearinghouse = null;

            if (medType == EnumClaimMedType.Dental)
            {
                if (PrefC.GetLong(PrefName.ClearinghouseDefaultDent) == 0)
                {
                    return(0);
                }
                clearinghouse = GetClearinghouse(PrefC.GetLong(PrefName.ClearinghouseDefaultDent));
            }
            if (medType == EnumClaimMedType.Medical || medType == EnumClaimMedType.Institutional)
            {
                if (PrefC.GetLong(PrefName.ClearinghouseDefaultMed) == 0)
                {
                    return(0);
                }
                clearinghouse = GetClearinghouse(PrefC.GetLong(PrefName.ClearinghouseDefaultMed));
            }
            if (clearinghouse == null)          //we couldn't find a default clearinghouse for that medType.  Needs to always be a default.
            {
                return(0);
            }
            if (payorID != "" && HList.ContainsKey(payorID))          //an override exists for this payorID
            {
                Clearinghouse ch = GetClearinghouse((long)HList[payorID]);
                if (ch.Eformat == ElectronicClaimFormat.x837D_4010 || ch.Eformat == ElectronicClaimFormat.x837D_5010_dental)
                {
                    if (medType == EnumClaimMedType.Dental)                  //med type matches
                    {
                        return(ch.ClearinghouseNum);
                    }
                }
                if (ch.Eformat == ElectronicClaimFormat.x837_5010_med_inst)
                {
                    if (medType == EnumClaimMedType.Medical || medType == EnumClaimMedType.Institutional)                //med type matches
                    {
                        return(ch.ClearinghouseNum);
                    }
                }
            }
            //no override, so just return the default.
            return(clearinghouse.ClearinghouseNum);
        }
Пример #21
0
        ///<summary></summary>
        public static string RetrieveAndImport(Clearinghouse clearinghouseClin, bool isAutomaticMode, IODProgressExtended progress = null
                                               , bool isTimeToRetrieve = false)
        {
            progress = progress ?? new ODProgressExtendedNull();
            string errorMessage      = "";
            bool   doRetrieveReports = isTimeToRetrieve || (!isAutomaticMode && IsTimeToRetrieveReports(isAutomaticMode, out errorMessage, progress));

            if (doRetrieveReports)             //Timer interval OK.  Now we can retrieve the reports from web services.
            {
                if (!isAutomaticMode)
                {
                    Prefs.UpdateDateT(PrefName.ClaimReportReceiveLastDateTime, DateTime.Now);
                }
                errorMessage = RetrieveReports(clearinghouseClin, isAutomaticMode, progress);
                if (errorMessage != "")
                {
                    progress.UpdateProgress(Lans.g(progress.LanThis, "Error getting reports, attempting to import manually downloaded reports."));
                }
                progress.UpdateProgress(Lans.g(progress.LanThis, "Report retrieval successful. Attempting to import."));
                //Don't return yet even if there was an error. This is so that Open Dental will automatically import reports that have been manually
                //downloaded to the Reports folder.
            }
            if (isAutomaticMode && clearinghouseClin.ResponsePath.Trim() == "")
            {
                return("");               //The user opened FormClaimsSend, or FormOpenDental called this function automatically.
            }
            if (progress.IsPauseOrCancel())
            {
                progress.UpdateProgress(Lans.g(progress.LanThis, "Canceled by user."));
                return(errorMessage);
            }
            string importErrors = ImportReportFiles(clearinghouseClin, progress);

            if (!string.IsNullOrWhiteSpace(importErrors))
            {
                if (string.IsNullOrWhiteSpace(errorMessage))
                {
                    errorMessage = importErrors;
                    progress.UpdateProgress(Lans.g(progress.LanThis, "Error importing."));
                }
                else
                {
                    errorMessage += "\r\n" + importErrors;
                }
            }
            if (string.IsNullOrWhiteSpace(errorMessage) && string.IsNullOrWhiteSpace(importErrors))
            {
                progress.UpdateProgress(Lans.g(progress.LanThis, "Import successful."));
            }
            return(errorMessage);
        }
Пример #22
0
		///<summary>Returns true if the communications were successful, and false if they failed.</summary>
		public static bool Launch(Clearinghouse clearhouse,int batchNum){
			try{
				//call the client program
				//Process process=
				Process.Start(clearhouse.ClientProgram);
				//process.EnableRaisingEvents=true;
				//process.WaitForExit();
			}
			catch{
				//X12.Rollback(clearhouse,batchNum);//doesn't actually do anything
				return false;
			}
			return true;
		}
Пример #23
0
        ///<summary>Returns the clearinghouseNum for claims for the supplied payorID.  If the payorID was not entered or if no default was set, then 0 is returned.</summary>
        public static long AutomateClearinghouseHqSelection(string payorID, EnumClaimMedType medType)
        {
            //No need to check RemotingRole; no call to db.
            //payorID can be blank.  For example, Renaissance does not require payorID.
            Clearinghouse clearinghouseHq = null;

            if (medType == EnumClaimMedType.Dental)
            {
                if (PrefC.GetLong(PrefName.ClearinghouseDefaultDent) == 0)
                {
                    return(0);
                }
                clearinghouseHq = GetClearinghouse(PrefC.GetLong(PrefName.ClearinghouseDefaultDent));
            }
            if (medType == EnumClaimMedType.Medical || medType == EnumClaimMedType.Institutional)
            {
                if (PrefC.GetLong(PrefName.ClearinghouseDefaultMed) == 0)
                {
                    return(0);
                }
                clearinghouseHq = GetClearinghouse(PrefC.GetLong(PrefName.ClearinghouseDefaultMed));
            }
            if (clearinghouseHq == null)          //we couldn't find a default clearinghouse for that medType.  Needs to always be a default.
            {
                return(0);
            }
            Clearinghouse clearingHouseOverride = GetClearinghouseByPayorID(payorID);

            if (clearingHouseOverride != null)           //an override exists for this payorID
            {
                if (clearingHouseOverride.Eformat == ElectronicClaimFormat.x837D_4010 || clearingHouseOverride.Eformat == ElectronicClaimFormat.x837D_5010_dental ||
                    clearingHouseOverride.Eformat == ElectronicClaimFormat.Canadian || clearingHouseOverride.Eformat == ElectronicClaimFormat.Ramq)
                {                                           //all dental formats
                    if (medType == EnumClaimMedType.Dental) //med type matches
                    {
                        return(clearingHouseOverride.ClearinghouseNum);
                    }
                }
                if (clearingHouseOverride.Eformat == ElectronicClaimFormat.x837_5010_med_inst)
                {
                    if (medType == EnumClaimMedType.Medical || medType == EnumClaimMedType.Institutional)                 //med type matches
                    {
                        return(clearingHouseOverride.ClearinghouseNum);
                    }
                }
            }
            //no override, so just return the default.
            return(clearinghouseHq.ClearinghouseNum);
        }
Пример #24
0
        ///<summary>Uses cache.</summary>
        public static CanadianNetwork GetNetwork(long networkNum, Clearinghouse clearinghouseClin)
        {
            //No need to check RemotingRole; no call to db.
            CanadianNetwork network = GetFirstOrDefault(x => x.CanadianNetworkNum == networkNum);

            //CSI is the previous name for the network now known as INSTREAM.
            //For ClaimStream, we use a "bidirect" such that any communication going to INSTREAM/CSI will be redirected to the TELUS B network instead.
            //This works because INSTREAM was bought out by TELUS and communications to both networks and handled by the same organization now.
            //Sending directly to INSTREAM fails with an error because TELUS expects us to use the "bidirect".
            if (clearinghouseClin.CommBridge == EclaimsCommBridge.Claimstream && network.Abbrev == "CSI")
            {
                network = GetFirstOrDefault(x => x.Abbrev == "TELUS B");
            }
            return(network);
        }
Пример #25
0
 public static void GenerateMessageText(StreamWriter sw,Clearinghouse clearhouse,int batchNum,List<ClaimSendQueueItem> listQueueItems,EnumClaimMedType medType)
 {
     if(clearhouse.SeparatorData=="") {
         s="*";
     }
     else {
         s=""+Encoding.ASCII.GetChars(new byte[] { Convert.ToByte(clearhouse.SeparatorData,16) })[0]; //Validated to be a 2 digit hexadecimal number in UI.
     }
     if(clearhouse.ISA16=="") {
         isa16=":";
     }
     else {
         isa16=""+Encoding.ASCII.GetChars(new byte[] { Convert.ToByte(clearhouse.ISA16,16) })[0]; //Validated to be a 2 digit hexadecimal number in UI.
     }
     if(clearhouse.SeparatorSegment=="") {
         endSegment="~"+Environment.NewLine;
     }
     else {
         endSegment=""+Encoding.ASCII.GetChars(new byte[] { Convert.ToByte(clearhouse.SeparatorSegment,16) })[0]+Environment.NewLine; //Validated to be a 2 digit hexadecimal number in UI.
     }
     //Interchange Control Header (Interchange number tracked separately from transactionNum)
     //We set it to between 1 and 999 for simplicity
     sw.Write("ISA"+s
         +"00"+s//ISA01 2/2 Authorization Information Qualifier: 00=No Authorization Information Present (No meaningful information in ISA02).
         +Sout(clearhouse.ISA02,10,10)+s//ISA02 10/10 Authorization Information: Blank
         +"00"+s//ISA03 2/2 Security Information Qualifier: 00=No Security Information Present (No meaningful information in ISA04).
         +Sout(clearhouse.ISA04,10,10)+s//ISA04 10/10 Security Information: Blank
         +clearhouse.ISA05+s//ISA05 2/2 Interchange ID Qualifier: ZZ=mutually defined. 30=TIN. Validated
         +X12Generator.GetISA06(clearhouse)+s//ISA06 15/15 Interchange Sender ID: Sender ID(TIN) Or might be TIN of Open Dental.
         +clearhouse.ISA07+s//ISA07 2/2 Interchange ID Qualifier: ZZ=mutually defined. 30=TIN. Validated
         +Sout(clearhouse.ISA08,15,15)+s//ISA08 15/15 Interchange Receiver ID: Validated to make sure length is at least 2.
         +DateTime.Today.ToString("yyMMdd")+s//ISA09 6/6 Interchange Date: today's date.
         +DateTime.Now.ToString("HHmm")+s//ISA10 4/4 Interchange Time: current time
         +"^"+s//ISA11 1/1 Repetition Separator:
         +"00501"+s//ISA12 5/5 Interchange Control Version Number:
         +batchNum.ToString().PadLeft(9,'0')+s//ISA13 9/9 Interchange Control Number:
         +"0"+s//ISA14 1/1 Acknowledgement Requested: 0=No Interchange Acknowledgment Requested.
         +clearhouse.ISA15+s//ISA15 1/1 Interchange Usage Indicator: T=Test, P=Production. Validated.
         +isa16//ISA16 1/1 Component Element Separator:
         +endSegment);
     //Just one functional group.
     WriteFunctionalGroup(sw,listQueueItems,batchNum,clearhouse,medType);
     //Interchange Control Trailer
     sw.Write("IEA"+s
         +"1"+s//IEA01 1/5 Number of Included Functional Groups:
         +batchNum.ToString().PadLeft(9,'0')//IEA02 9/9 Interchange Control Number:
         +endSegment);
 }
Пример #26
0
Файл: EDS.cs Проект: mnisl/OD
		///<summary>Sends an X12 270 request and returns X12 271 response or an error message.</summary>
		public static string Benefits270(Clearinghouse clearhouse,string x12message) {
			string retVal="";
			try {
				HttpWebRequest webReq;
				WebResponse webResponseXml;
				//Production URL.  For testing, set username to 'test' and password to 'test'.
				//When the username and password are both set to 'test', the X12 270 request will be ignored and just the transmission will be verified.
				webReq=(HttpWebRequest)WebRequest.Create("https://web2.edsedi.com/eds/Transmit_Request");
				webReq.KeepAlive=false;
				webReq.Method="POST";
				webReq.ContentType="text/xml";
				string postDataXml="<?xml version=\"1.0\" encoding=\"us-ascii\"?>"
					+"<content>"
						+"<header>"
							+"<userId>"+clearhouse.LoginID+"</userId>"
							+"<pass>"+clearhouse.Password+"</pass>"
							+"<process>transmitEligibility</process>"
							+"<version>1</version>"
						+"</header>"
						+"<body>"
							+"<type>EDI</type>"//Can only be EDI
							+"<data>"+x12message+"</data>"
							+"<returnType>EDI</returnType>"//Can be EDI, HTML, or EDI.HTML, but should mimic the above type
						+"</body>"
					+"</content>";
				ASCIIEncoding encoding=new ASCIIEncoding();
				byte[] arrayXmlBytes=encoding.GetBytes(postDataXml);
				Stream streamOut=webReq.GetRequestStream();
				streamOut.Write(arrayXmlBytes,0,arrayXmlBytes.Length);
				streamOut.Close();
				webResponseXml=webReq.GetResponse();
				//Process the response
				StreamReader readStream=new StreamReader(webResponseXml.GetResponseStream(),Encoding.ASCII);
				string responseXml=readStream.ReadToEnd();
				readStream.Close();
				XmlDocument xmlDoc=new XmlDocument();
				xmlDoc.LoadXml(responseXml);
				XmlNode nodeErrorCode=xmlDoc.SelectSingleNode(@"content/body/ERROR_CODE");
				if(nodeErrorCode!=null && nodeErrorCode.InnerText.ToString()!="0") {
					throw new Exception("Error Code: "+nodeErrorCode+" - "+xmlDoc.SelectSingleNode(@"content/body/ERROR_MSG").InnerText.ToString());
				}
				retVal=xmlDoc.SelectSingleNode(@"content/body/ediData").InnerText.ToString();
			}
			catch(Exception e) {
				retVal=e.Message;
			}
			return retVal;
		}
Пример #27
0
 ///<summary>Returns true if the communications were successful, and false if they failed. If they failed, a rollback will happen automatically by deleting the previously created X12 file. The batchnum is supplied for the possible rollback.  Also used for mail retrieval.</summary>
 public static bool Launch(Clearinghouse clearhouse,int batchNum)
 {
     string arguments="";
     try{
         if(!Directory.Exists(clearhouse.ExportPath)){
             throw new Exception("Clearinghouse export path is invalid.");
         }
         if(!Directory.Exists(clearhouse.ResponsePath)){
             throw new Exception("Clearinghouse response path is invalid.");
         }
         if(!File.Exists(clearhouse.ClientProgram)) {
             throw new Exception("Client program not installed properly.");
         }
         arguments=ODFileUtils.RemoveTrailingSeparators(clearhouse.ExportPath)+"\\"+"*.* "//upload claims path
             +ODFileUtils.RemoveTrailingSeparators(clearhouse.ResponsePath)+" "//Mail path
             +"316 "//vendor number.
             +clearhouse.LoginID+" "//Client number. Assigned by us, and we have to coordinate for all other 'vendors' of Open Dental, because there is only one vendor number for OD for now.
             +clearhouse.Password;
         //call the WebMD client program
         Process process=Process.Start(clearhouse.ClientProgram,arguments);
         process.EnableRaisingEvents=true;
         process.WaitForExit();
         //delete the uploaded claims
         string[] files=Directory.GetFiles(clearhouse.ExportPath);
         for(int i=0;i<files.Length;i++){
             //string t=files[i];
             File.Delete(files[i]);
         }
         //rename the downloaded mail files to end with txt
         files=Directory.GetFiles(clearhouse.ResponsePath);
         for(int i=0;i<files.Length;i++){
             //string t=files[i];
             if(Path.GetExtension(files[i])!=".txt"){
                 File.Move(files[i],files[i]+".txt");
             }
         }
     }
     catch(Exception e){
         MessageBox.Show(e.Message);//+"\r\n"+clearhouse.ClientProgram+" "+arguments);
         if(batchNum!=0){
             x837Controller.Rollback(clearhouse,batchNum);
         }
         return false;
     }
     return true;
 }
Пример #28
0
		///<summary>Gets the filename for this batch. Used when saving or when rolling back.</summary>
		private static string GetFileName(Clearinghouse clearhouse,int batchNum){
			string saveFolder=clearhouse.ExportPath;
			if(!Directory.Exists(saveFolder)) {
				MessageBox.Show(saveFolder+" not found.");
				return "";
			}
			if(clearhouse.CommBridge==EclaimsCommBridge.RECS){
				if(File.Exists(ODFileUtils.CombinePaths(saveFolder,"ecs.txt"))){
					MsgBox.Show("FormClaimsSend","You must send your existing claims from the RECS program before you can create another batch.");
					return "";//prevents overwriting an existing ecs.txt.
				}
				return ODFileUtils.CombinePaths(saveFolder,"ecs.txt");
			}
			else{
				return ODFileUtils.CombinePaths(saveFolder,"claims"+batchNum.ToString()+".txt");
			}
		}
Пример #29
0
 ///<summary>StringBuilder does not get altered if no invalid data.</summary>
 public static void ISA(Clearinghouse clearinghouseClin, StringBuilder strb)
 {
     if (clearinghouseClin.ISA05 != "01" && clearinghouseClin.ISA05 != "14" && clearinghouseClin.ISA05 != "20" && clearinghouseClin.ISA05 != "27" &&
         clearinghouseClin.ISA05 != "28" && clearinghouseClin.ISA05 != "29" && clearinghouseClin.ISA05 != "30" && clearinghouseClin.ISA05 != "33" &&
         clearinghouseClin.ISA05 != "ZZ")
     {
         Comma(strb);
         strb.Append("Clearinghouse ISA05");
     }
     if (clearinghouseClin.SenderTIN != "")           //if it IS blank, then we'll be using OD's info as the sender, so no need to validate the rest
     {
         if (clearinghouseClin.SenderTIN.Length < 2)
         {
             Comma(strb);
             strb.Append("Clearinghouse SenderTIN");
         }
         if (clearinghouseClin.SenderName == "")               //1000A NM103 min length=1
         {
             Comma(strb);
             strb.Append("Clearinghouse Sender Name");
         }
         if (!Regex.IsMatch(clearinghouseClin.SenderTelephone, @"^\d{10}$"))                //1000A PER04 min length=1
         {
             Comma(strb);
             strb.Append("Clearinghouse Sender Phone");
         }
     }
     if (clearinghouseClin.ISA07 != "01" && clearinghouseClin.ISA07 != "14" && clearinghouseClin.ISA07 != "20" && clearinghouseClin.ISA07 != "27" &&
         clearinghouseClin.ISA07 != "28" && clearinghouseClin.ISA07 != "29" && clearinghouseClin.ISA07 != "30" && clearinghouseClin.ISA07 != "33" &&
         clearinghouseClin.ISA07 != "ZZ")
     {
         Comma(strb);
         strb.Append("Clearinghouse ISA07");
     }
     if (clearinghouseClin.ISA08.Length < 2)
     {
         Comma(strb);
         strb.Append("Clearinghouse ISA08");
     }
     if (clearinghouseClin.ISA15 != "T" && clearinghouseClin.ISA15 != "P")
     {
         Comma(strb);
         strb.Append("Clearinghouse ISA15");
     }
 }
Пример #30
0
        ///<summary>Returns the clinic-level clearinghouse for the passed in Clearinghouse.  Usually used in conjunction with ReplaceFields().
        ///Can return null.</summary>
        public static Clearinghouse GetForClinic(Clearinghouse clearinghouseHq, long clinicNum)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                return(Meth.GetObject <Clearinghouse>(MethodBase.GetCurrentMethod(), clearinghouseHq, clinicNum));
            }
            if (clinicNum == 0)            //HQ
            {
                return(null);
            }
            string        command             = "SELECT * FROM clearinghouse WHERE HqClearinghouseNum=" + clearinghouseHq.ClearinghouseNum + " AND ClinicNum=" + clinicNum;
            Clearinghouse clearinghouseRetVal = Crud.ClearinghouseCrud.SelectOne(command);

            if (clearinghouseRetVal != null)
            {
                clearinghouseRetVal.Password = GetRevealPassword(clearinghouseRetVal.Password);
            }
            return(clearinghouseRetVal);
        }
Пример #31
0
        ///<summary>Returns the first clearinghouse that is associated to the corresponding payorID passed in.  Returns null if no match found.</summary>
        private static Clearinghouse GetClearinghouseByPayorID(string payorID)
        {
            //No need to check RemotingRole; no call to db.
            Clearinghouse clearinghouse = null;

            if (string.IsNullOrEmpty(payorID))
            {
                return(clearinghouse);
            }
            //Take the entire clearinghouse cache (which is typically small) and flatten it into a dictionary by payor ID to clearinhouse.
            //Each clearinghouse can be associated to multiple payor IDs (comma delimited string) so that must be broken down first.
            GetDeepCopy().Select(x => new {
                listPayorToHouse = x.Payors.Split(',').ToList()               //Take every clearinghouse's payors and split them up (comma delimited string per house).
                                   .Select(y => new { payor = y, house = x }) //Make a new object that ties the clearinghouse and payorID together (List<List<payor,house>>)
            }).SelectMany(x => x.listPayorToHouse)                            //Flatten the list of lists to make one long list of new objects (List<payor,house>)
            .GroupBy(x => x.payor)                                            //Group these new objects by the payor (if there are any duplicates we'll grab first in list)
            .ToDictionary(x => x.Key, x => x.First().house)                   //Make a dictionary out of the new objects where Key: payor Value: the first house
            .TryGetValue(payorID, out clearinghouse);                         //Try and find the corresponding clearinghouse via the payorID passed in.
            return(clearinghouse);                                            //Can return null and that is just fine.
        }
Пример #32
0
        ///<summary>Gets the last batch number from db for the HQ version of this clearinghouseClin and increments it by one.
        ///Then saves the new value to db and returns it.  So even if the new value is not used for some reason, it will have already been incremented.
        ///Remember that LastBatchNumber is never accurate with local data in memory.</summary>
        public static int GetNextBatchNumber(Clearinghouse clearinghouseClin)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                return(Meth.GetInt(MethodBase.GetCurrentMethod(), clearinghouseClin));
            }
            //get last batch number
            string command = "SELECT LastBatchNumber FROM clearinghouse "
                             + "WHERE ClearinghouseNum = " + POut.Long(clearinghouseClin.HqClearinghouseNum);
            DataTable table    = Db.GetTable(command);
            int       batchNum = PIn.Int(table.Rows[0][0].ToString());

            //and increment it by one
            if (clearinghouseClin.Eformat == ElectronicClaimFormat.Canadian)
            {
                if (batchNum == 999999)
                {
                    batchNum = 1;
                }
                else
                {
                    batchNum++;
                }
            }
            else
            {
                if (batchNum == 999)
                {
                    batchNum = 1;
                }
                else
                {
                    batchNum++;
                }
            }
            //save the new batch number. Even if user cancels, it will have incremented.
            command = "UPDATE clearinghouse SET LastBatchNumber=" + batchNum.ToString()
                      + " WHERE ClearinghouseNum = " + POut.Long(clearinghouseClin.HqClearinghouseNum);
            Db.NonQ(command);
            return(batchNum);
        }
Пример #33
0
		///<summary>StringBuilder does not get altered if no invalid data.</summary>
		public static void ISA(Clearinghouse clearhouse,StringBuilder strb) {
			if(clearhouse.ISA05!="01" && clearhouse.ISA05!="14" && clearhouse.ISA05!="20" && clearhouse.ISA05!="27" 
				&& clearhouse.ISA05!="28"	&& clearhouse.ISA05!="29" && clearhouse.ISA05!="30" && clearhouse.ISA05!="33"
				&& clearhouse.ISA05!="ZZ")
			{
				Comma(strb);
				strb.Append("Clearinghouse ISA05");
			}
			if(clearhouse.SenderTIN!="") {//if it IS blank, then we'll be using OD's info as the sender, so no need to validate the rest
				if(clearhouse.SenderTIN.Length<2) {
					Comma(strb);
					strb.Append("Clearinghouse SenderTIN");
				}
				if(clearhouse.SenderName=="") {//1000A NM103 min length=1
					Comma(strb);
					strb.Append("Clearinghouse Sender Name");
				}
				if(!Regex.IsMatch(clearhouse.SenderTelephone,@"^\d{10}$")) {//1000A PER04 min length=1
					Comma(strb);
					strb.Append("Clearinghouse Sender Phone");
				}
			}
			if(clearhouse.ISA07!="01" && clearhouse.ISA07!="14" && clearhouse.ISA07!="20" && clearhouse.ISA07!="27" 
				&& clearhouse.ISA07!="28"	&& clearhouse.ISA07!="29" && clearhouse.ISA07!="30" && clearhouse.ISA07!="33"
				&& clearhouse.ISA07!="ZZ") 
			{
				Comma(strb);
				strb.Append("Clearinghouse ISA07");
			}
			if(clearhouse.ISA08.Length<2) {
				Comma(strb);
				strb.Append("Clearinghouse ISA08");
			}
			if(clearhouse.ISA15!="T" && clearhouse.ISA15!="P") {
				Comma(strb);
				strb.Append("Clearinghouse ISA15");
			}
		}
Пример #34
0
		///<summary>Returns true if the communications were successful, and false if they failed. Both sends and retrieves.</summary>
		public static bool Launch(Clearinghouse clearhouse,int batchNum) {
			clearinghouse=clearhouse;
			//Before this function is called, the X12 file for the current batch has already been generated in
			//the clearinghouse export folder. The export folder will also contain batch files which have failed
			//to upload from previous attempts and we must attempt to upload these older batch files again if
			//there are any.
			//Step 1: Retrieve reports regarding the existing pending claim statuses.
			//Step 2: Send new claims in a new batch.
			bool success=true;
			//Connect to the Denti-Cal SFTP server.
			Session session=null;
			Channel channel=null;
			ChannelSftp ch=null;
			JSch jsch=new JSch();
			try {
				session=jsch.getSession(clearinghouse.LoginID,remoteHost);
				session.setPassword(clearinghouse.Password);
				Hashtable config=new Hashtable();
				config.Add("StrictHostKeyChecking","no");
				session.setConfig(config);
				session.connect();
				channel=session.openChannel("sftp");
				channel.connect();
				ch=(ChannelSftp)channel;
			}
			catch(Exception ex) {
				MessageBox.Show(Lan.g("DentiCal","Connection Failed")+": "+ex.Message);
				return false;
			}
			try {
				string homeDir="/Home/"+clearhouse.LoginID+"/";
				//At this point we are connected to the Denti-Cal SFTP server.
				if(batchNum==0) { //Retrieve reports.
					if(!Directory.Exists(clearhouse.ResponsePath)) {
						throw new Exception("Clearinghouse response path is invalid.");
					}
					//Only retrieving reports so do not send new claims.
					string retrievePath=homeDir+"out/";
					Tamir.SharpSsh.java.util.Vector fileList=ch.ls(retrievePath);
					for(int i=0;i<fileList.Count;i++) {
						string listItem=fileList[i].ToString().Trim();
						if(listItem[0]=='d') {
							continue;//Skip directories and focus on files.
						}
						Match fileNameMatch=Regex.Match(listItem,".*\\s+(.*)$");
						string getFileName=fileNameMatch.Result("$1");
						string getFilePath=retrievePath+getFileName;
						string exportFilePath=CodeBase.ODFileUtils.CombinePaths(clearhouse.ResponsePath,getFileName);
						Tamir.SharpSsh.java.io.InputStream fileStream=null;
						FileStream exportFileStream=null;
						try {
							fileStream=ch.get(getFilePath);
							exportFileStream=File.Open(exportFilePath,FileMode.Create,FileAccess.Write);//Creates or overwrites.
							byte[] dataBytes=new byte[4096];
							int numBytes=fileStream.Read(dataBytes,0,dataBytes.Length);
							while(numBytes>0) {
								exportFileStream.Write(dataBytes,0,numBytes);
								numBytes=fileStream.Read(dataBytes,0,dataBytes.Length);
							}
						}
						catch {
							success=false;
						}
						finally {
							if(exportFileStream!=null) {
								exportFileStream.Dispose();
							}
							if(fileStream!=null) {
								fileStream.Dispose();
							}
						}
						if(success) {
							//Removed the processed report from the Denti-Cal SFTP so it does not get processed again in the future.
							try {
								ch.rm(getFilePath);
							}
							catch {
							}
						}
					}
				}
				else { //Send batch of claims.
					if(!Directory.Exists(clearhouse.ExportPath)) {
						throw new Exception("Clearinghouse export path is invalid.");
					}
					string[] files=Directory.GetFiles(clearhouse.ExportPath);
					for(int i=0;i<files.Length;i++) {
						//First upload the batch file to a temporary file name. Denti-Cal does not process file names unless they start with the Login ID.
						//Uploading to a temporary file and then renaming the file allows us to avoid partial file uploads if there is connection loss.
						string tempRemoteFilePath=homeDir+"in/temp_"+Path.GetFileName(files[i]);
						ch.put(files[i],tempRemoteFilePath);
						//Denti-Cal requires the file name to start with the Login ID followed by a period and end with a .txt extension.
						//The middle part of the file name can be anything.
						string remoteFilePath=homeDir+"in/"+clearhouse.LoginID+"."+Path.GetFileName(files[i]);
						ch.rename(tempRemoteFilePath,remoteFilePath);
						File.Delete(files[i]);//Remove the processed file.
					}
				}
			}
			catch {
				success=false;
			}
			finally {
				//Disconnect from the Denti-Cal SFTP server.
				channel.disconnect();
				ch.disconnect();
				session.disconnect();
			}
			return success;
		}
Пример #35
0
		private const string emdeonServerUrl="";//TODO: Get from Emdeon!

		private static void SubmitBatch(Clearinghouse clearhouse,int batchNum){
			string[] files=Directory.GetFiles(clearhouse.ExportPath);
			for(int i=0;i<files.Length;i++){
				ZipFile zip=null;
				try{
					zip=new ZipFile();
					zip.AddFile(files[i]);
					MemoryStream ms=new MemoryStream();
					zip.Save(ms);
					string fileTextZippedBase64=Convert.ToBase64String(ms.GetBuffer());
					FileInfo fi=new FileInfo(files[i]);
					string claimXML="<?xml version=\"1.0\" ?>"
						+"<claim_submission_api xmlns=\"Emdeon_claim_submission_api\" revision=\"001\">"
							+"<authentication>"
								+"<vendor_id>"+vendorId+"</vendor_id>"
								+"<user_id>"+clearhouse.LoginID+"</user_id>"
								+"<password>"+clearhouse.Password+"</password>"
							+"</authentication>"
							+"<transaction>"
							+"<trace_id>"+batchNum+"</trace_id>"//TODO: Is this the right number to use?
							+"<trx_type>submit_claim_file_request</trx_type>"
							+"<test_mode>"+testMode+"</test_mode>"
							+"<trx_data>"
								+"<claim_file>"
									+"<file_name>"+Path.GetFileName(files[i])+"</file_name>"
									+"<file_format>DCDS2</file_format>"
									+"<file_size>"+fi.Length+"</file_size>"
									+"<file_compression>pkzip</file_compression>"
									+"<file_encoding>base64</file_encoding>"
									+"<file_data>"+fileTextZippedBase64+"</file_data>"
								+"</claim_file>"
							+"</trx_data>"
						+"</transaction>"
					+"</claim_submission_api>";
					byte[] claimXMLbytes=Encoding.UTF8.GetBytes(claimXML);
					WebClient myWebClient=new WebClient();
					myWebClient.Headers.Add("Content-Type","text/xml");
					byte[] responseBytes=myWebClient.UploadData(emdeonServerUrl,claimXMLbytes);




				}finally{
					if(zip!=null){
						zip.Dispose();
					}
				}
			}
		}
Пример #36
0
 ///<summary>Calling methods will typically pass in all non-HQ clearinghouses (overrides).
 ///This method will "sync" any clearinghouses that are associated to the same HQ Clearinghouse and Clinic with the values from clearinghouseNew.
 ///This method is only used in FormClearinghouseEdit.cs to defend against DB's with duplicate override rows.
 ///Loops through the list of overrides and updates each clearinghouse override associated to clearinghouseNew.ClinicNum.
 ///This was put into a centralized method for unit testing purposes. For more details see jobnum 11387.</summary>
 ///<param name="listClearinghouseOverrides">A list of all non-HQ clearinghouses which this method will manipulate (Clearinghouse overrides).</param>
 ///<param name="clearinghouseNew">The new Clearinghouse override object.  ClinicNum will be used from this clearinghouse.</param>
 public static void SyncOverridesForClinic(ref List <Clearinghouse> listClearinghouseOverrides, Clearinghouse clearinghouseNew)
 {
     //No need to check RemotingRole; no call to db and uses an out parameter.
     if (clearinghouseNew.ClinicNum == 0)
     {
         return;                //Nothing to do when the ClinicNum associated to clearinghouseNew is 0.
     }
     //Get all clearinghouse overrides that are associated to the same HQ clearinghouse and clinic.
     for (int i = 0; i < listClearinghouseOverrides.Count; i++)
     {
         if (listClearinghouseOverrides[i].HqClearinghouseNum != clearinghouseNew.HqClearinghouseNum ||
             listClearinghouseOverrides[i].ClinicNum != clearinghouseNew.ClinicNum)
         {
             continue;
         }
         //Take all of the values from clearinghouseNew and put them into the current clearinghouseOverride (sync them).
         //Make sure to preserve the ClearinghouseNum of the override before syncing the values.
         long clearinghouseNumOverride = listClearinghouseOverrides[i].ClearinghouseNum;
         listClearinghouseOverrides[i] = clearinghouseNew.Copy();
         listClearinghouseOverrides[i].ClearinghouseNum = clearinghouseNumOverride;
     }
 }
Пример #37
0
		private static string GetCarrierElectID(Carrier carrier,Clearinghouse clearhouse) {
			string electid=carrier.ElectID;
			if(electid=="" && IsApex(clearhouse)) {//only for Apex
				return "PAPRM";//paper claims
			}
			if(electid=="" && IsTesia(clearhouse)) {//only for Tesia
				return "00000";//paper claims
			}
			if(electid.Length<3) {
				return "06126";//paper claims
			}
			return electid;
		}
Пример #38
0
        ///<summary>In progress.  Probably needs a different name.  Info must be validated first.</summary>
        public static string GenerateMessageText(Clearinghouse clearhouse,Carrier carrier,Provider billProv,Clinic clinic,InsPlan insPlan,Patient subscriber,InsSub insSub)
        {
            int batchNum=Clearinghouses.GetNextBatchNumber(clearhouse);
            string groupControlNumber=batchNum.ToString();//Must be unique within file.  We will use batchNum
            int transactionNum=1;
            StringBuilder strb=new StringBuilder();
            //Interchange Control Header
            strb.AppendLine("ISA*00*          *"//ISA01,ISA02: 00 + 10 spaces
                +"00*          *"//ISA03,ISA04: 00 + 10 spaces
                +clearhouse.ISA05+"*"//ISA05: Sender ID type: ZZ=mutually defined. 30=TIN. Validated
                +X12Generator.GetISA06(clearhouse)+"*"//ISA06: Sender ID(TIN). Or might be TIN of Open Dental
                +clearhouse.ISA07+"*"//ISA07: Receiver ID type: ZZ=mutually defined. 30=TIN. Validated
                +Sout(clearhouse.ISA08,15,15)+"*"//ISA08: Receiver ID. Validated to make sure length is at least 2.
                +DateTime.Today.ToString("yyMMdd")+"*"//ISA09: today's date
                +DateTime.Now.ToString("HHmm")+"*"//ISA10: current time
                +"U*00401*"//ISA11 and ISA12.
                //ISA13: interchange control number, right aligned:
                +batchNum.ToString().PadLeft(9,'0')+"*"
                +"0*"//ISA14: no acknowledgment requested
                +clearhouse.ISA15+"*"//ISA15: T=Test P=Production. Validated.
                +":~");//ISA16: use ':'
            //Functional Group Header
            strb.AppendLine("GS*HS*"//GS01: HS for 270 benefit inquiry
                +X12Generator.GetGS02(clearhouse)+"*"//GS02: Senders Code. Sometimes Jordan Sparks.  Sometimes the sending clinic.
                +Sout(clearhouse.GS03,15,2)+"*"//GS03: Application Receiver's Code
                +DateTime.Today.ToString("yyyyMMdd")+"*"//GS04: today's date
                +DateTime.Now.ToString("HHmm")+"*"//GS05: current time
                +groupControlNumber+"*"//GS06: Group control number. Max length 9. No padding necessary.
                +"X*"//GS07: X
                +"004010X092~");//GS08: Version
            //Beginning of transaction--------------------------------------------------------------------------------
            int seg=0;//count segments for the ST-SE transaction
            //Transaction Set Header
            //ST02 Transact. control #. Must be unique within ISA
            seg++;
            strb.AppendLine("ST*270*"//ST01
                +transactionNum.ToString().PadLeft(4,'0')+"~");//ST02
            seg++;
            strb.AppendLine("BHT*0022*13*"//BHT02: 13=request
                +transactionNum.ToString().PadLeft(4,'0')+"*"//BHT03. Can be same as ST02
                +DateTime.Now.ToString("yyyyMMdd")+"*"//BHT04: Date
                +DateTime.Now.ToString("HHmmss")+"~");//BHT05: Time, BHT06: not used
            //HL Loops-----------------------------------------------------------------------------------------------
            int HLcount=1;
            //2000A HL: Information Source--------------------------------------------------------------------------
            seg++;
            strb.AppendLine("HL*"+HLcount.ToString()+"*"//HL01: Heirarchical ID.  Here, it's always 1.
                +"*"//HL02: No parent. Not used
                +"20*"//HL03: Heirarchical level code. 20=Information source
                +"1~");//HL04: Heirarchical child code. 1=child HL present
            //2100A NM1
            seg++;
            strb.AppendLine("NM1*PR*"//NM101: PR=Payer
                +"2*"//NM102: 2=Non person
                +Sout(carrier.CarrierName,35)+"*"//NM103: Name Last.
                +"****"//NM104-07 not used
                +"PI*"//NM108: PI=PayorID
                +Sout(carrier.ElectID,80,2)+"~");//NM109: PayorID. Validated to be at least length of 2.
            HLcount++;
            //2000B HL: Information Receiver------------------------------------------------------------------------
            seg++;
            strb.AppendLine("HL*"+HLcount.ToString()+"*"//HL01: Heirarchical ID.  Here, it's always 2.
                +"1*"//HL02: Heirarchical parent id number.  1 in this simple message.
                +"21*"//HL03: Heirarchical level code. 21=Information receiver
                +"1~");//HL04: Heirarchical child code. 1=child HL present
            seg++;
            //2100B NM1: Information Receiver Name
            strb.AppendLine("NM1*1P*"//NM101: 1P=Provider
                +(billProv.IsNotPerson?"2":"1")+"*"//NM102: 1=person,2=non-person
                +Sout(billProv.LName,35)+"*"//NM103: Last name
                +Sout(billProv.FName,25)+"*"//NM104: First name
                +Sout(billProv.MI,25,1)+"*"//NM105: Middle name
                +"*"//NM106: not used
                +"*"//NM107: Name suffix. not used
                +"XX*"//NM108: ID code qualifier. 24=EIN. 34=SSN, XX=NPI
                +Sout(billProv.NationalProvID,80)+"~");//NM109: ID code. NPI validated
            //2100B REF: Information Receiver ID
            seg++;
            strb.Append("REF*");
            if(billProv.UsingTIN) {
                strb.Append("TJ*");//REF01: qualifier. TJ=Federal TIN
            }
            else {//SSN
                strb.Append("SY*");//REF01: qualifier. SY=SSN
            }
            strb.AppendLine(Sout(billProv.SSN,30)+"~");//REF02: ID
            //2100B N3: Information Receiver Address
            seg++;
            if(PrefC.GetBool(PrefName.UseBillingAddressOnClaims)) {
                strb.Append("N3*"+Sout(PrefC.GetString(PrefName.PracticeBillingAddress),55));//N301: Address
            }
            else if(clinic==null) {
                strb.Append("N3*"+Sout(PrefC.GetString(PrefName.PracticeAddress),55));//N301: Address
            }
            else {
                strb.Append("N3*"+Sout(clinic.Address,55));//N301: Address
            }
            if(PrefC.GetBool(PrefName.UseBillingAddressOnClaims)) {
                if(PrefC.GetString(PrefName.PracticeBillingAddress2)=="") {
                    strb.AppendLine("~");
                }
                else {
                    //N302: Address2. Optional.
                    strb.AppendLine("*"+Sout(PrefC.GetString(PrefName.PracticeBillingAddress2),55)+"~");
                }
            }
            else if(clinic==null) {
                if(PrefC.GetString(PrefName.PracticeAddress2)=="") {
                    strb.AppendLine("~");
                }
                else {
                    //N302: Address2. Optional.
                    strb.AppendLine("*"+Sout(PrefC.GetString(PrefName.PracticeAddress2),55)+"~");
                }
            }
            else {
                if(clinic.Address2=="") {
                    strb.AppendLine("~");
                }
                else {
                    //N302: Address2. Optional.
                    strb.AppendLine("*"+Sout(clinic.Address2,55)+"~");
                }
            }
            //2100B N4: Information Receiver City/State/Zip
            seg++;
            if(PrefC.GetBool(PrefName.UseBillingAddressOnClaims)) {
                strb.AppendLine("N4*"+Sout(PrefC.GetString(PrefName.PracticeBillingCity),30)+"*"//N401: City
                    +Sout(PrefC.GetString(PrefName.PracticeBillingST),2)+"*"//N402: State
                    +Sout(PrefC.GetString(PrefName.PracticeBillingZip).Replace("-",""),15)+"~");//N403: Zip
            }
            else if(clinic==null) {
                strb.AppendLine("N4*"+Sout(PrefC.GetString(PrefName.PracticeCity),30)+"*"//N401: City
                    +Sout(PrefC.GetString(PrefName.PracticeST),2)+"*"//N402: State
                    +Sout(PrefC.GetString(PrefName.PracticeZip).Replace("-",""),15)+"~");//N403: Zip
            }
            else {
                strb.AppendLine("N4*"+Sout(clinic.City,30)+"*"//N401: City
                    +Sout(clinic.State,2)+"*"//N402: State
                    +Sout(clinic.Zip.Replace("-",""),15)+"~");//N403: Zip
            }
            //2100B PRV: Information Receiver Provider Info
            seg++;
            //PRV*PE*ZZ*1223G0001X~
            strb.AppendLine("PRV*PE*"//PRV01: Provider Code. PE=Performing.  There are many other choices.
                +"ZZ*"//PRV02: ZZ=Mutually defined = health care provider taxonomy code
                +X12Generator.GetTaxonomy(billProv)+"~");//PRV03: Specialty code
            HLcount++;
            //2000C HL: Subscriber-----------------------------------------------------------------------------------
            seg++;
            strb.AppendLine("HL*"+HLcount.ToString()+"*"//HL01: Heirarchical ID.  Here, it's always 3.
                +"2*"//HL02: Heirarchical parent id number.  2 in this simple message.
                +"22*"//HL03: Heirarchical level code. 22=Subscriber
                +"0~");//HL04: Heirarchical child code. 0=no child HL present (no dependent)
            //2000C TRN: Subscriber Trace Number
            seg++;
            strb.AppendLine("TRN*1*"//TRN01: Trace Type Code.  1=Current Transaction Trace Numbers
                +"1*"//TRN02: Trace Number.  We don't really have a good primary key yet.  Keep it simple. Use 1.
                +"1"+billProv.SSN+"~");//TRN03: Entity Identifier. First digit is 1=EIN.  Next 9 digits are EIN.  Length validated.
            //2100C NM1: Subscriber Name
            seg++;
            strb.AppendLine("NM1*IL*"//NM101: IL=Insured or Subscriber
                +"1*"//NM102: 1=Person
                +Sout(subscriber.LName,35)+"*"//NM103: LName
                +Sout(subscriber.FName,25)+"*"//NM104: FName
                +Sout(subscriber.MiddleI,25)+"*"//NM105: MiddleName
                +"*"//NM106: not used
                +"*"//NM107: suffix. Not present in Open Dental yet.
                +"MI*"//NM108: MI=MemberID
                +Sout(insSub.SubscriberID.Replace("-",""),80)+"~");//NM109: Subscriber ID. Validated to be L>2.
            //2100C REF: Subscriber Additional Information.  Without this, old plans seem to be frequently returned.
            seg++;
            strb.AppendLine("REF*6P*"//REF01: 6P=GroupNumber
                +Sout(insPlan.GroupNum,30)+"~");//REF02: Supplemental ID. Validated.
            //2100C DMG: Subscriber Demographic Information
            seg++;
            strb.AppendLine("DMG*D8*"//DMG01: Date Time Period Qualifier.  D8=CCYYMMDD
                +subscriber.Birthdate.ToString("yyyyMMdd")+"~");//DMG02: Subscriber birthdate.  Validated
                //DMG03: Gender code.  Situational.  F or M.  Since this was left out in the example,
                //and since we don't want to send the wrong gender, we will not send this element.
            //2100C DTP: Subscriber Date.  Deduced through trial and error that this is required by EHG even though not by X12 specs.
            seg++;
            strb.AppendLine("DTP*307*"//DTP01: Qualifier.  307=Eligibility
                +"D8*"//DTP02: Format Qualifier.
                +DateTime.Today.ToString("yyyyMMdd")+"~");//DTP03: Date
            //2110C EQ: Subscriber Eligibility or Benefit Enquiry Information
            //We can loop this 99 times to request very specific benefits.
            //strb.AppendLine("EQ*30~");//EQ01: 30=General Coverage
            seg++;
            strb.AppendLine("EQ*23~");//Diagnostic
            seg++;
            strb.AppendLine("EQ*4~");//Diagnostic Xray
            seg++;
            strb.AppendLine("EQ*41~");//Routine Preventive
            seg++;
            strb.AppendLine("EQ*25~");//Restorative
            seg++;
            strb.AppendLine("EQ*26~");//Endo
            seg++;
            strb.AppendLine("EQ*24~");//Perio
            seg++;
            strb.AppendLine("EQ*40~");//Oral Surgery
            seg++;
            strb.AppendLine("EQ*36~");//Crowns
            seg++;
            strb.AppendLine("EQ*39~");//Prosth
            seg++;
            strb.AppendLine("EQ*27~");//Maxillofacial Prosth
            seg++;
            strb.AppendLine("EQ*37~");//Accident
            seg++;
            strb.AppendLine("EQ*38~");//Ortho
            seg++;
            strb.AppendLine("EQ*28~");//Adjunctive
            //
            //2000D If we add a dependent loop it would go here.  It would be about 20 lines.
            //2100D, etc
            //EQ series, etc.
            //Not allowed to send this unless subscriber and dependent are different
            //We would also have to add code to process the EBs which distinguishes between subscribers and dependents.
            //
            //Transaction Trailer
            seg++;
            strb.AppendLine("SE*"
                +seg.ToString()+"*"//SE01: Total segments, including ST & SE
                +transactionNum.ToString().PadLeft(4,'0')+"~");
            //End of transaction--------------------------------------------------------------------------------------
            //Functional Group Trailer
            strb.AppendLine("GE*"+transactionNum.ToString()+"*"//GE01: Number of transaction sets included
                +groupControlNumber+"~");//GE02: Group Control number. Must be identical to GS06
            //Interchange Control Trailer
            strb.AppendLine("IEA*1*"//IEA01: number of functional groups
                +batchNum.ToString().PadLeft(9,'0')+"~");//IEA02: Interchange control number
            return strb.ToString();
            /*
            return @"
            ISA*00*          *00*          *30*AA0989922      *30*330989922      *030519*1608*U*00401*000012145*1*T*:~
            GS*HS*AA0989922*330989922*20030519*1608*12145*X*004010X092~
            ST*270*0001~
            BHT*0022*13*ASX012145WEB*20030519*1608~
            HL*1**20*1~
            NM1*PR*2*Metlife*****PI*65978~
            HL*2*1*21*1~
            NM1*1P*1*PROVLAST*PROVFIRST****XX*1234567893~
            REF*TJ*200384584~
            N3*JUNIT ROAD~
            N4*CHICAGO*IL*60602~
            PRV*PE*ZZ*1223G0001X~
            HL*3*2*22*0~
            TRN*1*12145*1AA0989922~
            NM1*IL*1*SUBLASTNAME*SUBFIRSTNAME****MI*123456789~
            DMG*D8*19750323~
            DTP*307*D8*20030519~
            EQ*30~
            SE*17*0001~
            GE*1*12145~
            IEA*1*000012145~";
            */

            //return "ISA*00*          *00*          *30*AA0989922      *30*330989922      *030519*1608*U*00401*000012145*1*T*:~GS*HS*AA0989922*330989922*20030519*1608*12145*X*004010X092~ST*270*0001~BHT*0022*13*ASX012145WEB*20030519*1608~HL*1**20*1~NM1*PR*2*Metlife*****PI*65978~HL*2*1*21*1~NM1*1P*1*PROVLAST*PROVFIRST****XX*1234567893~REF*TJ*200384584~N3*JUNIT ROAD~N4*CHICAGO*IL*60602~PRV*PE*ZZ*1223G0001X~HL*3*2*22*0~TRN*1*12145*1AA0989922~NM1*IL*1*SUBLASTNAME*SUBFIRSTNAME****MI*123456789~DMG*D8*19750323~DTP*307*D8*20030519~EQ*30~SE*17*0001~GE*1*12145~IEA*1*000012145~";
        }
Пример #39
0
        ///<summary>Returns a blank string if there were no errors while attempting to update internal carriers using iTrans n-cpl.json file.</summary>
        public static string TryCarrierUpdate(bool isAutomatic = true, ItransImportFields fieldsToImport = ItransImportFields.None)
        {
            string        json;
            DateTime      dateTimeTrans = DateTime.Now;
            Clearinghouse clearinghouse = Clearinghouses.GetDefaultDental();

            if (clearinghouse == null)
            {
                return(Lans.g("Clearinghosue", "Unable to update. No default dental clearinghouse set."));
            }
            //If ITRANS2 is fully setup, then use the local ITRANS2 install on server to import carrier data.
            if (clearinghouse.CommBridge == EclaimsCommBridge.ITRANS && !string.IsNullOrEmpty(clearinghouse.ResponsePath))
            {
                if (!File.Exists(ODFileUtils.CombinePaths(clearinghouse.ResponsePath, "ITRANS Claims Director.exe")))
                {
                    return(Lans.g("Clearinghouse", "Unable to find 'ITRANS Claims Director.exe'. Make sure the file exists and the path is correct."));
                }
                if (isAutomatic && PrefC.GetString(PrefName.WebServiceServerName).ToLower() != Dns.GetHostName().ToLower())               //Only server can run when isOnlyServer is true.
                {
                    return(Lans.g("Clearinghouse", "Update can only run on the web service server " + PrefC.GetString(PrefName.WebServiceServerName)) +
                           ". " + Lans.g("Clearinghouse", "Connect to the server and try again."));
                }
                Process process = new Process {
                    StartInfo = new ProcessStartInfo {
                        FileName  = ODFileUtils.CombinePaths(clearinghouse.ResponsePath, "ITRANS Claims Director.exe"),
                        Arguments = " --getncpl"
                    }
                };
                process.Start();
                process.WaitForExit();
                string ncplFilePath = ODFileUtils.CombinePaths(clearinghouse.ResponsePath, "n-cpl.json");
                json          = File.ReadAllText(ncplFilePath);     //Read n-cpl.json
                dateTimeTrans = File.GetCreationTime(ncplFilePath);
            }
            else              //ITRANS2 not used or not setup correctly, go to HQ for file content.
            {
                try {
                    string result = WebServiceMainHQProxy.GetWebServiceMainHQInstance().CanadaCarrierUpdate(PayloadHelper.CreatePayload("", eServiceCode.Undefined));
                    json = WebSerializer.DeserializePrimitiveOrThrow <string>(result);
                }
                catch (Exception ex) {
                    return(Lans.g("Clearinghouse", "Unable to update carrier list from HQ web services.") + "\r\n" + ex.Message.ToString());
                }
            }
            EtransMessageText msgTextPrev = EtransMessageTexts.GetMostRecentForType(EtransType.ItransNcpl);

            if (msgTextPrev != null && msgTextPrev.MessageText == json)
            {
                if (isAutomatic ||
                    ODMessageBox.Show("Carrier list has not changed since last checked.\r\nContinue?", "", MessageBoxButtons.YesNo) != DialogResult.Yes)
                {
                    return(Lans.g("Clearinghouse", "Carrier list has not changed since last checked."));                  //json has not changed since we last checked, no need to update.
                }
            }
            //Save json as new etrans entry.
            Etrans etrans = Etranss.CreateEtrans(dateTimeTrans, clearinghouse.HqClearinghouseNum, json, 0);

            etrans.Etype = EtransType.ItransNcpl;
            Etranss.Insert(etrans);
            ItransNCpl iTransNCpl = null;

            try {
                iTransNCpl = JsonConvert.DeserializeObject <ItransNCpl>(json);             //Deserialize n-cpl.json
            }
            catch (Exception ex) {
                ex.DoNothing();
                return(Lans.g("Clearinghouse", "Failed to import json."));
            }
            List <CanadianNetwork> listCanadianNetworks = CanadianNetworks.GetDeepCopy();
            //List of carriers from json file that were matched by electId to multiple internal carriers
            List <Carrier> listUnmatchedJsonCarriers = new List <Carrier>();
            List <long>    listMatchedDbCarrierNums  = new List <long> ();

            foreach (ItransNCpl.Carrier jsonCarrier in iTransNCpl.ListCarriers) //Update carriers.
            {
                string jsonCarrierPhone = jsonCarrier.Telephone?.First().Value; //Will be empty string if not found.
                List <OpenDentBusiness.Carrier> listDbCarriers = Carriers.GetAllByElectId(jsonCarrier.Bin).FindAll(x => x.IsCDA);
                if (listDbCarriers.Count > 1)                                   //Some Canadian carriers share ElectId, need to filter further.  This happens with carrier resellers.
                {
                    #region Additional matching based on phone numbers, 'continues' loop if a single match is not found.
                    List <OpenDentBusiness.Carrier> listPhoneMatchedDbCarriers = listDbCarriers.FindAll(x =>
                                                                                                        TelephoneNumbers.AreNumbersEqual(x.Phone, jsonCarrierPhone)
                                                                                                        );
                    if (listPhoneMatchedDbCarriers.Count != 1)                   //Either 0 or multiple matches, either way do not update any carriers.
                    //When 0 matches found:	jsonCarrier changed their phone number, can not determine which carrier to update.
                    //E.G. - JsonCarrier A matched to OD carriers B and C by electId.
                    //Phone number from JsonCarrier A did not match either carrier B or C due to jsonCarrier phone number change.
                    //Future iterations for jsonCarrier D might match to carrier B or C if phone number for jsonCarrier D did not change.
                    //If jsonCarrier D is matched to single OD carrier, then jsonCarrier A will attempt to match near end of method to a unmatched internal carrier.
                    //If ther are no future matches to OD carrier B or C then all unmatched jsonCarriers will not be imported and no OD carries will not be updated.
                    //----------------------------------------------------------------------//
                    //When greater than 1:	jsonCarrier number not changed and both internal carriers have matching electIds and phone numbers.
                    //This should be rare, most likely a setup error.
                    //There should not be multiple carriers that share electId and phone numbers. User should change or remove one of the matched carriers.
                    {
                        listUnmatchedJsonCarriers.Add(jsonCarrier);
                        continue;
                    }
                    listDbCarriers = listPhoneMatchedDbCarriers;
                    #endregion
                }
                //At this point listDbCarriers should either be empty or contain a single OD carrier.
                OpenDentBusiness.Carrier carrierInDb = listDbCarriers.FirstOrDefault(); //Null if list is empty.
                if (carrierInDb == null)                                                //Carrier can not be matched to internal Carrier based on ElectID.
                {
                    #region Insert new carrier
                    if (!fieldsToImport.HasFlag(ItransImportFields.AddMissing))
                    {
                        continue;
                    }
                    OpenDentBusiness.Carrier carrierNew = new OpenDentBusiness.Carrier();
                    carrierNew.CanadianEncryptionMethod = 1;                  //Default.  Deprecated for all Canadian carriers and will never be any other value.
                    TrySetCanadianNetworkNum(jsonCarrier, carrierNew, listCanadianNetworks);
                    carrierNew.ElectID     = jsonCarrier.Bin;
                    carrierNew.IsCDA       = true;
                    carrierNew.CarrierName = jsonCarrier.Name.En;
                    carrierNew.Phone       = TelephoneNumbers.AutoFormat(jsonCarrierPhone);
                    if (jsonCarrier.Address.Count() > 0)
                    {
                        Address add = jsonCarrier.Address.First();
                        carrierNew.Address  = add.Street1;
                        carrierNew.Address2 = add.Street2;
                        carrierNew.City     = add.City;
                        carrierNew.State    = add.Province;
                        carrierNew.Zip      = add.Postal_Code;
                    }
                    carrierNew.CanadianSupportedTypes = GetSupportedTypes(jsonCarrier);
                    carrierNew.CDAnetVersion          = POut.Int(jsonCarrier.Versions.Max(x => PIn.Int(x))).PadLeft(2, '0');        //Version must be in 2 digit format. ex. 02.
                    carrierNew.CarrierName            = jsonCarrier.Name.En;
                    try {
                        Carriers.Insert(carrierNew);
                    }
                    catch (Exception ex) {
                        ex.DoNothing();
                    }
                    #endregion
                    continue;
                }
                listMatchedDbCarrierNums.Add(carrierInDb.CarrierNum);
                UpdateCarrierInDb(carrierInDb, jsonCarrier, listCanadianNetworks, fieldsToImport, jsonCarrierPhone, isAutomatic);
            }
            foreach (Carrier jsonCarrier in listUnmatchedJsonCarriers)
            {
                List <OpenDentBusiness.Carrier> listDbCarriers = Carriers.GetWhere(x => x.IsCDA &&
                                                                                   x.ElectID == jsonCarrier.Bin && !listMatchedDbCarrierNums.Contains(x.CarrierNum)
                                                                                   );
                if (listDbCarriers.Count != 1)               //Either 0 or multiple matches, either way do not update any carriers.
                {
                    continue;
                }
                OpenDentBusiness.Carrier carrierInDb = listDbCarriers.FirstOrDefault();
                string jsonCarrierPhone = jsonCarrier.Telephone?.First().Value;
                UpdateCarrierInDb(carrierInDb, jsonCarrier, listCanadianNetworks, fieldsToImport, jsonCarrierPhone, isAutomatic);
            }
            return("");           //Blank string represents a completed update.
        }
Пример #40
0
 ///<summary>Pass in either a clinic or HQ-level clearinghouse.</summary>
 private static bool IsEmdeonDental(Clearinghouse clearinghouse)
 {
     return(clearinghouse.ISA08 == "0135WCH00");
 }
Пример #41
0
 ///<summary>Some clearinghouses do not work in WEB mode.</summary>
 public static bool IsDisabledForWeb(Clearinghouse clearinghouse)
 {
     return(IsDisabledForWeb(clearinghouse.Eformat, clearinghouse.CommBridge));
 }
Пример #42
0
		///<summary>Used for ITRANS and Claimstream. Takes a string, creates a file, and drops it into the clearinghouse export path.  Waits for the response, and then returns it as a string.  Will throw an exception if response not received in a reasonable amount of time.  </summary>
		public static string PassToIca(string msgText,Clearinghouse clearhouse) {
			if(clearhouse==null){
				throw new ApplicationException(Lan.g("Canadian","A CDAnet compatible clearinghouse could not be found."));
			}
			string saveFolder=clearhouse.ExportPath;
			if(!Directory.Exists(saveFolder)) {
				throw new ApplicationException(saveFolder+" not found.");
			}
			bool isItrans=(clearhouse.CommBridge==EclaimsCommBridge.ITRANS);
			bool isClaimstream=(clearhouse.CommBridge==EclaimsCommBridge.Claimstream);
			if(isClaimstream) {
				string certFilePath=ODFileUtils.CombinePaths(saveFolder,"OPENDENTAL.pem");
				if(!File.Exists(certFilePath)) {
					File.WriteAllBytes(certFilePath,Properties.Resources.OPENDENTAL_PEM);
				}
			}
			string officeSequenceNumber=msgText.Substring(12,6);//Field A02. Office Sequence Number is always part of every message type and is always in the same place.
			int fileNum=PIn.Int(officeSequenceNumber)%1000;
			//first, delete the result file from previous communication so that no such files can affect the loop logic below.
			string outputFile=ODFileUtils.CombinePaths(saveFolder,"output."+fileNum.ToString().PadLeft(3,'0'));
			if(File.Exists(outputFile)) {
				File.Delete(outputFile);//no exception thrown if file does not exist.
			}
			//create the input file with data:
			string tempInputFile=ODFileUtils.CombinePaths(saveFolder,"tempinput."+fileNum.ToString().PadLeft(3,'0'));
			//First, write to a temp file so that the clearinghouse sofware does not try to send the file while it is still being written.
			File.WriteAllText(tempInputFile,msgText,Encoding.GetEncoding(850));
			//Now that the file is completely written, rename it to the input format that the clearinghouse will recognize and process.
			string inputFile=ODFileUtils.CombinePaths(saveFolder,"input."+fileNum.ToString().PadLeft(3,'0'));
			File.Move(tempInputFile,inputFile);//The input file should not exist, because the clearinghouse software should process input files promptly, unless the clearinghouse service is off for 1000 transactions in a row. We want an exception to be thrown if this file already exists.
			DateTime start=DateTime.Now;
			while(DateTime.Now<start.AddSeconds(120)){//We wait for up to 120 seconds. Responses can take up to 95 seconds and we need some extra time to be sure.
				if(File.Exists(outputFile)){
					break;
				}
				Thread.Sleep(200);//1/10 second
				Application.DoEvents();
			}
			//The _nput.### file is just the input.### renamed after it is processed. The clearinghouse service renames the file so that it is not processed more than once.
			string nputFile=ODFileUtils.CombinePaths(saveFolder,"_nput."+fileNum.ToString().PadLeft(3,'0'));
			//We delete the intermediate file so that claim data is not just lying around.
			if(File.Exists(nputFile)) {//The file would not appear to exist if there was a permission issue.
				File.Delete(nputFile);//no exception thrown if file does not exist.
			}
			if(!File.Exists(outputFile)) {
				if(isItrans) {
					throw new ApplicationException("No response from iCAService. Ensure that the iCAService is started and the iCA folder has the necessary permissions.");
				}
				else if(isClaimstream) {
					throw new ApplicationException("No response from the CCDWS service. Ensure that the CCDWS service is started and the ccd folder has the necessary permissions.");
				}
				//Other clearinghouses, if we ever support them.
				throw new ApplicationException("No response from clearinghouse service. Ensure that the clearinghouse service is started and the export folder has the necessary permissions.");
			}
			byte[] resultBytes=File.ReadAllBytes(outputFile);
			string result=Encoding.GetEncoding(850).GetString(resultBytes);
			//strip the prefix.  Example prefix: 123456,0,000,
			string resultPrefix="";
			//Find position of third comma
			Match match=Regex.Match(result,@"^\d*,\d+,\d+,");
			if(match.Success){
				resultPrefix=result.Substring(0,match.Length);
				result=result.Substring(resultPrefix.Length);
			}
			//We delete the output file so that claim data is not just lying around.
			if(File.Exists(outputFile)) {//The file would not appear to exist if there was a permission issue.
				File.Delete(outputFile);//no exception thrown if file does not exist.
			}
			if(result.Length<42) {//The shortest message is a version 02 Request for Pended Claims with length 42. Any message shorter is considered to be an error message.
				//The only valid message less than 42 characters in length is an Outstanding Transactions Acknowledgement indicating that the mailbox is empty. 
				if(result.Length>=25 && result.Substring(12).StartsWith("NO MORE ITEMS")) {
					//Since the message does not have a well defined format, we skip the code below for parsing the result to check for a mailbox indicator.
					//Additionally, there is no need to check for a mailbox indicator because this message from ITRANS tells us that the mailbox is empty anyway.
					return result;
				}
				string[] responses=resultPrefix.Split(',');
				string errorCode=responses[1];
				string response="Error "+errorCode+"\r\n\r\n"+"Raw Response:\r\n"+resultPrefix+result+"\r\n\r\n";
				if(isItrans) {
					if(errorCode=="1013") {
						response+="The CDA digital certificate for the provider is either missing, not exportable, expired, or invalid.\r\n";
					}
					string errorFile=ODFileUtils.CombinePaths(Path.GetDirectoryName(clearhouse.ClientProgram),"ica.log");
					string errorlog="";
					if(File.Exists(errorFile)) {
						errorlog=File.ReadAllText(errorFile);
					}
					response+="\r\nPlease see http://goitrans.com/itrans_support/itrans_claim_support_error_codes.htm for more details.\r\n";
					response+="Error log:\r\n"+errorlog;
				}
				else if(isClaimstream) {					
					string errorDescription="";
					string errorMessage=GetErrorMessageForCodeClaimstream(errorCode,ref errorDescription);
					response+="Error Message: "+errorMessage+"\r\n";
					response+="Error Description: "+errorDescription+"\r\n\r\n";
					response+="For further error details, read the log file ccdws.log.";
				}
				throw new ApplicationException(response);
			}
			//We parse the result to look for a few things no matter what type of transaction we are dealing with.
			//string requestOfficeSequenceNumber=msgText.Substring(12,6);//Field A02 always exists on all messages and is always in the same location.
			//string responseOfficeSequenceNumber=result.Substring(12,6);//Field A02 always exists on all messages and is always in the same location.
			//string requestMessageType=msgText.Substring(20,2);//Field A04 always exists on all messages and is always in the same location.
			//string responseMessageType=result.Substring(20,2);//Field A04 always exists on all messages and is always in the same location.
			CCDFieldInputter messageData=new CCDFieldInputter(result);
			//if(responseOfficeSequenceNumber!=requestOfficeSequenceNumber) {
			//	CCDField responseStatus=messageData.GetFieldById("G05");
			//	bool isResponseRejection=false;
			//	if(responseStatus!=null && responseStatus.valuestr!=null && responseStatus.valuestr.ToUpper()=="R") {
			//		isResponseRejection=true;
			//	}
			//	if(isResponseRejection) {
			//		//We do not check office sequence numbers for rejection notices, due to the reason described in the following scenario.
			//		//Imagine that a claim is sent with request #000001 and a rejection notice is returned with the same response #000001.
			//		//No changes are made to the claim, and it is sent again, but this time with request #000002.
			//		//ITRANS will respond with the exact same message returned from the first rejection, including response #000001, not response #000002.
			//		//For any other transaction type, we have not seen any cases where the sequence number in the request and response do not match.
			//	}
			//	//Type 04 is an ROT, type 14 is an ROT response. Keep in mind that ROT transactions can get multiple types of responses back.
			//	else if(requestMessageType!="04" || (requestMessageType=="04" && responseMessageType=="14")) {
			//		if(isItrans) {
			//			throw new ApplicationException(Lan.g("Canadian","The office sequence number in the response from ITRANS is invalid. Response")+": "+result);
			//		}
			//		else if(isClaimstream) {
			//			throw new ApplicationException(Lan.g("Canadian","The office sequence number in the response from Claimstream is invalid. Response")+": "+result);
			//		}
			//		//Other clearinghouses, if we ever support them.
			//		throw new ApplicationException(Lan.g("Canadian","The office sequence number in the response from the clearinghouse is invalid. Response")+": "+result);
			//	}
			//}
			//We check the mailbox indicator here, only when the response is returned the first time instead of showing it in FormCCDPrint, because 
			//we do not want the mailbox indicator to be examined multiple times, which could happen if a transaction is viewed again using FormCCDPrint.
			CCDField mailboxIndicator=messageData.GetFieldById("A11");
			if(mailboxIndicator!=null) { //Field A11 should exist in all response types, but just in case.
				if(mailboxIndicator.valuestr.ToUpper()=="Y" || mailboxIndicator.valuestr.ToUpper()=="O") {
					MsgBox.Show("Canadian","NOTIFICATION: Items are waiting in the mailbox. Retrieve these items by going to the Manage module, click the Send Claims button, "
						+"then click the Outstanding button. This box will continue to show each time a claim is sent until the mailbox is cleared.");
				}
			}
			return result;
		}
Пример #43
0
        ///<summary>Replaces all clinic-level fields in ClearinghouseHq with non-blank fields in clearinghouseClin.
        ///Non clinic-level fields are commented out and not replaced.</summary>
        public static Clearinghouse OverrideFields(Clearinghouse clearinghouseHq, Clearinghouse clearinghouseClin)
        {
            //No need to check RemotingRole; no call to db.
            if (clearinghouseHq == null)
            {
                return(null);
            }
            Clearinghouse clearinghouseRetVal = clearinghouseHq.Copy();

            if (clearinghouseClin == null)            //if a null clearingHouseClin was passed in, just return clearinghouseHq.
            {
                return(clearinghouseRetVal);
            }
            //HqClearinghouseNum must be set for refreshing the cache when deleting.
            clearinghouseRetVal.HqClearinghouseNum = clearinghouseClin.HqClearinghouseNum;
            //ClearinghouseNum must be set so that updates do not create new entries every time.
            clearinghouseRetVal.ClearinghouseNum = clearinghouseClin.ClearinghouseNum;
            //ClinicNum must be set so that the correct clinic is assigned when inserting new clinic level clearinghouses.
            clearinghouseRetVal.ClinicNum            = clearinghouseClin.ClinicNum;
            clearinghouseRetVal.IsEraDownloadAllowed = clearinghouseClin.IsEraDownloadAllowed;
            clearinghouseRetVal.IsClaimExportAllowed = clearinghouseClin.IsClaimExportAllowed;
            //fields that should not be replaced are commented out.
            //if(!String.IsNullOrEmpty(clearinghouseClin.Description)) {
            //	clearinghouseRetVal.Description=clearinghouseClin.Description;
            //}
            if (!String.IsNullOrEmpty(clearinghouseClin.ExportPath))
            {
                clearinghouseRetVal.ExportPath = clearinghouseClin.ExportPath;
            }
            //if(!String.IsNullOrEmpty(clearinghouseClin.Payors)) {
            //	clearinghouseRetVal.Payors=clearinghouseClin.Payors;
            //}
            //if(clearinghouseClin.Eformat!=0 && clearinghouseClin.Eformat!=null) {
            //	clearinghouseRetVal.Eformat=clearinghouseClin.Eformat;
            //}
            //if(!String.IsNullOrEmpty(clearinghouseClin.ISA05)) {
            //	clearinghouseRetVal.ISA05=clearinghouseClin.ISA05;
            //}
            if (!String.IsNullOrEmpty(clearinghouseClin.SenderTIN))
            {
                clearinghouseRetVal.SenderTIN = clearinghouseClin.SenderTIN;
            }
            //if(!String.IsNullOrEmpty(clearinghouseClin.ISA07)) {
            //	clearinghouseRetVal.ISA07=clearinghouseClin.ISA07;
            //}
            //if(!String.IsNullOrEmpty(clearinghouseClin.ISA08)) {
            //	clearinghouseRetVal.ISA08=clearinghouseClin.ISA08;
            //}
            //if(!String.IsNullOrEmpty(clearinghouseClin.ISA15)) {
            //	clearinghouseRetVal.ISA15=clearinghouseClin.ISA15;
            //}
            if (!String.IsNullOrEmpty(clearinghouseClin.Password))
            {
                clearinghouseRetVal.Password = clearinghouseClin.Password;
            }
            if (!String.IsNullOrEmpty(clearinghouseClin.ResponsePath))
            {
                clearinghouseRetVal.ResponsePath = clearinghouseClin.ResponsePath;
            }
            //if(clearinghouseClin.CommBridge!=0 && clearinghouseClin.CommBridge!=null) {
            //	clearinghouseRetVal.CommBridge=clearinghouseClin.CommBridge;
            //}
            if (!String.IsNullOrEmpty(clearinghouseClin.ClientProgram))
            {
                clearinghouseRetVal.ClientProgram = clearinghouseClin.ClientProgram;
            }
            //clearinghouseRetVal.LastBatchNumber=;//Not editable is UI and should not be updated here.  See GetNextBatchNumber() above.
            //if(clearinghouseClin.ModemPort!=0 && clearinghouseClin.ModemPort!=null) {
            //	clearinghouseRetVal.ModemPort=clearinghouseClin.ModemPort;
            //}
            if (!String.IsNullOrEmpty(clearinghouseClin.LoginID))
            {
                clearinghouseRetVal.LoginID = clearinghouseClin.LoginID;
            }
            if (!String.IsNullOrEmpty(clearinghouseClin.SenderName))
            {
                clearinghouseRetVal.SenderName = clearinghouseClin.SenderName;
            }
            if (!String.IsNullOrEmpty(clearinghouseClin.SenderTelephone))
            {
                clearinghouseRetVal.SenderTelephone = clearinghouseClin.SenderTelephone;
            }
            //if(!String.IsNullOrEmpty(clearinghouseClin.GS03)) {
            //	clearinghouseRetVal.GS03=clearinghouseClin.GS03;
            //}
            //if(!String.IsNullOrEmpty(clearinghouseClin.ISA02)) {
            //	clearinghouseRetVal.ISA02=clearinghouseClin.ISA02;
            //}
            //if(!String.IsNullOrEmpty(clearinghouseClin.ISA04)) {
            //	clearinghouseRetVal.ISA04=clearinghouseClin.ISA04;
            //}
            //if(!String.IsNullOrEmpty(clearinghouseClin.ISA16)) {
            //	clearinghouseRetVal.ISA16=clearinghouseClin.ISA16;
            //}
            //if(!String.IsNullOrEmpty(clearinghouseClin.SeparatorData)) {
            //	clearinghouseRetVal.SeparatorData=clearinghouseClin.SeparatorData;
            //}
            //if(!String.IsNullOrEmpty(clearinghouseClin.SeparatorSegment)) {
            //	clearinghouseRetVal.SeparatorSegment=clearinghouseClin.SeparatorSegment;
            //}
            return(clearinghouseRetVal);
        }
Пример #44
0
 ///<summary>Supply a list of ClaimSendQueueItems. Called from FormClaimSend.  Can only send to one clearinghouse at a time.  Able to send just send one claim.  Cannot include Canadian.</summary>
 public static void SendBatch(List<ClaimSendQueueItem> queueItems,Clearinghouse clearhouse,EnumClaimMedType medType)
 {
     string messageText="";
     if(clearhouse.Eformat==ElectronicClaimFormat.Canadian){
         MsgBox.Show("Eclaims","Cannot send Canadian claims as part of Eclaims.SendBatch.");
         return;
     }
     //get next batch number for this clearinghouse
     int batchNum=Clearinghouses.GetNextBatchNumber(clearhouse);
     //---------------------------------------------------------------------------------------
     //Create the claim file for this clearinghouse
     if(clearhouse.Eformat==ElectronicClaimFormat.x837D_4010
         || clearhouse.Eformat==ElectronicClaimFormat.x837D_5010_dental
         || clearhouse.Eformat==ElectronicClaimFormat.x837_5010_med_inst)
     {
         messageText=x837Controller.SendBatch(queueItems,batchNum,clearhouse,medType);
     }
     else if(clearhouse.Eformat==ElectronicClaimFormat.Renaissance){
         messageText=Renaissance.SendBatch(queueItems,batchNum);
     }
     else if(clearhouse.Eformat==ElectronicClaimFormat.Dutch) {
         messageText=Dutch.SendBatch(queueItems,batchNum);
     }
     else{
         messageText="";//(ElectronicClaimFormat.None does not get sent)
     }
     if(messageText==""){//if failed to create claim file properly,
         return;//don't launch program or change claim status
     }
     //----------------------------------------------------------------------------------------
     //Launch Client Program for this clearinghouse if applicable
     if(clearhouse.CommBridge==EclaimsCommBridge.None){
         AttemptLaunch(clearhouse,batchNum);
     }
     else if(clearhouse.CommBridge==EclaimsCommBridge.WebMD){
         if(!WebMD.Launch(clearhouse,batchNum)){
             MessageBox.Show(Lan.g("Eclaims","Error sending."));
             return;
         }
     }
     else if(clearhouse.CommBridge==EclaimsCommBridge.BCBSGA){
         if(!BCBSGA.Launch(clearhouse,batchNum)){
             MessageBox.Show(Lan.g("Eclaims","Error sending."));
             return;
         }
     }
     else if(clearhouse.CommBridge==EclaimsCommBridge.Renaissance){
         AttemptLaunch(clearhouse,batchNum);
     }
     else if(clearhouse.CommBridge==EclaimsCommBridge.ClaimConnect){
         if(!ClaimConnect.Launch(clearhouse,batchNum)){
             MessageBox.Show(Lan.g("Eclaims","Error sending."));
             return;
         }
     }
     else if(clearhouse.CommBridge==EclaimsCommBridge.RECS){
         if(!RECS.Launch(clearhouse,batchNum)){
             MessageBox.Show("Claim file created, but could not launch RECS client.");
             //continue;
         }
     }
     else if(clearhouse.CommBridge==EclaimsCommBridge.Inmediata){
         if(!Inmediata.Launch(clearhouse,batchNum)){
             MessageBox.Show("Claim file created, but could not launch Inmediata client.");
             //continue;
         }
     }
     else if(clearhouse.CommBridge==EclaimsCommBridge.AOS){ // added by SPK 7/13/05
         if(!AOS.Launch(clearhouse,batchNum)){
             MessageBox.Show("Claim file created, but could not launch AOS Communicator.");
             //continue;
         }
     }
     else if(clearhouse.CommBridge==EclaimsCommBridge.PostnTrack){
         AttemptLaunch(clearhouse,batchNum);
     }
     else if(clearhouse.CommBridge==EclaimsCommBridge.MercuryDE){
         if(!MercuryDE.Launch(clearhouse,batchNum)){
             MsgBox.Show("Eclaims","Error sending.");
             return;
         }
     }
     else if(clearhouse.CommBridge==EclaimsCommBridge.ClaimX) {
         if(!ClaimX.Launch(clearhouse,batchNum)) {
             MessageBox.Show("Claim file created, but encountered an error while launching ClaimX Client.");
         }
     }
     else if(clearhouse.CommBridge==EclaimsCommBridge.EmdeonMedical) {
         if(!EmdeonMedical.Launch(clearhouse,batchNum,medType)) {
             MessageBox.Show(Lan.g("Eclaims","Error sending."));
             return;
         }
     }
     //----------------------------------------------------------------------------------------
     //finally, mark the claims sent. (only if not Canadian)
     EtransType etype=EtransType.ClaimSent;
     if(clearhouse.Eformat==ElectronicClaimFormat.Renaissance){
         etype=EtransType.Claim_Ren;
     }
     if(clearhouse.Eformat!=ElectronicClaimFormat.Canadian){
         for(int j=0;j<queueItems.Count;j++){
             Etrans etrans=Etranss.SetClaimSentOrPrinted(queueItems[j].ClaimNum,queueItems[j].PatNum,clearhouse.ClearinghouseNum,etype,batchNum);
             Etranss.SetMessage(etrans.EtransNum,messageText);
         }
     }
 }
Пример #45
0
 ///<summary>If no comm bridge is selected for a clearinghouse, this launches any client program the user has entered.  We do not want to cause a rollback, so no return value.</summary>
 private static void AttemptLaunch(Clearinghouse clearhouse,int batchNum)
 {
     if(clearhouse.ClientProgram==""){
         return;
     }
     if(!File.Exists(clearhouse.ClientProgram)){
         MessageBox.Show(clearhouse.ClientProgram+" "+Lan.g("Eclaims","does not exist."));
         return;
     }
     try{
         Process.Start(clearhouse.ClientProgram);
     }
     catch{
         MessageBox.Show(Lan.g("Eclaims","Client program could not be started.  It may already be running. You must open your client program to finish sending claims."));
     }
 }
Пример #46
0
		private static void WriteFunctionalGroup(StreamWriter sw,List<ClaimSendQueueItem> queueItems,int batchNum,Clearinghouse clearhouse,EnumClaimMedType medType) {
			#region Functional Group Header
			int transactionNum=1;//Gets incremented for each carrier. Can be reused in other functional groups and interchanges, so not persisted
			//Functional Group Header
			string groupControlNumber=batchNum.ToString();//Must be unique within file.  We will use batchNum
			string industryIdentifierCode="";
			if(medType==EnumClaimMedType.Medical) {
				industryIdentifierCode="005010X222A1";
			}
			else if(medType==EnumClaimMedType.Institutional) {
				industryIdentifierCode="005010X223A2";
			}
			else if(medType==EnumClaimMedType.Dental) {
				industryIdentifierCode="005010X224A2";
			}
			sw.Write("GS"+s
				+"HC"+s//GS01 2/2 Functional Identifier Code: Health Care Claim.
				+X12Generator.GetGS02(clearhouse)+s//GS02 2/15 Application Sender's Code: Sometimes Jordan Sparks.  Sometimes the sending clinic.
				+Sout(clearhouse.GS03,15,2)+s//GS03 2/15 Application Receiver's Code:
				+DateTime.Today.ToString("yyyyMMdd")+s//GS04 8/8 Date: today's date.
				+DateTime.Now.ToString("HHmm")+s//GS05 4/8 TIME: current time.
				+groupControlNumber+s//GS06 1/9 Group Control Number: No padding necessary.
				+"X"+s//GS07 1/2 Responsible Agency Code: X=Accredited Standards Committee X12.
				+industryIdentifierCode//GS08 1/12 Version/Release/Industry Identifier Code:
				+endSegment);
			#endregion Functional Group Header
			#region Define Variables
			int HLcount=1;
			int parentProv=0;//the HL sequence # of the current provider.
			int parentSubsc=0;//the HL sequence # of the current subscriber.
			string hasSubord="";//0 if no subordinate, 1 if at least one subordinate
			Claim claim;
			InsPlan insPlan;
			InsPlan otherPlan=null;
			InsSub sub;
			InsSub otherSub=new InsSub();
			Patient patient;
			Patient subscriber;
			Patient otherSubsc=new Patient();
			Carrier carrier;
			Carrier otherCarrier=new Carrier();
			List<ClaimProc> claimProcList;//all claimProcs for a patient.
			List<ClaimProc> claimProcs;
			List<Procedure> procList;
			List<ToothInitial> initialList;
			List<PatPlan> patPlans;
			Procedure proc;
			ProcedureCode procCode;
			Provider provTreat;//claim level treating provider.
			Provider billProv=null;
			Clinic clinic=null;
			seg=0;
			#endregion Define Variables
			#region Transaction Set Header
			//if(i==0//if this is the first claim
			//	|| claimItems[i].PayorId0 != claimItems[i-1].PayorId0)//or the payorID has changed
			//{
			//	newTrans=true;
			//	seg=0;
			//}
			//else newTrans=false;
			//if(newTrans) {
			//Transaction Set Header (one for each carrier)
			//transactionNum gets incremented in SE section
			//ST02 Transact. control #. Must be unique within ISA
			//NO: So we used combination of transaction and group, eg 00011
			sw.Write("ST"+s
				+"837"+s//ST01 3/3 Transaction Set Identifier Code: 
				+transactionNum.ToString().PadLeft(4,'0')+s//ST02 4/9 Transaction Set Control Number: 
				+industryIdentifierCode);//ST03 1/35 Implementation Convention Reference:
			EndSegment(sw);
			sw.Write("BHT"+s
				+"0019"+s//BHT01 4/4 Hierarchical Structure Code: 0019=Information Source, Subscriber, Dependant.
				+"00"+s//BHT02 2/2 Transaction Set Purpose Code: 00=Original transmissions are transmissions which have never been sent to the reciever.
				+transactionNum.ToString().PadLeft(4,'0')+s//BHT03 1/50 Reference Identification: Can be same as ST02.
				+DateTime.Now.ToString("yyyyMMdd")+s//BHT04 8/8 Date: 
				+DateTime.Now.ToString("HHmmss")+s//BHT05 4/8 Time: 
				+"CH");//BHT06 2/2 Transaction Type Code: CH=Chargable.
			EndSegment(sw);
			//1000A Submitter is OPEN DENTAL and sometimes it's the practice
			//(depends on clearinghouse and Partnership agreements)
			//See 2010AA PER (after REF) for the new billing provider contact phone number
			//1000A NM1: 41 (medical,institutional,dental) Submitter Name.
			Write1000A_NM1(sw,clearhouse);
			//1000A PER: IC (medical,institutional,dental) Submitter EDI Contact Information. Contact number.
			Write1000A_PER(sw,clearhouse);
			//1000B NM1: 40 (medical,institutional,dental) Receiver Name. Always the Clearinghouse.
			sw.Write("NM1"+s
				+"40"+s//NM101 2/3 Entity Identifier Code: 40=Receiver.
				+"2"+s);//NM102 1/1 Entity Type Qualifier: 2=Non-Person Entity.
			if(IsClaimConnect(clearhouse)) {
				sw.Write("CLAIMCONNECT"+s);//NM103 1/60 Name Last or Organization Name: Receiver Name.
			}
			else if(IsDentiCal(clearhouse)) {
				sw.Write("DENTICAL"+s);//NM103 1/60 Name Last or Organization Name: Receiver Name.
			}
			else {
				sw.Write(Sout(clearhouse.Description,60)+s);//NM103 1/60 Name Last or Organization Name: Receiver Name.
			}
			sw.Write(s//NM104 1/35 Name First: Not Used.
				+s//NM105 1/25 Name Middle: Not Used.
				+s//NM106 1/10 Name Prefix: Not Used.
				+s//NM107 1/10 Name Suffix: Not Used.
				+"46"+s);//NM108 1/2 Identification Code Qualifier: 46=Electronic Transmitter Identification Number (ETIN).
			if(IsDentiCal(clearhouse)) {
				sw.Write("1941461312");//NM109 2/80 Identification Code: Receiver ID Code. aka ETIN#.
			}
			else {
				sw.Write(Sout(clearhouse.ISA08,80,2));//NM109 2/80 Identification Code: Receiver ID Code. aka ETIN#.
			}
			EndSegment(sw);//NM110 through NM112 are not used.
			HLcount=1;
			parentProv=0;//the HL sequence # of the current provider.
			parentSubsc=0;//the HL sequence # of the current subscriber.
			hasSubord="";//0 if no subordinate, 1 if at least one subordinate
			//}
			#endregion
			for(int i=0;i<queueItems.Count;i++) {
				#region Initialize Variables
				claim=Claims.GetClaim(queueItems[i].ClaimNum);
				insPlan=InsPlans.GetPlan(claim.PlanNum,new List<InsPlan>());
				sub=InsSubs.GetSub(claim.InsSubNum,null);
				//insPlan could be null if db corruption. No error checking for that
				otherPlan=null;//Must be reset each time through because if otherPlan!=null below then we assume the current claim has a secondary plan.
				if(claim.PlanNum2>0) {
					otherPlan=InsPlans.GetPlan(claim.PlanNum2,new List<InsPlan>());
					otherSub=InsSubs.GetSub(claim.InsSubNum2,null);
					otherSubsc=Patients.GetPat(otherSub.Subscriber);
					otherCarrier=Carriers.GetCarrier(otherPlan.CarrierNum);
				}
				patient=Patients.GetPat(claim.PatNum);
				subscriber=Patients.GetPat(sub.Subscriber);
				carrier=Carriers.GetCarrier(insPlan.CarrierNum);
				claimProcList=ClaimProcs.Refresh(patient.PatNum);
				claimProcs=ClaimProcs.GetForSendClaim(claimProcList,claim.ClaimNum);
				procList=Procedures.Refresh(claim.PatNum);
				initialList=ToothInitials.Refresh(claim.PatNum);
				patPlans=PatPlans.Refresh(patient.PatNum);
				#endregion Initialize Variables
				#region Billing Provider
				//Billing address is based on clinic, not provider.  All claims in a batch are guaranteed to be from a single clinic.  That validation is done in FormClaimSend.
				//Although, now that we have a separate loop for each claim, we might be able to allow a batch with mixed clinics.
				if(!PrefC.GetBool(PrefName.EasyNoClinics)) {//if using clinics
					clinic=Clinics.GetClinic(claim.ClinicNum);//might be null
				}
				//2000A HL: (medical,instituational,dental) Billing Provider Hierarchical Level.
				sw.Write("HL"+s+HLcount.ToString()+s//HL01 1/12 Heirarchical ID Number: 
					+s//HL02 1/12 Hierarchical Parent ID Number: Not used.
					+"20"+s//HL03 1/2 Heirarchical Level Code: 20=Information Source.
					+"1");//HL04 1/1 Heirarchical Child Code. 1=Additional Subordinate HL Data Segment in This Hierarchical Structure.
				EndSegment(sw);
				//billProv=ProviderC.ListLong[Providers.GetIndexLong(claimItems[i].ProvBill1)];
				billProv=Providers.GetProv(claim.ProvBill);
				//2000A PRV: BI (medical,institutional,dental) Billing Provider Specialty Information. Situational. Required when billing provider is treating provider.
				bool usePrvBilling=false;
				if(claim.ProvBill==claim.ProvTreat) {
					usePrvBilling=true;
				}
				if(IsWashingtonMedicaid(clearhouse,carrier)) {
					usePrvBilling=true;
				}
				if(usePrvBilling) {
					sw.Write("PRV"+s
						+"BI"+s//PRV01 1/3 Provider Code: BI=Billing.
						+"PXC"+s//PRV02 2/3 Reference Identification Qualifier: PXC=Health Care Provider Taxonomy Code.
						+X12Generator.GetTaxonomy(billProv));//PRV03 1/50 Reference Identification: Provider Taxonomy Code.
					EndSegment(sw);//PRV04 through PRV06 are not used.
				}
				//2000A CUR: (medical,instituational,dental) Foreign Currency Information. Situational. We do not need to specify because united states dollars are default.
				//2010AA NM1: 85 (medical,institutional,dental) Billing Provider Name.
				if(medType==EnumClaimMedType.Institutional) {
					billProv.IsNotPerson=true;//Required by X12 specification. Cannot send a person as the billing provider.
				}
				WriteNM1Provider("85",sw,billProv);
				//2010AA N3: (medical,institutional,dental) Billing Provider Address.
				string billingAddress1="";
				string billingAddress2="";
				string billingCity="";
				string billingState="";
				string billingZip="";
				if(PrefC.GetBool(PrefName.UseBillingAddressOnClaims)) {
					billingAddress1=PrefC.GetString(PrefName.PracticeBillingAddress);
					billingAddress2=PrefC.GetString(PrefName.PracticeBillingAddress2);
					billingCity=PrefC.GetString(PrefName.PracticeBillingCity);
					billingState=PrefC.GetString(PrefName.PracticeBillingST);
					billingZip=PrefC.GetString(PrefName.PracticeBillingZip);
				}
				else if(clinic==null) {
					billingAddress1=PrefC.GetString(PrefName.PracticeAddress);
					billingAddress2=PrefC.GetString(PrefName.PracticeAddress2);
					billingCity=PrefC.GetString(PrefName.PracticeCity);
					billingState=PrefC.GetString(PrefName.PracticeST);
					billingZip=PrefC.GetString(PrefName.PracticeZip);
				}
				else {
					billingAddress1=clinic.Address;
					billingAddress2=clinic.Address2;
					billingCity=clinic.City;
					billingState=clinic.State;
					billingZip=clinic.Zip;
				}
				sw.Write("N3"+s+Sout(billingAddress1,55));//N301 1/55 Address Information:
				if(billingAddress2!="") {
					sw.Write(s+Sout(billingAddress2,55));//N302 1/55 Address Information:
				}
				EndSegment(sw);
				//2010AA N4: (medical,institutional,dental) Billing Provider City, State, Zip Code.
				sw.Write("N4"+s+Sout(billingCity,30)+s//N401 2/30 City Name: 
					+Sout(billingState,2,2)+s//N402 2/2 State or Province Code: 
					+Sout(billingZip.Replace("-",""),15));//N403 3/15 Postal Code: 
				EndSegment(sw);//NM404 through NM407 are either situational with United States as default, or not used, so we don't specify any of them.
				//2010AA REF: EI (medical,institutional,dental) Billing Provider Tax Identification.
				sw.Write("REF"+s);
				if(medType==EnumClaimMedType.Medical) {
					sw.Write((billProv.UsingTIN?"EI":"SY")+s);//REF01 2/3 Reference Identification Qualifier: EI=Employer's Identification Number (EIN). SY=Social Security Number (SSN).
				}
				else if(medType==EnumClaimMedType.Institutional) {
					sw.Write("EI"+s);//REF01 2/3 Reference Identification Qualifier: EI=Employer's Identification Number (EIN).
				}
				else if(medType==EnumClaimMedType.Dental) {
					sw.Write((billProv.UsingTIN?"EI":"SY")+s);//REF01 2/3 Reference Identification Qualifier: EI=Employer's Identification Number (EIN). SY=Social Security Number (SSN).
				}
				sw.Write(Sout(billProv.SSN,50));//REF02 1/50 Reference Identification. Tax ID #.
				EndSegment(sw);//REF03 and REF04 are not used.
				if(medType==EnumClaimMedType.Medical || medType==EnumClaimMedType.Dental) {
					//2010AA REF: (medical,dental) Billing Provider UIPN/License Information: Situational. We do not use. Max repeat 2.
				}
				if(medType==EnumClaimMedType.Dental) {
					//2010AA REF: (dental) State License Number: Required by RECS and Emdeon clearinghouses. We do NOT validate that it's entered because sending it with non-persons causes problems.
					//if(IsEmdeonDental(clearhouse) || clearhouse.CommBridge==EclaimsCommBridge.RECS) {
					if(!IsDentiCal(clearhouse)) { //Denti-Cal never wants this.
						if(billProv.StateLicense!="") {
							sw.Write("REF"+s
								+"0B"+s//REF01 2/3 Reference Identification Qualifier: 0B=State License Number.
								+Sout(billProv.StateLicense,50));//REF02 1/50 Reference Identification: 
							EndSegment(sw);//REF03 and REF04 are not used.
						}
					}
					//2010AA REF G5 (dental) Site Identification Number: NOT IN X12 5010 STANDARD DOCUMENTATION. Only required by Emdeon.
					if(IsEmdeonDental(clearhouse)) {
						Write2010AASiteIDforEmdeon(sw,billProv,carrier.ElectID);
					}
				}
				//2010AA PER: IC (medical,institutional,dental) Billing Provider Contact Information: Probably required by a number of carriers and by Emdeon.
				sw.Write("PER"+s
					+"IC"+s//PER01 2/2 Contact Function Code: IC=Information Contact.
					+Sout(PrefC.GetString(PrefName.PracticeTitle),60)+s//PER02 1/60 Name: Practice Title.
					+"TE"+s);//PER03 2/2 Communication Number Qualifier: TE=Telephone.
				if(PrefC.GetBool(PrefName.UseBillingAddressOnClaims)) {
					sw.Write(Sout(PrefC.GetString(PrefName.PracticePhone),256));//PER04  1/256 Communication Number: Telephone number.
				}
				else if(clinic==null){
					sw.Write(Sout(PrefC.GetString(PrefName.PracticePhone),256));//PER04  1/256 Communication Number: Telephone number.
				}
				else{
					sw.Write(Sout(clinic.Phone,256));//PER04  1/256 Communication Number: Telephone number.
				}
				EndSegment(sw);//PER05 through PER08 are situational and PER09 is not used. We do not use.
				if(PrefC.GetString(PrefName.PracticePayToAddress)!="") {
					//2010AB NM1: 87 (medical,institutional,dental) Pay-To Address Name.
					sw.Write("NM1"+
						s+"87"+s);//NM101 2/3 Entity Identifier Code: 87=Pay-to Provider.
					if(medType==EnumClaimMedType.Institutional) {
						sw.Write("2");//NM102 1/1 Entity Type Qualifier: 2=Non-Person Entity.
					}
					else { //(medical,dental)
						sw.Write((billProv.IsNotPerson?"2":"1"));//NM102 1/1 Entity Type Qualifier: 1=Person, 2=Non-Person Entity.
					}
					EndSegment(sw);//NM103 through NM112 are not used.
					//2010AB N3: (medical,institutional,dental) Pay-To Address.
					sw.Write("N3"+s+Sout(PrefC.GetString(PrefName.PracticePayToAddress),55));//N301 1/55 Address Information:
					if(PrefC.GetString(PrefName.PracticePayToAddress2)!="") {
						sw.Write(s+Sout(PrefC.GetString(PrefName.PracticePayToAddress2),55));//N302 1/55 Address Information:
					}
					EndSegment(sw);
					//2010AB N4: (medical,institutional,dental) Pay-To Address City, State, Zip Code.
					sw.Write("N4"+s+Sout(PrefC.GetString(PrefName.PracticePayToCity),30)+s//N401 2/30 City Name: 
						+Sout(PrefC.GetString(PrefName.PracticePayToST),2,2)+s//N402 2/2 State or Province Code: 
						+Sout(PrefC.GetString(PrefName.PracticePayToZip).Replace("-",""),15));//N403 3/15 Postal Code: 
					EndSegment(sw);//NM404 through NM407 are either situational with United States as default, or not used, so we don't specify any of them.
				}
				//2010AC NM1: 98 (medical,institutional,dental) Pay-To Plan Name. We do not use.
				//2010AC N3: (medical,institutional,dental) Pay-To Plan Address. We do not use.
				//2010AC N4: (medical,institutional,dental) Pay-To Plan City, State, Zip Code. We do not use.
				//2010AC REF: (medical,institutional,dental) Pay-To Plan Secondary Identification. We do not use.
				//2010AC REF: (medical,institutional,dental) Pay-To Plan Tax Identification Number. We do not use.
				parentProv=HLcount;
				HLcount++;
				#endregion Billing Provider
				#region Attachments
				/*if(IsTesia(clearhouse) && claim.Attachments.Count>0){//If Tesia and has attachments
					claim.ClaimNote="TESIA#"+claim.ClaimNum.ToString()+" "+claim.ClaimNote;
					string saveFolder=clearhouse.ExportPath;//we've already tested to make sure this exists.
					string saveFile;
					string storedFile;
					for(int c=0;c<claim.Attachments.Count;c++){
						saveFile=ODFileUtils.CombinePaths(saveFolder,
							claim.ClaimNum.ToString()+"_"+(c+1).ToString()+Path.GetExtension(claim.Attachments[c].DisplayedFileName)+".IMG");
						storedFile=ODFileUtils.CombinePaths(FormEmailMessageEdit.GetAttachPath(),claim.Attachments[c].ActualFileName);
						File.Clone(storedFile,saveFile,true);
					}					
				}*/
				#endregion
				#region Subscriber
				if(patient.PatNum==subscriber.PatNum){//if patient is the subscriber
					hasSubord="0";//-claim level will follow
					//subordinate patients will not follow in this loop.  The subscriber loop will be duplicated for them.
				}
				else {//patient is not the subscriber
					hasSubord="1";//-patient will always follow
				}
				//2000B HL: (medical,institutional,dental) Subscriber Hierarchical Level.
				sw.Write("HL"+s+HLcount.ToString()+s//HL01 1/12 Hierarchical ID Number:
					+parentProv.ToString()+s//HL02 1/12 Hierarchical Parent ID Number: parent HL is always the billing provider HL.
					+"22"+s//HL03 1/2 Hierarchical Level Code: 22=Subscriber.
					+hasSubord);//HL04 1/1 Hierarchical Child Code: 0=No subordinate HL segment in this hierarchical structure. 1=Additional subordinate HL data segment in this hierarchical structure.
				EndSegment(sw);
				//2000B SBR: (medical,institutional,dental) Subscriber Information.
				sw.Write("SBR"+s);
				bool claimIsPrimary=true;//we currently support only primary and secondary.  Plan2, if present, must be the opposite.
				if(claim.ClaimType=="PreAuth") {
					if(otherPlan!=null && PatPlans.GetOrdinal(claim.InsSubNum2,patPlans) < PatPlans.GetOrdinal(claim.InsSubNum,patPlans)) { //When there are two plans and the secondary plan is in the primary ins position.
						claimIsPrimary=false;
					}
				}
				else if(otherPlan!=null && (otherPlan.IsMedical || insPlan.IsMedical)) { //When there are two plans and at least one plan is medical.
					if(PatPlans.GetOrdinal(claim.InsSubNum2,patPlans) < PatPlans.GetOrdinal(claim.InsSubNum,patPlans)) { //The insurance plan order is determined by patplan.ordinal
						claimIsPrimary=false;
					}
				}
				else if(claim.ClaimType=="P") {
				}
				else if(claim.ClaimType=="S") { //Verification ensures that there are two plans associated with the claim in this case.
					claimIsPrimary=false;
				}
				else if(claim.ClaimType=="Other") { //Also used for a medical claim with only one insurance.
					//We always send medical plans as primary.  They are totally separate from the ordinals for dental.
				}
				else if(claim.ClaimType=="Cap") {
					//All captication claims are treated as primary claims.
					//todo: is secondary capitation possible?
				}
				sw.Write((claimIsPrimary?"P":"S")+s);//SBR01 1/1 Payer Responsibility Sequence Number Code: 
				string relationshipCode="";//empty if patient is not subscriber.
				if(patient.PatNum==subscriber.PatNum) {//if patient is the subscriber
					relationshipCode="18";
				}
				sw.Write(relationshipCode+s//SBR02 2/2 Individual Relationship Code: 18=Self (The only option besides blank).
					+Sout(insPlan.GroupNum,50)+s);//SBR03 1/50 Reference Identification: Does not need to be validated because group number is optional.
				//SBR04 1/60 Name: Situational. Required when SBR03 is not used. Does not need to be validated because group name is optional.
				if(insPlan.GroupNum!="") {
					sw.Write(s);
				} 
				else {
					sw.Write(Sout(insPlan.GroupName,60)+s);
				}
				sw.Write(s//SBR05 1/3 Insurance Type Code. Situational.  Skip because we don't support secondary Medicare.
					+s//SBR06 1/1 Coordination of Benefits Code: Not used.
					+s//SBR07 1/1 Yes/No Condition or Respose Code: Not used.
					+s//SBR08 2/2 Employment Status Code: Not used.
					+GetFilingCode(insPlan));//SBR09: 12=PPO,17=DMO,BL=BCBS,CI=CommercialIns,FI=FEP,HM=HMO. Will no longer be required when HIPPA National Plan ID is mandated.
				EndSegment(sw);
				if(medType==EnumClaimMedType.Medical) {
					//2000B PAT: (medical) Patient Information. Situational. Required when the patient is the subscriber or considered to be the subscriber and at least one of the element requirements are met. Element requirements include: when the patient is deceased and the date of death is available; or when the claim involves Medicare Durable Medical Equipment Regional Carriers Certificate of Medical Necessity (DMERC CMN) 02.03, 10.02, or DMA MAC 10.03; or when law requires to know if the patient is pregnant or not. We do not use, because we do not track death date, durable medical equipment information, nor do we know weather or not the patient is pregnant. Some of these fields may be necessary in the future, but not likely since our medical claims are usually pretty simple.
				}
				//2010BA NM1: IL (medical,institutional,dental) Subscriber Name.
				sw.Write("NM1"+s
					+"IL"+s//NM101 2/3 Entity Identifier Code: IL=Insured or Subscriber.
					+"1"+s//NM102 1/1 Entity Type Qualifier: 1=Person, 2=Non-Person Entity.
					+Sout(subscriber.LName,60)+s//NM103 1/60 Name Last or Organization Name: Never blank, because validated in the patient edit window when a patient is added/edited.
					+Sout(subscriber.FName,35)+s//NM104 1/35 Name First:
					+Sout(subscriber.MiddleI,25)+s//NM105 1/25 Name Middle:
					+s//NM106 1/10 Name Prefix: Not Used.
					+s//NM107 1/10 Name Suffix: Situational. Not present in Open Dental yet so we leave blank.
					+"MI"+s//NM108 1/2 Identification Code Qualifier: MI=Member Identification Number.
					+Sout(sub.SubscriberID.Replace("-",""),80,2));//NM109 2/80 Identification Code: Situational. Required when NM102=1.
				EndSegment(sw);//NM110 through NM112 are not used.
				//In 4010s, at the request of Emdeon, we always include N3,N4,and DMG even if patient is not subscriber.  This did not make the transaction non-compliant, and they found it useful.
				//In 5010s, we will follow the X12 specification for most clearinghouses and only include subsc address when subscriber=patient.
				//But for any clearinghouse who requests it, we will always include, [js 3/14/13 even when subscriber!=patient].  List them here:
				//ClaimConnect, EmdeonMed, EmdeonDent, LindsayTechnicalConsultants, OfficeAlly: Always include.
				//PostNTrack, BCBSIdaho: Only include when subscriber=patient.
				bool subscIncludeAddressAndGender=false;
				if(IsClaimConnect(clearhouse) || IsEmdeonDental(clearhouse) || IsEmdeonMedical(clearhouse) || IsLindsayTechnicalConsultants(clearhouse) || IsOfficeAlly(clearhouse)) {
					subscIncludeAddressAndGender=true;
				}
				else {//X12 standard behavior for everyone else, including: BCBSIdaho, ColoradoMedicaid, Denti-Cal, PostNTrack, WashingtonMedicaid.
					if(subscriber.PatNum==patient.PatNum) {//[js 3/14/13 only include when subscriber==patient]
						subscIncludeAddressAndGender=true;
					}
					//[js 3/14/13 when subscriber!=patient, don't include address]
				}
				if(subscIncludeAddressAndGender) {
					//2010BA N3: (medical,institutional,dental) Subscriber Address. Situational. Required when the patient is the subscriber.
					sw.Write("N3"+s+Sout(subscriber.Address,55));//N301 1/55 Address Information:
					if(subscriber.Address2!="") {
						sw.Write(s+Sout(subscriber.Address2,55));//N302 1/55 Address Information:
					}
					EndSegment(sw);
					//2010BA N4: (medical,institutional,dental) Subscriber City, State, Zip Code. Situational. Required when the patient is the subscriber.
					sw.Write("N4"+s
						+Sout(subscriber.City,30)+s//N401 2/30 City Name:
						+Sout(subscriber.State,2,2)+s//N402 2/2 State or Provice Code:
						+Sout(subscriber.Zip.Replace("-",""),15));//N403 3/15 Postal Code:
					EndSegment(sw);//N404 through N407 either not used or required for addresses outside of the United States.
					//2010BA DMG: (medical,institutional,dental) Subscriber Demographic Information. Situational. Required when the patient is the subscriber.
					//Carriers tend to complain if the BD is missing for the subscriber even though it's not strictly required.  So we will require it from users.
					sw.Write("DMG"+s
						+"D8"+s//DMG01 2/3 Date Time Period Format Qualifier: D8=Date Expressed in Format CCYYMMDD.
						+subscriber.Birthdate.ToString("yyyyMMdd")+s//DMG02 1/35 Date Time Period: Birthdate. The subscriber birtdate is validated.
						+GetGender(subscriber.Gender));//DMG03 1/1 Gender Code: F=Female, M=Male, U=Unknown.
					EndSegment(sw);
				}
				//2010BA REF: SY (medical,institutional,dental) Secondary Secondary Identification: Situational. Required when an additional identification number to that provided in NM109 of this loop is necessary. We do not use this.
				//2010BA REF: Y4 (medical,institutional,dental) Property and Casualty Claim Number: Required when the services included in this claim are to be considered as part of a property and casualty claim. We do not use this.
				//2010BA PER: IC (medical) Property and Casualty Subscriber Contact information: Situational. We do not use this.
				//2010BB NM1: PR (medical,institutional,dental) Payer Name.
				sw.Write("NM1"+s
					+"PR"+s//NM101 2/3 Entity Identifier Code: PR=Payer.
					+"2"+s);//NM102 1/1 Entity Type Qualifier: 2=Non-Person Entity.
				//NM103 1/60 Name Last or Organization Name:
				if(IsEMS(clearhouse)) {
					//This is a special situation requested by EMS.  This tacks the employer onto the end of the carrier.
					sw.Write(Sout(carrier.CarrierName,30)+"|"+Sout(Employers.GetName(insPlan.EmployerNum),30)+s);
				}
				else if(IsDentiCal(clearhouse)) {
					sw.Write("DENTICAL"+s);
				}
				else {
					sw.Write(Sout(carrier.CarrierName,60)+s);
				}
				sw.Write(s//NM104 1/35 Name First: Not used.
					+s//NM105 1/25 Name Middle: Not used.
					+s//NM106 1/10 Name Prefix: Not used.
					+s//NM107 1/10 Name Suffix: Not used.
					+"PI"+s);//NM108 1/2 Identification Code Qualifier: PI=Payor Identification.
				sw.Write(Sout(GetCarrierElectID(carrier,clearhouse),80,2));//NM109 2/80 Identification Code: PayorID.
				EndSegment(sw);//NM110 through NM112 Not Used.
				//2010BB N3: (medical,institutional,dental) Payer Address.
				sw.Write("N3"+s+Sout(carrier.Address,55));//N301 1/55 Address Information:
				if(carrier.Address2!="") {
					sw.Write(s+Sout(carrier.Address2,55));//N302 1/55 Address Information: Required when there is a second address line.
				}
				EndSegment(sw);
				//2010BB N4: (medical,institutional,dental) Payer City, State, Zip Code.
				sw.Write("N4"+s
					+Sout(carrier.City,30)+s//N401 2/30 City Name:
					+Sout(carrier.State,2)+s//N402 2/2 State or Province Code:
					+Sout(carrier.Zip.Replace("-",""),15));//N403 3/15 Postal Code:
				EndSegment(sw);//N404 through N407 are either not used or are for addresses outside of the United States.
				//2010BB REF 2U,EI,FY,NF (dental) Payer Secondary Identificaiton. Situational.
				//2010BB REF G2,LU Billing Provider Secondary Identification. Situational. Not required because we always send NPI.
				if(!IsDentiCal(clearhouse)){//DentiCal complained that they don't usually want this (except for non-subparted NPIs, which we don't handle).  So far, nobody else has complained.
					//Always required by Emdeon Dental.
					WriteProv_REFG2orLU(sw,billProv,carrier.ElectID);
				}
				parentSubsc=HLcount;
				HLcount++;
				#endregion
				#region Patient
				if(patient.PatNum!=subscriber.PatNum){//if patient is not the subscriber
					//2000C HL: (medical,institutional,dental) Patient Hierarchical Level.
					sw.Write("HL"+s+HLcount.ToString()+s//HL01 1/12 Hierarchical ID Number:
						+parentSubsc.ToString()+s//HL02 1/12 Hierarchical Parent ID Number: Parent is always the subscriber HL.
						+"23"+s//HL03 1/2 Hierarchical Level Code: 23=Dependent.
						+"0");//HL04 1/1 Hierarchical Child Code: 0=No subordinate HL segment in this hierarchical structure.
					EndSegment(sw);
					//2000C PAT: (medical,institutional,dental) Patient Information.
					if(IsEmdeonDental(clearhouse)) {
						sw.Write("PAT"+s
							+GetRelat(claim.PatRelat)+s//PAT01 2/2 Individual Relationship Code:
							+s//PAT02 1/1 Patient Location Code: Not used.
							+s//PAT03 2/2 Employment Status Code: Not used.
							+GetStudentEmdeon(patient.StudentStatus));//PAT04 1/1 Student Status Code: Not used. Emdeon wants us to sent this code corresponding to version 4010, even through it is not standard X12.
						EndSegment(sw);//PAT05 through PAT08 not used in institutional or dental, but is sometimes used in medical. We do not use.
					}
					else {
						sw.Write("PAT"+s
							+GetRelat(claim.PatRelat));//PAT01 2/2 Individual Relationship Code:
						EndSegment(sw);//PAT02 through PAT04 Not used. PAT05 through PAT08 not used in institutional or dental, but is sometimes used in medical. We do not use.
					}
					//2010CA NM1: QC (medical,institutional,dental) Patient Name.
					sw.Write("NM1"+s
						+"QC"+s//NM101 2/3 Entity Identifier Code: QC=Patient.
						+"1"+s//NM102 1/1 Entity Type Qualifier: 1=Person.
						+Sout(patient.LName,60)+s//NM103 1/60 Name Last or Organization Name:
						+Sout(patient.FName,35));//NM104 1/35 Name First: Never blank, because validated in the patient edit window when a patient is added/edited.
						if(patient.MiddleI!="") {
							sw.Write(s+Sout(patient.MiddleI,25));//NM105 1/25 Name Middle
						}
					EndSegment(sw);
					//NM106 not used. NM107, No suffix field in Open Dental. NM108 through NM112 not used.
					//2010CA N3: (medical,institutional,dental) Patient Address.
					sw.Write("N3"+s+
						Sout(patient.Address,55));//N301 1/55 Address Information
					if(patient.Address2!="") {
						sw.Write(s+Sout(patient.Address2,55));//N302 1/55 Address Information:
					}
					EndSegment(sw);
					//2010CA N4: (medical,institutional,dental) Patient City, State, Zip Code.
					sw.Write("N4"+s
						+Sout(patient.City,30)+s//N401 2/30 City Name:
						+Sout(patient.State,2,2)+s//N402 2/2 State or Provice Code: 
						+Sout(patient.Zip.Replace("-",""),15));//N403 3/15 Postal Code: 
					EndSegment(sw);//N404 through N407 are either not used or only required for addresses outside the United States.
					//2010CA DMG: (medical,institutional,dental) Patient Demographic Information.
					sw.Write("DMG"+s
						+"D8"+s//DMG01 2/3 Date Time Period Format Qualifier: D8=Date Expressed in Format CCYYMMDD.
						+patient.Birthdate.ToString("yyyyMMdd")+s//DMG02 1/35 Date Time Period:
						+GetGender(patient.Gender));//DMG03 1/1 Gender Code: F=Female,M=Male,U=Unknown.
					EndSegment(sw);//DMG04 through DMG11 are not used.
					//2010CA REF: (medical,instituional,dental) Property and Casualty Claim Number. Situational. We do not use this.
					//2010CA REF: (medical,institutional) Property and Casualty Patient Identifier. Situational.  We do not use.
					//2010CA PER: (medical) Property and Casualty Patient Contact Information. Situational. We do not use.
					HLcount++;
				}
				#endregion
				#region Claim CLM
				//2300 CLM: (medical,institutional,dental) Claim Information.
				string clm01=claim.ClaimIdentifier;//Typically PatNum/ClaimNum. Check for uniqueness is performed in UI.
				if(IsDentiCal(clearhouse)) {
					clm01=Sout(clm01,17);//Denti-Cal has a maximum of 17 chars here. This field is what Denti-Cal refers to as the PDCN.
				}
				else if(IsEmdeonMedical(clearhouse)) {
					clm01=clm01.Replace('/','-');//Emdeon Medical only allows letters, numbers, dashes, periods, spaces and asterisks. The claim identifier will contain / inside the claim edit window still.
				}
				string claimFrequencyTypeCode="1";
				if(claim.CorrectionType==ClaimCorrectionType.Original) {
					claimFrequencyTypeCode="1";
				}
				else if(claim.CorrectionType==ClaimCorrectionType.Replacement) {
					claimFrequencyTypeCode="7";
				}
				else if(claim.CorrectionType==ClaimCorrectionType.Void) {
					claimFrequencyTypeCode="8";
				}
				//the next 8 lines fix a rare bug where the total doesn't match the sum of the procs.  This would result in invalid X12
				decimal claimFeeBilled=0;
				for(int j=0;j<claimProcs.Count;j++) {
					claimFeeBilled+=(decimal)claimProcs[j].FeeBilled;
				}
				if(claimFeeBilled!=(decimal)claim.ClaimFee) {
					claim.ClaimFee=(double)claimFeeBilled;
				  Claims.Update(claim);
				}
				sw.Write("CLM"+s
					+Sout(clm01,20)+s//CLM01 1/38 Claim Submitter's Identifier: A unique id. Carriers are not required to handle more than 20 char. 
					+claimFeeBilled.ToString("f2")+s//CLM02 1/18 Monetary Amount:
					+s//CLM03 1/2 Claim Filing Indicator Code: Not used.
					+s);//CLM04 1/2 Non-Institutional Claim Type Code: Not used.
				//CLM05 (medical,institutional,dental) Health Care Services Location Information.
				if(medType==EnumClaimMedType.Medical) {
					sw.Write(GetPlaceService(claim.PlaceService)+isa16//CLM05-1 1/2  Facility Code Value: Place of Service.
						+"B"+isa16//CLM05-2 1/2 Facility Code Qualifier, B=Place of Service Codes.
						+claimFrequencyTypeCode+s);//CLM05-3 1/1 Claim Frequency Type Code: 1=original, 7=replacement, 8=void(in limited jurisdictions).
				}
				else if(medType==EnumClaimMedType.Institutional) {
					//claim.UniformBillType validated to be exactly 3 char
					//Example: 771: 7=clinic, 7=FQHC, 1=Only claim.  713: 7=clinic, 1=rural health clinic, 3=continuing claim.
					sw.Write(claim.UniformBillType.Substring(0,2)+isa16//CLM05-1 1/2  Facility Code Value: First and second position of UniformBillType.
						+"A"+isa16//CLM05-2 1/2 Facility Code Qualifier, A=Uniform Billing Claim Form Bill Type.
						+claim.UniformBillType.Substring(2,1)+s);//CLM05-3 1/1 Claim Frequency Type Code: Third position of UniformBillType.
				}
				else{//dental.
					sw.Write(GetPlaceService(claim.PlaceService)+isa16//CLM05-1 1/2  Facility Code Value: Place of Service.
						+"B"+isa16//CLM05-2 1/2 Facility Code Qualifier, B=Place of Service Codes.
						+claimFrequencyTypeCode+s);//CLM05-3 1/1 Claim Frequency Type Code: 1=original, 7=replacement, 8=void(in limited jurisdictions).
				}
				if(medType==EnumClaimMedType.Medical) {
					sw.Write("Y"+s);//CLM06 1/1 Yes/No Condition or Response Code: prov sig on file (always yes)
				}
				else if(medType==EnumClaimMedType.Institutional) {
					sw.Write(s);//CLM06 1/1 Yes/No Condition or Response Code: Not used.
				}
				else if(medType==EnumClaimMedType.Dental) {
					sw.Write("Y"+s);//CLM06 1/1 Yes/No Condition or Response Code: prov sig on file (always yes)
				}
				sw.Write("A"+s//CLM07 1/1 Provider Accept Assignment Code: Prov accepts medicaid assignment. OD has no field for this, so no choice.
					+(sub.AssignBen?"Y":"N")+s//CLM08 1/1 Yes/No Condition or Response Code: We do not support W.
					+(sub.ReleaseInfo?"Y":"I"));//CLM09 1/1 Release of Information Code: Y or I(which is equivalent to No)
				if(medType==EnumClaimMedType.Medical || medType==EnumClaimMedType.Dental) {
					if(claim.AccidentDate.Year>1880 || claim.SpecialProgramCode!=EnumClaimSpecialProgram.none || claim.ClaimType=="PreAuth") {//if val for 11,12, or 19
						sw.Write(s+s//end of CLM09. CLM10 not used
							+GetRelatedCauses(claim));//CLM11 2/3:2/3:2/3:2/2:2/3 Related Causes Information: Situational. Accident related, including state. Might be blank.
					}
					if(claim.SpecialProgramCode!=EnumClaimSpecialProgram.none || claim.ClaimType=="PreAuth") {//if val for 12, or 19
						sw.Write(s//nothing for CLM11.
							+GetSpecialProgramCode(claim.SpecialProgramCode));//CLM12 2/3 Special Program Code: Situational. Example EPSTD.
					}
					if(claim.ClaimType=="PreAuth") {//if val for 19
						sw.Write(s//nothing for CLM12.
							+s+s+s+s+s+s//CLM13-18 not used
							+"PB");//CLM19 2/2 Claim Submission Reason Code: PB=Predetermination of Benefits. TODO: Not allowed in medical claims. What is the replacement??
						//CLM20 1/2 Delay Reason Code: Situational. Required when claim is submitted late. Not supported.
					}
				}
				//CLM10-19 not used, 20 not supported for institutional.
				EndSegment(sw);
				#endregion Claim CLM
				#region Claim DTP
				if(medType==EnumClaimMedType.Medical) {
					//2300 DTP: 431 (medical) Date Onset of Current Illness or Symptom. Situational. We do not use.
					//2300 DTP: 454 (medical) Initial Treatment Date. Situational. We do not use. (spinal manipulation).
					//2300 DTP: 304 (medical) Date Last Seen. Situational. We do not use. (foot care)
					//2300 DTP: 453 (medical) Date Accute Manifestation. Situational. We do not use. (spinal manipulation)
					//2300 DTP: 439 (medical) Date Accident. Situational.
					if(claim.AccidentDate.Year>1880) {
						sw.Write("DTP"+s
							+"439"+s//DTP01 3/3 Date/Time Qualifier: 439=accident
							+"D8"+s//DTP02 2/3 Date Time Period Format Qualifer: D8=Date Expressed in Format CCYYMMDD.
							+claim.AccidentDate.ToString("yyyyMMdd"));//DTP03 1/35 Date Time Period:
						EndSegment(sw);
					}
					//2300 DTP: 484 (medical) Last Menstrual Period Date. Situational. We do not use.
					//2300 DTP: 455 (medical) Last X-ray Date. Situational. We do not use.
					//2300 DTP: 471 (medical) Hearing and Vision Prescription Date. Situational. We do not use.
					//2300 DTP: 314,360,361 (medical) Disability Dates. Situational. We do not use.
					//2300 DTP: 297 (medical) Date Last Worked. Situational. We do not use.
					//2300 DTP: 296 (medical) Date Authorized Return to Work. Situational. We do not use.
					//2300 DTP: 435 (medical) Date Admission. Situational. We do not use. Inpatient. Request #2843.
					//2300 DTP: 096 (medical) Date Discharge. Situational. We do not use. Inpatient. Request #2843.
					//2300 DTP: 090 (medical) Date Assumed and Relinquished Care Dates. Situational. We do not use.
					//2300 DTP: 444 (medical) Date Property and Casualty Date of First Contact. Situational. We do not use.
					//2300 DTP: 050 (medical) Repricer Received Date. Situational. We do not use.
				}
				else if(medType==EnumClaimMedType.Institutional) {
					//2300 DTP 096 (institutional) Discharge Hour. Situational. We do not use. Inpatient. 
					//2300 DTP 434 (instititional) Statement Dates.
//todo:how to handle preauths?
					if(claim.DateService.Year>1880) {//DateService validated
						sw.Write("DTP"+s
							+"434"+s//DTP01 3/3 Date/Time Qualifier: 434=Statement.
							+"RD8"+s//DTP02 2/3 Date Time Period Format Qualifier: RD8=Range of Dates Expressed in Format CCYYMMDD-CCYYMMDD.
							+claim.DateService.ToString("yyyyMMdd")+"-"+claim.DateService.ToString("yyyyMMdd"));//DTP03 1/35 Date Time Period:
						EndSegment(sw);
					}
					//2300 DTP 435 (institutional) Admission Date/Hour. Situational. We do not use. Inpatient.
					//For the UB04 we are using claim.DateService for this field.
					//2300 DTP 050 (institutional) Repricer Received Date. Situational. Not supported.
				}
				else if(medType==EnumClaimMedType.Dental) {
					//2300 DTP 439 (dental) Date accident. Situational. Required when there was an accident.
					if(claim.AccidentDate.Year>1880) {
						sw.Write("DTP"+s
							+"439"+s//DTP01 3/3 Date/Time Qualifier: 439=accident
							+"D8"+s//DTP02 2/3 Date Time Period Format Qualifer: D8=Date Expressed in Format CCYYMMDD.
							+claim.AccidentDate.ToString("yyyyMMdd"));//DTP03 1/35 Date Time Period:
						EndSegment(sw);
					}
					//2300 DTP 452 (dental) Date Appliance Placement. Situational. Values can be overriden in loop 2400 for individual service items, but we don't support that.
					if(claim.OrthoDate.Year>1880) {
						sw.Write("DTP"+s
							+"452"+s//DTP01 3/3 Date/Time Qualifier: 452=Appliance Placement.
							+"D8"+s//DTP02 2/3 Date Time Period Format Qualifier: D8=Date Expressed in Format CCYYMMDD.
							+claim.OrthoDate.ToString("yyyyMMdd"));//DTP03 1/35 Date Time Period:
						EndSegment(sw);
					}
					//2300 DTP 472 (dental) Service Date. Not used if predeterm.
					if(claim.ClaimType!="PreAuth") {
						if(claim.DateService.Year>1880) {
							sw.Write("DTP"+s
								+"472"+s//DTP01 3/3 Date/Time Qualifier: 472=Service.
								+"D8"+s//DTP02 2/3 Date Time Period Format Qualifier: D8=Date Expressed in Format CCYYMMDD.
								+claim.DateService.ToString("yyyyMMdd"));//DTP03 1/35 Date Time Period:
							EndSegment(sw);
						}
					}
					//2300 DTP 050 (dental) Repricer Received Date.  Not supported.
				}
				#endregion Claim DTP
				#region Claim DN CL1
				if(medType==EnumClaimMedType.Dental) {
					//2300 DN1: Orthodontic Total Months of Treatment.
					if(claim.IsOrtho) {
						sw.Write("DN1"+s
							+s//DN101 1/15 Quantity: Total months of orthodontic treatment. Not used because no field yet in OD.
							+claim.OrthoRemainM.ToString());//DN102 1/15 Quantity: Number of treatment months remaining.
						EndSegment(sw);//DN103 is not used and DN104 is situational but we do not use it.
					}
					//2300 DN2: Tooth Status. Missing teeth.
					List<string> missingTeeth=ToothInitials.GetMissingOrHiddenTeeth(initialList);
					bool doSkip;
					int countMissing=0;
					for(int j=0;j<missingTeeth.Count;j++) {
						//if the missing tooth is missing because of an extraction being billed here, then exclude it
						//still needed, even though missing teeth are not based on procedures any longer
						doSkip=false;
						for(int p=0;p<claimProcs.Count;p++) {
							proc=Procedures.GetProcFromList(procList,claimProcs[p].ProcNum);
							procCode=ProcedureCodes.GetProcCode(proc.CodeNum);
							if(procCode.PaintType==ToothPaintingType.Extraction && proc.ToothNum==missingTeeth[j]) {
								doSkip=true;
								break;
							}
						}
						if(doSkip) {
							continue;
						}
						countMissing++;
						if(countMissing>35) {//segment max use 35
							continue;
						}
						sw.Write("DN2"+s
							+missingTeeth[j]+s//DN201 1/50 Reference Identification: Tooth number.
							+"M"+s//DN202: M=Missing, I=Impacted, E=To be extracted.
							+s//DN203 1/15 Quantity: Not used.
							+s//DN204 2/3 Date Time Period Format Qualifier: Not used.
							+s//DN205 1/35 Date Time Period: Not used.
							+"JP");//DN206 1/3 Code List Qualifier Code: Required. JP=JP Universal National Tooth Designation System.
						EndSegment(sw);
					}
				}
				if(medType==EnumClaimMedType.Institutional) {
					//2300 CL1: Institutional Claim Code. Required
					sw.Write("CL1"+s
						+claim.AdmissionTypeCode+s//CL101 1/1 Admission Type Code: Validated.
						+claim.AdmissionSourceCode+s//CL102 1/1 Admission Source Code: Required for inpatient services. Validated.
						+claim.PatientStatusCode);//CL103 1/2 Patient Status Code: Validated.
					EndSegment(sw);//CL104 1/1 Nursing Home Residential Status Code: Not used.
				}
				#endregion Claim DN CL1
				#region Claim PWK
				//2300 PWK: (medical,institutional,dental) Claim Supplemental Information. Paperwork. Used to identify attachments.
				/*if(IsTesia(clearhouse) && claim.Attachments.Count>0) {//If Tesia and has attachments
					sw.Write("PWK"+s
						+"OZ"+s//PWK01: ReportTypeCode. OZ=Support data for claim.
						+"EL"+s//PWK02: Report Transmission Code. EL=Electronic
						+s+s//PWK03 and 04: not used
						+"AC"+s//PWK05: Identification Code Qualifier. AC=Attachment Control Number
						+"TES"+claim.ClaimNum.ToString());//PWK06: Identification Code.
				 	EndSegment(sw);
				}*/
				//If Attachment ID # is present but no attachment flag, then sending is blocked.
				//No other validation is done.  However, warnings are displayed if:
				//Warning if attachments are listed as Mail even though we are sending electronically.
				//Warning if any PWK segments are needed, and there is no ID code.
				//PWK can repeat max 10 times.  However, we only write one PWK segment, because the user can only enter one Attachment Control Number.
				string pwk01="  ";//This double blank will never actually get sent because of the trim and if statement around the PWK creation.
				if(claim.AttachedFlags.Contains("EoB")) {
					pwk01="EB";//Explaination of Benefits
				}
				if(claim.AttachedFlags.Contains("Perio")) {
					if(medType==EnumClaimMedType.Dental) {
						pwk01="P6";//Periodontal Charts
					}
					else {//Medical and institutional
						pwk01="OZ";//Support Data for Claim. There is no "P6" nor a code for perio charts.
					}
				}
				if(claim.AttachedFlags.Contains("Misc") || claim.AttachedFlags.Contains("Note") || claim.AttachedImages>0) {
					pwk01="OZ";//Support Data for Claim
				}
				if(claim.Radiographs>0) {
					pwk01="RB";//Radiology Films
				}
				if(claim.AttachedModels>0) {
					pwk01="DA";//Dental Models
				}
				string pwk02="  ";
				if(IsDentiCal(clearhouse)) {
					pwk02="FT";//"File Transfer". Might be electronic or mail, but Denti-Cal requires a value of FT here.
				}
				else {
					if(claim.AttachedFlags.Contains("Mail")) {
						pwk02="BM";//By Mail
					}
					else {
						pwk02="EL";//Elect
					}
				}
				string pwk06=claim.AttachmentID;
				if(pwk02=="BM" && pwk06=="") {//If By Mail is checked, they will typically leave attachment ID blank, but X12 requires a value, so we make one up.
					pwk06="00";
				}
				pwk06=Sout(pwk06,80,2);
				if(pwk01.Trim()!="" && pwk06!="") {
					sw.Write("PWK"+s
						+pwk01+s//PWK01 2/2 Report Type Code:
						+pwk02+s//PWK02 1/2 Report Transmission Code: EL=Electronically Only, BM=By Mail.
						+s+s//PWK03 and PWK04: Not Used.
						+"AC"+s//PWK05 1/2 Identification Code Qualifier: AC=Attachment Control Number.
						+pwk06);//PWK06 2/80 Identification Code:
					EndSegment(sw);//PWK07 through PWK09 are not used.
				}
				#endregion Claim PWK
				#region Claim CN1 AMT
				//2300 CN1: (medical,institutional,dental)Contract Information. Situational. We do not use this.
				//2300 AMT: (institutional) Patient Estimated Amount Due.
				//2300 AMT: (medical,dental) Patient Amount Paid. Situational. We do not use this.
				if(medType==EnumClaimMedType.Medical || medType==EnumClaimMedType.Dental) {
					//sw.Write("AMT"+s
				  //  +"F5"+s//AMT01 1/3 Amount Qualifier Code: F5=Patient Paid Amount.
				  //  +"0");//AMT02 1/18 Monetary Amount: We don't track this information very well so we always put zero.
					//EndSegment(sw);//AMT03 is not used.
				}
				#endregion Claim CN1 AMT
				#region Claim REF
				if(medType==EnumClaimMedType.Dental) {
					//2300 REF: G3 (dental) Predetermination Identification. Situational.  Required when sending claim for previously predetermined services. Do not send prior authorization number here.
					if(claim.PreAuthString!="") {//validated to be empty for medical and inst
						sw.Write("REF"+s
							+"G3"+s//REF01 2/3 G3=Predetermination of Benefits Identification Number.
							+Sout(claim.PreAuthString,50));//REF02 1/50 Predeterm of Benfits Identifier.
						EndSegment(sw);//REF03 and REF04 are not used.
					}
				}
				//2300 REF: 4N (medical,institutional,dental) Service Authorization Exception Code. Situational. Required if services were performed without authorization.
//todo: ServiceAuthException
				//2300 REF: F5 (medical) Mandatory Medicare (Section 4081) Crossover Indicator. Situational. Required when submitter is Medicare and the claim is a Medigap or COB crossover claim. We do not use.
				//2300 REF: EW (medical) Mammography Certification Number. Situational. We do not use.
				//2300 REF: F8 (medical,institutional,dental) Payer Claim Control Number: Situational. Required if this is a replacement or void claim. Might not be required for corrected, but we require anyway since it is required in 4010.
					//aka Original Document Control Number/Internal Control Number (DCN/ICN).
					//aka Transaction Control Number (TCN).  
					//aka Claim Reference Number. 
					//Seems to be required by Medicaid when voiding a claim or resubmitting a claim by setting the CLM05-3.
				if(claim.CorrectionType!=ClaimCorrectionType.Original 
					|| claim.UniformBillType.Length>2 && (claim.UniformBillType.Substring(2,1)=="6" || claim.UniformBillType.Substring(2,1)=="7" || claim.UniformBillType.Substring(2,1)=="8")) { //correction, replacement or void.
					sw.Write("REF"+s
						+"F8"+s//REF01 2/3 Reference Identification Qualifier: F8=Original Reference Number.
						+Sout(claim.OrigRefNum,50));//REF02 1/50 Reference Identification: Payer Claim Control Number.
					EndSegment(sw);//REF03 and REF04 are not used.
				}
				//2300 REF: 9F (medical,institutional,dental) Referral Number. Situational. Required when a referral number is assigned by the payer or Utilization Management Organization (UMO) AND a referral is involved.
				if(claim.RefNumString!="") {
					sw.Write("REF"+s
						+"9F"+s//REF01 2/3 Reference Identification Qualifier: 9F=Referral Number.
						+Sout(claim.RefNumString,30));//REF02 1/50 Reference Identification:
					EndSegment(sw);//REF03 and REF04 are not used.
				}
				//2300 REF: X4 (medical) Clinical Laboratory Improvement Amendment (CLIA) Number. Situational. We do not use.
				//2300 REF: G1 (medical,institutional,dental) Prior Authorization. Situational. Do not report predetermination of benefits id number here. G1 and G3 were muddled in 4010.  
				if(claim.PriorAuthorizationNumber!="") {
					sw.Write("REF"+s
						+"G1"+s//REF01 2/3 Reference Identification Qualifier: G1=Prior Authorization Number.
						+Sout(claim.PriorAuthorizationNumber,50));//REF02 1/50 Reference Identification: Prior Authorization Number.
					EndSegment(sw);//REF03 and REF04 are not used.
				}					
				//2300 REF: 9A (medical,institutional,dental) Repriced Claim Number. Situational. We do not use. 
				//2300 REF: 9C (medical,institutional,dental) Adjusted Repriced Claim Number. Situational. We do not use.
				//2300 REF: D9 (medical,institutional,dental) Claim Identifier For Transmission Intermediaries. Situational.
				if(IsClaimConnect(clearhouse)) { //Since this information has only been requested by ClaimConnect and is optional in the specification, we should only add specific clearinghouses here when requested.
					sw.Write("REF"+s
						+"D9"+s//REF01 2/3 Reference Identification Qualifier: D9=Claim Number.
						+Sout(claim.ClaimIdentifier,20));//REF02 1/50 Reference Identification: Value Added Network Trace Number. From specification, maximum of 20 characters even though there is space for 50.
					EndSegment(sw);//REF03 and REF04 are not used.
				}
				//2300 REF: LX (medical,institutional) Investigational Device Exemption Number. Situational. Required for FDA IDE.
				//2300 REF: LU (institutional) Auto Accident State. Situational. Seems to me to be a duplicate of the info in CLM11.
				//2300 REF: EA (medical,institutional) Medical Record Number. Situational. We do not use.
				//2300 REF: P4 (medical,institutional) Demonstration Project Identifier. Situational. We do not use. Seems very unimportant.
				//2300 REF: G4 (institutional) Peer Review Organization (PRO) Approval Number. Situational. We do not use.
				//2300 REF: 1J (medical) Care Plan Oversight. Situational. We do not use.
				#endregion Claim REF
				#region Claim K3 NTE CRx
				//2300 K3: File info (medical,institutional,dental). Situational. We do not use this.
				//NTE loops------------------------------------------------------------------------------------------------------
				//2300 NTE: (medical,institutional,dental) Claim Note. Situational. A number of NTE01 codes other than 'ADD', which we don't support.
				string note="";
				if(claim.AttachmentID!="" && !claim.ClaimNote.StartsWith(claim.AttachmentID)) {
					note=claim.AttachmentID+" ";
				}
				note+=claim.ClaimNote;
				if(note!="") {
					sw.Write("NTE"+s
						+"ADD"+s//NTE01 3/3 Note Reference Code: ADD=Additional information.
						+Sout(note,80));//NTE02 1/80 Description:
					EndSegment(sw);
				}
				//2300 NTE: (institutional) Billing Note. Situational. We do not use.
				//CRx loops------------------------------------------------------------------------------------------------------
				//2300 CR1: LB (medical) Ambulance Transport Information. Situational. We do not use.
				//2300 CR2: (medical) Spinal Manipulation Service Information. Situational. We do not use.
				//2300 CRC: (medical) Ambulance Certification. Situational. We do not use.
				//2300 CRC: (medical) Patient Condition Information Vision. Situational. We do not use.
				//2300 CRC: (medcial) Homebound Indicator. Situational. We do not use.
				//2300 CRC: (medical,institutional) EPSDT Referral. Situational. Required on EPSDT claims when the screening service is being billed in this claim. We do not use.
				#endregion Claim K3 NTE CRx
				#region Claim HI HCP
				//HI loops-------------------------------------------------------------------------------------------------------
				List<string> diagnosisList=new List<string>();//princDiag will always be the first element.
				if(medType==EnumClaimMedType.Medical || medType==EnumClaimMedType.Institutional){
					for(int j=0;j<claimProcs.Count;j++) {
						proc=Procedures.GetProcFromList(procList,claimProcs[j].ProcNum);
						if(proc.DiagnosticCode=="") {
							continue;
						}
						if(proc.IsPrincDiag) {
							if(diagnosisList.Contains(proc.DiagnosticCode)) {
								diagnosisList.Remove(proc.DiagnosticCode);
							}
							diagnosisList.Insert(0,proc.DiagnosticCode);//princDiag always goes first. There will always be one.
						}
						else {//not princDiag
							if(!diagnosisList.Contains(proc.DiagnosticCode)) {
								diagnosisList.Add(proc.DiagnosticCode);
							}
						}
					}
				}
				//2300 HI: BK (medical,dental) Health Care Diagnosis Code. Situational. For OMS or anesthesiology.
//todo: validate at least one diagnosis
				if(medType==EnumClaimMedType.Institutional) {
					sw.Write("HI"+s
						+"BK"+isa16//HI01-1 1/3 Code List Qualifier Code: BK=ICD-9 Principal Diagnosis.
						+Sout(diagnosisList[0].Replace(".",""),30));//HI01-2 1/30 Industry Code: Diagnosis code. No periods.
					EndSegment(sw);
				} 
				else if(medType==EnumClaimMedType.Medical) {
					sw.Write("HI"+s
						+"BK"+isa16//HI01-1 1/3 Code List Qualifier Code: BK=ICD-9 Principal Diagnosis.
						+Sout(diagnosisList[0].Replace(".",""),30));//HI01-2 1/30 Industry Code: Diagnosis code. No periods.
					for(int j=1;j<diagnosisList.Count;j++) {
						if(j>11) {//maximum of 12 diagnoses
							break;
						}
						sw.Write(s//this is the separator from the _previous_ field.
							+"BF"+isa16//HI0#-1 1/3 Code List Qualifier Code: BF=ICD-9 Diagnosis
							+Sout(diagnosisList[j].Replace(".",""),30));//HI0#-2 1/30 Industry Code: Diagnosis code. No periods.
					}
					EndSegment(sw);
				}
				//2300 HI: BP (medical) Anesthesia Related Procedure. Situational. We do not use.
				//2300 HI: BJ (institutional) Admitting Diagnosis. Situational. Required for inpatient admission. We do not use.
				//2300 HI: PR (institutional) Patient's Reason for Visit. Situational. Required for outpatient visits.
				if(medType==EnumClaimMedType.Institutional) {
					sw.Write("HI"+s
						+"PR"+isa16//HI01-1 1/3 Code List Qualifier Code: PR=ICD-9 Patient's Reason for Visit.
						+Sout(diagnosisList[0].Replace(".",""),30));//HI01-2 1/30 Industry Code: No periods. This is not really principal diagnosis but is close to the same, so someday we will add this field to claim.
					EndSegment(sw);
				}
				//2300 HI: BN (institutional) External Cause of Injury. Situational. We do not use.
				//2300 HI: (institutional) Diagnosis Related Group (DRG) Information. Situational. We do not use. For inpatient hospital under DRG contract.
				//2300 HI: BF (institutional) Other Diagnosis Information. Situational. We do not use. When other conditions coexist or develop.
				//2300 HI: BR (institutional) Principal Procedure Information. Situational. We do not use. Required on inpatient claims when a procedure was performed.
				//2300 HI: BQ (institutional) Other Procedure Information. Situational. We do not use. Inpatient claims for additional procedures.
				//2300 HI: BI (institutional) Occurence Span Information. Situational. We do not use. For an occurence span code.
				//2300 HI: BH (institutional) Occurence Information. Situational. We do not use. For an occurence code.
				//2300 HI: BE (institutional) Value Information. Situational. We do not use. For a value code.
				//2300 HI: BG (medical,institutional) Condition Information. Situational. We do not use. For a condition code.
				//2300 HI: TC (institutional) Treatment Code Information. Situational. We do not use. When home health agencies need to report plan of treatment information under contracts.
				//2300 HCP: (medical,institutional,dental) Claim Pricing/Repricing Information. Situational. We do not use.
				#endregion Claim HI HCP
				bool sendFacilityNameAndAddress=false;
				if(medType==EnumClaimMedType.Medical) {
					//Code added to send the segment below, but no logic here for sending yet, so it is never sent.
				}
				else if(medType==EnumClaimMedType.Institutional) {
					//Code added to send the segment below, but no logic here for sending yet, so it is never sent.
				}
				else if(medType==EnumClaimMedType.Dental) {
					if(claim.PlaceService!=PlaceOfService.Office) {
						if(IsClaimConnect(clearhouse)) {
							//Osvaldo Ferrer, VIP account manager for DentalXChange, says we need the segment whenever the place of service is not office.
							sendFacilityNameAndAddress=true;
						}
						else {//for other clearinghouses, the X12 specs say that we don't send it if it's the same as the billing prov.
							//and since we always set it the same as the billing prov, we shouldn't send it.
						}
					}
				}
				Provider facilityProv=billProv;//If this provider changes in the future, then the validation section will also need to be updated.
				string facilityAddress1=billingAddress1;
				string facilityAddress2=billingAddress2;
				string facilityCity=billingCity;
				string facilityState=billingState;
				string facilityZip=billingZip;
				//For medical, instititional, and dental, sending facility NPI must be for an organization (non-person).
				if(!facilityProv.IsNotPerson) {//Validated also
					sendFacilityNameAndAddress=false;
				}
				provTreat=Providers.GetProv(claim.ProvTreat);
				#region 2310 Claim Providers (medical)
				//Since order might be important, we have to handle medical, institutional, and dental separately.
				if(medType==EnumClaimMedType.Medical) {
					//2310A NM1: DN/P3 (medical) Referring Provider Name. Situational.
					WriteNM1_DN(sw,claim.ReferringProv);
					//2310A REF: (medical) Referring Provider Secondary Identification. Situational. We do not use.
					//Always included for Emdeon Medical, because Emdeon Medical will automatically remove this segment if the payer does not want it
					//Some payers reject if not specified, even when the claim.ProvTreat=claim.ProvBill. For example, Texas Medicaid.
					//if(claim.ProvTreat!=claim.ProvBill || IsEmdeonMedical(clearhouse)) {
					//2310B NM1: 82 (medical) Rendering Provider Name. Required when treating provider is different from billing provider.
					WriteNM1Provider("82",sw,provTreat);
					//2310B PRV: PE (medical) Rendering Provider Specialty Information. Situational.
					WritePRV_PE(sw,provTreat);
					//2310B REF: (medical) Rendering Provider Secondary Identification. Situational. We do not use.					
					//2310C NM1: 77 (medical) Service Facility Location Name. Conditions different than 4010.  
					//Not supposed to send if same location as 2010AA Billing Provider, but some clearinghouses want this segment anyway.
					if(sendFacilityNameAndAddress) {
						sw.Write("NM1"+s
							+"77"+s//NM101 2/3 Entity Identifier Code: 77=Service Location.
							+"2"+s//NM102 1/1 Entity Type Qualifier: 2=Non-Person Entity.
							+Sout(facilityProv.LName,60)+s//NM103 1/60 Name Last or Organization Name: Laboratory or Facility Name.
							+s//NM104 1/35 Name First: Not used.
							+s//NM105 1/25 Name Middle: Not used.
							+s//NM106 1/10 Name Prefix: Not used.
							+s//NM107 1/10 Name Suffix: Not used.
							+"XX"+s//NM108 1/2 Identification Code Qualifier: XX=NPI.
							+Sout(facilityProv.NationalProvID,80));//NM109 2/80 Identification Code: Laboratory or Facility Identifier. Validated.
						EndSegment(sw);//NM110 through NM112 not used.
						//2310C N3: (medical) Service Facility Location Address.
						sw.Write("N3"+s+Sout(facilityAddress1,55));//N301 1/55 Address Information: Laboratory or Facility Address Line.
						if(facilityAddress2!="") {
							sw.Write(s+Sout(facilityAddress2,55));//N302 1/55 Address Information: Laboratory or Facility Address Line 2. Only required when there is a secondary address line.
						}
						EndSegment(sw);
						//2310C N4: (medical) Service Facility Location City, State, Zip Code.
						sw.Write("N4"+s
							+Sout(facilityCity,30)+s//N401 2/30 City Name: Laboratory or Facility City Name.
							+Sout(facilityState,2,2)+s//N402 2/2 State or Provice Code: Laboratory or Facility State or Province Code.
							+Sout(facilityZip.Replace("-",""),15));//N403 3/15 Postal Code: Laboratory or Facility Postal Zone or ZIP Code.
						EndSegment(sw);//N404 through N407 are either not used or only required when outside of the United States.
						//2310C REF: (medical) Service Facility Location Secondary Identification. Situational. We do not use this.
						//2310C PER: (medical) Service Facility Contact Information. Situational. Required for property and casualty claims. We do not use.
					}
					//2310D NM1: (medical) Supervising Provider Name. Situational. We do not use.
					//2310D REF: (medical) Supervising Provider Secondary Identification. Situational. We do not use.
					//2310E NM1: (medical) Ambulance Pick-up Location. Situational. We do not use.
					//2310E N3: (medical) Ambulance Pick-up Location Address. We do not use.
					//2310E N4: (medical) Ambulance Pick-up Location City, State, Zip Code. We do not use.
					//2310F NM1: (medical) Ambulance Drop-off Location. Situational. We do not use.
					//2310F N3: (medical) Ambulance Drop-off Location Address. We do not use.
					//2310F N4: (medical) Ambulance Drop-off Location City, State, Zip Code. We do not use.
				}
				#endregion 2310 Claim Providers (medical)
				#region 2310 Claim Providers (inst)
				if(medType==EnumClaimMedType.Institutional) {
					//2310A NM1: 71 (institutional) Attending Provider Name. Situational. Always a person according to the specification (cannot be non-person).
					WriteNM1Provider("71",sw,provTreat.FName,provTreat.MI,provTreat.LName,provTreat.NationalProvID,false);
					//2310A PRV: AT (institutional) Attending Provider Specialty Information. Situational.
					sw.Write("PRV"+s
						+"AT"+s//PRV01 1/3 Provider Code: AT=Attending.
						+"PXC"+s//PRV02 2/3 Reference Identification Qualifier: PXC=Health Care Provider Taxonomy Code.
						+X12Generator.GetTaxonomy(provTreat));//PRV03 1/50 Reference Identification: Provider Taxonomy Code.
					EndSegment(sw);//PRV04 through PRV06 are not used.
					//2310A REF: (institutional) Attending Provider Secondary Identification. Situational.
					//2310B NM1: 72 (institutional) Operating Physician Name. Situational. For surgical procedure codes.
					//2310C REF: ZZ (institutional) Secondary Physician Secondary Identification. Situational.
					//2310C NM1: ZZ (institutional) Other Operating Physician Name. Situational.
					//2310C REF: ZZ (institutional) Other Operating Physician Secondary Identification. Situational.
					//2310D NM1: 82 (institutional) Rendering Provider Name. Situational. If different from attending provider AND when regulations require both facility and professional components.
					//2310D REF: ZZ (institutional) Rendering Provider Secondary Identificaiton. Situational.
					//2310E NM1: 77 (institutional) Service Facility Location Name. Conditions different than 4010.  
					//Not supposed to send if same location as 2010AA Billing Provider, but some clearinghouses want this segment anyway.
					if(sendFacilityNameAndAddress) {
						sw.Write("NM1"+s
							+"77"+s//NM101 2/3 Entity Identifier Code: 77=Service Location.
							+"2"+s//NM102 1/1 Entity Type Qualifier: 2=Non-Person Entity.
							+Sout(facilityProv.LName,60)+s//NM103 1/60 Name Last or Organization Name: Laboratory or Facility Name.
							+s//NM104 1/35 Name First: Not used.
							+s//NM105 1/25 Name Middle: Not used.
							+s//NM106 1/10 Name Prefix: Not used.
							+s//NM107 1/10 Name Suffix: Not used.
							+"XX"+s//NM108 1/2 Identification Code Qualifier: XX=NPI.
							+Sout(facilityProv.NationalProvID,80));//NM109 2/80 Identification Code: Laboratory or Facility Primary Identifier. Validated.
						EndSegment(sw);//NM110 through NM112 not used.
						//2310E N3: (institutional) Service Facility Location Address.
						sw.Write("N3"+s+Sout(facilityAddress1,55));//N301 1/55 Address Information: Laboratory or Facility Address Line.
						if(facilityAddress2!="") {
							sw.Write(s+Sout(facilityAddress2,55));//N302 1/55 Address Information: Laboratory or Facility Address Line 2. Only required when there is a secondary address line.
						}
						EndSegment(sw);
						//2310E N4: (institutional) Service Facility Location City, State, Zip Code.
						sw.Write("N4"+s
							+Sout(facilityCity,30)+s//N401 2/30 City Name: Laboratory or Facility City Name.
							+Sout(facilityState,2,2)+s//N402 2/2 State or Provice Code: Laboratory or Facility State or Province Code.
							+Sout(facilityZip.Replace("-",""),15));//N403 3/15 Postal Code: Laboratory or Facility Postal Zone or ZIP Code.
						EndSegment(sw);//N404 through N407 are either not used or only required when outside of the United States.
						//2310E REF: ZZ (institutional) Service Facility Location Secondary Identificiation. Situational. We do not use.
					}
					//2310F NM1: DN (institutional) Referring Provider Name. Situational. Required when referring provider is different from attending provider.
					if(claim.ReferringProv!=claim.ProvTreat) {
						WriteNM1_DN(sw,claim.ReferringProv);
					}
					//2310F REF: (institutional) Referring Provider Secondary Identification. Situational. 
				}
				#endregion 2310 Claim Providers (inst)
				#region 2310 Claim Providers (dental)
				if(medType==EnumClaimMedType.Dental) {
					//2310A NM1: DN (dental) Referring Provider Name. Situational.
					WriteNM1_DN(sw,claim.ReferringProv);
					//2310A PRV: (dental) Referring Provider Specialty Information. Situational.
					//2310A REF: G2 (dental) Referring Provider Secondary Identification. Situational.
					bool sendClaimTreatProv=false;
					if(claim.ProvTreat!=claim.ProvBill) { //Emdeon will reject the claim if this segment is the same as the billing provider for all claims in the batch.
						sendClaimTreatProv=true;//Standard X12 behavior to only include the treating provider if it is different than the billing provider.
					}
					//The following clearinghouses always want the claim treating provider, even if it is the same as the billing provider.
					if(IsOfficeAlly(clearhouse)) {
						sendClaimTreatProv=true;
					}
					if(sendClaimTreatProv) {
						//2310B NM1: 82 (dental) Rendering Provider Name. Situational. Only required if different from the billing provider.
						WriteNM1Provider("82",sw,provTreat);
						//2310B PRV: PE (dental) Rendering Provider Specialty Information.
						WritePRV_PE(sw,provTreat);
						//2310B REF: (dental) Rendering Provider Secondary Identification. Situational. Not required because we always send NPI. Max repeat of 4.
						if(IsClaimConnect(clearhouse) || IsEmdeonDental(clearhouse)) {
							//The state licence number can be anywhere between 4 and 14 characters depending on state, and most states have more than one state license format. 
							//Therefore, we only validate that the state license is present or not.
							if(provTreat.StateLicense!="") { 
								sw.Write("REF"+s
									+"0B"+s//REF01 2/3 Reference Identification Qualifier: 0B=State License Number.
									+Sout(provTreat.StateLicense,50));//REF02 1/50 Reference Identification:
								EndSegment(sw);//REF03 and REF04 are not used.
							}
						}
						if(IsEmdeonDental(clearhouse)) { //Always required by Emdeon Dental.
							WriteProv_REFG2orLU(sw,provTreat,carrier.ElectID);
						}
					}
					//2310C NM1: 77 (dental) Service Facility Location Name. Conditions different than 4010.  
					//Not supposed to send if same location as 2010AA Billing Provider, but ClaimConnect wants this segment anyway.
					if(sendFacilityNameAndAddress) {
						sw.Write("NM1"+s
							+"77"+s//NM101 2/3 Entity Identifier Code: 77=Service Location.
							+"2"+s//NM102 1/1 Entity Type Qualifier: 2=Non-Person Entity.
							+Sout(facilityProv.LName,60)+s//NM103 1/60 Name Last or Organization Name: Laboratory or Facility Name.
							+s//NM104 1/35 Name First: Not used.
							+s//NM105 1/25 Name Middle: Not used.
							+s//NM106 1/10 Name Prefix: Not used.
							+s//NM107 1/10 Name Suffix: Not used.
							+"XX"+s//NM108 1/2 Identification Code Qualifier: XX=NPI.
							+Sout(facilityProv.NationalProvID,80));//NM109 2/80 Identification Code: Laboratory or Facility Identifier. Validated.
						EndSegment(sw);//NM110 through NM112 not used.
						//2310C N3: (dental) Service Facility Location Address.
						sw.Write("N3"+s+Sout(facilityAddress1,55));//N301 1/55 Address Information: Laboratory or Facility Address Line.
						if(facilityAddress2!="") {
							sw.Write(s+Sout(facilityAddress2,55));//N302 1/55 Address Information: Laboratory or Facility Address Line 2. Only required when there is a secondary address line.
						}
						EndSegment(sw);
						//2310C N4: (dental) Service Facility Location City, State, Zip Code.
						sw.Write("N4"+s
							+Sout(facilityCity,30)+s//N401 2/30 City Name: Laboratory or Facility City Name.
							+Sout(facilityState,2,2)+s//N402 2/2 State or Provice Code: Laboratory or Facility State or Province Code.
							+Sout(facilityZip.Replace("-",""),15));//N403 3/15 Postal Code: Laboratory or Facility Postal Zone or ZIP Code.
						EndSegment(sw);//N404 through N407 are either not used or only required when outside of the United States.
						//2310C REF: (dental) Service Facility Location Secondary Identification. Situational. We do not use this.
					}
					//2310D NM1: (dental) Assistant Surgeon Name. Situational. We do not support.
					//2310D PRV: (dental) Assistant Surgeon Specialty Information. We do not support.
					//2310D REF: (dental) Assistant Surgeon Secondary Identification. We do not support.
					//2310E NM1: (dental) Supervising Provider Name. Situational. We do not support.
					//2310E REF: (dental) Supervising Provider Secondary Identification. Situational. We do not support.
				}
				#endregion 2310 Claim Providers (dental)
				#region 2320 Other subscriber information
				List<double> listProcWriteoffAmts=new List<double>();
				List<double> listProcDeductibleAmts=new List<double>();
				List<double> listProcPaidOtherInsAmts=new List<double>();
				bool hasAdjForOtherPlans=false;
				//2320 Other subscriber------------------------------------------------------------------------------------------
				if(otherPlan!=null) {
					//2320 SBR: Other Subscriber Information. Situational.
					sw.Write("SBR"+s);
					sw.Write((claimIsPrimary?"S":"P")+s);//SBR01 1/1 Payer Responsibility Sequence Number Code: When the claim is primary then the other insurance is secondary, and vice versa.
					sw.Write(GetRelat(claim.PatRelat2)+s//SBR02 2/2 Individual Relationship Code:
						+Sout(otherPlan.GroupNum,50)+s);//SBR03 1/50 Reference Identification:
					//SBR04 1/60 Name: Situational. Required when SBR03 is not specified.
					if(otherPlan.GroupNum!="") {
						sw.Write(s);
					}
					else {
						sw.Write(Sout(otherPlan.GroupName,60)+s);
					}
					sw.Write(s//SBR05 1/3 Insurance Type Code: Situational. Required when the payer in loop 2330B is Medicare and Medicare is not the primary payer. Medical and Dental only. TODO: implement.
						+s//SBR06 1/1 Coordination of Benefits Code: Not used.
						+s//SBR07 1/1 Yes/No Condition or Response Code: Not Used.
						+s//SBR08 2/2 Employment Status Code: Not Used.
						+GetFilingCode(otherPlan));//SBR09 1/2 Claim Filing Indicator Code: 12=PPO,17=DMO,BL=BCBS,CI=CommercialIns,FI=FEP,HM=HMO. Will no longer be required when HIPPA National Plan ID is mandated.
					EndSegment(sw);
					double claimWriteoffAmt=0;
					double claimDeductibleAmt=0;
					double claimPaidOtherInsAmt=0;
					double claimPatientPortionAmt=0;
					for(int j=0;j<claimProcs.Count;j++) {//Claim procs for this claim
						double procWriteoffAmt=0;
						double procDeductibleAmt=0;
						double procPaidOtherInsAmt=0;
						for(int k=0;k<claimProcList.Count;k++) {//All claim procs for patient
							if(ClaimProcs.IsValidClaimAdj(claimProcList[k],claimProcs[j].ProcNum,claimProcs[j].InsSubNum)) {//Adjustment due to other insurance plans.
								hasAdjForOtherPlans=true;
								claimWriteoffAmt+=claimProcList[k].WriteOff;
								claimDeductibleAmt+=claimProcList[k].DedApplied;
								claimPaidOtherInsAmt+=claimProcList[k].InsPayAmt;
								procWriteoffAmt+=claimProcList[k].WriteOff;
								procDeductibleAmt+=claimProcList[k].DedApplied;
								procPaidOtherInsAmt+=claimProcList[k].InsPayAmt;
							}
						}
						listProcWriteoffAmts.Add(procWriteoffAmt);
						listProcDeductibleAmts.Add(procDeductibleAmt);
						listProcPaidOtherInsAmts.Add(procPaidOtherInsAmt);
						double procPatientPortionAmt=Math.Max(0,claimProcs[j].FeeBilled-listProcWriteoffAmts[j]-listProcDeductibleAmts[j]-listProcPaidOtherInsAmts[j]);
						claimPatientPortionAmt+=procPatientPortionAmt;
					}
					//If sending the primary claim, then hasAdjForOtherPlans will be false, because all claimprocs for any other plans (secondary) will be estimates.
					//If sending the secondary claim, then hasAdjForOtherPlans will be true, because the primary claimprocs will be received.
					//This strategy works for dental and medical plans in any combination: D, M, DD, DM, MD, MM
					if(hasAdjForOtherPlans) {
						//2320 CAS: (medical,institutional,dental) Claim Level Adjustments. Situational. We use this to show patient responsibility, because the adjustments here plus AMT D below must equal claim amount in CLM02 for Emdeon.
						//Claim Adjustment Reason Codes can be found on the Washington Publishing Company website at: http://www.wpc-edi.com/reference/codelists/healthcare/claim-adjustment-reason-codes/
						if(claimWriteoffAmt>0) {
							sw.Write("CAS"+s
								+"CO"+s//CAS01 1/2 Claim Adjustment Group Code: CO=Contractual Obligations.
								+"45"+s//CAS02 1/5 Claim Adjustment Reason Code: 45=Charge exceeds fee schedule/maximum allowable or contracted/legislated fee arrangement.
								+AmountToStrNoLeading(claimWriteoffAmt));//CAS03 1/18 Monetary Amount:
							EndSegment(sw);
						}
						if(claimDeductibleAmt>0 || claimPatientPortionAmt>0) {
							sw.Write("CAS"+s
								+"PR");//CAS01 1/2 Claim Adjustment Group Code: PR=Patient Responsibility.
							if(claimDeductibleAmt>0) {
								sw.Write(s//end of previous field
									+"1"+s//CAS02 1/5 Claim Adjustment Reason Code: 1=Deductible.
									+AmountToStrNoLeading(claimDeductibleAmt)+s//CAS03 1/18 Monetary Amount:
									+"1");//CAS04 1/15 Quantity:
							}
							if(claimPatientPortionAmt>0) {
								sw.Write(s//end of previous field
									+"3"+s//CAS02 or CAS05 1/5 Claim Adjustment Reason Code: 3=Co-payment Amount.
									+AmountToStrNoLeading(claimPatientPortionAmt));//CAS03 or CAS06 1/18 Monetary Amount:
							}
							EndSegment(sw);
						}
						//2320 AMT: D (medical,institutional,dental) COB Payer Paid Amount. Situational. Required when the claim has been adjudicated by payer in loop 2330B.
						sw.Write("AMT"+s
							+"D"+s//AMT01 1/3 Amount Qualifier Code: D=Payor Amount Paid.
							+AmountToStrNoLeading(claimPaidOtherInsAmt));//AMT02 1/18 Monetary Amount:
						EndSegment(sw);//AMT03 Not used.
						//2320 AMT: EAF (medical,institutional,dental) Remaining Patient Liability. Situational. Required when claim has been adjudicated by payer in loop 2330B.
						sw.Write("AMT"+s
							+"EAF"+s//AMT01 1/3 Amount Qualifier Code: EAF=Amount Owed.
							+AmountToStrNoLeading(claimPatientPortionAmt));//AMT02 1/18 Monetary Amount:
						EndSegment(sw);//AMT03 Not used.
						//2320 AMT: A8 (medical,institutional,dental) COB Total Non-Covered Amount. Situational. Can be set when primary claim was not adjudicated. We do not use.
					}
					if(IsClaimConnect(clearhouse)) {
						//2320 DMG: Other subscriber demographics. This segment is not allowed in X12. ClaimConnect requires this information anyway. They will fix their validator later.
						sw.Write("DMG"+s
							+"D8"+s//DMG01 2/3 Date Time Period Format Qualifier: D8=Date Expressed in Format CCYYMMDD.
							+otherSubsc.Birthdate.ToString("yyyyMMdd")+s//DMG02 1/35 Date Time Period: Birthdate. The othet subscriber birtdate is validated.
							+GetGender(otherSubsc.Gender));//DMG03 1/1 Gender Code: F=Female, M=Male, U=Unknown.
							EndSegment(sw);
					}
					//2320 OI: (medical,institutional,dental) Other Insurance Coverage Information.
					sw.Write("OI"+s
						+s//OI01 1/2 Claim Filing Indicator Code: Not used.
						+s//OI02 2/2 Claim Submission Reason Code: Not used.
						+(otherSub.AssignBen?"Y":"N")+s//OI03 1/1 Yes/No Condition or Response Code:
						+s//OI04 1/1 Patient Signature Source Code: Not used in institutional or dental. Situational in medical, but we do not support.
						+s//OI05 1/1 Provider Agreement Code: Not used.
						+(otherSub.ReleaseInfo?"Y":"I"));//OI06 1/1 Release of Information Code:
					EndSegment(sw);
					//2320 MIA: (institutional) Inpatient Adjudication Information. Situational. We do not support.
					//2320 MOA: (medical,institutional,dental) Outpatient Adjudication Information. Situational. For reporting remark codes from ERAs. We don't support.
					#endregion 2320 Other subscriber information
					#region 2330A Other subscriber Name
					//2330A NM1: IL (medical,institutional,dental) Other Subscriber Name.
					sw.Write("NM1"+s
						+"IL"+s//NM101 2/3 Entity Identifier Code: IL=Insured or Subscriber.
						+"1"+s//NM102 1/1 Entity Type Qualifier: 1=Person.
						+Sout(otherSubsc.LName,60)+s//NM103 1/60 Name Last or Organization Name: Never blank, because validated in the patient edit window when a patient is added/edited.
						+Sout(otherSubsc.FName,35)+s//NM104 1/35 Name First:
						+Sout(otherSubsc.MiddleI,25)+s//NM105 1/25 Middle Name:
						+s//NM106 1/10 Name Prefix: Not used.
						+s//NM107 1/10 Name Suffix: Situational. No corresponding field in OD.
						+"MI"+s//NM108 1/2 Identification Code Qualifier: MI=Member Identification Number.
						+Sout(otherSub.SubscriberID,80));//NM109 2/80 Identification Code:
					EndSegment(sw);//NM110 through NM112 are not used.
					//2330A N3: Other Subscriber Address.
					sw.Write("N3"+s+Sout(otherSubsc.Address,55));//N301 1/55 Address Information:
					if(otherSubsc.Address2!="") {
						sw.Write(s+Sout(otherSubsc.Address2,55));
					}
					EndSegment(sw);//N302 1/55 Address Information:
					//2330A N4: (medical,institutional,dental) Other Subscriber City, State, Zip Code.
					sw.Write("N4"+s
						+Sout(otherSubsc.City,30)+s//N401 2/30 City Name:
						+Sout(otherSubsc.State,2,2)+s//N402 2/2 State or Province Code:
						+Sout(otherSubsc.Zip.Replace("-",""),15));//N403 3/15 Postal Code:
					EndSegment(sw);//N404 through N407 are either not required or are required when the address is outside of the United States.
					//2330A REF: (medical,institutional,dental) Other Subscriber Secondary Identification. Situational. Not supported.
					#endregion 2330A Other subscriber Name
					#region Other payer
					//2330B NM1: (medical,institutional,dental) Other Payer Name.
					sw.Write("NM1"+s
						+"PR"+s//NM101 2/3 Entity Code Identifier: PR=Payer.
						+"2"+s);//NM102 1/1 Entity Type Qualifier: 2=Non-Person.
					//NM103 1/60 Name Last or Organization Name:
					if(IsEMS(clearhouse)) {
						long employerNum=0;
						if(otherPlan!=null) {
							employerNum=otherPlan.EmployerNum;
						}
						//This is a special situation requested by EMS.  This tacks the employer onto the end of the carrier.
						sw.Write(Sout(otherCarrier.CarrierName,30)+"|"+Sout(Employers.GetName(employerNum),30)+s);
					}
					else if(IsDentiCal(clearhouse)) {
						sw.Write("DENTICAL"+s);
					}
					else {
						sw.Write(Sout(otherCarrier.CarrierName,60)+s);
					}
					sw.Write(s//NM104 1/35 Name First: Not used.
						+s//NM105 1/25 Name Middle: Not used.
						+s//NM106 1/10 Name Prefix: Not used.
						+s//NM107 1/10 Name Suffix: Not used.
						+"PI"+s);//NM108 1/2 Identification Code Qualifier: PI=Payor Identification. XV must be used after national plan ID mandated.
					sw.Write(Sout(GetCarrierElectID(otherCarrier,clearhouse),80,2));//NM109 2/80 Identification Code:
					EndSegment(sw);//NM110 through NM112 not used.
					//2230B N3: (medical,institutional,dental) Other Payer Address. Situational. We don't support.
					//2330B N4: (medical,institutional,dental) Other Payer City, State, Zip Code. Situational. We don't support.
					//2330B DTP: 573 (medical,institutional,dental) Claim Check or Remittance Date. Situational. Claim Paid date.
					if(hasAdjForOtherPlans) {
						DateTime datePaidOtherIns=DateTime.Today;
						DateTime dtThisCP;
						for(int j=0;j<claimProcs.Count;j++) {
							dtThisCP=ClaimProcs.GetDatePaid(claimProcList,claimProcs[j].ProcNum,claimProcs[j].PlanNum);
							if(dtThisCP>datePaidOtherIns) {
								datePaidOtherIns=dtThisCP;
							}
						}
						//it's a required segment, so always include it.
						sw.Write("DTP"+s
							+"573"+s//DTP01 3/3 Date/Time Qualifier: 573=Date Claim Paid.
							+"D8"+s//DTP02 2/3 Date Time Period Format Qualifier: D8=Date Expressed in Format CCYYMMDD.
							+datePaidOtherIns.ToString("yyyyMMdd"));//DTP03 1/35 Date Time Period:
						EndSegment(sw);
					}
					//2330B REF: (medical,institutional,dental) Other Payer Secondary Identifier. Situational. We do not use.
					//2330B REF: G1 (medical,institutional,dental) Other Payer Prior Authorization Number. Situational. We do not use.
					//2330B REF: 9F (medical,institutional,dental) Other Payer Referral Number. Situational. We do not use.
					//2330B REF: T4 (medical,institutional,dental) Other Payer Claim Adjustment Indicator. Situational. We do not use.
					//2330B REF: G3 (dental) Other Payer Predetermination Identification. Situational. We do not use.
					//2230B REF: F8 (medical,institutional,dental) Other Payer Claim Control Number. Situational. We do not use.					
					if(medType==EnumClaimMedType.Medical) {
						//2330C NM1: (medical) Other Payer Referring Provider. Situational. Only used in crosswalking COBs. We do not use.
						//2330C REF: (medical) Other Payer Referring Provider Secondary Identification. We do not use.
						//2330D NM1: 82 (medical) Other Payer Rendering Provider. Situational. Only used in crosswalking COBs. We do not use.
						//2330D REF: (medical) Other Payer Rendering Provider Secondary Identificaiton. We do not use.
						//2330E NM1: 77 (medical) Other Payer Service Facility Location. Situational. We do not use.
						//2330E REF: (medical) Other Payer Service Facility Location Secondary Identification. We do not use.
						//2330F NM1: DQ (medical) Other Payer Supervising Provider. Situational. We do not use.
						//2330F REF: (medical) Other Payer Supervising Provider Secondary Identificaiton. We do not use.
						//2330G NM1: 85 (medical) Other Payer Billing Provider. Situational. We do not use.
						//2330G REF: (medical) Other Payer Billing Provider Secondary Identification. We do not use.
					}
					else if(medType==EnumClaimMedType.Institutional) {
						//2330C NM1: 71 (institutional) Other Payer Attending Provider. Situational. Only used in crosswalking COBs. We do not use.
						//2330C REF: (institutional) Other Payer Attending Provider Secondary Identification. We do not use.
						//2330D NM1: 72 (institutional) Other Payer Operating Physician. Situational.
						//2330D REF: (institutional) Other Payer Operating Physician Secondary Identificaiton. We do not use.
						//2330E NM1: ZZ (institutional) Other Payer Other Operating Physician. Situational. We do not use.
						//2330E REF: (institutional) Other Payer Other Operating Physician Secondary Identificaiton. We do not use.
						//2330F NM1: 77 (institutional) Other Payer Service Facility Location. Situational. We do not use.
						//2330F REF: (institutional) Other Payer Service Facility Location Secondary Identification. We do not use.
						//2330G NM1: 82 (institutional) Other Payer Rendering Provider Name. Situatiuonal. We do not use.
						//2330G REF: (institutional) Other Payer Rendering Provider Secondary Identificaiton. We do not use.
						//2330H NM1: DN (institutional) Other Payer Referring Provider. Situational. We do not use.
						//2330H REF: (institutional) Other Payer Referring Provider Secondary Identificaiton. We do not use.
						//2330I NM1: 85 (institutional) Other Payer Billing Provider. Situational. We do not use.
						//2330I REF: (institutional) Other Payer Billing Provider Secondary Identification. We do not use.
					}
					else if(medType==EnumClaimMedType.Dental) {
						//2330C NM1: (dental) Other Payer Referring Provider. Situational. Only used in crosswalking COBs. We do not use.
						//2330C REF: (dental) Other Payer Referring Provider Secondary Identification. We do not use.
						//2330D NM1: 82 (dental) Other Payer Rendering Provider. Situational. Only used in crosswalking COBs. We do not use.
						//2330D REF: (dental) Other Payer Rendering Provider Secondary Identificaiton. We do not use.
						//2330E NM1: DQ (dental) Other Payer Supervising Provider. Situational. We do not use.
						//2330E REF: (dental) Other Payer Supervising Provider Secondary Identificaiton. We do not use.
						//2330F NM1: 85 (dental) Other Payer Billing Provider. Situational. We do not use.
						//2330F REF: (dental) Other Payer Billing Provider Secondary Identification. We do not use.
						//2330G NM1: 77 (dental) Other Payer Service Facility Location. Situational. We do not use.
						//2330G REF: (dental) Other Payer Service Facility Location Secondary Identification. We do not use.
						//2330H NM1: DD (dental) Other Payer Assistant Sugeon. Situational. We do not use.
						//2330H REF: (dental) Other Payer Assistant Surgeon Secondary Identifier. We do not use.
					}
					#endregion Other payer
				}
				for(int j=0;j<claimProcs.Count;j++) {
					#region Service Line
					proc=Procedures.GetProcFromList(procList,claimProcs[j].ProcNum);
					procCode=ProcedureCodes.GetProcCode(proc.CodeNum);
					//2400 LX: Service Line Number.
					sw.Write("LX"+s+(j+1).ToString());//LX01 1/6 Assigned Number:
					EndSegment(sw);
					if(medType==EnumClaimMedType.Medical) {
						//2400 SV1: Professional Service.
						sw.Write("SV1"+s
							//SV101 Composite Medical Procedure Identifier
							+"HC"+isa16//SV101-1 2/2 Product/Service ID Qualifier: HC=Health Care.
							+Sout(claimProcs[j].CodeSent));//SV101-2 1/48 Product/Service ID: Procedure code. The rest of SV101 is not supported.
						if(proc.CodeMod1!="" || proc.CodeMod2!="" || proc.CodeMod3!="" || proc.CodeMod4!="" || proc.ClaimNote!="") {
							sw.Write(isa16+Sout(proc.CodeMod1));//SV101-3 2/2 Procedure Modifier: Situational.
						}
						if(proc.CodeMod2!="" || proc.CodeMod3!="" || proc.CodeMod4!="" || proc.ClaimNote!="") {
							sw.Write(isa16+Sout(proc.CodeMod2));//SV101-4 2/2 Procedure Modifier: Situational.
						}
						if(proc.CodeMod3!="" || proc.CodeMod4!="" || proc.ClaimNote!="") {
							sw.Write(isa16+Sout(proc.CodeMod3));//SV101-5 2/2 Procedure Modifier: Situational.
						}
						if(proc.CodeMod4!="" || proc.ClaimNote!="") {
							sw.Write(isa16+Sout(proc.CodeMod4));//SV101-6 2/2 Procedure Modifier: Situational.
						}
						if(proc.ClaimNote!="") {
							sw.Write(isa16+Sout(proc.ClaimNote,80));//SV101-7 1/80 Description: Situational.
						}
						sw.Write(s//SV101-8 is not used.
							+claimProcs[j].FeeBilled.ToString()+s);//SV102 1/18 Monetary Amount: Charge Amt.
						if(proc.UnitQtyType==ProcUnitQtyType.MinutesAnesth) {
							sw.Write("MJ"+s);//SV103 2/2 Unit or Basis for Measurement Code: MJ=minutes, UN=Unit.
						}
						else {
							sw.Write("UN"+s);//SV103 2/2 Unit or Basis for Measurement Code: MJ=minutes, UN=Unit.
						}
						sw.Write(proc.UnitQty+s);//SV104 1/15 Quantity: Service Unit Count or Anesthesia Minutes.
						if(proc.PlaceService!=claim.PlaceService) {
							sw.Write(GetPlaceService(proc.PlaceService));
						}
						sw.Write(s//SV105 1/2 Facility Code Value: Place of Service Code if different from claim.
							+s);//SV106 1/2 Service Type Code: Not used.
						//SV107: Composite Diagnosis Code Pointer. Required when 2300HI(Health Care Diagnosis Code) is used (always).
						//SV107-1: Primary diagnosis. Only allowed pointers 1-8 even though 2300HI supports 12 diagnoses.
						//We don't validate that there are not more than 8 diagnoses on one claim.
						//If the diagnosis we need is not in the first 8, then we will use the primary.
						if(proc.DiagnosticCode=="") {//If the diagnosis is blank, we will use the primary.
							sw.Write("1");//use primary.
						}
						else {
							int diagI=1;
							for(int d=0;d<diagnosisList.Count;d++) {
								if(d>7) {//we can't point to any except first 8.
									continue;
								}
								if((string)diagnosisList[d]==proc.DiagnosticCode) {
									diagI=d+1;
								}
							}
							sw.Write(diagI.ToString());
						}
						//SV107-2 through SV107-4: Other diagnoses, which we don't support yet.
						EndSegment(sw);//SV108 through SV121 are not used or situational. We do not use.
					}
					else if(medType==EnumClaimMedType.Institutional) {
						//2400 SV2: Institutional Service Line.
						sw.Write("SV2"+s
							+Sout(proc.RevCode,48)+s//SV201 1/48 Product/Service ID: Revenue Code, validated.
							//SV202 Composite Medical Procedure Identifier
							+"HC"+isa16//SV202-1 2/2 Product/Service ID Qualifier: HC=Health Care. Includes CPT codes.
							+Sout(claimProcs[j].CodeSent));//SV202-2 1/48 Product/Service ID: Procedure code. 
						//mods validated to be exactly 2 char long or else blank.
						if(proc.CodeMod1!="" || proc.CodeMod2!="" || proc.CodeMod3!="" || proc.CodeMod4!="" || proc.ClaimNote!="") {
							sw.Write(isa16+Sout(proc.CodeMod1));//SV202-3 2/2 Procedure Modifier: Situational.
						}
						if(proc.CodeMod2!="" || proc.CodeMod3!="" || proc.CodeMod4!="" || proc.ClaimNote!="") {
							sw.Write(isa16+Sout(proc.CodeMod2));//SV202-4 2/2 Procedure Modifier: Situational.
						}
						if(proc.CodeMod3!="" || proc.CodeMod4!="" || proc.ClaimNote!="") {
							sw.Write(isa16+Sout(proc.CodeMod3));//SV202-5 2/2 Procedure Modifier: Situational.
						}
						if(proc.CodeMod4!="" || proc.ClaimNote!="") {
							sw.Write(isa16+Sout(proc.CodeMod4));//SV202-6 2/2 Procedure Modifier: Situational.
						}
						if(proc.ClaimNote!="") {
							sw.Write(isa16+Sout(proc.ClaimNote,80));//SV202-7 1/80 Description: Situational.
						}
						sw.Write(s//SV202-8 is not used.
							+claimProcs[j].FeeBilled.ToString()+s);//SV203 1/18 Monetary Amount: Charge Amt.
						if(proc.UnitQtyType==ProcUnitQtyType.Days) {
							sw.Write("DA"+s);//SV204 2/2 Unit or Basis for Measurement Code: DA=Days, UN=Unit.
						}
						else {
							sw.Write("UN"+s);//SV204 2/2 Unit or Basis for Measurement Code: DA=Days, UN=Unit.
						}
						sw.Write(proc.UnitQty.ToString());//SV205 1/15 Quantity:
						EndSegment(sw);//SV206,208,209 and 210 are not used, SV207 is situational but we do not use.
					}
					else if(medType==EnumClaimMedType.Dental) {
						//2400 SV3: Dental Service.
						sw.Write("SV3"+s
								+"AD"+isa16//SV301-1 2/2 Product/Service ID Qualifier: AD=American Dental Association Codes
								+Sout(claimProcs[j].CodeSent,5));//SV301-2 1/48 Product/Service ID: Procedure code
						if(proc.ClaimNote!="") {
							sw.Write(isa16//SV301-3 2/2 Procedure Modifier: Situational. We do not use.
								+isa16//SV301-4 2/2 Procedure Modifier: Situational. We do not use.
								+isa16//SV301-5 2/2 Procedure Modifier: Situational. We do not use.
								+isa16//SV301-6 2/2 Procedure Modifier: Situational. We do not use.
								+isa16+Sout(proc.ClaimNote,80));//SV301-7 1/80 Description: Situational.
						}
						sw.Write(s//SV301-8 is not used.
							+claimProcs[j].FeeBilled.ToString());//SV302 1/18 Monetary Amount: Charge Amount.
						string placeService="";
						if(proc.PlaceService!=claim.PlaceService) {
							placeService=GetPlaceService(proc.PlaceService);
						}
						string area=GetArea(proc,procCode);
						int unitQty=Math.Max(proc.UnitQty,1);//Minimum of 1
						bool includeUnits=false;
						if(unitQty>=2) {//Standard behavior based on the X12 guide.
							includeUnits=true;
						}
						//The following carriers always want to see the unit quantity, even if it is only 1.
						if(IsColoradoMedicaid(clearhouse) || IsWashingtonMedicaid(clearhouse,carrier)) {
							includeUnits=true;
						}
						if(placeService!="" || area!="" || proc.Prosthesis!="" || includeUnits) {
							sw.Write(s+placeService);//SV303 1/2 Facility Code Value: Location Code if different from claim.
						}
						if(area!="" || proc.Prosthesis!="" || includeUnits) {
							sw.Write(s+area);//SV304 Oral Cavity Designation: SV304-1 1/3 Oral Cavity Designation Code: Area. SV304-2 through SV304-5 are situational and we do not use.
						}
						if(proc.Prosthesis!="" || includeUnits) {
							sw.Write(s+proc.Prosthesis);//SV305 1/1 Prothesis, Crown or Inlay Code: I=Initial Placement. R=Replacement.
						}
						if(includeUnits) {
							sw.Write(s+unitQty.ToString());//SV306 1/15 Quantity: Situational. Procedure count.
						}
						EndSegment(sw);//SV307 throug SV311 are either not used or are situational and we do not use.
						//2400 TOO: Tooth Information. Number/Surface. Multiple iterations of the TOO segment are allowed only when the quantity reported in Loop ID-2400 SV306 is equal to one.
						if(procCode.TreatArea==TreatmentArea.Tooth) {
							sw.Write("TOO"+s
								+"JP"+s//TOO01 1/3 Code List Qualifier Code: JP=Universal National Tooth Designation System.
								+proc.ToothNum);//TOO02 1/30 Industry Code: Tooth number.
							EndSegment(sw);//TOO03 Tooth Surface: Situational. Not applicable.
						}
						else if(procCode.TreatArea==TreatmentArea.Surf) {
							sw.Write("TOO"+s
								+"JP"+s//TOO01 1/3 Code List Qualifier Code: JP=Universal National Tooth Designation System.
								+proc.ToothNum+s);//TOO02 1/30 Industry Code: Tooth number.
							string validSurfaces=Tooth.SurfTidyForClaims(proc.Surf,proc.ToothNum);
							for(int k=0;k<validSurfaces.Length;k++) {
								if(k>0) {
									sw.Write(isa16);
								}
								sw.Write(validSurfaces.Substring(k,1));//TOO03 Tooth Surface: TOO03-1 through TOO03-5 are for individual surfaces.
							}
							EndSegment(sw);
						}
						else if(procCode.TreatArea==TreatmentArea.ToothRange) {
							string[] individTeeth=proc.ToothRange.Split(',');
							for(int t=0;t<individTeeth.Length;t++) {
								sw.Write("TOO"+s
									+"JP"+s//TOO01 1/3 Code List Qualifier Code: JP=Universal National Tooth Designation System.
									+individTeeth[t]);//TOO02 1/30 Industry Code: Tooth number.
								EndSegment(sw);//TOO03 Tooth Surface: Situational. Not applicable.
							}
						}
					}//dental
					#endregion Service Line
					//2400 PWK: (institutional) Line Supplemental Information. Situational. We do not use.
					//2400 CRC: (medical) Condition Indicator/Durable Medical Equipment. Situational. We do not use.
					#region Service DTP
					//2400 DTP: 472 (medical,institutional,dental) Service Date. Situaitonal. Required for medical. Required if different from claim for dental and inst.
					if(claim.ClaimType!="PreAuth") {
						bool useProcDateService=false;
						//Always required for medical because there is no date of service at the claim level.
						if(medType==EnumClaimMedType.Medical) {
							useProcDateService=true;
						}
						else { //Institutional and dental.
							//Standard X12 behavior, preferred by the following clearinghouses: EmdeonDental.
							//Required for institutional and dental when procedure date of service is different from the claim date of service.
							if(proc.ProcDate!=claim.DateService) {
								useProcDateService=true;
							}
						}
						//The following clearinghouses always want this segment no matter what: Apex, Inmediata.
						if(IsApex(clearhouse) || IsInmediata(clearhouse)) {
							useProcDateService=true;
						}
						if(useProcDateService) {
							sw.Write("DTP"+s
								+"472"+s//DTP01 3/3 Date/Time Qualifier: 472=Service.
								+"D8"+s//DTP02 2/3 Date Time Period Format Qualifier: D8=Date Expressed in Format CCYYMMDD.
								+proc.ProcDate.ToString("yyyyMMdd"));//DTP03 1/35 Date Time Period:
							EndSegment(sw);
						}
					}
					//2400 DTP: 139/441 (dental) Date Prior Placement. Situational. Required when replacement.
					if(proc.Prosthesis=="R") {//already validated date
						sw.Write("DTP"+s
							+"441"+s//DTP01 3/3 Date/Time Qualifier: 441=Prior Placement.
							+"D8"+s//DTP02 2/3 Date Time Period Format Qualifier: D8=Date Expressed in Format CCYYMMDD.
							+proc.DateOriginalProsth.ToString("yyyyMMdd"));//DTP03 1/35 Date Time Period:
						EndSegment(sw);
					}
					//2400 DTP: 452 (dental) Date Appliance Placement. Situational. Ortho appliance placement. We do not use.
					//2400 DTP: 446 (dental) Date Replacement. Date ortho appliance replaced. We do not use.
					//2400 DTP: 196 (medical,dental) Date Treatment Start. Situational. Rx date. We do not use.
					//2400 DTP: 198 (dental) Date Treatment Completion. Situational. We do not use.
					//2400 DTP: 471 (medical) Prescription Date: Situational. We do not use.
					//2400 DTP: 607 (medical) Date Certification Revision/Recertification. Situational. Not supported.
					//2400 DTP: 463 (medical) Date Begin Therapy. Situational. Not supported.
					//2400 DTP: 461 (medical) Date Last Certification. Situational. Not supported.
					//2400 DTP: 304 (medical) Date Last Seen. Situational. Not supported.
					//2400 DTP: 738/739 (medical) Test Date. Situational. For Dialysis. Not supported.
					//2400 DTP: 011 (medical) Date Shipped. Situational. Not supported.
					//2400 DTP: 455 (medical) Date Last X-Ray. Situational. Not supported.
					//2400 DTP: 454 (medical) Date Initial Treatment. Situational. Not supported.					
					#endregion Service DTP
					#region Service QTY MEA CN1
					//2400 QTY: PT (medical) Ambulance Patient Count. Situational. Not supported.
					//2400 QTY: FL (medical) Obstetric Anesthesia Additional Units. Situational. Anesthesia quantity. We do not use.
					//2400 MEA: (medical) Test Result. Situational. We do not use.
					//2400 CN1: (medical,dental) Contract Information. Situational. We do not use.
					#endregion Service QTY MEA CN1
					#region Service REF
					//2400 REF: G3 (dental) Service Predetermination Identification. Situational. Pretermination ID. We do not use.
					//2400 REF: G1 (medical,dental) Prior Authorization. Situational. We do not use.
					//2400 REF: 9F (medical,dental) Referral Number. Situational. We do not use.
					//2400 REF: 9A (dental) Repriced Claim Number. Situational. We do not use.
					//2400 REF: 9B (medical,institutional) Repriced Line Item Reference Number. Situational. We do not use.
					//2400 REF: 9C (dental) Adjusted Repriced claim Number. Situational. We do not use.
					//2400 REF: 9D (medical,instituitonal) Adjusted Repriced Line Item Reference Number. Situational. We do not use.
					//2400 REF: 6R (medical,institutional,dental) Line Item Control Number. ProcNum. Will later be used for ERAs.
					sw.Write("REF"+s
						+"6R"+s//REF01 2/3 Reference Identification Qualifier: 6R=Procedure Control Number.
						+proc.ProcNum.ToString());//REF02 1/50 Reference Identification: 
					EndSegment(sw);//REF03 and REF04 are not used.
					//2400 REF: EW (medical) Mammography Certification Number. Situational. We do not use.
					//2400 REF: X4 (medical) Clinical Laboratory Improvement Amendment (CLIA) Number. Situational. We do not use.
					//2400 REF: F4 (medical) Referring Clinical Laboratory Improvement Amendment (CLIA) Facility Identification. Situational. We do not use.
					//2400 REF: BT (medical) Immunization Batch Number. Situational. We do not use.
					#endregion Service REF
					#region Service AMT K3 NTE PS1 HCP LIN CTP
					//2400 AMT: T (medical,dental) Sales Tax Amount. Situational. Not supported.
					//2400 AMT: F4 (medical) Postage Claimed Amount. Situational. We do not use.
					//2400 AMT GT (institutional) Service Tax Amount. Situational. Not supported.
					//2400 AMT N8 (institutional) Facility Tax Amount. Situational. Not supported.
					//2400 K3: (medical,dental) File Information. Situational. Not supported.
					//2400 NTE: ADD/DCP (medical) Line Note. Situational. We do not use.
					//2400 NTE: TPO (medical,institutional) Third Party Organization Notes. Situational. Not sent by providers. Not supported.
					//2400 PS1: (medical) Purchased Service Information. Situational. We do not use.
					//2400 HCP: (medical,institutional,dental) Line Pricing/Repricing Information. Situational. Not used by providers. Not supported.
					#endregion Service AMT K3 NTE PS1 HCP
					#region 2410 Service Drug Identification
					//2410 LIN,CTP,REF: (medical) ?
					if(medType==EnumClaimMedType.Medical || medType==EnumClaimMedType.Institutional) {
						//2410 LIN: (medical,institutional) Drug Identification
						if(procCode.DrugNDC!="" && proc.DrugQty>0){
							sw.Write("LIN"+s+s//LIN01 1/20 Assigned Identification: Not used.
								+"N4"+s//LIN02 2/2 Product/Service ID Qualifier: N4=NDC code in 5-4-2 format, no dashes.
								+procCode.DrugNDC);//LIN03 1/48 Product/Service ID: NDC.
							EndSegment(sw);//LIN04 through LIN31 not used.
							//2410 CTP: (medical,institutional) Drug Quantity.
							sw.Write("CTP"+s+s+s+s//CTP01 through CTP03 not used.
								+proc.DrugQty.ToString()+s//CTP04 1/15 Quantity:
								+GetDrugUnitCode(proc.DrugUnit));//CTP05-1 2/2 Unit or Basis for Measurement Code: Code Qualifier, validated to not be None.
							EndSegment(sw);//CTP05-2 through CTP05-15 not used. CTP06 through CTP11 not used.
							//2410 REF (inst) Rx or compound drug association number.  Not supported.
						}
					}
					#endregion 2410 Service Drug Identification
					Provider provTreatProc=provTreat;//procedure level treating provider.
					//2410 REF: VY/XZ (medical,institutional) Prescription or Compound Drug Association Number. Situational. We do not use.
					#region 2420 Service Providers (medical)
					if(medType==EnumClaimMedType.Medical) {
						if(claim.ProvTreat!=proc.ProvNum
							&& PrefC.GetBool(PrefName.EclaimsSeparateTreatProv)) {
							//2420A NM1: 82 (medical) Rendering Provider Name. Only if different from the claim.
							provTreatProc=Providers.GetProv(proc.ProvNum);
							WriteNM1Provider("82",sw,provTreatProc);
							//2420A PRV: (medical) Rendering Provider Specialty Information.
							sw.Write("PRV"+s
								+"PE"+s//PRV01 1/3 Provider Code: PE=Performing.
								+"PXC"+s//PRV02 2/3 Reference Identification Qualifier: PXC=Health Care Provider Taxonomy Code.
								+X12Generator.GetTaxonomy(provTreatProc));//PRV03 1/50 Reference Identification: Taxonomy Code.
							EndSegment(sw);//PRV04 through PRV06 not used.
							//2420A REF: (medical) Rendering Provider Secondary Identification.
							sw.Write("REF"+s
								+"0B"+s//REF01 2/3 Reference Identification Qualifier: 0B=State License Number.
								+Sout(provTreatProc.StateLicense,50));//REF02 1/50 Reference Identification: 
							EndSegment(sw);//REF03 1/80 Description: Not used. REF04 Reference Identifier: Situational. Not used when REF01 is 0B or 1G.
						}
						//2420B NM1: Purchased Service Provider Name. Situational. We do not use.
						//2420B REF: Purchased Service Provider Secondary Identificaiton. Situational. We do not use.
						//2420C NM1: 77 (medical) Service Facility Location Name. Situational. We enforce all procs on a claim being performed at the same location so we don't need this.
						//2420C N3: (medical) Service Facility Location Address. We do not use.
						//2420C N4: (medical) Service Facility Location City, State, Zip Code. We do not use.
						//2420C REF: (medical) Service Facility Location Secondary Identification. Situational. We do not use.
						//2420D NM1: DQ (medical) Supervising Provider Name. Situational. We do not support.
						//2420D REF: (medical) Supervising Provider Secondary Identification. Situational. We do not support.
						//Emdeon Medical requires loop 2420E when the claim is sent to DMERC (Medicaid) carriers. This loop can only be used for a provider that is a person, not an organization, so we don't send this loop if not a person.
						if(!provTreatProc.IsNotPerson) { //Treating provider is a person.
							//2420E NM1: DK (medical) Ordering Provider Name. Situational. Required to be a person.
							WriteNM1Provider("DK",sw,provTreatProc);
							//2420E N3: (medical) Ordering Provider Address. Situational.
							sw.Write("N3"+s+Sout(billingAddress1,55));//N301 1/55 Address Information:
							if(billingAddress2!="") {
								sw.Write(s+Sout(billingAddress2,55));//N302 1/55 Address Information: Only required when there is a secondary address line.
							}
							EndSegment(sw);
							//2420E N4: (medical) Ordering Provider City, State, Zip Code. Situational.
							sw.Write("N4"+s
								+Sout(billingCity,30)+s//N401 2/30 City Name:
								+Sout(billingState,2,2)+s//N402 2/2 State or Provice Code:
								+Sout(billingZip.Replace("-",""),15));//N403 3/15 Postal Code:
							EndSegment(sw);//N404 through N407 are either not used or only required when outside of the United States.						
							//2420E REF: (medical) Ordering Provider Secondary Identification. Situational. Required before NPIs were in effect. We do not use this segment because we require NPI.
							//2420E PER: (medical) Ordering Provider Contact Information. Situational.
							sw.Write("PER"+s
								+"IC"+s//PER01 2/2 Contact Function Code: IC=Information Contact.
								+Sout(PrefC.GetString(PrefName.PracticeTitle),60)+s//PER02 1/60 Name: Practice Title.
								+"TE"+s);//PER03 2/2 Communication Number Qualifier: TE=Telephone.
							if(clinic==null) {
								sw.Write(Sout(PrefC.GetString(PrefName.PracticePhone),256));//PER04 1/256 Communication Number: Telephone number.
							}
							else {
								sw.Write(Sout(clinic.Phone,256));//PER04 1/256 Communication Number: Telephone number.
							}
							EndSegment(sw);//PER05 through PER08 are situational and PER09 is not used. We do not use.
						}
						//2420F NM1: (medical) Referring Provider Name. Situational. We do not use.
						//2420F REF: (medical) Referring Provider Secondary Identification. Situational. We do not use.
						//2420G NM1: PW (medical) Ambulance Pick-up Location. Situational. We do not use.
						//2420G N3: (medical) Ambulance Pick-up Location Address. We do not use.
						//2420G N4: (medical) Ambulance Pick-up Location City, State, Zip Code. We do not use.
						//2420H NM1: (medical) Ambulance Drop-off Location. Situational. We do not use.
						//2420H N3: (medical) Ambulance Drop-off Location Address. We do not use.
						//2420H N4: (medical) Ambulance Drop-off Location City, State, Zip Code. We do not use.
					}
					#endregion 2420 Service Providers (medical)
					#region 2420 Service Providers (inst)
					if(medType==EnumClaimMedType.Institutional) {
						//2420A NM1: 72 (institutional) Operating Physician Name. Situational. Only for surgical procedures. We don't support.
						//2420A REF: (instititional) Operating Physician Secondary Identification. Situational. Only for surgical procedures. We don't support.						
						//2420B NM1: ZZ (institutional) Other Operating Physician Name. Situational. We don't support.
						//2420B REF: (institutional) Other Operating Physician Secondary Identification. Situational. We don't support.
						if(claim.ProvTreat!=proc.ProvNum
							&& PrefC.GetBool(PrefName.EclaimsSeparateTreatProv)) 
						{
							provTreatProc=Providers.GetProv(proc.ProvNum);
							//2420C NM1: 82 (institutional) Rendering Provider Name. Situational. Only if different than claim attending (treating) prov. Person only, non-person not allowed.
							WriteNM1Provider("82",sw,provTreatProc.FName,provTreatProc.MI,provTreatProc.LName,provTreatProc.NationalProvID,false);
							//2420C REF: Rendering Provider Secondary Identification. Situational.
							sw.Write("REF"+s
								+"0B"+s//REF01 2/3 Reference Identification Qualifier: 0B=State License Number.
								+Sout(provTreatProc.StateLicense,50));//REF02 1/50 Reference Identification: Valided to be present.
							EndSegment(sw);//REF03 through REF04 are not used or situational.
						}
						//2420D NM1: DN (institutional) Referring Provider Name. Situational. We do not use.
						//2420D REF: (institutional) Referring Provider Secondary Identification. Situational. We do not use.
					}
					#endregion 2420 Service Providers (inst)
					#region 2420 Service Providers (dental)
					if(medType==EnumClaimMedType.Dental) {
						if(claim.ProvTreat!=proc.ProvNum
							&& PrefC.GetBool(PrefName.EclaimsSeparateTreatProv)) 
						{
							//2420A NM1: 82 (dental) Rendering Provider Name. Only if different from the claim.
							provTreatProc=Providers.GetProv(proc.ProvNum);
							WriteNM1Provider("82",sw,provTreatProc);
							//2420A PRV: (dental) Rendering Provider Specialty Information.
							sw.Write("PRV"+s
								+"PE"+s//PRV01 1/3 Provider Code: PE=Performing.
								+"PXC"+s//PRV02 2/3 Reference Identification Qualifier: PXC=Health Care Provider Taxonomy Code.
								+X12Generator.GetTaxonomy(provTreatProc));//PRV03 1/50 Reference Identification: Taxonomy Code.
							EndSegment(sw);//PRV04 through PRV06 not used.
							//2420A REF: (dental) Rendering Provider Secondary Identification. Never required because we always send NPI (validated).
							if(!IsDentiCal(clearhouse)) { //Denti-Cal never wants this.
								if(provTreatProc.StateLicense!="") {
									sw.Write("REF"+s
										+"0B"+s//REF01 2/3 Reference Identification Qualifier: 0B=State License Number.
										+Sout(provTreatProc.StateLicense,50));//REF02 1/50 Reference Identification: 
									EndSegment(sw);//REF03 1/80 Description: Not used. REF04 Reference Identifier: Situational. Not used when REF01 is 0B or 1G.
								}
							}
						}
						//2420B NM1: DD (dental) Assistant Surgeon Name. Situational. We do not support.
						//2420B PRV: AS (dental) Assistant Surgeon Specialty Information. Situational. We do not support.
						//2420B REF: (dental) Assistant Surgeon Secondary Identification. Situational. We do not support.
						//2420C NM1: DQ (dental) Supervising Provider Name. Situational. We do not support.
						//2420C REF: (dental) Supervising Provider Secondary Identification. Situational. We do not support.
						//2420D NM1: 77 (dental) Service Facility Location Name. Situational. We enforce all procs on a claim being performed at the same location so we don't need this.
						//2420D N3: (dental) Service Facility Location Address. We do not use.
						//2420D N4: (dental) Service Facility Location City, State, Zip Code. We do not use.
						//2420D REF: (dental) Service Facility Location Secondary Identification. Situational. We do not use.
					}
					#endregion 2420 Service Providers (dental)
					//2430 SVD: (medical,institutional,dental) Line Adjudication Information. Situational. We do not support.   
					//2430 CAS: (medical,institutional,dental) Line Adjustment. Situational. Required when the payer identified in Loop 2330B made line level adjustments which caused the amount paid to differ from the amount originally charged.
					//These CAS segments at the procedure level should add up to their respective claim level 2320 CAS segments.
					//Claim Adjustment Reason Codes can be found on the Washington Publishing Company website at: http://www.wpc-edi.com/reference/codelists/healthcare/claim-adjustment-reason-codes/
					if(hasAdjForOtherPlans && IsApex(clearhouse)) {//This section of code might work for other clearinghouses, but has not yet been tested, and nobody else has requested this information yet.
						double procPatientPortionAmt=Math.Max(0,claimProcs[j].FeeBilled-listProcWriteoffAmts[j]-listProcDeductibleAmts[j]-listProcPaidOtherInsAmts[j]);
						if(listProcWriteoffAmts[j]>0) {
							sw.Write("CAS"+s
								+"CO"+s//CAS01 1/2 Claim Adjustment Group Code: CO=Contractual Obligations.
								+"45"+s//CAS02 1/5 Claim Adjustment Reason Code: 45=Charge exceeds fee schedule/maximum allowable or contracted/legislated fee arrangement.
								+AmountToStrNoLeading(listProcWriteoffAmts[j]));//CAS03 1/18 Monetary Amount:
							EndSegment(sw);
						}
						if(listProcDeductibleAmts[j]>0 || procPatientPortionAmt>0) {
							sw.Write("CAS"+s
								+"PR");//CAS01 1/2 Claim Adjustment Group Code: PR=Patient Responsibility.
							if(listProcDeductibleAmts[j]>0) {
								sw.Write(s//end of previous field
									+"1"+s//CAS02 1/5 Claim Adjustment Reason Code: 1=Deductible.
									+AmountToStrNoLeading(listProcDeductibleAmts[j])+s//CAS03 1/18 Monetary Amount:
									+"1");//CAS04 1/15 Quantity:
							}
							if(procPatientPortionAmt>0) {
								sw.Write(s//end of previous field
									+"3"+s//CAS02 or CAS05 1/5 Claim Adjustment Reason Code: 3=Co-payment Amount.
									+AmountToStrNoLeading(procPatientPortionAmt));//CAS03 or CAS06 1/18 Monetary Amount:
							}
							EndSegment(sw);
						}
					}
					//2430 DTP: (medical,institutional,dental) Line Check or Remittance Date. We do not support.
					//2430 AMT: (medical,institutional,dental) Remaining Patient Liability. We do not support.
					//2440 LQ: (medical) Form Identification Code. Situational. We do not use.
					//2440 FRM: (medical) Supporting Documentation. We do not use.
				}
			}
			#region Trailers
			//Transaction Trailer
			sw.Write("SE"+s
				+(seg+1).ToString()+s//SE01 1/10 Number of Included Segments: Total segments, including ST & SE. We add 1 for this SE segment, since the seg variable is not incremented until after this segment is written.
				+transactionNum.ToString().PadLeft(4,'0'));//SE02 4/9 Transaction Set Control Number:
			EndSegment(sw);
			//Functional Group Trailer
			sw.Write("GE"+s+transactionNum.ToString()+s//GE01 1/6 Number of Transaction Sets Included.  Always 1 for us.
				+groupControlNumber//GE02 1/9 Group Control Number: Must be identical to GS06.
				+endSegment);
			#endregion Trailers
		}
Пример #47
0
		///<summary>Returns true if the communications were successful, and false if they failed. If they failed, a rollback will happen automatically by deleting the previously created X12 file. The batchnum is supplied for the possible rollback.  Also used for mail retrieval.</summary>
		public static bool Launch(Clearinghouse clearhouse,int batchNum,EnumClaimMedType medType){
			string batchFile="";
			try {
				if(!Directory.Exists(clearhouse.ExportPath)) {
					throw new Exception("Clearinghouse export path is invalid.");
				}
				//We make sure to only send the X12 batch file for the current batch, so that if there is a failure, then we know
				//for sure that we need to reverse the batch. This will also help us avoid any exterraneous/old batch files in the
				//same directory which might be left if there is a permission issue when trying to delete the batch files after processing.
				batchFile=Path.Combine(clearhouse.ExportPath,"claims"+batchNum+".txt");
				//byte[] fileBytes=File.ReadAllBytes(batchFile);//unused
				MemoryStream zipMemoryStream=new MemoryStream();
				ZipFile tempZip=new ZipFile();
				tempZip.AddFile(batchFile,"");
				tempZip.Save(zipMemoryStream);
				tempZip.Dispose();
				zipMemoryStream.Position=0;
				byte[] zipFileBytes=zipMemoryStream.GetBuffer();
				string zipFileBytesBase64=Convert.ToBase64String(zipFileBytes);
				zipMemoryStream.Dispose();
				if(clearhouse.ISA15=="P") {//production interface
					string messageType="MCD";//medical
					if(medType==EnumClaimMedType.Institutional) {
						messageType="HCD";
					}
					else if(medType==EnumClaimMedType.Dental) {
						//messageType="DCD";//not used/tested yet, but planned for future.
					}
					EmdeonITS.ITSWS itsws=new EmdeonITS.ITSWS();
					itsws.Url=emdeonITSUrl;
					EmdeonITS.ITSReturn response=itsws.PutFileExt(clearhouse.LoginID,clearhouse.Password,messageType,Path.GetFileName(batchFile),zipFileBytesBase64);
					if(response.ErrorCode!=0) { //Batch submission successful.
						throw new Exception("Emdeon rejected all claims in the current batch file "+batchFile+". Error number from Emdeon: "+response.ErrorCode+". Error message from Emdeon: "+response.Response);
					}
				}
				else {//test interface
					string messageType="MCT";//medical
					if(medType==EnumClaimMedType.Institutional) {
						messageType="HCT";
					}
					else if(medType==EnumClaimMedType.Dental) {
						//messageType="DCT";//not used/tested yet, but planned for future.
					}
					EmdeonITSTest.ITSWS itswsTest=new EmdeonITSTest.ITSWS();
					itswsTest.Url=emdeonITSUrlTest;
					EmdeonITSTest.ITSReturn responseTest=itswsTest.PutFileExt(clearhouse.LoginID,clearhouse.Password,messageType,Path.GetFileName(batchFile),zipFileBytesBase64);
					if(responseTest.ErrorCode!=0) { //Batch submission successful.
						throw new Exception("Emdeon rejected all claims in the current batch file "+batchFile+". Error number from Emdeon: "+responseTest.ErrorCode+". Error message from Emdeon: "+responseTest.Response);
					}
				}
			}
			catch(Exception e) {
				MessageBox.Show(e.Message);
				x837Controller.Rollback(clearhouse,batchNum);
				return false;
			}
			finally {
				try {
					if(batchFile!="") {
						File.Delete(batchFile);
					}
				}
				catch {
					MessageBox.Show("Failed to remove batch file "+batchFile+". Probably due to a permission issue. Check folder permissions and manually delete.");
				}
			}
			return true;
		}
Пример #48
0
 ///<summary>DentiCal is a carrier.  Pass in either a clinic or HQ-level clearinghouse.</summary>
 private static bool IsDentiCalClearinghouse(Clearinghouse clearinghouse)
 {
     return(clearinghouse.ISA08 == "DENTICAL");
 }
Пример #49
0
		public static bool Retrieve(Clearinghouse clearhouse) {
			try {
				if(!Directory.Exists(clearhouse.ResponsePath)) {
					throw new Exception("Clearinghouse response path is invalid.");
				}
				bool reportsDownloaded=false;
				if(clearhouse.ISA15=="P") {//production interface
					string[] messageTypes=new string[] { 
						"MCD", //Medical
						"HCD", //Institutional
						//"DCD"  //Dental. Planned for future.
					};
					for(int i=0;i<messageTypes.Length;i++) {
						EmdeonITS.ITSWS itsws=new EmdeonITS.ITSWS();
						itsws.Url=emdeonITSUrl;
						//Download the most up to date reports, but do not delete them from the server yet.
						EmdeonITS.ITSReturn response=itsws.GetFile(clearhouse.LoginID,clearhouse.Password,messageTypes[i]+"G");
						if(response.ErrorCode==0) { //Report retrieval successful.
							string reportFileDataBase64=response.Response;
							byte[] reportFileDataBytes=Convert.FromBase64String(reportFileDataBase64);
							string reportFilePath=CodeBase.ODFileUtils.CreateRandomFile(clearhouse.ResponsePath,".zip");
							File.WriteAllBytes(reportFilePath,reportFileDataBytes);
							reportsDownloaded=true;
							//Now that the file has been saved, remove the report file from the Emdeon production server.
							//If deleting the report fails, we don't care because that will simply mean that we download it again next time.
							//Thus we don't need to check the status after this next call.
							itsws.GetFile(clearhouse.LoginID,clearhouse.Password,messageTypes[i]+"D");
						}
						else if(response.ErrorCode!=209) { //Report retrieval failure, excluding the error that can be returned when the mailbox is empty.
							throw new Exception("Failed to get reports. Error number from Emdeon: "+response.ErrorCode+". Error message from Emdeon: "+response.Response);
						}
					}
				}
				else { //test interface
					string[] messageTypes=new string[] { 
						"MCT", //Medical
						"HCT", //Institutional
						//"DCT"  //Dental. Planned for future.
					};
					for(int i=0;i<messageTypes.Length;i++) {
						EmdeonITSTest.ITSWS itswsTest=new EmdeonITSTest.ITSWS();
						itswsTest.Url=emdeonITSUrlTest;
						//Download the most up to date reports, but do not delete them from the server yet.
						EmdeonITSTest.ITSReturn responseTest=itswsTest.GetFile(clearhouse.LoginID,clearhouse.Password,messageTypes[i]+"G");
						if(responseTest.ErrorCode==0) { //Report retrieval successful.
							string reportFileDataBase64=responseTest.Response;
							byte[] reportFileDataBytes=Convert.FromBase64String(reportFileDataBase64);
							string reportFilePath=CodeBase.ODFileUtils.CreateRandomFile(clearhouse.ResponsePath,".zip");
							File.WriteAllBytes(reportFilePath,reportFileDataBytes);
							reportsDownloaded=true;
							//Now that the file has been saved, remove the report file from the Emdeon test server.
							//If deleting the report fails, we don't care because that will simply mean that we download it again next time.
							//Thus we don't need to check the status after this next call.
							itswsTest.GetFile(clearhouse.LoginID,clearhouse.Password,messageTypes[i]+"D");
						}
						else if(responseTest.ErrorCode!=209) { //Report retrieval failure, excluding the error that can be returned when the mailbox is empty.
							throw new Exception("Failed to get reports. Error number from Emdeon: "+responseTest.ErrorCode+". Error message from Emdeon: "+responseTest.Response);
						}
					}
				}
				if(!reportsDownloaded) {
					MessageBox.Show("Report mailbox is empty.");
				}
			}
			catch(Exception ex) {
				MessageBox.Show(ex.Message);
				return false;
			}
			return true;
		}
Пример #50
0
 ///<summary>Returns true if the communications were successful, and false if they failed. If they failed, a rollback will happen automatically by deleting the previously created X12 file. The batchnum is supplied for the possible rollback.</summary>
 public static bool Launch(Clearinghouse clearhouse,int batchNum)
 {
     try{
         //Step 1: Post authentication request:
         Version myVersion=new Version(Application.ProductVersion);
         HttpWebRequest webReq;
         WebResponse response;
         StreamReader readStream;
         string str;
         string[] responseParams;
         string status="";
         string group="";
         string userid="";
         string authid="";
         string errormsg="";
         string alertmsg="";
         string curParam="";
         string serverName=//"https://prelive.dentalxchange.com/dci/upload.svl";
             "https://claimconnect.dentalxchange.com/dci/upload.svl";
         webReq=(HttpWebRequest)WebRequest.Create(serverName);
         string postData=
             "Function=Auth"//CONSTANT; signifies that this is an authentication request
             +"&Source=EDI"//CONSTANT; file format
             +"&Username="******"&Password="******"&UploaderName=OpenDental"//CONSTANT
             +"&UploaderVersion="+myVersion.Major.ToString()+"."+myVersion.Minor.ToString();//eg 3.4
         webReq.KeepAlive=false;
         webReq.Method="POST";
         webReq.ContentType="application/x-www-form-urlencoded";
         webReq.ContentLength=postData.Length;
         ASCIIEncoding encoding=new ASCIIEncoding();
         byte[] bytes=encoding.GetBytes(postData);
         Stream streamOut=webReq.GetRequestStream();
         streamOut.Write(bytes,0,bytes.Length);
         streamOut.Close();
         response=webReq.GetResponse();
         //Process the authentication response:
         readStream=new StreamReader(response.GetResponseStream(),Encoding.ASCII);
         str=readStream.ReadToEnd();
         readStream.Close();
         //MessageBox.Show(str);
         responseParams=str.Split('&');
         for(int i=0;i<responseParams.Length;i++){
             curParam=GetParam(responseParams[i]);
             switch(curParam){
                 case "Status":
                     status=GetParamValue(responseParams[i]);
                     break;
                 case "GROUP":
                     group=GetParamValue(responseParams[i]);
                     break;
                 case "UserID":
                     userid=GetParamValue(responseParams[i]);
                     break;
                 case "AuthenticationID":
                     authid=GetParamValue(responseParams[i]);
                     break;
                 case "ErrorMessage":
                     errormsg=GetParamValue(responseParams[i]);
                     break;
                 case "AlertMessage":
                     alertmsg=GetParamValue(responseParams[i]);
                     break;
                 default:
                     throw new Exception("Unexpected parameter: "+curParam);
             }
         }
         //Process response for errors:
         if(alertmsg!=""){
             MessageBox.Show(alertmsg);
         }
         switch(status){
             case "0":
                 //MessageBox.Show("Authentication successful.");
                 break;
             case "1":
                 throw new Exception("Authentication failed. "+errormsg);
             case "2":
                 throw new Exception("Cannot authenticate at this time. "+errormsg);
             case "3":
                 throw new Exception("Invalid authentication request. "+errormsg);
             case "4":
                 throw new Exception("Invalid program version. "+errormsg);
             case "5":
                 throw new Exception("No customer contract. "+errormsg);
         }
         //Step 2: Post upload request:
         string[] fileNames=Directory.GetFiles(clearhouse.ExportPath);
         if(fileNames.Length>1){
             for(int f=0;f<fileNames.Length;f++) {
                 File.Delete(fileNames[f]);
             }
             throw new ApplicationException("A previous batch submission was found in an incomplete state.  You will need to resubmit your most recent batch as well as this batch.  Also check reports to be certain that all expected claims went through.");
         }
         string fileName=fileNames[0];
         string boundary="------------7d13e425b00d0";
         postData=
             "--"+boundary+"\r\n"
             +"Content-Disposition: form-data; name=\"Function\"\r\n"
             +"\r\n"
             +"Upload\r\n"
             +"--"+boundary+"\r\n"
             +"Content-Disposition: form-data; name=\"Source\"\r\n"
             +"\r\n"
             +"EDI\r\n"
             +"--"+boundary+"\r\n"
             +"Content-Disposition: form-data; name=\"AuthenticationID\"\r\n"
             +"\r\n"
             +authid+"\r\n"
             +"--"+boundary+"\r\n"
             +"Content-Disposition: form-data; name=\"File\"; filename=\""
                 +fileName+"\"\r\n"
             +"Content-Type: text/plain\r\n"
             +"\r\n";
         using(StreamReader sr=new StreamReader(fileName)){
             postData+=sr.ReadToEnd()+"\r\n"
                 +"--"+boundary+"--";
     }
         //Debug.Write(postData);
         //MessageBox.Show(postData);
         webReq=(HttpWebRequest)WebRequest.Create(serverName);
         webReq.KeepAlive=false;
         webReq.Method="POST";
         webReq.ContentType="multipart/form-data; boundary="+boundary;
         webReq.ContentLength=postData.Length;
         bytes=encoding.GetBytes(postData);
         streamOut=webReq.GetRequestStream();
         streamOut.Write(bytes,0,bytes.Length);
         streamOut.Close();
         response=webReq.GetResponse();
         //Process the response
         readStream=new StreamReader(response.GetResponseStream(),Encoding.ASCII);
         str=readStream.ReadToEnd();
         readStream.Close();
         errormsg="";
         status="";
         str=str.Replace("\r\n","");
         Debug.Write(str);
         if(str.Length>300){
             throw new Exception("Unknown lengthy error message received.");
         }
         responseParams=str.Split('&');
         for(int i=0;i<responseParams.Length;i++){
             curParam=GetParam(responseParams[i]);
             switch(curParam){
                 case "Status":
                     status=GetParamValue(responseParams[i]);
                     break;
                 case "ErrorMessage":
                     errormsg=GetParamValue(responseParams[i]);
                     break;
                 case "Filename":
                 case "Timestamp":
                     break;
                 case ""://errorMessage blank
                     break;
                 default:
                     throw new Exception("Unexpected parameter: "+curParam+"*");
             }
         }
         switch(status){
             case "0":
                 MessageBox.Show("Upload successful.");
                 break;
             case "1":
                 throw new Exception("Authentication failed. "+errormsg);
             case "2":
                 throw new Exception("Cannot upload at this time. "+errormsg);
         }
         //delete the uploaded claim
         File.Delete(fileName);
     }
     catch(Exception e){
         MessageBox.Show(e.Message);
         x837Controller.Rollback(clearhouse,batchNum);
         return false;
     }
     return true;
 }
Пример #51
0
Файл: NHS.cs Проект: mnisl/OD
		///<summary>Returns true if the communications were successful, and false if they failed. If they failed, a rollback will happen automatically by deleting the previously created FP17 file. The batchnum is supplied for the possible rollback.</summary>
		public static bool Launch(Clearinghouse clearhouse,int batchNum) {
			bool retVal=true;


			return retVal;
		}
Пример #52
0
        ///<summary>Returns a blank string if there were no errors while attempting to update internal carriers using iTrans n-cpl.json file..</summary>
        public static string TryCarrierUpdate(bool isAutomatic = true, ItransImportFields fieldsToImport = ItransImportFields.None)
        {
            Clearinghouse clearinghouse = Clearinghouses.GetDefaultDental();

            if (clearinghouse.CommBridge != EclaimsCommBridge.ITRANS ||
                string.IsNullOrEmpty(clearinghouse.ResponsePath) ||
                !File.Exists(ODFileUtils.CombinePaths(clearinghouse.ResponsePath, "ITRANS Claims Director.exe")) ||
                (isAutomatic && PrefC.GetString(PrefName.WebServiceServerName).ToLower() != Dns.GetHostName().ToLower()))                 //Only server can run when isOnlyServer is true.
            {
                return(Lans.g("Clearinghouse", "ITRANS must be the default dental clearinghouse and your Report Path must be set first."));
            }
            Process process = new Process {
                StartInfo = new ProcessStartInfo {
                    FileName  = ODFileUtils.CombinePaths(clearinghouse.ResponsePath, "ITRANS Claims Director.exe"),
                    Arguments = " --getncpl"
                }
            };

            process.Start();
            process.WaitForExit();
            string            ncplFilePath = ODFileUtils.CombinePaths(clearinghouse.ResponsePath, "n-cpl.json");
            string            json         = File.ReadAllText(ncplFilePath);//Read n-cpl.json
            EtransMessageText msgTextPrev  = EtransMessageTexts.GetMostRecentForType(EtransType.ItransNcpl);

            if (msgTextPrev != null && msgTextPrev.MessageText == json)
            {
                return(Lans.g("Clearinghouse", "Carrier list has not changed since last checked."));              //json has not changed since we last checked, no need to update.
            }
            //Save json as new etrans entry.
            Etrans etrans = Etranss.CreateEtrans(File.GetCreationTime(ncplFilePath), clearinghouse.HqClearinghouseNum, json, 0);

            etrans.Etype = EtransType.ItransNcpl;
            Etranss.Insert(etrans);
            ItransNCpl iTransNCpl = null;

            try {
                iTransNCpl = JsonConvert.DeserializeObject <ItransNCpl>(json);             //Deserialize n-cpl.json
            }
            catch (Exception ex) {
                ex.DoNothing();
                return(Lans.g("Clearinghouse", "Failed to import json."));
            }
            foreach (ItransNCpl.Carrier jsonCarrier in iTransNCpl.ListCarriers)              //Update providers.
            {
                OpenDentBusiness.Carrier odCarrier = Carriers.GetByElectId(jsonCarrier.Bin); //Cached
                if (odCarrier == null)                                                       //Carrier can not be matched to internal Carrier based on ElectID.
                {
                    if (!fieldsToImport.HasFlag(ItransImportFields.AddMissing))
                    {
                        continue;
                    }
                    OpenDentBusiness.Carrier carrierNew = new OpenDentBusiness.Carrier();
                    carrierNew.ElectID     = jsonCarrier.Bin;
                    carrierNew.IsCDA       = true;
                    carrierNew.CarrierName = jsonCarrier.Name.En;
                    carrierNew.Phone       = TelephoneNumbers.ReFormat(jsonCarrier.Telephone?.First().Value);
                    if (jsonCarrier.Address.Count() > 0)
                    {
                        Address add = jsonCarrier.Address.First();
                        carrierNew.Address  = add.Street1;
                        carrierNew.Address2 = add.Street2;
                        carrierNew.City     = add.City;
                        carrierNew.State    = add.Province;
                        carrierNew.Zip      = add.PostalCode;
                    }
                    carrierNew.CanadianSupportedTypes = GetSupportedTypes(jsonCarrier);
                    carrierNew.CarrierName            = jsonCarrier.Name.En;
                    try {
                        Carriers.Insert(carrierNew);
                    }
                    catch (Exception ex) {
                        ex.DoNothing();
                    }
                    continue;
                }
                else if (!odCarrier.IsCDA)
                {
                    continue;
                }
                OpenDentBusiness.Carrier odCarrierOld = odCarrier.Copy();
                odCarrier.CanadianSupportedTypes = GetSupportedTypes(jsonCarrier);
                odCarrier.CDAnetVersion          = POut.Int(jsonCarrier.Versions.Max(x => PIn.Int(x)));
                List <ItransImportFields> listFields = Enum.GetValues(typeof(ItransImportFields)).Cast <ItransImportFields>().ToList();
                foreach (ItransImportFields field in listFields)
                {
                    if (fieldsToImport == ItransImportFields.None)
                    {
                        break;                        //No point in looping.
                    }
                    if (field == ItransImportFields.None || !fieldsToImport.HasFlag(field))
                    {
                        continue;
                    }
                    switch (field)
                    {
                    case ItransImportFields.Phone:
                        if (jsonCarrier.Telephone.Count > 0)
                        {
                            odCarrier.Phone = TelephoneNumbers.ReFormat(jsonCarrier.Telephone.First().Value);
                        }
                        break;

                    case ItransImportFields.Address:
                        if (jsonCarrier.Address.Count() > 0)
                        {
                            Address add = jsonCarrier.Address.First();
                            odCarrier.Address  = add.Street1;
                            odCarrier.Address2 = add.Street2;
                            odCarrier.City     = add.City;
                            odCarrier.State    = add.Province;
                            odCarrier.Zip      = add.PostalCode;
                        }
                        break;

                    case ItransImportFields.Name:
                        odCarrier.CarrierName = jsonCarrier.Name.En;
                        break;
                    }
                }
                try {
                    long userNum = 0;
                    if (!isAutomatic)
                    {
                        userNum = Security.CurUser.UserNum;
                    }
                    Carriers.Update(odCarrier, odCarrierOld, userNum);
                }
                catch (Exception ex) {
                    ex.DoNothing();
                }
            }
            return("");           //Blank string represents a completed update.
        }
Пример #53
0
 public static string Validate(Clearinghouse clearhouse,Carrier carrier,Provider billProv,Clinic clinic,InsPlan insPlan,Patient subscriber,InsSub insSub)
 {
     StringBuilder strb=new StringBuilder();
     X12Validate.ISA(clearhouse,strb);
     X12Validate.Carrier(carrier,strb);
     if(carrier.ElectID.Length<2) {
         if(strb.Length!=0) {
             strb.Append(",");
         }
         strb.Append("Electronic ID");
     }
     if(billProv.SSN.Length!=9) {
         if(strb.Length!=0) {
             strb.Append(",");
         }
         strb.Append("Prov TIN 9 digits");
     }
     X12Validate.BillProv(billProv,strb);
     if(clinic==null) {
         X12Validate.PracticeAddress(strb);
     }
     else {
         X12Validate.Clinic(clinic,strb);
     }
     if(insSub.SubscriberID.Length<2) {
         if(strb.Length!=0) {
             strb.Append(",");
         }
         strb.Append("SubscriberID");
     }
     if(subscriber.Birthdate.Year<1880) {
         if(strb.Length!=0) {
             strb.Append(",");
         }
         strb.Append("Subscriber Birthdate");
     }
     if(insPlan.GroupNum=="") {
         if(strb.Length!=0) {
             strb.Append(",");
         }
         strb.Append("Group Number");
     }
     return strb.ToString();
 }
Пример #54
0
        ///<summary>In progress.  Probably needs a different name.  Info must be validated first.
        ///Set dependent to the currently selected patient, compares dependent.PatNum to subscriber.PatNum to either contruct a subscriber based or dependent based benefit request.</summary>
        public static string GenerateMessageText(Clearinghouse clearinghouseClin, Carrier carrier, Provider billProv, Clinic clinic, InsPlan insPlan, Patient subscriber, InsSub insSub, Patient patForRequest)
        {
            bool          isSubscriberRequest = (subscriber.PatNum == patForRequest.PatNum);
            int           batchNum            = Clearinghouses.GetNextBatchNumber(clearinghouseClin);
            string        groupControlNumber  = batchNum.ToString();  //Must be unique within file.  We will use batchNum
            int           transactionNum      = 1;
            StringBuilder strb = new StringBuilder();

            //Interchange Control Header
            strb.Append("ISA*00*          *");            //ISA01,ISA02: 00 + 10 spaces
            if (IsEmdeonDental(clearinghouseClin))
            {
                strb.Append("00*" + Sout(clearinghouseClin.Password, 10, 10) + "*"   //ISA03,ISA04: 00 + emdeon password padded to 10 characters
                            + clearinghouseClin.ISA05 + "*"                          //ISA05: Sender ID type: ZZ=mutually defined. 30=TIN. Validated
                            + "316:" + Sout(clearinghouseClin.LoginID, 11, 11) + "*" //ISA06: Emdeon vendor number + username
                            + clearinghouseClin.ISA07 + "*"                          //ISA07: Receiver ID type: ZZ=mutually defined. 30=TIN. Validated
                            + Sout("EMDEONDENTAL", 15, 15) + "*");                   //ISA08: Receiver ID. Validated to make sure length is at least 2.
            }
            else
            {
                strb.Append("00*          *"                                 //ISA03,ISA04: 00 + 10 spaces
                            + clearinghouseClin.ISA05 + "*"                  //ISA05: Sender ID type: ZZ=mutually defined. 30=TIN. Validated
                            + X12Generator.GetISA06(clearinghouseClin) + "*" //ISA06: Sender ID(TIN). Or might be TIN of Open Dental
                            + clearinghouseClin.ISA07 + "*"                  //ISA07: Receiver ID type: ZZ=mutually defined. 30=TIN. Validated
                            + Sout(clearinghouseClin.ISA08, 15, 15) + "*");  //ISA08: Receiver ID. Validated to make sure length is at least 2.
            }
            strb.AppendLine(DateTime.Today.ToString("yyMMdd") + "*"          //ISA09: today's date
                            + DateTime.Now.ToString("HHmm") + "*"            //ISA10: current time
                            + "U*00401*"                                     //ISA11 and ISA12.
                                                                             //ISA13: interchange control number, right aligned:
                            + batchNum.ToString().PadLeft(9, '0') + "*"
                            + "0*"                                           //ISA14: no acknowledgment requested
                            + clearinghouseClin.ISA15 + "*"                  //ISA15: T=Test P=Production. Validated.
                            + ":~");                                         //ISA16: use ':'
            //Functional Group Header
            if (IsEmdeonDental(clearinghouseClin))
            {
                strb.Append("GS*HS*"                                        //GS01: HS for 270 benefit inquiry
                            + X12Generator.GetGS02(clearinghouseClin) + "*" //GS02: Senders Code. Sometimes Jordan Sparks.  Sometimes the sending clinic.
                            + Sout("EMDEONDENTAL", 15, 15) + "*");          //GS03: Application Receiver's Code
            }
            else
            {
                strb.Append("GS*HS*"                                        //GS01: HS for 270 benefit inquiry
                            + X12Generator.GetGS02(clearinghouseClin) + "*" //GS02: Senders Code. Sometimes Jordan Sparks.  Sometimes the sending clinic.
                            + Sout(clearinghouseClin.GS03, 15, 2) + "*");   //GS03: Application Receiver's Code
            }
            strb.AppendLine(DateTime.Today.ToString("yyyyMMdd") + "*"       //GS04: today's date
                            + DateTime.Now.ToString("HHmm") + "*"           //GS05: current time
                            + groupControlNumber + "*"                      //GS06: Group control number. Max length 9. No padding necessary.
                            + "X*"                                          //GS07: X
                            + "004010X092~");                               //GS08: Version
            //Beginning of transaction--------------------------------------------------------------------------------
            int seg = 0;                                                    //count segments for the ST-SE transaction

            //Transaction Set Header
            //ST02 Transact. control #. Must be unique within ISA
            seg++;
            strb.AppendLine("ST*270*"                                           //ST01
                            + transactionNum.ToString().PadLeft(4, '0') + "~"); //ST02
            seg++;
            strb.AppendLine("BHT*0022*13*"                                      //BHT02: 13=request
                            + transactionNum.ToString().PadLeft(4, '0') + "*"   //BHT03. Can be same as ST02
                            + DateTime.Now.ToString("yyyyMMdd") + "*"           //BHT04: Date
                            + DateTime.Now.ToString("HHmmss") + "~");           //BHT05: Time, BHT06: not used
            //HL Loops-----------------------------------------------------------------------------------------------
            int HLcount = 1;

            //2000A HL: Information Source--------------------------------------------------------------------------
            seg++;
            strb.AppendLine("HL*" + HLcount.ToString() + "*" //HL01: Heirarchical ID.  Here, it's always 1.
                            + "*"                            //HL02: No parent. Not used
                            + "20*"                          //HL03: Heirarchical level code. 20=Information source
                            + "1~");                         //HL04: Heirarchical child code. 1=child HL present
            //2100A NM1
            seg++;
            strb.AppendLine("NM1*PR*"                              //NM101: PR=Payer
                            + "2*"                                 //NM102: 2=Non person
                            + Sout(carrier.CarrierName, 35) + "*"  //NM103: Name Last.
                            + "****"                               //NM104-07 not used
                            + "PI*"                                //NM108: PI=PayorID
                            + Sout(carrier.ElectID, 80, 2) + "~"); //NM109: PayorID. Validated to be at least length of 2.
            HLcount++;
            //2000B HL: Information Receiver------------------------------------------------------------------------
            seg++;
            strb.AppendLine("HL*" + HLcount.ToString() + "*" //HL01: Heirarchical ID.  Here, it's always 2.
                            + "1*"                           //HL02: Heirarchical parent id number.  1 in this simple message.
                            + "21*"                          //HL03: Heirarchical level code. 21=Information receiver
                            + "1~");                         //HL04: Heirarchical child code. 1=child HL present
            seg++;
            //2100B NM1: Information Receiver Name
            strb.AppendLine("NM1*1P*"                                   //NM101: 1P=Provider
                            + (billProv.IsNotPerson?"2":"1") + "*"      //NM102: 1=person,2=non-person
                            + Sout(billProv.LName, 35) + "*"            //NM103: Last name
                            + Sout(billProv.FName, 25) + "*"            //NM104: First name
                            + Sout(billProv.MI, 25, 1) + "*"            //NM105: Middle name
                            + "*"                                       //NM106: not used
                            + "*"                                       //NM107: Name suffix. not used
                            + "XX*"                                     //NM108: ID code qualifier. 24=EIN. 34=SSN, XX=NPI
                            + Sout(billProv.NationalProvID, 80) + "~"); //NM109: ID code. NPI validated
            //2100B REF: Information Receiver ID
            if (IsEmdeonDental(clearinghouseClin) && IsDentiCalCarrier(carrier))
            {
                string        ref4aSegment            = "";
                Clearinghouse clearinghouseDentiCalHQ = Clearinghouses.GetFirstOrDefault(x => IsDentiCalClearinghouse(x), true);
                if (clearinghouseDentiCalHQ != null)
                {
                    Clearinghouse clearinghouseDentiCalClin = Clearinghouses.OverrideFields(clearinghouseDentiCalHQ, clearinghouseClin.ClinicNum);
                    if (clearinghouseDentiCalClin != null)
                    {
                        ref4aSegment = clearinghouseDentiCalClin.Password;
                    }
                }
                seg++;
                strb.Append("REF*4A*" + ref4aSegment + "~");
            }
            seg++;
            strb.Append("REF*");
            if (billProv.UsingTIN)
            {
                strb.Append("TJ*");                        //REF01: qualifier. TJ=Federal TIN
            }
            else                                           //SSN
            {
                strb.Append("SY*");                        //REF01: qualifier. SY=SSN
            }
            strb.AppendLine(Sout(billProv.SSN, 30) + "~"); //REF02: ID
            //2100B N3: Information Receiver Address
            seg++;
            if (PrefC.GetBool(PrefName.UseBillingAddressOnClaims))
            {
                strb.Append("N3*" + Sout(PrefC.GetString(PrefName.PracticeBillingAddress), 55));             //N301: Address
            }
            else if (clinic == null)
            {
                strb.Append("N3*" + Sout(PrefC.GetString(PrefName.PracticeAddress), 55));             //N301: Address
            }
            else
            {
                strb.Append("N3*" + Sout(clinic.Address, 55));             //N301: Address
            }
            if (PrefC.GetBool(PrefName.UseBillingAddressOnClaims))
            {
                if (PrefC.GetString(PrefName.PracticeBillingAddress2) == "")
                {
                    strb.AppendLine("~");
                }
                else
                {
                    //N302: Address2. Optional.
                    strb.AppendLine("*" + Sout(PrefC.GetString(PrefName.PracticeBillingAddress2), 55) + "~");
                }
            }
            else if (clinic == null)
            {
                if (PrefC.GetString(PrefName.PracticeAddress2) == "")
                {
                    strb.AppendLine("~");
                }
                else
                {
                    //N302: Address2. Optional.
                    strb.AppendLine("*" + Sout(PrefC.GetString(PrefName.PracticeAddress2), 55) + "~");
                }
            }
            else
            {
                if (clinic.Address2 == "")
                {
                    strb.AppendLine("~");
                }
                else
                {
                    //N302: Address2. Optional.
                    strb.AppendLine("*" + Sout(clinic.Address2, 55) + "~");
                }
            }
            //2100B N4: Information Receiver City/State/Zip
            seg++;
            if (PrefC.GetBool(PrefName.UseBillingAddressOnClaims))
            {
                strb.AppendLine("N4*" + Sout(PrefC.GetString(PrefName.PracticeBillingCity), 30) + "*"             //N401: City
                                + Sout(PrefC.GetString(PrefName.PracticeBillingST), 2) + "*"                      //N402: State
                                + Sout(PrefC.GetString(PrefName.PracticeBillingZip).Replace("-", ""), 15) + "~"); //N403: Zip
            }
            else if (clinic == null)
            {
                strb.AppendLine("N4*" + Sout(PrefC.GetString(PrefName.PracticeCity), 30) + "*"             //N401: City
                                + Sout(PrefC.GetString(PrefName.PracticeST), 2) + "*"                      //N402: State
                                + Sout(PrefC.GetString(PrefName.PracticeZip).Replace("-", ""), 15) + "~"); //N403: Zip
            }
            else
            {
                strb.AppendLine("N4*" + Sout(clinic.City, 30) + "*"             //N401: City
                                + Sout(clinic.State, 2) + "*"                   //N402: State
                                + Sout(clinic.Zip.Replace("-", ""), 15) + "~"); //N403: Zip
            }
            //2100B PRV: Information Receiver Provider Info
            seg++;
            //PRV*PE*ZZ*1223G0001X~
            strb.AppendLine("PRV*PE*"                                    //PRV01: Provider Code. PE=Performing.  There are many other choices.
                            + "ZZ*"                                      //PRV02: ZZ=Mutually defined = health care provider taxonomy code
                            + X12Generator.GetTaxonomy(billProv) + "~"); //PRV03: Specialty code
            HLcount++;
            //2000C HL: Subscriber-----------------------------------------------------------------------------------
            seg++;
            strb.AppendLine("HL*" + HLcount.ToString() + "*"    //HL01: Heirarchical ID.  Here, it's always 3.
                            + "2*"                              //HL02: Heirarchical parent id number.  2 in this simple message.
                            + "22*"                             //HL03: Heirarchical level code. 22=Subscriber
                            + (isSubscriberRequest?"0~":"1~")); //HL04: Heirarchical child code. 0=no child HL present (no dependent) else 1
            //2000C TRN: Subscriber Trace Number
            seg++;
            strb.AppendLine("TRN*1*"                     //TRN01: Trace Type Code.  1=Current Transaction Trace Numbers
                            + "1*"                       //TRN02: Trace Number.  We don't really have a good primary key yet.  Keep it simple. Use 1.
                            + "1" + billProv.SSN + "~"); //TRN03: Entity Identifier. First digit is 1=EIN.  Next 9 digits are EIN.  Length validated.
            //2100C NM1: Subscriber Name
            seg++;
            strb.AppendLine("NM1*IL*"                                                //NM101: IL=Insured or Subscriber
                            + "1*"                                                   //NM102: 1=Person
                            + Sout(subscriber.LName, 35) + "*"                       //NM103: LName
                            + Sout(subscriber.FName, 25) + "*"                       //NM104: FName
                            + Sout(subscriber.MiddleI, 25) + "*"                     //NM105: MiddleName
                            + "*"                                                    //NM106: not used
                            + "*"                                                    //NM107: suffix. Not present in Open Dental yet.
                            + "MI*"                                                  //NM108: MI=MemberID
                            + Sout(insSub.SubscriberID.Replace("-", ""), 80) + "~"); //NM109: Subscriber ID. Validated to be L>2.
            //2100C REF: Subscriber Additional Information.  Without this, old plans seem to be frequently returned.
            seg++;
            strb.AppendLine("REF*6P*"                            //REF01: 6P=GroupNumber
                            + Sout(insPlan.GroupNum, 30) + "~"); //REF02: Supplemental ID. Validated.
            //2100C DMG: Subscriber Demographic Information
            seg++;
            strb.AppendLine("DMG*D8*"                                           //DMG01: Date Time Period Qualifier.  D8=CCYYMMDD
                            + subscriber.Birthdate.ToString("yyyyMMdd") + "~"); //DMG02: Subscriber birthdate.  Validated
            //DMG03: Gender code.  Situational.  F or M.  Since this was left out in the example,
            //and since we don't want to send the wrong gender, we will not send this element.
            //2100C DTP: Subscriber Date.  Deduced through trial and error that this is required by EHG even though not by X12 specs.
            seg++;
            strb.AppendLine("DTP*307*"                                    //DTP01: Qualifier.  307=Eligibility
                            + "D8*"                                       //DTP02: Format Qualifier.
                            + DateTime.Today.ToString("yyyyMMdd") + "~"); //DTP03: Date
            //2000D HL: Dependent Level Hierarchical Level
            if (isSubscriberRequest)
            {
                //2110C EQ: Subscriber Eligibility or Benefit Enquiry Information
                //X12 documentation seems to say that we can loop this 99 times to request very specific benefits.
                //ClaimConnect wants to see either an EQ*30 for "an eligibility request", or an EQ*35 for "a general benefits request".
                //The director of vendor implementation at ClaimConnect has informed us that we should send an EQ*35 to get the full set of benefits.
                seg++;
                strb.AppendLine("EQ*35~"); //Dental Care
            }
            else                           //Dependent based request.
            {
                HLcount++;
                seg++;
                strb.AppendLine("HL*" + HLcount.ToString() + "*" //HL01: Heirarchical ID.
                                + (HLcount - 1).ToString() + "*" //HL02: Heirarchical parent id number.
                                + "23*"                          //HL03: Heirarchical level code. 23=Dependent
                                + "0~");                         //HL04: Heirarchical child code. 0=no child HL present (no dependent)
                //2000D TRN: Dependent Trace Number
                seg++;
                strb.AppendLine("TRN*1*"                     //TRN01: Trace Type Code.  1=Current Transaction Trace Numbers
                                + "1*"                       //TRN02: Trace Number.  We don't really have a good primary key yet.  Keep it simple. Use 1.
                                + "1" + billProv.SSN + "~"); //TRN03: Entity Identifier. First digit is 1=EIN.  Next 9 digits are EIN.  Length validated.
                //2100D NM1: Dependent Name
                seg++;
                strb.AppendLine("NM1*03*"                                 //NM101: 03=Dependent
                                + "1*"                                    //NM102: 1=Person
                                + Sout(patForRequest.LName, 35) + "*"     //NM103: Name Last or Organization Name
                                + Sout(patForRequest.FName, 25) + "*"     //NM104: Name First
                                + Sout(patForRequest.MiddleI, 25) + "~"); //NM105: Name Middle
                //2100D REF: Dependent Additional Identification
                seg++;
                strb.AppendLine("REF*6P*"                            //REF01: 6P=GroupNumber
                                + Sout(insPlan.GroupNum, 30) + "~"); //REF02: Supplemental ID. Validated.
                //2100D DMG: Dependent Demographic Information
                seg++;
                strb.AppendLine("DMG*D8*"                                              //DMG01: Date Time Period Qualifier.  D8=CCYYMMDD
                                + patForRequest.Birthdate.ToString("yyyyMMdd") + "~"); //DMG02: Dependent birthdate.  Validated
                //DMG03: Gender code.  Situational.  F or M.  Since this was left out in the example,
                //and since we don't want to send the wrong gender, we will not send this element.
                //2100D DTP: DEPENDENT Date.  Deduced through trial and error that this is required by EHG even though not by X12 specs.
                seg++;
                strb.AppendLine("DTP*307*"                                    //DTP01: Qualifier.  307=Eligibility
                                + "D8*"                                       //DTP02: Format Qualifier.
                                + DateTime.Today.ToString("yyyyMMdd") + "~"); //DTP03: Date
                seg++;
                strb.AppendLine("EQ*35~");                                    //Dental Care
            }
            //Transaction Trailer
            seg++;
            strb.AppendLine("SE*"
                            + seg.ToString() + "*" //SE01: Total segments, including ST & SE
                            + transactionNum.ToString().PadLeft(4, '0') + "~");
            //End of transaction--------------------------------------------------------------------------------------
            //Functional Group Trailer
            strb.AppendLine("GE*" + transactionNum.ToString() + "*"       //GE01: Number of transaction sets included
                            + groupControlNumber + "~");                  //GE02: Group Control number. Must be identical to GS06
            //Interchange Control Trailer
            strb.AppendLine("IEA*1*"                                      //IEA01: number of functional groups
                            + batchNum.ToString().PadLeft(9, '0') + "~"); //IEA02: Interchange control number
            return(strb.ToString());

            /*
             * return @"
             * ISA*00*          *00*          *30*AA0989922      *30*330989922      *030519*1608*U*00401*000012145*1*T*:~
             * GS*HS*AA0989922*330989922*20030519*1608*12145*X*004010X092~
             * ST*270*0001~
             * BHT*0022*13*ASX012145WEB*20030519*1608~
             * HL*1**20*1~
             * NM1*PR*2*Metlife*****PI*65978~
             * HL*2*1*21*1~
             * NM1*1P*1*PROVLAST*PROVFIRST****XX*1234567893~
             * REF*TJ*200384584~
             * N3*JUNIT ROAD~
             * N4*CHICAGO*IL*60602~
             * PRV*PE*ZZ*1223G0001X~
             * HL*3*2*22*0~
             * TRN*1*12145*1AA0989922~
             * NM1*IL*1*SUBLASTNAME*SUBFIRSTNAME****MI*123456789~
             * DMG*D8*19750323~
             * DTP*307*D8*20030519~
             * EQ*30~
             * SE*17*0001~
             * GE*1*12145~
             * IEA*1*000012145~";
             */

            //return "ISA*00*          *00*          *30*AA0989922      *30*330989922      *030519*1608*U*00401*000012145*1*T*:~GS*HS*AA0989922*330989922*20030519*1608*12145*X*004010X092~ST*270*0001~BHT*0022*13*ASX012145WEB*20030519*1608~HL*1**20*1~NM1*PR*2*Metlife*****PI*65978~HL*2*1*21*1~NM1*1P*1*PROVLAST*PROVFIRST****XX*1234567893~REF*TJ*200384584~N3*JUNIT ROAD~N4*CHICAGO*IL*60602~PRV*PE*ZZ*1223G0001X~HL*3*2*22*0~TRN*1*12145*1AA0989922~NM1*IL*1*SUBLASTNAME*SUBFIRSTNAME****MI*123456789~DMG*D8*19750323~DTP*307*D8*20030519~EQ*30~SE*17*0001~GE*1*12145~IEA*1*000012145~";
        }
Пример #55
0
        ///<summary>Takes any files found in the reports folder for the clearinghouse, and imports them into the database.
        ///Moves the original file into an Archive sub folder.
        ///Returns a string with any errors that occured.</summary>
        private static string ImportReportFiles(Clearinghouse clearinghouseClin, IODProgressExtended progress = null)        //uses clinic-level clearinghouse where necessary.
        {
            progress = progress ?? new ODProgressExtendedNull();
            if (!Directory.Exists(clearinghouseClin.ResponsePath))
            {
                return(Lans.g("FormClaimReports", "Report directory does not exist") + ": " + clearinghouseClin.ResponsePath);
            }
            if (clearinghouseClin.Eformat == ElectronicClaimFormat.Canadian || clearinghouseClin.Eformat == ElectronicClaimFormat.Ramq)
            {
                //the report path is shared with many other important files.  Do not process anything.  Comm is synchronous only.
                return("");
            }
            progress.UpdateProgress(Lans.g(progress.LanThis, "Reading download files"), "reports", "55%", 55);
            if (progress.IsPauseOrCancel())
            {
                return(Lans.g(progress.LanThis, "Import canceled by user."));
            }
            string[] files = null;
            string   archiveDir;

            try {
                files      = Directory.GetFiles(clearinghouseClin.ResponsePath);
                archiveDir = ODFileUtils.CombinePaths(clearinghouseClin.ResponsePath, "Archive" + "_" + DateTime.Now.Year.ToString());
                if (!Directory.Exists(archiveDir))
                {
                    Directory.CreateDirectory(archiveDir);
                }
            }
            catch (UnauthorizedAccessException ex) {
                ex.DoNothing();
                return(Lans.g("FormClaimReports", "Access to the Report Path is denied.  Try running as administrator or contact your network administrator."));
            }
            List <string> listFailedFiles = new List <string>();

            progress.UpdateProgress(Lans.g(progress.LanThis, "Files read."));
            progress.UpdateProgress(Lans.g(progress.LanThis, "Importing files"), "reports", "83%", 83);
            if (files.Length > 0)
            {
                progress.UpdateProgressDetailed(Lans.g(progress.LanThis, "Importing"), tagString: "import");             //add a new progress bar for imports if there are any to import
            }
            else
            {
                progress.UpdateProgress(Lans.g(progress.LanThis, "No files to import."));
            }
            for (int i = 0; i < files.Length; i++)
            {
                int percent = (i / files.Length) * 100;
                progress.UpdateProgress(Lans.g(progress.LanThis, "Importing") + " " + i + " / " + files.Length, "import", percent + "%", percent);
                if (progress.IsPauseOrCancel())
                {
                    return(Lans.g(progress.LanThis, "Import canceled by user."));
                }
                string fileSource      = files[i];
                string fileDestination = ODFileUtils.CombinePaths(archiveDir, Path.GetFileName(files[i]));
                try {
                    File.Move(fileSource, fileDestination);
                }
                catch (Exception ex) {
                    ex.DoNothing();              //OK to continue, since ProcessIncomingReport() above saved the raw report into the etrans table.
                    listFailedFiles.Add(fileSource);
                    continue;                    //Skip current report file and leave in folder to processing later.
                }
                try {
                    Etranss.ProcessIncomingReport(
                        File.GetCreationTime(fileDestination),
                        clearinghouseClin.HqClearinghouseNum,
                        File.ReadAllText(fileDestination),
                        Security.CurUser.UserNum);
                }
                catch (Exception ex) {
                    ex.DoNothing();
                    listFailedFiles.Add(fileSource);
                    File.Move(fileDestination, fileSource);                   //Move file back so that the archived folder only contains succesfully processed reports.
                }
            }
            if (listFailedFiles.Count > 0)
            {
                return(Lans.g("FormClaimReports", "Failed to process the following files due to permission issues or malformed data")
                       + ":\r\n" + string.Join(",\r\n", listFailedFiles));
            }
            return("");
        }
Пример #56
0
		///<summary>The insplan that's passed in need not be properly updated to the database first.</summary>
		public static void RequestBenefits(Clearinghouse clearhouse,InsPlan plan,long patNum,Carrier carrier,List<Benefit> benList,long patPlanNum,InsSub insSub) {
			Patient pat=Patients.GetPat(patNum);
			Patient subsc=Patients.GetPat(insSub.Subscriber);
			Clinic clinic=Clinics.GetClinic(pat.ClinicNum);
			Provider billProv=Providers.GetProv(Providers.GetBillingProvNum(pat.PriProv,pat.ClinicNum));
			//validation.  Throw exception if missing info----------------------------------------
			string validationResult=X270.Validate(clearhouse,carrier,billProv,clinic,plan,subsc,insSub);
			if(validationResult != "") {
				throw new Exception(Lan.g("FormInsPlan","Please fix the following errors first:")+"\r\n"+validationResult);
			}
			//create a 270 message---------------------------------------------------------------
			string x12message=X270.GenerateMessageText(clearhouse,carrier,billProv,clinic,plan,subsc,insSub);
			EtransMessageText etransMessageText=new EtransMessageText();
			etransMessageText.MessageText=x12message;
			EtransMessageTexts.Insert(etransMessageText);
			//attach it to an etrans-------------------------------------------------------------
			Etrans etrans=new Etrans();
			etrans.DateTimeTrans=DateTime.Now;
			etrans.ClearingHouseNum=clearhouse.ClearinghouseNum;
			etrans.Etype=EtransType.BenefitInquiry270;
			etrans.PlanNum=plan.PlanNum;
			etrans.InsSubNum=insSub.InsSubNum;
			etrans.EtransMessageTextNum=etransMessageText.EtransMessageTextNum;
			Etranss.Insert(etrans);
			//send the 270----------------------------------------------------------------------
			string x12response="";
			//a connection error here needs to bubble up
			try {
				if(clearhouse.CommBridge==EclaimsCommBridge.ClaimConnect) {
					x12response=ClaimConnect.Benefits270(clearhouse,x12message);
				}
				if(clearhouse.CommBridge==EclaimsCommBridge.EDS) {
					x12response=EDS.Benefits270(clearhouse,x12message);
				}
			}
			catch(Exception ex) {
				EtransMessageTexts.Delete(etrans.EtransMessageTextNum);
				Etranss.Delete(etrans.EtransNum);
				throw new ApplicationException(Lan.g("FormInsPlan","Connection Error:")+"\r\n"+ex.GetType().Name+"\r\n"+ex.Message);
			}
			//start to process the 271----------------------------------------------------------
			X271 x271=null;
			if(X12object.IsX12(x12response)) {
				X12object x12obj=new X12object(x12response);
				if(x12obj.Is271()) {
					x271=new X271(x12response);
				}
			}
			else {//not a 997, 999, 277 or 271
				EtransMessageTexts.Delete(etrans.EtransMessageTextNum);
				Etranss.Delete(etrans.EtransNum);
				throw new ApplicationException(Lan.g("FormInsPlan","Error:")+"\r\n"+x12response);
			}
			/*
			//In realtime mode, X12 limits the request to one patient.
			//We will always use the subscriber.
			//So all EB segments are for the subscriber.
			List<EB271> listEB=new List<EB271>();
			EB271 eb;
			if(x271 != null) {
				for(int i=0;i<x271.Segments.Count;i++) {
					if(x271.Segments[i].SegmentID != "EB") {
						continue;
					}
					eb=new EB271(x271.Segments[i]);
					listEB.Add(eb);
				}
			}*/
			//create an etrans for the 271------------------------------------------------------
			etransMessageText=new EtransMessageText();
			etransMessageText.MessageText=x12response;
			EtransMessageTexts.Insert(etransMessageText);
			Etrans etrans271=new Etrans();
			etrans271.DateTimeTrans=DateTime.Now;
			etrans271.ClearingHouseNum=clearhouse.ClearinghouseNum;
			etrans271.Etype=EtransType.TextReport;
			if(X12object.IsX12(x12response)) {//this shouldn't need to be tested because it was tested above.
				if(x271==null){
					X12object Xobj=new X12object(x12response);
					if(Xobj.Is997()) {
						etrans271.Etype=EtransType.Acknowledge_997;
					}
					else if(Xobj.Is999()) {
						etrans271.Etype=EtransType.Acknowledge_999;
					}
					else if(X277.Is277(Xobj)) {
						etrans271.Etype=EtransType.StatusNotify_277;
					}
					else if(X835.Is835(Xobj)) {
						etrans271.Etype=EtransType.ERA_835;
					}
				}
				else{
					etrans271.Etype=EtransType.BenefitResponse271;
				}
			}
			etrans271.PlanNum=plan.PlanNum;
			etrans271.InsSubNum=insSub.InsSubNum;
			etrans271.EtransMessageTextNum=etransMessageText.EtransMessageTextNum;
			Etranss.Insert(etrans271);
			etrans.AckEtransNum=etrans271.EtransNum;
			if(etrans271.Etype==EtransType.Acknowledge_997) {
				X997 x997=new X997(x12response);
				string error997=x997.GetHumanReadable();
				etrans.Note="Error: "+error997;//"Malformed document sent.  997 error returned.";
				Etranss.Update(etrans);
				MessageBox.Show(etrans.Note);
				//CodeBase.MsgBoxCopyPaste msgbox=new CodeBase.MsgBoxCopyPaste(etrans.Note);
				//msgbox.ShowDialog();
				//don't show the 270 interface.
				return;
			}
			else if(etrans271.Etype==EtransType.Acknowledge_999) {
				X999 x999=new X999(x12response);
				string error999=x999.GetHumanReadable();
				etrans.Note="Error: "+error999;//"Malformed document sent.  999 error returned.";
				Etranss.Update(etrans);
				MessageBox.Show(etrans.Note);
				//CodeBase.MsgBoxCopyPaste msgbox=new CodeBase.MsgBoxCopyPaste(etrans.Note);
				//msgbox.ShowDialog();
				//don't show the 270 interface.
				return;
			}
			else if(etrans271.Etype==EtransType.StatusNotify_277) { 
				X277 x277=new X277(x12response);
				string error277=x277.GetHumanReadable();
				etrans.Note="Error: "+error277;//"Malformed document sent.  277 error returned.";
				Etranss.Update(etrans);
				MessageBox.Show(etrans.Note);
				//CodeBase.MsgBoxCopyPaste msgbox=new CodeBase.MsgBoxCopyPaste(etrans.Note);
				//msgbox.ShowDialog();
				//don't show the 277 interface.
				return;
			}
			else if(etrans271.Etype==EtransType.ERA_835) {
				X835 x835=new X835(x12response,"");
				string error835=x835.GetHumanReadable();
				etrans.Note="Error: "+error835;//"Malformed document sent.  835 error returned.";
				Etranss.Update(etrans);
				MessageBox.Show(etrans.Note);
				//CodeBase.MsgBoxCopyPaste msgbox=new CodeBase.MsgBoxCopyPaste(etrans.Note);
				//msgbox.ShowDialog();
				//don't show the 835 interface.
				return;
			}
			else { //271
				string processingerror=x271.GetProcessingError();
				if(processingerror != "") {
					etrans.Note=processingerror;
					Etranss.Update(etrans);
					MessageBox.Show(etrans.Note);
					//CodeBase.MsgBoxCopyPaste msgbox=new CodeBase.MsgBoxCopyPaste(etrans.Note);
					//msgbox.ShowDialog();
					//don't show the 270 interface.
					return;
				}
				else {
					etrans.Note="Normal 271 response.";//change this later to be explanatory of content.
				}
			}
			Etranss.Update(etrans);
			//show the user a list of benefits to pick from for import--------------------------
			FormEtrans270Edit formE=new FormEtrans270Edit(patPlanNum,plan.PlanNum,insSub.InsSubNum);
			formE.EtransCur=etrans;
			formE.IsInitialResponse=true;
			formE.benList=benList;
			formE.ShowDialog();
		}
Пример #57
0
        public static string Validate(Clearinghouse clearinghouseClin, Carrier carrier, Provider billProv, Clinic clinic, InsPlan insPlan, Patient subscriber, InsSub insSub, Patient patForRequest)
        {
            StringBuilder strb = new StringBuilder();

            X12Validate.ISA(clearinghouseClin, strb);
            X12Validate.Carrier(carrier, strb);
            if (carrier.ElectID.Length < 2)
            {
                if (strb.Length != 0)
                {
                    strb.Append(",");
                }
                strb.Append("Electronic ID");
            }
            if (billProv.SSN.Length != 9)
            {
                if (strb.Length != 0)
                {
                    strb.Append(",");
                }
                strb.Append("Prov TIN 9 digits");
            }
            X12Validate.BillProv(billProv, strb);
            if (PrefC.GetBool(PrefName.UseBillingAddressOnClaims))
            {
                X12Validate.BillingAddress(strb);
            }
            else if (clinic == null)
            {
                X12Validate.PracticeAddress(strb);
            }
            else
            {
                X12Validate.Clinic(clinic, strb);
            }
            if (insSub.SubscriberID.Length < 2)
            {
                if (strb.Length != 0)
                {
                    strb.Append(",");
                }
                strb.Append("SubscriberID");
            }
            if (subscriber.Birthdate.Year < 1880)
            {
                if (strb.Length != 0)
                {
                    strb.Append(",");
                }
                strb.Append("Subscriber Birthdate");
            }
            if (patForRequest.PatNum != subscriber.PatNum)           //Dependent validation.
            {
                if (patForRequest.Birthdate.Year < 1880)             //Dependent level validation.
                {
                    if (strb.Length != 0)
                    {
                        strb.Append(",");
                    }
                    strb.Append("Dependent Birthdate");
                }
            }
            ElectID eID = ElectIDs.GetID(carrier.ElectID);
            //Medicaid uses the patient First/Last/DOB to get benefits, not group number, so skip this validation if this is medicaid
            bool isMedicaid = (eID != null && eID.IsMedicaid) || carrier.CarrierName.ToLower().Contains("medicaid");

            if (!isMedicaid)
            {
                if (insPlan.GroupNum == "")
                {
                    if (strb.Length != 0)
                    {
                        strb.Append(",");
                    }
                    strb.Append("Group Number");
                }
            }
            //Darien at Dentalxchange helped us resolve one issue where the Group Number included a dash and was failing.
            //The fix suggested by Darien was to only include the numbers before the dash...  See task #705773
            if (IsClaimConnect(clearinghouseClin) && insPlan.GroupNum.Contains("-"))
            {
                if (strb.Length != 0)
                {
                    strb.Append(",");
                }
                strb.Append("Group Number: Only include the group number prior to the '-'");
            }
            return(strb.ToString());
        }
Пример #58
0
 private static string RetrieveReports(Clearinghouse clearinghouseClin, bool isAutomaticMode, IODProgressExtended progress = null)
 {
     progress = progress ?? new ODProgressExtendedNull();
     progress.UpdateProgress(Lans.g(progress.LanThis, "Beginning report retrieval..."), "reports", "0%");
     if (progress.IsPauseOrCancel())
     {
         return(Lans.g(progress.LanThis, "Process canceled by user."));
     }
     if (clearinghouseClin.ISA08 == "113504607")           //TesiaLink
     //But the import will still happen
     {
         return("");
     }
     if (clearinghouseClin.CommBridge == EclaimsCommBridge.None ||
         clearinghouseClin.CommBridge == EclaimsCommBridge.Renaissance ||
         clearinghouseClin.CommBridge == EclaimsCommBridge.RECS)
     {
         return("");
     }
     if (clearinghouseClin.CommBridge == EclaimsCommBridge.WebMD)
     {
         if (!WebMD.Launch(clearinghouseClin, 0, isAutomaticMode, progress))
         {
             return(Lans.g("FormClaimReports", "Error retrieving.") + "\r\n" + WebMD.ErrorMessage);
         }
     }
     else if (clearinghouseClin.CommBridge == EclaimsCommBridge.BCBSGA)
     {
         if (!BCBSGA.Retrieve(clearinghouseClin, true, new TerminalConnector(), progress))
         {
             return(Lans.g("FormClaimReports", "Error retrieving.") + "\r\n" + BCBSGA.ErrorMessage);
         }
     }
     else if (clearinghouseClin.CommBridge == EclaimsCommBridge.ClaimConnect)
     {
         if (!Directory.Exists(clearinghouseClin.ResponsePath))
         {
             //The clearinghouse report path is not setup.  Therefore, the customer does not use ClaimConnect reports via web services.
             if (isAutomaticMode)      //The user opened FormClaimsSend, or FormOpenDental called this function automatically.
             {
                 return("");           //Suppress error message.
             }
             else                      //The user pressed the Get Reports button manually.
             //This cannot happen, because the user is blocked by the UI before they get to this point.
             {
             }
         }
         else if (!ClaimConnect.Retrieve(clearinghouseClin, progress))
         {
             if (ClaimConnect.ErrorMessage.Contains(": 150\r\n")) //Error message 150 "Service Not Contracted"
             {
                 if (isAutomaticMode)                             //The user opened FormClaimsSend, or FormOpenDental called this function automatically.
                 {
                     return("");                                  //Pretend that there is no error when loading FormClaimsSend for those customers who do not pay for ERA service.
                 }
                 else                                             //The user pressed the Get Reports button manually.
                 //The old way.  Some customers still prefer to go to the dentalxchange web portal to view reports because the ERA service costs money.
                 {
                     try {
                         Process.Start(@"http://www.dentalxchange.com");
                     }
                     catch (Exception ex) {
                         ex.DoNothing();
                         return(Lans.g("FormClaimReports", "Could not locate the site."));
                     }
                     return("");
                 }
             }
             return(Lans.g("FormClaimReports", "Error retrieving.") + "\r\n" + ClaimConnect.ErrorMessage);
         }
     }
     else if (clearinghouseClin.CommBridge == EclaimsCommBridge.AOS)
     {
         try {
             //This path would never exist on Unix, so no need to handle back slashes.
             Process.Start(@"C:\Program files\AOS\AOSCommunicator\AOSCommunicator.exe");
         }
         catch {
             return(Lans.g("FormClaimReports", "Could not locate the file."));
         }
     }
     else if (clearinghouseClin.CommBridge == EclaimsCommBridge.MercuryDE)
     {
         if (!MercuryDE.Launch(clearinghouseClin, 0, progress))
         {
             return(Lans.g("FormClaimReports", "Error retrieving.") + "\r\n" + MercuryDE.ErrorMessage);
         }
     }
     else if (clearinghouseClin.CommBridge == EclaimsCommBridge.EmdeonMedical)
     {
         if (!EmdeonMedical.Retrieve(clearinghouseClin, progress))
         {
             return(Lans.g("FormClaimReports", "Error retrieving.") + "\r\n" + EmdeonMedical.ErrorMessage);
         }
     }
     else if (clearinghouseClin.CommBridge == EclaimsCommBridge.DentiCal)
     {
         if (!DentiCal.Launch(clearinghouseClin, 0, progress))
         {
             return(Lans.g("FormClaimReports", "Error retrieving.") + "\r\n" + DentiCal.ErrorMessage);
         }
     }
     else if (clearinghouseClin.CommBridge == EclaimsCommBridge.EDS)
     {
         List <string> listEdsErrors = new List <string>();
         if (!EDS.Retrieve277s(clearinghouseClin, progress))
         {
             listEdsErrors.Add(Lans.g("FormClaimReports", "Error retrieving.") + "\r\n" + EDS.ErrorMessage);
         }
         if (!EDS.Retrieve835s(clearinghouseClin, progress))
         {
             listEdsErrors.Add(Lans.g("FormClaimReports", "Error retrieving.") + "\r\n" + EDS.ErrorMessage);
         }
         if (listEdsErrors.Count > 0)
         {
             return(string.Join("\r\n", listEdsErrors));
         }
     }
     return("");
 }
Пример #59
0
        public static string Benefits270(Clearinghouse clearhouse,string x12message)
        {
            com.dentalxchange.webservices.Credentials cred = new com.dentalxchange.webservices.Credentials();
            if(PrefC.GetBool(PrefName.CustomizedForPracticeWeb)) {//even though they currently use code from a different part of the program.
                cred.client="Practice-Web";
                cred.serviceID="DCI Web Service ID: 001513";
            }
            else {
                cred.client="OpenDental";
                cred.serviceID="DCI Web Service ID: 002778";
            }
            cred.version=Application.ProductVersion;
            cred.username=clearhouse.LoginID;
            cred.password=clearhouse.Password;
            com.dentalxchange.webservices.Request request=new com.dentalxchange.webservices.Request();
            request.content=HttpUtility.HtmlEncode(x12message);//get rid of ampersands, etc.
            com.dentalxchange.webservices.WebServiceService service = new com.dentalxchange.webservices.WebServiceService();
            #if DEBUG
            //service.Url = "https://prelive2.dentalxchange.com/dws/services/dciservice.svl"; // testing
            service.Url = "https://webservices.dentalxchange.com/dws/services/dciservice.svl"; // production
            #else
            service.Url = "https://webservices.dentalxchange.com/dws/services/dciservice.svl"; //always use production. So I don't forget
            #endif
            string strResponse="";
            try {
                com.dentalxchange.webservices.Response response = service.lookupEligibility(cred,request);
                strResponse=response.content;
            }
            catch(SoapException ex) {
                strResponse=ex.Message+"\r\n\r\n"+ex.Detail.InnerText+"\r\n\r\n"+"If this is a new customer, this error might also be due to an invalid Username or Password.  Servers may need a few hours before ready to accept new user information.";
            }
            //cleanup response.  Seems to start with \n and 4 spaces.  Ends with trailing \n.
            strResponse=strResponse.Replace("\n","");
            strResponse=strResponse.TrimStart(' ');
            //CodeBase.MsgBoxCopyPaste msgbox=new CodeBase.MsgBoxCopyPaste(response.content);
            //msgbox.ShowDialog();
            return strResponse;

            /*
            string strRawResponse="";
            string strRawResponseNormal="ISA*00*          *00*          *30*330989922      *29*AA0989922      *030606*0936*U*00401*000013966*0*T*:~GS*HB*330989922*AA0989922*20030606*0936*13966*X*004010X092~ST*271*0001~BHT*0022*11*ASX012145WEB*20030606*0936~HL*1**20*1~NM1*PR*2*ACME INC*****PI*12345~HL*2*1*21*1~NM1*1P*1*PROVLAST*PROVFIRST****SV*5558006~HL*3*2*22*0~TRN*2*100*1330989922~NM1*IL*1*SMITH*JOHN*B***MI*123456789~REF*6P*XYZ123*GROUPNAME~REF*18*2484568*TEST PLAN NAME~N3*29 FREMONT ST*~N4*PEACE*NY*10023~DMG*D8*19570515*M~DTP*307*RD8*19910712-19920525~EB*1*FAM*30~SE*17*0001~GE*1*13966~IEA*1*000013966~";
            string strRawResponseFailureAuth=@"<?xml version=""1.0"" encoding=""UTF-8""?>
            <soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
            <soapenv:Body>
            <soapenv:Fault>
            <faultcode>soapenv:Server.userException</faultcode>
            <faultstring>Authentication failed.</faultstring>
            <faultactor/>
            <detail>
                <string>Authentication failed.</string>
            </detail>
            </soapenv:Fault>
            </soapenv:Body>
            </soapenv:Envelope>";
            string strRawResponseFailure997=@"<?xml version=""1.0"" encoding=""UTF-8""?>
            <soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
            <soapenv:Body>
            <soapenv:Fault>
            <faultcode>soapenv:Server.userException</faultcode>
            <faultstring>Malformed document sent. Please insure that the format is correct and all required data is present.</faultstring>
            <faultactor/>
            <detail>
                <string>ISA*00*          *00*          *30*330989922      *30*BB0989922      *030606*1351*U*00401*000014066*0*T*:~GS*FA*330989922**20030606*1351*14066*X*004010~ST*997*0001~AK1*HR*100~AK2*276*0001~AK3*DMG*10**8~AK4*2**8*20041210~AK5*R*5~AK9*R*0*0*0*3~SE*8*0001~GE*1*14066~IEA*1*000014066~</string>
            </detail>
            </soapenv:Fault>
            </soapenv:Body>
            </soapenv:Envelope>";
            return strRawResponseNormal;*/

            /*
            XmlDocument doc=new XmlDocument();
            doc.LoadXml(strRawResponse);
            //StringReader strReader=new StringReader(strRawResponseNormal);
            //XmlReader xmlReader=XmlReader.Create(strReader);
            //xmlReader...MoveToElement(
            XmlNode node=doc.SelectSingleNode("//lookupEligibilityReturn");
            if(node!=null) {
                return node.InnerText;//271
            }
            node=doc.SelectSingleNode("//detail/string");
            if(node==null) {
                throw new ApplicationException("Returned data not in expected format: "+strRawResponse);
            }
            if(node.InnerText=="Authentication failed.") {
                throw new ApplicationException("Authentication failed.");
            }
            return node.InnerText;//997
            */
        }
Пример #60
0
 ///<summary>Pass in either a clinic or HQ-level clearinghouse.</summary>
 private static bool IsClaimConnect(Clearinghouse clearinghouse)
 {
     return(clearinghouse.ISA08 == "330989922");
 }