Initial commit

This commit is contained in:
stud203999 2026-04-03 23:37:38 +03:00
commit bcd7c35c5c
5 changed files with 320 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.venv/
__pycache__/
*.pyc
insurance_report.json

21
data/appointments.csv Normal file
View File

@ -0,0 +1,21 @@
appointment_id,patient_id,doctor,date,time,status
A001,P001,Смирнова,20.04.2026,10:00,timetable
A002,P001,Кузнецов,15.03.2026,14:30,completed
A003,P002,Смирнова,18.03.2026,09:00,missed
A004,P003,Кузнецов,22.04.2026,11:15,timetable
A005,P002,Волкова,19.04.2026,15:45,timetable
A006,P004,Смирнова,17.03.2026,13:20,completed
A007,P005,Кузнецов,21.04.2026,08:30,timetable
A008,P003,Волкова,23.03.2026,12:00,cancelled
A009,P005,Смирнова,16.03.2026,16:10,completed
A010,P004,Кузнецов,24.03.2026,09:30,timetable
A011,P006,Волкова,23.04.2026,14:00,timetable
A012,P006,Смирнова,25.04.2026,11:30,completed
A013,P007,Кузнецов,24.04.2026,09:15,timetable
A014,P007,Волкова,26.04.2026,16:45,scheduled
A015,P008,Смирнова,22.04.2026,13:20,missed
A016,P008,Кузнецов,27.04.2026,10:00,timetable
A017,P009,Волкова,23.04.2026,12:10,missed
A018,P009,Смирнова,28.04.2026,15:30,timetable
A019,P010,Кузнецов,24.04.2026,08:45,missed
A020,P010,Волкова,29.04.2026,14:50,timetable
1 appointment_id patient_id doctor date time status
2 A001 P001 Смирнова 20.04.2026 10:00 timetable
3 A002 P001 Кузнецов 15.03.2026 14:30 completed
4 A003 P002 Смирнова 18.03.2026 09:00 missed
5 A004 P003 Кузнецов 22.04.2026 11:15 timetable
6 A005 P002 Волкова 19.04.2026 15:45 timetable
7 A006 P004 Смирнова 17.03.2026 13:20 completed
8 A007 P005 Кузнецов 21.04.2026 08:30 timetable
9 A008 P003 Волкова 23.03.2026 12:00 cancelled
10 A009 P005 Смирнова 16.03.2026 16:10 completed
11 A010 P004 Кузнецов 24.03.2026 09:30 timetable
12 A011 P006 Волкова 23.04.2026 14:00 timetable
13 A012 P006 Смирнова 25.04.2026 11:30 completed
14 A013 P007 Кузнецов 24.04.2026 09:15 timetable
15 A014 P007 Волкова 26.04.2026 16:45 scheduled
16 A015 P008 Смирнова 22.04.2026 13:20 missed
17 A016 P008 Кузнецов 27.04.2026 10:00 timetable
18 A017 P009 Волкова 23.04.2026 12:10 missed
19 A018 P009 Смирнова 28.04.2026 15:30 timetable
20 A019 P010 Кузнецов 24.04.2026 08:45 missed
21 A020 P010 Волкова 29.04.2026 14:50 timetable

72
data/patients.json Normal file
View File

@ -0,0 +1,72 @@
[
{
"patient_id": "P001",
"full_name": "Пересчетов Иван Иванович",
"birth_date": "15.06.1985",
"insurance": "РосГосСтрах",
"phone": "+7-999-123-4567"
},
{
"patient_id": "P002",
"full_name": "Выпивалова Анна Сергеевна",
"birth_date": "23.11.1990",
"insurance": "Согаз-МЕД",
"phone": "89161234567"
},
{
"patient_id": "P003",
"full_name": "Перекатиполе Павел Николаевич",
"birth_date": "10.03.1978",
"insurance": "ЗастрахуйБратуху",
"phone": "+7-903-111-2233"
},
{
"patient_id": "P004",
"full_name": "Пивоварова Елена Иннокентьевна",
"birth_date": "01.07.2000",
"insurance": "Макс-М",
"phone": "+7-985-777-8899"
},
{
"patient_id": "P005",
"full_name": "Красноносов Дмитрий Евграфович",
"birth_date": "30.12.1965",
"insurance": "Согаз-МЕД",
"phone": "8-800-555-3535"
},
{
"patient_id": "P006",
"full_name": "Зайцева-Кроликова Ольга Владимировна",
"birth_date": "12.09.1995",
"insurance": "РосГосСтрах",
"phone": "+7-912-345-6789"
},
{
"patient_id": "P007",
"full_name": "Соколовский Артём Дмитриевич",
"birth_date": "25.04.1988",
"insurance": "Макс-М",
"phone": "+7-922-111-2233"
},
{
"patient_id": "P008",
"full_name": "Лебедева-Гусева Мария Петровна",
"birth_date": "03.11.2002",
"insurance": "Согаз-МЕД",
"phone": "89205556677"
},
{
"patient_id": "P009",
"full_name": "Грошкин Андрей Сергеевич",
"birth_date": "19.07.1975",
"insurance": "ЗастрахуйБратуху",
"phone": "+7-951-444-5566"
},
{
"patient_id": "P010",
"full_name": "Тимофеева-Акакьева Екатерина Алексеевна",
"birth_date": "28.02.1999",
"insurance": "РосГосСтрах",
"phone": "8-953-777-8899"
}
]

