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/sms/tw_sms_tasks.py
import traceback
import logging as log
from datetime import datetime
from flask import current_app, url_for

from buyercall.app import create_celery_app
from buyercall.lib.util_twilio import subaccount_client
from buyercall.blueprints.sms.models import Message
from buyercall.blueprints.contacts.models import Contact
from buyercall.blueprints.phonenumbers.models import Phone
from buyercall.blueprints.partnership.models import PartnershipAccount, Partnership
from buyercall.blueprints.phonenumbers.routing import (
    get_sms_routing_agents, get_agent_number
)
from buyercall.lib.util_webhooks import WebhookUtil
from buyercall.extensions import db
from buyercall.blueprints.filters import format_phone_number

celery = create_celery_app(current_app)
webhooker = WebhookUtil()


@celery.task
def tw_forward_sms(inbound_id, text, lead, message_info, **kwargs):
    """ This function is used to send Twilio sms messages using celery. More information on bandwidth messaging
        can be found here; https://www.twilio.com/docs/sms/tutorials/how-to-send-sms-messages-python
    """
    # Query the inbound phone number and routing details
    inbound = Phone.query.filter(Phone.id == inbound_id).first()
    phonenumber = inbound.phonenumber
    log.info('The Twilio inbound number phone number for smsing is {}'.format(phonenumber))

    # import partnership information to get partnership id
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == inbound.partnership_account_id).first()
    partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

    # Connect to Twilio client
    twilio_client = subaccount_client(inbound.partnership_account.subscription.twilio_subaccount_sid, partner.id)

    routing = inbound.routing_config['defaultRouting']
    log.info('The Twilio inbound number routing config is {}'.format(routing))
    agents = get_sms_routing_agents(routing)
    lead_phone = format_phone_number(lead)
    contact = Contact.query.filter(Contact.phonenumber_1 == lead_phone)\
        .filter(Contact.partnership_account_id == inbound.partnership_account_id).first()
    if contact:
        if contact.firstname:
            contact_name = "{} {} {}".format(contact.firstname, contact.lastname, lead_phone)
        elif contact.caller_id:
            contact_name = "{} {}".format(contact.caller_id, lead_phone)
        else:
            contact_name = lead_phone

        partner_account = PartnershipAccount.query.filter(
            PartnershipAccount.id == inbound.partnership_account_id
        ).first()
        partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

        if partner.partner_url:
            lead_contact_url = '{}/contacts/contact/{}'.format(partner.partner_url, contact.id)
        else:
            lead_contact_url = url_for('contacts.contact_lead_page', id=contact.id, _external=True)
    else:
        contact_name = 'unknown'
        lead_contact_url = 'unavailable'
    log.info('The url for the contact is {}'.format(lead_contact_url))
    try:
        agent_list = []
        for agent in agents:
            agent_phone_number = get_agent_number(agent, routing)
            sms_agent_number = str(agent_phone_number[0])
            log.info('The available agent contact number is {}'.format(sms_agent_number))
            mod_body = 'FROM:{} MSG:{} REPLY: {}'.format(contact_name, text, lead_contact_url)
            twilio_client.messages.create(
                from_=phonenumber,
                to=sms_agent_number,
                body=mod_body
            )
            agent_list.append(agent.id)
            log.info('A Twilio sms message has been successfully sent to agent phone number: {} using phone number {}'
                     .format(sms_agent_number, phonenumber))
    except Exception:
        log.info(traceback.format_exc())
        log.info('The Twilio sms message could not be sent, either due to no agent to receive it o'
                 'r there was another error')
        return

    add_tw_message_lead(inbound_id, message_info, inbound.partnership_account_id, inbound.provider, None, agent_list)


@celery.task
def tw_send_sms(inbound_id, to, text, agent_list, **kwargs):
    """ This function is used to send Twilio sms messages using celery. More information on twilio messaging
        can be found here; https://www.twilio.com/docs/sms/tutorials/how-to-send-sms-messages-python
    """
    # Query the inbound phone number and routing details
    inbound = Phone.query.filter(Phone.id == inbound_id).first()
    phonenumber = inbound.phonenumber

    # import partnership information to get partnership id
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == inbound.partnership_account_id).first()
    partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

    # Connect to Twilio client
    twilio_client = subaccount_client(inbound.partnership_account.subscription.twilio_subaccount_sid, partner.id)

    try:
        message = twilio_client.messages.create(
            from_=phonenumber,
            to=to,
            body=text)
        log.info('A Twilio sms message has been successfully sent using phone number: {}'
                 .format(phonenumber))
        log.info('The message sid is {}'.format(message.sid))
        add_tw_message_lead(inbound_id, message, inbound.partnership_account_id, inbound.provider, '', agent_list)
    except Exception:
        log.info(traceback.format_exc())
        log.info('The Twilio sms message could not be sent! That was an error')


