diff --git a/BussinesLogic/BusinessLogic/ClientLogic.cs b/BussinesLogic/BusinessLogic/ClientLogic.cs new file mode 100644 index 0000000..2ec655e --- /dev/null +++ b/BussinesLogic/BusinessLogic/ClientLogic.cs @@ -0,0 +1,105 @@ +using Contracts.BindingModel; +using Contracts.BusinessLogicContracts; +using Contracts.SearchModels; +using Contracts.StoragesContracts; +using Contracts.ViewModels; +using Microsoft.Extensions.Logging; +using System.Text.RegularExpressions; + +namespace BusinessLogics.BusinessLogic +{ + public class ClientLogic : IClientLogic + { + private readonly ILogger _logger; + private readonly IClientStorage _clientStorage; + public ClientLogic(ILogger logger, IClientStorage clientStorage) + { + _logger = logger; + _clientStorage = clientStorage; + } + + private void CheckModel(ClientBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + if (string.IsNullOrEmpty(model.PhoneNumber)) + { + throw new ArgumentNullException(nameof(model.PhoneNumber), "Нет логина клиента"); + } + if (string.IsNullOrEmpty(model.Password)) + { + throw new ArgumentNullException(nameof(model.Password), "Нет пароля клиента"); + } + if (model.PhoneNumber.Length is < 11) + { + throw new ArgumentException(nameof(model.PhoneNumber), "Длина номера телефона должна быть 11 цифр"); + } + + if (model.Password.Length < 5) + { + throw new ArgumentException(nameof(model.Password), + "Пароль пользователя должен быть не менее 5 символов"); + } + if (!Regex.IsMatch(model.Password, "^[0-9]+")) + { + throw new ArgumentException(nameof(model.Password), + "Пароль пользователя должен содержать хотя бы одну цифру"); + } + _logger.LogDebug("{level} Проверка логина пользователя на уникальность {@Client}", model); + var element = _clientStorage.GetElement(new ClientSearchModel + { + PhoneNumber = model.PhoneNumber, + }); + if (element != null && element.Id != model.Id) + { + _logger.LogWarning("С номером {PhoneNumber}, уже есть пользователь: {@ExistClient}", model.PhoneNumber, element); + throw new InvalidOperationException($"Клиент с таким номером телефона уже есть"); + } + } + + public bool Create(ClientBindingModel model) + { + try + { + CheckModel(model); + var result = _clientStorage.Insert(model); + if (result == null) + { + throw new ArgumentNullException($"Клиент не создался"); + } + _logger.LogInformation("Создана сущность: {@ClientViewModel}", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Ошибка при попытки создать элемент по {@ClientBindingModel} модели", model); + throw; + } + } + + public ClientViewModel ReadElement(ClientSearchModel model) + { + try + { + var result = _clientStorage.GetElement(model); + if (result == null) + { + throw new ArgumentNullException($"Результат получения элемента с id {model.Id} оказался нулевым"); + } + _logger.LogInformation("Извлечение элемента {@ClientViewModel} c клиента по модели: {@ClientSearchModel}", result, model); + return result; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки получить элемент по модели: {@ClientSearchModel}", model); + throw; + } + } + } +} diff --git a/BussinesLogic/BusinessLogic/EmployeeLogic.cs b/BussinesLogic/BusinessLogic/EmployeeLogic.cs new file mode 100644 index 0000000..8d49718 --- /dev/null +++ b/BussinesLogic/BusinessLogic/EmployeeLogic.cs @@ -0,0 +1,106 @@ +using Contracts.BindingModel; +using Contracts.BusinessLogicContracts; +using Contracts.SearchModels; +using Contracts.StoragesContracts; +using Contracts.ViewModels; +using Microsoft.Extensions.Logging; +using System.Text.RegularExpressions; + +namespace BusinessLogics.BusinessLogic +{ + public class EmployeeLogic : IEmployeeLogic + { + + private readonly ILogger _logger; + private readonly IEmployeeStorage _employeeStorage; + public EmployeeLogic(ILogger logger, IEmployeeStorage employeeStorage) + { + _logger = logger; + _employeeStorage = employeeStorage; + } + + private void CheckModel(EmployeeBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + if (string.IsNullOrEmpty(model.PhoneNumber)) + { + throw new ArgumentNullException(nameof(model.PhoneNumber), "Нет логина клиента"); + } + if (string.IsNullOrEmpty(model.Password)) + { + throw new ArgumentNullException(nameof(model.Password), "Нет пароля клиента"); + } + if (model.PhoneNumber.Length is < 12) + { + throw new ArgumentException(nameof(model.PhoneNumber), "Длина номера телефона должна быть 11 цифр"); + } + + if (model.Password.Length < 5) + { + throw new ArgumentException(nameof(model.Password), + "Пароль пользователя должен быть не менее 5 символов"); + } + if (!Regex.IsMatch(model.Password, "[0-9]+")) + { + throw new ArgumentException(nameof(model.Password), + "Пароль пользователя должен содержать хотя бы одну цифру"); + } + _logger.LogDebug("{level} Проверка логина пользователя на уникальность {@Employee}", model); + var element = _employeeStorage.GetElement(new EmployeeSearchModel + { + PhoneNumber = model.PhoneNumber, + }); + if (element != null && element.Id != model.Id) + { + _logger.LogWarning("С номером {PhoneNumber}, уже есть пользователь: {@ExistEmployee}", model.PhoneNumber, element); + throw new InvalidOperationException($"Сотрудник с таким номером телефона уже есть"); + } + } + + public bool Create(EmployeeBindingModel model) + { + try + { + CheckModel(model); + var result = _employeeStorage.Insert(model); + if (result == null) + { + throw new ArgumentNullException($"Сотрудник не создался"); + } + _logger.LogInformation("Создана сущность: {@EmployeeViewModel}", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Ошибка при попытки создать элемент по {@EmployeeBindingModel} модели", model); + throw; + } + } + + public EmployeeViewModel ReadElement(EmployeeSearchModel model) + { + try + { + var result = _employeeStorage.GetElement(model); + if (result == null) + { + throw new ArgumentNullException($"Результат получения элемента с id {model.Id} оказался нулевым"); + } + _logger.LogInformation("Извлечение элемента {@EmployeeViewModel} c сотрудника по модели: {@EmployeeSearchModel}", result, model); + return result; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки получить элемент по модели: {@EmployeeSearchModel}", model); + throw; + } + } + } +} diff --git a/BussinesLogic/BusinessLogic/OperationLogic.cs b/BussinesLogic/BusinessLogic/OperationLogic.cs new file mode 100644 index 0000000..6aeaa0f --- /dev/null +++ b/BussinesLogic/BusinessLogic/OperationLogic.cs @@ -0,0 +1,143 @@ +using Contracts.BindingModel; +using Contracts.BusinessLogicContracts; +using Contracts.SearchModels; +using Contracts.StoragesContracts; +using Contracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace BusinessLogics.BusinessLogic +{ + public class OperationLogic : IOperationLogic + { + private readonly ILogger _logger; + private readonly IOperationStorage _carStorage; + + public OperationLogic(ILogger logger, IOperationStorage carStorage) + { + _logger = logger; + _carStorage = carStorage; + } + + public void CheckOnlyModel(OperationBindingModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model), "Произошла ошибка на уровне проверки OperationBindingModel"); + } + } + + private void CheckUpdateModel(OperationBindingModel model) + { + CheckOnlyModel(model); + if (model.Price <= 0) + { + throw new ArgumentException($"Произошла ошибка на уровне проверки OperationBindingModel. Стоимость операции (Price={model.Price}) должна быть больше 0"); + } + } + + public void CheckFullModel(OperationBindingModel model) + { + CheckOnlyModel(model); + CheckUpdateModel(model); + if (string.IsNullOrEmpty(model.Model) && string.IsNullOrEmpty(model.Mark)) + { + throw new ArgumentNullException($"Произошла ошибка на уровне проверки OperationBindingModel.Вид и тип операции не должна быть нулевыми или пустыми."); + } + } + + public List ReadList(OperationSearchModel? model) + { + try + { + var results = model != null ? _carStorage.GetFilteredList(model) : _carStorage.GetFullList(); + _logger.LogDebug("Список операций: {@operations}", results); + _logger.LogInformation("Извлечение списка операций по {@OperationSearchModel} модели", model); + return results; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки получить список по {@OperationSearchModel} модели", model); + throw; + } + } + + public OperationViewModel ReadElement(OperationSearchModel model) + { + try + { + var result = _carStorage.GetElement(model); + if (result == null) + { + throw new ArgumentNullException($"Не получилось получить эдемент с id {model.Id}"); + } + _logger.LogInformation("Извлечение элемента {@OperationViewModel} c обследований по {@OperationSearchModel} модели", result, model); + return result; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки получить элемент по {@OperationSearchModel} модели:", model); + throw; + } + } + + public bool Create(OperationBindingModel model) + { + try + { + CheckFullModel(model); + var result = _carStorage.Insert(model); + if (result == null) + { + throw new ArgumentNullException($"Не получилось создать операцию"); + } + _logger.LogInformation("Создана сущность {@OperationViewModel}", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки создать элемент по {@OperationBindingModel} модели", model); + throw; + } + } + + public bool Update(OperationBindingModel model) + { + try + { + CheckFullModel(model); + var result = _carStorage.Update(model); + if (result == null) + { + throw new ArgumentNullException($"Результат обновления обследований оказался нулевым"); + } + _logger.LogInformation("Была обновлена сущность на: {@OperationViewModel}", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки обновить элемент по модели: {@OperationBindingModel}", model); + throw; + } + } + + public bool Delete(OperationBindingModel model) + { + try + { + CheckOnlyModel(model); + var result = _carStorage.Delete(model); + if (result == null) + { + throw new ArgumentNullException($"Не получилось удалить операциб"); + } + _logger.LogInformation("Удалена сущность {@OperationViewModel}", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки удалить элемент по {@OperationBindingModel} модели", model); + throw; + } + } + } +} diff --git a/BussinesLogic/BusinessLogic/OrderLogic.cs b/BussinesLogic/BusinessLogic/OrderLogic.cs new file mode 100644 index 0000000..78fe795 --- /dev/null +++ b/BussinesLogic/BusinessLogic/OrderLogic.cs @@ -0,0 +1,138 @@ +using Contracts.BindingModel; +using Contracts.BusinessLogicContracts; +using Contracts.SearchModels; +using Contracts.StoragesContracts; +using Contracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace BusinessLogics.BusinessLogic +{ + public class OrderLogic : ICostLogic + { + private readonly ILogger _logger; + private readonly ICostStorage _costStorage; + + public OrderLogic(ILogger logger, ICostStorage costStorage) + { + _logger = logger; + _costStorage = costStorage; + } + + public void CheckModel(CostBindingModel model, bool checkParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (checkParams is false) + { + return; + } + + if (string.IsNullOrEmpty(model.NameOfCost)) + { + throw new ArgumentNullException($"Имя затраты не должно быть пустым"); + } + + if (model.Price <= 0) + { + throw new ArgumentException($"Стоимость должна быть больше 0"); + } + } + + public bool Create(CostBindingModel model) + { + try + { + CheckModel(model); + var result = _costStorage.Insert(model); + if (result == null) + { + throw new ArgumentNullException($"Затрата не создана"); + } + _logger.LogInformation("Была создана сущность {@CostViewModel}", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки создать элемент по {@CostBindingModel} модели", model); + throw; + } + } + + public bool Delete(CostBindingModel model) + { + try + { + CheckModel(model, false); + var result = _costStorage.Delete(model); + if (result == null) + { + throw new ArgumentNullException($"Удалить затрату не удалось"); + } + _logger.LogInformation("Была удалена сущность {@CostViewModel}", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки удалить элемент по {@CostBindingModel} модели", model); + throw; + } + } + + public CostViewModel ReadElement(CostSearchModel model) + { + try + { + var result = _costStorage.GetElement(model); + if (result == null) + { + throw new ArgumentNullException($"Не получилось получить id {model.Id}"); + } + _logger.LogInformation("Извлечение элемента {@CostViewModel} c затрат по {@CostSearchModel} модели", result, model); + return result; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки получить элемент по {@CostSearchModel} модели", model); + throw; + } + } + + public List ReadList(CostSearchModel? model = null) + { + try + { + var results = model != null ? _costStorage.GetFilteredList(model) : _costStorage.GetFullList(); + _logger.LogDebug("Список полученных статей затрат {@costs}", results); + _logger.LogInformation("Извлечение списка c затрат по {@CostSearchModel} модели", model); + return results; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки получить список по {@CostSearchModel} модели", model); + throw; + } + } + + public bool Update(CostBindingModel model) + { + try + { + //CheckModel(model); + var result = _costStorage.Update(model); + if (result == null) + { + throw new ArgumentNullException($"Не получилось обновить затраты"); + } + _logger.LogInformation("Обновлена сущность на {@CostViewModel}", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки обновить элемент по {@CostBindingModel} модели", model); + throw; + } + } + } +} diff --git a/BussinesLogic/BusinessLogic/PaymentLogic.cs b/BussinesLogic/BusinessLogic/PaymentLogic.cs new file mode 100644 index 0000000..d123592 --- /dev/null +++ b/BussinesLogic/BusinessLogic/PaymentLogic.cs @@ -0,0 +1,115 @@ +using Contracts.BindingModel; +using Contracts.BusinessLogicContracts; +using Contracts.SearchModels; +using Contracts.StoragesContracts; +using Contracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace BusinessLogics.BusinessLogic +{ + public class PaymentLogic : IPaymentLogic + { + private readonly ILogger _logger; + private readonly IPaymentStorage _paymentStorage; + private readonly IOperationStorage _carStorage; + public PaymentLogic(ILogger logger, IPaymentStorage paymentStorage, IOperationStorage carStorage) + { + _logger = logger; + _paymentStorage = paymentStorage; + _carStorage = carStorage; + } + + private void CheckModel(PaymentBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + if (model.PaidPrice < 0) + { + throw new ArgumentNullException(nameof(model.PaidPrice), "Оплаченная стоимость отрицательна"); + } + } + + public bool Create(PaymentBindingModel model) + { + try + { + CheckModel(model); + var result = _paymentStorage.Insert(model); + if (result == null) + { + throw new ArgumentNullException($"Оплата не создалась"); + } + _logger.LogInformation("Создана сущность: {@PaymentViewModel}", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Ошибка при попытки создать элемент по {@PaymentBindingModel} модели", model); + throw; + } + } + + public PaymentViewModel ReadElement(PaymentSearchModel model) + { + try + { + var result = _paymentStorage.GetElement(model); + if (result == null) + { + throw new ArgumentNullException($"Не получилось получить эдемент с id {model.Id}"); + } + _logger.LogInformation("Извлечение оплаты {@PaymentViewModel} по {@PaymentSearchModel} модели", result, model); + return result; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки получить элемент по {@PaymentSearchModel} модели", model); + throw; + } + } + + public List ReadList(PaymentSearchModel model) + { + try + { + var results = model != null ? _paymentStorage.GetFilteredList(model) : _paymentStorage.GetFullList(); + _logger.LogDebug("Список оплат {@payments}", results); + _logger.LogInformation("Извлечение списка в количестве {Count} c оплатой по модели: {@PaymentSearchModel}", results.Count, model); + return results; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки получить список по {@PaymentSearchModel} модели", model); + throw; + } + } + public bool GetPaymentInfo(PaymentSearchModel model, out double fullPrice, out double paidPrice) + { + try + { + var payments = ReadList(model); // Вызываем метод из бизнес логики, чтобы залогировать доп информацию + if (payments == null || payments.Count == 0) + { + fullPrice = _carStorage.GetElement(new() { Id = model.OperationId })?.Price ?? throw new InvalidOperationException("Не получена операция для оплаты"); ; + paidPrice = 0; + return true; + } + fullPrice = payments[0].FullPrice; + paidPrice = payments.Sum(x => x.PaidPrice); + _logger.LogInformation("По покупке({Id}) и операцийе({Id}) получена полная стоимостиь {fullPrice} и оплаченная стоимость {paidPrice}",model.PurchaseId, model.OperationId, fullPrice, paidPrice); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "При попытке получения оплат по {@searchModel} произошла ошибка", model); + throw; + } + } + } +} diff --git a/BussinesLogic/BusinessLogic/PurchaseLogic.cs b/BussinesLogic/BusinessLogic/PurchaseLogic.cs new file mode 100644 index 0000000..3648bfd --- /dev/null +++ b/BussinesLogic/BusinessLogic/PurchaseLogic.cs @@ -0,0 +1,128 @@ +using Contracts.BindingModel; +using Contracts.BusinessLogicContracts; +using Contracts.SearchModels; +using Contracts.StoragesContracts; +using Contracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace BusinessLogics.BusinessLogic +{ + public class PurchaseLogic : IPurchaseLogic + { + private readonly ILogger _logger; + private readonly IPurchaseStorage _purchaseVisitStorage; + + public PurchaseLogic(ILogger logger, IPurchaseStorage purchaseVisitStorage) + { + _logger = logger; + _purchaseVisitStorage = purchaseVisitStorage; + } + + public void CheckModel(PurchaseBindingModel model, bool checkParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (checkParams is false) + { + return; + } + } + + public List ReadList(PurchaseSearchModel? model) + { + try + { + var results = model != null ? _purchaseVisitStorage.GetFilteredList(model) : _purchaseVisitStorage.GetFullList(); + _logger.LogDebug("Полученные покупки: {@purchasesVisit}", results); + _logger.LogInformation("Извлечение списка в количестве {Count} c покупки по {@PurchaseSearchModel} модели", results.Count, model); + return results; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки получить список по {@PurchaseSearchModel} модели", model); + throw; + } + } + + public PurchaseViewModel ReadElement(PurchaseSearchModel model) + { + try + { + var result = _purchaseVisitStorage.GetElement(model); + if (result == null) + { + throw new ArgumentNullException($"Не получилось получить эдемент с id {model.Id}"); + } + _logger.LogInformation("Извлечение элемента {@PurchaseViewModel} c покупки по {@PurchaseSearchModel} модели", result, model); + return result; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки получить элемент по {@PurchaseSearchModel} модели", model); + throw; + } + } + + public bool Create(PurchaseBindingModel model) + { + try + { + CheckModel(model); + var result = _purchaseVisitStorage.Insert(model); + if (result == null) + { + throw new ArgumentNullException($"Не удалось создать покупку"); + } + _logger.LogInformation("Создана сущность {@PurchaseViewModel}", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки создать элемент по {@PurchaseBindingModel} модели", model); + throw; + } + } + + public bool Update(PurchaseBindingModel model) + { + try + { + CheckModel(model); + var result = _purchaseVisitStorage.Update(model); + if (result == null) + { + throw new ArgumentNullException($"Не удалось обновить покупку"); + } + _logger.LogInformation("Была обновлена сущность на: {@PurchaseViewModel}", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки обновить элемент по {@PurchaseBindingModel} модели", model); + throw; + } + } + + public bool Delete(PurchaseBindingModel model) + { + try + { + CheckModel(model, false); + var result = _purchaseVisitStorage.Delete(model); + if (result == null) + { + throw new ArgumentNullException($"Ну удалось удалить покупку"); + } + _logger.LogInformation("Сущность {@PurchaseViewModel} удалена ", result); + return true; + } + catch (Exception e) + { + _logger.LogError(e, "Произошла ошибка при попытки удалить элемент по {@PurchaseBindingModel} модели", model); + throw; + } + } + } +} diff --git a/BussinesLogic/BusinessLogic/ReportLogic.cs b/BussinesLogic/BusinessLogic/ReportLogic.cs new file mode 100644 index 0000000..ad56df8 --- /dev/null +++ b/BussinesLogic/BusinessLogic/ReportLogic.cs @@ -0,0 +1,132 @@ +using Contracts.BindingModel; +using Contracts.BusinessLogicContracts; +using Contracts.SearchModels; +using Contracts.StoragesContracts; +using Contracts.ViewModels; +using BusinessLogics.MailWorker; + +namespace BusinessLogics.BusinessLogics; + +public class ReportLogic : IReportLogic +{ + private readonly AbstractSaveToWord _saveToWord; + private readonly IPurchaseStorage _purchaseStorage; + private readonly IOperationStorage _carStorage; + private readonly AbstractSaveToExcel _saveToExcel; + private readonly IPaymentStorage _paymentStorage; + private readonly AbstractMailWorker _mailWorker; + private readonly AbstractSaveToPdf _saveToPdf; + + public ReportLogic(AbstractSaveToWord saveToWord, IPurchaseStorage purchaseStorage, AbstractSaveToExcel saveToExcel, + AbstractMailWorker mailWorker, IPaymentStorage paymentStorage, AbstractSaveToPdf saveToPdf, IOperationStorage carStorage) + { + _mailWorker = mailWorker; + _paymentStorage = paymentStorage; + _saveToExcel = saveToExcel; + _saveToWord = saveToWord; + _purchaseStorage = purchaseStorage; + _saveToPdf = saveToPdf; + _carStorage = carStorage; + } + + public void SavePurchasesToWord(ReportBindingModel option) + { + _saveToWord.CreateDoc(new() + { + FileName = option.FileName, + Stream = option.Stream, + Title = "Список сделок вместе с операциями", + ReportObjects = _purchaseStorage.GetFilteredList(new() { OperationsIds = option.Ids.ToList() }) + .Select(x => (object)x).ToList(), + }); + } + + public void SavePurchasesToExcel(ReportBindingModel option) + { + _saveToExcel.CreateReportPurchase(new() + { + FileName = option.FileName, + Stream = option.Stream, + Title = "Список сделок вместе с операциями", + ReportObjects = _purchaseStorage.GetFilteredList(new() { OperationsIds = option.Ids.ToList() }) + .Select(x => (object)x).ToList(), + Headers = new() { "Сделка", "Дата сделки",} + }); + } + + public void SendPaymentsToEmail(ReportDateRangeBindingModel option, string email) + { + var payments = _paymentStorage.GetFilteredList(new() + { + DateFrom = option.DateFrom, + DateTo = option.DateTo, + }); + option.Stream = new MemoryStream(); + _saveToPdf.CreateDocForPayments(new() + { + DateFrom = option.DateFrom, + DateTo = option.DateTo, + Stream = option.Stream, + Title = "Данные по операциям с оплатами за период", + ReportObjects = payments.Select(x => (object)x).ToList() + }); + + _mailWorker.MailSendAsync(new() + { + FilesStreams = new() { new(option.Stream, "report.pdf") }, + Subject = $"Отчет по оплатам за {option.DateFrom.ToShortDateString()}-{option.DateTo.ToShortDateString()}", + MailAddress = email, + }); + } + + public void SaveOperationsToWord(ReportBindingModel option) + { + _saveToWord.CreateDoc(new() + { + FileName = option.FileName, + Stream = option.Stream, + Title = "Список операций вместе с сделками", + ReportObjects = _carStorage.GetFilteredList(new() { PurchasesIds = option.Ids.ToList() }) + .Select(x => (object)x).ToList(), + }); + } + + public void SaveOperationsToExcel(ReportBindingModel option) + { + _saveToExcel.CreateReportOperations(new() + { + FileName = option.FileName, + Stream = option.Stream, + Ids = option.Ids.ToList(), + Title = "Список операций вместе с сделками", + ReportObjects = _carStorage.GetFilteredList(new() { PurchasesIds = option.Ids.ToList() }) + .Select(x => (object)x).ToList(), + Headers = new() { "Вид", "Тип", "Дата"} + }); + } + + public void SendCostsToEmail(ReportDateRangeBindingModel option, string email) + { + var purchaseVisit = _purchaseStorage.GetFilteredList(new() + { + DateFrom = option.DateFrom, + DateTo = option.DateTo, + }); + option.Stream = new MemoryStream(); + _saveToPdf.CreateDocForPurchases(new() + { + DateFrom = option.DateFrom, + DateTo = option.DateTo, + Stream = option.Stream, + Title = "Данные по сделке со статьями затрат за период", + ReportObjects = purchaseVisit.Select(x => (object)x).ToList() + }); + + _mailWorker.MailSendAsync(new() + { + FilesStreams = new() { new(option.Stream, "report.pdf") }, + Subject = $"Отчет по статьям затрат за {option.DateFrom.ToShortDateString()}-{option.DateTo.ToShortDateString()}", + MailAddress = email, + }); + } +} \ No newline at end of file diff --git a/BussinesLogic/BussinesLogic.csproj b/BussinesLogic/BussinesLogic.csproj new file mode 100644 index 0000000..0c1d671 --- /dev/null +++ b/BussinesLogic/BussinesLogic.csproj @@ -0,0 +1,25 @@ + + + + net8.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/BussinesLogic/MailWorker/AbstractMailWorker.cs b/BussinesLogic/MailWorker/AbstractMailWorker.cs new file mode 100644 index 0000000..9cc5a71 --- /dev/null +++ b/BussinesLogic/MailWorker/AbstractMailWorker.cs @@ -0,0 +1,42 @@ +using Contracts.BindingModel; +using Microsoft.Extensions.Logging; + +namespace BusinessLogics.MailWorker +{ + public abstract class AbstractMailWorker + { + protected MailConfigBindingModel? config; + + protected readonly ILogger _logger; + + public AbstractMailWorker(ILogger logger) + { + _logger = logger; + } + + public void MailConfig(MailConfigBindingModel config) + { + this.config = config; + _logger.LogDebug("Config: {@config}", config); + } + + public async void MailSendAsync(MailSendInfoBindingModel info) + { + if (config == null || string.IsNullOrEmpty(config.MailLogin) || string.IsNullOrEmpty(config.MailPassword) || + string.IsNullOrEmpty(config.SmtpClientHost) || config.SmtpClientPort == 0) + { + return; + } + + if (string.IsNullOrEmpty(info.MailAddress) || string.IsNullOrEmpty(info.Subject)) + { + return; + } + + _logger.LogDebug("Send Mail: {To}, {Subject}", info.MailAddress, info.Subject); + await SendMailAsync(info); + } + + protected abstract Task SendMailAsync(MailSendInfoBindingModel info); + } +} diff --git a/BussinesLogic/MailWorker/MailKitWorker.cs b/BussinesLogic/MailWorker/MailKitWorker.cs new file mode 100644 index 0000000..0cbaa60 --- /dev/null +++ b/BussinesLogic/MailWorker/MailKitWorker.cs @@ -0,0 +1,50 @@ +using System.Net; +using System.Net.Mail; +using System.Net.Mime; +using System.Text; +using Contracts.BindingModel; +using Microsoft.Extensions.Logging; + +namespace BusinessLogics.MailWorker +{ + public class MailKitWorker : AbstractMailWorker + { + public MailKitWorker(ILogger logger) : base(logger) + { + } + + protected override async Task SendMailAsync(MailSendInfoBindingModel info) + { + if (config == null) return; + + using var objMailMessage = new MailMessage(); + using var objSmtpClient = new SmtpClient(config.SmtpClientHost, config.SmtpClientPort); + try + { + objMailMessage.From = new MailAddress(config.MailLogin); + objMailMessage.To.Add(new MailAddress(info.MailAddress)); + objMailMessage.Subject = info.Subject; + objMailMessage.Body = info.Text; + objMailMessage.SubjectEncoding = Encoding.UTF8; + objMailMessage.BodyEncoding = Encoding.UTF8; + + foreach (var (stream, filename) in info.FilesStreams) + { + Attachment attachment = stream == null ? new(filename) : new(stream, filename, MediaTypeNames.Application.Octet); + objMailMessage.Attachments.Add(attachment); + } + + objSmtpClient.UseDefaultCredentials = false; + objSmtpClient.EnableSsl = true; + objSmtpClient.DeliveryMethod = SmtpDeliveryMethod.Network; + objSmtpClient.Credentials = new NetworkCredential(config.MailLogin, config.MailPassword); + + await Task.Run(() => objSmtpClient.Send(objMailMessage)); + } + catch (Exception e) + { + _logger.LogError(e, "При отправке сообщения на почту произошла ошибка:"); + } + } + } +} \ No newline at end of file diff --git a/BussinesLogic/OfficePackage/AbstractSaveToExcel.cs b/BussinesLogic/OfficePackage/AbstractSaveToExcel.cs new file mode 100644 index 0000000..7928364 --- /dev/null +++ b/BussinesLogic/OfficePackage/AbstractSaveToExcel.cs @@ -0,0 +1,171 @@ +using BusinessLogics.OfficePackage.HelperEnums; +using BusinessLogics.OfficePackage.HelperModels.Excel; +using Contracts.ViewModels; + +namespace BusinessLogics.OfficePackage +{ + public abstract class AbstractSaveToExcel + { + private void CreateHeaders(ExcelInfo info) + { + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "A", + RowIndex = 1, + Text = info.Title, + StyleInfo = ExcelStyleInfoType.Title + }); + + MergeCells(new ExcelMergeParameters + { + CellFromName = "A1", + CellToName = "G1" + }); + + for (var i = 0; i < info.Headers.Count; i++) + { + InsertCellInWorksheet(new ExcelCellParameters() + { + ColumnName = ((char)('A' + i)).ToString(), + RowIndex = 2, + Text = info.Headers[i], + StyleInfo = ExcelStyleInfoType.Text + }); + } + } + + /// + /// Создание отчета + /// + /// + public void CreateReportPurchase(ExcelInfo info) + { + CreateExcel(info); + CreateHeaders(info); + + uint rowIndex = 3; + foreach (var pc in info.ReportObjects) + { + if (pc is not PurchaseViewModel purchase) + { + throw new ArgumentException($"Передан некорректный тип в отчет: " + + $"ожидается PurchaseViewModel; Получен объект типа: {pc.GetType()}", nameof(info)); + } + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "B", + RowIndex = rowIndex, + Text = purchase.DatePurchase.ToShortDateString(), + StyleInfo = ExcelStyleInfoType.Text + }); + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "A", + RowIndex = rowIndex, + Text = purchase.Id.ToString(), + StyleInfo = ExcelStyleInfoType.Text + }); + int i = 0; + foreach (var car in purchase.OperationViewModels) + { + if (info.Ids != null && !info.Ids.Contains(car.Id)) + { + continue; + } + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = ((char)('C'+i)).ToString(), + RowIndex = rowIndex, + Text = $"{car.Mark} {car.Model} в количестве {purchase.OperationsModel[car.Id].CountOperations}", + StyleInfo = ExcelStyleInfoType.TextWithBroder + }); + if (info.Ids != null) + { + break; + } + i++; + } + rowIndex++; + } + SaveExcel(info); + } + + public void CreateReportOperations(ExcelInfo info) + { + CreateExcel(info); + CreateHeaders(info); + + uint rowIndex = 3; + foreach (var pc in info.ReportObjects) + { + var car = pc as OperationViewModel; + if (car == null) + { + throw new ArgumentException($"Передан некорректный тип в отчет: " + + $"ожидается OperationViewModel; Получен объект типа: {pc.GetType()}", nameof(info)); + } + foreach (var purchase in car.Purchases) + { + if (info.Ids != null && !info.Ids.Contains(purchase.Id)) + { + continue; + } + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "A", + RowIndex = rowIndex, + Text = car.Mark, + StyleInfo = ExcelStyleInfoType.Text + }); + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "B", + RowIndex = rowIndex, + Text = car.Model, + StyleInfo = ExcelStyleInfoType.Text + }); + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "C", + RowIndex = rowIndex, + Text = purchase.OperationsModel[car.Id].CountOperations.ToString(), + StyleInfo = ExcelStyleInfoType.Text + }); + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "C", + RowIndex = rowIndex, + Text = purchase.DatePurchase.ToString(), + StyleInfo = ExcelStyleInfoType.Text + }); + break; + } + rowIndex++; + } + SaveExcel(info); + } + /// + /// Создание excel-файла + /// + /// + protected abstract void CreateExcel(ExcelInfo info); + + /// + /// Добавляем новую ячейку в лист + /// + /// + protected abstract void InsertCellInWorksheet(ExcelCellParameters excelParams); + + /// + /// Объединение ячеек + /// + /// + protected abstract void MergeCells(ExcelMergeParameters excelParams); + + /// + /// Сохранение файла + /// + /// + protected abstract void SaveExcel(ExcelInfo info); + } +} diff --git a/BussinesLogic/OfficePackage/AbstractSaveToPdf.cs b/BussinesLogic/OfficePackage/AbstractSaveToPdf.cs new file mode 100644 index 0000000..02327bb --- /dev/null +++ b/BussinesLogic/OfficePackage/AbstractSaveToPdf.cs @@ -0,0 +1,143 @@ +using BusinessLogics.OfficePackage.HelperEnums; +using BusinessLogics.OfficePackage.HelperModels.Pdf; +using Contracts.ViewModels; + +namespace BusinessLogics.OfficePackage +{ + public abstract class AbstractSaveToPdf + { + public void CreateDocForPayments(PdfInfo info) + { + CreatePdf(info); + CreateParagraph(new PdfParagraph { Text = info.Title, Style = "NormalTitle", ParagraphAlignment = PdfParagraphAlignmentType.Center }); + CreateParagraph(new PdfParagraph + { + Text = $"с {info.DateFrom.ToShortDateString()} по {info.DateTo.ToShortDateString()}", + Style = "Normal", + ParagraphAlignment = PdfParagraphAlignmentType.Center + }); + + CreateTable(new List { "3cm", "6cm", "3cm", "3cm", "3cm", }); + + CreateRow(new PdfRowParameters + { + Texts = new List { "Сделка", "Операция", "Дата", "Оплаченная стоимость", "Полная стоимость" }, + Style = "NormalTitle", + ParagraphAlignment = PdfParagraphAlignmentType.Center + }); + var sumPaidPrice = 0.0; + foreach (var pc in info.ReportObjects) + { + if (pc is not PaymentViewModel payment) + { + throw new ArgumentException($"Передан некорректный тип в отчет: " + + $"ожидается Payment; Получен объект типа: {pc.GetType()}", nameof(info)); + } + + if (payment.Operation == null || payment.OperationByPurchase == null) + { + throw new ArgumentNullException($"Получена модель оплаты c нулевыми полями"); + } + sumPaidPrice += payment.PaidPrice; + CreateRow(new PdfRowParameters + { + Texts = new List + { + payment.OperationByPurchase.PurchaseId.ToString(), + payment.Operation.Mark + " " + payment.Operation.Model, + payment.Date.ToShortDateString(), + payment.PaidPrice.ToString(), + payment.FullPrice.ToString(), + }, + Style = "Normal", + ParagraphAlignment = PdfParagraphAlignmentType.Left + }); + } + CreateParagraph(new PdfParagraph { Text = $"Итого оплачено : {sumPaidPrice}\t", Style = "Normal", ParagraphAlignment = PdfParagraphAlignmentType.Rigth }); + + SavePdf(info); + } + + public void CreateDocForPurchases(PdfInfo info) + { + CreatePdf(info); + CreateParagraph(new PdfParagraph { Text = info.Title, Style = "NormalTitle", ParagraphAlignment = PdfParagraphAlignmentType.Center }); + CreateParagraph(new PdfParagraph + { + Text = $"с {info.DateFrom.ToShortDateString()} по {info.DateTo.ToShortDateString()}", + Style = "Normal", + ParagraphAlignment = PdfParagraphAlignmentType.Center + }); + + CreateTable(new List { "4cm", "5cm", "5cm", "3cm", }); + + CreateRow(new PdfRowParameters + { + Texts = new List { "Дата получения", "Сделка", "Статья затрат", "Сумма затраты" }, + Style = "NormalTitle", + ParagraphAlignment = PdfParagraphAlignmentType.Center + }); + foreach (var pc in info.ReportObjects) + { + if (pc is not PurchaseViewModel purchase) + { + throw new ArgumentException($"Передан некорректный тип в отчет: " + + $"ожидается Purchase; Получен объект типа: {pc.GetType()}", nameof(info)); + } + + if (purchase.CostViewModels == null) + { + throw new ArgumentNullException($"Получена модель статьи затрат c нулевыми полями"); + } + foreach (var cost in purchase.CostViewModels) + { + CreateRow(new PdfRowParameters + { + Texts = new List + { + purchase.DatePurchase.ToShortDateString(), + purchase.Id.ToString(), + cost.NameOfCost, + (cost.Price* cost.PurchaseModels[purchase.Id].Count).ToString(), + }, + Style = "Normal", + ParagraphAlignment = PdfParagraphAlignmentType.Left + }); + } + } + SavePdf(info); + } + + /// + /// Создание doc-файла + /// + /// + protected abstract void CreatePdf(PdfInfo info); + + /// + /// Создание параграфа с текстом + /// + /// + /// + protected abstract void CreateParagraph(PdfParagraph paragraph); + + /// + /// Создание таблицы + /// + /// + /// + protected abstract void CreateTable(List columns); + + /// + /// Создание и заполнение строки + /// + /// + protected abstract void CreateRow(PdfRowParameters rowParameters); + + /// + /// Сохранение файла + /// + /// + protected abstract void SavePdf(PdfInfo info); + } +} \ No newline at end of file diff --git a/BussinesLogic/OfficePackage/AbstractSaveToWord.cs b/BussinesLogic/OfficePackage/AbstractSaveToWord.cs new file mode 100644 index 0000000..a0a64bf --- /dev/null +++ b/BussinesLogic/OfficePackage/AbstractSaveToWord.cs @@ -0,0 +1,59 @@ +using BusinessLogics.OfficePackage.HelperEnums; +using BusinessLogics.OfficePackage.HelperModels.Word; + +namespace BusinessLogics.OfficePackage +{ + public abstract class AbstractSaveToWord + { + public void CreateDoc(WordInfo info) + { + CreateWord(info); + + CreateParagraph(new WordParagraph + { + Texts = new List<(string, WordTextProperties)> { (info.Title, new WordTextProperties { Bold = true, Size = "24", }) }, + TextProperties = new WordTextProperties + { + Size = "24", + JustificationType = WordJustificationType.Center + } + }); + + foreach (var text in info.ReportObjects.SelectMany(reportObject => reportObject.ToString()?.Split("\n") ?? new string[] { })) + { + CreateParagraph(new WordParagraph + { + Texts = new List<(string, WordTextProperties)> + { + (text, new WordTextProperties { Size = "24" }) + }, + TextProperties = new WordTextProperties + { + Size = "24", + JustificationType = WordJustificationType.Both + } + }); + } + SaveWord(info); + } + + /// + /// Создание doc-файла + /// + /// + protected abstract void CreateWord(WordInfo info); + + /// + /// Создание абзаца с текстом + /// + /// + /// + protected abstract void CreateParagraph(WordParagraph paragraph); + + /// + /// Сохранение файла + /// + /// + protected abstract void SaveWord(WordInfo info); + } +} \ No newline at end of file diff --git a/BussinesLogic/OfficePackage/HelperEnums/ExcelStyleInfoType.cs b/BussinesLogic/OfficePackage/HelperEnums/ExcelStyleInfoType.cs new file mode 100644 index 0000000..d7ab245 --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperEnums/ExcelStyleInfoType.cs @@ -0,0 +1,9 @@ +namespace BusinessLogics.OfficePackage.HelperEnums +{ + public enum ExcelStyleInfoType + { + Title, + Text, + TextWithBroder + } +} diff --git a/BussinesLogic/OfficePackage/HelperEnums/PdfParagraphAlignmentType.cs b/BussinesLogic/OfficePackage/HelperEnums/PdfParagraphAlignmentType.cs new file mode 100644 index 0000000..04f9c55 --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperEnums/PdfParagraphAlignmentType.cs @@ -0,0 +1,9 @@ +namespace BusinessLogics.OfficePackage.HelperEnums +{ + public enum PdfParagraphAlignmentType + { + Center, + Left, + Rigth + } +} diff --git a/BussinesLogic/OfficePackage/HelperEnums/WordJustificationType.cs b/BussinesLogic/OfficePackage/HelperEnums/WordJustificationType.cs new file mode 100644 index 0000000..4079475 --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperEnums/WordJustificationType.cs @@ -0,0 +1,8 @@ +namespace BusinessLogics.OfficePackage.HelperEnums +{ + public enum WordJustificationType + { + Center, + Both + } +} diff --git a/BussinesLogic/OfficePackage/HelperModels/Excel/ExcelCellParameters.cs b/BussinesLogic/OfficePackage/HelperModels/Excel/ExcelCellParameters.cs new file mode 100644 index 0000000..9d1f939 --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperModels/Excel/ExcelCellParameters.cs @@ -0,0 +1,13 @@ +using BusinessLogics.OfficePackage.HelperEnums; + +namespace BusinessLogics.OfficePackage.HelperModels.Excel +{ + public class ExcelCellParameters + { + public string ColumnName { get; set; } = string.Empty; + public uint RowIndex { get; set; } + public string Text { get; set; } = string.Empty; + public string CellReference => $"{ColumnName}{RowIndex}"; + public ExcelStyleInfoType StyleInfo { get; set; } + } +} diff --git a/BussinesLogic/OfficePackage/HelperModels/Excel/ExcelInfo.cs b/BussinesLogic/OfficePackage/HelperModels/Excel/ExcelInfo.cs new file mode 100644 index 0000000..cd5c151 --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperModels/Excel/ExcelInfo.cs @@ -0,0 +1,21 @@ + +namespace BusinessLogics.OfficePackage.HelperModels.Excel +{ + public class ExcelInfo + { + public string? FileName { get; set; } + + public Stream? Stream { get; set; } + + public string Title { get; set; } = string.Empty; + public List ReportObjects + { + get; + set; + } = new(); + + public List Headers { get; set; } = new(); + + public List? Ids { get; set; } + } +} diff --git a/BussinesLogic/OfficePackage/HelperModels/Excel/ExcelMergeParameters.cs b/BussinesLogic/OfficePackage/HelperModels/Excel/ExcelMergeParameters.cs new file mode 100644 index 0000000..54c6598 --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperModels/Excel/ExcelMergeParameters.cs @@ -0,0 +1,10 @@ + +namespace BusinessLogics.OfficePackage.HelperModels.Excel +{ + public class ExcelMergeParameters + { + public string CellFromName { get; set; } = string.Empty; + public string CellToName { get; set; } = string.Empty; + public string Merge => $"{CellFromName}:{CellToName}"; + } +} diff --git a/BussinesLogic/OfficePackage/HelperModels/Pdf/PdfInfo.cs b/BussinesLogic/OfficePackage/HelperModels/Pdf/PdfInfo.cs new file mode 100644 index 0000000..39f06eb --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperModels/Pdf/PdfInfo.cs @@ -0,0 +1,14 @@ + +namespace BusinessLogics.OfficePackage.HelperModels.Pdf +{ + public class PdfInfo + { + public string? FileName { get; set; } + public Stream? Stream { get; set; } + + public string Title { get; set; } = string.Empty; + public DateOnly DateFrom { get; set; } + public DateOnly DateTo { get; set; } + public List ReportObjects { get; set; } = new(); + } +} diff --git a/BussinesLogic/OfficePackage/HelperModels/Pdf/PdfParagraph.cs b/BussinesLogic/OfficePackage/HelperModels/Pdf/PdfParagraph.cs new file mode 100644 index 0000000..d792521 --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperModels/Pdf/PdfParagraph.cs @@ -0,0 +1,11 @@ +using BusinessLogics.OfficePackage.HelperEnums; + +namespace BusinessLogics.OfficePackage.HelperModels.Pdf +{ + public class PdfParagraph + { + public string Text { get; set; } = string.Empty; + public string Style { get; set; } = string.Empty; + public PdfParagraphAlignmentType ParagraphAlignment { get; set; } + } +} diff --git a/BussinesLogic/OfficePackage/HelperModels/Pdf/PdfRowParameters.cs b/BussinesLogic/OfficePackage/HelperModels/Pdf/PdfRowParameters.cs new file mode 100644 index 0000000..25100ca --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperModels/Pdf/PdfRowParameters.cs @@ -0,0 +1,11 @@ +using BusinessLogics.OfficePackage.HelperEnums; + +namespace BusinessLogics.OfficePackage.HelperModels.Pdf +{ + public class PdfRowParameters + { + public List Texts { get; set; } = new(); + public string Style { get; set; } = string.Empty; + public PdfParagraphAlignmentType ParagraphAlignment { get; set; } + } +} diff --git a/BussinesLogic/OfficePackage/HelperModels/Word/WordInfo.cs b/BussinesLogic/OfficePackage/HelperModels/Word/WordInfo.cs new file mode 100644 index 0000000..9233e7c --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperModels/Word/WordInfo.cs @@ -0,0 +1,12 @@ + +namespace BusinessLogics.OfficePackage.HelperModels.Word +{ + public class WordInfo + { + public string? FileName { get; set; } + public Stream? Stream { get; set; } + + public string Title { get; set; } = string.Empty; + public List ReportObjects { get; set; } = new(); + } +} diff --git a/BussinesLogic/OfficePackage/HelperModels/Word/WordParagraph.cs b/BussinesLogic/OfficePackage/HelperModels/Word/WordParagraph.cs new file mode 100644 index 0000000..b57cabc --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperModels/Word/WordParagraph.cs @@ -0,0 +1,9 @@ + +namespace BusinessLogics.OfficePackage.HelperModels.Word +{ + public class WordParagraph + { + public List<(string, WordTextProperties)> Texts { get; set; } = new(); + public WordTextProperties? TextProperties { get; set; } + } +} diff --git a/BussinesLogic/OfficePackage/HelperModels/Word/WordTextProperties.cs b/BussinesLogic/OfficePackage/HelperModels/Word/WordTextProperties.cs new file mode 100644 index 0000000..1a9e966 --- /dev/null +++ b/BussinesLogic/OfficePackage/HelperModels/Word/WordTextProperties.cs @@ -0,0 +1,11 @@ +using BusinessLogics.OfficePackage.HelperEnums; + +namespace BusinessLogics.OfficePackage.HelperModels.Word +{ + public class WordTextProperties + { + public string Size { get; set; } = string.Empty; + public bool Bold { get; set; } + public WordJustificationType JustificationType { get; set; } + } +} diff --git a/BussinesLogic/OfficePackage/Implements/SaveToExcel.cs b/BussinesLogic/OfficePackage/Implements/SaveToExcel.cs new file mode 100644 index 0000000..5243101 --- /dev/null +++ b/BussinesLogic/OfficePackage/Implements/SaveToExcel.cs @@ -0,0 +1,304 @@ +using BankBusinessLogics.OfficePackage.HelperEnums; +using DocumentFormat.OpenXml.Office2010.Excel; +using DocumentFormat.OpenXml.Office2013.Excel; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Spreadsheet; +using DocumentFormat.OpenXml; +using BankBusinessLogics.OfficePackage.HelperModels.Excel; + +namespace BankBusinessLogics.OfficePackage.Implements +{ + public class SaveToExcel : AbstractSaveToExcel + { + private SpreadsheetDocument? _spreadsheetDocument; + + private SharedStringTablePart? _shareStringPart; + + private Worksheet? _worksheet; + + /// + /// Настройка стилей для файла + /// + /// + private static void CreateStyles(WorkbookPart workbookpart) + { + var sp = workbookpart.AddNewPart(); + sp.Stylesheet = new Stylesheet(); + + var fonts = new Fonts() { Count = 2U, KnownFonts = true }; + + var fontUsual = new Font(); + fontUsual.Append(new FontSize() { Val = 12D }); + fontUsual.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Theme = 1U }); + fontUsual.Append(new FontName() { Val = "Times New Roman" }); + fontUsual.Append(new FontFamilyNumbering() { Val = 2 }); + fontUsual.Append(new FontScheme() { Val = FontSchemeValues.Minor }); + + var fontTitle = new Font(); + fontTitle.Append(new Bold()); + fontTitle.Append(new FontSize() { Val = 14D }); + fontTitle.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Theme = 1U }); + fontTitle.Append(new FontName() { Val = "Times New Roman" }); + fontTitle.Append(new FontFamilyNumbering() { Val = 2 }); + fontTitle.Append(new FontScheme() { Val = FontSchemeValues.Minor }); + + fonts.Append(fontUsual); + fonts.Append(fontTitle); + + var fills = new Fills() { Count = 2U }; + + var fill1 = new Fill(); + fill1.Append(new PatternFill() { PatternType = PatternValues.None }); + + var fill2 = new Fill(); + fill2.Append(new PatternFill() { PatternType = PatternValues.Gray125 }); + + fills.Append(fill1); + fills.Append(fill2); + + var borders = new Borders() { Count = 2U }; + + var borderNoBorder = new Border(); + borderNoBorder.Append(new LeftBorder()); + borderNoBorder.Append(new RightBorder()); + borderNoBorder.Append(new TopBorder()); + borderNoBorder.Append(new BottomBorder()); + borderNoBorder.Append(new DiagonalBorder()); + + var borderThin = new Border(); + + var leftBorder = new LeftBorder() { Style = BorderStyleValues.Thin }; + leftBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U }); + + var rightBorder = new RightBorder() { Style = BorderStyleValues.Thin }; + rightBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U }); + + var topBorder = new TopBorder() { Style = BorderStyleValues.Thin }; + topBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U }); + + var bottomBorder = new BottomBorder() { Style = BorderStyleValues.Thin }; + bottomBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U }); + + borderThin.Append(leftBorder); + borderThin.Append(rightBorder); + borderThin.Append(topBorder); + borderThin.Append(bottomBorder); + borderThin.Append(new DiagonalBorder()); + + borders.Append(borderNoBorder); + borders.Append(borderThin); + + var cellStyleFormats = new CellStyleFormats() { Count = 1U }; + var cellFormatStyle = new CellFormat() { NumberFormatId = 0U, FontId = 0U, FillId = 0U, BorderId = 0U }; + + cellStyleFormats.Append(cellFormatStyle); + + var cellFormats = new CellFormats() { Count = 3U }; + var cellFormatFont = new CellFormat() { NumberFormatId = 0U, FontId = 0U, FillId = 0U, BorderId = 0U, FormatId = 0U, ApplyFont = true }; + var cellFormatFontAndBorder = new CellFormat() { NumberFormatId = 0U, FontId = 0U, FillId = 0U, BorderId = 1U, FormatId = 0U, ApplyFont = true, ApplyBorder = true }; + var cellFormatTitle = new CellFormat() { NumberFormatId = 0U, FontId = 1U, FillId = 0U, BorderId = 0U, FormatId = 0U, Alignment = new Alignment() { Vertical = VerticalAlignmentValues.Center, WrapText = true, Horizontal = HorizontalAlignmentValues.Center }, ApplyFont = true }; + + cellFormats.Append(cellFormatFont); + cellFormats.Append(cellFormatFontAndBorder); + cellFormats.Append(cellFormatTitle); + + var cellStyles = new CellStyles() { Count = 1U }; + + cellStyles.Append(new CellStyle() { Name = "Normal", FormatId = 0U, BuiltinId = 0U }); + + var differentialFormats = new DocumentFormat.OpenXml.Office2013.Excel.DifferentialFormats() { Count = 0U }; + + var tableStyles = new TableStyles() { Count = 0U, DefaultTableStyle = "TableStyleMedium2", DefaultPivotStyle = "PivotStyleLight16" }; + + var stylesheetExtensionList = new StylesheetExtensionList(); + + var stylesheetExtension1 = new StylesheetExtension() { Uri = "{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}" }; + stylesheetExtension1.AddNamespaceDeclaration("x14", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"); + stylesheetExtension1.Append(new SlicerStyles() { DefaultSlicerStyle = "SlicerStyleLight1" }); + + var stylesheetExtension2 = new StylesheetExtension() { Uri = "{9260A510-F301-46a8-8635-F512D64BE5F5}" }; + stylesheetExtension2.AddNamespaceDeclaration("x15", "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"); + stylesheetExtension2.Append(new TimelineStyles() { DefaultTimelineStyle = "TimeSlicerStyleLight1" }); + + stylesheetExtensionList.Append(stylesheetExtension1); + stylesheetExtensionList.Append(stylesheetExtension2); + + sp.Stylesheet.Append(fonts); + sp.Stylesheet.Append(fills); + sp.Stylesheet.Append(borders); + sp.Stylesheet.Append(cellStyleFormats); + sp.Stylesheet.Append(cellFormats); + sp.Stylesheet.Append(cellStyles); + sp.Stylesheet.Append(differentialFormats); + sp.Stylesheet.Append(tableStyles); + sp.Stylesheet.Append(stylesheetExtensionList); + } + + /// + /// Получение номера стиля из типа + /// + /// + /// + private static uint GetStyleValue(ExcelStyleInfoType styleInfo) + { + return styleInfo switch + { + ExcelStyleInfoType.Title => 2U, + ExcelStyleInfoType.TextWithBroder => 1U, + ExcelStyleInfoType.Text => 0U, + _ => 0U, + }; + } + + protected override void CreateExcel(ExcelInfo info) + { + if (info.Stream != null) + { + _spreadsheetDocument = SpreadsheetDocument.Create(info.Stream, SpreadsheetDocumentType.Workbook); + } + else if (info.FileName != null) + { + _spreadsheetDocument = SpreadsheetDocument.Create(info.FileName, SpreadsheetDocumentType.Workbook); + } + else + { + throw new ArgumentException("Книга не может быть создана поскольку не было указано ни имя файла, ни поток, куда файл сохранится", nameof(info)); + + } + // Создаем книгу (в ней хранятся листы) + var workbookpart = _spreadsheetDocument.AddWorkbookPart(); + workbookpart.Workbook = new Workbook(); + + CreateStyles(workbookpart); + + // Получаем/создаем хранилище текстов для книги + _shareStringPart = _spreadsheetDocument.WorkbookPart!.GetPartsOfType().Any() + ? _spreadsheetDocument.WorkbookPart.GetPartsOfType().First() + : _spreadsheetDocument.WorkbookPart.AddNewPart(); + + // Создаем SharedStringTable, если его нет + if (_shareStringPart.SharedStringTable == null) + { + _shareStringPart.SharedStringTable = new SharedStringTable(); + } + + // Создаем лист в книгу + var worksheetPart = workbookpart.AddNewPart(); + worksheetPart.Worksheet = new Worksheet(new SheetData()); + + // Добавляем лист в книгу + var sheets = _spreadsheetDocument.WorkbookPart.Workbook.AppendChild(new Sheets()); + var sheet = new Sheet() + { + Id = _spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart), + SheetId = 1, + Name = "Лист" + }; + sheets.Append(sheet); + + _worksheet = worksheetPart.Worksheet; + } + + protected override void InsertCellInWorksheet(ExcelCellParameters excelParams) + { + if (_worksheet == null || _shareStringPart == null) + { + return; + } + var sheetData = _worksheet.GetFirstChild(); + if (sheetData == null) + { + return; + } + + // Ищем строку, либо добавляем ее + Row row; + if (sheetData.Elements().Where(r => r.RowIndex! == excelParams.RowIndex).Any()) + { + row = sheetData.Elements().Where(r => r.RowIndex! == excelParams.RowIndex).First(); + } + else + { + row = new Row() { RowIndex = excelParams.RowIndex }; + sheetData.Append(row); + } + + // Ищем нужную ячейку + Cell cell; + if (row.Elements().Where(c => c.CellReference!.Value == excelParams.CellReference).Any()) + { + cell = row.Elements().Where(c => c.CellReference!.Value == excelParams.CellReference).First(); + } + else + { + // Все ячейки должны быть последовательно друг за другом расположены + // нужно определить, после какой вставлять + Cell? refCell = null; + foreach (Cell rowCell in row.Elements()) + { + if (string.Compare(rowCell.CellReference!.Value, excelParams.CellReference, true) > 0) + { + refCell = rowCell; + break; + } + } + + var newCell = new Cell() { CellReference = excelParams.CellReference }; + row.InsertBefore(newCell, refCell); + + cell = newCell; + } + + // вставляем новый текст + _shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new Text(excelParams.Text))); + _shareStringPart.SharedStringTable.Save(); + + cell.CellValue = new CellValue((_shareStringPart.SharedStringTable.Elements().Count() - 1).ToString()); + cell.DataType = new EnumValue(CellValues.SharedString); + cell.StyleIndex = GetStyleValue(excelParams.StyleInfo); + } + + protected override void MergeCells(ExcelMergeParameters excelParams) + { + if (_worksheet == null) + { + return; + } + MergeCells mergeCells; + + if (_worksheet.Elements().Any()) + { + mergeCells = _worksheet.Elements().First(); + } + else + { + mergeCells = new MergeCells(); + + if (_worksheet.Elements().Any()) + { + _worksheet.InsertAfter(mergeCells, _worksheet.Elements().First()); + } + else + { + _worksheet.InsertAfter(mergeCells, _worksheet.Elements().First()); + } + } + + var mergeCell = new MergeCell() + { + Reference = new StringValue(excelParams.Merge) + }; + mergeCells.Append(mergeCell); + } + + protected override void SaveExcel(ExcelInfo info) + { + if (_spreadsheetDocument == null) + { + return; + } + _spreadsheetDocument.WorkbookPart!.Workbook.Save(); + _spreadsheetDocument.Close(); + } + } +} diff --git a/BussinesLogic/OfficePackage/Implements/SaveToPdf.cs b/BussinesLogic/OfficePackage/Implements/SaveToPdf.cs new file mode 100644 index 0000000..5bc79dd --- /dev/null +++ b/BussinesLogic/OfficePackage/Implements/SaveToPdf.cs @@ -0,0 +1,130 @@ +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml; +using MigraDoc.DocumentObjectModel; +using MigraDoc.DocumentObjectModel.Tables; +using MigraDoc.Rendering; +using BankBusinessLogics.OfficePackage.HelperEnums; +using BankBusinessLogics.OfficePackage.HelperModels.Pdf; +using BankBusinessLogics.OfficePackage; + +namespace BankBusinessLogics.OfficePackage.Implements +{ + public class SaveToPdf : AbstractSaveToPdf + { + private Document? _document; + + private Section? _section; + + private Table? _table; + + private static ParagraphAlignment GetParagraphAlignment(PdfParagraphAlignmentType type) + { + return type switch + { + PdfParagraphAlignmentType.Center => ParagraphAlignment.Center, + PdfParagraphAlignmentType.Left => ParagraphAlignment.Left, + PdfParagraphAlignmentType.Rigth => ParagraphAlignment.Right, + _ => ParagraphAlignment.Justify, + }; + } + + /// + /// Создание стилей для документа + /// + /// + private static void DefineStyles(Document document) + { + var style = document.Styles["Normal"]; + style.Font.Name = "Times New Roman"; + style.Font.Size = 14; + + style = document.Styles.AddStyle("NormalTitle", "Normal"); + style.Font.Bold = true; + } + + protected override void CreatePdf(PdfInfo info) + { + _document = new Document(); + DefineStyles(_document); + + _section = _document.AddSection(); + } + + protected override void CreateParagraph(PdfParagraph pdfParagraph) + { + if (_section == null) + { + return; + } + var paragraph = _section.AddParagraph(pdfParagraph.Text); + paragraph.Format.SpaceAfter = "1cm"; + paragraph.Format.Alignment = GetParagraphAlignment(pdfParagraph.ParagraphAlignment); + paragraph.Style = pdfParagraph.Style; + } + + protected override void CreateTable(List columns) + { + if (_document == null) + { + return; + } + _table = _document.LastSection.AddTable(); + + foreach (var elem in columns) + { + _table.AddColumn(elem); + } + } + + protected override void CreateRow(PdfRowParameters rowParameters) + { + if (_table == null) + { + return; + } + var row = _table.AddRow(); + for (int i = 0; i < rowParameters.Texts.Count; ++i) + { + row.Cells[i].AddParagraph(rowParameters.Texts[i]); + + if (!string.IsNullOrEmpty(rowParameters.Style)) + { + row.Cells[i].Style = rowParameters.Style; + } + + Unit borderWidth = 0.5; + + row.Cells[i].Borders.Left.Width = borderWidth; + row.Cells[i].Borders.Right.Width = borderWidth; + row.Cells[i].Borders.Top.Width = borderWidth; + row.Cells[i].Borders.Bottom.Width = borderWidth; + + row.Cells[i].Format.Alignment = GetParagraphAlignment(rowParameters.ParagraphAlignment); + row.Cells[i].VerticalAlignment = VerticalAlignment.Center; + } + } + + protected override void SavePdf(PdfInfo info) + { + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); + var renderer = new PdfDocumentRenderer(true) + { + Document = _document + }; + renderer.RenderDocument(); + if (info.Stream != null) + { + renderer.PdfDocument.Save(info.Stream); + } + else if (info.FileName != null) + { + renderer.PdfDocument.Save(info.FileName); + } + else + { + throw new ArgumentException("Книга не может быть создана поскольку не было указано ни имя файла, ни поток, куда файл сохранится", nameof(info)); + + } + } + } +} \ No newline at end of file diff --git a/BussinesLogic/OfficePackage/Implements/SaveToWord.cs b/BussinesLogic/OfficePackage/Implements/SaveToWord.cs new file mode 100644 index 0000000..c10b1b8 --- /dev/null +++ b/BussinesLogic/OfficePackage/Implements/SaveToWord.cs @@ -0,0 +1,146 @@ +using DocumentFormat.OpenXml; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; +using BankBusinessLogics.OfficePackage.HelperEnums; +using BankBusinessLogics.OfficePackage.HelperModels.Word; +using BankBusinessLogics.OfficePackage; + +namespace BankBusinessLogics.OfficePackage.Implements; + +public class SaveToWord : AbstractSaveToWord +{ + private WordprocessingDocument? _wordDocument; + + private Body? _docBody; + + /// + /// Получение типа выравнивания + /// + /// + /// + private static JustificationValues GetJustificationValues(WordJustificationType type) + { + return type switch + { + WordJustificationType.Both => JustificationValues.Both, + WordJustificationType.Center => JustificationValues.Center, + _ => JustificationValues.Left, + }; + } + + /// + /// Настройки страницы + /// + /// + private static SectionProperties CreateSectionProperties() + { + var properties = new SectionProperties(); + + var pageSize = new PageSize + { + Orient = PageOrientationValues.Portrait + }; + + properties.AppendChild(pageSize); + + return properties; + } + + /// + /// Задание форматирования для абзаца + /// + /// + /// + private static ParagraphProperties? CreateParagraphProperties(WordTextProperties? paragraphProperties) + { + if (paragraphProperties == null) + { + return null; + } + + var properties = new ParagraphProperties(); + + properties.AppendChild(new Justification() + { + Val = GetJustificationValues(paragraphProperties.JustificationType) + }); + + properties.AppendChild(new SpacingBetweenLines + { + LineRule = LineSpacingRuleValues.Auto + }); + + properties.AppendChild(new Indentation()); + + var paragraphMarkRunProperties = new ParagraphMarkRunProperties(); + if (!string.IsNullOrEmpty(paragraphProperties.Size)) + { + paragraphMarkRunProperties.AppendChild(new FontSize { Val = paragraphProperties.Size }); + } + properties.AppendChild(paragraphMarkRunProperties); + + return properties; + } + + protected override void CreateWord(WordInfo info) + { + if (info.FileName != null) + { + _wordDocument = WordprocessingDocument.Create(info.FileName, WordprocessingDocumentType.Document); + } + else if (info.Stream != null) + { + _wordDocument = WordprocessingDocument.Create(info.Stream, WordprocessingDocumentType.Document); + } + else + { + throw new ArgumentException("Документ не может быть создан поскольку не был указан ни имя файла, ни поток, куда файл сохранится", nameof(info)); + } + MainDocumentPart mainPart = _wordDocument.AddMainDocumentPart(); + mainPart.Document = new Document(); + _docBody = mainPart.Document.AppendChild(new Body()); + } + + protected override void CreateParagraph(WordParagraph paragraph) + { + if (_docBody == null || paragraph == null) + { + return; + } + var docParagraph = new Paragraph(); + + docParagraph.AppendChild(CreateParagraphProperties(paragraph.TextProperties)); + + foreach (var run in paragraph.Texts) + { + var docRun = new Run(); + + var properties = new RunProperties(); + properties.AppendChild(new FontSize { Val = run.Item2.Size }); + if (run.Item2.Bold) + { + properties.AppendChild(new Bold()); + } + docRun.AppendChild(properties); + + docRun.AppendChild(new Text { Text = run.Item1, Space = SpaceProcessingModeValues.Preserve }); + + docParagraph.AppendChild(docRun); + } + + _docBody.AppendChild(docParagraph); + } + + protected override void SaveWord(WordInfo info) + { + if (_docBody == null || _wordDocument == null) + { + return; + } + _docBody.AppendChild(CreateSectionProperties()); + + _wordDocument.MainDocumentPart!.Document.Save(); + + _wordDocument.Close(); + } +} diff --git a/Contracts/BindingModel/ClientBindingModel.cs b/Contracts/BindingModel/ClientBindingModel.cs new file mode 100644 index 0000000..bedf3ad --- /dev/null +++ b/Contracts/BindingModel/ClientBindingModel.cs @@ -0,0 +1,24 @@ +using DataModels.HelperInterfaces; +using DataModels; + + +namespace Contracts.BindingModel +{ + public class ClientBindingModel : IClientModel + { + + public string FirstName { get; set; } = string.Empty; + + public string LastName { get; set; } = string.Empty; + + public string? MiddleName { get; set; } + + public string PhoneNumber { get; set; } = string.Empty; + + public string Password { get; set; } = string.Empty; + + public int Id { get; set; } + + public string Email { get; set; } = string.Empty; + } +} diff --git a/Contracts/BindingModel/EmployeeBindingModel.cs b/Contracts/BindingModel/EmployeeBindingModel.cs new file mode 100644 index 0000000..f5b252e --- /dev/null +++ b/Contracts/BindingModel/EmployeeBindingModel.cs @@ -0,0 +1,23 @@ +using DataModels; + +namespace Contracts.BindingModel +{ + public class EmployeeBindingModel : IEmployeeModel + { + public string Post { get; set; } = string.Empty; + + public string FirstName { get; set; } = string.Empty; + + public string LastName { get; set; } = string.Empty; + + public string? MiddleName { get; set; } + + public string PhoneNumber { get; set; } = string.Empty; + + public string Password { get; set; } = string.Empty; + + public int Id { get; set; } + + public string Email { get; set; } = string.Empty; + } +} diff --git a/Contracts/BindingModel/MailConfigBindingModel.cs b/Contracts/BindingModel/MailConfigBindingModel.cs new file mode 100644 index 0000000..fffbaf3 --- /dev/null +++ b/Contracts/BindingModel/MailConfigBindingModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Contracts.BindingModel +{ + public class MailConfigBindingModel + { + public string MailLogin { get; set; } = string.Empty; + public string MailPassword { get; set; } = string.Empty; + public string SmtpClientHost { get; set; } = string.Empty; + public int SmtpClientPort { get; set; } + public string PopHost { get; set; } = string.Empty; + public int PopPort { get; set; } + } +} diff --git a/Contracts/BindingModel/MailSendInfoBindingModel.cs b/Contracts/BindingModel/MailSendInfoBindingModel.cs new file mode 100644 index 0000000..9738a62 --- /dev/null +++ b/Contracts/BindingModel/MailSendInfoBindingModel.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Contracts.BindingModel +{ + public class MailSendInfoBindingModel + { + public string MailAddress { get; set; } = string.Empty; + public string Subject { get; set; } = string.Empty; + public string Text { get; set; } = string.Empty; + + /// + /// Список потоков и c именами файлов. + /// Потоки опциональны и нужны только если файла нет на диске. + /// + public List> FilesStreams { get; set; } = new(); + } +} diff --git a/Contracts/BindingModel/OperationBindingModel.cs b/Contracts/BindingModel/OperationBindingModel.cs new file mode 100644 index 0000000..f26e140 --- /dev/null +++ b/Contracts/BindingModel/OperationBindingModel.cs @@ -0,0 +1,17 @@ +using DataModels; + +namespace Contracts.BindingModel +{ + public class OperationBindingModel : IOperationModel + { + public string Model { get; set; } = string.Empty; + + public string Mark { get; set; } = string.Empty; + + public double Price { get; set; } + + public int Id { get; set; } + + public int EmployeeId { get; set; } + } +} \ No newline at end of file diff --git a/Contracts/BindingModel/OrderBindingModel.cs b/Contracts/BindingModel/OrderBindingModel.cs new file mode 100644 index 0000000..02286b9 --- /dev/null +++ b/Contracts/BindingModel/OrderBindingModel.cs @@ -0,0 +1,17 @@ +using DataModels.ProxyModels; +using DataModels; + +namespace Contracts.BindingModel +{ + public class OrderBindingModel : IOrderModel + { + public int OrderId { get; set; } + + public string NameOrder { get; set; } = string.Empty; + + public double Price { get; set; } + public Dictionary PurchasesModels { get; set; } = new(); + + public int Id { get; set; } + } +} \ No newline at end of file diff --git a/Contracts/BindingModel/PaymentBindingModel.cs b/Contracts/BindingModel/PaymentBindingModel.cs new file mode 100644 index 0000000..fe5bd58 --- /dev/null +++ b/Contracts/BindingModel/PaymentBindingModel.cs @@ -0,0 +1,16 @@ +using DataModels; + + +namespace Contracts.BindingModel +{ + public class PaymentBindingModel : IPaymentModel + { + public DateOnly Date { get; set; } = DateOnly.FromDateTime(DateTime.Now); + + public double PaidPrice { get; set; } + + public int Id { get; set; } + + public int OperationByPurchaseId { get; set; } + } +} \ No newline at end of file diff --git a/Contracts/BindingModel/PurchaseBindingModel.cs b/Contracts/BindingModel/PurchaseBindingModel.cs new file mode 100644 index 0000000..def51a1 --- /dev/null +++ b/Contracts/BindingModel/PurchaseBindingModel.cs @@ -0,0 +1,15 @@ +using DataModels; +using DataModels.ProxyModels; + +namespace Contracts.BindingModel +{ + public class PurchaseBindingModel : IPurchaseModel + { + public int ClientId { get; set; } + public DateOnly DatePurchase { get; set; } + public Dictionary OperationsModel { get; set; } = new(); + public List CostsModel { get; set; } = new(); + + public int Id { get; set; } + } +} \ No newline at end of file diff --git a/Contracts/BindingModel/ReportBindingModel.cs b/Contracts/BindingModel/ReportBindingModel.cs new file mode 100644 index 0000000..fb32810 --- /dev/null +++ b/Contracts/BindingModel/ReportBindingModel.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Contracts.BindingModel +{ + public class ReportBindingModel + { + public string? FileName { get; set; } + public Stream? Stream { get; set; } + + /// + /// Массив айдишников по которым происходит выборка + /// + public int[] Ids { get; set; } + } +} diff --git a/Contracts/BindingModel/ReportDateRangeBindingModel.cs b/Contracts/BindingModel/ReportDateRangeBindingModel.cs new file mode 100644 index 0000000..5f44b23 --- /dev/null +++ b/Contracts/BindingModel/ReportDateRangeBindingModel.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Contracts.BindingModel +{ + public class ReportDateRangeBindingModel + { + public string? FileName { get; set; } + public Stream? Stream { get; set; } + + public DateOnly DateFrom { get; set; } + public DateOnly DateTo { get; set; } + } +} diff --git a/Contracts/BusinessLogicContracts/IClientLogic.cs b/Contracts/BusinessLogicContracts/IClientLogic.cs new file mode 100644 index 0000000..43cbbc1 --- /dev/null +++ b/Contracts/BusinessLogicContracts/IClientLogic.cs @@ -0,0 +1,12 @@ +using Contracts.SearchModels; +using Contracts.ViewModels; +using Contracts.BindingModel; + +namespace Contracts.BusinessLogicContracts +{ + public interface IClientLogic + { + ClientViewModel ReadElement(ClientSearchModel model); + bool Create(ClientBindingModel model); + } +} diff --git a/Contracts/BusinessLogicContracts/ICostLogic.cs b/Contracts/BusinessLogicContracts/ICostLogic.cs new file mode 100644 index 0000000..bdb8d28 --- /dev/null +++ b/Contracts/BusinessLogicContracts/ICostLogic.cs @@ -0,0 +1,15 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.BusinessLogicContracts +{ + public interface IOrderLogic + { + List ReadList(OrderSearchModel? model = null); + OrderViewModel ReadElement(OrderSearchModel model); + bool Create(OrderBindingModel model); + bool Update(OrderBindingModel model); + bool Delete(OrderBindingModel model); + } +} diff --git a/Contracts/BusinessLogicContracts/IEmployeeLogic.cs b/Contracts/BusinessLogicContracts/IEmployeeLogic.cs new file mode 100644 index 0000000..e222c18 --- /dev/null +++ b/Contracts/BusinessLogicContracts/IEmployeeLogic.cs @@ -0,0 +1,12 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.BusinessLogicContracts +{ + public interface IEmployeeLogic + { + EmployeeViewModel ReadElement(EmployeeSearchModel model); + bool Create(EmployeeBindingModel model); + } +} \ No newline at end of file diff --git a/Contracts/BusinessLogicContracts/IOperationLogic.cs b/Contracts/BusinessLogicContracts/IOperationLogic.cs new file mode 100644 index 0000000..a18e79f --- /dev/null +++ b/Contracts/BusinessLogicContracts/IOperationLogic.cs @@ -0,0 +1,15 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.BusinessLogicContracts +{ + public interface IOperationLogic + { + List ReadList(OperationSearchModel? model = null); + OperationViewModel ReadElement(OperationSearchModel model); + bool Create(OperationBindingModel model); + bool Update(OperationBindingModel model); + bool Delete(OperationBindingModel model); + } +} \ No newline at end of file diff --git a/Contracts/BusinessLogicContracts/IPaymentLogic.cs b/Contracts/BusinessLogicContracts/IPaymentLogic.cs new file mode 100644 index 0000000..eedbdc8 --- /dev/null +++ b/Contracts/BusinessLogicContracts/IPaymentLogic.cs @@ -0,0 +1,18 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.BusinessLogicContracts +{ + public interface IPaymentLogic + { + List ReadList(PaymentSearchModel model); + PaymentViewModel ReadElement(PaymentSearchModel model); + bool Create(PaymentBindingModel model); + + /// + /// Получение полной и оплаченной стоимости в бизнес логике, по обследованию и талону + /// + bool GetPaymentInfo(PaymentSearchModel model, out double fullPrice, out double paidPrice); + } +} \ No newline at end of file diff --git a/Contracts/BusinessLogicContracts/IPurchaseLogic.cs b/Contracts/BusinessLogicContracts/IPurchaseLogic.cs new file mode 100644 index 0000000..870d8b1 --- /dev/null +++ b/Contracts/BusinessLogicContracts/IPurchaseLogic.cs @@ -0,0 +1,16 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.ViewModels; + + +namespace Contracts.BusinessLogicContracts +{ + public interface IPurchaseLogic + { + List ReadList(PurchaseSearchModel? model = null); + PurchaseViewModel ReadElement(PurchaseSearchModel model); + bool Create(PurchaseBindingModel model); + bool Update(PurchaseBindingModel model); + bool Delete(PurchaseBindingModel model); + } +} diff --git a/Contracts/BusinessLogicContracts/IReportLogic.cs b/Contracts/BusinessLogicContracts/IReportLogic.cs new file mode 100644 index 0000000..89c2093 --- /dev/null +++ b/Contracts/BusinessLogicContracts/IReportLogic.cs @@ -0,0 +1,23 @@ +using Contracts.BindingModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Contracts.BusinessLogicContracts +{ + public interface IReportLogic + { + void SavePurchasesToWord(ReportBindingModel option); + + void SavePurchasesToExcel(ReportBindingModel option); + + void SendPaymentsToEmail(ReportDateRangeBindingModel option, string email); + void SaveOperationsToWord(ReportBindingModel option); + + void SaveOperationsToExcel(ReportBindingModel option); + + void SendCostsToEmail(ReportDateRangeBindingModel option, string email); + } +} diff --git a/Contracts/Contracts.csproj b/Contracts/Contracts.csproj new file mode 100644 index 0000000..e78682b --- /dev/null +++ b/Contracts/Contracts.csproj @@ -0,0 +1,24 @@ + + + + net8.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/Contracts/SearchModels/ClientSearchModel.cs b/Contracts/SearchModels/ClientSearchModel.cs new file mode 100644 index 0000000..42ca6a6 --- /dev/null +++ b/Contracts/SearchModels/ClientSearchModel.cs @@ -0,0 +1,9 @@ +namespace Contracts.SearchModels +{ + public class ClientSearchModel + { + public int? Id { get; set; } + public string? PhoneNumber { get; set; } + public string? Password { get; set; } + } +} diff --git a/Contracts/SearchModels/EmployeeSearchModel.cs b/Contracts/SearchModels/EmployeeSearchModel.cs new file mode 100644 index 0000000..5f846f7 --- /dev/null +++ b/Contracts/SearchModels/EmployeeSearchModel.cs @@ -0,0 +1,9 @@ +namespace Contracts.SearchModels +{ + public class EmployeeSearchModel + { + public int? Id { get; set; } + public string? PhoneNumber { get; set; } + public string? Password { get; set; } + } +} diff --git a/Contracts/SearchModels/OperationSearchModel.cs b/Contracts/SearchModels/OperationSearchModel.cs new file mode 100644 index 0000000..8d9e9c7 --- /dev/null +++ b/Contracts/SearchModels/OperationSearchModel.cs @@ -0,0 +1,12 @@ +namespace Contracts.SearchModels +{ + public class OperationSearchModel + { + public int? Id { get; set; } + public int? EmployeeId { get; set; } + public string Model { get; set; } = string.Empty; + public string Mark { get; set; } = string.Empty; + public int Price { get; set; } + public List? PurchasesIds { get; set; } + } +} \ No newline at end of file diff --git a/Contracts/SearchModels/OrderSearchModel.cs b/Contracts/SearchModels/OrderSearchModel.cs new file mode 100644 index 0000000..c65d075 --- /dev/null +++ b/Contracts/SearchModels/OrderSearchModel.cs @@ -0,0 +1,8 @@ +namespace Contracts.SearchModels +{ + public class OrderSearchModel + { + public int? Id { get; set; } + public int? EmployeeId { get; set; } + } +} \ No newline at end of file diff --git a/Contracts/SearchModels/PaymentSearchModel.cs b/Contracts/SearchModels/PaymentSearchModel.cs new file mode 100644 index 0000000..b9d55ba --- /dev/null +++ b/Contracts/SearchModels/PaymentSearchModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Contracts.SearchModels +{ + public class PaymentSearchModel + { + public int? Id { get; set; } + public int? OperationId { get; set; } + public int? PurchaseId { get; set; } + + public DateOnly? DateFrom { get; set; } + public DateOnly? DateTo { get; set; } + } +} \ No newline at end of file diff --git a/Contracts/SearchModels/PurchaseSearchModel.cs b/Contracts/SearchModels/PurchaseSearchModel.cs new file mode 100644 index 0000000..83ada9a --- /dev/null +++ b/Contracts/SearchModels/PurchaseSearchModel.cs @@ -0,0 +1,12 @@ +namespace Contracts.SearchModels +{ + public class PurchaseSearchModel + { + public int? Id { get; set; } + public DateOnly? DateTo { get; set; } + public DateOnly? DateFrom { get; set; } + public int? ClientId { get; set; } + + public List? OperationsIds { get; set; } + } +} diff --git a/Contracts/StoragesContracts/IClientStorage.cs b/Contracts/StoragesContracts/IClientStorage.cs new file mode 100644 index 0000000..b910e18 --- /dev/null +++ b/Contracts/StoragesContracts/IClientStorage.cs @@ -0,0 +1,12 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.StoragesContracts +{ + public interface IClientStorage + { + ClientViewModel? GetElement(ClientSearchModel model); + ClientViewModel? Insert(ClientBindingModel model); + } +} diff --git a/Contracts/StoragesContracts/IEmployeeStorage.cs b/Contracts/StoragesContracts/IEmployeeStorage.cs new file mode 100644 index 0000000..ffcfa55 --- /dev/null +++ b/Contracts/StoragesContracts/IEmployeeStorage.cs @@ -0,0 +1,12 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.StoragesContracts +{ + public interface IEmployeeStorage + { + EmployeeViewModel? GetElement(EmployeeSearchModel model); + EmployeeViewModel? Insert(EmployeeBindingModel model); + } +} diff --git a/Contracts/StoragesContracts/IOperationStorage.cs b/Contracts/StoragesContracts/IOperationStorage.cs new file mode 100644 index 0000000..ca1b096 --- /dev/null +++ b/Contracts/StoragesContracts/IOperationStorage.cs @@ -0,0 +1,16 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.StoragesContracts +{ + public interface IOperationStorage + { + List GetFullList(); + List GetFilteredList(OperationSearchModel model); + OperationViewModel? GetElement(OperationSearchModel model); + OperationViewModel? Insert(OperationBindingModel model); + OperationViewModel? Update(OperationBindingModel model); + OperationViewModel? Delete(OperationBindingModel model); + } +} diff --git a/Contracts/StoragesContracts/IOrderStorage.cs b/Contracts/StoragesContracts/IOrderStorage.cs new file mode 100644 index 0000000..c5071cc --- /dev/null +++ b/Contracts/StoragesContracts/IOrderStorage.cs @@ -0,0 +1,16 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.StoragesContracts +{ + public interface IOrderStorage + { + List GetFullList(); + List GetFilteredList(OrderSearchModel model); + CostViewModel? GetElement(OrderSearchModel model); + CostViewModel? Insert(CostBindingModel model); + CostViewModel? Update(CostBindingModel model); + CostViewModel? Delete(CostBindingModel model); + } +} diff --git a/Contracts/StoragesContracts/IPaymentStorage.cs b/Contracts/StoragesContracts/IPaymentStorage.cs new file mode 100644 index 0000000..4e759cc --- /dev/null +++ b/Contracts/StoragesContracts/IPaymentStorage.cs @@ -0,0 +1,14 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.StoragesContracts +{ + public interface IPaymentStorage + { + List GetFullList(); + List GetFilteredList(PaymentSearchModel model); + PaymentViewModel? GetElement(PaymentSearchModel model); + PaymentViewModel? Insert(PaymentBindingModel model); + } +} \ No newline at end of file diff --git a/Contracts/StoragesContracts/IPurchaseStorage.cs b/Contracts/StoragesContracts/IPurchaseStorage.cs new file mode 100644 index 0000000..f7ea40d --- /dev/null +++ b/Contracts/StoragesContracts/IPurchaseStorage.cs @@ -0,0 +1,18 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.StoragesContracts +{ + public interface IPurchaseStorage + { + List GetFullList(); + List GetFilteredList(PurchaseSearchModel model); + PurchaseViewModel? GetElement(PurchaseSearchModel model); + PurchaseViewModel? Insert(PurchaseBindingModel model); + PurchaseViewModel? Update(PurchaseBindingModel model); + PurchaseViewModel? Delete(PurchaseBindingModel model); + + List GetPaymentsFromPurchaseAndOperation(PurchaseSearchModel modelPurchase, OperationSearchModel modelOperation); + } +} diff --git a/Contracts/ViewModels/ClientViewModel.cs b/Contracts/ViewModels/ClientViewModel.cs new file mode 100644 index 0000000..6f3e8e4 --- /dev/null +++ b/Contracts/ViewModels/ClientViewModel.cs @@ -0,0 +1,23 @@ +using DataModels; +using DataModels.HelperInterfaces; +using System.ComponentModel; + + +namespace Contracts.ViewModels +{ + public class ClientViewModel : IClientModel + { + public int Id { get; set; } + [DisplayName("Фамилия")] + public string LastName { get; set; } = string.Empty; + [DisplayName("Имя")] + public string FirstName { get; set; } = string.Empty; + [DisplayName("Отчество")] + public string? MiddleName { get; set; } = string.Empty; + [DisplayName("Номер телефона")] + public string PhoneNumber { get; set; } = string.Empty; + [DisplayName("Пароль")] + public string Password { get; set; } = string.Empty; + public string Email { get; set; } = string.Empty; + } +} diff --git a/Contracts/ViewModels/EmployeeViewModel.cs b/Contracts/ViewModels/EmployeeViewModel.cs new file mode 100644 index 0000000..ff4a031 --- /dev/null +++ b/Contracts/ViewModels/EmployeeViewModel.cs @@ -0,0 +1,23 @@ +using DataModels; +using System.ComponentModel; + +namespace Contracts.ViewModels +{ + public class EmployeeViewModel : IEmployeeModel + { + public int Id { get; set; } + [DisplayName("Фамилия")] + public string LastName { get; set; } = string.Empty; + [DisplayName("Имя")] + public string FirstName { get; set; } = string.Empty; + [DisplayName("Отчество")] + public string? MiddleName { get; set; } = string.Empty; + [DisplayName("Номер телефона")] + public string PhoneNumber { get; set; } = string.Empty; + [DisplayName("Пароль")] + public string Password { get; set; } = string.Empty; + [DisplayName("Должность")] + public string Post { get; set; } = string.Empty; + public string Email { get; set; } = string.Empty; + } +} \ No newline at end of file diff --git a/Contracts/ViewModels/OperationViewModel.cs b/Contracts/ViewModels/OperationViewModel.cs new file mode 100644 index 0000000..b632220 --- /dev/null +++ b/Contracts/ViewModels/OperationViewModel.cs @@ -0,0 +1,33 @@ +using DataModels; +using System.ComponentModel; +using System.Text; +using System.Text.Json.Serialization; + +namespace Contracts.ViewModels +{ + public class OperationViewModel : IOperationModel + { + public int Id { get; set; } + public int EmployeeId { get; set; } + [DisplayName("Номер телефона сотрудника")] + public string EmployeePhoneNumber { get; set; } = string.Empty; + [DisplayName("Стоимость")] + public double Price { get; set; } + [DisplayName("Вид операции")] + public string Model { get; set; } = string.Empty; + [DisplayName("Тип операции")] + public string Mark { get; set; } = string.Empty; + [JsonIgnore] + public List Purchases { get; set; } = new(); + public override string ToString() + { + var result = new StringBuilder(); + foreach (var purchase in Purchases) + { + result.Append($"Операция вида {Model},Типа {Mark}, Купленная {purchase.DatePurchase.ToShortDateString()}," + + $"в покупе c id: {purchase.Id}\n"); + } + return result.ToString(); + } + } +} \ No newline at end of file diff --git a/Contracts/ViewModels/OrderViewModel.cs b/Contracts/ViewModels/OrderViewModel.cs new file mode 100644 index 0000000..984cd74 --- /dev/null +++ b/Contracts/ViewModels/OrderViewModel.cs @@ -0,0 +1,20 @@ +using DataModels.ProxyModels; +using DataModels; +using System.ComponentModel; + +namespace Contracts.ViewModels +{ + public class OrderViewModel : IOrderModel + { + public int Id { get; set; } + public int OrderId { get; set; } + [DisplayName("Номер телефона сотрудника")] + public string PhoneNumber { get; set; } = string.Empty; + [DisplayName("Наименование")] + public string NameOrder { get; set; } = string.Empty; + [DisplayName("Стоимость")] + public double Price { get; set; } + + public Dictionary PurchaseModels { get; set; } = new(); + } +} diff --git a/Contracts/ViewModels/PaymentViewModel.cs b/Contracts/ViewModels/PaymentViewModel.cs new file mode 100644 index 0000000..d36c490 --- /dev/null +++ b/Contracts/ViewModels/PaymentViewModel.cs @@ -0,0 +1,28 @@ +using DataModels; +using DataModels.ProxyModels; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Contracts.ViewModels +{ + public class PaymentViewModel : IPaymentModel + { + public int Id { get; set; } + public int OperationByPurchaseModelId { get; set; } + [DisplayName("Стоимость")] + public double FullPrice { get; set; } + [DisplayName("Оплаченная стоимость")] + public double PaidPrice { get; set; } + public int OperationByPurchaseId { get; set; } + [DisplayName("Дата оплаты")] + public DateOnly Date { get; set; } = DateOnly.FromDateTime(DateTime.Now); + public OperationByPurchaseModel OperationByPurchase { get; set; } + + // Машины для отчета за период + public OperationViewModel Operation { get; set; } + } +} diff --git a/Contracts/ViewModels/PurchaseViewModel.cs b/Contracts/ViewModels/PurchaseViewModel.cs new file mode 100644 index 0000000..ba37e2d --- /dev/null +++ b/Contracts/ViewModels/PurchaseViewModel.cs @@ -0,0 +1,39 @@ +using DataModels; +using System.ComponentModel; +using DataModels.ProxyModels; +using System.Text; + +namespace Contracts.ViewModels +{ + public class PurchaseViewModel : IPurchaseModel + { + public int Id { get; set; } + public int ClientId { get; set; } + [DisplayName("Логин клиента")] + public string ClientPhoneNumber { get; set; } = string.Empty; + [DisplayName("Дата Покупки")] + public DateOnly DatePurchase { get; set; } = DateOnly.FromDateTime(DateTime.Now); + public Dictionary OperationsModel { get; set; } = new(); + + public List OrderViewModels { get; set; } = new(); + + public List OperationViewModels { get; set; } = new(); + + public override string ToString() + { + var result = new StringBuilder( + $"Сделка, созданная {DatePurchase}, включает в себя операции:"); + for (int i = 0; i < OperationViewModels.Count; i++) + { + var car = OperationViewModels[i]; + if (car == null) + { + break; + } + result.Append($"\n\t{i + 1}. {car.Mark} {car.Model} стоимостью {car.Price}"); + } + return result.ToString(); + } + } +} + \ No newline at end of file diff --git a/DataModel1/DataModel.csproj b/DataModel1/DataModel.csproj new file mode 100644 index 0000000..67eaa0c --- /dev/null +++ b/DataModel1/DataModel.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/DataModel1/HelperInterfaces/IId.cs b/DataModel1/HelperInterfaces/IId.cs new file mode 100644 index 0000000..db8acb4 --- /dev/null +++ b/DataModel1/HelperInterfaces/IId.cs @@ -0,0 +1,7 @@ +namespace DataModels.HelperInterfaces +{ + public interface IId + { + int Id { get; } + } +} diff --git a/DataModel1/IClientModel.cs b/DataModel1/IClientModel.cs new file mode 100644 index 0000000..3b25bc4 --- /dev/null +++ b/DataModel1/IClientModel.cs @@ -0,0 +1,14 @@ +using DataModels.HelperInterfaces; + +namespace DataModels +{ + public interface IClientModel : IId + { + string Email { get; } + string FirstName { get; } + string LastName { get; } + string? MiddleName { get; } + string PhoneNumber { get; } + string Password { get; } + } +} \ No newline at end of file diff --git a/DataModel1/IEmployeeModel.cs b/DataModel1/IEmployeeModel.cs new file mode 100644 index 0000000..ce0b477 --- /dev/null +++ b/DataModel1/IEmployeeModel.cs @@ -0,0 +1,7 @@ +namespace DataModels +{ + public interface IEmployeeModel : IClientModel + { + string Post { get; } + } +} \ No newline at end of file diff --git a/DataModel1/IOperationModel.cs b/DataModel1/IOperationModel.cs new file mode 100644 index 0000000..3d30977 --- /dev/null +++ b/DataModel1/IOperationModel.cs @@ -0,0 +1,12 @@ +using DataModels.HelperInterfaces; + +namespace DataModels +{ + public interface IOperationModel : IId + { + int EmployeeId { get; } + string Model { get; } + string Mark { get; } + double Price { get; } + } +} \ No newline at end of file diff --git a/DataModel1/IOrderModel.cs b/DataModel1/IOrderModel.cs new file mode 100644 index 0000000..2bd1b0e --- /dev/null +++ b/DataModel1/IOrderModel.cs @@ -0,0 +1,11 @@ +using DataModels.HelperInterfaces; + +namespace DataModels +{ + public interface IOrderModel : IId + { + int OrderId { get; } + string NameOrder { get; } + double Price { get; } + } +} diff --git a/DataModel1/IPaymentModel.cs b/DataModel1/IPaymentModel.cs new file mode 100644 index 0000000..befbf3e --- /dev/null +++ b/DataModel1/IPaymentModel.cs @@ -0,0 +1,11 @@ +using DataModels.HelperInterfaces; + +namespace DataModels +{ + public interface IPaymentModel : IId + { + double PaidPrice { get; } + DateOnly Date { get; } + int OperationByPurchaseId { get; } + } +} \ No newline at end of file diff --git a/DataModel1/IPurchaseModel.cs b/DataModel1/IPurchaseModel.cs new file mode 100644 index 0000000..46ced48 --- /dev/null +++ b/DataModel1/IPurchaseModel.cs @@ -0,0 +1,10 @@ +using DataModels.HelperInterfaces; + +namespace DataModels +{ + public interface IPurchaseModel : IId + { + int ClientId { get; } + DateOnly DatePurchase { get; } + } +} \ No newline at end of file diff --git a/DataModel1/ProxyModels/CostByPurchaseModel.cs b/DataModel1/ProxyModels/CostByPurchaseModel.cs new file mode 100644 index 0000000..3392de8 --- /dev/null +++ b/DataModel1/ProxyModels/CostByPurchaseModel.cs @@ -0,0 +1,12 @@ +using DataModels.HelperInterfaces; + +namespace DataModels.ProxyModels +{ + public class CostByPurchaseModel : IId + { + public virtual int Id { get; set; } + public virtual int CostId { get; set; } + public virtual int PurchaseId { get; set; } + public virtual int Count { get; set; } + } +} \ No newline at end of file diff --git a/DataModel1/ProxyModels/OperationByPurchaseModel.cs b/DataModel1/ProxyModels/OperationByPurchaseModel.cs new file mode 100644 index 0000000..21f5244 --- /dev/null +++ b/DataModel1/ProxyModels/OperationByPurchaseModel.cs @@ -0,0 +1,12 @@ +using DataModels.HelperInterfaces; + +namespace DataModels.ProxyModels +{ + public class OperationByPurchaseModel : IId + { + public virtual int Id { get; set; } + public virtual int OperationId { get; set; } + public virtual int PurchaseId { get; set; } + public virtual int CountOperations { get; set; } + } +} \ No newline at end of file diff --git a/DatabaseImplement/AutoShopDB.cs b/DatabaseImplement/AutoShopDB.cs new file mode 100644 index 0000000..fdeed78 --- /dev/null +++ b/DatabaseImplement/AutoShopDB.cs @@ -0,0 +1,31 @@ +using DatabaseImplement.Models; +using Microsoft.EntityFrameworkCore; + +namespace DatabaseImplement +{ + public class AutoShopDB : DbContext + { + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (optionsBuilder.IsConfigured == false) + { + optionsBuilder.UseNpgsql(@" + Host=localhost; + Port=5432; + Database=AutoShopFullNew; + Username=postgres; + Password=55256636a;"); + } + base.OnConfiguring(optionsBuilder); + } + + public virtual DbSet Clients { set; get; } + public virtual DbSet Costs { set; get; } + public virtual DbSet OrderByPurchases { set; get; } + public virtual DbSet Employees { set; get; } + public virtual DbSet Operations { set; get; } + public virtual DbSet OperationByPurchases { set; get; } + public virtual DbSet Payments { set; get; } + public virtual DbSet Purchases { set; get; } + } +} diff --git a/DatabaseImplement/DatabaseImplement.csproj b/DatabaseImplement/DatabaseImplement.csproj new file mode 100644 index 0000000..0c1d671 --- /dev/null +++ b/DatabaseImplement/DatabaseImplement.csproj @@ -0,0 +1,25 @@ + + + + net8.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/DatabaseImplement/Implements/ClientStorage.cs b/DatabaseImplement/Implements/ClientStorage.cs new file mode 100644 index 0000000..df470c6 --- /dev/null +++ b/DatabaseImplement/Implements/ClientStorage.cs @@ -0,0 +1,40 @@ +using Contracts.BindingModel; +using Contracts.SearchModels; +using Contracts.StoragesContracts; +using Contracts.ViewModels; +using DatabaseImplement.Models; + +namespace DatabaseImplement.Implements +{ + public class ClientStorage : IClientStorage + { + private void CheckSearchModel(ClientSearchModel model) + { + if (model == null) + throw new ArgumentNullException("Передаваемая модель для поиска равна нулю", nameof(model)); + if (!model.Id.HasValue && string.IsNullOrEmpty(model.PhoneNumber) && string.IsNullOrEmpty(model.Password)) + throw new ArgumentException("Все передаваемые поля поисковой модели оказались пусты или равны null"); + if (!model.Id.HasValue && (string.IsNullOrEmpty(model.PhoneNumber) && !string.IsNullOrEmpty(model.Password))) + throw new ArgumentException("Для нахождения соответствующего пользователя вместе с паролем нужен логин"); + } + public ClientViewModel? GetElement(ClientSearchModel model) + { + CheckSearchModel(model); + using var context = new AutoShopDB(); + + return context.Clients.FirstOrDefault(x => x.PhoneNumber.Equals(model.PhoneNumber) && (string.IsNullOrEmpty(model.Password) || x.Password.Equals(model.Password)))?.GetViewModel; + } + public ClientViewModel? Insert(ClientBindingModel model) + { + if (model == null) + { + return null; + } + var newClient = Client.Create(model); + using var context = new AutoShopDB(); + context.Clients.Add(newClient); + context.SaveChanges(); + return newClient.GetViewModel; + } + } +} diff --git a/DatabaseImplement/Implements/CostStorage.cs b/DatabaseImplement/Implements/CostStorage.cs new file mode 100644 index 0000000..778b9c4 --- /dev/null +++ b/DatabaseImplement/Implements/CostStorage.cs @@ -0,0 +1,96 @@ +using Contracts.BindingModels; +using Contracts.SearchModels; +using Contracts.StoragesContracts; +using Contracts.ViewModels; +using DatabaseImplement.Models; +using Microsoft.EntityFrameworkCore; + +namespace kDatabaseImplement.Implements +{ + public class CostStorage : IOrderStorage + { + private void CheckSearchModel(OrderSearchModel model) + { + if (model == null) + throw new ArgumentNullException("Передаваемая модель для поиска равна нулю", nameof(model)); + if (!model.Id.HasValue && !model.EmployeeId.HasValue) + throw new ArgumentException("Все передаваемые поля поисковой модели оказались пусты или равны null"); + } + public CostViewModel? Delete(CostBindingModel model) + { + using var context = new AutoShopDB(); + var element = context.Costs.FirstOrDefault(x => x.Id == model.Id); + if (element != null) + { + context.Costs.Remove(element); + context.SaveChanges(); + return element.GetViewModel; + } + return null; + } + + public CostViewModel? GetElement(OrderSearchModel model) + { + CheckSearchModel(model); + using var context = new AutoShopDB(); + if (!model.Id.HasValue) + { + return null; + } + return context.Costs + .Include(cost => cost.Employee) + .Include(cost => cost.Purchases).ThenInclude(costByPurchase => costByPurchase.Purchase) + .FirstOrDefault(x => model.Id.HasValue && x.Id == model.Id)?.GetViewModel; + } + + public List GetFilteredList(OrderSearchModel model) + { + CheckSearchModel(model); + using var context = new AutoShopDB(); + return context.Costs + .Include(cost => cost.Employee) + .Include(cost => cost.Purchases).ThenInclude(costByPurchase => costByPurchase.Purchase) + .Where(x => x.EmployeeId == model.EmployeeId || x.Id == model.Id) + .Select(x => x.GetViewModel) + .ToList(); + } + + public List GetFullList() + { + using var context = new AutoShopDB(); + return context.Costs + .Include(cost => cost.Employee) + .Include(cost => cost.Purchases).ThenInclude(costByPurchase => costByPurchase.Purchase) + .Select(x => x.GetViewModel) + .ToList(); + } + + public CostViewModel? Insert(CostBindingModel model) + { + var newCost = Cost.Create(model); + if (newCost == null) + { + return null; + } + using var context = new AutoShopDB(); + + context.Costs.Add(newCost); + context.SaveChanges(); + return newCost.GetViewModel; + } + public CostViewModel? Update(CostBindingModel model) + { + using var context = new AutoShopDB(); + var cost = context.Costs.FirstOrDefault(x => x.Id == model.Id); + if (cost == null) + { + return null; + } + cost.Update(model); + context.SaveChanges(); + cost.UpdatePurchases(context, model); + context.SaveChanges(); + return cost.GetViewModel; + } + } +} diff --git a/DatabaseImplement/Implements/EmployeeStorage.cs b/DatabaseImplement/Implements/EmployeeStorage.cs new file mode 100644 index 0000000..08de9c4 --- /dev/null +++ b/DatabaseImplement/Implements/EmployeeStorage.cs @@ -0,0 +1,41 @@ +using BankContracts.BindingModels; +using BankContracts.SearchModels; +using BankContracts.StoragesContracts; +using BankContracts.ViewModels; +using BankDatabaseImplement.Models; + +namespace BankDatabaseImplement.Implements +{ + public class EmployeeStorage : IEmployeeStorage + { + private void CheckSearchModel(EmployeeSearchModel model) + { + if (model == null) + throw new ArgumentNullException("Передаваемая модель для поиска равна нулю", nameof(model)); + if (!model.Id.HasValue && string.IsNullOrEmpty(model.PhoneNumber) && string.IsNullOrEmpty(model.Password)) + throw new ArgumentException("Все передаваемые поля поисковой модели оказались пусты или равны null"); + if (!model.Id.HasValue && (string.IsNullOrEmpty(model.PhoneNumber) && !string.IsNullOrEmpty(model.Password))) + throw new ArgumentException("Для нахождения соответствующего пользователя вместе с паролем нужен логин"); + } + public EmployeeViewModel? GetElement(EmployeeSearchModel model) + { + CheckSearchModel(model); + using var context = new AutoShopDB(); + + return context.Employees + .FirstOrDefault(x => x.PhoneNumber.Equals(model.PhoneNumber) && (string.IsNullOrEmpty(model.Password) || x.Password.Equals(model.Password)))?.GetViewModel; + } + public EmployeeViewModel? Insert(EmployeeBindingModel model) + { + if (model == null) + { + return null; + } + var newEmployee = Employee.Create(model); + using var context = new AutoShopDB(); + context.Employees.Add(newEmployee); + context.SaveChanges(); + return newEmployee.GetViewModel; + } + } +} diff --git a/DatabaseImplement/Implements/OperationStorage.cs b/DatabaseImplement/Implements/OperationStorage.cs new file mode 100644 index 0000000..b4ec052 --- /dev/null +++ b/DatabaseImplement/Implements/OperationStorage.cs @@ -0,0 +1,111 @@ +using BankContracts.BindingModels; +using BankContracts.SearchModels; +using BankContracts.StoragesContracts; +using BankContracts.ViewModels; +using BankDatabaseImplement.Models; +using Microsoft.EntityFrameworkCore; + +namespace BankDatabaseImplement.Implements +{ + public class OperationStorage : IOperationStorage + { + private void CheckSearchModel(OperationSearchModel model) + { + if (model == null) + throw new ArgumentNullException("Передаваемая модель для поиска равна нулю", nameof(model)); + if (!model.Id.HasValue && !model.EmployeeId.HasValue && model.PurchasesIds == null) + throw new ArgumentException("Все передаваемые поля поисковой модели оказались пусты или равны null"); + } + + public OperationViewModel? Delete(OperationBindingModel model) + { + using var context = new AutoShopDB(); + var element = context.Operations.FirstOrDefault(x => x.Id == model.Id); + if (element != null) + { + context.Operations.Remove(element); + context.SaveChanges(); + return element.GetViewModel; + } + return null; + } + + public OperationViewModel? GetElement(OperationSearchModel model) + { + CheckSearchModel(model); + if (!model.Id.HasValue) + { + return null; + } + using var context = new AutoShopDB(); + return context.Operations + .Include(x => x.Employee) + .FirstOrDefault(x => model.Id.HasValue && x.Id == model.Id)?.GetViewModel; + } + + public List GetFilteredList(OperationSearchModel model) + { + CheckSearchModel(model); + if (model.Id.HasValue) + { + var res = GetElement(model); + return res != null ? new() { res } : new(); + } + using var context = new AutoShopDB(); + + var query = context.Operations.Include(x => x.Employee); + if (model.EmployeeId.HasValue) + { + + return query + .Where(x => model.EmployeeId == x.EmployeeId) + .Select(x => x.GetViewModel) + .ToList(); + } + + if (model.PurchasesIds != null) + return query + .Include(x => x.Purchases)! + .ThenInclude(x => x.Purchase) + .ThenInclude(x => x.Operations) + .Where(x => x.Purchases.Any(y => model.PurchasesIds.Contains(y.PurchaseId))) + .Select(x => x.GetViewModel) + .ToList(); + return new(); + } + + public List GetFullList() + { + using var context = new AutoShopDB(); + return context.Operations.Include(x => x.Employee) + .Select(x => x.GetViewModel) + .ToList(); + } + + public OperationViewModel? Insert(OperationBindingModel model) + { + var newOperation = Operation.Create(model); + if (newOperation == null) + { + return null; + } + using var context = new AutoShopDB(); + context.Operations.Add(newOperation); + context.SaveChanges(); + return newOperation.GetViewModel; + } + + public OperationViewModel? Update(OperationBindingModel model) + { + using var context = new AutoShopDB(); + var car = context.Operations.FirstOrDefault(x => x.Id == model.Id); + if (car == null) + { + return null; + } + car.Update(model); + context.SaveChanges(); + return car.GetViewModel; + } + } +} diff --git a/DatabaseImplement/Implements/PaymentStorage.cs b/DatabaseImplement/Implements/PaymentStorage.cs new file mode 100644 index 0000000..1fc14e4 --- /dev/null +++ b/DatabaseImplement/Implements/PaymentStorage.cs @@ -0,0 +1,76 @@ +using BankContracts.BindingModels; +using BankContracts.SearchModels; +using BankContracts.StoragesContracts; +using BankContracts.ViewModels; +using BankDatabaseImplement.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; + +namespace BankDatabaseImplement.Implements +{ + public class PaymentStorage : IPaymentStorage + { + private static IIncludableQueryable Payments(AutoShopDB context) + => context.Payments.Include(x => x.OperationByPurchase).ThenInclude(x => x.Operation); + + public List GetFullList() + { + using var context = new AutoShopDB(); + return Payments(context) + .Select(x => x.GetViewModel) + .ToList(); + } + + public List GetFilteredList(PaymentSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model), "Получена пустая поисковая модель"); + } + if (model.DateFrom.HasValue && !model.DateTo.HasValue || model.DateTo.HasValue && !model.DateFrom.HasValue) + { + throw new ArgumentException("Получена поисковая модель только с началом или концом периода"); + } + if (!model.DateFrom.HasValue && !model.OperationId.HasValue) + { + throw new ArgumentNullException(nameof(model.OperationId), "Получена поисковая модель без OperationId"); + + } + if (!model.DateFrom.HasValue && !model.PurchaseId.HasValue) + { + throw new ArgumentNullException(nameof(model.PurchaseId), "Получена поисковая модель без PurchaseId"); + } + using var context = new AutoShopDB(); + if (model.DateFrom.HasValue) + return Payments(context) + .Where(x => model.DateFrom.Value <= x.Date && x.Date <= model.DateTo.Value) + .Select(x => x.GetViewModel) + .ToList(); + + return Payments(context) + .Where(x => x.OperationByPurchase != null && + x.OperationByPurchase.OperationId == model.OperationId && + x.OperationByPurchase.PurchaseId == model.PurchaseId) + .Select(x => x.GetViewModel) + .ToList(); + } + public PaymentViewModel? GetElement(PaymentSearchModel model) + { + using var context = new AutoShopDB(); + return Payments(context) + .FirstOrDefault(x => (model.Id.HasValue && x.Id == model.Id))?.GetViewModel; + } + public PaymentViewModel? Insert(PaymentBindingModel model) + { + if (model == null) + { + return null; + } + var newPayment = Payment.Create(model); + using var context = new AutoShopDB(); + context.Payments.Add(newPayment); + context.SaveChanges(); + return newPayment.GetViewModel; + } + } +} diff --git a/DatabaseImplement/Implements/PurchaseStorage.cs b/DatabaseImplement/Implements/PurchaseStorage.cs new file mode 100644 index 0000000..84a3bf0 --- /dev/null +++ b/DatabaseImplement/Implements/PurchaseStorage.cs @@ -0,0 +1,151 @@ +using System.Security.Cryptography.X509Certificates; +using BankContracts.BindingModels; +using BankContracts.SearchModels; +using BankContracts.StoragesContracts; +using BankContracts.ViewModels; +using BankDatabaseImplement.Models; +using Microsoft.EntityFrameworkCore; + +namespace BankDatabaseImplement.Implements +{ + public class PurchaseStorage : IPurchaseStorage + { + private void CheckSearchModel(PurchaseSearchModel model) + { + if (model == null) + throw new ArgumentNullException("Передаваемая модель для поиска равна нулю", nameof(model)); + if (!model.Id.HasValue && !model.ClientId.HasValue && !model.DateFrom.HasValue && !model.DateTo.HasValue && model.OperationsIds == null) + throw new ArgumentException("Все передаваемые поля поисковой модели оказались пусты или равны null"); + if (model.DateFrom.HasValue != model.DateTo.HasValue) + throw new ArgumentException($"Не указано начало {model.DateFrom} или конец {model.DateTo} периода для поиска по дате."); + } + public PurchaseViewModel? Delete(PurchaseBindingModel model) + { + using var context = new AutoShopDB(); + var element = context.Purchases.FirstOrDefault(x => x.Id == model.Id); + if (element != null) + { + context.Purchases.Remove(element); + context.SaveChanges(); + return element.GetViewModel; + } + return null; + } + + + public List GetPaymentsFromPurchaseAndOperation(PurchaseSearchModel modelPurchase, OperationSearchModel modelOperation) + { + if (!modelPurchase.Id.HasValue) + { + throw new ArgumentNullException(nameof(modelPurchase), "Получена поисковая модель без Id"); + } + if (!modelOperation.Id.HasValue) + { + throw new ArgumentNullException(nameof(modelOperation), "Получена поисковая модель без Id"); + } + using var context = new AutoShopDB(); + var carByPurchase = context.OperationByPurchases + .Include(x => x.Payments) + .FirstOrDefault(x => x.OperationId == modelOperation.Id && x.PurchaseId == modelPurchase.Id); + if (carByPurchase?.Payments == null) + { + throw new InvalidOperationException( + $"Не существует связи между данной операции(Id={modelOperation.Id}) и покупкой(Id={modelPurchase.Id})"); + } + return carByPurchase.Payments.Select(payment => payment.GetViewModel).ToList(); + } + + public PurchaseViewModel? GetElement(PurchaseSearchModel model) + { + using var context = new AutoShopDB(); + if (!model.Id.HasValue) + { + return null; + } + return context.Purchases + .Include(x => x.Client) + .Include(x => x.Operations) + .FirstOrDefault(x => model.Id.HasValue && x.Id == model.Id)?.GetViewModel; + } + + public List GetFilteredList(PurchaseSearchModel model) + { + CheckSearchModel(model); + if (model.Id.HasValue) + { + var res = GetElement(model); + return res != null ? new() { res } : new(); + } + + using var context = new AutoShopDB(); + + var query = context.Purchases.Include(x => x.Client); + IQueryable? resultQuery = null; + if (model.ClientId.HasValue) + { + + return query + .Where(x => model.ClientId == x.ClientId) + .Select(x => x.GetViewModel) + .ToList(); + } + + if (model.DateTo.HasValue) + resultQuery = query + .Include(x => x.Operations) + .ThenInclude(x => x.Operation) + .Include(x => x.Costs)! + .ThenInclude(x => x.Cost) + .Where(x => model.DateFrom <= x.DatePurchase && x.DatePurchase <= model.DateTo); + + else if (model.OperationsIds != null) + resultQuery = query + .Where(x => x.Operations.Any(x => model.OperationsIds.Contains(x.OperationId))) + .Include(x => x.Operations) + .ThenInclude(x => x.Operation); + + return resultQuery? + .Select(x => x.GetViewModel) + .ToList() ?? new(); + } + + public List GetFullList() + { + using var context = new AutoShopDB(); + return context.Purchases + .Include(x => x.Client) + .Include(x => x.Operations) + .Select(x => x.GetViewModel) + .ToList(); + } + + public PurchaseViewModel? Insert(PurchaseBindingModel model) + { + var newPurchase = Purchase.Create(model); + if (newPurchase == null) + { + return null; + } + using var context = new AutoShopDB(); + context.Purchases.Add(newPurchase); + context.SaveChanges(); + newPurchase.UpdateOperations(context, model); + context.SaveChanges(); + return newPurchase.GetViewModel; + } + + public PurchaseViewModel? Update(PurchaseBindingModel model) + { + using var context = new AutoShopDB(); + var purchase = context.Purchases.FirstOrDefault(x => x.Id == model.Id); + if (purchase == null) + { + return null; + } + purchase.Update(model); + purchase.UpdateOperations(context, model); + context.SaveChanges(); + return purchase.GetViewModel; + } + } +} diff --git a/DatabaseImplement/Models/CarByPurchase.cs b/DatabaseImplement/Models/CarByPurchase.cs new file mode 100644 index 0000000..120c761 --- /dev/null +++ b/DatabaseImplement/Models/CarByPurchase.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; +using DataModels.ProxyModels; + +namespace DatabaseImplement.Models +{ + public class OperationByPurchase : OperationByPurchaseModel + { + [Required] + public Operation? Operation { get; private set; } + [Required] + public Purchase? Purchase { get; private set; } + [Required] + public List? Payments { get; private set; } + } +} \ No newline at end of file diff --git a/DatabaseImplement/Models/Client.cs b/DatabaseImplement/Models/Client.cs new file mode 100644 index 0000000..7ac9f4c --- /dev/null +++ b/DatabaseImplement/Models/Client.cs @@ -0,0 +1,57 @@ +using Contracts.BindingModel; +using Contracts.ViewModels; +using DataModels; +using System.ComponentModel.DataAnnotations; + +namespace DatabaseImplement.Models +{ + public class Client : IClientModel + { + public int Id { get; set; } + [Required] + public string FirstName { get; private set; } = string.Empty; + [Required] + public string LastName { get; private set; } = string.Empty; + + public string? MiddleName { get; private set; } + [Required] + public string Address { get; private set; } = string.Empty; + [Required] + public string PhoneNumber { get; private set; } = string.Empty; + [Required] + public string Email { get; set; } = string.Empty; + [Required] + public string Password { get; private set; } = string.Empty; + [Required] + public List? Purchases { get; private set; } + + public static Client Create(ClientBindingModel model) + { + if (model == null) + { + return null; + } + return new Client() + { + FirstName = model.FirstName, + LastName = model.LastName, + MiddleName = model.MiddleName, + PhoneNumber = model.PhoneNumber, + Password = model.Password, + Id = model.Id, + Email = model.Email, + }; + } + + public ClientViewModel GetViewModel => new() + { + FirstName = FirstName, + LastName = LastName, + MiddleName = MiddleName, + PhoneNumber =PhoneNumber, + Password = Password, + Id = Id, + Email = Email, + }; + } +} diff --git a/DatabaseImplement/Models/CostByPurchase.cs b/DatabaseImplement/Models/CostByPurchase.cs new file mode 100644 index 0000000..85386d2 --- /dev/null +++ b/DatabaseImplement/Models/CostByPurchase.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; +using BankDataModels.ProxyModels; + +namespace BankDatabaseImplement.Models +{ + public class CostByPurchase : CostByPurchaseModel + { + [Required] + public Order? Cost { get; private set; } + [Required] + public Purchase? Purchase { get; private set; } + } +} diff --git a/DatabaseImplement/Models/Employee.cs b/DatabaseImplement/Models/Employee.cs new file mode 100644 index 0000000..39c9eb1 --- /dev/null +++ b/DatabaseImplement/Models/Employee.cs @@ -0,0 +1,60 @@ +using BankContracts.BindingModels; +using BankContracts.ViewModels; +using BankDataModels; +using System.ComponentModel.DataAnnotations; + +namespace BankDatabaseImplement.Models +{ + public class Employee : IEmployeeModel + { + public int Id { get; private set; } + [Required] + public string FirstName { get; private set; } = string.Empty; + [Required] + public string LastName { get; private set; } = string.Empty; + public string? MiddleName { get; private set; } + [Required] + public string Post { get; private set; } = string.Empty; + [Required] + public string PhoneNumber { get; private set; } = string.Empty; + [Required] + public string Password { get; private set; } = string.Empty; + [Required] + public string Email { get; set; } = string.Empty; + [Required] + public List? Operations { get; private set; } + [Required] + public List? Costs { get; private set; } + + public static Employee Create(EmployeeBindingModel model) + { + if (model == null) + { + return null; + } + return new Employee() + { + FirstName = model.FirstName, + LastName = model.LastName, + MiddleName = model.MiddleName, + PhoneNumber = model.PhoneNumber, + Password = model.Password, + Id = model.Id, + Post = model.Post, + Email = model.Email, + }; + } + + public EmployeeViewModel GetViewModel => new() + { + FirstName = FirstName, + LastName = LastName, + MiddleName = MiddleName, + PhoneNumber = PhoneNumber, + Password = Password, + Id = Id, + Post = Post, + Email = Email, + }; + } +} \ No newline at end of file diff --git a/DatabaseImplement/Models/Operation.cs b/DatabaseImplement/Models/Operation.cs new file mode 100644 index 0000000..4641355 --- /dev/null +++ b/DatabaseImplement/Models/Operation.cs @@ -0,0 +1,62 @@ +using BankContracts.BindingModels; +using BankContracts.SearchModels; +using BankContracts.ViewModels; +using BankDatabaseImplement.Implements; +using BankDataModels; +using BankDataModels.ProxyModels; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace BankDatabaseImplement.Models +{ + public class Operation : IOperationModel + { + [Required] + public int EmployeeId { get; private set; } + [Required] + public string Model { get; private set; } = string.Empty; + [Required] + public double Price { get; private set; } + [Required] + public string Mark { get; private set; } = string.Empty; + + public int Id { get; private set; } + [Required] + public Employee? Employee { get; private set; } + + [Required] + public List Purchases { get; private set; } = new(); + + public static Operation Create(OperationBindingModel model) + { + if (model == null) + { + return null; + } + return new Operation() + { + EmployeeId = model.EmployeeId, + Model = model.Model, + Price = model.Price, + Mark = model.Mark, + Id = model.Id, + }; + } + + public OperationViewModel GetViewModel => new() + { + EmployeePhoneNumber = Employee?.PhoneNumber??string.Empty, + EmployeeId = EmployeeId, + Model = Model, + Price = Price, + Mark = Mark, + Id = Id, + Purchases = Purchases.Select(x=>x.Purchase?.GetViewModel2).ToList(), + }; + + public void Update(OperationBindingModel model) + { + Price = model.Price; + } + } +} diff --git a/DatabaseImplement/Models/Order.cs b/DatabaseImplement/Models/Order.cs new file mode 100644 index 0000000..7cf8d73 --- /dev/null +++ b/DatabaseImplement/Models/Order.cs @@ -0,0 +1,81 @@ +using Contracts.BindingModel; +using Contracts.ViewModels; +using DataModels; +using System.ComponentModel.DataAnnotations; +using DataModels.ProxyModels; + +namespace DatabaseImplement.Models +{ + public class Order : IOrderModel + { + [Required] + public int OrderId { get; private set; } + [Required] + public string NameOrder { get; private set; } = string.Empty; + public int Id { get; private set; } + [Required] + public double Price { get; private set; } + private Dictionary? _cachedPurchases; + public Dictionary PurchasesModels => _cachedPurchases ??= Purchases.Select(x => (CostByPurchaseModel)x).ToDictionary(x => x.PurchaseId, x => x); + [Required] + public Order? Order{ get; private set; } + [Required] + public List Purchases { get; private set; } = new(); + + public static Order Create(OrderBindingModel model) + { + if (model == null) + { + return null; + } + return new Order() + { + OrderId = model.OrderId, + NameOrder = model.NameOrder, + Price = model.Price, + //PurchasesModels = model.PurchasesModels, + Id = model.Id + }; + } + + public OrderViewModel GetViewModel => new() + { + PhoneNumber = Employee?.PhoneNumber??string.Empty, + PurchaseModels = PurchasesModels, + EmployeeId = EmployeeId, + NameOfCost = NameOfCost, + Price = Price, + Id = Id + }; + + public void Update(OrderBindingModel model) + { + NameOrder = model.NameOrder; + Price = model.Price; + } + + /// + /// Привязка статей затрат к покупкам + /// + public void UpdatePurchases(AutoShopDB context, OrderBindingModel model) + { + var oldPurchases = context.CostByPurchases.Where(x => x.CostId == model.Id).ToDictionary(x => x.PurchaseId, x => x); + var newPurchases = model.PurchasesModels.ToDictionary( + x => x.Key, + x => new OrderByPurchase() + { + CostId = model.Id, + PurchaseId = x.Key, + Count = x.Value.Count, + } + ); + context.RemoveRange(oldPurchases.Where(x => !newPurchases.ContainsKey(x.Key)).Select(x => x.Value)); + context.AddRange (newPurchases.Where(x => !oldPurchases.ContainsKey(x.Key)).Select(x => x.Value)); + oldPurchases.Where(x => newPurchases.ContainsKey(x.Key)) + .Select(x => x.Value).ToList() + .ForEach(x => x.Count = newPurchases[x.PurchaseId].Count); + context.SaveChanges(); + _cachedPurchases = null; + } + } +} diff --git a/DatabaseImplement/Models/Payment.cs b/DatabaseImplement/Models/Payment.cs new file mode 100644 index 0000000..0cefd3e --- /dev/null +++ b/DatabaseImplement/Models/Payment.cs @@ -0,0 +1,51 @@ +using Contracts.BindingModel; +using Contracts.ViewModels; +using DataModels; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; + +namespace DatabaseImplement.Models +{ + public class Payment : IPaymentModel + { + [Required] + public int OperationByPurchaseId { get; private set; } + + [Required] + public DateOnly Date { get; private set; } + + [Required] + public double PaidPrice { get; private set; } + + public int Id { get; private set; } + + [Required] + public OperationByPurchase? OperationByPurchase { get; private set; } + + public static Payment Create(PaymentBindingModel model) + { + if (model == null) + { + return null; + } + return new Payment() + { + + Date = model.Date, + PaidPrice = model.PaidPrice, + Id = model.Id, + OperationByPurchaseId = model.OperationByPurchaseId, + }; + } + public PaymentViewModel GetViewModel => new() + { + Operation = OperationByPurchase?.Operation?.GetViewModel, + OperationByPurchase = OperationByPurchase, + FullPrice = OperationByPurchase?.Operation?.Price ?? -1, + Date = Date, + PaidPrice = PaidPrice, + Id = Id, + OperationByPurchaseId = OperationByPurchaseId, + }; + } +} diff --git a/DatabaseImplement/Models/Purchase.cs b/DatabaseImplement/Models/Purchase.cs new file mode 100644 index 0000000..5d7aab1 --- /dev/null +++ b/DatabaseImplement/Models/Purchase.cs @@ -0,0 +1,95 @@ +using Contracts.BindingModel; +using Contracts.ViewModels; +using DataModels; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq.Expressions; +using DataModels.ProxyModels; + +namespace DatabaseImplement.Models +{ + public class Purchase : IPurchaseModel + { + public int ClientId { get; private set; } + public DateOnly DatePurchase { get; private set; } + private Dictionary? _cachedOperations; + [NotMapped] + public Dictionary OperationsModel => _cachedOperations ??= Operations.Select(x => (OperationByPurchaseModel)x).ToDictionary(x => x.OperationId, x => x); + [NotMapped] + public List? OrderModel => null; + public int Id { get; private set; } + [Required] + public Client? Client { get; private set; } + [Required] + public List Operations { get; private set; } = new(); + [Required] + public List Order { get; private set; } = new(); + + public static Purchase Create(PurchaseBindingModel model) + { + return new Purchase() + { + ClientId = model.ClientId, + Id = model.Id, + DatePurchase = model.DatePurchase, + + }; + } + public void Update(PurchaseBindingModel model) + { + DatePurchase = model.DatePurchase; + } + + public PurchaseViewModel GetViewModel => new() + { + OperationsModel = OperationsModel, + Id = Id, + DatePurchase = DatePurchase, + ClientId = ClientId, + ClientPhoneNumber = Client?.PhoneNumber ?? string.Empty, + + CostViewModels = Costs? + .Select(x => x.Cost.GetViewModel) + .ToList() ?? new(), + OperationViewModels = Operations? + .Select(x => x.Operation?.GetViewModel) + .ToList() ?? new() + }; + + public PurchaseViewModel GetViewModel2 => new() + { + OperationsModel = OperationsModel, + Id = Id, + DatePurchase = DatePurchase, + ClientId = ClientId, + ClientPhoneNumber = Client?.PhoneNumber ?? string.Empty, + + CostViewModels = Costs? + .Select(x => x.Cost.GetViewModel) + .ToList() ?? new() + }; + + public void UpdateOperations(AutoShopDB context, PurchaseBindingModel model) + { + var oldOperations = context.OperationByPurchases.Where(x => x.PurchaseId == model.Id).ToDictionary(x => x.OperationId, x => x); + var newOperations = model.OperationsModel.ToDictionary( + x => x.Key, + x => new OperationByPurchase() + { + OperationId = x.Key, + PurchaseId = Id, + CountOperations = x.Value.CountOperations + } + ); + + context.RemoveRange(oldOperations.Where(x => !newOperations.ContainsKey(x.Key)).Select(x => x.Value)); + context.AddRange (newOperations.Where(x => !oldOperations.ContainsKey(x.Key)).Select(x => x.Value)); + oldOperations + .Where(x => newOperations.ContainsKey(x.Key)) + .Select(x => x.Value).ToList() + .ForEach(x => x.CountOperations = newOperations[x.OperationId].CountOperations); + context.SaveChanges(); + _cachedOperations = null; + } + } +} diff --git a/WebApplication2/AutoRepairShop.csproj b/WebApplication2/AutoRepairShop.csproj new file mode 100644 index 0000000..867990d --- /dev/null +++ b/WebApplication2/AutoRepairShop.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + enable + enable + true + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/WebApplication2/AutoRepairShop.sln b/WebApplication2/AutoRepairShop.sln new file mode 100644 index 0000000..c04112c --- /dev/null +++ b/WebApplication2/AutoRepairShop.sln @@ -0,0 +1,137 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34525.116 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoRepairShop", "AutoRepairShop.csproj", "{16B8DA1D-079B-41D4-BD49-66E67227A87B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataModel", "..\DataModel1\DataModel.csproj", "{EBEF686C-AE20-44B7-834F-EE20E71481A7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BussinesLogic", "..\BussinesLogic\BussinesLogic.csproj", "{0C8B86BC-3246-47AD-8237-51A277412A2C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contracts", "..\Contracts\Contracts.csproj", "{33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseImplement", "..\DatabaseImplement\DatabaseImplement.csproj", "{45AF9928-B17D-4F6A-B461-736DD540937F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Debug|ARM.ActiveCfg = Debug|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Debug|ARM.Build.0 = Debug|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Debug|ARM64.Build.0 = Debug|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Debug|x64.ActiveCfg = Debug|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Debug|x64.Build.0 = Debug|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Debug|x86.ActiveCfg = Debug|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Debug|x86.Build.0 = Debug|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Release|Any CPU.Build.0 = Release|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Release|ARM.ActiveCfg = Release|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Release|ARM.Build.0 = Release|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Release|ARM64.ActiveCfg = Release|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Release|ARM64.Build.0 = Release|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Release|x64.ActiveCfg = Release|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Release|x64.Build.0 = Release|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Release|x86.ActiveCfg = Release|Any CPU + {16B8DA1D-079B-41D4-BD49-66E67227A87B}.Release|x86.Build.0 = Release|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Debug|ARM.ActiveCfg = Debug|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Debug|ARM.Build.0 = Debug|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Debug|ARM64.Build.0 = Debug|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Debug|x64.ActiveCfg = Debug|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Debug|x64.Build.0 = Debug|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Debug|x86.ActiveCfg = Debug|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Debug|x86.Build.0 = Debug|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Release|Any CPU.Build.0 = Release|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Release|ARM.ActiveCfg = Release|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Release|ARM.Build.0 = Release|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Release|ARM64.ActiveCfg = Release|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Release|ARM64.Build.0 = Release|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Release|x64.ActiveCfg = Release|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Release|x64.Build.0 = Release|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Release|x86.ActiveCfg = Release|Any CPU + {EBEF686C-AE20-44B7-834F-EE20E71481A7}.Release|x86.Build.0 = Release|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Debug|ARM.Build.0 = Debug|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Debug|ARM64.Build.0 = Debug|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Debug|x64.ActiveCfg = Debug|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Debug|x64.Build.0 = Debug|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Debug|x86.ActiveCfg = Debug|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Debug|x86.Build.0 = Debug|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Release|Any CPU.Build.0 = Release|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Release|ARM.ActiveCfg = Release|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Release|ARM.Build.0 = Release|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Release|ARM64.ActiveCfg = Release|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Release|ARM64.Build.0 = Release|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Release|x64.ActiveCfg = Release|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Release|x64.Build.0 = Release|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Release|x86.ActiveCfg = Release|Any CPU + {0C8B86BC-3246-47AD-8237-51A277412A2C}.Release|x86.Build.0 = Release|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Debug|ARM.Build.0 = Debug|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Debug|ARM64.Build.0 = Debug|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Debug|x64.ActiveCfg = Debug|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Debug|x64.Build.0 = Debug|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Debug|x86.ActiveCfg = Debug|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Debug|x86.Build.0 = Debug|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Release|Any CPU.Build.0 = Release|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Release|ARM.ActiveCfg = Release|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Release|ARM.Build.0 = Release|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Release|ARM64.ActiveCfg = Release|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Release|ARM64.Build.0 = Release|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Release|x64.ActiveCfg = Release|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Release|x64.Build.0 = Release|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Release|x86.ActiveCfg = Release|Any CPU + {33119A37-AB7A-4CE3-A0B1-E5377CB7CF1A}.Release|x86.Build.0 = Release|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Debug|ARM.ActiveCfg = Debug|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Debug|ARM.Build.0 = Debug|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Debug|ARM64.Build.0 = Debug|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Debug|x64.ActiveCfg = Debug|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Debug|x64.Build.0 = Debug|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Debug|x86.ActiveCfg = Debug|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Debug|x86.Build.0 = Debug|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Release|Any CPU.Build.0 = Release|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Release|ARM.ActiveCfg = Release|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Release|ARM.Build.0 = Release|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Release|ARM64.ActiveCfg = Release|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Release|ARM64.Build.0 = Release|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Release|x64.ActiveCfg = Release|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Release|x64.Build.0 = Release|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Release|x86.ActiveCfg = Release|Any CPU + {45AF9928-B17D-4F6A-B461-736DD540937F}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2555F57D-3305-4A37-80DB-C655B9CFB18C} + EndGlobalSection +EndGlobal diff --git a/WebApplication2/Controllers/WeatherForecastController.cs b/WebApplication2/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000..2094269 --- /dev/null +++ b/WebApplication2/Controllers/WeatherForecastController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace WebApplication2.Controllers +{ + [ApiController] + [Route("[controller]")] + public class WeatherForecastController : ControllerBase + { + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } + } +} diff --git a/WebApplication2/Program.cs b/WebApplication2/Program.cs new file mode 100644 index 0000000..48863a6 --- /dev/null +++ b/WebApplication2/Program.cs @@ -0,0 +1,25 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/WebApplication2/Properties/launchSettings.json b/WebApplication2/Properties/launchSettings.json new file mode 100644 index 0000000..f555672 --- /dev/null +++ b/WebApplication2/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:2499", + "sslPort": 44361 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5081", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7025;http://localhost:5081", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/WebApplication2/WeatherForecast.cs b/WebApplication2/WeatherForecast.cs new file mode 100644 index 0000000..bfdf165 --- /dev/null +++ b/WebApplication2/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace WebApplication +{ + public class WeatherForecast + { + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } + } +} diff --git a/WebApplication2/WebApplication2.http b/WebApplication2/WebApplication2.http new file mode 100644 index 0000000..5d5a8bd --- /dev/null +++ b/WebApplication2/WebApplication2.http @@ -0,0 +1,6 @@ +@WebApplication2_HostAddress = http://localhost:5081 + +GET {{WebApplication2_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/WebApplication2/appsettings.Development.json b/WebApplication2/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/WebApplication2/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/WebApplication2/appsettings.json b/WebApplication2/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/WebApplication2/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +}