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/form_leads/form_tasks.py
import logging as log
import traceback
import datetime
import os.path
import redis

from buyercall.lib.util_crypto import AESCipher
from flask import current_app, render_template, json
from buyercall.app import create_celery_app
from sqlalchemy import and_
from buyercall.extensions import db
from flask_weasyprint import HTML, render_pdf
from buyercall.blueprints.agents import Agent
from buyercall.blueprints.contacts.models import Contact, Campaigns, ContactVehicle
from buyercall.blueprints.form_leads.models import (FormLead, ExternalForm,
                                                    FormLeadField, ExternalFormField)
from buyercall.blueprints.filters import format_phone_number
from buyercall.lib.util_ses_email import send_ses_email
from buyercall.blueprints.sms.views import send_text_message

celery = create_celery_app(current_app)


def decrypt_value(text):
    crypto_key = current_app.config['CRYPTO_SECRET_KEY']
    cipher = AESCipher(crypto_key)

    if text is not None:
        try:
            return cipher.decrypt(text)
        except TypeError:
            return text
        except ValueError:
            return text
    else:
        return text


@celery.task
def add_form_contact(form_lead_id, first_name, last_name, email_address, phone_number,
                     address_1, address_2, city, state, zip, country, rep, interest_vehicle_year, interest_vehicle_make,
                     interest_vehicle_model, interest_vehicle_vin, interest_vehicle_trim, interest_vehicle_stock_no,
                     interest_vehicle_price, interest_vehicle_mileage, interest_vehicle_condition,
                     interest_vehicle_listing_url, tradein_vehicle_year, tradein_vehicle_make, tradein_vehicle_model,
                     tradein_vehicle_vin, tradein_vehicle_price, tradein_vehicle_mileage, tradein_vehicle_condition,
                     partnership_account_id, updated_on, dob, eq_lead=False, campaign=None,
                     **kwargs):

    latest_lead = FormLead.query.filter(FormLead.id == form_lead_id)\
        .order_by(FormLead.created_on.desc()).first()

    phone = format_phone_number(phone_number)

    # Add campaign id if available
    campaign_id = None
    if campaign:
        campaign_id = Campaigns.add_campaign(campaign, partnership_account_id)

    contact = Contact.query\
        .filter(Contact.phonenumber_1 == phone)\
        .filter(Contact.partnership_account_id == partnership_account_id)\
        .first()
    if contact:
        log.info('The contact number is {}'.format(contact.phonenumber_1))
        contact.updated_on = updated_on
        contact.partnership_account_id = partnership_account_id
        if first_name:
            contact.firstname = first_name
        if last_name:
            contact.lastname = last_name
        if email_address:
            contact.email = email_address
        if address_1:
            contact.address_1 = address_1
        if address_2:
            contact.address_2 = address_2
        if city:
            contact.city = city
        if state:
            contact.state = state
        if zip:
            contact.zip = zip
        if country:
            contact.country = country
        old_agent = contact.agent_id
        if not contact.agent_assigned:
            contact.agent_assigned = rep
            agent_id = Agent.reverse_agent_id_lookup(contact.partnership_account_id, rep)
            if agent_id:
                contact.agent_id = agent_id
        if dob:
            contact.birthday = dob
        if eq_lead:
            contact.is_eq_lead = eq_lead
        if campaign_id:
            contact.campaign_id = campaign_id
        db.session.commit()
        if contact.agent_id != old_agent:
            from buyercall.blueprints.mobile.utils import send_agent_push_notification
            send_agent_push_notification(contact)
    else:
        try:
            contact = Contact(
                firstname=first_name,
                lastname=last_name,
                phonenumber_1=phone,
                email=email_address,
                address_1=address_1,
                address_2=address_2,
                birthday=dob,
                city=city,
                state=state,
                zip=zip,
                agent_assigned=rep,
                partnership_account_id=partnership_account_id,
                is_eq_lead=eq_lead,
                campaign_id=campaign_id
            )
        except Exception as e:
            log.error(e)
        agent_id = Agent.reverse_agent_id_lookup(contact.partnership_account_id, rep)
        if agent_id:
            contact.agent_id = agent_id
        db.session.add(contact)
        db.session.flush()
        db.session.commit()

        log.info('The contact has been added')
        from buyercall.blueprints.mobile.utils import send_agent_push_notification
        send_agent_push_notification(contact)

    new_contact = Contact \
        .query \
        .filter(Contact.phonenumber_1 == phone) \
        .filter(Contact.partnership_account_id == partnership_account_id) \
        .first()
    try:
        if new_contact:
            latest_lead.contact_id = new_contact.id
            db.session.commit()
            contact_vehicle = ContactVehicle.query\
                .filter(ContactVehicle.contact_id == new_contact.id).first()
            if contact_vehicle:
                if interest_vehicle_year:
                    contact_vehicle.interest_year = interest_vehicle_year
                if interest_vehicle_make:
                    contact_vehicle.interest_make = interest_vehicle_make
                if interest_vehicle_model:
                    contact_vehicle.interest_model = interest_vehicle_model
                if interest_vehicle_vin:
                    contact_vehicle.interest_vin = interest_vehicle_vin
                if interest_vehicle_trim:
                    contact_vehicle.interest_trim = interest_vehicle_trim
                if interest_vehicle_stock_no:
                    contact_vehicle.interest_stock = interest_vehicle_stock_no
                if interest_vehicle_price:
                    if type(interest_vehicle_price) == str:
                        contact_vehicle.interest_price = interest_vehicle_price.replace(' ', '').replace(',',  '')
                    else:
                        contact_vehicle.interest_price = interest_vehicle_price
                if interest_vehicle_mileage:
                    contact_vehicle.interest_mileage = interest_vehicle_mileage
                if interest_vehicle_condition:
                    contact_vehicle.interest_condition = interest_vehicle_condition
                if interest_vehicle_listing_url:
                    contact_vehicle.interest_listing_url = interest_vehicle_listing_url
                if tradein_vehicle_year:
                    contact_vehicle.current_year = tradein_vehicle_year
                if tradein_vehicle_make:
                    contact_vehicle.current_make = tradein_vehicle_make
                if tradein_vehicle_model:
                    contact_vehicle.current_model = tradein_vehicle_model
                if tradein_vehicle_vin:
                    contact_vehicle.current_vin = tradein_vehicle_vin
                if tradein_vehicle_price:
                    if type(tradein_vehicle_price) == str:
                        contact_vehicle.current_value = tradein_vehicle_price.replace(' ', '').replace(',',  '')
                    else:
                        contact_vehicle.current_value = tradein_vehicle_price
                if tradein_vehicle_mileage:
                    contact_vehicle.current_mileage = tradein_vehicle_mileage
                if tradein_vehicle_condition:
                    contact_vehicle.current_condition = tradein_vehicle_condition
                db.session.commit()
            else:
                if interest_vehicle_year or interest_vehicle_make or interest_vehicle_model or interest_vehicle_vin or \
                        interest_vehicle_trim or interest_vehicle_stock_no or interest_vehicle_price or \
                        interest_vehicle_mileage or tradein_vehicle_year or tradein_vehicle_make or \
                        tradein_vehicle_model or tradein_vehicle_vin or tradein_vehicle_mileage or \
                        tradein_vehicle_price:
                    in_v_price = None
                    if interest_vehicle_price:
                        in_v_price = interest_vehicle_price.replace(' ', '').replace(',',  '')
                    ti_veh_vin = ''
                    if tradein_vehicle_vin:
                        ti_veh_vin = tradein_vehicle_vin
                    ti_veh_make = ''
                    if tradein_vehicle_make:
                        ti_veh_make = tradein_vehicle_make
                    ti_veh_model = ''
                    if tradein_vehicle_model:
                        ti_veh_model = tradein_vehicle_model
                    ti_veh_year = None
                    if tradein_vehicle_year:
                        ti_veh_year = tradein_vehicle_year
                    ti_veh_price = None
                    if tradein_vehicle_price:
                        ti_veh_price = tradein_vehicle_price.replace(' ', '').replace(',',  '')
                    ti_veh_mileage = None
                    if tradein_vehicle_mileage:
                        ti_veh_mileage = tradein_vehicle_mileage
                    ti_veh_condition = ''
                    if tradein_vehicle_condition:
                        ti_veh_condition = tradein_vehicle_condition
                    in_v_vin = ''
                    if interest_vehicle_vin:
                        in_v_vin = interest_vehicle_vin
                    in_v_mileage = None
                    if interest_vehicle_mileage:
                        in_v_mileage = interest_vehicle_mileage
                    in_v_year = None
                    if interest_vehicle_year:
                        in_v_year = interest_vehicle_year
                    in_v_make = ''
                    if interest_vehicle_make:
                        in_v_make = interest_vehicle_make
                    in_v_model = ''
                    if interest_vehicle_model:
                        in_v_model = interest_vehicle_model
                    in_v_condition = ''
                    if interest_vehicle_condition:
                        in_v_condition = interest_vehicle_condition
                    in_v_trim = ''
                    if interest_vehicle_trim:
                        in_v_trim = interest_vehicle_trim
                    in_v_stock = ''
                    if interest_vehicle_stock_no:
                        in_v_stock = interest_vehicle_stock_no
                    in_v_url = ''
                    if interest_vehicle_listing_url:
                        in_v_url = interest_vehicle_listing_url

                    new_contact_vehicle = ContactVehicle(
                        contact_id=new_contact.id,
                        current_vin=ti_veh_vin,
                        current_make=ti_veh_make,
                        current_model=ti_veh_model,
                        current_year=ti_veh_year,
                        current_value=ti_veh_price,
                        current_mileage=ti_veh_mileage,
                        current_condition=ti_veh_condition,
                        interest_vin=in_v_vin,
                        interest_make=in_v_make,
                        interest_model=in_v_model,
                        interest_year=in_v_year,
                        interest_trim=in_v_trim,
                        interest_stock=in_v_stock,
                        interest_price=in_v_price,
                        interest_mileage=in_v_mileage,
                        interest_condition=in_v_condition,
                        interest_listing_url=in_v_url
                    )
                    db.session.add(new_contact_vehicle)
                    db.session.flush()
                    db.session.commit()
        else:
            log.info('no lead contact exist')
    except Exception as e:
        log.info('No contact exist: ' + str(e))


