Compare commits

...

36 Commits

Author SHA1 Message Date
e61e753300 Связи. 2024-12-09 23:59:28 +04:00
2f7e26689d Доделал тесты 2024-12-09 23:46:32 +04:00
3eff31e7b3 Фух, ui тесты заработали 2024-12-08 23:01:23 +04:00
6715396027 Осталось сделать только тестирование 2024-12-08 20:28:54 +04:00
61311886a1 Диалоговое окно для сотрудинка так-же создано. 2024-12-08 18:05:34 +04:00
66c0dcc6c6 Добавлено окно для excel 2024-12-08 18:01:44 +04:00
e61e11a192 Отчет для зарплат. 2024-12-08 17:52:25 +04:00
c36d12c9dd Формируется отчет для сотрудников 2024-12-08 17:27:48 +04:00
f8e8a0cc2b Фух, доделал...
Остались лабы и отчеты
2024-12-08 00:41:13 +04:00
5389b63b05 Фух, осталось только на ввод правила поставить 2024-12-07 23:59:01 +04:00
69726bde25 Сделал половину дезигн изменений 2024-12-07 23:36:29 +04:00
7b0a8dd3d6 Добавил обраотку полей для добавление физ.лица, осталось куча всего этого перекинуть на остольные поля. 2024-12-03 01:30:30 +04:00
206ffc4c76 Чуть-чуть подонал поля 2024-12-03 00:16:38 +04:00
f5f36425c0 Добавил просмотр для сотрудников и прочее. Остался фулл дезигн и делать 6 лабу 2024-12-02 23:48:58 +04:00
b83fcba0aa Удаление возможности редактирование привязки сотрудника 2024-12-02 23:23:57 +04:00
22b0af7ad5 Сделано редактирование, но с плохим дизайном 2024-12-01 18:08:18 +04:00
1c04d20d13 Сделано удаление и почти редактирование 2024-12-01 17:32:41 +04:00
41e4e00fd2 Добавление запрлпаты и отпусков 2024-12-01 17:14:10 +04:00
1cca9432eb Добавил куча окон для CRUD зарплат и отпусков 2024-12-01 16:34:36 +04:00
eaf9cdb71d Добавление экранов менеджеров для Salary и Vacation 2024-12-01 16:19:48 +04:00
c228db433f Весь CRUD добавлен для сотрудника добавлен. 2024-12-01 15:51:49 +04:00
bdf3269ea7 Удаление готово 2024-12-01 15:27:38 +04:00
8b68e2c7ec Добавление страничек. Работает добавление сотрудников 2024-12-01 15:14:20 +04:00
e2c838da47 Добавление логики и контрактов 2024-12-01 14:29:10 +04:00
a2631c83cb Ну вроде бы блок физ.лица сделал 2024-11-30 18:09:32 +04:00
a3dda6e679 Туда сюда пару пикселей, чисто дезигн 2024-11-30 17:27:32 +04:00
f063934489 Ура, нормально работает выдление. Осталось анимацию сделать. 2024-11-30 16:48:09 +04:00
43903ceb95 Доделал поиск. Мб по коду, но так то работает. 2024-11-30 16:06:37 +04:00
7db0881977 Теперь в редактирование норм выводит ФИО + др 2024-11-30 15:44:45 +04:00
d299dc1a45 Почти доделал модуль. Надо его просто допилить 2024-11-30 15:36:29 +04:00
94277268fd Мини изменение на отображение на поверхности. 2024-11-27 01:24:40 +04:00
af01b18e80 Подправил чуть-чуть дезигн. Наврное, надо уже другое релизовывать. 2024-11-27 01:21:37 +04:00
74f1fda7c7 Исправил нажатие кнопки. 2024-11-26 22:52:43 +04:00
ca42b880f1 Теперь работает переключение между страницами и добавление физического лица. 2024-11-26 22:35:12 +04:00
4b004a2628 Ох уж эти ошибки в VisualStudio... 2024-11-26 21:24:08 +04:00
Sosees04ka
7847a4e41a Добавил файлы. Сделал миграцию. 2024-11-13 14:41:01 +04:00
104 changed files with 8010 additions and 454 deletions

View File

@ -11,7 +11,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EmployeeManagmentBusinessLo
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EmployeeManagmentDataModels", "EmployeeManagmentDataModels\EmployeeManagmentDataModels.csproj", "{C5293211-E924-4CFA-9DE5-69003D8C9F48}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EmployeeManagmentDataModels", "EmployeeManagmentDataModels\EmployeeManagmentDataModels.csproj", "{C5293211-E924-4CFA-9DE5-69003D8C9F48}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmployeeManagmentDataBaseImplement", "EmployeeManagmentDataBaseImplement\EmployeeManagmentDataBaseImplement.csproj", "{18CB8173-C3E1-4655-A453-A48F20E1DF2E}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EmployeeManagmentDataBaseImplement", "EmployeeManagmentDataBaseImplement\EmployeeManagmentDataBaseImplement.csproj", "{18CB8173-C3E1-4655-A453-A48F20E1DF2E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmployeeManagmentTests", "EmployeeManagmentTests\EmployeeManagmentTests.csproj", "{6C2F1F37-B54C-493D-82DC-70561145CF49}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -39,6 +41,10 @@ Global
{18CB8173-C3E1-4655-A453-A48F20E1DF2E}.Debug|Any CPU.Build.0 = Debug|Any CPU {18CB8173-C3E1-4655-A453-A48F20E1DF2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18CB8173-C3E1-4655-A453-A48F20E1DF2E}.Release|Any CPU.ActiveCfg = Release|Any CPU {18CB8173-C3E1-4655-A453-A48F20E1DF2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18CB8173-C3E1-4655-A453-A48F20E1DF2E}.Release|Any CPU.Build.0 = Release|Any CPU {18CB8173-C3E1-4655-A453-A48F20E1DF2E}.Release|Any CPU.Build.0 = Release|Any CPU
{6C2F1F37-B54C-493D-82DC-70561145CF49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C2F1F37-B54C-493D-82DC-70561145CF49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C2F1F37-B54C-493D-82DC-70561145CF49}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C2F1F37-B54C-493D-82DC-70561145CF49}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -1,31 +1,67 @@
using EmployeeManagmentContracts.BindingModels; using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.SearchModels; using EmployeeManagmentContracts.SearchModels;
using EmployeeManagmentContracts.StoragesContracts; using EmployeeManagmentContracts.StoragesContracts;
using EmployeeManagmentContracts.ViewModels; using EmployeeManagmentContracts.ViewModels;
using Microsoft.Extensions.Logging;
namespace EmployeeManagmentBusinessLogic.BusinessLogic namespace EmployeeManagmentBusinessLogic.BusinessLogic
{ {
public class EmployeeLogic : IEmployeeLogic public class EmployeeLogic : IEmployeeLogic
{ {
public void CreateOrUpdate(EmployeeBindingModel model) private readonly ILogger<EmployeeLogic> _logger;
private readonly IEmployeeStorage _employeeStorage;
public EmployeeLogic(ILogger<EmployeeLogic> logger, IEmployeeStorage employeeStorage)
{ {
throw new NotImplementedException(); _logger = logger;
_employeeStorage = employeeStorage;
}
public List<EmployeeViewModel> GetFullList()
{
return _employeeStorage.GetFullList();
}
public List<EmployeeViewModel> GetFilteredList(EmployeeSearchModel model)
{
return _employeeStorage.GetFilteredList(model);
}
public EmployeeViewModel? GetElement(int id)
{
return _employeeStorage.GetElement(id);
}
public void Insert(EmployeeViewModel model)
{
if (string.IsNullOrWhiteSpace(model.NameJob))
{
throw new ArgumentException("Название должности обязательно для заполнения.");
}
_employeeStorage.Insert(model);
}
public void Update(EmployeeViewModel model)
{
var element = _employeeStorage.GetElement(model.Id);
if (element == null)
{
throw new ArgumentException("Сотрудник не найден.");
}
_employeeStorage.Update(model);
} }
public void Delete(int id) public void Delete(int id)
{ {
throw new NotImplementedException(); var element = _employeeStorage.GetElement(id);
} if (element == null)
{
throw new ArgumentException("Сотрудник не найден.");
}
public EmployeeViewModel? GetEmployeeById(int id) _employeeStorage.Delete(id);
{
throw new NotImplementedException();
}
public List<EmployeeViewModel> GetEmployees(EmployeeSearchModel model)
{
throw new NotImplementedException();
} }
} }
} }

View File

@ -2,34 +2,75 @@
using EmployeeManagmentContracts.BusinessLogicContracts; using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.SearchModels; using EmployeeManagmentContracts.SearchModels;
using EmployeeManagmentContracts.ViewModels; using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentDataBaseImplement.Models;
using EmployeeManagmentDataBaseImplement;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using EmployeeManagmentContracts.StoragesContracts;
using Microsoft.Extensions.Logging;
using EmployeeManagmentDataBaseImplement.Implements;
namespace EmployeeManagmentBusinessLogic.BusinessLogic namespace EmployeeManagmentBusinessLogic.BusinessLogic
{ {
public class PhisicalPersonLogic : IPhisicalPersonLogic public class PhisicalPersonLogic : IPhisicalPersonLogic
{ {
public void CreateOrUpdate(PhisicalPersonBindingModel model) private readonly ILogger<PhisicalPersonLogic> _logger;
private readonly IPhisicalPersonStorage _phisicalPersonStorage;
public PhisicalPersonLogic(ILogger<PhisicalPersonLogic> logger, IPhisicalPersonStorage phisicalPersonStorage)
{ {
throw new NotImplementedException(); _logger = logger;
_phisicalPersonStorage = phisicalPersonStorage;
}
public List<PhisicalPersonViewModel> GetFullList()
{
return _phisicalPersonStorage.GetFullList();
}
public List<PhisicalPersonViewModel> GetFilteredList(PhisicalPersonSearchModel model)
{
return _phisicalPersonStorage.GetFilteredList(model);
}
public PhisicalPersonViewModel? GetElement(int id)
{
return _phisicalPersonStorage.GetElement(id);
}
public void Insert(PhisicalPersonViewModel model)
{
if (string.IsNullOrWhiteSpace(model.Name) || string.IsNullOrWhiteSpace(model.Surname))
{
throw new ArgumentException("Имя и фамилия обязательны для заполнения.");
}
_phisicalPersonStorage.Insert(model);
}
public void Update(PhisicalPersonViewModel model)
{
var element = _phisicalPersonStorage.GetElement(model.Id);
if (element == null)
{
throw new ArgumentException("Элемент не найден.");
}
_phisicalPersonStorage.Update(model);
} }
public void Delete(int id) public void Delete(int id)
{ {
throw new NotImplementedException(); var element = _phisicalPersonStorage.GetElement(id);
} if (element == null)
{
throw new ArgumentException("Элемент не найден.");
}
public PhisicalPersonViewModel? GetPhisicalPersonById(int id) _phisicalPersonStorage.Delete(id);
{
throw new NotImplementedException();
}
public List<PhisicalPersonViewModel> GetPhisicalPersons(PhisicalPersonSearchModel model)
{
throw new NotImplementedException();
} }
} }
} }

View File

@ -1,31 +1,69 @@
using EmployeeManagmentContracts.BindingModels; using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.SearchModels; using EmployeeManagmentContracts.SearchModels;
using EmployeeManagmentContracts.StoragesContracts;
using EmployeeManagmentContracts.ViewModels; using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentContracts.StoragesContracts;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
namespace EmployeeManagmentBusinessLogic.BusinessLogic namespace EmployeeManagmentBusinessLogic.BusinessLogic
{ {
public class SalaryLogic : ISalaryLogic public class SalaryLogic : ISalaryLogic
{ {
public void CreateOrUpdate(SalaryBindingModel model) private readonly ILogger<SalaryLogic> _logger;
private readonly ISalaryStorage _salaryStorage;
public SalaryLogic(ILogger<SalaryLogic> logger, ISalaryStorage salaryStorage)
{ {
throw new NotImplementedException(); _logger = logger;
_salaryStorage = salaryStorage;
}
public List<SalaryViewModel> GetFullList()
{
return _salaryStorage.GetFullList();
}
public List<SalaryViewModel> GetFilteredList(SalarySearchModel model)
{
return _salaryStorage.GetFilteredList(model);
}
public SalaryViewModel? GetElement(int id)
{
return _salaryStorage.GetElement(id);
}
public void Insert(SalaryViewModel model)
{
if (model.EmployeeId == null)
{
throw new ArgumentException("Сотрудник обязательно должен быть указан.");
}
_salaryStorage.Insert(model);
}
public void Update(SalaryViewModel model)
{
var element = _salaryStorage.GetElement(model.Id);
if (element == null)
{
throw new ArgumentException("Зарплата не найдена.");
}
_salaryStorage.Update(model);
} }
public void Delete(int id) public void Delete(int id)
{ {
throw new NotImplementedException(); var element = _salaryStorage.GetElement(id);
} if (element == null)
{
throw new ArgumentException("Зарплата не найдена.");
}
public List<SalaryViewModel> GetSalaries(SalarySearchModel model) _salaryStorage.Delete(id);
{
throw new NotImplementedException();
}
public SalaryViewModel? GetSalaryById(int id)
{
throw new NotImplementedException();
} }
} }
} }

View File

@ -1,31 +1,69 @@
using EmployeeManagmentContracts.BindingModels; using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.SearchModels; using EmployeeManagmentContracts.SearchModels;
using EmployeeManagmentContracts.StoragesContracts;
using EmployeeManagmentContracts.ViewModels; using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentContracts.StoragesContracts;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
namespace EmployeeManagmentBusinessLogic.BusinessLogic namespace EmployeeManagmentBusinessLogic.BusinessLogic
{ {
public class VacationLogic : IVacationLogic public class VacationLogic : IVacationLogic
{ {
public void CreateOrUpdate(VacationBindingModel model) private readonly ILogger<VacationLogic> _logger;
private readonly IVacationStorage _vacationStorage;
public VacationLogic(ILogger<VacationLogic> logger, IVacationStorage vacationStorage)
{ {
throw new NotImplementedException(); _logger = logger;
_vacationStorage = vacationStorage;
}
public List<VacationViewModel> GetFullList()
{
return _vacationStorage.GetFullList();
}
public List<VacationViewModel> GetFilteredList(VacationSearchModel model)
{
return _vacationStorage.GetFilteredList(model);
}
public VacationViewModel? GetElement(int id)
{
return _vacationStorage.GetElement(id);
}
public void Insert(VacationViewModel model)
{
if (model.EmployeeId == null)
{
throw new ArgumentException("Сотрудник обязательно должен быть указан.");
}
_vacationStorage.Insert(model);
}
public void Update(VacationViewModel model)
{
var element = _vacationStorage.GetElement(model.Id);
if (element == null)
{
throw new ArgumentException("Отпуск не найден.");
}
_vacationStorage.Update(model);
} }
public void Delete(int id) public void Delete(int id)
{ {
throw new NotImplementedException(); var element = _vacationStorage.GetElement(id);
} if (element == null)
{
throw new ArgumentException("Отпуск не найден.");
}
public VacationViewModel? GetVacationById(int id) _vacationStorage.Delete(id);
{
throw new NotImplementedException();
}
public List<VacationViewModel> GetVacations(VacationSearchModel model)
{
throw new NotImplementedException();
} }
} }
} }

View File

@ -8,6 +8,22 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\EmployeeManagmentContracts\EmployeeManagmentContracts.csproj" /> <ProjectReference Include="..\EmployeeManagmentContracts\EmployeeManagmentContracts.csproj" />
<ProjectReference Include="..\EmployeeManagmentDataBaseImplement\EmployeeManagmentDataBaseImplement.csproj" />
<ProjectReference Include="..\EmployeeManagmentDataModels\EmployeeManagmentDataModels.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -14,6 +14,6 @@ namespace EmployeeManagmentContracts.BindingModels
public DateTime? EndJob { get; set; } public DateTime? EndJob { get; set; }
public string? PartTimeJob { get; set; } public string? PartTimeJob { get; set; }
public float Bid { get; set; } public float Bid { get; set; }
public int PhisicalPersonId { get; set; } public int PhisicalPersonsId { get; set; }
} }
} }

View File

@ -11,9 +11,11 @@ namespace EmployeeManagmentContracts.BusinessLogicContracts
{ {
public interface IEmployeeLogic public interface IEmployeeLogic
{ {
List<EmployeeViewModel> GetEmployees(EmployeeSearchModel model); List<EmployeeViewModel> GetFullList();
EmployeeViewModel? GetEmployeeById(int id); List<EmployeeViewModel> GetFilteredList(EmployeeSearchModel model);
void CreateOrUpdate(EmployeeBindingModel model); EmployeeViewModel? GetElement(int id);
void Insert(EmployeeViewModel model);
void Update(EmployeeViewModel model);
void Delete(int id); void Delete(int id);
} }

View File

@ -11,9 +11,11 @@ namespace EmployeeManagmentContracts.BusinessLogicContracts
{ {
public interface IPhisicalPersonLogic public interface IPhisicalPersonLogic
{ {
List<PhisicalPersonViewModel> GetPhisicalPersons(PhisicalPersonSearchModel model); List<PhisicalPersonViewModel> GetFullList();
PhisicalPersonViewModel? GetPhisicalPersonById(int id); List<PhisicalPersonViewModel> GetFilteredList(PhisicalPersonSearchModel model);
void CreateOrUpdate(PhisicalPersonBindingModel model); PhisicalPersonViewModel? GetElement(int id);
void Insert(PhisicalPersonViewModel model);
void Update(PhisicalPersonViewModel model);
void Delete(int id); void Delete(int id);
} }
} }

View File

@ -11,9 +11,11 @@ namespace EmployeeManagmentContracts.BusinessLogicContracts
{ {
public interface ISalaryLogic public interface ISalaryLogic
{ {
List<SalaryViewModel> GetSalaries(SalarySearchModel model); List<SalaryViewModel> GetFullList();
SalaryViewModel? GetSalaryById(int id); List<SalaryViewModel> GetFilteredList(SalarySearchModel model);
void CreateOrUpdate(SalaryBindingModel model); SalaryViewModel? GetElement(int id);
void Insert(SalaryViewModel model);
void Update(SalaryViewModel model);
void Delete(int id); void Delete(int id);
} }

View File

@ -11,9 +11,11 @@ namespace EmployeeManagmentContracts.BusinessLogicContracts
{ {
public interface IVacationLogic public interface IVacationLogic
{ {
List<VacationViewModel> GetVacations(VacationSearchModel model); List<VacationViewModel> GetFullList();
VacationViewModel? GetVacationById(int id); List<VacationViewModel> GetFilteredList(VacationSearchModel model);
void CreateOrUpdate(VacationBindingModel model); VacationViewModel? GetElement(int id);
void Insert(VacationViewModel model);
void Update(VacationViewModel model);
void Delete(int id); void Delete(int id);
} }
} }

View File

@ -9,5 +9,19 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\EmployeeManagmentDataModels\EmployeeManagmentDataModels.csproj" /> <ProjectReference Include="..\EmployeeManagmentDataModels\EmployeeManagmentDataModels.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" />
</ItemGroup>
</Project> </Project>

View File

@ -10,11 +10,14 @@ namespace EmployeeManagmentContracts.ViewModels
{ {
public int Id { get; set; } public int Id { get; set; }
public string NameJob { get; set; } = string.Empty; public string NameJob { get; set; } = string.Empty;
public DateTime StartJob { get; set; } public DateTime? StartJob { get; set; }
public DateTime? EndJob { get; set; } public DateTime? EndJob { get; set; }
public string? PartTimeJob { get; set; } public string? PartTimeJob { get; set; }
public float Bid { get; set; } public float Bid { get; set; }
public string PhisicalPersonName { get; set; } = string.Empty; public int? PhysicalPersonsId { get; set; }
public string? PhysicalPersonName { get; set; }
// Новое свойство для отображения комбинированного текста
public string DisplayText => $"{NameJob} ({PhysicalPersonName})";
} }
} }

View File

@ -11,10 +11,17 @@ namespace EmployeeManagmentContracts.ViewModels
public int Id { get; set; } public int Id { get; set; }
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
public string Surname { get; set; } = string.Empty; public string Surname { get; set; } = string.Empty;
public string Patronomic { get; set; } = string.Empty; public string Patronymic { get; set; } = string.Empty;
public DateTime Birthday { get; set; } public DateTime Birthday { get; set; }
public string Gender { get; set; } = string.Empty; public string Gender { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty; public string Address { get; set; } = string.Empty;
public string Telephone { get; set; } = string.Empty; public string Telephone { get; set; } = string.Empty;
// Вычисляемое свойство для полного имени
public string FullName => $"{Surname} {Name} {Patronymic}";
// Вычисляемое свойство для полного имени с датой рождения
public string FullNameWithBirthday => $"{Surname} {Name} {Patronymic} ({Birthday:dd.MM.yyyy})";
} }
} }

View File

@ -14,6 +14,16 @@ namespace EmployeeManagmentContracts.ViewModels
public float? Premium { get; set; } public float? Premium { get; set; }
public DateTime? Date { get; set; } public DateTime? Date { get; set; }
public bool Passed { get; set; } public bool Passed { get; set; }
public string EmployeeName { get; set; } = string.Empty;
public int? EmployeeId { get; set; }
public string? EmployeeName { get; set; } = string.Empty;
public string DisplayName
{
get
{
return $"{EmployeeName} ({Date:dd.MM.yyyy})";
}
}
} }
} }

View File

@ -12,6 +12,17 @@ namespace EmployeeManagmentContracts.ViewModels
public DateTime StartData { get; set; } public DateTime StartData { get; set; }
public DateTime EndData { get; set; } public DateTime EndData { get; set; }
public bool Passed { get; set; } public bool Passed { get; set; }
public string EmployeeName { get; set; } = string.Empty; public int? EmployeeId { get; set; }
public string? EmployeeName { get; set; } = string.Empty;
public string DisplayName
{
get
{
return $"{EmployeeName} ({StartData:dd.MM.yyyy} - {EndData:dd.MM.yyyy})";
}
}
} }
} }

View File

@ -1,23 +1,24 @@
using EmployeeManagmentDataBaseImplement.Models; using EmployeeManagmentDataBaseImplement.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataBaseImplement namespace EmployeeManagmentDataBaseImplement
{ {
public class EmployeeManagementDbContext : DbContext public class EmployeeManagementDbContext : DbContext
{ {
public DbSet<Employee> Employees { get; set; } // DbSets для моделей
public DbSet<PhisicalPerson> PhisicalPersons { get; set; } public virtual DbSet<Employee> Employees { get; set; }
public DbSet<Salary> Salaries { get; set; } public virtual DbSet<PhisicalPerson> PhysicalPersons { get; set; }
public DbSet<Vacation> Vacations { get; set; } public virtual DbSet<Salary> Salaries { get; set; }
public virtual DbSet<Vacation> Vacations { get; set; }
// Метод для настройки конфигурации
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {
optionsBuilder.UseSqlServer("YourConnectionStringHere"); if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseNpgsql("Host=localhost;Database=EmployeeManagementDB;Username=postgres;Password=23859");
}
base.OnConfiguring(optionsBuilder);
} }
} }
} }

View File

@ -9,24 +9,21 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\EmployeeManagmentContracts\EmployeeManagmentContracts.csproj" /> <ProjectReference Include="..\EmployeeManagmentContracts\EmployeeManagmentContracts.csproj" />
<ProjectReference Include="..\EmployeeManagmentDataModels\EmployeeManagmentDataModels.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -7,34 +7,130 @@ namespace EmployeeManagmentDataBaseImplement.Implements
{ {
public class EmployeeStorage : IEmployeeStorage public class EmployeeStorage : IEmployeeStorage
{ {
public void Delete(int id) // Получить полный список сотрудников
{
throw new NotImplementedException();
}
public EmployeeViewModel? GetElement(int id)
{
throw new NotImplementedException();
}
public List<EmployeeViewModel> GetFilteredList(EmployeeSearchModel model)
{
throw new NotImplementedException();
}
public List<EmployeeViewModel> GetFullList() public List<EmployeeViewModel> GetFullList()
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
return context.Employees
.Select(e => new EmployeeViewModel
{
Id = e.Id,
NameJob = e.NameJob,
StartJob = e.StartJob,
EndJob = e.EndJob,
PartTimeJob = e.PartTimeJob,
Bid = e.Bid,
PhysicalPersonsId = e.PhisicalPersonsId,
PhysicalPersonName = $"{e.PhisicalPerson.Surname} {e.PhisicalPerson.Name} {e.PhisicalPerson.Patronymic} "
})
.ToList();
} }
// Получить отфильтрованный список сотрудников
public List<EmployeeViewModel> GetFilteredList(EmployeeSearchModel model)
{
using var context = new EmployeeManagementDbContext();
if (model == null) return new List<EmployeeViewModel>();
return context.Employees
.Where(e =>
(string.IsNullOrEmpty(model.NameJob) || e.NameJob.Contains(model.NameJob)) &&
(!model.StartDateFrom.HasValue || e.StartJob >= model.StartDateFrom) &&
(!model.StartDateTo.HasValue || e.EndJob <= model.StartDateTo))
.Select(e => new EmployeeViewModel
{
Id = e.Id,
NameJob = e.NameJob,
StartJob = e.StartJob,
EndJob = e.EndJob,
PartTimeJob = e.PartTimeJob,
Bid = e.Bid,
PhysicalPersonsId = e.PhisicalPersonsId,
PhysicalPersonName = $"{e.PhisicalPerson.Surname} {e.PhisicalPerson.Name} {e.PhisicalPerson.Patronymic}",
})
.ToList();
}
// Получить сотрудника по ID
public EmployeeViewModel? GetElement(int id)
{
using var context = new EmployeeManagementDbContext();
var entity = context.Employees
.FirstOrDefault(e => e.Id == id);
return entity == null ? null : new EmployeeViewModel
{
Id = entity.Id,
NameJob = entity.NameJob,
StartJob = entity.StartJob,
EndJob = entity.EndJob,
PartTimeJob = entity.PartTimeJob,
Bid = entity.Bid,
PhysicalPersonsId = entity.PhisicalPersonsId,
PhysicalPersonName = entity.PhisicalPerson != null
? $"{entity.PhisicalPerson.Surname} {entity.PhisicalPerson.Name} {entity.PhisicalPerson.Patronymic} "
: "Не указано" // Обработка отсутствующего физического лица
};
}
// Добавить нового сотрудника
public void Insert(EmployeeViewModel model) public void Insert(EmployeeViewModel model)
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
var newEmployee = new Employee
{
NameJob = model.NameJob,
StartJob = model.StartJob,
EndJob = model.EndJob,
PartTimeJob = model.PartTimeJob,
Bid = model.Bid,
PhisicalPersonsId = model.PhysicalPersonsId
};
context.Employees.Add(newEmployee);
context.SaveChanges();
} }
// Обновить сотрудника
public void Update(EmployeeViewModel model) public void Update(EmployeeViewModel model)
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
var entity = context.Employees.FirstOrDefault(e => e.Id == model.Id);
if (entity != null)
{
entity.NameJob = model.NameJob;
entity.StartJob = model.StartJob;
entity.EndJob = model.EndJob;
entity.PartTimeJob = model.PartTimeJob;
entity.Bid = model.Bid;
entity.PhisicalPersonsId = model.PhysicalPersonsId;
context.SaveChanges();
}
} }
// Удалить сотрудника
public void Delete(int id)
{
using var context = new EmployeeManagementDbContext();
var entity = context.Employees.FirstOrDefault(e => e.Id == id);
if (entity != null)
{
// Убедимся, что связи остаются нетронутыми
entity.PhisicalPersonsId = null; // Удаляем связь, если это нужно
context.Employees.Remove(entity);
context.SaveChanges();
}
}
} }
} }