@celery.task
def tw_forward_mms(inbound_id, text, lead, media, message_info, **kwargs):
    """ This function is used to send Twilio sms messages using celery. More information on bandwidth messaging
        can be found here; https://www.twilio.com/docs/sms/tutorials/how-to-send-sms-messages-python
    """
    # Query the inbound phone number and routing details
    inbound = Phone.query.filter(Phone.id == inbound_id).first()
    phonenumber = inbound.phonenumber

    # import partnership information to get partnership id
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == inbound.partnership_account_id).first()
    partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

    # Connect to the Twilio client
    twilio_client = subaccount_client(inbound.partnership_account.subscription.twilio_subaccount_sid, partner.id)

    lead_phone = format_phone_number(lead)
    contact = Contact.query.filter(Contact.phonenumber_1 == lead_phone) \
        .filter(Contact.partnership_account_id == inbound.partnership_account_id).first()
    if contact:
        if contact.firstname:
            contact_name = '{} {} - {}'.format(contact.firstname, contact.lastname, lead_phone)
        elif contact.caller_id:
            contact_name = "{} - {}".format(contact.caller_id, lead_phone)
        else:
            contact_name = lead_phone

        partner_account = PartnershipAccount.query \
            .filter(PartnershipAccount.id == inbound.partnership_account_id).first()
        partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

        if partner.partner_url:
            lead_contact_url = partner.partner_url + '/contacts/contact/' + str(contact.id)
        else:
            lead_contact_url = url_for('contacts.contact_lead_page', id=contact.id, _external=True)
    else:
        contact_name = 'unknown'
        lead_contact_url = 'unavailable'

    log.info('The url for the contact is {}'.format(lead_contact_url))
    log.info('The Twilio inbound number phone number for mmsing is {}'.format(phonenumber))
    routing = inbound.routing_config['defaultRouting']
    log.info('The Twilio inbound number routing config is {}'.format(routing))
    agents = get_sms_routing_agents(routing)
    try:
        agent_list = []
        for agent in agents:
            agent_phone_number = get_agent_number(agent, routing)
            sms_agent_number = str(agent_phone_number[0])
            mod_body = 'FROM:' + contact_name + ' MSG:' + text + ' REPLY:' + lead_contact_url
            log.info('The available agent contact number is {}'.format(sms_agent_number))
            twilio_client.messages.create(
                from_=phonenumber,
                to=sms_agent_number,
                body=mod_body,
                media_url=media,
            )
            agent_list.append(agent.id)
            log.info('A Twilio mms message has been successfully sent to agent phone number: {} using phone number {}'
                     .format(sms_agent_number, phonenumber))
    except Exception:
        log.info(traceback.format_exc())
        log.info('The Twilio mms message could not be sent, '
                 'either due to no agent to receive it or there was another error')
        return

    add_tw_message_lead(inbound_id, message_info, inbound.partnership_account_id, inbound.provider, media, agent_list)


@celery.task
def tw_send_mms(inbound_id, to, text, media, agent_list, **kwargs):
    """ This function is used to send Twilio mms messages using celery. More information on Twilio messaging
        can be found here; https://www.twilio.com/docs/sms/tutorials/how-to-send-sms-messages-python
    """
    # Query the inbound phone number and routing details
    inbound = Phone.query.filter(Phone.id == inbound_id).first()
    phonenumber = inbound.phonenumber
    log.info('The Twilio inbound number phone number for mmsing is {}'.format(phonenumber))
    log.info('the media is {}'.format(media))

    # import partnership information to get partnership id
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == inbound.partnership_account_id).first()
    partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

    # Connect to the Twilio client
    twilio_client = subaccount_client(inbound.partnership_account.subscription.twilio_subaccount_sid, partner.id)
    try:
        message = twilio_client.messages.create(
            from_=phonenumber,
            to=to,
            body=text,
            media_url=media,
        )
        log.info('A Twilio mms message has been successfully sent using phone number: {}'
                 .format(phonenumber))
        log.info('The message sid is {}'.format(message.sid))
        add_tw_message_lead(inbound_id, message, inbound.partnership_account_id, inbound.provider, media, agent_list)
    except Exception as e:
        log.info(traceback.format_exc())
        log.info('The Twilio mms message could not be sent, either due to no agent to receive it or '
                 'there was another error')


