Compare commits

..

11 Commits

Author SHA1 Message Date
59637a3e18 8 лаба 2025-05-22 09:32:03 +04:00
018a222a2c готовая работа 2025-05-13 18:08:27 +04:00
3791fac299 смена public на internal 2025-04-26 11:22:30 +04:00
22b9ea1bc2 даты 2025-04-24 08:55:21 +04:00
c9e9186093 Numbers 2025-04-23 17:41:11 +04:00
bf2577198b полная 6 лаба 2025-04-23 17:33:09 +04:00
478200b4a4 подготовка 2025-04-13 11:44:29 +04:00
e984b4d66f добавлена многпопоточность 2025-04-12 10:52:56 +04:00
afe18e1631 лаба 5 2025-04-10 09:38:24 +04:00
c9793000e3 подготовка ко 2 миграции 2025-04-09 14:37:39 +04:00
064a7c88b2 Первая миграция 2025-04-08 15:07:54 +04:00
185 changed files with 6939 additions and 4846 deletions

View File

@@ -1,74 +0,0 @@
using MagicCarpetContracts.BusinessLogicContracts;
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Enums;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.StoragesContracts;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.Implementations;
public class AgencyBusinessLogicContract(IAgencyStorageContract agencyStorageContract, ILogger logger) : IAgencyBusinessLogicContract
{
private readonly IAgencyStorageContract _agencyStorageContract = agencyStorageContract;
private readonly ILogger _logger = logger;
public List<AgencyDataModel> GetAllComponents()
{
_logger.LogInformation("GetAllComponents");
return _agencyStorageContract.GetList() ?? throw new NullListException();
return [];
}
public AgencyDataModel GetComponentByData(string data)
{
_logger.LogInformation("Get element by data: {data}", data);
if (data.IsEmpty())
{
throw new ArgumentNullException(nameof(data));
}
if (!data.IsGuid())
{
throw new ElementNotFoundException(data);
}
return _agencyStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data);
return new("", TourType.None, 0, []);
}
public void InsertComponent(AgencyDataModel agencyDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(agencyDataModel));
ArgumentNullException.ThrowIfNull(agencyDataModel);
agencyDataModel.Validate();
_agencyStorageContract.AddElement(agencyDataModel);
}
public void UpdateComponent(AgencyDataModel agencyDataModel)
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(agencyDataModel));
ArgumentNullException.ThrowIfNull(agencyDataModel);
agencyDataModel.Validate();
_agencyStorageContract.UpdElement(agencyDataModel);
}
public void DeleteComponent(string id)
{
logger.LogInformation("Delete by id: {id}", id);
if (id.IsEmpty())
{
throw new ArgumentNullException(nameof(id));
}
if (!id.IsGuid())
{
throw new ValidationException("Id is not a unique identifier");
}
_agencyStorageContract.DelElement(id);
}
}

View File

@@ -2,7 +2,9 @@
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
@@ -14,15 +16,16 @@ using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.Implementations;
public class ClientBusinessLogicContract(IClientStorageContract clientStorageContract, ILogger logger) : IClientBusinessLogicContract
internal class ClientBusinessLogicContract(IClientStorageContract clientStorageContract, IStringLocalizer<Messages> localizer, ILogger logger) : IClientBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly IClientStorageContract _clientStorageContract = clientStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<ClientDataModel> GetAllClients()
{
_logger.LogInformation("GetAllClients");
return _clientStorageContract.GetList() ?? throw new NullListException();
return _clientStorageContract.GetList();
}
public ClientDataModel GetClientByData(string data)
@@ -34,20 +37,20 @@ public class ClientBusinessLogicContract(IClientStorageContract clientStorageCon
}
if (data.IsGuid())
{
return _clientStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data);
return _clientStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
}
if (Regex.IsMatch(data, @"^((8|\+7)[\- ]?)?(\(?\d{3}\)?[\- ]?)?[\d\- ]{7,10}$"))
{
return _clientStorageContract.GetElementByPhoneNumber(data) ?? throw new ElementNotFoundException(data);
return _clientStorageContract.GetElementByPhoneNumber(data) ?? throw new ElementNotFoundException(data, _localizer);
}
return _clientStorageContract.GetElementByFIO(data) ?? throw new ElementNotFoundException(data);
return _clientStorageContract.GetElementByFIO(data) ?? throw new ElementNotFoundException(data, _localizer);
}
public void InsertClient(ClientDataModel clientDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(clientDataModel));
ArgumentNullException.ThrowIfNull(clientDataModel);
clientDataModel.Validate();
clientDataModel.Validate(_localizer);
_clientStorageContract.AddElement(clientDataModel);
}
@@ -55,7 +58,7 @@ public class ClientBusinessLogicContract(IClientStorageContract clientStorageCon
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(clientDataModel));
ArgumentNullException.ThrowIfNull(clientDataModel);
clientDataModel.Validate();
clientDataModel.Validate(_localizer);
_clientStorageContract.UpdElement(clientDataModel);
}
@@ -68,7 +71,7 @@ public class ClientBusinessLogicContract(IClientStorageContract clientStorageCon
}
if (!id.IsGuid())
{
throw new ValidationException("Id is not a unique identifier");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_clientStorageContract.DelElement(id);
}

View File

@@ -2,7 +2,9 @@
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
@@ -14,15 +16,16 @@ using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.Implementations;
public class EmployeeBusinessLogicContract(IEmployeeStorageContract employeeStorageContract, ILogger logger) : IEmployeeBusinessLogicContract
internal class EmployeeBusinessLogicContract(IEmployeeStorageContract employeeStorageContract, IStringLocalizer<Messages> localizer, ILogger logger) : IEmployeeBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly IEmployeeStorageContract _employeeStorageContract = employeeStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<EmployeeDataModel> GetAllEmployees(bool onlyActive = true)
{
_logger.LogInformation("GetAllEmployees params: {onlyActive}", onlyActive);
return _employeeStorageContract.GetList(onlyActive) ?? throw new NullListException();
return _employeeStorageContract.GetList(onlyActive);
}
public List<EmployeeDataModel> GetAllEmployeesByPost(string postId, bool onlyActive = true)
@@ -34,9 +37,9 @@ public class EmployeeBusinessLogicContract(IEmployeeStorageContract employeeStor
}
if (!postId.IsGuid())
{
throw new ValidationException("The value in the field postId is not a unique identifier.");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "PostId"));
}
return _employeeStorageContract.GetList(onlyActive, postId) ?? throw new NullListException();
return _employeeStorageContract.GetList(onlyActive, postId);
}
public List<EmployeeDataModel> GetAllEmployeesByBirthDate(DateTime fromDate, DateTime toDate, bool onlyActive = true)
@@ -44,9 +47,9 @@ public class EmployeeBusinessLogicContract(IEmployeeStorageContract employeeStor
_logger.LogInformation("GetAllEmployees params: {onlyActive}, {fromDate}, {toDate}", onlyActive, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
return _employeeStorageContract.GetList(onlyActive, fromBirthDate: fromDate, toBirthDate: toDate) ?? throw new NullListException();
return _employeeStorageContract.GetList(onlyActive, fromBirthDate: fromDate, toBirthDate: toDate);
}
public List<EmployeeDataModel> GetAllEmployeesByEmploymentDate(DateTime fromDate, DateTime toDate, bool onlyActive = true)
@@ -54,9 +57,9 @@ public class EmployeeBusinessLogicContract(IEmployeeStorageContract employeeStor
_logger.LogInformation("GetAllEmployees params: {onlyActive}, {fromDate}, {toDate}", onlyActive, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
return _employeeStorageContract.GetList(onlyActive, fromEmploymentDate: fromDate, toEmploymentDate: toDate) ?? throw new NullListException();
return _employeeStorageContract.GetList(onlyActive, fromEmploymentDate: fromDate, toEmploymentDate: toDate);
}
public EmployeeDataModel GetEmployeeByData(string data)
@@ -68,20 +71,20 @@ public class EmployeeBusinessLogicContract(IEmployeeStorageContract employeeStor
}
if (data.IsGuid())
{
return _employeeStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data);
return _employeeStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
}
if (Regex.IsMatch(data, @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"))
{
return _employeeStorageContract.GetElementByEmail(data) ?? throw new ElementNotFoundException(data);
return _employeeStorageContract.GetElementByEmail(data) ?? throw new ElementNotFoundException(data, _localizer);
}
return _employeeStorageContract.GetElementByFIO(data) ?? throw new ElementNotFoundException(data);
return _employeeStorageContract.GetElementByFIO(data) ?? throw new ElementNotFoundException(data, _localizer);
}
public void InsertEmployee(EmployeeDataModel employeeDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(employeeDataModel));
ArgumentNullException.ThrowIfNull(employeeDataModel);
employeeDataModel.Validate();
employeeDataModel.Validate(_localizer);
_employeeStorageContract.AddElement(employeeDataModel);
}
@@ -89,7 +92,7 @@ public class EmployeeBusinessLogicContract(IEmployeeStorageContract employeeStor
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(employeeDataModel));
ArgumentNullException.ThrowIfNull(employeeDataModel);
employeeDataModel.Validate();
employeeDataModel.Validate(_localizer);
_employeeStorageContract.UpdElement(employeeDataModel);
}
@@ -102,7 +105,7 @@ public class EmployeeBusinessLogicContract(IEmployeeStorageContract employeeStor
}
if (!id.IsGuid())
{
throw new ValidationException("Id is not a unique identifier");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_employeeStorageContract.DelElement(id);
}

View File

@@ -2,7 +2,9 @@
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
@@ -12,14 +14,15 @@ using System.Text.Json;
using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.Implementations;
public class PostBusinessLogicContract(IPostStorageContract postStorageContract, ILogger logger) : IPostBusinessLogicContract
internal class PostBusinessLogicContract(IPostStorageContract postStorageContract, IStringLocalizer<Messages> localizer, ILogger logger) : IPostBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly IPostStorageContract _postStorageContract = postStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<PostDataModel> GetAllPosts()
{
_logger.LogInformation("GetAllPosts");
return _postStorageContract.GetList() ?? throw new NullListException();
return _postStorageContract.GetList();
}
public List<PostDataModel> GetAllDataOfPost(string postId)
@@ -31,9 +34,9 @@ public class PostBusinessLogicContract(IPostStorageContract postStorageContract,
}
if (!postId.IsGuid())
{
throw new ValidationException("The value in the field postId is not a unique identifier.");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "PostId"));
}
return _postStorageContract.GetPostWithHistory(postId) ?? throw new NullListException();
return _postStorageContract.GetPostWithHistory(postId);
}
public PostDataModel GetPostByData(string data)
@@ -45,16 +48,16 @@ public class PostBusinessLogicContract(IPostStorageContract postStorageContract,
}
if (data.IsGuid())
{
return _postStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data);
return _postStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
}
return _postStorageContract.GetElementByName(data) ?? throw new ElementNotFoundException(data);
return _postStorageContract.GetElementByName(data) ?? throw new ElementNotFoundException(data, _localizer);
}
public void InsertPost(PostDataModel postDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(postDataModel));
ArgumentNullException.ThrowIfNull(postDataModel);
postDataModel.Validate();
postDataModel.Validate(_localizer);
_postStorageContract.AddElement(postDataModel);
}
@@ -62,7 +65,7 @@ public class PostBusinessLogicContract(IPostStorageContract postStorageContract,
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(postDataModel));
ArgumentNullException.ThrowIfNull(postDataModel);
postDataModel.Validate();
postDataModel.Validate(_localizer);
_postStorageContract.UpdElement(postDataModel);
}
@@ -75,7 +78,7 @@ public class PostBusinessLogicContract(IPostStorageContract postStorageContract,
}
if (!id.IsGuid())
{
throw new ValidationException("Id is not a unique identifier");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_postStorageContract.DelElement(id);
}
@@ -89,7 +92,7 @@ public class PostBusinessLogicContract(IPostStorageContract postStorageContract,
}
if (!id.IsGuid())
{
throw new ValidationException("Id is not a unique identifier");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_postStorageContract.ResElement(id);
}

View File

@@ -0,0 +1,179 @@
using DocumentFormat.OpenXml.Wordprocessing;
using MagicCarpetBusinessLogic.OfficePackage;
using MagicCarpetContracts.BusinessLogicContracts;
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.Implementations;
internal class ReportContract : IReportContract
{
private readonly ITourStorageContract _tourStorageContract;
private readonly ISalaryStorageContract _salaryStorageContract;
private readonly ISaleStorageContract _saleStorageContract;
private readonly BaseWordBuilder _baseWordBuilder;
private readonly BaseExcelBuilder _baseExcelBuilder;
private readonly BasePdfBuilder _basePdfBuilder;
private readonly ILogger _logger;
private readonly IStringLocalizer<Messages> _localizer;
internal readonly string[] _documentHeader;
internal readonly string[] _tableHeader;
public ReportContract(ITourStorageContract tourStorageContract, ISalaryStorageContract salaryStorageContract,
ISaleStorageContract saleStorageContract, BaseWordBuilder baseWordBuilder, BaseExcelBuilder baseExcelBuilder,
BasePdfBuilder basePdfBuilder, ILogger logger, IStringLocalizer<Messages> localizer)
{
_tourStorageContract = tourStorageContract;
_saleStorageContract = saleStorageContract;
_salaryStorageContract = salaryStorageContract;
_baseWordBuilder = baseWordBuilder;
_baseExcelBuilder = baseExcelBuilder;
_basePdfBuilder = basePdfBuilder;
_logger = logger;
_localizer = localizer;
_documentHeader = [_localizer["DocumentDocCaptionTour"], _localizer["DocumentDocCaptionPreviousNames"], _localizer["DocumentDocCaptionData"]];
_tableHeader = [_localizer["DocumentExcelCaptionDate"], _localizer["DocumentExcelCaptionSum"], _localizer["DocumentExcelCaptionDiscount"], _localizer["DocumentExcelCaptionTour"], _localizer["DocumentExcelCaptionCount"]];
}
public Task<List<TourAndTourHistoryDataModel>> GetDataToursHistoryAsync(CancellationToken ct)
{
_logger.LogInformation("Get data PostHistory");
return GetToursHistoriesAsync(ct);
}
public async Task<Stream> CreateDocumentToursHistoryAsync(CancellationToken ct)
{
_logger.LogInformation("Create report TourHistory");
var data = await GetToursHistoriesAsync(ct) ?? throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
return _baseWordBuilder
.AddHeader(_localizer["DocumentDocHeader"])
.AddParagraph(string.Format(_localizer["DocumentDocSubHeader"], DateTime.Now))
.AddTable(
new[] { 3000, 3000, 3000 },
new List<string[]> { _documentHeader }
.Concat(data.SelectMany(x =>
new[] { new[] { x.TourName, "", "" } }
.Concat(x.Histories.Zip(x.Data, (price, date) => new[] { "", price, date }))
))
.ToList())
.Build();
}
private async Task<List<TourAndTourHistoryDataModel>> GetToursHistoriesAsync(CancellationToken ct) =>
[.. (await _tourStorageContract.GetHistoriesListAsync(ct)).GroupBy(x => x.TourName).Select(x => new TourAndTourHistoryDataModel {
TourName = x.Key, Histories = [.. x.Select(y => y.OldPrice.ToString())], Data = [.. x.Select(y => y.ChangeDate.ToString())] })];
public async Task<Stream> CreateDocumentSalesByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
{
var tableHeader1 = new string[]
{
_localizer["DocumentExcelHeaderEmployee"],
_localizer["DocumentExcelCaptionDate"],
_localizer["DocumentExcelCaptionSum"],
_localizer["DocumentExcelCaptionDiscount"],
_localizer["DocumentExcelCaptionCocktail"],
_localizer["DocumentExcelCaptionCount"]
};
_logger.LogInformation("Create report SalesByPeriod from {dateStart} to {dateFinish}", dateStart, dateFinish);
var data = await GetDataBySalesAsync(dateStart, dateFinish, ct) ?? throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
var tableRows = new List<string[]>
{
tableHeader1
};
foreach (var sale in data)
{
tableRows.Add(new string[]
{
sale.EmployeeFIO ?? "",
sale.SaleDate.ToShortDateString(),
sale.Sum.ToString("N2"),
sale.Discount.ToString("N2"),
"", ""
});
foreach (var cocktail in sale.Tours ?? Enumerable.Empty<SaleTourDataModel>())
{
tableRows.Add(new string[]
{
"", "", "", "", cocktail.TourName, cocktail.Count.ToString("N2")
});
}
}
tableRows.Add(new string[]
{
_localizer["DocumentExcelCaptionTotal"], "", data.Sum(x => x.Sum).ToString("N2"), data.Sum(x => x.Discount).ToString("N2"), "", ""
});
return _baseExcelBuilder
.AddHeader(_localizer["DocumentExcelHeader"], 0, 6)
.AddParagraph(string.Format(_localizer["DocumentExcelSubHeader"], dateStart.ToLocalTime().ToShortDateString(), dateFinish.ToLocalTime().ToShortDateString()), 2)
.AddTable([15, 15, 10, 10, 25, 10], tableRows)
.Build();
}
public async Task<List<SaleDataModel>> GetDataBySalesAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
{
if (dateStart.IsDateNotOlder(dateFinish))
{
throw new IncorrectDatesException(dateStart, dateFinish, _localizer);
}
return [.. (await _saleStorageContract.GetListAsync(dateStart,
dateFinish, ct)).OrderBy(x => x.SaleDate)];
}
public Task<List<SaleDataModel>> GetDataSaleByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
{
_logger.LogInformation("Get data SalesByPeriod from {dateStart} to {dateFinish}", dateStart, dateFinish);
return GetDataBySalesAsync(dateStart, dateFinish, ct);
}
public Task<List<EmployeeSalaryByPeriodDataModel>> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
{
_logger.LogInformation("Get data SalaryByPeriod from {dateStart} to { dateFinish}", dateStart, dateFinish);
return GetDataBySalaryAsync(dateStart, dateFinish, ct);
}
private async Task<List<EmployeeSalaryByPeriodDataModel>> GetDataBySalaryAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
{
if (dateStart.IsDateNotOlder(dateFinish))
{
throw new IncorrectDatesException(dateStart, dateFinish, _localizer);
}
return [.. (await _salaryStorageContract.GetListAsync(dateStart, dateFinish, ct))
.GroupBy(x => x.EmployeeId)
.Select(x => new EmployeeSalaryByPeriodDataModel {
EmployeeFIO = x.First().EmployeeFIO,
TotalSalary = x.Sum(y => y.Salary),
FromPeriod = x.Min(y => y.SalaryDate),
ToPeriod = x.Max(y => y.SalaryDate)
})
.OrderBy(x => x.EmployeeFIO)];
}
public async Task<Stream> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
{
_logger.LogInformation("Create report SalaryByPeriod from {dateStart} to {dateFinish}", dateStart, dateFinish);
var data = await GetDataBySalaryAsync(dateStart, dateFinish, ct) ?? throw new InvalidOperationException("No found data");
return _basePdfBuilder
.AddHeader("Зарплатная ведомость")
.AddParagraph($"за период с {dateStart.ToShortDateString()} по {dateFinish.ToShortDateString()}")
.AddPieChart("Начисления", [.. data.Select(x => (x.EmployeeFIO, x.TotalSalary))])
.Build();
}
}