View File

@ -2,6 +2,7 @@
using EmployeeManagmentContracts.SearchModels; using EmployeeManagmentContracts.SearchModels;
using EmployeeManagmentContracts.StoragesContracts; using EmployeeManagmentContracts.StoragesContracts;
using EmployeeManagmentContracts.ViewModels; using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentDataBaseImplement.Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -12,34 +13,117 @@ namespace EmployeeManagmentDataBaseImplement.Implements
{ {
public class PhisicalPersonStorage : IPhisicalPersonStorage public class PhisicalPersonStorage : IPhisicalPersonStorage
{ {
public void Delete(int id) // Метод для получения полного списка
{
throw new NotImplementedException();
}
public PhisicalPersonViewModel? GetElement(int id)
{
throw new NotImplementedException();
}
public List<PhisicalPersonViewModel> GetFilteredList(PhisicalPersonSearchModel model)
{
throw new NotImplementedException();
}
public List<PhisicalPersonViewModel> GetFullList() public List<PhisicalPersonViewModel> GetFullList()
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
return context.PhysicalPersons
.Select(p => new PhisicalPersonViewModel
{
Id = p.Id,
Name = p.Name,
Surname = p.Surname,
Patronymic = p.Patronymic,
Birthday = p.Birthday,
Gender = p.Gender,
Address = p.Address,
Telephone = p.Telephone
}).ToList();
} }
// Метод для получения отфильтрованного списка
public List<PhisicalPersonViewModel> GetFilteredList(PhisicalPersonSearchModel model)
{
using var context = new EmployeeManagementDbContext();
if (model == null) return new List<PhisicalPersonViewModel>();
return context.PhysicalPersons
.Where(p => p.Surname.Contains(model.Surname ?? string.Empty))
.Select(p => new PhisicalPersonViewModel
{
Id = p.Id,
Name = p.Name,
Surname = p.Surname,
Patronymic = p.Patronymic,
Birthday = p.Birthday,
Gender = p.Gender,
Address = p.Address,
Telephone = p.Telephone
}).ToList();
}
// Метод для получения одного элемента по ID
public PhisicalPersonViewModel? GetElement(int id)
{
using var context = new EmployeeManagementDbContext();
var entity = context.PhysicalPersons.FirstOrDefault(p => p.Id == id);
return entity == null ? null : new PhisicalPersonViewModel
{
Id = entity.Id,
Name = entity.Name,
Surname = entity.Surname,
Patronymic = entity.Patronymic,
Birthday = entity.Birthday,
Gender = entity.Gender,
Address = entity.Address,
Telephone = entity.Telephone
};
}
// Метод для добавления нового физического лица
public void Insert(PhisicalPersonViewModel model) public void Insert(PhisicalPersonViewModel model)
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
var newPerson = new PhisicalPerson
{
Name = model.Name,
Surname = model.Surname,
Patronymic = model.Patronymic,
Birthday = model.Birthday,
Gender = model.Gender,
Address = model.Address,
Telephone = model.Telephone
};
context.PhysicalPersons.Add(newPerson);
context.SaveChanges();
} }
// Метод для обновления физического лица
public void Update(PhisicalPersonViewModel model) public void Update(PhisicalPersonViewModel model)
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
var entity = context.PhysicalPersons.FirstOrDefault(p => p.Id == model.Id);
if (entity != null)
{
entity.Name = model.Name;
entity.Surname = model.Surname;
entity.Patronymic = model.Patronymic;
entity.Birthday = model.Birthday;
entity.Gender = model.Gender;
entity.Address = model.Address;
entity.Telephone = model.Telephone;
context.SaveChanges();
}
}
// Метод для удаления физического лица
public void Delete(int id)
{
using var context = new EmployeeManagementDbContext();
var entity = context.PhysicalPersons.FirstOrDefault(p => p.Id == id);
if (entity != null)
{
context.PhysicalPersons.Remove(entity);
context.SaveChanges();
}
} }
} }
} }

View File

@ -1,44 +1,125 @@
using EmployeeManagmentContracts.SearchModels; using EmployeeManagmentContracts.SearchModels;
using EmployeeManagmentContracts.StoragesContracts; using EmployeeManagmentContracts.StoragesContracts;
using EmployeeManagmentContracts.ViewModels; using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentDataBaseImplement.Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataBaseImplement.Implements namespace EmployeeManagmentDataBaseImplement.Implements
{ {
public class SalaryStorage : ISalaryStorage public class SalaryStorage : ISalaryStorage
{ {
public void Delete(int id) public List<SalaryViewModel> GetFullList()
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
}
public SalaryViewModel? GetElement(int id) return context.Salaries
{ .Select(s => new SalaryViewModel
throw new NotImplementedException(); {
Id = s.Id,
CountHours = s.CountHours,
PriceHour = s.PriceHour,
Premium = s.Premium,
Date = s.Data,
Passed = s.Passed,
EmployeeId = s.EmployeesId,
EmployeeName = s.Employee != null ? $"{s.Employee.PhisicalPerson.Surname} {s.Employee.PhisicalPerson.Name} {s.Employee.PhisicalPerson.Patronymic} ({s.Employee.NameJob})" : "Не указано"
})
.ToList();
} }
public List<SalaryViewModel> GetFilteredList(SalarySearchModel model) public List<SalaryViewModel> GetFilteredList(SalarySearchModel model)
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
if (model == null) return new List<SalaryViewModel>();
return context.Salaries
.Where(s =>
(!model.Date.HasValue || s.Data >= model.Date))
.Select(s => new SalaryViewModel
{
Id = s.Id,
CountHours = s.CountHours,
PriceHour = s.PriceHour,
Premium = s.Premium,
Date = s.Data,
Passed = s.Passed,
EmployeeId = s.EmployeesId,
EmployeeName = s.Employee != null ? $"{s.Employee.PhisicalPerson.Surname} {s.Employee.PhisicalPerson.Name} {s.Employee.PhisicalPerson.Patronymic} ({s.Employee.NameJob})" : "Не указано"
})
.ToList();
} }
public List<SalaryViewModel> GetFullList() public SalaryViewModel? GetElement(int id)
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
var entity = context.Salaries
.FirstOrDefault(s => s.Id == id);
return entity == null ? null : new SalaryViewModel
{
Id = entity.Id,
CountHours = entity.CountHours,
PriceHour = entity.PriceHour,
Premium = entity.Premium,
Date = entity.Data,
Passed = entity.Passed,
EmployeeId = entity.EmployeesId,
EmployeeName = entity.Employee != null ? $"{entity.Employee.PhisicalPerson.Surname} {entity.Employee.PhisicalPerson.Name} {entity.Employee.PhisicalPerson.Patronymic} ({entity.Employee.NameJob})" : "Не указано"
};
} }
public void Insert(SalaryViewModel model) public void Insert(SalaryViewModel model)
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
var newSalary = new Salary
{
CountHours = model.CountHours,
PriceHour = model.PriceHour,
Premium = model.Premium,
Data = model.Date,
Passed = model.Passed,
EmployeesId = model.EmployeeId
};
context.Salaries.Add(newSalary);
context.SaveChanges();
} }
public void Update(SalaryViewModel model) public void Update(SalaryViewModel model)
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
var entity = context.Salaries.FirstOrDefault(s => s.Id == model.Id);
if (entity != null)
{
entity.CountHours = model.CountHours;
entity.PriceHour = model.PriceHour;
entity.Premium = model.Premium;
entity.Data = model.Date;
entity.Passed = model.Passed;
entity.EmployeesId = model.EmployeeId;
context.SaveChanges();
}
}
public void Delete(int id)
{
using var context = new EmployeeManagementDbContext();
var entity = context.Salaries.FirstOrDefault(s => s.Id == id);
if (entity != null)
{
context.Salaries.Remove(entity);
context.SaveChanges();
}
} }
} }
} }

View File

@ -1,44 +1,117 @@
using EmployeeManagmentContracts.SearchModels; using EmployeeManagmentContracts.SearchModels;
using EmployeeManagmentContracts.StoragesContracts; using EmployeeManagmentContracts.StoragesContracts;
using EmployeeManagmentContracts.ViewModels; using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentDataBaseImplement.Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataBaseImplement.Implements namespace EmployeeManagmentDataBaseImplement.Implements
{ {
public class VacationStorage : ISalaryStorage public class VacationStorage : IVacationStorage
{ {
public List<VacationViewModel> GetFullList()
{
using var context = new EmployeeManagementDbContext();
return context.Vacations
.Select(v => new VacationViewModel
{
Id = v.Id,
StartData = v.StartData,
EndData = v.EndData,
Passed = v.Passed,
EmployeeId = v.EmployeesId,
EmployeeName = v.Employee != null ? $"{v.Employee.PhisicalPerson.Surname} {v.Employee.PhisicalPerson.Name} {v.Employee.PhisicalPerson.Patronymic} ({v.Employee.NameJob})" : "Не указано"
})
.ToList();
}
public List<VacationViewModel> GetFilteredList(VacationSearchModel model)
{
using var context = new EmployeeManagementDbContext();
if (model == null) return new List<VacationViewModel>();
return context.Vacations
.Where(v =>
(!model.StartData.HasValue || v.StartData >= model.StartData) &&
(!model.EndData.HasValue || v.EndData <= model.EndData))
.Select(v => new VacationViewModel
{
Id = v.Id,
StartData = v.StartData,
EndData = v.EndData,
Passed = v.Passed,
EmployeeId = v.EmployeesId,
EmployeeName = v.Employee != null ? $"{v.Employee.PhisicalPerson.Surname} {v.Employee.PhisicalPerson.Name} {v.Employee.PhisicalPerson.Patronymic} ({v.Employee.NameJob})" : "Не указано"
})
.ToList();
}
public VacationViewModel? GetElement(int id)
{
using var context = new EmployeeManagementDbContext();
var entity = context.Vacations
.FirstOrDefault(v => v.Id == id);
return entity == null ? null : new VacationViewModel
{
Id = entity.Id,
StartData = entity.StartData,
EndData = entity.EndData,
Passed = entity.Passed,
EmployeeId = entity.EmployeesId,
EmployeeName = entity.Employee != null ? $"{entity.Employee.PhisicalPerson.Surname} {entity.Employee.PhisicalPerson.Name} {entity.Employee.PhisicalPerson.Patronymic} ({entity.Employee.NameJob})" : "Не указано"
};
}
public void Insert(VacationViewModel model)
{
using var context = new EmployeeManagementDbContext();
var newVacation = new Vacation
{
StartData = model.StartData,
EndData = model.EndData,
Passed = model.Passed,
EmployeesId = model.EmployeeId
};
context.Vacations.Add(newVacation);
context.SaveChanges();
}
public void Update(VacationViewModel model)
{
using var context = new EmployeeManagementDbContext();
var entity = context.Vacations.FirstOrDefault(v => v.Id == model.Id);
if (entity != null)
{
entity.StartData = model.StartData;
entity.EndData = model.EndData;
entity.Passed = model.Passed;
entity.EmployeesId = model.EmployeeId;
context.SaveChanges();
}
}
public void Delete(int id) public void Delete(int id)
{ {
throw new NotImplementedException(); using var context = new EmployeeManagementDbContext();
}
public SalaryViewModel? GetElement(int id) var entity = context.Vacations.FirstOrDefault(v => v.Id == id);
{
throw new NotImplementedException();
}
public List<SalaryViewModel> GetFilteredList(SalarySearchModel model) if (entity != null)
{ {
throw new NotImplementedException(); context.Vacations.Remove(entity);
} context.SaveChanges();
}
public List<SalaryViewModel> GetFullList()
{
throw new NotImplementedException();
}
public void Insert(SalaryViewModel model)
{
throw new NotImplementedException();
}
public void Update(SalaryViewModel model)
{
throw new NotImplementedException();
} }
} }
} }

View File

