228 lines
9.9 KiB
Python
228 lines
9.9 KiB
Python
"""
|
|
"""
|
|
|
|
# --------------------------------------- #
|
|
# imports #
|
|
# --------------------------------------- #
|
|
from pandas import DataFrame, concat
|
|
|
|
from BBUtils.logging_handle import logger
|
|
|
|
# --------------------------------------- #
|
|
# definitions #
|
|
# --------------------------------------- #
|
|
MODULE_LOGGER_HEAD = "request_load_estimator -> "
|
|
|
|
START_NR_OF_EMPLOYEES = 50
|
|
START_NR_OF_APPLICATIONS = 5
|
|
START_NR_OF_SERVICE_REQUESTS = 0
|
|
START_NR_OF_SERVICE_DESK_EMPLOYEES = 3
|
|
START_DOCUMENTATION_LEVEL = 1
|
|
START_KNOWLEDGE_LEVEL = 1
|
|
START_SYSTEMS_COMPLEXITY = 1
|
|
|
|
KNOWLEDGE_REDUCTION_FACTOR = 0.2
|
|
|
|
DOCUMENTATION_LEVEL_MAX = 4
|
|
DOCUMENTATION_LEVEL_MIN = 0.5
|
|
KNOWLEDGE_LEVEL_MAX = 4
|
|
KNOWLEDGE_LEVEL_MIN = 0.5
|
|
|
|
|
|
# --------------------------------------- #
|
|
# global vars #
|
|
# --------------------------------------- #
|
|
|
|
|
|
# --------------------------------------- #
|
|
# functions #
|
|
# --------------------------------------- #
|
|
def limit_value(value: float, min_value: float, max_value: float) -> float:
|
|
if value < min_value:
|
|
return min_value
|
|
elif value > max_value:
|
|
return max_value
|
|
else:
|
|
return value
|
|
|
|
|
|
# --------------------------------------- #
|
|
# classes #
|
|
# --------------------------------------- #
|
|
class RequestLoadEstimator:
|
|
AVERAGE_REQUEST_WORKING_TIME = 0.5
|
|
AVERAGE_DAY_WORKING_TIME = 6
|
|
AVERAGE_PROBLEM_LEVEL_IN_PERCENT = 0.1
|
|
|
|
def __init__(self):
|
|
self._days_cycle = 4
|
|
self.service_desk_employees = 0
|
|
self.documentation_level = 0
|
|
self.service_desk_knowledge_level = 0
|
|
self.systems_complexity = 0
|
|
self.nr_of_applications = 0
|
|
self.nr_of_employees = 0
|
|
self.new_application_problems = 0
|
|
self.nr_of_open_service_requests = 0
|
|
self.processed_service_requests = 0
|
|
self._desired_request_working_time = 0
|
|
self.personal_available_time = 0
|
|
self.actual_week = 0
|
|
self.data_set = DataFrame()
|
|
self.initialize_data()
|
|
self.prev_dict = {"day": 0, "days_cycle": 0, "service_desk_employees": 0, "documentation_level": 0,
|
|
"service_desk_knowledge_level": 0, "systems_complexity": 0, "nr_of_applications": 0,
|
|
"new_application_problems": 0, "nr_of_open_service_requests": 0, "request_working_time": 0,
|
|
"personal_available_time": 0, "processed_service_requests": 0, "nr_of_employees": 0}
|
|
pass
|
|
|
|
def set_weeks_cycle(self, days: int):
|
|
self._days_cycle = days
|
|
|
|
def add_new_applications(self, nr: int):
|
|
if nr > 0:
|
|
logger.info(MODULE_LOGGER_HEAD + "Adding new applications: " + str(nr))
|
|
documentation_level_reduction = (nr / self.nr_of_applications) * 0.2
|
|
self.documentation_level -= documentation_level_reduction
|
|
if self.documentation_level < DOCUMENTATION_LEVEL_MIN:
|
|
self.documentation_level = DOCUMENTATION_LEVEL_MIN
|
|
complexity_increase = (nr / self.nr_of_applications) * 0.2
|
|
self.systems_complexity += complexity_increase
|
|
self.nr_of_applications += nr
|
|
elif nr < 0:
|
|
logger.info(MODULE_LOGGER_HEAD + "Removing applications: " + str(nr))
|
|
complexity_reduction = (nr / self.nr_of_applications) * 0.2
|
|
self.systems_complexity -= complexity_reduction
|
|
self.nr_of_applications += nr
|
|
|
|
def add_new_employees(self, nr: int):
|
|
if nr > 0:
|
|
logger.info(MODULE_LOGGER_HEAD + "Adding new employees: " + str(nr))
|
|
self.systems_complexity += nr / self.nr_of_employees
|
|
self.nr_of_employees += nr
|
|
elif nr < 0:
|
|
logger.info(MODULE_LOGGER_HEAD + "Removing employees: " + str(nr))
|
|
self.systems_complexity -= nr / self.nr_of_employees
|
|
self.nr_of_employees += nr
|
|
|
|
def add_service_desk_employees(self, nr: int):
|
|
if nr > 0:
|
|
logger.info(MODULE_LOGGER_HEAD + "Adding new service desk employees: " + str(nr))
|
|
knowledge_level_reduction = (nr / self.service_desk_employees) * 0.2
|
|
self.service_desk_knowledge_level = limit_value(self.service_desk_knowledge_level - knowledge_level_reduction,
|
|
KNOWLEDGE_LEVEL_MIN,
|
|
KNOWLEDGE_LEVEL_MAX)
|
|
self.service_desk_employees += nr
|
|
elif nr < 0:
|
|
logger.info(MODULE_LOGGER_HEAD + "Removing service desk employees: " + str(nr))
|
|
self.service_desk_employees += nr
|
|
|
|
def process_weeks(self):
|
|
logger.info(MODULE_LOGGER_HEAD + "Processing weeks")
|
|
for day in range(self._days_cycle):
|
|
self._calc_nr_of_service_requests()
|
|
self._calc_request_working_time()
|
|
self._calc_personal_available_time()
|
|
self._calc_documentation_and_knowledge_level()
|
|
self._calc_application_problems()
|
|
self.actual_week += 1
|
|
self._process_data_set()
|
|
pass
|
|
|
|
def initialize_data(self):
|
|
logger.info(MODULE_LOGGER_HEAD + "Initializing data")
|
|
self._days_cycle = 7
|
|
self.service_desk_employees = START_NR_OF_SERVICE_DESK_EMPLOYEES
|
|
self.documentation_level = START_DOCUMENTATION_LEVEL
|
|
self.service_desk_knowledge_level = START_KNOWLEDGE_LEVEL
|
|
self.systems_complexity = START_SYSTEMS_COMPLEXITY
|
|
self.nr_of_applications = START_NR_OF_APPLICATIONS
|
|
self.nr_of_employees = START_NR_OF_EMPLOYEES
|
|
self.new_application_problems = 0
|
|
self.processed_service_requests = 0
|
|
self.nr_of_open_service_requests = START_NR_OF_SERVICE_REQUESTS
|
|
self._desired_request_working_time = 0
|
|
self.personal_available_time = 0
|
|
self.actual_week = 0
|
|
self.data_set = DataFrame()
|
|
|
|
def _calc_application_problems(self):
|
|
self.new_application_problems = ((self.nr_of_employees * self.nr_of_applications *
|
|
self.systems_complexity / self.documentation_level)
|
|
* self.AVERAGE_PROBLEM_LEVEL_IN_PERCENT)
|
|
if self.new_application_problems < 0:
|
|
self.new_application_problems = 0
|
|
pass
|
|
|
|
def _calc_nr_of_service_requests(self):
|
|
self.nr_of_open_service_requests += int(self.new_application_problems)
|
|
|
|
def _calc_request_working_time(self):
|
|
self._desired_request_working_time = (self.nr_of_open_service_requests *
|
|
(self.AVERAGE_REQUEST_WORKING_TIME / self.service_desk_knowledge_level))
|
|
|
|
if self._desired_request_working_time < 0:
|
|
self._desired_request_working_time = 0
|
|
|
|
if self._desired_request_working_time < (self.service_desk_employees * self.AVERAGE_DAY_WORKING_TIME):
|
|
self.processed_service_requests = self.nr_of_open_service_requests
|
|
self.nr_of_open_service_requests = 0
|
|
else:
|
|
self.processed_service_requests = int((self.service_desk_employees * self.AVERAGE_DAY_WORKING_TIME) /
|
|
(
|
|
self.AVERAGE_REQUEST_WORKING_TIME / self.service_desk_knowledge_level))
|
|
|
|
self.nr_of_open_service_requests -= self.processed_service_requests
|
|
|
|
if self.nr_of_open_service_requests < 0:
|
|
self.nr_of_open_service_requests = 0
|
|
pass
|
|
|
|
def _calc_personal_available_time(self):
|
|
self.personal_available_time = (self.service_desk_employees * self.AVERAGE_DAY_WORKING_TIME) - \
|
|
self._desired_request_working_time
|
|
pass
|
|
|
|
def _calc_documentation_and_knowledge_level(self):
|
|
documentation_level_reduction = (self.personal_available_time * KNOWLEDGE_REDUCTION_FACTOR /
|
|
(self.nr_of_employees * self.nr_of_applications))
|
|
self.documentation_level += documentation_level_reduction if documentation_level_reduction >= 0 else documentation_level_reduction / 10
|
|
|
|
know_how_reduction = self.personal_available_time * KNOWLEDGE_REDUCTION_FACTOR / (
|
|
self.nr_of_employees *
|
|
self.service_desk_employees)
|
|
|
|
self.service_desk_knowledge_level += know_how_reduction if know_how_reduction >= 0 else know_how_reduction / 10
|
|
|
|
self.documentation_level = limit_value(self.documentation_level, DOCUMENTATION_LEVEL_MIN,
|
|
DOCUMENTATION_LEVEL_MAX)
|
|
self.service_desk_knowledge_level = limit_value(self.service_desk_knowledge_level, KNOWLEDGE_LEVEL_MIN,
|
|
KNOWLEDGE_LEVEL_MAX)
|
|
|
|
def _process_data_set(self):
|
|
row = {
|
|
"day": self.actual_week,
|
|
"days_cycle": self._days_cycle,
|
|
"service_desk_employees": self.service_desk_employees,
|
|
"documentation_level": self.documentation_level,
|
|
"service_desk_knowledge_level": self.service_desk_knowledge_level,
|
|
"systems_complexity": self.systems_complexity,
|
|
"nr_of_applications": self.nr_of_applications,
|
|
"new_application_problems": self.new_application_problems,
|
|
"nr_of_open_service_requests": self.nr_of_open_service_requests,
|
|
"request_working_time": self._desired_request_working_time,
|
|
"personal_available_time": self.personal_available_time,
|
|
"nr_of_processed_service_requests": self.processed_service_requests,
|
|
"nr_of_employees": self.nr_of_employees,
|
|
}
|
|
new_df = DataFrame([row])
|
|
if self.data_set.empty:
|
|
self.data_set = new_df
|
|
else:
|
|
self.data_set = concat([self.data_set, new_df], ignore_index=False)
|
|
pass
|
|
|
|
# --------------------------------------- #
|
|
# main #
|
|
# --------------------------------------- #
|