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_forms/buyercall/buyercall/blueprints/api2/doc/endpoints/agents.py
from datetime import datetime
import logging

from flask import request, jsonify
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.api2.restplus import api
from buyercall.blueprints.billing.models.subscription import Subscription
from buyercall.blueprints.agents.models import Agent, AgentSchedule
from buyercall.blueprints.partnership.models import Partnership, PartnershipAccount
from buyercall.extensions import db


log = logging.getLogger(__name__)
ns = api.namespace('Agents', description='Operations related to agents.', path='/accounts')


def getDayNumber(scheduled_day):
    switcher = {
        'Sunday': 0,
        'Monday': 1,
        'Tuesday': 2,
        'Wednesday': 3,
        'Thursday': 4,
        'Friday': 5,
        'Saturday': 6
    }

    return switcher.get(scheduled_day)


def getboolean(param):
    if param.lower() == 'true':
        return True
    else:
        return False


def validate_time(time_text):
    try:
        retrieved = datetime.strptime(time_text, '%H:%M %p').strftime('%H:%M %p')

        return True
    except Exception as e:
        return False


def format_time(time_text):
    try:
        retrieved = datetime.strptime(time_text, '%H:%M %p').strftime('%H:%M %p')

        return retrieved
    except Exception as e:
        log.error('Error formatting time. Error: {}'.format(e))
        return ''


def validate_time_compare(time_text_start, time_text_stop):
    try:
        start_hour = int(datetime.strptime(time_text_start, '%H:%M %p').strftime('%H'))
        start_min = int(datetime.strptime(time_text_start, '%H:%M %p').strftime('%M'))
        stop_hour = int(datetime.strptime(time_text_stop, '%H:%M %p').strftime('%H'))
        stop_min = int(datetime.strptime(time_text_stop, '%H:%M %p').strftime('%M'))

        if start_hour < stop_hour:
            return True
        elif start_hour == stop_hour:
            if start_min < stop_min:
                return True
            else:
                return False
        else:
            return False
    except Exception as e:
        return False


@ns.route('/<int:paid>/agents')
@api.doc(responses={200: 'OK',
                    400: 'Error performing operation.',
                    401: 'Unauthorized request.'},
         params={'paid': 'The partner account Id'})
