4 Commits

Author SHA1 Message Date
user
d41f6d5089 готово 2025-05-17 06:31:17 +04:00
user
439eab4c5f lab7 вроде finish 2025-05-08 15:55:40 +04:00
user
7b86908eaf task 6 ready 2025-04-23 02:36:48 +04:00
user
0fad6bdb13 Чуть чуть начал 2025-04-21 01:28:05 +04:00
164 changed files with 4873 additions and 5042 deletions

View File

@@ -6,18 +6,21 @@ using SquirrelContract.Extensions;
using System.Text.Json;
using System.Text.RegularExpressions;
using SquirrelContract.DataModels;
using Microsoft.Extensions.Localization;
using SquirrelContract.Resources;
namespace SquirrelBusinessLogic.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)
@@ -29,20 +32,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);
}
@@ -50,7 +53,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);
}
@@ -63,7 +66,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

@@ -1,22 +1,25 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using SquirrelContract.BusinessLogicContracts;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Resources;
using SquirrelContract.StoragesContracts;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace SquirrelBusinessLogic.Implementations;
public class CocktailBusinessLogicContract(ICocktailStorageContract cocktailStorageContract, ILogger logger) : ICocktailBusinessLogicContract
internal class CocktailBusinessLogicContract(ICocktailStorageContract cocktailStorageContract, IStringLocalizer<Messages> localizer, ILogger logger) : ICocktailBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly ICocktailStorageContract _cocktailStorageContract = cocktailStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<CocktailDataModel> GetAllCocktails()
{
_logger.LogInformation("GetAllCocktails");
return _cocktailStorageContract.GetList() ?? throw new NullListException();
return _cocktailStorageContract.GetList();
}
public List<CocktailHistoryDataModel> GetCocktailHistoryByCocktail(string cocktailId)
@@ -28,9 +31,9 @@ public class CocktailBusinessLogicContract(ICocktailStorageContract cocktailStor
}
if (!cocktailId.IsGuid())
{
throw new ValidationException("The value in the field cocktailId is not a unique identifier.");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "CocktailId"));
}
return _cocktailStorageContract.GetHistoryByCocktailId(cocktailId) ?? throw new NullListException();
return _cocktailStorageContract.GetHistoryByCocktailId(cocktailId);
}
public CocktailDataModel GetCocktailByData(string data)
@@ -42,16 +45,16 @@ public class CocktailBusinessLogicContract(ICocktailStorageContract cocktailStor
}
if (data.IsGuid())
{
return _cocktailStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data);
return _cocktailStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
}
return _cocktailStorageContract.GetElementByName(data) ?? throw new ElementNotFoundException(data);
return _cocktailStorageContract.GetElementByName(data) ?? throw new ElementNotFoundException(data, _localizer);
}
public void InsertCocktail(CocktailDataModel cocktailDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(cocktailDataModel));
ArgumentNullException.ThrowIfNull(cocktailDataModel);
cocktailDataModel.Validate();
cocktailDataModel.Validate(_localizer);
_cocktailStorageContract.AddElement(cocktailDataModel);
}
@@ -59,7 +62,7 @@ public class CocktailBusinessLogicContract(ICocktailStorageContract cocktailStor
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(cocktailDataModel));
ArgumentNullException.ThrowIfNull(cocktailDataModel);
cocktailDataModel.Validate();
cocktailDataModel.Validate(_localizer);
_cocktailStorageContract.UpdElement(cocktailDataModel);
}
@@ -72,7 +75,7 @@ public class CocktailBusinessLogicContract(ICocktailStorageContract cocktailStor
}
if (!id.IsGuid())
{
throw new ValidationException("Id is not a unique identifier");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_cocktailStorageContract.DelElement(id);
}

View File

@@ -1,23 +1,26 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using SquirrelContract.BusinessLogicContracts;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Resources;
using SquirrelContract.StoragesContracts;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace SquirrelBusinessLogic.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)
@@ -29,9 +32,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)
@@ -39,9 +42,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)
@@ -49,9 +52,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)
@@ -63,20 +66,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);
}
@@ -84,7 +87,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);
}
@@ -97,7 +100,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

@@ -1,21 +1,25 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using SquirrelContract.BusinessLogicContracts;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Resources;
using SquirrelContract.StoragesContracts;
using System.Text.Json;
namespace SquirrelBusinessLogic.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)
@@ -27,9 +31,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)
@@ -41,16 +45,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);
}
@@ -58,7 +62,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);
}
@@ -71,7 +75,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);
}
@@ -85,7 +89,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,173 @@
using SquirrelBusinessLogic.OfficePackage;
using SquirrelContract.BusinessLogicContracts;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.StoragesContracts;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Localization;
using SquirrelContract.Resources;
namespace SquirrelBusinessLogic.Implementations;
internal class ReportContract : IReportContract
{
private readonly ICocktailStorageContract _cocktailStorageContract;
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(ICocktailStorageContract cocktailStorageContract, ISaleStorageContract saleStorageContract, ISalaryStorageContract salaryStorageContract, BaseWordBuilder baseWordBuilder, BaseExcelBuilder baseExcelBuilder, BasePdfBuilder basePdfBuilder, ILogger logger, IStringLocalizer<Messages> localizer)
{
_cocktailStorageContract = cocktailStorageContract;
_saleStorageContract = saleStorageContract;
_salaryStorageContract = salaryStorageContract;
_baseWordBuilder = baseWordBuilder;
_baseExcelBuilder = baseExcelBuilder;
_basePdfBuilder = basePdfBuilder;
_logger = logger;
_localizer = localizer;
_documentHeader = [_localizer["DocumentDocCaptionCocktail"], _localizer["DocumentDocCaptionPreviousNames"], _localizer["DocumentDocCaptionData"]];
_tableHeader = [_localizer["DocumentExcelCaptionDate"], _localizer["DocumentExcelCaptionSum"], _localizer["DocumentExcelCaptionDiscount"], _localizer["DocumentExcelCaptionCocktail"], _localizer["DocumentExcelCaptionCount"]];
}
public Task<List<CocktailAndCocktailHistoryDataModel>> GetDataCocktailsHistoryAsync(CancellationToken ct)
{
_logger.LogInformation("Get data PostHistory");
return GetCocktailsHistoriesAsync(ct);
}
public async Task<Stream> CreateDocumentCocktailsHistoryAsync(CancellationToken ct)
{
_logger.LogInformation("Create report CocktailHistory");
var data = await GetCocktailsHistoriesAsync(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.CocktailName, "", "" } }
.Concat(x.Histories.Zip(x.Data, (price, date) => new[] { "", price, date }))
))
.ToList()
)
.Build();
}
private async Task<List<CocktailAndCocktailHistoryDataModel>> GetCocktailsHistoriesAsync(CancellationToken ct) =>
[.. (await _cocktailStorageContract.GetHistoriesListAsync(ct)).GroupBy(x => x.CocktailName).Select(x => new CocktailAndCocktailHistoryDataModel {
CocktailName = 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.Cocktails ?? Enumerable.Empty<SaleCocktailDataModel>())
{
tableRows.Add(new string[]
{
"", "", "", "", cocktail.CocktailName, 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(_localizer["NotFoundDataMessage"]);
return _basePdfBuilder
.AddHeader(_localizer["DocumentPdfHeader"])
.AddParagraph(string.Format(_localizer["DocumentPdfSubHeader"], dateStart.ToLocalTime().ToShortDateString(), dateFinish.ToLocalTime().ToShortDateString()))
.AddPieChart(_localizer["DocumentPdfDiagramCaption"], [.. data.Select(x => (x.EmployeeFIO, x.TotalSalary))])
.Build();
}
}

View File

@@ -1,4 +1,5 @@
using BarBelochkaContract.DataModels;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using SquirrelContract.BusinessLogicContracts;
using SquirrelContract.DataModels;
@@ -6,12 +7,13 @@ using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
using SquirrelContract.Infastructure.PostConfigurations;
using SquirrelContract.Resources;
using SquirrelContract.StoragesContracts;
namespace SquirrelBusinessLogic.Implementations;
public class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageContract,
ISaleStorageContract saleStorageContract, IPostStorageContract postStorageContract, IEmployeeStorageContract employeeStorageContract, ILogger logger, IConfigurationSalary сonfiguration) : 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;
@@ -19,6 +21,7 @@ public class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageCon
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)
@@ -26,16 +29,16 @@ public class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageCon
_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())
{
@@ -43,10 +46,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)
@@ -54,11 +57,11 @@ 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) ?? throw new NullListException();
var post = _postStorageContract.GetElementById(employee.PostId) ?? throw new NullListException();
var sales = _saleStorageContract.GetList(startDate, finishDate, employeeId: employee.Id);
var post = _postStorageContract.GetElementById(employee.PostId) ?? throw new ElementNotFoundException(employee.PostId, _localizer);
var salary = post.ConfigurationModel switch
{
null => 0,
@@ -73,43 +76,40 @@ public class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageCon
private double CalculateSalaryForBartender(List<SaleDataModel> sales, DateTime startDate, DateTime finishDate, BartenderPostConfiguration config)
{
var tasks = new List<Task>();
var calcPercent = 0.0;
var days = (finishDate - startDate).Days;
var dates = Enumerable.Range(0, days)
.Select(offset => startDate.AddDays(offset))
.ToList();
var parallelOptions = new ParallelOptions
for (var date = startDate; date < finishDate; date = date.AddDays(1))
{
MaxDegreeOfParallelism = _salaryConfiguration.MaxConcurrentThreads
};
Parallel.ForEach(dates, parallelOptions, date =>
{
var salesInDay = sales.Where(x => x.SaleDate.Date == date.Date).ToArray();
if (salesInDay.Length == 0) return;
double dailySum = salesInDay.Sum(x => x.Sum);
double averageSale = dailySum / salesInDay.Length;
lock (_lockObject)
tasks.Add(Task.Factory.StartNew((object? obj) =>
{
calcPercent += averageSale * config.SalePercent;
}
var dateInTask = (DateTime)obj!;
var salesInDay = sales.Where(x => x.SaleDate >= dateInTask && x.SaleDate <= dateInTask.AddDays(1)).ToArray();
if (salesInDay.Length > 0)
{
lock (_lockObject)
{
calcPercent += (salesInDay.Sum(x => x.Sum) / salesInDay.Length) * config.SalePercent;
}
}
}, date));
}
var calcBonusTask = Task.Run(() =>
{
return sales.Where(x => x.Sum > _salaryConfiguration.ExtraSaleSum).Sum(x => x.Sum) * config.BonusForExtraSales;
});
double bonus = 0;
try
{
bonus = sales.Where(x => x.Sum > _salaryConfiguration.ExtraSaleSum)
.Sum(x => x.Sum) * config.BonusForExtraSales;
Task.WaitAll([Task.WhenAll(tasks), calcBonusTask]);
}
catch (Exception ex)
catch (AggregateException agEx)
{
_logger.LogError(ex, "Error in bonus calculation");
foreach (var ex in agEx.InnerExceptions)
{
_logger.LogError(ex, "Error in the cashier payroll process");
}
return 0;
}
return config.Rate + calcPercent + bonus;
return config.Rate + calcPercent + calcBonusTask.Result;
}
private double CalculateSalaryForManager(DateTime startDate, DateTime finishDate, ManagerPostConfiguration config)
{

View File

@@ -1,69 +1,31 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using SquirrelContract.BusinessLogicContracts;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Resources;
using SquirrelContract.StoragesContracts;
using System.Text.Json;
using System.Threading;
namespace SquirrelBusinessLogic.Implementations;
public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract, IWarehouseStorageContract warehouseStorageContract, 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 IWarehouseStorageContract _warehouseStorageContract = warehouseStorageContract;
private readonly Lock _lockObject = new();
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();
}
public double CalculateTotalRevenue(DateTime fromDate, DateTime toDate)
{
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
}
var sales = _saleStorageContract.GetList(fromDate, toDate);
var salesByDay = sales
.Where(x => !x.IsCancel)
.GroupBy(x => x.SaleDate.Date)
.ToList();
var revenue = 0.0;
try
{
Parallel.ForEach(salesByDay, group =>
{
var daySum = group.Sum(x => x.Sum - x.Discount);
lock (_lockObject)
{
revenue += daySum;
}
});
}
catch (AggregateException agEx)
{
foreach (var ex in agEx.InnerExceptions)
{
_logger.LogError(ex, "Error in the cashier payroll process");
}
return 0;
}
return revenue;
return _saleStorageContract.GetList(fromDate, toDate);
}
public List<SaleDataModel> GetAllSalesByEmployeeByPeriod(string employeeId, DateTime fromDate, DateTime toDate)
@@ -71,7 +33,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())
{
@@ -79,9 +41,9 @@ public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,
}
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"));
}
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)
@@ -89,7 +51,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())
{
@@ -97,9 +59,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> GetAllSalesByCocktailByPeriod(string cocktailId, DateTime fromDate, DateTime toDate)
@@ -107,7 +69,7 @@ public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,
_logger.LogInformation("GetAllSales params: {cocktailId}, {fromDate}, {toDate}", cocktailId, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
if (cocktailId.IsEmpty())
{
@@ -115,9 +77,9 @@ public class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract,
}
if (!cocktailId.IsGuid())
{
throw new ValidationException("The value in the field cocktailId is not a unique identifier.");
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "cocktailId"));
}
return _saleStorageContract.GetList(fromDate, toDate, cocktailId: cocktailId) ?? throw new NullListException();
return _saleStorageContract.GetList(fromDate, toDate, cocktailId: cocktailId);
}
public SaleDataModel GetSaleByData(string data)
@@ -129,20 +91,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 (!_warehouseStorageContract.CheckCocktails(saleDataModel))
{
throw new InsufficientStockException("Dont have cocktails in warehouse");
}
saleDataModel.Validate(_localizer);
_saleStorageContract.AddElement(saleDataModel);
}
@@ -155,7 +113,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,124 +0,0 @@
using Microsoft.Extensions.Logging;
using SquirrelContract.BusinessLogicContracts;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.StoragesContracts;
using System.Text.Json;
namespace SquirrelBusinessLogic.Implementations;
public class SupplyBusinessLogicContract(ISupplyStorageContract supplyStorageContract, IWarehouseStorageContract warehouseStorageContract, ILogger logger) : ISupplyBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly ISupplyStorageContract _supplyStorageContract = supplyStorageContract;
private readonly IWarehouseStorageContract _warehouseStorageContract = warehouseStorageContract;
public List<SupplyDataModel> GetAllSuppliesByPeriod(DateTime fromDate, DateTime toDate)
{
_logger.LogInformation("GetAllSupplies params: {fromDate}, {toDate}", fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
}
return _supplyStorageContract.GetList(fromDate, toDate) ?? throw new NullListException();
}
public List<SupplyDataModel> GetAllSuppliesByCocktailByPeriod(string cocktailId, DateTime fromDate, DateTime toDate)
{
_logger.LogInformation("GetAllSupplies params: {cocktailId}, {fromDate}, {toDate}", cocktailId, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
}
if (cocktailId.IsEmpty())
{
throw new ArgumentNullException(nameof(cocktailId));
}
if (!cocktailId.IsGuid())
{
throw new ValidationException("The value in the field cocktailId is not a unique identifier.");
}
return _supplyStorageContract.GetList(fromDate, toDate, cocktailId: cocktailId) ?? throw new NullListException();
}
public int CountByPeriod(DateTime fromDate, DateTime toDate)
{
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate);
}
var supplies = _supplyStorageContract.GetList(fromDate, toDate);
int count = 0;
var lockObject = new object();
Parallel.ForEach(supplies, supply =>
{
int supplyCount = supply.Cocktails.Sum(c => c.Count);
if (supplyCount > 0)
{
Interlocked.Add(ref count, supplyCount);
}
});
return count;
}
public SupplyDataModel GetSupplyByData(string data)
{
_logger.LogInformation("Get supply by data: {data}", data);
if (data.IsEmpty())
{
throw new ArgumentNullException(nameof(data));
}
if (!data.IsGuid())
{
throw new ElementNotFoundException(data);
}
return _supplyStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data);
}
public void ProcessSupply(SupplyDataModel supplyDataModel)
{
_logger.LogInformation("Processing supply: {json}", JsonSerializer.Serialize(supplyDataModel));
ArgumentNullException.ThrowIfNull(supplyDataModel);
supplyDataModel.Validate();
foreach (var supplyCocktail in supplyDataModel.Cocktails)
{
var warehouses = _warehouseStorageContract.GetList();
var targetWarehouse = warehouses.FirstOrDefault(w =>
w.Cocktails.Any(c => c.CocktailId == supplyCocktail.CocktailId));
if (targetWarehouse == null)
{
targetWarehouse = warehouses.FirstOrDefault();
if (targetWarehouse == null)
{
throw new ElementNotFoundException("No warehouse found for supply.");
}
}
_warehouseStorageContract.UpdWarehouseOnSupply(targetWarehouse.Id, supplyCocktail.CocktailId, supplyCocktail.Count);
}
}
public void InsertSupply(SupplyDataModel supplyDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(supplyDataModel));
ArgumentNullException.ThrowIfNull(supplyDataModel);
supplyDataModel.Validate();
_supplyStorageContract.AddElement(supplyDataModel);
ProcessSupply(supplyDataModel);
}
public void UpdateSupply(SupplyDataModel supplyDataModel)
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(supplyDataModel));
ArgumentNullException.ThrowIfNull(supplyDataModel);
supplyDataModel.Validate();
_supplyStorageContract.UpdateElement(supplyDataModel);
ProcessSupply(supplyDataModel);
}
}

View File

@@ -1,87 +0,0 @@
using Microsoft.Extensions.Logging;
using SquirrelContract.BusinessLogicContracts;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.StoragesContracts;
using System.Text.Json;
namespace SquirrelBusinessLogic.Implementations;
public class WarehouseBusinessLogicContract(IWarehouseStorageContract warehouseStorageContract, ISupplyStorageContract supplyStorageContract, ISaleStorageContract saleStorageContract, ILogger logger) : IWarehouseBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly IWarehouseStorageContract _warehouseStorageContract = warehouseStorageContract;
private readonly ISupplyStorageContract _supplyStorageContract = supplyStorageContract;
private readonly ISaleStorageContract _saleStorageContract = saleStorageContract;
public List<WarehouseDataModel> GetAllWarehouses()
{
_logger.LogInformation("GetAllWarehouses");
return _warehouseStorageContract.GetList() ?? throw new NullListException();
}
public async Task<int> GetCocktailStockCountAsync()
{
var incomingTask = Task.Run(() =>
{
var supplies = _supplyStorageContract.GetList();
return supplies.SelectMany(x => x.Cocktails).Sum(x => x.Count);
});
var outcomingTask = Task.Run(() =>
{
var sales = _saleStorageContract.GetList();
return sales.SelectMany(x => x.Cocktails).Sum(x => x.Count);
});
await Task.WhenAll(incomingTask, outcomingTask);
return incomingTask.Result - outcomingTask.Result;
}
public WarehouseDataModel GetWarehouseByData(string data)
{
_logger.LogInformation("Get element by data: {data}", data);
if (data.IsEmpty())
{
throw new ArgumentNullException(nameof(data));
}
if (data.IsGuid())
{
return _warehouseStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data);
}
return _warehouseStorageContract.GetElementByName(data) ?? throw new ElementNotFoundException(data);
}
public void InsertWarehouse(WarehouseDataModel warehouseDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(warehouseDataModel));
ArgumentNullException.ThrowIfNull(warehouseDataModel);
warehouseDataModel.Validate();
_warehouseStorageContract.AddElement(warehouseDataModel);
}
public void UpdateWarehouse(WarehouseDataModel warehouseDataModel)
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(warehouseDataModel));
ArgumentNullException.ThrowIfNull(warehouseDataModel);
warehouseDataModel.Validate();
_warehouseStorageContract.UpdElement(warehouseDataModel);
}
public void DeleteWarehouse(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");
}
_warehouseStorageContract.DelElement(id);
}
}

View File

@@ -0,0 +1,9 @@
namespace SquirrelBusinessLogic.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,9 @@
namespace SquirrelBusinessLogic.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,9 @@
namespace SquirrelBusinessLogic.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,85 @@
using MigraDoc.DocumentObjectModel;
using MigraDoc.DocumentObjectModel.Shapes.Charts;
using MigraDoc.Rendering;
using System.Text;
namespace SquirrelBusinessLogic.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,303 @@
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml;
namespace SquirrelBusinessLogic.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,94 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace SquirrelBusinessLogic.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

@@ -8,11 +8,14 @@
<ItemGroup>
<InternalsVisibleTo Include="SquirrelTests" />
<InternalsVisibleTo Include="SquirrelWebApi" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.3" />
<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,13 @@
using SquirrelContract.AdapterContracts.OperationResponses;
namespace SquirrelContract.AdapterContracts;
public interface IReportAdapter
{
Task<ReportOperationResponse> GetDataCocktailsHistoryAsync(CancellationToken ct);
Task<ReportOperationResponse> GetDataBySalesByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<ReportOperationResponse> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<ReportOperationResponse> CreateDocumentCocktailsHistoryAsync(CancellationToken ct);
Task<ReportOperationResponse> CreateDocumentSalesByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<ReportOperationResponse> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
}

View File

@@ -1,15 +0,0 @@
using SquirrelContract.BindingModels;
using SquirrelContract.AdapterContracts.OperationResponses;
using SquirrelContract.DataModels;
namespace SquirrelContract.AdapterContracts;
public interface ISupplyAdapter
{
SupplyOperationResponse GetAllSuppliesByPeriod(DateTime fromDate, DateTime toDate);
SupplyOperationResponse GetCocktailList(string id, DateTime fromDate, DateTime toDate);
SupplyOperationResponse GetSupplyByData(string data);
SupplyOperationResponse InsertSupply(SupplyBindingModel supplyDataModel);
SupplyOperationResponse UpdateSupply(SupplyBindingModel supplyDataModel);
}

View File

