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_forms/buyercall/buyercall/blueprints/partnership/views.py
import os
import csv
import sys
import traceback
import logging as log
import uuid

from buyercall.blueprints.agents import Agent
from buyercall.blueprints.filters import format_phone_number
from buyercall.lib.util_crypto import AESCipher
from flask import (
    Blueprint,
    make_response,
    json,
    flash,
    render_template,
    request,
    redirect,
    url_for,
    current_app as app, jsonify
)
from flask_babel import gettext as _
from flask_babel import ngettext as _n
from flask_login import login_required, current_user, logout_user, login_user
from buyercall.lib.supervisor_manager import current_supervisor_user
from buyercall.lib.supervisor_manager import (
    login_user as supervisor_login_user
)
from sqlalchemy.sql.elements import and_
from sqlalchemy import asc, desc, func, extract
from contextlib import closing
from io import StringIO
from buyercall.blueprints.user.decorators import role_required
from buyercall.blueprints.admin.forms import SearchForm, BulkDeleteForm, UserForm, UserCancelSubscriptionForm
from buyercall.blueprints.reports.models import Report, ReportUserTie
from buyercall.extensions import db
from sqlalchemy.sql import text
from buyercall.blueprints.user.models import User
from buyercall.blueprints.leads.models import Lead
from buyercall.blueprints.partnership.models import Partnership, \
    PartnershipAccount, PartnershipAccountGroup, PartnershipAccountGroupTie, \
    ExternalApiServiceProviders, ExternalApiServiceProvidersPartnershipAccountTie, PartnershipCpaasProviders, \
    PartnershipCreditTie, PartnershipAccountCreditTie
from buyercall.blueprints.billing.models.subscription import Subscription
from buyercall.blueprints.user.decorators import anonymous_required
from wtforms import Label
from datetime import date
from datetime import datetime
import math
from buyercall.blueprints.partnership.forms import PartnershipAccountForm, PartnershipForm, \
    ExternalApiServiceProvider, PartnershipTwilioApiForm, PartnershipBandwidthApiForm, PartnerFinservPrequalifyForm, \
    PartnershipAccountCreateForm
from datatables import DataTables, ColumnDT
import random
import string

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


@partnership.before_request
def before_request():
    if request.path.find('partnership/partnership_invite') == -1:
        # @login_required
        if not current_user.is_authenticated:
            return app.login_manager.unauthorized()
        # @role_required('partner')
        if current_user.role not in ['partner']:
            if current_user.role == 'admin':
                if not current_user.is_admin_user_with_groups:
                    flash(_('You do not have permission to do that.'), 'danger')
                    return redirect('/')
                elif current_user.is_admin_user_with_groups and current_user.is_viewing_partnership \
                        and current_user.get_user_viewing_partnership_account_subscription_plan == 'partnershipsingle':
                    if request.path.find('company_accounts/switch_back') == -1:
                        return redirect(url_for('contacts.contact_list'))
                elif current_user.is_admin_user_with_groups and current_user.is_viewing_partnership:
                    if request.path.find('company_accounts/switch_back') == -1:
                        return redirect(url_for('dashboard.user_dashboard'))
            else:
                flash(_('You do not have permission to do that.'), 'danger')
                return redirect('/')
    # @anonymous_required()
    elif current_user.is_authenticated:
        return redirect('/settings')


# Account Groups ------------------------------------------------------------------
@role_required('admin')
@partnership.route('/company_accounts/group_act_as', methods=['POST'])
def group_act_as():
    if current_user.is_authenticated and current_user.is_admin_user_with_groups:
        target_partnership_account = PartnershipAccount.query \
            .filter(PartnershipAccount.id == int(request.form.get('account_id'))).first()

        if target_partnership_account is None:
            flash(_("Such Account does not exist"))
            return redirect(url_for('partnership.company_accounts'))

        if not User.is_in_same_group(current_user.id, target_partnership_account.id):
            flash(_("You don't have access to load this account"))
            return redirect(url_for('partnership.company_accounts'))

        if User.set_user_viewing_partnership_account(current_user.id, target_partnership_account.id):
            if current_user.get_user_viewing_partnership_account_subscription_plan == 'partnershipsingle':
                return redirect(url_for('contacts.contact_list'))
            else:
                return redirect(url_for('dashboard.user_dashboard'))
        else:
            flash(_("Error loading this account"))
            return redirect(url_for('partnership.company_accounts'))
    else:
        return redirect(url_for('user.login'))


@role_required('admin')
@partnership.route('/company_accounts')
def company_accounts():
    search_form = SearchForm()
    bulk_form = BulkDeleteForm()

    partnership_account_groups_list = None
    company_account_name = ''

    if current_user.is_admin_user_with_groups and not current_user.is_viewing_partnership:

        group_tie = PartnershipAccountGroup.query.filter(
            and_(PartnershipAccountGroupTie.partnership_account_id == current_user.partnership_account_id,
                 PartnershipAccountGroupTie.partnership_account_group_id == PartnershipAccountGroup.id,
                 PartnershipAccountGroupTie.partnership_account_group_id == current_user.partnership_account_group_id)
        ).first()

        company_account_name = group_tie.name
        sort_by = PartnershipAccount.sort_by(request.args.get('sort', 'name'),
                                             request.args.get('direction', 'asc'))
        table = 'partnership_accounts'
        order_values = '{0}.{1} {2}'.format(table, sort_by[0], sort_by[1])

        if request.args.get('sort', 'name') == 'count':
            table = 'partnership_accounts'
            sort_by = 'count(users.partnership_account_id)', sort_by[1]
            order_values = '{1} {2}'.format(table, sort_by[0], sort_by[1])

        partnership_account_groups_list = PartnershipAccount \
            .query \
            .with_entities(PartnershipAccount.active, PartnershipAccount.id, PartnershipAccount.name) \
            .filter(PartnershipAccount.search(request.args.get('q', ''))) \
            .filter(and_(PartnershipAccountGroupTie.partnership_account_group_id == group_tie.id,
                         PartnershipAccount.id == PartnershipAccountGroupTie.partnership_account_id)) \
            .all()

        return render_template('company_accounts/index.jinja2',
                               form=search_form,
                               bulk_form=bulk_form,
                               company_account=company_account_name,
                               partnership_account_groups=partnership_account_groups_list)
    else:
        if current_user.role == 'admin':
            return redirect(url_for('dashboard.user_dashboard'))
        elif current_user.role == 'partner':
            return redirect(url_for('partnership.accounts'))
        else:
            return redirect(url_for('user.settings'))


@partnership.route('/company_accounts/switch_back', methods=['GET'])
@login_required
def switch_back():
    if current_user.is_admin_user_with_groups:
        User.set_user_viewing_partnership_account(current_user.id, -1)

        return redirect(url_for('partnership.company_accounts'))
    else:
        return redirect(url_for('user.settings'))


