HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: //home/arjun/projects/buyercall_new/buyercall/buyercall/blueprints/contacts/views.py
import logging as log
import csv
import json
import uuid
import re
import sys
import traceback
from pytz import timezone
from io import StringIO
from html import unescape
from contextlib import closing
from datetime import date, timedelta
from datetime import datetime
from dateutil import rrule
from collections import OrderedDict
from buyercall.blueprints.filters import format_phone_number
from buyercall.lib.util_crypto import AESCipher
from flask import (
    Blueprint,
    request,
    flash,
    url_for,
    send_file,
    jsonify,
    redirect,
    make_response,
    render_template,
    current_app as app)
from sqlalchemy import extract, or_, and_, desc, func, text, distinct
from sqlalchemy.orm import contains_eager, load_only
from flask_login import login_required, current_user
from flask_babel import gettext as _
from buyercall.extensions import csrf
from buyercall.extensions import db
from .forms import ContactForm, ContactVehicleForm, ContactNoteForm
from .models import Contact, ContactNotes, Lead, Message, CreditReports, Campaigns, BdcStatuses, Status, \
    MarketingSources, ContactVehicle
from buyercall.blueprints.form_leads.models import FormLead, ExternalForm, FormLeadField
from buyercall.blueprints.agents.models import Agent
from buyercall.blueprints.billing.decorators import subscription_required
from buyercall.lib.util_wtforms import choices_from_dict
from buyercall.blueprints.widgets.bw_outbound import agent_manual_outbound_call
from buyercall.blueprints.activity.models import ActivityType, ActivityName, ActivityLogs

contacts = Blueprint('contacts', __name__, template_folder='templates')
log = log.getLogger(__name__)

email_regex = re.compile(r'\S+@\S+\.\S+')
phone_regex = re.compile(r'^\+?[0-9]{10,12}$')

ALLOWED_EXTENSIONS = {'csv'}


def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


# Searches the statuses dictionary for the correct key
def get_call_status_key(status_value):
    result = ''
    status_value = status_value.replace('_', ' ')

    for k, v in Contact.STATUSES.items():
        if k == status_value:
            result = k
    return result


# Searches the sources dictionary for the correct key
def get_marketing_source_key(source_value):
    result = ''
    source_value = source_value.replace('_', ' ')

    for k, v in Contact.MARKETING_SOURCES.items():
        if k == source_value:
            result = k
    return result


def days_between(d1, d2):
    d1 = datetime.strptime(d1, "%m%d%Y")
    d2 = datetime.strptime(d2, "%m%d%Y")
    return abs((d2 - d1).days)


def getboolean(param):
    if param == 'true' or param == 'True':
        return True
    else:
        return False


def valid_csv_value(value):
    result = True

    if value:
        if '<--invalid' in value.lower():
            result = False

    return result


def is_do_not_call_csv_value(value):
    result = False

    if value:
        value = value.lower()

        if 'dnc list - don''t contact' in value:
            result = True
        elif 'don''t contact' in value:
            result = True
        elif 'do not contact' in value:
            result = True
        elif 'don''t call' in value:
            result = True
        elif 'do not call' in value:
            result = True
        elif 'true' in value:
            result = True

    return result


def validate_contact(row, firstname, lastname, phonenumber, email, phone_list):
    lead_details = []
    error_message = ""
    missing = []

    if firstname is None or firstname == '':
        missing.append('firstname')
        lead_details.append('')
    else:
        lead_details.append(firstname)

    if lastname is None or lastname == '':
        missing.append('lastname')
        lead_details.append('')
    else:
        lead_details.append(lastname)

    if email is None or email == '':
    #    missing.append('email')
        lead_details.append('')
    else:
        lead_details.append(email)

    if phonenumber is None or phonenumber == '' or phonenumber == "+1":
        missing.append('phonenumber')
        lead_details.append('')
    else:
        lead_details.append(phonenumber)
        test_number = phonenumber\
            .replace(" ", "")\
            .replace("(", "")\
            .replace(")", "")\
            .replace("-", "")\
            .replace("+", "")

        if not phone_regex.match(test_number):
            error_message += "Phonenumber " + phonenumber + " is invalid. "
        elif test_number in phone_list or phonenumber in phone_list:
            error_message += "Phonenumber " + phonenumber + " already exists. "

    if len(missing) > 0:
        error_message = error_message + "Required field(s) are missing: "
        count = 0

        for miss in missing:
            count += 1
            error_message = error_message + miss

            if count < len(missing):
                error_message += "; "
            else:
                error_message += "."

    if error_message and error_message is not "":
        lead_details.append(error_message)
        lead_details.insert(0, str(row))
    else:
        lead_details = None

    return lead_details


@contacts.route('/api/contacts/message/<int:lead_id>', methods=['GET'])
@login_required
@csrf.exempt
def get_lead_message_info(lead_id):
    """ Return this lead's message information in JSON format, with the following
    fields:

    - agentNumber: The phone number of the agent used to call the lead.
    - routingNumber: The routing number used to call the lead.
    - allAgentNumbers: An array of all agent numbers for this user.
    - allRoutingNumbers: An array of all routing numbers for this user.

    The numbers should be returned in E.123 format.
    """
    from buyercall.blueprints.phonenumbers.models import Phone

    routing_number = ''
    display_agents = False
    agent_list = []
    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    contact = Contact.query.filter(
        Contact.partnership_account_id == partnership_account_id, Contact.id == lead_id
    ).first()

    if not contact:
        return ''

    # retrieve specific message details
    message = Phone.query.join(Message)\
        .filter(and_(Message.contact_id == contact.id, Message.partnership_account_id == partnership_account_id))\
        .order_by(Message.updated_on.desc()).first()

    if message is not None:
        routing_number = message.phonenumber

    routings = Phone.query.filter(and_(
        Phone.partnership_account_id == partnership_account_id,
        Phone.active,
        Phone.is_deactivated == False
    )).all()
    processsed_routing_list = []

    for route in routings:
        if route.routing_config:
            if route.routing_config.get('configSMSSetup', ''):
                processsed_routing_list.append(route)

    routing_nos = [
        {
            "friendlyName": '{} ({})'.format(x.friendly_name, x.phonenumber),
            "number": x.id
        } for x in processsed_routing_list
    ]

    if partnership_account_group_viewing:
        if current_user.partnership_account_id != partnership_account_id:
            display_agents = True

            agent_list = [(g.id, g.full_name) for g in Agent.query.filter(
                Agent.partnership_account_id == partnership_account_id,
                Agent.is_deactivated.is_(False)
            ).distinct().order_by('firstname')]

    return jsonify({
        "routingNumber": routing_number,
        "allRoutingNumbers": routing_nos,
        "agentView": display_agents,
        "agents": agent_list,
        "phonenumber": contact.phonenumber_1,
        "name": contact.name
    })


@contacts.route('/contacts/campaigns', methods=['GET'])
@login_required
@csrf.exempt
def get_partnership_account_campaigns():
    default_campaign = False
    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    campaign_list, default_campaign = Campaigns.get_assigned_campaign_list_as_dict(partnership_account_id)

    return jsonify({
        "default_campaign": default_campaign,
        "campaigns": campaign_list
    })


@contacts.route('/contacts/campaigns', methods=['POST'])
@login_required
@csrf.exempt
def set_partnership_account_campaigns():
    result = False
    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    campaign_id = request.args.get('id', '')
    campaign_text = request.args.get('text', '')

    if (int(campaign_id) < 0):
        result = Campaigns.add_campaign(campaign_text, partnership_account_id)
    else:
        result = Campaigns.update_campaign(campaign_id, campaign_text, partnership_account_id)

    return jsonify({
        "result": result
    })


@contacts.route('/contacts/contact/<int:id>', methods=['GET', 'POST'])
@login_required
def contact_lead_page(id):
    partnership_account_id = current_user.partnership_account_id
    is_admin_in_group = current_user.is_admin_user_with_groups
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if is_admin_in_group and viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id
    elif not viewing_partnership_account and is_admin_in_group:
        return redirect(url_for('partnership.company_accounts'))

    contact = Contact.query.filter(
        Contact.id == id, Contact.partnership_account_id == partnership_account_id
    ).first()
    if not contact:
        flash('Contact with ID {} not found.'.format(id))
        return redirect(url_for('contacts.contact_list'))

    ActivityLogs.add_log(current_user.id, ActivityType.PAGE, ActivityName.VIEW, request, id)

    from buyercall.blueprints.phonenumbers.models import Phone
    phonenumber = Phone.query.filter(Phone.partnership_account_id == partnership_account_id).first()
    return render_template('contacts/contact_lead_page.jinja2',
                           contact=contact,
                           phonenumber=phonenumber)


