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: //proc/thread-self/root/home/arjun/projects/buyercall/buyercall/blueprints/contacts/endpoints.py
import logging as log
from flask_login.utils import login_required
from flask import (current_app as app)
from buyercall.blueprints.user.decorators import api_role_required
from buyercall.lib.util_rest import api_jsonify
from flask_login import current_user
from flask import Blueprint, request
from buyercall.blueprints.contacts.models import Contact, ContactChannelTie, ContactTags, Lead, Message, Status
from buyercall.blueprints.contacts.serializers import ContactTagSchema
from flask import Blueprint, jsonify
from datetime import datetime, date, timedelta
from dateutil import rrule
from sqlalchemy import extract, or_, and_, desc, func, text
from pytz import timezone
from .models import Contact, ContactNotes, Lead, Message, CreditReports, Campaigns, BdcStatuses, Status, \
    MarketingSources, ContactVehicle
from buyercall.blueprints.agents.models import Agent
from buyercall.blueprints.form_leads.models import FormLead, FormLeadField
from sqlalchemy.orm import contains_eager
from buyercall.blueprints.filters import format_phone_number
from buyercall.lib.util_crypto import AESCipher
from flask import current_app as app
import re
from sqlalchemy.orm import contains_eager, load_only
from buyercall.blueprints.filters import format_phone_number, format_phone_number_bracket
from buyercall.lib.util_datetime import tza_to_leadtime
email_regex = re.compile(r'\S+@\S+\.\S+')
phone_regex = re.compile(r'^\+?[0-9]{10,12}$')
from buyercall.extensions import db

contact_api = Blueprint('contactsapi', __name__, url_prefix='/api/contacts')
logger = log.getLogger(__name__)


# INBOX APIS
# ----------
@login_required
def account_leads():
    success = True
    message = "Account leads fetched successfully!"
    status_code = 200
    data = []
    partnership_account_id = current_user.partnership_account_id or 1

    leads = Contact.query.filter(Contact.partnership_account_id == partnership_account_id).all()
    for lead in leads:
        _lead = {
            "leadId": lead.sid,
            "name": f'{lead.firstname} {lead.lastname}',
            "primaryTags": ['Hot', 'Qualified Lead'],
            "secondaryTags": ['Pre-approved'],
            "manualStatus": lead.status
        }
        contact_sources = []
        contact_channel_ties = ContactChannelTie.query.filter(ContactChannelTie.contact == lead.id).all()
        for cct in contact_channel_ties:
            contact_sources.append(cct.source_obj)

        unique_contact_sources = list(set(contact_sources))
        _sources = []
        for source in unique_contact_sources:
            _sources.append({
                "id": source.sid,
                "name": source.name
            })
        _lead['sources'] = _sources
        data.append(_lead)
    return api_jsonify(data, status_code, message, success)


@api_role_required('agent', 'admin', 'partner', 'sysadmin')
def get_contact_tags():
    message = "Contact tags fetched successfully"
    contact_tags = ContactTags.query.filter(ContactTags.is_active == True, ContactTags.tag_type == 'secondary').all()
    return api_jsonify(data=ContactTagSchema(many=True).dump(contact_tags), message=message)


@api_role_required('agent', 'admin', 'partner', 'sysadmin')
def get_tags_by_contact(contact_sid):
    message = "Tags of the contact fetched successfully!"
    contact = Contact.get_by_sid(contact_sid)
    if contact:
        contact_tags = ContactTags.query.filter(ContactTags.is_active == True, ContactTags.contacts.any(id=contact.id))
        return api_jsonify(data=ContactTagSchema(many=True).dump(contact_tags), message=message)
    message = "Contact not found"
    return api_jsonify({}, status_code=404, message=message, success=False)