@@ -1,13 +0,0 @@
using SquirrelContract.AdapterContracts.OperationResponses;
using SquirrelContract.BindingModels;
namespace SquirrelContract.AdapterContracts;
public interface IWarehouseAdapter
{
WarehouseOperationResponse GetAllWarehouses();
WarehouseOperationResponse GetWarehouseByData(string data);
WarehouseOperationResponse InsertWarehouse(WarehouseBindingModel warehouseDataModel);
WarehouseOperationResponse UpdateWarehouse(WarehouseBindingModel warehouseDataModel);
WarehouseOperationResponse DeleteWarehouse(string id);
}

View File

@@ -0,0 +1,19 @@
using SquirrelContract.Infrastructure;
using SquirrelContract.ViewModels;
namespace SquirrelContract.AdapterContracts.OperationResponses;
public class ReportOperationResponse : OperationResponse
{
public static ReportOperationResponse OK(List<CocktailAndCocktailHistoryViewModel> data) => OK<ReportOperationResponse, List<CocktailAndCocktailHistoryViewModel>>(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,19 +0,0 @@
using SquirrelContract.Infrastructure;
using SquirrelContract.ViewModels;
namespace SquirrelContract.AdapterContracts.OperationResponses;
public class SupplyOperationResponse : OperationResponse
{
public static SupplyOperationResponse OK(List<SupplyViewModel> data) => OK<SupplyOperationResponse, List<SupplyViewModel>>(data);
public static SupplyOperationResponse OK(SupplyViewModel data) => OK<SupplyOperationResponse, SupplyViewModel>(data);
public static SupplyOperationResponse NoContent() => NoContent<SupplyOperationResponse>();
public static SupplyOperationResponse NotFound(string message) => NotFound<SupplyOperationResponse>(message);
public static SupplyOperationResponse BadRequest(string message) => BadRequest<SupplyOperationResponse>(message);
public static SupplyOperationResponse InternalServerError(string message) => InternalServerError<SupplyOperationResponse>(message);
}

View File

@@ -1,19 +0,0 @@
using SquirrelContract.Infrastructure;
using SquirrelContract.ViewModels;
namespace SquirrelContract.AdapterContracts.OperationResponses;
public class WarehouseOperationResponse : OperationResponse
{
public static WarehouseOperationResponse OK(List<WarehouseViewModel> data) => OK<WarehouseOperationResponse, List<WarehouseViewModel>>(data);
public static WarehouseOperationResponse OK(WarehouseViewModel data) => OK<WarehouseOperationResponse, WarehouseViewModel>(data);
public static WarehouseOperationResponse NoContent() => NoContent<WarehouseOperationResponse>();
public static WarehouseOperationResponse NotFound(string message) => NotFound<WarehouseOperationResponse>(message);
public static WarehouseOperationResponse BadRequest(string message) => BadRequest<WarehouseOperationResponse>(message);
public static WarehouseOperationResponse InternalServerError(string message) => InternalServerError<WarehouseOperationResponse>(message);
}

View File

@@ -1,4 +1,10 @@
namespace SquirrelContract.BindingModels;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using SquirrelContract.Infastructure.PostConfigurations;
using SquirrelContract.Mapper;
using System.Text.Json;
namespace SquirrelContract.BindingModels;
public class PostBindingModel
{
@@ -10,5 +16,27 @@ public class PostBindingModel
public string? PostType { 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(BartenderPostConfiguration) => JsonConvert.DeserializeObject<BartenderPostConfiguration>(json)!,
nameof(ManagerPostConfiguration) => JsonConvert.DeserializeObject<ManagerPostConfiguration>(json)!,
_ => JsonConvert.DeserializeObject<PostConfiguration>(json)!,
};
}
return null;
}
}

View File

@@ -1,9 +0,0 @@
namespace SquirrelContract.BindingModels;
public class SupplyBindingModel
{
public string? Id { get; set; }
public DateTime SupplyDate { get; set; }
public int Count { get; set; }
public List<SupplyCocktailBindingModel>? Cocktails { get; set; }
}

View File

@@ -1,8 +0,0 @@
namespace SquirrelContract.BindingModels;
public class SupplyCocktailBindingModel
{
public string? SupplyId { get; set; }
public string? CocktailId { get; set; }
public int Count { get; set; }
}

View File

@@ -1,9 +0,0 @@
namespace SquirrelContract.BindingModels;
public class WarehouseBindingModel
{
public string? Id { get; set; }
public string? Name { get; set; }
public int Count { get; set; }
public List<WarehouseCocktailBindingModel>? Cocktails { get; set; }
}

View File

@@ -1,8 +0,0 @@
namespace SquirrelContract.BindingModels;
public class WarehouseCocktailBindingModel
{
public string? WarehouseId { get; set; }
public string? CocktailId { get; set; }
public int Count { get; set; }
}

View File

@@ -2,7 +2,7 @@
namespace SquirrelContract.BusinessLogicContracts;
public interface IClientBusinessLogicContract
internal interface IClientBusinessLogicContract
{
List<ClientDataModel> GetAllClients();

View File

@@ -2,7 +2,7 @@
namespace SquirrelContract.BusinessLogicContracts;
public interface ICocktailBusinessLogicContract
internal interface ICocktailBusinessLogicContract
{
List<CocktailDataModel> GetAllCocktails();

View File

@@ -2,7 +2,7 @@
namespace SquirrelContract.BusinessLogicContracts;
public interface IEmployeeBusinessLogicContract
internal interface IEmployeeBusinessLogicContract
{
List<EmployeeDataModel> GetAllEmployees(bool onlyActive = true);

View File

@@ -2,7 +2,7 @@
namespace SquirrelContract.BusinessLogicContracts;
public interface IPostBusinessLogicContract
internal interface IPostBusinessLogicContract
{
List<PostDataModel> GetAllPosts();

View File

@@ -0,0 +1,13 @@
using SquirrelContract.DataModels;
namespace SquirrelContract.BusinessLogicContracts;
internal interface IReportContract
{
Task<List<CocktailAndCocktailHistoryDataModel>> GetDataCocktailsHistoryAsync(CancellationToken ct);
Task<Stream> CreateDocumentCocktailsHistoryAsync(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

@@ -2,7 +2,7 @@
namespace SquirrelContract.BusinessLogicContracts;
public interface ISalaryBusinessLogicContract
internal interface ISalaryBusinessLogicContract
{
List<SalaryDataModel> GetAllSalariesByPeriod(DateTime fromDate, DateTime toDate);

View File

@@ -2,12 +2,10 @@
namespace SquirrelContract.BusinessLogicContracts;
public interface ISaleBusinessLogicContract
internal interface ISaleBusinessLogicContract
{
List<SaleDataModel> GetAllSalesByPeriod(DateTime fromDate, DateTime toDate);
double CalculateTotalRevenue(DateTime fromDate, DateTime toDate);
List<SaleDataModel> GetAllSalesByEmployeeByPeriod(string employeeId, DateTime fromDate, DateTime toDate);
List<SaleDataModel> GetAllSalesByClientByPeriod(string clientId, DateTime fromDate, DateTime toDate);

View File

@@ -1,19 +0,0 @@
using SquirrelContract.DataModels;
namespace SquirrelContract.BusinessLogicContracts;
public interface ISupplyBusinessLogicContract
{
List<SupplyDataModel> GetAllSuppliesByPeriod(DateTime fromDate, DateTime toDate);
List<SupplyDataModel> GetAllSuppliesByCocktailByPeriod(string cocktailId, DateTime fromDate, DateTime toDate);
int CountByPeriod(DateTime fromDate, DateTime toDate);
SupplyDataModel GetSupplyByData(string data);
void InsertSupply(SupplyDataModel supplyDataModel);
void UpdateSupply(SupplyDataModel supplyDataModel);
}

View File

@@ -1,18 +0,0 @@
using SquirrelContract.DataModels;
namespace SquirrelContract.BusinessLogicContracts;
public interface IWarehouseBusinessLogicContract
{
List<WarehouseDataModel> GetAllWarehouses();
Task<int> GetCocktailStockCountAsync();
WarehouseDataModel GetWarehouseByData(string data);
void InsertWarehouse(WarehouseDataModel cocktailDataModel);
void UpdateWarehouse(WarehouseDataModel cocktailDataModel);
void DeleteWarehouse(string id);
}

View File

@@ -1,32 +1,35 @@
using SquirrelContract.Exceptions;
using Microsoft.Extensions.Localization;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
using SquirrelContract.Resources;
using System.Text.RegularExpressions;
namespace SquirrelContract.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;
public string FIO { get; private set;} = fio;
public string PhoneNumber { get; private set;} = phoneNumber;
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["ValidationExceptionMessageIncorrectPhoneNumber"]);
}
}

View File

@@ -0,0 +1,8 @@
namespace SquirrelContract.DataModels;
public class CocktailAndCocktailHistoryDataModel
{
public required string CocktailName { get; set; }
public required List<string> Histories { get; set; }
public required List<string> Data { get; set; }
}

View File

@@ -1,32 +1,35 @@
using SquirrelContract.Enums;
using Microsoft.Extensions.Localization;
using SquirrelContract.Enums;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
using SquirrelContract.Resources;
namespace SquirrelContract.DataModels;
public class CocktailDataModel(string id, string cocktailName, double price, AlcoholType baseAlcohol) : IValidation
internal class CocktailDataModel(string id, string cocktailName, double price, AlcoholType baseAlcohol) : IValidation
{
public string Id { get; private set; } = id;
public string CocktailName { get; private set; } = cocktailName;
public double Price { get; private set; } = price;
public AlcoholType BaseAlcohol { get; private set; } = baseAlcohol;
public void Validate()
public CocktailDataModel() : this(string.Empty, string.Empty, 0, AlcoholType.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 (CocktailName.IsEmpty())
throw new ValidationException("Field CocktailName is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "CocktailName"));
if (Price <= 0)
throw new ValidationException("Field Price is less than or equal to 0");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "Price"));
if (BaseAlcohol == AlcoholType.None)
throw new ValidationException("Field BaseAlcohol is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "BaseAlcohol"));
}
}

View File

@@ -1,10 +1,12 @@
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
using Microsoft.Extensions.Localization;
using SquirrelContract.Resources;
namespace SquirrelContract.DataModels;
public class CocktailHistoryDataModel(string cocktailId, double oldPrice) : IValidation
internal class CocktailHistoryDataModel(string cocktailId, double oldPrice) : IValidation
{
private readonly CocktailDataModel? _cocktail;
@@ -21,16 +23,17 @@ public class CocktailHistoryDataModel(string cocktailId, double oldPrice) : IVal
ChangeDate = changeDate;
_cocktail = cocktail;
}
public CocktailHistoryDataModel() : this(string.Empty, 0) { }
public void Validate()
public void Validate(IStringLocalizer<Messages> localizer)
{
if (CocktailId.IsEmpty())
throw new ValidationException("Field CocktailId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "CocktailId"));
if (!CocktailId.IsGuid())
throw new ValidationException("The value in the field CocktailId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "CocktailId"));
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,11 +1,13 @@
using SquirrelContract.Exceptions;
using Microsoft.Extensions.Localization;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
using SquirrelContract.Resources;
using System.Text.RegularExpressions;
namespace SquirrelContract.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;
@@ -17,9 +19,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;
@@ -31,37 +33,41 @@ 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 EmployeeDataModel() : this(string.Empty, string.Empty, string.Empty, string.Empty, DateTime.MinValue, DateTime.MinValue, false) { }
public void Validate()
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) // EmploymentDate.Year - BirthDate.Year
throw new ValidationException($"Only adults can be hired (EmploymentDate - {EmploymentDate.ToShortDateString()}, BirthDate - {BirthDate.ToShortDateString()})");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageMinorsEmploymentDate"],
EmploymentDate.ToShortDateString(), BirthDate.ToShortDateString()));
}
}

View File

@@ -0,0 +1,12 @@
namespace SquirrelContract.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

@@ -5,50 +5,76 @@ using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
using SquirrelContract.Infastructure.PostConfigurations;
using Microsoft.Extensions.Localization;
using SquirrelContract.Resources;
using SquirrelContract.Mapper;
namespace SquirrelContract.DataModels;
public class PostDataModel(string postId, string postName, PostType postType, PostConfiguration configuration) : 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;
[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, PostType postType, string configurationJson) : this(postId, postName, postType, (PostConfiguration)null)
{
var obj = JToken.Parse(configurationJson);
if (obj is not null)
{
ConfigurationModel = obj.Value<string>("Type") switch
{
nameof(BartenderPostConfiguration) => JsonConvert.DeserializeObject<BartenderPostConfiguration>(configurationJson)!,
nameof(ManagerPostConfiguration) => JsonConvert.DeserializeObject<ManagerPostConfiguration>(configurationJson)!,
_ => JsonConvert.DeserializeObject<PostConfiguration>(configurationJson)!,
};
}
}
public PostDataModel(string postId, string postName) : this(postId, postName, PostType.None, new PostConfiguration() { Rate = 10 }) { }
public void Validate()
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");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "PostType"));
if (ConfigurationModel is null)
throw new ValidationException("Field ConfigurationModel is not initialized");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotInitialized"], "ConfigurationModel"));
if (ConfigurationModel!.Rate <= 0)
throw new ValidationException("Field Rate is less or equal zero");
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(BartenderPostConfiguration):
ConfigurationModel = JsonConvert.DeserializeObject<BartenderPostConfiguration>((string)json);
break;
case nameof(ManagerPostConfiguration):
ConfigurationModel = JsonConvert.DeserializeObject<ManagerPostConfiguration>((string)json);
break;
default:
ConfigurationModel = JsonConvert.DeserializeObject<PostConfiguration>((string)json);
break;
}
return ConfigurationModel;
}
return null;
}
}