@contacts.route('/contacts/edit/<int:id>', methods=['GET', 'POST'])
@login_required
def contact_edit(id):
    partnership_account_id = current_user.partnership_account_id
    is_admin_in_group = current_user.is_admin_user_with_groups
    viewing_partnership_account = current_user.is_viewing_partnership
    contact_vehicle = None
    is_adf = False

    # Check if being viewed by super partner
    if is_admin_in_group and viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id
    elif not viewing_partnership_account and is_admin_in_group:
        return redirect(url_for('partnership.company_accounts'))

    # Import the partnership account model
    from ..partnership.models import PartnershipAccount
    partnership_account = PartnershipAccount\
        .query\
        .filter(PartnershipAccount.id == partnership_account_id)\
        .first()

    contact = Contact.query.filter(
        Contact.id == id, Contact.partnership_account_id == partnership_account_id
    ).first()

    if contact:
        contact_vehicle = ContactVehicle.query.filter(ContactVehicle.contact_id == contact.id).first()
        if contact.external_source_type == 'adf_import':
            is_adf = True

    if not contact:
        flash('Contact with ID {} not found.'.format(id))
        return redirect(url_for('contacts.contact_list'))

    if request.method == 'GET':
        args = request.args
        if not args:
            ActivityLogs.add_log(current_user.id, ActivityType.PAGE, ActivityName.VIEW, request, id)

        if not contact.marketing_source:
            contact.marketing_source = 'no source'
        if not contact.bdc_status:
            contact.bdc_status = 'no status'

    form = ContactForm(obj=contact)
    form_vehicle = ContactVehicleForm(obj=contact_vehicle)
    form_note = ContactNoteForm(obj=contact)

    # Get list of agents
    form.agent_assigned.choices = [(g.full_name, g.full_name) for g in Agent.query.filter(
        Agent.partnership_account_id == partnership_account_id,
        Agent.is_deactivated.is_(False)
    ).order_by('firstname')]
    if contact.agent_assigned:
        form.agent_assigned.choices.insert(0, (contact.agent_assigned, contact.agent_assigned))
    form.agent_assigned.choices.insert(0, ('', ''))

    # Get list of bdc statuses
    bdc_status_list = BdcStatuses.get_assigned_status_list(partnership_account_id)
    form.bdc_status.choices = [(s.status, s.display_name) for s in bdc_status_list]

    # Get list of statuses
    status_list = Status.get_assigned_status_list(partnership_account_id)
    form.status.choices = [(s.status, s.display_name) for s in status_list]

    # Get list of marketing sources
    source_list = MarketingSources.get_assigned_source_list(partnership_account_id)
    form.marketing_source.choices = [(ms.source, ms.display_name) for ms in source_list]

    # Get campaign id
    form.campaign_id = contact.campaign_id

    # Get voi status
    form_vehicle.interest_status.choices = ['', 'new', 'used']

    # Get vehicle conditions
    form_vehicle.interest_condition.choices = ['', 'excellent', 'good', 'fair', 'poor', 'unknown']
    form_vehicle.current_condition.choices = ['', 'excellent', 'good', 'fair', 'poor', 'unknown']

    if form.validate_on_submit():
        form.populate_obj(contact)

        if contact.campaign_id == str(-1) or contact.campaign_id == "":
            contact.campaign_id = None

        # Lookup Agent id to save to the contacts.agent_id field
        old_agent_id = contact.agent_id
        agent_id = Agent.reverse_agent_id_lookup(partnership_account_id, contact.agent_assigned)
        contact.agent_id = agent_id

        # Save the fields to the contact table
        ActivityLogs.add_log(current_user.id, ActivityType.PAGE, ActivityName.EDIT, request, id)
        contact.save()
        # Current Vehicle and Vehicle of Interest fields
        edit_current_year = form_vehicle.data['current_year']
        if edit_current_year and edit_current_year == 0:
            edit_current_year = None

        edit_interest_year = form_vehicle.data['interest_year']
        if edit_interest_year and edit_interest_year == 0:
            edit_interest_year = None
        if partnership_account.business_type == 'automotive':
            if contact_vehicle:
                ContactVehicle.update(contact_id=contact.id,
                                      current_vin=form_vehicle.data['current_vin'],
                                      current_make=form_vehicle.data['current_make'],
                                      current_model=form_vehicle.data['current_model'],
                                      current_year=edit_current_year,
                                      current_mileage=form_vehicle.data['current_mileage'],
                                      current_condition=form_vehicle.data['current_condition'],
                                      current_value=form_vehicle.data['current_value'],
                                      interest_vin=form_vehicle.data['interest_vin'],
                                      interest_make=form_vehicle.data['interest_make'],
                                      interest_model=form_vehicle.data['interest_model'],
                                      interest_year=edit_interest_year,
                                      interest_trim=form_vehicle.data['interest_trim'],
                                      interest_stock=form_vehicle.data['interest_stock'],
                                      interest_price=form_vehicle.data['interest_price'],
                                      interest_status=form_vehicle.data['interest_status'],
                                      interest_mileage=form_vehicle.data['interest_mileage'],
                                      interest_condition=form_vehicle.data['interest_condition'],
                                      interest_listing_url=form_vehicle.data['interest_listing_url']
                                      )
            else:
                ContactVehicle.create(contact_id=contact.id,
                                      current_vin=form_vehicle.data['current_vin'],
                                      current_make=form_vehicle.data['current_make'],
                                      current_model=form_vehicle.data['current_model'],
                                      current_year=edit_current_year,
                                      current_mileage=form_vehicle.data['current_mileage'],
                                      current_condition=form_vehicle.data['current_condition'],
                                      current_value=form_vehicle.data['current_value'],
                                      interest_vin=form_vehicle.data['interest_vin'],
                                      interest_make=form_vehicle.data['interest_make'],
                                      interest_model=form_vehicle.data['interest_model'],
                                      interest_year=edit_interest_year,
                                      interest_trim=form_vehicle.data['interest_trim'],
                                      interest_stock=form_vehicle.data['interest_stock'],
                                      interest_price=form_vehicle.data['interest_price'],
                                      interest_status=form_vehicle.data['interest_status'],
                                      interest_mileage=form_vehicle.data['interest_mileage'],
                                      interest_condition=form_vehicle.data['interest_condition'],
                                      interest_listing_url=form_vehicle.data['interest_listing_url']
                                      )
        # Update status across contact and lead
        if current_user.is_bdc_user:
            Contact.update_status(contact.id, None, form.data['status'], partnership_account_id, False)

        if contact.agent_id != old_agent_id:
            from buyercall.blueprints.mobile.utils import send_agent_push_notification
            send_agent_push_notification(contact)
        try:
            form_leads = FormLead.query.filter(FormLead.contact_id == contact.id).all()
            for form_lead in form_leads:
                lead_fields = FormLeadField.query.filter(
                    and_(FormLeadField.lead_id == form_lead.id, FormLeadField.field_id == 'repfield')
                ).first()
                lead_fields.field_value = contact.agent_assigned
                db.session.commit()
        except Exception as e:
            log.error('No form leads available for the contact. Error: ' + str(sys.exc_info()[0]))

    if form_note.validate_on_submit():
        form_note.populate_obj(contact)
        contact_form_note = contact.notes
        contact.notes = ""
        contact.save()
        notequery = ''

        if form.edited_notes_str.data is not None:
            notequery = str(unescape(form.edited_notes_str.data))

        db.session.commit()

        if len(str(contact_form_note)) > 0:
            note = {
                'text': contact_form_note,
                'contact_id': contact.id,
                'created_on': datetime.now(),
                'updated_on': datetime.now(),
                'user_id': int(current_user.id),
                'is_enabled': True,
                'partnership_account_id': int(partnership_account_id)
            }
            result = ContactNotes.create(note)
        else:
            result = True

        if len(notequery) > 0:
            noteobject = json.loads(notequery)

            for lpnote in noteobject:

                _lpresult = ContactNotes.update(
                    int(lpnote["id"]),
                    str(lpnote["newtext"]),
                    datetime.now(),
                    int(current_user.id),
                    getboolean(str(lpnote["isenabled"]))
                )

        if result:
            flash(_('The contact has been updated successfully.'), 'success')
            return redirect(url_for('contacts.contact_edit', id=contact.id, redirect='true'))

    # Return all calls for this contact
    previous_calls = Lead.query.filter(
        Lead.partnership_account_id == partnership_account_id,
        Lead.contact_id == contact.id
    ).options(
        load_only("firstname", "lastname", "starttime", "call_type", "status")
    ).order_by(text('starttime desc')).limit(10).all()

    # Return the number of calls for this contact
    previous_calls_count = Lead.query.filter(
        Lead.partnership_account_id == partnership_account_id,
        Lead.contact_id == contact.id
    ).count()

    # Return all messages for this contact
    previous_messages_raw = Message.query.filter(
        Message.partnership_account_id == partnership_account_id,
        Message.contact_id == contact.id
    ).order_by(text('messages.created_on desc')).limit(100).all()
    previous_messages = []
    for msg in previous_messages_raw:
        if msg.media_url and msg.media_url[:1] == '[':
            bracket_msg_list = str(msg.media_url).replace("[", "").replace("]", "").replace(" ", "")
            bracket_msg_list_split = bracket_msg_list.split(",")
            msg.media_url = bracket_msg_list_split
            previous_messages.append(msg)
        elif msg.media_url and msg.media_url[:1] == '{':
            replace_msg_str = str(msg.media_url).replace("{", "").replace("}", "").replace(" ", "")
            media_str_links = replace_msg_str.split(",")
            msg.media_url = media_str_links
            previous_messages.append(msg)
        elif msg.media_url and msg.media_url[:1] not in ['[', '{']:
            single_link = str(msg.media_url).split(",")
            single_link_list = []
            for s in single_link:
                single_link_list.append(s)
            msg.media_url = single_link_list
            previous_messages.append(msg)
        else:
            previous_messages.append(msg)

    # Return the number of messages for this contact
    previous_message_count = Message.query.filter(
        Message.partnership_account_id == partnership_account_id,
        Message.contact_id == contact.id
    ).count()

    # Return all form lead for this contact
    previous_forms = FormLead.query.filter(
        FormLead.partnership_account_id == partnership_account_id,
        FormLead.contact_id == contact.id
    ).order_by(text('form_leads.created_on desc')).limit(10).all()

    # Return the number of form lead for this contact
    previous_form_count = FormLead.query.filter(
        FormLead.partnership_account_id == partnership_account_id,
        FormLead.contact_id == contact.id
    ).count()

    # Return the contact notes of this contact
    all_contact_notes = ContactNotes.query.join(Contact).filter(
        contact.id == ContactNotes.contact_id,
        contact.partnership_account_id == partnership_account_id,
        ContactNotes.is_enabled == 't'
        ).order_by(desc(ContactNotes.created_on)).all()

    # Import the partnership account model for credit tie
    from ..partnership.models import PartnershipAccountCreditTie, PartnershipCreditTie
    # Return the credentials for an account based on the credit product type
    credit_credentials = PartnershipAccountCreditTie.partner_account_seven_hundred_credit_info(
        current_user.partnership_account_id,
        'credit'
    )
    account_prequalify_provider = PartnershipAccountCreditTie.query\
        .filter(and_(PartnershipAccountCreditTie.partnership_account_id == current_user.partnership_account_id,
                     PartnershipAccountCreditTie.active.is_(True),
                     PartnershipAccountCreditTie.product_type == 'prequalify')).first()
    if account_prequalify_provider is not None and account_prequalify_provider.service_provider != 'offerlogix':
        # Return the credentials for an account based on the prequalify product type
        prequalify_credentials = PartnershipAccountCreditTie.partner_account_seven_hundred_credit_info(
            current_user.partnership_account_id,
            'prequalify'
        )

        if not prequalify_credentials:
            prequalify_credentials = PartnershipCreditTie.\
                partner_finserv_credit_info(current_user.partnership_id, 'prequalify')
    else:
        prequalify_credentials = account_prequalify_provider

    # Return the credit reports for this contact
    credit_reports = CreditReports.contact_credit_score_object(contact.id, partnership_account_id)
    xpn_credit = 0
    xpn_prequalify = 0
    tu_credit = 0
    tu_prequalify = 0
    eq_credit = 0
    eq_prequalify = 0
    for report in credit_reports:
        if report.credit_bureau == 'experian' and report.product_type == 'credit' and report.is_successful:
            xpn_credit = xpn_credit + 1
        elif report.credit_bureau == 'experian' and report.product_type == 'prequalify' and report.is_successful:
            xpn_prequalify = xpn_prequalify + 1
        if report.credit_bureau == 'transunion' and report.product_type == 'credit' and report.is_successful:
            tu_credit = tu_credit + 1
        elif report.credit_bureau == 'transunion' and report.product_type == 'prequalify' and report.is_successful:
            tu_prequalify = tu_prequalify + 1
        if report.credit_bureau == 'equifax' and report.product_type == 'credit' and report.is_successful:
            eq_credit = eq_credit + 1
        elif report.credit_bureau == 'equifax' and report.product_type == 'prequalify' and report.is_successful:
            eq_prequalify = eq_prequalify + 1

    # Return the credit report count for this contact
    credit_report_count = CreditReports.contact_credit_report_count(contact.id, partnership_account_id)

    # Get the current user
    user_id = current_user.id

    # Check to see if enough data is available to run a credit prequalification
    if not contact.firstname or not contact.lastname or not contact.address_1 or not contact.city \
            or not contact.state or not contact.zip:
        credit_pull_able = False
    else:
        credit_pull_able = True

    # Get available forms forms
    forms_result = {}
    forms_list = ExternalForm\
        .query\
        .filter(ExternalForm.partnership_account_id == partnership_account_id,
                ExternalForm.is_deactivated == False)\
        .all()
    for item in forms_list:
        form_id = item.id
        forms_result[form_id] = item.display_name

    supervisor_user_business_type = None
    from buyercall.lib.supervisor_manager import current_supervisor_user
    if current_supervisor_user and current_supervisor_user.is_authenticated:
        partner_id = current_supervisor_user.partnership_id

        if partner_id:
            from ..partnership.models import Partnership
            supervisor_user_partnership = Partnership.query.filter(Partnership.id == partner_id).first()
            if supervisor_user_partnership and supervisor_user_partnership.business_type:
                supervisor_user_business_type = supervisor_user_partnership.business_type
        elif current_supervisor_user.role == 'limitsysadmin':
            supervisor_user_business_type = 'automotive'

    return render_template('contacts/edit.jinja2',
                           bdc_status_user=current_user.is_bdc_user,
                           business_type=partnership_account.business_type,
                           contact=contact,
                           contact_notes=all_contact_notes,
                           credit_credentials=credit_credentials,
                           credit_pull_able=credit_pull_able,
                           credit_report_log=credit_reports,
                           credit_report_count=credit_report_count,
                           eq_credit=eq_credit,
                           eq_prequalify=eq_prequalify,
                           form=form,
                           form_log=previous_forms,
                           form_log_count=previous_form_count,
                           form_vehicle=form_vehicle,
                           forms_choice=choices_from_dict(forms_result, prepend_blank=False),
                           is_adf=is_adf,
                           message_log=previous_messages,
                           message_log_count=previous_message_count,
                           phone_log=previous_calls,
                           phone_log_count=previous_calls_count,
                           prequalify_credentials=prequalify_credentials,
                           supervisor_user_business_type=supervisor_user_business_type,
                           total_calls=previous_calls_count,
                           total_messages=previous_message_count,
                           total_forms=previous_form_count,
                           tu_credit=tu_credit,
                           tu_prequalify=tu_prequalify,
                           user_id=user_id,
                           xpn_credit=xpn_credit,
                           xpn_prequalify=xpn_prequalify
                           )


@contacts.route('/contacts/pdf/<int:id>', methods=['GET', 'POST'])
@login_required
@subscription_required
def contact_pdf(id):
    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    contact = Contact.query.filter(
        Contact.id == id, Contact.partnership_account_id == partnership_account_id
    ).first()
    if not contact:
        flash('Contact with ID {} not found.'.format(id))
        return redirect(url_for('contacts.contact_list'))

    # Return the partnership account name
    from buyercall.blueprints.partnership.models import PartnershipAccount
    account = PartnershipAccount.query.filter(PartnershipAccount.id == contact.partnership_account_id).first()

    # Return current day's date
    import datetime
    today = datetime.date.today()
    today_str = today.strftime('%b, %d %Y')

    if contact.form_leads:
        max_field = None

        for field in contact.form_leads:
            if max_field is None and field.updated_datetime is not None:
                max_field = field
            elif field.updated_datetime > max_field.updated_datetime:
                max_field = field

        form_lead_id = max_field.id
        log.info("The contact leads form lead id is {}:".format(field.id))
        return redirect(url_for('form_leads.leads_pdf', lead_id=form_lead_id))
    else:
        from .contact_tasks import generate_pdf
        ActivityLogs.add_log(current_user.id, ActivityType.DATA, ActivityName.PDF, request, id)
        return generate_pdf(contact.id, account.name, contact, today_str, account.business_type)


@contacts.route('/contacts')
@login_required
def contact_list():
    from buyercall.blueprints.phonenumbers.models import Phone

    partnership_account_id = current_user.partnership_account_id
    is_admin_in_group = current_user.is_admin_user_with_groups
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if is_admin_in_group and viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id
    elif not viewing_partnership_account and is_admin_in_group:
        return redirect(url_for('partnership.company_accounts'))

    phonenumber = Phone.query.filter(Phone.partnership_account_id == partnership_account_id).first()
    total_contacts = Contact.query.filter(Contact.partnership_account_id == partnership_account_id).count()
    total_notes = ContactNotes.query.filter(ContactNotes.partnership_account_id == partnership_account_id).count()

    # Import the partnership account model
    from ..partnership.models import PartnershipAccount
    partnership_account = PartnershipAccount\
        .query\
        .filter(PartnershipAccount.id == partnership_account_id)\
        .first()

    # Get available forms forms
    forms_result = {}
    forms_list = ExternalForm\
        .query\
        .filter(ExternalForm.partnership_account_id == partnership_account_id,
                ExternalForm.is_deactivated == False)\
        .all()
    for item in forms_list:
        form_id = item.id
        forms_result[form_id] = item.display_name

    # Populate bdc status result
    bdc_status_result = {}
    bdc_status_list = BdcStatuses.get_assigned_status_list(partnership_account_id)
    for item in bdc_status_list:
        status_id = item.status
        bdc_status_result[status_id] = item.display_name

    # Populate status result
    status_result = {}
    status_list = Status.get_assigned_status_list(partnership_account_id)
    for item in status_list:
        status_id = item.status
        status_result[status_id] = item.display_name

    # Populate marketing result
    marketing_result = {}
    marketing_list = MarketingSources.get_assigned_source_list(partnership_account_id)
    for item in marketing_list:
        marketing_id = item.source
        marketing_result[marketing_id] = item.display_name

    supervisor_user_business_type = None
    from buyercall.lib.supervisor_manager import current_supervisor_user
    if current_supervisor_user and current_supervisor_user.is_authenticated:
        partner_id = current_supervisor_user.partnership_id

        if partner_id:
            from ..partnership.models import Partnership
            supervisor_user_partnership = Partnership.query.filter(Partnership.id == partner_id).first()
            if supervisor_user_partnership and supervisor_user_partnership.business_type:
                supervisor_user_business_type = supervisor_user_partnership.business_type
        elif current_supervisor_user.role == 'limitsysadmin':
            supervisor_user_business_type = 'automotive'

    if not partnership_account:
        flash(_('You do not have permission to access this page. Please try again.'), 'danger')
        return redirect(url_for('user.settings'))

    return render_template('contacts/contacts.jinja2',
                            forms_choice=choices_from_dict(forms_result, prepend_blank=False),
                            supervisor_user_business_type=supervisor_user_business_type,
                            business_type=partnership_account.business_type,
                            status_choice=choices_from_dict(status_result, prepend_blank=False),
                            bdc_status_user=current_user.is_bdc_user,
                            bdc_status_choice=choices_from_dict(bdc_status_result, prepend_blank=False),
                            marketing_source=choices_from_dict(marketing_result, prepend_blank=False),
                            phonenumber=phonenumber,
                            total_contacts=total_contacts,
                            import_leads=partnership_account.import_leads,
                            total_notes=total_notes)