0
requirements.txt Normal file
View File

223
src/main.py Normal file
View File

@ -0,0 +1,223 @@
import json
import csv
from datetime import datetime, date, timedelta
#загрузка данных пациента из json
def Load_Patients(filepath: str) -> list[dict]:
try:
with open(filepath, 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
print(f"Ошибка: файл {filepath} не найден.")
return []
except json.JSONDecodeError:
print(f"Ошибка: файл {filepath} содержит некорректный JSON.")
return []
#загрузка записей из csv
def Load_Appointments(filepath: str) -> list[dict]:
try:
with open(filepath, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
return list(reader)
except FileNotFoundError:
print(f"Ошибка: файл {filepath} не найден.")
return []
except Exception as e:
print(f"Ошибка при чтении CSV: {e}")
return []
#вычисление возраста пацинта
def Calculate_Age(birth_date_str: str) -> int:
birth = datetime.strptime(birth_date_str, "%d.%m.%Y").date()
today = date.today()
age = today.year - birth.year - ((today.month, today.day) < (birth.month, birth.day))
return age
def Validate_Patient(patient: dict) -> tuple[bool, str]:
required_fields = {"patient_id", "full_name", "birth_date", "insurance", "phone"}
missing = required_fields - patient.keys()
if missing:
return False, f"отсутствуют поля: {missing}"
try:
age = Calculate_Age(patient["birth_date"])
if not (0 < age < 120):
return False, f"возраст не корректен. Возраст: {age}"
except Exception:
return False, "некорректная дата рождения"
phone = patient["phone"]
allowed_chars = set("0123456789+- ")
if not all(ch in allowed_chars for ch in phone) or len(phone)<6:
return False, f"некорректный телефон: {phone}"
return True, ""
def Calculate_Average_Age(patients: list[dict]) -> float:
if not patients:
return 0.0
total_age = sum(Calculate_Age(p["birth_date"]) for p in patients)
return total_age / len(patients)
def Get_Patients_by_Insurance(patients: list[dict], insurer: str) -> list[dict]:
insurer_lower = insurer.lower()
return [p for p in patients if p["insurance"].lower() == insurer_lower]
def Count_Appointments_per_Patient(appointments: list[dict]) -> dict[str, int]:
counts = {}
for app in appointments:
pid = app["patient_id"]
counts[pid] = counts.get(pid, 0) + 1
return counts
def Get_Missed_Appointments(appointments: list[dict]) -> list[dict]:
return [app for app in appointments if app.get("status") == "missed"]
def Calculate_Doctor_Workload(appointments: list[dict], start_date: str, end_date: str) -> dict[str, int]:
workload = {}
start = datetime.strptime(start_date, "%d.%m.%Y").date()
end = datetime.strptime(end_date, "%d.%m.%Y").date()
for app in appointments:
try:
app_date = datetime.strptime(app["date"], "%d.%m.%Y").date()
if start <= app_date <= end:
doctor = app["doctor"]
workload[doctor] = workload.get(doctor, 0) + 1
except (KeyError, ValueError):
continue
return workload
def Generate_Weekly_Timetable(appointments: list[dict], start_date: str) -> list[dict]:
start = datetime.strptime(start_date, "%d.%m.%Y").date()
end = start + timedelta(days=6)
filtered = []
for app in appointments:
try:
app_date = datetime.strptime(app["date"], "%d.%m.%Y").date()
if start <= app_date <= end:
filtered.append(app)
except (KeyError, ValueError):
continue
filtered.sort(key=lambda x: datetime.strptime(x["date"], "%d.%m.%Y"))
return filtered
def Export_Insurance_Report(patients: list[dict], appointments: list[dict], filename: str) -> str:
#словарь страховая -> количество пациентов
insurance_patients = {}
for p in patients:
ins = p["insurance"]
insurance_patients[ins] = insurance_patients.get(ins, 0) + 1
#словарь patient_id -> страховая
patient_insurance = {p["patient_id"]: p["insurance"] for p in patients}
#число приёмов со статусом timetable или completed
insurance_appointments = {}
for app in appointments:
status = app.get("status", "")
if status in ("timetable", "completed"):
pid = app["patient_id"]
ins = patient_insurance.get(pid)
if ins:
insurance_appointments[ins] = insurance_appointments.get(ins, 0) + 1
#итоговый отчёт
report = {}
all_insurances = set(insurance_patients.keys()) | set(insurance_appointments.keys())
for ins in all_insurances:
report[ins] = {
"patient_count": insurance_patients.get(ins, 0),
"timetable_completed_appointments": insurance_appointments.get(ins, 0)
}
with open(filename, 'w', encoding='utf-8') as f:
json.dump(report, f, ensure_ascii=False, indent=4)
return f"Report saved to {filename}"
#Демонстрация
def main():
#1. Загрузка данных
patients = Load_Patients('data/patients.json')
if not patients:
print("Нет данных о пациентах. Завершение.")
return
appointments = Load_Appointments('data/appointments.csv')
if not appointments:
print("Нет данных о записях. Завершение.")
return
# 2.Валидация пациентов
print("\n=== Проверка пациентов ===")
for patient in patients:
valid, msg = Validate_Patient(patient)
if not valid:
print(f"Ошибка у пациента {patient['patient_id']}: {msg}")
#3. Средний возраст
avg_age = Calculate_Average_Age(patients)
print(f"\n=== Средний возраст пациентов ===")
print(f" {avg_age:.1f} лет")
#4.Пациенты по страховке
insurer = "Согаз-МЕД"
filtered_patients = Get_Patients_by_Insurance(patients, insurer)
print(f"\n=== Пациенты со страховкой {insurer} ===")
for p in filtered_patients:
print(f" {p['full_name']} ({p['patient_id']})")
# 5. Количество приёмов на пациента
appointment_counts = Count_Appointments_per_Patient(appointments)
print("\n=== Количество приёмов по пациентам ===")
for pid, count in appointment_counts.items():
print(f" {pid}: {count}")
# 6.Пропущенные приёмы
missed = Get_Missed_Appointments(appointments)
print("\n=== Пропущенные приёмы ===")
for app in missed:
print(f" {app['appointment_id']} — пациент {app['patient_id']}, врач {app['doctor']}")
#7. Нагрузка врачей за текущий месяц
today = datetime.today()
start_month = date(today.year, today.month, 1).strftime("%d.%m.%Y")
if today.month == 12:
end_month = date(today.year + 1, 1, 1) - timedelta(days=1)
else:
end_month = date(today.year, today.month + 1, 1) - timedelta(days=1)
end_month_str = end_month.strftime("%d.%m.%Y")
workload = Calculate_Doctor_Workload(appointments, start_month, end_month_str)
months_ru = {
1: "Январь", 2: "Февраль", 3: "Март", 4: "Апрель",
5: "Май", 6: "Июнь", 7: "Июль", 8: "Август",
9: "Сентябрь", 10: "Октябрь", 11: "Ноябрь", 12: "Декабрь"
}
day, month, year = map(int, start_month.split('.'))
print(f"\n=== Нагрузка врачей за {months_ru[month]} {year} ===")
for doctor, count in workload.items():
print(f" {doctor}: {count} приёмов")
# 8.Расписание на неделю с понедельника
days_from_monday = today.weekday() # понедельник = 0
start_week = (today.date() - timedelta(days=days_from_monday)).strftime("%d.%m.%Y")
weekly = Generate_Weekly_Timetable(appointments, start_week)
print(f"\n=== Расписание на неделю с {start_week} ===")
for app in weekly:
print(f" {app['date']} {app['time']}{app['doctor']}, пациент {app['patient_id']}")
# 9. Экспорт отчёта по страховкам
result = Export_Insurance_Report(patients, appointments, 'insurance_report.json')
print(f"\n=== {result} ===")
print("\n=== Демонстрация завершена ===")
if __name__ == "__main__":
main()