Skip to content

Instantly share code, notes, and snippets.

@goroba
Last active December 13, 2023 13:33
Show Gist options
  • Save goroba/7a51b5477a2e9030b6ced4ff577d8124 to your computer and use it in GitHub Desktop.
Save goroba/7a51b5477a2e9030b6ced4ff577d8124 to your computer and use it in GitHub Desktop.
# app/models/enums.py
class IndicatorType(StrEnum):
PEOPLE = 'PEOPLE'
QUANTITY = 'QUANTITY'
QUALITY = 'QUALITY'
FINANCE = 'FINANCE'
# app/services/indicators/evaluators/base.py
Evaluable = TypeVar('Evaluable') # Это может быть Client, Account, Project, etc.
class IndicatorEvaluator(DataTypeAwared, Generic[Evaluable]):
@property
def code(self) -> str:
raise NotImplemented()
@property
def title(self) -> str:
raise NotImplemented()
@property
def description(self) -> str:
raise NotImplemented()
@property
def indicator_type(self) -> IndicatorType:
raise NotImplemented()
def evaluate(self, evaluable: Evaluable) -> str:
value = str(self.do_evaluation(evaluable))
validate_value(value, self)
return value
def do_evaluation(self, evaluable: Evaluable) -> Any:
raise NotImplemented()
# app/services/indicators/evaluators/projects/base.py
class ProjectIndicatorEvaluator(IndicatorEvaluator[Project]):
...
# app/services/indicators/evaluators/accounts/base.py
class AccountIndicatorEvaluator(IndicatorEvaluator[Account]):
...
# app/services/indicators/evaluators/projects/duration.py
class DurationIndicatorEvaluator(ProjectIndicatorEvaluator):
@property
def code(self) -> str:
return 'projects.duration'
@property
def title(self) -> str:
return 'Project Duration'
@property
def description(self) -> str:
return 'Evaluate project duration in full months. Calculates the period since the start of the very first timer for the project till now.'
@property
def indicator_type(self) -> IndicatorType:
return IndicatorType.QUANTITY
@property
def data_type(self) -> DataType:
return DataType.INTEGER # измеряем в полных месяцах
@property
def data_options(self) -> list[str] | None:
return None
def do_evaluation(project: Project) -> int:
return int(math.floor(3.4))
# app/services/indicators/evaluators/projects/active_employees_number.py
class ActiveEmployeesNumberIndicatorEvaluator(ProjectIndicatorEvaluator):
@property
def code(self) -> str:
return 'projects.active_employees_number'
@property
def title(self) -> str:
return 'Project Active Employees Number'
@property
def description(self) -> str:
return 'Evaluate the number of employees for the project. Calculates number of distinct users that ran timers for the previous 30 days for the project.'
@property
def indicator_type(self) -> IndicatorType:
return IndicatorType.PEOPLE
@property
def data_type(self) -> DataType:
return DataType.INTEGER
@property
def data_options(self) -> list[str] | None:
return None
def do_evaluation(project: Project) -> int:
return 84
# app/services/indicators/evaluators/projects/hours_spent.py
class HoursSpentIndicatorEvaluator(ProjectIndicatorEvaluator):
@property
def code(self) -> str:
return 'project.hours_spent'
@property
def title(self) -> str:
return 'Number of hours spent'
@property
def description(self) -> str:
return 'Evaluate number of hours spent the project. This is a summary duration of all timers for the project.'
@property
def indicator_type(self) -> IndicatorType:
return IndicatorType.QUANTITY
@property
def data_type(self) -> DataType:
return DataType.INTEGER
@property
def data_options(self) -> list[str] | None:
return None
def do_evaluation(project: Project) -> int:
return int(10827.5 // 60) # минуты в timer.duration конвертирыем в часы
# app/services/indicators/evaluators/accounts/duration.py
class DurationIndicatorEvaluator(AccountIndicatorEvaluator):
@property
def code(self) -> str:
return 'accounts.duration'
def do_evaluation(account: Account) -> int:
return int(math.floor(3.4))
...
# Период с момента запуска первого таймера для проекта этого аккаунта
# app/services/indicators/evaluators/accounts/active_employees_number.py
class ActiveEmployeesNumberIndicatorEvaluator(AccountIndicatorEvaluator):
@property
def code(self) -> str:
return 'accounts.active_employees_number'
def do_evaluation(account: Account) -> int:
return 84
...
# все distinct юзеры, кто запускал таймеры для проектов данного акканта за последние 30 дней
# app/services/indicators/evaluators/accounts/hours_spent.py
class HoursSpentIndicatorEvaluator(AccountIndicatorEvaluator):
@property
def code(self) -> str:
return 'accounts.hours_spent'
def do_evaluation(account: Account) -> int:
return int(10827.5 // 60) # минуты в timer.duration конвертирыем в часы
# сколько всего времени затрекано на всех проектах данного аккаунта
# app/services/indicators/evaluators/__init__.py
# сюда пока что выносим только индикаторы для проектов, т.к. для аккаунтов эти индикаторы нужны в расчетах рангов и пока не используются в бизнес-правилах
indicator_evaluators = {
DurationIndicatorEvaluator.code: DurationIndicatorEvaluator,
ActiveEmployeesNumberIndicatorEvaluator.code: ActiveEmployeesNumberIndicatorEvaluator,
HoursSpentIndicatorEvaluator.code: HoursSpentIndicatorEvaluator,
}
def has_indicator_evaluator(evaluator_code: str) -> bool:
return evaluator_code in indicator_evaluators
def get_indicator_evaluator(evaluator_code: str) -> IndicatorEvaluator:
try:
return indicator_evaluators[evaluator_code]()
except Exception:
raise ValueError('Indicator evaluator is not implemented.')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment