From 49fdc3111bc6dd15a63ff157843e4ff87b68ebb8 Mon Sep 17 00:00:00 2001 From: Tattaboe Date: Fri, 13 Feb 2026 11:16:07 +0400 Subject: [PATCH 1/4] Lab1: Complete --- .../Polyclinic.Domain/Entities/Appointment.cs | 53 +++ .../Polyclinic.Domain/Entities/Doctor.cs | 60 +++ .../Polyclinic.Domain/Entities/Patient.cs | 75 +++ .../Entities/Specialization.cs | 39 ++ .../Polyclinic.Domain/Enums/BloodGroup.cs | 33 ++ Polyclinic/Polyclinic.Domain/Enums/Gender.cs | 28 ++ .../Polyclinic.Domain/Enums/RhFactor.cs | 23 + .../Polyclinic.Domain.csproj | 9 + .../Polyclinic.Tests/Polyclinic.Tests.csproj | 30 ++ .../Polyclinic.Tests/PolyclinicFixture.cs | 440 ++++++++++++++++++ .../Polyclinic.Tests/PolyclinicTests.cs | 175 +++++++ Polyclinic/Polyclinic.Tests/TestConstants.cs | 47 ++ Polyclinic/Polyclinic.sln | 31 ++ README.md | 160 ++----- 14 files changed, 1080 insertions(+), 123 deletions(-) create mode 100644 Polyclinic/Polyclinic.Domain/Entities/Appointment.cs create mode 100644 Polyclinic/Polyclinic.Domain/Entities/Doctor.cs create mode 100644 Polyclinic/Polyclinic.Domain/Entities/Patient.cs create mode 100644 Polyclinic/Polyclinic.Domain/Entities/Specialization.cs create mode 100644 Polyclinic/Polyclinic.Domain/Enums/BloodGroup.cs create mode 100644 Polyclinic/Polyclinic.Domain/Enums/Gender.cs create mode 100644 Polyclinic/Polyclinic.Domain/Enums/RhFactor.cs create mode 100644 Polyclinic/Polyclinic.Domain/Polyclinic.Domain.csproj create mode 100644 Polyclinic/Polyclinic.Tests/Polyclinic.Tests.csproj create mode 100644 Polyclinic/Polyclinic.Tests/PolyclinicFixture.cs create mode 100644 Polyclinic/Polyclinic.Tests/PolyclinicTests.cs create mode 100644 Polyclinic/Polyclinic.Tests/TestConstants.cs create mode 100644 Polyclinic/Polyclinic.sln diff --git a/Polyclinic/Polyclinic.Domain/Entities/Appointment.cs b/Polyclinic/Polyclinic.Domain/Entities/Appointment.cs new file mode 100644 index 000000000..b9031c89c --- /dev/null +++ b/Polyclinic/Polyclinic.Domain/Entities/Appointment.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Polyclinic.Domain.Entities; + +/// +/// Запись пациента на прием к врачу +/// +public class Appointment +{ + /// + /// Уникальный идентификатор записи + /// + public int Id { get; set; } + + /// + /// Дата и время приема + /// + public DateTime AppointmentDateTime { get; set; } + + /// + /// Номер кабинета + /// + public required string RoomNumber { get; set; } + + /// + /// Флаг повторного приема + /// + public bool IsRepeat { get; set; } + + /// + /// Идентификатор пациента + /// + public int PatientId { get; set; } + + /// + /// Идентификатор врача + /// + public int DoctorId { get; set; } + + /// + /// Навигационное свойство: пациент + /// + public Patient? Patient { get; set; } + + /// + /// Навигационное свойство: врач + /// + public Doctor? Doctor { get; set; } +} \ No newline at end of file diff --git a/Polyclinic/Polyclinic.Domain/Entities/Doctor.cs b/Polyclinic/Polyclinic.Domain/Entities/Doctor.cs new file mode 100644 index 000000000..907e42a27 --- /dev/null +++ b/Polyclinic/Polyclinic.Domain/Entities/Doctor.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Polyclinic.Domain.Enums; + +namespace Polyclinic.Domain.Entities; + +/// +/// Врач поликлиники +/// +public class Doctor +{ + /// + /// Уникальный идентификатор врача + /// + public int Id { get; set; } + + /// + /// Номер паспорта (уникальный) + /// + public required string PassportNumber { get; set; } + + /// + /// ФИО врача + /// + public required string FullName { get; set; } + + /// + /// Год рождения + /// + public int BirthYear { get; set; } + + /// + /// Идентификатор специализации + /// + public int SpecializationId { get; set; } + + /// + /// Стаж работы (в годах) + /// + public int ExperienceYears { get; set; } + + /// + /// Навигационное свойство: специализация + /// + public Specialization? Specialization { get; set; } + + /// + /// Список приемов у этого врача + /// + public List Appointments { get; set; } = []; + + /// + /// Вычисление возраста врача на указанную дату + /// + public int GetAge(DateTime onDate) => onDate.Year - BirthYear; +} \ No newline at end of file diff --git a/Polyclinic/Polyclinic.Domain/Entities/Patient.cs b/Polyclinic/Polyclinic.Domain/Entities/Patient.cs new file mode 100644 index 000000000..cd40dc67c --- /dev/null +++ b/Polyclinic/Polyclinic.Domain/Entities/Patient.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Polyclinic.Domain.Enums; + +namespace Polyclinic.Domain.Entities; + +/// +/// Пациент поликлиники +/// +public class Patient +{ + /// + /// Уникальный идентификатор пациента + /// + public int Id { get; set; } + + /// + /// Номер паспорта (уникальный) + /// + public required string PassportNumber { get; set; } + + /// + /// ФИО пациента + /// + public required string FullName { get; set; } + + /// + /// Пол пациента + /// + public Gender Gender { get; set; } + + /// + /// Дата рождения + /// + public DateTime BirthDate { get; set; } + + /// + /// Адрес проживания + /// + public required string Address { get; set; } + + /// + /// Группа крови + /// + public BloodGroup BloodGroup { get; set; } + + /// + /// Резус-фактор + /// + public RhFactor RhFactor { get; set; } + + /// + /// Контактный телефон + /// + public required string PhoneNumber { get; set; } + + /// + /// Список записей на прием этого пациента + /// + public List Appointments { get; set; } = []; + + /// + /// Вычисление возраста пациента на указанную дату + /// + public int GetAge(DateTime onDate) + { + var age = onDate.Year - BirthDate.Year; + if (BirthDate.Date > onDate.AddYears(-age)) age--; + return age; + } +} diff --git a/Polyclinic/Polyclinic.Domain/Entities/Specialization.cs b/Polyclinic/Polyclinic.Domain/Entities/Specialization.cs new file mode 100644 index 000000000..9aadf9fda --- /dev/null +++ b/Polyclinic/Polyclinic.Domain/Entities/Specialization.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace Polyclinic.Domain.Entities; + +/// +/// Специализация врача (справочник) +/// +public class Specialization +{ + /// + /// Уникальный идентификатор специализации + /// + public int Id { get; set; } + + /// + /// Название специализации + /// + public required string Name { get; set; } + + /// + /// Описание специализации + /// + public required string Description { get; set; } + + /// + /// Код специализации + /// + public required string Code { get; set; } + + /// + /// Список врачей с этой специализацией + /// + public List Doctors { get; set; } = []; +} diff --git a/Polyclinic/Polyclinic.Domain/Enums/BloodGroup.cs b/Polyclinic/Polyclinic.Domain/Enums/BloodGroup.cs new file mode 100644 index 000000000..10d251989 --- /dev/null +++ b/Polyclinic/Polyclinic.Domain/Enums/BloodGroup.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Polyclinic.Domain.Enums; + +/// +/// Группа крови пациента +/// +public enum BloodGroup +{ + /// + /// Первая (0) + /// + O, + + /// + /// Вторая (A) + /// + A, + + /// + /// Третья (B) + /// + B, + + /// + /// Четвертая (AB) + /// + AB +} diff --git a/Polyclinic/Polyclinic.Domain/Enums/Gender.cs b/Polyclinic/Polyclinic.Domain/Enums/Gender.cs new file mode 100644 index 000000000..09d9260a7 --- /dev/null +++ b/Polyclinic/Polyclinic.Domain/Enums/Gender.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Polyclinic.Domain.Enums; + +/// +/// Пол пациента +/// +public enum Gender +{ + /// + /// Мужской + /// + Male, + + /// + /// Женский + /// + Female, + + /// + /// Не указано + /// + Other +} diff --git a/Polyclinic/Polyclinic.Domain/Enums/RhFactor.cs b/Polyclinic/Polyclinic.Domain/Enums/RhFactor.cs new file mode 100644 index 000000000..ed4b1726e --- /dev/null +++ b/Polyclinic/Polyclinic.Domain/Enums/RhFactor.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Polyclinic.Domain.Enums; + +/// +/// Резус-фактор пациента +/// +public enum RhFactor +{ + /// + /// Положительный + /// + Positive, + + /// + /// Отрицательный + /// + Negative +} diff --git a/Polyclinic/Polyclinic.Domain/Polyclinic.Domain.csproj b/Polyclinic/Polyclinic.Domain/Polyclinic.Domain.csproj new file mode 100644 index 000000000..fa71b7ae6 --- /dev/null +++ b/Polyclinic/Polyclinic.Domain/Polyclinic.Domain.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/Polyclinic/Polyclinic.Tests/Polyclinic.Tests.csproj b/Polyclinic/Polyclinic.Tests/Polyclinic.Tests.csproj new file mode 100644 index 000000000..bb1e0508d --- /dev/null +++ b/Polyclinic/Polyclinic.Tests/Polyclinic.Tests.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/Polyclinic/Polyclinic.Tests/PolyclinicFixture.cs b/Polyclinic/Polyclinic.Tests/PolyclinicFixture.cs new file mode 100644 index 000000000..54e65d018 --- /dev/null +++ b/Polyclinic/Polyclinic.Tests/PolyclinicFixture.cs @@ -0,0 +1,440 @@ +using Polyclinic.Domain.Entities; +using Polyclinic.Domain.Enums; + +namespace Polyclinic.Tests; + +/// +/// Фикстура с тестовыми данными для поликлиники +/// +public class PolyclinicFixture +{ + /// + /// Список специализаций + /// + public List Specializations { get; } + + /// + /// Список врачей + /// + public List Doctors { get; } + + /// + /// Список пациентов + /// + public List Patients { get; } + + /// + /// Список записей на прием + /// + public List Appointments { get; } + + /// + /// Конструктор, инициализирующий тестовые данные + /// + public PolyclinicFixture() + { + Specializations = GetSpecializations(); + Doctors = GetDoctors(); + Patients = GetPatients(); + Appointments = GetAppointments(); + + LinkDoctorsWithSpecializations(); + LinkAppointmentsWithDoctorsAndPatients(); + } + + private List GetSpecializations() => + [ + new() { Id = 1, Name = "Терапевт", Code = "THERAPIST", Description = "Врач общей практики" }, + new() { Id = 2, Name = "Хирург", Code = "SURGEON", Description = "Проведение операций" }, + new() { Id = 3, Name = "Кардиолог", Code = "CARDIOLOGIST", Description = "Заболевания сердца" }, + new() { Id = 4, Name = "Невролог", Code = "NEUROLOGIST", Description = "Заболевания нервной системы" }, + new() { Id = 5, Name = "Педиатр", Code = "PEDIATRICIAN", Description = "Детские болезни" }, + new() { Id = 6, Name = "Гинеколог", Code = "GYNECOLOGIST", Description = "Женское здоровье" }, + new() { Id = 7, Name = "Офтальмолог", Code = "OPHTHALMOLOGIST", Description = "Заболевания глаз" }, + new() { Id = 8, Name = "Отоларинголог", Code = "ENT", Description = "Ухо, горло, нос" }, + new() { Id = 9, Name = "Дерматолог", Code = "DERMATOLOGIST", Description = "Кожные заболевания" }, + new() { Id = 10, Name = "Эндокринолог", Code = "ENDOCRINOLOGIST", Description = "Гормональные нарушения" } + ]; + + private List GetDoctors() => + [ + new() + { + Id = 1, + PassportNumber = "4501 123456", + FullName = "Иванов Иван Иванович", + BirthYear = 1980, + SpecializationId = 1, + ExperienceYears = 15 + }, + new() + { + Id = 2, + PassportNumber = "4502 234567", + FullName = "Петров Петр Петрович", + BirthYear = 1975, + SpecializationId = 2, + ExperienceYears = 20 + }, + new() + { + Id = 3, + PassportNumber = "4503 345678", + FullName = "Сидорова Анна Сергеевна", + BirthYear = 1985, + SpecializationId = 3, + ExperienceYears = 12 + }, + new() + { + Id = 4, + PassportNumber = "4504 456789", + FullName = "Козлов Дмитрий Николаевич", + BirthYear = 1990, + SpecializationId = 4, + ExperienceYears = 8 + }, + new() + { + Id = 5, + PassportNumber = "4505 567890", + FullName = "Морозова Елена Владимировна", + BirthYear = 1982, + SpecializationId = 5, + ExperienceYears = 14 + }, + new() + { + Id = 6, + PassportNumber = "4506 678901", + FullName = "Волков Андрей Игоревич", + BirthYear = 1978, + SpecializationId = 6, + ExperienceYears = 18 + }, + new() + { + Id = 7, + PassportNumber = "4507 789012", + FullName = "Соколова Татьяна Александровна", + BirthYear = 1988, + SpecializationId = 7, + ExperienceYears = 10 + }, + new() + { + Id = 8, + PassportNumber = "4508 890123", + FullName = "Лебедев Михаил Сергеевич", + BirthYear = 1992, + SpecializationId = 8, + ExperienceYears = 6 + }, + new() + { + Id = 9, + PassportNumber = "4509 901234", + FullName = "Николаева Ольга Викторовна", + BirthYear = 1983, + SpecializationId = 9, + ExperienceYears = 13 + }, + new() + { + Id = 10, + PassportNumber = "4510 012345", + FullName = "Федоров Алексей Павлович", + BirthYear = 1970, + SpecializationId = 10, + ExperienceYears = 25 + } + ]; + + private List GetPatients() => + [ + new() + { + Id = 1, + PassportNumber = "6001 123456", + FullName = "Смирнов Алексей Викторович", + Gender = Gender.Male, + BirthDate = new DateTime(1990, 5, 15), + Address = "ул. Ленина, д. 10, кв. 25", + BloodGroup = BloodGroup.A, + RhFactor = RhFactor.Positive, + PhoneNumber = "+7 (999) 123-45-67" + }, + new() + { + Id = 2, + PassportNumber = "6002 234567", + FullName = "Кузнецова Елена Дмитриевна", + Gender = Gender.Female, + BirthDate = new DateTime(1985, 8, 22), + Address = "ул. Гагарина, д. 5, кв. 12", + BloodGroup = BloodGroup.O, + RhFactor = RhFactor.Positive, + PhoneNumber = "+7 (999) 234-56-78" + }, + new() + { + Id = 3, + PassportNumber = "6003 345678", + FullName = "Попов Сергей Иванович", + Gender = Gender.Male, + BirthDate = new DateTime(1978, 3, 10), + Address = "пр. Мира, д. 15, кв. 7", + BloodGroup = BloodGroup.B, + RhFactor = RhFactor.Negative, + PhoneNumber = "+7 (999) 345-67-89" + }, + new() + { + Id = 4, + PassportNumber = "6004 456789", + FullName = "Васильева Мария Петровна", + Gender = Gender.Female, + BirthDate = new DateTime(1995, 11, 30), + Address = "ул. Советская, д. 8, кв. 42", + BloodGroup = BloodGroup.AB, + RhFactor = RhFactor.Positive, + PhoneNumber = "+7 (999) 456-78-90" + }, + new() + { + Id = 5, + PassportNumber = "6005 567890", + FullName = "Соколов Андрей Николаевич", + Gender = Gender.Male, + BirthDate = new DateTime(1982, 7, 18), + Address = "ул. Пушкина, д. 3, кв. 56", + BloodGroup = BloodGroup.A, + RhFactor = RhFactor.Negative, + PhoneNumber = "+7 (999) 567-89-01" + }, + new() + { + Id = 6, + PassportNumber = "6006 678901", + FullName = "Михайлова Анна Сергеевна", + Gender = Gender.Female, + BirthDate = new DateTime(1975, 9, 25), + Address = "пр. Ленинградский, д. 22, кв. 15", + BloodGroup = BloodGroup.O, + RhFactor = RhFactor.Positive, + PhoneNumber = "+7 (999) 678-90-12" + }, + new() + { + Id = 7, + PassportNumber = "6007 789012", + FullName = "Новиков Денис Александрович", + Gender = Gender.Male, + BirthDate = new DateTime(1988, 2, 14), + Address = "ул. Кирова, д. 12, кв. 8", + BloodGroup = BloodGroup.B, + RhFactor = RhFactor.Positive, + PhoneNumber = "+7 (999) 789-01-23" + }, + new() + { + Id = 8, + PassportNumber = "6008 890123", + FullName = "Морозова Татьяна Владимировна", + Gender = Gender.Female, + BirthDate = new DateTime(1992, 6, 5), + Address = "ул. Садовая, д. 7, кв. 31", + BloodGroup = BloodGroup.AB, + RhFactor = RhFactor.Negative, + PhoneNumber = "+7 (999) 890-12-34" + }, + new() + { + Id = 9, + PassportNumber = "6009 901234", + FullName = "Зайцев Игорь Павлович", + Gender = Gender.Male, + BirthDate = new DateTime(1970, 12, 3), + Address = "пр. Невский, д. 45, кв. 19", + BloodGroup = BloodGroup.A, + RhFactor = RhFactor.Positive, + PhoneNumber = "+7 (999) 901-23-45" + }, + new() + { + Id = 10, + PassportNumber = "6010 012345", + FullName = "Волкова Ольга Игоревна", + Gender = Gender.Female, + BirthDate = new DateTime(1965, 4, 20), + Address = "ул. Комсомольская, д. 6, кв. 23", + BloodGroup = BloodGroup.O, + RhFactor = RhFactor.Positive, + PhoneNumber = "+7 (999) 012-34-56" + }, + new() + { + Id = 11, + PassportNumber = "6011 123456", + FullName = "Белова Наталья Сергеевна", + Gender = Gender.Female, + BirthDate = new DateTime(1998, 1, 8), + Address = "ул. Мичурина, д. 18, кв. 67", + BloodGroup = BloodGroup.B, + RhFactor = RhFactor.Positive, + PhoneNumber = "+7 (999) 123-56-78" + }, + new() + { + Id = 12, + PassportNumber = "6012 234567", + FullName = "Карпов Евгений Владимирович", + Gender = Gender.Male, + BirthDate = new DateTime(1983, 9, 12), + Address = "ул. Лермонтова, д. 9, кв. 14", + BloodGroup = BloodGroup.AB, + RhFactor = RhFactor.Negative, + PhoneNumber = "+7 (999) 234-67-89" + } + ]; + + private List GetAppointments() + { + var appointments = new List(); + var appointmentId = 1; + + // Записи на текущий месяц (февраль 2026) + appointments.AddRange([ + new() + { + Id = appointmentId++, + AppointmentDateTime = new DateTime(2026, 2, 5, 10, 0, 0), + RoomNumber = TestConstants.TherapyRoom, + IsRepeat = false, + PatientId = 1, + DoctorId = 1 + }, + new() + { + Id = appointmentId++, + AppointmentDateTime = new DateTime(2026, 2, 5, 11, 0, 0), + RoomNumber = TestConstants.TherapyRoom, + IsRepeat = true, + PatientId = 2, + DoctorId = 1 + }, + new() + { + Id = appointmentId++, + AppointmentDateTime = new DateTime(2026, 2, 10, 14, 30, 0), + RoomNumber = TestConstants.SurgeryRoom, + IsRepeat = false, + PatientId = 3, + DoctorId = 2 + }, + new() + { + Id = appointmentId++, + AppointmentDateTime = new DateTime(2026, 2, 15, 9, 15, 0), + RoomNumber = TestConstants.CardiologyRoom, + IsRepeat = false, + PatientId = 4, + DoctorId = 3 + }, + new() + { + Id = appointmentId++, + AppointmentDateTime = new DateTime(2026, 2, 12, 13, 30, 0), + RoomNumber = TestConstants.TherapyRoom, + IsRepeat = false, + PatientId = 8, + DoctorId = 1 + }, + new() + { + Id = appointmentId++, + AppointmentDateTime = new DateTime(2026, 2, 16, 9, 30, 0), + RoomNumber = TestConstants.TherapyRoom, + IsRepeat = false, + PatientId = 11, + DoctorId = 1 + } + ]); + + // Записи на прошлый месяц (январь 2026) + appointments.AddRange([ + new() + { + Id = appointmentId++, + AppointmentDateTime = new DateTime(2026, 1, 15, 10, 0, 0), + RoomNumber = TestConstants.TherapyRoom, + IsRepeat = true, + PatientId = 6, + DoctorId = 2 + }, + new() + { + Id = appointmentId++, + AppointmentDateTime = new DateTime(2026, 1, 20, 11, 0, 0), + RoomNumber = TestConstants.SurgeryRoom, + IsRepeat = true, + PatientId = 7, + DoctorId = 2 + }, + new() + { + Id = appointmentId++, + AppointmentDateTime = new DateTime(2026, 1, 5, 9, 0, 0), + RoomNumber = TestConstants.CardiologyRoom, + IsRepeat = false, + PatientId = 8, + DoctorId = 3 + } + ]); + + // Пациент Соколов (Id=5) записан к нескольким врачам + appointments.AddRange([ + new() + { + Id = appointmentId++, + AppointmentDateTime = new DateTime(2026, 2, 8, 9, 0, 0), + RoomNumber = "102", + IsRepeat = false, + PatientId = 5, + DoctorId = 2 + }, + new() + { + Id = appointmentId++, + AppointmentDateTime = new DateTime(2026, 2, 22, 11, 30, 0), + RoomNumber = "606", + IsRepeat = false, + PatientId = 5, + DoctorId = 6 + } + ]); + + return appointments; + } + + private void LinkDoctorsWithSpecializations() + { + foreach (var doctor in Doctors) + { + doctor.Specialization = Specializations.First(s => s.Id == doctor.SpecializationId); + doctor.Specialization.Doctors.Add(doctor); + } + } + + private void LinkAppointmentsWithDoctorsAndPatients() + { + foreach (var appointment in Appointments) + { + appointment.Doctor = Doctors.First(d => d.Id == appointment.DoctorId); + appointment.Patient = Patients.First(p => p.Id == appointment.PatientId); + + appointment.Doctor.Appointments.Add(appointment); + appointment.Patient.Appointments.Add(appointment); + } + } +} \ No newline at end of file diff --git a/Polyclinic/Polyclinic.Tests/PolyclinicTests.cs b/Polyclinic/Polyclinic.Tests/PolyclinicTests.cs new file mode 100644 index 000000000..4eee79fa9 --- /dev/null +++ b/Polyclinic/Polyclinic.Tests/PolyclinicTests.cs @@ -0,0 +1,175 @@ +using Polyclinic.Domain.Entities; + +namespace Polyclinic.Tests; + +/// +/// Тесты для поликлиники с использованием фикстуры +/// +public class PolyclinicTests(PolyclinicFixture fixture) : IClassFixture +{ + /// + /// ТЕСТ 1: Вывести информацию о всех врачах, стаж работы которых не менее 10 лет + /// + [Fact] + public void GetDoctorsWithExperienceMoreThan10Years() + { + var actual = ( + from doctor in fixture.Doctors + where doctor.ExperienceYears >= TestConstants.MinExperienceYears + orderby doctor.FullName + select doctor + ).ToList(); + + Assert.NotEmpty(actual); + Assert.All(actual, doctor => + Assert.True(doctor.ExperienceYears >= TestConstants.MinExperienceYears)); + + var excludedDoctors = fixture.Doctors.Except(actual); + Assert.All(excludedDoctors, doctor => + Assert.True(doctor.ExperienceYears < TestConstants.MinExperienceYears)); + + Assert.Equal([.. actual.OrderBy(d => d.FullName)], actual); + } + + /// + /// ТЕСТ 2: Вывести информацию о всех пациентах, записанных к указанному врачу, упорядочить по ФИО + /// + [Fact] + public void GetPatientsByDoctorOrderedByFullName() + { + var testDoctor = fixture.Doctors.First(d => fixture.Appointments.Any(a => a.DoctorId == d.Id)); + + var actual = ( + from appointment in fixture.Appointments + where appointment.DoctorId == testDoctor.Id + join patient in fixture.Patients on appointment.PatientId equals patient.Id + orderby patient.FullName + select patient + ).Distinct().ToList(); + + Assert.NotEmpty(actual); + Assert.All(actual, patient => + { + var hasAppointmentWithDoctor = fixture.Appointments + .Any(a => a.PatientId == patient.Id && a.DoctorId == testDoctor.Id); + Assert.True(hasAppointmentWithDoctor); + }); + + Assert.Equal([.. actual.OrderBy(p => p.FullName)], actual); + } + + /// + /// ТЕСТ 3: Вывести информацию о количестве повторных приемов пациентов за последний месяц + /// + [Fact] + public void CountRepeatAppointmentsLastMonth() + { + var actual = ( + from appointment in fixture.Appointments + where appointment.AppointmentDateTime >= TestConstants.StartOfLastMonth + where appointment.AppointmentDateTime < TestConstants.StartOfCurrentMonth + where appointment.IsRepeat + select appointment + ).ToList(); + + Assert.All(actual, appointment => + { + Assert.True(appointment.IsRepeat); + Assert.True(appointment.AppointmentDateTime >= TestConstants.StartOfLastMonth); + Assert.True(appointment.AppointmentDateTime < TestConstants.StartOfCurrentMonth); + }); + + var nonRepeatInLastMonth = fixture.Appointments + .Where(a => a.AppointmentDateTime >= TestConstants.StartOfLastMonth) + .Where(a => a.AppointmentDateTime < TestConstants.StartOfCurrentMonth) + .Where(a => !a.IsRepeat); + + Assert.All(nonRepeatInLastMonth, a => Assert.False(a.IsRepeat)); + } + + /// + /// ТЕСТ 4: Вывести информацию о пациентах старше 30 лет, + /// которые записаны на прием к нескольким врачам, упорядочить по дате рождения + /// + [Fact] + public void GetPatientsOver30WithMultipleDoctorsOrderedByBirthDate() + { + var actual = ( + from patient in fixture.Patients + where patient.GetAge(TestConstants.Today) >= TestConstants.MinPatientAge + let doctorsCount = ( + from appointment in fixture.Appointments + where appointment.PatientId == patient.Id + select appointment.DoctorId + ).Distinct().Count() + where doctorsCount >= 2 + orderby patient.BirthDate + select patient + ).ToList(); + + Assert.All(actual, patient => + { + Assert.True(patient.GetAge(TestConstants.Today) >= TestConstants.MinPatientAge); + + var doctorsCount = fixture.Appointments + .Where(a => a.PatientId == patient.Id) + .Select(a => a.DoctorId) + .Distinct() + .Count(); + Assert.True(doctorsCount >= 2); + }); + + var excludedPatients = fixture.Patients.Except(actual); + Assert.All(excludedPatients, patient => + { + if (patient.GetAge(TestConstants.Today) >= TestConstants.MinPatientAge) + { + var doctorsCount = fixture.Appointments + .Where(a => a.PatientId == patient.Id) + .Select(a => a.DoctorId) + .Distinct() + .Count(); + Assert.True(doctorsCount < 2); + } + }); + + Assert.Equal([.. actual.OrderBy(p => p.BirthDate)], actual); + } + + /// + /// ТЕСТ 5: Вывести информацию о приемах за текущий месяц, проходящих в выбранном кабинете + /// + [Fact] + public void GetAppointmentsCurrentMonthInRoom() + { + var testRoom = fixture.Appointments + .First(a => a.AppointmentDateTime >= TestConstants.StartOfCurrentMonth && + a.AppointmentDateTime < TestConstants.StartOfCurrentMonth.AddMonths(1)) + .RoomNumber; + + var actual = ( + from appointment in fixture.Appointments + where appointment.RoomNumber == testRoom + where appointment.AppointmentDateTime >= TestConstants.StartOfCurrentMonth + where appointment.AppointmentDateTime < TestConstants.StartOfCurrentMonth.AddMonths(1) + orderby appointment.AppointmentDateTime + select appointment + ).ToList(); + + Assert.NotEmpty(actual); + Assert.All(actual, appointment => + { + Assert.Equal(testRoom, appointment.RoomNumber); + Assert.True(appointment.AppointmentDateTime >= TestConstants.StartOfCurrentMonth); + Assert.True(appointment.AppointmentDateTime < TestConstants.StartOfCurrentMonth.AddMonths(1)); + }); + + var otherRoomAppointments = fixture.Appointments + .Where(a => a.AppointmentDateTime >= TestConstants.StartOfCurrentMonth) + .Where(a => a.AppointmentDateTime < TestConstants.StartOfCurrentMonth.AddMonths(1)) + .Where(a => a.RoomNumber != testRoom); + + Assert.All(otherRoomAppointments, a => Assert.NotEqual(testRoom, a.RoomNumber)); + Assert.Equal([.. actual.OrderBy(a => a.AppointmentDateTime)], actual); + } +} \ No newline at end of file diff --git a/Polyclinic/Polyclinic.Tests/TestConstants.cs b/Polyclinic/Polyclinic.Tests/TestConstants.cs new file mode 100644 index 000000000..53541a3f7 --- /dev/null +++ b/Polyclinic/Polyclinic.Tests/TestConstants.cs @@ -0,0 +1,47 @@ +namespace Polyclinic.Tests; + +/// +/// Константы для тестов +/// +public static class TestConstants +{ + /// + /// Фиксированная дата для тестов (15 февраля 2026) + /// + public static readonly DateTime Today = new(2026, 2, 15); + + /// + /// Начало текущего месяца + /// + public static readonly DateTime StartOfCurrentMonth = new(Today.Year, Today.Month, 1); + + /// + /// Начало прошлого месяца + /// + public static readonly DateTime StartOfLastMonth = StartOfCurrentMonth.AddMonths(-1); + + /// + /// Минимальный стаж для опытных врачей + /// + public const int MinExperienceYears = 10; + + /// + /// Минимальный возраст для "пациенты старше 30 лет" + /// + public const int MinPatientAge = 30; + + /// + /// Номер кабинета терапевта + /// + public const string TherapyRoom = "101"; + + /// + /// Номер кабинета хирурга + /// + public const string SurgeryRoom = "202"; + + /// + /// Номер кабинета кардиолога + /// + public const string CardiologyRoom = "303"; +} \ No newline at end of file diff --git a/Polyclinic/Polyclinic.sln b/Polyclinic/Polyclinic.sln new file mode 100644 index 000000000..28573c5ce --- /dev/null +++ b/Polyclinic/Polyclinic.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36915.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Polyclinic.Domain", "Polyclinic.Domain\Polyclinic.Domain.csproj", "{6C9C08E8-CE8E-422F-8BDC-E7B751E8E84A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Polyclinic.Tests", "Polyclinic.Tests\Polyclinic.Tests.csproj", "{0C24BBBB-C432-4776-9968-5DAD9432AB5A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6C9C08E8-CE8E-422F-8BDC-E7B751E8E84A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C9C08E8-CE8E-422F-8BDC-E7B751E8E84A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C9C08E8-CE8E-422F-8BDC-E7B751E8E84A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C9C08E8-CE8E-422F-8BDC-E7B751E8E84A}.Release|Any CPU.Build.0 = Release|Any CPU + {0C24BBBB-C432-4776-9968-5DAD9432AB5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C24BBBB-C432-4776-9968-5DAD9432AB5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C24BBBB-C432-4776-9968-5DAD9432AB5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C24BBBB-C432-4776-9968-5DAD9432AB5A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1F0773E0-B943-4E7B-A2FB-1B30E6ADA139} + EndGlobalSection +EndGlobal diff --git a/README.md b/README.md index 76afcbfdd..5b1298a8d 100644 --- a/README.md +++ b/README.md @@ -1,137 +1,51 @@ -# Разработка корпоративных приложений -[Таблица с успеваемостью](https://docs.google.com/spreadsheets/d/1JD6aiOG6r7GrA79oJncjgUHWtfeW4g_YZ9ayNgxb_w0/edit?usp=sharing) +# Разработка корпоративных приложений. Лабораторная работа №1. -## Задание -### Цель -Реализация проекта сервисно-ориентированного приложения. +### Цель - Реализация объектной модели данных и unit-тестов -### Задачи -* Реализация объектно-ориентированной модели данных, -* Изучение реализации серверных приложений на базе WebAPI/OpenAPI, -* Изучение работы с брокерами сообщений, -* Изучение паттернов проектирования, -* Изучение работы со средствами оркестрации на примере .NET Aspire, -* Повторение основ работы с системами контроля версий, -* Unit-тестирование. +Необходимо подготовить структуру классов, описывающих предметную область. В каждом из заданий присутствует часть, связанная с обработкой данных, представленная в разделе «Unit-тесты». Данную часть необходимо реализовать в виде unit-тестов: подготовить тестовые данные, выполнить запрос с использованием LINQ, проверить результаты. Хранение данных на этом этапе допускается осуществлять в памяти в виде коллекций. -### Лабораторные работы -
-1. «Классы» - Реализация объектной модели данных и unit-тестов -
-В рамках первой лабораторной работы необходимо подготовить структуру классов, описывающих предметную область, определяемую в задании. В каждом из заданий присутствует часть, связанная с обработкой данных, представленная в разделе «Unit-тесты». Данную часть необходимо реализовать в виде unit-тестов: подготовить тестовые данные, выполнить запрос с использованием LINQ, проверить результаты. +### Предметная область - Поликлиника -Хранение данных на этом этапе допускается осуществлять в памяти в виде коллекций. -Необходимо включить **как минимум 10** экземпляров каждого класса в датасид. - -
-
-2. «Сервер» - Реализация серверного приложения с использованием REST API -
-Во второй лабораторной работе необходимо реализовать серверное приложение, которое должно: -- Осуществлять базовые CRUD-операции с реализованными в первой лабораторной сущностями -- Предоставлять результаты аналитических запросов (раздел «Unit-тесты» задания) +В базе данных поликлиники содержится информация о записях пациентов на прием к врачам. -Хранение данных на этом этапе допускается осуществлять в памяти в виде коллекций. -
-
-
-3. «ORM» - Реализация объектно-реляционной модели. Подключение к базе данных и настройка оркестрации -
-В третьей лабораторной работе хранение должно быть переделано c инмемори коллекций на базу данных. -Должны быть созданы миграции для создания таблиц в бд и их первоначального заполнения. -
-Также необходимо настроить оркестратор Aspire на запуск сервера и базы данных. -
-
-
-4. «Инфраструктура» - Реализация сервиса генерации данных и его интеграция с сервером -
-В четвертой лабораторной работе необходимо имплементировать сервис, который генерировал бы контракты. Контракты далее передаются в сервер и сохраняются в бд. -Сервис должен представлять из себя отдельное приложение без референсов к серверным проектам за исключением библиотеки с контрактами. -Отправка контрактов при помощи gRPC должна выполняться в потоковом виде. -При использовании брокеров сообщений, необходимо предусмотреть ретраи при подключении к брокеру. +Пациент характеризуется: номером паспорта, ФИО, полом, датой рождения, адресом, группой крови, резус фактором и контактным телефоном. +Пол пациента является перечислением. +Группа крови пациента является перечислением. +Резус фактор пациента является перечислением. -Также необходимо добавить в конфигурацию Aspire запуск генератора и (если того требует вариант) брокера сообщений. -
-
-
-5. «Клиент» - Интеграция клиентского приложения с оркестратором -
-В пятой лабораторной необходимо добавить в конфигурацию Aspire запуск клиентского приложения для написанного ранее сервера. Клиент создается в рамках курса "Веб разработка". -
-
+Информация о враче включает номер паспорта, ФИО, год рождения, специализацию, стаж работы. Специализация врача является справочником. -## Задание. Общая часть -**Обязательно**: -* Реализация серверной части на [.NET 8](https://learn.microsoft.com/ru-ru/dotnet/core/whats-new/dotnet-8/overview). -* Реализация серверной части на [ASP.NET](https://dotnet.microsoft.com/ru-ru/apps/aspnet). -* Реализация unit-тестов с использованием [xUnit](https://xunit.net/?tabs=cs). -* Использование хранения данных в базе данных согласно варианту задания. -* Оркестрация проектов при помощи [.NET Aspire](https://learn.microsoft.com/ru-ru/dotnet/aspire/get-started/aspire-overview) -* Реализация сервиса генерации данных при помощи [Bogus](https://github.com/bchavez/Bogus) и его взаимодейсвие с сервером согласно варианту задания. -* Автоматизация тестирования на уровне репозитория через [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions). -* Создание минимальной документации к проекту: страница на GitHub с информацией о задании, скриншоты приложения и прочая информация. +При записи на прием пациента в базе данных фиксируется дата и время приема, номер кабинета, а также индикатор того, является ли прием повторным. +Используется в качестве контракта. -**Факультативно**: -* Реализация авторизации/аутентификации. -* Реализация atomic batch publishing/atomic batch consumption для брокеров, поддерживающих такой функционал. -* Реализация интеграционных тестов при помощи .NET Aspire. -* Реализация клиента на Blazor WASM. +### Юнит-тесты -Внимательно прочитайте [дискуссии](https://github.com/itsecd/enterprise-development/discussions/1) о том, как работает автоматическое распределение на ревью. -Сразу корректно называйте свои pr, чтобы они попали на ревью нужному преподавателю. + - Вывести информацию о всех врачах, стаж работы которых не менее 10 лет. + - Вывести информацию о всех пациентах, записанных на прием к указанному врачу, упорядочить по ФИО. + - Вывести информацию о количестве повторных приемов пациентов за последний месяц. + - Вывести информацию о пациентах старше 30 лет, которые записаны на прием к нескольким врачам, упорядочить по дате рождения. + - Вывести информацию о приемах за текущий месяц, проходящих в выбранном кабинете. -По итогу работы в семестре должна получиться следующая информационная система: -
-C4 диаграмма +### Структура проекта -image1 +Polyclinic (Solution) +│ +├── Polyclinic.Domain (Class Library) +│ ├── Entities/ +│ │ ├── Appointment.cs +│ │ ├── Doctor.cs +│ │ ├── Patient.cs +│ │ └── Specialization.cs +│ │ +│ └── Enums/ +│ ├── BloodGroup.cs +│ ├── Gender.cs +│ └── RhFactor.cs +│ +└── Polyclinic.Tests (xUnit) + ├── PolyclinicFixture.cs + ├── PolyclinicTests.cs + └── TestConstants.cs -
-## Варианты заданий -Номер варианта задания присваивается в начале семестра. Изменить его нельзя. Каждый вариант имеет уникальную комбинацию из предметной области, базы данных и технологии для общения сервиса генерации данных и сервера апи. -[Список вариантов](https://docs.google.com/document/d/1Wc8AvsKS_1JptpsxHO-cwfAxz2ghxvQRQ0fy4el2ZOc/edit?usp=sharing) -[Список предметных областей](https://docs.google.com/document/d/15jWhXMwd2K8giFMKku_yrY_s2uQNEu4ugJXLYPvYJAE/edit?usp=sharing) -[Вопросы к экзамену](https://docs.google.com/document/d/1bjfvtzjyMljJbcu8YCvC8DzDegDUAmDeNtBz9M6FQes/edit?usp=sharing) - -## Схема сдачи - -На каждую из лабораторных работ необходимо сделать отдельный [Pull Request (PR)](https://docs.github.com/en/pull-requests). - -Общая схема: -1. Сделать форк данного репозитория -2. Выполнить задание -3. Сделать PR в данный репозиторий -4. Исправить замечания после code review -5. Получить approve -6. Прийти на занятие и защитить работу - -## Критерии оценивания - -Конкурентный принцип. -Так как задания в первой лабораторной будут повторяться между студентами, то выделяются следующие показатели для оценки: -1. Скорость разработки -2. Качество разработки -3. Полнота выполнения задания - -Быстрее делаете PR - у вас преимущество. -Быстрее получаете Approve - у вас преимущество. -Выполните нечто немного выходящее за рамки проекта - у вас преимущество. - -### Шкала оценивания - -- **3 балла** за качество кода, из них: - - 2 балла - базовая оценка - - 1 балл (но не более) можно получить за выполнение любого из следующих пунктов: - - Реализация факультативного функционала - - Выполнение работы раньше других: первые 5 человек из каждой группы, которые сделали PR и получили approve, получают дополнительный балл -- **3 балла** за защиту: при сдаче лабораторной работы вам задается 3 вопроса, за каждый правильный ответ - 1 балл - -У вас 2 попытки пройти ревью (первичное ревью, ревью по результатам исправления). Если замечания по итогу не исправлены, то снимается один балл за код лабораторной работы. - -## Вопросы и обратная связь по курсу - -Чтобы задать вопрос по лабораторной, воспользуйтесь [соотвествующим разделом дискуссий](https://github.com/itsecd/enterprise-development/discussions/categories/questions) или заведите [ишью](https://github.com/itsecd/enterprise-development/issues/new). -Если у вас появились идеи/пожелания/прочие полезные мысли по преподаваемой дисциплине, их можно оставить [здесь](https://github.com/itsecd/enterprise-development/discussions/categories/ideas). From c4503953703aabd931aa3367eb1ce2d2f93dfac0 Mon Sep 17 00:00:00 2001 From: Tattaboe Date: Fri, 13 Feb 2026 11:37:24 +0400 Subject: [PATCH 2/4] Fix github actions workflow --- .github/workflows/dotnet_tests.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/dotnet_tests.yml diff --git a/.github/workflows/dotnet_tests.yml b/.github/workflows/dotnet_tests.yml new file mode 100644 index 000000000..ac58b9bb8 --- /dev/null +++ b/.github/workflows/dotnet_tests.yml @@ -0,0 +1,28 @@ +name: .NET Tests + +on: + push: + branches: [ "main", "master" ] + pull_request: + branches: [ "main", "master" ] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Restore dependencies + run: dotnet restore Polyclinic.sln + + - name: Build + run: dotnet build Polyclinic.sln --no-restore --configuration Release + + - name: Test + run: dotnet test Polyclinic.sln --no-build --configuration Release --verbosity normal \ No newline at end of file From ead176fdda733f4279de645f7d80a500bbb9b347 Mon Sep 17 00:00:00 2001 From: Tattaboe Date: Fri, 13 Feb 2026 11:42:36 +0400 Subject: [PATCH 3/4] Fix github actions workflow. YML file --- .github/workflows/dotnet_tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dotnet_tests.yml b/.github/workflows/dotnet_tests.yml index ac58b9bb8..1f55f21a3 100644 --- a/.github/workflows/dotnet_tests.yml +++ b/.github/workflows/dotnet_tests.yml @@ -19,10 +19,10 @@ jobs: dotnet-version: 8.0.x - name: Restore dependencies - run: dotnet restore Polyclinic.sln + run: dotnet restore Polyclinic/Polyclinic.sln - name: Build - run: dotnet build Polyclinic.sln --no-restore --configuration Release + run: dotnet build Polyclinic/Polyclinic.sln --no-restore --configuration Release - name: Test - run: dotnet test Polyclinic.sln --no-build --configuration Release --verbosity normal \ No newline at end of file + run: dotnet test Polyclinic/Polyclinic.sln --no-build --configuration Release --verbosity normal \ No newline at end of file From f2c7b75a7c2f88b23b26f2ada17417e8350fc3e1 Mon Sep 17 00:00:00 2001 From: Tattaboe Date: Sat, 14 Feb 2026 01:41:02 +0400 Subject: [PATCH 4/4] Fix: static method, Doctor BirthDate, BloodGroup Ab and more --- .../Polyclinic.Domain/Entities/Appointment.cs | 8 +-- .../Polyclinic.Domain/Entities/Doctor.cs | 21 +++--- .../Polyclinic.Domain/Entities/Patient.cs | 8 +-- .../Entities/Specialization.cs | 9 +-- .../Polyclinic.Domain/Enums/BloodGroup.cs | 10 +-- Polyclinic/Polyclinic.Domain/Enums/Gender.cs | 20 ++---- .../Polyclinic.Domain/Enums/RhFactor.cs | 8 +-- .../Polyclinic.Tests/PolyclinicFixture.cs | 70 +++++++------------ .../Polyclinic.Tests/PolyclinicTests.cs | 4 +- 9 files changed, 49 insertions(+), 109 deletions(-) diff --git a/Polyclinic/Polyclinic.Domain/Entities/Appointment.cs b/Polyclinic/Polyclinic.Domain/Entities/Appointment.cs index b9031c89c..627d57291 100644 --- a/Polyclinic/Polyclinic.Domain/Entities/Appointment.cs +++ b/Polyclinic/Polyclinic.Domain/Entities/Appointment.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Polyclinic.Domain.Entities; +namespace Polyclinic.Domain.Entities; /// /// Запись пациента на прием к врачу diff --git a/Polyclinic/Polyclinic.Domain/Entities/Doctor.cs b/Polyclinic/Polyclinic.Domain/Entities/Doctor.cs index 907e42a27..94c610777 100644 --- a/Polyclinic/Polyclinic.Domain/Entities/Doctor.cs +++ b/Polyclinic/Polyclinic.Domain/Entities/Doctor.cs @@ -1,12 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using Polyclinic.Domain.Enums; - -namespace Polyclinic.Domain.Entities; +namespace Polyclinic.Domain.Entities; /// /// Врач поликлиники @@ -29,9 +21,9 @@ public class Doctor public required string FullName { get; set; } /// - /// Год рождения + /// Дата рождения /// - public int BirthYear { get; set; } + public DateTime BirthDate { get; set; } /// /// Идентификатор специализации @@ -56,5 +48,10 @@ public class Doctor /// /// Вычисление возраста врача на указанную дату /// - public int GetAge(DateTime onDate) => onDate.Year - BirthYear; + public int GetAge(DateTime onDate) + { + var age = onDate.Year - BirthDate.Year; + if (BirthDate.Date > onDate.AddYears(-age)) age--; + return age; + } } \ No newline at end of file diff --git a/Polyclinic/Polyclinic.Domain/Entities/Patient.cs b/Polyclinic/Polyclinic.Domain/Entities/Patient.cs index cd40dc67c..aab8ee069 100644 --- a/Polyclinic/Polyclinic.Domain/Entities/Patient.cs +++ b/Polyclinic/Polyclinic.Domain/Entities/Patient.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using Polyclinic.Domain.Enums; +using Polyclinic.Domain.Enums; namespace Polyclinic.Domain.Entities; diff --git a/Polyclinic/Polyclinic.Domain/Entities/Specialization.cs b/Polyclinic/Polyclinic.Domain/Entities/Specialization.cs index 9aadf9fda..6f728be3f 100644 --- a/Polyclinic/Polyclinic.Domain/Entities/Specialization.cs +++ b/Polyclinic/Polyclinic.Domain/Entities/Specialization.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Text; -using System.Threading.Tasks; - -namespace Polyclinic.Domain.Entities; +namespace Polyclinic.Domain.Entities; /// /// Специализация врача (справочник) diff --git a/Polyclinic/Polyclinic.Domain/Enums/BloodGroup.cs b/Polyclinic/Polyclinic.Domain/Enums/BloodGroup.cs index 10d251989..f9a6f0722 100644 --- a/Polyclinic/Polyclinic.Domain/Enums/BloodGroup.cs +++ b/Polyclinic/Polyclinic.Domain/Enums/BloodGroup.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Polyclinic.Domain.Enums; +namespace Polyclinic.Domain.Enums; /// /// Группа крови пациента @@ -29,5 +23,5 @@ public enum BloodGroup /// /// Четвертая (AB) /// - AB + Ab } diff --git a/Polyclinic/Polyclinic.Domain/Enums/Gender.cs b/Polyclinic/Polyclinic.Domain/Enums/Gender.cs index 09d9260a7..2f909a5c4 100644 --- a/Polyclinic/Polyclinic.Domain/Enums/Gender.cs +++ b/Polyclinic/Polyclinic.Domain/Enums/Gender.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Polyclinic.Domain.Enums; +namespace Polyclinic.Domain.Enums; /// /// Пол пациента @@ -12,17 +6,17 @@ namespace Polyclinic.Domain.Enums; public enum Gender { /// - /// Мужской + /// Не указано /// - Male, + NotSet, /// - /// Женский + /// Мужской /// - Female, + Male, /// - /// Не указано + /// Женский /// - Other + Female } diff --git a/Polyclinic/Polyclinic.Domain/Enums/RhFactor.cs b/Polyclinic/Polyclinic.Domain/Enums/RhFactor.cs index ed4b1726e..0766c45e3 100644 --- a/Polyclinic/Polyclinic.Domain/Enums/RhFactor.cs +++ b/Polyclinic/Polyclinic.Domain/Enums/RhFactor.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Polyclinic.Domain.Enums; +namespace Polyclinic.Domain.Enums; /// /// Резус-фактор пациента diff --git a/Polyclinic/Polyclinic.Tests/PolyclinicFixture.cs b/Polyclinic/Polyclinic.Tests/PolyclinicFixture.cs index 54e65d018..0dd92b41b 100644 --- a/Polyclinic/Polyclinic.Tests/PolyclinicFixture.cs +++ b/Polyclinic/Polyclinic.Tests/PolyclinicFixture.cs @@ -8,29 +8,11 @@ namespace Polyclinic.Tests; /// public class PolyclinicFixture { - /// - /// Список специализаций - /// public List Specializations { get; } - - /// - /// Список врачей - /// public List Doctors { get; } - - /// - /// Список пациентов - /// public List Patients { get; } - - /// - /// Список записей на прием - /// public List Appointments { get; } - /// - /// Конструктор, инициализирующий тестовые данные - /// public PolyclinicFixture() { Specializations = GetSpecializations(); @@ -42,7 +24,7 @@ public PolyclinicFixture() LinkAppointmentsWithDoctorsAndPatients(); } - private List GetSpecializations() => + private static List GetSpecializations() => [ new() { Id = 1, Name = "Терапевт", Code = "THERAPIST", Description = "Врач общей практики" }, new() { Id = 2, Name = "Хирург", Code = "SURGEON", Description = "Проведение операций" }, @@ -56,14 +38,14 @@ private List GetSpecializations() => new() { Id = 10, Name = "Эндокринолог", Code = "ENDOCRINOLOGIST", Description = "Гормональные нарушения" } ]; - private List GetDoctors() => + private static List GetDoctors() => [ new() { Id = 1, PassportNumber = "4501 123456", FullName = "Иванов Иван Иванович", - BirthYear = 1980, + BirthDate = new DateTime(1980, 5, 15), SpecializationId = 1, ExperienceYears = 15 }, @@ -72,7 +54,7 @@ private List GetDoctors() => Id = 2, PassportNumber = "4502 234567", FullName = "Петров Петр Петрович", - BirthYear = 1975, + BirthDate = new DateTime(1975, 8, 22), SpecializationId = 2, ExperienceYears = 20 }, @@ -81,7 +63,7 @@ private List GetDoctors() => Id = 3, PassportNumber = "4503 345678", FullName = "Сидорова Анна Сергеевна", - BirthYear = 1985, + BirthDate = new DateTime(1985, 3, 10), SpecializationId = 3, ExperienceYears = 12 }, @@ -90,7 +72,7 @@ private List GetDoctors() => Id = 4, PassportNumber = "4504 456789", FullName = "Козлов Дмитрий Николаевич", - BirthYear = 1990, + BirthDate = new DateTime(1990, 11, 30), SpecializationId = 4, ExperienceYears = 8 }, @@ -99,7 +81,7 @@ private List GetDoctors() => Id = 5, PassportNumber = "4505 567890", FullName = "Морозова Елена Владимировна", - BirthYear = 1982, + BirthDate = new DateTime(1982, 7, 18), SpecializationId = 5, ExperienceYears = 14 }, @@ -108,7 +90,7 @@ private List GetDoctors() => Id = 6, PassportNumber = "4506 678901", FullName = "Волков Андрей Игоревич", - BirthYear = 1978, + BirthDate = new DateTime(1978, 9, 25), SpecializationId = 6, ExperienceYears = 18 }, @@ -117,7 +99,7 @@ private List GetDoctors() => Id = 7, PassportNumber = "4507 789012", FullName = "Соколова Татьяна Александровна", - BirthYear = 1988, + BirthDate = new DateTime(1988, 2, 14), SpecializationId = 7, ExperienceYears = 10 }, @@ -126,7 +108,7 @@ private List GetDoctors() => Id = 8, PassportNumber = "4508 890123", FullName = "Лебедев Михаил Сергеевич", - BirthYear = 1992, + BirthDate = new DateTime(1992, 6, 5), SpecializationId = 8, ExperienceYears = 6 }, @@ -135,7 +117,7 @@ private List GetDoctors() => Id = 9, PassportNumber = "4509 901234", FullName = "Николаева Ольга Викторовна", - BirthYear = 1983, + BirthDate = new DateTime(1983, 12, 3), SpecializationId = 9, ExperienceYears = 13 }, @@ -144,13 +126,13 @@ private List GetDoctors() => Id = 10, PassportNumber = "4510 012345", FullName = "Федоров Алексей Павлович", - BirthYear = 1970, + BirthDate = new DateTime(1970, 4, 20), SpecializationId = 10, ExperienceYears = 25 } ]; - private List GetPatients() => + private static List GetPatients() => [ new() { @@ -196,7 +178,7 @@ private List GetPatients() => Gender = Gender.Female, BirthDate = new DateTime(1995, 11, 30), Address = "ул. Советская, д. 8, кв. 42", - BloodGroup = BloodGroup.AB, + BloodGroup = BloodGroup.Ab, RhFactor = RhFactor.Positive, PhoneNumber = "+7 (999) 456-78-90" }, @@ -244,7 +226,7 @@ private List GetPatients() => Gender = Gender.Female, BirthDate = new DateTime(1992, 6, 5), Address = "ул. Садовая, д. 7, кв. 31", - BloodGroup = BloodGroup.AB, + BloodGroup = BloodGroup.Ab, RhFactor = RhFactor.Negative, PhoneNumber = "+7 (999) 890-12-34" }, @@ -292,13 +274,13 @@ private List GetPatients() => Gender = Gender.Male, BirthDate = new DateTime(1983, 9, 12), Address = "ул. Лермонтова, д. 9, кв. 14", - BloodGroup = BloodGroup.AB, + BloodGroup = BloodGroup.Ab, RhFactor = RhFactor.Negative, PhoneNumber = "+7 (999) 234-67-89" } ]; - private List GetAppointments() + private static List GetAppointments() { var appointments = new List(); var appointmentId = 1; @@ -309,7 +291,7 @@ private List GetAppointments() { Id = appointmentId++, AppointmentDateTime = new DateTime(2026, 2, 5, 10, 0, 0), - RoomNumber = TestConstants.TherapyRoom, + RoomNumber = "101", IsRepeat = false, PatientId = 1, DoctorId = 1 @@ -318,7 +300,7 @@ private List GetAppointments() { Id = appointmentId++, AppointmentDateTime = new DateTime(2026, 2, 5, 11, 0, 0), - RoomNumber = TestConstants.TherapyRoom, + RoomNumber = "101", IsRepeat = true, PatientId = 2, DoctorId = 1 @@ -327,7 +309,7 @@ private List GetAppointments() { Id = appointmentId++, AppointmentDateTime = new DateTime(2026, 2, 10, 14, 30, 0), - RoomNumber = TestConstants.SurgeryRoom, + RoomNumber = "202", IsRepeat = false, PatientId = 3, DoctorId = 2 @@ -336,7 +318,7 @@ private List GetAppointments() { Id = appointmentId++, AppointmentDateTime = new DateTime(2026, 2, 15, 9, 15, 0), - RoomNumber = TestConstants.CardiologyRoom, + RoomNumber = "303", IsRepeat = false, PatientId = 4, DoctorId = 3 @@ -345,7 +327,7 @@ private List GetAppointments() { Id = appointmentId++, AppointmentDateTime = new DateTime(2026, 2, 12, 13, 30, 0), - RoomNumber = TestConstants.TherapyRoom, + RoomNumber = "101", IsRepeat = false, PatientId = 8, DoctorId = 1 @@ -354,7 +336,7 @@ private List GetAppointments() { Id = appointmentId++, AppointmentDateTime = new DateTime(2026, 2, 16, 9, 30, 0), - RoomNumber = TestConstants.TherapyRoom, + RoomNumber = "101", IsRepeat = false, PatientId = 11, DoctorId = 1 @@ -367,7 +349,7 @@ private List GetAppointments() { Id = appointmentId++, AppointmentDateTime = new DateTime(2026, 1, 15, 10, 0, 0), - RoomNumber = TestConstants.TherapyRoom, + RoomNumber = "101", IsRepeat = true, PatientId = 6, DoctorId = 2 @@ -376,7 +358,7 @@ private List GetAppointments() { Id = appointmentId++, AppointmentDateTime = new DateTime(2026, 1, 20, 11, 0, 0), - RoomNumber = TestConstants.SurgeryRoom, + RoomNumber = "202", IsRepeat = true, PatientId = 7, DoctorId = 2 @@ -385,7 +367,7 @@ private List GetAppointments() { Id = appointmentId++, AppointmentDateTime = new DateTime(2026, 1, 5, 9, 0, 0), - RoomNumber = TestConstants.CardiologyRoom, + RoomNumber = "303", IsRepeat = false, PatientId = 8, DoctorId = 3 diff --git a/Polyclinic/Polyclinic.Tests/PolyclinicTests.cs b/Polyclinic/Polyclinic.Tests/PolyclinicTests.cs index 4eee79fa9..d9c3a412e 100644 --- a/Polyclinic/Polyclinic.Tests/PolyclinicTests.cs +++ b/Polyclinic/Polyclinic.Tests/PolyclinicTests.cs @@ -1,6 +1,4 @@ -using Polyclinic.Domain.Entities; - -namespace Polyclinic.Tests; +namespace Polyclinic.Tests; /// /// Тесты для поликлиники с использованием фикстуры