class ApiAgentCollection(Resource):
    @requires_auth
    def get(self, paid):
        """
        Retrieves agents of a partnership account.

        <p>The Agents GET endpoint should be used to return information an a specific partner account agent.
        </p>
        <br />
        <p>
        You 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">
        {
          "agents": [
            {
              "all_hours": false,
              "available_now": false,
              "created_on": "2019-03-14 14:40:51",
              "deactivated_on": "",
              "department": "Sales",
              "description": "",
              "email": "harry@conway.co",
              "firstname": "Harry",
              "id": 9,
              "is_deactivated": false,
              "lastname": "Conway",
              "mobile_number": "",
              "phone_number": "7732909650",
              "timezone": "US/Pacific",
              "title": "Owner",
              "updated_on": "2019-03-14 14:40:51"
            },
            {
              "all_hours": true,
              "available_now": true,
              "created_on": "2019-01-16 21:53:08",
              "deactivated_on": "",
              "department": "none",
              "description": "",
              "email": "bullgull@buyercall.com",
              "firstname": "Sue",
              "id": 2,
              "is_deactivated": false,
              "lastname": "Matthews",
              "mobile_number": "",
              "phone_number": "7732909650",
              "timezone": "",
              "title": "",
              "updated_on": "2019-03-18 21:22:49"
            }
          ]
        }
     </pre>

        """
        if rest_is_partnership and rest_partnership is not None:
            agent_list = list()
            partnership_account = PartnershipAccount\
                .query\
                .filter(and_(PartnershipAccount.id == paid, PartnershipAccount.partnership_id == rest_partnership.id))\
                .first()

            if partnership_account is not None:
                agents = db.session.query(Agent) \
                    .filter(and_(Agent.partnership_account_id == paid, Agent.is_group == False)) \
                    .distinct() \
                    .all()

                if agents is not None:
                    for agent in agents:
                        add_agent = {
                            'id': agent.id,
                            'created_on': agent.created_datetime,
                            'updated_on': agent.updated_datetime,
                            'title': agent.title,
                            'firstname': agent.firstname,
                            'lastname': agent.lastname,
                            'email': agent.email,
                            'phone_number': agent.phonenumber,
                            'mobile_number': agent.mobile,
                            'department': agent.department,
                            'description': agent.description,
                            'timezone': agent.timezone,
                            'all_hours': agent.all_hours,
                            'available_now': agent.available_now,
                            'is_deactivated': agent.is_deactivated,
                            'deactivated_on': agent.deactivated_on_datetime
                        }
                        agent_list.append(add_agent)

                return jsonify(
                    agents=agent_list
                )
            else:
                return api.abort(401)
        else:
            return api.abort(401)

    """
    # DISABLE ENDPOINT
    @api.response(200, 'Agent successfully added.')
    @api.expect(serializers.agent_add, validate=True)
    @requires_auth
    def post(self, paid):
    """
    """
        Adds a partnership account agent.

        <p>
        The Agents POST endpoint should be used to create new partner account agents. This means you will need a
        partner account id before being able  to create an agent. It's recommended that this endpoint be one of
        the first endpoints utilized after the Accounts POST request. Many of the other BuyerCall Partner API
        endpoints will depend on an agent existing for a partner account.
        </p>
        <br />
        <p>
        Please note when "ALL HOURS" is true, agents will be set to active 24/7. Otherwise, agents will be added by
        default as active between 8AM and 5PM during week days. The schedule for the agent will be automatically be
        created with this POST request. You can utilize the Agent Schedule PUT request endpoint to alter the schedule
        for an agent.
        </p>
        <br />
        <p>
        You 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">
        {
          "agent_id": 12,
          "partnership_account_id": 6
        }
        </pre>
    """
    """
        if rest_is_partnership and rest_partnership is not None:
            received = request.json

            partnership = Partnership.query.filter(Partnership.id == rest_partnership.id).first()
            partnership_account = PartnershipAccount\
                .query\
                .filter(and_(PartnershipAccount.id == paid, PartnershipAccount.partnership_id == rest_partnership.id))\
                .first()

            if received is not None and partnership_account is not None:
                total_agents = Agent.query.filter(partnership_account.id == Agent.partnership_account_id).count()

                # TODO: Review me - Should it check the partnership or partnership account?
                subscription = (db.session.query(Subscription))\
                    .filter(Subscription.id == partnership.subscription_id)\
                    .first()

                if total_agents is not None and subscription is not None:
                    if total_agents >= subscription.agent_limit:
                        api.abort(code=400, message="Error creating agent. Agent limit exceeded.")
                    else:
                        result_all_hours = True
                        result_firstname = ''
                        result_lastname = ''
                        result_title = ''
                        result_email = ''
                        result_mobile = ''
                        result_department = ''
                        result_description = ''
                        result_timezone = 'US/Central'

                        if 'all_hours' in received:
                            result_all_hours = received['all_hours']

                        if 'firstname' in received:
                            result_firstname = received['firstname']

                        if 'lastname' in received:
                            result_lastname = received['lastname']

                        if 'title' in received:
                            result_title = received['title']

                        if 'email' in received:
                            result_email = received['email']

                        if 'department' in received:
                            result_department = received['department']

                        if 'description' in received:
                            result_description = received['description']

                        if 'timezone' in received:
                            result_timezone = received['timezone']

                        if 'mobile_number' in received:
                            result_mobile = received['mobile_number']

                        params = {
                            'user_id': None,
                            'firstname': result_firstname,
                            'lastname': result_lastname,
                            'title': result_title,
                            'email': result_email,
                            'phonenumber': received['phone_number'],
                            'mobile': result_mobile,
                            'extension': None,
                            'department': result_department,
                            'description': result_description,
                            'partnership_account_id': partnership_account.id,
                            'all_hours': result_all_hours,
                            'timezone': result_timezone
                        }

                        agent_added = Agent.create(params)

                        if agent_added > 0:
                            day1param = {
                                'day': 0,
                                'available_from': '08:00 AM',
                                'available_to': '17:00 PM',
                                'is_active': False,
                                'partnership_account_id': partnership_account.id,
                                'agent_id': int(agent_added)
                            }

                            day2param = {
                                'day': 1,
                                'available_from': '08:00 AM',
                                'available_to': '17:00 PM',
                                'is_active': True,
                                'partnership_account_id': partnership_account.id,
                                'agent_id': int(agent_added)
                            }

                            day3param = {
                                'day': 2,
                                'available_from': '08:00 AM',
                                'available_to': '17:00 PM',
                                'is_active': True,
                                'partnership_account_id': partnership_account.id,
                                'agent_id': int(agent_added)
                            }

                            day4param = {
                                'day': 3,
                                'available_from': '08:00 AM',
                                'available_to': '17:00 PM',
                                'is_active': True,
                                'partnership_account_id': partnership_account.id,
                                'agent_id': int(agent_added)
                            }

                            day5param = {
                                'day': 4,
                                'available_from': '08:00 AM',
                                'available_to': '17:00 PM',
                                'is_active': True,
                                'partnership_account_id': partnership_account.id,
                                'agent_id': int(agent_added)
                            }

                            day6param = {
                                'day': 5,
                                'available_from': '08:00 AM',
                                'available_to': '17:00 PM',
                                'is_active': True,
                                'partnership_account_id': partnership_account.id,
                                'agent_id': int(agent_added)
                            }

                            day7param = {
                                'day': 6,
                                'available_from': '08:00 AM',
                                'available_to': '17:00 PM',
                                'is_active': False,
                                'partnership_account_id': partnership_account.id,
                                'agent_id': int(agent_added)
                            }

                            day_result = AgentSchedule.create(day1param,
                                                              day2param,
                                                              day3param,
                                                              day4param,
                                                              day5param,
                                                              day6param,
                                                              day7param)
                            if day_result:
                                return jsonify(
                                    partnership_account_id=partnership_account.id,
                                    agent_id=agent_added
                                )
                            else:
                                api.abort(code=400, message="Error creating agent schedule.")
                        else:
                            api.abort(code=400, message="Error creating agent.")
                else:
                    api.abort(code=400, message="Error creating agent. No active subscription.")
            else:
                api.abort(code=404, message="Error creating agent. Partnership account not found.")
        else:
            api.abort(code=401)
    """

    
"""
# DISABLE ENDPOINT
@ns.route('/<int:paid>/agents/<int:aid>')
@api.doc(responses={200: 'OK',
                    400: 'Error performing operation.',
                    401: 'Unauthorized request.',
                    404: 'Agent not found.'},
         params={'aid': 'The agent Id',
                 'paid': 'The partner account Id'})
"""
class ApiAgent(Resource):
    @api.response(204, 'Agent successfully updated.')
    @api.expect(serializers.agent_update, validate=True)
    @requires_auth
    def put(self, paid, aid):
        """
        Update an agent.

        <p>
         The Accounts PUT endpoint should be used to update an existing partner account agent. For example,
         you should use this endpoint to update the agent's phone number when provisioning
         a mobile phone number for them using the Mobile phone number POST request endpoint.
        </p>
        <br />
        <p>
        You will require a partner authentication token, a partner account id as well as a partner account
        agent id to make a successful request
        </p>
        """
        if rest_is_partnership and rest_partnership is not None:
            received = request.json

            partnership_account = PartnershipAccount\
                .query\
                .filter(and_(PartnershipAccount.id == paid,
                             PartnershipAccount.partnership_id == rest_partnership.id))\
                .first()

            if received is not None and partnership_account is not None:
                result_all_hours = None
                result_firstname = None
                result_lastname = None
                result_title = None
                result_email = None
                result_phonenumber = None
                result_mobilenumber = None
                result_department = None
                result_description = None
                result_timezone = None

                if 'title' in received:
                    result_title = received['title']

                if 'firstname' in received:
                    result_firstname = received['firstname']

                if 'lastname' in received:
                    result_lastname = received['lastname']

                if 'email' in received:
                    result_email = received['email']

                if 'phone_number' in received:
                    result_phonenumber = received['phone_number']

                if 'mobile_number' in received:
                    result_mobilenumber = received['mobile_number']

                if 'department' in received:
                    result_department = received['department']

                if 'description' in received:
                    result_description = received['description']

                if 'timezone' in received:
                    result_timezone = received['timezone']

                if 'all_hours' in received:
                    result_all_hours = received['all_hours']

                final_result = Agent.api_update_v2(
                    partnership_account.id,
                    aid,
                    result_title,
                    result_firstname,
                    result_lastname,
                    result_phonenumber,
                    result_mobilenumber,
                    result_email,
                    result_department,
                    result_description,
                    result_timezone,
                    result_all_hours)
                if final_result:
                    return final_result, 204
                else:
                    api.abort(code=400, message="Error updating agent.")
            else:
                return api.abort(code=404)
        else:
            return api.abort(code=401)

    @api.response(204, 'Agent successfully deactivated.')
    @requires_auth
    def delete(self, paid, aid):
        """
        Deactivate a partnership account agent.

        <p>
        The Agents DELETE endpoint should be used to deactivate a partner account agent. Please note that the agent
        does not get hard deleted, but rather deactivated, with their schedule being set to unavailable. A deactivated
        agent can't perform any task and only exist for legacy purposes. Though deactivated, the agent will still be
        returned in the Agents GET request with a is_deactivated set to True.
        </p>
        </br >
        <p>
        You will require a partner authentication token, a partner account id as well as a partner account agent
        id to make a successful request.
        </p>
        """
        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:
                agent = Agent.query\
                    .filter(and_(Agent.id == aid, Agent.partnership_account_id == partnership_account.id))\
                    .first()

                if agent is not None:
                    return agent.deactivate(aid, partnership_account.id), 204
                else:
                    return api.abort(code=404)
            else:
                return api.abort(code=401)
        else:
            return api.abort(code=401)

"""
# DISABLE ENDPOINT
@ns.route('/<int:paid>/agents/<int:aid>/schedule')
@api.doc(responses={200: 'OK',
                    401: 'Unauthorized request.',
                    404: 'Agent not found.'},
         params={'aid': 'The agent Id',
                 'paid': 'The partner account Id'})
"""
class ApiAgentSchedule(Resource):

    @requires_auth
    def get(self, paid, aid):
        """
        Retrieves agent schedule of an agent.

        <p>
        The Agents Schedule GET endpoint should be used to return the schedule for a partner account agent. The schedule
        dictates an agent's availability for a specific day of the week.
        </p>
        <br />
        <p>
        You 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">
        {
          "schedule": [
            {
              "available_from": "05:00 AM",
              "available_to": "15:00 PM",
              "day": "Sunday",
              "id": 2,
              "is_active": true
            },
            {
              "available_from": "08:00 AM",
              "available_to": "17:00 PM",
              "day": "Monday",
              "id": 3,
              "is_active": false
            },
            {
              "available_from": "08:00 AM",
              "available_to": "17:00 PM",
              "day": "Tuesday",
              "id": 4,
              "is_active": true
            },
            {
              "available_from": "08:00 AM",
              "available_to": "17:00 PM",
              "day": "Wednesday",
              "id": 5,
              "is_active": true
            },
            {
              "available_from": "08:00 AM",
              "available_to": "17:00 PM",
              "day": "Thursday",
              "id": 6,
              "is_active": true
            },
            {
              "available_from": "08:00 AM",
              "available_to": "17:00 PM",
              "day": "Friday",
              "id": 7,
              "is_active": true
            },
            {
              "available_from": "08:00 AM",
              "available_to": "17:00 PM",
              "day": "Saturday",
              "id": 8,
              "is_active": false
            }
          ]
        }
        </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:
                agent = (db.session.query(Agent))\
                    .filter(Agent.partnership_account_id == partnership_account.id)\
                    .filter(Agent.id == aid)\
                    .first()
                schedules = list()

                if agent is not None:
                    for sched in agent.schedules:
                        day_name = ''

                        if sched.day == 0:
                            day_name = 'Sunday'
                        elif sched.day == 1:
                            day_name = 'Monday'
                        elif sched.day == 2:
                            day_name = 'Tuesday'
                        elif sched.day == 3:
                            day_name = 'Wednesday'
                        elif sched.day == 4:
                            day_name = 'Thursday'
                        elif sched.day == 5:
                            day_name = 'Friday'
                        elif sched.day == 6:
                            day_name = 'Saturday'

                        day = {
                            'id': sched.id,
                            'day': day_name,
                            'available_from': sched.available_from,
                            'available_to': sched.available_to,
                            'is_active': sched.is_active
                        }
                        schedules.append(day)

                    return jsonify(
                        schedule=schedules
                    )
                else:
                    api.abort(code=404, message="Agent not found.")
            else:
                return api.abort(code=404, message="Partnership account not found.")
        else:
            return api.abort(code=401)

    @api.response(204, 'Agent schedule successfully updated.')
    @api.expect(serializers.agent_schedule_update, validate=True)
    @requires_auth
    def put(self, paid, aid):
        """
        Update schedule of an agent.

        <p>
        The Agents Schedule PUT endpoint should be used to update the schedule for a partner account agent. The schedule
        dictates an agent's availability for a specific day of the week. You will be able to update multiple agent
        schedule entries simultaneously using this endpoint.
        </p>
        <br />
        <p>
        Please note that an agent's schedule gets created when an agent gets created with the Agents POST
        request endpoint. There is no Agents Schedule POST request endpoint.
        </p>
        <br />
        <p>
        You will require a partner authentication token, a partner account id as well as a partner account
        agent id to make a successful request.
        </p>
        """
        if rest_is_partnership and rest_partnership:
            received = request.json

            if received:
                partnership_account = PartnershipAccount\
                    .query\
                    .filter(and_(PartnershipAccount.id == paid,
                                 PartnershipAccount.partnership_id == rest_partnership.id))\
                    .first()

                if partnership_account:
                    agent = (db.session.query(Agent))\
                        .filter(Agent.partnership_account_id == partnership_account.id)\
                        .filter(Agent.id == aid)\
                        .first()

                    if agent:
                        result_schedule = received['schedule']
                        schedule_count = len(result_schedule)

                        if schedule_count and schedule_count > 0:
                            result_schedule_day_list = list()

                            for result_schedule_day in result_schedule:
                                result_is_active = None
                                result_from = None
                                result_to = None
                                result_day_name = result_schedule_day['day']
                                result_day = getDayNumber(result_day_name)

                                agent_schedule = AgentSchedule.query \
                                    .filter(and_(AgentSchedule.day == result_day, AgentSchedule.agent_id == agent.id)) \
                                    .first()

                                if agent_schedule:
                                    if 'is_active' in result_schedule_day:
                                        result_is_active = result_schedule_day['is_active']

                                    if 'available_from' in result_schedule_day and \
                                            'available_to' in result_schedule_day:
                                        result_from = result_schedule_day['available_from']
                                        result_to = result_schedule_day['available_to']

                                        if not validate_time(result_from):
                                            return api.abort(code=400,
                                                             message="Error updating agent schedule. "
                                                                     "Incorrect FROM time format.")

                                        if not validate_time(result_to):
                                            return api.abort(code=result_to,
                                                             message="Error updating agent schedule. "
                                                                     "Incorrect TO time format.")

                                        date_passed = validate_time_compare(result_from, result_to)

                                        if not date_passed:
                                            return api.abort(code=400,
                                                             message="Error updating agent schedule. "
                                                                     "Start time falls after stop time.")

                                        result_from = format_time(result_from)
                                        result_to = format_time(result_to)
                                        if result_from == '' or result_to == '':
                                            return api.abort(code=400,
                                                             message="Error updating agent schedule. "
                                                                     "Incorrect time format.")

                                    if 'available_from' in result_schedule_day \
                                            and 'available_to' not in result_schedule_day:
                                        result_from = result_schedule_day['available_from']
                                        if not validate_time(result_from):
                                            return api.abort(code=400,
                                                             message="Error updating agent schedule. "
                                                                     "Incorrect FROM time format.")
                                        elif not validate_time_compare(result_from, agent_schedule.available_to):
                                            return api.abort(code=400,
                                                             message="Error updating agent schedule. "
                                                                     "Start time falls after stop time.")
                                        result_from = format_time(result_from)
                                        if result_from == '':
                                            return api.abort(code=400,
                                                             message="Error updating agent schedule. "
                                                                     "Incorrect time format.")

                                    if 'available_to' in result_schedule_day \
                                            and 'available_from' not in result_schedule_day:
                                        result_to = result_schedule_day['available_to']
                                        if not validate_time(result_to):
                                            return api.abort(code=400,
                                                             message="Error updating agent schedule. "
                                                                     "Incorrect TO time format.")
                                        elif not validate_time_compare(agent_schedule.available_from, result_to):
                                            return api.abort(code=400,
                                                             message="Error updating agent schedule. "
                                                                     "Stop time falls before start time.")

                                        result_to = format_time(result_to)
                                        if result_to == '':
                                            return api.abort(code=400,
                                                             message="Error updating agent schedule. "
                                                                     "Incorrect time format.")

                                    final_result = AgentSchedule.api_update(agent_schedule.id, result_from, result_to,
                                                                            result_is_active, partnership_account.id)
                                else:
                                    result_schedule_day_list.append(result_day_name)

                            if len(result_schedule_day_list) > 0:
                                return api.abort(
                                    code=404,
                                    message="Agent schedule day not found. Days: {}".format(
                                        jsonify(result_schedule_day_list))
                                )
                            return True, 204
                    return api.abort(code=404, message="Agent not found.")
                return api.abort(code=404, message="Partnership account not found.")
            return api.abort(code=401)
        return api.abort(code=401)