@celery.task
def generate_pdf(lead_id, account, form, fields, date, ssn, dob, co_ssn, co_dob, fin_info, reference_info,
                 vehicle_info, contact_vehicle_info, vehicle_seller_info, credit_score, browser_used='',
                 contact_id=None, contact_vehicle=None, additional_reference_info=None,  **kwargs):

    # Make a PDF straight from HTML in a string.
    html = render_template('lead_form_pdf.html', lead_id=lead_id, account=account, form=form, fields=fields,
                           date=date, ssn=ssn, dob=dob, co_ssn=co_ssn, co_dob=co_dob, fin_info=fin_info,
                           reference_info=reference_info, vehicle_info=vehicle_info,
                           contact_vehicle_info=contact_vehicle_info,
                           vehicle_seller_info=vehicle_seller_info, credit_score=credit_score,
                           contact_vehicle=contact_vehicle, additional_reference_info=additional_reference_info)

    if browser_used and contact_id and browser_used == 'msie':
        current_date = datetime.datetime.now().strftime('%m-%d-%Y')
        current_filename = 'form_lead_{}_{}.pdf'.format(contact_id, current_date)

        return render_pdf(HTML(string=html), download_filename=current_filename, automatic_download=True)
    else:
        return render_pdf(HTML(string=html))