@ -0,0 +1,202 @@
// <auto-generated />
using System;
using EmployeeManagmentDataBaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace EmployeeManagmentDataBaseImplement.Migrations
{
[DbContext(typeof(EmployeeManagementDbContext))]
[Migration("20241126175607_Init")]
partial class Init
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Employee", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<float>("Bid")
.HasColumnType("real");
b.Property<DateTime?>("EndJob")
.HasColumnType("timestamp with time zone");
b.Property<string>("NameJob")
.IsRequired()
.HasColumnType("text");
b.Property<string>("PartTimeJob")
.HasColumnType("text");
b.Property<int?>("PhisicalPersonsId")
.HasColumnType("integer");
b.Property<DateTime?>("StartJob")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("PhisicalPersonsId");
b.ToTable("Employees");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.PhisicalPerson", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Address")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("Birthday")
.HasColumnType("timestamp with time zone");
b.Property<string>("Gender")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Patronymic")
.HasColumnType("text");
b.Property<string>("Surname")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Telephone")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("PhysicalPersons");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Salary", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("CountHours")
.HasColumnType("integer");
b.Property<DateTime?>("Data")
.HasColumnType("timestamp with time zone");
b.Property<int?>("EmployeesId")
.HasColumnType("integer");
b.Property<bool>("Passed")
.HasColumnType("boolean");
b.Property<float?>("Premium")
.HasColumnType("real");
b.Property<float>("PriceHour")
.HasColumnType("real");
b.HasKey("Id");
b.HasIndex("EmployeesId");
b.ToTable("Salaries");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Vacation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int?>("EmployeesId")
.HasColumnType("integer");
b.Property<DateTime>("EndData")
.HasColumnType("timestamp with time zone");
b.Property<bool>("Passed")
.HasColumnType("boolean");
b.Property<DateTime>("StartData")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("EmployeesId");
b.ToTable("Vacations");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Employee", b =>
{
b.HasOne("EmployeeManagmentDataBaseImplement.Models.PhisicalPerson", "PhisicalPerson")
.WithMany("Employees")
.HasForeignKey("PhisicalPersonsId");
b.Navigation("PhisicalPerson");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Salary", b =>
{
b.HasOne("EmployeeManagmentDataBaseImplement.Models.Employee", "Employee")
.WithMany("Salaries")
.HasForeignKey("EmployeesId");
b.Navigation("Employee");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Vacation", b =>
{
b.HasOne("EmployeeManagmentDataBaseImplement.Models.Employee", "Employee")
.WithMany("Vacations")
.HasForeignKey("EmployeesId");
b.Navigation("Employee");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Employee", b =>
{
b.Navigation("Salaries");
b.Navigation("Vacations");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.PhisicalPerson", b =>
{
b.Navigation("Employees");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,133 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace EmployeeManagmentDataBaseImplement.Migrations
{
/// <inheritdoc />
public partial class Init : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "PhysicalPersons",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false),
Surname = table.Column<string>(type: "text", nullable: false),
Patronymic = table.Column<string>(type: "text", nullable: true),
Birthday = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Gender = table.Column<string>(type: "text", nullable: false),
Address = table.Column<string>(type: "text", nullable: false),
Telephone = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_PhysicalPersons", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Employees",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
NameJob = table.Column<string>(type: "text", nullable: false),
StartJob = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
EndJob = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
PartTimeJob = table.Column<string>(type: "text", nullable: true),
Bid = table.Column<float>(type: "real", nullable: false),
PhisicalPersonsId = table.Column<int>(type: "integer", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Employees", x => x.Id);
table.ForeignKey(
name: "FK_Employees_PhysicalPersons_PhisicalPersonsId",
column: x => x.PhisicalPersonsId,
principalTable: "PhysicalPersons",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "Salaries",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
CountHours = table.Column<int>(type: "integer", nullable: false),
PriceHour = table.Column<float>(type: "real", nullable: false),
Premium = table.Column<float>(type: "real", nullable: true),
Data = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
Passed = table.Column<bool>(type: "boolean", nullable: false),
EmployeesId = table.Column<int>(type: "integer", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Salaries", x => x.Id);
table.ForeignKey(
name: "FK_Salaries_Employees_EmployeesId",
column: x => x.EmployeesId,
principalTable: "Employees",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "Vacations",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
StartData = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
EndData = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Passed = table.Column<bool>(type: "boolean", nullable: false),
EmployeesId = table.Column<int>(type: "integer", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Vacations", x => x.Id);
table.ForeignKey(
name: "FK_Vacations_Employees_EmployeesId",
column: x => x.EmployeesId,
principalTable: "Employees",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_Employees_PhisicalPersonsId",
table: "Employees",
column: "PhisicalPersonsId");
migrationBuilder.CreateIndex(
name: "IX_Salaries_EmployeesId",
table: "Salaries",
column: "EmployeesId");
migrationBuilder.CreateIndex(
name: "IX_Vacations_EmployeesId",
table: "Vacations",
column: "EmployeesId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Salaries");
migrationBuilder.DropTable(
name: "Vacations");
migrationBuilder.DropTable(
name: "Employees");
migrationBuilder.DropTable(
name: "PhysicalPersons");
}
}
}

View File

@ -0,0 +1,199 @@
// <auto-generated />
using System;
using EmployeeManagmentDataBaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace EmployeeManagmentDataBaseImplement.Migrations
{
[DbContext(typeof(EmployeeManagementDbContext))]
partial class EmployeeManagementDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Employee", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<float>("Bid")
.HasColumnType("real");
b.Property<DateTime?>("EndJob")
.HasColumnType("timestamp with time zone");
b.Property<string>("NameJob")
.IsRequired()
.HasColumnType("text");
b.Property<string>("PartTimeJob")
.HasColumnType("text");
b.Property<int?>("PhisicalPersonsId")
.HasColumnType("integer");
b.Property<DateTime?>("StartJob")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("PhisicalPersonsId");
b.ToTable("Employees");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.PhisicalPerson", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Address")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("Birthday")
.HasColumnType("timestamp with time zone");
b.Property<string>("Gender")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Patronymic")
.HasColumnType("text");
b.Property<string>("Surname")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Telephone")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("PhysicalPersons");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Salary", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("CountHours")
.HasColumnType("integer");
b.Property<DateTime?>("Data")
.HasColumnType("timestamp with time zone");
b.Property<int?>("EmployeesId")
.HasColumnType("integer");
b.Property<bool>("Passed")
.HasColumnType("boolean");
b.Property<float?>("Premium")
.HasColumnType("real");
b.Property<float>("PriceHour")
.HasColumnType("real");
b.HasKey("Id");
b.HasIndex("EmployeesId");
b.ToTable("Salaries");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Vacation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int?>("EmployeesId")
.HasColumnType("integer");
b.Property<DateTime>("EndData")
.HasColumnType("timestamp with time zone");
b.Property<bool>("Passed")
.HasColumnType("boolean");
b.Property<DateTime>("StartData")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("EmployeesId");
b.ToTable("Vacations");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Employee", b =>
{
b.HasOne("EmployeeManagmentDataBaseImplement.Models.PhisicalPerson", "PhisicalPerson")
.WithMany("Employees")
.HasForeignKey("PhisicalPersonsId");
b.Navigation("PhisicalPerson");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Salary", b =>
{
b.HasOne("EmployeeManagmentDataBaseImplement.Models.Employee", "Employee")
.WithMany("Salaries")
.HasForeignKey("EmployeesId");
b.Navigation("Employee");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Vacation", b =>
{
b.HasOne("EmployeeManagmentDataBaseImplement.Models.Employee", "Employee")
.WithMany("Vacations")
.HasForeignKey("EmployeesId");
b.Navigation("Employee");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.Employee", b =>
{
b.Navigation("Salaries");
b.Navigation("Vacations");
});
modelBuilder.Entity("EmployeeManagmentDataBaseImplement.Models.PhisicalPerson", b =>
{
b.Navigation("Employees");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,27 +1,29 @@
using System; using EmployeeManagmentDataModels.Models;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
using System.Threading.Tasks;
using EmployeeManagmentDataModels.Models;
namespace EmployeeManagmentDataBaseImplement.Models namespace EmployeeManagmentDataBaseImplement.Models
{ {
public class Employee public class Employee : IEmployee
{ {
[Key] [Key]
public int Id { get; set; } public int Id { get; set; }
[Required] [Required]
public string Name { get; set; } = string.Empty; public string NameJob { get; set; } = string.Empty;
public DateTime? StartJob { get; set; } public DateTime? StartJob { get; set; }
public DateTime? EndJob { get; set; } public DateTime? EndJob { get; set; }
public string? PartTimeJob { get; set; } public string? PartTimeJob { get; set; }
public float Bid { get; set; } public float Bid { get; set; }
[ForeignKey("PhysicalPerson")] [ForeignKey("PhisicalPerson")]
public int PhysicalPersonsId { get; set; } public int? PhisicalPersonsId { get; set; }
public PhysicalPerson? PhysicalPerson { get; set; } public PhisicalPerson? PhisicalPerson { get; set; }
public List<Salary> Salaries { get; set; } = new();
public List<Vacation> Vacations { get; set; } = new();
} }
} }

View File

@ -1,4 +1,5 @@
using System; using EmployeeManagmentDataModels.Models;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
@ -7,21 +8,27 @@ using System.Threading.Tasks;
namespace EmployeeManagmentDataBaseImplement.Models namespace EmployeeManagmentDataBaseImplement.Models
{ {
public class PhisicalPerson public class PhisicalPerson : IPhisicalPerson
{ {
[Key] [Key]
public int Id { get; set; } public int Id { get; set; }
[Required] [Required]
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
[Required] [Required]
public string Surname { get; set; } = string.Empty; public string Surname { get; set; } = string.Empty;
public string? Patronymic { get; set; } public string? Patronymic { get; set; }
[Required]
public DateTime Birthday { get; set; } public DateTime Birthday { get; set; }
[Required]
public string Gender { get; set; } = string.Empty; public string Gender { get; set; } = string.Empty;
[Required]
public string Address { get; set; } = string.Empty; public string Address { get; set; } = string.Empty;
[Required]
public string Telephone { get; set; } = string.Empty; public string Telephone { get; set; } = string.Empty;
// Связь с сотрудниками public List<Employee> Employees { get; set; } = new();
public List<Employee>? Employees { get; set; }
} }
} }

View File

@ -1,12 +1,27 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using EmployeeManagmentDataModels.Models;
namespace EmployeeManagmentDataBaseImplement.Models namespace EmployeeManagmentDataBaseImplement.Models
{ {
public class Salary public class Salary : ISalary
{ {
[Key]
public int Id { get; set; }
public int CountHours { get; set; }
public float PriceHour { get; set; }
public float? Premium { get; set; }
public DateTime? Data { get; set; }
public bool Passed { get; set; }
[ForeignKey("Employee")]
public int? EmployeesId { get; set; }
public Employee? Employee { get; set; }
} }
} }

View File

@ -1,12 +1,25 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using EmployeeManagmentDataModels.Models;
namespace EmployeeManagmentDataBaseImplement.Models namespace EmployeeManagmentDataBaseImplement.Models
{ {
public class Vacation public class Vacation : IVacation
{ {
[Key]
public int Id { get; set; }
public DateTime StartData { get; set; }
public DateTime EndData { get; set; }
public bool Passed { get; set; }
[ForeignKey("Employee")]
public int? EmployeesId { get; set; }
public Employee? Employee { get; set; }
} }
} }

View File

@ -1,18 +1,23 @@
version: '3.9' version: '3.9'
services: services:
sqlserver-db: mysql:
image: mcr.microsoft.com/mssql/server:2022-latest image: mysql:8.0
container_name: sqlserver-db container_name: employee_db
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=YourStrong@Password123
- MSSQL_PID=Express
ports:
- "1433:1433"
volumes:
- sql_data:/var/opt/mssql
restart: always restart: always
environment:
MYSQL_ROOT_PASSWORD: SuperSecretPasswork2003
MYSQL_DATABASE: EmployeeDB
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
networks:
- employee_network
volumes: volumes:
sql_data: mysql_data:
networks:
employee_network:
driver: bridge

View File

@ -5,5 +5,21 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" />
<PackageReference Include="PresentationFramework" Version="4.6.0" />
</ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using System.Windows.Data;
namespace EmployeeManagmentDataModels.Enums
{
public class BooleanToSalaryConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool booleanValue)
{
return booleanValue ? "Заплачено" : "Не заплачено";
}
return "Неизвестно";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException("Обратное преобразование не поддерживается.");
}
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace EmployeeManagmentDataModels.Enums
{
public class BooleanToVacationConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool booleanValue)
{
return booleanValue ? "Завершен" : "Не завершено";
}
return "Неизвестно";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException("Обратное преобразование не поддерживается.");
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataModels.Enums
{
public enum GenderType
{
Мужчина,
Женщина
}
}

View File

@ -1,25 +0,0 @@
using EmployeeManagmentDataModels.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataModels.Models
{
public class Employee
{
public int Id { get; set; }
public string NameJob { get; set; } = string.Empty;
public DateTime StartJob { get; set; }
public DateTime? EndJob { get; set; }
public JobType PartTimeJob { get; set; }
public decimal Bid { get; set; } // Ставка
public int PhysicalPersonId { get; set; }
// Связь с физическим лицом
public PhysicalPerson? PhysicalPerson { get; set; }
public List<Salary>? Salaries { get; set; }
public List<Vacation>? Vacations { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using EmployeeManagmentDataModels.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataModels.Models
{
public interface IEmployee
{
int Id { get; set; }
string NameJob { get; set; }
DateTime? StartJob { get; set; }
DateTime? EndJob { get; set; }
string? PartTimeJob { get; set; }
float Bid { get; set; }
int? PhisicalPersonsId { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataModels.Models
{
public interface IPhisicalPerson
{
int Id { get; set; }
string Name { get; set; }
string Surname { get; set; }
string? Patronymic { get; set; }
DateTime Birthday { get; set; }
string Gender { get; set; }
string Address { get; set; }
string Telephone { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataModels.Models
{
public interface ISalary
{
int Id { get; set; }
int CountHours { get; set; }
float PriceHour { get; set; }
float? Premium { get; set; }
DateTime? Data { get; set; }
bool Passed { get; set; }
int? EmployeesId { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using EmployeeManagmentDataModels.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataModels.Models
{
public interface IVacation
{
int Id { get; set; }
DateTime StartData { get; set; }
DateTime EndData { get; set; }
bool Passed { get; set; }
int? EmployeesId { get; set; }
}
}

View File

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataModels.Models
{
public class PhysicalPerson
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public DateTime BirthDate { get; set; }
public string Address { get; set; } = string.Empty;
// Связь с сотрудниками
public List<Employee>? Employees { get; set; }
}
}

View File

@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataModels.Models
{
public class Salary
{
public int Id { get; set; }
public int CountHours { get; set; }
public decimal PriceHour { get; set; }
public decimal Premium { get; set; }
public DateTime Date { get; set; }
public bool Passed { get; set; }
public int EmployeeId { get; set; }
// Связь с сотрудником
public Employee? Employee { get; set; }
}
}

View File

@ -1,21 +0,0 @@
using EmployeeManagmentDataModels.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagmentDataModels.Models
{
public class Vacation
{
public int Id { get; set; }
public DateTime StartData { get; set; }
public DateTime EndData { get; set; }
public VacationStatus Passed { get; set; }
public int EmployeeId { get; set; }
// Связь с сотрудником
public Employee? Employee { get; set; }
}
}

View File

@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Appium.WebDriver" Version="6.0.1" />
<PackageReference Include="FlaUI.Core" Version="4.0.0" />
<PackageReference Include="FlaUI.UIA3" Version="4.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Microsoft.TestPlatform" Version="17.12.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="MSTest.TestFramework" Version="3.6.3" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EmployeeManagmentBusinessLogic\EmployeeManagmentBusinessLogic.csproj" />
<ProjectReference Include="..\EmployeeManagmentContracts\EmployeeManagmentContracts.csproj" />
<ProjectReference Include="..\EmployeeManagmentDataBaseImplement\EmployeeManagmentDataBaseImplement.csproj" />
<ProjectReference Include="..\EmployeeManagmentDataModels\EmployeeManagmentDataModels.csproj" />
<ProjectReference Include="..\EmployeeManagmentView\EmployeeManagmentView.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,191 @@
using EmployeeManagmentView.PhysicalPerson;
using FlaUI.Core;
using FlaUI.Core.AutomationElements;
using FlaUI.UIA3;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace EmployeeManagmentTests.UI
{
[Collection("Sequential")]
public class EmployeeWindowTests
{
private readonly Application _application;
private readonly AutomationBase _automation;
public EmployeeWindowTests()
{
_automation = new UIA3Automation();
_application = Application.Launch("C:\\Users\\kashi\\Desktop\\Univer\\7\\КПО\\Project\\EmployeeManagmentView\\bin\\Debug\\net8.0-windows\\EmployeeManagmentView.exe");
}
[Fact]
public void TestOpenAddEmployeeManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var employeeButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(employeeButton.IsEnabled, "Работа с сотрудниками");
employeeButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var employeeManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(employeeManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(employeeManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(employeeButton.IsEnabled, "Добавление сотрудника");
employeeButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var employeeAddWindow = WaitForWindow("Добавление сотрудника");
Assert.NotNull(employeeManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(employeeManagementWindow.IsEnabled, "Добавление сотрудника");
// Закрытие окон
employeeManagementWindow?.Close();
employeeAddWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenDeleteEmployeeManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var employeeButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(employeeButton.IsEnabled, "Работа с сотрудниками");
employeeButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var employeeManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(employeeManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(employeeManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(employeeButton.IsEnabled, "Удаление сотрудников");
employeeButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var employeeAddWindow = WaitForWindow("Удаление сотрудников");
Assert.NotNull(employeeManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(employeeManagementWindow.IsEnabled, "Удаление сотрудников");
// Закрытие окон
employeeManagementWindow?.Close();
employeeAddWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenEditEmployeeManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var employeeButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(employeeButton.IsEnabled, "Работа с сотрудниками");
employeeButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var employeeManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(employeeManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(employeeManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(employeeButton.IsEnabled, "Редактирование сотрудника");
employeeButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var employeeAddWindow = WaitForWindow("Редактирование сотрудника");
Assert.NotNull(employeeManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(employeeManagementWindow.IsEnabled, "Редактирование сотрудника");
// Закрытие окон
employeeManagementWindow?.Close();
employeeAddWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenViewEmployeeManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var employeeButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(employeeButton.IsEnabled, "Работа с сотрудниками");
employeeButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var employeeManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(employeeManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(employeeManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(employeeButton.IsEnabled, "Просмотр сотрудников");
employeeButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var employeeAddWindow = WaitForWindow("Просмотр сотрудников");
Assert.NotNull(employeeManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(employeeManagementWindow.IsEnabled, "Просмотр сотрудников");
// Закрытие окон
employeeManagementWindow?.Close();
employeeAddWindow?.Close();
mainWindow?.Close();
}
private Window WaitForWindow(string windowTitle, int timeout = 10000) // Увеличен таймаут
{
var startTime = DateTime.Now;
while ((DateTime.Now - startTime).TotalMilliseconds < timeout)
{
var window = _application.GetAllTopLevelWindows(_automation)
.FirstOrDefault(w => w.Title.Contains(windowTitle));
if (window != null && window.IsEnabled)
{
return window;
}
Thread.Sleep(200); // Увеличена пауза между попытками
}
return null; // Если окно не найдено в пределах тайм-аута
}
public void Dispose()
{
_application.Close();
_automation.Dispose();
}
}
}

View File

@ -0,0 +1,98 @@
using FlaUI.Core;
using FlaUI.Core.AutomationElements;
using FlaUI.Core.Input;
using FlaUI.Core.Tools;
using FlaUI.UIA3;
using Xunit;
using System.Linq;
using System.Threading;
using EmployeeManagmentView.PhysicalPerson;
using EmployeeManagmentView.Employee;
namespace EmployeeManagmentTests.UI
{
[Collection("Sequential")]
public class MainWindowTests : IDisposable
{
private readonly Application _application;
private readonly AutomationBase _automation;
public MainWindowTests()
{
_automation = new UIA3Automation();
_application = Application.Launch("C:\\Users\\kashi\\Desktop\\Univer\\7\\КПО\\Project\\EmployeeManagmentView\\bin\\Debug\\net8.0-windows\\EmployeeManagmentView.exe");
}
[Fact]
public void TestOpenEmployeeManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var employeeButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(employeeButton.IsEnabled, "Работа с сотрудниками");
employeeButton.Invoke();
// Ждем появления окна "Работа с сотрудниками" с тайм-аутом
var employeeManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(employeeManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(employeeManagementWindow.IsEnabled, "Управление сотрудниками");
// Закрытие окон
mainWindow?.Close();
employeeManagementWindow?.Close();
}
[Fact]
public void TestOpenPhysicalPersonManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var physicalPersonButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с физ. лицами")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(physicalPersonButton.IsEnabled, "Работа с физ. лицами");
physicalPersonButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var physicalPersonManagementWindow = WaitForWindow("Управление физическими лицами");
Assert.NotNull(physicalPersonManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(physicalPersonManagementWindow.IsEnabled, "Управление физическими лицами");
// Закрытие окон
mainWindow?.Close();
physicalPersonManagementWindow?.Close();
}
private Window WaitForWindow(string windowTitle, int timeout = 10000) // Увеличен таймаут
{
var startTime = DateTime.Now;
while ((DateTime.Now - startTime).TotalMilliseconds < timeout)
{
var window = _application.GetAllTopLevelWindows(_automation)
.FirstOrDefault(w => w.Title.Contains(windowTitle));
if (window != null && window.IsEnabled)
{
return window;
}
Thread.Sleep(200); // Увеличена пауза между попытками
}
return null; // Если окно не найдено в пределах тайм-аута
}
public void Dispose()
{
_application.Close();
_automation.Dispose();
}
}
}

View File

@ -0,0 +1,188 @@
using EmployeeManagmentView.Employee;
using FlaUI.Core;
using FlaUI.Core.AutomationElements;
using FlaUI.UIA3;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace EmployeeManagmentTests.UI
{
[Collection("Sequential")]
public class PhysicalPersonWindowTests
{
private readonly Application _application;
private readonly AutomationBase _automation;
public PhysicalPersonWindowTests()
{
_automation = new UIA3Automation();
_application = Application.Launch("C:\\Users\\kashi\\Desktop\\Univer\\7\\КПО\\Project\\EmployeeManagmentView\\bin\\Debug\\net8.0-windows\\EmployeeManagmentView.exe");
}
[Fact]
public void TestOpenAddPhysicalPersonManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var physicalPersonButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с физ. лицами")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(physicalPersonButton.IsEnabled, "Работа с физ. лицами");
physicalPersonButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var physicalPersonManagementWindow = WaitForWindow("Управление физическими лицами");
Assert.NotNull(physicalPersonManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(physicalPersonManagementWindow.IsEnabled, "Управление физическими лицами");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(physicalPersonButton.IsEnabled, "Добавление физического лица");
physicalPersonButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var physicalPersonAddWindow = WaitForWindow("Добавление физического лица");
Assert.NotNull(physicalPersonManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(physicalPersonManagementWindow.IsEnabled, "Добавление физического лица");
// Закрытие окон
physicalPersonAddWindow?.Close();
physicalPersonManagementWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenDeletePhysicalPersonManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var physicalPersonButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с физ. лицами")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(physicalPersonButton.IsEnabled, "Работа с физ. лицами");
physicalPersonButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var physicalPersonManagementWindow = WaitForWindow("Управление физическими лицами");
Assert.NotNull(physicalPersonManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(physicalPersonManagementWindow.IsEnabled, "Управление физическими лицами");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(physicalPersonButton.IsEnabled, "Удаление физического лица");
physicalPersonButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var physicalPersonAddWindow = WaitForWindow("Удаление физического лица");
Assert.NotNull(physicalPersonManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(physicalPersonManagementWindow.IsEnabled, "Удаление физического лица");
// Закрытие окон
physicalPersonAddWindow?.Close();
physicalPersonManagementWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenEditPhysicalPersonManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var physicalPersonButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с физ. лицами")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(physicalPersonButton.IsEnabled, "Работа с физ. лицами");
physicalPersonButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var physicalPersonManagementWindow = WaitForWindow("Управление физическими лицами");
Assert.NotNull(physicalPersonManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(physicalPersonManagementWindow.IsEnabled, "Управление физическими лицами");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(physicalPersonButton.IsEnabled, "Редактирование физического лица");
physicalPersonButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var physicalPersonAddWindow = WaitForWindow("Редактирование физического лица");
Assert.NotNull(physicalPersonManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(physicalPersonManagementWindow.IsEnabled, "Редактирование физического лица");
// Закрытие окон
physicalPersonAddWindow?.Close();
physicalPersonManagementWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenViewPhysicalPersonManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var physicalPersonButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с физ. лицами")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(physicalPersonButton.IsEnabled, "Работа с физ. лицами");
physicalPersonButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var physicalPersonManagementWindow = WaitForWindow("Управление физическими лицами");
Assert.NotNull(physicalPersonManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(physicalPersonManagementWindow.IsEnabled, "Управление физическими лицами");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(physicalPersonButton.IsEnabled, "Просмотр физического лица");
physicalPersonButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var physicalPersonAddWindow = WaitForWindow("Просмотр физического лица");
Assert.NotNull(physicalPersonManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(physicalPersonManagementWindow.IsEnabled, "Просмотр физического лица");
// Закрытие окон
physicalPersonAddWindow?.Close();
physicalPersonManagementWindow?.Close();
mainWindow?.Close();
}
private Window WaitForWindow(string windowTitle, int timeout = 10000) // Увеличен таймаут
{
var startTime = DateTime.Now;
while ((DateTime.Now - startTime).TotalMilliseconds < timeout)
{
var window = _application.GetAllTopLevelWindows(_automation)
.FirstOrDefault(w => w.Title.Contains(windowTitle));
if (window != null && window.IsEnabled)
{
return window;
}
Thread.Sleep(200); // Увеличена пауза между попытками
}
return null; // Если окно не найдено в пределах тайм-аута
}
public void Dispose()
{
_application.Close();
_automation.Dispose();
}
}
}

View File

@ -0,0 +1,306 @@
using FlaUI.Core;
using FlaUI.Core.AutomationElements;
using FlaUI.UIA3;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace EmployeeManagmentTests.UI
{
public class SalaryWindowTests
{
private readonly Application _application;
private readonly AutomationBase _automation;
public SalaryWindowTests()
{
_automation = new UIA3Automation();
_application = Application.Launch("C:\\Users\\kashi\\Desktop\\Univer\\7\\КПО\\Project\\EmployeeManagmentView\\bin\\Debug\\net8.0-windows\\EmployeeManagmentView.exe");
}
[Fact]
public void TestOpenViewSalaryManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var salaryButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Работа с сотрудниками");
salaryButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var salaryManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Просмотр сотрудников");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryAddWindow = WaitForWindow("Просмотр сотрудников");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Просмотр сотрудников");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Работа с зарплатой");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryManagmentWindow = WaitForWindow("Управление зарплатой");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Управление зарплатой");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Просмотр зарплат");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryCrudWindow = WaitForWindow("Список зарплат");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Список зарплат");
// Закрытие окон
salaryManagementWindow?.Close();
salaryAddWindow?.Close();
salaryManagmentWindow?.Close();
salaryCrudWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenEditSalaryManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var salaryButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Работа с сотрудниками");
salaryButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var salaryManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Просмотр сотрудников");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryAddWindow = WaitForWindow("Просмотр сотрудников");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Просмотр сотрудников");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Работа с зарплатой");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryManagmentWindow = WaitForWindow("Управление зарплатой");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Управление зарплатой");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Редактирование зарплат");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryCrudWindow = WaitForWindow("Редактирование зарплат");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Редактирование зарплат");
// Закрытие окон
salaryManagementWindow?.Close();
salaryAddWindow?.Close();
salaryManagmentWindow?.Close();
salaryCrudWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenDeleteSalaryManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var salaryButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Работа с сотрудниками");
salaryButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var salaryManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Просмотр сотрудников");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryAddWindow = WaitForWindow("Просмотр сотрудников");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Просмотр сотрудников");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Работа с зарплатой");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryManagmentWindow = WaitForWindow("Управление зарплатой");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Управление зарплатой");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Удаление зарплат");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryCrudWindow = WaitForWindow("Удаление зарплат");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Удаление зарплат");
// Закрытие окон
salaryManagementWindow?.Close();
salaryAddWindow?.Close();
salaryManagmentWindow?.Close();
salaryCrudWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenAddSalaryManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var salaryButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Работа с сотрудниками");
salaryButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var salaryManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Просмотр сотрудников");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryAddWindow = WaitForWindow("Просмотр сотрудников");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Просмотр сотрудников");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Работа с зарплатой");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryManagmentWindow = WaitForWindow("Управление зарплатой");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Управление зарплатой");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(salaryButton.IsEnabled, "Добавление зарплаты");
salaryButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var salaryCrudWindow = WaitForWindow("Добавление зарплаты");
Assert.NotNull(salaryManagementWindow);
Thread.Sleep(100);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(salaryManagementWindow.IsEnabled, "Добавление зарплаты");
// Закрытие окон
salaryManagementWindow?.Close();
salaryAddWindow?.Close();
salaryManagmentWindow?.Close();
salaryCrudWindow?.Close();
mainWindow?.Close();
}
private Window WaitForWindow(string windowTitle, int timeout = 10000) // Увеличен таймаут
{
var startTime = DateTime.Now;
while ((DateTime.Now - startTime).TotalMilliseconds < timeout)
{
var window = _application.GetAllTopLevelWindows(_automation)
.FirstOrDefault(w => w.Title.Contains(windowTitle));
if (window != null && window.IsEnabled)
{
return window;
}
Thread.Sleep(200); // Увеличена пауза между попытками
}
return null; // Если окно не найдено в пределах тайм-аута
}
public void Dispose()
{
_application.Close();
_automation.Dispose();
}
}
}

View File

@ -0,0 +1,283 @@
using FlaUI.Core;
using FlaUI.Core.AutomationElements;
using FlaUI.UIA3;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace EmployeeManagmentTests.UI
{
[Collection("Sequential")]
public class VacationWindowTests
{
private readonly Application _application;
private readonly AutomationBase _automation;
public VacationWindowTests()
{
_automation = new UIA3Automation();
_application = Application.Launch("C:\\Users\\kashi\\Desktop\\Univer\\7\\КПО\\Project\\EmployeeManagmentView\\bin\\Debug\\net8.0-windows\\EmployeeManagmentView.exe");
}
[Fact]
public void TestOpenViewVacationManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var vacationButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Работа с сотрудниками");
vacationButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var vacationManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Просмотр сотрудников");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationAddWindow = WaitForWindow("Просмотр сотрудников");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Просмотр сотрудников");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Работа с отпусками");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationManagmentWindow = WaitForWindow("Управление отпуском");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Управление отпуском");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Просмотр отпусков");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationCrudWindow = WaitForWindow("Список отпусков сотрудников");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Список отпусков сотрудников");
// Закрытие окон
vacationManagementWindow?.Close();
vacationAddWindow?.Close();
vacationManagmentWindow?.Close();
vacationCrudWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenEditVacationManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var vacationButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Работа с сотрудниками");
vacationButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var vacationManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Просмотр сотрудников");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationAddWindow = WaitForWindow("Просмотр сотрудников");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Просмотр сотрудников");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Работа с отпусками");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationManagmentWindow = WaitForWindow("Управление отпуском");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Управление отпуском");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Редактирование отпуска");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationCrudWindow = WaitForWindow("Редактирование отпуска");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Редактирование отпуска");
// Закрытие окон
vacationManagementWindow?.Close();
vacationAddWindow?.Close();
vacationManagmentWindow?.Close();
vacationCrudWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenDeleteVacationManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var vacationButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Работа с сотрудниками");
vacationButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var vacationManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Просмотр сотрудников");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationAddWindow = WaitForWindow("Просмотр сотрудников");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Просмотр сотрудников");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Работа с отпусками");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationManagmentWindow = WaitForWindow("Управление отпуском");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Управление зарплатой");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Удаление отпуска");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationCrudWindow = WaitForWindow("Удаление отпуска");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Удаление отпуска");
// Закрытие окон
vacationManagementWindow?.Close();
vacationAddWindow?.Close();
vacationManagmentWindow?.Close();
vacationCrudWindow?.Close();
mainWindow?.Close();
}
[Fact]
public void TestOpenAddVacationManagementWindow()
{
var mainWindow = _application.GetMainWindow(_automation);
var vacationButton = mainWindow.FindFirstDescendant(cf => cf.ByText("Работа с сотрудниками")).AsButton();
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Работа с сотрудниками");
vacationButton.Invoke();
// Ждем появления окна "Работа с физ. лицами" с тайм-аутом
var vacationManagementWindow = WaitForWindow("Управление сотрудниками");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Управление сотрудниками");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Просмотр сотрудников");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationAddWindow = WaitForWindow("Просмотр сотрудников");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Просмотр сотрудников");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Работа с отпусками");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationManagmentWindow = WaitForWindow("Управление отпуском");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Управление отпуском");
// Проверяем, что кнопка доступна и выполняем клик
Assert.True(vacationButton.IsEnabled, "Добавление отпуска");
vacationButton.Invoke();
// Ждем появления окна "Добавление физ.лица" с тайм-аутом
var vacationCrudWindow = WaitForWindow("Добавление отпуска");
Assert.NotNull(vacationManagementWindow);
// Проверяем, что окно доступно и готово к взаимодействию
Assert.True(vacationManagementWindow.IsEnabled, "Добавление отпуска");
// Закрытие окон
vacationManagementWindow?.Close();
vacationAddWindow?.Close();
vacationManagmentWindow?.Close();
vacationCrudWindow?.Close();
mainWindow?.Close();
}
private Window WaitForWindow(string windowTitle, int timeout = 10000) // Увеличен таймаут
{
var startTime = DateTime.Now;
while ((DateTime.Now - startTime).TotalMilliseconds < timeout)
{
var window = _application.GetAllTopLevelWindows(_automation)
.FirstOrDefault(w => w.Title.Contains(windowTitle));
if (window != null && window.IsEnabled)
{
return window;
}
Thread.Sleep(200); // Увеличена пауза между попытками
}
return null; // Если окно не найдено в пределах тайм-аута
}
}
}

View File

@ -0,0 +1,138 @@
using Xunit;
using Moq;
using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentContracts.SearchModels;
using EmployeeManagmentContracts.StoragesContracts;
using Microsoft.Extensions.Logging;
namespace EmployeeManagmentTests.Unit
{
public class EmployeeLogicTests
{
private readonly Mock<IEmployeeStorage> _mockStorage;
private readonly Mock<ILogger<EmployeeLogic>> _mockLogger;
private readonly EmployeeLogic _logic;
public EmployeeLogicTests()
{
_mockStorage = new Mock<IEmployeeStorage>();
_mockLogger = new Mock<ILogger<EmployeeLogic>>();
_logic = new EmployeeLogic(_mockLogger.Object, _mockStorage.Object);
}
[Fact]
public void GetFullList_ShouldReturnListOfEmployees()
{
// Arrange
var expectedList = new List<EmployeeViewModel>
{
new EmployeeViewModel { Id = 1, NameJob = "Developer", StartJob = DateTime.Now.AddYears(-1) },
new EmployeeViewModel { Id = 2, NameJob = "Manager", StartJob = DateTime.Now.AddYears(-2) }
};
_mockStorage.Setup(x => x.GetFullList()).Returns(expectedList);
// Act
var result = _logic.GetFullList();
// Assert
Assert.Equal(expectedList.Count, result.Count);
Assert.Equal(expectedList[0].NameJob, result[0].NameJob);
}
[Fact]
public void GetFilteredList_ShouldReturnFilteredResults()
{
// Arrange
var model = new EmployeeSearchModel { NameJob = "Developer" };
var expectedList = new List<EmployeeViewModel>
{
new EmployeeViewModel { Id = 1, NameJob = "Developer", StartJob = DateTime.Now.AddYears(-1) }
};
_mockStorage.Setup(x => x.GetFilteredList(model)).Returns(expectedList);
// Act
var result = _logic.GetFilteredList(model);
// Assert
Assert.Single(result);
Assert.Equal("Developer", result[0].NameJob);
}
[Fact]
public void GetFilteredList_ShouldReturnEmptyList_IfNoMatch()
{
// Arrange
var model = new EmployeeSearchModel { NameJob = "Unknown" };
_mockStorage.Setup(x => x.GetFilteredList(model)).Returns(new List<EmployeeViewModel>());
// Act
var result = _logic.GetFilteredList(model);
// Assert
Assert.Empty(result);
}
[Fact]
public void Insert_ShouldThrowException_IfNameJobIsEmpty()
{
// Arrange
var invalidModel = new EmployeeViewModel { NameJob = "" };
// Act & Assert
Assert.Throws<ArgumentException>(() => _logic.Insert(invalidModel));
}
[Fact]
public void Insert_ShouldCallStorageInsert_IfDataIsValid()
{
// Arrange
var validModel = new EmployeeViewModel { NameJob = "Developer", StartJob = DateTime.Now };
// Act
_logic.Insert(validModel);
// Assert
_mockStorage.Verify(x => x.Insert(validModel), Times.Once);
}
[Fact]
public void Update_ShouldThrowException_IfElementNotFound()
{
// Arrange
var model = new EmployeeViewModel { Id = 1, NameJob = "Developer" };
_mockStorage.Setup(x => x.GetElement(model.Id)).Returns((EmployeeViewModel?)null);
// Act & Assert
Assert.Throws<ArgumentException>(() => _logic.Update(model));
}
[Fact]
public void Delete_ShouldThrowException_IfElementNotFound()
{
// Arrange
var id = 1;
_mockStorage.Setup(x => x.GetElement(id)).Returns((EmployeeViewModel?)null);
// Act & Assert
Assert.Throws<ArgumentException>(() => _logic.Delete(id));
}
[Fact]
public void Delete_ShouldCallStorageDelete_IfElementExists()
{
// Arrange
var id = 1;
var model = new EmployeeViewModel { Id = id };
_mockStorage.Setup(x => x.GetElement(id)).Returns(model);
// Act
_logic.Delete(id);
// Assert
_mockStorage.Verify(x => x.Delete(id), Times.Once);
}
}
}

View File

@ -0,0 +1,139 @@
using Xunit;
using Moq;
using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentContracts.SearchModels;
using EmployeeManagmentContracts.StoragesContracts;
using Microsoft.Extensions.Logging;
namespace EmployeeManagmentTests.Unit
{
public class PhisicalPersonLogicTests
{
private readonly Mock<IPhisicalPersonStorage> _mockStorage;
private readonly Mock<ILogger<PhisicalPersonLogic>> _mockLogger;
private readonly PhisicalPersonLogic _logic;
public PhisicalPersonLogicTests()
{
_mockStorage = new Mock<IPhisicalPersonStorage>();
_mockLogger = new Mock<ILogger<PhisicalPersonLogic>>();
_logic = new PhisicalPersonLogic(_mockLogger.Object, _mockStorage.Object);
}
[Fact]
public void GetFullList_ShouldReturnListOfPhisicalPersons()
{
// Arrange
var expectedList = new List<PhisicalPersonViewModel>
{
new PhisicalPersonViewModel { Id = 1, Name = "John", Surname = "Doe" },
new PhisicalPersonViewModel { Id = 2, Name = "Jane", Surname = "Smith" }
};
_mockStorage.Setup(x => x.GetFullList()).Returns(expectedList);
// Act
var result = _logic.GetFullList();
// Assert
Assert.Equal(expectedList.Count, result.Count);
Assert.Equal(expectedList[0].Name, result[0].Name);
}
[Fact]
public void GetFilteredList_ShouldReturnFilteredResults()
{
// Arrange
var model = new PhisicalPersonSearchModel { Surname = "Doe" };
var expectedList = new List<PhisicalPersonViewModel>
{
new PhisicalPersonViewModel { Id = 1, Name = "John", Surname = "Doe" }
};
_mockStorage.Setup(x => x.GetFilteredList(model)).Returns(expectedList);
// Act
var result = _logic.GetFilteredList(model);
// Assert
Assert.Single(result);
Assert.Equal("Doe", result[0].Surname);
}
[Fact]
public void GetFilteredList_ShouldReturnEmptyList_IfNoMatch()
{
// Arrange
var model = new PhisicalPersonSearchModel { Surname = "Unknown" };
_mockStorage.Setup(x => x.GetFilteredList(model)).Returns(new List<PhisicalPersonViewModel>());
// Act
var result = _logic.GetFilteredList(model);
// Assert
Assert.Empty(result);
}
[Fact]
public void Insert_ShouldThrowException_IfNameOrSurnameIsEmpty()
{
// Arrange
var invalidModel = new PhisicalPersonViewModel { Name = "", Surname = "" };
// Act & Assert
Assert.Throws<ArgumentException>(() => _logic.Insert(invalidModel));
}
[Fact]
public void Insert_ShouldCallStorageInsert_IfDataIsValid()
{
// Arrange
var validModel = new PhisicalPersonViewModel { Name = "John", Surname = "Doe" };
// Act
_logic.Insert(validModel);
// Assert
_mockStorage.Verify(x => x.Insert(validModel), Times.Once);
}
[Fact]
public void Update_ShouldThrowException_IfElementNotFound()
{
// Arrange
var model = new PhisicalPersonViewModel { Id = 1, Name = "John", Surname = "Doe" };
_mockStorage.Setup(x => x.GetElement(model.Id)).Returns((PhisicalPersonViewModel?)null);
// Act & Assert
Assert.Throws<ArgumentException>(() => _logic.Update(model));
}
[Fact]
public void Delete_ShouldThrowException_IfElementNotFound()
{
// Arrange
var id = 1;
_mockStorage.Setup(x => x.GetElement(id)).Returns((PhisicalPersonViewModel?)null);
// Act & Assert
Assert.Throws<ArgumentException>(() => _logic.Delete(id));
}
[Fact]
public void Delete_ShouldCallStorageDelete_IfElementExists()
{
// Arrange
var id = 1;
var model = new PhisicalPersonViewModel { Id = id };
_mockStorage.Setup(x => x.GetElement(id)).Returns(model);
// Act
_logic.Delete(id);
// Assert
_mockStorage.Verify(x => x.Delete(id), Times.Once);
}
}
}

View File

@ -0,0 +1,142 @@
using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.SearchModels;
using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentDataBaseImplement.Implements;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
namespace EmployeeManagmentTests.Unit
{
public class SalaryLogicTests
{
private readonly Mock<ILogger<SalaryLogic>> _loggerMock;
private readonly SalaryStorage _salaryStorage;
private readonly SalaryLogic _salaryLogic;
public SalaryLogicTests()
{
_loggerMock = new Mock<ILogger<SalaryLogic>>();
_salaryStorage = new SalaryStorage();
_salaryLogic = new SalaryLogic(_loggerMock.Object, _salaryStorage);
}
[Fact]
public void GetFullList_ShouldReturnAllSalaries()
{
// Arrange
var expectedCount = _salaryStorage.GetFullList().Count;
// Act
var result = _salaryLogic.GetFullList();
// Assert
Assert.NotNull(result);
Assert.Equal(expectedCount, result.Count);
}
[Fact]
public void GetFilteredList_ShouldReturnFilteredSalaries()
{
// Arrange
var filter = new SalarySearchModel
{
Date = DateTime.UtcNow.AddMonths(-1) // Используйте UTC
};
// Act
var result = _salaryLogic.GetFilteredList(filter);
// Assert
Assert.NotNull(result);
Assert.All(result, salary => Assert.True(salary.Date >= filter.Date));
}
[Fact]
public void GetElement_ShouldReturnCorrectSalary()
{
// Arrange
var salaries = _salaryLogic.GetFullList();
if (salaries.Count == 0)
{
Assert.True(false, "No salaries available for testing.");
}
var salaryId = salaries.First().Id;
// Act
var result = _salaryLogic.GetElement(salaryId);
// Assert
Assert.NotNull(result);
Assert.Equal(salaryId, result.Id);
}
[Fact]
public void Insert_ShouldAddSalary()
{
// Arrange
var newSalary = new SalaryViewModel
{
CountHours = 40,
PriceHour = 15,
Premium = 200,
Date = DateTime.UtcNow, // Используем UTC для даты
Passed = false,
EmployeeId = 1
};
var initialCount = _salaryLogic.GetFullList().Count;
// Act
_salaryLogic.Insert(newSalary);
var updatedCount = _salaryLogic.GetFullList().Count;
// Assert
Assert.Equal(initialCount + 1, updatedCount);
}
[Fact]
public void Update_ShouldModifySalary()
{
// Arrange
var salary = _salaryLogic.GetFullList().FirstOrDefault();
if (salary == null)
{
Assert.True(false, "No salaries available for testing.");
}
salary.PriceHour += 5;
// Act
_salaryLogic.Update(salary);
var updatedSalary = _salaryLogic.GetElement(salary.Id);
// Assert
Assert.NotNull(updatedSalary);
Assert.Equal(salary.PriceHour, updatedSalary.PriceHour);
}
[Fact]
public void Delete_ShouldRemoveSalary()
{
// Arrange
var salary = _salaryLogic.GetFullList().LastOrDefault();
if (salary == null)
{
Assert.True(false, "No salaries available for testing.");
}
var initialCount = _salaryLogic.GetFullList().Count;
// Act
_salaryLogic.Delete(salary.Id);
var updatedCount = _salaryLogic.GetFullList().Count;
// Assert
Assert.Equal(initialCount - 1, updatedCount);
}
}
}

View File

@ -0,0 +1,144 @@
using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.SearchModels;
using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentDataBaseImplement.Implements;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
namespace EmployeeManagmentTests.Unit
{
public class VacationLogicTests
{
private readonly Mock<ILogger<VacationLogic>> _loggerMock;
private readonly VacationStorage _vacationStorage;
private readonly VacationLogic _vacationLogic;
public VacationLogicTests()
{
_loggerMock = new Mock<ILogger<VacationLogic>>();
_vacationStorage = new VacationStorage();
_vacationLogic = new VacationLogic(_loggerMock.Object, _vacationStorage);
}
[Fact]
public void GetFullList_ShouldReturnAllVacations()
{
// Arrange
var expectedCount = _vacationStorage.GetFullList().Count;
// Act
var result = _vacationLogic.GetFullList();
// Assert
Assert.NotNull(result);
Assert.Equal(expectedCount, result.Count);
}
[Fact]
public void GetFilteredList_ShouldReturnFilteredVacations()
{
// Arrange
var filter = new VacationSearchModel
{
StartData = DateTime.UtcNow.AddMonths(-1),
EndData = DateTime.UtcNow
};
// Act
var result = _vacationLogic.GetFilteredList(filter);
// Assert
Assert.NotNull(result);
Assert.All(result, vacation =>
Assert.True(vacation.StartData >= filter.StartData && vacation.EndData <= filter.EndData)
);
}
[Fact]
public void GetElement_ShouldReturnCorrectVacation()
{
// Arrange
var vacations = _vacationLogic.GetFullList();
if (vacations.Count == 0)
{
Assert.True(false, "No vacations available for testing.");
}
var vacationId = vacations.First().Id;
// Act
var result = _vacationLogic.GetElement(vacationId);
// Assert
Assert.NotNull(result);
Assert.Equal(vacationId, result.Id);
}
[Fact]
public void Insert_ShouldAddVacation()
{
// Arrange
var newVacation = new VacationViewModel
{
StartData = DateTime.UtcNow.AddDays(1).ToUniversalTime(), // Преобразование в UTC
EndData = DateTime.UtcNow.AddDays(10).ToUniversalTime(), // Преобразование в UTC
Passed = false,
EmployeeId = 1 // ID существующего сотрудника
};
var initialCount = _vacationLogic.GetFullList().Count;
// Act
_vacationLogic.Insert(newVacation);
var updatedCount = _vacationLogic.GetFullList().Count;
// Assert
Assert.Equal(initialCount + 1, updatedCount);
}
[Fact]
public void Update_ShouldModifyVacation()
{
// Arrange
var vacation = _vacationLogic.GetFullList().FirstOrDefault();
if (vacation == null)
{
Assert.True(false, "No vacations available for testing.");
}
vacation.EndData = DateTime.UtcNow.AddDays(20).ToUniversalTime(); // Преобразование в UTC
// Act
_vacationLogic.Update(vacation);
var updatedVacation = _vacationLogic.GetElement(vacation.Id);
// Assert
Assert.NotNull(updatedVacation);
// Сравниваем с учетом допустимой погрешности в миллисекундах
Assert.Equal(vacation.EndData, updatedVacation.EndData, TimeSpan.FromMilliseconds(1));
}
[Fact]
public void Delete_ShouldRemoveVacation()
{
// Arrange
var vacation = _vacationLogic.GetFullList().LastOrDefault();
if (vacation == null)
{
Assert.True(false, "No vacations available for testing.");
}
var initialCount = _vacationLogic.GetFullList().Count;
// Act
_vacationLogic.Delete(vacation.Id);
var updatedCount = _vacationLogic.GetFullList().Count;
// Assert
Assert.Equal(initialCount - 1, updatedCount);
}
}
}

View File

@ -1,9 +1,184 @@
<Application x:Class="EmployeeManagmentView.App" <Application x:Class="EmployeeManagmentView.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:local="clr-namespace:EmployeeManagmentView"
StartupUri="MainWindow.xaml">
<Application.Resources> <Application.Resources>
<!-- Стиль для закругленных кнопок -->
<Style x:Key="RoundedButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Border Background="{TemplateBinding Background}"
CornerRadius="15"
BorderBrush="Transparent"
BorderThickness="0"
x:Name="ButtonBorder">
<Border.Effect>
<DropShadowEffect Color="Black" BlurRadius="10" ShadowDepth="2" Opacity="0.4" />
</Border.Effect>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<Grid.RenderTransform>
<ScaleTransform x:Name="scaleTransform" ScaleX="1" ScaleY="1" />
</Grid.RenderTransform>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="ButtonBorder"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="#0066CC" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="ButtonBorder"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="#004890" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
<Setter Property="RenderTransform" TargetName="ButtonBorder">
<Setter.Value>
<ScaleTransform ScaleX="0.95" ScaleY="0.95" />
</Setter.Value>
</Setter>
<Setter TargetName="ButtonBorder" Property="Effect">
<Setter.Value>
<DropShadowEffect Color="Black" BlurRadius="15" ShadowDepth="0" Opacity="0.6" />
</Setter.Value>
</Setter>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="scaleTransform"
Storyboard.TargetProperty="ScaleX"
To="0.95" Duration="0:0:0.2" />
<DoubleAnimation Storyboard.TargetName="scaleTransform"
Storyboard.TargetProperty="ScaleY"
To="0.95" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="scaleTransform"
Storyboard.TargetProperty="ScaleX"
To="1.0" Duration="0:0:0.2" />
<DoubleAnimation Storyboard.TargetName="scaleTransform"
Storyboard.TargetProperty="ScaleY"
To="1.0" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Стиль для закругленного TextBox -->
<Style x:Key="RoundedTextBoxStyle" TargetType="TextBox">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border Background="White"
CornerRadius="15"
BorderBrush="Black">
<ScrollViewer Margin="5" x:Name="PART_ContentHost"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<!-- Подсветка рамки при фокусе -->
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderBrush" Value="#004890"/>
</Trigger>
</Style.Triggers>
</Style>
<!-- Стиль для DataGrid -->
<Style x:Key="RoundedDataGridStyle" TargetType="DataGrid">
<Setter Property="Background" Value="#FFFFFF"/>
<Setter Property="Foreground" Value="#000000"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="10"/>
<Setter Property="AlternatingRowBackground" Value="#FFFFFF"/>
<Setter Property="RowHeight" Value="30"/>
<Style.Triggers>
<!-- Эффект при наведении на строку -->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FFFFFF"/>
</Trigger>
</Style.Triggers>
<Style.Resources>
<!-- Стиль для ячеек DataGrid -->
<Style TargetType="DataGridCell">
<Setter Property="Padding" Value="10"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#004890"/>
<Setter Property="Foreground" Value="#FFFFFF"/>
</Trigger>
</Style.Triggers>
</Style>
<!-- Стиль для строк -->
<Style TargetType="DataGridRow">
<Setter Property="Padding" Value="5"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#0D2D4F"/>
<Setter Property="Foreground" Value="#FFFFFF"/>
</Trigger>
<!-- Стиль для выделенной строки (не должна быть белой) -->
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#0D2D4F"/>
<!-- Цвет фона выделенной строки -->
<Setter Property="Foreground" Value="#FFFFFF"/>
<!-- Цвет текста в выделенной строке -->
</Trigger>
</Style.Triggers>
</Style>
<!-- Стиль для шапки DataGrid -->
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#0D2D4F"/>
<Setter Property="Foreground" Value="#FFFFFF"/>
<Setter Property="Height" Value="40"/>
<!-- Увеличение высоты шапки -->
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="10"/>
</Style>
</Style.Resources>
</Style>
</Application.Resources> </Application.Resources>
</Application> </Application>

View File

@ -1,14 +1,59 @@
using System.Configuration; using EmployeeManagmentDataBaseImplement;
using System.Data; using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.BusinessLogicContracts;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using System;
using System.Windows; using System.Windows;
using Microsoft.Extensions.Logging;
using EmployeeManagmentContracts.StoragesContracts;
using EmployeeManagmentDataBaseImplement.Implements;
namespace EmployeeManagmentView namespace EmployeeManagmentView
{ {
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application public partial class App : Application
{ {
} private static ServiceProvider? _serviceProvider;
public static ServiceProvider? ServiceProvider => _serviceProvider;
protected override void OnStartup(StartupEventArgs e)
{
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
_serviceProvider = serviceCollection.BuildServiceProvider();
try
{
var mainWindow = _serviceProvider.GetRequiredService<MainWindow>();
mainWindow.Show();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка при открытии MainWindow", MessageBoxButton.OK, MessageBoxImage.Error);
}
base.OnStartup(e);
}
private static void ConfigureServices(ServiceCollection services)
{
services.AddLogging(configure => configure.AddConsole());
services.AddTransient<IEmployeeStorage, EmployeeStorage>();
services.AddTransient<IPhisicalPersonStorage, PhisicalPersonStorage>();
services.AddTransient<ISalaryStorage, SalaryStorage>();
services.AddTransient<IVacationStorage, VacationStorage>();
services.AddTransient<IPhisicalPersonLogic, PhisicalPersonLogic>();
services.AddTransient<IEmployeeLogic, EmployeeLogic>();
services.AddTransient<ISalaryLogic, SalaryLogic>();
services.AddTransient<IVacationLogic, VacationLogic>();
services.AddTransient<MainWindow>();
}
}
} }

View File

@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
using System.Windows; using System.Windows;
[assembly: ThemeInfo( [assembly: ThemeInfo(
@ -8,3 +9,6 @@ using System.Windows;
//(used if a resource is not found in the page, //(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries) // app, or any theme specific resource dictionaries)
)] )]
[assembly: InternalsVisibleTo("EmployeeManagmentTests")]

View File

@ -0,0 +1,115 @@
<Window x:Class="EmployeeManagmentView.Employee.AddEmployeeWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Добавление сотрудника"
Height="500" Width="600"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Добавление сотрудника"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Сетка для ввода данных в два столбца -->
<Grid Margin="0,60">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Поле для имени работы -->
<StackPanel Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Название должности" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="JobNameTextBox"
Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}"
Margin="0,5"
ToolTip="Введите название должности" HorizontalAlignment="Center"
PreviewTextInput="NameTextBox_PreviewTextInput"
TextChanged="NameTextBox_TextChanged"/>
</StackPanel>
<!-- Поле для даты начала работы -->
<StackPanel Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Дата начала работы" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="StartDatePicker"
Width="250" Height="40"
Margin="0,5"
ToolTip="Выберите дату начала работы" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Поле для даты окончания работы -->
<StackPanel Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Дата окончания работы" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="EndDatePicker"
Width="250" Height="40"
Margin="0,5"
ToolTip="Выберите дату окончания работы (если есть)" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Поле для ставки -->
<StackPanel Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Ставка" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="BidTextBox"
Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}"
Margin="0,5"
ToolTip="Введите почасовую ставку" HorizontalAlignment="Center"
PreviewTextInput="DecimalTextBox_PreviewTextInput"
TextChanged="DecimalTextBox_TextChanged"/>
</StackPanel>
<!-- Поле для физического лица -->
<StackPanel Grid.Row="2" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Физическое лицо" Foreground="White" HorizontalAlignment="Center"/>
<ComboBox x:Name="PhysicalPersonComboBox"
Width="250" Height="40"
Margin="0,5"
ToolTip="Выберите физическое лицо"
Background="White" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Поле для совместительства -->
<StackPanel Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Совместительство" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="PartTimeJobTextBox"
Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}"
Margin="0,5"
ToolTip="Введите почасовую ставку" HorizontalAlignment="Center"
PreviewTextInput="NameTextBox_PreviewTextInput"
TextChanged="NameTextBox_TextChanged"/>
</StackPanel>
<!-- Кнопка для добавления сотрудника -->
<Button Grid.Row="3" Grid.ColumnSpan="2" Content="Добавить сотрудника"
Width="250" Height="40"
Margin="20,10,0,0"
Style="{StaticResource RoundedButtonStyle}"
Click="SaveButton_Click"
Background="#004890" Foreground="#FFFFFF" HorizontalAlignment="Left"/>
<Button Grid.Row="3" Grid.ColumnSpan="2" Content="Сформировать договор"
Width="250" Height="40"
Margin="0,10,20,0"
Style="{StaticResource RoundedButtonStyle}"
Click="GenerateContractButton_Click"
Background="#004890" Foreground="#FFFFFF" HorizontalAlignment="Right"/>
</Grid>
</Grid>
</Window>

View File

@ -0,0 +1,374 @@
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;
using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;
using Microsoft.Win32;
namespace EmployeeManagmentView.Employee
{
/// <summary>
/// Логика взаимодействия для AddEmployeeWindow.xaml
/// </summary>
public partial class AddEmployeeWindow : Window
{
private readonly IEmployeeLogic _employeeLogic;
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
public AddEmployeeWindow(IEmployeeLogic employeeLogic, IPhisicalPersonLogic phisicalPersonLogic)
{
_employeeLogic = employeeLogic;
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
LoadPhysicalPersons();
}
private void LoadPhysicalPersons()
{
if (PhysicalPersonComboBox == null)
{
throw new InvalidOperationException("PhysicalPersonComboBox не инициализирован.");
}
var persons = _phisicalPersonLogic.GetFullList();
PhysicalPersonComboBox.ItemsSource = persons;
PhysicalPersonComboBox.DisplayMemberPath = "FullNameWithBirthday";
PhysicalPersonComboBox.SelectedValuePath = "Id";
}
private void NameTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
// Разрешаем только буквы
e.Handled = !char.IsLetter(e.Text, 0);
}
private void NameTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Получаем текущий текст
string currentText = textBox.Text;
// Если текст не пустой, преобразуем первую букву в заглавную, а остальные в строчные
if (!string.IsNullOrEmpty(currentText))
{
// Разбиваем строку по пробелам, чтобы обрабатывать каждое слово отдельно
var words = currentText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < words.Length; i++)
{
// Преобразуем первую букву в заглавную, а остальные в строчные
words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower();
}
// Объединяем слова обратно в строку и обновляем текст
textBox.Text = string.Join(" ", words);
// Устанавливаем курсор в конец текста
textBox.SelectionStart = textBox.Text.Length;
}
}
// Проверка на ввод только чисел и одной запятой
private void DecimalTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Разрешаем только цифры и запятую
e.Handled = !(char.IsDigit(e.Text, 0) || e.Text == ",");
// Проверка на количество запятых
if (e.Text == "," && textBox.Text.Contains(","))
{
e.Handled = true;
}
}
// Ограничение на 2 знака после запятой
private void DecimalTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Получаем текущий текст
string currentText = textBox.Text;
// Проверяем наличие запятой
int commaIndex = currentText.IndexOf(',');
if (commaIndex != -1 && currentText.Length - commaIndex > 3)
{
// Обрезаем текст до двух знаков после запятой
textBox.Text = currentText.Substring(0, commaIndex + 3);
textBox.SelectionStart = textBox.Text.Length; // Устанавливаем курсор в конец текста
}
}
private void TelephoneTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !char.IsDigit(e.Text, 0);
}
public static void CreateEmploymentContract(string filePath, string employeeName, string jobTitle, DateTime startDate, DateTime? endDate, decimal hourlyRate, string partTimeInfo)
{
using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(filePath, WordprocessingDocumentType.Document))
{
// Добавление основной части документа
MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();
mainPart.Document = new Document();
Body body = new Body();
// Канцелярская информация
body.Append(new Paragraph(new Run(new Text($"Номер договора: {Guid.NewGuid().ToString("N").ToUpper().Substring(0, 10)}"))));
body.Append(new Paragraph(new Run(new Text($"Дата составления: {DateTime.Now:dd.MM.yyyy}"))));
// Заголовок
body.Append(new Paragraph(new Run(new Text("Трудовой договор"))
{
RunProperties = new RunProperties
{
Bold = new Bold(),
FontSize = new FontSize { Val = "28" }
}
}));
// Преамбула
body.Append(new Paragraph(new Run(new Text(
"Настоящий трудовой договор (далее Договор) заключается между Работодателем, " +
"именуемым далее «Работодатель», и Работником, именуемым далее «Работник», на " +
"основании Трудового кодекса Российской Федерации. Работодатель обязуется " +
"предоставить Работнику работу по должности, указанной в настоящем договоре, " +
"обеспечивать необходимые условия труда, а Работник обязуется лично выполнять " +
"трудовые функции в соответствии с условиями договора."
))));
// Сведения о работнике
body.Append(new Paragraph(new Run(new Text($"Сотрудник: {employeeName}"))));
body.Append(new Paragraph(new Run(new Text($"Должность: {jobTitle}"))));
body.Append(new Paragraph(new Run(new Text($"Дата начала работы: {startDate:dd.MM.yyyy}"))));
body.Append(new Paragraph(new Run(new Text(endDate.HasValue ? $"Дата окончания работы: {endDate:dd.MM.yyyy}" : "Дата окончания работы: бессрочный договор"))));
body.Append(new Paragraph(new Run(new Text($"Ставка: {hourlyRate}"))));
body.Append(new Paragraph(new Run(new Text($"Совместительство: {partTimeInfo}"))));
// Создание параграфа с текстом, который будет перенесен
body.Append(new Paragraph(
new Run(new Text("Условия трудового договора:"))));
// Пример добавления нескольких строк с переносом
string contractConditions =
"1. Рабочее время Работника составляет 40 часов в неделю, если иное не предусмотрено " +
"действующим законодательством. Работник обязуется являться на рабочее место своевременно, " +
"выполнять свои трудовые обязанности добросовестно и качественно.\n" +
"2. Работодатель обязуется своевременно выплачивать Работнику заработную плату. Заработная плата " +
"состоит из оклада и дополнительных выплат в виде премий и надбавок.\n" +
"3. Работник имеет право на ежегодный оплачиваемый отпуск продолжительностью 28 календарных дней, " +
"а также другие виды отпусков в соответствии с законодательством.\n" +
"4. Работодатель имеет право привлекать Работника к дисциплинарной ответственности в случаях, " +
"предусмотренных Трудовым кодексом РФ.";
// Разбиваем на строки и добавляем в документ
foreach (var line in contractConditions.Split('\n'))
{
body.Append(new Paragraph(new Run(new Text(line))));
}
// Права и обязанности работника
body.Append(new Paragraph(new Run(new Text("Права и обязанности Работника:"))));
string rules = "1. Работник имеет право на:\n" +
" 1.1. Получение своевременной оплаты труда.\n" +
" 1.2. Условия труда, соответствующие установленным нормам охраны труда.\n" +
" 1.3. Отдых в соответствии с трудовым законодательством Российской Федерации.\n" +
"2. Работник обязан:\n" +
" 2.1. Соблюдать правила внутреннего трудового распорядка.\n" +
" 2.2. Выполнять должностные обязанности в соответствии с трудовым договором и локальными нормативными актами Работодателя.\n" +
" 2.3. Бережно относиться к имуществу Работодателя.";
// Разбиваем на строки и добавляем в документ
foreach (var line in rules.Split('\n'))
{
body.Append(new Paragraph(new Run(new Text(line))));
}
// Права и обязанности работодателя
body.Append(new Paragraph(new Run(new Text("Права и обязанности Работодателя:"))));
string rulesRussia =
"1. Работодатель имеет право на:\n" +
" 1.1. Привлечение Работника к выполнению трудовых функций в рамках установленных обязанностей.\n" +
" 1.2. Осуществление контроля за выполнением Работником трудовых обязанностей.\n" +
"2. Работодатель обязан:\n" +
" 2.1. Своевременно выплачивать заработную плату Работнику.\n" +
" 2.2. Предоставлять Работнику возможность использовать ежегодный оплачиваемый отпуск.\n" +
" 2.3. Соблюдать нормы трудового законодательства Российской Федерации.";
// Разбиваем на строки и добавляем в документ
foreach (var line in rulesRussia.Split('\n'))
{
body.Append(new Paragraph(new Run(new Text(line))));
}
// Подписи сторон
body.Append(new Paragraph(new Run(new Text("\nПодписи сторон:"))));
body.Append(new Paragraph(new Run(new Text("\nРаботодатель: _______________________"))));
body.Append(new Paragraph(new Run(new Text("\nРаботник: ___________________________"))));
// Привязка тела документа
mainPart.Document.Append(body);
mainPart.Document.Save();
}
}
private void GenerateContractButton_Click(object sender, RoutedEventArgs e)
{
// Проверка данных
if (string.IsNullOrWhiteSpace(JobNameTextBox.Text) ||
!StartDatePicker.SelectedDate.HasValue ||
string.IsNullOrWhiteSpace(BidTextBox.Text) ||
string.IsNullOrWhiteSpace(PhysicalPersonComboBox.Text))
{
MessageBox.Show("Пожалуйста, заполните все обязательные поля.");
return;
}
// Получение данных
string employeeName = PhysicalPersonComboBox.Text;
string jobTitle = JobNameTextBox.Text;
DateTime startDate = StartDatePicker.SelectedDate.Value;
DateTime? endDate = EndDatePicker.SelectedDate;
decimal hourlyRate = decimal.Parse(BidTextBox.Text);
string partTimeInfo = PartTimeJobTextBox.Text;
try
{
// Открытие диалогового окна для сохранения файла
SaveFileDialog saveFileDialog = new SaveFileDialog
{
Filter = "Excel файлы (*.docx)|*.docx", // фильтр для файлов .docx
Title = "Сохранить договор о трудоустройстве", // заголовок окна
FileName = "Договор.docx" // имя по умолчанию
};
// Проверка, что пользователь выбрал путь и имя файла
if (saveFileDialog.ShowDialog() == true)
{
string filePath = saveFileDialog.FileName; // Путь и имя файла
CreateEmploymentContract(filePath, employeeName, jobTitle, startDate, endDate, hourlyRate, partTimeInfo); // Генерация отчета
MessageBox.Show($"Договор успешно сохранен: {filePath}", "Успех", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка при создании документа: {ex.Message}");
}
}
private void TelephoneTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Удаляем все символы, кроме цифр
string rawInput = new string(textBox.Text.Where(char.IsDigit).ToArray());
// Добавляем "7" по умолчанию
if (!rawInput.StartsWith("7"))
rawInput = "7" + rawInput;
if (rawInput.Length > 11) rawInput = rawInput.Substring(0, 11);
// Форматируем как +7 (XXX) XXX-XX-XX
if (rawInput.Length <= 1)
textBox.Text = "+7 ";
else if (rawInput.Length <= 4)
textBox.Text = $"+7 ({rawInput.Substring(1)}";
else if (rawInput.Length <= 7)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4)}";
else if (rawInput.Length <= 9)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7)}";
else
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7, 2)}-{rawInput.Substring(9)}";
// Устанавливаем курсор в конец
textBox.SelectionStart = textBox.Text.Length;
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
bool isValid = true;
// Проверка обязательных полей
if (string.IsNullOrWhiteSpace(JobNameTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Название должности' не заполнено.");
}
if (string.IsNullOrWhiteSpace(PartTimeJobTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Совместительство' не заполнено.");
}
if (string.IsNullOrWhiteSpace(BidTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Ставка' не заполнено.");
}
if (!StartDatePicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Начало работы' не выбрано.");
}
if (!EndDatePicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Конец работы' не выбрано.");
}
// Если все поля заполнены, продолжаем выполнение
if (isValid)
try
{
var model = new EmployeeViewModel
{
NameJob = JobNameTextBox.Text,
StartJob = StartDatePicker.SelectedDate.Value.ToUniversalTime(),
EndJob = EndDatePicker.SelectedDate.Value.ToUniversalTime(),
Bid = float.Parse(BidTextBox.Text),
PartTimeJob = PartTimeJobTextBox.Text,
PhysicalPersonsId = (int?)PhysicalPersonComboBox.SelectedValue
};
_employeeLogic.Insert(model);
MessageBox.Show("Данные сотрудника успешно сохранены!");
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка: {ex.Message}");
}
}
}
}

View File

@ -0,0 +1,52 @@
<Window x:Class="EmployeeManagmentView.Employee.DeleteEmployeeWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Удаление сотрудников"
Height="500" Width="800"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Список сотрудников для удаления"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="White"
Margin="0,20,0,0" />
<!-- Поле поиска -->
<TextBox x:Name="SearchTextBox"
Width="560"
VerticalAlignment="Top"
Margin="0,60,0,0"
HorizontalAlignment="Center"
Style="{StaticResource RoundedTextBoxStyle}"
TextChanged="SearchTextBox_TextChanged" />
<!-- Таблица сотрудников -->
<DataGrid x:Name="EmployeesDataGrid"
Margin="20,100,20,80"
AutoGenerateColumns="False"
Style="{StaticResource RoundedDataGridStyle}">
<DataGrid.Columns>
<DataGridTextColumn Header="Должность" Binding="{Binding NameJob}" Width="*" />
<DataGridTextColumn Header="Дата начала" Binding="{Binding StartJob, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Дата окончания" Binding="{Binding EndJob, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Частичная занятость" Binding="{Binding PartTimeJob}" Width="*" />
<DataGridTextColumn Header="Ставка" Binding="{Binding Bid}" Width="*" />
<DataGridTextColumn Header="Физическое лицо" Binding="{Binding PhysicalPersonName}" Width="*" />
</DataGrid.Columns>
</DataGrid>
<!-- Кнопка удаления -->
<Button Content="Удалить"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Width="100" Height="40"
Margin="0,0,0,20"
Background="#004890"
Foreground="White"
Style="{StaticResource RoundedButtonStyle}"
Click="DeleteButton_Click" />
</Grid>
</Window>

View File

@ -0,0 +1,68 @@
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
namespace EmployeeManagmentView.Employee
{
public partial class DeleteEmployeeWindow : Window
{
private readonly IEmployeeLogic _employeeLogic;
private IEnumerable<EmployeeViewModel> _allEmployees; // Список сотрудников для фильтрации
public DeleteEmployeeWindow(IEmployeeLogic employeeLogic)
{
_employeeLogic = employeeLogic;
InitializeComponent();
LoadEmployees();
}
private void LoadEmployees()
{
_allEmployees = _employeeLogic.GetFullList(); // Загрузка всех данных
EmployeesDataGrid.ItemsSource = _allEmployees;
}
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
if (EmployeesDataGrid.SelectedItem is EmployeeViewModel selectedEmployee)
{
// Удаление сотрудника
_employeeLogic.Delete(selectedEmployee.Id);
MessageBox.Show("Сотрудник успешно удален!");
LoadEmployees(); // Перезагрузка данных после удаления
SearchTextBox.Text = string.Empty; // Очистка поля поиска
}
else
{
MessageBox.Show("Пожалуйста, выберите сотрудника для удаления.");
}
}
private void SearchTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
string query = SearchTextBox.Text.ToLower();
if (string.IsNullOrWhiteSpace(query))
{
// Отображаем все записи
EmployeesDataGrid.ItemsSource = _allEmployees;
}
else
{
// Фильтрация по всем полям сущности
var filteredList = _allEmployees.Where(emp =>
(emp.NameJob?.ToLower().Contains(query) ?? false) ||
(emp.PartTimeJob?.ToLower().Contains(query) ?? false) ||
(emp.PhysicalPersonName?.ToLower().Contains(query) ?? false) ||
(emp.StartJob.HasValue && emp.StartJob.Value.ToString("dd.MM.yyyy").Contains(query)) ||
(emp.EndJob.HasValue && emp.EndJob.Value.ToString("dd.MM.yyyy").Contains(query)) ||
emp.Bid.ToString().Contains(query)
).ToList();
EmployeesDataGrid.ItemsSource = filteredList;
}
}
}
}

View File

@ -0,0 +1,125 @@
<Window x:Class="EmployeeManagmentView.Employee.EditEmployeeWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Редактирование сотрудника"
Height="600" Width="600"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid Margin="0,0,0,-6">
<!-- Заголовок окна -->
<TextBlock Text="Редактирование сотрудника"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Основная сетка -->
<Grid Margin="0,70,0,60">
<Grid.RowDefinitions>
<!-- Поиск -->
<RowDefinition Height="2*" />
<!-- Редактирование -->
<RowDefinition Height="5*" />
<!-- Кнопка сохранения -->
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Блок поиска -->
<Grid Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0, 0, 0, 0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Поле для поиска сотрудников -->
<Label Grid.Row="0" Grid.Column="0"
Content="Поиск сотрудника" Foreground="White" HorizontalAlignment="Center" Margin="0,10,0,10" VerticalContentAlignment="Center"/>
<TextBox x:Name="SearchTextBox" Grid.Row="0" Grid.Column="1"
Width="250" Height="30"
Style="{StaticResource RoundedTextBoxStyle}"
Margin="0,10,0,10"
VerticalContentAlignment="Center"
ToolTip="Введите для поиска"
TextChanged="SearchTextBox_TextChanged"/>
<!-- Поле для выбора сотрудника -->
<Label Grid.Row="1" Grid.Column="0"
Content="Выберите сотрудника" Foreground="White" HorizontalAlignment="Center" Margin="0,10,0,10" VerticalContentAlignment="Center"/>
<ComboBox x:Name="EmployeeComboBox" Grid.Row="1" Grid.Column="1"
Width="400" Height="30"
Margin="0,10,0,10"
VerticalAlignment="Top"
ToolTip="Выберите сотрудника"
SelectionChanged="EmployeeComboBox_SelectionChanged" />
</Grid>
<!-- Блок редактирования -->
<Grid Grid.Row="1" Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Поля редактирования -->
<StackPanel Grid.Row="0" Grid.Column="0" Margin="10">
<Label Content="Название работы" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="JobNameTextBox" Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}" ToolTip="Введите название работы"
PreviewTextInput="NameTextBox_PreviewTextInput"
TextChanged="NameTextBox_TextChanged"/>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" Margin="10">
<Label Content="Дата начала работы" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="StartJobPicker" Width="250" Height="40"
ToolTip="Выберите дату начала" />
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="0" Margin="10">
<Label Content="Дата окончания работы" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="EndJobPicker" Width="250" Height="40"
ToolTip="Выберите дату окончания" />
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="1" Margin="10">
<Label Content="Совместительство" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="PartTimeTextBox" Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}" ToolTip="Укажите частичную занятость"
PreviewTextInput="NameTextBox_PreviewTextInput"
TextChanged="NameTextBox_TextChanged"/>
</StackPanel>
<StackPanel Grid.Row="2" Grid.Column="0" Margin="10">
<Label Content="Ставка" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="BidTextBox" Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}" ToolTip="Введите ставку"
PreviewTextInput="NameTextBox_PreviewTextInput"
TextChanged="NameTextBox_TextChanged"/>
</StackPanel>
<StackPanel Grid.Row="2" Grid.Column="1" Margin="10">
<Label Content="Физическое лицо" Foreground="White" HorizontalAlignment="Center"/>
<ComboBox x:Name="PhysicalPersonComboBox" Width="250" Height="40"
ToolTip="Выберите физическое лицо" />
</StackPanel>
</Grid>
<!-- Кнопка сохранения -->
<Button Grid.Row="2" Content="Сохранить изменения"
Width="250" Height="40"
VerticalAlignment="Bottom"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="SaveButton_Click"
HorizontalAlignment="Center" Margin="0,10,0,0"/>
</Grid>
</Grid>
</Window>