# Accounts  -----------------------------------------------------------------------
@partnership.route('/accounts', defaults={'page': 1})
@partnership.route('/accounts/page/<int:page>')
@login_required
def accounts(page):
    if current_user.role != 'admin':
        search_form = SearchForm()
        bulk_form = BulkDeleteForm()

        sort_by = PartnershipAccount.sort_by(request.args.get('sort', 'name'),
                                             request.args.get('direction', 'asc'))
        table = 'partnership_accounts'
        order_values = '{0}.{1} {2}'.format(table, sort_by[0], sort_by[1])

        if request.args.get('sort', 'name') == 'count':
            table = 'partnership_accounts'
            sort_by = 'count(users.partnership_account_id)', sort_by[1]
            order_values = '{1} {2}'.format(table, sort_by[0], sort_by[1])

        order_query = text(order_values)

        paginated_accounts = PartnershipAccount.query.with_entities(
            PartnershipAccount.active,
            PartnershipAccount.id,
            PartnershipAccount.name,
            func.count(User.partnership_account_id).label('count')
        ).outerjoin(
            User,
            and_(
                User.partnership_account_id == PartnershipAccount.id,
                User.partnership_account_id is not None,
                User.partnership_id == current_user.partnership_id,
                User.role == 'admin'
            )) \
            .filter(PartnershipAccount.partnership_id == current_user.partnership_id) \
            .filter(PartnershipAccount.search(request.args.get('q', ''))) \
            .order_by(order_query) \
            .group_by(PartnershipAccount.active, PartnershipAccount.id, PartnershipAccount.name,
                      User.partnership_account_id) \
            .paginate(page, 20, True)

        # Create domain section of partner token url
        token_domain = current_user.partnership.partner_url
        if not token_domain:
            token_domain = 'https://buyercall.com'

        return render_template('accounts/index.jinja2',
                               form=search_form, bulk_form=bulk_form,
                               partnership_accounts=paginated_accounts,
                               domain=token_domain)
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/accounts/new-partnership-account', methods=['GET', 'POST'])
@login_required
@role_required('partner', 'sysadmin', 'limitsysadmin')
def create_new_account():
    form = PartnershipAccountCreateForm()
    characters = string.ascii_letters + string.digits + string.punctuation
    temp_pass = ''.join(random.choice(characters) for i in range(12))
    if form.validate_on_submit():
        is_role_valid = False
        email_set = set()
        for user in form.users.data:
            _role = user.get('role')
            if _role in ['admin', 'agent']:
                if _role == 'admin':
                    is_role_valid = True
            else:
                flash(_(f'Invalid user role: {_role}'), 'danger')
                return render_template('accounts/create.jinja2', form=form)

            user_email = user.get('email')
            if user_email in email_set:
                flash(_(f"Duplicate email address: {user_email}"), 'danger')
                return render_template('accounts/create.jinja2', form=form)

            email_set.add(user_email)

            if User.query.filter(func.lower(User.email) == user.get('email'), User.is_deactivated == False).first():
                flash(_(f"User with email address: {user['email']} already exists."), 'danger')
                return render_template('accounts/create.jinja2', form=form)

        if not is_role_valid:
            flash(_('The account requires at least one admin user.'), 'danger')
            return render_template('accounts/create.jinja2', form=form)

        credit_service_provider = form.credit_service_provider.data.lower()
        if credit_service_provider not in ['', 'offerlogix', '700credit']:
            flash(_(f'Invalid credit service provider: {credit_service_provider}'), 'danger')
            return render_template('accounts/create.jinja2', form=form)

        result_is_active = form.is_active.data
        result_name = form.name.data
        if form.partner_account_code.data:
            result_account_code = form.partner_account_code.data
        else:
            result_account_code = ''

        partnership_account_result = PartnershipAccount.create_partial(
            result_name,
            current_user.partnership_id,
            result_is_active,
            result_account_code,
            'automotive'
        )

        if partnership_account_result > 0:
            # Create account users
            for user in form.users.data:
                email = user['email'].lower()
                u = User.query.filter(func.lower(User.email) == email).first()
                if u:
                    if u.is_deactivated:
                        u.partnership_account_id = partnership_account_result
                        u.partnership_id = current_user.partnership_id
                        u.company = form.name.data
                        u.is_deactivated = False
                        u.deactivated_on = None
                        db.session.commit()
                else:
                    if 'temp_password' in user:
                        new_password = user['temp_password']
                    else:
                        hex_value = uuid.uuid4().hex
                        new_password = hex_value
                    new_user = User(
                        firstname=user['first_name'],
                        lastname=user['last_name'],
                        email=user['email'].lower(),
                        phonenumber=format_phone_number(str(user['mobile_number'])),
                        password=new_password,
                        role=user['role'],
                        partnership_account_id=partnership_account_result,
                        partnership_id=current_user.partnership_id,
                        company=form.name.data,
                        tos_agreement=False,
                        active=True,
                        full_feature_access=True,
                        inbound_routing_access=True,
                        outbound_routing_access=True,
                        forms_access=True,
                        external_api_access=False,
                        two_factor_auth=False,
                    )
                    db.session.add(new_user)
                    db.session.flush()
                    if new_user.id:
                        agent = Agent(
                            user_id=new_user.id,
                            firstname=new_user.firstname,
                            lastname=new_user.lastname,
                            email=new_user.email,
                            title=new_user.title or '',
                            department=new_user.department or '',
                            phonenumber=new_user.phonenumber,
                            mobile='',
                            extension=new_user.extension or None,
                            partnership_account_id=new_user.partnership_account_id
                        )
                        db.session.add(agent)
                        db.session.flush()
            db.session.commit()
            if form.credit_service_provider.data:
                result_credit_sp = form.credit_service_provider.data.lower()
                new_credit_sp = PartnershipAccountCreditTie(
                    service_provider=result_credit_sp,
                    active=True,
                    partnership_account_id=partnership_account_result,
                    product_type='prequalify',
                    equifax_enabled=True,
                    experian_enabled=False,
                    transunion_enabled=False,
                )
                db.session.add(new_credit_sp)
                db.session.flush()
                db.session.commit()

            flash(_('Partnership account created successfully.'), 'success')
            return redirect(url_for('partnership.accounts', page=1))
        else:
            flash(_('Error creating partnership account.'), 'danger')
    return render_template('accounts/create.jinja2', form=form, temp_pass=temp_pass)