@celery.task
def generate_partnership_account_form_lead_pdfs(partnership_account_id, partnership_account_name, form_list_part, **kwargs):

    # Get all form leads for partnership account
    form_leads = FormLead.query\
        .filter(FormLead.partnership_account_id == partnership_account_id)\
        .filter(FormLead.id.in_(form_list_part))\
        .all()

    dir_name = 'upload/' + partnership_account_name.replace(" ", "").replace("-", "").replace("_", "").lower()

    if not os.path.exists(dir_name):
        try:
            os.makedirs(dir_name)
        except Exception:
            log.error("Directory {} already exists. Proceeding with document generation.".format(dir_name))

    for form_lead in form_leads:
        try:
            format_first_name = "Unknown"
            format_last_name = "Unknown"
            format_form_id = str(form_lead.form_id)

            # Return contact linked to lead
            from ..contacts.models import Contact
            contact = Contact\
                .query\
                .filter(Contact.id == form_lead.contact_id,
                        Contact.partnership_account_id == form_lead.partnership_account_id)\
                .first()

            # Return form used to capture lead
            form = ExternalForm.query\
                .filter(ExternalForm.id == form_lead.form_id)\
                .first()

            # Return the predefined form fields
            form_fields = ExternalFormField.query.filter(
                form_lead.form_id == ExternalFormField.form_id
            ).subquery()

            # Return the form field values for the specific lead
            fields = FormLeadField.query.filter(
                FormLeadField.lead_id == form_lead.id
            ).outerjoin(
                (form_fields, FormLeadField.field_id == form_fields.c.field_id)
            ).order_by('position').with_entities(
                form_fields.c.display_name,
                FormLeadField.field_id,
                FormLeadField.field_value
            ).all()

            ss_number = ''
            dob_date = ''
            co_ssn = ''
            co_dob = ''
            test_fields = []

            for field in fields:
                decrypted_field = FormLeadField(field.field_id, decrypt_value(field.field_value))

                if contact:
                    if contact.firstname and (decrypted_field.field_id == 'firstname' or decrypted_field.field_id == 'firstnamefield'):
                        decrypted_field.field_value = contact.firstname
                    elif contact.lastname and (decrypted_field.field_id == 'lastname' or decrypted_field.field_id == 'lastnamefield'):
                        decrypted_field.field_value = contact.lastname
                    elif contact.email and (decrypted_field.field_id == 'email' or decrypted_field.field_id == 'emailfield'):
                        decrypted_field.field_value = contact.email
                    elif contact.city and (decrypted_field.field_id == 'city' or decrypted_field.field_id == 'cityfield' or field.field_id == 'citytfield'):
                        decrypted_field.field_value = contact.city
                    elif contact.state and (decrypted_field.field_id == 'state' or decrypted_field.field_id == 'statefield'):
                        decrypted_field.field_value = contact.state
                    elif contact.zip and (decrypted_field.field_id == 'zip' or decrypted_field.field_id == 'zipfield'):
                        decrypted_field.field_value = contact.zip
                    elif contact.address_1 and (decrypted_field.field_id == 'address_1' or decrypted_field.field_id == 'streetfield'):
                        decrypted_field.field_value = contact.address_1
                    elif contact.address_2 and (decrypted_field.field_id == 'address_2'):
                        decrypted_field.field_value = contact.address_2

                field_id = decrypted_field.field_id
                field_value = decrypted_field.field_value
                test_field = {}
                test_field['field_id'] = field_id
                test_field['field_value'] = field_value
                test_fields.append(test_field)

                if field.field_id == 'firstname' or field.field_id == 'firstnamefield':
                    format_first_name = decrypted_field.field_value.replace(" ", "")
                elif field.field_id == 'lastname' or field.field_id == 'lastnamefield':
                    format_last_name = decrypted_field.field_value.replace(" ", "")
                if field.field_id == 'cumemberfield' or field.field_id == 'ssnfield' or field.field_id == 'ssn':
                    ss_number = decrypted_field.field_value
                    if len(ss_number) > 16:
                        ss_number = 'unavailable'
                elif field.field_id == 'datepicker' or field.field_id == 'dobfield' or field.field_id == 'birthday':
                    dob_date = decrypted_field.field_value
                    if len(dob_date) > 16:
                        dob_date = 'unavailable'
                elif field.field_id == 'cosignerssnfield' or field.field_id == 'co_applicant_ssn':
                    co_ssn = decrypted_field.field_value
                    if len(co_ssn) > 16:
                        co_ssn = 'unavailable'
                elif field.field_id == 'cosignerdateofbirthfield' or field.field_id == 'co_applicant_birthday':
                    co_dob = decrypted_field.field_value
                    if len(co_dob) > 16:
                        co_dob = 'unavailable'

            finance_fields = FormLeadField.query \
                .filter(and_(FormLeadField.lead_id == form_lead.id,
                             FormLeadField.field_id.in_(['cosignerbankruptcyfield', 'co_applicant_bankruptcy_declaration',
                                                     'cosignerrepossessionfield', 'co_applicant_repossession_declaration',
                                                     'cosigneramountowedfield', 'co_applicant_load_amount_outstanding',
                                                     'cosignerbanknamefield', 'co_applicant_bank_name',
                                                     'cosignercheckingbalancefield', 'co_applicant_checking_balance'
                                                     'cosignersavingbalancefield', 'co_applicant_saving_balance',
                                                     'cosignerchildcarepaymentfield', 'co_applicant_child_care_payment',
                                                     'cosignerutilitiespaymentfield', 'co_applicant_utilities_payment',
                                                     'cosignerdownpaymentfield', 'co_applicant_down_payment_amount',
                                                     'cosignermaintenancepaymentfield', 'co_applicant_maintenance_payment'])))\
                .first()
            if finance_fields:
                fin_info = True
            else:
                fin_info = False

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

            # Retrieve the credit score for the form lead
            # Get the credit score for the leads in the form leads table
            from buyercall.blueprints.contacts.models import CreditReports
            credit_report = CreditReports.query \
                .filter(and_(CreditReports.contact_id == form_lead.contact_id,
                             CreditReports.partnership_account_id == partnership_account_id,
                             CreditReports.is_successful.is_(True)))\
                .order_by(CreditReports.created_on.desc())\
                .first()

            if credit_report:
                credit_score = decrypt_value(credit_report.credit_score)
            else:
                credit_score = 'Unknown'

            generate_server_pdf.delay(form_lead.id, format_form_id, format_first_name, format_last_name, partnership_account_name,
                                      dir_name, form.display_name, test_fields, today_str, ss_number, dob_date, co_ssn,
                                      co_dob, fin_info, credit_score)
        except Exception:
            error_filename = '{}_{}_{}_{}.txt'.format(format_form_id, form_lead.id, format_first_name, format_last_name)
            f = open(dir_name.join(error_filename), "w+")
            f.write(traceback.format_exc())
            f.close()