View File

@@ -1,11 +1,14 @@
using SquirrelContract.DataModels;
using Microsoft.Extensions.Localization;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
using SquirrelContract.Mapper;
using SquirrelContract.Resources;
namespace BarBelochkaContract.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;
@@ -13,6 +16,7 @@ public class SalaryDataModel(string employeeId, DateTime salaryDate, double empl
public DateTime SalaryDate { get; private set; } = salaryDate;
[AlternativeName("EmployeeSalary")]
public double Salary { get; private set; } = employeeSalary;
public string EmployeeFIO => _employee?.FIO ?? string.Empty;
@@ -22,15 +26,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

@@ -1,10 +1,12 @@
using SquirrelContract.Exceptions;
using Microsoft.Extensions.Localization;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
using SquirrelContract.Resources;
namespace SquirrelContract.DataModels;
public class SaleCocktailDataModel(string saleId, string cocktailId, int count, double price) : IValidation
internal class SaleCocktailDataModel(string saleId, string cocktailId, int count, double price) : IValidation
{
private readonly CocktailDataModel? _cocktail;
@@ -18,29 +20,32 @@ public class SaleCocktailDataModel(string saleId, string cocktailId, int count,
public string CocktailName => _cocktail?.CocktailName ?? string.Empty;
public SaleCocktailDataModel() : this(string.Empty, string.Empty, 0, 0.0) { }
public SaleCocktailDataModel(string saleId, string cocktailId, int count, double price, CocktailDataModel cocktail) : this(saleId, cocktailId, count, price)
{
_cocktail = cocktail;
}
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 (CocktailId.IsEmpty())
throw new ValidationException("Field CocktailId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "IProductIdd"));
if (!CocktailId.IsGuid())
throw new ValidationException("The value in the field CocktailId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "ProductId"));
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,11 +1,14 @@
using SquirrelContract.Enums;
using Microsoft.Extensions.Localization;
using SquirrelContract.Enums;
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
using SquirrelContract.Mapper;
using SquirrelContract.Resources;
namespace SquirrelContract.DataModels;
public class SaleDataModel : IValidation
internal class SaleDataModel : IValidation
{
private readonly ClientDataModel? _client;
@@ -27,6 +30,7 @@ public class SaleDataModel : IValidation
public bool IsCancel { get; private set; }
[AlternativeName("SaleCocktails")]
public List<SaleCocktailDataModel>? Cocktails { get; private set; }
public string ClientFIO => _client?.FIO ?? string.Empty;
@@ -75,28 +79,34 @@ public class SaleDataModel : IValidation
}
public SaleDataModel(string id, string employeeId, string? clientId, int discountType, List<SaleCocktailDataModel> cocktails) : this(id, employeeId, clientId, (DiscountType)discountType, false, cocktails) { }
public SaleDataModel() : this(string.Empty, string.Empty, string.Empty, DiscountType.None, false, new List<SaleCocktailDataModel>()) { }
public void Validate()
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"], "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 (!ClientId?.IsGuid() ?? !ClientId?.IsEmpty() ?? false)
throw new ValidationException("The value in the field ClientId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "ClientId"));
if (Sum <= 0)
throw new ValidationException("Field Sum is less than or equal to 0");
//if (Sum <= 0)
// throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "Sum"));
if ((Cocktails?.Count ?? 0) == 0)
throw new ValidationException("The sale must include cocktails");
if (Cocktails is null)
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotInitialized"], "Cocktails"));
if (Cocktails.Count == 0)
throw new ValidationException(localizer["ValidationExceptionMessageNoCocktailsInSale"]);
Cocktails.ForEach(x => x.Validate(localizer));
}
}

View File

@@ -1,33 +0,0 @@
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
using System.ComponentModel;
namespace SquirrelContract.DataModels;
public class SupplyCocktailDataModel(string? supplyId, string? cocktailId, int count) : IValidation
{
public string SupplyId { get; private set; } = supplyId;
public string CocktailId { get; private set; } = cocktailId;
public int Count { get; private set; } = count;
public void Validate()
{
if (SupplyId.IsEmpty())
throw new ValidationException("Field SupplyId is empty");
if (!SupplyId.IsGuid())
throw new ValidationException("The value in the field SupplyId is not a unique identifier");
if (CocktailId.IsEmpty())
throw new ValidationException("Field CocktailId is empty");
if (!CocktailId.IsGuid())
throw new ValidationException("The value in the field CocktailId is not a unique identifier");
if (Count <= 0)
throw new ValidationException("Field Count is less than or equal to 0");
}
}

View File

@@ -1,29 +0,0 @@
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
namespace SquirrelContract.DataModels;
public class SupplyDataModel(string id, DateTime supplyDate, List<SupplyCocktailDataModel> cocktails) : IValidation
{
public string Id { get; private set; } = id;
public DateTime SupplyDate { get; private set; } = supplyDate;
public List<SupplyCocktailDataModel> Cocktails { get; private set; } = cocktails;
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 (SupplyDate.Date > DateTime.Now)
throw new ValidationException($"It is impossible to supply things in the future");
if ((Cocktails?.Count ?? 0) == 0)
throw new ValidationException("The components must include products");
}
}

View File

@@ -1,32 +0,0 @@
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
namespace SquirrelContract.DataModels;
public class WarehouseCocktailDataModel(string? warehouseId, string? cocktailId, int count) : IValidation
{
public string WarehouseId { get; private set; } = warehouseId;
public string CocktailId { get; private set; } = cocktailId;
public int Count { get; private set; } = count;
public void Validate()
{
if (WarehouseId.IsEmpty())
throw new ValidationException("Field WarehouseId is empty");
if (!WarehouseId.IsGuid())
throw new ValidationException("The value in the field WarehouseId is not a unique identifier");
if (CocktailId.IsEmpty())
throw new ValidationException("Field CocktailId is empty");
if (!CocktailId.IsGuid())
throw new ValidationException("The value in the field CocktailId is not a unique identifier");
if (Count <= 0)
throw new ValidationException("Field Count is less than or equal to 0");
}
}

View File

@@ -1,30 +0,0 @@
using SquirrelContract.Exceptions;
using SquirrelContract.Extensions;
using SquirrelContract.Infastructure;
using System.Xml.Linq;
namespace SquirrelContract.DataModels;
public class WarehouseDataModel(string? id, string name, List<WarehouseCocktailDataModel> cocktails) : IValidation
{
public string Id { get; private set; } = id;
public string Name { get; private set; } = name;
public List<WarehouseCocktailDataModel> Cocktails { get; private set; } = cocktails;
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 (Name.IsEmpty())
throw new ValidationException("Field Name is empty");
if ((Cocktails?.Count ?? 0) == 0)
throw new ValidationException("The cocktails must include drinks");
}
}

View File

@@ -1,11 +1,10 @@
namespace SquirrelContract.Exceptions;
using Microsoft.Extensions.Localization;
using SquirrelContract.Resources;
public class ElementNotFoundException : Exception
namespace SquirrelContract.Exceptions;
internal class ElementNotFoundException(string value, IStringLocalizer<Messages> localizer) :
Exception(string.Format(localizer["ElementNotFoundExceptionMessage"], 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,14 +1,12 @@
namespace SquirrelContract.Exceptions;
using Microsoft.Extensions.Localization;
using SquirrelContract.Resources;
public class ElementExistsException : Exception
namespace SquirrelContract.Exceptions;
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,6 +1,8 @@
namespace SquirrelContract.Exceptions;
using Microsoft.Extensions.Localization;
using SquirrelContract.Resources;
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}") { }
}
namespace SquirrelContract.Exceptions;
internal class IncorrectDatesException(DateTime start, DateTime end, IStringLocalizer<Messages> localizer) :
Exception(string.Format(localizer["IncorrectDatesExceptionMessage"], start.ToShortDateString(), end.ToShortDateString()))
{ }

View File

@@ -1,5 +0,0 @@
namespace SquirrelContract.Exceptions;
public class InsufficientStockException(string message) : Exception(message)
{
}

View File

@@ -1,6 +0,0 @@
namespace SquirrelContract.Exceptions;
public class NullListException : Exception
{
public NullListException() : base("The returned list is null") { }
}

View File

@@ -1,6 +1,8 @@
namespace SquirrelContract.Exceptions;
using Microsoft.Extensions.Localization;
using SquirrelContract.Resources;
public class StorageException : Exception
{
public StorageException(Exception ex) : base($"Error while working in storage: {ex.Message}", ex) { }
}
namespace SquirrelContract.Exceptions;
internal class StorageException(Exception ex, IStringLocalizer<Messages> localizer) :
Exception(string.Format(localizer["StorageExceptionMessage"], ex.Message), ex)
{ }

View File

@@ -1,6 +1,9 @@
namespace SquirrelContract.Infastructure;
using Microsoft.Extensions.Localization;
using SquirrelContract.Resources;
public interface IValidation
namespace SquirrelContract.Infastructure;
internal interface IValidation
{
void Validate();
void Validate(IStringLocalizer<Messages> localizer);
}

View File

@@ -6,32 +6,44 @@ namespace SquirrelContract.Infrastructure;
public class OperationResponse
{
public HttpStatusCode StatusCode { get; set; }
protected HttpStatusCode StatusCode { get; set; }
public object? Result { get; set; }
protected object? Result { get; set; }
public IActionResult GetResponse(HttpRequest request, HttpResponse response)
{
ArgumentNullException.ThrowIfNull(request);
ArgumentNullException.ThrowIfNull(response);
protected string? FileName { get; set; }
response.StatusCode = (int)StatusCode;
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 };
if (Result is null)
{
return new StatusCodeResult((int)StatusCode);
}
protected static TResult OK<TResult, TData>(TData data, string fileName) where TResult : OperationResponse, new()
=> new() { StatusCode = HttpStatusCode.OK, Result = data, FileName = fileName };
return new ObjectResult(Result);
}
protected static TResult NoContent<TResult>() where TResult : OperationResponse, new() => new() { StatusCode = HttpStatusCode.NoContent };
protected static TResult OK<TResult, TData>(TData data) where TResult : OperationResponse, new() => new() { StatusCode = HttpStatusCode.OK, Result = data };
protected static TResult BadRequest<TResult>(string? errorMessage = null)
where TResult : OperationResponse, new() => new() { StatusCode = HttpStatusCode.BadRequest, Result = errorMessage };
protected static TResult NoContent<TResult>() where TResult : OperationResponse, new() => new() { StatusCode = HttpStatusCode.NoContent };
protected static TResult NotFound<TResult>(string? errorMessage = null)
where TResult : OperationResponse, new() => new() { StatusCode = HttpStatusCode.NotFound, Result = errorMessage };
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, new() => new() { StatusCode = HttpStatusCode.NotFound, Result = errorMessage };
protected static TResult InternalServerError<TResult>(string? errorMessage = null) where TResult : OperationResponse, new() => new() { StatusCode = HttpStatusCode.InternalServerError, Result = errorMessage };
}
protected static TResult InternalServerError<TResult>(string? errorMessage = null)
where TResult : OperationResponse, new() => new() { StatusCode = HttpStatusCode.InternalServerError, Result = errorMessage };
}