@contacts.route('/contacts/data')
@csrf.exempt
@login_required
def data():
    """Return server side data."""
    phone_list = []
    lead_list = []
    form_list = []
    message_list = []
    filtered_contact_list = []
    filtered_phone_list = []
    filtered_message_list = []
    filtered_form_list = []

    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    search = request.args.get('search[value]', '')
    order = int(request.args.get('order[0][column]', '-1'))
    direction = request.args.get('order[0][dir]', 'asc')
    offset = int(request.args.get('start', 0))
    limit = int(request.args.get('length', 99))

    date_from = str(request.args.get('df'))
    date_to = str(request.args.get('dt'))
    assigned_agent = (request.args.get('aa'))
    form_check = str(request.args.get('stf'))
    phone_check = str(request.args.get('stp'))
    sms_check = str(request.args.get('sts'))
    import_check = str(request.args.get('sis'))
    api_check = str(request.args.get('sas'))
    adf_import_check = str(request.args.get('sais'))
    phone_source = str(request.args.get('ps'))
    sms_source = str(request.args.get('ms'))
    marketing_source = str(request.args.get('mks'))
    form_source = str(request.args.get('fs'))
    call_status = str(request.args.get('cs'))
    call_bdc_status = str(request.args.get('cbs'))
    date_difference = days_between(date_from, date_to)

    # filter initiation section - check box filter
    filter_by_phone_check = text('')
    filter_by_sms_check = text('')
    filter_by_form_check = text('')
    all_check = False

    # filter initiation section - external source type filters
    filter_by_api_check = text('')
    filter_by_adf_import_check = text('')
    filter_by_import_check = text('')

    # filter initiation section - drop down filters
    filter_by_assigned_agent = text('')
    filter_by_form = text('')
    filter_by_call_status = text('')
    filter_by_call_bdc_status = text('')
    filter_by_marketing_source = text('')
    filter_by_assigned_agent_id = text('')
    assigned_agent_id = -1

    # filter initiation section - source
    filter_by_phone_source = text('')
    filter_by_sms_source = text('')
    filter_by_sms_inbound_source = text('')
    filter_by_form_source = text('')
    filter_by_phone_complete_source = text('')
    filter_by_sms_complete_source = text('')
    filter_by_form_complete_source = text('')

    # set the date filters
    converted_dateFrom = datetime.strptime(date_from, "%m%d%Y").replace(tzinfo=timezone('UTC'))
    converted_dateTo = datetime.strptime(date_to, "%m%d%Y").replace(tzinfo=timezone('UTC'))
    filter_by_date = and_(
        func.date(Contact.updated_on) >= converted_dateFrom,
        func.date(Contact.updated_on) <= converted_dateTo
    )
    lead_filter_by_date = and_(
        func.date(Lead.created_on) >= converted_dateFrom,
        func.date(Lead.created_on) <= converted_dateTo
    )
    message_filter_by_date = and_(
        func.date(Message.created_on) >= converted_dateFrom,
        func.date(Message.created_on) <= converted_dateTo
    )
    form_filter_by_date = and_(
        func.date(FormLead.created_on) >= converted_dateFrom,
        func.date(FormLead.created_on) <= converted_dateTo
    )

    # set the data permission restrictions
    filter_by = (Contact.partnership_account_id == partnership_account_id)

    # Lead phone number filter section
    if phone_source and phone_source != 'null' and phone_source != 'None':
        if phone_source.count('-') == 4:
            filter_by_phone_source = text("widgets.guid = '" + phone_source + "'")
        else:
            filter_by_phone_source = text("phonenumbers.id = " + phone_source)
        phone_list = Lead.query.outerjoin(Lead.widget).outerjoin(Lead.inbound).options(
            contains_eager(Lead.widget).load_only('id', 'name'),
            contains_eager(Lead.inbound).load_only('id', 'friendly_name'),
         ).join(Contact).filter(filter_by)\
            .filter(filter_by_phone_source)\
            .with_entities('leads.contact_id')\
            .distinct().all()
        if phone_list is not None:
            filter_by_phone_complete_source = and_(Contact.id.in_(phone_list))

    # Message filter section
    if sms_source and sms_source != 'null' and sms_source != 'None':
        filter_by_sms_source = text("phonenumbers.id = {}".format(sms_source))
        filter_by_sms_inbound_source = (Message.inbound_id == sms_source)
        message_list = Message.query.outerjoin(
            Message.inbound
        ).options(
            contains_eager(Message.inbound).load_only('id'),
         ).join(
            Contact
        ).filter(filter_by).filter(
            filter_by_sms_source
        ).with_entities('messages.contact_id').distinct().all()
        if message_list is not None:
            filter_by_sms_complete_source = and_(Contact.id.in_(message_list))

    # Form lead filter section
    if form_source and form_source != 'null' and form_source != 'None':
        filter_by_form = text("form_leads.id = {}".format(form_source))
        filter_by_form_source = text("external_forms.id = {}".format(form_source))
        form_list = FormLead.query.outerjoin(
            FormLead.form
        ).options(
            contains_eager(FormLead.form).load_only('id'),
        ).join(Contact)\
            .filter(filter_by)\
            .filter(filter_by_form_source)\
            .with_entities('form_leads.contact_id')\
            .distinct().all()
        if form_list is not None:
            filter_by_form_complete_source = and_(Contact.id.in_(form_list))

    # Assigned agent filter section
    if assigned_agent != 'null' and assigned_agent:
        formatted_assigned_agent = assigned_agent.replace("'", "''")
        filter_by_assigned_agent = and_(text("contacts.agent_assigned = '" + formatted_assigned_agent + "'"))
        assigned_agent_id = Agent.query\
            .filter(and_(Agent.partnership_account_id == partnership_account_id, Agent.full_name.like(assigned_agent)))\
            .with_entities('id')\
            .first()
        if assigned_agent_id is not None:
            filter_by_assigned_agent_id = and_(text("leads.agent_assigned_id = " + str(assigned_agent_id[0])))

    # Form check filter section
    if form_check == '1' or form_check == 1:
        filter_by_form_check = and_(Contact.form_count > 0)

    # Message check filter section
    if sms_check == '1' or sms_check == 1:
        filter_by_sms_check = and_(Contact.sms_count > 0)

    # Phone check filter section
    if phone_check == '1' or phone_check == 1:
        filter_by_phone_check = and_(Contact.phone_count > 0)

    if (
            (form_check == '1' or form_check == 1) and (sms_check == '1' or sms_check == 1)
            and (phone_check == '1' or phone_check == 1)
    ) or (
            (form_check == '0' or form_check == 0) and (sms_check == '0' or sms_check == 0)
            and (phone_check == '0' or phone_check == 0)
    ):
        all_check = True

    # Call status filter section
    if call_status != 'null' and call_status:
        filter_by_call_status = and_(text("contacts.status = '{}'".format(call_status)))

    # Call status filter section
    if current_user.is_bdc_user and call_bdc_status != 'null' and call_bdc_status:
        filter_by_call_bdc_status = and_(text("contacts.bdc_status = '{}'".format(call_bdc_status)))

    # Marketing source filter section
    if marketing_source != 'null' and marketing_source:
        if marketing_source == 'no_source':
            formatted_marketing_source = marketing_source.replace("'", "''")
            filter_by_marketing_source = and_(
                or_(text("contacts.marketing_source = '" + formatted_marketing_source + "'"),
                    text("contacts.marketing_source = '""'")))
        else:
            filter_by_marketing_source = and_((text("contacts.marketing_source = '" + marketing_source + "'")))

    # Source type - API
    if api_check == '1' or api_check == 1:
        filter_by_api_check = and_(Contact.external_source_type == 'api')

    # Source type - ADF Import
    if adf_import_check == '1' or adf_import_check == 1:
        filter_by_adf_import_check = and_(Contact.external_source_type == 'adf_import')

    # Source type - Import
    if import_check == '1' or import_check == 1:
        filter_by_import_check = and_(Contact.external_source_type == 'import')

    # define data columns for the searching data view window
    columns_search = [
        Contact.id,
        Contact.firstname,
        Contact.lastname,
        Contact.phonenumber_1,
        Contact.email,
        Status.status,
        Contact.agent_assigned
    ]

    # define data columns for the shifting data view window
    columns_window = [
        Contact.id,
        Contact.firstname,
        Contact.phonenumber_1,
        Contact.email,
        Contact.source,
        Contact.created_on,
        Contact.updated_on,
        Status.status,
        Contact.agent_assigned,
        Contact.credit_score,
        #Contact.phone_source,
        Contact.lastname
        #Contact.caller_id
    ]

    # define data columns for the counts
    columns_total = [
        Contact.id
    ]

    # define/execute main query
    total = Contact.query\
        .join(Status, Contact.status == Status.status) \
        .filter(filter_by) \
        .filter(filter_by_date) \
        .filter(filter_by_sms_check) \
        .filter(filter_by_phone_check)\
        .filter(filter_by_form_check)\
        .filter(filter_by_call_status) \
        .filter(filter_by_call_bdc_status) \
        .filter(filter_by_marketing_source) \
        .filter(filter_by_assigned_agent) \
        .filter(filter_by_phone_complete_source)\
        .filter(filter_by_sms_complete_source)\
        .filter(filter_by_form_complete_source)\
        .filter(filter_by_api_check) \
        .filter(filter_by_adf_import_check) \
        .filter(filter_by_import_check)

    filtered = total

    # Remove this searching due to issues with db encrypted field.
    #if search:
    #    pattern = '%{}%'.format(search)
    #    filtered = total.filter(or_(
    #        Contact.name.ilike(pattern),
    #        Contact.phonenumber_1.ilike(pattern),
    #        Contact.email.ilike(pattern),
    #        Contact.status.ilike(pattern),
    #        Contact.agent_assigned.ilike(pattern),
    #        Contact.source.ilike(pattern)
    #    ))
    # New searching functionality that works with encrypted fields
    if search:
        total_list = total.with_entities(*columns_search).all()
        searched_result_list = [x for x in total_list
                                if x.firstname.lower() + ' ' + x.lastname.lower() == search.lower()
                                or x.email.lower() == search.lower()
                                or x.firstname.lower() == search.lower()
                                or x.lastname.lower() == search.lower()
                                or x.phonenumber_1 == search
                                or x.status.lower() == search.lower()
                                or x.agent_assigned == search]
        searched_result_ids = [x.id for x in searched_result_list]
        filtered = Contact.query.join(Status, Contact.status == Status.status)\
            .filter(Contact.id.in_(searched_result_ids))

    sorted_ = filtered.with_entities(*columns_window)

    if order in range(len(columns_window)):
        order_pred = columns_window[order]
        if direction == 'desc':
            order_pred = desc(order_pred)
        sorted_ = sorted_.order_by(order_pred)
    sorted_ = sorted_.offset(offset).limit(limit)

    data = [
        {i: row[i] for i in range(len(row))
         } for row in sorted_.all()
        ]

    for lp_data in data:
        if lp_data[9] is not None:
            encrypt_key = app.config['CRYPTO_SECRET_KEY']
            cipher = AESCipher(encrypt_key)
            lp_data[9] = cipher.decrypt(lp_data[9])
        else:
            lp_data[9] = 'Unknown'

    # set specific columns for the total count
    filtered_total = filtered.with_entities(*columns_total)

    for c in filtered_total.all():
        filtered_contact_list.append(c[0])

    # total lead count
    total_leads = len(filtered_contact_list)

    # total call count
    if phone_check == '1' or phone_check == 1 or all_check:
        phone_query = Lead.query.outerjoin(
            Lead.widget
        ).outerjoin(
            Lead.inbound
        ).options(
            contains_eager(Lead.widget).load_only('id', 'name'),
            contains_eager(Lead.inbound).load_only('id', 'friendly_name')
         ).filter(Lead.partnership_account_id == partnership_account_id)\
            .filter(filter_by_phone_source).with_entities(Lead.phonenumber)\
            .filter(lead_filter_by_date)\
            .filter(filter_by_assigned_agent_id)\

        total_phone = phone_query.count()
        total_unique_phone = phone_query.distinct().count()

        for phone in phone_query.with_entities(Lead.id).all():
            filtered_phone_list.append(phone[0])
    else:
        total_phone = 0
        total_unique_phone = 0

    # total message count
    if sms_check == '1' or sms_check == 1 or all_check:
        messages_query = Message.query\
            .filter(Message.partnership_account_id == current_user.partnership_account_id)\
            .filter(filter_by_sms_inbound_source)\
            .with_entities(Message.from_)\
            .filter(message_filter_by_date)

        if messages_query is not None:
            total_messages = messages_query.count()
            total_unique_messages = messages_query.distinct().count()

            for message in messages_query.with_entities(Message.id).all():
                filtered_message_list.append(message[0])
        else:
            total_messages = 0
            total_unique_messages = 0
    else:
        total_messages = 0
        total_unique_messages = 0

    # total form lead count
    if form_check == '1' or form_check == 1 or all_check:
        form_query = FormLead.query\
            .filter(FormLead.partnership_account_id == partnership_account_id)\
            .filter(form_filter_by_date)\
            .filter(filter_by_form) \
            .filter(FormLead.contact_id > 0)\
            .with_entities(FormLead.form_id)

        total_formleads = form_query.count()
        # total_unique_formleads = form_query.distinct().count()

        for form in form_query.with_entities(FormLead.id).all():
            filtered_form_list.append(form[0])

        total_unique_formleads_query = FormLeadField.query\
            .filter(or_(FormLeadField.field_id == 'phonefield', FormLeadField.field_id == 'phonenumber'))\
            .filter(FormLeadField.lead_id.in_(filtered_form_list)) \
            .with_entities(FormLeadField.field_value).distinct().all()

        total_unique_formleads_list = []

        for i in total_unique_formleads_query:
            if i is not None:
                formatted_phonenumber = format_phone_number(i[0])
                if formatted_phonenumber not in total_unique_formleads_list:
                    total_unique_formleads_list.append(formatted_phonenumber)

        total_unique_formleads = len(total_unique_formleads_list)
    else:
        total_formleads = 0
        total_unique_formleads = 0

    graph_labels = []

    if date_difference <= 31:
        for i in range((converted_dateTo - converted_dateFrom).days + 1):
            graph_labels.append((converted_dateFrom + timedelta(days=i)).strftime('%d/%m'))
    elif 32 <= date_difference <= 366:
        daysLater = converted_dateFrom + timedelta(days=date_difference)
        for dt in rrule.rrule(rrule.MONTHLY, dtstart=converted_dateFrom, until=daysLater):
            graph_labels.append(dt.strftime('%m/%Y'))
    elif date_difference > 366:
        daysLater = converted_dateFrom + timedelta(days=date_difference)
        for dt in rrule.rrule(rrule.YEARLY, dtstart=converted_dateFrom, until=daysLater):
            graph_labels.append(dt.strftime('%Y'))

    graph_leads_points = contact_chart_data(date_difference, converted_dateFrom, converted_dateTo,
                                            filtered_contact_list, graph_labels)
    graph_phone_points = phone_chart_data(date_difference, converted_dateFrom, converted_dateTo,
                                          filtered_phone_list, graph_labels)
    graph_message_points = message_chart_data(date_difference, converted_dateFrom, converted_dateTo,
                                              filtered_message_list, graph_labels)
    graph_form_points = form_chart_data(date_difference, converted_dateFrom, converted_dateTo,
                                        filtered_form_list, graph_labels)

    return jsonify(
        draw=request.args['draw'],
        recordsFiltered=total_leads,
        recordsTotal=total_leads,
        data=data,
        graphLeadPoints=graph_leads_points,
        graphFormPoints=graph_form_points,
        graphMessagePoints=graph_message_points,
        graphPhonePoints=graph_phone_points,
        graphLabels=graph_labels,
        totalLeads=total_leads,
        totalPhone=total_phone,
        totalUniquePhone=total_unique_phone,
        totalMessages=total_messages,
        totalUniqueMessages=total_unique_messages,
        totalFormLeads=total_formleads,
        totalUniqueFormLeads=total_unique_formleads
    )


