Skip to content

Commit

Permalink
Add incremental calls api
Browse files Browse the repository at this point in the history
  • Loading branch information
NiallRees committed Oct 16, 2020
1 parent 6d3dc8d commit ff66b08
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 16 deletions.
43 changes: 43 additions & 0 deletions specification/talk/call.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"agent_id": 1,
"call_charge": "0.025",
"call_group_id": 1,
"call_recording_consent": "always",
"call_recording_consent_action": "caller_opted_in",
"call_recording_consent_keypress": "3",
"callback": false,
"callback_source": null,
"completion_status": "completed",
"consultation_time": 0,
"created_at": "2020-10-15T13:19:09Z",
"customer_id": 1,
"customer_requested_voicemail": false,
"default_group": true,
"direction": "inbound",
"duration": 782,
"exceeded_queue_wait_time": false,
"hold_time": 0,
"id": 123,
"ivr_action": null,
"ivr_destination_group_name": null,
"ivr_hops": null,
"ivr_routed_to": null,
"ivr_time_spent": null,
"minutes_billed": 14,
"not_recording_time": 5,
"outside_business_hours": false,
"overflowed": false,
"overflowed_to": null,
"phone_number": "+1234567890",
"phone_number_id": 123,
"quality_issues": ["high_latency"],
"recording_control_interactions": 5,
"recording_time": 15,
"talk_time": 751,
"ticket_id": 1059354,
"time_to_answer": 31,
"updated_at": "2020-10-15T14:12:22Z",
"voicemail": false,
"wait_time": 16,
"wrap_up_time": 66
}
11 changes: 10 additions & 1 deletion zenpy/lib/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from zenpy.lib.api_objects.help_centre_objects import (
Section, Article, Comment, ArticleAttachment, Label, Category, Translation,
Topic, Post, Subscription)
from zenpy.lib.api_objects.talk_objects import (CurrentQueueActivity,
from zenpy.lib.api_objects.talk_objects import (Call, CurrentQueueActivity,
PhoneNumbers, ShowAvailability,
AgentsOverview,
AccountOverview,
Expand Down Expand Up @@ -2408,6 +2408,9 @@ def __init__(self, config):
endpoint=EndpointFactory('talk'),
object_type='talk')

self.calls = CallApi(config,
self.endpoint.calls,
object_type='call')
self.current_queue_activity = StatsApi(
config,
self.endpoint.current_queue_activity,
Expand All @@ -2432,6 +2435,12 @@ def __call__(self, *args, **kwargs):
raise NotImplementedError("Cannot directly call the TalkApi!")


class CallApi(TalkApiBase, IncrementalApi):
def __init__(self, config, endpoint, object_type):
super(CallApi, self).__init__(config,
object_type=object_type,
endpoint=endpoint)

class StatsApi(TalkApiBase):
def __init__(self, config, endpoint, object_type):
super(StatsApi, self).__init__(config,
Expand Down
24 changes: 9 additions & 15 deletions zenpy/lib/api_objects/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

######################################################################
# Do not modify, these classes are autogenerated by gen_classes.py #
######################################################################
Expand All @@ -11,6 +12,7 @@ class BaseObject(object):
"""
Base for all Zenpy objects. Keeps track of which attributes have been modified.
"""

def __new__(cls, *args, **kwargs):
instance = super(BaseObject, cls).__new__(cls)
instance.__dict__['_dirty_attributes'] = set()
Expand Down Expand Up @@ -42,17 +44,14 @@ def _set_dirty(self, obj=None):
""" Recursively set self and all child objects _dirty flag. """
obj = obj or self
for key, value in vars(obj).items():
if key not in ('api', '_dirty_attributes', '_always_dirty',
'_dirty_callback', '_dirty'):
if key not in ('api', '_dirty_attributes', '_always_dirty', '_dirty_callback', '_dirty'):
setattr(obj, key, value)
if isinstance(value, BaseObject):
self._set_dirty(value)

def to_json(self, indent=2):
""" Return self formatted as JSON. """
return json.dumps(self,
default=json_encode_for_printing,
indent=indent)
return json.dumps(self, default=json_encode_for_printing, indent=indent)

def to_dict(self, serialize=False):
"""
Expand All @@ -63,9 +62,7 @@ def to_dict(self, serialize=False):
encode_method = json_encode_for_zendesk
else:
encode_method = json_encode_for_printing
return json.loads(
json.dumps(self._to_dict(serialize=serialize),
default=encode_method))
return json.loads(json.dumps(self._to_dict(serialize=serialize), default=encode_method))

def _to_dict(self, serialize=False):
"""
Expand All @@ -90,8 +87,7 @@ def _to_dict(self, serialize=False):
continue

# These are for internal tracking, so just delete.
elif key in ('api', '_dirty_attributes', '_always_dirty',
'_dirty_callback', '_dirty'):
elif key in ('api', '_dirty_attributes', '_always_dirty', '_dirty_callback', '_dirty'):
del copy_dict[key]

# If the attribute has not been modified, do not send it.
Expand All @@ -106,17 +102,15 @@ def _to_dict(self, serialize=False):

def __repr__(self):
class_name = type(self).__name__
if class_name in ('UserField', ):
if class_name in ('UserField',):
return "{}()".format(class_name)

def formatted(item):
return item if (isinstance(item, int)
or item is None) else "'{}'".format(item)
return item if (isinstance(item, int) or item is None) else "'{}'".format(item)

for identifier in ('id', 'token', 'key', 'name', 'account_key'):
if hasattr(self, identifier):
return "{}({}={})".format(class_name, identifier,
formatted(getattr(self, identifier)))
return "{}({}={})".format(class_name, identifier, formatted(getattr(self, identifier)))
return "{}()".format(class_name)


Expand Down
187 changes: 187 additions & 0 deletions zenpy/lib/api_objects/talk_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,193 @@ def __init__(self,
continue


class Call(BaseObject):
"""
######################################################################
# Do not modify, this class is autogenerated by gen_classes.py #
######################################################################
"""
def __init__(self,
api=None,
agent_id=None,
call_charge=None,
call_group_id=None,
call_recording_consent=None,
call_recording_consent_action=None,
call_recording_consent_keypress=None,
callback=None,
callback_source=None,
completion_status=None,
consultation_time=None,
created_at=None,
customer_id=None,
customer_requested_voicemail=None,
default_group=None,
direction=None,
duration=None,
exceeded_queue_wait_time=None,
hold_time=None,
id=None,
ivr_action=None,
ivr_destination_group_name=None,
ivr_hops=None,
ivr_routed_to=None,
ivr_time_spent=None,
minutes_billed=None,
not_recording_time=None,
outside_business_hours=None,
overflowed=None,
overflowed_to=None,
phone_number=None,
phone_number_id=None,
quality_issues=None,
recording_control_interactions=None,
recording_time=None,
talk_time=None,
ticket_id=None,
time_to_answer=None,
updated_at=None,
voicemail=None,
wait_time=None,
wrap_up_time=None,
**kwargs):

self.api = api
self.agent_id = agent_id
self.call_charge = call_charge
self.call_group_id = call_group_id
self.call_recording_consent = call_recording_consent
self.call_recording_consent_action = call_recording_consent_action
self.call_recording_consent_keypress = call_recording_consent_keypress
self.callback = callback
self.callback_source = callback_source
self.completion_status = completion_status
self.consultation_time = consultation_time
self.created_at = created_at
self.customer_id = customer_id
self.customer_requested_voicemail = customer_requested_voicemail
self.default_group = default_group
self.direction = direction
self.duration = duration
self.exceeded_queue_wait_time = exceeded_queue_wait_time
self.hold_time = hold_time
self.id = id
self.ivr_action = ivr_action
self.ivr_destination_group_name = ivr_destination_group_name
self.ivr_hops = ivr_hops
self.ivr_routed_to = ivr_routed_to
self.ivr_time_spent = ivr_time_spent
self.minutes_billed = minutes_billed
self.not_recording_time = not_recording_time
self.outside_business_hours = outside_business_hours
self.overflowed = overflowed
self.overflowed_to = overflowed_to
self.phone_number = phone_number
self.phone_number_id = phone_number_id
self.quality_issues = quality_issues
self.recording_control_interactions = recording_control_interactions
self.recording_time = recording_time
self.talk_time = talk_time
self.ticket_id = ticket_id
self.time_to_answer = time_to_answer
self.updated_at = updated_at
self.voicemail = voicemail
self.wait_time = wait_time
self.wrap_up_time = wrap_up_time

for key, value in kwargs.items():
setattr(self, key, value)

for key in self.to_dict():
if getattr(self, key) is None:
try:
self._dirty_attributes.remove(key)
except KeyError:
continue

@property
def agent(self):

if self.api and self.agent_id:
return self.api._get_agent(self.agent_id)

@agent.setter
def agent(self, agent):
if agent:
self.agent_id = agent.id
self._agent = agent

@property
def call_group(self):

if self.api and self.call_group_id:
return self.api._get_call_group(self.call_group_id)

@call_group.setter
def call_group(self, call_group):
if call_group:
self.call_group_id = call_group.id
self._call_group = call_group

@property
def created(self):

if self.created_at:
return dateutil.parser.parse(self.created_at)

@created.setter
def created(self, created):
if created:
self.created_at = created

@property
def customer(self):

if self.api and self.customer_id:
return self.api._get_customer(self.customer_id)

@customer.setter
def customer(self, customer):
if customer:
self.customer_id = customer.id
self._customer = customer

@property
def phone_number(self):

if self.api and self.phone_number_id:
return self.api._get_phone_number(self.phone_number_id)

@phone_number.setter
def phone_number(self, phone_number):
if phone_number:
self.phone_number_id = phone_number.id
self._phone_number = phone_number

@property
def ticket(self):

if self.api and self.ticket_id:
return self.api._get_ticket(self.ticket_id)

@ticket.setter
def ticket(self, ticket):
if ticket:
self.ticket_id = ticket.id
self._ticket = ticket

@property
def updated(self):

if self.updated_at:
return dateutil.parser.parse(self.updated_at)

@updated.setter
def updated(self, updated):
if updated:
self.updated_at = updated


class CurrentQueueActivity(BaseObject):
"""
######################################################################
Expand Down
3 changes: 3 additions & 0 deletions zenpy/lib/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,9 @@ class Dummy(object):
pass

talk = Dummy()
talk.calls = Dummy()
talk.calls.incremental = IncrementalEndpoint(
'channels/voice/stats/incremental/calls.json')
talk.current_queue_activity = PrimaryEndpoint(
'channels/voice/stats/current_queue_activity')
talk.agents_activity = PrimaryEndpoint(
Expand Down
1 change: 1 addition & 0 deletions zenpy/lib/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ class TalkObjectMapping(ZendeskObjectMapping):
to prevent namespace collisions between APIs.
"""
class_mapping = {
'call': Call,
'account_overview': AccountOverview,
'agents_activity': AgentsActivity,
'agents_overview': AgentsOverview,
Expand Down

0 comments on commit ff66b08

Please sign in to comment.