34 Commits

Author SHA1 Message Date
57303c13cd Выполнение требований 7 2025-09-02 22:37:47 +04:00
04cf37e84b Локализация 2025-09-02 21:28:05 +04:00
14700fd8bd Проверка локализуемости 2025-09-02 21:21:02 +04:00
5ed5eeade7 Лок. строки 2025-08-29 23:16:48 +04:00
ba7552972e Лок. даты 2025-08-26 18:14:18 +04:00
d9ffe24510 Лок. числа 2025-08-26 17:40:40 +04:00
d072666372 Правки 2025-08-22 23:36:47 +04:00
874f19bfa3 Лаба 6 2025-08-22 22:06:45 +04:00
82c1778405 Выполнение требований 2025-08-19 14:48:30 +04:00
64c4467919 Изменение зарплаты 2025-08-18 20:24:36 +04:00
7f0916a758 Изменение ранга 2025-08-18 20:23:57 +04:00
6250fe019e Первая миграция 2025-05-05 16:18:19 +04:00
dca7a5752d Реализация Salary 2025-04-24 09:18:01 +04:00
bb6387e6eb Всё работает 2025-04-23 21:06:15 +04:00
a5dbe17292 WebApi 2025-04-08 20:00:32 +04:00
beef5c0232 Правка DataModels 2025-04-08 19:30:51 +04:00
09a0c6759c ViewModel, Adapter, OperationResponse 2025-04-08 19:02:27 +04:00
d992d6e280 Исправления 2025-03-13 11:20:23 +04:00
9ef676657b Тесты контрактов хранилища 2025-03-13 09:44:27 +04:00
9be7a2c78b Мелкие правки 2025-03-13 09:43:09 +04:00
6667a1103b Реализация контрактов хранилища 2025-03-12 18:26:45 +04:00
3a43e7ae89 DbContext 2025-03-12 17:15:26 +04:00
f3559dcddb Проект и модели 2025-03-12 16:54:16 +04:00
1eeb4014f5 Reapply "Реализация бизнесс логики"
This reverts commit 4b6ec2b79d.
2025-03-11 18:03:33 +04:00
4b6ec2b79d Revert "Реализация бизнесс логики"
This reverts commit f92aa70f71.
2025-03-11 17:37:33 +04:00
f92aa70f71 Реализация бизнесс логики 2025-03-11 17:17:30 +04:00
d63585404b Изменения 2 2025-03-11 17:16:24 +04:00
0cdd3c07ef Исправления из-за обновления условий 2025-03-11 16:55:06 +04:00
1ac006185a Тесты бизнесс логики 2025-03-11 15:52:16 +04:00
b43e799cd6 Контракты бизнесс логики 2025-03-11 15:51:59 +04:00
a9557fed86 Исправление названий 2025-03-11 15:50:23 +04:00
bedb4987a3 Исправления 2025-02-26 15:43:39 +04:00
fe53c2a542 Заготовки реализаций 2025-02-26 15:35:44 +04:00
21b006b0fa Контракты 2025-02-26 14:25:15 +04:00
198 changed files with 19036 additions and 372 deletions

View File

@@ -0,0 +1,71 @@
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System.Text.Json;
using TheBlacksmithVakulaContract.BusinessLogicsContracts;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
namespace TheBlacksmithVakulaBusinessLogic.Implementations
{
internal class BilletBusinessLogicContract(IBilletStorageContract billetStorageContract, IStringLocalizer<Messages> localizer,
ILogger logger) : IBilletBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly IBilletStorageContract _billetStorageContract = billetStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<BilletDataModel> GetAllBillets()
{
_logger.LogInformation("GetAllBillets");
return _billetStorageContract.GetList();
}
public BilletDataModel GetBilletByData(string data)
{
_logger.LogInformation("Get element by data: {data}", data);
if (data.IsEmpty())
{
throw new ArgumentNullException(nameof(data));
}
if (data.IsGuid())
{
return _billetStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
}
return _billetStorageContract.GetElementByName(data) ?? _billetStorageContract.GetElementByOldName(data) ??
throw new ElementNotFoundException(data, _localizer);
}
public void InsertBillet(BilletDataModel billetDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(billetDataModel));
ArgumentNullException.ThrowIfNull(billetDataModel);
billetDataModel.Validate(_localizer);
_billetStorageContract.AddElement(billetDataModel);
}
public void UpdateBillet(BilletDataModel billetDataModel)
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(billetDataModel));
ArgumentNullException.ThrowIfNull(billetDataModel);
billetDataModel.Validate(_localizer);
_billetStorageContract.UpdElement(billetDataModel);
}
public void DeleteBillet(string id)
{
_logger.LogInformation("Delete by id: {id}", id);
if (id.IsEmpty())
{
throw new ArgumentNullException(nameof(id));
}
if (!id.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_billetStorageContract.DelElement(id);
}
}
}

View File

@@ -0,0 +1,104 @@
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System.Text.Json;
using TheBlacksmithVakulaContract.BusinessLogicsContracts;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
namespace TheBlacksmithVakulaBusinessLogic.Implementations
{
internal class BlacksmithBusinessLogicContract(IBlacksmithStorageContract blacksmithStorageContract,
IStringLocalizer<Messages> localizer, ILogger logger) : IBlacksmithBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly IBlacksmithStorageContract _blacksmithStorageContract = blacksmithStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<BlacksmithDataModel> GetAllBlacksmiths(bool onlyActive = true)
{
_logger.LogInformation("GetAllBlacksmiths params: {onlyActive}", onlyActive);
return _blacksmithStorageContract.GetList(onlyActive);
}
public List<BlacksmithDataModel> GetAllBlacksmithsByRank(string rankId, bool onlyActive = true)
{
_logger.LogInformation("GetAllBlacksmiths params: {rankId}, {onlyActive},", rankId, onlyActive);
if (rankId.IsEmpty())
{
throw new ArgumentNullException(nameof(rankId));
}
if (!rankId.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "RankId"));
}
return _blacksmithStorageContract.GetList(onlyActive, rankId);
}
public List<BlacksmithDataModel> GetAllBlacksmithsByBirthDate(DateTime fromDate, DateTime toDate, bool onlyActive = true)
{
_logger.LogInformation("GetAllBlacksmiths params: {onlyActive}, {fromDate}, {toDate}", onlyActive, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
return _blacksmithStorageContract.GetList(onlyActive, fromBirthDate: fromDate, toBirthDate: toDate);
}
public List<BlacksmithDataModel> GetAllBlacksmithsByEmploymentDate(DateTime fromDate, DateTime toDate, bool onlyActive = true)
{
_logger.LogInformation("GetAllBlacksmiths params: {onlyActive}, {fromDate}, {toDate}", onlyActive, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
return _blacksmithStorageContract.GetList(onlyActive, fromEmploymentDate: fromDate, toEmploymentDate: toDate);
}
public BlacksmithDataModel GetBlacksmithByData(string data)
{
_logger.LogInformation("Get element by data: {data}", data);
if (data.IsEmpty())
{
throw new ArgumentNullException(nameof(data));
}
if (data.IsGuid())
{
return _blacksmithStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
}
return _blacksmithStorageContract.GetElementByFIO(data) ?? throw new ElementNotFoundException(data, _localizer);
}
public void InsertBlacksmith(BlacksmithDataModel blacksmithDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(blacksmithDataModel));
ArgumentNullException.ThrowIfNull(blacksmithDataModel);
blacksmithDataModel.Validate(_localizer);
_blacksmithStorageContract.AddElement(blacksmithDataModel);
}
public void UpdateBlacksmith(BlacksmithDataModel blacksmithDataModel)
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(blacksmithDataModel));
ArgumentNullException.ThrowIfNull(blacksmithDataModel);
blacksmithDataModel.Validate(_localizer);
_blacksmithStorageContract.UpdElement(blacksmithDataModel);
}
public void DeleteBlacksmith(string id)
{
_logger.LogInformation("Delete by id: {id}", id);
if (id.IsEmpty())
{
throw new ArgumentNullException(nameof(id));
}
if (!id.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_blacksmithStorageContract.DelElement(id);
}
}
}

View File

@@ -0,0 +1,75 @@
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System.Text.Json;
using System.Text.RegularExpressions;
using TheBlacksmithVakulaContract.BusinessLogicsContracts;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
namespace TheBlacksmithVakulaBusinessLogic.Implementations
{
internal class BuyerBusinessLogicContract(IBuyerStorageContract buyerStorageContract, IStringLocalizer<Messages> localizer,
ILogger logger) : IBuyerBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly IBuyerStorageContract _buyerStorageContract = buyerStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<BuyerDataModel> GetAllBuyers()
{
_logger.LogInformation("GetAllBuyers");
return _buyerStorageContract.GetList();
}
public BuyerDataModel GetBuyerByData(string data)
{
_logger.LogInformation("Get element by data: {data}", data);
if (data.IsEmpty())
{
throw new ArgumentNullException(nameof(data));
}
if (data.IsGuid())
{
return _buyerStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
}
if (Regex.IsMatch(data, @"^((8|\+7)[\- ]?)?(\(?\d{3}\)?[\- ]?)?[\d\- ]{7,10}$"))
{
return _buyerStorageContract.GetElementByPhoneNumber(data) ?? throw new ElementNotFoundException(data, _localizer);
}
return _buyerStorageContract.GetElementByFIO(data) ?? throw new ElementNotFoundException(data, _localizer);
}
public void InsertBuyer(BuyerDataModel buyerDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(buyerDataModel));
ArgumentNullException.ThrowIfNull(buyerDataModel);
buyerDataModel.Validate(_localizer);
_buyerStorageContract.AddElement(buyerDataModel);
}
public void UpdateBuyer(BuyerDataModel buyerDataModel)
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(buyerDataModel));
ArgumentNullException.ThrowIfNull(buyerDataModel);
buyerDataModel.Validate(_localizer);
_buyerStorageContract.UpdElement(buyerDataModel);
}
public void DeleteBuyer(string id)
{
_logger.LogInformation("Delete by id: {id}", id);
if (id.IsEmpty())
{
throw new ArgumentNullException(nameof(id));
}
if (!id.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_buyerStorageContract.DelElement(id);
}
}
}

View File

@@ -0,0 +1,120 @@
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System.Text.Json;
using TheBlacksmithVakulaContract.BusinessLogicsContracts;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
namespace TheBlacksmithVakulaBusinessLogic.Implementations
{
internal class OrderBusinessLogicContract(IOrderStorageContract orderStorageContract, IStringLocalizer<Messages> localizer,
ILogger logger) : IOrderBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly IOrderStorageContract _orderStorageContract = orderStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<OrderDataModel> GetAllOrdersByPeriod(DateTime fromDate, DateTime toDate)
{
_logger.LogInformation("GetAllOrders params: {fromDate}, {toDate}", fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
return _orderStorageContract.GetList(fromDate, toDate);
}
public List<OrderDataModel> GetAllOrdersByBlacksmithByPeriod(string blacksmithId, DateTime fromDate, DateTime toDate)
{
_logger.LogInformation("GetAllOrders params: {blacksmithId}, {fromDate}, {toDate}", blacksmithId, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
if (blacksmithId.IsEmpty())
{
throw new ArgumentNullException(nameof(blacksmithId));
}
if (!blacksmithId.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "BlacksmithId"));
}
return _orderStorageContract.GetList(fromDate, toDate, blacksmithId: blacksmithId);
}
public List<OrderDataModel> GetAllOrdersByBuyerByPeriod(string buyerId, DateTime fromDate, DateTime toDate)
{
_logger.LogInformation("GetAllOrders params: {buyerId}, {fromDate}, {toDate}", buyerId, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
if (buyerId.IsEmpty())
{
throw new ArgumentNullException(nameof(buyerId));
}
if (!buyerId.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "BuyerId"));
}
return _orderStorageContract.GetList(fromDate, toDate, buyerId: buyerId);
}
public List<OrderDataModel> GetAllOrdersByProductByPeriod(string productId, DateTime fromDate, DateTime toDate)
{
_logger.LogInformation("GetAllOrders params: {productId}, {fromDate}, {toDate}", productId, fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
if (productId.IsEmpty())
{
throw new ArgumentNullException(nameof(productId));
}
if (!productId.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "ProductId"));
}
return _orderStorageContract.GetList(fromDate, toDate, productId: productId);
}
public OrderDataModel GetOrderByData(string data)
{
_logger.LogInformation("Get element by data: {data}", data);
if (data.IsEmpty())
{
throw new ArgumentNullException(nameof(data));
}
if (!data.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
return _orderStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
}
public void InsertOrder(OrderDataModel orderDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(orderDataModel));
ArgumentNullException.ThrowIfNull(orderDataModel);
orderDataModel.Validate(_localizer);
_orderStorageContract.AddElement(orderDataModel);
}
public void CancelOrder(string id)
{
_logger.LogInformation("Cancel by id: {id}", id);
if (id.IsEmpty())
{
throw new ArgumentNullException(nameof(id));
}
if (!id.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_orderStorageContract.DelElement(id);
}
}
}

View File

@@ -0,0 +1,98 @@
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System.Text.Json;
using TheBlacksmithVakulaContract.BusinessLogicsContracts;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
namespace TheBlacksmithVakulaBusinessLogic.Implementations
{
internal class ProductBusinessLogicContract(IProductStorageContract productStorageContract, IStringLocalizer<Messages> localizer,
ILogger logger) : IProductBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly IProductStorageContract _productStorageContract = productStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<ProductDataModel> GetAllProducts(bool onlyActive)
{
_logger.LogInformation("GetAllProducts params: {onlyActive}", onlyActive);
return _productStorageContract.GetList(onlyActive);
}
public List<ProductDataModel> GetAllProductsByBillet(string billetId, bool onlyActive = true)
{
if (billetId.IsEmpty())
{
throw new ArgumentNullException(nameof(billetId));
}
if (!billetId.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "BilletId"));
}
_logger.LogInformation("GetAllProducts params: {billetId}, {onlyActive}", billetId, onlyActive);
return _productStorageContract.GetList(onlyActive, billetId);
}
public List<ProductHistoryDataModel> GetProductHistoryByProduct(string productId)
{
_logger.LogInformation("GetProductHistoryByProduct for {productId}", productId);
if (productId.IsEmpty())
{
throw new ArgumentNullException(nameof(productId));
}
if (!productId.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "ProductId"));
}
return _productStorageContract.GetHistoryByProductId(productId);
}
public ProductDataModel GetProductByData(string data)
{
_logger.LogInformation("Get element by data: {data}", data);
if (data.IsEmpty())
{
throw new ArgumentNullException(nameof(data));
}
if (data.IsGuid())
{
return _productStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
}
return _productStorageContract.GetElementByName(data) ?? throw new ElementNotFoundException(data, _localizer);
}
public void InsertProduct(ProductDataModel productDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(productDataModel));
ArgumentNullException.ThrowIfNull(productDataModel);
productDataModel.Validate(_localizer);
_productStorageContract.AddElement(productDataModel);
}
public void UpdateProduct(ProductDataModel productDataModel)
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(productDataModel));
ArgumentNullException.ThrowIfNull(productDataModel);
productDataModel.Validate(_localizer);
_productStorageContract.UpdElement(productDataModel);
}
public void DeleteProduct(string id)
{
_logger.LogInformation("Delete by id: {id}", id);
if (id.IsEmpty())
{
throw new ArgumentNullException(nameof(id));
}
if (!id.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_productStorageContract.DelElement(id);
}
}
}

View File

@@ -0,0 +1,98 @@
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System.Text.Json;
using TheBlacksmithVakulaContract.BusinessLogicsContracts;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
namespace TheBlacksmithVakulaBusinessLogic.Implementations
{
internal class RankBusinessLogicContract(IRankStorageContract rankStorageContract, IStringLocalizer<Messages> localizer,
ILogger logger) : IRankBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly IRankStorageContract _rankStorageContract = rankStorageContract;
private readonly IStringLocalizer<Messages> _localizer = localizer;
public List<RankDataModel> GetAllRanks()
{
_logger.LogInformation("GetAllRanks");
return _rankStorageContract.GetList();
}
public List<RankDataModel> GetAllDataOfRank(string rankId)
{
_logger.LogInformation("GetAllDataOfRank for {rankId}", rankId);
if (rankId.IsEmpty())
{
throw new ArgumentNullException(nameof(rankId));
}
if (!rankId.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "RankId"));
}
return _rankStorageContract.GetRankWithHistory(rankId);
}
public RankDataModel GetRankByData(string data)
{
_logger.LogInformation("Get element by data: {data}", data);
if (data.IsEmpty())
{
throw new ArgumentNullException(nameof(data));
}
if (data.IsGuid())
{
return _rankStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
}
return _rankStorageContract.GetElementByName(data) ?? throw new ElementNotFoundException(data, _localizer);
}
public void InsertRank(RankDataModel rankDataModel)
{
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(rankDataModel));
ArgumentNullException.ThrowIfNull(rankDataModel);
rankDataModel.Validate(_localizer);
_rankStorageContract.AddElement(rankDataModel);
}
public void UpdateRank(RankDataModel rankDataModel)
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(rankDataModel));
ArgumentNullException.ThrowIfNull(rankDataModel);
rankDataModel.Validate(_localizer);
_rankStorageContract.UpdElement(rankDataModel);
}
public void DeleteRank(string id)
{
_logger.LogInformation("Delete by id: {id}", id);
if (id.IsEmpty())
{
throw new ArgumentNullException(nameof(id));
}
if (!id.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_rankStorageContract.DelElement(id);
}
public void RestoreRank(string id)
{
_logger.LogInformation("Restore by id: {id}", id);
if (id.IsEmpty())
{
throw new ArgumentNullException(nameof(id));
}
if (!id.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
}
_rankStorageContract.ResElement(id);
}
}
}

View File

@@ -0,0 +1,122 @@
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using TheBlacksmithVakulaBusinessLogic.OfficePackage;
using TheBlacksmithVakulaContract.BusinessLogicsContracts;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
namespace TheBlacksmithVakulaBusinessLogic.Implementations
{
internal class ReportContract : IReportContract
{
private readonly IProductStorageContract _productStorageContract;
private readonly IOrderStorageContract _orderStorageContract;
private readonly ISalaryStorageContract _salaryStorageContract;
private readonly BaseWordBuilder _baseWordBuilder;
private readonly BaseExcelBuilder _baseExcelBuilder;
private readonly BasePdfBuilder _basePdfBuilder;
private readonly IStringLocalizer<Messages> _localizer;
private readonly ILogger _logger;
internal readonly string[] _documentHeader;
internal readonly string[] _tableHeader;
public ReportContract(IProductStorageContract productStorageContract, IOrderStorageContract orderStorageContract,
ISalaryStorageContract salaryStorageContract, BaseWordBuilder baseWordBuilder, BaseExcelBuilder baseExcelBuilder,
BasePdfBuilder basePdfBuilder, IStringLocalizer<Messages> localizer, ILogger logger)
{
_productStorageContract = productStorageContract;
_orderStorageContract = orderStorageContract;
_salaryStorageContract = salaryStorageContract;
_baseWordBuilder = baseWordBuilder;
_baseExcelBuilder = baseExcelBuilder;
_basePdfBuilder = basePdfBuilder;
_localizer = localizer;
_logger = logger;
_documentHeader = [_localizer["DocumentDocCaptionBillet"], _localizer["DocumentDocCaptionProduct"]];
_tableHeader = [_localizer["DocumentExcelCaptionDate"], _localizer["DocumentExcelCaptionSum"],
_localizer["DocumentExcelCaptionDiscount"], _localizer["DocumentExcelCaptionProduct"], _localizer["DocumentExcelCaptionCount"]];
}
public async Task<Stream> CreateDocumentProductsByBilletAsync(CancellationToken ct)
{
_logger.LogInformation("Create report ProductsByBillet");
var data = await GetDataByProductsAsync(ct);
return _baseWordBuilder
.AddHeader(_localizer["DocumentDocHeader"])
.AddParagraph(string.Format(_localizer["DocumentDocSubHeader"], DateTime.Now))
.AddTable([3000, 5000], [.. new List<string[]>() { _documentHeader }.Union([.. data.SelectMany(x => (new List<string[]>() { new string[] { x.BilletName, "" } }).Union(x.Products.Select(y => new string[] { "", y })))])])
.Build();
}
public async Task<Stream> CreateDocumentOrdersByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
{
_logger.LogInformation("Create report OrdersByPeriod from {dateStart} to {dateFinish}", dateStart, dateFinish);
var data = await GetDataByOrdersAsync(dateStart, dateFinish, ct) ?? throw new InvalidOperationException("No found data");
return _baseExcelBuilder
.AddHeader(_localizer["DocumentExcelHeader"], 0, 5)
.AddParagraph(string.Format(_localizer["DocumentExcelSubHeader"], dateStart.ToLocalTime().ToShortDateString(), dateFinish.ToLocalTime().ToShortDateString()), 2)
.AddTable([10, 10, 10, 10, 10], [.. new List<string[]>() { _tableHeader }.Union(data.SelectMany(x => (new List<string[]>() { new string[] { x.OrderDate.ToShortDateString(), x.Sum.ToString("N2"), x.Discount.ToString("N2"), "", "" } }).Union(x.Products!.Select(y => new string[] { "", "", "", y.ProductName, y.Count.ToString("N2") })).ToArray())).Union([["Всего", data.Sum(x => x.Sum).ToString("N2"), data.Sum(x => x.Discount).ToString("N2"), "", ""]])])
.Build();
}
public async Task<Stream> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
{
_logger.LogInformation("Create report SalaryByPeriod from {dateStart} to {dateFinish}", dateStart, dateFinish);
var data = await GetDataBySalaryAsync(dateStart, dateFinish, ct) ?? throw new InvalidOperationException("No found data");
return _basePdfBuilder
.AddHeader(_localizer["DocumentPdfHeader"])
.AddParagraph(string.Format(_localizer["DocumentPdfSubHeader"], dateStart.ToLocalTime().ToShortDateString(), dateFinish.ToLocalTime().ToShortDateString()))
.AddPieChart("Начисления", [.. data.Select(x => (x.BlacksmithFIO, x.TotalSalary))])
.Build();
}
public Task<List<BilletProductDataModel>> GetDataProductsByBilletAsync(CancellationToken ct)
{
_logger.LogInformation("Get data ProductsByBillet");
return GetDataByProductsAsync(ct);
}
public Task<List<OrderDataModel>> GetDataOrderByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
{
_logger.LogInformation("Get data OrdersByPeriod from {dateStart} to {dateFinish}", dateStart, dateFinish);
return GetDataByOrdersAsync(dateStart, dateFinish, ct);
}
public Task<List<BlacksmithSalaryByPeriodDataModel>> 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<BilletProductDataModel>> GetDataByProductsAsync(CancellationToken ct) => [.. (await _productStorageContract.GetListAsync(ct)).GroupBy(x => x.BilletName).Select(x => new BilletProductDataModel { BilletName = x.Key, Products = [.. x.Select(y => y.ProductName)] })];
private async Task<List<OrderDataModel>> GetDataByOrdersAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
{
if (dateStart.IsDateNotOlder(dateFinish))
{
throw new IncorrectDatesException(dateStart, dateFinish, _localizer);
}
return [.. (await _orderStorageContract.GetListAsync(dateStart, dateFinish, ct)).OrderBy(x => x.OrderDate)];
}
private async Task<List<BlacksmithSalaryByPeriodDataModel>> 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.BlacksmithId).Select(x => new BlacksmithSalaryByPeriodDataModel { BlacksmithFIO = x.Key, TotalSalary = x.Sum(y => y.Salary), FromPeriod = x.Min(y => y.SalaryDate), ToPeriod = x.Max(y => y.SalaryDate) }).OrderBy(x => x.BlacksmithFIO)];
}
}
}

View File

@@ -0,0 +1,127 @@
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using TheBlacksmithVakulaContract.BusinessLogicsContracts;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.Infrastructure.RankConfigurations;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
namespace TheBlacksmithVakulaBusinessLogic.Implementations
{
internal class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageContract, IOrderStorageContract orderStorageContract,
IRankStorageContract rankStorageContract, IBlacksmithStorageContract blacksmithStorageContract,
IStringLocalizer<Messages> localizer, ILogger logger, IConfigurationSalary сonfiguration) : ISalaryBusinessLogicContract
{
private readonly ILogger _logger = logger;
private readonly ISalaryStorageContract _salaryStorageContract = salaryStorageContract;
private readonly IOrderStorageContract _orderStorageContract = orderStorageContract;
private readonly IRankStorageContract _rankStorageContract = rankStorageContract;
private readonly IBlacksmithStorageContract _blacksmithStorageContract = blacksmithStorageContract;
private readonly IConfigurationSalary _salaryConfiguration = сonfiguration;
private readonly IStringLocalizer<Messages> _localizer = localizer;
private readonly Lock _lockObject = new();
public List<SalaryDataModel> GetAllSalariesByPeriod(DateTime fromDate, DateTime toDate)
{
_logger.LogInformation("GetAllSalaries params: {fromDate}, {toDate}", fromDate, toDate);
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
return _salaryStorageContract.GetList(fromDate, toDate);
}
public List<SalaryDataModel> GetAllSalariesByPeriodByBlacksmith(DateTime fromDate, DateTime toDate, string blacksmithId)
{
if (fromDate.IsDateNotOlder(toDate))
{
throw new IncorrectDatesException(fromDate, toDate, _localizer);
}
if (blacksmithId.IsEmpty())
{
throw new ArgumentNullException(nameof(blacksmithId));
}
if (!blacksmithId.IsGuid())
{
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "BlacksmithId"));
}
_logger.LogInformation("GetAllSalaries params: {fromDate}, {toDate}, {blacksmithId}", fromDate, toDate, blacksmithId);
return _salaryStorageContract.GetList(fromDate, toDate, blacksmithId);
}
public void CalculateSalaryByMounth(DateTime date)
{
_logger.LogInformation("CalculateSalaryByMounth: {date}", date);
var startDate = new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
var finishDate = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month), date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
var blacksmiths = _blacksmithStorageContract.GetList();
foreach (var blacksmith in blacksmiths)
{
var orders = _orderStorageContract.GetList(startDate, finishDate, blacksmithId: blacksmith.Id);
var rank = _rankStorageContract.GetElementById(blacksmith.RankId) ?? throw new ElementNotFoundException(blacksmith.RankId, _localizer);
var salary = rank.ConfigurationModel switch
{
null => 0,
StudentRankConfiguration cpc => CalculateSalaryForStudent(orders, startDate, finishDate, cpc),
ExpertRankConfiguration spc => CalculateSalaryForExpert(startDate, finishDate, spc),
RankConfiguration pc => pc.Rate,
};
_logger.LogDebug("The employee {blacksmithId} was paid a salary of {salary}", blacksmith.Id, salary);
_salaryStorageContract.AddElement(new SalaryDataModel(blacksmith.Id, finishDate, salary));
}
}
private double CalculateSalaryForStudent(List<OrderDataModel> orders, DateTime startDate, DateTime finishDate, StudentRankConfiguration config)
{
double calcPercent = 0.0;
object lockObj = new();
var parallelOptions = new ParallelOptions
{
MaxDegreeOfParallelism = _salaryConfiguration.MaxCountThreads
};
var days = Enumerable.Range(0, (finishDate - startDate).Days)
.Select(offset => startDate.AddDays(offset))
.ToList();
Parallel.ForEach(days, parallelOptions, date =>
{
var ordersInDay = orders
.Where(x => x.OrderDate >= date && x.OrderDate < date.AddDays(1))
.ToArray();
if (ordersInDay.Length > 0)
{
double dayPercent = (ordersInDay.Sum(x => x.Sum) / ordersInDay.Length) * config.OrderPercent;
lock (lockObj)
{
calcPercent += dayPercent;
}
}
});
double bonus = orders
.Where(x => x.Sum > _salaryConfiguration.ExtraOrderSum)
.Sum(x => x.Sum) * config.BonusForExtraOrders;
return config.Rate + calcPercent + bonus;
}
private double CalculateSalaryForExpert(DateTime startDate, DateTime finishDate, ExpertRankConfiguration config)
{
try
{
return config.Rate + config.PersonalCountTrendPremium * _blacksmithStorageContract.GetBlacksmithTrend(startDate, finishDate);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in the expert payroll process");
return 0;
}
}
}
}