View File

@ -0,0 +1,243 @@
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView.Employee
{
/// <summary>
/// Логика взаимодействия для EditEmployeeWindow.xaml
/// </summary>
public partial class EditEmployeeWindow : Window
{
private readonly IEmployeeLogic _employeeLogic;
private readonly IPhisicalPersonLogic _physicalPersonLogic;
private List<EmployeeViewModel> _employees;
public EditEmployeeWindow(IEmployeeLogic employeeLogic, IPhisicalPersonLogic physicalPersonLogic)
{
_employeeLogic = employeeLogic;
_physicalPersonLogic = physicalPersonLogic;
InitializeComponent();
LoadEmployees();
LoadPhysicalPersons();
}
private void LoadEmployees()
{
_employees = _employeeLogic.GetFullList();
// Заполняем комбинированное свойство, если нужно
foreach (var employee in _employees)
{
var physicalPerson = _physicalPersonLogic.GetElement(employee.PhysicalPersonsId ?? 0);
employee.PhysicalPersonName = physicalPerson?.FullNameWithBirthday;
}
EmployeeComboBox.ItemsSource = _employees;
EmployeeComboBox.DisplayMemberPath = "DisplayText"; // Используем новое свойство
EmployeeComboBox.SelectedValuePath = "Id";
}
private void LoadPhysicalPersons()
{
var physicalPersons = _physicalPersonLogic.GetFullList();
PhysicalPersonComboBox.ItemsSource = physicalPersons;
PhysicalPersonComboBox.DisplayMemberPath = "FullNameWithBirthday";
PhysicalPersonComboBox.SelectedValuePath = "Id";
}
private void EmployeeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (EmployeeComboBox.SelectedValue is int selectedEmployeeId)
{
LoadEmployee(selectedEmployeeId);
}
}
private void LoadEmployee(int employeeId)
{
var employee = _employeeLogic.GetElement(employeeId);
if (employee != null)
{
JobNameTextBox.Text = employee.NameJob;
StartJobPicker.SelectedDate = employee.StartJob;
EndJobPicker.SelectedDate = employee.EndJob;
PartTimeTextBox.Text = employee.PartTimeJob;
BidTextBox.Text = employee.Bid.ToString();
PhysicalPersonComboBox.SelectedValue = employee.PhysicalPersonsId;
}
}
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var searchText = SearchTextBox.Text.ToLower();
var filteredEmployees = _employees
.Where(emp => emp.NameJob.ToLower().Contains(searchText) ||
emp.PhysicalPersonName?.ToLower().Contains(searchText) == true)
.ToList();
EmployeeComboBox.ItemsSource = filteredEmployees;
}
private void NameTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
// Разрешаем только буквы
e.Handled = !char.IsLetter(e.Text, 0);
}
private void NameTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Получаем текущий текст
string currentText = textBox.Text;
// Если текст не пустой, преобразуем первую букву в заглавную, а остальные в строчные
if (!string.IsNullOrEmpty(currentText))
{
// Разбиваем строку по пробелам, чтобы обрабатывать каждое слово отдельно
var words = currentText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < words.Length; i++)
{
// Преобразуем первую букву в заглавную, а остальные в строчные
words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower();
}
// Объединяем слова обратно в строку и обновляем текст
textBox.Text = string.Join(" ", words);
// Устанавливаем курсор в конец текста
textBox.SelectionStart = textBox.Text.Length;
}
}
private void TelephoneTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !char.IsDigit(e.Text, 0);
}
private void TelephoneTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Удаляем все символы, кроме цифр
string rawInput = new string(textBox.Text.Where(char.IsDigit).ToArray());
// Добавляем "7" по умолчанию
if (!rawInput.StartsWith("7"))
rawInput = "7" + rawInput;
if (rawInput.Length > 11) rawInput = rawInput.Substring(0, 11);
// Форматируем как +7 (XXX) XXX-XX-XX
if (rawInput.Length <= 1)
textBox.Text = "+7 ";
else if (rawInput.Length <= 4)
textBox.Text = $"+7 ({rawInput.Substring(1)}";
else if (rawInput.Length <= 7)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4)}";
else if (rawInput.Length <= 9)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7)}";
else
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7, 2)}-{rawInput.Substring(9)}";
// Устанавливаем курсор в конец
textBox.SelectionStart = textBox.Text.Length;
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
bool isValid = true;
// Проверка обязательных полей
if (string.IsNullOrWhiteSpace(JobNameTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Название должности' не заполнено.");
}
if (string.IsNullOrWhiteSpace(PartTimeTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Совместительство' не заполнено.");
}
if (string.IsNullOrWhiteSpace(BidTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Ставка' не заполнено.");
}
if (!StartJobPicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Начало работы' не выбрано.");
}
if (!EndJobPicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Конец работы' не выбрано.");
}
if (PhysicalPersonComboBox.SelectedItem == null)
{
isValid = false;
MessageBox.Show("Поле 'Пол' не выбрано.");
}
// Если все поля заполнены, продолжаем выполнение
if (isValid)
if (EmployeeComboBox.SelectedValue is int selectedEmployeeId)
{
try
{
var updatedEmployee = new EmployeeViewModel
{
Id = selectedEmployeeId,
NameJob = JobNameTextBox.Text,
StartJob = StartJobPicker.SelectedDate.Value.ToUniversalTime(),
EndJob = EndJobPicker.SelectedDate.Value.ToUniversalTime(),
PartTimeJob = PartTimeTextBox.Text,
Bid = float.Parse(BidTextBox.Text),
PhysicalPersonsId = PhysicalPersonComboBox.SelectedValue as int?
};
_employeeLogic.Update(updatedEmployee);
MessageBox.Show("Данные успешно обновлены!");
this.Close();
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка: {ex.Message}");
}
}
else
{
MessageBox.Show("Выберите сотрудника перед сохранением!", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
}
}

View File

@ -0,0 +1,51 @@
<Window x:Class="EmployeeManagmentView.Employee.EmployeeManagementWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Управление сотрудниками"
Height="400" Width="400"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Управление сотрудниками"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Стек кнопок -->
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- Кнопка "Удаление сотрудника" -->
<Button Content="Удаление сотрудника"
Width="250" Height="40"
Margin="0,0,0,10"
Background="#004890" Foreground="#FFFFFF"
Style="{StaticResource RoundedButtonStyle}"
Click ="OpenDeleteEmployeeWindow"/>
<!-- Кнопка "Добавление сотрудника" -->
<Button Content="Добавление сотрудника"
Width="250" Height="40"
Margin="0,0,0,10"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenAddEmployeeWindow"/>
<!-- Кнопка "Редактирование сотрудника" -->
<Button Content="Редактирование сотрудника"
Width="250" Height="40"
Margin="0,0,0,10"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenEditEmployeeWindow"/>
<!-- Кнопка "Просмотр сотрудника" -->
<Button Content="Просмотр сотрудников"
Width="250" Height="40"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenViewEmployeesWindow"/>
</StackPanel>
</Grid>
</Window>

View File

@ -0,0 +1,100 @@
using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentView.PhysicalPerson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView.Employee
{
/// <summary>
/// Логика взаимодействия для EmployeeManagementWindow.xaml
/// </summary>
public partial class EmployeeManagementWindow : Window
{
private readonly IEmployeeLogic _employeeLogic;
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
private readonly ISalaryLogic _salaryLogic;
private readonly IVacationLogic _vacationLogic;
public EmployeeManagementWindow(IEmployeeLogic employeeLogic, IPhisicalPersonLogic phisicalPersonLogic, ISalaryLogic salaryLogic, IVacationLogic vacationLogic)
{
_employeeLogic = employeeLogic;
_phisicalPersonLogic = phisicalPersonLogic;
_salaryLogic = salaryLogic;
_vacationLogic = vacationLogic;
InitializeComponent();
}
private void OpenAddEmployeeWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is AddEmployeeWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var addWindow = new AddEmployeeWindow(_employeeLogic, _phisicalPersonLogic);
addWindow.Show();
}
private void OpenDeleteEmployeeWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is DeleteEmployeeWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var deleteWindow = new DeleteEmployeeWindow(_employeeLogic);
deleteWindow.Show();
}
private void OpenEditEmployeeWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is EditEmployeeWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var editWindow = new EditEmployeeWindow(_employeeLogic, _phisicalPersonLogic);
editWindow.Show();
}
private void OpenViewEmployeesWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is ViewEmployeeWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var viewWindow = new ViewEmployeeWindow(_employeeLogic, _salaryLogic, _vacationLogic, _phisicalPersonLogic);
viewWindow.Show();
}
}
}