@celery.task
def generate_server_pdf(lead_id, form_id, first_name, last_name, account, dir_name, form, fields, date, ssn, dob,
                        co_ssn, co_dob, fin_info, credit_score, **kwargs):

    # Make a PDF straight from HTML in a string.
    html = render_template('lead_form_pdf.html', lead_id=lead_id, account=account, form=form, fields=fields, date=date,
                           ssn=ssn, dob=dob, co_ssn=co_ssn, co_dob=co_dob, fin_info=fin_info, credit_score=credit_score)

    pdf = HTML(string=html).write_pdf()

    try:
        filename = os.path.join(dir_name, '{}_{}_{}_{}.pdf'.format(form_id, lead_id, first_name, last_name))

        if not os.path.exists(filename):
            f = open(os.path.join(dir_name, '{}_{}_{}_{}.pdf'.format(form_id, lead_id, first_name, last_name)), 'wb')
            f.write(pdf)
        else:
            log.error("File {} already exists.".format(filename))
    except Exception:
        log.error(traceback.format_exc())


@celery.task(soft_time_limit=60)
def form_lead_email_notifications(lead_id, **kwargs):
    from buyercall.blueprints.form_leads.views import send_notifications
    lead = FormLead.query.filter(FormLead.id == lead_id).first()
    if lead:
        send_notifications(lead)
    else:
        log.info('There was no form lead found for lead id: {}'.format(lead_id))