View File

@@ -0,0 +1,13 @@
namespace TheBlacksmithVakulaBusinessLogic.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,13 @@
namespace TheBlacksmithVakulaBusinessLogic.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,13 @@
namespace TheBlacksmithVakulaBusinessLogic.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,86 @@
using MigraDoc.DocumentObjectModel;
using MigraDoc.DocumentObjectModel.Shapes.Charts;
using MigraDoc.Rendering;
using System.Text;
namespace TheBlacksmithVakulaBusinessLogic.OfficePackage
{
internal 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,304 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
namespace TheBlacksmithVakulaBusinessLogic.OfficePackage
{
internal 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,95 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace TheBlacksmithVakulaBusinessLogic.OfficePackage
{
internal 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

@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="TheBlacksmithVakulaTests" />
<InternalsVisibleTo Include="TheBlacksmithVakulaWebApi" />
<InternalsVisibleTo Include="DinamicProxyGenAssembly2" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
<PackageReference Include="DocumentFormat.OpenXml.Framework" Version="3.3.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.8" />
<PackageReference Include="PdfSharp.MigraDoc.Standard" Version="1.51.15" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TheBlacksmithVakulaContract\TheBlacksmithVakulaContract.csproj" />
</ItemGroup>
</Project>

View File

@@ -7,6 +7,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheBlacksmithVakulaContract
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheBlacksmithVakulaTests", "TheBlacksmithVakulaTests\TheBlacksmithVakulaTests.csproj", "{E713C757-C913-43D7-AC6C-F146E676EECF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheBlacksmithVakulaBusinessLogic", "TheBlacksmithVakulaBuisnessLogic\TheBlacksmithVakulaBusinessLogic.csproj", "{4EC98B18-0ED9-42F1-940F-3D620727D34E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheBlacksmithVakulaDatabase", "TheBlacksmithVakulaDatabase\TheBlacksmithVakulaDatabase.csproj", "{A68C4088-F1BD-47E6-8E14-8BCA8AE86B52}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheBlacksmithVakulaWebApi", "TheBlacksmithVakulaWebApi\TheBlacksmithVakulaWebApi.csproj", "{19350294-4EF7-4476-9418-A119EF83CDE4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,8 +27,23 @@ Global
{E713C757-C913-43D7-AC6C-F146E676EECF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E713C757-C913-43D7-AC6C-F146E676EECF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E713C757-C913-43D7-AC6C-F146E676EECF}.Release|Any CPU.Build.0 = Release|Any CPU
{4EC98B18-0ED9-42F1-940F-3D620727D34E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EC98B18-0ED9-42F1-940F-3D620727D34E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EC98B18-0ED9-42F1-940F-3D620727D34E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EC98B18-0ED9-42F1-940F-3D620727D34E}.Release|Any CPU.Build.0 = Release|Any CPU
{A68C4088-F1BD-47E6-8E14-8BCA8AE86B52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A68C4088-F1BD-47E6-8E14-8BCA8AE86B52}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A68C4088-F1BD-47E6-8E14-8BCA8AE86B52}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A68C4088-F1BD-47E6-8E14-8BCA8AE86B52}.Release|Any CPU.Build.0 = Release|Any CPU
{19350294-4EF7-4476-9418-A119EF83CDE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{19350294-4EF7-4476-9418-A119EF83CDE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19350294-4EF7-4476-9418-A119EF83CDE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19350294-4EF7-4476-9418-A119EF83CDE4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D78097F2-2881-49D7-A49C-DFD5B169283B}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,18 @@
using TheBlacksmithVakulaContract.AdapterContracts.OperationResponses;
using TheBlacksmithVakulaContract.BindingModels;
namespace TheBlacksmithVakulaContract.AdapterContracts
{
public interface IBilletAdapter
{
BilletOperationResponse GetList();
BilletOperationResponse GetElement(string data);
BilletOperationResponse RegisterBillet(BilletBindingModel billetModel);
BilletOperationResponse ChangeBilletInfo(BilletBindingModel billetModel);
BilletOperationResponse RemoveBillet(string id);
}
}

View File

@@ -0,0 +1,24 @@
using TheBlacksmithVakulaContract.AdapterContracts.OperationResponses;
using TheBlacksmithVakulaContract.BindingModels;
namespace TheBlacksmithVakulaContract.AdapterContracts
{
public interface IBlacksmithAdapter
{
BlacksmithOperationResponse GetList(bool includeDeleted);
BlacksmithOperationResponse GetRankList(string id, bool includeDeleted);
BlacksmithOperationResponse GetListByBirthDate(DateTime fromDate, DateTime toDate, bool includeDeleted);
BlacksmithOperationResponse GetListByEmploymentDate(DateTime fromDate, DateTime toDate, bool includeDeleted);
BlacksmithOperationResponse GetElement(string data);
BlacksmithOperationResponse RegisterBlacksmith(BlacksmithBindingModel blacksmithModel);
BlacksmithOperationResponse ChangeBlacksmithInfo(BlacksmithBindingModel blacksmithModel);
BlacksmithOperationResponse RemoveBlacksmith(string id);
}
}

View File

@@ -0,0 +1,18 @@
using TheBlacksmithVakulaContract.AdapterContracts.OperationResponses;
using TheBlacksmithVakulaContract.BindingModels;
namespace TheBlacksmithVakulaContract.AdapterContracts
{
public interface IBuyerAdapter
{
BuyerOperationResponse GetList();
BuyerOperationResponse GetElement(string data);
BuyerOperationResponse RegisterBuyer(BuyerBindingModel buyerModel);
BuyerOperationResponse ChangeBuyerInfo(BuyerBindingModel buyerModel);
BuyerOperationResponse RemoveBuyer(string id);
}
}

View File

@@ -0,0 +1,22 @@
using TheBlacksmithVakulaContract.AdapterContracts.OperationResponses;
using TheBlacksmithVakulaContract.BindingModels;
namespace TheBlacksmithVakulaContract.AdapterContracts
{
public interface IOrderAdapter
{
OrderOperationResponse GetList(DateTime fromDate, DateTime toDate);
OrderOperationResponse GetBlacksmithList(string id, DateTime fromDate, DateTime toDate);
OrderOperationResponse GetBuyerList(string id, DateTime fromDate, DateTime toDate);
OrderOperationResponse GetProductList(string id, DateTime fromDate, DateTime toDate);
OrderOperationResponse GetElement(string id);
OrderOperationResponse MakeOrder(OrderBindingModel orderModel);
OrderOperationResponse CancelOrder(string id);
}
}

View File

@@ -0,0 +1,22 @@
using TheBlacksmithVakulaContract.AdapterContracts.OperationResponses;
using TheBlacksmithVakulaContract.BindingModels;
namespace TheBlacksmithVakulaContract.AdapterContracts
{
public interface IProductAdapter
{
ProductOperationResponse GetList(bool includeDeleted);
ProductOperationResponse GetBilletList(string id, bool includeDeleted);
ProductOperationResponse GetHistory(string id);
ProductOperationResponse GetElement(string data);
ProductOperationResponse RegisterProduct(ProductBindingModel productModel);
ProductOperationResponse ChangeProductInfo(ProductBindingModel productModel);
ProductOperationResponse RemoveProduct(string id);
}
}

View File

@@ -0,0 +1,22 @@
using TheBlacksmithVakulaContract.AdapterContracts.OperationResponses;
using TheBlacksmithVakulaContract.BindingModels;
namespace TheBlacksmithVakulaContract.AdapterContracts
{
public interface IRankAdapter
{
RankOperationResponse GetList();
RankOperationResponse GetHistory(string id);
RankOperationResponse GetElement(string data);
RankOperationResponse RegisterRank(RankBindingModel rankModel);
RankOperationResponse ChangeRankInfo(RankBindingModel rankModel);
RankOperationResponse RemoveRank(string id);
RankOperationResponse RestoreRank(string id);
}
}

View File

@@ -0,0 +1,19 @@
using TheBlacksmithVakulaContract.AdapterContracts.OperationResponses;
namespace TheBlacksmithVakulaContract.AdapterContracts
{
public interface IReportAdapter
{
Task<ReportOperationResponse> GetDataProductsByBilletAsync(CancellationToken ct);
Task<ReportOperationResponse> GetDataOrderByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<ReportOperationResponse> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<ReportOperationResponse> CreateDocumentProductsByBilletAsync(CancellationToken ct);
Task<ReportOperationResponse> CreateDocumentOrdersByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<ReportOperationResponse> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
}
}

View File

@@ -0,0 +1,13 @@
using TheBlacksmithVakulaContract.AdapterContracts.OperationResponses;
namespace TheBlacksmithVakulaContract.AdapterContracts
{
public interface ISalaryAdapter
{
SalaryOperationResponse GetListByPeriod(DateTime fromDate, DateTime toDate);
SalaryOperationResponse GetListByPeriodByBlacksmith(DateTime fromDate, DateTime toDate, string blacksmithId);
SalaryOperationResponse CalculateSalary(DateTime date);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,22 @@
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.ViewModels;
namespace TheBlacksmithVakulaContract.AdapterContracts.OperationResponses
{
public class ProductOperationResponse : OperationResponse
{
public static ProductOperationResponse OK(List<ProductViewModel> data) => OK<ProductOperationResponse, List<ProductViewModel>>(data);
public static ProductOperationResponse OK(List<ProductHistoryViewModel> data) => OK<ProductOperationResponse, List<ProductHistoryViewModel>>(data);
public static ProductOperationResponse OK(ProductViewModel data) => OK<ProductOperationResponse, ProductViewModel>(data);
public static ProductOperationResponse NoContent() => NoContent<ProductOperationResponse>();
public static ProductOperationResponse NotFound(string message) => NotFound<ProductOperationResponse>(message);
public static ProductOperationResponse BadRequest(string message) => BadRequest<ProductOperationResponse>(message);
public static ProductOperationResponse InternalServerError(string message) => InternalServerError<ProductOperationResponse>(message);
}
}

View File

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

View File

@@ -0,0 +1,20 @@
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.ViewModels;
namespace TheBlacksmithVakulaContract.AdapterContracts.OperationResponses
{
public class ReportOperationResponse : OperationResponse
{
public static ReportOperationResponse OK(List<BilletProductViewModel> data) => OK<ReportOperationResponse, List<BilletProductViewModel>>(data);
public static ReportOperationResponse OK(List<OrderViewModel> data) => OK<ReportOperationResponse, List<OrderViewModel>>(data);
public static ReportOperationResponse OK(List<BlacksmithSalaryByPeriodViewModel> data) => OK<ReportOperationResponse, List<BlacksmithSalaryByPeriodViewModel>>(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

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

View File

@@ -0,0 +1,9 @@
namespace TheBlacksmithVakulaContract.BindingModels
{
public class BilletBindingModel
{
public string? Id { get; set; }
public string? BilletName { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
namespace TheBlacksmithVakulaContract.BindingModels
{
public class BlacksmithBindingModel
{
public string? Id { get; set; }
public string? FIO { get; set; }
public string? RankId { get; set; }
public DateTime BirthDate { get; set; }
public DateTime EmploymentDate { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
namespace TheBlacksmithVakulaContract.BindingModels
{
public class BuyerBindingModel
{
public string? Id { get; set; }
public string? FIO { get; set; }
public string? PhoneNumber { get; set; }
public double DiscountSize { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
namespace TheBlacksmithVakulaContract.BindingModels
{
public class OrderBindingModel
{
public string? Id { get; set; }
public string? BlacksmithId { get; set; }
public string? BuyerId { get; set; }
public int DiscountType { get; set; }
public List<OrderProductBindingModel>? Products { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
namespace TheBlacksmithVakulaContract.BindingModels
{
public class OrderProductBindingModel
{
public string? OrderId { get; set; }
public string? ProductId { get; set; }
public int Count { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
namespace TheBlacksmithVakulaContract.BindingModels
{
public class ProductBindingModel
{
public string? Id { get; set; }
public string? ProductName { get; set; }
public string? ProductType { get; set; }
public string? BilletId { get; set; }
public double Price { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
namespace TheBlacksmithVakulaContract.BindingModels
{
public class RankBindingModel
{
public string? Id { get; set; }
public string? RankId => Id;
public string? RankName { get; set; }
public string? RankType { get; set; }
public string? ConfigurationJson { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.BusinessLogicsContracts
{
public interface IBilletBusinessLogicContract
{
List<BilletDataModel> GetAllBillets();
BilletDataModel GetBilletByData(string data);
void InsertBillet(BilletDataModel billetDataModel);
void UpdateBillet(BilletDataModel billetDataModel);
void DeleteBillet(string id);
}
}

View File

@@ -0,0 +1,23 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.BusinessLogicsContracts
{
public interface IBlacksmithBusinessLogicContract
{
List<BlacksmithDataModel> GetAllBlacksmiths(bool onlyActive = true);
List<BlacksmithDataModel> GetAllBlacksmithsByRank(string rankId, bool onlyActive = true);
List<BlacksmithDataModel> GetAllBlacksmithsByBirthDate(DateTime fromDate, DateTime toDate, bool onlyActive = true);
List<BlacksmithDataModel> GetAllBlacksmithsByEmploymentDate(DateTime fromDate, DateTime toDate, bool onlyActive = true);
BlacksmithDataModel GetBlacksmithByData(string data);
void InsertBlacksmith(BlacksmithDataModel blacksmithDataModel);
void UpdateBlacksmith(BlacksmithDataModel blacksmithDataModel);
void DeleteBlacksmith(string id);
}
}

View File

@@ -0,0 +1,17 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.BusinessLogicsContracts
{
public interface IBuyerBusinessLogicContract
{
List<BuyerDataModel> GetAllBuyers();
BuyerDataModel GetBuyerByData(string data);
void InsertBuyer(BuyerDataModel buyerDataModel);
void UpdateBuyer(BuyerDataModel buyerDataModel);
void DeleteBuyer(string id);
}
}

View File

@@ -0,0 +1,21 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.BusinessLogicsContracts
{
public interface IOrderBusinessLogicContract
{
List<OrderDataModel> GetAllOrdersByPeriod(DateTime startDate, DateTime endDate);
List<OrderDataModel> GetAllOrdersByBlacksmithByPeriod(string blacksmithId, DateTime startDate, DateTime endDate);
List<OrderDataModel> GetAllOrdersByBuyerByPeriod(string buyerId, DateTime startDate, DateTime endDate);
List<OrderDataModel> GetAllOrdersByProductByPeriod(string productId, DateTime startDate, DateTime endDate);
OrderDataModel GetOrderByData(string data);
void InsertOrder(OrderDataModel orderDataModel);
void CancelOrder(string id);
}
}

View File

@@ -0,0 +1,21 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.BusinessLogicsContracts
{
public interface IProductBusinessLogicContract
{
List<ProductDataModel> GetAllProducts(bool onlyActive = true);
List<ProductDataModel> GetAllProductsByBillet(string billetId, bool onlyActive = true);
List<ProductHistoryDataModel> GetProductHistoryByProduct(string productId);
ProductDataModel GetProductByData(string data);
void InsertProduct(ProductDataModel productDataModel);
void UpdateProduct(ProductDataModel productDataModel);
void DeleteProduct(string id);
}
}

View File

@@ -0,0 +1,21 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.BusinessLogicsContracts
{
public interface IRankBusinessLogicContract
{
List<RankDataModel> GetAllRanks();
List<RankDataModel> GetAllDataOfRank(string rankId);
RankDataModel GetRankByData(string data);
void InsertRank(RankDataModel rankDataModel);
void UpdateRank(RankDataModel rankDataModel);
void DeleteRank(string id);
void RestoreRank(string id);
}
}

View File

@@ -0,0 +1,19 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.BusinessLogicsContracts
{
public interface IReportContract
{
Task<List<BilletProductDataModel>> GetDataProductsByBilletAsync(CancellationToken ct);
Task<List<OrderDataModel>> GetDataOrderByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<List<BlacksmithSalaryByPeriodDataModel>> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<Stream> CreateDocumentProductsByBilletAsync(CancellationToken ct);
Task<Stream> CreateDocumentOrdersByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
Task<Stream> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
}
}

View File

@@ -0,0 +1,13 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.BusinessLogicsContracts
{
public interface ISalaryBusinessLogicContract
{
List<SalaryDataModel> GetAllSalariesByPeriod(DateTime startDate, DateTime endDate);
List<SalaryDataModel> GetAllSalariesByPeriodByBlacksmith(DateTime startDate, DateTime endDate, string blacksmithId);
void CalculateSalaryByMounth(DateTime date);
}
}

View File

@@ -1,27 +1,33 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.DataModels
{
public class BilletDataModel(string id, string billetName, string prevBilletName, string prevPrevBilletName) : IValidation
public class BilletDataModel(string id, string billetName, string? prevBilletName, string? prevPrevBilletName) : IValidation
{
public string Id { get; private set; } = id;
public string BilletName { get; private set; } = billetName;
public string PrevBilletName { get; private set; } = prevBilletName;
public string? PrevBilletName { get; private set; } = prevBilletName;
public string PrevPrevBilletName { get; private set; } = prevPrevBilletName;
public string? PrevPrevBilletName { get; private set; } = prevPrevBilletName;
public void Validate()
public BilletDataModel(string id, string billetName) : this(id, billetName, null, null) { }
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 (BilletName.IsEmpty())
throw new ValidationException("Field BilletName is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "ManufacturerName"));
}
}
}

View File

@@ -0,0 +1,9 @@
namespace TheBlacksmithVakulaContract.DataModels
{
public class BilletProductDataModel
{
public required string BilletName { get; set; }
public required List<string> Products { get; set; }
}
}

View File

@@ -1,42 +1,65 @@
using TheBlacksmithVakulaContract.Exceptions;
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.DataModels
{
public class BlacksmithDataModel(string id, string fio, string rankId, DateTime birthDate, DateTime employmentDate, bool isDeleted) : IValidation
{
private readonly RankDataModel? _rank;
public string Id { get; private set; } = id;
public string FIO { get; private set; } = fio;
public string RankId { get; private set; } = rankId;
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;
public void Validate()
public string RankName => _rank?.RankName ?? string.Empty;
public BlacksmithDataModel(string id, string fio, string rankId, DateTime birthDate, DateTime employmentDate, bool isDeleted, RankDataModel rank) : this(id, fio, rankId, birthDate, employmentDate, isDeleted)
{
_rank = rank;
}
public BlacksmithDataModel(string id, string fio, string rankId, DateTime birthDate, DateTime employmentDate) : this(id, fio, rankId, birthDate, employmentDate, false) { }
public void Validate(IStringLocalizer<Messages> localizer)
{
if (Id.IsEmpty())
throw new ValidationException("Field Id is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "Id"));
if (!Id.IsGuid())
throw new ValidationException("The value in the field Id is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "Id"));
if (FIO.IsEmpty())
throw new ValidationException("Field FIO is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "FIO"));
if (RankId.IsEmpty())
throw new ValidationException("Field RankId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "RankId"));
if (!RankId.IsGuid())
throw new ValidationException("The value in the field RankId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "RankId"));
if (BirthDate.Date > DateTime.Now.AddYears(-16).Date)
throw new ValidationException($"Minors cannot 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 < 16)
throw new ValidationException($"Minors cannot be (EmploymentDate - { EmploymentDate.ToShortDateString() }," +
$" BirthDate - { BirthDate.ToShortDateString()})");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageMinorsEmploymentDate"],
EmploymentDate.ToShortDateString(), BirthDate.ToShortDateString()));
}
}
}

View File

@@ -0,0 +1,13 @@
namespace TheBlacksmithVakulaContract.DataModels
{
public class BlacksmithSalaryByPeriodDataModel
{
public required string BlacksmithFIO { get; set; }
public double TotalSalary { get; set; }
public DateTime FromPeriod { get; set; }
public DateTime ToPeriod { get; set; }
}
}

View File

@@ -1,7 +1,9 @@
using System.Text.RegularExpressions;
using Microsoft.Extensions.Localization;
using System.Text.RegularExpressions;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.DataModels
{
@@ -15,18 +17,22 @@ namespace TheBlacksmithVakulaContract.DataModels
public double DiscountSize { get; private set; } = discountSize;
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 (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

@@ -1,48 +1,110 @@
using TheBlacksmithVakulaContract.Exceptions;
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Enums;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.DataModels
{
public class OrderDataModel(string id, string blacksmithId, string? buyerId, double sum, DiscountType discountType,
double discount, bool isCancel, List<OrderProductDataModel> products) : IValidation
public class OrderDataModel : IValidation
{
public string Id { get; private set; } = id;
private readonly BuyerDataModel? _buyer;
public string BlacksmithId { get; private set; } = blacksmithId;
private readonly BlacksmithDataModel? _blacksmith;
public string? BuyerId { get; private set; } = buyerId;
public string Id { get; private set; }
public string BlacksmithId { get; private set; }
public string? BuyerId { get; private set; }
public DateTime OrderDate { get; private set; } = DateTime.UtcNow;
public double Sum { get; private set; } = sum;
public double Sum { get; private set; }
public DiscountType DiscountType { get; private set; } = discountType;
public DiscountType DiscountType { get; private set; }
public double Discount { get; private set; } = discount;
public double Discount { get; private set; }
public bool IsCancel { get; private set; } = isCancel;
public bool IsCancel { get; private set; }
public List<OrderProductDataModel> Products { get; private set; } = products;
public List<OrderProductDataModel> Products { get; private set; }
public void Validate()
public string BuyerFIO => _buyer?.FIO ?? string.Empty;
public string BlacksmithFIO => _blacksmith?.FIO ?? string.Empty;
public OrderDataModel(string id, string blacksmithId, string? buyerId, DiscountType discountType, bool isCancel, List<OrderProductDataModel> orderProducts)
{
Id = id;
BlacksmithId = blacksmithId;
BuyerId = buyerId;
DiscountType = discountType;
IsCancel = isCancel;
Products = orderProducts;
var percent = 0.0;
foreach (DiscountType elem in Enum.GetValues<DiscountType>())
{
if ((elem & discountType) != 0)
{
switch (elem)
{
case DiscountType.None:
break;
case DiscountType.OnSale:
percent += 0.1;
break;
case DiscountType.RegularCustomer:
percent += 0.5;
break;
case DiscountType.Certificate:
percent += 0.3;
break;
}
}
}
Sum = Products?.Sum(x => 1000 * x.Count) ?? 0;
Discount = Sum * percent;
}
public OrderDataModel(string id, string blacksmithId, string? buyerId, double sum, DiscountType discountType, double discount, bool isCancel, List<OrderProductDataModel> orderProducts, BlacksmithDataModel? blacksmith, BuyerDataModel? buyer) : this(id, blacksmithId, buyerId, discountType, isCancel, orderProducts)
{
Sum = sum;
Discount = discount;
_blacksmith = blacksmith;
_buyer = buyer;
}
public OrderDataModel(string id, string blacksmithId, string? buyerId, int discountType, List<OrderProductDataModel> products) : this(id, blacksmithId, buyerId, (DiscountType)discountType, false, products) { }
public void Validate(IStringLocalizer<Messages> localizer)
{
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 (BlacksmithId.IsEmpty())
throw new ValidationException("Field BlacksmithId is empty");
if (!BlacksmithId.IsGuid())
throw new ValidationException("The value in the field BlacksmithId is not a unique identifier");
if (!BuyerId?.IsGuid() ?? !BuyerId?.IsEmpty() ?? false)
throw new ValidationException("The value in the field BuyerId is not a unique identifier");
if (Sum <= 0)
throw new ValidationException("Field Sum is less than or equal to 0");
if ((Products?.Count ?? 0) == 0)
throw new ValidationException("The sale must include products");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "Id"));
if (!Id.IsGuid())
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "Id"));
if (BlacksmithId.IsEmpty())
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "BlacksmithId"));
if (!BlacksmithId.IsGuid())
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "BlacksmithId"));
if (!BuyerId?.IsGuid() ?? !BuyerId?.IsEmpty() ?? false)
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "BuyerId"));
if (Sum <= 0)
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "Sum"));
if (Products is null)
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotInitialized"], "Products"));
if (Products.Count == 0)
throw new ValidationException(localizer["ValidationExceptionMessageNoProductsInSale"]);
Products.ForEach(x => x.Validate(localizer));
}
}
}

View File

@@ -1,29 +1,44 @@
using TheBlacksmithVakulaContract.Exceptions;
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.DataModels
{
public class OrderProductDataModel(string orderId, string productId, int count) : IValidation
{
private readonly ProductDataModel? _product;
public string OrderId { get; private set; } = orderId;
public string ProductId { get; private set; } = productId;
public int Count { get; private set; } = count;
public void Validate()
public string ProductName => _product?.ProductName ?? string.Empty;
public OrderProductDataModel(string orderId, string productId, int count, ProductDataModel product) : this(orderId, productId, count)
{
_product = product;
}
public void Validate(IStringLocalizer<Messages> localizer)
{
if (OrderId.IsEmpty())
throw new ValidationException("Field OrderId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "OrderId"));
if (!OrderId.IsGuid())
throw new ValidationException("The value in the field OrderId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "OrderId"));
if (ProductId.IsEmpty())
throw new ValidationException("Field ProductId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "IProductIdd"));
if (!ProductId.IsGuid())
throw new ValidationException("The value in the field ProductId 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"));
}
}
}

View File

@@ -1,13 +1,17 @@
using TheBlacksmithVakulaContract.Enums;
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Enums;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.DataModels
{
public class ProductDataModel(string id, string productName, ProductType productType,
string billetId, double price, bool isDeleted) : IValidation
{
private readonly BilletDataModel? _billet;
public string Id { get; private set; } = id;
public string ProductName { get; private set; } = productName;
@@ -20,22 +24,37 @@ namespace TheBlacksmithVakulaContract.DataModels
public bool IsDeleted { get; private set; } = isDeleted;
public void Validate()
public string BilletName => _billet?.BilletName ?? string.Empty;
public ProductDataModel(string id, string productName, ProductType productType, string billetId, double price, bool isDeleted, BilletDataModel billet) : this(id, productName, productType, billetId, price, isDeleted)
{
_billet = billet;
}
public ProductDataModel(string id, string productName, ProductType productType, string billetId, double price) : this(id, productName, productType, billetId, price, false) { }
public void Validate(IStringLocalizer<Messages> localizer)
{
if (Id.IsEmpty())
throw new ValidationException("Field Id is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "Id"));
if (!Id.IsGuid())
throw new ValidationException("The value in the field Id is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "Id"));
if (ProductName.IsEmpty())
throw new ValidationException("Field ProductName is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "ProductName"));
if (ProductType == ProductType.None)
throw new ValidationException("Field ProductType is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "ProductType"));
if (BilletId.IsEmpty())
throw new ValidationException("Field BilletId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "BilletId"));
if (!BilletId.IsGuid())
throw new ValidationException("The value in the field BilletId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "BilletId"));
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,25 +1,38 @@
using TheBlacksmithVakulaContract.Exceptions;
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.DataModels
{
public class ProductHistoryDataModel(string productId, double oldPrice) : IValidation
{
private readonly ProductDataModel? _product;
public string ProductId { get; private set; } = productId;
public double OldPrice { get; private set; } = oldPrice;
public DateTime ChangeDate { get; private set; } = DateTime.UtcNow;
public void Validate()
public string ProductName => _product?.ProductName ?? string.Empty;
public ProductHistoryDataModel(string productId, double oldPrice, DateTime changeDate, ProductDataModel product) : this(productId, oldPrice)
{
ChangeDate = changeDate;
_product = product;
}
public void Validate(IStringLocalizer<Messages> localizer)
{
if (ProductId.IsEmpty())
throw new ValidationException("Field ProductId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "ProductId"));
if (!ProductId.IsGuid())
throw new ValidationException("The value in the field ProductId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "ProductId"));
if (OldPrice <= 0)
throw new ValidationException("Field Price is less than or equal to 0");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "OldPrice"));
}
}
}

View File

@@ -1,38 +1,58 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.Localization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TheBlacksmithVakulaContract.Enums;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.Infrastructure.RankConfigurations;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.DataModels
{
public class RankDataModel(string id, string rankId, string rankName, RankType rankType, bool isActual, DateTime changeDate) : IValidation
public class RankDataModel(string rankId, string rankName, RankType rankType, RankConfiguration configuration) : IValidation
{
public string Id { get; private set; } = id;
public string RankId { get; private set; } = rankId;
public string Id { get; private set; } = rankId;
public string RankName { get; private set; } = rankName;
public RankType RankType { get; private set; } = rankType;
public bool IsActual { get; private set; } = isActual;
public RankConfiguration ConfigurationModel { get; private set; } = configuration;
public DateTime ChangeDate { get; private set; } = changeDate;
public RankDataModel(string rankId, string rankName, RankType rankType, string configurationJson) : this(rankId, rankName, rankType, (RankConfiguration)null)
{
var obj = JToken.Parse(configurationJson);
if (obj is not null)
{
ConfigurationModel = obj.Value<string>("Type") switch
{
nameof(ExpertRankConfiguration) => JsonConvert.DeserializeObject<ExpertRankConfiguration>(configurationJson)!,
nameof(StudentRankConfiguration) => JsonConvert.DeserializeObject<StudentRankConfiguration>(configurationJson)!,
_ => JsonConvert.DeserializeObject<RankConfiguration>(configurationJson)!,
};
}
}
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");
if (RankId.IsEmpty())
throw new ValidationException("Field RankId is empty");
if (!RankId.IsGuid())
throw new ValidationException("The value in the field RankId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "Id"));
if (RankName.IsEmpty())
throw new ValidationException("Field RankName is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "RankName"));
if (RankType == RankType.None)
throw new ValidationException("Field RankType is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "RankType"));
if (ConfigurationModel is null)
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotInitialized"], "ConfigurationModel"));
if (ConfigurationModel!.Rate <= 0)
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageLessOrEqualZero"], "Rate"));
}
}
}

View File

@@ -1,25 +1,38 @@
using TheBlacksmithVakulaContract.Exceptions;
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Extensions;
using TheBlacksmithVakulaContract.Infrastructure;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.DataModels
{
public class SalaryDataModel(string blacksmithId, DateTime salaryDate, double salary) : IValidation
public class SalaryDataModel(string blacksmithId, DateTime salaryDate, double blacksmithSalary) : IValidation
{
private readonly BlacksmithDataModel? _blacksmith;
public string BlacksmithId { get; private set; } = blacksmithId;
public DateTime SalaryDate { get; private set; } = salaryDate;
public DateTime SalaryDate { get; private set; } = salaryDate.ToUniversalTime();
public double Salary { get; private set; } = salary;
public double Salary { get; private set; } = blacksmithSalary;
public void Validate()
public string BlacksmithFIO => _blacksmith?.FIO ?? string.Empty;
public SalaryDataModel(string blacksmithId, DateTime salaryDate, double blacksmithSalary, BlacksmithDataModel blacksmith) : this(blacksmithId, salaryDate, blacksmithSalary)
{
_blacksmith = blacksmith;
}
public void Validate(IStringLocalizer<Messages> localizer)
{
if (BlacksmithId.IsEmpty())
throw new ValidationException("Field BlacksmithId is empty");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageEmptyField"], "BlacksmithId"));
if (!BlacksmithId.IsGuid())
throw new ValidationException("The value in the field BlacksmithId is not a unique identifier");
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "BlacksmithId"));
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

@@ -0,0 +1,8 @@
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.Exceptions
{
public class ElementDeletedException(string id, IStringLocalizer<Messages> localizer) :
Exception(string.Format(localizer["ElementDeletedExceptionMessage"], id)) { }
}

View File

@@ -0,0 +1,13 @@
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.Exceptions
{
public class ElementExistsException(string paramName, string paramValue, IStringLocalizer<Messages> localizer) :
Exception(string.Format(localizer["ElementExistsExceptionMessage"], paramValue, paramName))
{
public string ParamName { get; private set; } = paramName;
public string ParamValue { get; private set; } = paramValue;
}
}

View File

@@ -0,0 +1,11 @@
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.Exceptions
{
public class ElementNotFoundException(string value, IStringLocalizer<Messages> localizer) :
Exception(string.Format(localizer["ElementNotFoundExceptionMessage"], value))
{
public string Value { get; private set; } = value;
}
}

View File

@@ -0,0 +1,8 @@
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.Exceptions
{
public class IncorrectDatesException(DateTime start, DateTime end, IStringLocalizer<Messages> localizer) :
Exception(string.Format(localizer["IncorrectDatesExceptionMessage"], start.ToShortDateString(), end.ToShortDateString())) { }
}

View File

@@ -0,0 +1,8 @@
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.Exceptions
{
public class StorageException(Exception ex, IStringLocalizer<Messages> localizer) :
Exception(string.Format(localizer["StorageExceptionMessage"], ex.Message), ex) { }
}

View File

@@ -1,6 +1,4 @@
namespace TheBlacksmithVakulaContract.Exceptions
{
public class ValidationException(string message) : Exception(message)
{
}
public class ValidationException(string message) : Exception(message) { }
}

View File

@@ -0,0 +1,10 @@
namespace TheBlacksmithVakulaContract.Extensions
{
public static class DateTimeExtensions
{
public static bool IsDateNotOlder(this DateTime date, DateTime olderDate)
{
return date >= olderDate;
}
}
}

View File

@@ -0,0 +1,7 @@
namespace TheBlacksmithVakulaContract.Infrastructure
{
public interface IConfigurationDatabase
{
string ConnectionString { get; }
}
}

View File

@@ -0,0 +1,9 @@
namespace TheBlacksmithVakulaContract.Infrastructure
{
public interface IConfigurationSalary
{
double ExtraOrderSum { get; }
int MaxCountThreads { get; }
}
}

View File

@@ -1,7 +1,10 @@
namespace TheBlacksmithVakulaContract.Infrastructure
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.Resources;
namespace TheBlacksmithVakulaContract.Infrastructure
{
public interface IValidation
{
void Validate();
void Validate(IStringLocalizer<Messages> localizer);
}
}

View File

@@ -0,0 +1,55 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Net;
namespace TheBlacksmithVakulaContract.Infrastructure
{
public class OperationResponse
{
protected HttpStatusCode StatusCode { get; set; }
protected object? Result { get; set; }
protected string? FileName { get; set; }
public IActionResult GetResponse(HttpRequest request, HttpResponse response)
{
ArgumentNullException.ThrowIfNull(request);
ArgumentNullException.ThrowIfNull(response);
response.StatusCode = (int)StatusCode;
if (Result is null)
{
return new StatusCodeResult((int)StatusCode);
}
if (Result is Stream stream)
{
return new FileStreamResult(stream, "application/octet-stream")
{
FileDownloadName = FileName
};
}
return new ObjectResult(Result);
}
protected static TResult OK<TResult, TData>(TData data) where TResult : OperationResponse, new() =>
new() { StatusCode = HttpStatusCode.OK, Result = data };
protected static TResult OK<TResult, TData>(TData data, string fileName) where TResult : OperationResponse, new() =>
new() { StatusCode = HttpStatusCode.OK, Result = data, FileName = fileName };
protected static TResult NoContent<TResult>() where TResult : OperationResponse, new() =>
new() { StatusCode = HttpStatusCode.NoContent };
protected static TResult BadRequest<TResult>(string? errorMessage = null) where TResult : OperationResponse, 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 };
}
}

View File

@@ -0,0 +1,9 @@
namespace TheBlacksmithVakulaContract.Infrastructure.RankConfigurations
{
public class ExpertRankConfiguration : RankConfiguration
{
public override string Type => nameof(ExpertRankConfiguration);
public double PersonalCountTrendPremium { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
using System.Globalization;
namespace TheBlacksmithVakulaContract.Infrastructure.RankConfigurations
{
public class RankConfiguration
{
public virtual string Type => nameof(RankConfiguration);
public double Rate { get; set; }
public string CultureName { get; set; } = CultureInfo.CurrentCulture.Name;
}
}

View File

@@ -0,0 +1,11 @@
namespace TheBlacksmithVakulaContract.Infrastructure.RankConfigurations
{
public class StudentRankConfiguration : RankConfiguration
{
public override string Type => nameof(StudentRankConfiguration);
public double OrderPercent { get; set; }
public double BonusForExtraOrders { get; set; }
}
}

View File

@@ -0,0 +1,405 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Этот код создан программой.
// Исполняемая версия:4.0.30319.42000
//
// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
// повторной генерации кода.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TheBlacksmithVakulaContract.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()]
public 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)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TheBlacksmithVakulaContract.Resources.Messages", typeof(Messages).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Перезаписывает свойство CurrentUICulture текущего потока для всех
/// обращений к ресурсу с помощью этого класса ресурса со строгой типизацией.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Элемент по данным: {0} был удален.
/// </summary>
public static string AdapterMessageElementDeletedException {
get {
return ResourceManager.GetString("AdapterMessageElementDeletedException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Не найден элемент по данным: {0}.
/// </summary>
public static string AdapterMessageElementNotFoundException {
get {
return ResourceManager.GetString("AdapterMessageElementNotFoundException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Данные пусты.
/// </summary>
public static string AdapterMessageEmptyDate {
get {
return ResourceManager.GetString("AdapterMessageEmptyDate", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Неправильные даты: {0}.
/// </summary>
public static string AdapterMessageIncorrectDatesException {
get {
return ResourceManager.GetString("AdapterMessageIncorrectDatesException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Ошибка при обработке данных: {0}.
/// </summary>
public static string AdapterMessageInvalidOperationException {
get {
return ResourceManager.GetString("AdapterMessageInvalidOperationException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Ошибка при работе с хранилищем данных: {0}.
/// </summary>
public static string AdapterMessageStorageException {
get {
return ResourceManager.GetString("AdapterMessageStorageException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Переданы неверные данные: {0}.
/// </summary>
public static string AdapterMessageValidationException {
get {
return ResourceManager.GetString("AdapterMessageValidationException", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Производитель.
/// </summary>
public static string DocumentDocCaptionManufacturer {
get {
return ResourceManager.GetString("DocumentDocCaptionManufacturer", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Товар.
/// </summary>
public static string DocumentDocCaptionProduct {
get {
return ResourceManager.GetString("DocumentDocCaptionProduct", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Продукты по производителям.
/// </summary>
public static string DocumentDocHeader {
get {
return ResourceManager.GetString("DocumentDocHeader", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Сформировано на дату {0}.
/// </summary>
public static string DocumentDocSubHeader {
get {
return ResourceManager.GetString("DocumentDocSubHeader", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Кол-во.
/// </summary>
public static string DocumentExcelCaptionCount {
get {
return ResourceManager.GetString("DocumentExcelCaptionCount", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Дата.
/// </summary>
public static string DocumentExcelCaptionDate {
get {
return ResourceManager.GetString("DocumentExcelCaptionDate", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Скидка.
/// </summary>
public static string DocumentExcelCaptionDiscount {
get {
return ResourceManager.GetString("DocumentExcelCaptionDiscount", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Товар.
/// </summary>
public static string DocumentExcelCaptionProduct {
get {
return ResourceManager.GetString("DocumentExcelCaptionProduct", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Сумма.
/// </summary>
public static string DocumentExcelCaptionSum {
get {
return ResourceManager.GetString("DocumentExcelCaptionSum", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Всего.
/// </summary>
public static string DocumentExcelCaptionTotal {
get {
return ResourceManager.GetString("DocumentExcelCaptionTotal", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Продажи за период.
/// </summary>
public static string DocumentExcelHeader {
get {
return ResourceManager.GetString("DocumentExcelHeader", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на c {0} по {1}.
/// </summary>
public static string DocumentExcelSubHeader {
get {
return ResourceManager.GetString("DocumentExcelSubHeader", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Начисления.
/// </summary>
public static string DocumentPdfDiagramCaption {
get {
return ResourceManager.GetString("DocumentPdfDiagramCaption", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Зарплатная ведомость.
/// </summary>
public static string DocumentPdfHeader {
get {
return ResourceManager.GetString("DocumentPdfHeader", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на за период с {0} по {1}.
/// </summary>
public static string DocumentPdfSubHeader {
get {
return ResourceManager.GetString("DocumentPdfSubHeader", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Нельзя изменить удаленный элемент (идентификатор: {0}).
/// </summary>
public static string ElementDeletedExceptionMessage {
get {
return ResourceManager.GetString("ElementDeletedExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Уже существует элемент со значением {0} параметра {1}.
/// </summary>
public static string ElementExistsExceptionMessage {
get {
return ResourceManager.GetString("ElementExistsExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Элемент не найден по значению = {0}.
/// </summary>
public static string ElementNotFoundExceptionMessage {
get {
return ResourceManager.GetString("ElementNotFoundExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Дата окончания должна быть позже даты начала. Дата начала: {0}. ​​Дата окончания: {1}.
/// </summary>
public static string IncorrectDatesExceptionMessage {
get {
return ResourceManager.GetString("IncorrectDatesExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Недостаточно данных для обработки: {0}.
/// </summary>
public static string NotEnoughDataToProcessExceptionMessage {
get {
return ResourceManager.GetString("NotEnoughDataToProcessExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Не найдены данные.
/// </summary>
public static string NotFoundDataMessage {
get {
return ResourceManager.GetString("NotFoundDataMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Ошибка при работе в хранилище: {0}.
/// </summary>
public static string StorageExceptionMessage {
get {
return ResourceManager.GetString("StorageExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Дата трудоустройства не может быть раньше даты рождения ({0}, {1}).
/// </summary>
public static string ValidationExceptionMessageEmploymentDateAndBirthDate {
get {
return ResourceManager.GetString("ValidationExceptionMessageEmploymentDateAndBirthDate", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Значение в поле {0} пусто.
/// </summary>
public static string ValidationExceptionMessageEmptyField {
get {
return ResourceManager.GetString("ValidationExceptionMessageEmptyField", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Значение в поле Телефонный номер не является телефонным номером.
/// </summary>
public static string ValidationExceptionMessageIncorrectPhoneNumber {
get {
return ResourceManager.GetString("ValidationExceptionMessageIncorrectPhoneNumber", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Значение в поле {0} меньше или равно 0.
/// </summary>
public static string ValidationExceptionMessageLessOrEqualZero {
get {
return ResourceManager.GetString("ValidationExceptionMessageLessOrEqualZero", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Несовершеннолетние не могут быть приняты на работу (Дата рождения: {0}).
/// </summary>
public static string ValidationExceptionMessageMinorsBirthDate {
get {
return ResourceManager.GetString("ValidationExceptionMessageMinorsBirthDate", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Несовершеннолетние не могут быть приняты на работу (Дата трудоустройства {0}, Дата рождения: {1}).
/// </summary>
public static string ValidationExceptionMessageMinorsEmploymentDate {
get {
return ResourceManager.GetString("ValidationExceptionMessageMinorsEmploymentDate", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на В продаже должен быть хотя бы один товар.
/// </summary>
public static string ValidationExceptionMessageNoProductsInSale {
get {
return ResourceManager.GetString("ValidationExceptionMessageNoProductsInSale", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Значение в поле {0} не является типом уникального идентификатора.
/// </summary>
public static string ValidationExceptionMessageNotAId {
get {
return ResourceManager.GetString("ValidationExceptionMessageNotAId", resourceCulture);
}
}
/// <summary>
/// Ищет локализованную строку, похожую на Значение в поле {0} не проиницализировано.
/// </summary>
public static string ValidationExceptionMessageNotInitialized {
get {
return ResourceManager.GetString("ValidationExceptionMessageNotInitialized", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,234 @@
<?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="ValidationExceptionMessageEmploymentDateAndBirthDate" xml:space="preserve">
<value>Date of employment cannot be earlier than date of birth ({0}, {1})</value>
</data>
<data name="ValidationExceptionMessageEmptyField" xml:space="preserve">
<value>The value in field {0} is empty</value>
</data>
<data name="ValidationExceptionMessageIncorrectPhoneNumber" xml:space="preserve">
<value>The value in the Phone Number field is not a phone number.</value>
</data>
<data name="ValidationExceptionMessageLessOrEqualZero" xml:space="preserve">
<value>The value in field {0} is less than or equal to 0</value>
</data>
<data name="ValidationExceptionMessageMinorsBirthDate" xml:space="preserve">
<value>Minors cannot be hired (BirthDate = {0})</value>
</data>
<data name="ValidationExceptionMessageMinorsEmploymentDate" xml:space="preserve">
<value>Minors cannot be hired (EmploymentDate: {0}, BirthDate {1})</value>
</data>
<data name="ValidationExceptionMessageNoProductsInSale" xml:space="preserve">
<value>There must be at least one item on sale</value>
</data>
<data name="ValidationExceptionMessageNotAId" xml:space="preserve">
<value>The value in the {0} field is not a unique identifier type.</value>
</data>
<data name="ValidationExceptionMessageNotInitialized" xml:space="preserve">
<value>The value in field {0} is not initialized</value>
</data>
<data name="ElementDeletedExceptionMessage" xml:space="preserve">
<value>Cannot modify a deleted item (id: {0})</value>
</data>
<data name="ElementExistsExceptionMessage" xml:space="preserve">
<value>There is already an element with value {0} of parameter {1}</value>
</data>
<data name="ElementNotFoundExceptionMessage" xml:space="preserve">
<value>Element not found at value = {0}</value>
</data>
<data name="IncorrectDatesExceptionMessage" xml:space="preserve">
<value>The end date must be later than the start date.. StartDate: {0}. EndDate: {1}</value>
</data>
<data name="NotEnoughDataToProcessExceptionMessage" xml:space="preserve">
<value>Not enough data to process: {0}</value>
</data>
<data name="NotFoundDataMessage" xml:space="preserve">
<value>No data found</value>
</data>
<data name="StorageExceptionMessage" xml:space="preserve">
<value>Error while working in storage: {0}</value>
</data>
<data name="DocumentDocCaptionManufacturer" xml:space="preserve">
<value>Manufacturer</value>
</data>
<data name="DocumentDocCaptionProduct" xml:space="preserve">
<value>Product</value>
</data>
<data name="DocumentDocHeader" xml:space="preserve">
<value>Products by Manufacturer</value>
</data>
<data name="DocumentDocSubHeader" xml:space="preserve">
<value>Generated on 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="DocumentExcelCaptionProduct" xml:space="preserve">
<value>Product</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="DocumentPdfDiagramCaption" xml:space="preserve">
<value>Accruals</value>
</data>
<data name="DocumentPdfHeader" xml:space="preserve">
<value>Payroll</value>
</data>
<data name="DocumentPdfSubHeader" xml:space="preserve">
<value>for the period from {0} to {1}</value>
</data>
<data name="AdapterMessageElementDeletedException" xml:space="preserve">
<value>Element by data: {0} was deleted</value>
</data>
<data name="AdapterMessageElementNotFoundException" xml:space="preserve">
<value>Not found element by data: {0}</value>
</data>
<data name="AdapterMessageEmptyDate" xml:space="preserve">
<value>Data is empty</value>
</data>
<data name="AdapterMessageIncorrectDatesException" xml:space="preserve">
<value>Incorrect dates: {0}</value>
</data>
<data name="AdapterMessageInvalidOperationException" xml:space="preserve">
<value>Error processing data: {0}</value>
</data>
<data name="AdapterMessageStorageException" xml:space="preserve">
<value>Error while working with data storage: {0}</value>
</data>
<data name="AdapterMessageValidationException" xml:space="preserve">
<value>Incorrect data transmitted: {0}</value>
</data>
</root>

View File

@@ -0,0 +1,234 @@
<?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="ValidationExceptionMessageEmploymentDateAndBirthDate" xml:space="preserve">
<value>La date d'emploi ne peut pas être antérieure à la date de naissance ({0}, {1})</value>
</data>
<data name="ValidationExceptionMessageEmptyField" xml:space="preserve">
<value>La valeur dans le champ {0} est vide</value>
</data>
<data name="ValidationExceptionMessageIncorrectPhoneNumber" xml:space="preserve">
<value>La valeur dans le champ Numéro de téléphone n'est pas un numéro de téléphone.</value>
</data>
<data name="ValidationExceptionMessageLessOrEqualZero" xml:space="preserve">
<value>La valeur du champ {0} est inférieure ou égale à 0</value>
</data>
<data name="ValidationExceptionMessageMinorsBirthDate" xml:space="preserve">
<value>Les mineurs ne peuvent pas être employés (Date de naissance : {0})</value>
</data>
<data name="ValidationExceptionMessageMinorsEmploymentDate" xml:space="preserve">
<value>Les mineurs ne peuvent pas être employés (Date d'emploi : {0}, Date de naissance : {1})</value>
</data>
<data name="ValidationExceptionMessageNoProductsInSale" xml:space="preserve">
<value>Il doit y avoir au moins un article en vente</value>
</data>
<data name="ValidationExceptionMessageNotAId" xml:space="preserve">
<value>La valeur dans le champ {0} n'est pas un type d'identifiant unique</value>
</data>
<data name="ValidationExceptionMessageNotInitialized" xml:space="preserve">
<value>La valeur du champ {0} n'est pas initialisée</value>
</data>
<data name="ElementDeletedExceptionMessage" xml:space="preserve">
<value>Impossible de modifier l'élément supprimé (id : {0})</value>
</data>
<data name="ElementExistsExceptionMessage" xml:space="preserve">
<value>Il existe déjà un élément avec la valeur {0} pour le paramètre {1}</value>
</data>
<data name="ElementNotFoundExceptionMessage" xml:space="preserve">
<value>Élément non trouvé par valeur = {0}</value>
</data>
<data name="IncorrectDatesExceptionMessage" xml:space="preserve">
<value>La date de fin doit être postérieure à la date de début. Date de début : {0}. Date de fin : {1}</value>
</data>
<data name="NotEnoughDataToProcessExceptionMessage" xml:space="preserve">
<value>Pas assez de données à traiter : {0}</value>
</data>
<data name="NotFoundDataMessage" xml:space="preserve">
<value>Données introuvables</value>
</data>
<data name="StorageExceptionMessage" xml:space="preserve">
<value>Erreur lors du travail dans le stockage : {0}</value>
</data>
<data name="DocumentDocCaptionManufacturer" xml:space="preserve">
<value>Fabricant</value>
</data>
<data name="DocumentDocCaptionProduct" xml:space="preserve">
<value>Produit</value>
</data>
<data name="DocumentDocHeader" xml:space="preserve">
<value>Classer les historiques par statut</value>
</data>
<data name="DocumentDocSubHeader" xml:space="preserve">
<value>Généré à la date {0}</value>
</data>
<data name="DocumentExcelCaptionCount" xml:space="preserve">
<value>Quantité</value>
</data>
<data name="DocumentExcelCaptionDate" xml:space="preserve">
<value>Date</value>
</data>
<data name="DocumentExcelCaptionDiscount" xml:space="preserve">
<value>Rabais</value>
</data>
<data name="DocumentExcelCaptionProduct" xml:space="preserve">
<value>Produit</value>
</data>
<data name="DocumentExcelCaptionSum" xml:space="preserve">
<value>Somme</value>
</data>
<data name="DocumentExcelCaptionTotal" xml:space="preserve">
<value>Total</value>
</data>
<data name="DocumentExcelHeader" xml:space="preserve">
<value>Ventes de la période</value>
</data>
<data name="DocumentExcelSubHeader" xml:space="preserve">
<value>de {0} à {1}</value>
</data>
<data name="DocumentPdfDiagramCaption" xml:space="preserve">
<value>Accumulations</value>
</data>
<data name="DocumentPdfHeader" xml:space="preserve">
<value>Paie</value>
</data>
<data name="DocumentPdfSubHeader" xml:space="preserve">
<value>pour la période de {0} à {1}</value>
</data>
<data name="AdapterMessageElementDeletedException" xml:space="preserve">
<value>L'élément de données : {0} a été supprimé</value>
</data>
<data name="AdapterMessageElementNotFoundException" xml:space="preserve">
<value>Élément non trouvé pour les données : {0}</value>
</data>
<data name="AdapterMessageEmptyDate" xml:space="preserve">
<value>Les données sont vides</value>
</data>
<data name="AdapterMessageIncorrectDatesException" xml:space="preserve">
<value>Dates non valides : {0}</value>
</data>
<data name="AdapterMessageInvalidOperationException" xml:space="preserve">
<value>Erreur lors du traitement des données : {0}</value>
</data>
<data name="AdapterMessageStorageException" xml:space="preserve">
<value>Erreur lors de l'utilisation du stockage de données : {0}</value>
</data>
<data name="AdapterMessageValidationException" xml:space="preserve">
<value>Données non valides envoyées : {0}</value>
</data>
</root>

View File

@@ -0,0 +1,234 @@
<?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="ValidationExceptionMessageEmploymentDateAndBirthDate" xml:space="preserve">
<value>Дата трудоустройства не может быть раньше даты рождения ({0}, {1})</value>
</data>
<data name="ValidationExceptionMessageEmptyField" xml:space="preserve">
<value>Значение в поле {0} пусто</value>
</data>
<data name="ValidationExceptionMessageIncorrectPhoneNumber" xml:space="preserve">
<value>Значение в поле Телефонный номер не является телефонным номером</value>
</data>
<data name="ValidationExceptionMessageLessOrEqualZero" xml:space="preserve">
<value>Значение в поле {0} меньше или равно 0</value>
</data>
<data name="ValidationExceptionMessageMinorsBirthDate" xml:space="preserve">
<value>Несовершеннолетние не могут быть приняты на работу (Дата рождения: {0})</value>
</data>
<data name="ValidationExceptionMessageMinorsEmploymentDate" xml:space="preserve">
<value>Несовершеннолетние не могут быть приняты на работу (Дата трудоустройства {0}, Дата рождения: {1})</value>
</data>
<data name="ValidationExceptionMessageNoProductsInSale" xml:space="preserve">
<value>В продаже должен быть хотя бы один товар</value>
</data>
<data name="ValidationExceptionMessageNotAId" xml:space="preserve">
<value>Значение в поле {0} не является типом уникального идентификатора</value>
</data>
<data name="ValidationExceptionMessageNotInitialized" xml:space="preserve">
<value>Значение в поле {0} не проиницализировано</value>
</data>
<data name="ElementDeletedExceptionMessage" xml:space="preserve">
<value>Нельзя изменить удаленный элемент (идентификатор: {0})</value>
</data>
<data name="ElementExistsExceptionMessage" xml:space="preserve">
<value>Уже существует элемент со значением {0} параметра {1}</value>
</data>
<data name="ElementNotFoundExceptionMessage" xml:space="preserve">
<value>Элемент не найден по значению = {0}</value>
</data>
<data name="IncorrectDatesExceptionMessage" xml:space="preserve">
<value>Дата окончания должна быть позже даты начала. Дата начала: {0}. ​​Дата окончания: {1}</value>
</data>
<data name="NotEnoughDataToProcessExceptionMessage" xml:space="preserve">
<value>Недостаточно данных для обработки: {0}</value>
</data>
<data name="NotFoundDataMessage" xml:space="preserve">
<value>Не найдены данные</value>
</data>
<data name="StorageExceptionMessage" xml:space="preserve">
<value>Ошибка при работе в хранилище: {0}</value>
</data>
<data name="DocumentDocCaptionManufacturer" xml:space="preserve">
<value>Производитель</value>
</data>
<data name="DocumentDocCaptionProduct" 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="DocumentExcelCaptionProduct" 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="DocumentPdfDiagramCaption" xml:space="preserve">
<value>Начисления</value>
</data>
<data name="DocumentPdfHeader" xml:space="preserve">
<value>Зарплатная ведомость</value>
</data>
<data name="DocumentPdfSubHeader" xml:space="preserve">
<value>за период с {0} по {1}</value>
</data>
<data name="AdapterMessageElementDeletedException" xml:space="preserve">
<value>Элемент по данным: {0} был удален</value>
</data>
<data name="AdapterMessageElementNotFoundException" xml:space="preserve">
<value>Не найден элемент по данным: {0}</value>
</data>
<data name="AdapterMessageEmptyDate" xml:space="preserve">
<value>Данные пусты</value>
</data>
<data name="AdapterMessageIncorrectDatesException" xml:space="preserve">
<value>Неправильные даты: {0}</value>
</data>
<data name="AdapterMessageInvalidOperationException" xml:space="preserve">
<value>Ошибка при обработке данных: {0}</value>
</data>
<data name="AdapterMessageStorageException" xml:space="preserve">
<value>Ошибка при работе с хранилищем данных: {0}</value>
</data>
<data name="AdapterMessageValidationException" xml:space="preserve">
<value>Переданы неверные данные: {0}</value>
</data>
</root>

View File

@@ -0,0 +1,21 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.StoragesContracts
{
public interface IBilletStorageContract
{
List<BilletDataModel> GetList();
BilletDataModel? GetElementById(string id);
BilletDataModel? GetElementByName(string name);
BilletDataModel? GetElementByOldName(string name);
void AddElement(BilletDataModel billetDataModel);
void UpdElement(BilletDataModel billetDataModel);
void DelElement(string id);
}
}

View File

@@ -0,0 +1,22 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.StoragesContracts
{
public interface IBlacksmithStorageContract
{
List<BlacksmithDataModel> GetList(bool onlyActive = true, string? rankId = null, DateTime? fromBirthDate = null,
DateTime? toBirthDate = null, DateTime? fromEmploymentDate = null, DateTime? toEmploymentDate = null);
BlacksmithDataModel? GetElementById(string id);
BlacksmithDataModel? GetElementByFIO(string fio);
void AddElement(BlacksmithDataModel blacksmithDataModel);
void UpdElement(BlacksmithDataModel blacksmithDataModel);
void DelElement(string id);
int GetBlacksmithTrend(DateTime fromPeriod, DateTime toPeriod);
}
}

View File

@@ -0,0 +1,21 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.StoragesContracts
{
public interface IBuyerStorageContract
{
List<BuyerDataModel> GetList();
BuyerDataModel? GetElementById(string id);
BuyerDataModel? GetElementByPhoneNumber(string phoneNumber);
BuyerDataModel? GetElementByFIO(string fio);
void AddElement(BuyerDataModel buyerDataModel);
void UpdElement(BuyerDataModel buyerDataModel);
void DelElement(string id);
}
}

View File

@@ -0,0 +1,18 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.StoragesContracts
{
public interface IOrderStorageContract
{
List<OrderDataModel> GetList(DateTime? startDate = null, DateTime? endDate = null, string? blacksmithId = null,
string? productId = null, string? buyerId = null);
Task<List<OrderDataModel>> GetListAsync(DateTime startDate, DateTime endDate, CancellationToken ct);
OrderDataModel? GetElementById(string id);
void AddElement(OrderDataModel orderDataModel);
void DelElement(string id);
}
}

View File

@@ -0,0 +1,23 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.StoragesContracts
{
public interface IProductStorageContract
{
List<ProductDataModel> GetList(bool onlyActive = true, string? billetId = null);
Task<List<ProductDataModel>> GetListAsync(CancellationToken ct);
List<ProductHistoryDataModel> GetHistoryByProductId(string productId);
ProductDataModel? GetElementById(string id);
ProductDataModel? GetElementByName(string name);
void AddElement(ProductDataModel productDataModel);
void UpdElement(ProductDataModel productDataModel);
void DelElement(string id);
}
}

View File

@@ -0,0 +1,23 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.StoragesContracts
{
public interface IRankStorageContract
{
List<RankDataModel> GetList();
List<RankDataModel> GetRankWithHistory(string rankId);
RankDataModel? GetElementById(string id);
RankDataModel? GetElementByName(string name);
void AddElement(RankDataModel rankDataModel);
void UpdElement(RankDataModel rankDataModel);
void DelElement(string id);
void ResElement(string id);
}
}

View File

@@ -0,0 +1,13 @@
using TheBlacksmithVakulaContract.DataModels;
namespace TheBlacksmithVakulaContract.StoragesContracts
{
public interface ISalaryStorageContract
{
List<SalaryDataModel> GetList(DateTime startDate, DateTime endDate, string? blacksmithId = null);
Task<List<SalaryDataModel>> GetListAsync(DateTime startDate, DateTime endDate, CancellationToken ct);
void AddElement(SalaryDataModel salaryDataModel);
}
}

View File

@@ -6,4 +6,27 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.3.0" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Logging" 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>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Messages.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,9 @@
namespace TheBlacksmithVakulaContract.ViewModels
{
public class BilletProductViewModel
{
public required string BilletName { get; set; }
public required List<string> Products { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
namespace TheBlacksmithVakulaContract.ViewModels
{
public class BilletViewModel
{
public required string Id { get; set; }
public required string BilletName { get; set; }
public string? PrevBilletName { get; set; }
public string? PrevPrevBilletName { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
namespace TheBlacksmithVakulaContract.ViewModels
{
public class BlacksmithSalaryByPeriodViewModel
{
public required string BlacksmithFIO { get; set; }
public double TotalSalary { get; set; }
public DateTime FromPeriod { get; set; }
public DateTime ToPeriod { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
namespace TheBlacksmithVakulaContract.ViewModels
{
public class BlacksmithViewModel
{
public required string Id { get; set; }
public required string FIO { get; set; }
public required string RankId { get; set; }
public required string RankName { get; set; }
public bool IsDeleted { get; set; }
public DateTime BirthDate { get; set; }
public DateTime EmploymentDate { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
namespace TheBlacksmithVakulaContract.ViewModels
{
public class BuyerViewModel
{
public required string Id { get; set; }
public required string FIO { get; set; }
public required string PhoneNumber { get; set; }
public double DiscountSize { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
namespace TheBlacksmithVakulaContract.ViewModels
{
public class OrderProductViewModel
{
public required string ProductId { get; set; }
public required string ProductName { get; set; }
public int Count { get; set; }
}
}

View File

@@ -0,0 +1,27 @@
namespace TheBlacksmithVakulaContract.ViewModels
{
public class OrderViewModel
{
public required string Id { get; set; }
public required string BlacksmithId { get; set; }
public required string BlacksmithFIO { get; set; }
public string? BuyerId { get; set; }
public string? BuyerFIO { get; set; }
public DateTime OrderDate { get; set; }
public double Sum { get; set; }
public required string DiscountType { get; set; }
public double Discount { get; set; }
public bool IsCancel { get; set; }
public required List<OrderProductViewModel> Products { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
namespace TheBlacksmithVakulaContract.ViewModels
{
public class ProductHistoryViewModel
{
public required string ProductName { get; set; }
public double OldPrice { get; set; }
public DateTime ChangeDate { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
namespace TheBlacksmithVakulaContract.ViewModels
{
public class ProductViewModel
{
public required string Id { get; set; }
public required string ProductName { get; set; }
public required string BilletId { get; set; }
public required string BilletName { get; set; }
public required string ProductType { get; set; }
public double Price { get; set; }
public bool IsDeleted { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
namespace TheBlacksmithVakulaContract.ViewModels
{
public class RankViewModel
{
public required string Id { get; set; }
public required string RankName { get; set; }
public required string RankType { get; set; }
public required string Configuration { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
namespace TheBlacksmithVakulaContract.ViewModels
{
public class SalaryViewModel
{
public required string BlacksmithId { get; set; }
public required string BlacksmithFIO { get; set; }
public DateTime SalaryDate { get; set; }
public double Salary { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
using TheBlacksmithVakulaContract.Infrastructure;
namespace TheBlacksmithVakulaDatabase
{
internal class DefaultConfigurationDatabase : IConfigurationDatabase
{
public string ConnectionString => "";
}
}

View File

@@ -0,0 +1,166 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Npgsql;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
using TheBlacksmithVakulaDatabase.Models;
namespace TheBlacksmithVakulaDatabase.Implementations
{
internal class BilletStorageContract : IBilletStorageContract
{
private readonly TheBlacksmithVakulaDbContext _dbContext;
private readonly Mapper _mapper;
private readonly IStringLocalizer<Messages> _localizer;
public BilletStorageContract(TheBlacksmithVakulaDbContext dbContext, IStringLocalizer<Messages> localizer)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Billet, BilletDataModel>();
cfg.CreateMap<BilletDataModel, Billet>();
});
_mapper = new Mapper(config);
_localizer = localizer;
}
public List<BilletDataModel> GetList()
{
try
{
return [.. _dbContext.Billets.Select(x => _mapper.Map<BilletDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public BilletDataModel? GetElementById(string id)
{
try
{
return _mapper.Map<BilletDataModel>(GetBilletById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public BilletDataModel? GetElementByName(string name)
{
try
{
return _mapper.Map<BilletDataModel>(_dbContext.Billets.FirstOrDefault(x => x.BilletName == name));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public BilletDataModel? GetElementByOldName(string name)
{
try
{
return _mapper.Map<BilletDataModel>(_dbContext.Billets.FirstOrDefault(x => x.PrevBilletName == name ||
x.PrevPrevBilletName == name));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public void AddElement(BilletDataModel billetDataModel)
{
try
{
_dbContext.Billets.Add(_mapper.Map<Billet>(billetDataModel));
_dbContext.SaveChanges();
}
catch (InvalidOperationException ex) when (ex.TargetSite?.Name == "ThrowIdentityConflict")
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", billetDataModel.Id, _localizer);
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Billets_BilletName" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("BilletName", billetDataModel.BilletName, _localizer);
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "PK_Billets" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", billetDataModel.Id, _localizer);
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public void UpdElement(BilletDataModel billetDataModel)
{
try
{
var element = GetBilletById(billetDataModel.Id) ?? throw new ElementNotFoundException(billetDataModel.Id, _localizer);
if (element.BilletName != billetDataModel.BilletName)
{
element.PrevPrevBilletName = element.PrevBilletName;
element.PrevBilletName = element.BilletName;
element.BilletName = billetDataModel.BilletName;
}
_dbContext.Billets.Update(element);
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Billets_BilletName" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("BilletName", billetDataModel.BilletName, _localizer);
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public void DelElement(string id)
{
try
{
var element = GetBilletById(id) ?? throw new ElementNotFoundException(id, _localizer);
_dbContext.Billets.Remove(element);
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
private Billet? GetBilletById(string id) => _dbContext.Billets.FirstOrDefault(x => x.Id == id);
}
}

View File

@@ -0,0 +1,177 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Npgsql;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
using TheBlacksmithVakulaDatabase.Models;
namespace TheBlacksmithVakulaDatabase.Implementations;
internal class BlacksmithStorageContract : IBlacksmithStorageContract
{
private readonly TheBlacksmithVakulaDbContext _dbContext;
private readonly Mapper _mapper;
private readonly IStringLocalizer<Messages> _localizer;
public BlacksmithStorageContract(TheBlacksmithVakulaDbContext dbContext, IStringLocalizer<Messages> localizer)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Rank, RankDataModel>()
.ForMember(x => x.Id, x => x.MapFrom(src => src.RankId));
cfg.CreateMap<Blacksmith, BlacksmithDataModel>();
cfg.CreateMap<BlacksmithDataModel, Blacksmith>();
});
_mapper = new Mapper(config);
_localizer = localizer;
}
public List<BlacksmithDataModel> GetList(bool onlyActive = true, string? rankId = null, DateTime? fromBirthDate = null, DateTime? toBirthDate = null, DateTime? fromEmploymentDate = null, DateTime? toEmploymentDate = null)
{
try
{
var query = _dbContext.Blacksmiths.AsQueryable();
if (onlyActive)
{
query = query.Where(x => !x.IsDeleted);
}
if (rankId is not null)
{
query = query.Where(x => x.RankId == rankId);
}
if (fromBirthDate is not null && toBirthDate is not null)
{
query = query.Where(x => x.BirthDate >= fromBirthDate && x.BirthDate <= toBirthDate);
}
if (fromEmploymentDate is not null && toEmploymentDate is not null)
{
query = query.Where(x => x.EmploymentDate >= fromEmploymentDate && x.EmploymentDate <= toEmploymentDate);
}
return [.. JoinRank(query).Select(x => _mapper.Map<BlacksmithDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public BlacksmithDataModel? GetElementById(string id)
{
try
{
return _mapper.Map<BlacksmithDataModel>(GetBlacksmithById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public BlacksmithDataModel? GetElementByFIO(string fio)
{
try
{
return _mapper.Map<BlacksmithDataModel>(AddRank(_dbContext.Blacksmiths.FirstOrDefault(x => x.FIO == fio && !x.IsDeleted)));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public void AddElement(BlacksmithDataModel blacksmithDataModel)
{
try
{
_dbContext.Blacksmiths.Add(_mapper.Map<Blacksmith>(blacksmithDataModel));
_dbContext.SaveChanges();
}
catch (InvalidOperationException ex) when (ex.TargetSite?.Name == "ThrowIdentityConflict")
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", blacksmithDataModel.Id, _localizer);
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "PK_Blacksmiths" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", blacksmithDataModel.Id, _localizer);
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public void UpdElement(BlacksmithDataModel blacksmithDataModel)
{
try
{
var element = GetBlacksmithById(blacksmithDataModel.Id) ?? throw new ElementNotFoundException(blacksmithDataModel.Id, _localizer);
_dbContext.Blacksmiths.Update(_mapper.Map(blacksmithDataModel, element));
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public void DelElement(string id)
{
try
{
var element = GetBlacksmithById(id) ?? throw new ElementNotFoundException(id, _localizer);
element.IsDeleted = true;
element.DateOfDelete = DateTime.UtcNow;
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public int GetBlacksmithTrend(DateTime fromPeriod, DateTime toPeriod)
{
try
{
var countBlacksmithsOnBegining = _dbContext.Blacksmiths.Count(x => x.EmploymentDate < fromPeriod && (!x.IsDeleted || x.DateOfDelete > fromPeriod));
var countBlacksmithsOnEnding = _dbContext.Blacksmiths.Count(x => x.EmploymentDate < toPeriod && (!x.IsDeleted || x.DateOfDelete > toPeriod));
return countBlacksmithsOnEnding - countBlacksmithsOnBegining;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
private Blacksmith? GetBlacksmithById(string id) => AddRank(_dbContext.Blacksmiths.FirstOrDefault(x => x.Id == id && !x.IsDeleted));
private IQueryable<Blacksmith> JoinRank(IQueryable<Blacksmith> query)
=> query.GroupJoin(_dbContext.Ranks.Where(x => x.IsActual), x => x.RankId, y => y.RankId, (x, y) => new { Blacksmith = x, Rank = y })
.SelectMany(xy => xy.Rank.DefaultIfEmpty(), (x, y) => x.Blacksmith.AddRank(y));
private Blacksmith? AddRank(Blacksmith? blacksmith)
=> blacksmith?.AddRank(_dbContext.Ranks.FirstOrDefault(x => x.RankId == blacksmith.RankId && x.IsActual));
}

View File

@@ -0,0 +1,159 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Npgsql;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
using TheBlacksmithVakulaDatabase.Models;
namespace TheBlacksmithVakulaDatabase.Implementations
{
internal class BuyerStorageContract : IBuyerStorageContract
{
private readonly TheBlacksmithVakulaDbContext _dbContext;
private readonly Mapper _mapper;
private readonly IStringLocalizer<Messages> _localizer;
public BuyerStorageContract(TheBlacksmithVakulaDbContext theBlacksmithVakulaDbContext, IStringLocalizer<Messages> localizer)
{
_dbContext = theBlacksmithVakulaDbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Buyer, BuyerDataModel>();
cfg.CreateMap<BuyerDataModel, Buyer>();
});
_mapper = new Mapper(config);
_localizer = localizer;
}
public List<BuyerDataModel> GetList()
{
try
{
return [.. _dbContext.Buyers.Select(x => _mapper.Map<BuyerDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public BuyerDataModel? GetElementById(string id)
{
try
{
return _mapper.Map<BuyerDataModel>(GetBuyerById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public BuyerDataModel? GetElementByFIO(string fio)
{
try
{
return _mapper.Map<BuyerDataModel>(_dbContext.Buyers.FirstOrDefault(x => x.FIO == fio));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public BuyerDataModel? GetElementByPhoneNumber(string phoneNumber)
{
try
{
return _mapper.Map<BuyerDataModel>(_dbContext.Buyers.FirstOrDefault(x => x.PhoneNumber == phoneNumber));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public void AddElement(BuyerDataModel buyerDataModel)
{
try
{
_dbContext.Buyers.Add(_mapper.Map<Buyer>(buyerDataModel));
_dbContext.SaveChanges();
}
catch (InvalidOperationException ex) when (ex.TargetSite?.Name == "ThrowIdentityConflict")
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", buyerDataModel.Id, _localizer);
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Buyers_PhoneNumber" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("PhoneNumber", buyerDataModel.PhoneNumber, _localizer);
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "PK_Buyers" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("Id", buyerDataModel.Id, _localizer);
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public void UpdElement(BuyerDataModel buyerDataModel)
{
try
{
var element = GetBuyerById(buyerDataModel.Id) ?? throw new ElementNotFoundException(buyerDataModel.Id, _localizer);
_dbContext.Buyers.Update(_mapper.Map(buyerDataModel, element));
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Buyers_PhoneNumber" })
{
_dbContext.ChangeTracker.Clear();
throw new ElementExistsException("PhoneNumber", buyerDataModel.PhoneNumber, _localizer);
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public void DelElement(string id)
{
try
{
var element = GetBuyerById(id) ?? throw new ElementNotFoundException(id, _localizer);
_dbContext.Buyers.Remove(element);
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
private Buyer? GetBuyerById(string id) => _dbContext.Buyers.FirstOrDefault(x => x.Id == id);
}
}

View File

@@ -0,0 +1,133 @@
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using TheBlacksmithVakulaContract.DataModels;
using TheBlacksmithVakulaContract.Exceptions;
using TheBlacksmithVakulaContract.Resources;
using TheBlacksmithVakulaContract.StoragesContracts;
using TheBlacksmithVakulaDatabase.Models;
namespace TheBlacksmithVakulaDatabase.Implementations;
internal class OrderStorageContract : IOrderStorageContract
{
private readonly TheBlacksmithVakulaDbContext _dbContext;
private readonly Mapper _mapper;
private readonly IStringLocalizer<Messages> _localizer;
public OrderStorageContract(TheBlacksmithVakulaDbContext dbContext, IStringLocalizer<Messages> localizer)
{
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Billet, BilletDataModel>();
cfg.CreateMap<Buyer, BuyerDataModel>();
cfg.CreateMap<Product, ProductDataModel>();
cfg.CreateMap<Blacksmith, BlacksmithDataModel>();
cfg.CreateMap<OrderProduct, OrderProductDataModel>();
cfg.CreateMap<OrderProductDataModel, OrderProduct>();
cfg.CreateMap<Order, OrderDataModel>();
cfg.CreateMap<OrderDataModel, Order>()
.ForMember(x => x.IsCancel, x => x.MapFrom(src => false))
.ForMember(x => x.OrderProducts, x => x.MapFrom(src => src.Products));
});
_mapper = new Mapper(config);
_localizer = localizer;
}
public List<OrderDataModel> GetList(DateTime? startDate = null, DateTime? endDate = null, string? blacksmithId = null, string? buyerId = null, string? productId = null)
{
try
{
var query = _dbContext.Orders.Include(x => x.Buyer).Include(x => x.Blacksmith).Include(x => x.OrderProducts)!.ThenInclude(x => x.Product).AsQueryable();
if (startDate is not null && endDate is not null)
{
query = query.Where(x => x.OrderDate >= startDate && x.OrderDate < endDate);
}
if (blacksmithId is not null)
{
query = query.Where(x => x.BlacksmithId == blacksmithId);
}
if (buyerId is not null)
{
query = query.Where(x => x.BuyerId == buyerId);
}
if (productId is not null)
{
query = query.Where(x => x.OrderProducts!.Any(y => y.ProductId == productId));
}
return [.. query.Select(x => _mapper.Map<OrderDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public async Task<List<OrderDataModel>> GetListAsync(DateTime startDate, DateTime endDate, CancellationToken ct)
{
try
{
return [.. await _dbContext.Orders.Include(x => x.OrderProducts)!.ThenInclude(x => x.Product).Where(x => x.OrderDate >= startDate && x.OrderDate < endDate).Select(x => _mapper.Map<OrderDataModel>(x)).ToListAsync(ct)];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public OrderDataModel? GetElementById(string id)
{
try
{
return _mapper.Map<OrderDataModel>(GetOrderById(id));
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public void AddElement(OrderDataModel orderDataModel)
{
try
{
_dbContext.Orders.Add(_mapper.Map<Order>(orderDataModel));
_dbContext.SaveChanges();
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
public void DelElement(string id)
{
try
{
var element = GetOrderById(id) ?? throw new ElementNotFoundException(id, _localizer);
if (element.IsCancel)
{
throw new ElementDeletedException(id, _localizer);
}
element.IsCancel = true;
_dbContext.SaveChanges();
}
catch (Exception ex) when (ex is ElementDeletedException || ex is ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex, _localizer);
}
}
private Order? GetOrderById(string id) => _dbContext.Orders.Include(x => x.Buyer).Include(x => x.Blacksmith).Include(x => x.OrderProducts)!.ThenInclude(x => x.Product).FirstOrDefault(x => x.Id == id);
}

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