@contacts.route('/contacts/agents', methods=['GET'])
@csrf.exempt
@login_required
def contact_agents():
    partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    agents = [(g.id, g.full_name) for g in Agent
        .query
        .filter((Agent.partnership_account_id == partnership_account_id),
                Agent.is_deactivated.is_(False))
        .order_by('firstname')]
    return jsonify({
        "agents": agents
    })


@contacts.route('/contacts/details/add', methods=['POST'])
@csrf.exempt
@login_required
def details_add():
    partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership
    missing_message = []
    invalid_message = []
    error_message = []
    success = False

    # Check if being viewed by super partner
    if viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    data = request.get_json()

    if data:
        request_firstname = data.get('firstname')
        request_lastname = data.get('lastname')
        request_status = data.get('status')
        request_marketing_source = data.get('marketing_source')
        request_agent_assigned_id = data.get('agent_assigned_id')
        request_agent_assigned_text = data.get('agent_assigned_text')
        request_phonenumber = data.get('phonenumber')
        request_email = data.get('email')
        request_contact_note = data.get('note')
        request_address_1 = data.get('address1')
        request_address_2 = data.get('address2')
        request_city = data.get('city')
        request_state = data.get('state')
        request_country = data.get('country')
        request_zip = data.get('zip')
        request_birthday = data.get('birthday')
        request_do_not_call = data.get('donotcall')
        request_unsubscribed = data.get('unsubscribed')

        agent_assigned = None
        agent_assigned_id = None

        if not request_firstname:
            missing_message.append('firstname')

        if not request_lastname:
            missing_message.append('lastname')

        if request_email:
            request_email = request_email.lower()

            if not email_regex.match(request_email):
                invalid_message.append('Email is invalid.')

        if not request_phonenumber or request_phonenumber == "+1":
            missing_message.append('phonenumber')
        else:
            request_phonenumber = request_phonenumber.replace(" ", "").replace("(", "").replace(")", "").replace("-", "")
            phonenumber_exists = Contact\
                .query\
                .filter(Contact.partnership_account_id == partnership_account_id)\
                .filter(or_(
                    Contact.phonenumber_1 == format_phone_number(request_phonenumber),
                    Contact.phonenumber_1 == request_phonenumber))\
                .first()

            if phonenumber_exists:
                error_message.append('Phonenumber already exists.')
            elif not phone_regex.match(request_phonenumber):
                invalid_message.append('Phonenumber is invalid.')

        if request_status != "Select status..." and request_status != "":
            request_status = request_status
        else:
            request_status = 'no status'

        if request_marketing_source == "Select marketing source..." or request_marketing_source == "":
            request_marketing_source = 'no source'

        if request_agent_assigned_text != "Select agent..." and request_agent_assigned_text != "":
            agent_assigned = request_agent_assigned_text
            agent_assigned_id = request_agent_assigned_id

        if request_birthday and request_birthday != "":
            try:
                datetime.strptime(request_birthday, '%m/%d/%Y')
            except ValueError:
                invalid_message.append('Birthday is invalid, it should be in mm/dd/yyyy format.')

        if not error_message and not missing_message and not invalid_message:
            new_contact = Contact()
            new_contact.email = request_email
            new_contact.status = request_status
            new_contact.marketing_source = request_marketing_source
            new_contact.firstname = request_firstname
            new_contact.lastname = request_lastname
            new_contact.phonenumber_1 = format_phone_number(request_phonenumber)
            new_contact.agent_assigned = agent_assigned
            new_contact.agent_id = agent_assigned_id
            new_contact.partnership_account_id = partnership_account_id
            new_contact.address_1 = request_address_1
            new_contact.address_2 = request_address_2
            new_contact.city = request_city
            new_contact.state = request_state
            new_contact.country = request_country
            new_contact.zip = request_zip
            new_contact.birthday = request_birthday
            new_contact.is_do_not_call = request_do_not_call
            new_contact.is_unsubscribe = request_unsubscribed
            new_contact.external_source_type = 'import'

            db.session.add(new_contact)
            db.session.commit()
            from buyercall.blueprints.mobile.utils import send_agent_push_notification
            send_agent_push_notification(new_contact)

            if request_contact_note:
                ContactNotes.create({
                        'text': request_contact_note,
                        'contact_id': new_contact.id,
                        'created_on': datetime.now(),
                        'updated_on': datetime.now(),
                        'user_id': int(current_user.id),
                        'is_enabled': True,
                        'partnership_account_id': int(partnership_account_id)
                    })
            success = True
    else:
        log.error('No request parameters received to add lead.')

    return jsonify({
        'error_message': error_message,
        'missing_message': missing_message,
        'invalid_message': invalid_message,
        'success': success
    })


@contacts.route('/contacts/details/<int:contact_id>', methods=['GET'])
@csrf.exempt
@login_required
def details_view(contact_id):
    partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    contact = Contact.query.filter(
        Contact.partnership_account_id == partnership_account_id, Contact.id == contact_id
    ).first()

    # Get the latest note for the contact
    latest_contact_note = ContactNotes.query.filter(
        ContactNotes.contact_id == contact_id
    ).order_by(desc(ContactNotes.created_on)).first()
    if latest_contact_note:
        note_date = latest_contact_note.date_edited
        note_text = latest_contact_note.text
        note_user = "{} {}".format(latest_contact_note.user.firstname, latest_contact_note.user.lastname)
    else:
        note_date = ''
        note_text = ''
        note_user = ''

    # Get list of agents
    agents = [(g.full_name, g.full_name) for g in Agent.query.filter(
        (Agent.partnership_account_id == partnership_account_id),
        Agent.is_deactivated.is_(False)).order_by('firstname')]
    if agents and contact:
        agents.insert(0, (contact.agent_assigned, contact.agent_assigned))

    if not contact:
        return ''
    else:
        ActivityLogs.add_log(current_user.id, ActivityType.MODAL, ActivityName.VIEW, request, contact_id)

        return jsonify({
            "agents": agents,
            "firstname": contact.firstname,
            "lastname": contact.lastname,
            "status": contact.status,
            "bdc_status": contact.bdc_status,
            "source": contact.marketing_source,
            "agentassigned": contact.agent_assigned,
            "phonenumber": contact.phonenumber_1,
            "email": contact.email,
            "campaign_id": contact.campaign_id,
            "notedate": note_date,
            "notetext": note_text,
            "noteuser": note_user,
        })


@contacts.route('/contacts/details/<int:contact_id>', methods=['POST'])
@csrf.exempt
@login_required
def details_save(contact_id):
    partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    try:
        data = request.get_json()

        if data is not None and contact_id is not None and contact_id > 0:
            contact = Contact.query.filter(
                Contact.partnership_account_id == partnership_account_id, Contact.id == contact_id
            ).first()

            if not contact:
                return 'NOK'
            else:
                firstname = data.get('firstname')
                lastname = data.get('lastname')
                status = data.get('status')
                bdc_status = data.get('bdc_status')
                marketing_source = data.get('source')
                agentassigned = data.get('agentassigned')
                email = data.get('email')
                campaign_id = data.get('campaign_id')
                contact_note = data.get('note')

                contact.firstname = firstname
                contact.lastname = lastname

                if status != "Select status..." and status != "":
                    Contact.update_status(contact.id, None, status, partnership_account_id, None)

                if marketing_source != "Select marketing source..." and marketing_source != "":
                    contact.marketing_source = marketing_source

                if current_user.is_bdc_user and bdc_status != "Select BDC status..." and bdc_status != "":
                    contact.bdc_status = bdc_status

                old_agent_id = contact.agent_id
                if agentassigned != "Select agent..." and agentassigned != "":
                    contact.agent_assigned = agentassigned
                    assigned_agent_id = Agent.reverse_agent_id_lookup(partnership_account_id, agentassigned)
                    contact.agent_id = assigned_agent_id

                if campaign_id == "" or str(campaign_id) == "-1":
                    contact.campaign_id = None
                else:
                    contact.campaign_id = campaign_id

                contact.email = email

                try:
                    form_leads = FormLead.query.filter(FormLead.contact_id == contact.id).all()
                    for form_lead in form_leads:
                        lead_fields = FormLeadField.query.filter(
                            and_(FormLeadField.lead_id == form_lead.id, FormLeadField.field_id == 'repfield')).first()
                        lead_fields.field_value = contact.agent_assigned
                except Exception as e:
                    log.error('No form leads available for the contact. Error: ' + str(sys.exc_info()[0]))

                ActivityLogs.add_log(current_user.id, ActivityType.MODAL, ActivityName.EDIT, request, contact_id)
                db.session.commit()
                if old_agent_id != contact.agent_id:
                    from buyercall.blueprints.mobile.utils import send_agent_push_notification
                    send_agent_push_notification(contact)

                if contact_note and contact_note != "" and len(contact_note) > 3:
                    note = {
                        'text': contact_note,
                        'contact_id': contact_id,
                        'created_on': datetime.now(),
                        'updated_on': datetime.now(),
                        'user_id': int(current_user.id),
                        'partnership_account_id': int(partnership_account_id),
                        'is_enabled': True
                    }
                    result = ContactNotes.create(note)

                return 'OK'
        else:
            log.error('No request parameters received to edit lead.')
            return 'NOK'
    except Exception as e:
        log.error('Error editing lead. Error: ' + str(sys.exc_info()[0]))
        return 'NOK'


@contacts.route('/api/contacts/message/<int:inbound_id>', methods=['POST'])
@login_required
@csrf.exempt
def send_text_message(inbound_id):
    from buyercall.blueprints.sms.views import send_text_message
    agent_id = None

    try:
        result = request.json

        if result is not None and inbound_id is not None and inbound_id > 0:
            param_to = result['to']
            param_text = result['text']
            param_media = result['media']
            param_agent_id = result['agent_id']
            param_agents_visible = result['agents_visible']

            if param_agents_visible and param_agents_visible == True and param_agent_id:
                try:
                    agent_id = int(param_agent_id)

                    if agent_id <= 0:
                        agent_id = None
                except Exception:
                    log.error("Error retrieving agent ID for send SMS. Error: " + traceback.format_exc())

            send_text_message(inbound_id, param_to, param_text, param_media, agent_id)

            return 'OK'
        else:
            log.error('No request parameters received for SMS API.')
            return 'NOK'
    except Exception as e:
        log.error('Error sending text message via API. Error: ' + str(sys.exc_info()[0]))
        return 'NOK'


def contact_chart_data(date_difference, converted_dateFrom, converted_dateTo, contact_list, graph_labels):
    filter_by_date = and_(
        func.date(Contact.updated_on) >= converted_dateFrom,
        func.date(Contact.updated_on) <= converted_dateTo
    )

    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    # Get selectors
    parent_type_filter = extract('day', func.date(Contact.updated_on))
    child_type_filter = extract('month', func.date(Contact.updated_on))
    year_selector = False
    order_by_year = 'parent'

    # Check filter type days/month/year
    if date_difference <= 31:
        parent_type_filter = extract('day', func.date(Contact.updated_on))
        child_type_filter = extract('month', func.date(Contact.updated_on))
    elif 32 <= date_difference <= 366:
        parent_type_filter = extract('month', func.date(Contact.updated_on))
        child_type_filter = extract('year', func.date(Contact.updated_on))
        if converted_dateFrom.year < converted_dateTo.year:
            order_by_year = 'child'
    elif date_difference > 366:
        parent_type_filter = extract('year', func.date(Contact.updated_on))
        child_type_filter = extract('year', func.date(Contact.updated_on))
        year_selector = True

    labels = db.session.query(
        parent_type_filter.label('parent'),
        child_type_filter.label('child'),
        func.count(Contact.id).label('total')) \
        .filter(filter_by_date) \
        .filter(Contact.partnership_account_id == partnership_account_id) \
        .filter(Contact.id.in_(contact_list)) \
        .group_by('parent', 'child') \
        .order_by(order_by_year)

    filter_data_points = []
    filter_labels = []
    filter_date = []
    for label in labels:
        split_filter_date = str(label.parent).split('.')
        split_filter_child = str(label.child).split('.')

        if label.parent not in filter_date:
            filter_date.append(label.parent)
        if year_selector:
            filter_labels.append(split_filter_date[0])
        else:
            if len(split_filter_date[0]) == 1:
                split_filter_date[0] = '0{}'.format(split_filter_date[0])
            if len(split_filter_child[0]) == 1:
                split_filter_child[0] = '0{}'.format(split_filter_child[0])
            filter_labels.append('{}/{}'.format(split_filter_date[0], split_filter_child[0]))
        filter_data_points.append(label.total)

    totals = labels

    date = []
    value = []
    for row in totals:
        date.append(row.parent)
        value.append(row.total)

    data_points = []
    point = 0
    for day in filter_date:
        if day in date:
            if point < (len(value)):
                data_points.append(value[point])
                point = point + 1
        else:
            data_points.append(0)

    graph_points = []
    for i in data_points:
        graph_points.append(i)

    result = []

    for x in graph_labels:
        if x in filter_labels:
            index_pos = filter_labels.index(x)

            if index_pos is not None and index_pos >= 0:
                if index_pos >= len(graph_points):
                    log.error('Error drawing lead charts (contact). Point out of range.')
                    log.error('Index: {}'.format(index_pos))
                    log.error('Filter labels: {}'.format(filter_labels))
                    log.error('Graph points: {}'.format(graph_points))
                    result.append(0)
                else:
                    result.append(graph_points[index_pos])
            else:
                result.append(0)
        else:
            result.append(0)
    return result


def phone_chart_data(date_difference, converted_dateFrom, converted_dateTo, phone_list, graph_labels):
    filter_by_date = and_(
        func.date(Lead.created_on) >= converted_dateFrom,
        func.date(Lead.created_on) <= converted_dateTo
    )

    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    # Get selectors
    parent_type_filter = extract('day', func.date(Lead.created_on))
    child_type_filter = extract('month', func.date(Lead.created_on))
    year_selector = False
    order_by_year = 'parent'

    # Check filter type days/month/year
    if date_difference <= 31:
        parent_type_filter = extract('day', func.date(Lead.created_on))
        child_type_filter = extract('month', func.date(Lead.created_on))
    elif 32 <= date_difference <= 366:
        parent_type_filter = extract('month', func.date(Lead.created_on))
        child_type_filter = extract('year', func.date(Lead.created_on))
        if converted_dateFrom.year < converted_dateTo.year:
            order_by_year = 'child'
    elif date_difference > 366:
        parent_type_filter = extract('year', func.date(Lead.created_on))
        child_type_filter = extract('year', func.date(Lead.created_on))
        year_selector = True

    labels = db.session.query(
        parent_type_filter.label('parent'),
        child_type_filter.label('child'),
        func.count(Lead.id).label('total')) \
        .filter(filter_by_date) \
        .filter(Lead.partnership_account_id == partnership_account_id) \
        .filter(Lead.id.in_(phone_list)) \
        .group_by('parent', 'child') \
        .order_by(order_by_year)

    filter_data_points = []
    filter_labels = []
    filter_date = []
    for label in labels:
        split_filter_date = str(label.parent).split('.')
        split_filter_child = str(label.child).split('.')

        if label.parent not in filter_date:
            filter_date.append(label.parent)
        if year_selector:
            filter_labels.append(split_filter_date[0])
        else:
            if len(split_filter_date[0]) == 1:
                split_filter_date[0] = '0' + split_filter_date[0]
            if len(split_filter_child[0]) == 1:
                split_filter_child[0] = '0' + split_filter_child[0]
            filter_labels.append(split_filter_date[0] + '/' + split_filter_child[0])
        filter_data_points.append(label.total)

    date_list = []
    value = []
    for row in labels:
        date_list.append(row.parent)
        value.append(row.total)

    data_points = []
    point = 0
    for day in filter_date:
        if day in date_list:
            if point < (len(value)):
                data_points.append(value[point])
                point = point + 1
        else:
            data_points.append(0)

    graph_points = []
    for i in data_points:
        graph_points.append(i)

    result = []

    for x in graph_labels:
        if x in filter_labels:
            index_pos = filter_labels.index(x)

            if index_pos is not None and index_pos >= 0:
                if index_pos >= len(graph_points):
                    log.error('Error drawing lead charts (phone). Point out of range.')
                    log.error('Index: ' + str(index_pos))
                    log.error('Filter labels: ' + str(filter_labels))
                    log.error('Graph points: ' + str(graph_points))
                    result.append(0)
                else:
                    result.append(graph_points[index_pos])
            else:
                result.append(0)
        else:
            result.append(0)

    return result


def message_chart_data(date_difference, converted_dateFrom, converted_dateTo, message_list, graph_labels):
    filter_by_date = and_(
        func.date(Message.created_on) >= converted_dateFrom,
        func.date(Message.created_on) <= converted_dateTo
    )

    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    # Get selectors
    parent_type_filter = extract('day', func.date(Message.created_on))
    child_type_filter = extract('month', func.date(Message.created_on))
    year_selector = False
    order_by_year = 'parent'

    # Check filter type days/month/year
    if date_difference <= 31:
        parent_type_filter = extract('day', func.date(Message.created_on))
        child_type_filter = extract('month', func.date(Message.created_on))
    elif 32 <= date_difference <= 366:
        parent_type_filter = extract('month', func.date(Message.created_on))
        child_type_filter = extract('year', func.date(Message.created_on))
        if converted_dateFrom.year < converted_dateTo.year:
            order_by_year = 'child'
    elif date_difference > 366:
        parent_type_filter = extract('year', func.date(Message.created_on))
        child_type_filter = extract('year', func.date(Message.created_on))
        year_selector = True

    labels = db.session.query(
        parent_type_filter.label('parent'),
        child_type_filter.label('child'),
        func.count(Message.id).label('total')) \
        .filter(filter_by_date) \
        .filter(Message.partnership_account_id == partnership_account_id) \
        .filter(Message.id.in_(message_list)) \
        .group_by('parent', 'child') \
        .order_by(order_by_year)

    filter_data_points = []
    filter_labels = []
    filter_date = []
    for label in labels:
        split_filter_date = str(label.parent).split('.')
        split_filter_child = str(label.child).split('.')

        if label.parent not in filter_date:
            filter_date.append(label.parent)
        if year_selector:
            filter_labels.append(split_filter_date[0])
        else:
            if len(split_filter_date[0]) == 1:
                split_filter_date[0] = '0{}'.format(split_filter_date[0])
            if len(split_filter_child[0]) == 1:
                split_filter_child[0] = '0{}'.format(split_filter_child[0])
            filter_labels.append(split_filter_date[0] + '/' + split_filter_child[0])
        filter_data_points.append(label.total)

    date_list = []
    value = []
    for row in labels:
        date_list.append(row.parent)
        value.append(row.total)

    data_points = []
    point = 0
    for day in filter_date:
        if day in date_list:
            if point < (len(value)):
                data_points.append(value[point])
                point = point + 1
        else:
            data_points.append(0)

    graph_points = []
    for i in data_points:
        graph_points.append(i)

    result = []

    for x in graph_labels:
        if x in filter_labels:
            index_pos = filter_labels.index(x)

            if index_pos is not None and index_pos >= 0:
                if index_pos >= len(graph_points):
                    log.error('Error drawing lead charts (message). Point out of range.')
                    log.error('Index: ' + str(index_pos))
                    log.error('Filter labels: ' + str(filter_labels))
                    log.error('Graph points: ' + str(graph_points))
                    result.append(0)
                else:
                    result.append(graph_points[index_pos])
            else:
                result.append(0)
        else:
            result.append(0)

    return result


def form_chart_data(date_difference, converted_dateFrom, converted_dateTo, form_list, graph_labels):
    filter_by_date = and_(
        func.date(FormLead.created_on) >= converted_dateFrom,
        func.date(FormLead.created_on) <= converted_dateTo
    )

    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    # Get selectors
    parent_type_filter = extract('day', func.date(FormLead.created_on))
    child_type_filter = extract('month', func.date(FormLead.created_on))
    year_selector = False
    order_by_year = 'parent'

    # Check filter type days/month/year
    if date_difference <= 31:
        parent_type_filter = extract('day', func.date(FormLead.created_on))
        child_type_filter = extract('month', func.date(FormLead.created_on))
    elif 32 <= date_difference <= 366:
        parent_type_filter = extract('month', func.date(FormLead.created_on))
        child_type_filter = extract('year', func.date(FormLead.created_on))
        if converted_dateFrom.year < converted_dateTo.year:
            order_by_year = 'child'
    elif date_difference > 366:
        parent_type_filter = extract('year', func.date(FormLead.created_on))
        child_type_filter = extract('year', func.date(FormLead.created_on))
        year_selector = True

    labels = db.session.query(
        parent_type_filter.label('parent'),
        child_type_filter.label('child'),
        func.count(FormLead.id).label('total')) \
        .filter(filter_by_date) \
        .filter(FormLead.partnership_account_id == partnership_account_id) \
        .filter(FormLead.id.in_(form_list)) \
        .group_by('parent', 'child') \
        .order_by(order_by_year)

    filter_data_points = []
    filter_labels = []
    filter_date = []
    for label in labels:
        split_filter_date = str(label.parent).split('.')
        split_filter_child = str(label.child).split('.')

        if label.parent not in filter_date:
            filter_date.append(label.parent)
        if year_selector:
            filter_labels.append(split_filter_date[0])
        else:
            if len(split_filter_date[0]) == 1:
                split_filter_date[0] = '0{}'.format(split_filter_date[0])
            if len(split_filter_child[0]) == 1:
                split_filter_child[0] = '0{}'.format(split_filter_child[0])
            filter_labels.append('{}/{}'.format(split_filter_date[0], split_filter_child[0]))
        filter_data_points.append(label.total)

    date_list = []
    value = []
    for row in labels:
        date_list.append(row.parent)
        value.append(row.total)

    data_points = []
    point = 0
    for day in filter_date:
        if day in date_list:
            if point < (len(value)):
                data_points.append(value[point])
                point = point + 1
        else:
            data_points.append(0)

    graph_points = []
    for i in data_points:
        graph_points.append(i)

    result = []

    for x in graph_labels:
        if x in filter_labels:
            index_pos = filter_labels.index(x)

            if index_pos is not None and index_pos >= 0:
                if index_pos >= len(graph_points):
                    log.error('Error drawing lead charts (form). Point out of range.')
                    log.error('Index: ' + str(index_pos))
                    log.error('Filter labels: ' + str(filter_labels))
                    log.error('Graph points: ' + str(graph_points))
                    result.append(0)
                else:
                    result.append(graph_points[index_pos])
            else:
                result.append(0)
        else:
            result.append(0)

    return result


# return data for the filter options
@contacts.route('/contacts/filteroptions', methods=['GET'])
@csrf.exempt
@login_required
def filteroptions():
    """Return server side filter data."""
    phone_source_result = {}
    message_source_result = {}
    form_source_result = {}
    status_result = {}
    bdc_status_result = {}
    marketing_result = {}
    assigned_agent_result = {}
    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    filter_by_lead = and_(
        Lead.partnership_account_id == partnership_account_id,
        Lead.contact_id == Contact.id,
        Contact.partnership_account_id == partnership_account_id
    )

    filter_by_sms = and_(
        Message.partnership_account_id == partnership_account_id,
        Message.contact_id == Contact.id,
        Contact.partnership_account_id == partnership_account_id
    )

    filter_by_form = and_(
        FormLead.partnership_account_id == partnership_account_id,
        FormLead.contact_id == Contact.id,
        Contact.partnership_account_id == partnership_account_id
    )

    filter_by_partnership_account = and_(
        Contact.partnership_account_id == partnership_account_id,
        Contact.agent_assigned != ""
    )

    # populate agent result
    agent_data = Contact.query.with_entities('contacts.agent_assigned').filter(filter_by_partnership_account).distinct()
    for i in agent_data:
        if i:
            if i[0]:
                id = i[0]
                name = i[0]
                assigned_agent_result[id] = name

    # populate phone result
    inbound_data = Lead.query.join(Lead.contact)\
        .outerjoin(Lead.inbound).options(
        contains_eager(Lead.inbound)
    ).with_entities(
        'phonenumbers.id', 'phonenumbers.friendly_name', 'phonenumbers.phonenumber'
    ).filter(filter_by_lead).distinct()

    outbound_data = Lead.query.join(Lead.contact)\
        .outerjoin(Lead.widget).options(
        contains_eager(Lead.widget)
    ).with_entities('widgets.guid', 'widgets.name').filter(filter_by_lead).distinct()

    for i in inbound_data:
        if i:
            if i[0] and i[2]:
                id = str(i[0])
                name = str(i[2])
                friendly_name = str(i[1])
                phone_source_result[id] = '{} ({})'.format(name, friendly_name)

    for i in outbound_data:
        if i:
            if i[0] and i[1]:
                id = str(i[0])
                name = str(i[1])
                phone_source_result[id] = name

    # populate message result
    message_data = Message.query.join(Message.contact)\
        .outerjoin(Message.inbound).options(
        contains_eager(Message.inbound)
    ).with_entities(
        'phonenumbers.id', 'phonenumbers.friendly_name', 'phonenumbers.phonenumber'
    ).filter(filter_by_sms).distinct()

    for i in message_data:
        if i:
            if i[0] and i[2]:
                id = str(i[0])
                name = str(i[2])
                friendly_name = str(i[1])
                message_source_result[id] = '{} ({})'.format(name, friendly_name)
                # populate form lead result
    form_data = FormLead.query.join(FormLead.contact)\
        .outerjoin(FormLead.form).options(
        contains_eager(FormLead.form)
    ).with_entities('external_forms.id', 'external_forms.display_name').filter(filter_by_form).distinct()

    for i in form_data:
        if i:
            if i[0] and i[1]:
                id = str(i[0])
                name = str(i[1])
                form_source_result[id] = name

    # populate bdc status result
    bdc_status_list = BdcStatuses.get_assigned_status_list(partnership_account_id)
    for item in bdc_status_list:
        id = item.status
        bdc_status_result[id] = item.display_name

    # populate status result
    status_list = Status.get_assigned_status_list(partnership_account_id)
    for item in status_list:
        id = item.status
        status_result[id] = item.display_name

    # populate marketing result
    marketing_list = MarketingSources.get_assigned_source_list(partnership_account_id)
    for item in marketing_list:
        id = item.source
        marketing_result[id] = item.display_name

    return jsonify(
        phone_source_data=phone_source_result,
        message_source_data=message_source_result,
        form_source_data=form_source_result,
        assigned_agent_data=assigned_agent_result,
        bdc_status_data=bdc_status_result,
        status_data=status_result,
        marketing_data=marketing_result
    )


@contacts.route('/contacts/csv', methods=['GET'])
@login_required
def data_csv():
    phone_list = []
    lead_list = []
    form_list = []
    message_list = []
    filtered_contact_list = []
    filtered_phone_list = []
    filtered_message_list = []
    filtered_form_list = []
    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    from ..partnership.models import PartnershipAccount
    partnership_account = PartnershipAccount \
        .query \
        .filter(PartnershipAccount.id == partnership_account_id) \
        .first()

    search = request.args.get('search[value]', '')
    order = int(request.args.get('order[0][column]', '-1'))
    direction = request.args.get('order[0][dir]', 'asc')
    offset = int(request.args.get('start', 0))
    limit = int(request.args.get('length', 99))

    date_from = str(request.args.get('df'))
    date_to = str(request.args.get('dt'))
    assigned_agent = str(request.args.get('aa'))
    form_check = str(request.args.get('stf'))
    phone_check = str(request.args.get('stp'))
    sms_check = str(request.args.get('sts'))
    import_check = str(request.args.get('sis'))
    api_check = str(request.args.get('sas'))
    adf_import_check = str(request.args.get('sais'))
    phone_source = str(request.args.get('ps'))
    sms_source = str(request.args.get('ms'))
    form_source = str(request.args.get('fs'))
    call_status = str(request.args.get('cs'))
    call_bdc_status = str(request.args.get('cbs'))
    marketing_source = str(request.args.get('mks'))
    date_difference = days_between(date_from, date_to)

    # set the date filters
    converted_dateFrom = datetime.strptime(date_from, "%m%d%Y").date()
    converted_dateTo = datetime.strptime(date_to, "%m%d%Y").date()
    filter_by_date = and_(
        func.date(Contact.updated_on) >= converted_dateFrom,
        func.date(Contact.updated_on) <= converted_dateTo
    )

    # filter initiation section - check box filter
    filter_by_phone_check = text('')
    filter_by_sms_check = text('')
    filter_by_form_check = text('')

    # filter initiation section - external source type filters
    filter_by_api_check = text('')
    filter_by_adf_import_check = text('')
    filter_by_import_check = text('')

    # filter initiation section - drop down filters
    filter_by_assigned_agent = text('')
    filter_by_form = text('')
    filter_by_call_status = text('')
    filter_by_call_bdc_status = text('')
    filter_by_marketing_source = text('')
    filter_by_assigned_agent_id = text('')
    assigned_agent_id = -1

    # filter initiation section - source
    filter_by_phone_source = text('')
    filter_by_sms_source = text('')
    filter_by_form_source = text('')
    filter_by_phone_complete_source = text('')
    filter_by_sms_complete_source = text('')
    filter_by_form_complete_source = text('')

    # set the data permission restrictions
    filter_by = (Contact.partnership_account_id == partnership_account_id)

    # Lead phone number filter section
    if phone_source and phone_source != 'null' and phone_source != 'None':
        if phone_source.count('-') == 4:
            filter_by_phone_source = "widgets.guid = '{}'".format(phone_source)
        else:
            filter_by_phone_source = text("phonenumbers.id = {}".format(phone_source))
        phone_list = Lead.query.outerjoin(
            Lead.widget
        ).outerjoin(Lead.inbound).options(
            contains_eager(Lead.widget).load_only('id', 'name'),
            contains_eager(Lead.inbound).load_only('id', 'friendly_name'),
         ).join(Contact)\
            .filter(filter_by)\
            .filter(filter_by_phone_source)\
            .with_entities('leads.contact_id')\
            .distinct().all()
        if phone_list is not None:
            filter_by_phone_complete_source = and_(Contact.id.in_(phone_list))

    # Message filter section
    if sms_source and sms_source != 'null' and sms_source != 'None':
        filter_by_sms_source = "phonenumbers.id = {}".format(sms_source)
        message_list = Message.query.outerjoin(
            Message.inbound
        ).options(
            contains_eager(Message.inbound).load_only('id'),
         ).join(Contact)\
            .filter(filter_by)\
            .filter(filter_by_sms_source)\
            .with_entities('messages.contact_id')\
            .distinct().all()
        if message_list is not None:
            filter_by_sms_complete_source = and_(Contact.id.in_(message_list))

    # Form lead filter section
    if form_source and form_source != 'null' and form_source != 'None':
        filter_by_form_source = text("external_forms.id = {}".format(form_source))
        form_list = FormLead.query.outerjoin(
            FormLead.form
        ).options(
            contains_eager(FormLead.form).load_only('id'),
         ).join(Contact)\
            .filter(filter_by)\
            .filter(filter_by_form_source)\
            .with_entities('form_leads.contact_id')\
            .distinct().all()
        if form_list is not None:
            filter_by_form_complete_source = and_(Contact.id.in_(form_list))

    # Assigned agent filter section
    if assigned_agent != 'null' and assigned_agent:
        filter_by_assigned_agent = and_(text("contacts.agent_assigned = '" + str(assigned_agent) + "'"))

    # Form check filter section
    if form_check == '1' or form_check == 1:
        filter_by_form_check = and_(Contact.form_count > 0)

    # Message check filter section
    if sms_check == '1' or sms_check == 1:
        filter_by_sms_check = and_(Contact.sms_count > 0)

    # Phone check filter section
    if phone_check == '1' or phone_check == 1:
        filter_by_phone_check = and_(Contact.phone_count > 0)

    # Source type - API
    if api_check == '1' or api_check == 1:
        filter_by_api_check = and_(Contact.external_source_type == 'api')

    # Source type - ADF Import
    if adf_import_check == '1' or adf_import_check == 1:
        filter_by_adf_import_check = and_(Contact.external_source_type == 'adf_import')

    # Source type - Import
    if import_check == '1' or import_check == 1:
        filter_by_import_check = and_(Contact.external_source_type == 'import')

    # call status filter section
    if call_status != 'null' and call_status:
        filter_by_call_status = and_(text("contacts.status = '" + call_status + "'"))

    # call bdc status filter section
    if current_user.is_bdc_user and call_bdc_status != 'null' and call_bdc_status:
        filter_by_call_bdc_status = and_(text("contacts.bdc_status = '" + call_bdc_status + "'"))

    # Marketing source filter section
    if marketing_source != 'null' and marketing_source:
        if marketing_source == 'no_source':
            filter_by_marketing_source = and_(
                or_(text("contacts.marketing_source = '" + marketing_source + "'"),
                    text("contacts.marketing_source = '""'")))
        else:
            filter_by_marketing_source = and_((text("contacts.marketing_source = '" + marketing_source + "'")))

    search = request.args.get('search[value]', '')
    header = [
        'No',
        'Created On',
        'Updated On',
        'First Name',
        'Last Name',
        'Credit Score',
        'Caller Id',
        'Phonenumber_1',
        'Phonenumber_2',
        'Email',
        'Address_1',
        'Address_2',
        'City',
        'State',
        'Zip',
        'Country',
        'Do Not Call',
        'SMS Unsubscribe',
        'Agent Assigned',
        'Status',
        'BDC Status',
        'Marketing Source',
        # 'Total Phone Calls', # Removed to optimize download and speed it up
        # 'Phone Source', # Removed to optimize download and speed it up
        # 'Total Messages', # Removed to optimize download and speed it up
        # 'Message Source', # Removed to optimize download and speed it up
        # 'Total Form Leads', # Removed to optimize download and speed it up
        # 'Form Lead Source' # Removed to optimize download and speed it up
    ]

    if partnership_account.business_type != 'automotive':
        del header[5]

    total = Contact.query \
        .join(Status, Contact.status == Status.status) \
        .filter(filter_by) \
        .filter(filter_by_date) \
        .filter(filter_by_form_check)\
        .filter(filter_by_sms_check) \
        .filter(filter_by_phone_check) \
        .filter(filter_by_assigned_agent) \
        .filter(filter_by_call_status) \
        .filter(filter_by_call_bdc_status) \
        .filter(filter_by_marketing_source) \
        .filter(filter_by_phone_complete_source)\
        .filter(filter_by_sms_complete_source)\
        .filter(filter_by_form_complete_source)\
        .filter(filter_by_api_check) \
        .filter(filter_by_adf_import_check) \
        .filter(filter_by_import_check)

    filtered = total

    # define data columns for the searching data view window
    columns_search = [
        Contact.id,
        Contact.name,
        Contact.firstname,
        Contact.lastname,
        Contact.phonenumber_1,
        Contact.email,
        Status.status,
        Contact.agent_assigned
    ]

    #if search:
    #    pattern = '%{}%'.format(search)
    #    filtered = total.filter(or_(
    #        Contact.name.ilike(pattern),
    #        Contact.phonenumber_1.ilike(pattern),
    #        Contact.email.ilike(pattern),
    #        Contact.status.ilike(pattern),
    #        Contact.agent_assigned.ilike(pattern),
    #        Contact.source.ilike(pattern)
    #    ))
    if search:
        total_list = total.with_entities(*columns_search).all()
        searched_result_list = [x for x in total_list if x.name == search
                                or x.email == search
                                or x.firstname == search
                                or x.lastname == search
                                or x.phonenumber_1 == search
                                or x.status == search
                                or x.agent_assigned == search]
        searched_result_ids = [x.id for x in searched_result_list]
        filtered = Contact.query.join(Status, Contact.status == Status.status)\
            .filter(Contact.id.in_(searched_result_ids))

    query = filtered.order_by(Contact.updated_on)

    # Get status list
    bdc_status_list = BdcStatuses.get_complete_status_list_as_dict()

    # Get status list
    status_list = Status.get_complete_status_list_as_dict()

    # Get source list
    marketing_source_list = MarketingSources.get_complete_source_list_as_dict()

    # Build the CSV
    row_no = 0
    with closing(StringIO()) as out:
        writer = csv.writer(out)
        writer.writerow(header)
        for contact in query.all():
            # lead_source_name = ''  # Removed to optimize download and speed it up
            # sms_source_name = '' # Removed to optimize download and speed it up
            # form_lead_source_name = '' # Removed to optimize download and speed it up
            row_no += 1
            decrypted_credit_score = ''

            # lead_source = Lead.query.filter(and_(
            #    Lead.contact_id == contact.id,
            #    Lead.partnership_account_id == partnership_account_id
            # )).first() # Removed to optimize download and speed it up

            # sms_source = Message.query.filter(and_(
            #    Message.contact_id == contact.id,
            #    Message.partnership_account_id == partnership_account_id
            # )).first() # Removed to optimize download and speed it up

            # form_lead_source = FormLead.query.filter(and_(
            #    FormLead.contact_id == contact.id,
            #    FormLead.partnership_account_id == partnership_account_id
            # )).first() # Removed to optimize download and speed it up

            # if lead_source is not None:
            #    lead_source_name = lead_source.source # Removed to optimize download and speed it up

            # if sms_source is not None:
            #    sms_source_name = sms_source.source # Removed to optimize download and speed it up

            # if form_lead_source is not None:
            #     form_lead_source_name = form_lead_source.source # Removed to optimize download and speed it up

            sms_unsubscribe = "Yes" if contact.is_unsubscribe else "No"
            do_not_call = "Yes" if contact.is_do_not_call else "No"

            if partnership_account.business_type == 'automotive':
                # Decrypt credit score
                encrypt_key = app.config['CRYPTO_SECRET_KEY']
                cipher = AESCipher(encrypt_key)
                if contact.credit_score:
                    decrypted_credit_score = cipher.decrypt(contact.credit_score)

            csv_row = [
                row_no,
                contact.created_datetime,
                contact.updated_datetime,
                contact.firstname,
                contact.lastname,
                decrypted_credit_score,
                contact.caller_id,
                contact.phonenumber_1,
                contact.phonenumber_2,
                contact.email,
                contact.address_1,
                contact.address_2,
                contact.city,
                contact.state,
                contact.zip,
                contact.country,
                do_not_call,
                sms_unsubscribe,
                contact.agent_assigned,
                Status.get_formatted_status(status_list, contact.status),
                BdcStatuses.get_formatted_status(bdc_status_list, contact.bdc_status),
                MarketingSources.get_formatted_source(marketing_source_list, contact.marketing_source),
                # contact.phone_count, # Removed to optimize download and speed it up
                # lead_source_name, # Removed to optimize download and speed it up
                # contact.sms_count, # Removed to optimize download and speed it up
                # sms_source_name, # Removed to optimize download and speed it up
                # contact.form_count, # Removed to optimize download and speed it up
                # form_lead_source_name # Removed to optimize download and speed it up
            ]

            if partnership_account.business_type != 'automotive':
                del csv_row[5]

            writer.writerow([x for x in csv_row])

        filename = 'Buyercall Leads - {}.csv'.format(
            date.today().strftime('%Y-%m-%d')
        )

        resp = make_response(out.getvalue())
        resp.headers['Content-Type'] = 'text/csv'
        resp.headers['Content-Disposition'] = \
            'attachment; filename="{}"'.format(filename)
        ActivityLogs.add_log(current_user.id, ActivityType.DATA, ActivityName.DOWNLOAD, request, None, 'csv')
        return resp


@contacts.route('/contacts/call/<int:contact_id>', methods=['GET'])
@login_required
@csrf.exempt
def get_contact_call_info(contact_id):
    """ Return this contact lead's call information in JSON format, with the following
    fields:

    - agentNumber: The phone number of the agent used to call the lead.
    - routingNumber: The routing number used to call the lead.
    - allAgentNumbers: An array of all agent numbers for this user.
    - allRoutingNumbers: An array of all routing numbers for this user.

    The numbers should be returned in E.123 format.
    """
    from buyercall.blueprints.phonenumbers.models import Phone

    partnership_account_id = current_user.partnership_account_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    result_agent_number = ''
    result_my_phone = ''

    lead = Lead.query.filter(
        Lead.partnership_account_id == partnership_account_id, Lead.contact_id == contact_id
    ).first()
    agent_nos = []

    if current_user.role == 'agent':
        agents = Agent.query.filter(and_(
            Agent.user_id == current_user.id,
            Agent.is_deactivated.is_(False))
        ).all()
    else:
        agents = Agent.query.filter(and_(
            Agent.partnership_account_id == partnership_account_id,
            Agent.is_deactivated.is_(False))
        ).all()

    for agent in agents:
        if agent.phonenumber:
            agent_nos.append({
                "agent": "{}, Phone ({})".format(
                    agent.full_name, agent.phonenumber),
                "number": agent.phonenumber
            })
        if agent.mobile and (
            agent.mobile != agent.phonenumber or not agent.phonenumber
        ):
            agent_nos.append({
                "agent": "{}, Mobile ({})".format(
                    agent.full_name, agent.mobile),
                "number": agent.mobile
            })
        if agent.app_number and (
            agent.app_number != agent.mobile or agent.app_number != agent.phonenumber or not agent.phonenumber
        ):
            agent_nos.append({
                "agent": "{}, App ({})".format(
                    agent.full_name, agent.app_number),
                "number": agent.app_number
            })
    routings = Phone.query.filter(and_(
        Phone.partnership_account_id == partnership_account_id,
        Phone.active == True, Phone.is_deactivated == False
    )).all()
    routing_nos = [
        {
            "friendlyName": '{} ({})'.format(x.friendly_name, x.phonenumber),
            "number": x.phonenumber
        } for x in routings
    ]

    if lead:
        result_agent_number = lead.agent and lead.agent.phonenumber
        result_my_phone = lead.my_phone
    else:
        contact_details = Contact.query.filter(
            Contact.partnership_account_id == current_user.partnership_account_id, Contact.id == contact_id
        ).first()

        if contact_details:
            route_number = Phone.query \
                .filter(and_(Phone.partnership_account_id == current_user.partnership_account_id, Phone.active,
                             Phone.is_deactivated == False)).first()

            assigned_agent = Agent.query.filter(
                and_(Agent.full_name == contact_details.agent_assigned,
                     Agent.partnership_account_id == current_user.partnership_account_id)).first()

            if route_number:
                result_my_phone = route_number.phonenumber
            if assigned_agent:
                result_agent_number = assigned_agent and assigned_agent.phonenumber

    return jsonify({
        "agentNumber": result_agent_number,
        "allAgentNumbers": agent_nos,
        "routingNumber": result_my_phone,
        "allRoutingNumbers": routing_nos
    })


@contacts.route('/contacts/call/<int:contact_id>', methods=['POST'])
@csrf.exempt
def call_contact(contact_id):
    from buyercall.blueprints.phonenumbers.models import Phone
    from buyercall.blueprints.agents.models import Agent
    from buyercall.blueprints.phonenumbers.tasks import connect_lead_to_agent

    partnership_account_id = current_user.partnership_account_id
    partnership_id = current_user.partnership_id
    partnership_account_group_viewing = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if partnership_account_group_viewing:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    data = request.get_json()
    agent_number, routing_number = (
        data.get('agentNumber'), data.get('routingNumber')
    )

    routing = Phone.query.filter(
        Phone.partnership_account_id == partnership_account_id,
        Phone.phonenumber == routing_number
    ).options(load_only('id')).first()
    if not routing:
        return 'Cannot find routing phone number', 400

    agent = Agent.query.filter(
        Agent.partnership_account_id == partnership_account_id,
        or_(Agent.phonenumber == agent_number,
            Agent.mobile == agent_number,
            Agent.app_number == agent_number),  # TODO: Include extension!
    ).options(load_only('id')).first()
    if not agent:
        return 'Cannot find agent', 400

    old_lead = Lead.query.filter(
        Lead.partnership_account_id == partnership_account_id, Lead.contact_id == contact_id
    ).first()

    if old_lead:
        progress_status = old_lead.progress_status
    else:
        progress_status = 'new lead'

    # Return contact details
    contact_lead = Contact.query.filter(Contact.id == contact_id).first()
    contact_lead_id = contact_lead.id
    if not contact_lead_id:
        return 'Contact lead with ID {} not found'.format(contact_id), 400

    lead = Lead(
        partnership_account_id=partnership_account_id,
        firstname=contact_lead.firstname,
        lastname=contact_lead.lastname,
        phonenumber=contact_lead.phonenumber_1,
        email=contact_lead.email,
        starttime=datetime.utcnow(),
        call_type='outbound',
        my_phone=routing_number,
        inbound_id=routing.id,
        agent_id=agent.id,
        progress_status=progress_status,
        status='ringing',
        contact_id=contact_lead_id,
        originating_number=routing_number,
        call_source='Agent Outbound Call',
    )
    lead.save()

    # A hack to specify how to contact the agent
    if agent.mobile == agent_number:
        contact_using = 'mobile'
    elif agent.app_number == agent_number:
        contact_using = 'app'
    else:
        contact_using = 'phone'

    call_settings = {
        'agents': [{'id': agent.id, 'contactUsing': contact_using}]
    }

    if routing.type == 'tracking':
        agent_manual_outbound_call(lead, call_settings)
    else:
        connect_lead_to_agent.delay(lead.id, agent.id, call_settings)

    return ''