@celery.task(soft_time_limit=60)
def form_lead_email_notifications_with_options(lead_id, error_occurred=False, external_provider_name=None,
                                               is_conditional=False, conditional_subject_line=None, conditional_emails=None,
                                               conditional_adf_emails=None,
                                               **kwargs):
    from buyercall.blueprints.form_leads.views import send_notifications
    lead = FormLead.query.filter(FormLead.id == lead_id).first()
    if lead:
        send_notifications(lead, error_occurred, external_provider_name, is_conditional, conditional_subject_line,
                           conditional_emails, conditional_adf_emails)
    else:
        log.info('There was no form lead found for lead id: {}'.format(lead_id))


# This celery task gets used for sending the auto responds email to the lead after form submission
@celery.task(soft_time_limit=60)
def send_email_auto_responds(
        lead_email, lead_name, form_name, company_name, email_from, email_subject, email_body, **kwargs
):
    try:
        variables = ['#NAME#', '#FORM#', '#COMPANY#']

        if any(x in email_subject for x in variables):
            new_email_subject = email_subject.replace('#NAME#', lead_name).replace('#FORM#', form_name)\
                .replace('#COMPANY#', company_name)
        else:
            new_email_subject = email_subject

        if any(x in email_body for x in variables):
            new_email_body = email_body.replace('#NAME#', lead_name).replace('#FORM#', form_name)\
                .replace('#COMPANY#', company_name)
        else:
            new_email_body = email_body

        send_ses_email(recipients=[lead_email],
                       p_id=1,
                       subject=new_email_subject,
                       text=new_email_body,
                       sender=email_from,
                       account_name=company_name
                       )

    except Exception:
        log.error(traceback.format_exc())