@partnership.route('/all_admins')
def admins():
    if current_user.role != 'admin':
        return redirect(url_for('partnership.accounts', page=1))
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/accounts/<int:id>')
def account_admins(id):
    if current_user.role != 'admin':
        search_form = SearchForm()
        bulk_form = BulkDeleteForm()

        sort_by = User.sort_by(request.args.get('sort', 'name'),
                               request.args.get('direction', 'asc'))
        table = 'users'

        order_values = '{0}.{1} {2}'.format(table, sort_by[0], sort_by[1])

        order_query = text(order_values)
        if request.args.get('sort', 'name') == 'name':
            order_query = asc(User.name.expression) if sort_by[1] == 'asc' else desc(User.name.expression)

        partnership_account_var = PartnershipAccount.query.get(id)

        paginated_users = User.query \
            .join(User.partnership) \
            .join(User.partnership_account) \
            .filter(User.partnership_account_id == id, User.partnership_id == current_user.partnership_id,
                    User.role == 'admin') \
            .filter(User.search(request.args.get('q', ''))) \
            .filter(User.is_deactivated.is_(False)) \
            .order_by(order_query) \
            .all()

        return render_template('admins/index.jinja2',
                               form=search_form, bulk_form=bulk_form,
                               users=paginated_users, partnership_account=partnership_account_var)
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/account/<int:id>/edit', methods=['GET', 'POST'])
def account_edit(id):
    from ..widgets.models import Widget
    if current_user.role == 'partner' or (current_user.is_admin_user_with_groups
                                          and not current_user.is_viewing_partnership):

        if current_user.is_admin_user_with_groups:
            if not User.is_in_same_group(current_user.id, id):
                flash(_("You don't have access to load this account"), 'danger')
                return redirect(url_for('partnership.company_accounts'))

        # TODO: Confirm that super user can view from other partners.
        partnership_account = PartnershipAccount.query.filter(
            PartnershipAccount.id == id,
            PartnershipAccount.partnership_id == current_user.partnership_id,
        ).first()

        imports_allowed = partnership_account.import_leads

        if partnership_account is None:
            if current_user.role == 'partner':
                flash(_('This account does not exist.'), 'danger')
                return redirect(url_for('partnership.accounts', page=1))
            else:
                flash(_("This account does not exist."), 'danger')
                return redirect(url_for('partnership.company_accounts'))

        # Get current year, month
        now = datetime.now()
        year = now.year
        month = now.month
        previous_month = month - 1

        # Total minute usage queries for an account
        partnership_account_total_minutes = Lead.query.with_entities(Lead.duration) \
            .filter(Lead.partnership_account_id == id).all()

        new_total_duration = [i.duration for i in partnership_account_total_minutes]
        total_duration_list = list()
        for total in new_total_duration:
            if not total:
                total_zero = float(0)
                total_duration_list.append(total_zero)
            else:
                total_float_duration = math.ceil(float(total) / 60.0)
                total_duration_list.append(total_float_duration)

        total_minutes = int(sum(total_duration_list))

        # Current monthly minute usage queries for an account
        partnership_account_month_minutes = Lead.query.with_entities(Lead.duration) \
            .filter(Lead.partnership_account_id == id) \
            .filter(extract('year', Lead.created_on) == year) \
            .filter(extract('month', Lead.created_on) == month).all()

        new_call_duration = [i.duration for i in partnership_account_month_minutes]
        call_duration_list = list()
        for duration in new_call_duration:
            if not duration:
                duration_zero = float(0)
                call_duration_list.append(duration_zero)
            else:
                float_duration = math.ceil(float(duration) / 60.0)
                call_duration_list.append(float_duration)

        month_minutes = int(sum(call_duration_list))

        # The previous month's minute usage
        partnership_account_previous_month_minutes = Lead.query.with_entities(Lead.duration) \
            .filter(Lead.partnership_account_id == id) \
            .filter(extract('year', Lead.created_on) == year) \
            .filter(extract('month', Lead.created_on) == previous_month).all()

        previous_new_call_duration = [i.duration for i in partnership_account_previous_month_minutes]
        previous_call_duration_list = list()
        for previous_duration in previous_new_call_duration:
            if not previous_duration:
                previous_duration_zero = float(0)
                previous_call_duration_list.append(previous_duration_zero)
            else:
                previous_float_duration = math.ceil(float(previous_duration) / 60.0)
                previous_call_duration_list.append(previous_float_duration)

        previous_month_minutes = int(sum(previous_call_duration_list))

        # Monthly unique call count
        monthly_unique_calls = Lead.query.filter(extract('month', Lead.created_on) == month) \
            .filter(extract('year', Lead.created_on) == year) \
            .filter(Lead.partnership_account_id == id) \
            .distinct(Lead.phonenumber).count()

        # Total unique call count
        total_unique_calls = Lead.query.filter(Lead.partnership_account_id == id) \
            .distinct(Lead.phonenumber).count()

        # Total call count
        total_calls = Lead.query.filter(Lead.partnership_account_id == id).count()

        from buyercall.blueprints.phonenumbers.models import Phone
        # Total tracking phone numbers
        total_tracking_pn = Phone.query.filter(Phone.partnership_account_id == id) \
            .filter(Phone.type == 'tracking', Phone.is_deactivated == '0').count()
        # Total priority phone numbers
        total_priority_pn = Phone.query.filter(Phone.partnership_account_id == id) \
            .filter(Phone.type == 'priority', Phone.is_deactivated == '0').count()

        from buyercall.blueprints.form_leads.models import FormLead
        # Current month's form leads total
        monthly_form_leads = FormLead.query.filter(extract('month', FormLead.created_on) == month) \
            .filter(extract('year', FormLead.created_on) == year) \
            .filter(FormLead.partnership_account_id == id).count()

        # Previous month's form leads total
        previous_month_form_leads = FormLead.query.filter(extract('month', FormLead.created_on) == previous_month) \
            .filter(extract('year', FormLead.created_on) == year) \
            .filter(FormLead.partnership_account_id == id).count()

        # Total form leads
        total_form_leads = FormLead.query.filter(FormLead.partnership_account_id == id).count()

        from buyercall.blueprints.form_leads.models import ExternalForm
        # Previous month's form leads total
        total_forms = ExternalForm.query.filter(ExternalForm.partnership_account_id == id).count()

        # Get partnership account group
        selected_group = 0
        partnership_account_group = PartnershipAccountGroupTie \
            .query \
            .filter(PartnershipAccountGroupTie.partnership_account_id == partnership_account.id).first()
        # if partnership_account_group:
        #    selected_group = partnership_account_group.partnership_account_group_id

        if partnership_account is None:
            flash(_('This account does not exist.'), 'danger')
            return redirect(url_for('partnership.accounts', page=1))

        form = PartnershipAccountForm(obj=partnership_account)
        # form.partnership_account_group_id.choices = [(g.id, g.name) for g in PartnershipAccountGroup \
        #    .query \
        #    .order_by(PartnershipAccountGroup.name.asc()) \
        #    .all()]
        # form.partnership_account_group_id.choices.insert(0, (0, ''))

        # Get external service provider
        selected_external_provider_id = 0
        partnership_account_provider = ExternalApiServiceProvidersPartnershipAccountTie \
            .query \
            .filter(ExternalApiServiceProvidersPartnershipAccountTie.partnership_account_id == partnership_account.id) \
            .join(ExternalApiServiceProviders) \
            .filter(ExternalApiServiceProviders.name == 'AMS 2000') \
            .first()

        if partnership_account_provider is not None:
            encrypt_key = app.config['CRYPTO_SECRET_KEY']
            cipher = AESCipher(encrypt_key)

            if partnership_account_provider.username is not None and partnership_account_provider.username is not '':
                decrypted_username = cipher.decrypt(partnership_account_provider.username)

            if partnership_account_provider.password is not None and partnership_account_provider.password is not '':
                decrypted_password = cipher.decrypt(partnership_account_provider.password)

            if partnership_account_provider.secret is not None and partnership_account_provider.secret is not '':
                decrypted_secret = cipher.decrypt(partnership_account_provider.secret)

            external_service_provider_form = ExternalApiServiceProvider(
                external_api_service_provider_id=partnership_account_provider.external_api_service_provider_id,
                username=decrypted_username,
                password=decrypted_password,
                url=partnership_account_provider.url,
                token_url=partnership_account_provider.token_url,
                client_id=partnership_account_provider.client_id,
                source=partnership_account_provider.source,
                app_source=partnership_account_provider.app_source,
                secret=decrypted_secret)
        else:
            external_service_provider_form = ExternalApiServiceProvider()

        external_service_provider_form.external_api_service_provider_id.choices = [
            (g.id, g.name) for g in ExternalApiServiceProviders.query.filter(
                ExternalApiServiceProviders.name == 'AMS 2000'
            ).order_by(ExternalApiServiceProviders.name.asc()).all()
        ]
        external_service_provider_form.external_api_service_provider_id.choices.insert(0, (0, ''))

        if partnership_account_provider:
            selected_external_provider_id = partnership_account_provider.external_api_service_provider_id

        del form.billing_type

        from buyercall.blueprints.form_leads.models import ExternalForm, ExternalFormField as FormField, \
            ExternalFieldFieldTemplate
        external_forms = ExternalForm.query.filter(ExternalForm.partnership_account_id == partnership_account.id,
                                                   ExternalForm.is_deactivated == False).all()

        templates = ExternalFieldFieldTemplate.query.filter(
            ExternalFieldFieldTemplate.partnership_id == current_user.partnership_id).all()

        add_external_forms = request.form.get('add_external_forms', 'false')
        edit_external_tab = request.form.get('edit_external_tab', 'false')
        # add_external_forms = request.args.get('add_external_forms', 'false')

        routings = Widget.query.filter(
            Widget.partnership_account_id == id,
            Widget.enabled == True  # noqa
        ).all()
        if add_external_forms == "false" and edit_external_tab == "false":
            if form.validate_on_submit():
                # form.populate_obj(partnership_account)
                partnership_account.name = request.form.get('name')
                partnership_account.partner_account_code = request.form.get('partner_account_code')
                partnership_account.business_type = request.form.get('business_type')
                credit_provider = request.form.get('credit_sp')
                    # Set the partnership account group id in the db
                    # form_partnership_account_group_id = request.form.get('partnership_account_group_id')
                    # PartnershipAccountGroupTie.update(form_partnership_account_group_id, partnership_account.id)

                partnership_account.save()

                if credit_provider:
                    credit_profile = (PartnershipAccountCreditTie.query
                                      .filter(and_(PartnershipAccountCreditTie
                                                   .partnership_account_id == partnership_account.id,
                                                   PartnershipAccountCreditTie.service_provider == credit_provider))
                                      .first())

                    if not credit_profile:
                        new_credit_sp = PartnershipAccountCreditTie(
                            service_provider=credit_provider,
                            active=True,
                            partnership_account_id=partnership_account.id,
                            product_type='prequalify',
                            equifax_enabled=True
                        )
                        db.session.add(new_credit_sp)
                        db.session.flush()
                        db.session.commit()

                flash(_('Account has been saved successfully.'), 'success')

                if current_user.is_admin_user_with_groups:
                    return redirect(url_for('partnership.company_accounts'))
                else:
                    return redirect(url_for('partnership.accounts', page=1))
            else:
                pass

        if edit_external_tab == "true":
            external_forms_id = request.form.get('external_forms_id')
            external_edit_forms = ExternalForm.query.get(external_forms_id)
        else:
            external_edit_forms = []

        fields = FormField.query.filter(
            FormField.form_id == 2
        ).order_by(FormField.position).all()
        import re

        account_name = re.sub('[^A-Za-z0-9]+', '', partnership_account.name).lower() + '@buyercall.com'
        auto_email_subject = '#COMPANY# - Thank you for your submission'
        body_string = '\n\nThank you for your submission\n---\n{0}\n---\n' \
            .format('We are in the process of reviewing your submission for the #FORM#. '
                    'Once we will be in contact as soon as possible')
        auto_email_body = _('Hi #NAME#,%(body)s Thanks,\n#COMPANY# support team'
                            '\n\n Please note this is an automated email notification. Do not reply to this email.',
                            body=body_string)

        # This section will handle some pre-stuff for the auto sms template
        from ..phonenumbers.models import Phone
        phone_numbers = Phone.query \
            .filter(Phone.partnership_account_id == id) \
            .filter(Phone.is_deactivated == '0').all()

        if phone_numbers:
            active_numbers = True
        else:
            active_numbers = False

        # Count how many active phone numbers there are for the user and update the total in total_numbers above
        # Also declare the phone numbers and the friendly name for the user and add them to a list above

        numbers = []
        for no in phone_numbers:
            number = no.phonenumber
            name = no.friendly_name
            inbound_id = no.id
            display_name = '{} - {}'.format(name, number)
            phone_info = [inbound_id, display_name]
            numbers.append(phone_info)
        # Look through the phone numbers for the current user and create a dictionary
        phone_dict = {}
        for number in numbers:
            phone_dict[number[0]] = number[1]

        auto_sms_body = _('#COMPANY#: Hi #NAME#, thanks for your form submission. We will review it and get back '
                          'to you asap.')

        return render_template('accounts/edit.jinja2',
                               form=form,
                               api_form=external_service_provider_form,
                               account=partnership_account,
                               imports_allowed=imports_allowed,
                               selected_external_service_provider_id=selected_external_provider_id,
                               # selected_group_id=selected_group,
                               total_minutes=total_minutes,
                               month_minutes=month_minutes,
                               total_unique_calls=total_unique_calls,
                               monthly_unique_calls=monthly_unique_calls,
                               total_calls=total_calls,
                               total_tracking_pn=total_tracking_pn,
                               total_priority_pn=total_priority_pn,
                               monthly_form_leads=monthly_form_leads,
                               previous_month_form_leads=previous_month_form_leads,
                               total_form_leads=total_form_leads,
                               total_forms=total_forms,
                               previous_month_minutes=previous_month_minutes,
                               external_forms=external_forms,
                               add_external_forms=add_external_forms,
                               routings=routings,
                               external_edit_forms=external_edit_forms,
                               fields=fields,
                               account_name=account_name,
                               subject=auto_email_subject,
                               body=auto_email_body,
                               phone_options=phone_dict,
                               active_numbers=active_numbers,
                               auto_sms_body=auto_sms_body,
                               edit_external_tab=edit_external_tab,
                               templates_list=templates)
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


