Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Решение тестового задания #12

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea
__pycache__
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,30 @@ a30b4d51-11b4-49b2-b356-466e92a66df7 Иванов Иван Иванович 16.0
Примеры входного и выходного файлов приложены к настоящему техническому заданию.

## Автор решения
Лузин Никита Игоревич

## Описание реализации
Данный проект имеет три основные функции, отвечающие за логику программы - **read_report**, **check_imbalance**, **write_imbalance_staff**.

Также существует вспомогательная функция - **write_imbalance_staff** - отсеивающая некорректно введённые данные о списаниях сотрудников.

`read_report` Отвечает за считывание файла *report.txt*, а также проверяет корректность введённого значения нормы часов (первая строка файла).

`check_imbalance` Вычисляет всех сотрудников, у которых дизбаланс списаний времени за неделю составляет более 10% в обе стороны. Попутно, используя функцию **write_imbalance_staff**, отсеивает невалидные строки.

`write_imbalance_staff` Записывает отформатированные нужным образом строки в файл *result.txt*.

## Инструкция по сборке и запуску решения
Для запуска программы необходимо записать данные, которые следует проверить в файл *report.txt* в следующем формате:
1. Первая строка - число, норма списания для одного сотрудника
2. Все последующие строки в формате "TSR-3": `<id сотрудника в формате UUID> <Фамилия> <Имя> <Отчество> <Дата списания в формате dd.MM.YYYY> <количество часов>`

После готовности файла *report.txt* можно выполнить программу, передав файл *main.py* на вход интерпретатору python:

`python main.py`

В зависимости от настроек Вашего компьютера, запуск программы может отличаться в части вызова интерпретатора python. Например, может быть один из следующих вариантов запуска программы:

`python3 main.py`

`python3.12 main.py`
3 changes: 3 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MAX_PERCENT_DEVIATION = 0.1
INPUT_FILE = "report.txt"
OUTPUT_FILE = "result.txt"
76 changes: 76 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from config import MAX_PERCENT_DEVIATION, INPUT_FILE, OUTPUT_FILE


def is_correct_line(line: str) -> bool:
line = line.strip().split()
if len(line) != 6:
return False
hours = line[5].replace(".", "")
correct_hours = all(digit.isdigit() for digit in hours)
correct_last_name = all(char.isalpha() for char in line[1])
correct_first_name = all(char.isalpha() for char in line[2])
correct_patronymic = all(char.isalpha() for char in line[3])
return all((correct_last_name, correct_first_name, correct_patronymic, correct_hours))


def read_report(report_file: str) -> tuple:
with open(report_file, "r") as report:
working_time_standard = report.readline()
try:
working_time_standard = float(working_time_standard)
except ValueError as e:
return "Первая строка файла report.txt (норма рабочего времени) должна быть числом!!!", e

line = report.readline()
staff_working_hours = {}
while line:
if is_correct_line(line):
uuid, last_name, first_name, patronymic, date, working_hours = line.strip().split()
full_name = last_name + " " + first_name[0] + "." + patronymic[0] + "."
if full_name not in staff_working_hours:
staff_working_hours[full_name] = 0
staff_working_hours[full_name] += float(working_hours)
line = report.readline()
return working_time_standard, staff_working_hours


def check_imbalance(normal_hours: float, staff_working_hours: dict) -> list[tuple]:
abnormal_working_hours_less_null = []
abnormal_working_hours_more_null = []
for name, working_hours in staff_working_hours.items():
difference = round(working_hours - normal_hours, 3)
normal_variation = normal_hours * MAX_PERCENT_DEVIATION
if abs(difference) > normal_variation:
if difference > 0:
abnormal_working_hours_more_null.append((name, difference))
else:
abnormal_working_hours_less_null.append((name, difference))
staff_less_normal = sorted(abnormal_working_hours_less_null)
staff_more_normal = sorted(abnormal_working_hours_more_null)
all_imbalance_staff = []
all_imbalance_staff.extend(staff_less_normal)
all_imbalance_staff.extend(staff_more_normal)
return all_imbalance_staff


def write_imbalance_staff(all_staff: list[tuple], result_file):
with open(result_file, "w") as result:
for employee_data in all_staff:
username, imbalance_hours = employee_data
if imbalance_hours % 1 == 0:
imbalance_hours = int(imbalance_hours)

if imbalance_hours > 0:
result.write(" +".join((username, str(imbalance_hours))))
else:
result.write(" ".join((username, str(imbalance_hours))))
result.write("\n")


if __name__ == "__main__":
normal_time, data_of_staff = read_report(INPUT_FILE)
if isinstance(normal_time, float) and isinstance(data_of_staff, dict):
imbalance_staff = check_imbalance(normal_time, data_of_staff)
write_imbalance_staff(imbalance_staff, OUTPUT_FILE)
else:
print(normal_time, data_of_staff, sep="\n")