call_center.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. from abc import ABCMeta, abstractmethod
  2. from collections import deque
  3. from enum import Enum
  4. class Rank(Enum):
  5. OPERATOR = 0
  6. SUPERVISOR = 1
  7. DIRECTOR = 2
  8. class Employee(metaclass=ABCMeta):
  9. def __init__(self, employee_id, name, rank, call_center):
  10. self.employee_id = employee_id
  11. self.name = name
  12. self.rank = rank
  13. self.call = None
  14. self.call_center = call_center
  15. def take_call(self, call):
  16. """Assume the employee will always successfully take the call."""
  17. self.call = call
  18. self.call.employee = self
  19. self.call.state = CallState.IN_PROGRESS
  20. def complete_call(self):
  21. self.call.state = CallState.COMPLETE
  22. self.call_center.notify_call_completed(self.call)
  23. @abstractmethod
  24. def escalate_call(self):
  25. pass
  26. def _escalate_call(self):
  27. self.call.state = CallState.READY
  28. call = self.call
  29. self.call = None
  30. self.call_center.notify_call_escalated(call)
  31. class Operator(Employee):
  32. def __init__(self, employee_id, name):
  33. super(Operator, self).__init__(employee_id, name, Rank.OPERATOR)
  34. def escalate_call(self):
  35. self.call.level = Rank.SUPERVISOR
  36. self._escalate_call()
  37. class Supervisor(Employee):
  38. def __init__(self, employee_id, name):
  39. super(Operator, self).__init__(employee_id, name, Rank.SUPERVISOR)
  40. def escalate_call(self):
  41. self.call.level = Rank.DIRECTOR
  42. self._escalate_call()
  43. class Director(Employee):
  44. def __init__(self, employee_id, name):
  45. super(Operator, self).__init__(employee_id, name, Rank.DIRECTOR)
  46. def escalate_call(self):
  47. raise NotImplementedError('Directors must be able to handle any call')
  48. class CallState(Enum):
  49. READY = 0
  50. IN_PROGRESS = 1
  51. COMPLETE = 2
  52. class Call(object):
  53. def __init__(self, rank):
  54. self.state = CallState.READY
  55. self.rank = rank
  56. self.employee = None
  57. class CallCenter(object):
  58. def __init__(self, operators, supervisors, directors):
  59. self.operators = operators
  60. self.supervisors = supervisors
  61. self.directors = directors
  62. self.queued_calls = deque()
  63. def dispatch_call(self, call):
  64. if call.rank not in (Rank.OPERATOR, Rank.SUPERVISOR, Rank.DIRECTOR):
  65. raise ValueError('Invalid call rank: {}'.format(call.rank))
  66. employee = None
  67. if call.rank == Rank.OPERATOR:
  68. employee = self._dispatch_call(call, self.operators)
  69. if call.rank == Rank.SUPERVISOR or employee is None:
  70. employee = self._dispatch_call(call, self.supervisors)
  71. if call.rank == Rank.DIRECTOR or employee is None:
  72. employee = self._dispatch_call(call, self.directors)
  73. if employee is None:
  74. self.queued_calls.append(call)
  75. def _dispatch_call(self, call, employees):
  76. for employee in employees:
  77. if employee.call is None:
  78. employee.take_call(call)
  79. return employee
  80. return None
  81. def notify_call_escalated(self, call):
  82. pass
  83. def notify_call_completed(self, call):
  84. pass
  85. def dispatch_queued_call_to_newly_freed_employee(self, call, employee):
  86. pass