# This is a csv containing all partner account data
@login_required
@partnership.route('/accounts/csv', methods=['GET'])
def partner_accounts_csv():
    if current_user.role != 'admin':
        header = [
            '#', 'id', 'name', 'active', 'created_on', 'partnership_id', 'partner_account_code', 'issues.issue_count',
            'total_min_usage', 'current_month_min_usage', 'previous_month_minutes', 'total_calls', 'total_unique_calls',
            'current_month_unique_calls', 'previous_month_unique_calls', 'total_active_phonenumbers',
            'total_tracking_phonenumbers', 'total_priority_phonenumbers', 'total_forms', 'total_form_leads',
            'current_month_form_leads', 'previous_month_form_leads'
        ]

        params = {'partnership_id': current_user.partnership_id}

        query = text("""SELECT result.id
            ,result.name
            ,result.is_active
            ,result.created_on
            ,result.partnership_id
            ,result.partner_account_code
            ,issue_count
        FROM (
            SELECT partnership_accounts.id
                ,partnership_accounts.name
                ,partnership_accounts.is_active
                ,partnership_accounts.created_on
                ,partnership_accounts.partnership_id
                ,partnership_accounts.partner_account_code
                ,COUNT(issues.id) AS issue_count
            FROM partnership_accounts
            LEFT OUTER JOIN issues ON issues.partnership_account_id = partnership_accounts.id
            WHERE partnership_accounts.partnership_id = :partnership_id
            GROUP BY partnership_accounts.id
            ) result""")

        connection = db.engine.connect()
        partnership_accounts = connection.execute(query, params)

        # Build the CSV
        row_no = 0
        with closing(StringIO()) as out:
            writer = csv.writer(out)
            writer.writerow(header)
            for account in partnership_accounts:

                # Get current year, month
                now = datetime.now()
                year = now.year
                month = now.month
                previous_month = month - 1

                # Get total minutes for an account
                partnership_account_total_minutes = Lead.query.with_entities(Lead.duration) \
                    .filter(Lead.partnership_account_id == account.id).all()

                # If there's more than 0 minutes round the seconds up
                # to nearest minute and add them together
                new_call_duration = [i.duration for i in partnership_account_total_minutes]
                call_duration_list = list()
                for duration in new_call_duration:
                    if not duration:
                        duration_zero = float(0)
                        call_duration_list.append(duration_zero)
                    else:
                        float_duration = math.ceil(float(duration) / 60.0)
                        call_duration_list.append(float_duration)

                total_minutes = int(sum(call_duration_list))

                # Get Current month minute usage for account
                partnership_account_month_minutes = Lead.query.with_entities(Lead.duration) \
                    .filter(Lead.partnership_account_id == account.id) \
                    .filter(extract('year', Lead.created_on) == year) \
                    .filter(extract('month', Lead.created_on) == month).all()

                # If there's more than 0 minutes round the seconds up
                # to nearest minute and add them together

                new_call_duration = [i.duration for i in partnership_account_month_minutes]
                call_duration_list = list()
                for duration in new_call_duration:
                    if not duration:
                        duration_zero = float(0)
                        call_duration_list.append(duration_zero)
                    else:
                        float_duration = math.ceil(float(duration) / 60.0)
                        call_duration_list.append(float_duration)

                month_minutes = int(sum(call_duration_list))

                # The previous month's minute usage
                partnership_account_previous_month_minutes = Lead.query.with_entities(Lead.duration) \
                    .filter(Lead.partnership_account_id == account.id) \
                    .filter(extract('year', Lead.created_on) == year) \
                    .filter(extract('month', Lead.created_on) == previous_month).all()

                previous_new_call_duration = [i.duration for i in partnership_account_previous_month_minutes]
                previous_call_duration_list = list()
                for previous_duration in previous_new_call_duration:
                    if not previous_duration:
                        previous_duration_zero = float(0)
                        previous_call_duration_list.append(previous_duration_zero)
                    else:
                        previous_float_duration = math.ceil(float(previous_duration) / 60.0)
                        previous_call_duration_list.append(previous_float_duration)

                previous_month_minutes = int(sum(previous_call_duration_list))

                # Monthly unique call count
                monthly_unique_calls = Lead.query.filter(extract('month', Lead.created_on) == month) \
                    .filter(extract('year', Lead.created_on) == year) \
                    .filter(Lead.partnership_account_id == account.id) \
                    .distinct(Lead.phonenumber).count()

                # Total unique call count
                total_unique_calls = Lead.query.filter(Lead.partnership_account_id == account.id) \
                    .distinct(Lead.phonenumber).count()

                # Total previous unique call count
                previous_month_unique_calls = Lead.query.filter(Lead.partnership_account_id == account.id) \
                    .filter(extract('month', Lead.created_on) == previous_month) \
                    .filter(extract('year', Lead.created_on) == year) \
                    .distinct(Lead.phonenumber).count()

                # Total call count
                total_calls = Lead.query.filter(Lead.partnership_account_id == account.id).count()

                from buyercall.blueprints.phonenumbers.models import Phone
                # Total tracking phone numbers
                total_tracking_pn = Phone.query.filter(Phone.partnership_account_id == account.id) \
                    .filter(Phone.type == 'tracking', Phone.is_deactivated == '0').count()
                # Total priority phone numbers
                total_priority_pn = Phone.query.filter(Phone.partnership_account_id == account.id) \
                    .filter(Phone.type == 'priority', Phone.is_deactivated == '0').count()

                # Total active phonenumbers
                total_active_pn = total_tracking_pn + total_priority_pn

                from buyercall.blueprints.form_leads.models import FormLead
                # Current month's form leads total
                monthly_form_leads = FormLead.query.filter(extract('month', FormLead.created_on) == month) \
                    .filter(extract('year', FormLead.created_on) == year) \
                    .filter(FormLead.partnership_account_id == account.id).count()

                # Previous month's form leads total
                previous_month_form_leads = FormLead.query.filter(
                    extract('month', FormLead.created_on) == previous_month) \
                    .filter(extract('year', FormLead.created_on) == year) \
                    .filter(FormLead.partnership_account_id == account.id).count()

                # Total form leads
                total_form_leads = FormLead.query.filter(FormLead.partnership_account_id == account.id).count()

                from buyercall.blueprints.form_leads.models import ExternalForm
                # Previous month's form leads total
                total_forms = ExternalForm.query.filter(ExternalForm.partnership_account_id == account.id).count()

                row_no += 1
                csv_row = [
                    row_no, account.id, account.name, account.is_active,
                    account.created_on, account.partnership_id, account.partner_account_code, account['issue_count'],
                    total_minutes, month_minutes, previous_month_minutes, total_calls, total_unique_calls,
                    monthly_unique_calls, previous_month_unique_calls, total_active_pn, total_tracking_pn,
                    total_priority_pn, total_forms, total_form_leads, monthly_form_leads, previous_month_form_leads
                ]
                writer.writerow(csv_row)

            filename = 'Partnership Accounts - Usage Report - {}.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)
            return resp
    else:
        return ''


