File: //home/arjun/projects/buyercall_forms/buyercall/buyercall/blueprints/api2/doc/endpoints/calls.py
import logging
from datetime import datetime
from flask import jsonify, request
from flask_restx import Resource
from sqlalchemy import and_
from buyercall.lib.util_rest import rest_partnership, requires_auth, rest_is_partnership
from buyercall.blueprints.api2.doc import serializers
from buyercall.blueprints.phonenumbers.models import Phone
from buyercall.blueprints.filters import format_phone_number
from buyercall.blueprints.agents.models import Agent
from buyercall.blueprints.contacts.models import Contact
from buyercall.blueprints.api2.restplus import api
from buyercall.blueprints.partnership.models import PartnershipAccount
from buyercall.blueprints.leads.models import Lead
from buyercall.extensions import db
log = logging.getLogger(__name__)
ns = api.namespace('Calls', description='Operations related to calls.', path='/accounts')
@ns.route('/<int:paid>/calls')
@api.doc(responses={200: 'OK',
400: 'Error performing operation.',
401: 'Unauthorized request.'},
params={'paid': 'The partner account Id'})
class Calls(Resource):
"""
# DISABLE ENDPOINT
@api.response(200, 'Call successfully triggered.')
@api.expect(serializers.call_outbound, validate=True)
@requires_auth
def post(self, paid):
"""
"""
Performs an outbound call.
<p>
The Calls API POST endpoint should be used to create an outbound call between a partner account agent and a lead
or customer. The agent will be called first. When the agent picks up the phone will ring and a call to the
lead or customer will be initiated. Once the lead or customer answers they will be connected to the agent.
</p>
<br />
<p>
This endpoint request is similar to a widget outbound call, except for a few key differences. This call request
does not allow for any specific settings, such as greeting messages etc. and calls can only be assigned to a
single agent. The widget outbound calls can handle additional settings, such as greeting messages and calls can
be sent to multiple agents.
</p>
<br />
<p>
It's also important to note that only operational phone numbers with the type 'priority' can be used to perform
outbound calls using this request endpoint. Phone numbers with types; 'tracking' or 'mobile' can not be used for
outbound calls.
</p>
<br />
<p>
You will require a partner authentication token, a partner account id, an agent id
and a phone number id to make a successful request.
"""
"""
if rest_is_partnership and rest_partnership is not None:
from buyercall.blueprints.phonenumbers.tasks import connect_lead_to_agent
_new_contact = None
progress_status = 'new lead'
_contact_using = 'phone'
partnership_account = PartnershipAccount \
.query \
.filter(and_(PartnershipAccount.id == paid, PartnershipAccount.partnership_id == rest_partnership.id)) \
.first()
if partnership_account is not None:
received = request.json
if received is not None:
try:
result_agent_id = received['agent_id']
result_phone_number_id = received['phone_number_id']
result_number = format_phone_number(received['number'])
routing = Phone.query\
.filter(and_(Phone.partnership_account_id == paid, Phone.id == result_phone_number_id))\
.first()
if not routing:
return api.abort(400, message='Error performing call. Cannot find routing phone number.')
agent = Agent.query\
.filter(and_(Agent.partnership_account_id == paid, Agent.id == result_agent_id))\
.first()
if not agent:
return api.abort(400, message='Error performing call. Cannot find agent.')
# check if contact exists... if not create a new one
contact = Contact.query\
.filter(Contact.phonenumber_1 == result_number)\
.filter(Contact.partnership_account_id == paid)\
.first()
if not contact:
contact_entry = Contact(
phonenumber_1=result_number,
partnership_account_id=paid
)
db.session.add(contact_entry)
db.session.commit()
log.info('The lead contact has been added')
new_contact = Contact.query\
.filter(Contact.phonenumber_1 == result_number)\
.filter(Contact.partnership_account_id == paid)\
.first()
contact = new_contact
else:
old_lead = Lead.query.filter(
Lead.partnership_account_id == paid,
Lead.contact_id == contact.id
).first()
if old_lead:
progress_status = old_lead.progress_status
lead = Lead(
partnership_account_id=paid,
firstname=contact.firstname,
lastname=contact.lastname,
phonenumber=contact.phonenumber_1,
email=contact.email,
starttime=datetime.utcnow(),
call_type='outbound',
my_phone=routing.phonenumber,
inbound_id=routing.id,
agent_id=agent.id,
progress_status=progress_status,
status='ringing',
contact_id=contact.id
)
lead.save()
# A hack to specify how to contact the agent
if agent.app_number:
contact_using = 'app'
elif agent.mobile:
contact_using = 'mobile'
else:
contact_using = 'phone'
call_settings = {
'agents': [{
'id': agent.id,
'contactUsing': contact_using
}]
}
connect_lead_to_agent.delay(lead.id, agent.id, call_settings)
return 200
except Exception as e:
log.error('Error performing call. Error: ' + str(e))
return api.abort(400, message='Error performing call.')
else:
return api.abort(400, message='Error performing call.')
else:
return api.abort(404, message='Partnership account not found.')
else:
api.abort(401)
"""
@requires_auth
def get(self, paid):
"""
Retrieves all call lead details for a partnership account.
<p>
The Calls API GET endpoint should be used to retrieve information on all calls from all phone numbers
associated with a partner account.
</p>
<br />
<p>
You will require a partner authentication token and a partner account id to make a
successful request. A response will
be returned, similar to the example below, based
on a successful request:
<br />
<br />
</p>
<pre class="code-background" style="color: white">
{
"calls": [
{
"agent_id": null,
"call_count": 0,
"call_source": "Beef Stew Inc",
"call_type": "inbound",
"caller_id": "",
"created_on": "2018-12-12 21:24:27",
"duration": null,
"endtime": null,
"id": 8,
"my_phone": "+18722217507",
"phonenumber": "+17732909650",
"phonenumber_id": 2,
"progress_status": "new lead",
"recording_url": "",
"starttime": "2018-12-12 21:24:27",
"status": "ringing",
"updated_on": "2018-12-12 21:24:27",
"widget_guid": "",
"originating_number": "+17732909650"
},
{
"agent_id": null,
"call_count": 0,
"call_source": "Beef Stew Inc",
"call_type": "inbound",
"caller_id": "",
"created_on": "2018-12-12 21:24:31",
"duration": null,
"endtime": null,
"id": 9,
"my_phone": "+18722217507",
"phonenumber": "+17732909650",
"phonenumber_id": 2,
"progress_status": "new lead",
"recording_url": "",
"starttime": "2018-12-12 21:24:31",
"status": "ringing",
"updated_on": "2018-12-12 21:24:31",
"widget_guid": "",
"originating_number": "+17732909650"
}
]
}
</pre>
"""
if rest_is_partnership and rest_partnership is not None:
lead_list = []
partnership_account = PartnershipAccount \
.query \
.filter(and_(PartnershipAccount.id == paid, PartnershipAccount.partnership_id == rest_partnership.id)) \
.first()
if partnership_account is not None:
leads = Lead.query\
.filter(Lead.partnership_account_id == paid)\
.all()
if leads is not None:
for lead in leads:
if lead.starttime is not None:
result_starttime = lead.starttime.strftime('%Y-%m-%d %H:%M:%S')
else:
result_starttime = None
if lead.endtime is not None:
result_stoptime = lead.endtime.strftime('%Y-%m-%d %H:%M:%S')
else:
result_stoptime = None
if lead.status is not None:
result_status = lead.status
else:
result_status = ''
if lead.widget_guid is not None:
result_widget_guid = lead.widget_guid
else:
result_widget_guid = ''
lead_add = {
'id': lead.id,
'created_on': lead.created_datetime,
'updated_on': lead.updated_datetime,
'agent_id': lead.agent_id,
'call_source': lead.source,
'progress_status': lead.progress_status,
'caller_id': lead.caller_id,
'phonenumber_id': lead.inbound_id,
'phonenumber': lead.phonenumber,
'my_phone': lead.my_phone,
'duration': lead.duration,
'starttime': result_starttime,
'endtime': result_stoptime,
'call_type': lead.call_type,
'status': result_status,
'recording_url': lead.recording_url,
'widget_guid': result_widget_guid,
'call_count': lead.call_count,
'originating_number': lead.originating_number
}
lead_list.append(lead_add)
return jsonify(
calls=lead_list
)
else:
return api.abort(404, message='No calls found.')
else:
return api.abort(404, message='Partnership account not found.')
else:
api.abort(401)
@ns.route('/<int:paid>/calls/<int:cid>')
@api.doc(responses={200: 'OK',
400: 'Error performing operation.',
401: 'Unauthorized request.'},
params={'paid': 'The partner account Id',
'cid': 'The call Id'})
class Call(Resource):
@requires_auth
def get(self, paid, cid):
"""
Retrieves call lead details of a call.
<p>
The Calls API GET endpoint should be used to retrieve information on a single call for
a specific partner account.
</p>
<br />
<p>
You will require a partner authentication token, a partner account id and a call id to make a
successful request. A response will
be returned, similar to the example below, based
on a successful request:
<br />
<br />
</p>
<pre class="code-background" style="color: white">
{
"agent_id": 3,
"call_count": 0,
"call_source": "twilio PN",
"call_type": "outbound",
"caller_id": "",
"created_on": "2019-04-04 19:51:21",
"duration": null,
"endtime": null,
"id": 431,
"my_phone": "+13367394103",
"phonenumber": "+17732909650",
"phonenumber_id": 5,
"progress_status": "new lead",
"recording_url": "",
"starttime": "2019-04-04 19:51:21",
"status": "missed",
"updated_on": "2019-04-04 19:51:28",
"widget_guid": "",
"originating_number": "+17732909650"
}
</pre>
"""
if rest_is_partnership and rest_partnership is not None:
partnership_account = PartnershipAccount \
.query \
.filter(and_(PartnershipAccount.id == paid, PartnershipAccount.partnership_id == rest_partnership.id)) \
.first()
if partnership_account is not None:
lead = Lead.query\
.filter(and_(Lead.id == cid, Lead.partnership_account_id == paid))\
.first()
if lead is not None:
if lead.starttime is not None:
result_starttime = lead.starttime.strftime('%Y-%m-%d %H:%M:%S')
else:
result_starttime = None
if lead.endtime is not None:
result_stoptime = lead.endtime.strftime('%Y-%m-%d %H:%M:%S')
else:
result_stoptime = None
if lead.status is not None:
result_status = lead.status
else:
result_status = ''
if lead.widget_guid is not None:
result_widget_guid = lead.widget_guid
else:
result_widget_guid = ''
return jsonify(
id=lead.id,
created_on=lead.created_datetime,
updated_on=lead.updated_datetime,
agent_id=lead.agent_id,
call_source=lead.source,
progress_status=lead.progress_status,
caller_id=lead.caller_id,
phonenumber_id=lead.inbound_id,
phonenumber=lead.phonenumber,
my_phone=lead.my_phone,
duration=lead.duration,
starttime=result_starttime,
endtime=result_stoptime,
status=result_status,
call_type=lead.call_type,
recording_url=lead.recording_url,
widget_guid=result_widget_guid,
call_count=lead.call_count,
originating_number=lead.originating_number
)
else:
return api.abort(404, message='Call not found.')
else:
return api.abort(404, message='Partnership account not found.')
else:
api.abort(401)