def format_date(date):
    """ Format a local date for consumption by Excel
    """
    if not date:
        return ''
    return date.strftime('%Y-%m-%d %H:%M:%S')


@contacts.route('/contacts/credit_report/<bureau>/<product_type>/<int:contact_id>/<service_provider>', methods=['POST', 'GET'])
@login_required
@csrf.exempt
def contact_credit_report(bureau, product_type, contact_id, service_provider):
    from .contact_tasks import successful_credit_check_seven_hundred, unsuccessful_credit_check, \
        successful_credit_check_finserv
    from buyercall.lib.util_credit_reports import seven_hundred_credit_client, validate_ssn, \
        validate_name, validate_address_street, format_street, validate_address_city, \
        validate_address_state, format_city, format_state, validate_address_zip, \
        format_full_name, validate_city_state_zip_combo, format_zip, format_dob_year, finserv_credit_client
    from buyercall.blueprints.sysadmin.utilities.request_log_task_call import LogRequestTaskTrigger
    from flask import request

    LogRequestTaskTrigger().log_request_task_trigger(
                        request, "seven-hundred-credit")
    # Set the encryption and cipher key
    encrypt_key = app.config['CRYPTO_SECRET_KEY']
    cipher = AESCipher(encrypt_key)
    lead = Contact.query.filter(Contact.id == contact_id).first()

    # Set the Jinja2 page veriables to avoid errors
    url = ''
    finserv_credit_score = ''
    finserv_credit_approve = ''
    finserv_credit_trade_lines = ''

    contact = Contact.query.filter(Contact.id == contact_id).first()

    existing_report = CreditReports.query\
        .filter(and_(CreditReports.contact_id == contact_id,
                     CreditReports.partnership_account_id == lead.partnership_account_id,
                     CreditReports.credit_bureau == bureau,
                     CreditReports.product_type == product_type,
                     CreditReports.is_successful.is_(True))).first()

    if existing_report:
        if existing_report.iframe_url:
            if contact.is_eq_lead:
                decrypt_url_field = cipher.decrypt(existing_report.iframe_url).split('::')
                print(decrypt_url_field)
                url_bucket = decrypt_url_field[0]
                url_key = decrypt_url_field[1]
                # build presigned url
                from buyercall.lib.util_boto3_s3 import generate_presigned_aws_url
                url = generate_presigned_aws_url(url_key, url_bucket)
            else:
                url = cipher.decrypt(existing_report.iframe_url)
        else:
            url = ''
        if existing_report.trades:
            finserv_credit_score = cipher.decrypt(existing_report.credit_score)
            finserv_credit_approve = existing_report.is_approved
            finserv_credit_trade_lines = json.loads(cipher.decrypt(existing_report.trades))
        else:
            finserv_credit_score = ''
            finserv_credit_approve = ''
            finserv_credit_trade_lines = ''

    else:
        validate_name = validate_name(lead.firstname, lead.lastname)
        if not validate_name:
            description = 'This lead does not have a valid first name and/or last name.'
            trans_id = cipher.encrypt('Unavailable')
            unsuccessful_credit_check(contact_id, lead.partnership_account_id, description, bureau, product_type,
                                      trans_id, service_provider)
            flash(_('{} Please update the lead with a valid name and try again.').format(description), 'danger')
            return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')
        validate_street = validate_address_street(lead.address_1)
        if not validate_street:
            description = 'This lead does not have a valid street address.'
            trans_id = cipher.encrypt('Unavailable')
            unsuccessful_credit_check(contact_id, lead.partnership_account_id, description, bureau, product_type,
                                      trans_id, service_provider)
            flash(_('{} Please update the lead with a valid address and try again.').format(description), 'danger')
            return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')
        validate_city = validate_address_city(lead.city)
        if not validate_city:
            description = 'This lead does not have a valid city.'
            trans_id = cipher.encrypt('Unavailable')
            unsuccessful_credit_check(contact_id, lead.partnership_account_id, description, bureau, product_type,
                                      trans_id, service_provider)
            flash(_('{} Please update the lead with a valid city and try again.').format(description), 'danger')
            return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')
        validate_state = validate_address_state(lead.state)
        if not validate_state:
            description = 'This lead does not have a valid state.'
            trans_id = cipher.encrypt('Unavailable')
            unsuccessful_credit_check(contact_id, lead.partnership_account_id, description, bureau, product_type,
                                      trans_id, service_provider)
            flash(_('{} Please update the lead with a valid state and try again.').format(description), 'danger')
            return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')
        validate_zip = validate_address_zip(lead.zip)
        if not validate_zip:
            description = 'This lead does not have a valid zip code.'
            trans_id = cipher.encrypt('Unavailable')
            unsuccessful_credit_check(contact_id, lead.partnership_account_id, description, bureau, product_type,
                                      trans_id, service_provider)
            flash(_('{} Please update the lead with a valid zip code and try again.').format(description), 'danger')
            return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')
        validate_combo = validate_city_state_zip_combo(lead.zip, lead.city, lead.state)
        if not validate_combo:
            description = 'This lead zip code, city and state does not seem to match as a valid zip, ' \
                          'city and state combination.'
            trans_id = cipher.encrypt('Unavailable')
            unsuccessful_credit_check(contact_id, lead.partnership_account_id, description, bureau, product_type,
                                      trans_id, service_provider)
            flash(_('{} Please review the zip code, city, state for the lead and try again.').format(description),
                  'danger')
            return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')
        try:
            # Set the credit report table
            if bureau == 'experian':
                bureau_abv = 'XPN'
            elif bureau == 'transunion':
                bureau_abv = 'TU'
            elif bureau == 'equifax':
                bureau_abv = 'EFX'
            else:
                bureau_abv = ''
            name = format_full_name(lead.user_fullname)
            address = format_street(lead.address_1)
            city = format_city(lead.city)
            state = format_state(lead.state)
            zip_code = format_zip(lead.zip)
            a_username = 'buyercall'
            a_user_id = lead.partnership_account_id
            score_card_name = ''
            credit_score = ''
            ssn = ''
            if service_provider == '700Credit':
                client = seven_hundred_credit_client(lead.partnership_account_id, product_type)
                # Get form lead associated with the contact id
                form_lead = FormLead.query.filter(FormLead.contact_id == contact_id).first()
                if form_lead:
                    ssn_field = FormLeadField.query.filter(FormLeadField.lead_id == form_lead.id) \
                        .filter(
                        or_(FormLeadField.field_id == 'cumemberfield',
                            FormLeadField.field_id == 'ssnfield',
                            FormLeadField.field_id == 'ssn')).first()
                    if ssn_field.field_value:
                        # Check to see if SSN field is not a string. If not make it a string
                        decrypted_ssn = cipher.decrypt(ssn_field.field_value)
                        # decrypted_ssn = '000344544'
                        if type(decrypted_ssn) == str:
                            ssn = decrypted_ssn
                        else:
                            ssn = str(decrypted_ssn)
                        if ssn:
                            # Check to see if its a valid SSN number
                            valid_ssn = validate_ssn(ssn)
                            if not valid_ssn:
                                description = 'This lead does not have a valid Social Security Number (SSN).'
                                trans_id = cipher.encrypt('Unavailable')
                                unsuccessful_credit_check(contact_id, lead.partnership_account_id, description, bureau,
                                                          product_type, trans_id, service_provider)
                                flash(_('{} Please update the lead with a valid SSN and try again.').format(description),
                                      'danger')
                                return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')

                # Perform the API post request to get credit report
                if product_type == 'credit':
                    if not ssn:
                        description = 'This lead does not have a Social Security Number (SSN).'
                        trans_id = cipher.encrypt('Unavailable')
                        unsuccessful_credit_check(contact_id, lead.partnership_account_id, description, bureau,
                                                  product_type, trans_id, service_provider)
                        flash(_(' {} Please update the lead with a valid SSN and try generating a'
                                ' Credit Report again.').format(description), 'danger')
                        return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')

                    credit_pull = client.credit_report.get_full_credit_report(bureau_abv, name, ssn, address,
                                                                              city, state, zip_code, a_username,
                                                                              a_user_id)
                else:
                    credit_pull = client.credit_report.get_prequalify_credit_report(bureau_abv, name, address, city,
                                                                                    state, zip_code, ssn, a_username,
                                                                                    a_user_id)
                log.info('The response return by the credit POST: {}'.format(credit_pull))

                if product_type == 'prequalify':
                    trans_id = cipher.encrypt(credit_pull['Results']['XML_Report']['Transid'])
                    credit_score_raw = credit_pull['Results']['XML_Report']['Prescreen_Report']['Score']
                    if credit_score_raw is None:
                        description = credit_pull['Results']['XML_Report']['Prescreen_Report']['ResultDescription']
                        unsuccessful_credit_check(contact_id, lead.partnership_account_id, description, bureau,
                                                  product_type, trans_id, service_provider)
                        flash(_('Error Description: {}. Please contact Support for assistance.'.format(description)),
                              'danger')
                        return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')
                    credit_score = cipher.encrypt(credit_pull['Results']['XML_Report']['Prescreen_Report']['Score'])
                    score_card_name = credit_pull['Results']['XML_Report']['Prescreen_Report']['ScorecardName']
                    iframe = credit_pull['Results']['custom_report']
                    extract_url = re.findall('HTTPS?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\), ]|(?:%[0-9a-fA-F][0-9a-fA-F]))+',
                                             iframe)
                    url = json.dumps(extract_url[0])
                    encrypted_url = cipher.encrypt(url)
                    description = 'Successful soft credit pull.'
                else:
                    trans_id = cipher.encrypt(credit_pull['Results']['Transaction_Information']['Transid'])
                    if bureau == 'experian':
                        try:
                            credit_score = cipher.encrypt(credit_pull['Results']['bureau_xml_data']['XPN_Report']['subject_segments']['risk_models']['risk_model'][0]['score']['#text'])
                            score_card_name = credit_pull['Results']['bureau_xml_data']['XPN_Report']['subject_segments']['risk_models']['risk_model'][0]['ModelIndicator']['#text']
                        except:
                            description = 'Consumer file not found.'
                            unsuccessful_credit_check(contact_id, lead.partnership_account_id, description,
                                                      bureau, product_type, trans_id, service_provider)
                            flash(_('{} Please contact Support for assistance.').format(description), 'danger')
                            return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')

                    elif bureau == 'transunion' or bureau == 'equifax':
                        try:
                            credit_score = cipher.encrypt(credit_pull['Results']['bureau_xml_data']['TU_Report'][
                                                              'subject_segments']['scoring_segments'][
                                                              'scoring'][0]['score'])
                            score_card_name = credit_pull['Results']['bureau_xml_data']['TU_Report'][
                                'subject_segments']['scoring_segments']['scoring'][0]['ModelIndicator']['#text']
                        except Exception as e:
                            log.info('The exception is: {}'.format(e))
                            log.info('The trans id is {}'.format(trans_id))
                            try:
                                description = credit_pull['Results']['bureau_xml_data']['TU_Report']['Error']['#text']
                            except:
                                description = 'Consumer file not found.'
                            unsuccessful_credit_check(contact_id, lead.partnership_account_id, description,
                                                      bureau, product_type, trans_id, service_provider)
                            flash(_('{} Please contact Support for assistance.').format(description), 'danger')
                            return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')

                    url = credit_pull['Results']['custom_report_url']['iframe']['@src']
                    encrypted_url = cipher.encrypt(url)
                    description = 'Successful hard credit pull.'

                credit_entry = successful_credit_check_seven_hundred(contact_id, lead.partnership_account_id, trans_id,
                                                                     credit_score, description, bureau, product_type,
                                                                     service_provider, encrypted_url, score_card_name)
                log.info('The credit report id is: {}'.format(credit_entry))
            elif service_provider == 'Finserv':
                # Set the client to connect to the Finserv API
                client = finserv_credit_client(lead.partnership_account_id, 'prequalify')
                contact_birthday = ''
                if lead.birthday is None:
                    form_lead = FormLead \
                        .query \
                        .filter(and_(FormLead.contact_id == contact_id,
                                     FormLead.partnership_account_id == lead.partnership_account_id)) \
                        .first()
                    if form_lead is not None:
                        form_lead_field = FormLeadField \
                            .query \
                            .filter(and_(FormLeadField.lead_id == form_lead.id,
                                         or_(FormLeadField.field_id == 'birthday',
                                             FormLeadField.field_id == 'datepicker'))) \
                            .first()
                        if form_lead_field is None or form_lead_field.field_value is None:
                            contact_birthday = cipher.decrypt(form_lead_field.field_value)
                else:
                    contact_birthday = lead.birthday
                # Set a random trans_id for BuyerCall purposes because Finserv does not provide one
                trans_id = cipher.encrypt(uuid.uuid4().hex)
                try:
                    # format the birthday for the lead
                    contact_birthday = format_dob_year(contact_birthday)
                    if not contact_birthday:
                        description = 'This lead does not have a valid birth year.'
                        unsuccessful_credit_check(contact_id, lead.partnership_account_id, description, bureau,
                                                  product_type, trans_id, service_provider)
                        flash(_('{} Please update the lead with a valid Year of'
                                ' Birth and try again.').format(description), 'danger')
                        return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')

                    r = client.credit_prequalify.get_token()
                    r_content = json.loads(r)
                    token = 'Bearer ' + str(r_content['access_token'])
                    kwargs = {}
                    kwargs['FirstName'] = lead.firstname
                    kwargs['LastName'] = lead.lastname
                    kwargs['YearOfBirth'] = contact_birthday
                    kwargs['Address'] = format_street(address)
                    kwargs['Zip'] = format_zip(zip_code)
                    kwargs['City'] = format_city(city)
                    kwargs['State'] = format_state(state)
                    finserv_response = client.credit_prequalify.soft_pull(token, **kwargs)
                    credit_score = cipher.encrypt(str(finserv_response['score']))
                    approved = finserv_response['approved']
                    trades = cipher.encrypt(json.dumps({'trades': finserv_response['trades']}))
                    description = 'Successful soft credit pull.'
                    credit_entry = successful_credit_check_finserv(contact_id, lead.partnership_account_id, trans_id,
                                                                   credit_score, description, bureau, product_type,
                                                                   service_provider, approved, trades)
                    log.info('The credit report id is: {}'.format(credit_entry))
                    finserv_credit_report = CreditReports.query.filter(CreditReports.id == credit_entry).first()
                    finserv_credit_score = cipher.decrypt(finserv_credit_report.credit_score)
                    finserv_credit_approve = finserv_credit_report.is_approved
                    finserv_credit_trade_lines = json.loads(cipher.decrypt(finserv_credit_report.trades))
                except Exception as e:
                    log.error(traceback.format_exc())
                    description = str(e)
                    log.error('The finserv exception is: {} for contact {}'.format(e, contact_id))
                    unsuccessful_credit_check(contact_id, lead.partnership_account_id, description, bureau,
                                              product_type, trans_id, service_provider)
                    flash(_('We were unable to run the soft pull for this lead. Please make sure all the lead fields '
                            'are complete and correct.'), 'danger')
                    return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')
        except Exception as e:
            log.error(traceback.format_exc())
            flash(_('An unexpected error occurred: {}. Please contact Support for assistance.'.format(e)), 'danger')
            return redirect(url_for('contacts.contact_edit', id=contact_id) + '#credit')

    ActivityLogs.add_log(current_user.id, ActivityType.CREDIT, ActivityName.VIEW, request, contact_id)

    return render_template('contacts/credit_report.jinja2', lead=lead, url=url, contact_id=contact_id,
                           finserv_credit_score=finserv_credit_score, finserv_credit_approve=finserv_credit_approve,
                           finserv_credit_trade_lines=finserv_credit_trade_lines)