View File

@ -0,0 +1,78 @@
<Window x:Class="EmployeeManagmentView.Employee.Salary.AddSalaryWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Добавление зарплаты"
Height="500" Width="600"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<TextBlock Text="Добавление зарплаты"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<Grid Margin="0,60">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Поле для сотрудника -->
<StackPanel Grid.Row="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" Margin="0,10">
<Label Content="Сотрудник" Foreground="White" HorizontalAlignment="Center"/>
<ComboBox x:Name="EmployeeComboBox" Width="400" Height="40"
Background="White" Margin="0,5"
ToolTip="Выберите сотрудника" />
</StackPanel>
<!-- Поле для количества часов -->
<StackPanel Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" Margin="0,10">
<Label Content="Количество часов" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="HoursTextBox" Width="200" Height="40"
Margin="0,5" ToolTip="Введите количество часов"
PreviewTextInput="NumericTextBox_PreviewTextInput"/>
</StackPanel>
<!-- Поле для ставки -->
<StackPanel Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" Margin="0,10">
<Label Content="Цена за час" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="PriceTextBox" Width="200" Height="40"
Margin="0,5" ToolTip="Введите ставку"
PreviewTextInput="DecimalTextBox_PreviewTextInput"
TextChanged="DecimalTextBox_TextChanged"/>
</StackPanel>
<!-- Поле для премии -->
<StackPanel Grid.Row="2" Grid.Column="0" HorizontalAlignment="Center" Margin="0,10">
<Label Content="Премия" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="PremiumTextBox" Width="200" Height="40"
Margin="0,5" ToolTip="Введите премию (если есть)"
PreviewTextInput="DecimalTextBox_PreviewTextInput"
TextChanged="DecimalTextBox_TextChanged"/>
</StackPanel>
<!-- Поле для даты -->
<StackPanel Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center" Margin="0,10">
<Label Content="Дата" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="DatePicker" Width="200" Height="40"
Margin="0,5" ToolTip="Выберите дату выплаты" />
</StackPanel>
<Button Grid.Row="4" Grid.ColumnSpan="2" Content="Сохранить"
Width="200" Height="40"
Background="#004890" Foreground="White"
Margin="0,10"
Click="SaveButton_Click" HorizontalAlignment="Center"/>
</Grid>
</Grid>
</Window>

View File

@ -0,0 +1,228 @@
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView.Employee.Salary
{
/// <summary>
/// Логика взаимодействия для AddSalaryWindow.xaml
/// </summary>
public partial class AddSalaryWindow : Window
{
private readonly ISalaryLogic _salaryLogic;
private readonly IEmployeeLogic _employeeLogic;
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
private List<EmployeeViewModel> _employees;
public AddSalaryWindow(ISalaryLogic salaryLogic, IEmployeeLogic employeeLogic, IPhisicalPersonLogic phisicalPersonLogic)
{
_salaryLogic = salaryLogic;
_employeeLogic = employeeLogic;
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
LoadEmployees();
}
private void NameTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
// Разрешаем только буквы
e.Handled = !char.IsLetter(e.Text, 0);
}
private void NameTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Получаем текущий текст
string currentText = textBox.Text;
// Если текст не пустой, преобразуем первую букву в заглавную, а остальные в строчные
if (!string.IsNullOrEmpty(currentText))
{
// Разбиваем строку по пробелам, чтобы обрабатывать каждое слово отдельно
var words = currentText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < words.Length; i++)
{
// Преобразуем первую букву в заглавную, а остальные в строчные
words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower();
}
// Объединяем слова обратно в строку и обновляем текст
textBox.Text = string.Join(" ", words);
// Устанавливаем курсор в конец текста
textBox.SelectionStart = textBox.Text.Length;
}
}
// Проверка на ввод только чисел и одной запятой
private void DecimalTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Разрешаем только цифры и запятую
e.Handled = !(char.IsDigit(e.Text, 0) || e.Text == ",");
// Проверка на количество запятых
if (e.Text == "," && textBox.Text.Contains(","))
{
e.Handled = true;
}
}
private void NumericTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
// Разрешаем ввод только цифр и запятой
e.Handled = !char.IsDigit(e.Text, 0);
}
// Ограничение на 2 знака после запятой
private void DecimalTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Получаем текущий текст
string currentText = textBox.Text;
// Проверяем наличие запятой
int commaIndex = currentText.IndexOf(',');
if (commaIndex != -1 && currentText.Length - commaIndex > 3)
{
// Обрезаем текст до двух знаков после запятой
textBox.Text = currentText.Substring(0, commaIndex + 3);
textBox.SelectionStart = textBox.Text.Length; // Устанавливаем курсор в конец текста
}
}
private void TelephoneTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !char.IsDigit(e.Text, 0);
}
private void TelephoneTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Удаляем все символы, кроме цифр
string rawInput = new string(textBox.Text.Where(char.IsDigit).ToArray());
// Добавляем "7" по умолчанию
if (!rawInput.StartsWith("7"))
rawInput = "7" + rawInput;
if (rawInput.Length > 11) rawInput = rawInput.Substring(0, 11);
// Форматируем как +7 (XXX) XXX-XX-XX
if (rawInput.Length <= 1)
textBox.Text = "+7 ";
else if (rawInput.Length <= 4)
textBox.Text = $"+7 ({rawInput.Substring(1)}";
else if (rawInput.Length <= 7)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4)}";
else if (rawInput.Length <= 9)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7)}";
else
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7, 2)}-{rawInput.Substring(9)}";
// Устанавливаем курсор в конец
textBox.SelectionStart = textBox.Text.Length;
}
private void LoadEmployees()
{
_employees = _employeeLogic.GetFullList();
// Заполняем комбинированное свойство, если нужно
foreach (var employee in _employees)
{
var physicalPerson = _phisicalPersonLogic.GetElement(employee.PhysicalPersonsId ?? 0);
employee.PhysicalPersonName = physicalPerson?.FullNameWithBirthday;
}
EmployeeComboBox.ItemsSource = _employees;
EmployeeComboBox.DisplayMemberPath = "DisplayText"; // Используем новое свойство
EmployeeComboBox.SelectedValuePath = "Id";
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
bool isValid = true;
// Проверка обязательных полей
if (string.IsNullOrWhiteSpace(HoursTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Название должности' не заполнено.");
}
if (string.IsNullOrWhiteSpace(PriceTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Совместительство' не заполнено.");
}
if (string.IsNullOrWhiteSpace(PremiumTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Ставка' не заполнено.");
}
if (!DatePicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Дата зарплаты' не выбрано.");
}
if (EmployeeComboBox.SelectedItem == null)
{
isValid = false;
MessageBox.Show("Поле 'Сотрудник' не выбрано.");
}
// Если все поля заполнены, продолжаем выполнение
if (isValid)
try
{
var salary = new SalaryViewModel
{
CountHours = int.Parse(HoursTextBox.Text),
PriceHour = float.Parse(PriceTextBox.Text),
Premium = string.IsNullOrEmpty(PremiumTextBox.Text) ? null : float.Parse(PremiumTextBox.Text),
Date = DatePicker.SelectedDate.Value.ToUniversalTime(),
EmployeeId = (int?)EmployeeComboBox.SelectedValue
};
_salaryLogic.Insert(salary);
MessageBox.Show("Зарплата успешно сохранена!");
Close();
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка: {ex.Message}");
}
}
}
}

View File

@ -0,0 +1,57 @@
<Window x:Class="EmployeeManagmentView.Employee.Salary.DeleteSalaryWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:EmployeeManagmentDataModels.Enums;assembly=EmployeeManagmentDataModels"
Title="Удаление зарплат"
Height="600" Width="800"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Window.Resources>
<local:BooleanToSalaryConverter x:Key="BooleanToSalaryConverter" />
</Window.Resources>
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Список зарплат"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="White"
Margin="0,20,0,0" />
<!-- Поле поиска -->
<TextBox x:Name="SearchTextBox"
Width="560"
VerticalAlignment="Top"
Margin="0,60,0,0"
HorizontalAlignment="Center"
Style="{StaticResource RoundedTextBoxStyle}"
TextChanged="SearchTextBox_TextChanged" />
<!-- Таблица зарплат -->
<DataGrid x:Name="SalariesDataGrid"
Margin="20,100,20,80"
AutoGenerateColumns="False"
Style="{StaticResource RoundedDataGridStyle}">
<DataGrid.Columns>
<DataGridTextColumn Header="Часы работы" Binding="{Binding CountHours}" Width="*" />
<DataGridTextColumn Header="Цена за час" Binding="{Binding PriceHour, StringFormat={}{0:F2}}" Width="*" />
<DataGridTextColumn Header="Премия" Binding="{Binding Premium, StringFormat={}{0:F2}}" Width="*" />
<DataGridTextColumn Header="Дата" Binding="{Binding Date, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Вылачено" Binding="{Binding Passed, Converter={StaticResource BooleanToSalaryConverter}}" Width="*" />
<DataGridTextColumn Header="Сотрудник" Binding="{Binding EmployeeName}" Width="*" />
</DataGrid.Columns>
</DataGrid>
<!-- Кнопка добавления/редактирования -->
<Button Content="Удалить"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Width="150" Height="40"
Margin="0,0,0,20"
Background="#004890"
Foreground="White"
Style="{StaticResource RoundedButtonStyle}"
Click="DeleteButton_Click" />
</Grid>
</Window>

View File

@ -0,0 +1,82 @@
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView.Employee.Salary
{
/// <summary>
/// Логика взаимодействия для DeleteSalaryWindow.xaml
/// </summary>
public partial class DeleteSalaryWindow : Window
{
private readonly ISalaryLogic _salaryLogic;
private IEnumerable<SalaryViewModel> _allSalaries;
public DeleteSalaryWindow(ISalaryLogic salaryLogic)
{
_salaryLogic = salaryLogic;
InitializeComponent();
LoadSalaries();
}
private void LoadSalaries()
{
_allSalaries = _salaryLogic.GetFullList(); // Загрузка всех данных
SalariesDataGrid.ItemsSource = _allSalaries;
}
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
if (SalariesDataGrid.SelectedItem is SalaryViewModel selectedSalary)
{
// Удаление зарплаты
_salaryLogic.Delete(selectedSalary.Id);
MessageBox.Show("Зарплата успешно удалена!");
LoadSalaries(); // Перезагрузка данных после удаления
SearchTextBox.Text = string.Empty; // Очистка поля поиска
}
else
{
MessageBox.Show("Пожалуйста, выберите запись для удаления.");
}
}
private void SearchTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
string query = SearchTextBox.Text.ToLower();
if (string.IsNullOrWhiteSpace(query))
{
// Отображаем все записи
SalariesDataGrid.ItemsSource = _allSalaries;
}
else
{
// Фильтрация по всем полям сущности
var filteredList = _allSalaries.Where(sal =>
(sal.EmployeeName?.ToLower().Contains(query) ?? false) ||
sal.CountHours.ToString().Contains(query) ||
sal.PriceHour.ToString().Contains(query) ||
sal.Passed.ToString().ToLower().Contains(query) ||
(sal.Premium.HasValue && sal.Premium.Value.ToString().Contains(query)) ||
(sal.Date.HasValue && sal.Date.Value.ToString("dd.MM.yyyy").Contains(query))
).ToList();
SalariesDataGrid.ItemsSource = filteredList;
}
}
}
}