@api_role_required('agent', 'admin', 'partner', 'sysadmin')
def create_contact_tag():
    message = "Contact tag created successfully"
    status_code = 201
    success = True
    received = request.get_json() or {}
    name = received.get('name', '')
    if name:
        existing_tag = ContactTags.get_by_name(name)
        if not existing_tag:
            contact_tag = ContactTags.create(name=name.lower(), tag_type='secondary')
        else:
            message = f"The tag '{name}' already exists"
            status_code = 401
            success = False
    else:
        message = "Invalid parameters"
        status_code = 401
        success = False

    return api_jsonify(message=message, status_code=status_code, success=success)

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

@api_role_required('agent', 'admin', 'partner', 'sysadmin')
def manage_tag_by_contact(contact_sid):
    message = "Tags of the contact updated successfully!"
    contact = Contact.get_by_sid(contact_sid)
    if contact:
        received = request.get_json()
        tags = received.get('tags', [])
        if tags:
            contact_tags = ContactTags.get_by_sids(tags)
            contact.contact_tags = contact_tags
            contact.save()
            return api_jsonify(message=message)
        else:
            message = "No tags found"
    else:
        message = "Contact not found"
    return api_jsonify({}, status_code=404, message=message, success=False)



@login_required
def contacts_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
    print(partnership_account_id)
    print(partnership_account_group_viewing)

    # 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'))
    print(date_from, date_to, "#######")
    assigned_agent = (request.args.get('aa'))
    print(assigned_agent, "#######--assigned_agent")
    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'))
    print(form_check, phone_check, sms_check, import_check, api_check, "#######--assigned_agent")
    print(adf_import_check, phone_source, sms_source, marketing_source, form_source)
    print(call_status, call_bdc_status)
    date_difference = days_between(date_from, date_to)
    print(date_difference, "++++++++++++++")

    # 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,
        Contact.status,
        Contact.agent_assigned,
        Contact.credit_score,
        #Contact.phone_source,
        Contact.lastname,
        #Contact.caller_id
        Contact.sid
    ]

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

    # define/execute main query
    total = Contact.query\
        .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

   
    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()
    ]
    print(data,"+++++data")
    try:
        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'
    except Exception as e:
        print(e)

    print(data,"+++++data")
    user = current_user
    value = None
    if user.agent:
        if user.agent.timezone:
            if user.agent.timezone == 'US/Eastern':
                value = 'EST'
            elif user.agent.timezone == 'US/Central':
                value = 'CST'
            elif user.agent.timezone == 'US/Mountain':
                value = 'MST'
            elif user.agent.timezone == 'US/Pacific':
                value = 'PST'
            else:
                value = None

    for user in data:
        if user.get(2):
            user[2] = format_phone_number_bracket(user[2])
        if user.get(4):
            user[4] = user[4].replace('-', ' ')
        if user.get(5):
            user[5] =  f'{user[5].strftime("%b %d, %I:%M %p ")} {value}'
        if user.get(6):
            user[6] =  f'{user[6].strftime("%b %d, %I:%M %p ")} {value}'
        
    print(data,"+++++data")
    # 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'))


    return jsonify(
        recordsFiltered=total_leads,
        recordsTotal=total_leads,
        data=data,
        totalLeads=total_leads,
        totalPhone=total_phone,
        totalUniquePhone=total_unique_phone,
        totalMessages=total_messages,
        totalUniqueMessages=total_unique_messages,
        totalFormLeads=total_formleads,
        totalUniqueFormLeads=total_unique_formleads,
        offset=offset
    )




@login_required
def contacts_add():
    print("------------")
    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')
        print(request_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:
            try:
                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()
            except Exception as e:
                print(e, "------")

            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
    })


def contacts_add_bulk():
    print("------------")
    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:
        contacts_data = data.get('contacts')

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

                agent_assigned = None
                agent_assigned_id = None

                # Validation checks...
                # (similar to the ones in the original function)

                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()
            success = True
        else:
            error_message.append('No contact data provided.')
    else:
        error_message.append('No data received.')

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