View File

@@ -1,7 +1,10 @@
namespace SquirrelContract.Infastructure.PostConfigurations;
using System.Globalization;
namespace SquirrelContract.Infastructure.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,12 @@
namespace SquirrelContract.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.Reflection;
namespace SquirrelContract.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 SquirrelContract.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,7 @@
namespace SquirrelContract.Mapper;
[AttributeUsage(AttributeTargets.Property)]
class IgnoreMappingAttribute : Attribute
{
}

View File

@@ -0,0 +1,9 @@
namespace SquirrelContract.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 SquirrelContract.Mapper;
enum PostProcessingType
{
None = -1,
ToUniversalTime = 1,
ToLocalTime = 2
}

View File

@@ -0,0 +1,432 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Этот код создан программой.
// Исполняемая версия:4.0.30319.42000
//
// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
// повторной генерации кода.
// </auto-generated>
//------------------------------------------------------------------------------
namespace SquirrelContract.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("SquirrelContract.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 AdapterMessageElementDeletedException {
get {
return ResourceManager.GetString("AdapterMessageElementDeletedException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Не найден элемент по данным: {0}.
/// </summary>
internal static string AdapterMessageElementNotFoundException {
get {
return ResourceManager.GetString("AdapterMessageElementNotFoundException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Данные пусты.
/// </summary>
internal static string AdapterMessageEmptyDate {
get {
return ResourceManager.GetString("AdapterMessageEmptyDate", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Неправильные даты: {0}.
/// </summary>
internal static string AdapterMessageIncorrectDatesException {
get {
return ResourceManager.GetString("AdapterMessageIncorrectDatesException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Ошибка при обработке данных: {0}.
/// </summary>
internal static string AdapterMessageInvalidOperationException {
get {
return ResourceManager.GetString("AdapterMessageInvalidOperationException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Ошибка при работе с хранилищем данных: {0}.
/// </summary>
internal static string AdapterMessageStorageException {
get {
return ResourceManager.GetString("AdapterMessageStorageException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Переданы неверные данные: {0}.
/// </summary>
internal static string AdapterMessageValidationException {
get {
return ResourceManager.GetString("AdapterMessageValidationException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Коктель.
/// </summary>
internal static string DocumentDocCaptionCocktail {
get {
return ResourceManager.GetString("DocumentDocCaptionCocktail", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Дата.
/// </summary>
internal static string DocumentDocCaptionData {
get {
return ResourceManager.GetString("DocumentDocCaptionData", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Предыдущие названия.
/// </summary>
internal static string DocumentDocCaptionPreviousNames {
get {
return ResourceManager.GetString("DocumentDocCaptionPreviousNames", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на История изменения коктелей.
/// </summary>
internal static string DocumentDocHeader {
get {
return ResourceManager.GetString("DocumentDocHeader", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Сформировано на дату {0}.
/// </summary>
internal static string DocumentDocSubHeader {
get {
return ResourceManager.GetString("DocumentDocSubHeader", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Товар.
/// </summary>
internal static string DocumentExcelCaptionCocktail {
get {
return ResourceManager.GetString("DocumentExcelCaptionCocktail", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Кол-во.
/// </summary>
internal static string DocumentExcelCaptionCount {
get {
return ResourceManager.GetString("DocumentExcelCaptionCount", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Дата.
/// </summary>
internal static string DocumentExcelCaptionDate {
get {
return ResourceManager.GetString("DocumentExcelCaptionDate", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Скидка.
/// </summary>
internal static string DocumentExcelCaptionDiscount {
get {
return ResourceManager.GetString("DocumentExcelCaptionDiscount", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Сумма.
/// </summary>
internal static string DocumentExcelCaptionSum {
get {
return ResourceManager.GetString("DocumentExcelCaptionSum", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Всего.
/// </summary>
internal static string DocumentExcelCaptionTotal {
get {
return ResourceManager.GetString("DocumentExcelCaptionTotal", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Продажи за период.
/// </summary>
internal static string DocumentExcelHeader {
get {
return ResourceManager.GetString("DocumentExcelHeader", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Сотрудник.
/// </summary>
internal static string DocumentExcelHeaderEmployee {
get {
return ResourceManager.GetString("DocumentExcelHeaderEmployee", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на c {0} по {1}.
/// </summary>
internal static string DocumentExcelSubHeader {
get {
return ResourceManager.GetString("DocumentExcelSubHeader", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Начисления.
/// </summary>
internal static string DocumentPdfDiagramCaption {
get {
return ResourceManager.GetString("DocumentPdfDiagramCaption", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Зарплатная ведомость.
/// </summary>
internal static string DocumentPdfHeader {
get {
return ResourceManager.GetString("DocumentPdfHeader", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на за период с {0} по {1}.
/// </summary>
internal static string DocumentPdfSubHeader {
get {
return ResourceManager.GetString("DocumentPdfSubHeader", resourceCulture);
}
}
/// <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 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="DocumentDocCaptionCocktail" xml:space="preserve">
<value>Cocktail</value>
</data>
<data name="DocumentDocHeader" xml:space="preserve">
<value>The history of cocktail 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="DocumentExcelCaptionCocktail" xml:space="preserve">
<value>Cocktail</value>
</data>
<data name="DocumentExcelCaptionSum" xml:space="preserve">
<value>Sum</value>
</data>
<data name="DocumentExcelCaptionTotal" xml:space="preserve">
<value>Total</value>
</data>
<data name="DocumentExcelHeader" xml:space="preserve">
<value>Sales for the period</value>
</data>
<data name="DocumentExcelSubHeader" xml:space="preserve">
<value>from {0} to {1}</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="DocumentPdfDiagramCaption" xml:space="preserve">
<value>Accruals</value>
</data>
<data name="NotFoundDataMessage" xml:space="preserve">
<value>No data found</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="ValidationExceptionMessageEmptyField" xml:space="preserve">
<value>The value in field {0} is empty</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="ValidationExceptionMessageNotInitialized" xml:space="preserve">
<value>The value in field {0} is not initialized</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="ValidationExceptionMessageNoProductsInSale" xml:space="preserve">
<value>There must be at least one product on sale.</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="ValidationExceptionMessageEmploymentDateAndBirthDate" xml:space="preserve">
<value>Date of employment cannot be earlier than date of birth ({0}, {1})</value>
</data>
<data name="AdapterMessageStorageException" xml:space="preserve">
<value>Error while working with data storage: {0}</value>
</data>
<data name="AdapterMessageEmptyDate" xml:space="preserve">
<value>Data is empty</value>
</data>
<data name="AdapterMessageElementNotFoundException" xml:space="preserve">
<value>Not found element by data: {0}</value>
</data>
<data name="AdapterMessageValidationException" xml:space="preserve">
<value>Incorrect data transmitted: {0}</value>
</data>
<data name="AdapterMessageElementDeletedException" xml:space="preserve">
<value>The item according to the data: {0} has been deleted</value>
</data>
<data name="AdapterMessageInvalidOperationException" xml:space="preserve">
<value>Error processing data: {0}</value>
</data>
<data name="AdapterMessageIncorrectDatesException" xml:space="preserve">
<value>Incorrect dates: {0}</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="StorageExceptionMessage" xml:space="preserve">
<value>Error while working in storage: {0}</value>
</data>
<data name="DocumentExcelHeaderEmployee" xml:space="preserve">
<value>Employee</value>
</data>
<data name="DocumentDocCaptionPreviousNames" xml:space="preserve">
<value>Previous names</value>
</data>
<data name="DocumentDocCaptionData" xml:space="preserve">
<value>Data</value>
</data>
<data name="ValidationExceptionMessageIncorrectFIO " xml:space="preserve">
<value>Fio is not correct</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="DocumentDocCaptionCocktail" 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="DocumentExcelCaptionCocktail" 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="DocumentExcelHeader" xml:space="preserve">
<value>Продажи за период</value>
</data>
<data name="DocumentExcelSubHeader" xml:space="preserve">
<value>c {0} по {1}</value>
</data>
<data name="DocumentPdfHeader" xml:space="preserve">
<value>Зарплатная ведомость</value>
</data>
<data name="DocumentPdfSubHeader" xml:space="preserve">
<value>за период с {0} по {1}</value>
</data>
<data name="DocumentPdfDiagramCaption" xml:space="preserve">
<value>Начисления</value>
</data>
<data name="NotFoundDataMessage" xml:space="preserve">
<value>Не найдены данные</value>
</data>
<data name="ValidationExceptionMessageNotAId" xml:space="preserve">
<value>Значение в поле {0} не является типом уникального идентификатора</value>
</data>
<data name="ValidationExceptionMessageEmptyField" xml:space="preserve">
<value>Значение в поле {0} пусто</value>
</data>
<data name="ValidationExceptionMessageIncorrectPhoneNumber" xml:space="preserve">
<value>Значение в поле Телефонный номер не является телефонным номером</value>
</data>
<data name="ValidationExceptionMessageNotInitialized" xml:space="preserve">
<value>Значение в поле {0} не проиницализировано</value>
</data>
<data name="ValidationExceptionMessageLessOrEqualZero" xml:space="preserve">
<value>Значение в поле {0} меньше или равно 0</value>
</data>
<data name="ValidationExceptionMessageNoProductsInSale" xml:space="preserve">
<value>В продаже должен быть хотя бы один товар</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="ValidationExceptionMessageEmploymentDateAndBirthDate" xml:space="preserve">
<value>Дата трудоустройства не может быть раньше даты рождения ({0}, {1})</value>
</data>
<data name="AdapterMessageStorageException" xml:space="preserve">
<value>Ошибка при работе с хранилищем данных: {0}</value>
</data>
<data name="AdapterMessageEmptyDate" xml:space="preserve">
<value>Данные пусты</value>
</data>
<data name="AdapterMessageElementNotFoundException" xml:space="preserve">
<value>Не найден элемент по данным: {0}</value>
</data>
<data name="AdapterMessageValidationException" xml:space="preserve">
<value>Переданы неверные данные: {0}</value>
</data>
<data name="AdapterMessageElementDeletedException" xml:space="preserve">
<value>Элемент по данным: {0} был удален</value>
</data>
<data name="AdapterMessageInvalidOperationException" xml:space="preserve">
<value>Ошибка при обработке данных: {0}</value>
</data>
<data name="AdapterMessageIncorrectDatesException" xml:space="preserve">
<value>Неправильные даты: {0}</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="StorageExceptionMessage" xml:space="preserve">
<value>Ошибка при работе в хранилище: {0}</value>
</data>
<data name="DocumentExcelHeaderEmployee" xml:space="preserve">
<value>Сотрудник</value>
</data>
<data name="DocumentDocCaptionPreviousNames" xml:space="preserve">
<value>Предыдущие названия</value>
</data>
<data name="DocumentDocCaptionData" xml:space="preserve">
<value>Дата</value>
</data>
<data name="ValidationExceptionMessageIncorrectFIO " xml:space="preserve">
<value>Фамилия не корректна</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="DocumentDocCaptionCocktail" 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="DocumentExcelCaptionCocktail" 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="DocumentExcelHeader" xml:space="preserve">
<value>期间的销售额</value>
</data>
<data name="DocumentExcelSubHeader" xml:space="preserve">
<value>从{0}到{1}</value>
</data>
<data name="DocumentPdfHeader" xml:space="preserve">
<value>薪金表</value>
</data>
<data name="DocumentPdfSubHeader" xml:space="preserve">
<value>从{0}到{1}的期间</value>
</data>
<data name="DocumentPdfDiagramCaption" xml:space="preserve">
<value>应计事项</value>
</data>
<data name="NotFoundDataMessage" xml:space="preserve">
<value>未找到数据</value>
</data>
<data name="ValidationExceptionMessageNotAId" xml:space="preserve">
<value>字段 {0} 的值不是唯一标识符类型</value>
</data>
<data name="ValidationExceptionMessageEmptyField" xml:space="preserve">
<value>字段 {0} 的值为空</value>
</data>
<data name="ValidationExceptionMessageIncorrectPhoneNumber" xml:space="preserve">
<value>电话号码字段中的值不是电话号码。</value>
</data>
<data name="ValidationExceptionMessageNotInitialized" xml:space="preserve">
<value>{0}字段中的值未初始化</value>
</data>
<data name="ValidationExceptionMessageLessOrEqualZero" xml:space="preserve">
<value>{0}字段中的值小于或等于0</value>
</data>
<data name="ValidationExceptionMessageNoProductsInSale" xml:space="preserve">
<value>必须至少有一种产品在售。</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="ValidationExceptionMessageEmploymentDateAndBirthDate" xml:space="preserve">
<value>就业日期不能早于出生日期({0},{1})</value>
</data>
<data name="AdapterMessageStorageException" xml:space="preserve">
<value>使用数据仓库时出错:{0}</value>
</data>
<data name="AdapterMessageEmptyDate" xml:space="preserve">
<value>数据为空</value>
</data>
<data name="AdapterMessageElementNotFoundException" xml:space="preserve">
<value>未找到元素数据: {0}</value>
</data>
<data name="AdapterMessageValidationException" xml:space="preserve">
<value>传递的数据不正确: {0}</value>
</data>
<data name="AdapterMessageElementDeletedException" xml:space="preserve">
<value>根据数据的项目:{0}已被删除</value>
</data>
<data name="AdapterMessageInvalidOperationException" xml:space="preserve">
<value>数据处理过程中的错误:{0}</value>
</data>
<data name="AdapterMessageIncorrectDatesException" xml:space="preserve">
<value>不正确的日期:{0}</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="StorageExceptionMessage" xml:space="preserve">
<value>在存储中工作时出错:{0}</value>
</data>
<data name="DocumentExcelHeaderEmployee" xml:space="preserve">
<value>工人</value>
</data>
<data name="DocumentDocCaptionPreviousNames" xml:space="preserve">
<value>以前的名字</value>
</data>
<data name="DocumentDocCaptionData" xml:space="preserve">
<value>日期</value>
</data>
<data name="ValidationExceptionMessageIncorrectFIO " xml:space="preserve">
<value>名称格式不正确</value>
</data>
</root>

View File

@@ -9,6 +9,31 @@
<ItemGroup>
<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" Version="9.0.4" />
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\Messages.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Messages.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Messages.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Messages.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="SquirrelBusinessLogic" />
<InternalsVisibleTo Include="SquirrelDatabase" />
<InternalsVisibleTo Include="SquirrelWebApi" />
<InternalsVisibleTo Include="SquirrelTests" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
namespace SquirrelContract.StoragesContracts;
public interface IClientStorageContract
internal interface IClientStorageContract
{
List<ClientDataModel> GetList();

View File

@@ -2,10 +2,11 @@
namespace SquirrelContract.StoragesContracts;
public interface ICocktailStorageContract
internal interface ICocktailStorageContract
{
List<CocktailDataModel> GetList();
List<CocktailHistoryDataModel> GetHistoryByCocktailId(string cocktailId);
Task<List<CocktailHistoryDataModel>> GetHistoriesListAsync(CancellationToken ct);
CocktailDataModel? GetElementById(string id);
CocktailDataModel? GetElementByName(string name);
void AddElement(CocktailDataModel cocktailDataModel);

View File

@@ -2,7 +2,7 @@
namespace SquirrelContract.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);

View File

@@ -2,7 +2,7 @@
namespace SquirrelContract.StoragesContracts;
public interface IPostStorageContract
internal interface IPostStorageContract
{
List<PostDataModel> GetList();
List<PostDataModel> GetPostWithHistory(string postId);

View File

@@ -2,9 +2,9 @@
namespace SquirrelContract.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

@@ -2,10 +2,12 @@
namespace SquirrelContract.StoragesContracts;
public interface ISaleStorageContract
internal interface ISaleStorageContract
{
List<SaleDataModel> GetList(DateTime? startDate = null, DateTime? endDate = null, string? employeeId = null, string? clientId = null, string? cocktailId = null);
Task<List<SaleDataModel>> GetListAsync(DateTime startDate, DateTime endDate, CancellationToken ct);
SaleDataModel? GetElementById(string id);
void AddElement(SaleDataModel saleDataModel);

View File

@@ -1,11 +0,0 @@
using SquirrelContract.DataModels;
namespace SquirrelContract.StoragesContracts;
public interface ISupplyStorageContract
{
List<SupplyDataModel> GetList(DateTime? startDate = null, DateTime? endDate = null, string? cocktailId = null);
SupplyDataModel? GetElementById(string id);
void AddElement(SupplyDataModel warehouseDataModel);
void UpdateElement(SupplyDataModel warehouseDataModel);
}

View File

@@ -1,15 +0,0 @@
using SquirrelContract.DataModels;
namespace SquirrelContract.StoragesContracts;
public interface IWarehouseStorageContract
{
List<WarehouseDataModel> GetList();
WarehouseDataModel? GetElementByName(string name);
WarehouseDataModel? GetElementById(string id);
void AddElement(WarehouseDataModel warehouseDataModel);
void UpdElement(WarehouseDataModel warehouseDataModel);
void UpdWarehouseOnSupply(string warehouseId, string cocktailId, int count);
void DelElement(string id);
bool CheckCocktails(SaleDataModel saleDataModel);
}

View File

@@ -0,0 +1,8 @@
namespace SquirrelContract.ViewModels;
public class CocktailAndCocktailHistoryViewModel
{
public required string CocktailName { get; set; }
public required List<string> Histories { get; set; }
public required List<string> Data { get; set; }
}

View File

@@ -0,0 +1,9 @@
namespace SquirrelContract.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,7 +1,10 @@
namespace SquirrelContract.ViewModels;
using SquirrelContract.Mapper;
namespace SquirrelContract.ViewModels;
public class EmployeeViewModel
{
[AlternativeName("EmployeeId")]
public required string Id { get; set; }
public required string FIO { get; set; }
@@ -14,7 +17,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,12 +1,26 @@
namespace SquirrelContract.ViewModels;
using SquirrelContract.Infastructure.PostConfigurations;
using SquirrelContract.Mapper;
using System.Text.Json;
namespace SquirrelContract.ViewModels;
public class PostViewModel
{
[AlternativeName("PostId")]
public required string Id { get; set; }
public required string PostName { get; set; }
public required string PostType { 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,9 +1,13 @@
namespace SquirrelContract.ViewModels;
using SquirrelContract.Mapper;
namespace SquirrelContract.ViewModels;
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,6 @@
namespace SquirrelContract.ViewModels;
using SquirrelContract.Mapper;
namespace SquirrelContract.ViewModels;
public class SaleViewModel
{
@@ -12,6 +14,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,8 +0,0 @@
namespace SquirrelContract.ViewModels;
public class SupplyCocktailViewModel
{
public required string SupplyId { get; set; }
public required string CocktailId { get; set; }
public int Count { get; set; }
}

View File

@@ -1,9 +0,0 @@
namespace SquirrelContract.ViewModels;
public class SupplyViewModel
{
public required string Id { get; set; }
public DateTime SupplyDate { get; set; }
public int Count { get; set; }
public required List<SupplyCocktailViewModel> Cocktails { get; set; }
}

View File

@@ -1,8 +0,0 @@
namespace SquirrelContract.ViewModels;
public class WarehouseCocktailViewModel
{
public required string WarehouseId { get; set; }
public required string CocktailId { get; set; }
public int Count { get; set; }
}

View File

@@ -1,9 +0,0 @@
namespace SquirrelContract.ViewModels;
public class WarehouseViewModel
{
public required string Id { get; set; }
public required string Name { get; set; }
public required int Count { get; set; }
public required List<WarehouseCocktailViewModel> Cocktails { get; set; }
}

View File

@@ -1,39 +1,32 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Npgsql;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Mapper;
using SquirrelContract.Resources;
using SquirrelContract.StoragesContracts;
using SquirrelDatabase.Models;
using System;
namespace SquirrelDatabase.Implementations;
public class ClientStorageContract : IClientStorageContract
internal class ClientStorageContract(SquirrelDbContext squirrelDbContext, IStringLocalizer<Messages> localizer) : IClientStorageContract
{
private readonly SquirrelDbContext _dbContext;
private readonly Mapper _mapper;
public ClientStorageContract(SquirrelDbContext squirrelDbContext)
{
_dbContext = squirrelDbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.AddMaps(typeof(SquirrelDbContext).Assembly);
});
_mapper = new Mapper(config);
}
private readonly SquirrelDbContext _dbContext = squirrelDbContext;
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);
}
}
@@ -41,12 +34,12 @@ public class ClientStorageContract : IClientStorageContract
{
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);
}
}
@@ -54,12 +47,12 @@ public class ClientStorageContract : IClientStorageContract
{
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);
}
}
@@ -67,12 +60,12 @@ public class ClientStorageContract : IClientStorageContract
{
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);
}
}
@@ -80,23 +73,28 @@ public class ClientStorageContract : IClientStorageContract
{
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 (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "PK_Clients" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", clientDataModel.Id, _localizer);
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -104,8 +102,8 @@ public class ClientStorageContract : IClientStorageContract
{
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)
@@ -116,12 +114,12 @@ 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);
}
}
@@ -129,7 +127,7 @@ public class ClientStorageContract : IClientStorageContract
{
try
{
var element = GetClientById(id) ?? throw new ElementNotFoundException(id);
var element = GetClientById(id) ?? throw new ElementNotFoundException(id, _localizer);
_dbContext.Clients.Remove(element);
_dbContext.SaveChanges();
}
@@ -141,7 +139,7 @@ public class ClientStorageContract : IClientStorageContract
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}

View File

@@ -1,40 +1,31 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Npgsql;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Mapper;
using SquirrelContract.Resources;
using SquirrelContract.StoragesContracts;
using SquirrelDatabase.Models;
namespace SquirrelDatabase.Implementations;
public class CocktailStorageContract : ICocktailStorageContract
internal class CocktailStorageContract(SquirrelDbContext dbContext, IStringLocalizer<Messages> localizer) : ICocktailStorageContract
{
private readonly SquirrelDbContext _dbContext;
private readonly Mapper _mapper;
public CocktailStorageContract(SquirrelDbContext dbContext)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Cocktail, CocktailDataModel>();
cfg.CreateMap<CocktailDataModel, Cocktail>();
cfg.CreateMap<CocktailHistory, CocktailHistoryDataModel>();
});
_mapper = new Mapper(config);
}
private readonly SquirrelDbContext _dbContext = dbContext;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<CocktailDataModel> GetList()
{
try
{
return [.. _dbContext.Cocktails.Select(x => _mapper.Map<CocktailDataModel>(x))];
return [.. _dbContext.Cocktails.Select(x => CustomMapper.MapObject<CocktailDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -42,12 +33,25 @@ public class CocktailStorageContract : ICocktailStorageContract
{
try
{
return [.. _dbContext.CocktailHistories.Include(x => x.Cocktail).Where(x => x.CocktailId == cocktailId).OrderByDescending(x => x.ChangeDate).Select(x => _mapper.Map<CocktailHistoryDataModel>(x))];
return [.. _dbContext.CocktailHistories.Include(x => x.Cocktail).Where(x => x.CocktailId == cocktailId).OrderByDescending(x => x.ChangeDate).Select(x => CustomMapper.MapObject<CocktailHistoryDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
public async Task<List<CocktailHistoryDataModel>> GetHistoriesListAsync(CancellationToken ct)
{
try
{
return [.. await _dbContext.CocktailHistories.Include(x => x.Cocktail).Select(x => CustomMapper.MapObject<CocktailHistoryDataModel>(x)).ToListAsync(ct)];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
@@ -55,12 +59,12 @@ public class CocktailStorageContract : ICocktailStorageContract
{
try
{
return _mapper.Map<CocktailDataModel>(GetCocktailById(id));
return CustomMapper.MapObjectWithNull<CocktailDataModel>(GetCocktailById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -68,12 +72,12 @@ public class CocktailStorageContract : ICocktailStorageContract
{
try
{
return _mapper.Map<CocktailDataModel>(_dbContext.Cocktails.FirstOrDefault(x => x.CocktailName == name));
return CustomMapper.MapObjectWithNull<CocktailDataModel>(_dbContext.Cocktails.FirstOrDefault(x => x.CocktailName == name));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -81,23 +85,28 @@ public class CocktailStorageContract : ICocktailStorageContract
{
try
{
_dbContext.Cocktails.Add(_mapper.Map<Cocktail>(cocktailDataModel));
_dbContext.Cocktails.Add(CustomMapper.MapObject<Cocktail>(cocktailDataModel));
_dbContext.SaveChanges();
}
catch (InvalidOperationException ex) when (ex.TargetSite?.Name == "ThrowIdentityConflict")
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", cocktailDataModel.Id);
throw new ElementExistsException("Id", cocktailDataModel.Id, _localizer);
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Cocktails_CocktailName" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("CocktailName", cocktailDataModel.CocktailName);
throw new ElementExistsException("CocktailName", cocktailDataModel.CocktailName, _localizer);
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "PK_Cocktails" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", cocktailDataModel.Id, _localizer);
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -108,13 +117,13 @@ public class CocktailStorageContract : ICocktailStorageContract
var transaction = _dbContext.Database.BeginTransaction();
try
{
var element = GetCocktailById(cocktailDataModel.Id) ?? throw new ElementNotFoundException(cocktailDataModel.Id);
var element = GetCocktailById(cocktailDataModel.Id) ?? throw new ElementNotFoundException(cocktailDataModel.Id, _localizer);
if (element.Price != cocktailDataModel.Price)
{
_dbContext.CocktailHistories.Add(new CocktailHistory() { CocktailId = element.Id, OldPrice = element.Price });
_dbContext.SaveChanges();
}
_dbContext.Cocktails.Update(_mapper.Map(cocktailDataModel, element));
_dbContext.Cocktails.Update(CustomMapper.MapObject(cocktailDataModel, element));
_dbContext.SaveChanges();
transaction.Commit();
}
@@ -127,7 +136,7 @@ public class CocktailStorageContract : ICocktailStorageContract
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Cocktails_CocktailName" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("CocktailName", cocktailDataModel.CocktailName);
throw new ElementExistsException("CocktailName", cocktailDataModel.CocktailName, _localizer);
}
catch (Exception ex) when (ex is ElementDeletedException || ex is ElementNotFoundException)
{
@@ -137,7 +146,7 @@ public class CocktailStorageContract : ICocktailStorageContract
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -145,7 +154,7 @@ public class CocktailStorageContract : ICocktailStorageContract
{
try
{
var element = GetCocktailById(id) ?? throw new ElementNotFoundException(id);
var element = GetCocktailById(id) ?? throw new ElementNotFoundException(id, _localizer);
_dbContext.Cocktails.Remove(element);
_dbContext.SaveChanges();
}
@@ -157,7 +166,7 @@ public class CocktailStorageContract : ICocktailStorageContract
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -165,7 +174,7 @@ public class CocktailStorageContract : ICocktailStorageContract
{
try
{
var element = GetCocktailById(id) ?? throw new ElementNotFoundException(id);
var element = GetCocktailById(id) ?? throw new ElementNotFoundException(id, _localizer);
_dbContext.SaveChanges();
}
catch

View File

@@ -1,28 +1,21 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Npgsql;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Mapper;
using SquirrelContract.Resources;
using SquirrelContract.StoragesContracts;
using SquirrelDatabase.Models;
namespace SquirrelDatabase.Implementations;
public class EmployeeStorageContract : IEmployeeStorageContract
internal class EmployeeStorageContract(SquirrelDbContext dbContext, IStringLocalizer<Messages> localizer) : IEmployeeStorageContract
{
private readonly SquirrelDbContext _dbContext;
private readonly Mapper _mapper;
private readonly SquirrelDbContext _dbContext = dbContext;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public EmployeeStorageContract(SquirrelDbContext 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);
}
public List<EmployeeDataModel> GetList(bool onlyActive = true, string? postId = null, DateTime? fromBirthDate = null, DateTime? toBirthDate = null, DateTime? fromEmploymentDate = null, DateTime? toEmploymentDate = null)
{
@@ -45,12 +38,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);
}
}
@@ -58,12 +51,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);
}
}
@@ -71,12 +64,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);
}
}
@@ -84,12 +77,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);
}
}
@@ -97,18 +90,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);
}
}
@@ -116,8 +114,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)
@@ -128,7 +126,7 @@ public class EmployeeStorageContract : IEmployeeStorageContract
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -136,7 +134,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();
}
@@ -148,7 +146,7 @@ public class EmployeeStorageContract : IEmployeeStorageContract
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -163,7 +161,7 @@ public class EmployeeStorageContract : IEmployeeStorageContract
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}

View File

@@ -1,46 +1,31 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Npgsql;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Mapper;
using SquirrelContract.Resources;
using SquirrelContract.StoragesContracts;
using SquirrelDatabase.Models;
namespace SquirrelDatabase.Implementations;
public class PostStorageContract : IPostStorageContract
internal class PostStorageContract(SquirrelDbContext dbContext, IStringLocalizer<Messages> localizer) : IPostStorageContract
{
private readonly SquirrelDbContext _dbContext;
private readonly Mapper _mapper;
public PostStorageContract(SquirrelDbContext 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))
.ForMember(x => x.Configuration, x => x.MapFrom(src =>
src.ConfigurationModel));
});
_mapper = new Mapper(config);
}
private readonly SquirrelDbContext _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);
}
}
@@ -48,12 +33,12 @@ src.ConfigurationModel));
{
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.MapObjectWithNull<PostDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -61,12 +46,12 @@ src.ConfigurationModel));
{
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);
}
}
@@ -74,12 +59,12 @@ src.ConfigurationModel));
{
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);
}
}
@@ -87,23 +72,27 @@ src.ConfigurationModel));
{
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);
}
}
@@ -114,14 +103,18 @@ src.ConfigurationModel));
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);
}
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();
@@ -135,7 +128,7 @@ src.ConfigurationModel));
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)
{
@@ -145,7 +138,7 @@ src.ConfigurationModel));
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -153,7 +146,7 @@ src.ConfigurationModel));
{
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);
@@ -172,7 +165,7 @@ src.ConfigurationModel));
{
try
{
var element = GetPostById(id) ?? throw new ElementNotFoundException(id);
var element = GetPostById(id) ?? throw new ElementNotFoundException(id, _localizer);
element.IsActual = true;
_dbContext.SaveChanges();
}
@@ -183,5 +176,13 @@ src.ConfigurationModel));
}
}
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,30 +1,20 @@
using AutoMapper;
using BarBelochkaContract.DataModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Mapper;
using SquirrelContract.Resources;
using SquirrelContract.StoragesContracts;
using SquirrelDatabase.Models;
namespace SquirrelDatabase.Implementations;
public class SalaryStorageContract : ISalaryStorageContract
internal class SalaryStorageContract(SquirrelDbContext dbContext, IStringLocalizer<Messages> localizer) : ISalaryStorageContract
{
private readonly SquirrelDbContext _dbContext;
private readonly Mapper _mapper;
public SalaryStorageContract(SquirrelDbContext 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 SquirrelDbContext _dbContext = dbContext;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<SalaryDataModel> GetList(DateTime? startDate, DateTime? endDate, string? employeeId = null)
{
@@ -37,12 +27,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);
}
}
@@ -50,13 +56,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,39 +1,19 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.Mapper;
using SquirrelContract.Resources;
using SquirrelContract.StoragesContracts;
using SquirrelDatabase.Models;
using System;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace SquirrelDatabase.Implementations;
public class SaleStorageContract : ISaleStorageContract
internal class SaleStorageContract(SquirrelDbContext dbContext, IStringLocalizer<Messages> localizer) : ISaleStorageContract
{
private readonly SquirrelDbContext _dbContext;
private readonly Mapper _mapper;
public SaleStorageContract(SquirrelDbContext dbContext)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Client, ClientDataModel>();
cfg.CreateMap<Cocktail, CocktailDataModel>();
cfg.CreateMap<Employee, EmployeeDataModel>();
cfg.CreateMap<SaleCocktail, SaleCocktailDataModel>();
cfg.CreateMap<SaleCocktailDataModel, SaleCocktail>()
.ForMember(x => x.Cocktail, x => x.Ignore());
cfg.CreateMap<Sale, SaleDataModel>();
cfg.CreateMap<SaleDataModel, Sale>()
.ForMember(x => x.IsCancel, x => x.MapFrom(src => false))
.ForMember(x => x.SaleCocktails, x => x.MapFrom(src => src.Cocktails))
.ForMember(x => x.Employee, x => x.Ignore())
.ForMember(x => x.Client, x => x.Ignore());
});
_mapper = new Mapper(config);
}
private readonly SquirrelDbContext _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? cocktailId = null)
{
@@ -56,12 +36,33 @@ public class SaleStorageContract : ISaleStorageContract
if (cocktailId != null)
query = query.Where(x => x.SaleCocktails!.Any(y => y.CocktailId == cocktailId));
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.SaleCocktails)!
.ThenInclude(sc => sc.Cocktail)
.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);
}
}
@@ -69,12 +70,13 @@ public class SaleStorageContract : ISaleStorageContract
{
try
{
return _mapper.Map<SaleDataModel>(GetSaleById(id));
var sale = GetSaleById(id);
return sale != null ? CustomMapper.MapObject<SaleDataModel>(sale) : null;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
throw new StorageException(ex, _localizer);
}
}
@@ -82,13 +84,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);
}
}
@@ -96,7 +99,7 @@ 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);
@@ -112,9 +115,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.SaleCocktails = dataModel.Cocktails?
.Select(p => new SaleCocktail
{
CocktailId = p.CocktailId,
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.SaleCocktails)!.ThenInclude(x => x.Cocktail).FirstOrDefault(x => x.Id == id);
}

View File

@@ -1,100 +0,0 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.StoragesContracts;
using SquirrelDatabase.Models;
using System;
namespace SquirrelDatabase.Implementations;
public class SupplyStorageContract : ISupplyStorageContract
{
private readonly SquirrelDbContext _dbContext;
private readonly IMapper _mapper;
public SupplyStorageContract(SquirrelDbContext dbContext)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<SupplyCocktail, SupplyCocktailDataModel>();
cfg.CreateMap<SupplyCocktailDataModel, SupplyCocktail>();
cfg.CreateMap<Supply, SupplyDataModel>();
cfg.CreateMap<SupplyDataModel, Supply>()
.ForMember(x => x.Cocktails, x => x.MapFrom(src => src.Cocktails));
});
_mapper = new Mapper(config);
}
public List<SupplyDataModel> GetList(DateTime? startDate = null, DateTime? endDate = null, string? cocktailId = null)
{
try
{
var query = _dbContext.Supplies.Include(x => x.Cocktails).AsQueryable();
if (startDate.HasValue)
query = query.Where(x => x.SupplyDate >= DateTime.SpecifyKind(startDate ?? DateTime.UtcNow, DateTimeKind.Utc));
if (endDate.HasValue)
query = query.Where(x => x.SupplyDate <= DateTime.SpecifyKind(endDate ?? DateTime.UtcNow, DateTimeKind.Utc));
if (cocktailId is not null)
{
query = query.Where(x => x.Cocktails!.Any(y => y.CocktailId == cocktailId));
}
return [.. query.Select(x => _mapper.Map<SupplyDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public SupplyDataModel GetElementById(string id)
{
try
{
return _mapper.Map<SupplyDataModel>(GetSuppliesById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public void AddElement(SupplyDataModel suppliesDataModel)
{
try
{
_dbContext.Supplies.Add(_mapper.Map<Supply>(suppliesDataModel));
_dbContext.SaveChanges();
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public void UpdateElement(SupplyDataModel suppliesDataModel)
{
try
{
var element = GetSuppliesById(suppliesDataModel.Id) ?? throw new ElementNotFoundException(suppliesDataModel.Id);
_dbContext.Supplies.Update(_mapper.Map(suppliesDataModel, element));
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
private Supply? GetSuppliesById(string id) => _dbContext.Supplies.FirstOrDefault(x => x.Id == id);
}

View File

@@ -1,211 +0,0 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using SquirrelContract.DataModels;
using SquirrelContract.Exceptions;
using SquirrelContract.StoragesContracts;
using SquirrelDatabase.Models;
namespace SquirrelDatabase.Implementations;
public class WarehouseStorageContract : IWarehouseStorageContract
{
private readonly SquirrelDbContext _dbContext;
private readonly Mapper _mapper;
public WarehouseStorageContract(SquirrelDbContext dbContext)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<WarehouseCocktail, WarehouseCocktailDataModel>();
cfg.CreateMap<WarehouseCocktailDataModel, WarehouseCocktail>();
cfg.CreateMap<Warehouse, WarehouseDataModel>();
cfg.CreateMap<WarehouseDataModel, Warehouse>()
.ForMember(x => x.Cocktails, x => x.MapFrom(src => src.Cocktails));
});
_mapper = new Mapper(config);
}
public List<WarehouseDataModel> GetList()
{
try
{
return [.. _dbContext.Warehouses.Select(x => _mapper.Map<WarehouseDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public WarehouseDataModel GetElementById(string id)
{
try
{
return _mapper.Map<WarehouseDataModel>(GetWarehouseById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public WarehouseDataModel GetElementByName(string name)
{
try
{
return _mapper.Map<WarehouseDataModel>(_dbContext.Warehouses.FirstOrDefault(x => x.Name == name));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public void AddElement(WarehouseDataModel warehouseDataModel)
{
try
{
_dbContext.Warehouses.Add(_mapper.Map<Warehouse>(warehouseDataModel));
_dbContext.SaveChanges();
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public void UpdElement(WarehouseDataModel warehouseDataModel)
{
try
{
var element = GetWarehouseById(warehouseDataModel.Id) ?? throw new ElementNotFoundException(warehouseDataModel.Id);
_dbContext.Warehouses.Update(_mapper.Map(warehouseDataModel, 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 = GetWarehouseById(id) ?? throw new ElementNotFoundException(id);
_dbContext.Warehouses.Remove(element);
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public void UpdWarehouseOnSupply(string warehouseId, string cocktailId, int count)
{
using var transaction = _dbContext.Database.BeginTransaction();
try
{
var warehouse = _dbContext.Warehouses
.Include(w => w.Cocktails)
.FirstOrDefault(w => w.Id == warehouseId);
if (warehouse == null)
{
throw new ElementNotFoundException($"Warehouse with id {warehouseId} not found.");
}
var warehouseCocktail = warehouse.Cocktails.FirstOrDefault(c => c.CocktailId == cocktailId);
if (warehouseCocktail != null)
{
warehouseCocktail.Count += count;
}
else
{
warehouse.Cocktails.Add(new WarehouseCocktail
{
WarehouseId = warehouseId,
CocktailId = cocktailId,
Count = count
});
}
_dbContext.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public bool CheckCocktails(SaleDataModel saleDataModel)
{
using var transaction = _dbContext.Database.BeginTransaction();
try
{
foreach (var saleCocktail in saleDataModel.Cocktails)
{
int requiredCount = saleCocktail.Count;
var warehousesWithCocktail = _dbContext.Warehouses.Include(w => w.Cocktails)
.Where(w => w.Cocktails.Any(c => c.CocktailId == saleCocktail.CocktailId && c.Count > 0))
.ToList();
foreach (var warehouse in warehousesWithCocktail)
{
var warehouseCocktail = warehouse.Cocktails
.FirstOrDefault(c => c.CocktailId == saleCocktail.CocktailId);
if (warehouseCocktail == null || warehouseCocktail.Count == 0)
continue;
int toWithdraw = Math.Min(warehouseCocktail.Count, requiredCount);
warehouseCocktail.Count -= toWithdraw;
requiredCount -= toWithdraw;
_dbContext.SaveChanges();
if (requiredCount == 0)
break;
}
if (requiredCount > 0)
{
transaction.Rollback();
return false;
}
}
_dbContext.SaveChanges();
transaction.Commit();
return true;
}
catch (Exception ex)
{
transaction.Rollback();
throw new StorageException(ex);
}
}
private Warehouse? GetWarehouseById(string id) => _dbContext.Warehouses.FirstOrDefault(x => x.Id == id);
}

View File

@@ -1,5 +1,6 @@
using AutoMapper;
using SquirrelContract.DataModels;
using SquirrelContract.Mapper;
using System.ComponentModel.DataAnnotations.Schema;
namespace SquirrelDatabase.Models;
@@ -24,6 +25,7 @@ public class Employee
public DateTime? DateOfDelete { get; set; }
[NotMapped]
[IgnoreMapping]
public Post? Post { get; set; }
[ForeignKey("EmployeeId")]

View File

@@ -2,6 +2,7 @@
using SquirrelContract.DataModels;
using SquirrelContract.Enums;
using SquirrelContract.Infastructure.PostConfigurations;
using SquirrelContract.Mapper;
namespace SquirrelDatabase.Models;
@@ -15,9 +16,12 @@ public class Post
public PostType PostType { get; set; }
[AlternativeName("ConfigurationModel")]
public required PostConfiguration Configuration { get; set; }
[DefaultValue(DefaultValue = true)]
public bool IsActual { get; set; }
[DefaultValue(FuncName = "UtcNow")]
public DateTime ChangeDate { get; set; }
}

View File

@@ -1,5 +1,5 @@
using AutoMapper;
using BarBelochkaContract.DataModels;
using SquirrelContract.Mapper;
namespace SquirrelDatabase.Models;
@@ -11,6 +11,7 @@ public class Salary
public DateTime SalaryDate { get; set; }
[AlternativeName("EmployeeSalary")]
public double EmployeeSalary { get; set; }
public Employee? Employee { get; set; }

View File

@@ -1,14 +0,0 @@
using AutoMapper;
using SquirrelContract.DataModels;
using System.ComponentModel.DataAnnotations.Schema;
namespace SquirrelDatabase.Models;
public class Supply
{
public required string Id { get; set; }
public DateTime SupplyDate { get; set; }
[ForeignKey("SupplyId")]
public List<SupplyCocktail>? Cocktails { get; set; }
}

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