@partnership.route('/account/<int:id>/edit/api_access', methods=['POST'])
def account_edit_api_access(id):
    encrypt_key = app.config['CRYPTO_SECRET_KEY']
    partnership_account = PartnershipAccount \
        .query \
        .filter(PartnershipAccount.id == id,
                PartnershipAccount.partnership_id == current_user.partnership_id
                ) \
        .first()

    if partnership_account is not None:
        api_url = request.form.get('url')
        api_token_url = request.form.get('token_url')
        api_client_id = request.form.get('client_id')
        api_username = request.form.get('username')
        api_password = request.form.get('password')
        api_secret = request.form.get('secret')
        api_source = request.form.get('source')
        api_app_source = request.form.get('app_source')
        api_external_api_service_provider_id = request.form.get('external_api_service_provider_id')

        if api_username is not None and api_username is not '':
            cipher = AESCipher(encrypt_key)
            api_username = cipher.encrypt(api_username)

        if api_password is not None and api_password is not '':
            cipher = AESCipher(encrypt_key)
            api_password = cipher.encrypt(api_password)

        if api_secret is not None and api_secret is not '':
            cipher = AESCipher(encrypt_key)
            api_secret = cipher.encrypt(api_secret)

        if api_external_api_service_provider_id is None or \
                api_external_api_service_provider_id == '' or \
                int(api_external_api_service_provider_id) <= 0:
            flash(_('Error updating partnership account API details.'), 'danger')
            return redirect(url_for('partnership.accounts', page=1))

        try:
            # api_record_exists = ExternalApiServiceProvidersPartnershipAccountTie.exists(
            # partnership_account.id, api_external_api_service_provider_id)
            # if int(api_record_exists) > 0 and (api_external_api_service_provider_id is None or int(
            # api_external_api_service_provider_id) == 0):
            #    result = ExternalApiServiceProvidersPartnershipAccountTie.delete(
            #    api_record_exists, partnership_account.id)
            #
            #    if result:
            #        flash(_('Account has been changed successfully.'), 'success')
            #    else:
            #        flash(_('Error updating partnership account API details.'), 'danger')
            #    return redirect(url_for('partnership.accounts', page=1))
            if api_external_api_service_provider_id is not None and int(api_external_api_service_provider_id) > 0:
                ExternalApiServiceProvidersPartnershipAccountTie.update(
                    api_external_api_service_provider_id,
                    partnership_account.id,
                    api_client_id,
                    api_username,
                    api_password,
                    api_url,
                    api_token_url,
                    api_source,
                    api_app_source,
                    api_secret
                )

                flash(_('Account has been changed successfully.'), 'success')
                return redirect(url_for('partnership.accounts', page=1))
        except Exception as e:
            log.error('Error updating partnership account API details: {}'.format(sys.exc_info()[0]))
            flash(_('Error updating partnership account API details.'), 'danger')
            return redirect(url_for('partnership.accounts', page=1))
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/account/<int:id>/edit/login_access', methods=['POST'])
def account_edit_login_access(id):
    if current_user.role != 'admin':
        partnership_account = PartnershipAccount.query.filter(
            PartnershipAccount.id == id,
            PartnershipAccount.partnership_id == current_user.partnership_id
        ).first()
        status = request.form.get('status', 'off')

        if partnership_account is None:
            flash(_('This account does not exist.'), 'danger')
            return redirect(url_for('partnership.accounts', page=1))

        status = not (True if status == 'on' else False)

        db.session.query(PartnershipAccount) \
            .filter(PartnershipAccount.id == id) \
            .update({"active": status}, synchronize_session='fetch')

        db.session.query(User) \
            .filter(User.partnership_account_id == id, User.role.in_(['admin', 'agent'])) \
            .update({"active": status}, synchronize_session='fetch')

        db.session.commit()

        flash(_('Account has been changed successfully.'), 'success')
        return redirect(url_for('partnership.accounts', page=1))
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/account/<int:id>/edit/lead_import_access', methods=['POST'])
def account_edit_lead_import_access(id):
    if current_user.role != 'admin':
        partnership_account = PartnershipAccount.query.filter(PartnershipAccount.id == id,
                                                              PartnershipAccount.partnership_id == current_user.partnership_id,
                                                              ).first()
        status = request.form.get('status', 'false')

        if partnership_account is None:
            flash(_('This account does not exist.'), 'danger')
            return redirect(url_for('partnership.accounts', page=1))

        status = (True if status == 'true' else False)

        db.session.query(PartnershipAccount) \
            .filter(PartnershipAccount.id == id) \
            .update({"import_leads": status}, synchronize_session='fetch')

        db.session.commit()

        flash(_('Account has been changed successfully.'), 'success')
        return redirect(url_for('partnership.accounts', page=1))
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/account/<int:id>/edit/edit_twillio', methods=['POST'])
def account_edit_twillio(id):
    if current_user.role != 'admin':
        partnership_account = PartnershipAccount.query.filter(
            PartnershipAccount.id == id,
            PartnershipAccount.partnership_id == current_user.partnership_id,
        ).first()
        status = request.form.get('status', 'off')

        if partnership_account is None or partnership_account.subscription is None:
            flash(_('This account does not exist.'), 'danger')
            return redirect(url_for('partnership.accounts', page=1))

        status = not (True if status == 'on' else False)

        if status:
            partnership_account.subscription.activate_twilio_account()
        else:
            partnership_account.subscription.suspend_twilio_account()

        flash(_('Account has been changed successfully.'), 'success')
        return redirect(url_for('partnership.accounts', page=1))
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/account/<int:id>/edit/close_subscription', methods=['POST'])
def account_close_subscription(id):
    if current_user.role != 'admin':
        partnership_account = PartnershipAccount.query.filter(
            PartnershipAccount.id == id,
            PartnershipAccount.partnership_id == current_user.partnership_id,
        ).first()
        if partnership_account is None or partnership_account.subscription is None:
            flash(_('This account does not exist.'), 'danger')
            return redirect(url_for('partnership.accounts', page=1))

        partnership_account.subscription.close_twilio_account()

        flash(_('Account has been changed successfully.'), 'success')
        return redirect(url_for('partnership.accounts', page=1))
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


# TODO: needs review
@partnership.route('/admins/<int:id>/edit', methods=['GET', 'POST'])
def admins_edit(id):
    if current_user.role != 'admin':
        user = User.query.filter(User.id == id, User.partnership_id == current_user.partnership_id,
                                 User.role == 'admin', User.is_deactivated.is_(False)).first()
        if user is None:
            flash(_('This user does not exist.'), 'danger')
            return redirect(url_for('partnership.admins'))

        form = UserForm(obj=user)
        form.role = Label('lbl_role', _('%s' % user.role))
        form.role.label = {'text': 'Privileges'}

        form.reports_list.choices = []
        rework_reports = [(report.id, report.name) for report in Report.query.all()]
        for r in rework_reports:
            if r != (3, 'Partner Channel Account Report'):
                form.reports_list.choices.append(r)

        if form.validate_on_submit():
            if User.is_last_admin(user,
                                  'admin',
                                  request.form.get('active')):
                flash(_('This is the last admin within the account, you cannot do that.'),
                      'danger')
                return redirect(url_for('partnership.admins_edit', id=id))

            del form.role
            form.populate_obj(user)

            if user.username == '':
                user.username = None
            user.save()

            user.reports = list()
            # re-adding reports
            for id in form.reports_list.data:
                link = ReportUserTie()
                link.report_id = id
                link.user_id = user.id
                db.session.add(link)
            db.session.commit()

            flash(_('User has been saved successfully.'), 'success')
            return redirect(url_for('partnership.account_admins', id=user.partnership_account_id))
        else:
            form.reports_list.process_data([link.report.id for link in user.reports])

        return render_template('admins/edit.jinja2', form=form, user=user)
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


# TODO: DISCUSS PARTNERSHIP REMOVAL LOGIC
# TODO: needs review
@partnership.route('/accounts/bulk_delete', methods=['POST'])
def accounts_bulk_delete():
    if current_user.role != 'admin':
        form = BulkDeleteForm()

        # db.session.query(User) \
        #     .filter(User.partnership_id.in_(ids)) \
        #     .update({"active": False}, synchronize_session='fetch')
        #
        # # TODO: cancel subscription for all admin users
        #
        # db.session.query(PartnershipAccount) \
        #     .filter(PartnershipAccount.partnership_id.in_(ids)) \
        #     .update({"active": False}, synchronize_session='fetch')

        if form.validate_on_submit():
            ids = User.get_bulk_action_ids(request.form.get('scope'),
                                           request.form.getlist('bulk_ids'),
                                           omit_ids=[current_user.id],
                                           query=request.args.get('q', ''))

            # Prevent circular imports.
            from buyercall.blueprints.billing.tasks import delete_users

            delete_users.delay(ids)

            flash(_n('%(num)d user was scheduled to be deleted.',
                     '%(num)d users were scheduled to be deleted.',
                     num=len(ids)), 'success')
        else:
            flash(_('No users were deleted, something went wrong.'), 'danger')

        return redirect(url_for('partnership.accounts'))
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


# TODO: DISCUSS PARTNERSHIP SUBSCRIPTION LOGIC
# TODO: needs review
@partnership.route('/accounts/cancel_subscription', methods=['POST'])
def accounts_cancel_subscription():
    if current_user.role != 'admin':
        form = UserCancelSubscriptionForm()

        if form.validate_on_submit():
            user = User.query.get(request.form.get('id'))

            if user:
                subscription = Subscription()
                if subscription.cancel(user):
                    flash(_('Subscription has been cancelled for %(user)s.',
                            user=user.name), 'success')
            else:
                flash(_('No subscription was cancelled, something went wrong.'),
                      'danger')

        return redirect(url_for('partnership.accounts'))
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/accounts/act_as', methods=['POST'])
def act_as():
    if current_user.role != 'admin':
        s = current_supervisor_user
        u = current_user

        target_user = User.query.get(request.form.get('account_id'))

        if target_user is None:
            flash(_('Such Account does not exist'))
            return redirect(url_for('partnership.accounts'))

        if target_user.partnership_id != current_user.partnership_id:
            flash(_("You don't have access to load this account"))
            return redirect(url_for('partnership.accounts'))

        if not current_supervisor_user.is_authenticated:
            supervisor_login_user(u, remember=False, force=True)

        logout_user()
        login_user(target_user, remember=False, force=True)

        return redirect(url_for('user.settings'))
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/partnership/partnership_invite', methods=['GET', 'POST'])
@anonymous_required()
def partnership_invite(reset_token=None):
    from buyercall.blueprints.user.models import User
    from buyercall.blueprints.partnership.forms import PartnershipSignupForm

    form = PartnershipSignupForm(reset_token=request.args.get('reset_token'))

    u = User.deserialize_token(form.reset_token.data)
    if u is None:
        flash(_('Your reset token has expired or was tampered with.'),
              'danger')
        return redirect(url_for('user.login'))

    if form.validate_on_submit():
        form.populate_obj(u)
        u.password = User.encrypt_password(request.form.get('password', None))
        u.save()

        # save password updated date
        u.save_password_updated_date()

        flash(_('Successfully signed up. Please login to continue.'), 'success')
        return redirect(url_for('user.login'))

    partner = Partnership.query.filter(Partnership.id == u.partnership_id).first()
    if partner is None:
        partner_name = ''
    else:
        partner_name = partner.name

    return render_template('partnership/signup.jinja2', form=form, user=u, partner_name=partner_name)