View File

@@ -2,7 +2,11 @@
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using MagicCarpetContracts.Infrastructure.PostConfigurations;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
@@ -11,29 +15,32 @@ using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.Implementations;
public class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageContract,ISaleStorageContract saleStorageContract,
IPostStorageContract postStorageContract, IEmployeeStorageContract employeeStorageContract, ILogger logger) : ISalaryBusinessLogicContract
internal class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageContract,ISaleStorageContract saleStorageContract,
IPostStorageContract postStorageContract, IEmployeeStorageContract employeeStorageContract, IStringLocalizer<Messages> localizer, ILogger logger, IConfigurationSalary сonfiguration) : ISalaryBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly ISalaryStorageContract _salaryStorageContract = salaryStorageContract;
private readonly ISaleStorageContract _saleStorageContract = saleStorageContract;
private readonly IPostStorageContract _postStorageContract = postStorageContract;
private readonly IEmployeeStorageContract _employeeStorageContract = employeeStorageContract;
private readonly IConfigurationSalary _salaryConfiguration = сonfiguration;
private readonly IStringLocalizer<Messages> _localizer = localizer;
private readonly Lock _lockObject = new();
public List<SalaryDataModel> GetAllSalariesByPeriod(DateTime fromDate, DateTime toDate)
{
_logger.LogInformation("GetAllSalaries params: {fromDate}, {toDate}", fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
return _salaryStorageContract.GetList(fromDate, toDate) ?? throw new NullListException();
return _salaryStorageContract.GetList(fromDate, toDate);
}
public List<SalaryDataModel> GetAllSalariesByPeriodByEmployee(DateTime fromDate, DateTime toDate, string employeeId)
{
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
if (employeeId.IsEmpty())
{
@@ -41,10 +48,10 @@ public class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageCon
}
if (!employeeId.IsGuid())
{
throw new ValidationException("The value in the field employeeId is not a unique identifier.");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "EmployeeId"));
}
_logger.LogInformation("GetAllSalaries params: {fromDate}, {toDate}, {employeeId}", fromDate, toDate, employeeId);
return _salaryStorageContract.GetList(fromDate, toDate, employeeId) ?? throw new NullListException();
return _salaryStorageContract.GetList(fromDate, toDate, employeeId);
}
public void CalculateSalaryByMounth(DateTime date)
@@ -52,16 +59,69 @@ public class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageCon
_logger.LogInformation("CalculateSalaryByMounth: {date}", date);
var startDate = new DateTime(date.Year, date.Month, 1);
var finishDate = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
var employees = _employeeStorageContract.GetList() ?? throw new NullListException();
var employees = _employeeStorageContract.GetList();
foreach (var employee in employees)
{
var sales = _saleStorageContract.GetList(startDate, finishDate, employeeId: employee.Id)?.Sum(x => x.Sum) ??
throw new NullListException();
var post = _postStorageContract.GetElementById(employee.PostId) ??
throw new NullListException();
var salary = post.Salary + sales * 0.1;
var sales = _saleStorageContract.GetList(startDate, finishDate, employeeId: employee.Id);
var post = _postStorageContract.GetElementById(employee.PostId);
var salary = post.ConfigurationModel switch
{
null => 0,
TravelAgentPostConfiguration cpc => CalculateSalaryForTravelAgent(sales, startDate, finishDate, cpc),
ChiefPostConfiguration spc => CalculateSalaryForChief(startDate, finishDate, spc),
PostConfiguration pc => pc.Rate,
};
_logger.LogDebug("The employee {employeeId} was paid a salary of {salary}", employee.Id, salary);
_salaryStorageContract.AddElement(new SalaryDataModel(employee.Id, DateTime.SpecifyKind(finishDate, DateTimeKind.Utc), salary));
_salaryStorageContract.AddElement(new SalaryDataModel(employee.Id, finishDate, salary));
}
}
private double CalculateSalaryForTravelAgent(List<SaleDataModel> sales, DateTime startDate, DateTime finishDate, TravelAgentPostConfiguration config)
{
var calcPercent = 0.0;
var dates = new List<DateTime>();
for (var date = startDate; date < finishDate; date = date.AddDays(1))
{
dates.Add(date);
}
var parallelOptions = new ParallelOptions
{
MaxDegreeOfParallelism = _salaryConfiguration.MaxConcurrentThreads
};
Parallel.ForEach(dates, parallelOptions, date =>
{
var salesInDay = sales.Where(x => x.SaleDate.Date == date.Date).ToArray();
if (salesInDay.Length > 0)
{
lock (_lockObject)
{
calcPercent += (salesInDay.Sum(x => x.Sum) / salesInDay.Length) * config.SalePercent;
}
}
});
double calcBonusTask = 0;
try
{
calcBonusTask = sales.Where(x => x.Sum > _salaryConfiguration.ExtraSaleSum).Sum(x => x.Sum) * config.BonusForExtraSales;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in bonus calculation");
}
return config.Rate + calcPercent + calcBonusTask;
}
private double CalculateSalaryForChief(DateTime startDate, DateTime finishDate, ChiefPostConfiguration config)
{
try
{
return config.Rate + config.PersonalCountTrendPremium * _employeeStorageContract.GetEmployeeTrend(startDate, finishDate);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in the chief payroll process");
return 0;
}
}
}

View File

@@ -2,7 +2,9 @@
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
@@ -13,20 +15,20 @@ using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.Implementations;
public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,IAgencyStorageContract agencyStorageContract, ILogger logger) : ISaleBusinessLogicContract
internal class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract, IStringLocalizer<Messages> localizer, ILogger logger) : ISaleBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly ISaleStorageContract _saleStorageContract = saleStorageContract;
private readonly IAgencyStorageContract _agencyStorageContract = agencyStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<SaleDataModel> GetAllSalesByPeriod(DateTime fromDate, DateTime toDate)
{
_logger.LogInformation("GetAllSales params: {fromDate}, {toDate}", fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
return _saleStorageContract.GetList(fromDate, toDate) ?? throw new NullListException();
return _saleStorageContract.GetList(fromDate, toDate);
}
public List<SaleDataModel> GetAllSalesByEmployeeByPeriod(string employeeId, DateTime fromDate, DateTime toDate)
@@ -34,7 +36,7 @@ public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,
_logger.LogInformation("GetAllSales params: {employeeId}, {fromDate}, {toDate}", employeeId, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
if (employeeId.IsEmpty())
{
@@ -44,7 +46,7 @@ public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,
{
throw new ValidationException("The value in the field employeeId is not a unique identifier.");
}
return _saleStorageContract.GetList(fromDate, toDate, employeeId: employeeId) ?? throw new NullListException();
return _saleStorageContract.GetList(fromDate, toDate, employeeId: employeeId);
}
public List<SaleDataModel> GetAllSalesByClientByPeriod(string clientId, DateTime fromDate, DateTime toDate)
@@ -52,7 +54,7 @@ public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,
_logger.LogInformation("GetAllSales params: {buyerId}, {fromDate}, {toDate}", clientId, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
if (clientId.IsEmpty())
{
@@ -60,9 +62,9 @@ public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,
}
if (!clientId.IsGuid())
{
throw new ValidationException("The value in the field clientId is not a unique identifier.");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "ClientId"));
}
return _saleStorageContract.GetList(fromDate, toDate, clientId: clientId) ?? throw new NullListException();
return _saleStorageContract.GetList(fromDate, toDate, clientId: clientId);
}
public List<SaleDataModel> GetAllSalesByTourByPeriod(string tourId, DateTime fromDate, DateTime toDate)
@@ -70,7 +72,7 @@ public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,
_logger.LogInformation("GetAllSales params: {tourId}, {fromDate}, {toDate}", tourId, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
if (tourId.IsEmpty())
{
@@ -78,9 +80,9 @@ public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,
}
if (!tourId.IsGuid())
{
throw new ValidationException("The value in the field tourId is not a unique identifier.");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "TourId"));
}
return _saleStorageContract.GetList(fromDate, toDate, tourId: tourId) ?? throw new NullListException();
return _saleStorageContract.GetList(fromDate, toDate, tourId: tourId);
}
public SaleDataModel GetSaleByData(string data)
@@ -92,20 +94,16 @@ public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,
}
if (!data.IsGuid())
{
throw new ValidationException("Id is not a unique identifier");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
return _saleStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data);
return _saleStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data,_localizer);
}
public void InsertSale(SaleDataModel saleDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(saleDataModel));
ArgumentNullException.ThrowIfNull(saleDataModel);
saleDataModel.Validate();
if (!_agencyStorageContract.CheckComponents(saleDataModel))
{
throw new InsufficientException("Dont have tour in agency");
}
saleDataModel.Validate(_localizer);
_saleStorageContract.AddElement(saleDataModel);
}
@@ -118,7 +116,7 @@ public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,
}
if (!id.IsGuid())
{
throw new ValidationException("Id is not a unique identifier");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_saleStorageContract.DelElement(id);
}

View File

@@ -1,61 +0,0 @@
using MagicCarpetContracts.BusinessLogicContracts;
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Enums;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.StoragesContracts;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.Implementations;
public class SuppliesBusinessLogicContract(ISuppliesStorageContract suppliesStorageContract, ILogger logger) : ISuppliesBusinessLogicContract
{
private readonly ISuppliesStorageContract _suppliesStorageContract = suppliesStorageContract;
private readonly ILogger _logger = logger;
public List<SuppliesDataModel> GetAllComponents()
{
_logger.LogInformation("GetAllComponents");
return _suppliesStorageContract.GetList() ?? throw new NullListException();
return [];
}
public SuppliesDataModel GetComponentByData(string data)
{
_logger.LogInformation("Get element by data: {data}", data);
if (data.IsEmpty())
{
throw new ArgumentNullException(nameof(data));
}
if (!data.IsGuid())
{
throw new ElementNotFoundException(data);
}
return _suppliesStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data);
return new("", TourType.None, DateTime.UtcNow, 0, []);
}
public void InsertComponent(SuppliesDataModel suppliesDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(suppliesDataModel));
ArgumentNullException.ThrowIfNull(suppliesDataModel);
suppliesDataModel.Validate();
_suppliesStorageContract.AddElement(suppliesDataModel);
}
public void UpdateComponent(SuppliesDataModel suppliesDataModel)
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(suppliesDataModel));
ArgumentNullException.ThrowIfNull(suppliesDataModel);
suppliesDataModel.Validate();
_suppliesStorageContract.UpdElement(suppliesDataModel);
}
}

View File

@@ -2,7 +2,9 @@
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
@@ -13,14 +15,15 @@ using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.Implementations;
public class TourBusinessLogicContract(ITourStorageContract tourStorageContract, ILogger logger) : ITourBusinessLogicContract
internal class TourBusinessLogicContract(ITourStorageContract tourStorageContract, IStringLocalizer<Messages> localizer, ILogger logger) : ITourBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly ITourStorageContract _tourStorageContract = tourStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<TourDataModel> GetAllTours()
{
_logger.LogInformation("GetAllTours");
return _tourStorageContract.GetList() ?? throw new NullListException();
return _tourStorageContract.GetList();
}
public List<TourHistoryDataModel> GetTourHistoryByTour(string tourId)
@@ -32,9 +35,9 @@ public class TourBusinessLogicContract(ITourStorageContract tourStorageContract,
}
if (!tourId.IsGuid())
{
throw new ValidationException("The value in the field tourId is not a unique identifier.");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "TourId"));
}
return _tourStorageContract.GetHistoryByTourId(tourId) ?? throw new NullListException();
return _tourStorageContract.GetHistoryByTourId(tourId);
}
public TourDataModel GetTourByData(string data)
@@ -46,23 +49,25 @@ public class TourBusinessLogicContract(ITourStorageContract tourStorageContract,
}
if (data.IsGuid())
{
return _tourStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data);
return _tourStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
}
return _tourStorageContract.GetElementByName(data) ?? throw new ElementNotFoundException(data);
return _tourStorageContract.GetElementByName(data) ?? throw new ElementNotFoundException(data, _localizer);
}
public void InsertTour(TourDataModel tourDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(tourDataModel));
ArgumentNullException.ThrowIfNull(tourDataModel);
tourDataModel.Validate();
tourDataModel.Validate(_localizer);
_tourStorageContract.AddElement(tourDataModel);
}
public void UpdateTour(TourDataModel tourDataModel)
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(tourDataModel));
ArgumentNullException.ThrowIfNull(tourDataModel);
tourDataModel.Validate();
tourDataModel.Validate(_localizer);
_tourStorageContract.UpdElement(tourDataModel);
}
public void DeleteTour(string id)
@@ -74,7 +79,7 @@ public class TourBusinessLogicContract(ITourStorageContract tourStorageContract,
}
if (!id.IsGuid())
{
throw new ValidationException("Id is not a unique identifier");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_tourStorageContract.DelElement(id);
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
@@ -11,7 +11,9 @@
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.2" />
<PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.4" />
<PackageReference Include="PdfSharp.MigraDoc.Standard" Version="1.51.15" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.OfficePackage;
public abstract class BaseExcelBuilder
{
public abstract BaseExcelBuilder AddHeader(string header, int startIndex, int count);
public abstract BaseExcelBuilder AddParagraph(string text, int columnIndex);
public abstract BaseExcelBuilder AddTable(int[] columnsWidths, List<string[]> data);
public abstract Stream Build();
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.OfficePackage;
public abstract class BasePdfBuilder
{
public abstract BasePdfBuilder AddHeader(string header);
public abstract BasePdfBuilder AddParagraph(string text);
public abstract BasePdfBuilder AddPieChart(string title, List<(string Caption, double Value)> data);
public abstract Stream Build();
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.OfficePackage;
public abstract class BaseWordBuilder
{
public abstract BaseWordBuilder AddHeader(string header);
public abstract BaseWordBuilder AddParagraph(string text);
public abstract BaseWordBuilder AddTable(int[] widths, List<string[]> data);
public abstract Stream Build();
}

View File

@@ -0,0 +1,89 @@
using MigraDoc.DocumentObjectModel;
using MigraDoc.DocumentObjectModel.Shapes.Charts;
using MigraDoc.Rendering;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.OfficePackage;
public class MigraDocPdfBuilder : BasePdfBuilder
{
private readonly Document _document;
public MigraDocPdfBuilder()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
_document = new Document();
DefineStyles();
}
public override BasePdfBuilder AddHeader(string header)
{
_document.AddSection().AddParagraph(header, "NormalBold");
return this;
}
public override BasePdfBuilder AddParagraph(string text)
{
_document.LastSection.AddParagraph(text, "Normal");
return this;
}
public override BasePdfBuilder AddPieChart(string title, List<(string Caption, double Value)> data)
{
if (data == null || data.Count == 0)
{
return this;
}
var chart = new Chart(ChartType.Pie2D);
var series = chart.SeriesCollection.AddSeries();
series.Add(data.Select(x => x.Value).ToArray());
var xseries = chart.XValues.AddXSeries();
xseries.Add(data.Select(x => x.Caption).ToArray());
chart.DataLabel.Type = DataLabelType.Percent;
chart.DataLabel.Position = DataLabelPosition.OutsideEnd;
chart.Width = Unit.FromCentimeter(16);
chart.Height = Unit.FromCentimeter(12);
chart.TopArea.AddParagraph(title);
chart.XAxis.MajorTickMark = TickMarkType.Outside;
chart.YAxis.MajorTickMark = TickMarkType.Outside;
chart.YAxis.HasMajorGridlines = true;
chart.PlotArea.LineFormat.Width = 1;
chart.PlotArea.LineFormat.Visible = true;
chart.TopArea.AddLegend();
_document.LastSection.Add(chart);
return this;
}
public override Stream Build()
{
var stream = new MemoryStream();
var renderer = new PdfDocumentRenderer(true)
{
Document = _document
};
renderer.RenderDocument();
renderer.PdfDocument.Save(stream);
return stream;
}
private void DefineStyles()
{
var style = _document.Styles.AddStyle("NormalBold", "Normal");
style.Font.Bold = true;
}
}

View File

@@ -0,0 +1,308 @@
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.OfficePackage;
public class OpenXmlExcelBuilder : BaseExcelBuilder
{
private readonly SheetData _sheetData;
private readonly MergeCells _mergeCells;
private readonly Columns _columns;
private uint _rowIndex = 0;
public OpenXmlExcelBuilder()
{
_sheetData = new SheetData();
_mergeCells = new MergeCells();
_columns = new Columns();
_rowIndex = 1;
}
public override BaseExcelBuilder AddHeader(string header, int startIndex, int count)
{
CreateCell(startIndex, _rowIndex, header, StyleIndex.BoldTextWithoutBorder);
for (int i = startIndex + 1; i < startIndex + count; ++i)
{
CreateCell(i, _rowIndex, "", StyleIndex.SimpleTextWithoutBorder);
}
_mergeCells.Append(new MergeCell()
{
Reference =
new StringValue($"{GetExcelColumnName(startIndex)}{_rowIndex}:{GetExcelColumnName(startIndex + count - 1)}{_rowIndex}")
});
_rowIndex++;
return this;
}
public override BaseExcelBuilder AddParagraph(string text, int columnIndex)
{
CreateCell(columnIndex, _rowIndex++, text, StyleIndex.SimpleTextWithoutBorder);
return this;
}
public override BaseExcelBuilder AddTable(int[] columnsWidths, List<string[]> data)
{
if (columnsWidths == null || columnsWidths.Length == 0)
{
throw new ArgumentNullException(nameof(columnsWidths));
}
if (data == null || data.Count == 0)
{
throw new ArgumentNullException(nameof(data));
}
if (data.Any(x => x.Length != columnsWidths.Length))
{
throw new InvalidOperationException("widths.Length != data.Length");
}
uint counter = 1;
int coef = 2;
_columns.Append(columnsWidths.Select(x => new Column
{
Min = counter,
Max = counter++,
Width = x * coef,
CustomWidth = true
}));
for (var j = 0; j < data.First().Length; ++j)
{
CreateCell(j, _rowIndex, data.First()[j], StyleIndex.BoldTextWithBorder);
}
_rowIndex++;
for (var i = 1; i < data.Count - 1; ++i)
{
for (var j = 0; j < data[i].Length; ++j)
{
CreateCell(j, _rowIndex, data[i][j], StyleIndex.SimpleTextWithBorder);
}
_rowIndex++;
}
for (var j = 0; j < data.Last().Length; ++j)
{
CreateCell(j, _rowIndex, data.Last()[j], StyleIndex.BoldTextWithBorder);
}
_rowIndex++;
return this;
}
public override Stream Build()
{
var stream = new MemoryStream();
using var spreadsheetDocument = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook);
var workbookpart = spreadsheetDocument.AddWorkbookPart();
GenerateStyle(workbookpart);
workbookpart.Workbook = new Workbook();
var worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet();
if (_columns.HasChildren)
{
worksheetPart.Worksheet.Append(_columns);
}
worksheetPart.Worksheet.Append(_sheetData);
var sheets = spreadsheetDocument.WorkbookPart!.Workbook.AppendChild(new Sheets());
var sheet = new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart),
SheetId = 1,
Name = "Лист 1"
};
sheets.Append(sheet);
if (_mergeCells.HasChildren)
{
worksheetPart.Worksheet.InsertAfter(_mergeCells, worksheetPart.Worksheet.Elements<SheetData>().First());
}
return stream;
}
private static void GenerateStyle(WorkbookPart workbookPart)
{
var workbookStylesPart = workbookPart.AddNewPart<WorkbookStylesPart>();
workbookStylesPart.Stylesheet = new Stylesheet();
var fonts = new Fonts() { Count = 2, KnownFonts = BooleanValue.FromBoolean(true) };
fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font
{
FontSize = new FontSize() { Val = 11 },
FontName = new FontName() { Val = "Calibri" },
FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 },
FontScheme = new FontScheme() { Val = new EnumValue<FontSchemeValues>(FontSchemeValues.Minor) }
});
fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font
{
FontSize = new FontSize() { Val = 11 },
FontName = new FontName() { Val = "Calibri" },
FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 },
FontScheme = new FontScheme() { Val = new EnumValue<FontSchemeValues>(FontSchemeValues.Minor) },
Bold = new Bold()
});
workbookStylesPart.Stylesheet.Append(fonts);
// Default Fill
var fills = new Fills() { Count = 1 };
fills.Append(new Fill
{
PatternFill = new PatternFill() { PatternType = new EnumValue<PatternValues>(PatternValues.None) }
});
workbookStylesPart.Stylesheet.Append(fills);
// Default Border
var borders = new Borders() { Count = 2 };
borders.Append(new Border
{
LeftBorder = new LeftBorder(),
RightBorder = new RightBorder(),
TopBorder = new TopBorder(),
BottomBorder = new BottomBorder(),
DiagonalBorder = new DiagonalBorder()
});
borders.Append(new Border
{
LeftBorder = new LeftBorder() { Style = BorderStyleValues.Thin },
RightBorder = new RightBorder() { Style = BorderStyleValues.Thin },
TopBorder = new TopBorder() { Style = BorderStyleValues.Thin },
BottomBorder = new BottomBorder() { Style = BorderStyleValues.Thin }
});
workbookStylesPart.Stylesheet.Append(borders);
// Default cell format and a date cell format
var cellFormats = new CellFormats() { Count = 4 };
cellFormats.Append(new CellFormat
{
NumberFormatId = 0,
FormatId = 0,
FontId = 0,
BorderId = 0,
FillId = 0,
Alignment = new Alignment()
{
Horizontal = HorizontalAlignmentValues.Left,
Vertical = VerticalAlignmentValues.Center,
WrapText = true
}
});
cellFormats.Append(new CellFormat
{
NumberFormatId = 0,
FormatId = 0,
FontId = 0,
BorderId = 1,
FillId = 0,
Alignment = new Alignment()
{
Horizontal = HorizontalAlignmentValues.Left,
Vertical = VerticalAlignmentValues.Center,
WrapText = true
}
});
cellFormats.Append(new CellFormat
{
NumberFormatId = 0,
FormatId = 0,
FontId = 1,
BorderId = 0,
FillId = 0,
Alignment = new Alignment()
{
Horizontal = HorizontalAlignmentValues.Center,
Vertical = VerticalAlignmentValues.Center,
WrapText = true
}
});
cellFormats.Append(new CellFormat
{
NumberFormatId = 0,
FormatId = 0,
FontId = 1,
BorderId = 1,
FillId = 0,
Alignment = new Alignment()
{
Horizontal = HorizontalAlignmentValues.Center,
Vertical = VerticalAlignmentValues.Center,
WrapText = true
}
});
workbookStylesPart.Stylesheet.Append(cellFormats);
}
private enum StyleIndex
{
SimpleTextWithoutBorder = 0,
SimpleTextWithBorder = 1,
BoldTextWithoutBorder = 2,
BoldTextWithBorder = 3
}
private void CreateCell(int columnIndex, uint rowIndex, string text, StyleIndex styleIndex)
{
var columnName = GetExcelColumnName(columnIndex);
var cellReference = columnName + rowIndex;
var row = _sheetData.Elements<Row>().FirstOrDefault(r => r.RowIndex! == rowIndex);
if (row == null)
{
row = new Row() { RowIndex = rowIndex };
_sheetData.Append(row);
}
var newCell = row.Elements<Cell>()
.FirstOrDefault(c => c.CellReference != null && c.CellReference.Value == columnName + rowIndex);
if (newCell == null)
{
Cell? refCell = null;
foreach (Cell cell in row.Elements<Cell>())
{
if (cell.CellReference?.Value != null && cell.CellReference.Value.Length == cellReference.Length)
{
if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
{
refCell = cell;
break;
}
}
}
newCell = new Cell() { CellReference = cellReference };
row.InsertBefore(newCell, refCell);
}
newCell.CellValue = new CellValue(text);
newCell.DataType = CellValues.String;
newCell.StyleIndex = (uint)styleIndex;
}
private static string GetExcelColumnName(int columnNumber)
{
columnNumber += 1;
int dividend = columnNumber;
string columnName = string.Empty;
int modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
dividend = (dividend - modulo) / 26;
}
return columnName;
}
}

View File

@@ -0,0 +1,99 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetBusinessLogic.OfficePackage;
public class OpenXmlWordBuilder : BaseWordBuilder
{
private readonly Document _document;
private readonly Body _body;
public OpenXmlWordBuilder()
{
_document = new Document();
_body = _document.AppendChild(new Body());
}
public override BaseWordBuilder AddHeader(string header)
{
var paragraph = _body.AppendChild(new Paragraph());
var run = paragraph.AppendChild(new Run());
run.AppendChild(new RunProperties(new Bold()));
run.AppendChild(new Text(header));
return this;
}
public override BaseWordBuilder AddParagraph(string text)
{
var paragraph = _body.AppendChild(new Paragraph());
var run = paragraph.AppendChild(new Run());
run.AppendChild(new Text(text));
return this;
}
public override BaseWordBuilder AddTable(int[] widths, List<string[]> data)
{
if (widths == null || widths.Length == 0)
{
throw new ArgumentNullException(nameof(widths));
}
if (data == null || data.Count == 0)
{
throw new ArgumentNullException(nameof(data));
}
if (data.Any(x => x.Length != widths.Length))
{
throw new InvalidOperationException("widths.Length != data.Length");
}
var table = new Table();
table.AppendChild(new TableProperties(
new TableBorders(
new TopBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
new BottomBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
new LeftBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
new RightBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
new InsideHorizontalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
new InsideVerticalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 }
)
));
// Заголовок
var tr = new TableRow();
for (var j = 0; j < widths.Length; ++j)
{
tr.Append(new TableCell(
new TableCellProperties(new TableCellWidth() { Width = widths[j].ToString() }),
new Paragraph(new Run(new RunProperties(new Bold()), new Text(data.First()[j])))));
}
table.Append(tr);
// Данные
table.Append(data.Skip(1).Select(x =>
new TableRow(x.Select(y => new TableCell(new Paragraph(new Run(new Text(y))))))));
_body.Append(table);
return this;
}
public override Stream Build()
{
var stream = new MemoryStream();
using var wordDocument = WordprocessingDocument.Create(stream, WordprocessingDocumentType.Document);
var mainPart = wordDocument.AddMainDocumentPart();
mainPart.Document = _document;
return stream;
}
}

View File

@@ -1,18 +0,0 @@
using MagicCarpetContracts.AdapterContracts.OperationResponses;
using MagicCarpetContracts.BindingModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.AdapterContracts;
public interface IAgencyAdapter
{
AgencyOperationResponse GetAllComponents();
AgencyOperationResponse GetComponentByData(string data);
AgencyOperationResponse InsertComponent(AgencyBindingModel warehouseDataModel);
AgencyOperationResponse UpdateComponent(AgencyBindingModel warehouseDataModel);
AgencyOperationResponse DeleteComponent(string id);
}

View File

@@ -0,0 +1,18 @@
using MagicCarpetContracts.AdapterContracts.OperationResponses;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.AdapterContracts;
public interface IReportAdapter
{
Task<ReportOperationResponse> GetDataToursHistoryAsync(CancellationToken ct);
Task<ReportOperationResponse> GetDataBySalesByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<ReportOperationResponse> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<ReportOperationResponse> CreateDocumentToursHistoryAsync(CancellationToken ct);
Task<ReportOperationResponse> CreateDocumentSalesByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<ReportOperationResponse> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
}

View File

@@ -1,17 +0,0 @@
using MagicCarpetContracts.AdapterContracts.OperationResponses;
using MagicCarpetContracts.BindingModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.AdapterContracts;
public interface ISuppliesAdapter
{
SuppliesOperationResponse GetAllComponents();
SuppliesOperationResponse GetComponentByData(string data);
SuppliesOperationResponse InsertComponent(SuppliesBindingModel componentDataModel);
SuppliesOperationResponse UpdateComponent(SuppliesBindingModel componentDataModel);
}

View File

@@ -1,26 +0,0 @@
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Infrastructure;
using MagicCarpetContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.AdapterContracts.OperationResponses;
public class AgencyOperationResponse : OperationResponse
{
public static AgencyOperationResponse OK(List<AgencyViewModel> data) => OK<AgencyOperationResponse, List<AgencyViewModel>>(data);
public static AgencyOperationResponse OK(AgencyViewModel data) => OK<AgencyOperationResponse, AgencyViewModel>(data);
public static AgencyOperationResponse NoContent() => NoContent<AgencyOperationResponse>();
public static AgencyOperationResponse NotFound(string message) => NotFound<AgencyOperationResponse>(message);
public static AgencyOperationResponse BadRequest(string message) => BadRequest<AgencyOperationResponse>(message);
public static AgencyOperationResponse InternalServerError(string message) => InternalServerError<AgencyOperationResponse>(message);
}

View File

@@ -0,0 +1,24 @@
using MagicCarpetContracts.Infrastructure;
using MagicCarpetContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.AdapterContracts.OperationResponses;
public class ReportOperationResponse : OperationResponse
{
public static ReportOperationResponse OK(List<TourAndTourHistoryViewModel> data) => OK<ReportOperationResponse, List<TourAndTourHistoryViewModel>>(data);
public static ReportOperationResponse OK(List<SaleViewModel> data) => OK<ReportOperationResponse, List<SaleViewModel>>(data);
public static ReportOperationResponse OK(List<EmployeeSalaryByPeriodViewModel> data) => OK<ReportOperationResponse, List<EmployeeSalaryByPeriodViewModel>>(data);
public static ReportOperationResponse OK(Stream data, string fileName) => OK<ReportOperationResponse, Stream>(data, fileName);
public static ReportOperationResponse BadRequest(string message) => BadRequest<ReportOperationResponse>(message);
public static ReportOperationResponse InternalServerError(string message) => InternalServerError<ReportOperationResponse>(message);
}

View File

@@ -1,24 +0,0 @@
using MagicCarpetContracts.Infrastructure;
using MagicCarpetContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.AdapterContracts.OperationResponses;
public class SuppliesOperationResponse : OperationResponse
{
public static SuppliesOperationResponse OK(List<SuppliesViewModel> data) => OK<SuppliesOperationResponse, List<SuppliesViewModel>>(data);
public static SuppliesOperationResponse OK(SuppliesViewModel data) => OK<SuppliesOperationResponse, SuppliesViewModel>(data);
public static SuppliesOperationResponse NoContent() => NoContent<SuppliesOperationResponse>();
public static SuppliesOperationResponse NotFound(string message) => NotFound<SuppliesOperationResponse>(message);
public static SuppliesOperationResponse BadRequest(string message) => BadRequest<SuppliesOperationResponse>(message);
public static SuppliesOperationResponse InternalServerError(string message) => InternalServerError<SuppliesOperationResponse>(message);
}

View File

@@ -1,16 +0,0 @@
using MagicCarpetContracts.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.BindingModels;
public class AgencyBindingModel
{
public string? Id { get; set; }
public TourType? TourType { get; set; }
public int Count { get; set; }
public List<TourAgencyBindingModel>? Tours { get; set; }
}

View File

@@ -1,7 +1,12 @@
using System;
using MagicCarpetContracts.Infrastructure.PostConfigurations;
using MagicCarpetContracts.Mapper;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace MagicCarpetContracts.BindingModels;
@@ -16,5 +21,26 @@ public class PostBindingModel
public string? PostType { get; set; }
public double Salary { get; set; }
[PostProcessing(MappingCallMethodName = "ParseConfiguration")]
public string? ConfigurationJson { get; set; }
private string ParseConfiguration(PostConfiguration model) =>
System.Text.Json.JsonSerializer.Serialize(model, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
private PostConfiguration? ParseJson(string json)
{
if (ConfigurationJson is null)
return null;
var obj = JToken.Parse(json);
if (obj is not null)
{
return obj.Value<string>("Type") switch
{
nameof(TravelAgentPostConfiguration) => JsonConvert.DeserializeObject<TravelAgentPostConfiguration>(json)!,
nameof(ChiefPostConfiguration) => JsonConvert.DeserializeObject<ChiefPostConfiguration>(json)!,
_ => JsonConvert.DeserializeObject<PostConfiguration>(json)!,
};
}
return null;
}
}

View File

@@ -1,17 +0,0 @@
using MagicCarpetContracts.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.BindingModels;
public class SuppliesBindingModel
{
public string? Id { get; set; }
public TourType? TourType { get; set; }
public DateTime ProductuionDate { get; set; }
public int Count { get; set; }
public List<TourSuppliesBindingModel>? Tours { get; set; }
}

View File

@@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.BindingModels;
public class TourAgencyBindingModel
{
public string? AgencyId { get; set; }
public string? TourId { get; set; }
public int Count { get; set; }
}

View File

@@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.BindingModels;
public class TourSuppliesBindingModel
{
public string? SuppliesId { get; set; }
public string? TourId { get; set; }
public int Count { get; set; }
}

View File

@@ -1,17 +0,0 @@
using MagicCarpetContracts.DataModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.BusinessLogicContracts;
public interface IAgencyBusinessLogicContract
{
List<AgencyDataModel> GetAllComponents();
AgencyDataModel GetComponentByData(string data);
void InsertComponent(AgencyDataModel agencyDataModel);
void UpdateComponent(AgencyDataModel agencyDataModel);
void DeleteComponent(string id);
}

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.BuisnessLogicContracts;
public interface IClientBusinessLogicContract
internal interface IClientBusinessLogicContract
{
List<ClientDataModel> GetAllClients();

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.BuisnessLogicContracts;
public interface IEmployeeBusinessLogicContract
internal interface IEmployeeBusinessLogicContract
{
List<EmployeeDataModel> GetAllEmployees(bool onlyActive = true);

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.BuisnessLogicContracts;
public interface IPostBusinessLogicContract
internal interface IPostBusinessLogicContract
{
List<PostDataModel> GetAllPosts();

View File

@@ -0,0 +1,18 @@
using MagicCarpetContracts.DataModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.BusinessLogicContracts;
internal interface IReportContract
{
Task<List<TourAndTourHistoryDataModel>> GetDataToursHistoryAsync(CancellationToken ct);
Task<Stream> CreateDocumentToursHistoryAsync(CancellationToken ct);
Task<List<SaleDataModel>> GetDataBySalesAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<Stream> CreateDocumentSalesByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<List<EmployeeSalaryByPeriodDataModel>> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<Stream> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
}

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.BuisnessLogicContracts;
public interface ISalaryBusinessLogicContract
internal interface ISalaryBusinessLogicContract
{
List<SalaryDataModel> GetAllSalariesByPeriod(DateTime fromDate, DateTime toDate);

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.BuisnessLogicContracts;
public interface ISaleBusinessLogicContract
internal interface ISaleBusinessLogicContract
{
List<SaleDataModel> GetAllSalesByPeriod(DateTime fromDate, DateTime toDate);

View File

@@ -1,16 +0,0 @@
using MagicCarpetContracts.DataModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.BusinessLogicContracts;
public interface ISuppliesBusinessLogicContract
{
List<SuppliesDataModel> GetAllComponents();
SuppliesDataModel GetComponentByData(string data);
void InsertComponent(SuppliesDataModel componentDataModel);
void UpdateComponent(SuppliesDataModel componentDataModel);
}

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.BuisnessLogicContracts;
public interface ITourBusinessLogicContract
internal interface ITourBusinessLogicContract
{
List<TourDataModel> GetAllTours();

View File

@@ -1,33 +0,0 @@
using MagicCarpetContracts.Enums;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.DataModels;
public class AgencyDataModel(string id, TourType tourType, int count, List<TourAgencyDataModel> tours) : IValidation
{
public string Id { get; private set; } = id;
public TourType TourType { get; private set; } = tourType;
public int Count { get; private set; } = count;
public List<TourAgencyDataModel> Tours { get; private set; } = tours;
public void Validate()
{
if (Id.IsEmpty())
throw new ValidationException("Field Id is empty");
if (!Id.IsGuid())
throw new ValidationException("The value in the field Id is not a unique identifier");
if (TourType == TourType.None)
throw new ValidationException("Field Type is empty");
if (Count <= 0)
throw new ValidationException("Field Count is less than or equal to 0");
if ((Tours?.Count ?? 0) == 0)
throw new ValidationException("The sale must include tours");
}
}

View File

@@ -9,10 +9,12 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ValidationException = MagicCarpetContracts.Exceptions.ValidationException;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
namespace MagicCarpetContracts.DataModels;
public class ClientDataModel(string id, string fIO, string phoneNumber, double discountSize) : IValidation
internal class ClientDataModel(string id, string fIO, string phoneNumber, double discountSize) : IValidation
{
public string Id { get; private set; } = id;
@@ -22,21 +24,23 @@ public class ClientDataModel(string id, string fIO, string phoneNumber, double d
public double DiscountSize { get; private set; } = discountSize;
public void Validate()
public ClientDataModel() : this(string.Empty, string.Empty, string.Empty, 0) { }
public void Validate(IStringLocalizer<Messages> localizer)
{
if (Id.IsEmpty())
throw new ValidationException("Field Id is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "Id"));
if (!Id.IsGuid())
throw new ValidationException("The value in the field Id is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "Id"));
if (FIO.IsEmpty())
throw new ValidationException("Field FIO is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "FIO"));
if (PhoneNumber.IsEmpty())
throw new ValidationException("Field PhoneNumber is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "PhoneNumber"));
if (!Regex.IsMatch(PhoneNumber, @"^((8|\+7)[\- ]?)?(\(?\d{3}\)?[\- ]?)?[\d\- ]{7,10}$"))
throw new ValidationException("Field PhoneNumber is not a phone number");
throw new ValidationException(localizer["ValidationExceptionIncorrectPhoneNumber"]);
}
}

View File

@@ -1,7 +1,9 @@
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,7 +13,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.DataModels;
public class EmployeeDataModel(string id, string fio, string email, string postId, DateTime birthDate, DateTime employmentDate, bool isDeleted) : IValidation
internal class EmployeeDataModel(string id, string fio, string email, string postId, DateTime birthDate, DateTime employmentDate, bool isDeleted) : IValidation
{
private readonly PostDataModel? _post;
@@ -23,9 +25,9 @@ public class EmployeeDataModel(string id, string fio, string email, string postI
public string PostId { get; private set; } = postId;
public DateTime BirthDate { get; private set; } = birthDate;
public DateTime BirthDate { get; private set; } = birthDate.ToUniversalTime();
public DateTime EmploymentDate { get; private set; } = employmentDate;
public DateTime EmploymentDate { get; private set; } = employmentDate.ToUniversalTime();
public bool IsDeleted { get; private set; } = isDeleted;
@@ -40,36 +42,40 @@ public class EmployeeDataModel(string id, string fio, string email, string postI
public EmployeeDataModel(string id, string fio, string email, string postId, DateTime birthDate,
DateTime employmentDate) : this(id, fio, email, postId, birthDate, employmentDate, false) { }
public void Validate()
public EmployeeDataModel() : this(string.Empty, string.Empty, string.Empty, string.Empty, DateTime.MinValue, DateTime.MinValue, false) { }
public void Validate(IStringLocalizer<Messages> localizer)
{
if (Id.IsEmpty())
throw new ValidationException("Field Id is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "Id"));
if (!Id.IsGuid())
throw new ValidationException("The value in the field Id is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "Id"));
if (FIO.IsEmpty())
throw new ValidationException("Field FIO is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "FIO"));
if (Email.IsEmpty())
throw new ValidationException("Field Email is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "Email"));
if (!Regex.IsMatch(Email, @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"))
throw new ValidationException("Field Email is not a valid email address");
throw new ValidationException(localizer["ValidationExceptionMessageIncorrectEmail"]);
if (PostId.IsEmpty())
throw new ValidationException("Field PostId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "PostId"));
if (!PostId.IsGuid())
throw new ValidationException("The value in the field PostId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "PostId"));
if (BirthDate.Date > DateTime.Now.AddYears(-18).Date)
throw new ValidationException($"Only adults can be hired (BirthDate = {BirthDate.ToShortDateString()})");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageMinorsBirthDate"], BirthDate.ToShortDateString()));
if (EmploymentDate.Date < BirthDate.Date)
throw new ValidationException("The date of employment cannot be less than the date of birth");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmploymentDateAndBirthDate"],
EmploymentDate.ToShortDateString(), BirthDate.ToShortDateString()));
if ((EmploymentDate - BirthDate).TotalDays / 365 < 18)
throw new ValidationException($"Only adults can be hired (EmploymentDate - {EmploymentDate.ToShortDateString()}, BirthDate - {BirthDate.ToShortDateString()})");
if ((EmploymentDate - BirthDate).TotalDays / 365 < 18)
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageMinorsEmploymentDate"],
EmploymentDate.ToShortDateString(), BirthDate.ToShortDateString()));
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.DataModels;
public class EmployeeSalaryByPeriodDataModel
{
public required string EmployeeFIO { get; set; }
public double TotalSalary { get; set; }
public DateTime FromPeriod { get; set; }
public DateTime ToPeriod { get; set; }
}

View File

@@ -2,32 +2,82 @@
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using MagicCarpetContracts.Infrastructure.PostConfigurations;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
using MagicCarpetContracts.Mapper;
namespace MagicCarpetContracts.DataModels;
public class PostDataModel(string postId, string postName, PostType postType, double salary) : IValidation
internal class PostDataModel(string postId, string postName, PostType postType, PostConfiguration configuration) : IValidation
{
[AlternativeName("PostId")]
public string Id { get; private set; } = postId;
public string PostName { get; private set; } = postName;
public PostType PostType { get; private set; } = postType;
public double Salary { get; private set; } = salary;
public void Validate()
[AlternativeName("Configuration")]
[AlternativeName("ConfigurationJson")]
[PostProcessing(MappingCallMethodName = "ParseJson")]
public PostConfiguration ConfigurationModel { get; private set; } = configuration;
public PostDataModel() : this(string.Empty, string.Empty, PostType.None, null) { }
public PostDataModel(string postId, string postName) : this(postId, postName, PostType.None, new PostConfiguration() { Rate = 10 }) { }
public void Validate(IStringLocalizer<Messages> localizer)
{
if (Id.IsEmpty())
throw new ValidationException("Field Id is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "Id"));
if (!Id.IsGuid())
throw new ValidationException("The value in the field Id is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "Id"));
if (PostName.IsEmpty())
throw new ValidationException("Field PostName is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "PostName"));
if (PostType == PostType.None)
throw new ValidationException("Field PostType is empty");
if (Salary <= 0)
throw new ValidationException("Field Salary is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "PostType"));
if (ConfigurationModel is null)
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotInitialized"], "ConfigurationModel"));
if (ConfigurationModel!.Rate <= 0)
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "Rate"));
}
private PostConfiguration? ParseJson(object json)
{
if (json is PostConfiguration config)
{
return config;
}
if (json is string)
{
var obj = JToken.Parse((string)json);
var type = obj.Value<string>("Type");
switch (type)
{
case nameof(TravelAgentPostConfiguration):
ConfigurationModel = JsonConvert.DeserializeObject<TravelAgentPostConfiguration>((string)json);
break;
case nameof(ChiefPostConfiguration):
ConfigurationModel = JsonConvert.DeserializeObject<ChiefPostConfiguration>((string)json);
break;
default:
ConfigurationModel = JsonConvert.DeserializeObject<PostConfiguration>((string)json);
break;
}
return ConfigurationModel;
}
return null;
}
}

View File

@@ -1,6 +1,9 @@
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using MagicCarpetContracts.Mapper;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -9,13 +12,14 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.DataModels;
public class SalaryDataModel(string employeeId, DateTime salaryDate, double employeeSalary) : IValidation
internal class SalaryDataModel(string employeeId, DateTime salaryDate, double employeeSalary) : IValidation
{
private readonly EmployeeDataModel? _employee;
public string EmployeeId { get; private set; } = employeeId;
public DateTime SalaryDate { get; private set; } = salaryDate;
public DateTime SalaryDate { get; private set; } = salaryDate.ToUniversalTime();
[AlternativeName("EmployeeSalary")]
public double Salary { get; private set; } = employeeSalary;
public string EmployeeFIO => _employee?.FIO ?? string.Empty;
@@ -25,15 +29,17 @@ public class SalaryDataModel(string employeeId, DateTime salaryDate, double empl
_employee = employee;
}
public void Validate()
public SalaryDataModel() : this(string.Empty, DateTime.Now, 0) { }
public void Validate(IStringLocalizer<Messages> localizer)
{
if (EmployeeId.IsEmpty())
throw new ValidationException("Field EmployeeId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "EmployeeId"));
if (!EmployeeId.IsGuid())
throw new ValidationException("The value in the field EmployeeId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "EmployeeId"));
if (Salary <= 0)
throw new ValidationException("Field Salary is less than or equal to 0");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "Salary"));
}
}

View File

@@ -2,6 +2,9 @@
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using MagicCarpetContracts.Mapper;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -10,7 +13,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.DataModels;
public class SaleDataModel : IValidation
internal class SaleDataModel : IValidation
{
private readonly ClientDataModel? _client;
@@ -32,6 +35,7 @@ public class SaleDataModel : IValidation
public bool IsCancel { get; private set; }
[AlternativeName("SaleTours")]
public List<SaleTourDataModel>? Tours { get; private set; }
public string ClientFIO => _client?.FIO ?? string.Empty;
@@ -83,27 +87,34 @@ public class SaleDataModel : IValidation
public SaleDataModel(string id, string employeeId, string? clientId, int discountType,
List<SaleTourDataModel> tours) : this(id, employeeId, clientId, (DiscountType)discountType, false, tours) { }
public void Validate()
public SaleDataModel() : this(string.Empty, string.Empty, string.Empty, DiscountType.None, false, new List<SaleTourDataModel>()) { }
public void Validate(IStringLocalizer<Messages> localizer)
{
if (Id.IsEmpty())
throw new ValidationException("Field Id is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "Id"));
if (!Id.IsGuid())
throw new ValidationException("The value in the field Id is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "Id"));
if (EmployeeId.IsEmpty())
throw new ValidationException("Field EmployeeId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "WorkerId"));
if (!EmployeeId.IsGuid())
throw new ValidationException("The value in the field EmployeeId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "WorkerId"));
if (!ClientId?.IsGuid() ?? !ClientId?.IsEmpty() ?? false)
throw new ValidationException("The value in the field BuyerId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "BuyerId"));
if (Sum <= 0)
throw new ValidationException("Field Sum is less than or equal to 0");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "Sum"));
if ((Tours?.Count ?? 0) == 0)
throw new ValidationException("The sale must include tours");
if (Tours is null)
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotInitialized"], "Tours"));
if (Tours.Count == 0)
throw new ValidationException(localizer["ValidationExceptionMessageNoProductsInSale"]);
Tours.ForEach(x => x.Validate(localizer));
}
}

View File

@@ -1,6 +1,8 @@
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -10,7 +12,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.DataModels;
public class SaleTourDataModel(string saleId, string tourId, int count, double price) : IValidation
internal class SaleTourDataModel(string saleId, string tourId, int count, double price) : IValidation
{
private readonly TourDataModel? _tour;
@@ -24,29 +26,31 @@ public class SaleTourDataModel(string saleId, string tourId, int count, double p
public string TourName => _tour?.TourName ?? string.Empty;
public SaleTourDataModel() : this(string.Empty, string.Empty, 0, 0.0) { }
public SaleTourDataModel(string saleId, string tourId, int count, double price, TourDataModel tour) : this(saleId, tourId, count, price)
{
_tour = tour;
}
public void Validate()
public void Validate(IStringLocalizer<Messages> localizer)
{
if (SaleId.IsEmpty())
throw new ValidationException("Field SaleId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "SaleId"));
if (!SaleId.IsGuid())
throw new ValidationException("The value in the field SaleId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "SaleId"));
if (TourId.IsEmpty())
throw new ValidationException("Field ProductId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "ITourIdd"));
if (!TourId.IsGuid())
throw new ValidationException("The value in the field ProductId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "TourId"));
if (Count <= 0)
throw new ValidationException("Field Count is less than or equal to 0");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "Count"));
if (Price <= 0)
throw new ValidationException("Field Price is less than or equal to 0");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "Price"));
}
}

View File

@@ -1,35 +0,0 @@
using MagicCarpetContracts.Enums;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace MagicCarpetContracts.DataModels;
public class SuppliesDataModel(string id, TourType tourType, DateTime productuionDate, int count, List<TourSuppliesDataModel> tours) : IValidation
{
public string Id { get; private set; } = id;
public TourType TourType { get; private set; } = tourType;
public DateTime ProductuionDate { get; private set; } = productuionDate;
public int Count { get; private set; } = count;
public List<TourSuppliesDataModel> Tours { get; private set; } = tours;
public void Validate()
{
if (Id.IsEmpty())
throw new ValidationException("Field Id is empty");
if (!Id.IsGuid())
throw new ValidationException("The value in the field Id is not a unique identifier");
if (TourType == TourType.None)
throw new ValidationException("Field Type is empty");
if (Count <= 0)
throw new ValidationException("Field Count is less than or equal to 0");
if ((Tours?.Count ?? 0) == 0)
throw new ValidationException("The sale must include tours");
}
}

View File

@@ -1,32 +0,0 @@
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.DataModels;
public class TourAgencyDataModel(string agencyId, string tourId, int count) : IValidation
{
public string AgencyId { get; private set; } = agencyId;
public string TourId { get; private set; } = tourId;
public int Count { get; private set; } = count;
public void Validate()
{
if (AgencyId.IsEmpty())
throw new ValidationException("Field AgencyId is empty");
if (!AgencyId.IsGuid())
throw new ValidationException("The value in the field AgencyId is not a unique identifier");
if (TourId.IsEmpty())
throw new ValidationException("Field TourId is empty");
if (!TourId.IsGuid())
throw new ValidationException("The value in the field TourId is not a unique identifier");
if (Count <= 0)
throw new ValidationException("Field Count is less than or equal to 0");
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.DataModels;
public class TourAndTourHistoryDataModel
{
public required string TourName { get; set; }
public required List<string> Histories { get; set; }
public required List<string> Data { get; set; }
}

View File

@@ -2,6 +2,8 @@
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -12,7 +14,7 @@ using System.Xml.Linq;
namespace MagicCarpetContracts.DataModels;
public class TourDataModel(string id, string tourName, string tourCountry, double price, TourType tourType) : IValidation
internal class TourDataModel(string id, string tourName, string tourCountry, double price, TourType tourType) : IValidation
{
public string Id { get; private set; } = id;
public string TourName { get; private set; } = tourName;
@@ -20,19 +22,21 @@ public class TourDataModel(string id, string tourName, string tourCountry, doubl
public double Price { get; private set; } = price;
public TourType TourType { get; private set; } = tourType;
public void Validate()
public TourDataModel() : this(string.Empty, string.Empty, string.Empty, 0, TourType.None) { }
public void Validate(IStringLocalizer<Messages> localizer)
{
if (Id.IsEmpty())
throw new ValidationException("Field Id is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "Id"));
if (!Id.IsGuid())
throw new ValidationException("The value in the field Id is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "Id"));
if (TourName.IsEmpty())
throw new ValidationException("Field TourName is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "TourName"));
if (TourCountry.IsEmpty())
throw new ValidationException("Field TourCountry is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "TourCountry"));
if (Price <= 0)
throw new ValidationException("Field Price is less than or equal to 0");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "Price"));
if (TourType == TourType.None)
throw new ValidationException("Field Type is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "TourType"));
}
}

View File

@@ -1,15 +1,12 @@
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
namespace MagicCarpetContracts.DataModels;
public class TourHistoryDataModel(string tourId, double oldPrice) : IValidation
internal class TourHistoryDataModel(string tourId, double oldPrice) : IValidation
{
private readonly TourDataModel? _tour;
@@ -27,15 +24,17 @@ public class TourHistoryDataModel(string tourId, double oldPrice) : IValidation
_tour = tour;
}
public void Validate()
public TourHistoryDataModel() : this(string.Empty, 0) { }
public void Validate(IStringLocalizer<Messages> localizer)
{
if (TourId.IsEmpty())
throw new ValidationException("Field TourId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "TourId"));
if (!TourId.IsGuid())
throw new ValidationException("The value in the field TourId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "TourId"));
if (OldPrice <= 0)
throw new ValidationException("Field OldPrice is less than or equal to 0");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "OldPrice"));
}
}

View File

@@ -1,32 +0,0 @@
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Extensions;
using MagicCarpetContracts.Infrastructure;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.DataModels;
public class TourSuppliesDataModel(string suppliesId, string tourId, int count) : IValidation
{
public string SuppliesId { get; private set; } = suppliesId;
public string TourId { get; private set; } = tourId;
public int Count { get; private set; } = count;
public void Validate()
{
if (SuppliesId.IsEmpty())
throw new ValidationException("Field SuppliesId is empty");
if (!SuppliesId.IsGuid())
throw new ValidationException("The value in the field SuppliesId is not a unique identifier");
if (TourId.IsEmpty())
throw new ValidationException("Field TourId is empty");
if (!TourId.IsGuid())
throw new ValidationException("The value in the field BlandId is not a unique identifier");
if (Count <= 0)
throw new ValidationException("Field Count is less than or equal to 0");
}
}

View File

@@ -1,4 +1,6 @@
using System;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,7 +8,6 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.Exceptions;
public class ElementDeletedException : Exception
{
public ElementDeletedException(string id) : base($"Cannot modify a deleted item (id: {id})") { }
}
internal class ElementDeletedException(string id, IStringLocalizer<Messages> localizer)
: Exception(string.Format(localizer["ElementDeletedExceptionMessage"], id))
{ }

View File

@@ -1,4 +1,6 @@
using System;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,15 +8,10 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.Exceptions;
public class ElementExistsException : Exception
internal class ElementExistsException(string paramName, string paramValue, IStringLocalizer<Messages> localizer) :
Exception(string.Format(localizer["ElementExistsExceptionMessage"], paramValue, paramName))
{
public string ParamName { get; private set; }
public string ParamName { get; private set; } = paramName;
public string ParamValue { get; private set; }
public ElementExistsException(string paramName, string paramValue) : base($"There is already an element with value{paramValue} of parameter {paramName}")
{
ParamName = paramName;
ParamValue = paramValue;
}
public string ParamValue { get; private set; } = paramValue;
}

View File

@@ -1,4 +1,6 @@
using System;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,12 +8,8 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.Exceptions;
public class ElementNotFoundException : Exception
internal class ElementNotFoundException(string value, IStringLocalizer<Messages> localizer) :
Exception(string.Format(localizer["AdapterMessageElementNotFoundException"], value))
{
public string Value { get; private set; }
public ElementNotFoundException(string value) : base($"Element not found at value = {value}")
{
Value = value;
}
public string Value { get; private set; } = value;
}

View File

@@ -1,4 +1,6 @@
using System;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,8 +8,6 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.Exceptions;
public class IncorrectDatesException : Exception
{
public IncorrectDatesException(DateTime start, DateTime end) : base($"The end date must be later than the start date.. StartDate: " +
$"{start:dd.MM.YYYY}. EndDate: {end:dd.MM.YYYY}") { }
}
internal class IncorrectDatesException(DateTime start, DateTime end, IStringLocalizer<Messages> localizer) :
Exception(string.Format(localizer["IncorrectDatesExceptionMessage"], start.ToShortDateString(), end.ToShortDateString()))
{ }

View File

@@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.Exceptions;
public class InsufficientException(string message) : Exception(message)
{
}

View File

@@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.Exceptions;
public class NullListException : Exception
{
public NullListException() : base("The returned list is null") { }
}

View File

@@ -1,4 +1,6 @@
using System;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,7 +8,5 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.Exceptions;
public class StorageException : Exception
{
public StorageException(Exception ex) : base($"Error while working in storage: {ex.Message}", ex) { }
}
internal class StorageException(Exception ex, IStringLocalizer<Messages> localizer) : Exception(string.Format(localizer["StorageExceptionMessage"], ex.Message), ex)
{ }

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.Infrastructure;
public interface IConfigurationSalary
{
double ExtraSaleSum { get; }
int MaxConcurrentThreads { get; }
}

View File

@@ -1,4 +1,6 @@
using System;
using MagicCarpetContracts.Resources;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,8 +8,8 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.Infrastructure;
public interface IValidation
internal interface IValidation
{
void Validate();
void Validate(IStringLocalizer<Messages> localizer);
}

View File

@@ -11,32 +11,41 @@ namespace MagicCarpetContracts.Infrastructure;
public class OperationResponse
{
public HttpStatusCode StatusCode { get; set; }
protected HttpStatusCode StatusCode { get; set; }
public object? Result { get; set; }
protected object? Result { get; set; }
protected string? FileName { get; set; }
public IActionResult GetResponse(HttpRequest request, HttpResponse response)
{
ArgumentNullException.ThrowIfNull(request);
ArgumentNullException.ThrowIfNull(response);
response.StatusCode = (int)StatusCode;
if (Result is null)
{
return new StatusCodeResult((int)StatusCode);
}
if (Result is Stream stream)
{
return new FileStreamResult(stream, "application/octetstream")
{
FileDownloadName = FileName
};
}
return new ObjectResult(Result);
}
protected static TResult OK<TResult, TData>(TData data) where TResult : OperationResponse,
new() => new() { StatusCode = HttpStatusCode.OK, Result = data };
protected static TResult NoContent<TResult>() where TResult : OperationResponse,
protected static TResult OK<TResult, TData>(TData data, string fileName) where TResult : OperationResponse,
new() => new() { StatusCode = HttpStatusCode.OK, Result = data, FileName = fileName };
protected static TResult NoContent<TResult>() where TResult : OperationResponse,
new() => new() { StatusCode = HttpStatusCode.NoContent };
protected static TResult BadRequest<TResult>(string? errorMessage = null) where TResult : OperationResponse,
protected static TResult BadRequest<TResult>(string? errorMessage = null) where TResult : OperationResponse,
new() => new() { StatusCode = HttpStatusCode.BadRequest, Result = errorMessage };
protected static TResult NotFound<TResult>(string? errorMessage = null) where TResult : OperationResponse,

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.Infrastructure.PostConfigurations;
public class ChiefPostConfiguration : PostConfiguration
{
public override string Type => nameof(ChiefPostConfiguration);
public double PersonalCountTrendPremium { get; set; }
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.Infrastructure.PostConfigurations;
public class PostConfiguration
{
public virtual string Type => nameof(PostConfiguration);
public double Rate { get; set; }
public string CultureName { get; set; } = CultureInfo.CurrentCulture.Name;
}

View File

@@ -0,0 +1,15 @@
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.Infrastructure.PostConfigurations;
public class TravelAgentPostConfiguration : PostConfiguration
{
public override string Type => nameof(TravelAgentPostConfiguration);
public double SalePercent { get; set; }
public double BonusForExtraSales { get; set; }
}

View File

@@ -10,6 +10,14 @@
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.3.0" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="9.0.4" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="MagicCarpetDatabase" />
<InternalsVisibleTo Include="MagicCarpetTests" />
<InternalsVisibleTo Include="MagicCarpetBusinessLogic" />
<InternalsVisibleTo Include="MagicCarpetWebApi" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,12 @@
namespace MagicCarpetContracts.Mapper;
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
public class AlternativeNameAttribute : Attribute
{
public string AlternativeName { get; }
public AlternativeNameAttribute(string alternativeName)
{
AlternativeName = alternativeName;
}
}

View File

@@ -0,0 +1,281 @@
using System.Collections;
using System.ComponentModel;
using System.Reflection;
namespace MagicCarpetContracts.Mapper;
internal static class CustomMapper
{
public static To MapObject<To>(object obj, To newObject)
{
ArgumentNullException.ThrowIfNull(obj);
ArgumentNullException.ThrowIfNull(newObject);
var typeFrom = obj.GetType();
var typeTo = newObject.GetType();
var propertiesFrom = typeFrom.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(x => x.CanRead)
.ToArray();
// свойств
foreach (var property in typeTo.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(x => x.CanWrite))
{
if (property.GetCustomAttribute<IgnoreMappingAttribute>() is not null)
continue;
var propertyFrom = TryGetPropertyFrom(property, propertiesFrom);
if (propertyFrom is null)
{
FindAndMapDefaultValue(property, newObject);
continue;
}
var fromValue = propertyFrom.GetValue(obj);
var postProcessingAttribute = property.GetCustomAttribute<PostProcessingAttribute>();
if (postProcessingAttribute is not null)
{
var value = PostProcessing(fromValue, postProcessingAttribute, newObject);
if (value is not null)
{
property.SetValue(newObject, value);
}
continue;
}
if (propertyFrom.PropertyType.IsGenericType && propertyFrom.PropertyType.Name.StartsWith("List") && fromValue is not null)
{
fromValue = MapListOfObjects(property, fromValue);
}
if (propertyFrom.PropertyType.IsEnum && property.PropertyType == typeof(string) && fromValue != null)
{
fromValue = fromValue.ToString();
}
else if (!propertyFrom.PropertyType.IsEnum && property.PropertyType.IsEnum && fromValue is not null)
{
if (fromValue is string stringValue)
fromValue = Enum.Parse(property.PropertyType, stringValue);
else
fromValue = Enum.ToObject(property.PropertyType, fromValue);
}
if (fromValue is not null)
{
if (propertyFrom.PropertyType.IsClass
&& property.PropertyType.IsClass
&& propertyFrom.PropertyType != typeof(string)
&& property.PropertyType != typeof(string)
&& !property.PropertyType.IsAssignableFrom(propertyFrom.PropertyType))
{
try
{
var nestedInstance = Activator.CreateInstance(property.PropertyType);
if (nestedInstance != null)
{
var nestedMapped = MapObject(fromValue, nestedInstance);
property.SetValue(newObject, nestedMapped);
continue;
}
}
catch
{
// ignore
}
}
property.SetValue(newObject, fromValue);
}
}
// полей
var fieldsTo = typeTo.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
var fieldsFrom = typeFrom.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (var field in fieldsTo)
{
if (field.Name.Contains("k__BackingField"))
continue;
if (field.GetCustomAttribute<IgnoreMappingAttribute>() is not null)
continue;
var sourceField = fieldsFrom.FirstOrDefault(f => f.Name == field.Name);
object? fromValue = null;
if (sourceField is not null)
{
fromValue = sourceField.GetValue(obj);
}
else
{
var propertyName = field.Name.TrimStart('_');
var sourceProperty = typeFrom.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (sourceProperty is not null && sourceProperty.CanRead)
{
fromValue = sourceProperty.GetValue(obj);
}
}
if (fromValue is null)
continue;
if (field.FieldType.IsClass && field.FieldType != typeof(string))
{
try
{
var nested = Activator.CreateInstance(field.FieldType)!;
var mapped = MapObject(fromValue, nested);
RemoveReadOnly(field);
field.SetValue(newObject, mapped);
continue;
}
catch
{
// ignore
}
}
RemoveReadOnly(field);
field.SetValue(newObject, fromValue);
}
var classPostProcessing = typeTo.GetCustomAttribute<PostProcessingAttribute>();
if (classPostProcessing is not null && classPostProcessing.MappingCallMethodName is not null)
{
var methodInfo = typeTo.GetMethod(classPostProcessing.MappingCallMethodName, BindingFlags.NonPublic | BindingFlags.Instance);
methodInfo?.Invoke(newObject, []);
}
return newObject;
}
private static void RemoveReadOnly(FieldInfo field)
{
if (!field.IsInitOnly)
return;
var attr = typeof(FieldInfo).GetField("m_fieldAttributes", BindingFlags.Instance | BindingFlags.NonPublic);
if (attr != null)
{
var current = (FieldAttributes)attr.GetValue(field)!;
attr.SetValue(field, current & ~FieldAttributes.InitOnly);
}
}
public static To MapObject<To>(object obj) => MapObject(obj, Activator.CreateInstance<To>()!);
public static To? MapObjectWithNull<To>(object? obj) => obj is null ? default : MapObject(obj, Activator.CreateInstance<To>());
private static PropertyInfo? TryGetPropertyFrom(PropertyInfo propertyTo, PropertyInfo[] propertiesFrom)
{
var customAttribute = propertyTo.GetCustomAttributes<AlternativeNameAttribute>()?
.ToArray()
.FirstOrDefault(x => propertiesFrom.Any(y => y.Name == x.AlternativeName));
if (customAttribute is not null)
{
return propertiesFrom.FirstOrDefault(x => x.Name == customAttribute.AlternativeName);
}
return propertiesFrom.FirstOrDefault(x => x.Name == propertyTo.Name);
}
private static object? PostProcessing<T>(object? value, PostProcessingAttribute postProcessingAttribute, T newObject)
{
if (value is null || newObject is null)
{
return null;
}
if (!string.IsNullOrEmpty(postProcessingAttribute.MappingCallMethodName))
{
var methodInfo =
newObject.GetType().GetMethod(postProcessingAttribute.MappingCallMethodName, BindingFlags.NonPublic | BindingFlags.Instance);
if (methodInfo is not null)
{
return methodInfo.Invoke(newObject, [value]);
}
}
else if (postProcessingAttribute.ActionType != PostProcessingType.None)
{
switch (postProcessingAttribute.ActionType)
{
case PostProcessingType.ToUniversalTime:
return ToUniversalTime(value);
case PostProcessingType.ToLocalTime:
return ToLocalTime(value);
}
}
return null;
}
private static object? ToLocalTime(object? obj)
{
if (obj is DateTime date)
return date.ToLocalTime();
return obj;
}
private static object? ToUniversalTime(object? obj)
{
if (obj is DateTime date)
return date.ToUniversalTime();
return obj;
}
private static void FindAndMapDefaultValue<T>(PropertyInfo property, T newObject)
{
var defaultValueAttribute = property.GetCustomAttribute<DefaultValueAttribute>();
if (defaultValueAttribute is null)
{
return;
}
if (defaultValueAttribute.DefaultValue is not null)
{
property.SetValue(newObject, defaultValueAttribute.DefaultValue);
return;
}
var value = defaultValueAttribute.Func switch
{
DefaultValueFunc.UtcNow => DateTime.UtcNow,
_ => (object?)null,
};
if (value is not null)
{
property.SetValue(newObject, value);
}
}
private static object? MapListOfObjects(PropertyInfo propertyTo, object list)
{
var listResult = Activator.CreateInstance(propertyTo.PropertyType);
var elementType = propertyTo.PropertyType.GenericTypeArguments[0];
foreach (var elem in (IEnumerable)list)
{
object? newElem;
if (elementType.IsPrimitive || elementType == typeof(string) || elementType == typeof(decimal) || elementType == typeof(DateTime))
{
newElem = elem;
}
else
{
newElem = MapObject(elem, Activator.CreateInstance(elementType)!);
}
if (newElem is not null)
{
propertyTo.PropertyType.GetMethod("Add")!.Invoke(listResult, [newElem]);
}
}
return listResult;
}
}
enum DefaultValueFunc
{
None,
UtcNow
}

View File

@@ -0,0 +1,12 @@
namespace MagicCarpetContracts.Mapper;
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
class DefaultValueAttribute : Attribute
{
public object? DefaultValue { get; set; }
public string? FuncName { get; set; }
public DefaultValueFunc Func { get; set; } = DefaultValueFunc.None;
}

View File

@@ -0,0 +1,6 @@
namespace MagicCarpetContracts.Mapper;
[AttributeUsage(AttributeTargets.Property)]
class IgnoreMappingAttribute : Attribute
{
}

View File

@@ -0,0 +1,9 @@
namespace MagicCarpetContracts.Mapper;
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Field)]
class PostProcessingAttribute : Attribute
{
public string? MappingCallMethodName { get; set; }
public PostProcessingType ActionType { get; set; } = PostProcessingType.None;
}

View File

@@ -0,0 +1,10 @@
namespace MagicCarpetContracts.Mapper;
enum PostProcessingType
{
None = -1,
ToUniversalTime = 1,
ToLocalTime = 2
}

View File

@@ -0,0 +1,225 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Этот код создан программой.
// Исполняемая версия:4.0.30319.42000
//
// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
// повторной генерации кода.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MagicCarpetContracts.Resources {
using System;
/// <summary>
/// Класс ресурса со строгой типизацией для поиска локализованных строк и т.д.
/// </summary>
// Этот класс создан автоматически классом StronglyTypedResourceBuilder
// с помощью такого средства, как ResGen или Visual Studio.
// Чтобы добавить или удалить член, измените файл .ResX и снова запустите ResGen
// с параметром /str или перестройте свой проект VS.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Messages {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Messages() {
}
/// <summary>
/// Возвращает кэшированный экземпляр ResourceManager, использованный этим классом.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MagicCarpetContracts.Resources.Messages", typeof(Messages).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Перезаписывает свойство CurrentUICulture текущего потока для всех
/// обращений к ресурсу с помощью этого класса ресурса со строгой типизацией.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Нельзя изменить удаленный элемент (идентификатор: {0}).
/// </summary>
internal static string ElementDeletedExceptionMessage {
get {
return ResourceManager.GetString("ElementDeletedExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Уже существует элемент со значением {0} параметра {1}.
/// </summary>
internal static string ElementExistsExceptionMessage {
get {
return ResourceManager.GetString("ElementExistsExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Элемент не найден по значению = {0}.
/// </summary>
internal static string ElementNotFoundExceptionMessage {
get {
return ResourceManager.GetString("ElementNotFoundExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Дата окончания должна быть позже даты начала. Дата начала: {0}. ​​Дата окончания: {1}.
/// </summary>
internal static string IncorrectDatesExceptionMessage {
get {
return ResourceManager.GetString("IncorrectDatesExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Недостаточно данных для обработки: {0}.
/// </summary>
internal static string NotEnoughDataToProcessExceptionMessage {
get {
return ResourceManager.GetString("NotEnoughDataToProcessExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Не найдены данные.
/// </summary>
internal static string NotFoundDataMessage {
get {
return ResourceManager.GetString("NotFoundDataMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Ошибка при работе в хранилище: {0}.
/// </summary>
internal static string StorageExceptionMessage {
get {
return ResourceManager.GetString("StorageExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Дата трудоустройства не может быть раньше даты рождения ({0}, {1}).
/// </summary>
internal static string ValidationExceptionMessageEmploymentDateAndBirthDate {
get {
return ResourceManager.GetString("ValidationExceptionMessageEmploymentDateAndBirthDate", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Значение в поле {0} пусто.
/// </summary>
internal static string ValidationExceptionMessageEmptyField {
get {
return ResourceManager.GetString("ValidationExceptionMessageEmptyField", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Некорректный формат ФИО.
/// </summary>
internal static string ValidationExceptionMessageIncorrectFIO {
get {
return ResourceManager.GetString("ValidationExceptionMessageIncorrectFIO", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Значение в поле Телефонный номер не является телефонным номером.
/// </summary>
internal static string ValidationExceptionMessageIncorrectPhoneNumber {
get {
return ResourceManager.GetString("ValidationExceptionMessageIncorrectPhoneNumber", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Значение в поле {0} меньше или равно 0.
/// </summary>
internal static string ValidationExceptionMessageLessOrEqualZero {
get {
return ResourceManager.GetString("ValidationExceptionMessageLessOrEqualZero", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Несовершеннолетние не могут быть приняты на работу (Дата рождения: {0}).
/// </summary>
internal static string ValidationExceptionMessageMinorsBirthDate {
get {
return ResourceManager.GetString("ValidationExceptionMessageMinorsBirthDate", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Несовершеннолетние не могут быть приняты на работу (Дата трудоустройства: {0}, Дата рождения: {1}).
/// </summary>
internal static string ValidationExceptionMessageMinorsEmploymentDate {
get {
return ResourceManager.GetString("ValidationExceptionMessageMinorsEmploymentDate", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Отсутствуют компоненты.
/// </summary>
internal static string ValidationExceptionMessageNoComponents {
get {
return ResourceManager.GetString("ValidationExceptionMessageNoComponents", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на В продаже должен быть хотя бы один товар.
/// </summary>
internal static string ValidationExceptionMessageNoProductsInSale {
get {
return ResourceManager.GetString("ValidationExceptionMessageNoProductsInSale", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Значение в поле {0} не является типом уникального идентификатора.
/// </summary>
internal static string ValidationExceptionMessageNotAId {
get {
return ResourceManager.GetString("ValidationExceptionMessageNotAId", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Значение в поле {0} не проинициализировано.
/// </summary>
internal static string ValidationExceptionMessageNotInitialized {
get {
return ResourceManager.GetString("ValidationExceptionMessageNotInitialized", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,243 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AdapterMessageElementDeletedException" xml:space="preserve">
<value>The item according to the data: {0} has been deleted</value>
</data>
<data name="AdapterMessageElementNotFoundException" xml:space="preserve">
<value>Not found element by data: {0}</value>
</data>
<data name="AdapterMessageEmptyDate" xml:space="preserve">
<value>Data is empty</value>
</data>
<data name="AdapterMessageIncorrectDatesException" xml:space="preserve">
<value>Incorrect dates: {0}</value>
</data>
<data name="AdapterMessageInvalidOperationException" xml:space="preserve">
<value>Error processing data: {0}</value>
</data>
<data name="AdapterMessageStorageException" xml:space="preserve">
<value>Error while working with data storage: {0}</value>
</data>
<data name="AdapterMessageValidationException" xml:space="preserve">
<value>Incorrect data transmitted: {0}</value>
</data>
<data name="DocumentDocCaptionData" xml:space="preserve">
<value>Date</value>
</data>
<data name="DocumentDocCaptionPreviousNames" xml:space="preserve">
<value>Previous names</value>
</data>
<data name="DocumentDocCaptionTour" xml:space="preserve">
<value>Tour</value>
</data>
<data name="DocumentDocHeader" xml:space="preserve">
<value>The history of tour changes</value>
</data>
<data name="DocumentDocSubHeader" xml:space="preserve">
<value>Make In Date {0}</value>
</data>
<data name="DocumentExcelCaptionCount" xml:space="preserve">
<value>Count</value>
</data>
<data name="DocumentExcelCaptionDate" xml:space="preserve">
<value>Date</value>
</data>
<data name="DocumentExcelCaptionDiscount" xml:space="preserve">
<value>Discount</value>
</data>
<data name="DocumentExcelCaptionSum" xml:space="preserve">
<value>Sum</value>
</data>
<data name="DocumentExcelCaptionTotal" xml:space="preserve">
<value>Total</value>
</data>
<data name="DocumentExcelCaptionTour" xml:space="preserve">
<value>Tour</value>
</data>
<data name="DocumentExcelHeader" xml:space="preserve">
<value>Sales for the period</value>
</data>
<data name="DocumentExcelHeaderEmployee" xml:space="preserve">
<value>Employee</value>
</data>
<data name="DocumentExcelSubHeader" xml:space="preserve">
<value>from {0} to {1}</value>
</data>
<data name="DocumentPdfDiagramCaption" xml:space="preserve">
<value>Accruals</value>
</data>
<data name="DocumentPdfHeader" xml:space="preserve">
<value>Payroll</value>
</data>
<data name="DocumentPdfSubHeader" xml:space="preserve">
<value>for the period from {0} to {1}</value>
</data>
<data name="ElementDeletedExceptionMessage" xml:space="preserve">
<value>Cannot modify a deleted item (id: {0})</value>
</data>
<data name="ElementExistsExceptionMessage" xml:space="preserve">
<value>There is already an element with value {0} of parameter {1}</value>
</data>
<data name="ElementNotFoundExceptionMessage" xml:space="preserve">
<value>Element not found at value = {0}</value>
</data>
<data name="IncorrectDatesExceptionMessage" xml:space="preserve">
<value>The end date must be later than the start date.. StartDate: {0}. EndDate: {1}</value>
</data>
<data name="NotEnoughDataToProcessExceptionMessage" xml:space="preserve">
<value>Not enough data to process: {0}</value>
</data>
<data name="NotFoundDataMessage" xml:space="preserve">
<value>No data found</value>
</data>
<data name="StorageExceptionMessage" xml:space="preserve">
<value>Error while working in storage: {0}</value>
</data>
<data name="ValidationExceptionMessageEmploymentDateAndBirthDate" xml:space="preserve">
<value>Date of employment cannot be earlier than date of birth ({0}, {1})</value>
</data>
<data name="ValidationExceptionMessageEmptyField" xml:space="preserve">
<value>The value in field {0} is empty</value>
</data>
<data name="ValidationExceptionMessageIncorrectFIO" xml:space="preserve">
<value>Fio is not correct</value>
</data>
<data name="ValidationExceptionMessageIncorrectPhoneNumber" xml:space="preserve">
<value>The value in the Phone Number field is not a phone number.</value>
</data>
<data name="ValidationExceptionMessageLessOrEqualZero" xml:space="preserve">
<value>The value in field {0} is less than or equal to 0</value>
</data>
<data name="ValidationExceptionMessageMinorsBirthDate" xml:space="preserve">
<value>Minors cannot be hired (BirthDate = {0})</value>
</data>
<data name="ValidationExceptionMessageMinorsEmploymentDate" xml:space="preserve">
<value>Minors cannot be hired (EmploymentDate: {0}, BirthDate {1})</value>
</data>
<data name="ValidationExceptionMessageNoProductsInSale" xml:space="preserve">
<value>There must be at least one product on sale.</value>
</data>
<data name="ValidationExceptionMessageNotAId" xml:space="preserve">
<value>The value in the {0} field is not a unique identifier type.</value>
</data>
<data name="ValidationExceptionMessageNotInitialized" xml:space="preserve">
<value>The value in field {0} is not initialized</value>
</data>
</root>

View File

@@ -0,0 +1,243 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AdapterMessageElementDeletedException" xml:space="preserve">
<value>Элемент по данным: {0} был удален</value>
</data>
<data name="AdapterMessageElementNotFoundException" xml:space="preserve">
<value>Не найден элемент по данным: {0}</value>
</data>
<data name="AdapterMessageEmptyDate" xml:space="preserve">
<value>Данные пусты</value>
</data>
<data name="AdapterMessageIncorrectDatesException" xml:space="preserve">
<value>Неправильные даты: {0}</value>
</data>
<data name="AdapterMessageInvalidOperationException" xml:space="preserve">
<value>Ошибка при обработке данных: {0}</value>
</data>
<data name="AdapterMessageStorageException" xml:space="preserve">
<value>Ошибка при работе с хранилищем данных: {0}</value>
</data>
<data name="AdapterMessageValidationException" xml:space="preserve">
<value>Переданы неверные данные: {0}</value>
</data>
<data name="DocumentDocCaptionData" xml:space="preserve">
<value>Дата</value>
</data>
<data name="DocumentDocCaptionPreviousNames" xml:space="preserve">
<value>Предыдущие названия</value>
</data>
<data name="DocumentDocCaptionTour" xml:space="preserve">
<value>Тур</value>
</data>
<data name="DocumentDocHeader" xml:space="preserve">
<value>История изменения коктелей</value>
</data>
<data name="DocumentDocSubHeader" xml:space="preserve">
<value>Сформировано на дату {0}</value>
</data>
<data name="DocumentExcelCaptionCount" xml:space="preserve">
<value>Кол-во</value>
</data>
<data name="DocumentExcelCaptionDate" xml:space="preserve">
<value>Дата</value>
</data>
<data name="DocumentExcelCaptionDiscount" xml:space="preserve">
<value>Скидка</value>
</data>
<data name="DocumentExcelCaptionSum" xml:space="preserve">
<value>Сумма</value>
</data>
<data name="DocumentExcelCaptionTotal" xml:space="preserve">
<value>Всего</value>
</data>
<data name="DocumentExcelCaptionTour" xml:space="preserve">
<value>Товар</value>
</data>
<data name="DocumentExcelHeader" xml:space="preserve">
<value>Продажи за период</value>
</data>
<data name="DocumentExcelHeaderEmployee" xml:space="preserve">
<value>Работник</value>
</data>
<data name="DocumentExcelSubHeader" xml:space="preserve">
<value>c {0} по {1}</value>
</data>
<data name="DocumentPdfDiagramCaption" xml:space="preserve">
<value>Начисления</value>
</data>
<data name="DocumentPdfHeader" xml:space="preserve">
<value>Зарплатная ведомость</value>
</data>
<data name="DocumentPdfSubHeader" xml:space="preserve">
<value>за период с {0} по {1}</value>
</data>
<data name="ElementDeletedExceptionMessage" xml:space="preserve">
<value>Нельзя изменить удаленный элемент (идентификатор: {0})</value>
</data>
<data name="ElementExistsExceptionMessage" xml:space="preserve">
<value>Уже существует элемент со значением {0} параметра {1}</value>
</data>
<data name="ElementNotFoundExceptionMessage" xml:space="preserve">
<value>Элемент не найден по значению = {0}</value>
</data>
<data name="IncorrectDatesExceptionMessage" xml:space="preserve">
<value>Дата окончания должна быть позже даты начала. Дата начала: {0}. ​​Дата окончания: {1}</value>
</data>
<data name="NotEnoughDataToProcessExceptionMessage" xml:space="preserve">
<value>Недостаточно данных для обработки: {0}</value>
</data>
<data name="NotFoundDataMessage" xml:space="preserve">
<value>Не найдены данные</value>
</data>
<data name="StorageExceptionMessage" xml:space="preserve">
<value>Ошибка при работе в хранилище: {0}</value>
</data>
<data name="ValidationExceptionMessageEmploymentDateAndBirthDate" xml:space="preserve">
<value>Дата трудоустройства не может быть раньше даты рождения ({0}, {1})</value>
</data>
<data name="ValidationExceptionMessageEmptyField" xml:space="preserve">
<value>Значение в поле {0} пусто</value>
</data>
<data name="ValidationExceptionMessageIncorrectFIO" xml:space="preserve">
<value>Некорректный формат ФИО</value>
</data>
<data name="ValidationExceptionMessageIncorrectPhoneNumber" xml:space="preserve">
<value>Значение в поле Телефонный номер не является телефонным номером</value>
</data>
<data name="ValidationExceptionMessageLessOrEqualZero" xml:space="preserve">
<value>Значение в поле {0} меньше или равно 0</value>
</data>
<data name="ValidationExceptionMessageMinorsBirthDate" xml:space="preserve">
<value>Несовершеннолетние не могут быть приняты на работу (Дата рождения: {0})</value>
</data>
<data name="ValidationExceptionMessageMinorsEmploymentDate" xml:space="preserve">
<value>Несовершеннолетние не могут быть приняты на работу (Дата трудоустройства: {0}, Дата рождения: {1})</value>
</data>
<data name="ValidationExceptionMessageNoProductsInSale" xml:space="preserve">
<value>В продаже должен быть хотя бы один товар</value>
</data>
<data name="ValidationExceptionMessageNotAId" xml:space="preserve">
<value>Значение в поле {0} не является типом уникального идентификатора</value>
</data>
<data name="ValidationExceptionMessageNotInitialized" xml:space="preserve">
<value>Значение в поле {0} не проинициализировано</value>
</data>
</root>

View File

@@ -0,0 +1,243 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AdapterMessageElementDeletedException" xml:space="preserve">
<value>根据数据的项目:{0}已被删除</value>
</data>
<data name="AdapterMessageElementNotFoundException" xml:space="preserve">
<value>未找到元素数据: {0}</value>
</data>
<data name="AdapterMessageEmptyDate" xml:space="preserve">
<value>数据为空</value>
</data>
<data name="AdapterMessageIncorrectDatesException" xml:space="preserve">
<value>不正确的日期:{0}</value>
</data>
<data name="AdapterMessageInvalidOperationException" xml:space="preserve">
<value>数据处理过程中的错误:{0}</value>
</data>
<data name="AdapterMessageStorageException" xml:space="preserve">
<value>使用数据仓库时出错:{0}</value>
</data>
<data name="AdapterMessageValidationException" xml:space="preserve">
<value>传递的数据不正确: {0}</value>
</data>
<data name="DocumentDocCaptionData" xml:space="preserve">
<value>日期</value>
</data>
<data name="DocumentDocCaptionPreviousNames" xml:space="preserve">
<value>以前的名字</value>
</data>
<data name="DocumentDocCaptionTour" xml:space="preserve">
<value>旅游</value>
</data>
<data name="DocumentDocHeader" xml:space="preserve">
<value>鸡尾酒变化的历史</value>
</data>
<data name="DocumentDocSubHeader" xml:space="preserve">
<value>在日期{0}生成</value>
</data>
<data name="DocumentExcelCaptionCount" xml:space="preserve">
<value>数量</value>
</data>
<data name="DocumentExcelCaptionDate" xml:space="preserve">
<value>日期</value>
</data>
<data name="DocumentExcelCaptionDiscount" xml:space="preserve">
<value>折扣优惠</value>
</data>
<data name="DocumentExcelCaptionSum" xml:space="preserve">
<value>金额</value>
</data>
<data name="DocumentExcelCaptionTotal" xml:space="preserve">
<value>总计</value>
</data>
<data name="DocumentExcelCaptionTour" xml:space="preserve">
<value>旅游</value>
</data>
<data name="DocumentExcelHeader" xml:space="preserve">
<value>期间的销售额</value>
</data>
<data name="DocumentExcelHeaderEmployee" xml:space="preserve">
<value>工人</value>
</data>
<data name="DocumentExcelSubHeader" xml:space="preserve">
<value>从{0}到{1}</value>
</data>
<data name="DocumentPdfDiagramCaption" xml:space="preserve">
<value>应计事项</value>
</data>
<data name="DocumentPdfHeader" xml:space="preserve">
<value>薪金表</value>
</data>
<data name="DocumentPdfSubHeader" xml:space="preserve">
<value>从{0}到{1}的期间</value>
</data>
<data name="ElementDeletedExceptionMessage" xml:space="preserve">
<value>无法更改已删除的项目(id:{0})</value>
</data>
<data name="ElementExistsExceptionMessage" xml:space="preserve">
<value>已经有一个具有参数{1}的值{0}的元素</value>
</data>
<data name="ElementNotFoundExceptionMessage" xml:space="preserve">
<value>值={0}未找到该元素</value>
</data>
<data name="IncorrectDatesExceptionMessage" xml:space="preserve">
<value>结束日期必须晚于开始日期。 开始日期:{0}。 ​​结束日期:{1}</value>
</data>
<data name="NotEnoughDataToProcessExceptionMessage" xml:space="preserve">
<value>处理数据不足:{0}</value>
</data>
<data name="NotFoundDataMessage" xml:space="preserve">
<value>未找到数据</value>
</data>
<data name="StorageExceptionMessage" xml:space="preserve">
<value>在存储中工作时出错:{0}</value>
</data>
<data name="ValidationExceptionMessageEmploymentDateAndBirthDate" xml:space="preserve">
<value>就业日期不能早于出生日期({0},{1})</value>
</data>
<data name="ValidationExceptionMessageEmptyField" xml:space="preserve">
<value>字段 {0} 的值为空</value>
</data>
<data name="ValidationExceptionMessageIncorrectFIO" xml:space="preserve">
<value>名称格式不正确</value>
</data>
<data name="ValidationExceptionMessageIncorrectPhoneNumber" xml:space="preserve">
<value>电话号码字段中的值不是电话号码</value>
</data>
<data name="ValidationExceptionMessageLessOrEqualZero" xml:space="preserve">
<value>{0}字段中的值小于或等于0</value>
</data>
<data name="ValidationExceptionMessageMinorsBirthDate" xml:space="preserve">
<value>未成年人不能就业(出生日期:{0})</value>
</data>
<data name="ValidationExceptionMessageMinorsEmploymentDate" xml:space="preserve">
<value>未成年人不能就业(就业日期:{0},出生日期:{1})</value>
</data>
<data name="ValidationExceptionMessageNoProductsInSale" xml:space="preserve">
<value>必须至少有一种产品在售。</value>
</data>
<data name="ValidationExceptionMessageNotAId" xml:space="preserve">
<value>字段 {0} 的值不是唯一标识符类型</value>
</data>
<data name="ValidationExceptionMessageNotInitialized" xml:space="preserve">
<value>{0}字段中的值未初始化</value>
</data>
</root>

View File

@@ -1,18 +0,0 @@
using MagicCarpetContracts.DataModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.StoragesContracts;
public interface IAgencyStorageContract
{
List<AgencyDataModel> GetList();
AgencyDataModel GetElementById(string id);
void AddElement(AgencyDataModel agencyDataModel);
void UpdElement(AgencyDataModel agencyDataModel);
void DelElement(string id);
bool CheckComponents(SaleDataModel saleDataModel);
}

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.StoragesContracts;
public interface IClientStorageContract
internal interface IClientStorageContract
{
List<ClientDataModel> GetList();

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.StoragesContracts;
public interface IEmployeeStorageContract
internal interface IEmployeeStorageContract
{
List<EmployeeDataModel> GetList(bool onlyActive = true, string? postId = null, DateTime? fromBirthDate = null,
DateTime? toBirthDate = null, DateTime? fromEmploymentDate = null, DateTime? toEmploymentDate = null);
@@ -23,4 +23,6 @@ public interface IEmployeeStorageContract
void UpdElement(EmployeeDataModel employeeDataModel);
void DelElement(string id);
int GetEmployeeTrend(DateTime fromPeriod, DateTime toPeriod);
}

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.StoragesContracts;
public interface IPostStorageContract
internal interface IPostStorageContract
{
List<PostDataModel> GetList();
List<PostDataModel> GetPostWithHistory(string postId);

View File

@@ -7,9 +7,11 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.StoragesContracts;
public interface ISalaryStorageContract
internal interface ISalaryStorageContract
{
List<SalaryDataModel> GetList(DateTime? startDate, DateTime? endDate, string? employeeId = null);
Task<List<SalaryDataModel>> GetListAsync(DateTime startDate, DateTime endDate, CancellationToken ct);
void AddElement(SalaryDataModel salaryDataModel);
}

View File

@@ -7,11 +7,13 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.StoragesContracts;
public interface ISaleStorageContract
internal interface ISaleStorageContract
{
List<SaleDataModel> GetList(DateTime? startDate = null, DateTime? endDate = null, string? employeeId = null,
string? clientId = null, string? tourId = null);
Task<List<SaleDataModel>> GetListAsync(DateTime startDate, DateTime endDate, CancellationToken ct);
SaleDataModel? GetElementById(string id);
void AddElement(SaleDataModel saleDataModel);

View File

@@ -1,16 +0,0 @@
using MagicCarpetContracts.DataModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.StoragesContracts;
public interface ISuppliesStorageContract
{
List<SuppliesDataModel> GetList(DateTime? startDate = null);
SuppliesDataModel GetElementById(string id);
void AddElement(SuppliesDataModel suppliesDataModel);
void UpdElement(SuppliesDataModel suppliesDataModel);
}

View File

@@ -7,10 +7,11 @@ using System.Threading.Tasks;
namespace MagicCarpetContracts.StoragesContracts;
public interface ITourStorageContract
internal interface ITourStorageContract
{
List<TourDataModel> GetList();
List<TourHistoryDataModel> GetHistoryByTourId(string tourId);
Task<List<TourHistoryDataModel>> GetHistoriesListAsync(CancellationToken ct);
TourDataModel? GetElementById(string id);
TourDataModel? GetElementByName(string name);
void AddElement(TourDataModel tourDataModel);

View File

@@ -1,16 +0,0 @@
using MagicCarpetContracts.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.ViewModels;
public class AgencyViewModel
{
public required string Id { get; set; }
public required TourType TourType { get; set; }
public required int Count { get; set; }
public required List<TourAgencyViewModel> Tours { get; set; }
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.ViewModels;
public class EmployeeSalaryByPeriodViewModel
{
public required string EmployeeFIO { get; set; }
public double TotalSalary { get; set; }
public DateTime FromPeriod { get; set; }
public DateTime ToPeriod { get; set; }
}

View File

@@ -1,4 +1,5 @@
using System;
using MagicCarpetContracts.Mapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -8,6 +9,7 @@ namespace MagicCarpetContracts.ViewModels;
public class EmployeeViewModel
{
[AlternativeName("EmployeeId")]
public required string Id { get; set; }
public required string FIO { get; set; }
@@ -20,7 +22,9 @@ public class EmployeeViewModel
public bool IsDeleted { get; set; }
[PostProcessing(ActionType = PostProcessingType.ToLocalTime)]
public DateTime BirthDate { get; set; }
[PostProcessing(ActionType = PostProcessingType.ToLocalTime)]
public DateTime EmploymentDate { get; set; }
}

View File

@@ -1,18 +1,32 @@
using System;
using MagicCarpetContracts.Infrastructure.PostConfigurations;
using MagicCarpetContracts.Mapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace MagicCarpetContracts.ViewModels;
public class PostViewModel
{
[AlternativeName("PostId")]
public required string Id { get; set; }
public required string PostName { get; set; }
public required string PostType { get; set; }
public double Salary { get; set; }
[AlternativeName("ConfigurationModel")]
[PostProcessing(MappingCallMethodName = "ParseConfiguration")]
public required string Configuration { get; set; }
private string ParseConfiguration(PostConfiguration? model)
{
if (model == null)
return string.Empty;
return JsonSerializer.Serialize(model, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
}

View File

@@ -1,4 +1,5 @@
using System;
using MagicCarpetContracts.Mapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -11,5 +12,7 @@ public class SalaryViewModel
public required string EmployeeId { get; set; }
public required string EmployeeFIO { get; set; }
public DateTime SalaryDate { get; set; }
[AlternativeName("EmployeeSalary")]
public double Salary { get; set; }
}

View File

@@ -1,4 +1,5 @@
using System;
using MagicCarpetContracts.Mapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -18,6 +19,7 @@ public class SaleViewModel
public string? ClientFIO { get; set; }
[PostProcessing(ActionType = PostProcessingType.ToLocalTime)]
public DateTime SaleDate { get; set; }
public double Sum { get; set; }

View File

@@ -1,17 +0,0 @@
using MagicCarpetContracts.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.ViewModels;
public class SuppliesViewModel
{
public required string Id { get; set; }
public required TourType TourType { get; set; }
public DateTime ProductuionDate { get; set; }
public int Count { get; set; }
public required List<TourSuppliesViewModel> Tours { get; set; }
}

View File

@@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.ViewModels;
public class TourAgencyViewModel
{
public required string AgencyId { get; set; }
public required string TourId { get; set; }
public int Count { get; set; }
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.ViewModels;
public class TourAndTourHistoryViewModel
{
public required string TourName { get; set; }
public required List<string> Histories { get; set; }
public required List<string> Data { get; set; }
}

View File

@@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetContracts.ViewModels;
public class TourSuppliesViewModel
{
public required string SuppliesId { get; set; }
public required string TourId { get; set; }
public int Count { get; set; }
}

View File

@@ -0,0 +1,8 @@
using MagicCarpetContracts.Infrastructure;
namespace MagicCarpetDatabase;
class DefaultConfigurationDatabase : IConfigurationDatabase
{
public string ConnectionString => "";
}

View File

@@ -1,140 +0,0 @@
using AutoMapper;
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.StoragesContracts;
using MagicCarpetDatabase.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetDatabase.Implementations;
public class AgencyStorageContract : IAgencyStorageContract
{
private readonly MagicCarpetDbContext _dbContext;
private readonly Mapper _mapper;
public AgencyStorageContract(MagicCarpetDbContext dbContext)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.AddMaps(typeof(TourAgency));
cfg.AddMaps(typeof(Agency));
});
_mapper = new Mapper(config);
}
public List<AgencyDataModel> GetList()
{
try
{
return [.. _dbContext.Agencies.Select(x => _mapper.Map<AgencyDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public AgencyDataModel GetElementById(string id)
{
try
{
return _mapper.Map<AgencyDataModel>(GetAgencyById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public void AddElement(AgencyDataModel agencyDataModel)
{
try
{
_dbContext.Agencies.Add(_mapper.Map<Agency>(agencyDataModel));
_dbContext.SaveChanges();
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public void UpdElement(AgencyDataModel agencyDataModel)
{
try
{
var element = GetAgencyById(agencyDataModel.Id) ?? throw new ElementNotFoundException(agencyDataModel.Id);
_dbContext.Agencies.Update(_mapper.Map(agencyDataModel, element));
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public void DelElement(string id)
{
try
{
var element = GetAgencyById(id) ?? throw new ElementNotFoundException(id);
_dbContext.Agencies.Remove(element);
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public bool CheckComponents(SaleDataModel saleDataModel)
{
using (var transaction = _dbContext.Database.BeginTransaction())
{
foreach (SaleTourDataModel sale_tour in saleDataModel.Tours)
{
var tour = _dbContext.Tours.FirstOrDefault(x => x.Id == sale_tour.TourId);
var agency = _dbContext.Agencies.FirstOrDefault(x => x.TourType == tour.TourType && x.Count >= sale_tour.Count);
if (agency == null)
{
transaction.Rollback();
return false;
}
if (agency.Count - sale_tour.Count == 0)
{
DelElement(agency.Id);
}
else
{
agency.Count -= sale_tour.Count;
}
}
transaction.Commit();
_dbContext.SaveChanges();
return true;
}
}
private Agency? GetAgencyById(string id) => _dbContext.Agencies.FirstOrDefault(x => x.Id == id);
}

View File

@@ -1,9 +1,12 @@
using AutoMapper;
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Mapper;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using MagicCarpetDatabase.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Npgsql;
using System;
using System.Collections.Generic;
@@ -13,96 +16,88 @@ using System.Threading.Tasks;
namespace MagicCarpetDatabase.Implementations;
public class ClientStorageContract : IClientStorageContract
internal class ClientStorageContract(MagicCarpetDbContext magicCarpetDbContext, IStringLocalizer<Messages> localizer) : IClientStorageContract
{
private readonly MagicCarpetDbContext _dbContext;
private readonly Mapper _mapper;
public ClientStorageContract(MagicCarpetDbContext magicCarpetDbContext)
{
_dbContext = magicCarpetDbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.AddMaps(typeof(MagicCarpetDbContext).Assembly);
});
_mapper = new Mapper(config);
}
private readonly MagicCarpetDbContext _dbContext = magicCarpetDbContext;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<ClientDataModel> GetList()
{
try
{
return [.. _dbContext.Clients.Select(x => _mapper.Map<ClientDataModel>(x))];
return [.. _dbContext.Clients.Select(x => CustomMapper.MapObject<ClientDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
public ClientDataModel? GetElementById(string id)
{
try
{
return _mapper.Map<ClientDataModel>(GetClientById(id));
return CustomMapper.MapObjectWithNull<ClientDataModel>(GetClientById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
public ClientDataModel? GetElementByFIO(string fio)
{
try
{
return _mapper.Map<ClientDataModel>(_dbContext.Clients.FirstOrDefault(x => x.FIO == fio));
return CustomMapper.MapObjectWithNull<ClientDataModel>(_dbContext.Clients.FirstOrDefault(x => x.FIO == fio));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
public ClientDataModel? GetElementByPhoneNumber(string phoneNumber)
{
try
{
return _mapper.Map<ClientDataModel>(_dbContext.Clients.FirstOrDefault(x => x.PhoneNumber == phoneNumber));
return CustomMapper.MapObjectWithNull<ClientDataModel>(_dbContext.Clients.FirstOrDefault(x => x.PhoneNumber == phoneNumber));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
public void AddElement(ClientDataModel clientDataModel)
{
try
{
_dbContext.Clients.Add(_mapper.Map<Client>(clientDataModel));
_dbContext.Clients.Add(CustomMapper.MapObject<Client>(clientDataModel));
_dbContext.SaveChanges();
}
catch (InvalidOperationException ex) when (ex.TargetSite?.Name == "ThrowIdentityConflict")
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", clientDataModel.Id);
throw new ElementExistsException("Id", clientDataModel.Id, _localizer);
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Clients_PhoneNumber" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("PhoneNumber", clientDataModel.PhoneNumber);
throw new ElementExistsException("PhoneNumber", clientDataModel.PhoneNumber, _localizer);
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
public void UpdElement(ClientDataModel clientDataModel)
{
try
{
var element = GetClientById(clientDataModel.Id) ?? throw new ElementNotFoundException(clientDataModel.Id);
_dbContext.Clients.Update(_mapper.Map(clientDataModel, element));
var element = GetClientById(clientDataModel.Id) ?? throw new ElementNotFoundException(clientDataModel.Id, _localizer);
_dbContext.Clients.Update(CustomMapper.MapObject(clientDataModel, element));
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
@@ -113,19 +108,19 @@ public class ClientStorageContract : IClientStorageContract
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Clients_PhoneNumber" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("PhoneNumber", clientDataModel.PhoneNumber);
throw new ElementExistsException("PhoneNumber", clientDataModel.PhoneNumber, _localizer);
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
public void DelElement(string id)
{
try
{
var element = GetClientById(id) ?? throw new ElementNotFoundException(id);
var element = GetClientById(id) ?? throw new ElementNotFoundException(id, _localizer);
_dbContext.Clients.Remove(element);
_dbContext.SaveChanges();
}
@@ -137,7 +132,7 @@ public class ClientStorageContract : IClientStorageContract
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
private Client? GetClientById(string id) => _dbContext.Clients.FirstOrDefault(x => x.Id == id);

View File

@@ -1,8 +1,13 @@
using AutoMapper;
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Mapper;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using MagicCarpetDatabase.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,23 +16,10 @@ using System.Threading.Tasks;
namespace MagicCarpetDatabase.Implementations;
public class EmployeeStorageContract : IEmployeeStorageContract
internal class EmployeeStorageContract(MagicCarpetDbContext dbContext, IStringLocalizer<Messages> localizer) : IEmployeeStorageContract
{
private readonly MagicCarpetDbContext _dbContext;
private readonly Mapper _mapper;
public EmployeeStorageContract(MagicCarpetDbContext dbContext)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Post, PostDataModel>()
.ForMember(x => x.Id, x => x.MapFrom(src => src.PostId));
cfg.CreateMap<Employee, EmployeeDataModel>();
cfg.CreateMap<EmployeeDataModel, Employee>();
});
_mapper = new Mapper(config);
}
private readonly MagicCarpetDbContext _dbContext = dbContext;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<EmployeeDataModel> GetList(bool onlyActive = true, string? postId = null, DateTime? fromBirthDate = null, DateTime? toBirthDate = null, DateTime? fromEmploymentDate = null, DateTime? toEmploymentDate = null)
{
@@ -50,12 +42,12 @@ public class EmployeeStorageContract : IEmployeeStorageContract
{
query = query.Where(x => x.EmploymentDate >= DateTime.SpecifyKind(fromEmploymentDate ?? DateTime.UtcNow, DateTimeKind.Utc) && x.EmploymentDate <= DateTime.SpecifyKind(toEmploymentDate ?? DateTime.UtcNow, DateTimeKind.Utc));
}
return [.. JoinPost(query).Select(x => _mapper.Map<EmployeeDataModel>(x))];
return [.. JoinPost(query).Select(x => CustomMapper.MapObject<EmployeeDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -63,12 +55,12 @@ public class EmployeeStorageContract : IEmployeeStorageContract
{
try
{
return _mapper.Map<EmployeeDataModel>(GetEmployeeById(id));
return CustomMapper.MapObjectWithNull<EmployeeDataModel>(GetEmployeeById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -76,12 +68,12 @@ public class EmployeeStorageContract : IEmployeeStorageContract
{
try
{
return _mapper.Map<EmployeeDataModel>(AddPost(_dbContext.Employees.FirstOrDefault(x => x.FIO == fio && !x.IsDeleted)));
return CustomMapper.MapObjectWithNull<EmployeeDataModel>(AddPost(_dbContext.Employees.FirstOrDefault(x => x.FIO == fio && !x.IsDeleted)));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -89,12 +81,12 @@ public class EmployeeStorageContract : IEmployeeStorageContract
{
try
{
return _mapper.Map<EmployeeDataModel>(AddPost(_dbContext.Employees.FirstOrDefault(x => x.Email == email && !x.IsDeleted)));
return CustomMapper.MapObjectWithNull<EmployeeDataModel>(AddPost(_dbContext.Employees.FirstOrDefault(x => x.Email == email && !x.IsDeleted)));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -102,18 +94,23 @@ public class EmployeeStorageContract : IEmployeeStorageContract
{
try
{
_dbContext.Employees.Add(_mapper.Map<Employee>(employeeDataModel));
_dbContext.Employees.Add(CustomMapper.MapObject<Employee>(employeeDataModel));
_dbContext.SaveChanges();
}
catch (InvalidOperationException ex) when (ex.TargetSite?.Name == "ThrowIdentityConflict")
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", employeeDataModel.Id);
throw new ElementExistsException("Id", employeeDataModel.Id, _localizer);
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "PK_Employees" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", employeeDataModel.Id, _localizer);
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -121,8 +118,8 @@ public class EmployeeStorageContract : IEmployeeStorageContract
{
try
{
var element = GetEmployeeById(employeeDataModel.Id) ?? throw new ElementNotFoundException(employeeDataModel.Id);
_dbContext.Employees.Update(_mapper.Map(employeeDataModel, element));
var element = GetEmployeeById(employeeDataModel.Id) ?? throw new ElementNotFoundException(employeeDataModel.Id, _localizer);
_dbContext.Employees.Update(CustomMapper.MapObject(employeeDataModel, element));
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
@@ -133,7 +130,7 @@ public class EmployeeStorageContract : IEmployeeStorageContract
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -141,7 +138,7 @@ public class EmployeeStorageContract : IEmployeeStorageContract
{
try
{
var element = GetEmployeeById(id) ?? throw new ElementNotFoundException(id);
var element = GetEmployeeById(id) ?? throw new ElementNotFoundException(id, _localizer);
element.IsDeleted = true;
_dbContext.SaveChanges();
}
@@ -153,7 +150,22 @@ public class EmployeeStorageContract : IEmployeeStorageContract
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
public int GetEmployeeTrend(DateTime fromPeriod, DateTime toPeriod)
{
try
{
var countWorkersOnBegining = _dbContext.Employees.Count(x => x.EmploymentDate < fromPeriod && (!x.IsDeleted || x.DateOfDelete > fromPeriod));
var countWorkersOnEnding = _dbContext.Employees.Count(x => x.EmploymentDate < toPeriod && (!x.IsDeleted || x.DateOfDelete > toPeriod));
return countWorkersOnEnding - countWorkersOnBegining;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
@@ -164,5 +176,5 @@ public class EmployeeStorageContract : IEmployeeStorageContract
.SelectMany(xy => xy.Post.DefaultIfEmpty(), (x, y) => x.Employee.AddPost(y));
private Employee? AddPost(Employee? employee)
=> employee?.AddPost(_dbContext.Posts.FirstOrDefault(x => x.PostId == employee.PostId && x.IsActual));
=> employee == null ? null : employee.AddPost(_dbContext.Posts.FirstOrDefault(x => x.PostId == employee.PostId && x.IsActual));
}

View File

@@ -1,9 +1,12 @@
using AutoMapper;
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Mapper;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using MagicCarpetDatabase.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Npgsql;
using System;
using System.Collections.Generic;
@@ -13,37 +16,21 @@ using System.Threading.Tasks;
namespace MagicCarpetDatabase.Implementations;
public class PostStorageContract : IPostStorageContract
internal class PostStorageContract(MagicCarpetDbContext dbContext, IStringLocalizer<Messages> localizer) : IPostStorageContract
{
private readonly MagicCarpetDbContext _dbContext;
private readonly Mapper _mapper;
public PostStorageContract(MagicCarpetDbContext dbContext)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Post, PostDataModel>()
.ForMember(x => x.Id, x => x.MapFrom(src => src.PostId));
cfg.CreateMap<PostDataModel, Post>()
.ForMember(x => x.Id, x => x.Ignore())
.ForMember(x => x.PostId, x => x.MapFrom(src => src.Id))
.ForMember(x => x.IsActual, x => x.MapFrom(src => true))
.ForMember(x => x.ChangeDate, x => x.MapFrom(src => DateTime.UtcNow));
});
_mapper = new Mapper(config);
}
private readonly MagicCarpetDbContext _dbContext = dbContext;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<PostDataModel> GetList()
{
try
{
return [.. _dbContext.Posts.Select(x => _mapper.Map<PostDataModel>(x))];
return [.. _dbContext.Posts.Select(x => CustomMapper.MapObject<PostDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -51,12 +38,12 @@ public class PostStorageContract : IPostStorageContract
{
try
{
return [.. _dbContext.Posts.Where(x => x.PostId == postId).Select(x => _mapper.Map<PostDataModel>(x))];
return [.. _dbContext.Posts.Where(x => x.PostId == postId).Select(x => CustomMapper.MapObject<PostDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -64,12 +51,12 @@ public class PostStorageContract : IPostStorageContract
{
try
{
return _mapper.Map<PostDataModel>(_dbContext.Posts.FirstOrDefault(x => x.PostId == id && x.IsActual));
return CustomMapper.MapObjectWithNull<PostDataModel>(_dbContext.Posts.FirstOrDefault(x => x.PostId == id && x.IsActual));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -77,12 +64,12 @@ public class PostStorageContract : IPostStorageContract
{
try
{
return _mapper.Map<PostDataModel>(_dbContext.Posts.FirstOrDefault(x => x.PostName == name && x.IsActual));
return CustomMapper.MapObjectWithNull<PostDataModel>(_dbContext.Posts.FirstOrDefault(x => x.PostName == name && x.IsActual));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -90,23 +77,27 @@ public class PostStorageContract : IPostStorageContract
{
try
{
_dbContext.Posts.Add(_mapper.Map<Post>(postDataModel));
var post = MapToEntity(postDataModel);
post.IsActual = true;
post.ChangeDate = DateTime.UtcNow;
_dbContext.Posts.Add(post);
_dbContext.SaveChanges();
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Posts_PostName_IsActual" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("PostName", postDataModel.PostName);
throw new ElementExistsException("PostName", postDataModel.PostName, _localizer);
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Posts_PostId_IsActual" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("PostId", postDataModel.Id);
throw new ElementExistsException("PostId", postDataModel.Id, _localizer);
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -117,14 +108,18 @@ public class PostStorageContract : IPostStorageContract
var transaction = _dbContext.Database.BeginTransaction();
try
{
var element = GetPostById(postDataModel.Id) ?? throw new ElementNotFoundException(postDataModel.Id);
var element = GetPostById(postDataModel.Id) ?? throw new ElementNotFoundException(postDataModel.Id, _localizer);
if (!element.IsActual)
{
throw new ElementDeletedException(postDataModel.Id);
throw new ElementDeletedException(postDataModel.Id, _localizer);
}
element.IsActual = false;
_dbContext.SaveChanges();
var newElement = _mapper.Map<Post>(postDataModel);
var newElement = MapToEntity(postDataModel);
newElement.IsActual = true;
newElement.ChangeDate = DateTime.UtcNow;
_dbContext.Posts.Add(newElement);
_dbContext.SaveChanges();
transaction.Commit();
@@ -138,7 +133,7 @@ public class PostStorageContract : IPostStorageContract
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Posts_PostName_IsActual" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("PostName", postDataModel.PostName);
throw new ElementExistsException("PostName", postDataModel.PostName, _localizer);
}
catch (Exception ex) when (ex is ElementDeletedException || ex is ElementNotFoundException)
{
@@ -148,7 +143,7 @@ public class PostStorageContract : IPostStorageContract
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -156,10 +151,10 @@ public class PostStorageContract : IPostStorageContract
{
try
{
var element = GetPostById(id) ?? throw new ElementNotFoundException(id);
var element = GetPostById(id) ?? throw new ElementNotFoundException(id, _localizer);
if (!element.IsActual)
{
throw new ElementDeletedException(id);
throw new ElementDeletedException(id, _localizer);
}
element.IsActual = false;
_dbContext.SaveChanges();
@@ -175,7 +170,7 @@ public class PostStorageContract : IPostStorageContract
{
try
{
var element = GetPostById(id) ?? throw new ElementNotFoundException(id);
var element = GetPostById(id) ?? throw new ElementNotFoundException(id, _localizer);
element.IsActual = true;
_dbContext.SaveChanges();
}
@@ -186,6 +181,14 @@ public class PostStorageContract : IPostStorageContract
}
}
private Post MapToEntity(PostDataModel model)
{
var post = CustomMapper.MapObject<Post>(model);
post.PostId = model.Id;
post.Configuration = model.ConfigurationModel;
return post;
}
private Post? GetPostById(string id) => _dbContext.Posts.Where(x => x.PostId == id)
.OrderByDescending(x => x.ChangeDate).FirstOrDefault();
}

View File

@@ -1,9 +1,12 @@
using AutoMapper;
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Mapper;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using MagicCarpetDatabase.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -12,23 +15,10 @@ using System.Threading.Tasks;
namespace MagicCarpetDatabase.Implementations;
public class SalaryStorageContract : ISalaryStorageContract
internal class SalaryStorageContract(MagicCarpetDbContext dbContext, IStringLocalizer<Messages> localizer) : ISalaryStorageContract
{
private readonly MagicCarpetDbContext _dbContext;
private readonly Mapper _mapper;
public SalaryStorageContract(MagicCarpetDbContext dbContext)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Employee, EmployeeDataModel>();
cfg.CreateMap<Salary, SalaryDataModel>();
cfg.CreateMap<SalaryDataModel, Salary>()
.ForMember(dest => dest.EmployeeSalary, opt => opt.MapFrom(src => src.Salary));
});
_mapper = new Mapper(config);
}
private readonly MagicCarpetDbContext _dbContext = dbContext;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<SalaryDataModel> GetList(DateTime? startDate, DateTime? endDate, string? employeeId = null)
{
@@ -41,12 +31,28 @@ public class SalaryStorageContract : ISalaryStorageContract
query = query.Where(x => x.SalaryDate <= DateTime.SpecifyKind(endDate ?? DateTime.UtcNow, DateTimeKind.Utc));
if (employeeId != null)
query = query.Where(x => x.EmployeeId == employeeId);
return [.. query.Select(x => _mapper.Map<SalaryDataModel>(x))];
return [.. query.Select(x => CustomMapper.MapObject<SalaryDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
public async Task<List<SalaryDataModel>> GetListAsync(DateTime startDate, DateTime endDate, CancellationToken ct)
{
try
{
return [.. await _dbContext.Salaries.Include(x =>
x.Employee).Where(x => x.SalaryDate >= DateTime.SpecifyKind(startDate, DateTimeKind.Utc) &&
x.SalaryDate <= DateTime.SpecifyKind(endDate, DateTimeKind.Utc))
.Select(x => CustomMapper.MapObject < SalaryDataModel >(x)).ToListAsync(ct)];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
@@ -54,13 +60,22 @@ public class SalaryStorageContract : ISalaryStorageContract
{
try
{
_dbContext.Salaries.Add(_mapper.Map<Salary>(salaryDataModel));
var salary = MapToEntity(salaryDataModel);
_dbContext.Salaries.Add(salary);
_dbContext.SaveChanges();
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
private Salary MapToEntity(SalaryDataModel dataModel)
{
var salary = CustomMapper.MapObject<Salary>(dataModel);
salary.EmployeeSalary = dataModel.Salary;
return salary;
}
}

View File

@@ -1,9 +1,12 @@
using AutoMapper;
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.Mapper;
using MagicCarpetContracts.Resources;
using MagicCarpetContracts.StoragesContracts;
using MagicCarpetDatabase.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -12,31 +15,10 @@ using System.Threading.Tasks;
namespace MagicCarpetDatabase.Implementations;
public class SaleStorageContract : ISaleStorageContract
internal class SaleStorageContract(MagicCarpetDbContext dbContext, IStringLocalizer<Messages> localizer) : ISaleStorageContract
{
private readonly MagicCarpetDbContext _dbContext;
private readonly Mapper _mapper;
public SaleStorageContract(MagicCarpetDbContext dbContext)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Client, ClientDataModel>();
cfg.CreateMap<Tour, TourDataModel>();
cfg.CreateMap<Employee, EmployeeDataModel>();
cfg.CreateMap<SaleTour, SaleTourDataModel>();
cfg.CreateMap<SaleTourDataModel, SaleTour>()
.ForMember(x => x.Tour, x => x.Ignore());
cfg.CreateMap<Sale, SaleDataModel>();
cfg.CreateMap<SaleDataModel, Sale>()
.ForMember(x => x.IsCancel, x => x.MapFrom(src => false))
.ForMember(x => x.SaleTours, x => x.MapFrom(src => src.Tours))
.ForMember(x => x.Employee, x => x.Ignore())
.ForMember(x => x.Client, x => x.Ignore());
});
_mapper = new Mapper(config);
}
private readonly MagicCarpetDbContext _dbContext = dbContext;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<SaleDataModel> GetList(DateTime? startDate = null, DateTime? endDate = null, string? employeeId = null, string? clientId = null, string? tourId = null)
{
@@ -59,12 +41,33 @@ public class SaleStorageContract : ISaleStorageContract
if (tourId != null)
query = query.Where(x => x.SaleTours!.Any(y => y.TourId == tourId));
var s = query.ToList();
return [.. query.Select(x => _mapper.Map<SaleDataModel>(x))];
return [.. query.Select(x => CustomMapper.MapObject<SaleDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
public async Task<List<SaleDataModel>> GetListAsync(DateTime startDate, DateTime endDate, CancellationToken ct)
{
try
{
return [.. await _dbContext.Sales
.Include(x => x.Employee)
.Include(x => x.Client)
.Include(x => x.SaleTours)!
.ThenInclude(sc => sc.Tour)
.Where(x => x.SaleDate >= DateTime.SpecifyKind(startDate, DateTimeKind.Utc)
&& x.SaleDate < DateTime.SpecifyKind(endDate, DateTimeKind.Utc))
.Select(x => CustomMapper.MapObject < SaleDataModel >(x))
.ToListAsync(ct)];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
@@ -72,12 +75,12 @@ public class SaleStorageContract : ISaleStorageContract
{
try
{
return _mapper.Map<SaleDataModel>(GetSaleById(id));
return CustomMapper.MapObjectWithNull<SaleDataModel>(GetSaleById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -85,13 +88,14 @@ public class SaleStorageContract : ISaleStorageContract
{
try
{
_dbContext.Sales.Add(_mapper.Map<Sale>(saleDataModel));
var sale = MapToEntity(saleDataModel);
_dbContext.Sales.Add(sale);
_dbContext.SaveChanges();
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -99,10 +103,10 @@ public class SaleStorageContract : ISaleStorageContract
{
try
{
var element = GetSaleById(id) ?? throw new ElementNotFoundException(id);
var element = GetSaleById(id) ?? throw new ElementNotFoundException(id, _localizer);
if (element.IsCancel)
{
throw new ElementDeletedException(id);
throw new ElementDeletedException(id, _localizer);
}
element.IsCancel = true;
_dbContext.SaveChanges();
@@ -115,9 +119,27 @@ public class SaleStorageContract : ISaleStorageContract
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
private Sale MapToEntity(SaleDataModel dataModel)
{
var sale = CustomMapper.MapObject<Sale>(dataModel);
sale.IsCancel = false;
sale.SaleTours = dataModel.Tours?
.Select(p => new SaleTour
{
TourId = p.TourId,
Count = p.Count,
Price = p.Price,
SaleId = sale.Id
})
.ToList();
return sale;
}
private Sale? GetSaleById(string id) => _dbContext.Sales.Include(x => x.Client).Include(x => x.Employee).Include(x => x.SaleTours)!.ThenInclude(x => x.Tour).FirstOrDefault(x => x.Id == id);
}

View File

@@ -1,100 +0,0 @@
using AutoMapper;
using MagicCarpetContracts.DataModels;
using MagicCarpetContracts.Exceptions;
using MagicCarpetContracts.StoragesContracts;
using MagicCarpetDatabase.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MagicCarpetDatabase.Implementations;
public class SuppliesStorageContract : ISuppliesStorageContract
{
private readonly MagicCarpetDbContext _dbContext;
private readonly Mapper _mapper;
public SuppliesStorageContract(MagicCarpetDbContext dbContext)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Supplies, SuppliesDataModel>()
.ConstructUsing(src => new SuppliesDataModel(
src.Id,
src.Type,
src.ProductuionDate,
src.Count,
_mapper.Map<List<TourSuppliesDataModel>>(src.Tours)
));
cfg.CreateMap<SuppliesDataModel, Supplies>();
cfg.CreateMap<TourSuppliesDataModel, TourSupplies>().ReverseMap();
});
_mapper = new Mapper(config);
}
public List<SuppliesDataModel> GetList(DateTime? startDate = null)
{
try
{
return [.. _dbContext.Supplieses.Select(x => _mapper.Map<SuppliesDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public SuppliesDataModel GetElementById(string id)
{
try
{
return _mapper.Map<SuppliesDataModel>(GetSuppliesById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public void AddElement(SuppliesDataModel suppliesDataModel)
{
try
{
_dbContext.Supplieses.Add(_mapper.Map<Supplies>(suppliesDataModel));
_dbContext.SaveChanges();
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public void UpdElement(SuppliesDataModel suppliesDataModel)
{
try
{
var element = GetSuppliesById(suppliesDataModel.Id) ?? throw new ElementNotFoundException(suppliesDataModel.Id);
_dbContext.Supplieses.Update(_mapper.Map(suppliesDataModel, element));
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
private Supplies? GetSuppliesById(string id) => _dbContext.Supplieses.FirstOrDefault(x => x.Id == id);
}

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