@celery.task
def add_tw_message_lead(inbound_id, message_info, partnership_account_id, provider, media, agent_list, **kwargs):
    """
        Add sms lead message to the messages table
    """
    msg_status = ''
    if message_info.direction == 'outbound-api':
        direct = 'outbound'
        msg_status = 'sent'
    else:
        direct = message_info.direction
    # The sender's formatted phone number
    if direct == 'inbound':
        msg_status = 'received'
        format_phone = format_phone_number(message_info.from_)
    else:
        format_phone = format_phone_number(message_info.to)

    contact = Contact.query.filter(Contact.phonenumber_1 == format_phone).filter(
        Contact.partnership_account_id == partnership_account_id
    ).first()
    if not contact:
        contact_entry = Contact(
            phonenumber_1=format_phone,
            partnership_account_id=partnership_account_id
        )
        db.session.add(contact_entry)
        db.session.commit()
        # from buyercall.blueprints.mobile.utils import send_agent_push_notification
        # send_agent_push_notification(contact_entry)
        log.info('The message contact has been added')
    new_contact = Contact.query.filter(Contact.phonenumber_1 == format_phone).filter(
        Contact.partnership_account_id == partnership_account_id
    ).first()
    date = str(message_info.date_created)
    media_url = media
    formatted_pn = format_phone_number(message_info.from_)
    log.info('The media_url is: {}'.format(media_url))
    try:
        if new_contact:
            new_contact_id = new_contact.id
            new_contact.updated_on = date
            if media_url:
                eventype = 'mms'
                url = media_url
            else:
                eventype = 'sms'
                url = ''
            if not agent_list:
                agent_list = []
            message = Message(
                type=eventype,
                provider=provider,
                provider_message_id=message_info.sid,
                provider_message_date=message_info.date_created,
                to=message_info.to,
                from_=formatted_pn,
                body_text=message_info.body,
                media_url=url,
                status=msg_status,
                direction=direct,
                inbound_id=inbound_id,
                partnership_account_id=partnership_account_id,
                contact_id=new_contact_id,
                originating_number=formatted_pn,
                agent_id=agent_list
            )
            db.session.add(message)
            db.session.commit()

            if direct == 'outbound':
                webhooker.trigger_generic_webhook('operational_send_message', message.id)
            elif direct == 'inbound':
                webhooker.trigger_generic_webhook('operational_receive_message', message.id)
        else:
            log.error('There no new contact')
    except Exception as e:
        log.error('Error: Unable to add message lead')


@celery.task
def sms_rule_call_lead(inbound_id, lead_number, agent_id, **kwargs):
    from buyercall.blueprints.leads.models import Lead
    from buyercall.blueprints.phonenumbers.models import Phone
    from buyercall.blueprints.agents.models import Agent
    from buyercall.blueprints.phonenumbers.tasks import connect_lead_to_agent

    inbound = Phone.query.filter(Phone.id == inbound_id).first()

    all_inbound_lead = Lead.query.filter(
        Lead.partnership_account_id == Lead.inbound_id == inbound_id
    ).all()

    if all_inbound_lead:
        for row in all_inbound_lead:
            lead_no = format_phone_number(row.phonenumber)
            log.info('The phonenumber is {}'.format(row.phonenumber))
            if lead_no == lead_number:
                progress_status = row.progress_status
    else:
        progress_status = 'new lead'

    agent = Agent.query.filter(Agent.id == agent_id).first()
    log.info('Is the agent available now? {}'.format(agent.available_now))

    # Return contact details
    contact_lead = Contact.query.filter(Contact.phonenumber_1 == lead_number).filter(
        Contact.partnership_account_id == inbound.partnership_account_id
    ).first()
    if not contact_lead:
        return 'Contact lead with phone nummber: {} not found'.format(lead_number), 400

    try:
        lead = Lead(
            partnership_account_id=inbound.partnership_account_id,
            firstname=contact_lead.firstname,
            lastname=contact_lead.lastname,
            phonenumber=contact_lead.phonenumber_1,
            email=contact_lead.email,
            starttime=datetime.utcnow(),
            call_type='outbound',
            my_phone=inbound.phonenumber,
            inbound_id=inbound_id,
            agent_id=agent_id,
            progress_status=progress_status,
            status='ringing',
            contact_id=contact_lead.id,
        )
        lead.save()
        # A hack to specify how to contact the agent
        contact_using = 'phone'
        call_settings = {
            'agents': [{'id': agent_id, 'contactUsing': contact_using}]
        }

        connect_lead_to_agent.delay(lead.id, agent_id, call_settings)

    except Exception as e:
        log.error('An outbound call to agent and lead can not be made based on the '
                  'sms rule for the inbound id: {}'.format(inbound_id))
        log.error(traceback.format_exc())

    return ''