File: //home/arjun/projects/buyercall_forms/buyercall/buyercall/blueprints/phonenumbers/tasks.py
import traceback
import logging as log
import time
import boto
import uuid
import boto3
import requests
from io import BytesIO
from buyercall.lib.util_crypto import AESCipher
import redis
from flask import url_for, current_app as app
import pytz
from flask_babel import lazy_gettext as _
from sqlalchemy.orm import load_only
from buyercall.app import create_celery_app
from buyercall.lib.flask_mailplus import _try_renderer_template
from buyercall.lib.util_ses_email import send_ses_email
from buyercall.lib.util_twilio import (
CallStorage, subaccount_client, InboundCallState as State,
)
from buyercall.lib.util_webhooks import WebhookUtil
from buyercall.extensions import db
from buyercall.blueprints.phonenumbers.models import Phone
from buyercall.blueprints.leads.models import Lead
from buyercall.blueprints.agents.models import Agent
from buyercall.blueprints.user.models import User
from buyercall.blueprints.contacts.models import Contact
from buyercall.blueprints.partnership.models import PartnershipAccount, Partnership
from buyercall.blueprints.phonenumbers.routing import (
get_available_agents, get_routing_agents,
schedule_callback, get_agent_number
)
HOURS = 3600
DAYS = 86400 # The length of a day in seconds
AGENT_TIMEOUT = 23 # The agent calls will be timed out/dropped in the seconds specified if no answer from agent
celery = create_celery_app(app)
webhooker = WebhookUtil()
@celery.task
def call_simultaneous(agent_ids, lead_id, routing, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
log.debug('Parallel call task started.')
lead = Lead.query\
.join(Lead.partnership_account)\
.join(PartnershipAccount.partnership)\
.filter(Lead.id == lead_id)\
.one()
# import partnership information to get partnership id
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
# Get the partner id to get relevant twilio credentails with twilio client
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
agents = get_available_agents(agent_ids, expand_groups=True)
if not agents:
# TODO: Notify lead
log.warning('No agents are available to service lead {}.'.format(
lead_id
))
lead.status = 'missed'
db.session.commit()
# send_notify_email(lead, lead.widget)
storage = CallStorage(redis_db, lead_id)
log.debug('Calling {} agents...'.format(len(agents)))
call = None
subscription = lead.partnership_account.subscription
if not subscription:
subscription = lead.partnership_account.partnership.subscription
storage.is_group = False
twilio_client = subaccount_client(subscription.twilio_subaccount_sid, partner.id)
for agent in agents:
try:
agent_number, extension = get_agent_number(agent, routing)
digits = 'wwww{}'.format(extension) if extension else None
with storage.lock():
if storage.state in [
State.NEW, State.LEAD_ONHOLD, State.CALLBACK_PROMPT
]:
call = twilio_client.calls.create(
to=agent_number,
from_=lead.inbound.phonenumber,
url=url_for(
'twilio_inbound.agent_digit_prompt',
lead_id=lead_id,
agent_id=agent.id,
_external=True,
_scheme='https'
),
status_callback=url_for(
'twilio_inbound.agent_inbound_call_status',
dial_digit=str(routing['dialDigit']),
agent_id=agent.id,
lead_id=lead_id,
_external=True,
_scheme='https'
),
status_callback_event=['ringing', 'answered', 'completed'],
send_digits=digits,
timeout=AGENT_TIMEOUT
)
storage.push_agent_call(agent.id, call.sid)
if agent and lead:
# from buyercall.blueprints.contacts.models import Contact
contact = Contact.query.filter(Contact.id == lead.contact_id).first()
if contact and contact.agent_id != agent.id:
contact.agent_id = agent.id
contact.agent_assigned = agent.full_name
db.session.commit()
from buyercall.blueprints.mobile.utils import send_agent_push_notification
send_agent_push_notification(contact)
except Exception as e:
log.warning(traceback.format_exc())
log.warning('Error calling agent {}...'.format(
agent.id
))
if call is None:
# None of the calls got through
lead.status = 'missed'
db.session.commit()
@celery.task
def redirect_to_callback_prompt(lead_id, **kwargs):
"""
If nobody has picked up in 30 seconds, redirect lead to a callback
prompt. See https://trello.com/c/Gbwmo0Ox/ for discussion.
"""
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
lead = Lead.query.join(Lead.partnership_account).join(PartnershipAccount.partnership).filter(
Lead.id == lead_id
).first()
# import partnership information to get partnership id
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
# Get the partner id to get relevant twilio credentails with twilio client
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
subscription = lead.partnership_account.subscription
if not subscription:
subscription = lead.partnership_account.partnership.subscription
twilio_client = subaccount_client(subscription.twilio_subaccount_sid, partner.id)
storage = CallStorage(redis_db, lead_id)
with storage.lock():
if storage.state == State.LEAD_ONHOLD:
twilio_client.calls.route(storage.call_sid, url=url_for(
'twilio_inbound.lead_callback_prompt',
lead_id=lead_id,
_external=True,
_scheme='https'
))
storage.state = State.CALLBACK_PROMPT
@celery.task
def callback_lead(lead_id, **kwargs):
""" Scheduled callbacks for missed leads (1, 6, 12 hours)
"""
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
lead = Lead.query.join(Lead.partnership_account).join(PartnershipAccount.partnership).join(Lead.inbound).filter(
Lead.id == lead_id
).first()
if not lead:
return
# import partnership information to get partnership idt
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
# Get the partner id to get relevant twilio credentails with twilio client
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
storage = CallStorage(redis_db, lead_id)
routing = storage.routing
if not routing:
log.warning('Callback routing missing; canceling callback')
return
if storage.state != State.CALL_ME_BACK:
log.warning('Lead state {} instead of CALL_ME_BACK; canceling.'.format(
storage.state
))
return
routing['callOrder'] = 'simultaneous'
storage.routing = routing
subscription = lead.partnership_account.subscription
if not subscription:
subscription = lead.partnership_account.partnership.subscription
twilio_client = subaccount_client(subscription.twilio_subaccount_sid, partner.id)
storage.inc_callback_cnt()
agents = get_routing_agents(routing)
if not agents:
log.warning('No available agents to serve lead {}!'.format(lead_id))
schedule_callback(storage)
return
storage.state = State.CALLBACK
storage.is_group = False
log.debug('Calling {} agents...'.format(len(agents)))
call = None
webhooker.trigger_generic_webhook('operational_start_call', lead.id)
for agent in agents:
try:
agent_number, extension = get_agent_number(agent, routing)
digits = 'wwww{}'.format(extension) if extension else None
with storage.lock():
if storage.state == State.CALLBACK:
call = twilio_client.calls.create(
to=agent_number,
from_=lead.inbound.phonenumber,
url=url_for(
'twilio_inbound.agent_callback_lead',
lead_id=lead_id,
agent_id=agent.id,
_external=True,
_scheme='https'
),
status_callback=url_for(
'twilio_inbound.agent_callback_call_status',
dial_digit=str(routing['dialDigit']),
agent_id=agent.id,
lead_id=lead_id,
_external=True,
_scheme='https'
),
status_callback_event=['answered', 'completed'],
send_digits=digits,
timeout=AGENT_TIMEOUT
)
storage.push_agent_call(agent.id, call.sid)
except Exception as e:
log.warning(traceback.format_exc())
log.warning('Error calling agent {}...'.format(
agent.id
))
if call is None:
# None of the calls got through
lead.status = 'missed'
db.session.commit()
schedule_callback(storage)
@celery.task
def connect_lead_to_agent(lead_id, agent_id, call_settings, **kwargs):
""" Scheduled callbacks for missed leads (1, 6, 12 hours)
"""
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
from ..agents.models import Agent
lead = Lead.query.join(Lead.partnership_account).join(PartnershipAccount.partnership).join(Lead.inbound).filter(
Lead.id == lead_id
).first()
if not lead:
return
# import partnership information to get partnership id
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
# Get the partner id to get relevant twilio credentails with twilio client
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
storage = CallStorage(redis_db, lead_id)
storage.routing = call_settings
storage.manual_call = 'True'
storage.routing_config = {}
subscription = lead.partnership_account.subscription
if not subscription:
subscription = lead.partnership_account.partnership.subscription
twilio_client = subaccount_client(subscription.twilio_subaccount_sid, partner.id)
agent = Agent.query.filter(Agent.id == agent_id).first()
if not agent:
log.error('Cannot find agent with ID {}!'.format(lead_id))
return
storage.state = State.CALLBACK
storage.is_group = False
log.debug('Calling agent with ID {}...'.format(agent_id))
call = None
try:
agent_number, extension = get_agent_number(agent, call_settings)
digits = 'wwww{}'.format(extension) if extension else None
with storage.lock():
if storage.state == State.CALLBACK:
call = twilio_client.calls.create(
to=agent_number,
from_=lead.inbound.phonenumber,
url=url_for(
'twilio_inbound.agent_callback_lead',
lead_id=lead_id,
agent_id=agent.id,
_external=True,
_scheme='https'
),
status_callback=url_for(
'twilio_inbound.agent_callback_call_status',
agent_id=agent.id,
lead_id=lead_id,
_external=True,
_scheme='https'
),
status_callback_event=['answered', 'completed'],
send_digits=digits,
timeout=AGENT_TIMEOUT
)
storage.push_agent_call(agent.id, call.sid)
except Exception as e:
log.warning(traceback.format_exc())
log.warning('Error calling agent {}...'.format(
agent.id
))
if call is None:
# None of the calls got through
lead.status = 'missed'
db.session.commit()
@celery.task
def call_me_back(**kwargs):
"""
Task which executes every minute, and tries to call back leads which
have asked to be called back soon.
"""
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
for lead_id in redis_db.hkeys('CALL_ME_BACK'):
time_added = float(redis_db.hget('CALL_ME_BACK', lead_id))
if time.time() - time_added > 2 * HOURS:
log.info('Lead {}, added at {}, is probably not waiting for our '
'callback anymore. Removing.'.format(lead_id, time_added))
redis_db.hdel('CALL_ME_BACK', lead_id)
continue
lead = Lead.query.join(Lead.partnership_account).join(PartnershipAccount.partnership).join(Lead.inbound).filter(
Lead.id == lead_id
).first()
if not lead:
log.warning(
'Lead {} not found - removing from callback list.'.format(
lead_id))
redis_db.hdel('CALL_ME_BACK', lead_id)
continue
# import partnership information to get partnership id
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
# Get the partner id to get relevant twilio credentails with twilio client
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
subscription = lead.partnership_account.subscription
if not subscription:
subscription = lead.partnership_account.partnership.subscription
twilio_client = subaccount_client(subscription.twilio_subaccount_sid, partner.id)
storage = CallStorage(redis_db, lead_id)
storage.state = State.CALLBACK
storage.is_group = False
routing = storage.routing
agents = get_routing_agents(routing)
if not agents:
log.warning(
'No available agents to serve lead {}!'.format(lead_id)
)
continue
log.debug('Calling {} agents...'.format(len(agents)))
call = None
for agent in agents:
try:
agent_number, extension = get_agent_number(agent, routing)
digits = 'wwww{}'.format(extension) if extension else None
# Did any agent pick up?
with storage.lock():
if storage.state == State.CALLBACK:
call = twilio_client.calls.create(
to=agent_number,
from_=lead.inbound.phonenumber,
url=url_for(
'twilio_inbound.agent_callback_lead',
lead_id=lead_id,
agent_id=agent.id,
_external=True,
_scheme='https'
),
status_callback=url_for(
'twilio_inbound.agent_callback_call_status',
dial_digit=str(routing['dialDigit']),
agent_id=agent.id,
lead_id=lead_id,
_external=True,
_scheme='https'
),
status_callback_event=['answered', 'completed'],
send_digits=digits,
timeout=AGENT_TIMEOUT,
)
storage.push_agent_call(agent.id, call.sid)
except Exception as e:
log.warning(traceback.format_exc())
log.warning('Error calling agent {}...'.format(
agent.id
))
@celery.task
def send_phonenumber_email(phonenumber, email, partnership_account_id, **kwargs):
partner_account = PartnershipAccount.query.filter(PartnershipAccount.id == partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
partnership_name = partner.name
partnership_logo = partner.logo
ctx = {'phonenumber': phonenumber, 'company': partnership_name, 'partner_logo': partnership_logo}
# Render html template for email
tn_email_template = _try_renderer_template('mail/new_number', ext='html', **ctx)
send_ses_email(recipients=[email],
p_id=partner.id,
subject='New Phone Number Notification',
html=tn_email_template
)
@celery.task
def tw_upload_recording(lead_id, r_url, partner_name, **kwargs):
""" After the call, grab the first recording from Twilio, if any, and
upload to S3.
"""
lead = Lead.query.filter(Lead.id == lead_id).first()
r = r_url
f = '{}.wav'.format(r)
fr = requests.get(f)
log.debug('The recording url is {}'.format(f))
if r == 0:
log.warning('No recordings found for lead {}!'.format(lead.id))
return
hex_value = uuid.uuid4().hex
try:
key = '{}_{}/{}_{}_{}'.format(
partner_name, lead.partnership_account_id, lead.id, 'recording', hex_value)
log.debug('The recording key is {}'.format(key))
finally:
log.debug('Could not set key for recording url')
s3 = boto3.client(
's3',
aws_access_key_id=celery.conf['AMAZON_ACCESS_KEY'],
aws_secret_access_key=celery.conf['AMAZON_SECRET_KEY']
)
s3.put_object(Body=BytesIO(fr.content),
Bucket=celery.conf['RECORDING_BUCKET'],
Key=key,
Metadata={'Content-Type': 'audio/wav'},
ACL='private')
log.info('Uploaded file {}'.format(key))
# Update recording link
lead = Lead.query.options(
load_only("id", "recording_url")
).filter(Lead.id == lead_id).first()
lead.recording_url = '{}::{}'.format(celery.conf['RECORDING_BUCKET'], key)
db.session.commit()
log.info('Lead {} have been updated with recording url {}'.format(lead.id, lead.recording_url))
webhooker.trigger_generic_webhook('operational_end_call', lead.id)
@celery.task
def add_tw_contact(phonenumber, firstname, lastname, callername, partnership_account_id, **kwargs):
# Query the leads table to retrieve the latest lead that was added
latest_lead = Lead.query.filter(Lead.phonenumber == phonenumber).order_by(Lead.created_on.desc()).first()
log.info('latest lead: {}'.format(latest_lead))
# Query contacts to see if lead already exist in the contacts table
contact = Contact.query.filter(
Contact.phonenumber_1 == latest_lead.phonenumber
).filter(Contact.partnership_account_id == partnership_account_id).first()
if contact:
log.info('a lead exist with number {}'.format(contact.phonenumber_1))
contact.updated_on = latest_lead.updated_on
contact.caller_id = callername
log.info('The updated date is: {}'.format(latest_lead.updated_on))
db.session.commit()
else:
contact = Contact(
firstname=firstname,
lastname=lastname,
caller_id=callername,
phonenumber_1=phonenumber,
email='',
partnership_account_id=partnership_account_id,
)
db.session.add(contact)
db.session.commit()
log.info('The contact has been added')
new_contact = Contact.query.filter(
Contact.phonenumber_1 == latest_lead.phonenumber
).filter(Contact.partnership_account_id == partnership_account_id).first()
if new_contact:
latest_lead.contact_id = new_contact.id
db.session.commit()
else:
log.info('no lead contact exist')
@celery.task
def send_email(lead_id, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
from ..widgets.models import split_emails
lead = Lead.query.filter(Lead.id == lead_id).first()
storage = CallStorage(redis_db, lead.id)
if storage.manual_call:
app.logger.debug('Notification email suppressed.')
return
inbound = Phone.query.filter(
Phone.id == lead.inbound_id,
Phone.partnership_account_id == lead.partnership_account_id
).first()
if not inbound:
return
notifications = inbound.notifications
routings = inbound.routing_config
if notifications and ('notifyLeads' not in notifications
or ('notifyLeads' in notifications
and notifications['notifyLeads'] == 'none')):
return
# Send eventual notifications
emails = []
adf_emails = []
user_email = None
user = User.query.filter(
User.partnership_account_id == lead.partnership_account_id,
User.active,
User.is_deactivated.is_(False),
User.role == 'admin'
).first()
if user:
user_email = user.email
agent_ids = [
a['id'] for a in inbound.routing_config['defaultRouting']['agents']
]
agent_emails = [
a.email
for a in Agent.query.options(load_only('email')).filter(
Agent.partnership_account_id == lead.partnership_account_id,
Agent.id.in_(agent_ids)
).all()
]
partner_account = PartnershipAccount.query.filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
if notifications['notifyLeads'] == 'missed' and lead.status == 'missed':
emails.extend(split_emails(notifications['notifyMissedCustom']))
if notifications['notifyMissedAgents']:
emails.extend(agent_emails)
if notifications['notifyMissedMe'] and user_email:
emails.append(user_email)
if notifications['notifyLeads'] == 'all':
emails.extend(split_emails(notifications['notifyAllCustom']))
if notifications['notifyAllAgents']:
emails.extend(agent_emails)
if notifications['notifyAllMe'] and user_email:
emails.append(user_email)
if not emails:
app.logger.warning('Nowhere to send {} lead notification!'.format(
lead.status
))
return
ctx = vars(lead)
eastern = pytz.timezone('US/Eastern')
ctx['created_on'] = lead.created_on.astimezone(eastern).strftime('%c')
ctx['updated_on'] = lead.updated_on.astimezone(eastern).strftime('%c')
ctx['adf_updated_on'] = lead.interaction_time
ctx['partner_logo'] = partner.logo
ctx['company'] = partner.name
if partner.partner_url:
ctx['lead_contact_url'] = partner.partner_url + '/contacts/contact/' + str(lead.contact_id)
else:
ctx['lead_contact_url'] = url_for('contacts.contact_lead_page', id=lead.contact_id, _external=True, _scheme='https')
if lead.firstname:
ctx['caller_name_label'] = 'Caller Name:'
ctx['caller_name'] = ''.join((lead.firstname,' ',lead.lastname))
if lead.caller_id:
ctx['caller_id_label'] = 'Caller Id:'
ctx['caller_id'] =lead.caller_id
log.info('The lead recording url is {}'.format(lead.recording_url))
if lead.recording_url:
ctx['vm_div_style'] = 'block'
else:
ctx['vm_div_style'] = 'none'
if lead.source:
ctx['call_source'] = lead.source
if lead.inbound:
ctx['reference'] = lead.inbound.routing_config.get(
'hiddenInformation', ''
)
try:
app.logger.debug('The email list are {}'.format(emails))
if routings.get('notifyAdf'):
if routings['notifyAdfCustom'] is not None and routings['notifyAdfCustom'] is not '':
multi_adf_emails = split_emails(routings['notifyAdfCustom'])
if multi_adf_emails is not None:
adf_emails.extend(multi_adf_emails)
else:
adf_emails.append(routings['notifyAdfCustom'])
ctx['lead_comments'] = 'Call status: ' + lead.status
ctx['receiver'] = ''
agent_name = lead.agent_name
friendly_name = lead.source
phonenumber = lead.inbound.phonenumber
dealership = partner_account.name
if dealership:
ctx['vendor_name'] = dealership
else:
ctx['vendor_name'] = ''
call_lead_id = lead.id
if call_lead_id:
ctx['call_lead_id'] = call_lead_id
else:
ctx['call_lead_id'] = ''
if agent_name is not None and agent_name is not '' and len(agent_name) > 2:
ctx['lead_comments'] = ctx['lead_comments'] + ', Agent name: ' + agent_name
if friendly_name is not None and friendly_name is not '':
ctx['lead_comments'] = ctx['lead_comments'] + ', Call source: ' + friendly_name
ctx['receiver'] = friendly_name
if phonenumber is not None and phonenumber is not '':
ctx['lead_comments'] = ctx['lead_comments'] + ', Phonenumber: ' + phonenumber
ctx['campaign_name'] = ''
ctx['campaign_exists'] = False
from buyercall.blueprints.contacts.models import Contact, Campaigns
contact = Contact.query.filter(
Contact.id == lead.contact_id,
Contact.partnership_account_id == lead.partnership_account_id)\
.first()
if contact and contact.campaign_id:
campaign = Campaigns.query.filter(
Campaigns.id == contact.campaign_id)\
.first()
if campaign:
ctx['campaign_exists'] = True
ctx['campaign_name'] = campaign.display_name
if adf_emails is not None and len(adf_emails) > 0:
# Render text template for adf email
adf_lead_email_template = _try_renderer_template('mail/adf_lead', ext='txt', **ctx)
send_ses_email(recipients=adf_emails,
p_id=partner.id,
subject=partner.name + ' - ADF lead notification',
text=adf_lead_email_template
)
if lead.status == 'missed' and storage.state == State.MISSED:
# Render html template for email
missed_lead_email_template = _try_renderer_template('mail/missed_lead', ext='html', **ctx)
send_ses_email(recipients=emails,
p_id=partner.id,
subject=partner.name + ' - Missed lead notification',
html=missed_lead_email_template
)
elif lead.status == 'missed' and storage.state == State.CALLBACK:
# Render html template for email
missed_lead_email_template = _try_renderer_template('mail/missed_lead', ext='html', **ctx)
send_ses_email(recipients=emails,
p_id=partner.id,
subject=partner.name + ' - Missed lead notification',
html=missed_lead_email_template
)
elif lead.status == 'retry-pending' or lead.status == 'missed' and storage.state == State.CALL_ME_BACK:
# Render html template for email
callback_lead_email_template = _try_renderer_template('mail/call_back', ext='html', **ctx)
send_ses_email(recipients=emails,
p_id=partner.id,
subject=partner.name + ' - Missed Call-back lead notification',
html=callback_lead_email_template
)
elif lead.status == 'completed' and storage.state == State.CAPTURED:
# Render html template for email
completed_lead_email_template = _try_renderer_template('mail/captured_lead', ext='html', **ctx)
send_ses_email(recipients=emails,
p_id=partner.id,
subject=partner.name + ' - Answered lead notification',
html=completed_lead_email_template
)
else:
# Render html template for email
captured_lead_email_template = _try_renderer_template('mail/captured_lead', ext='html', **ctx)
send_ses_email(recipients=emails,
p_id=partner.id,
subject=partner.name + ' - New lead notification',
html=captured_lead_email_template
)
except Exception as e:
app.logger.error(traceback.format_exc())
@celery.task
def send_callback_email(data, **kwargs):
sub_id = data['Notification']['SubscriptionId']
status = data['Notification']['Status']
message = data['Notification']['Message']
order_id = data['Notification']['OrderId']
order_type = data['Notification']['OrderType']
number = data['Notification']['CompletedTelephoneNumbers']['TelephoneNumber']
ctx = {'sub_id': sub_id, 'status': status,
'message': message, 'order_id': order_id,
'order_type': order_type, 'number': number}
from ..partnership.models import Partnership, PartnershipCpaasProviders, \
PartnershipCpaasPhoneNumberSubscriptions as SubscriptionTable
sub = SubscriptionTable.query.options(
load_only("partnership_id")
).filter(SubscriptionTable.subscription_id == sub_id).first()
partner = Partnership.query.filter(Partnership.id == sub.partnership_id).first()
# Get the encryption key to decrypt email
encrypt_key = celery.conf['CRYPTO_SECRET_KEY']
# Retrieve the bandwidth cpaas details
partner_cpaas = PartnershipCpaasProviders.partnership_bandwidth_credentials(sub.partnership_id)
cipher = AESCipher(encrypt_key)
# Decrypt the email
decrypted_email = cipher.decrypt(partner_cpaas.cpaas_api_username)
try:
# Render html template for email
subscription_email_template = _try_renderer_template('mail/subscription_webhook_email', ext='txt', **ctx)
send_ses_email(recipients=[decrypted_email],
p_id=partner.id,
subject='Bandwidth Subscription Webhook Response',
text=subscription_email_template
)
except Exception as e:
log.error(traceback.format_exc())