@partnership.route('/partnership/settings', methods=['GET', 'POST'])
def settings():
    if current_user.role != 'admin':
        pship = current_user.partnership
        form = PartnershipForm(obj=pship)
        form.logo.label.text = 'Change Logo'
        del form.default_billing_type

        if form.validate_on_submit():
            with db.session.no_autoflush:
                try:
                    del form.logo
                    form.populate_obj(pship)

                    if len(request.files) > 0:
                        file = request.files['logo']
                        file.seek(0, os.SEEK_END)
                        file_length = file.tell()
                        if file_length == 0:
                            pass
                        elif file_length > 1 * 1024 * 1024:
                            flash('Logo is too big and was not saved. Max size is 1MB', 'danger')
                            return render_template('partnership/settings.jinja2', form=form)
                        else:
                            file.seek(0)
                            folder_name = '%s_%s' % (pship.id, pship.name)
                            file_name = file.filename
                            from buyercall.blueprints.partnership.tasks import upload_partnership_logo
                            upload_partnership_logo(folder_name, file)
                            pship.logo = '%s/%s' % (folder_name, file_name)
                            db.session.add(pship)
                            db.session.flush()

                    db.session.commit()

                    return redirect(url_for('user.settings'))
                except Exception as e:
                    form.logo = PartnershipForm(obj=pship).logo
                    flash(_("{}".format(e)), 'danger')
                    db.session.rollback()
        return render_template('partnership/settings.jinja2', form=form, partnership=pship)
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/partnership/twilio_credentials', methods=['GET', 'POST'])
def twilio_credentials():
    encrypt_key = app.config['CRYPTO_SECRET_KEY']
    if current_user.role == 'partner':
        partner = current_user.partnership
        # Check and Get the twilio record for a specific partner account thats active
        cpaas = PartnershipCpaasProviders.query.filter(
            PartnershipCpaasProviders.partnership_id == partner.id,
            PartnershipCpaasProviders.active.is_(True),
            PartnershipCpaasProviders.cpaas_provider_name == 'twilio'
        ).first()

        if cpaas is not None:
            cipher = AESCipher(encrypt_key)
            # Decrypt the credentials before pushing it through to the form
            if cpaas.cpaas_account_id is not None and cpaas.cpaas_account_id is not '':
                decrypted_username = cipher.decrypt(cpaas.cpaas_account_id)
            else:
                decrypted_username = ''

            if cpaas.cpaas_api_token is not None and cpaas.cpaas_api_token is not '':
                decrypted_token = cipher.decrypt(cpaas.cpaas_api_token)
            else:
                decrypted_token = ''

            # Pass the descrypted and other cpaas values to the form
            form = PartnershipTwilioApiForm(cpaas_account_id=decrypted_username,
                                            cpaas_api_token=decrypted_token,
                                            cpaas_caller_id=cpaas.cpaas_caller_id)

            if form.validate_on_submit():
                cipher = AESCipher(encrypt_key)
                try:
                    # On gathering the data from the form encrypt the twilio credentials
                    if form.cpaas_account_id.data:
                        cpaas.cpaas_account_id = cipher.encrypt(form.cpaas_account_id.data)
                    if form.cpaas_api_token.data:
                        cpaas.cpaas_api_token = cipher.encrypt(form.cpaas_api_token.data)
                    cpaas.cpaas_caller_id = form.cpaas_caller_id.data

                    cpaas.save()
                    db.session.commit()

                    flash(_('The Twilio API Credentials have been updated successfully.'), 'success')
                    return redirect(url_for('admin.integrations'))
                except Exception as e:
                    log.error(traceback.format_exc())
                    db.session.rollback()
                    flash(_("An error occurred while saving the Twilio API Credentials. Please contact support "
                            "for assistance."), 'danger')
        else:
            cpaas = PartnershipCpaasProviders()
            form = PartnershipTwilioApiForm(obj=cpaas)
            if form.validate_on_submit():
                cipher = AESCipher(encrypt_key)
                try:
                    cpaas.cpaas_provider_name = 'twilio'
                    cpaas.partnership_id = partner.id
                    if form.cpaas_account_id.data is not None and form.cpaas_account_id.data is not '':
                        cpaas.cpaas_account_id = cipher.encrypt(form.cpaas_account_id.data)
                    if form.cpaas_api_token.data is not None and form.cpaas_api_token.data is not '':
                        cpaas.cpaas_api_token = cipher.encrypt(form.cpaas_api_token.data)
                    cpaas.cpaas_caller_id = form.cpaas_caller_id.data
                    cpaas.save()
                    db.session.commit()

                    flash(_('The Twilio API Credentials have been updated successfully.'), 'success')
                    return redirect(url_for('admin.integrations'))
                except Exception as e:
                    log.error(traceback.format_exc())
                    db.session.rollback()
                    flash(_("An error occurred while saving the Twilio API Credentials. Please contact support "
                            "for assistance."), 'danger')
        return render_template('partnership/twilio_credentials.jinja2', form=form)
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/partnership/bandwidth_credentials', methods=['GET', 'POST'])
def bandwidth_credentials():
    encrypt_key = app.config['CRYPTO_SECRET_KEY']
    if current_user.role == 'partner':
        partner = current_user.partnership
        # Check and Get the Bandwidth record for a specific partner account thats active
        cpaas = PartnershipCpaasProviders.query \
            .filter(PartnershipCpaasProviders.partnership_id == partner.id,
                    PartnershipCpaasProviders.active.is_(True),
                    PartnershipCpaasProviders.cpaas_provider_name == 'bandwidth').first()

        if cpaas is not None:
            cipher = AESCipher(encrypt_key)
            # Decrypt the credentials before pushing it through to the form
            if cpaas.cpaas_user_id is not None and cpaas.cpaas_user_id is not '':
                decrypted_username = cipher.decrypt(cpaas.cpaas_user_id)
            else:
                decrypted_username = ''

            if cpaas.cpaas_api_token is not None and cpaas.cpaas_api_token is not '':
                decrypted_token = cipher.decrypt(cpaas.cpaas_api_token)
            else:
                decrypted_token = ''

            if cpaas.cpaas_api_secret is not None and cpaas.cpaas_api_secret is not '':
                decrypted_secret = cipher.decrypt(cpaas.cpaas_api_secret)
            else:
                decrypted_secret = ''

            if cpaas.cpaas_account_id is not None and cpaas.cpaas_account_id is not '':
                decrypted_account = cipher.decrypt(cpaas.cpaas_account_id)
            else:
                decrypted_account = ''

            if cpaas.cpaas_api_username is not None and cpaas.cpaas_api_username is not '':
                decrypted_api_username = cipher.decrypt(cpaas.cpaas_api_username)
            else:
                decrypted_api_username = ''

            if cpaas.cpaas_api_password is not None and cpaas.cpaas_api_password is not '':
                decrypted_api_password = cipher.decrypt(cpaas.cpaas_api_password)
            else:
                decrypted_api_password = ''

            if cpaas.cpaas_cnam_password is not None and cpaas.cpaas_cnam_password is not '':
                decrypted_cnam_password = cipher.decrypt(cpaas.cpaas_cnam_password)
            else:
                decrypted_cnam_password = ''

            # Pass the descrypted and other cpaas values to the form
            form = PartnershipBandwidthApiForm(cpaas_user_id=decrypted_username,
                                               cpaas_api_token=decrypted_token,
                                               cpaas_api_secret=decrypted_secret,
                                               cpaas_caller_id=cpaas.cpaas_caller_id,
                                               cpaas_account_id=decrypted_account,
                                               cpaas_api_username=decrypted_api_username,
                                               cpaas_api_password=decrypted_api_password,
                                               cpaas_site_id=cpaas.cpaas_site_id,
                                               cpaas_location_id=cpaas.cpaas_location_id,
                                               cpaas_sms_application_id=cpaas.cpaas_sms_application_id,
                                               cpaas_voice_application_id=cpaas.cpaas_voice_application_id,
                                               cpaas_cnam_password=decrypted_cnam_password)
            if form.validate_on_submit():
                cipher = AESCipher(encrypt_key)
                try:
                    # On gathering the data from the form encrypt the Bandwidth credentials
                    if form.cpaas_user_id.data is not None and form.cpaas_user_id.data is not '':
                        cpaas.cpaas_user_id = cipher.encrypt(form.cpaas_user_id.data)
                    if form.cpaas_api_token.data is not None and form.cpaas_api_token.data is not '':
                        cpaas.cpaas_api_token = cipher.encrypt(form.cpaas_api_token.data)
                    if form.cpaas_api_secret.data is not None and form.cpaas_api_secret.data is not '':
                        cpaas.cpaas_api_secret = cipher.encrypt(form.cpaas_api_secret.data)
                    if form.cpaas_account_id.data is not None and form.cpaas_account_id.data is not '':
                        cpaas.cpaas_account_id = cipher.encrypt(form.cpaas_account_id.data)
                    if form.cpaas_api_username.data is not None and form.cpaas_api_username.data is not '':
                        cpaas.cpaas_api_username = cipher.encrypt(form.cpaas_api_username.data)
                    if form.cpaas_api_password.data is not None and form.cpaas_api_password.data is not '':
                        cpaas.cpaas_api_password = cipher.encrypt(form.cpaas_api_password.data)
                    cpaas.cpaas_site_id = form.cpaas_site_id.data
                    cpaas.cpaas_location_id = form.cpaas_location_id.data
                    cpaas.cpaas_sms_application_id = form.cpaas_sms_application_id.data
                    cpaas.cpaas_voice_application_id = form.cpaas_voice_application_id.data
                    cpaas.cpaas_caller_id = form.cpaas_caller_id.data
                    if form.cpaas_cnam_password.data is not None and form.cpaas_cnam_password.data is not '':
                        cpaas.cpaas_cnam_password = cipher.encrypt(form.cpaas_cnam_password.data)

                    cpaas.save()
                    db.session.commit()

                    flash(_('The Bandwidth API Credentials have been updated successfully.'), 'success')
                    return redirect(url_for('admin.integrations'))
                except:
                    log.error(traceback.format_exc())
                    db.session.rollback()
                    flash(_("An error occurred while saving the Bandwidth API Credentials. Please contact support "
                            "for assistance."), 'danger')
        else:
            cpaas = PartnershipCpaasProviders()
            form = PartnershipBandwidthApiForm(obj=cpaas)
            if form.validate_on_submit():
                cipher = AESCipher(encrypt_key)
                try:
                    cpaas.cpaas_provider_name = 'bandwidth'
                    cpaas.partnership_id = partner.id
                    if form.cpaas_user_id.data is not None and form.cpaas_user_id.data is not '':
                        cpaas.cpaas_user_id = cipher.encrypt(form.cpaas_user_id.data)
                    if form.cpaas_api_token.data is not None and form.cpaas_api_token.data is not '':
                        cpaas.cpaas_api_token = cipher.encrypt(form.cpaas_api_token.data)
                    if form.cpaas_api_secret.data is not None and form.cpaas_api_secret.data is not '':
                        cpaas.cpaas_api_secret = cipher.encrypt(form.cpaas_api_secret.data)
                    if form.cpaas_account_id.data is not None and form.cpaas_account_id.data is not '':
                        cpaas.cpaas_account_id = cipher.encrypt(form.cpaas_account_id.data)
                    if form.cpaas_api_username.data is not None and form.cpaas_api_username.data is not '':
                        cpaas.cpaas_api_username = cipher.encrypt(form.cpaas_api_username.data)
                    if form.cpaas_api_password.data is not None and form.cpaas_api_password.data is not '':
                        cpaas.cpaas_api_password = cipher.encrypt(form.cpaas_api_password.data)
                    cpaas.cpaas_site_id = form.cpaas_site_id.data
                    cpaas.cpaas_location_id = form.cpaas_location_id.data
                    cpaas.cpaas_sms_application_id = form.cpaas_sms_application_id.data
                    cpaas.cpaas_voice_application_id = form.cpaas_voice_application_id.data
                    cpaas.cpaas_caller_id = form.cpaas_caller_id.data
                    if form.cpaas_cnam_password.data is not None and form.cpaas_cnam_password.data is not '':
                        cpaas.cpaas_cnam_password = cipher.encrypt(form.cpaas_cnam_password.data)

                    cpaas.save()
                    db.session.commit()

                    flash(_('The Bandwidth API Credentials have been updated successfully.'), 'success')
                    return redirect(url_for('admin.integrations'))
                except Exception as e:
                    log.error(traceback.format_exc())
                    db.session.rollback()
                    flash(_("An error occurred while saving the Bandwidth API Credentials. Please contact support"
                            "for assistance."), 'danger')
        return render_template('partnership/bandwidth_credentials.jinja2', form=form)
    else:
        flash(_('You do not have permission to do that.'), 'danger')
        return redirect('/')