View File

@ -0,0 +1,84 @@
<Window x:Class="EmployeeManagmentView.Employee.Salary.EditSalaryWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Редактирование зарплаты"
Height="500" Width="600"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid Margin="0,0,0,0">
<TextBlock Text="Редактирование зарплаты"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Блок поиска и выбора зарплаты -->
<Grid HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,70,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Поиск зарплаты" Foreground="White" HorizontalAlignment="Center" Margin="0,0,10,10" />
<TextBox x:Name="SearchTextBox" Grid.Row="0" Grid.Column="1" Width="250" Height="30"
Style="{StaticResource RoundedTextBoxStyle}" ToolTip="Введите для поиска"
TextChanged="SearchTextBox_TextChanged" />
<Label Grid.Row="1" Grid.Column="0" Content="Выберите зарплату" Foreground="White" HorizontalAlignment="Center" Margin="0,10,10,10" />
<ComboBox x:Name="SalaryComboBox" Grid.Row="1" Grid.Column="1" Width="250" Height="30"
SelectionChanged="SalaryComboBox_SelectionChanged" />
</Grid>
<!-- Блок редактирования зарплаты -->
<Grid Margin="0,150,0,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Margin="10">
<Label Content="Часы работы" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="CountHoursTextBox" Width="250" Height="40" Style="{StaticResource RoundedTextBoxStyle}"
PreviewTextInput="NumericTextBox_PreviewTextInput"/>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" Margin="10">
<Label Content="Ставка за час" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="PriceHourTextBox" Width="250" Height="40" Style="{StaticResource RoundedTextBoxStyle}"
PreviewTextInput="DecimalTextBox_PreviewTextInput"
TextChanged="DecimalTextBox_TextChanged"/>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="0" Margin="10">
<Label Content="Премия" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="PremiumTextBox" Width="250" Height="40" Style="{StaticResource RoundedTextBoxStyle}"
PreviewTextInput="DecimalTextBox_PreviewTextInput"
TextChanged="DecimalTextBox_TextChanged"/>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="1" Margin="10">
<Label Content="Дата" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="DatePicker" Width="250" Height="40" />
</StackPanel>
<StackPanel Grid.Row="2" Grid.ColumnSpan="2" Margin="10">
<Label Content="Зарплата выплачена" Foreground="White" HorizontalAlignment="Center"/>
<CheckBox x:Name="PassedCheckBox" Content="Выплачено" Foreground="White" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Кнопка сохранения -->
<Button Grid.Row="4" Grid.ColumnSpan="2" Content="Сохранить изменения" Width="250" Height="40"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="SaveButton_Click" Margin="0,10,0,0"/>
</Grid>
</Grid>
</Window>

View File

@ -0,0 +1,255 @@
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView.Employee.Salary
{
/// <summary>
/// Логика взаимодействия для EditSalaryWindow.xaml
/// </summary>
public partial class EditSalaryWindow : Window
{
private readonly ISalaryLogic _salaryLogic; // Логика для работы с зарплатами
private readonly IEmployeeLogic _employeeLogic; // Логика для работы с сотрудниками
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
private List<SalaryViewModel> _salaries;
private List<EmployeeViewModel> _employees; // Список сотрудников
public EditSalaryWindow(ISalaryLogic salaryLogic, IEmployeeLogic employeeLogic, IPhisicalPersonLogic phisicalPersonLogic)
{
_salaryLogic = salaryLogic;
_employeeLogic = employeeLogic;
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
LoadSalaries();
}
private void LoadSalaries()
{
_salaries = _salaryLogic.GetFullList();
SalaryComboBox.ItemsSource = _salaries;
SalaryComboBox.DisplayMemberPath = "DisplayName";
SalaryComboBox.SelectedValuePath = "Id";
}
private void SalaryComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (SalaryComboBox.SelectedValue is int selectedSalaryId)
{
LoadSalary(selectedSalaryId);
}
}
private void LoadSalary(int salaryId)
{
var salary = _salaryLogic.GetElement(salaryId);
if (salary != null)
{
CountHoursTextBox.Text = salary.CountHours.ToString();
PriceHourTextBox.Text = salary.PriceHour.ToString();
PremiumTextBox.Text = salary.Premium?.ToString() ?? string.Empty;
DatePicker.SelectedDate = salary.Date;
PassedCheckBox.IsChecked = salary.Passed;
}
else
{
MessageBox.Show("Зарплата не найдена", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var searchText = SearchTextBox.Text.ToLower();
var filteredSalaries = _salaries
.Where(sal => sal.EmployeeName.ToLower().Contains(searchText))
.ToList();
SalaryComboBox.ItemsSource = filteredSalaries;
}
private void NameTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
// Разрешаем только буквы
e.Handled = !char.IsLetter(e.Text, 0);
}
private void NameTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Получаем текущий текст
string currentText = textBox.Text;
// Если текст не пустой, преобразуем первую букву в заглавную, а остальные в строчные
if (!string.IsNullOrEmpty(currentText))
{
// Разбиваем строку по пробелам, чтобы обрабатывать каждое слово отдельно
var words = currentText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < words.Length; i++)
{
// Преобразуем первую букву в заглавную, а остальные в строчные
words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower();
}
// Объединяем слова обратно в строку и обновляем текст
textBox.Text = string.Join(" ", words);
// Устанавливаем курсор в конец текста
textBox.SelectionStart = textBox.Text.Length;
}
}
// Проверка на ввод только чисел и одной запятой
private void DecimalTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Разрешаем только цифры и запятую
e.Handled = !(char.IsDigit(e.Text, 0) || e.Text == ",");
// Проверка на количество запятых
if (e.Text == "," && textBox.Text.Contains(","))
{
e.Handled = true;
}
}
private void NumericTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
// Разрешаем ввод только цифр и запятой
e.Handled = !char.IsDigit(e.Text, 0);
}
// Ограничение на 2 знака после запятой
private void DecimalTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Получаем текущий текст
string currentText = textBox.Text;
// Проверяем наличие запятой
int commaIndex = currentText.IndexOf(',');
if (commaIndex != -1 && currentText.Length - commaIndex > 3)
{
// Обрезаем текст до двух знаков после запятой
textBox.Text = currentText.Substring(0, commaIndex + 3);
textBox.SelectionStart = textBox.Text.Length; // Устанавливаем курсор в конец текста
}
}
private void TelephoneTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !char.IsDigit(e.Text, 0);
}
private void TelephoneTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Удаляем все символы, кроме цифр
string rawInput = new string(textBox.Text.Where(char.IsDigit).ToArray());
// Добавляем "7" по умолчанию
if (!rawInput.StartsWith("7"))
rawInput = "7" + rawInput;
if (rawInput.Length > 11) rawInput = rawInput.Substring(0, 11);
// Форматируем как +7 (XXX) XXX-XX-XX
if (rawInput.Length <= 1)
textBox.Text = "+7 ";
else if (rawInput.Length <= 4)
textBox.Text = $"+7 ({rawInput.Substring(1)}";
else if (rawInput.Length <= 7)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4)}";
else if (rawInput.Length <= 9)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7)}";
else
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7, 2)}-{rawInput.Substring(9)}";
// Устанавливаем курсор в конец
textBox.SelectionStart = textBox.Text.Length;
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
bool isValid = true;
// Проверка обязательных полей
if (string.IsNullOrWhiteSpace(CountHoursTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Название должности' не заполнено.");
}
if (string.IsNullOrWhiteSpace(PriceHourTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Совместительство' не заполнено.");
}
if (string.IsNullOrWhiteSpace(PremiumTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Ставка' не заполнено.");
}
if (!DatePicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Дата зарплаты' не выбрано.");
}
if (isValid)
try
{
if (SalaryComboBox.SelectedValue is int selectedSalaryId)
{
var updatedSalary = new SalaryViewModel
{
Id = selectedSalaryId,
CountHours = int.Parse(CountHoursTextBox.Text),
PriceHour = float.Parse(PriceHourTextBox.Text),
Premium = float.TryParse(PremiumTextBox.Text, out var premium) ? premium : (float?)null,
Date = DatePicker.SelectedDate.Value.ToUniversalTime(),
Passed = PassedCheckBox.IsChecked ?? false,
};
_salaryLogic.Update(updatedSalary);
MessageBox.Show("Зарплата успешно обновлена!");
this.Close();
}
else
{
MessageBox.Show("Выберите зарплату перед сохранением!", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка при сохранении данных: {ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}

View File

@ -0,0 +1,51 @@
<Window x:Class="EmployeeManagmentView.Employee.Salary.SalaryManagementWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Управление зарплатой"
Height="400" Width="400"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Управление зарплатой"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Стек кнопок -->
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- Кнопка "Удаление зарплаты" -->
<Button Content="Удаление зарплаты"
Width="250" Height="40"
Margin="0,0,0,10"
Background="#004890" Foreground="#FFFFFF"
Style="{StaticResource RoundedButtonStyle}"
Click="OpenDeleteSalaryWindow"/>
<!-- Кнопка "Добавление зарплаты" -->
<Button Content="Добавление зарплаты"
Width="250" Height="40"
Margin="0,0,0,10"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenAddSalaryWindow"/>
<!-- Кнопка "Редактирование зарплаты" -->
<Button Content="Редактирование зарплаты"
Width="250" Height="40"
Margin="0,0,0,10"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenEditSalaryWindow"/>
<!-- Кнопка "Просмотр зарплат" -->
<Button Content="Просмотр зарплат"
Width="250" Height="40"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenViewSalaryWindow"/>
</StackPanel>
</Grid>
</Window>

View File

@ -0,0 +1,101 @@
using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentView.Employee.Vacation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView.Employee.Salary
{
/// <summary>
/// Логика взаимодействия для SalaryManagementWindow.xaml
/// </summary>
public partial class SalaryManagementWindow : Window
{
private readonly ISalaryLogic _salaryLogic;
private readonly IEmployeeLogic _employeeLogic;
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
public SalaryManagementWindow(ISalaryLogic salaryLogic, IEmployeeLogic employeeLogic, IPhisicalPersonLogic phisicalPersonLogic)
{
_salaryLogic = salaryLogic;
_employeeLogic = employeeLogic;
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
}
private void OpenAddSalaryWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is AddSalaryWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var addWindow = new AddSalaryWindow(_salaryLogic, _employeeLogic, _phisicalPersonLogic);
addWindow.Show();
}
private void OpenDeleteSalaryWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is DeleteSalaryWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var deleteWindow = new DeleteSalaryWindow(_salaryLogic);
deleteWindow.Show();
}
private void OpenEditSalaryWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is EditSalaryWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var editWindow = new EditSalaryWindow(_salaryLogic, _employeeLogic, _phisicalPersonLogic);
editWindow.Show();
}
private void OpenViewSalaryWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is ViewSalaryWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var viewWindow = new ViewSalaryWindow(_salaryLogic);
viewWindow.Show();
}
}
}

View File

@ -0,0 +1,56 @@
<Window x:Class="EmployeeManagmentView.Employee.Salary.ViewSalaryWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:EmployeeManagmentDataModels.Enums;assembly=EmployeeManagmentDataModels"
Title="Список зарплат"
Height="600" Width="800"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Window.Resources>
<local:BooleanToSalaryConverter x:Key="BooleanToSalaryConverter" />
</Window.Resources>
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Список зарплат"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="White"
Margin="0,20,0,0" />
<!-- Поле поиска -->
<TextBox x:Name="SearchTextBox"
Width="560"
VerticalAlignment="Top"
Margin="0,60,0,0"
HorizontalAlignment="Center"
Style="{StaticResource RoundedTextBoxStyle}"
TextChanged="SearchTextBox_TextChanged" />
<!-- Таблица зарплат -->
<DataGrid x:Name="SalariesDataGrid"
Margin="20,100,20,80"
AutoGenerateColumns="False"
Style="{StaticResource RoundedDataGridStyle}">
<DataGrid.Columns>
<DataGridTextColumn Header="Часы работы" Binding="{Binding CountHours}" Width="*" />
<DataGridTextColumn Header="Цена за час" Binding="{Binding PriceHour, StringFormat={}{0:F2}}" Width="*" />
<DataGridTextColumn Header="Премия" Binding="{Binding Premium, StringFormat={}{0:F2}}" Width="*" />
<DataGridTextColumn Header="Дата" Binding="{Binding Date, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Оплачено" Binding="{Binding Passed, Converter={StaticResource BooleanToSalaryConverter}}" Width="*" />
<DataGridTextColumn Header="Работник" Binding="{Binding EmployeeName}" Width="*" />
</DataGrid.Columns>
</DataGrid>
<!-- Кнопка генерации отчета -->
<Button Content="Генерация отчета"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Width="150" Height="40"
Margin="0,0,0,20"
Background="#004890"
Click="ExportToExcelButton_Click"
Foreground="White"
Style="{StaticResource RoundedButtonStyle}" />
</Grid>
</Window>

View File

@ -0,0 +1,180 @@
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;
using Microsoft.Win32;
namespace EmployeeManagmentView.Employee.Salary
{
/// <summary>
/// Логика взаимодействия для ViewSalaryWindow.xaml
/// </summary>
public partial class ViewSalaryWindow : Window
{
private readonly ISalaryLogic _salaryLogic;
private IEnumerable<SalaryViewModel> _allSalaries;
public ViewSalaryWindow(ISalaryLogic salaryLogic)
{
_salaryLogic = salaryLogic;
InitializeComponent();
LoadSalaries();
}
private void LoadSalaries()
{
_allSalaries = _salaryLogic.GetFullList(); // Загрузка всех данных
SalariesDataGrid.ItemsSource = _allSalaries;
}
private void ExportToExcelButton_Click(object sender, RoutedEventArgs e)
{
try
{
// Получаем данные о зарплатах
var salaries = _salaryLogic.GetFullList();
if (salaries == null || !salaries.Any())
{
MessageBox.Show("Нет данных для экспорта.", "Внимание", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
// Открытие диалогового окна для сохранения файла
SaveFileDialog saveFileDialog = new SaveFileDialog
{
Filter = "Excel файлы (*.xlsx)|*.xlsx", // фильтр для файлов .xlsx
Title = "Сохранить отчет об зарплатах", // заголовок окна
FileName = "Отчет_зарплат.xlsx" // имя по умолчанию
};
// Проверка, что пользователь выбрал путь и имя файла
if (saveFileDialog.ShowDialog() == true)
{
string filePath = saveFileDialog.FileName; // Путь и имя файла
GenerateExcelReport(filePath, salaries); // Генерация отчета
MessageBox.Show($"Отчет успешно сохранен: {filePath}", "Успех", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка экспорта: {ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void GenerateExcelReport(string filePath, List<SalaryViewModel> salaries)
{
using (SpreadsheetDocument document = SpreadsheetDocument.Create(filePath, SpreadsheetDocumentType.Workbook))
{
// Создаем Workbook
WorkbookPart workbookPart = document.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
// Создаем Worksheet
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
// Добавляем лист в Workbook
Sheets sheets = document.WorkbookPart.Workbook.AppendChild(new Sheets());
Sheet sheet = new Sheet()
{
Id = document.WorkbookPart.GetIdOfPart(worksheetPart),
SheetId = 1,
Name = "Зарплаты"
};
sheets.Append(sheet);
// Получаем SheetData
SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
// Заполняем заголовки
Row headerRow = new Row();
headerRow.Append(
CreateTextCell("A", "ID"),
CreateTextCell("B", "Сотрудник"),
CreateTextCell("C", "Часы"),
CreateTextCell("D", "Ставка"),
CreateTextCell("E", "Премия"),
CreateTextCell("F", "Дата"),
CreateTextCell("G", "Статус оплаты") // Добавлен заголовок для Passed
);
sheetData.AppendChild(headerRow);
// Заполняем данные
foreach (var salary in salaries)
{
Row row = new Row();
row.Append(
CreateTextCell("A", salary.Id.ToString()),
CreateTextCell("B", salary.EmployeeName),
CreateTextCell("C", salary.CountHours.ToString()),
CreateTextCell("D", salary.PriceHour.ToString("F2")),
CreateTextCell("E", salary.Premium?.ToString("F2") ?? "0"),
CreateTextCell("F", salary.Date.Value.ToString("dd.MM.yyyy")),
CreateTextCell("G", salary.Passed ? "Заплачено" : "Не заплачено") // Используем поле Passed
);
sheetData.AppendChild(row);
}
workbookPart.Workbook.Save();
}
}
// Метод для создания текстовой ячейки
private Cell CreateTextCell(string columnName, string text)
{
return new Cell
{
DataType = CellValues.String,
CellReference = columnName,
CellValue = new CellValue(text)
};
}
private void SearchTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
string query = SearchTextBox.Text.ToLower();
if (string.IsNullOrWhiteSpace(query))
{
// Отображаем все записи
SalariesDataGrid.ItemsSource = _allSalaries;
}
else
{
// Фильтрация по всем полям сущности
var filteredList = _allSalaries.Where(sal =>
(sal.EmployeeName?.ToLower().Contains(query) ?? false) ||
sal.CountHours.ToString().Contains(query) ||
sal.PriceHour.ToString().Contains(query) ||
(sal.Premium.HasValue && sal.Premium.Value.ToString().Contains(query)) ||
(sal.Date.HasValue && sal.Date.Value.ToString("dd.MM.yyyy").Contains(query)) ||
(sal.Passed ? "заплачено" : "не заплачено").Contains(query) // Добавлен фильтр для Passed
).ToList();
SalariesDataGrid.ItemsSource = filteredList;
}
}
}
}

View File

@ -0,0 +1,65 @@
<Window x:Class="EmployeeManagmentView.Employee.Vacation.AddVacationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Добавление отпуска"
Height="450" Width="600"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<TextBlock Text="Добавление отпуска"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<Grid Margin="0,60">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Поле для сотрудника -->
<StackPanel Grid.Row="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" Margin="0,10">
<Label Content="Сотрудник" Foreground="White" HorizontalAlignment="Center"/>
<ComboBox x:Name="EmployeeComboBox" Width="400" Height="40"
Background="White" Margin="0,5"
ToolTip="Выберите сотрудника" />
</StackPanel>
<!-- Поле для начала отпуска -->
<StackPanel Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" Margin="0,10">
<Label Content="Дата начала" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="StartDatePicker" Width="200" Height="40"
Margin="0,5" ToolTip="Выберите дату начала отпуска" />
</StackPanel>
<!-- Поле для окончания отпуска -->
<StackPanel Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" Margin="0,10">
<Label Content="Дата окончания" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="EndDatePicker" Width="200" Height="40"
Margin="0,5" ToolTip="Выберите дату окончания отпуска" />
</StackPanel>
<!-- Чекбокс для отметки пройденного отпуска -->
<StackPanel Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Center" Margin="0,10">
<CheckBox x:Name="PassedCheckBox" Content="Отпуск завершен" Foreground="White"
FontSize="14" VerticalAlignment="Center"/>
</StackPanel>
<Button Grid.Row="3" Grid.ColumnSpan="2" Content="Сохранить"
Width="200" Height="40"
Background="#004890" Foreground="White"
Margin="0,10"
Click="SaveButton_Click" HorizontalAlignment="Center"/>
</Grid>
</Grid>
</Window>

View File

@ -0,0 +1,172 @@
using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView.Employee.Vacation
{
/// <summary>
/// Логика взаимодействия для AddVacationWindow.xaml
/// </summary>
public partial class AddVacationWindow : Window
{
private readonly IVacationLogic _vacationLogic;
private readonly IEmployeeLogic _employeeLogic;
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
private List<EmployeeViewModel> _employees;
public AddVacationWindow(IVacationLogic vacationLogic, IEmployeeLogic employeeLogic, IPhisicalPersonLogic phisicalPersonLogic)
{
_vacationLogic = vacationLogic;
_employeeLogic = employeeLogic;
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
LoadEmployees();
}
private void LoadEmployees()
{
_employees = _employeeLogic.GetFullList();
// Заполняем комбинированное свойство, если нужно
foreach (var employee in _employees)
{
var physicalPerson = _phisicalPersonLogic.GetElement(employee.PhysicalPersonsId ?? 0);
employee.PhysicalPersonName = physicalPerson?.FullNameWithBirthday;
}
EmployeeComboBox.ItemsSource = _employees;
EmployeeComboBox.DisplayMemberPath = "DisplayText"; // Используем новое свойство
EmployeeComboBox.SelectedValuePath = "Id";
}
private void NameTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
// Разрешаем только буквы
e.Handled = !char.IsLetter(e.Text, 0);
}
private void NameTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Получаем текущий текст
string currentText = textBox.Text;
// Если текст не пустой, преобразуем первую букву в заглавную, а остальные в строчные
if (!string.IsNullOrEmpty(currentText))
{
// Разбиваем строку по пробелам, чтобы обрабатывать каждое слово отдельно
var words = currentText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < words.Length; i++)
{
// Преобразуем первую букву в заглавную, а остальные в строчные
words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower();
}
// Объединяем слова обратно в строку и обновляем текст
textBox.Text = string.Join(" ", words);
// Устанавливаем курсор в конец текста
textBox.SelectionStart = textBox.Text.Length;
}
}
private void TelephoneTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !char.IsDigit(e.Text, 0);
}
private void TelephoneTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Удаляем все символы, кроме цифр
string rawInput = new string(textBox.Text.Where(char.IsDigit).ToArray());
// Добавляем "7" по умолчанию
if (!rawInput.StartsWith("7"))
rawInput = "7" + rawInput;
if (rawInput.Length > 11) rawInput = rawInput.Substring(0, 11);
// Форматируем как +7 (XXX) XXX-XX-XX
if (rawInput.Length <= 1)
textBox.Text = "+7 ";
else if (rawInput.Length <= 4)
textBox.Text = $"+7 ({rawInput.Substring(1)}";
else if (rawInput.Length <= 7)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4)}";
else if (rawInput.Length <= 9)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7)}";
else
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7, 2)}-{rawInput.Substring(9)}";
// Устанавливаем курсор в конец
textBox.SelectionStart = textBox.Text.Length;
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
bool isValid = true;
if (!StartDatePicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Начало отпуска' не выбрано.");
}
if (!EndDatePicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Конец отпуска' не выбрано.");
}
if (EmployeeComboBox.SelectedItem == null)
{
isValid = false;
MessageBox.Show("Поле 'Сотрудник' не выбрано.");
}
// Если все поля заполнены, продолжаем выполнение
if (isValid)
try
{
var vacation = new VacationViewModel
{
StartData = StartDatePicker.SelectedDate.Value.ToUniversalTime(),
EndData = EndDatePicker.SelectedDate.Value.ToUniversalTime(),
Passed = PassedCheckBox.IsChecked ?? false,
EmployeeId = (int?)EmployeeComboBox.SelectedValue
};
_vacationLogic.Insert(vacation);
MessageBox.Show("Отпуск успешно сохранен!");
Close();
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка: {ex.Message}");
}
}
}
}

View File

@ -0,0 +1,54 @@
<Window x:Class="EmployeeManagmentView.Employee.Vacation.DeleteVacationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:EmployeeManagmentDataModels.Enums;assembly=EmployeeManagmentDataModels"
Title="Удаление отпуска"
Height="600" Width="800"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Window.Resources>
<local:BooleanToVacationConverter x:Key="BooleanToVacationConverter" />
</Window.Resources>
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Список отпусков"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="White"
Margin="0,20,0,0" />
<!-- Поле поиска -->
<TextBox x:Name="SearchTextBox"
Width="560"
VerticalAlignment="Top"
Margin="0,60,0,0"
HorizontalAlignment="Center"
Style="{StaticResource RoundedTextBoxStyle}"
TextChanged="SearchTextBox_TextChanged" />
<!-- Таблица отпусков -->
<DataGrid x:Name="VacationsDataGrid"
Margin="20,100,20,80"
AutoGenerateColumns="False"
Style="{StaticResource RoundedDataGridStyle}">
<DataGrid.Columns>
<DataGridTextColumn Header="Дата начала" Binding="{Binding StartData, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Дата окончания" Binding="{Binding EndData, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Заврешен" Binding="{Binding Passed, Converter={StaticResource BooleanToVacationConverter}}" Width="*" />
<DataGridTextColumn Header="Сотрудник" Binding="{Binding EmployeeName}" Width="*" />
</DataGrid.Columns>
</DataGrid>
<!-- Удалить -->
<Button Content="Удалить"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Width="150" Height="40"
Margin="0,0,0,20"
Background="#004890"
Foreground="White"
Style="{StaticResource RoundedButtonStyle}"
Click="DeleteButton_Click" />
</Grid>
</Window>

