private void Import834_Unsafe() { if (!MsgBox.Show(this, true, "Importing insurance plans is a database intensive operation and can take 10 minutes or more to run. " + "It is best to import insurance plans after hours or during another time period when database usage is otherwise low.\r\n" + "Click OK to import insurance plans now, or click Cancel.")) { return; } checkIsPatientCreate.Enabled = false; gridInsPlans.Enabled = false; butOK.Enabled = false; butCancel.Enabled = false; Cursor = Cursors.WaitCursor; Prefs.UpdateBool(PrefName.Ins834IsPatientCreate, checkIsPatientCreate.Checked); int rowIndex = 1; int createdPatsCount = 0; int updatedPatsCount = 0; int skippedPatsCount = 0; int createdCarrierCount = 0; int createdPlanCount = 0; int droppedPlanCount = 0; int updatedPlanCount = 0; StringBuilder sbErrorMessages = new StringBuilder(); List <int> listImportedSegments = new List <int> (); //Used to reconstruct the 834 with imported patients removed. for (int i = 0; i < _x834.ListTransactions.Count; i++) { Hx834_Tran tran = _x834.ListTransactions[i]; for (int j = 0; j < tran.ListMembers.Count; j++) { Hx834_Member member = tran.ListMembers[j]; ShowStatus("Progress " + (rowIndex).ToString().PadLeft(6) + "/" + gridInsPlans.Rows.Count.ToString().PadLeft(6) + " Importing plans for patient " + member.Pat.GetNameLF()); //The patient's status is not affected by the maintenance code. After reviewing all of the possible maintenance codes in //member.MemberLevelDetail.MaintenanceTypeCode, we believe that all statuses suggest either insert or update, except for "Cancel". //Nathan and Derek feel that archiving the patinet in response to a Cancel request is a bit drastic. //Thus we ignore the patient maintenance code and always assume insert/update. //Even if the status was "Cancel", then updating the patient does not hurt. bool isMemberImported = false; bool isMultiMatch = false; if (member.Pat.PatNum == 0) { //The patient may need to be created below. However, the patient may have already been inserted in a pervious iteration of this loop //in following scenario: Two different 834s include updates for the same patient and both documents are being imported at the same time. //If the patient was already inserted, then they would show up in _listPatients and also in the database. Attempt to locate the patient //in _listPatients again before inserting. List <Patient> listPatientMatches = Patients.GetPatientsByNameAndBirthday(member.Pat, _listPatients); if (listPatientMatches.Count == 1) { member.Pat.PatNum = listPatientMatches[0].PatNum; } else if (listPatientMatches.Count > 1) { isMultiMatch = true; } } if (isMultiMatch) { skippedPatsCount++; } else if (member.Pat.PatNum == 0 && checkIsPatientCreate.Checked) { //The code here mimcs the behavior of FormPatientSelect.butAddPt_Click(). Patients.Insert(member.Pat, false); Patient memberPatOld = member.Pat.Copy(); member.Pat.PatStatus = PatientStatus.Patient; member.Pat.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType); if (!PrefC.GetBool(PrefName.PriProvDefaultToSelectProv)) { //Set the patients primary provider to the practice default provider. member.Pat.PriProv = Providers.GetDefaultProvider().ProvNum; } member.Pat.ClinicNum = Clinics.ClinicNum; member.Pat.Guarantor = member.Pat.PatNum; Patients.Update(member.Pat, memberPatOld); int patIdx = _listPatients.BinarySearch(member.Pat); //Preserve sort order by locating the index in which to insert the newly added patient. int insertIdx = ~patIdx; //According to MSDN, the index returned by BinarySearch() is a "bitwise compliment", since not currently in list. _listPatients.Insert(insertIdx, member.Pat); SecurityLogs.MakeLogEntry(Permissions.PatientCreate, member.Pat.PatNum, "Created from Import Ins Plans 834.", LogSources.InsPlanImport834); isMemberImported = true; createdPatsCount++; } else if (member.Pat.PatNum == 0 && !checkIsPatientCreate.Checked) { skippedPatsCount++; } else //member.Pat.PatNum!=0 { Patient patDb = _listPatients.FirstOrDefault(x => x.PatNum == member.Pat.PatNum); //Locate by PatNum, in case user selected manually. member.MergePatientIntoDbPatient(patDb); //Also updates the patient to the database and makes log entry. _listPatients.Remove(patDb); //Remove patient from list so we can add it back in the correct location (in case name or bday changed). int patIdx = _listPatients.BinarySearch(patDb); //Preserve sort order by locating the index in which to insert the newly added patient. //patIdx could be positive if the user manually selected a patient when there were multiple matches found. //If patIdx is negative, then according to MSDN, the index returned by BinarySearch() is a "bitwise compliment". //If there were mult instances of patDb BinarySearch() would return 0, which should not be complimented (OutOfRangeException) int insertIdx = (patIdx >= 0)?patIdx:~patIdx; _listPatients.Insert(insertIdx, patDb); isMemberImported = true; updatedPatsCount++; } if (isMemberImported) { //Import insurance changes for patient. for (int k = 0; k < member.ListHealthCoverage.Count; k++) { Hx834_HealthCoverage healthCoverage = member.ListHealthCoverage[k]; if (k > 0) { rowIndex++; } List <Carrier> listCarriers = Carriers.GetByNameAndTin(tran.Payer.Name, tran.Payer.IdentificationCode); if (listCarriers.Count == 0) { Carrier carrier = new Carrier(); carrier.CarrierName = tran.Payer.Name; carrier.TIN = tran.Payer.IdentificationCode; Carriers.Insert(carrier); DataValid.SetInvalid(InvalidType.Carriers); listCarriers.Add(carrier); SecurityLogs.MakeLogEntry(Permissions.CarrierCreate, 0, "Carrier '" + carrier.CarrierName + "' created from Import Ins Plans 834.", LogSources.InsPlanImport834); createdCarrierCount++; } //Update insurance plans. Match based on carrier and SubscriberId. bool isDropping = false; if (healthCoverage.HealthCoverage.MaintenanceTypeCode == "002") { isDropping = true; } //The insPlanNew will only be inserted if necessary. Created temporarily in order to determine if insert is needed. InsPlan insPlanNew = InsertOrUpdateInsPlan(null, member, listCarriers[0], false); //Since the insurance plans in the 834 do not include very much information, it is likely that many patients will share the same exact plan. //We look for an existing plan being used by any other patinents which match the fields we typically import. List <InsPlan> listInsPlans = InsPlans.GetAllByCarrierNum(listCarriers[0].CarrierNum); InsPlan insPlanMatch = null; for (int p = 0; p < listInsPlans.Count; p++) { //Set the PlanNums equal so that AreEqualValue() will ignore this field. We must ignore PlanNum, since we do not know the PlanNum. insPlanNew.PlanNum = listInsPlans[p].PlanNum; if (InsPlans.AreEqualValue(listInsPlans[p], insPlanNew)) { insPlanMatch = listInsPlans[p]; break; } } Family fam = Patients.GetFamily(member.Pat.PatNum); List <InsSub> listInsSubs = InsSubs.RefreshForFam(fam); List <PatPlan> listPatPlans = PatPlans.Refresh(member.Pat.PatNum); InsSub insSubMatch = null; PatPlan patPlanMatch = null; for (int p = 0; p < listInsSubs.Count; p++) { InsSub insSub = listInsSubs[p]; //According to section 1.4.3 of the standard, the preferred method of matching a dependent to a subscriber is to use the subscriberId. if (insSub.SubscriberID.Trim() != member.SubscriberId.Trim()) { continue; } insSubMatch = insSub; patPlanMatch = PatPlans.GetFromList(listPatPlans, insSub.InsSubNum); break; } if (patPlanMatch == null && isDropping) //No plan match and dropping plan. //Nothing to do. The plan either never existed or is already dropped. { } else if (patPlanMatch == null && !isDropping) //No plan match and not dropping plan. Create the plan. { insPlanMatch = InsertOrUpdateInsPlan(insPlanMatch, member, listCarriers[0]); insSubMatch = InsertOrUpdateInsSub(insSubMatch, insPlanMatch, member, healthCoverage, listCarriers[0]); patPlanMatch = InsertOrUpdatePatPlan(patPlanMatch, insSubMatch, insPlanMatch, member, listCarriers[0], listPatPlans); createdPlanCount++; } else if (patPlanMatch != null && isDropping) //Plan matched and dropping plan. Drop the plan. //This code mimics the behavior of FormInsPlan.butDrop_Click(), except here we do not care if there are claims for this plan today. //We need this feature to be as streamlined as possible so that it might become an automated process later. //Testing for claims on today's date does not seem that useful anyway, or at least not as useful as checking for any claims //associated to the plan, instead of just today's date. { PatPlans.Delete(patPlanMatch.PatPlanNum); //Estimates recomputed within Delete() SecurityLogs.MakeLogEntry(Permissions.InsPlanDropPat, patPlanMatch.PatNum, "Insurance plan dropped from patient for carrier '" + listCarriers[0].CarrierName + "' and groupnum " + "'" + insPlanMatch.GroupNum + "' and subscriber ID '" + insSubMatch.SubscriberID + "' " + "from Import Ins Plans 834.", insPlanMatch.PlanNum, LogSources.InsPlanImport834, insPlanMatch.SecDateTEdit); droppedPlanCount++; } else if (patPlanMatch != null && !isDropping) //Plan matched and not dropping plan. Update the plan. { insPlanMatch = InsertOrUpdateInsPlan(insPlanMatch, member, listCarriers[0]); insSubMatch = InsertOrUpdateInsSub(insSubMatch, insPlanMatch, member, healthCoverage, listCarriers[0]); patPlanMatch = InsertOrUpdatePatPlan(patPlanMatch, insSubMatch, insPlanMatch, member, listCarriers[0], listPatPlans); updatedPlanCount++; } } //end loop k //Remove the member from the X834. int endSegIndex = 0; if (j < tran.ListMembers.Count - 1) { endSegIndex = tran.ListMembers[j + 1].MemberLevelDetail.SegmentIndex - 1; } else { X12Segment segSe = _x834.GetNextSegmentById(member.MemberLevelDetail.SegmentIndex + 1, "SE"); //SE segment is required. endSegIndex = segSe.SegmentIndex - 1; } for (int s = member.MemberLevelDetail.SegmentIndex; s <= endSegIndex; s++) { listImportedSegments.Add(s); } } rowIndex++; } //end loop j } //end loop i if (listImportedSegments.Count > 0 && skippedPatsCount > 0) //Some patients imported, while others did not. { if (MoveFileToArchiveFolder()) { //Save the unprocessed members back to the import directory, so the user can try to import them again. File.WriteAllText(_x834.FilePath, _x834.ReconstructRaw(listImportedSegments)); } } else if (listImportedSegments.Count > 0) //All patinets imported. { MoveFileToArchiveFolder(); } else if (skippedPatsCount > 0) //No patients imported. All patients were skipped. //Leave the raw file unaltered and where it is, so it can be processed again. { } Cursor = Cursors.Default; string msg = Lan.g(this, "Done."); if (createdPatsCount > 0) { msg += "\r\n" + Lan.g(this, "Number of patients created:") + " " + createdPatsCount; } if (updatedPatsCount > 0) { msg += "\r\n" + Lan.g(this, "Number of patients updated:") + " " + updatedPatsCount; } if (skippedPatsCount > 0) { msg += "\r\n" + Lan.g(this, "Number of patients skipped:") + " " + skippedPatsCount; msg += sbErrorMessages.ToString(); } if (createdCarrierCount > 0) { msg += "\r\n" + Lan.g(this, "Number of carriers created:") + " " + createdCarrierCount; msg += sbErrorMessages.ToString(); } if (createdPlanCount > 0) { msg += "\r\n" + Lan.g(this, "Number of plans created:") + " " + createdPlanCount; msg += sbErrorMessages.ToString(); } if (droppedPlanCount > 0) { msg += "\r\n" + Lan.g(this, "Number of plans dropped:") + " " + droppedPlanCount; msg += sbErrorMessages.ToString(); } if (updatedPlanCount > 0) { msg += "\r\n" + Lan.g(this, "Number of plans updated:") + " " + updatedPlanCount; msg += sbErrorMessages.ToString(); } MsgBoxCopyPaste msgBox = new MsgBoxCopyPaste(msg); msgBox.ShowDialog(); }