@login_required
def contacts_advanced_filters():
    """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(text('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(
        text('phonenumbers.id'), 
        text('phonenumbers.friendly_name'), 
        text('phonenumbers.phonenumber')
    ).filter(filter_by_lead).distinct()

    outbound_data = Lead.query.join(Lead.contact)\
        .outerjoin(Lead.widget).options(
        contains_eager(Lead.widget)
    ).with_entities(text('widgets.guid'), text('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(
        text('phonenumbers.id'), 
        text('phonenumbers.friendly_name'), 
        text('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(text('external_forms.id'), text('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


    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')]

    # Populate marketing result
    marketing_result_list = {}
    marketing_list = MarketingSources.get_assigned_source_list(partnership_account_id)
    for item in marketing_list:
        marketing_id = item.source
        marketing_result_list[marketing_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
    
    campaign_list, default_campaign = Campaigns.get_assigned_campaign_list_as_dict(partnership_account_id)


    filters_result = {
        '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,
    }
    leads_result = {
        'status_choice':status_result,
        'agents_list': agents,
        'marketing_result_list': marketing_result_list,
        'campaign_list':campaign_list,
        'default_campaign':default_campaign
    }
    response = {'leads': leads_result, 'filters': filters_result}
    return jsonify(response)



@login_required
def contacts_edit(contact_sid): 
    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

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


    data = request.get_json()

    if data:
        # Retrieve the existing contact
        existing_contact = Contact.get_by_sid(contact_sid)

        if existing_contact:
            contact_vehicle = ContactVehicle.query.filter(ContactVehicle.contact_id == existing_contact.id).first()
            
            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')
            campaign_id = data.get('campaignId')
            social_security = data.get('social_security')

            # Update the existing contact with new data
            if request_email:
                existing_contact.email = request_email
            if request_status:
                existing_contact.status = request_status
            if request_marketing_source:
                existing_contact.marketing_source = request_marketing_source
            if request_firstname:
                existing_contact.firstname = request_firstname
            if request_lastname:
                existing_contact.lastname = request_lastname
            if request_agent_assigned_id:
                existing_contact.agent_assigned = request_agent_assigned_id
            if request_agent_assigned_id:
                existing_contact.agent_id = request_agent_assigned_id
            if request_address_1:
                existing_contact.address_1 = request_address_1
            if request_address_2:
                existing_contact.address_2 = request_address_2
            if request_city:
                existing_contact.city = request_city
            if request_state:
                existing_contact.state = request_state
            if request_country:
                existing_contact.country = request_country
            if request_zip:
                existing_contact.zip = request_zip
            if request_birthday:
                existing_contact.birthday = request_birthday
            if request_do_not_call is not None:
                existing_contact.is_do_not_call = request_do_not_call
            if request_unsubscribed is not None:
                existing_contact.is_unsubscribe = request_unsubscribed
            if campaign_id:
                try:
                    existing_contact.campaign_id = int(campaign_id)
                except ValueError:
                    invalid_message.append('Invalid campaign ID.')
            if social_security:
                existing_contact.social_security = social_security

            if partnership_account.business_type == 'automotive':
                update_contact_vehicle(existing_contact, data, contact_vehicle)


            # try:
            db.session.commit()
            success = True
            # except Exception as e:
            #     db.session.rollback()
            #     error_message.append(str(e))
        else:
            error_message.append('Contact not found.')
    else:
        error_message.append('No request parameters received to edit contact.')

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



@login_required
def contacts_details(contact_sid):
    print("------------")
    partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership
    error_message = []
    success = False

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


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

    # Retrieve the contact based on contact_sid
    existing_contact = Contact.get_by_sid(contact_sid)
    import json
    try:
        contact_vehicle = ContactVehicle.query.filter(ContactVehicle.contact_id == existing_contact.id).first()
        contact_vehicle_data = {
            'created_on': contact_vehicle.created_on.strftime('%Y-%m-%d %H:%M:%S'),  # Convert to string
            'updated_on': contact_vehicle.updated_on.strftime('%Y-%m-%d %H:%M:%S'),  # Convert to string
            'id': contact_vehicle.id,
            'contact_id': contact_vehicle.contact_id,
            'current_vin': contact_vehicle.current_vin,
            'current_make': contact_vehicle.current_make,
            'current_model': contact_vehicle.current_model,
            'current_year': contact_vehicle.current_year,
            'current_mileage': contact_vehicle.current_mileage,
            'current_condition': contact_vehicle.current_condition,
            'current_value': contact_vehicle.current_value,  # Convert Decimal to float
            'interest_vin': contact_vehicle.interest_vin,
            'interest_make': contact_vehicle.interest_make,
            'interest_model': contact_vehicle.interest_model,
            'interest_trim': contact_vehicle.interest_trim,
            'interest_stock': contact_vehicle.interest_stock,
            'interest_year': contact_vehicle.interest_year,
            'interest_price': contact_vehicle.interest_price,  # Convert Decimal to float
            'interest_status': contact_vehicle.interest_status,
            'interest_mileage': contact_vehicle.interest_mileage,
            'interest_condition': contact_vehicle.interest_condition,
            'interest_listing_url': contact_vehicle.interest_listing_url
        }
        contact_vehicle = (contact_vehicle_data)
    except Exception as e:
        contact_vehicle = {}
        print(e,"contact_vehicle=======")

    if existing_contact:
        # If contact is found, return contact details
        contact_data = {
            'id': existing_contact.id,
            'firstname': existing_contact.firstname,
            'lastname': existing_contact.lastname,
            'email': existing_contact.email,
            'phonenumber': existing_contact.phonenumber_1,
            'status': existing_contact.status,
            'marketing_source': existing_contact.marketing_source,
            'agent_assigned_id': existing_contact.agent_id,
            'agent_assigned_text': existing_contact.agent_assigned,
            'address1': existing_contact.address_1,
            'address2': existing_contact.address_2,
            'city': existing_contact.city,
            'state': existing_contact.state,
            'country': existing_contact.country,
            'zip': existing_contact.zip,
            'birthday': existing_contact.birthday,
            'do_not_call': existing_contact.is_do_not_call,
            'unsubscribed': existing_contact.is_unsubscribe,
            'contact_notes': get_contact_notes(existing_contact.id),  # Include ContactNotes
            # Add other fields as needed
            'business_type': partnership_account.business_type,
            'credit_score': existing_contact.credit_score
        }
        try:
            # Return the contact notes of this contact
            all_contact_notes = ContactNotes.query.join(Contact).filter(
                ContactNotes.contact_id == existing_contact.id,
                ContactNotes.partnership_account_id == partnership_account_id,
                ContactNotes.is_enabled == 't'
            ).order_by(desc(ContactNotes.created_on)).all()
        except Exception as e:
            all_contact_notes = []
            print(e)

        try:
            # Return all calls for this contact
            previous_calls = Lead.query.filter(
                Lead.partnership_account_id == partnership_account_id,
                Lead.contact_id == existing_contact.id
            ).options(
                load_only("firstname", "lastname", "starttime", "call_type", "status")
            ).order_by(text('starttime desc')).limit(10).all()
        except Exception as e:
            previous_calls = []
            print(e,"previous_calls")
        
        try:
            # Return all messages for this contact
            previous_messages_raw = Message.query.filter(
                Message.partnership_account_id == partnership_account_id,
                Message.contact_id == existing_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)
        except Exception as e:
            previous_messages_raw = []
            print(e,"previous_messages")
        
        try:
            # Return all form lead for this contact
            previous_forms = FormLead.query.filter(
                FormLead.partnership_account_id == partnership_account_id,
                FormLead.contact_id == existing_contact.id
            ).order_by(text('form_leads.created_on desc')).limit(10).all()
        except Exception as e:
            previous_forms = []
            print(e,"previous_forms")

        # Return the credit reports for this contact
        try:
            credit_reports_data = CreditReports.contact_credit_score_object(existing_contact.id, partnership_account_id)
            credit_reports = [report.to_dict() for report in credit_reports_data] 
        except Exception as e:
            credit_reports = []
            print(e,"credit_reports")
        success = True
    else:
        error_message.append('Contact not found.')

    return jsonify({
        'error_message': error_message,
        'success': success,
        'contact': contact_data if success else None,
        'contact_notes':all_contact_notes if success else None,
        'previous_calls':previous_calls if success else None,
        'previous_forms': previous_forms  if success else None,
        'previous_messages_raw': previous_messages_raw if success else None,
        'credit_reports' : credit_reports if success else None,
        'contact_vehicle' : contact_vehicle if success else None,
    })


def get_contact_notes(contact_id):
    contact_note = ContactNotes.query.filter_by(contact_id=contact_id).first()
    return contact_note.text if contact_note else None


@login_required
def set_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
    data = request.get_json()
    campaign_id = data.get('id', '')
    campaign_text = data.get('text', '')
    print(campaign_id,"campaign_id------")
    if (int(campaign_id) < 0):
        print(campaign_id,"campaign_id------")
        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
    })



def update_contact_vehicle(contact, data, contact_vehicle=None):
    for key, value in data.items():
        if value == "":
            data[key] = None
    
    if contact_vehicle:
        # Update existing contact_vehicle if data is provided
        if data:
            edit_current_year = data.get('current_year')
            if edit_current_year == 0:
                edit_current_year = None

            edit_interest_year = data.get('interest_year')
            if edit_interest_year == 0:
                edit_interest_year = None

            ContactVehicle.update(contact_id=contact.id,
                                current_vin=data.get('current_vin'),
                                current_make=data.get('current_make'),
                                current_model=data.get('current_model'),
                                current_year=edit_current_year,
                                current_mileage=data.get('current_mileage'),
                                current_condition=data.get('current_condition'),
                                current_value=data.get('current_value'),
                                interest_vin=data.get('interest_vin'),
                                interest_make=data.get('interest_make'),
                                interest_model=data.get('interest_model'),
                                interest_year=edit_interest_year,
                                interest_trim=data.get('interest_trim'),
                                interest_stock=data.get('interest_stock'),
                                interest_price=data.get('interest_price'),
                                interest_status=data.get('interest_status'),
                                interest_mileage=data.get('interest_mileage'),
                                interest_condition=data.get('interest_condition'),
                                interest_listing_url=data.get('interest_listing_url')
                                )
    else:
        # Create new ContactVehicle if contact_vehicle doesn't exist
        new_contact_vehicle = ContactVehicle(
            contact_id=contact.id,
            current_vin=data.get('current_vin'),
            current_make=data.get('current_make'),
            current_model=data.get('current_model'),
            current_year=data.get('current_year'),
            current_mileage=data.get('current_mileage'),
            current_condition=data.get('current_condition'),
            current_value=data.get('current_value'),
            interest_vin=data.get('interest_vin'),
            interest_make=data.get('interest_make'),
            interest_model=data.get('interest_model'),
            interest_year=data.get('interest_year'),
            interest_trim=data.get('interest_trim'),
            interest_stock=data.get('interest_stock'),
            interest_price=data.get('interest_price'),
            interest_status=data.get('interest_status'),
            interest_mileage=data.get('interest_mileage'),
            interest_condition=data.get('interest_condition'),
            interest_listing_url=data.get('interest_listing_url')
        )

        db.session.add(new_contact_vehicle)
        db.session.commit()


@login_required
def contacts_credit_details(contact_sid):
    existing_contact = Contact.get_by_sid(contact_sid)
    partnership_account_id = current_user.partnership_account_id
    try:
        credit_reports_data = CreditReports.contact_credit_score_object(existing_contact.id, partnership_account_id)
        credit_reports = [report.to_dict() for report in credit_reports_data] 
        success = True
    except Exception as e:
        credit_reports = []
        print(e,"credit_reports")
        success = False

    return jsonify({
        'success': success,
        'credit_reports' : credit_reports if success else None
    })