View File

@ -0,0 +1,79 @@
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView.Employee.Vacation
{
/// <summary>
/// Логика взаимодействия для DeleteVacationWindow.xaml
/// </summary>
public partial class DeleteVacationWindow : Window
{
private readonly IVacationLogic _vacationLogic;
private IEnumerable<VacationViewModel> _allVacations;
public DeleteVacationWindow(IVacationLogic vacationLogic)
{
_vacationLogic = vacationLogic;
InitializeComponent();
LoadVacations();
}
private void LoadVacations()
{
_allVacations = _vacationLogic.GetFullList(); // Загрузка всех данных
VacationsDataGrid.ItemsSource = _allVacations;
}
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
if (VacationsDataGrid.SelectedItem is VacationViewModel selectedVacation)
{
// Удаление отпуска
_vacationLogic.Delete(selectedVacation.Id);
MessageBox.Show("Отпуск успешно удален!");
LoadVacations(); // Перезагрузка данных после удаления
SearchTextBox.Text = string.Empty; // Очистка поля поиска
}
else
{
MessageBox.Show("Пожалуйста, выберите запись для удаления.");
}
}
private void SearchTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
string query = SearchTextBox.Text.ToLower();
if (string.IsNullOrWhiteSpace(query))
{
// Отображаем все записи
VacationsDataGrid.ItemsSource = _allVacations;
}
else
{
// Фильтрация по всем полям сущности
var filteredList = _allVacations.Where(vac =>
(vac.EmployeeName?.ToLower().Contains(query) ?? false) ||
(vac.StartData.ToString("dd.MM.yyyy").Contains(query)) ||
(vac.EndData.ToString("dd.MM.yyyy").Contains(query)) ||
(vac.Passed.ToString().ToLower().Contains(query))
).ToList();
VacationsDataGrid.ItemsSource = filteredList;
}
}
}
}

View File

@ -0,0 +1,71 @@
<Window x:Class="EmployeeManagmentView.Employee.Vacation.EditVacationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Редактирование отпуска"
Height="450" Width="600"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid Margin="0,0,0,0">
<TextBlock Text="Редактирование отпуска"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Блок поиска и выбора отпуска -->
<Grid HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,70,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Поиск отпуска" Foreground="White" HorizontalAlignment="Center" Margin="0,0,10,10" />
<TextBox x:Name="SearchTextBox" Grid.Row="0" Grid.Column="1" Width="250" Height="30"
Style="{StaticResource RoundedTextBoxStyle}" ToolTip="Введите для поиска"
TextChanged="SearchTextBox_TextChanged" />
<Label Grid.Row="1" Grid.Column="0" Content="Выберите отпуск" Foreground="White" HorizontalAlignment="Center" Margin="0,10,10,10" />
<ComboBox x:Name="VacationComboBox" Grid.Row="1" Grid.Column="1" Width="250" Height="30"
SelectionChanged="VacationComboBox_SelectionChanged" />
</Grid>
<!-- Блок редактирования отпуска -->
<Grid Margin="0,150,0,60">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Margin="10">
<Label Content="Дата начала" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="StartDatePicker" Width="250" Height="40" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" Margin="10">
<Label Content="Дата окончания" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="EndDatePicker" Width="250" Height="40" />
</StackPanel>
<StackPanel Grid.Row="1" Grid.ColumnSpan="2" Margin="10" HorizontalAlignment="Center">
<Label Content="Завершение отпуска" Foreground="White" HorizontalAlignment="Center"/>
<CheckBox x:Name="PassedCheckBox" Content="Завершено" Foreground="White" HorizontalAlignment="Center" />
</StackPanel>
<!-- Кнопка сохранения -->
<Button Grid.Row="4" Grid.ColumnSpan="2" Content="Сохранить изменения" Width="250" Height="40"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="SaveButton_Click" Margin="0,10,0,0"/>
</Grid>
</Grid>
</Window>

View File

@ -0,0 +1,200 @@
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView.Employee.Vacation
{
/// <summary>
/// Логика взаимодействия для EditVacationWindow.xaml
/// </summary>
public partial class EditVacationWindow : Window
{
private readonly IVacationLogic _vacationLogic; // Логика для работы с отпусками
private readonly IEmployeeLogic _employeeLogic; // Логика для работы с сотрудниками
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
private List<VacationViewModel> _vacations;
private List<EmployeeViewModel> _employees; // Список сотрудников
public EditVacationWindow(IVacationLogic vacationLogic, IEmployeeLogic employeeLogic, IPhisicalPersonLogic phisicalPersonLogic)
{
_vacationLogic = vacationLogic;
_employeeLogic = employeeLogic;
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
LoadVacations();
}
private void LoadVacations()
{
_vacations = _vacationLogic.GetFullList();
VacationComboBox.ItemsSource = _vacations;
VacationComboBox.DisplayMemberPath = "DisplayName";
VacationComboBox.SelectedValuePath = "Id";
}
private void VacationComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (VacationComboBox.SelectedValue is int selectedVacationId)
{
LoadVacation(selectedVacationId);
}
}
private void LoadVacation(int vacationId)
{
var vacation = _vacationLogic.GetElement(vacationId);
if (vacation != null)
{
StartDatePicker.SelectedDate = vacation.StartData;
EndDatePicker.SelectedDate = vacation.EndData;
PassedCheckBox.IsChecked = vacation.Passed;
}
else
{
MessageBox.Show("Отпуск не найден", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var searchText = SearchTextBox.Text.ToLower();
var filteredVacations = _vacations
.Where(vac => vac.EmployeeName.ToLower().Contains(searchText))
.ToList();
VacationComboBox.ItemsSource = filteredVacations;
}
private void NameTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
// Разрешаем только буквы
e.Handled = !char.IsLetter(e.Text, 0);
}
private void NameTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Получаем текущий текст
string currentText = textBox.Text;
// Если текст не пустой, преобразуем первую букву в заглавную, а остальные в строчные
if (!string.IsNullOrEmpty(currentText))
{
// Разбиваем строку по пробелам, чтобы обрабатывать каждое слово отдельно
var words = currentText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < words.Length; i++)
{
// Преобразуем первую букву в заглавную, а остальные в строчные
words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower();
}
// Объединяем слова обратно в строку и обновляем текст
textBox.Text = string.Join(" ", words);
// Устанавливаем курсор в конец текста
textBox.SelectionStart = textBox.Text.Length;
}
}
private void TelephoneTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !char.IsDigit(e.Text, 0);
}
private void TelephoneTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Удаляем все символы, кроме цифр
string rawInput = new string(textBox.Text.Where(char.IsDigit).ToArray());
// Добавляем "7" по умолчанию
if (!rawInput.StartsWith("7"))
rawInput = "7" + rawInput;
if (rawInput.Length > 11) rawInput = rawInput.Substring(0, 11);
// Форматируем как +7 (XXX) XXX-XX-XX
if (rawInput.Length <= 1)
textBox.Text = "+7 ";
else if (rawInput.Length <= 4)
textBox.Text = $"+7 ({rawInput.Substring(1)}";
else if (rawInput.Length <= 7)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4)}";
else if (rawInput.Length <= 9)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7)}";
else
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7, 2)}-{rawInput.Substring(9)}";
// Устанавливаем курсор в конец
textBox.SelectionStart = textBox.Text.Length;
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
bool isValid = true;
if (!StartDatePicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Начало отпуска' не выбрано.");
}
if (!EndDatePicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Конец отпуска' не выбрано.");
}
// Если все поля заполнены, продолжаем выполнение
if (isValid)
try
{
if (VacationComboBox.SelectedValue is int selectedVacationId)
{
var updatedVacation = new VacationViewModel
{
Id = selectedVacationId,
StartData = StartDatePicker.SelectedDate.Value.ToUniversalTime(),
EndData = EndDatePicker.SelectedDate.Value.ToUniversalTime(),
Passed = PassedCheckBox.IsChecked ?? false,
};
_vacationLogic.Update(updatedVacation);
MessageBox.Show("Отпуск успешно обновлен!");
this.Close();
}
else
{
MessageBox.Show("Выберите отпуск перед сохранением!", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка при сохранении данных: {ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}

View File

@ -0,0 +1,52 @@
<Window x:Class="EmployeeManagmentView.Employee.Vacation.VacationManagementWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Управление отпуском"
Height="400" Width="400"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Управление отпуском"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Стек кнопок -->
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- Кнопка "Удаление отпуска" -->
<Button Content="Удаление отпуска"
Width="250" Height="40"
Margin="0,0,0,10"
Background="#004890" Foreground="#FFFFFF"
Style="{StaticResource RoundedButtonStyle}"
Click="OpenDeleteVacationWindow"/>
<!-- Кнопка "Добавление отпуска" -->
<Button Content="Добавление отпуска"
Width="250" Height="40"
Margin="0,0,0,10"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenAddVacationWindow"/>
<!-- Кнопка "Редактирование отпуска" -->
<Button Content="Редактирование отпуска"
Width="250" Height="40"
Margin="0,0,0,10"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenEditVacationWindow"/>
<!-- Кнопка "Просмотр отпусков" -->
<Button Content="Просмотр отпусков"
Width="250" Height="40"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenViewVacationWindow"/>
</StackPanel>
</Grid>
</Window>

View File

@ -0,0 +1,99 @@
using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.BusinessLogicContracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView.Employee.Vacation
{
/// <summary>
/// Логика взаимодействия для VacationManagementWindow.xaml
/// </summary>
public partial class VacationManagementWindow : Window
{
private readonly IVacationLogic _vacationLogic;
private readonly IEmployeeLogic _employeeLogic;
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
public VacationManagementWindow(IVacationLogic vacationLogic, IEmployeeLogic employeeLogic, IPhisicalPersonLogic phisicalPersonLogic)
{
_vacationLogic = vacationLogic;
_employeeLogic = employeeLogic;
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
}
private void OpenAddVacationWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is AddVacationWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var addWindow = new AddVacationWindow(_vacationLogic, _employeeLogic, _phisicalPersonLogic);
addWindow.Show();
}
private void OpenDeleteVacationWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is DeleteVacationWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var deleteWindow = new DeleteVacationWindow(_vacationLogic);
deleteWindow.Show();
}
private void OpenEditVacationWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is EditVacationWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var editWindow = new EditVacationWindow(_vacationLogic, _employeeLogic, _phisicalPersonLogic);
editWindow.Show();
}
private void OpenViewVacationWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is ViewVacationWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var viewWindow = new ViewVacationWindow(_vacationLogic, _employeeLogic, _phisicalPersonLogic);
viewWindow.Show();
}
}
}

View File

@ -0,0 +1,53 @@
<Window x:Class="EmployeeManagmentView.Employee.Vacation.ViewVacationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:EmployeeManagmentDataModels.Enums;assembly=EmployeeManagmentDataModels"
Title="Управление отпусками"
Height="600" Width="800"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Window.Resources>
<local:BooleanToVacationConverter x:Key="BooleanToVacationConverter" />
</Window.Resources>
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Список отпусков"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="White"
Margin="0,20,0,0" />
<!-- Поле поиска -->
<TextBox x:Name="SearchTextBox"
Width="560"
VerticalAlignment="Top"
Margin="0,60,0,0"
HorizontalAlignment="Center"
Style="{StaticResource RoundedTextBoxStyle}"
TextChanged="SearchTextBox_TextChanged" />
<!-- Таблица отпусков -->
<DataGrid x:Name="VacationsDataGrid"
Margin="20,100,20,80"
AutoGenerateColumns="False"
Style="{StaticResource RoundedDataGridStyle}">
<DataGrid.Columns>
<DataGridTextColumn Header="Дата начала" Binding="{Binding StartData, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Дата окончания" Binding="{Binding EndData, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Заврешен" Binding="{Binding Passed, Converter={StaticResource BooleanToVacationConverter}}" Width="*" />
<DataGridTextColumn Header="Работник" Binding="{Binding EmployeeName}" Width="*" />
</DataGrid.Columns>
</DataGrid>
<!-- Кнопка отчета -->
<Button Content="Генерация отчета"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Width="150" Height="40"
Margin="0,0,0,20"
Click="ExportToExcelButton_Click"
Background="#004890"
Foreground="White"
Style="{StaticResource RoundedButtonStyle}" />
</Grid>
</Window>

View File

@ -0,0 +1,173 @@
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml;
using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;
using Microsoft.Win32;
namespace EmployeeManagmentView.Employee.Vacation
{
/// <summary>
/// Логика взаимодействия для ViewVacationWindow.xaml
/// </summary>
public partial class ViewVacationWindow : Window
{
private readonly IVacationLogic _vacationLogic;
private readonly IEmployeeLogic _employeeLogic;
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
private IEnumerable<VacationViewModel> _allVacations;
private List<EmployeeViewModel> _employees;
public ViewVacationWindow(IVacationLogic vacationLogic, IEmployeeLogic employeeLogic, IPhisicalPersonLogic phisicalPersonLogic)
{
_vacationLogic = vacationLogic;
_employeeLogic = employeeLogic;
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
LoadVacations();
}
private void LoadVacations()
{
_allVacations = _vacationLogic.GetFullList(); // Загрузка всех данных
VacationsDataGrid.ItemsSource = _allVacations;
}
private void ExportToExcelButton_Click(object sender, RoutedEventArgs e)
{
try
{
var vacations = _vacationLogic.GetFullList();
if (vacations == null || !vacations.Any())
{
MessageBox.Show("Нет данных для экспорта.", "Внимание", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
// Открытие диалогового окна для сохранения файла
SaveFileDialog saveFileDialog = new SaveFileDialog
{
Filter = "Excel файлы (*.xlsx)|*.xlsx",
Title = "Сохранить отчет об отпусках",
FileName = "Отчет_отпуска.xlsx"
};
if (saveFileDialog.ShowDialog() == true)
{
string filePath = saveFileDialog.FileName; // Путь и имя файла
GenerateExcelReport(filePath, vacations); // Генерация отчета
MessageBox.Show($"Отчет успешно сохранен: {filePath}", "Успех", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка экспорта: {ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void GenerateExcelReport(string filePath, List<VacationViewModel> vacations)
{
using (SpreadsheetDocument document = SpreadsheetDocument.Create(filePath, SpreadsheetDocumentType.Workbook))
{
// Создаем Workbook
WorkbookPart workbookPart = document.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
// Создаем Worksheet
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
// Добавляем лист в Workbook
Sheets sheets = document.WorkbookPart.Workbook.AppendChild(new Sheets());
Sheet sheet = new Sheet()
{
Id = document.WorkbookPart.GetIdOfPart(worksheetPart),
SheetId = 1,
Name = "Отпуска"
};
sheets.Append(sheet);
// Получаем SheetData
SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
// Заполняем заголовки
Row headerRow = new Row();
headerRow.Append(
CreateTextCell("A", "ID"),
CreateTextCell("B", "Сотрудник"),
CreateTextCell("C", "Дата начала"),
CreateTextCell("D", "Дата окончания"),
CreateTextCell("E", "Статус")
);
sheetData.AppendChild(headerRow);
// Заполняем данные
foreach (var vacation in vacations)
{
Row row = new Row();
row.Append(
CreateTextCell("A", vacation.Id.ToString()),
CreateTextCell("B", vacation.EmployeeName),
CreateTextCell("C", vacation.StartData.ToString("dd.MM.yyyy")),
CreateTextCell("D", vacation.EndData.ToString("dd.MM.yyyy")),
CreateTextCell("E", vacation.Passed ? "Проведен" : "Не проведен")
);
sheetData.AppendChild(row);
}
workbookPart.Workbook.Save();
}
}
// Метод для создания текстовой ячейки
private Cell CreateTextCell(string columnName, string text)
{
return new Cell
{
DataType = CellValues.String,
CellReference = columnName,
CellValue = new CellValue(text)
};
}
private void SearchTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
string query = SearchTextBox.Text.ToLower();
if (string.IsNullOrWhiteSpace(query))
{
// Отображаем все записи
VacationsDataGrid.ItemsSource = _allVacations;
}
else
{
// Фильтрация по всем полям сущности
var filteredList = _allVacations.Where(vac =>
(vac.EmployeeName?.ToLower().Contains(query) ?? false) ||
(vac.StartData.ToString("dd.MM.yyyy").Contains(query)) ||
(vac.EndData.ToString("dd.MM.yyyy").Contains(query)) ||
(vac.Passed.ToString().ToLower().Contains(query))
).ToList();
VacationsDataGrid.ItemsSource = filteredList;
}
}
}
}

View File

@ -0,0 +1,61 @@
<Window x:Class="EmployeeManagmentView.Employee.ViewEmployeeWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Просмотр сотрудников"
Height="500" Width="800"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Список сотрудников"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="White"
Margin="0,20,0,0" />
<!-- Поле поиска -->
<TextBox x:Name="SearchTextBox"
Width="560"
VerticalAlignment="Top"
Margin="0,60,0,0"
HorizontalAlignment="Center"
Style="{StaticResource RoundedTextBoxStyle}"
TextChanged="SearchTextBox_TextChanged" />
<!-- Таблица сотрудников -->
<DataGrid x:Name="EmployeesDataGrid"
Margin="20,100,20,75"
AutoGenerateColumns="False"
Style="{StaticResource RoundedDataGridStyle}">
<DataGrid.Columns>
<DataGridTextColumn Header="Должность" Binding="{Binding NameJob}" Width="*" />
<DataGridTextColumn Header="Дата начала" Binding="{Binding StartJob, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Дата окончания" Binding="{Binding EndJob, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Частичная занятость" Binding="{Binding PartTimeJob}" Width="*" />
<DataGridTextColumn Header="Ставка" Binding="{Binding Bid}" Width="*" />
<DataGridTextColumn Header="Физическое лицо" Binding="{Binding PhysicalPersonName}" Width="*" />
</DataGrid.Columns>
</DataGrid>
<Button Content="Работа с отпусками"
HorizontalAlignment="Left" VerticalAlignment="Bottom"
Width="200" Height="40"
Margin="180,0,0,20"
Background="#004890"
Foreground="White"
Style="{StaticResource RoundedButtonStyle}"
Click="OpenVacationManagementWindow"/>
<Button Content="Работа с зарплатой"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
Width="200" Height="40"
Margin="0,0,180,20"
Background="#004890"
Foreground="White"
Style="{StaticResource RoundedButtonStyle}"
Click="OpenSalaryManagementWindow"/>
</Grid>
</Window>

View File

@ -0,0 +1,118 @@
using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentView.Employee.Salary;
using EmployeeManagmentView.Employee.Vacation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView.Employee
{
/// <summary>
/// Логика взаимодействия для ViewEmployeeWindow.xaml
/// </summary>
public partial class ViewEmployeeWindow : Window
{
private readonly IEmployeeLogic _employeeLogic;
private readonly ISalaryLogic _salaryLogic;
private readonly IVacationLogic _vacationLogic;
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
private IEnumerable<EmployeeViewModel> _allEmployees; // Список сотрудников для фильтрации
private List<EmployeeViewModel> _employees;
public ViewEmployeeWindow(IEmployeeLogic employeeLogic, ISalaryLogic salaryLogic, IVacationLogic vacationLogic, IPhisicalPersonLogic phisicalPersonLogic)
{
_employeeLogic = employeeLogic;
_salaryLogic = salaryLogic;
_vacationLogic = vacationLogic;
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
LoadEmployees();
}
private void LoadEmployees()
{
_allEmployees = _employeeLogic.GetFullList(); // Загрузка всех данных
EmployeesDataGrid.ItemsSource = _allEmployees;
_employees = _employeeLogic.GetFullList();
}
private void SearchTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
string query = SearchTextBox.Text.ToLower();
if (string.IsNullOrWhiteSpace(query))
{
// Отображаем все записи
EmployeesDataGrid.ItemsSource = _allEmployees;
}
else
{
// Фильтрация по всем полям сущности
var filteredList = _allEmployees.Where(emp =>
(emp.NameJob?.ToLower().Contains(query) ?? false) ||
(emp.PartTimeJob?.ToLower().Contains(query) ?? false) ||
(emp.PhysicalPersonName?.ToLower().Contains(query) ?? false) ||
(emp.StartJob.HasValue && emp.StartJob.Value.ToString("dd.MM.yyyy").Contains(query)) ||
(emp.EndJob.HasValue && emp.EndJob.Value.ToString("dd.MM.yyyy").Contains(query)) ||
emp.Bid.ToString().Contains(query)
).ToList();
EmployeesDataGrid.ItemsSource = filteredList;
}
}
private void OpenSalaryManagementWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is SalaryManagementWindow)
{
// Если окно уже открыто, активируем его и ставим на передний план
window.Activate();
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
window.Topmost = true; // Ставим окно на передний план
window.Topmost = false; // Сразу снимаем флаг, чтобы окно не оставалось всегда наверху
return;
}
}
var salaryWindow = new SalaryManagementWindow(_salaryLogic, _employeeLogic, _phisicalPersonLogic);
salaryWindow.Show();
}
private void OpenVacationManagementWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is VacationManagementWindow)
{
// Если окно уже открыто, активируем его и ставим на передний план
window.Activate();
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
window.Topmost = true; // Ставим окно на передний план
window.Topmost = false; // Сразу снимаем флаг, чтобы окно не оставалось всегда наверху
return;
}
}
var vacationWindow = new VacationManagementWindow(_vacationLogic, _employeeLogic, _phisicalPersonLogic);
vacationWindow.Show();
}
}
}

View File

@ -8,4 +8,28 @@
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" />
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.6.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EmployeeManagmentBusinessLogic\EmployeeManagmentBusinessLogic.csproj" />
<ProjectReference Include="..\EmployeeManagmentContracts\EmployeeManagmentContracts.csproj" />
<ProjectReference Include="..\EmployeeManagmentDataBaseImplement\EmployeeManagmentDataBaseImplement.csproj" />
<ProjectReference Include="..\EmployeeManagmentDataModels\EmployeeManagmentDataModels.csproj" />
</ItemGroup>
</Project> </Project>

View File

@ -1,8 +0,0 @@
<Window x:Class="EmployeeManagmentView.EmployeesWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Employees" Height="450" Width="800">
<Grid>
<TextBlock Text="Список сотрудников" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Window>

View File

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace EmployeeManagmentView
{
/// <summary>
/// Логика взаимодействия для EmployeesWindow.xaml
/// </summary>
public partial class EmployeesWindow : Window
{
public EmployeesWindow()
{
InitializeComponent();
}
}
}

View File

@ -1,33 +1,30 @@
<Window x:Class="EmployeeManagmentView.MainWindow" <Window x:Class="EmployeeManagmentView.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" Title="Отдел кадров УлГТУ" Height="450" Width="800" Background="#0D2D4F"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" MinWidth="400" MinHeight="300"
mc:Ignorable="d" WindowStartupLocation="CenterScreen"
Title="Employee Management System" MaxWidth="{Binding Source={x:Static SystemParameters.PrimaryScreenWidth}}"
Height="450" Width="800"> MaxHeight="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight}}">
<Grid>
<StackPanel>
<TextBlock Text="Система управления сотрудниками"
FontSize="24"
FontWeight="Bold"
Margin="10"/>
<Button Content="Просмотр сотрудников"
Width="200" <Grid>
Height="40" <!-- Заголовок -->
Margin="10" <TextBlock Text="Отдел кадров УлГТУ"
Click="ViewEmployees_Click"/> HorizontalAlignment="Center" VerticalAlignment="Top"
<Button Content="Управление зарплатами" FontSize="24" FontWeight="Bold"
Width="200" Foreground="#FFFFFF" Margin="0,20,0,0" />
Height="40"
Margin="10" <!-- Центральный StackPanel -->
Click="ManageSalaries_Click"/> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,40">
<Button Content="Управление отпусками" <!-- Кнопка 1 -->
Width="200" <Button Content="Работа с сотрудниками" Width="200" Height="50" Margin="0,10"
Height="40" Background="#004890" Foreground="#FFFFFF" FontSize="16"
Margin="10" Style="{StaticResource RoundedButtonStyle}" Click="OpenEmployeeManagementWindow"/>
Click="ManageVacations_Click"/> <!-- Кнопка 2 -->
<Button Content="Работа с физ. лицами" Width="200" Height="50" Margin="0,10"
Background="#004890" Foreground="#FFFFFF" FontSize="16"
Style="{StaticResource RoundedButtonStyle}" Click="OpenPhysicalPersonManagementWindow"/>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Window> </Window>

View File

@ -1,45 +1,71 @@
using System.Text; using EmployeeManagmentBusinessLogic.BusinessLogic;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using EmployeeManagmentView.Employee;
using EmployeeManagmentView.PhysicalPerson;
using System.Windows; using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace EmployeeManagmentView namespace EmployeeManagmentView
{ {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
public MainWindow()
private readonly IEmployeeLogic _employeeLogic;
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
private readonly ISalaryLogic _salaryLogic;
private readonly IVacationLogic _vacationLogic;
// Constructor with Dependency Injection
public MainWindow(IEmployeeLogic employeeLogic, IPhisicalPersonLogic phisicalPersonLogic, ISalaryLogic salaryLogic, IVacationLogic vacationLogic)
{ {
_employeeLogic = employeeLogic;
_phisicalPersonLogic = phisicalPersonLogic;
_salaryLogic = salaryLogic;
_vacationLogic = vacationLogic;
InitializeComponent(); InitializeComponent();
} }
private void ViewEmployees_Click(object sender, RoutedEventArgs e) public MainWindow()
{ {
// Логика для открытия окна просмотра сотрудников
var employeesWindow = new EmployeesWindow();
employeesWindow.Show();
} }
private void ManageSalaries_Click(object sender, RoutedEventArgs e) public void OpenPhysicalPersonManagementWindow(object sender, RoutedEventArgs e)
{ {
// Логика для открытия окна управления зарплатами foreach (Window window in Application.Current.Windows)
var salariesWindow = new SalariesWindow(); {
salariesWindow.Show(); if (window is PhysicalPersonManagementWindow)
{
// Если окно уже открыто, активируем его и ставим на передний план
window.Activate();
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
window.Topmost = true; // Ставим окно на передний план
window.Topmost = false; // Сразу снимаем флаг, чтобы окно не оставалось всегда наверху
return;
}
}
var physicalPersonWindow = new PhysicalPersonManagementWindow(_phisicalPersonLogic);
physicalPersonWindow.Show();
} }
private void ManageVacations_Click(object sender, RoutedEventArgs e) public void OpenEmployeeManagementWindow(object sender, RoutedEventArgs e)
{ {
// Логика для открытия окна управления отпусками foreach (Window window in Application.Current.Windows)
var vacationsWindow = new VacationsWindow(); {
vacationsWindow.Show(); if (window is EmployeeManagementWindow)
{
// Если окно уже открыто, активируем его и ставим на передний план
window.Activate();
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
window.Topmost = true; // Ставим окно на передний план
window.Topmost = false; // Сразу снимаем флаг, чтобы окно не оставалось всегда наверху
return;
}
}
var employeeWindow = new EmployeeManagementWindow(_employeeLogic, _phisicalPersonLogic, _salaryLogic, _vacationLogic);
employeeWindow.Show();
} }
} }
} }

