"""Handler module for incoming data through the API"""
import datetime
from . import const
from .exceptions import InvalidDataException
from .helpers import map_dict_fields, add_list_value, last_period
from .jobs import save_callevent
from .models import Bill
from .forms import CallEventForm
[docs]class BaseDataHandler:
"""Base data handler"""
def __init__(self, data):
self.data = data or {}
self.errors = {}
[docs] def handle(self):
"""Process the current data.
**MUST BE OVERRIDDEN BY THE USER** - By default, this returns
``NotImplementedError``.
Returns:
dict: Result for the data processed.
"""
raise NotImplementedError
[docs] def validate(self):
"""Run the validation for the current data.
**MUST BE OVERRIDDEN BY THE USER** - By default, this returns
``NotImplementedError``.
"""
raise NotImplementedError
[docs] def add_error(self, field, message):
"""Add message error for a field.
Args:
field (str): Field name.
message (str): Message error.
"""
add_list_value(self.errors, field, message)
[docs]class CallEventHandler(BaseDataHandler):
"""Handler class for CallEvent data."""
def __init__(self, data):
super().__init__(data)
[docs] def handle(self):
"""Process CallEvent current data.
Raises:
InvalidDataException: Raises if data is not valid.
"""
# parse the data
map_dict_fields(self.data, const.API_FIELDS, const.DB_FIELDS)
self.validate()
if self.errors:
raise InvalidDataException(self.errors)
# save data
self.save()
[docs] def validate(self):
"""Validate fields for current data."""
form = CallEventForm(self.data)
if not form.is_valid():
self.errors = form.errors
map_dict_fields(self.errors, const.DB_FIELDS, const.API_FIELDS)
[docs] def save(self):
"""Save current data for CallEvent.
This function calls an async job to save the current data.
"""
# send data to be saved by another job
save_callevent.delay(self.data)
[docs]class BillHandler(BaseDataHandler):
"""Handler class for Bill data."""
def __init__(self, data):
super().__init__(data)
[docs] def handle(self):
"""Process Bill current data.
Raises:
InvalidDataException: Raises if data is not valid.
"""
self.validate()
if self.errors:
raise InvalidDataException(self.errors)
phone_number = self.data.get('phone_number')
month = self.data.get('month')
year = self.data.get('year')
# if a period was not informed, get the current last one
if not month and not year:
year, month = last_period()
bill_data = Bill.data_by_number_period(phone_number, month, year)
return bill_data
[docs] def validate(self):
"""Validate fields for current data."""
# validate phone number
phone_number = self.data.get('phone_number', '')
if not phone_number:
self.add_error('phone_number', const.MESSAGE_FIELD_REQUIRED)
elif not str(phone_number).isdigit():
self.add_error('phone_number', const.MESSAGE_FIELD_INVALID_VALUE)
elif len(str(phone_number)) > 11:
self.add_error('phone_number', const.MESSAGE_FIELD_INVALID_LENGTH)
# validate period
month = self.data.get('month')
year = self.data.get('year')
if (not month and year) or (month and not year):
self.add_error('period', const.MESSAGE_PERIOD_WRONG)
elif month and year:
try:
month = int(month)
year = int(year)
if len(str(month)) > 2 or len(str(year)) != 4:
self.add_error(
'period', const.MESSAGE_FIELD_INVALID_LENGTH
)
else:
period_date = datetime.date(year, month, 1)
last_period_date = datetime.date(*last_period(), day=1)
if period_date > last_period_date:
self.add_error('period', const.MESSAGE_PERIOD_INVALID)
except ValueError:
self.add_error('period', const.MESSAGE_FIELD_INVALID_VALUE)
[docs]def callevent_handler(data):
"""Convenient function to return CallEvent handler instance."""
return CallEventHandler(data)
[docs]def bill_handler(data):
"""Convenient function to return Bill handler instance."""
return BillHandler(data)