# This celery task gets used for sending the auto responds email to the lead after form submission
@celery.task(soft_time_limit=60)
def send_sms_auto_responds(lead_phone_number, lead_name, form_name, company_name, inbound_id, message_body, **kwargs):
    try:
        variables = ['#NAME#', '#FORM#', '#COMPANY#']
        # Check if any dynamic variables are used in the text message body and replace them
        if any(x in message_body for x in variables):
            dynamic_message_body = message_body.replace('#NAME#', lead_name).replace('#FORM#', form_name)\
                .replace('#COMPANY#', company_name)
            new_message_body = dynamic_message_body + ' Reply STOP to unsubscribe.'
        else:
            new_message_body = message_body + ' Reply STOP to unsubscribe.'
        # There is no media for sms auto responder messages yet. So we set media as an empty string
        media = ''
        log.info('The leads number is: {}'.format(lead_phone_number))
        log.info('The companys inbound id is: {}'.format(inbound_id))
        log.info('The text message body is: {}'.format(new_message_body))
        log.info('The text message media is: {}'.format(media))
        send_text_message(inbound_id, lead_phone_number, new_message_body, media)
    except Exception:
        log.error(traceback.format_exc())


@celery.task(soft_time_limit=60)
def form_external_api_request(lead_id, partnership_account_id, service_provider_id, **kwargs):
    from buyercall.blueprints.form_leads.views import determine_external_api_request
    determine_external_api_request(lead_id, partnership_account_id, service_provider_id)


@celery.task(soft_time_limit=60)
def form_prequalify_credit_check(bureau, credit_type, contact_id, partnership_account_id, firstname, lastname, address,
                                 city, state, zip_code, service_provider, birthday, **kwargs):
    from ..contacts.contact_tasks import pull_prequalify_credit
    pull_prequalify_credit(bureau, credit_type, contact_id, partnership_account_id, firstname, lastname, address,
                           city, state, zip_code, service_provider, birthday)


@celery.task
def check_conditional_notification(lead_id, form_id, conditions, **kwargs):
    try:
        redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
        processed_key = 'lead-' + str(lead_id) + '-form-processed'
        processed_state = str(redis_db.get(processed_key).decode("utf-8"))

        log.error('Entering check_conditional_notification celery task for lead ' + str(lead_id))

        if processed_state and processed_state == 'incomplete':
            log.error('Lead conditional notification incomplete. Processing conditional notification.')
            from buyercall.blueprints.form_leads.views import \
                process_conditional_notification
            process_conditional_notification(lead_id, form_id, conditions)
        else:
            log.error('Lead conditional notification complete. Exiting celery task.')
    except Exception:
        log.error(traceback.format_exc())