View File

@ -0,0 +1,132 @@
<Window x:Class="EmployeeManagmentView.PhysicalPerson.AddPhysicalPersonWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
Title="Добавление физического лица"
Height="600" Width="600"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Добавление физического лица"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Сетка для ввода данных в два столбца -->
<Grid Margin="0,60">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Поле для имени -->
<StackPanel Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Имя" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="NameTextBox"
Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}"
Margin="0,5"
ToolTip="Введите имя" HorizontalAlignment="Center"
PreviewTextInput="NameTextBox_PreviewTextInput"
TextChanged="NameTextBox_TextChanged"/>
</StackPanel>
<!-- Поле для фамилии -->
<StackPanel Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Фамилия" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="SurnameTextBox"
Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}"
Margin="0,5"
PreviewTextInput="NameTextBox_PreviewTextInput"
TextChanged="NameTextBox_TextChanged"
ToolTip="Введите фамилию" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Поле для отчества -->
<StackPanel Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Отчество" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="PatronomicTextBox"
Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}"
Margin="0,5"
PreviewTextInput="NameTextBox_PreviewTextInput"
TextChanged="NameTextBox_TextChanged"
ToolTip="Введите отчество" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Поле для выбора даты рождения -->
<StackPanel Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Дата рождения" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="BirthdayPicker"
Width="250" Height="40"
Margin="0,5"
ToolTip="Выберите дату рождения" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Поле для выбора пола -->
<StackPanel Grid.Row="2" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Пол" Foreground="White" HorizontalAlignment="Center"/>
<ComboBox x:Name="GenderComboBox"
Width="250" Height="40"
Margin="0,5"
ToolTip="Выберите пол"
Background="White" HorizontalAlignment="Center">
<ComboBoxItem Content="Мужчина"/>
<ComboBoxItem Content="Женщина"/>
</ComboBox>
</StackPanel>
<!-- Поле для адреса -->
<StackPanel Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Адрес" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="AddressTextBox"
Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}"
Margin="0,5"
ToolTip="Введите адрес" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Поле для телефона -->
<StackPanel Grid.Row="3" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Label Content="Телефон" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="TelephoneTextBox"
Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}"
Margin="0,5"
ToolTip="Введите номер телефона"
HorizontalAlignment="Center"
Foreground="Black"
PreviewTextInput="TelephoneTextBox_PreviewTextInput"
TextChanged="TelephoneTextBox_TextChanged"/>
</StackPanel>
<!-- Кнопка для добавления физического лица -->
<Button Grid.Row="4" Grid.ColumnSpan="2" Content="Добавить физическое лицо"
Width="250" Height="40"
Margin="0,10"
Style="{StaticResource RoundedButtonStyle}"
Click="SaveButton_Click"
Background="#004890" Foreground="#FFFFFF" HorizontalAlignment="Center"/>
</Grid>
</Grid>
</Window>

View File

@ -0,0 +1,167 @@
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace EmployeeManagmentView.PhysicalPerson
{
public partial class AddPhysicalPersonWindow : Window
{
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
public AddPhysicalPersonWindow(IPhisicalPersonLogic phisicalPersonLogic)
{
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
}
private void NameTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
// Разрешаем только буквы
e.Handled = !char.IsLetter(e.Text, 0);
}
private void NameTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Получаем текущий текст
string currentText = textBox.Text;
// Если текст не пустой, преобразуем первую букву в заглавную, а остальные в строчные
if (!string.IsNullOrEmpty(currentText))
{
// Разбиваем строку по пробелам, чтобы обрабатывать каждое слово отдельно
var words = currentText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < words.Length; i++)
{
// Преобразуем первую букву в заглавную, а остальные в строчные
words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower();
}
// Объединяем слова обратно в строку и обновляем текст
textBox.Text = string.Join(" ", words);
// Устанавливаем курсор в конец текста
textBox.SelectionStart = textBox.Text.Length;
}
}
private void TelephoneTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !char.IsDigit(e.Text, 0);
}
private void TelephoneTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Удаляем все символы, кроме цифр
string rawInput = new string(textBox.Text.Where(char.IsDigit).ToArray());
// Добавляем "7" по умолчанию
if (!rawInput.StartsWith("7"))
rawInput = "7" + rawInput;
if (rawInput.Length > 11) rawInput = rawInput.Substring(0, 11);
// Форматируем как +7 (XXX) XXX-XX-XX
if (rawInput.Length <= 1)
textBox.Text = "+7 ";
else if (rawInput.Length <= 4)
textBox.Text = $"+7 ({rawInput.Substring(1)}";
else if (rawInput.Length <= 7)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4)}";
else if (rawInput.Length <= 9)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7)}";
else
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7, 2)}-{rawInput.Substring(9)}";
// Устанавливаем курсор в конец
textBox.SelectionStart = textBox.Text.Length;
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
bool isValid = true;
// Проверка обязательных полей
if (string.IsNullOrWhiteSpace(NameTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Имя' не заполнено.");
}
if (string.IsNullOrWhiteSpace(SurnameTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Фамилия' не заполнено.");
}
if (string.IsNullOrWhiteSpace(PatronomicTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Отчество' не заполнено.");
}
if (!BirthdayPicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Дата рождения' не выбрано.");
}
if (GenderComboBox.SelectedItem == null)
{
isValid = false;
MessageBox.Show("Поле 'Пол' не выбрано.");
}
if (string.IsNullOrWhiteSpace(AddressTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Адрес' не заполнено.");
}
if (string.IsNullOrWhiteSpace(TelephoneTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Телефон' не заполнено.");
}
// Если все поля заполнены, продолжаем выполнение
if (isValid)
{
try
{
var model = new PhisicalPersonViewModel
{
Name = NameTextBox.Text,
Surname = SurnameTextBox.Text,
Patronymic = PatronomicTextBox.Text,
Birthday = BirthdayPicker.SelectedDate.Value.ToUniversalTime(),
Gender = GenderComboBox.Text,
Address = AddressTextBox.Text,
Telephone = TelephoneTextBox.Text
};
_phisicalPersonLogic.Insert(model);
MessageBox.Show("Данные успешно сохранены!");
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка: {ex.Message}");
}
}
}
}
}

View File

@ -0,0 +1,53 @@
<Window x:Class="EmployeeManagmentView.PhysicalPerson.DeletePhysicalPersonWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Удаление физического лица"
Height="500" Width="800"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Список физических лиц для удаления"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Поиск -->
<TextBox x:Name="SearchTextBox"
Width="560"
VerticalAlignment="Top"
Margin="0,60,0,0"
HorizontalAlignment="Center"
Style="{StaticResource RoundedTextBoxStyle}"
TextChanged="SearchTextBox_TextChanged" />
<!-- Таблица для отображения -->
<DataGrid x:Name="PhysicalPersonsDataGrid"
Margin="20,100,20,80"
AutoGenerateColumns="False"
Style="{StaticResource RoundedDataGridStyle}">
<DataGrid.Columns>
<DataGridTextColumn Header="Фамилия" Binding="{Binding Surname}" Width="*" />
<DataGridTextColumn Header="Имя" Binding="{Binding Name}" Width="*" />
<DataGridTextColumn Header="Отчество" Binding="{Binding Patronymic}" Width="*" />
<DataGridTextColumn Header="Дата рождения" Binding="{Binding Birthday, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Пол" Binding="{Binding Gender}" Width="*" />
<DataGridTextColumn Header="Адрес" Binding="{Binding Address}" Width="*" />
<DataGridTextColumn Header="Телефон" Binding="{Binding Telephone}" Width="*" />
</DataGrid.Columns>
</DataGrid>
<!-- Кнопка для удаления -->
<Button Content="Удалить"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Width="100" Height="40"
Margin="0,0,0,20"
Background="#004890"
Foreground="#FFFFFF"
Style="{StaticResource RoundedButtonStyle}"
Click="DeleteButton_Click"/>
</Grid>
</Window>

View File

@ -0,0 +1,74 @@
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System.Windows;
namespace EmployeeManagmentView.PhysicalPerson
{
public partial class DeletePhysicalPersonWindow : Window
{
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
private IEnumerable<PhisicalPersonViewModel> _allPersons; // Храним все записи для фильтрации
public DeletePhysicalPersonWindow(IPhisicalPersonLogic phisicalPersonLogic)
{
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
LoadPhysicalPersons();
}
private void LoadPhysicalPersons()
{
_allPersons = _phisicalPersonLogic.GetFullList();
PhysicalPersonsDataGrid.ItemsSource = _allPersons;
}
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
if (PhysicalPersonsDataGrid.SelectedItem != null)
{
var selectedPerson = PhysicalPersonsDataGrid.SelectedItem as PhisicalPersonViewModel;
if (selectedPerson != null)
{
_phisicalPersonLogic.Delete(selectedPerson.Id); // Используем Id для удаления
LoadPhysicalPersons(); // Перезагружаем список
MessageBox.Show("Данные успешно удалены!");
// Очистка поля поиска после удаления
SearchTextBox.Text = string.Empty;
}
}
else
{
MessageBox.Show("Пожалуйста, выберите физическое лицо для удаления.");
}
}
private void SearchTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
string searchQuery = SearchTextBox.Text.ToLower(); // Получаем текст для поиска
if (string.IsNullOrWhiteSpace(searchQuery))
{
// Если поле пустое, показываем все записи
PhysicalPersonsDataGrid.ItemsSource = _allPersons;
}
else
{
// Фильтруем записи по всем полям
var filteredList = _allPersons.Where(p =>
p.Name.ToLower().Contains(searchQuery) ||
p.Surname.ToLower().Contains(searchQuery) ||
p.Patronymic.ToLower().Contains(searchQuery) ||
p.Address.ToLower().Contains(searchQuery) || // Поиск по адресу
p.Telephone.Contains(searchQuery) || // Поиск по телефону
p.Gender.ToLower().Contains(searchQuery) || // Поиск по полу
p.Birthday.ToString("dd.MM.yyyy").Contains(searchQuery) // Поиск по дате рождения
).ToList();
PhysicalPersonsDataGrid.ItemsSource = filteredList;
}
}
}
}

View File

@ -0,0 +1,134 @@
<Window x:Class="EmployeeManagmentView.PhysicalPerson.EditPhysicalPersonWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Редактирование физического лица"
Height="704" Width="600"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid Margin="0,0,0,-6">
<!-- Заголовок окна -->
<TextBlock Text="Редактирование физического лица"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Основная сетка -->
<Grid Margin="0,70,0,60">
<Grid.RowDefinitions>
<!-- Поиск -->
<RowDefinition Height="2*" />
<!-- Редактирование -->
<RowDefinition Height="5*" />
<!-- Кнопка сохранения -->
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Блок поиска -->
<Grid Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Поле для поиска физического лица -->
<Label Grid.Row="0" Grid.Column="0"
Content="Поиск физического лица" Foreground="White" HorizontalAlignment="Center" Margin="0,10,0,10" VerticalContentAlignment="Center"/>
<TextBox x:Name="SearchTextBox" Grid.Row="0" Grid.Column="1"
Width="250" Height="30"
Style="{StaticResource RoundedTextBoxStyle}"
Margin="0,10,0,10"
VerticalContentAlignment="Center"
ToolTip="Введите для поиска"
TextChanged="SearchTextBox_TextChanged"/>
<!-- Поле для выбора физического лица -->
<Label Grid.Row="1" Grid.Column="0"
Content="Выберите физическое лицо" Foreground="White" HorizontalAlignment="Center" Margin="0,10,0,10" VerticalContentAlignment="Center"/>
<ComboBox x:Name="PhysicalPersonComboBox" Grid.Row="1" Grid.Column="1"
Width="400" Height="30"
VerticalAlignment="Top"
Margin="0,10,0,10"
ToolTip="Выберите физическое лицо"
SelectionChanged="PhysicalPersonComboBox_SelectionChanged" />
</Grid>
<!-- Блок редактирования -->
<Grid Grid.Row="1" Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Поля редактирования -->
<StackPanel Grid.Row="0" Grid.Column="0" Margin="10">
<Label Content="Имя" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="NameTextBox" Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}" ToolTip="Введите имя"
PreviewTextInput="NameTextBox_PreviewTextInput"
TextChanged="NameTextBox_TextChanged"/>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" Margin="10">
<Label Content="Фамилия" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="SurnameTextBox" Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}" ToolTip="Введите фамилию"
PreviewTextInput="NameTextBox_PreviewTextInput"
TextChanged="NameTextBox_TextChanged"/>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="0" Margin="10" >
<Label Content="Отчество" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="PatronomicTextBox" Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}" ToolTip="Введите отчество"
PreviewTextInput="NameTextBox_PreviewTextInput"
TextChanged="NameTextBox_TextChanged"/>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="1" Margin="10">
<Label Content="Дата рождения" Foreground="White" HorizontalAlignment="Center"/>
<DatePicker x:Name="BirthdayPicker" Width="250" Height="40"
ToolTip="Выберите дату рождения" />
</StackPanel>
<StackPanel Grid.Row="2" Grid.Column="0" Margin="10">
<Label Content="Пол" Foreground="White" HorizontalAlignment="Center"/>
<ComboBox x:Name="GenderComboBox" Width="250" Height="40" ToolTip="Выберите пол">
<ComboBoxItem Content="Мужчина" />
<ComboBoxItem Content="Женщина" />
</ComboBox>
</StackPanel>
<StackPanel Grid.Row="2" Grid.Column="1" Margin="10">
<Label Content="Адрес" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="AddressTextBox" Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}" ToolTip="Введите адрес" />
</StackPanel>
<StackPanel Grid.Row="3" Grid.Column="0" Margin="10">
<Label Content="Телефон" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="TelephoneTextBox" Width="250" Height="40"
Style="{StaticResource RoundedTextBoxStyle}" ToolTip="Введите номер телефона"
PreviewTextInput="TelephoneTextBox_PreviewTextInput"
TextChanged="TelephoneTextBox_TextChanged"/>
</StackPanel>
</Grid>
<!-- Кнопка сохранения -->
<Button Grid.Row="2" Content="Сохранить изменения"
Width="250" Height="40"
VerticalAlignment="Bottom"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="SaveButton_Click"
HorizontalAlignment="Center" Margin="0,10,0,0"/>
</Grid>
</Grid>
</Window>

View File

@ -0,0 +1,235 @@
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
namespace EmployeeManagmentView.PhysicalPerson
{
public partial class EditPhysicalPersonWindow : Window
{
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
private List<PhisicalPersonViewModel> _physicalPersons;
public EditPhysicalPersonWindow(IPhisicalPersonLogic phisicalPersonLogic)
{
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
LoadPhysicalPersons();
}
// Загрузка всех физ.лиц в ComboBox
private void LoadPhysicalPersons()
{
_physicalPersons = _phisicalPersonLogic.GetFullList();
PhysicalPersonComboBox.ItemsSource = _physicalPersons;
PhysicalPersonComboBox.DisplayMemberPath = "FullNameWithBirthday";
PhysicalPersonComboBox.SelectedValuePath = "Id";
}
// Событие при выборе физ.лица
private void PhysicalPersonComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (PhysicalPersonComboBox.SelectedValue is int selectedPersonId)
{
LoadPerson(selectedPersonId);
}
}
// Загрузка данных выбранного физ.лица в поля
private void LoadPerson(int personId)
{
var person = _phisicalPersonLogic.GetElement(personId);
if (person != null)
{
NameTextBox.Text = person.Name;
SurnameTextBox.Text = person.Surname;
PatronomicTextBox.Text = person.Patronymic;
BirthdayPicker.SelectedDate = person.Birthday;
// Устанавливаем выбранное значение для GenderComboBox
foreach (ComboBoxItem item in GenderComboBox.Items)
{
if (item.Content.ToString() == person.Gender)
{
GenderComboBox.SelectedItem = item;
break;
}
}
AddressTextBox.Text = person.Address;
TelephoneTextBox.Text = person.Telephone;
}
}
private void NameTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
// Разрешаем только буквы
e.Handled = !char.IsLetter(e.Text, 0);
}
private void NameTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Получаем текущий текст
string currentText = textBox.Text;
// Если текст не пустой, преобразуем первую букву в заглавную, а остальные в строчные
if (!string.IsNullOrEmpty(currentText))
{
// Разбиваем строку по пробелам, чтобы обрабатывать каждое слово отдельно
var words = currentText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < words.Length; i++)
{
// Преобразуем первую букву в заглавную, а остальные в строчные
words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower();
}
// Объединяем слова обратно в строку и обновляем текст
textBox.Text = string.Join(" ", words);
// Устанавливаем курсор в конец текста
textBox.SelectionStart = textBox.Text.Length;
}
}
private void TelephoneTextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !char.IsDigit(e.Text, 0);
}
private void TelephoneTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// Удаляем все символы, кроме цифр
string rawInput = new string(textBox.Text.Where(char.IsDigit).ToArray());
// Добавляем "7" по умолчанию
if (!rawInput.StartsWith("7"))
rawInput = "7" + rawInput;
if (rawInput.Length > 11) rawInput = rawInput.Substring(0, 11);
// Форматируем как +7 (XXX) XXX-XX-XX
if (rawInput.Length <= 1)
textBox.Text = "+7 ";
else if (rawInput.Length <= 4)
textBox.Text = $"+7 ({rawInput.Substring(1)}";
else if (rawInput.Length <= 7)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4)}";
else if (rawInput.Length <= 9)
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7)}";
else
textBox.Text = $"+7 ({rawInput.Substring(1, 3)}) {rawInput.Substring(4, 3)}-{rawInput.Substring(7, 2)}-{rawInput.Substring(9)}";
// Устанавливаем курсор в конец
textBox.SelectionStart = textBox.Text.Length;
}
// Фильтрация списка физических лиц по всем полям
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var searchText = SearchTextBox.Text.ToLower();
var filteredPersons = _physicalPersons
.Where(p => p.Name.ToLower().Contains(searchText) ||
p.Surname.ToLower().Contains(searchText) ||
p.Patronymic.ToLower().Contains(searchText) ||
p.Gender.ToLower().Contains(searchText) ||
p.Address.ToLower().Contains(searchText) ||
p.Telephone.ToLower().Contains(searchText) ||
p.Birthday.ToString("dd.MM.yyyy").Contains(searchText) // Поиск по дате рождения
).ToList();
PhysicalPersonComboBox.ItemsSource = filteredPersons;
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
bool isValid = true;
// Проверка обязательных полей
if (string.IsNullOrWhiteSpace(NameTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Имя' не заполнено.");
}
if (string.IsNullOrWhiteSpace(SurnameTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Фамилия' не заполнено.");
}
if (string.IsNullOrWhiteSpace(PatronomicTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Отчество' не заполнено.");
}
if (!BirthdayPicker.SelectedDate.HasValue)
{
isValid = false;
MessageBox.Show("Поле 'Дата рождения' не выбрано.");
}
if (GenderComboBox.SelectedItem == null)
{
isValid = false;
MessageBox.Show("Поле 'Пол' не выбрано.");
}
if (string.IsNullOrWhiteSpace(AddressTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Адрес' не заполнено.");
}
if (string.IsNullOrWhiteSpace(TelephoneTextBox.Text))
{
isValid = false;
MessageBox.Show("Поле 'Телефон' не заполнено.");
}
// Если все поля заполнены, продолжаем выполнение
if (isValid)
if (PhysicalPersonComboBox.SelectedValue is int selectedPersonId)
{
try
{
var updatedPerson = new PhisicalPersonViewModel
{
Id = selectedPersonId,
Name = NameTextBox.Text,
Surname = SurnameTextBox.Text,
Patronymic = PatronomicTextBox.Text,
Birthday = BirthdayPicker.SelectedDate.Value.ToUniversalTime(),
Gender = GenderComboBox.Text,
Address = AddressTextBox.Text,
Telephone = TelephoneTextBox.Text
};
_phisicalPersonLogic.Update(updatedPerson);
MessageBox.Show("Данные успешно обновлены!");
this.Close();
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка: {ex.Message}");
}
}
else
{
MessageBox.Show("Выберите физическое лицо перед сохранением!", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
}
}

View File

@ -0,0 +1,51 @@
<Window x:Class="EmployeeManagmentView.PhysicalPerson.PhysicalPersonManagementWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Управление физическими лицами"
Height="400" Width="400"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Управление физическими лицами"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Стек кнопок -->
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- Кнопка "Удаление физического лица" -->
<Button Content="Удаление физического лица"
Width="250" Height="40"
Margin="0,0,0,10"
Background="#004890" Foreground="#FFFFFF"
Style="{StaticResource RoundedButtonStyle}"
Click ="OpenDeletePhysicalPersonWindow"/>
<!-- Кнопка "Добавление физического лица" -->
<Button Content="Добавление физического лица"
Width="250" Height="40"
Margin="0,0,0,10"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenAddPhysicalPersonWindow" RenderTransformOrigin="0.402,0.626"/>
<!-- Кнопка "Редактирование физического лица" -->
<Button Content="Редактирование физического лица"
Width="250" Height="40"
Margin="0,0,0,10"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenEditPhysicalPersonWindow"/>
<!-- Кнопка "Просмотр физических лиц" -->
<Button Content="Просмотр физических лиц"
Width="250" Height="40"
Style="{StaticResource RoundedButtonStyle}"
Background="#004890" Foreground="#FFFFFF"
Click="OpenViewPhysicalPersonsWindow"/>
</StackPanel>
</Grid>
</Window>

View File

@ -0,0 +1,76 @@
using EmployeeManagmentContracts.BusinessLogicContracts;
using System.Windows;
namespace EmployeeManagmentView.PhysicalPerson
{
public partial class PhysicalPersonManagementWindow : Window
{
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
public PhysicalPersonManagementWindow(IPhisicalPersonLogic phisicalPersonLogic)
{
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
}
private void OpenAddPhysicalPersonWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is AddPhysicalPersonWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var addWindow = new AddPhysicalPersonWindow(_phisicalPersonLogic);
addWindow.Show();
}
private void OpenDeletePhysicalPersonWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is DeletePhysicalPersonWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var deleteWindow = new DeletePhysicalPersonWindow(_phisicalPersonLogic);
deleteWindow.Show();
}
private void OpenEditPhysicalPersonWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is EditPhysicalPersonWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var editWindow = new EditPhysicalPersonWindow(_phisicalPersonLogic);
editWindow.Show();
}
private void OpenViewPhysicalPersonsWindow(object sender, RoutedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window is ViewPhysicalPersonsWindow existingWindow)
{
existingWindow.Activate();
return;
}
}
var viewWindow = new ViewPhysicalPersonsWindow(_phisicalPersonLogic);
viewWindow.Show();
}
}
}

View File

@ -0,0 +1,45 @@
<Window x:Class="EmployeeManagmentView.PhysicalPerson.ViewPhysicalPersonsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Список физических лиц"
Height="500" Width="800"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="#0D2D4F">
<Grid>
<!-- Заголовок окна -->
<TextBlock Text="Список физических лиц"
HorizontalAlignment="Center" VerticalAlignment="Top"
FontSize="18" FontWeight="Bold"
Foreground="#FFFFFF"
Margin="0,20,0,0" />
<!-- Поиск -->
<TextBox x:Name="SearchTextBox"
Width="560"
VerticalAlignment="Top"
Margin="0,49,0,0"
HorizontalAlignment="Center"
Style="{StaticResource RoundedTextBoxStyle}"
TextChanged="SearchTextBox_TextChanged" Height="35" />
<!-- Таблица для отображения -->
<DataGrid x:Name="PhysicalPersonsDataGrid"
Margin="20,100,20,20"
AutoGenerateColumns="False"
Style="{StaticResource RoundedDataGridStyle}">
<DataGrid.Columns>
<DataGridTextColumn Header="Фамилия" Binding="{Binding Surname}" Width="*" />
<DataGridTextColumn Header="Имя" Binding="{Binding Name}" Width="*" />
<DataGridTextColumn Header="Отчество" Binding="{Binding Patronymic}" Width="*" />
<DataGridTextColumn Header="Дата рождения" Binding="{Binding Birthday, StringFormat=dd.MM.yyyy}" Width="*" />
<DataGridTextColumn Header="Пол" Binding="{Binding Gender}" Width="*" />
<DataGridTextColumn Header="Адрес" Binding="{Binding Address}" Width="*" />
<DataGridTextColumn Header="Телефон" Binding="{Binding Telephone}" Width="*" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>

View File

@ -0,0 +1,52 @@
using EmployeeManagmentContracts.BusinessLogicContracts;
using EmployeeManagmentContracts.ViewModels;
using System.Linq;
using System.Windows;
namespace EmployeeManagmentView.PhysicalPerson
{
public partial class ViewPhysicalPersonsWindow : Window
{
private readonly IPhisicalPersonLogic _phisicalPersonLogic;
private IEnumerable<PhisicalPersonViewModel> _allPersons; // Храним все записи для фильтрации
public ViewPhysicalPersonsWindow(IPhisicalPersonLogic phisicalPersonLogic)
{
_phisicalPersonLogic = phisicalPersonLogic;
InitializeComponent();
LoadPhysicalPersons();
}
private void LoadPhysicalPersons()
{
_allPersons = _phisicalPersonLogic.GetFullList();
PhysicalPersonsDataGrid.ItemsSource = _allPersons;
}
private void SearchTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
string searchQuery = SearchTextBox.Text.ToLower(); // Получаем текст для поиска
if (string.IsNullOrWhiteSpace(searchQuery))
{
// Если поле пустое, показываем все записи
PhysicalPersonsDataGrid.ItemsSource = _allPersons;
}
else
{
// Фильтруем записи по всем полям
var filteredList = _allPersons.Where(p =>
p.Name.ToLower().Contains(searchQuery) ||
p.Surname.ToLower().Contains(searchQuery) ||
p.Patronymic.ToLower().Contains(searchQuery) || // Поиск по ФИО
p.Address.ToLower().Contains(searchQuery) || // Поиск по адресу
p.Telephone.Contains(searchQuery) || // Поиск по телефону
p.Gender.ToLower().Contains(searchQuery) || // Поиск по полу
p.Birthday.ToString("dd.MM.yyyy").Contains(searchQuery) // Поиск по дате рождения
).ToList();
PhysicalPersonsDataGrid.ItemsSource = filteredList;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More