Пример #1
0
        /// <summary>
        /// Maps the communication data.
        /// </summary>
        /// <param name="tableData">The table data.</param>
        /// <returns></returns>
        private void MapCommunication( IQueryable<Row> tableData )
        {
            var lookupContext = new RockContext();
            var personService = new PersonService( lookupContext );
            var attributeService = new AttributeService( lookupContext );

            var numberTypeValues = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_PHONE_TYPE ), lookupContext ).DefinedValues;

            // Look up additional Person attributes (existing)
            var personAttributes = attributeService.GetByEntityTypeId( PersonEntityTypeId ).ToList();

            // Remove previously defined Excavator social attributes & categories if they exist
            var oldFacebookAttribute = personAttributes.Where( a => a.Key == "FacebookUsername" ).FirstOrDefault();
            if ( oldFacebookAttribute != null )
            {
                Rock.Web.Cache.AttributeCache.Flush( oldFacebookAttribute.Id );
                attributeService.Delete( oldFacebookAttribute );
                lookupContext.SaveChanges( true );
            }

            var oldTwitterAttribute = personAttributes.Where( a => a.Key == "TwitterUsername" ).FirstOrDefault();
            if ( oldTwitterAttribute != null )
            {
                Rock.Web.Cache.AttributeCache.Flush( oldTwitterAttribute.Id );
                attributeService.Delete( oldTwitterAttribute );
                lookupContext.SaveChanges( true );
            }

            int attributeEntityTypeId = EntityTypeCache.Read( "Rock.Model.Attribute" ).Id;
            var socialMediaCategory = new CategoryService( lookupContext ).GetByEntityTypeId( attributeEntityTypeId )
                .Where( c => c.Name == "Social Media" &&
                    c.EntityTypeQualifierValue == PersonEntityTypeId.ToString() &&
                    c.IconCssClass == "fa fa-twitter" )
                .FirstOrDefault();
            if ( socialMediaCategory != null )
            {
                lookupContext.Categories.Remove( socialMediaCategory );
                lookupContext.SaveChanges( true );
            }

            // Cached Rock attributes: Facebook, Twitter, Instagram
            var twitterAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "Twitter" ) );
            var facebookAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "Facebook" ) );
            var instagramAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "Instagram" ) );
            var secondaryEmailAttribute = AttributeCache.Read( SecondaryEmailAttributeId );

            var existingNumbers = new PhoneNumberService( lookupContext ).Queryable().ToList();

            var newNumberList = new List<PhoneNumber>();
            var updatedPersonList = new List<Person>();

            int completed = 0;
            int totalRows = tableData.Count();
            int percentage = ( totalRows - 1 ) / 100 + 1;
            ReportProgress( 0, string.Format( "Verifying communication import ({0:N0} found, {1:N0} already exist).", totalRows, existingNumbers.Count() ) );

            foreach ( var row in tableData )
            {
                string value = row["Communication_Value"] as string;
                int? individualId = row["Individual_ID"] as int?;
                int? householdId = row["Household_ID"] as int?;
                var personList = new List<int?>();

                if ( individualId != null )
                {
                    int? personId = GetPersonAliasId( individualId, householdId );
                    if ( personId != null )
                    {
                        personList.Add( personId );
                    }
                }
                else
                {
                    List<int?> personIds = GetFamilyByHouseholdId( householdId );
                    if ( personIds.Any() )
                    {
                        personList.AddRange( personIds );
                    }
                }

                if ( personList.Any() && !string.IsNullOrWhiteSpace( value ) )
                {
                    DateTime? lastUpdated = row["LastUpdatedDate"] as DateTime?;
                    string communicationComment = row["Communication_Comment"] as string;
                    string type = row["Communication_Type"] as string;
                    bool isListed = (bool)row["Listed"];
                    value = value.RemoveWhitespace();

                    // Communication value is a number
                    if ( type.Contains( "Phone" ) || type.Contains( "Mobile" ) )
                    {
                        var extension = string.Empty;
                        var countryCode = Rock.Model.PhoneNumber.DefaultCountryCode();
                        var normalizedNumber = string.Empty;
                        var countryIndex = value.IndexOf( '+' );
                        int extensionIndex = value.LastIndexOf( 'x' ) > 0 ? value.LastIndexOf( 'x' ) : value.Length;
                        if ( countryIndex >= 0 )
                        {
                            countryCode = value.Substring( countryIndex, countryIndex + 3 ).AsNumeric();
                            normalizedNumber = value.Substring( countryIndex + 3, extensionIndex - 3 ).AsNumeric();
                            extension = value.Substring( extensionIndex );
                        }
                        else if ( extensionIndex > 0 )
                        {
                            normalizedNumber = value.Substring( 0, extensionIndex ).AsNumeric();
                            extension = value.Substring( extensionIndex ).AsNumeric();
                        }
                        else
                        {
                            normalizedNumber = value.AsNumeric();
                        }

                        if ( !string.IsNullOrWhiteSpace( normalizedNumber ) )
                        {
                            foreach ( var familyPersonId in personList )
                            {
                                bool numberExists = existingNumbers.Any( n => n.PersonId == familyPersonId && n.Number.Equals( value ) );
                                if ( !numberExists )
                                {
                                    var newNumber = new PhoneNumber();
                                    newNumber.CreatedByPersonAliasId = ImportPersonAlias.Id;
                                    newNumber.ModifiedDateTime = lastUpdated;
                                    newNumber.PersonId = (int)familyPersonId;
                                    newNumber.IsMessagingEnabled = false;
                                    newNumber.CountryCode = countryCode;
                                    newNumber.IsUnlisted = !isListed;
                                    newNumber.Extension = extension.Left( 20 );
                                    newNumber.Number = normalizedNumber.Left( 20 );
                                    newNumber.Description = communicationComment;

                                    newNumber.NumberTypeValueId = numberTypeValues.Where( v => type.StartsWith( v.Value ) )
                                        .Select( v => (int?)v.Id ).FirstOrDefault();

                                    newNumberList.Add( newNumber );
                                    existingNumbers.Add( newNumber );
                                }
                            }

                            completed++;
                        }
                    }
                    else
                    {
                        var person = personService.Queryable( includeDeceased: true ).FirstOrDefault( p => p.Id == personList.FirstOrDefault() );
                        person.Attributes = new Dictionary<string, AttributeCache>();
                        person.AttributeValues = new Dictionary<string, AttributeValue>();

                        if ( value.IsValidEmail() )
                        {
                            string secondaryEmail = string.Empty;
                            if ( string.IsNullOrWhiteSpace( person.Email ) )
                            {
                                secondaryEmail = person.Email;
                                person.Email = value.Left( 75 );
                                person.IsEmailActive = isListed;
                                person.ModifiedDateTime = lastUpdated;
                                person.EmailNote = communicationComment;
                                lookupContext.SaveChanges( true );
                            }
                            else if ( !person.Email.Equals( value ) )
                            {
                                secondaryEmail = value;
                            }

                            var existingSecondaryEmail = new AttributeValueService( lookupContext ).Queryable().Where( av => av.AttributeId == SecondaryEmailAttributeId && av.EntityId == person.Id ).FirstOrDefault();

                            if ( !string.IsNullOrWhiteSpace( secondaryEmail ) && existingSecondaryEmail == null )
                            {
                                person.Attributes.Add( secondaryEmailAttribute.Key, secondaryEmailAttribute );
                                person.AttributeValues.Add( secondaryEmailAttribute.Key, new AttributeValue()
                                {
                                    AttributeId = secondaryEmailAttribute.Id,
                                    Value = secondaryEmail
                                } );
                            }
                        }
                        else if ( type.Contains( "Twitter" ) )
                        {
                            person.Attributes.Add( twitterAttribute.Key, twitterAttribute );
                            person.AttributeValues.Add( twitterAttribute.Key, new AttributeValue()
                            {
                                AttributeId = twitterAttribute.Id,
                                Value = value
                            } );
                        }
                        else if ( type.Contains( "Facebook" ) )
                        {
                            var existingFacebook = new AttributeValueService( lookupContext ).Queryable().Where( av => av.AttributeId == facebookAttribute.Id && av.EntityId == person.Id ).FirstOrDefault();
                            if ( existingFacebook == null )
                            {
                                person.Attributes.Add( facebookAttribute.Key, facebookAttribute );
                                person.AttributeValues.Add( facebookAttribute.Key, new AttributeValue()
                                {
                                    AttributeId = facebookAttribute.Id,
                                    Value = value
                                } );
                            }
                        }
                        else if ( type.Contains( "Instagram" ) )
                        {
                            person.Attributes.Add( instagramAttribute.Key, instagramAttribute );
                            person.AttributeValues.Add( instagramAttribute.Key, new AttributeValue()
                            {
                                AttributeId = instagramAttribute.Id,
                                Value = value
                            } );
                        }

                        updatedPersonList.Add( person );
                        completed++;
                    }

                    if ( completed % percentage < 1 )
                    {
                        int percentComplete = completed / percentage;
                        ReportProgress( percentComplete, string.Format( "{0:N0} records imported ({1}% complete).", completed, percentComplete ) );
                    }
                    else if ( completed % ReportingNumber < 1 )
                    {
                        SaveCommunication( newNumberList, updatedPersonList );

                        // reset so context doesn't bloat
                        lookupContext = new RockContext();
                        personService = new PersonService( lookupContext );
                        updatedPersonList.Clear();
                        newNumberList.Clear();
                        ReportPartialProgress();
                    }
                }
            }

            if ( newNumberList.Any() || updatedPersonList.Any() )
            {
                SaveCommunication( newNumberList, updatedPersonList );
            }

            ReportProgress( 100, string.Format( "Finished communication import: {0:N0} records imported.", completed ) );
        }