@contacts.route('/contacts/import/leads', methods=['GET', 'POST'])
@login_required
@csrf.exempt
def import_lead_file():
    error_result = []
    contacts = []
    csvfile = None
    csv_error_list = ''
    csv_errors = False
    error_status = False
    error_message = ''
    contact_phone_list = []
    contact_count = 0
    contact_total_count = 0
    partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership
    header = [
        'No', 'First Name', 'Last Name', 'Email', 'Phone Number', 'Error'
    ]

    if request.method == 'POST':

        # Check if being viewed by super partner
        if viewing_partnership_account:
            partnership_account_id = current_user.get_user_viewing_partnership_account_id

        current_datetime = datetime.now()

        if 'file' not in request.files:
            error_message = 'No file found.'
            error_status = True
        else:
            try:
                csvfile = request.files['file']
                contact_list = db.session\
                    .query(Contact.phonenumber_1)\
                    .filter(Contact.partnership_account_id == partnership_account_id)\
                    .distinct()

                for contact in contact_list:
                    if contact.phonenumber_1 and contact.phonenumber_1 not in contact_phone_list:
                        formated_phonenumber = contact\
                            .phonenumber_1\
                            .replace(" ", "")\
                            .replace("(", "")\
                            .replace(")", "")\
                            .replace("-", "") \
                            .replace("+", "")
                        contact_phone_list.append(formated_phonenumber)

            except Exception as ex:
                error_message = 'An error occurred while processing the file.'
                error_status = True
                log.error(traceback.format_exc())

            if not error_status and allowed_file(csvfile.filename):
                stream = StringIO(csvfile.stream.read().decode("UTF8"), newline=None)
                reader = csv.DictReader(stream)
                reader.fieldnames = [fn.lower()
                                     .replace(" ", "")
                                     .replace("_", "")
                                     .replace("-", "") for fn in reader.fieldnames]
                data = [row for row in reader]

                status_list = Status.get_assigned_status_list_as_dict(current_user.partnership_account_id)
                new_status_dict = {}
                marketing_source_list = MarketingSources.get_assigned_source_list_as_dict(current_user.partnership_account_id)
                new_marketing_source_dict = {}

                for row in data:
                    contact_total_count += 1

                    contact_firstname = ''
                    if 'firstname' in row and valid_csv_value(row['firstname']):
                        contact_firstname = row['firstname']

                    contact_lastname = ''
                    if 'lastname' in row and valid_csv_value(row['lastname']):
                        contact_lastname = row['lastname']

                    contact_city = ''
                    if 'city' in row and valid_csv_value(row['city']):
                        contact_city = row['city']

                    contact_state = ''
                    if 'state' in row and valid_csv_value(row['state']):
                        contact_state = row['state']

                    contact_zip = ''
                    if 'zip' in row and valid_csv_value(row['zip']):
                        contact_zip = row['zip']
                    elif 'postalcode' in row and valid_csv_value(row['postalcode']):
                        contact_zip = row['postalcode']
                    elif 'zipcode' in row and valid_csv_value(row['zipcode']):
                        contact_zip = row['zipcode']

                    contact_address_1 = ''
                    if 'address1' in row and valid_csv_value(row['address1']):
                        contact_address_1 = row['address1']

                    contact_address_2 = ''
                    if 'address2' in row and valid_csv_value(row['address2']):
                        contact_address_2 = row['address2']

                    contact_phonenumber_1 = None
                    phone_found_on_main = False
                    contact_phonenumber_2 = None
                    if 'home/mainnumber' in row and valid_csv_value(row['home/mainnumber']):
                        contact_phonenumber_1 = row['home/mainnumber']
                        phone_found_on_main = True
                    elif 'phonenumber' in row and valid_csv_value(row['phonenumber']):
                        contact_phonenumber_1 = row['phonenumber']
                        phone_found_on_main = True
                    elif 'phonenumber1' in row and valid_csv_value(row['phonenumber1']):
                        contact_phonenumber_1 = row['phonenumber1']
                        phone_found_on_main = True
                    elif 'mainnumber' in row and valid_csv_value(row['mainnumber']):
                        contact_phonenumber_1 = row['mainnumber']
                        phone_found_on_main = True
                    elif 'phone' in row and valid_csv_value(row['phone']):
                        contact_phonenumber_1 = row['phone']
                        phone_found_on_main = True

                    if contact_phonenumber_1 is None or contact_phonenumber_1 == '':
                        if 'mobilenumber' in row and valid_csv_value(row['mobilenumber']):
                            contact_phonenumber_1 = row['mobilenumber']
                        elif 'mobilephonenumber' in row and valid_csv_value(row['mobilephonenumber']):
                            contact_phonenumber_1 = row['mobilephonenumber']
                        elif 'cellphone' in row and valid_csv_value(row['cellphone']):
                            contact_phonenumber_1 = row['cellphone']
                        elif 'cellphonenumber' in row and valid_csv_value(row['cellphonenumber']):
                            contact_phonenumber_1 = row['cellphonenumber']
                        elif 'cell' in row and valid_csv_value(row['cell']):
                            contact_phonenumber_1 = row['cell']

                    if contact_phonenumber_1 is None or contact_phonenumber_1 == '':
                        if 'worknumber' in row and valid_csv_value(row['worknumber']):
                            contact_phonenumber_1 = row['worknumber']
                        elif 'workphonenumber' in row and valid_csv_value(row['workphonenumber']):
                            contact_phonenumber_1 = row['workphonenumber']
                        elif 'work' in row and valid_csv_value(row['work']):
                            contact_phonenumber_1 = row['work']

                    if contact_phonenumber_1:
                        if phone_found_on_main:
                            if 'mobilenumber' in row and valid_csv_value(row['mobilenumber']):
                                contact_phonenumber_2 = row['mobilenumber']
                            elif 'mobilephonenumber' in row and valid_csv_value(row['mobilephonenumber']):
                                contact_phonenumber_2 = row['mobilephonenumber']
                            elif 'cellphone' in row and valid_csv_value(row['cellphone']):
                                contact_phonenumber_2 = row['cellphone']
                            elif 'cellphonenumber' in row and valid_csv_value(row['cellphonenumber']):
                                contact_phonenumber_2 = row['cellphonenumber']
                            elif 'cell' in row and valid_csv_value(row['cell']):
                                contact_phonenumber_2 = row['cell']
                            elif 'phonenumber2' in row and valid_csv_value(row['phonenumber2']):
                                contact_phonenumber_2 = row['phonenumber2']

                        if contact_phonenumber_2 is None or contact_phonenumber_2 == '':
                            if 'worknumber' in row and valid_csv_value(row['worknumber']):
                                contact_phonenumber_2 = row['worknumber']
                            elif 'phonenumber2' in row and valid_csv_value(row['phonenumber2']):
                                contact_phonenumber_2 = row['phonenumber2']
                            elif 'workphonenumber' in row and valid_csv_value(row['workphonenumber']):
                                contact_phonenumber_2 = row['workphonenumber']
                            elif 'work' in row and valid_csv_value(row['work']):
                                contact_phonenumber_2 = row['work']

                    if contact_phonenumber_1:
                        if not is_do_not_call_csv_value(contact_phonenumber_1):
                            contact_phonenumber_1 = contact_phonenumber_1

                    if contact_phonenumber_2:
                        if not is_do_not_call_csv_value(contact_phonenumber_2):
                            contact_phonenumber_2 = contact_phonenumber_2

                    contact_is_do_not_call = False
                    if 'nevercontacttype' in row:
                        contact_is_do_not_call = is_do_not_call_csv_value(row['nevercontacttype'])
                    elif 'isdonotcall' in row:
                        contact_is_do_not_call = is_do_not_call_csv_value(row['isdonotcall'])
                    elif 'donotcall' in row:
                        contact_is_do_not_call = is_do_not_call_csv_value(row['donotcall'])

                    contact_email = ''
                    if 'email' in row and valid_csv_value(row['email']):
                        contact_email = row['email']
                    elif 'emailaddress' in row and valid_csv_value(row['emailaddress']):
                        contact_email = row['emailaddress']

                    contact_birthday = ''
                    if 'birthday' in row and valid_csv_value(row['birthday']):
                        contact_birthday = row['birthday']
                    elif 'birthdate' in row and valid_csv_value(row['birthdate']):
                        contact_birthday = row['birthdate']
                    elif 'dateofbirth' in row and valid_csv_value(row['dateofbirth']):
                        contact_birthday = row['dateofbirth']

                    if len(contact_birthday) > 10:
                        contact_birthday = contact_birthday[0: 10]

                        try:
                            datetime.strptime(contact_birthday, '%m/%d/%Y')
                        except ValueError:
                            contact_birthday = ''

                    contact_status = ''
                    if 'status' in row and valid_csv_value(row['status']):
                        contact_status = row['status']
                    elif 'individualtype' in row and valid_csv_value(row['individualtype']):
                        contact_status = row['individualtype']

                    if contact_status:
                        contact_status_lower_case = contact_status.lower()

                        if contact_status_lower_case not in status_list:
                            new_status_dict[contact_status_lower_case] = contact_status

                        contact_status = contact_status_lower_case
                    else:
                        contact_status = 'no status'

                    contact_marketing_source = ''
                    if 'marketingsource' in row and valid_csv_value(row['marketingsource']):
                        contact_marketing_source = row['marketingsource']

                    if contact_marketing_source:
                        contact_marketing_source_lower_case = contact_marketing_source.lower()

                        if contact_marketing_source_lower_case not in marketing_source_list:
                            new_marketing_source_dict[contact_marketing_source_lower_case] = contact_marketing_source

                        contact_marketing_source = contact_marketing_source_lower_case

                    contact_note = ''
                    if 'note' in row and valid_csv_value(row['note']):
                        contact_note = row['note']
                    elif 'notes' in row and valid_csv_value(row['notes']):
                        contact_note = row['notes']
                    elif 'specialnote' in row and valid_csv_value(row['specialnote']):
                        contact_note = row['specialnote']
                    elif 'specialnotes' in row and valid_csv_value(row['specialnotes']):
                        contact_note = row['specialnotes']

                    valid_message = validate_contact(contact_total_count,
                                                     contact_firstname,
                                                     contact_lastname,
                                                     contact_phonenumber_1,
                                                     contact_email,
                                                     contact_phone_list)

                    if valid_message is None:
                        new_contact = Contact()
                        new_contact.firstname = contact_firstname
                        new_contact.lastname = contact_lastname
                        new_contact.phonenumber_1 = format_phone_number(contact_phonenumber_1)
                        new_contact.phonenumber_2 = format_phone_number(contact_phonenumber_2)
                        new_contact.email = contact_email
                        new_contact.is_do_not_call = contact_is_do_not_call
                        new_contact.address_1 = contact_address_1
                        new_contact.address_2 = contact_address_2
                        new_contact.state = contact_state
                        new_contact.zip = contact_zip
                        new_contact.city = contact_city
                        new_contact.birthday = contact_birthday
                        new_contact.status = contact_status
                        new_contact.marketing_source = contact_marketing_source
                        new_contact.partnership_account_id = partnership_account_id
                        new_contact.external_source_type = 'import'

                        if contact_note and contact_note != "":
                            new_contact_note = ContactNotes()
                            new_contact_note.created_on = current_datetime
                            new_contact_note.updated_on = current_datetime
                            new_contact_note.partnership_account_id = partnership_account_id
                            new_contact_note.user_id = current_user.id
                            new_contact_note.text = contact_note
                            new_contact_note.is_enabled = True
                            new_contact.note_list.append(new_contact_note)

                        contacts.append(new_contact)
                        contact_count += 1
                    else:
                        error_result.append(valid_message)

                try:
                    if len(contacts) > 0:
                        # process status
                        if new_status_dict:
                            Status.add_status_dict(new_status_dict, partnership_account_id)

                        # process marketing sources
                        if new_marketing_source_dict:
                            MarketingSources.add_source_dict(new_marketing_source_dict, partnership_account_id)

                        db.session.add_all(contacts)
                        db.session.commit()
                except Exception as ex:
                    error_message = 'An error occurred while processing the file.'
                    error_status = True
                    log.error(traceback.format_exc())
            else:
                error_message = 'Only CSV files allowed.'
                error_status = True

        if error_result and len(error_result) > 0:
            csv_errors = True
            error_result.insert(0, header)
            joiner = ","

            for row in error_result:
                if row:
                    csv_error_list += joiner.join(row) + "\n"

        if error_status:
            return jsonify(success=False, message=error_message), 201
        elif not error_status:
            if contact_count == 0 and contact_total_count > 0:
                success_message = str(contact_count) + " leads out of " + str(contact_total_count) + " were imported."
                success_status = False
            elif contact_count == contact_total_count:
                success_message = "All " + str(contact_count) + " lead(s) successfully imported."
                success_status = True
            else:
                success_message = "Only " + str(contact_count) + " lead(s) out of " + str(contact_total_count) + " were successfully imported."
                success_status = True

            return jsonify(success=success_status, message=success_message, csv_download=csv_errors, csv_error_list=csv_error_list, count=contact_count, total_count=contact_total_count), 200


@contacts.route('/contacts/import/leads/example', methods=['GET', 'POST'])
@login_required
def download():
    return send_file('blueprints/contacts/templates/contacts/example.csv', as_attachment=True)