@partnership.route('/partnership/<int:pid>/finserv_prequalify_credit', methods=['POST', 'GET'])
@role_required('partner', 'sysadmin')
def partner_finserv_prequalify_credit(pid):
    credit_object = PartnershipCreditTie()
    form = PartnerFinservPrequalifyForm(obj=credit_object)
    partner_id = pid
    provider = 'Finserv'
    product = 'prequalify'
    credit_profile = PartnershipCreditTie.query \
        .filter(and_(PartnershipCreditTie.service_provider ==
                     provider, PartnershipCreditTie.product_type == product,
                     PartnershipCreditTie.partnership_id == partner_id)).first()
    if credit_profile is not None and credit_profile.product_type == 'prequalify':
        encrypt_key = app.config['CRYPTO_SECRET_KEY']
        cipher = AESCipher(encrypt_key)
        # Decrypt the credentials before pushing it through to the form
        if credit_profile.api_username is not None and credit_profile.api_username is not '':
            decrypted_username = cipher.decrypt(credit_profile.api_username)
        else:
            decrypted_username = ''

        if credit_profile.api_password is not None and credit_profile.api_password is not '':
            decrypted_password = cipher.decrypt(credit_profile.api_password)
        else:
            decrypted_password = ''
        if credit_profile.api_account is not None and credit_profile.api_account is not '':
            decrypted_account = cipher.decrypt(credit_profile.api_account)
        else:
            decrypted_account = ''
        # Pass the decrypted and other credit values to the form
        form = PartnerFinservPrequalifyForm(active=credit_profile.active,
                                            api_username=decrypted_username,
                                            api_password=decrypted_password,
                                            api_account=decrypted_account)
        if form.validate_on_submit():
            cipher = AESCipher(encrypt_key)
            try:
                # On gathering the data from the form encrypt the Bandwidth credentials
                credit_profile.active = form.active.data
                if form.api_username.data is not None and form.api_username.data is not '':
                    credit_profile.api_username = cipher.encrypt(form.api_username.data)
                if form.api_password.data is not None and form.api_password.data is not '':
                    credit_profile.api_password = cipher.encrypt(form.api_password.data)
                if form.api_account.data is not None and form.api_account.data is not '':
                    credit_profile.api_account = cipher.encrypt(form.api_account.data)
                credit_profile.experian_enabled = True
                credit_profile.save()
                db.session.commit()

                flash(_('The Finserv API Credentials have been updated successfully.'), 'success')
                return redirect(url_for('admin.integrations'))
            except:
                log.error(traceback.format_exc())
                db.session.rollback()
                flash(_("An error occurred while saving the Finserv API Credentials. Please contact support "
                        "for assistance."), 'danger')
    else:
        new_partner_credit_credentials_set(credit_object, provider, product, partner_id)
    return render_template('partnership/partner_finserv_prequalify_credit.jinja2', form=form)


def new_partner_credit_credentials_set(credit_object, provider, product_type, pid):
    encrypt_key = app.config['CRYPTO_SECRET_KEY']
    if product_type.lower() == 'prequalify' and provider == 'Finserv':
        form = PartnerFinservPrequalifyForm(obj=credit_object)
    else:
        flash(_('The product type and credit provider mapping is not available.'), 'danger')
        return redirect(url_for('admin.integrations'))
    if provider == 'Finserv':
        try:
            if form.validate_on_submit():
                cipher = AESCipher(encrypt_key)
                credit_object.service_provider = provider
                credit_object.active = form.active.data
                credit_object.partnership_id = pid
                credit_object.product_type = product_type
                if form.api_username.data is not None and form.api_username.data is not '':
                    credit_object.api_username = cipher.encrypt(form.api_username.data)
                if form.api_password.data is not None and form.api_password.data is not '':
                    credit_object.api_password = cipher.encrypt(form.api_password.data)
                if form.api_account.data is not None and form.api_account.data is not '':
                    credit_object.api_account = cipher.encrypt(form.api_account.data)
                credit_object.experian_enabled = True
                credit_object.save()
                db.session.commit()

                flash(_('The Finserv API Credentials have been updated successfully.'), 'success')
                return redirect(url_for('admin.integrations'))
        except Exception as e:
            log.error(traceback.format_exc())
            log.error(e)
            db.session.rollback()
            flash(_("An error occurred while saving the Finserv Credentials. Please contact support"
                    "for assistance."), 'danger')
    else:
        flash(_('A service provider was not found. Please contact support for assistance.'), 'success')
        return redirect(url_for('admin.integrations'))