Пример #2
0
        /// <summary>
        /// Maps the communication data.
        /// </summary>
        /// <param name="tableData">The table data.</param>
        /// <returns></returns>
        private void MapCommunication( IQueryable<Row> tableData )
        {
            var lookupContext = new RockContext();
            var personService = new PersonService( lookupContext );
            var attributeService = new AttributeService( lookupContext );

            var definedTypePhoneType = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_PHONE_TYPE ), lookupContext );
            var otherNumberType = definedTypePhoneType.DefinedValues.Where( dv => dv.Value.StartsWith( "Other" ) ).Select( v => (int?)v.Id ).FirstOrDefault();
            if ( otherNumberType == null )
            {
                var otherType = new DefinedValue();
                otherType.IsSystem = false;
                otherType.DefinedTypeId = definedTypePhoneType.Id;
                otherType.Order = 0;
                otherType.Value = "Other";
                otherType.Description = "Imported from FellowshipOne";
                otherType.CreatedByPersonAliasId = ImportPersonAliasId;

                lookupContext.DefinedValues.Add( otherType );
                lookupContext.SaveChanges( DisableAuditing );
            }

            // Look up existing Person attributes
            var personAttributes = attributeService.GetByEntityTypeId( PersonEntityTypeId ).ToList();

            // Cached Rock attributes: Facebook, Twitter, Instagram
            var twitterAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key.Equals( "Twitter", StringComparison.InvariantCultureIgnoreCase ) ) );
            var facebookAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key.Equals( "Facebook", StringComparison.InvariantCultureIgnoreCase ) ) );
            var instagramAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key.Equals( "Instagram", StringComparison.InvariantCultureIgnoreCase ) ) );

            var newNumbers = new List<PhoneNumber>();
            var existingNumbers = new PhoneNumberService( lookupContext ).Queryable().AsNoTracking().ToList();
            var newPeopleAttributes = new Dictionary<int, Person>();

            int completed = 0;
            int totalRows = tableData.Count();
            int percentage = ( totalRows - 1 ) / 100 + 1;
            ReportProgress( 0, string.Format( "Verifying communication import ({0:N0} found, {1:N0} already exist).", totalRows, existingNumbers.Count ) );

            foreach ( var groupedRows in tableData.OrderByDescending( r => r["LastUpdatedDate"] ).GroupBy<Row, int?>( r => r["Household_ID"] as int? ) )
            {
                foreach ( var row in groupedRows.Where( r => r != null ) )
                {
                    string value = row["Communication_Value"] as string;
                    int? individualId = row["Individual_ID"] as int?;
                    int? householdId = row["Household_ID"] as int?;
                    var peopleToUpdate = new List<PersonKeys>();

                    if ( individualId != null )
                    {
                        var matchingPerson = GetPersonKeys( individualId, householdId, includeVisitors: false );
                        if ( matchingPerson != null )
                        {
                            peopleToUpdate.Add( matchingPerson );
                        }
                    }
                    else
                    {
                        peopleToUpdate = GetFamilyByHouseholdId( householdId, includeVisitors: false );
                    }

                    if ( peopleToUpdate.Any() && !string.IsNullOrWhiteSpace( value ) )
                    {
                        DateTime? lastUpdated = row["LastUpdatedDate"] as DateTime?;
                        string communicationComment = row["Communication_Comment"] as string;
                        string type = row["Communication_Type"] as string;
                        bool isListed = (bool)row["Listed"];
                        value = value.RemoveWhitespace();

                        // Communication value is a number
                        if ( type.Contains( "Phone" ) || type.Contains( "Mobile" ) )
                        {
                            var extension = string.Empty;
                            var countryCode = PhoneNumber.DefaultCountryCode();
                            var normalizedNumber = string.Empty;
                            var countryIndex = value.IndexOf( '+' );
                            int extensionIndex = value.LastIndexOf( 'x' ) > 0 ? value.LastIndexOf( 'x' ) : value.Length;
                            if ( countryIndex >= 0 )
                            {
                                countryCode = value.Substring( countryIndex, countryIndex + 3 ).AsNumeric();
                                normalizedNumber = value.Substring( countryIndex + 3, extensionIndex - 3 ).AsNumeric();
                                extension = value.Substring( extensionIndex );
                            }
                            else if ( extensionIndex > 0 )
                            {
                                normalizedNumber = value.Substring( 0, extensionIndex ).AsNumeric();
                                extension = value.Substring( extensionIndex ).AsNumeric();
                            }
                            else
                            {
                                normalizedNumber = value.AsNumeric();
                            }

                            if ( !string.IsNullOrWhiteSpace( normalizedNumber ) )
                            {
                                foreach ( var personKeys in peopleToUpdate )
                                {
                                    bool numberExists = existingNumbers.Any( n => n.PersonId == personKeys.PersonId && n.Number.Equals( value ) );
                                    if ( !numberExists )
                                    {
                                        var newNumber = new PhoneNumber();
                                        newNumber.CreatedByPersonAliasId = ImportPersonAliasId;
                                        newNumber.ModifiedDateTime = lastUpdated;
                                        newNumber.PersonId = (int)personKeys.PersonId;
                                        newNumber.IsMessagingEnabled = false;
                                        newNumber.CountryCode = countryCode;
                                        newNumber.IsUnlisted = !isListed;
                                        newNumber.Extension = extension.Left( 20 ) ?? string.Empty;
                                        newNumber.Number = normalizedNumber.Left( 20 );
                                        newNumber.Description = communicationComment;
                                        newNumber.NumberFormatted = PhoneNumber.FormattedNumber( countryCode, newNumber.Number, true );

                                        var matchingNumberType = definedTypePhoneType.DefinedValues.Where( v => type.StartsWith( v.Value ) )
                                            .Select( v => (int?)v.Id ).FirstOrDefault();
                                        newNumber.NumberTypeValueId = matchingNumberType ?? otherNumberType;

                                        newNumbers.Add( newNumber );
                                        existingNumbers.Add( newNumber );
                                    }
                                }

                                completed++;
                            }
                        }
                        else
                        {
                            Person person = null;

                            var personKeys = peopleToUpdate.FirstOrDefault();
                            if ( !newPeopleAttributes.ContainsKey( personKeys.PersonId ) )
                            {
                                // not in dictionary, get person from database
                                person = personService.Queryable( includeDeceased: true ).FirstOrDefault( p => p.Id == personKeys.PersonId );
                            }
                            else
                            {
                                // reuse person from dictionary
                                person = newPeopleAttributes[personKeys.PersonId];
                            }

                            if ( person != null )
                            {
                                if ( person.Attributes == null || person.AttributeValues == null )
                                {
                                    // make sure we have valid objects to assign to
                                    person.Attributes = new Dictionary<string, AttributeCache>();
                                    person.AttributeValues = new Dictionary<string, AttributeValueCache>();
                                }

                                // Check for an InFellowship ID/email before checking other types of email
                                var isLoginValue = type.IndexOf( "InFellowship", StringComparison.OrdinalIgnoreCase ) >= 0;
                                var personAlreadyHasLogin = person.Attributes.ContainsKey( InFellowshipLoginAttribute.Key );
                                if ( isLoginValue && !personAlreadyHasLogin )
                                {
                                    AddPersonAttribute( InFellowshipLoginAttribute, person, value );
                                    AddUserLogin( AuthProviderEntityTypeId, person, value );
                                }
                                else if ( value.IsEmail() )
                                {
                                    // person email is empty
                                    if ( string.IsNullOrWhiteSpace( person.Email ) )
                                    {
                                        person.Email = value.Left( 75 );
                                        person.IsEmailActive = isListed;
                                        person.EmailPreference = isListed ? EmailPreference.EmailAllowed : EmailPreference.DoNotEmail;
                                        person.ModifiedDateTime = lastUpdated;
                                        person.EmailNote = communicationComment;
                                        lookupContext.SaveChanges( DisableAuditing );
                                    }
                                    // this is a different email, assign it to SecondaryEmail
                                    else if ( !person.Email.Equals( value ) && !person.Attributes.ContainsKey( SecondaryEmailAttribute.Key ) )
                                    {
                                        AddPersonAttribute( SecondaryEmailAttribute, person, value );
                                    }
                                }
                                else if ( type.Contains( "Twitter" ) && !person.Attributes.ContainsKey( twitterAttribute.Key ) )
                                {
                                    AddPersonAttribute( twitterAttribute, person, value );
                                }
                                else if ( type.Contains( "Facebook" ) && !person.Attributes.ContainsKey( facebookAttribute.Key ) )
                                {
                                    AddPersonAttribute( facebookAttribute, person, value );
                                }
                                else if ( type.Contains( "Instagram" ) && !person.Attributes.ContainsKey( instagramAttribute.Key ) )
                                {
                                    AddPersonAttribute( instagramAttribute, person, value );
                                }

                                if ( !newPeopleAttributes.ContainsKey( personKeys.PersonId ) )
                                {
                                    newPeopleAttributes.Add( personKeys.PersonId, person );
                                }
                                else
                                {
                                    newPeopleAttributes[personKeys.PersonId] = person;
                                }
                            }

                            completed++;
                        }

                        if ( completed % percentage < 1 )
                        {
                            int percentComplete = completed / percentage;
                            ReportProgress( percentComplete, string.Format( "{0:N0} records imported ({1}% complete).", completed, percentComplete ) );
                        }
                        else if ( completed % ReportingNumber < 1 )
                        {
                            if ( newNumbers.Any() || newPeopleAttributes.Any() )
                            {
                                SaveCommunication( newNumbers, newPeopleAttributes );
                            }

                            // reset so context doesn't bloat
                            lookupContext = new RockContext();
                            personService = new PersonService( lookupContext );
                            newPeopleAttributes.Clear();
                            newNumbers.Clear();
                            ReportPartialProgress();
                        }
                    }
                }
            }

            if ( newNumbers.Any() || newPeopleAttributes.Any() )
            {
                SaveCommunication( newNumbers, newPeopleAttributes );
            }

            ReportProgress( 100, string.Format( "Finished communication import: {0:N0} records imported.", completed ) );
        }
Пример #3
0
        /// <summary>
        /// Maps the communication data.
        /// </summary>
        /// <param name="tableData">The table data.</param>
        /// <returns></returns>
        private void MapCommunication( IQueryable<Row> tableData )
        {
            var categoryService = new CategoryService();
            var personService = new PersonService();

            List<DefinedValue> numberTypeValues = new DefinedValueService().Queryable()
                .Where( dv => dv.DefinedType.Guid == new Guid( Rock.SystemGuid.DefinedType.PERSON_PHONE_TYPE ) ).ToList();

            // Add a Social Media category if it doesn't exist
            int attributeEntityTypeId = EntityTypeCache.Read( "Rock.Model.Attribute" ).Id;
            int socialMediaCategoryId = categoryService.Queryable().Where( c => c.EntityType.Id == attributeEntityTypeId && c.Name == "Social Media" ).Select( c => c.Id ).FirstOrDefault();
            if ( socialMediaCategoryId == 0 )
            {
                var socialMediaCategory = new Category();
                socialMediaCategory.IsSystem = false;
                socialMediaCategory.Name = "Social Media";
                socialMediaCategory.IconCssClass = "fa fa-twitter";
                socialMediaCategory.EntityTypeId = attributeEntityTypeId;
                socialMediaCategory.EntityTypeQualifierColumn = "EntityTypeId";
                socialMediaCategory.EntityTypeQualifierValue = PersonEntityTypeId.ToString();
                socialMediaCategory.Order = 0;

                categoryService.Add( socialMediaCategory, ImportPersonAlias );
                categoryService.Save( socialMediaCategory, ImportPersonAlias );
                socialMediaCategoryId = socialMediaCategory.Id;
            }

            int visitInfoCategoryId = categoryService.Queryable().Where( c => c.EntityTypeId == attributeEntityTypeId && c.Name == "Visit Information" ).Select( c => c.Id ).FirstOrDefault();

            // Look up additional Person attributes (existing)
            var personAttributes = new AttributeService().GetByEntityTypeId( PersonEntityTypeId ).ToList();

            // Add an Attribute for the secondary email
            int secondaryEmailAttributeId = personAttributes.Where( a => a.Key == "SecondaryEmail" ).Select( a => a.Id ).FirstOrDefault();
            if ( secondaryEmailAttributeId == 0 )
            {
                var newSecondaryEmailAttribute = new Rock.Model.Attribute();
                newSecondaryEmailAttribute.Key = "SecondaryEmail";
                newSecondaryEmailAttribute.Name = "Secondary Email";
                newSecondaryEmailAttribute.FieldTypeId = TextFieldTypeId;
                newSecondaryEmailAttribute.EntityTypeId = PersonEntityTypeId;
                newSecondaryEmailAttribute.EntityTypeQualifierValue = string.Empty;
                newSecondaryEmailAttribute.EntityTypeQualifierColumn = string.Empty;
                newSecondaryEmailAttribute.Description = "The secondary email for this person";
                newSecondaryEmailAttribute.DefaultValue = string.Empty;
                newSecondaryEmailAttribute.IsMultiValue = false;
                newSecondaryEmailAttribute.IsRequired = false;
                newSecondaryEmailAttribute.Order = 0;

                using ( new UnitOfWorkScope() )
                {
                    var attributeService = new AttributeService();
                    attributeService.Add( newSecondaryEmailAttribute );
                    var visitInfoCategory = new CategoryService().Get( visitInfoCategoryId );
                    newSecondaryEmailAttribute.Categories.Add( visitInfoCategory );
                    attributeService.Save( newSecondaryEmailAttribute );
                    secondaryEmailAttributeId = newSecondaryEmailAttribute.Id;
                }
            }

            // Add an Attribute for Twitter
            int twitterAttributeId = personAttributes.Where( a => a.Key == "TwitterUsername" ).Select( a => a.Id ).FirstOrDefault();
            if ( twitterAttributeId == 0 )
            {
                var newTwitterAttribute = new Rock.Model.Attribute();
                newTwitterAttribute.Key = "TwitterUsername";
                newTwitterAttribute.Name = "Twitter Username";
                newTwitterAttribute.FieldTypeId = TextFieldTypeId;
                newTwitterAttribute.EntityTypeId = PersonEntityTypeId;
                newTwitterAttribute.EntityTypeQualifierValue = string.Empty;
                newTwitterAttribute.EntityTypeQualifierColumn = string.Empty;
                newTwitterAttribute.Description = "The Twitter username (or link) for this person";
                newTwitterAttribute.DefaultValue = string.Empty;
                newTwitterAttribute.IsMultiValue = false;
                newTwitterAttribute.IsRequired = false;
                newTwitterAttribute.Order = 0;

                using ( new UnitOfWorkScope() )
                {
                    var attributeService = new AttributeService();
                    attributeService.Add( newTwitterAttribute );
                    var socialMediaCategory = new CategoryService().Get( socialMediaCategoryId );
                    newTwitterAttribute.Categories.Add( socialMediaCategory );
                    attributeService.Save( newTwitterAttribute );
                    twitterAttributeId = newTwitterAttribute.Id;
                }
            }

            // Add an Attribute for Facebook
            var facebookAttributeId = personAttributes.Where( a => a.Key == "FacebookUsername" ).Select( a => a.Id ).FirstOrDefault();
            if ( facebookAttributeId == 0 )
            {
                var newFacebookAttribute = new Rock.Model.Attribute();
                newFacebookAttribute.Key = "FacebookUsername";
                newFacebookAttribute.Name = "Facebook Username";
                newFacebookAttribute.FieldTypeId = TextFieldTypeId;
                newFacebookAttribute.EntityTypeId = PersonEntityTypeId;
                newFacebookAttribute.EntityTypeQualifierValue = string.Empty;
                newFacebookAttribute.EntityTypeQualifierColumn = string.Empty;
                newFacebookAttribute.Description = "The Facebook username (or link) for this person";
                newFacebookAttribute.DefaultValue = string.Empty;
                newFacebookAttribute.IsMultiValue = false;
                newFacebookAttribute.IsRequired = false;
                newFacebookAttribute.Order = 0;

                using ( new UnitOfWorkScope() )
                {
                    var attributeService = new AttributeService();
                    attributeService.Add( newFacebookAttribute );
                    var socialMediaCategory = new CategoryService().Get( socialMediaCategoryId );
                    newFacebookAttribute.Categories.Add( socialMediaCategory );
                    attributeService.Save( newFacebookAttribute );
                    facebookAttributeId = newFacebookAttribute.Id;
                }
            }

            var secondaryEmailAttribute = AttributeCache.Read( secondaryEmailAttributeId );
            var twitterUsernameAttribute = AttributeCache.Read( twitterAttributeId );
            var facebookUsernameAttribute = AttributeCache.Read( facebookAttributeId );

            var existingNumbers = new PhoneNumberService().Queryable().ToList();

            var newNumberList = new List<PhoneNumber>();
            var updatedPersonList = new List<Person>();

            int completed = 0;
            int totalRows = tableData.Count();
            int percentage = ( totalRows - 1 ) / 100 + 1;
            ReportProgress( 0, string.Format( "Checking communication import ({0:N0} found).", totalRows ) );

            foreach ( var row in tableData )
            {
                string value = row["Communication_Value"] as string;
                int? individualId = row["Individual_ID"] as int?;
                int? householdId = row["Household_ID"] as int?;
                int? personId = GetPersonId( individualId, householdId );
                if ( personId != null && !string.IsNullOrWhiteSpace( value ) )
                {
                    DateTime? lastUpdated = row["LastUpdatedDate"] as DateTime?;
                    string communicationComment = row["Communication_Comment"] as string;
                    string type = row["Communication_Type"] as string;
                    bool isListed = (bool)row["Listed"];

                    if ( type.Contains( "Phone" ) || type.Contains( "Mobile" ) )
                    {
                        var extension = string.Empty;
                        int extensionIndex = value.LastIndexOf( 'x' );
                        if ( extensionIndex > 0 )
                        {
                            extension = value.Substring( extensionIndex ).AsNumeric();
                            value = value.Substring( 0, extensionIndex ).AsNumeric();
                        }
                        else
                        {
                            value = value.AsNumeric();
                        }

                        if ( !string.IsNullOrWhiteSpace( value ) )
                        {
                            bool numberExists = existingNumbers.Any( n => n.PersonId == (int)personId && n.Number.Equals( value ) );
                            if ( !numberExists )
                            {
                                var newNumber = new PhoneNumber();
                                newNumber.CreatedByPersonAliasId = ImportPersonAlias.Id;
                                newNumber.ModifiedDateTime = lastUpdated;
                                newNumber.PersonId = (int)personId;
                                newNumber.IsMessagingEnabled = false;
                                newNumber.IsUnlisted = !isListed;
                                newNumber.Extension = extension.Left( 20 );
                                newNumber.Number = value.Left( 20 );
                                newNumber.Description = communicationComment;

                                newNumber.NumberTypeValueId = numberTypeValues.Where( v => type.StartsWith( v.Name ) )
                                    .Select( v => (int?)v.Id ).FirstOrDefault();

                                newNumberList.Add( newNumber );
                                completed++;
                            }
                        }
                    }
                    else
                    {
                        var person = personService.Get( (int)personId );
                        person.Attributes = new Dictionary<string, AttributeCache>();
                        person.AttributeValues = new Dictionary<string, List<AttributeValue>>();

                        if ( value.IsValidEmail() )
                        {
                            string secondaryEmail = string.Empty;
                            if ( string.IsNullOrWhiteSpace( person.Email ) || ( isListed && person.IsEmailActive == false ) )
                            {
                                secondaryEmail = person.Email;
                                person.Email = value.Left( 75 );
                                person.IsEmailActive = isListed;
                                person.DoNotEmail = !isListed;
                                person.ModifiedDateTime = lastUpdated;
                                person.EmailNote = communicationComment;
                            }
                            else if ( !person.Email.Equals( value ) )
                            {
                                secondaryEmail = value;
                            }

                            if ( !string.IsNullOrWhiteSpace( secondaryEmail ) )
                            {
                                person.Attributes.Add( "SecondaryEmail", secondaryEmailAttribute );
                                person.AttributeValues.Add( "SecondaryEmail", new List<AttributeValue>() );
                                person.AttributeValues["SecondaryEmail"].Add( new AttributeValue()
                                {
                                    AttributeId = secondaryEmailAttribute.Id,
                                    Value = secondaryEmail,
                                    Order = 0
                                } );
                            }
                        }
                        else if ( type.Contains( "Twitter" ) )
                        {
                            person.Attributes.Add( "TwitterUsername", twitterUsernameAttribute );
                            person.AttributeValues.Add( "TwitterUsername", new List<AttributeValue>() );
                            person.AttributeValues["TwitterUsername"].Add( new AttributeValue()
                            {
                                AttributeId = twitterUsernameAttribute.Id,
                                Value = value,
                                Order = 0
                            } );
                        }
                        else if ( type.Contains( "Facebook" ) )
                        {
                            person.Attributes.Add( "FacebookUsername", facebookUsernameAttribute );
                            person.AttributeValues.Add( "FacebookUsername", new List<AttributeValue>() );
                            person.AttributeValues["FacebookUsername"].Add( new AttributeValue()
                            {
                                AttributeId = facebookUsernameAttribute.Id,
                                Value = value,
                                Order = 0
                            } );
                        }

                        updatedPersonList.Add( person );
                        completed++;
                    }

                    if ( completed % percentage < 1 )
                    {
                        int percentComplete = completed / percentage;
                        ReportProgress( percentComplete, string.Format( "{0:N0} records imported ({1}% complete).", completed, percentComplete ) );
                    }
                    else if ( completed % ReportingNumber < 1 )
                    {
                        RockTransactionScope.WrapTransaction( () =>
                        {
                            var numberService = new PhoneNumberService();
                            numberService.RockContext.PhoneNumbers.AddRange( newNumberList );
                            numberService.RockContext.SaveChanges();

                            // don't add updatedPeople, they're already tracked with current context
                            personService.RockContext.SaveChanges();

                            var attributeValueService = new AttributeValueService();
                            foreach ( var updatedPerson in updatedPersonList.Where( p => p.Attributes.Any() ) )
                            {
                                foreach ( var attributeCache in updatedPerson.Attributes.Select( a => a.Value ) )
                                {
                                    var newValue = updatedPerson.AttributeValues[attributeCache.Key].FirstOrDefault();
                                    if ( newValue != null )
                                    {
                                        newValue.EntityId = updatedPerson.Id;
                                        attributeValueService.RockContext.AttributeValues.Add( newValue );
                                    }
                                }
                            }

                            attributeValueService.RockContext.SaveChanges();
                        } );

                        // reset the person context so it doesn't bloat
                        if ( updatedPersonList.Any() )
                        {
                            personService = new PersonService();
                            updatedPersonList.Clear();
                        }

                        newNumberList.Clear();
                        ReportPartialProgress();
                    }
                }
            }

            RockTransactionScope.WrapTransaction( () =>
            {
                var numberService = new PhoneNumberService();
                numberService.RockContext.PhoneNumbers.AddRange( newNumberList );
                numberService.RockContext.SaveChanges();
                personService.RockContext.SaveChanges();

                var attributeValueService = new AttributeValueService();
                foreach ( var updatedPerson in updatedPersonList.Where( p => p.Attributes.Any() ) )
                {
                    foreach ( var attributeCache in updatedPerson.Attributes.Select( a => a.Value ) )
                    {
                        var newValue = updatedPerson.AttributeValues[attributeCache.Key].FirstOrDefault();
                        if ( newValue != null )
                        {
                            newValue.EntityId = updatedPerson.Id;
                            attributeValueService.RockContext.AttributeValues.Add( newValue );
                        }
                    }
                }

                attributeValueService.RockContext.SaveChanges();
            } );

            ReportProgress( 100, string.Format( "Finished communication import: {0:N0} records imported.", completed ) );
        }