@partnership.route('/forms-data')
@role_required('partner', 'sysadmin', 'limitsysadmin')
def forms_data():
    from buyercall.blueprints.form_leads.models import ExternalForm
    """Return server side data."""
    # defining columns
    columns = [
        ColumnDT(ExternalForm.display_name),
        ColumnDT(ExternalForm.created_on),
        ColumnDT(ExternalForm.updated_on)
    ]

    filter_by = (ExternalForm.is_deactivated == True)

    log.error('every: {}'.format(filter_by))

    # defining the initial query depending on your purpose
    query = db.session.query().select_from(ExternalForm).filter(filter_by)

    # instantiating a DataTable for the query and table needed
    row_table = DataTables(request.args, query, columns)

    # returns what is needed by DataTable
    return jsonify(row_table.output_result())


@partnership.route('/add-forms', methods=['POST'])
@role_required('partner', 'sysadmin', 'limitsysadmin')
def add_account_form():
    from buyercall.blueprints.form_leads.models import ExternalForm, ExternalFormFieldDefinition, ExternalFormField, \
        template_field_association
    from ..widgets.models import Widget
    if request.method == 'POST':
        display_name = request.form.get('display_name', '')

        web_form = request.form.get('web_form')

        # Check the value of the web_form checkbox
        if web_form == 'on':
            web_form = True
            public_id = request.form.get('public_id')
            field_template = request.form.get('field_template')
        else:
            web_form = False

        partnership_account_id = request.form.get('partnership_account_id')
        routing = Widget.query.filter(
            Widget.partnership_account_id == partnership_account_id,
            Widget.id == (request.form.get('routing') or None)
        ).first()

        conditional_notification = request.form.get('is_conditional', '')
        conditions = request.form.get('condition_criteria', '')

        if conditional_notification in ['true', 'True'] and conditions:
            is_conditional_notification = True
        else:
            is_conditional_notification = False

        partial_data_email = request.form.get('partial_data_email', '')
        if partial_data_email == 'on':
            partial_data_email = True
        else:
            partial_data_email = False

        full_submit_email = request.form.get('full_submit_email', '')
        if full_submit_email == 'on':
            full_submit_email = True
        else:
            full_submit_email = False

        send_auto_email = int(request.form.get('send_auto_email') == 'on')
        send_auto_sms = int(request.form.get('send_auto_sms') == 'on')

        # Create a new ExternalForm instance
        form = ExternalForm(
            display_name=display_name,
            public_id=public_id if web_form == True else "None",
            template_id=field_template if web_form == True else None,
            routing=routing,
            is_external_api_auto=False,
            auto_prequalify_credit=False,
            partnership_account_id=partnership_account_id,
            is_conditional_notification=is_conditional_notification,
            email_addresses={"emails": request.form.get('recipient_emails', '')},
            adf_email_addresses={"emails": request.form.get('form_adf_emails', '')},
            email_subject=request.form.get('email_subject', ''),
            partial_data_email=partial_data_email,
            full_submit_email=full_submit_email,
            conditional_criteria=json.loads(conditions),
            send_auto_email=send_auto_email,
            send_auto_email_subject=request.form.get('auto_email_subject', ''),
            send_auto_email_msg=request.form.get('auto_email_body', ''),
            send_auto_sms=send_auto_sms,
            send_auto_sms_inbound_id=request.form.get('phoneOptions', ''),
            send_auto_sms_msg=request.form.get('auto_sms_body', ''),
        )

        db.session.add(form)
        db.session.commit()
        if web_form == True:
            field_definition_ids = (
                db.select([template_field_association.c.field_definition_id])
                .where(template_field_association.c.external_form_field_template_id == field_template)
            )

            field_definition_ids = db.engine.execute(field_definition_ids).fetchall()
            field_definition_ids = [result[0] for result in field_definition_ids]
            for field_definition_id in field_definition_ids:
                # Fetch data from the field_definition_id table
                field_definition = ExternalFormFieldDefinition.query.filter_by(field_id=field_definition_id).first()
                print(field_definition)
                if field_definition:
                    # Create a new ExternalFormField instance
                    new_field = ExternalFormField(
                        form_id=form.id,
                        position=field_definition.position,
                        field_id=field_definition.old_field_id,  # Assuming 'old_field_id' is what you need
                        display_name=field_definition.display_name,
                        show_in_table=field_definition.show_in_table
                    )

                    # Add the new_field instance to the session
                    db.session.add(new_field)
            db.session.commit()
        flash(_('The form has been created successfully.'), 'success')
        return redirect(url_for('partnership.account_edit', id=partnership_account_id))


@partnership.route('/account/<int:id>/forms/<int:pid>/delete')
@role_required('partner', 'sysadmin', 'limitsysadmin')
def delete_account_form(id, pid):
    from buyercall.blueprints.form_leads.models import ExternalForm

    deactivated = ExternalForm.api_deactivate(pid, id)
    if deactivated:
        flash(_('The form has been deactivated successfully.'), 'success')
        return redirect(url_for('partnership.account_edit', id=id))
    else:
        flash(_('Form deactivation failed.'), 'danger')
        return redirect(url_for('partnership.account_edit', id=id))


@partnership.route('/update-forms', methods=['POST'])
@role_required('partner', 'sysadmin', 'limitsysadmin')
def update_account_form():
    from buyercall.blueprints.form_leads.models import ExternalForm, ExternalFormFieldDefinition, ExternalFormField, \
        template_field_association
    from ..widgets.models import Widget
    if request.method == 'POST':
        partnership_account_id = request.form.get('partnership_account_id')
        form_id = request.form.get('form_id')
        form = ExternalForm.query.filter(
            ExternalForm.partnership_account_id == partnership_account_id,
            ExternalForm.id == form_id
        ).one()

        web_form = request.form.get('web_form')
        if web_form == 'on':
            web_form = True
            public_id = request.form.get('public_id')
            field_template = request.form.get('field_template')
        else:
            web_form = False

        conditional_notification = request.form.get('is_conditional', '')
        conditions = request.form.get('condition_criteria', '')

        auto_email_respond = request.form.get('send_auto_email', '')
        if auto_email_respond == 'on':
            auto_email_respond = True
        else:
            auto_email_respond = False

        full_submit_email = request.form.get('full_submit_email', '')
        if full_submit_email == 'on':
            full_submit_email = True
        else:
            full_submit_email = False

        auto_sms_respond = request.form.get('send_auto_sms', '')
        if auto_sms_respond == 'on':
            auto_sms_respond = True
        else:
            auto_sms_respond = False

        partial_data_email = request.form.get('partial_data_email', '')
        if partial_data_email == 'on':
            partial_data_email = True
        else:
            partial_data_email = False

        if conditional_notification in ['true', 'True'] and conditions:
            form.is_conditional_notification = True
        else:
            form.is_conditional_notification = False
        form.conditional_criteria = json.loads(conditions)

        routing = Widget.query.filter(
            Widget.partnership_account_id == partnership_account_id,
            Widget.id == (request.form.get('routing') or None)
        ).first()

        # Save the form to the database
        form.display_name = request.form.get('display_name', '')
        form.routing = routing
        form.public_id = public_id if web_form == True else "None",
        form.template_id = field_template if web_form == True else None,
        form.email_addresses = {'emails': request.form.get('recipient_emails', '')}
        form.adf_email_addresses = {'emails': request.form.get('form_adf_emails', '')}
        form.email_subject = request.form.get('email_subject', '')
        form.partial_data_email = partial_data_email
        form.full_submit_email = full_submit_email
        form.send_auto_email = auto_email_respond
        form.send_auto_sms = auto_sms_respond
        form.send_auto_email_subject = request.form.get('auto_email_subject', '')
        form.send_auto_email_msg = request.form.get('auto_email_body', '')
        form.send_auto_sms_inbound_id = request.form.get('phoneOptions', '')
        form.send_auto_sms_msg = request.form.get('auto_sms_body', '')

        old_fields_to_delete = ExternalFormField.query.filter_by(form_id=form.id)
        if old_fields_to_delete:
            for old_field in old_fields_to_delete:
                db.session.delete(old_field)
        db.session.commit()
        if web_form == True:
            field_definition_ids = (
                db.select([template_field_association.c.field_definition_id])
                .where(template_field_association.c.external_form_field_template_id == field_template)
            )

            field_definition_ids = db.engine.execute(field_definition_ids).fetchall()
            field_definition_ids = [result[0] for result in field_definition_ids]
            for field_definition_id in field_definition_ids:
                # Fetch data from the field_definition_id table
                field_definition = ExternalFormFieldDefinition.query.filter_by(field_id=field_definition_id).first()
                print(field_definition)
                if field_definition:
                    # Create a new ExternalFormField instance
                    new_field = ExternalFormField(
                        form_id=form.id,
                        position=field_definition.position,
                        field_id=field_definition.old_field_id,  # Assuming 'old_field_id' is what you need
                        display_name=field_definition.display_name,
                        show_in_table=field_definition.show_in_table
                    )

                    # Add the new_field instance to the session
                    db.session.add(new_field)
            db.session.commit()
        flash(_('The form has been updated successfully.'), 'success')
        return redirect(url_for('partnership.account_edit', id=partnership_account_id))